Compare commits
2278 Commits
v1.0.4
...
pascallang
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b26c20c54 | ||
|
|
ed2e2e4f32 | ||
|
|
b2f8f482bb | ||
|
|
89023d4b55 | ||
|
|
66ac007d4c | ||
|
|
139cd4c583 | ||
|
|
0fed2486f5 | ||
|
|
11c01004bf | ||
|
|
f49f03d7da | ||
|
|
90bb5f8871 | ||
|
|
401cc76f20 | ||
|
|
6297810edc | ||
|
|
01aef0a822 | ||
|
|
186730231e | ||
|
|
770a12ffdf | ||
|
|
40fa242012 | ||
|
|
c4e70ab4fd | ||
|
|
2da8b3c42a | ||
|
|
38a79c816a | ||
|
|
1d8f1a0857 | ||
|
|
5901bac374 | ||
|
|
2e7b1dc904 | ||
|
|
7052751261 | ||
|
|
60047e2c73 | ||
|
|
40b393ac4a | ||
|
|
1c6dc01959 | ||
|
|
5148449066 | ||
|
|
fcc4d19430 | ||
|
|
c80f705fa2 | ||
|
|
c95db35b41 | ||
|
|
35f3548992 | ||
|
|
58f6716035 | ||
|
|
2b15de0f90 | ||
|
|
be91409df9 | ||
|
|
4d8e440965 | ||
|
|
2d469d074e | ||
|
|
96405d27b5 | ||
|
|
75c9fb40a7 | ||
|
|
cd1c15a45a | ||
|
|
2bd50f4c8c | ||
|
|
4c2ddcbe48 | ||
|
|
d7f9ef6967 | ||
|
|
bfc8c2f9fd | ||
|
|
ce6243d6e3 | ||
|
|
80f9ff4163 | ||
|
|
d9f8a3989a | ||
|
|
416f7d5c19 | ||
|
|
eb24dd5549 | ||
|
|
ba19592973 | ||
|
|
98d8d7fb5f | ||
|
|
ad0947b0b7 | ||
|
|
c093f21b31 | ||
|
|
c5a3e305f9 | ||
|
|
e085602a6c | ||
|
|
dee25215cf | ||
|
|
ef1bb1ead7 | ||
|
|
90170493c0 | ||
|
|
00a9057186 | ||
|
|
05c300e979 | ||
|
|
6730ed6246 | ||
|
|
0a0463652b | ||
|
|
4f580a4286 | ||
|
|
0616cab386 | ||
|
|
175cfa5e93 | ||
|
|
dbfccad568 | ||
|
|
3fe6dc64fa | ||
|
|
49068af59f | ||
|
|
fbd81c6e26 | ||
|
|
9cac96d6a7 | ||
|
|
5987aa40a6 | ||
|
|
30cb812549 | ||
|
|
0fd2e36046 | ||
|
|
8b05e55ebd | ||
|
|
af71a208fd | ||
|
|
7e5cb8e884 | ||
|
|
8c669ea015 | ||
|
|
acd8379077 | ||
|
|
97c6088715 | ||
|
|
db017c73b6 | ||
|
|
24aaa0dd0c | ||
|
|
da33df4346 | ||
|
|
22590ed4f7 | ||
|
|
c0bc64c2aa | ||
|
|
694d968e8c | ||
|
|
fff3b8830e | ||
|
|
b740f4cd24 | ||
|
|
e247b8b9c1 | ||
|
|
4f7af553d1 | ||
|
|
570e6f8c64 | ||
|
|
b6e665b567 | ||
|
|
48e82304a0 | ||
|
|
7b58b9aca0 | ||
|
|
dfcf3f533c | ||
|
|
4c14925b4f | ||
|
|
4c74bc869d | ||
|
|
45edfa1ec0 | ||
|
|
88343b7424 | ||
|
|
13197840c2 | ||
|
|
ffe4ac68fd | ||
|
|
5bab5f03db | ||
|
|
ae748e25f8 | ||
|
|
e9c7959ecb | ||
|
|
bf09855014 | ||
|
|
32bd39f209 | ||
|
|
940f241b9d | ||
|
|
5c00ce6b88 | ||
|
|
016b282246 | ||
|
|
d6ecac1302 | ||
|
|
901f8ca6b0 | ||
|
|
9c3b6ba9f6 | ||
|
|
53ec484028 | ||
|
|
246e808cb4 | ||
|
|
a7b68dc2aa | ||
|
|
08404f9223 | ||
|
|
149554e61c | ||
|
|
7b71425db2 | ||
|
|
f9cfb7f20f | ||
|
|
506ee43d41 | ||
|
|
ebde0915cd | ||
|
|
2501656bf4 | ||
|
|
9356e7654e | ||
|
|
4f1e5d2452 | ||
|
|
64c75414d8 | ||
|
|
5147833487 | ||
|
|
324419241f | ||
|
|
1a921b1cdb | ||
|
|
25c052c0a3 | ||
|
|
a02586cca9 | ||
|
|
226e082c5a | ||
|
|
5afdff8477 | ||
|
|
c52ac2cefc | ||
|
|
09f39ea60f | ||
|
|
41e31eae6d | ||
|
|
dcf20951ba | ||
|
|
6e9ebfd695 | ||
|
|
c36b112437 | ||
|
|
24fbd44f5b | ||
|
|
d0db7829e5 | ||
|
|
58ed8ca60f | ||
|
|
4d2c8ef04e | ||
|
|
438e85c551 | ||
|
|
06b336ee59 | ||
|
|
a93adeb75e | ||
|
|
802e69563e | ||
|
|
a8897df3f2 | ||
|
|
7157d3d906 | ||
|
|
96b8a500b4 | ||
|
|
51a3ef8ee9 | ||
|
|
652d6604e7 | ||
|
|
b9028ab4b4 | ||
|
|
62c509b03c | ||
|
|
1648a0780a | ||
|
|
3b1af68ed6 | ||
|
|
aeed7bac57 | ||
|
|
2bb76a40f3 | ||
|
|
0c129a45aa | ||
|
|
2a383c7285 | ||
|
|
34f16b0b66 | ||
|
|
a9d9c4cdfa | ||
|
|
4a1c986dd0 | ||
|
|
756e9b3213 | ||
|
|
61a284863e | ||
|
|
39410c290b | ||
|
|
9e0684b6cb | ||
|
|
13add5b9f2 | ||
|
|
475cd1af98 | ||
|
|
04d08c6d67 | ||
|
|
6295bb1bbc | ||
|
|
931ba2bd68 | ||
|
|
769fb4ff94 | ||
|
|
aa7c18a2bd | ||
|
|
f95cfa1261 | ||
|
|
8c12aaf2c1 | ||
|
|
94f73bd54f | ||
|
|
9b3549d4a9 | ||
|
|
7bc05cb63c | ||
|
|
84780a9d90 | ||
|
|
37e029c612 | ||
|
|
c47ed8aca8 | ||
|
|
5bb0752d5e | ||
|
|
4a626eaf14 | ||
|
|
47de19c8a5 | ||
|
|
3d4cfa30ac | ||
|
|
d658bee05a | ||
|
|
820c181394 | ||
|
|
c9774f557e | ||
|
|
b17618a5a8 | ||
|
|
03d0adbd74 | ||
|
|
905ee4b1ed | ||
|
|
dbc33951a4 | ||
|
|
732e66cab2 | ||
|
|
0dab92552a | ||
|
|
047952537a | ||
|
|
d4bf1fb36e | ||
|
|
ff817cd098 | ||
|
|
04ea44ed4b | ||
|
|
e23c8e2216 | ||
|
|
afb4802a2c | ||
|
|
3a5d341514 | ||
|
|
b6bcab1604 | ||
|
|
0a998d2dc5 | ||
|
|
7927bc601e | ||
|
|
f8cc913898 | ||
|
|
a5428bc180 | ||
|
|
c0285f81f0 | ||
|
|
600049898a | ||
|
|
0e1db8f06b | ||
|
|
ec83f1e5a3 | ||
|
|
f8f7769d9c | ||
|
|
4dacac29c6 | ||
|
|
593f3b87f1 | ||
|
|
bb70116df0 | ||
|
|
d7c24d62ed | ||
|
|
07df1a8959 | ||
|
|
ca9e2870ab | ||
|
|
99ca6fa36c | ||
|
|
3d82560f71 | ||
|
|
44d362aeb4 | ||
|
|
3d4ed5ad11 | ||
|
|
ca3c2bbdc8 | ||
|
|
90c226c748 | ||
|
|
b757283f41 | ||
|
|
b3132c7bf1 | ||
|
|
9ba56f040a | ||
|
|
ac71b4d981 | ||
|
|
6bb2c06cf6 | ||
|
|
2ad3c727fd | ||
|
|
d36af55b84 | ||
|
|
f19bb05c7a | ||
|
|
08ea8818fb | ||
|
|
59c541d013 | ||
|
|
37e2b5f41c | ||
|
|
614a330cf2 | ||
|
|
9106548859 | ||
|
|
2f07e79e50 | ||
|
|
2233f6f862 | ||
|
|
ae842f0bdc | ||
|
|
4b36656246 | ||
|
|
ea282489f9 | ||
|
|
6f2d9430d0 | ||
|
|
bccd9dc0d9 | ||
|
|
af919fb940 | ||
|
|
7dab0de3c5 | ||
|
|
2c0525421a | ||
|
|
0844ec2efd | ||
|
|
49c3af12f9 | ||
|
|
96d335f458 | ||
|
|
eae412fe41 | ||
|
|
0270420531 | ||
|
|
93bb117961 | ||
|
|
29d1fb00b1 | ||
|
|
5a49d99c4f | ||
|
|
d66bf1a5b3 | ||
|
|
b41dccef67 | ||
|
|
addf2c5143 | ||
|
|
ff829f1f7b | ||
|
|
7ee72976c4 | ||
|
|
dc18e8e5b2 | ||
|
|
97de2aaf3d | ||
|
|
3b8b2ef376 | ||
|
|
d496f62719 | ||
|
|
fc978f95ef | ||
|
|
596e8c9b55 | ||
|
|
0cf58c2990 | ||
|
|
6ba1c8b118 | ||
|
|
b949ac0fed | ||
|
|
510f892d2f | ||
|
|
17750e774a | ||
|
|
be1591c489 | ||
|
|
3b22705166 | ||
|
|
c05c0a5693 | ||
|
|
d6fc6a3517 | ||
|
|
7bfaee8b4f | ||
|
|
89c00e8f17 | ||
|
|
447a58966f | ||
|
|
74162aa972 | ||
|
|
78a1e61f7a | ||
|
|
a917227ddc | ||
|
|
c866d07743 | ||
|
|
43d969f962 | ||
|
|
3973b42f81 | ||
|
|
6046ad81db | ||
|
|
63a9874aea | ||
|
|
89420fe2d4 | ||
|
|
9769354989 | ||
|
|
580b996215 | ||
|
|
8f5fb5083f | ||
|
|
821076ce95 | ||
|
|
0bfe1f8e63 | ||
|
|
9c35f6f73c | ||
|
|
983debe6ce | ||
|
|
66704b5a13 | ||
|
|
f11da0c1de | ||
|
|
7676398aab | ||
|
|
9c6c55fa00 | ||
|
|
5b9ca3ba06 | ||
|
|
23141b6087 | ||
|
|
6d4b4bd2c0 | ||
|
|
5cec22a757 | ||
|
|
153ba2e090 | ||
|
|
21e8bed52b | ||
|
|
ecfc5b0313 | ||
|
|
2bcebbda45 | ||
|
|
52e8d87ab1 | ||
|
|
b613345da4 | ||
|
|
f2665ca786 | ||
|
|
e3189d3aed | ||
|
|
c829e1c86f | ||
|
|
8499a508f5 | ||
|
|
50dec0e55d | ||
|
|
6f419adb7f | ||
|
|
502e8beafb | ||
|
|
5aae065dc0 | ||
|
|
152dbed3fa | ||
|
|
b516bb8d20 | ||
|
|
30e3e84066 | ||
|
|
8338104266 | ||
|
|
00c6aa52b9 | ||
|
|
e5689d2f1b | ||
|
|
b51dedcea1 | ||
|
|
49f004e53f | ||
|
|
062fc05eac | ||
|
|
6d080d5d5f | ||
|
|
0955340a93 | ||
|
|
9b2318cc7e | ||
|
|
2098cdc5e0 | ||
|
|
d19b5187c5 | ||
|
|
2a78b1d6b7 | ||
|
|
84ae6366eb | ||
|
|
e5b235ac83 | ||
|
|
0195384592 | ||
|
|
0937f832fc | ||
|
|
c77b4af2a0 | ||
|
|
b943bae8dd | ||
|
|
4955978eb6 | ||
|
|
df409fddf5 | ||
|
|
0330c596e4 | ||
|
|
8c6c58f12f | ||
|
|
4bc08d22b8 | ||
|
|
96fb3b20b7 | ||
|
|
47f713c6c8 | ||
|
|
443c7a6b99 | ||
|
|
e79ca9b7d7 | ||
|
|
b94f774f80 | ||
|
|
5614e8bef6 | ||
|
|
4ce3a5d298 | ||
|
|
f6de3de78c | ||
|
|
8099018132 | ||
|
|
360dde2e1b | ||
|
|
cc7b7638d3 | ||
|
|
321e4aee34 | ||
|
|
f18847df57 | ||
|
|
a2559a65d3 | ||
|
|
5ac41fdd15 | ||
|
|
6d38dd2d7a | ||
|
|
667058269c | ||
|
|
ad6f934892 | ||
|
|
714220c349 | ||
|
|
4887fca873 | ||
|
|
cfe80edcb6 | ||
|
|
484588ff6b | ||
|
|
1bb059c2a2 | ||
|
|
ef5d9cb6b3 | ||
|
|
37a06c050d | ||
|
|
5f0ed395ba | ||
|
|
ae27c8b671 | ||
|
|
088bfb9c2f | ||
|
|
b01462e36b | ||
|
|
abd36dc6a4 | ||
|
|
ebb8a33c1a | ||
|
|
2b0f663482 | ||
|
|
956e632392 | ||
|
|
90b6bb8f7d | ||
|
|
6153e84abf | ||
|
|
16357f29e9 | ||
|
|
0b8a5a7539 | ||
|
|
6874e3a6a7 | ||
|
|
96263ed8a6 | ||
|
|
7bb1cb9ae3 | ||
|
|
20e32c4cb0 | ||
|
|
b4421306c0 | ||
|
|
e53f723fdb | ||
|
|
832a331437 | ||
|
|
12e66bd84f | ||
|
|
d290cc519f | ||
|
|
f4b19fe33e | ||
|
|
767d2c079a | ||
|
|
7750310be5 | ||
|
|
6de4e1e1dd | ||
|
|
627d47f139 | ||
|
|
36675cf729 | ||
|
|
33d8234eb3 | ||
|
|
347eb11328 | ||
|
|
5ed61f30e1 | ||
|
|
a633f46f4f | ||
|
|
baf9a0f978 | ||
|
|
c98b8fc8bf | ||
|
|
2fae0a35b8 | ||
|
|
b04f38ed3d | ||
|
|
60d5dd4101 | ||
|
|
75b7dd1dd7 | ||
|
|
aa2717d6ab | ||
|
|
4058f04b39 | ||
|
|
25ebd55c85 | ||
|
|
d00b58c8ed | ||
|
|
e7eb07a5a4 | ||
|
|
a4cac50261 | ||
|
|
4f8da64822 | ||
|
|
4f89721cd0 | ||
|
|
43c2843490 | ||
|
|
c152265284 | ||
|
|
b591b92b4e | ||
|
|
090388aa1b | ||
|
|
c6ab696949 | ||
|
|
df45a3ff83 | ||
|
|
fedd04b724 | ||
|
|
d8630da09d | ||
|
|
6192f7287e | ||
|
|
5b8a08ab22 | ||
|
|
313b03fb84 | ||
|
|
5639def6fb | ||
|
|
15a254879c | ||
|
|
5baa9bd256 | ||
|
|
d5346c0eaf | ||
|
|
a2213fd6dc | ||
|
|
9b07f12f90 | ||
|
|
c9b49483e0 | ||
|
|
e2972a5823 | ||
|
|
d5b3ed832d | ||
|
|
9fcc030c15 | ||
|
|
fc81b7ee5a | ||
|
|
f168abc2bb | ||
|
|
fe6778635e | ||
|
|
65a6c19d02 | ||
|
|
a32b5561a1 | ||
|
|
4b4393952e | ||
|
|
ea205b1e69 | ||
|
|
748140cdee | ||
|
|
e8037c857f | ||
|
|
15e37cefee | ||
|
|
b1e4daf1c2 | ||
|
|
4e0fccfc63 | ||
|
|
48b90029c4 | ||
|
|
8b189af2f9 | ||
|
|
030cdd35a2 | ||
|
|
3789998ba9 | ||
|
|
ea24ab6032 | ||
|
|
1408431649 | ||
|
|
6810372064 | ||
|
|
708e2ac5f6 | ||
|
|
2178f6761d | ||
|
|
aa5fd82004 | ||
|
|
660282db2e | ||
|
|
fdd357619b | ||
|
|
5f12f99761 | ||
|
|
3d98abb6d4 | ||
|
|
e35879a5d0 | ||
|
|
37138f03ae | ||
|
|
51d39bbd8c | ||
|
|
0932a1c93f | ||
|
|
19164521e4 | ||
|
|
df28cfe3cc | ||
|
|
354878d542 | ||
|
|
695264d59a | ||
|
|
de190f3349 | ||
|
|
b049385094 | ||
|
|
75dc616130 | ||
|
|
b542f5e7cd | ||
|
|
f3bee3cded | ||
|
|
a9b7ab9a06 | ||
|
|
ed019e954e | ||
|
|
65186b4356 | ||
|
|
e1d4f9a270 | ||
|
|
69c95ca153 | ||
|
|
e6976fb08d | ||
|
|
f502ba3659 | ||
|
|
e6ccc7e7cc | ||
|
|
da9d8851c2 | ||
|
|
ad48291d2a | ||
|
|
d6da230369 | ||
|
|
f8ac406a94 | ||
|
|
e691ecd167 | ||
|
|
930c26a111 | ||
|
|
64419a6cf4 | ||
|
|
5c59cddc7a | ||
|
|
4c7a51be46 | ||
|
|
7dad0fb89f | ||
|
|
adebb3fc5c | ||
|
|
5ab00b9d18 | ||
|
|
fbd5d7cf48 | ||
|
|
84132678cc | ||
|
|
78421748ba | ||
|
|
7112f58dae | ||
|
|
e56f737b34 | ||
|
|
49d993f613 | ||
|
|
63dd8a9215 | ||
|
|
d5f819dd59 | ||
|
|
a68787f16e | ||
|
|
858ef5801c | ||
|
|
9e0bd29cee | ||
|
|
15395de579 | ||
|
|
db4aad04a7 | ||
|
|
466e4cf227 | ||
|
|
05a3780c38 | ||
|
|
85ea91cdbb | ||
|
|
985d7a6fd9 | ||
|
|
2a19b8dd45 | ||
|
|
b2b3078861 | ||
|
|
2ac92f5725 | ||
|
|
e2f5afd71e | ||
|
|
e094ee036d | ||
|
|
2ad7f3e9f2 | ||
|
|
8e1f2258f8 | ||
|
|
5c01bbf284 | ||
|
|
647425fc1a | ||
|
|
7286049d07 | ||
|
|
ce67a065cd | ||
|
|
8948cb6287 | ||
|
|
4daa5fa2bb | ||
|
|
c49a7dae0a | ||
|
|
890a042a43 | ||
|
|
c95e576ef3 | ||
|
|
2aa96dd129 | ||
|
|
908634474b | ||
|
|
79b525ee71 | ||
|
|
872b8259ab | ||
|
|
a14c82708f | ||
|
|
7e53778680 | ||
|
|
210fbe3b9e | ||
|
|
0a5fd72bdc | ||
|
|
6e1701ecc5 | ||
|
|
a5f627a2d6 | ||
|
|
b4a1f175c6 | ||
|
|
e0690fa661 | ||
|
|
bd962eff35 | ||
|
|
b515355249 | ||
|
|
d1feef97be | ||
|
|
f52f96d44e | ||
|
|
944ec62f49 | ||
|
|
30905014d2 | ||
|
|
32dbdfc6e3 | ||
|
|
b2e312b41e | ||
|
|
52f4096197 | ||
|
|
c547ea0c0f | ||
|
|
c73ee61128 | ||
|
|
90b287f1f4 | ||
|
|
0316c9eea9 | ||
|
|
374b46966c | ||
|
|
3705415927 | ||
|
|
bff68f482e | ||
|
|
32ed758072 | ||
|
|
5ce99ee419 | ||
|
|
ceea384a36 | ||
|
|
fd3b026e12 | ||
|
|
7e451c13a8 | ||
|
|
3dcf74c2e4 | ||
|
|
50f1eca4be | ||
|
|
0d97af5ae2 | ||
|
|
aeb8d67219 | ||
|
|
1f65025036 | ||
|
|
8df3687684 | ||
|
|
adf59a9d0d | ||
|
|
b9f00bdbc5 | ||
|
|
a10e169573 | ||
|
|
317b9a8156 | ||
|
|
1c632d462f | ||
|
|
c46b49ccf1 | ||
|
|
e70708b133 | ||
|
|
62486c2220 | ||
|
|
cffe66747a | ||
|
|
b31bbfa04f | ||
|
|
48e4cad3ad | ||
|
|
53f58ce2e1 | ||
|
|
eb8b5eac01 | ||
|
|
02008a8b2e | ||
|
|
5b82599eb9 | ||
|
|
a5e4b2c6fa | ||
|
|
987753ff73 | ||
|
|
ee080839b1 | ||
|
|
4290c75478 | ||
|
|
cc6be6027d | ||
|
|
4cfde0a80a | ||
|
|
a77aee0e1a | ||
|
|
6f36473975 | ||
|
|
f5720d38bb | ||
|
|
23478d3d21 | ||
|
|
ba72b6dedd | ||
|
|
103f595891 | ||
|
|
957d623b4b | ||
|
|
2be757e609 | ||
|
|
c4be660a05 | ||
|
|
c1c5f9fe3a | ||
|
|
53c0637a85 | ||
|
|
4ae30dc3b0 | ||
|
|
fc5fbc9899 | ||
|
|
2397bf365b | ||
|
|
42cd17d5f2 | ||
|
|
a35e01bbeb | ||
|
|
b21e8030b3 | ||
|
|
0984a42fe5 | ||
|
|
ed50d60108 | ||
|
|
a7f72a73e5 | ||
|
|
1c02cb46f5 | ||
|
|
da8fd21177 | ||
|
|
7e5cd9819a | ||
|
|
00aecb3ab1 | ||
|
|
cde77a88fd | ||
|
|
08a555f187 | ||
|
|
4039cbf8af | ||
|
|
3f652fa06c | ||
|
|
272d2be3ae | ||
|
|
7e461344a8 | ||
|
|
8af985a2cb | ||
|
|
08eee34446 | ||
|
|
0a5b97a177 | ||
|
|
cab782b38e | ||
|
|
d1518d763b | ||
|
|
44a676b809 | ||
|
|
d66709ea87 | ||
|
|
358a77cf7c | ||
|
|
1a631908f4 | ||
|
|
9f32a1f22b | ||
|
|
dfd3386319 | ||
|
|
3df836e6b8 | ||
|
|
2b8ed25843 | ||
|
|
62250d2f25 | ||
|
|
a4e9082f53 | ||
|
|
7217e8c41d | ||
|
|
a7ac093753 | ||
|
|
5503502bad | ||
|
|
5124c2a96d | ||
|
|
73d7728e08 | ||
|
|
8b7bd00a48 | ||
|
|
68a6af0eb5 | ||
|
|
693f9f58eb | ||
|
|
4a01e2d472 | ||
|
|
e4fd1f4399 | ||
|
|
0d5fcb0849 | ||
|
|
2236c256ba | ||
|
|
945ad2e7bd | ||
|
|
6f9740f03f | ||
|
|
f9fa4dff73 | ||
|
|
77bf17967d | ||
|
|
7281c0b5bf | ||
|
|
e6cab65560 | ||
|
|
cc115323e1 | ||
|
|
58665ea7a7 | ||
|
|
3920644caf | ||
|
|
25aecbf15e | ||
|
|
e18d8868d2 | ||
|
|
c6e5d00a2b | ||
|
|
7a5b4dea1a | ||
|
|
5df877f32c | ||
|
|
c5c7dda2e0 | ||
|
|
492b9e5ed4 | ||
|
|
9f721c528d | ||
|
|
7f3c80c2a9 | ||
|
|
8f789607e4 | ||
|
|
6a9b6ed4be | ||
|
|
953a97dae4 | ||
|
|
86778c5997 | ||
|
|
8c32cdf5fd | ||
|
|
d092593e5c | ||
|
|
edbf4b6908 | ||
|
|
43f688d011 | ||
|
|
054c3088c3 | ||
|
|
0cedd5bb66 | ||
|
|
1961579fe4 | ||
|
|
6906f1652e | ||
|
|
e2bbe8a422 | ||
|
|
8ea4e00d31 | ||
|
|
917e27280f | ||
|
|
ec92edfc85 | ||
|
|
afd2be6c59 | ||
|
|
a23d50bf0d | ||
|
|
cace1144db | ||
|
|
0d646ed1a6 | ||
|
|
e9b09ffecd | ||
|
|
0008633d6e | ||
|
|
396c005b0a | ||
|
|
d3c3fac4f7 | ||
|
|
cf4acc1d4c | ||
|
|
5bd95f8414 | ||
|
|
a31d9a83a3 | ||
|
|
9b24589897 | ||
|
|
8f3d634132 | ||
|
|
5ef1ccb99b | ||
|
|
e7d91bc76a | ||
|
|
e4309824c2 | ||
|
|
cc6a35ac8a | ||
|
|
1f13a6c281 | ||
|
|
69519bdf14 | ||
|
|
2e5a8f384a | ||
|
|
c803eeb26a | ||
|
|
6a7497cdf8 | ||
|
|
3067ea3a5c | ||
|
|
9a5309d84b | ||
|
|
fff18f825a | ||
|
|
e70bdd4152 | ||
|
|
cf77a1981f | ||
|
|
10e33f5d5c | ||
|
|
db442d81dd | ||
|
|
f800b4f90b | ||
|
|
712f297d86 | ||
|
|
0afed7d3a4 | ||
|
|
6a03972ff3 | ||
|
|
0e40f64c6b | ||
|
|
c83b769f28 | ||
|
|
dad3282bbb | ||
|
|
1621263fb0 | ||
|
|
2686cd0c48 | ||
|
|
b07b081a15 | ||
|
|
c5d4e8c191 | ||
|
|
928641f535 | ||
|
|
c4c5ffec4f | ||
|
|
c048e97d3a | ||
|
|
00f0719659 | ||
|
|
0482627512 | ||
|
|
5856442e0f | ||
|
|
7b281e47d6 | ||
|
|
6ef2934c18 | ||
|
|
19b931223b | ||
|
|
ca15d7108f | ||
|
|
e6e4d33847 | ||
|
|
815cf4fd99 | ||
|
|
5cf2bf2cf5 | ||
|
|
6632da0276 | ||
|
|
9b499ab7d1 | ||
|
|
d29461607b | ||
|
|
243bdf2240 | ||
|
|
cde185901a | ||
|
|
a9f35f8095 | ||
|
|
63d7e32e06 | ||
|
|
400fdb3cc6 | ||
|
|
9f1bdc901c | ||
|
|
61970b028e | ||
|
|
aee92737ca | ||
|
|
0fddd9c119 | ||
|
|
b156f66146 | ||
|
|
63e6590b65 | ||
|
|
103be7f6e0 | ||
|
|
2154b75499 | ||
|
|
6a83cb5577 | ||
|
|
70ce8e9a1f | ||
|
|
fdd0a00d5a | ||
|
|
a8cad1e70a | ||
|
|
40afd67fc6 | ||
|
|
f3b9206d67 | ||
|
|
b76dd4c8ac | ||
|
|
3eb507ebe6 | ||
|
|
fe0a1f0f94 | ||
|
|
fab3339b8d | ||
|
|
10604cf820 | ||
|
|
e297310a25 | ||
|
|
d71006f2ae | ||
|
|
7a8e099a79 | ||
|
|
822aa84fa2 | ||
|
|
948ce9e8b8 | ||
|
|
caf145c38a | ||
|
|
f964cdec98 | ||
|
|
6848fab873 | ||
|
|
72d57cae71 | ||
|
|
a23178e20e | ||
|
|
5ae4f0288b | ||
|
|
e0e51eb187 | ||
|
|
840944ea94 | ||
|
|
31ff27b1d3 | ||
|
|
a234ccbd05 | ||
|
|
6dfd54b8be | ||
|
|
edb7729b35 | ||
|
|
d434e63c22 | ||
|
|
cd7ede006c | ||
|
|
d4d0dc3dbc | ||
|
|
5c7f997e7a | ||
|
|
1623a007a4 | ||
|
|
0b19fa0bdf | ||
|
|
897c8b6ec5 | ||
|
|
d427a7fec1 | ||
|
|
b0749a1bee | ||
|
|
2406080515 | ||
|
|
ff96146b04 | ||
|
|
e3a5b2825d | ||
|
|
9fd72b5ad5 | ||
|
|
c2bf63991f | ||
|
|
a75ae7b65a | ||
|
|
507e4cb07b | ||
|
|
0f250bb04b | ||
|
|
4a315057a2 | ||
|
|
c8f44a0c4b | ||
|
|
382d853fe2 | ||
|
|
a5996c488e | ||
|
|
760642ecb3 | ||
|
|
c7a3548df0 | ||
|
|
d8acc6a5e8 | ||
|
|
431808286b | ||
|
|
747fa19259 | ||
|
|
bf61295b76 | ||
|
|
49a1ecea00 | ||
|
|
11f0e55bb1 | ||
|
|
331da37840 | ||
|
|
032e0641a5 | ||
|
|
f3d2ab61e4 | ||
|
|
e8b5f071fe | ||
|
|
ada72d6113 | ||
|
|
c2404d4f0d | ||
|
|
821732bba9 | ||
|
|
b6df650f50 | ||
|
|
e783ce5788 | ||
|
|
18af4a0724 | ||
|
|
7e6ec1dc8d | ||
|
|
4fbe0859e0 | ||
|
|
b89c23fe7c | ||
|
|
e038c49ae9 | ||
|
|
bed02c9384 | ||
|
|
96bc4f7cdf | ||
|
|
6503469ddd | ||
|
|
61a1c3742c | ||
|
|
1fb2a38bc1 | ||
|
|
22a0d79315 | ||
|
|
0cc72772a3 | ||
|
|
11f4e636e3 | ||
|
|
fef1a2e041 | ||
|
|
41a9c8e013 | ||
|
|
c1ad02b792 | ||
|
|
ab2315c951 | ||
|
|
7948e33cbc | ||
|
|
2be2dce584 | ||
|
|
69bdfe3dba | ||
|
|
d73d163a58 | ||
|
|
48a52ae5b2 | ||
|
|
078dc2ab17 | ||
|
|
6f4522caa6 | ||
|
|
3c76ce9f39 | ||
|
|
8601149051 | ||
|
|
d7ef15d435 | ||
|
|
27e3645b56 | ||
|
|
95eb4e1a22 | ||
|
|
32ea07bf5a | ||
|
|
06272575c5 | ||
|
|
edd6432d4c | ||
|
|
303c4615e9 | ||
|
|
7d327c1622 | ||
|
|
6a74b83f98 | ||
|
|
c601c2dd98 | ||
|
|
c27b60749f | ||
|
|
b3cb286088 | ||
|
|
361903e8ec | ||
|
|
d72c69242d | ||
|
|
539819fa0c | ||
|
|
d80c218744 | ||
|
|
0603d220a9 | ||
|
|
e13fe56f47 | ||
|
|
acd7694485 | ||
|
|
7f50edacc8 | ||
|
|
5a4906c5b5 | ||
|
|
4e906757b9 | ||
|
|
1f0b21e351 | ||
|
|
2f3ea323c7 | ||
|
|
d4e77c6499 | ||
|
|
ffc56b049d | ||
|
|
ddac89d732 | ||
|
|
fecf2805c7 | ||
|
|
4dcc88ba32 | ||
|
|
084308d8a4 | ||
|
|
1ffb5c405b | ||
|
|
ad29409407 | ||
|
|
6f33abb25e | ||
|
|
2c9693389e | ||
|
|
d3c82c4da4 | ||
|
|
541a96e7b4 | ||
|
|
5b234a9cbc | ||
|
|
24c3a62f3a | ||
|
|
23756a387a | ||
|
|
efbd350dfd | ||
|
|
072e95c84e | ||
|
|
4be26e7202 | ||
|
|
a616cbb95c | ||
|
|
8aea9aa3dd | ||
|
|
e4992bc917 | ||
|
|
000b3e97c7 | ||
|
|
cb91e19413 | ||
|
|
c72e690085 | ||
|
|
f1a4e659e7 | ||
|
|
0d56d17d52 | ||
|
|
96c89c8c97 | ||
|
|
7df5a1f211 | ||
|
|
8ae8e028c7 | ||
|
|
581ad5f8f4 | ||
|
|
977bae3750 | ||
|
|
8a0161607e | ||
|
|
cd6a7bfc3a | ||
|
|
4671700b7d | ||
|
|
840ca74407 | ||
|
|
0d8a7e46de | ||
|
|
8b9940b0f0 | ||
|
|
521b819b8a | ||
|
|
208e9ef64b | ||
|
|
a7ea8e012e | ||
|
|
d940a7e49a | ||
|
|
9d50171034 | ||
|
|
701a5b9e28 | ||
|
|
d11785ef2d | ||
|
|
f4a4d91ef8 | ||
|
|
9514e47ed3 | ||
|
|
9461f2d632 | ||
|
|
f6064d03e1 | ||
|
|
0d917e0dc5 | ||
|
|
9408af8d08 | ||
|
|
862ab48bbc | ||
|
|
f498347c53 | ||
|
|
3f77f59c8a | ||
|
|
e96186015d | ||
|
|
1fa6e4526b | ||
|
|
3853d585a0 | ||
|
|
e8c6225ef0 | ||
|
|
17c67cc780 | ||
|
|
dcc4236833 | ||
|
|
6a7c735924 | ||
|
|
3c40cd853e | ||
|
|
5357660b68 | ||
|
|
a15a911f8e | ||
|
|
ded0487ce6 | ||
|
|
e7b079ece7 | ||
|
|
0cbe4de920 | ||
|
|
5c3bf30fe7 | ||
|
|
56b8694fd5 | ||
|
|
c9fecafada | ||
|
|
f3ca7ad644 | ||
|
|
c3b48c78af | ||
|
|
18dcc29a0d | ||
|
|
c3a5c263d3 | ||
|
|
ccdf60d525 | ||
|
|
443e1cec75 | ||
|
|
aa540514b8 | ||
|
|
fda7e2e5b6 | ||
|
|
fb4d5cf437 | ||
|
|
9fc2898a56 | ||
|
|
2e24323adf | ||
|
|
77abc1ed7c | ||
|
|
259d550d04 | ||
|
|
1a8f9c5a12 | ||
|
|
1916eb3095 | ||
|
|
fc3eec7ae1 | ||
|
|
8d10c9b004 | ||
|
|
511f77f5e7 | ||
|
|
a58d7a4d79 | ||
|
|
6748f6ce78 | ||
|
|
2dcb6b1987 | ||
|
|
2b4ac41142 | ||
|
|
2b47958207 | ||
|
|
5538d4d1c4 | ||
|
|
467756df48 | ||
|
|
534ebb26c0 | ||
|
|
21790a9725 | ||
|
|
6bc22c8ac4 | ||
|
|
ac1c422f14 | ||
|
|
efa1860104 | ||
|
|
c673b4254f | ||
|
|
96db173694 | ||
|
|
1d5be624fe | ||
|
|
56f9672896 | ||
|
|
303b3f08b8 | ||
|
|
150e3fd92e | ||
|
|
840b01273c | ||
|
|
8a7beda339 | ||
|
|
65606f7083 | ||
|
|
0095071ebf | ||
|
|
ae4ee9061d | ||
|
|
6ba06bc006 | ||
|
|
00f247eae1 | ||
|
|
c250c91ab4 | ||
|
|
b1ac10a4c4 | ||
|
|
af4185fbea | ||
|
|
aa85d4d797 | ||
|
|
74cc63e6dd | ||
|
|
04ed613ca3 | ||
|
|
9ea157b9b6 | ||
|
|
536d7f6124 | ||
|
|
869a01b57f | ||
|
|
ea982b23c2 | ||
|
|
15dfe8cead | ||
|
|
b50027150e | ||
|
|
103acb8294 | ||
|
|
aca23b8bca | ||
|
|
aaffbbc5be | ||
|
|
e0002c9488 | ||
|
|
687d6d914c | ||
|
|
9a61b2701e | ||
|
|
d8224ebefe | ||
|
|
cc2af73a05 | ||
|
|
aecd44ada6 | ||
|
|
72593c4d99 | ||
|
|
52ca258616 | ||
|
|
04412667ff | ||
|
|
4124ec80ec | ||
|
|
693ea75e95 | ||
|
|
9e3c1ab059 | ||
|
|
5fc860702f | ||
|
|
6ad2ee5a47 | ||
|
|
b0f64297cb | ||
|
|
f99a63dbc0 | ||
|
|
9261e8fe94 | ||
|
|
52bb116e24 | ||
|
|
7006c36101 | ||
|
|
f7d452e3f1 | ||
|
|
598e50a40f | ||
|
|
eadfa26c3b | ||
|
|
b03491fdf7 | ||
|
|
42911c63b3 | ||
|
|
43462757ed | ||
|
|
0eee1c5d15 | ||
|
|
3a21bf69f1 | ||
|
|
7d4c8f7f07 | ||
|
|
866d19d649 | ||
|
|
c27ec2475c | ||
|
|
1d64cbfaa0 | ||
|
|
5d1baa89e4 | ||
|
|
e846ce7e98 | ||
|
|
300b3582a6 | ||
|
|
3a7ffe62b0 | ||
|
|
d990ebe49e | ||
|
|
bd78739217 | ||
|
|
6c7312a09c | ||
|
|
1525e564cb | ||
|
|
7fb4bbbf3c | ||
|
|
2553d44d32 | ||
|
|
dc902b7a61 | ||
|
|
b992cbd92e | ||
|
|
22711fad28 | ||
|
|
a9df0abed3 | ||
|
|
fd65550f8d | ||
|
|
b910ad3386 | ||
|
|
fb9f094365 | ||
|
|
05470446a0 | ||
|
|
903982afb7 | ||
|
|
8bea5b125b | ||
|
|
c658a892f2 | ||
|
|
3f0d6cfcf1 | ||
|
|
c6657c199c | ||
|
|
cf6d980b8b | ||
|
|
c3ff49e86e | ||
|
|
e51f91f041 | ||
|
|
2589c67f6c | ||
|
|
2f4f19b52b | ||
|
|
b3ed7563dc | ||
|
|
ea96c328fc | ||
|
|
f42da14413 | ||
|
|
2149149723 | ||
|
|
f1916b3d0b | ||
|
|
10788976b6 | ||
|
|
567d26a385 | ||
|
|
220eb8f6f4 | ||
|
|
b40e7d6e97 | ||
|
|
97dd90a718 | ||
|
|
75ba6401a4 | ||
|
|
5cf8d8d263 | ||
|
|
058e09c413 | ||
|
|
63fb1b1f36 | ||
|
|
7c0b9ce3c6 | ||
|
|
c153d236f2 | ||
|
|
3b3a3c275c | ||
|
|
f4691d08cc | ||
|
|
e5d9471b33 | ||
|
|
ab9525c507 | ||
|
|
b1fb3a5470 | ||
|
|
b2194790eb | ||
|
|
8901310ed4 | ||
|
|
09c6adaa95 | ||
|
|
5fe1e9674e | ||
|
|
601116bd59 | ||
|
|
27dc02fdec | ||
|
|
03f417546e | ||
|
|
3b9aa79201 | ||
|
|
5aa4936c0e | ||
|
|
1e65d58113 | ||
|
|
e2a66bdd1f | ||
|
|
4f9c30505a | ||
|
|
1ec817c96c | ||
|
|
41528ae7b6 | ||
|
|
77d248df0b | ||
|
|
c6cb13b332 | ||
|
|
d67108fa8b | ||
|
|
b7447f055a | ||
|
|
3902ed19b7 | ||
|
|
51ba7cf75c | ||
|
|
82fb5dd0da | ||
|
|
2ac20cb575 | ||
|
|
3f33e5b2a8 | ||
|
|
655ea98bf1 | ||
|
|
238260612c | ||
|
|
cd26c2d8e6 | ||
|
|
814e28b86a | ||
|
|
f515ba79af | ||
|
|
e6f16700e4 | ||
|
|
f38e7c35da | ||
|
|
b3576b7162 | ||
|
|
d9914e95d9 | ||
|
|
64c79626b4 | ||
|
|
e047a76855 | ||
|
|
e7449897f9 | ||
|
|
db093cf25b | ||
|
|
4bb4bd9792 | ||
|
|
c16654c8cf | ||
|
|
817ff7e239 | ||
|
|
685de52538 | ||
|
|
1dc52773f4 | ||
|
|
fbb04ea88a | ||
|
|
23da318645 | ||
|
|
30b77931d7 | ||
|
|
39327b2b27 | ||
|
|
13c3af96a6 | ||
|
|
4411732022 | ||
|
|
0c08b8b93b | ||
|
|
838755aabf | ||
|
|
2bca104e33 | ||
|
|
cf857f3256 | ||
|
|
1647d3d841 | ||
|
|
2f5252ab88 | ||
|
|
eb89b5be1b | ||
|
|
e80fe29dba | ||
|
|
74ab2a4bd7 | ||
|
|
edd4f740e0 | ||
|
|
d0c9bc801b | ||
|
|
73dd63caa1 | ||
|
|
cc4703ea40 | ||
|
|
f105d7c7eb | ||
|
|
e85ad00a46 | ||
|
|
658dfa4290 | ||
|
|
df75036501 | ||
|
|
9ab5353122 | ||
|
|
5345ece322 | ||
|
|
9f09c81ef4 | ||
|
|
c8dea20865 | ||
|
|
bf09177916 | ||
|
|
d71640ad7e | ||
|
|
68afcc0c44 | ||
|
|
9b30a3d72a | ||
|
|
789cd21618 | ||
|
|
d9f343e20b | ||
|
|
0b8ff15133 | ||
|
|
27a4748111 | ||
|
|
18efaef38c | ||
|
|
35137b87ed | ||
|
|
9019c46102 | ||
|
|
52d0869c50 | ||
|
|
236b375669 | ||
|
|
9502b5a12a | ||
|
|
ad18856f7a | ||
|
|
9015b78aaf | ||
|
|
8cc7a4f693 | ||
|
|
ac298fee61 | ||
|
|
457fc5296e | ||
|
|
b8f3cd1ad8 | ||
|
|
f9f265271a | ||
|
|
dde5f6e119 | ||
|
|
add3fb13ef | ||
|
|
51c1936c24 | ||
|
|
07adeaf60d | ||
|
|
811913bf89 | ||
|
|
8906c85d06 | ||
|
|
7df5894ca4 | ||
|
|
fa9e559195 | ||
|
|
81f408ee77 | ||
|
|
aa8a059553 | ||
|
|
8c7918577d | ||
|
|
7219885196 | ||
|
|
9f8915239f | ||
|
|
83401f6e1a | ||
|
|
dd686ad9d1 | ||
|
|
7d04005c72 | ||
|
|
cdbaeb1c6c | ||
|
|
6bf432a112 | ||
|
|
f6ef136502 | ||
|
|
4a9d295f1a | ||
|
|
105e0bb7a4 | ||
|
|
ab27ee50b0 | ||
|
|
f4a4f67453 | ||
|
|
fb88eebc2f | ||
|
|
6fea0c2a93 | ||
|
|
301c8da9eb | ||
|
|
4facdf0932 | ||
|
|
ce489887db | ||
|
|
55e30bd4aa | ||
|
|
eb0d03d420 | ||
|
|
db1da2d9cf | ||
|
|
6fa3b8597f | ||
|
|
c8da89f0d3 | ||
|
|
c3c89801e9 | ||
|
|
eb3f8b0d91 | ||
|
|
d3285f002e | ||
|
|
e81ee38fa5 | ||
|
|
499e854275 | ||
|
|
cd235bbcde | ||
|
|
984aa3f413 | ||
|
|
11287cb9c0 | ||
|
|
5cc49a8862 | ||
|
|
fabda76e98 | ||
|
|
70db505dd9 | ||
|
|
29fd1c800b | ||
|
|
d70d8f62a4 | ||
|
|
bef562964d | ||
|
|
fc5495b6d1 | ||
|
|
f3838ae4b0 | ||
|
|
b3eccf55ba | ||
|
|
835cc3d0a2 | ||
|
|
b49584ec16 | ||
|
|
334e49c4ca | ||
|
|
3fc5be111b | ||
|
|
1bc2dd2964 | ||
|
|
68dcc75949 | ||
|
|
dc9f738f30 | ||
|
|
4171d2f93b | ||
|
|
64fb90960b | ||
|
|
93e277bb0f | ||
|
|
337216efac | ||
|
|
f1f5b68821 | ||
|
|
8f941e6d12 | ||
|
|
6a4dcbd6e1 | ||
|
|
7e773dfe1b | ||
|
|
465ae75ffc | ||
|
|
8da03940e8 | ||
|
|
f280779528 | ||
|
|
5c568da125 | ||
|
|
f46b8366b0 | ||
|
|
1d9c052c01 | ||
|
|
544927b9b7 | ||
|
|
8b5bb0d358 | ||
|
|
6031f1e3b8 | ||
|
|
c297df76ef | ||
|
|
122e9f4fca | ||
|
|
748ed01252 | ||
|
|
56188328fb | ||
|
|
880e463b01 | ||
|
|
a53046bf12 | ||
|
|
a8050fd8a1 | ||
|
|
6ae819e8d5 | ||
|
|
79c73444ab | ||
|
|
8cc1b07456 | ||
|
|
0d43614ac3 | ||
|
|
19f879da7f | ||
|
|
ed42bf311f | ||
|
|
fd4346cb64 | ||
|
|
6e458ebd4a | ||
|
|
0f0be60245 | ||
|
|
27783677c2 | ||
|
|
4418cab3a5 | ||
|
|
b3cddfe2d4 | ||
|
|
a19ac87a04 | ||
|
|
3ba951fd91 | ||
|
|
824f23c3d6 | ||
|
|
fc49a32008 | ||
|
|
5ca0d31606 | ||
|
|
ebd44d9628 | ||
|
|
329fa1c2a5 | ||
|
|
9a5bf7999b | ||
|
|
7debad6c67 | ||
|
|
dc9b84ea8b | ||
|
|
199c254838 | ||
|
|
7ff482dafe | ||
|
|
9376019198 | ||
|
|
cec654a75b | ||
|
|
3e004d01ec | ||
|
|
21266d0a17 | ||
|
|
2b62b8dab3 | ||
|
|
b24564ffe9 | ||
|
|
f57d436640 | ||
|
|
762613bd7f | ||
|
|
e2ed752b51 | ||
|
|
2610926f47 | ||
|
|
cf1a74e532 | ||
|
|
f55b451d9b | ||
|
|
ae51e389ca | ||
|
|
6f71ef1d03 | ||
|
|
94a9e4db05 | ||
|
|
82dc0c4f32 | ||
|
|
bb5827629e | ||
|
|
76f7cb7126 | ||
|
|
d5005323d4 | ||
|
|
9bc1a9963f | ||
|
|
cefbf2ee70 | ||
|
|
e10dc6dcec | ||
|
|
e4f4d278a8 | ||
|
|
3dd9df558e | ||
|
|
87c2216d0f | ||
|
|
8cd5ff6bd6 | ||
|
|
28868e4c78 | ||
|
|
01bef23ac9 | ||
|
|
9379bd1792 | ||
|
|
63a479b6b6 | ||
|
|
49b0d92c75 | ||
|
|
277402a25d | ||
|
|
cc83177542 | ||
|
|
5a342cf8e6 | ||
|
|
7d5dabde82 | ||
|
|
e3917226cc | ||
|
|
4e3c1edd52 | ||
|
|
e52b7ea7ff | ||
|
|
6f60d87f85 | ||
|
|
049db615e3 | ||
|
|
e557155b17 | ||
|
|
9bf5b0c9a7 | ||
|
|
ea860f24a1 | ||
|
|
5e89d49bd9 | ||
|
|
cb1ba0e00c | ||
|
|
0f965b6800 | ||
|
|
486c2170cd | ||
|
|
83641a4f54 | ||
|
|
5cb2326ea7 | ||
|
|
84d7986353 | ||
|
|
a3c2628359 | ||
|
|
8ae34bdd9d | ||
|
|
4a9374936d | ||
|
|
110378e3b4 | ||
|
|
bd60feff60 | ||
|
|
2181d0b33c | ||
|
|
2afa7ea691 | ||
|
|
d0f76117cd | ||
|
|
e25060a16e | ||
|
|
5e6da326f6 | ||
|
|
981a8f8d2c | ||
|
|
5c7e592e1e | ||
|
|
2a25f76b56 | ||
|
|
41d579dc23 | ||
|
|
7d41017850 | ||
|
|
daeba0d43a | ||
|
|
24fd5ba361 | ||
|
|
3353637c8f | ||
|
|
9601e6942d | ||
|
|
4b32a93f27 | ||
|
|
9e8978166e | ||
|
|
6bf873f4db | ||
|
|
1318f1a29b | ||
|
|
d9282ac750 | ||
|
|
205d728798 | ||
|
|
bd9c772a52 | ||
|
|
76e9002995 | ||
|
|
e990d44bb6 | ||
|
|
2ffa2d7b73 | ||
|
|
0e4583f8e2 | ||
|
|
3802722bb1 | ||
|
|
41f0a712fd | ||
|
|
4633c37380 | ||
|
|
b779becf8c | ||
|
|
35089febab | ||
|
|
a95fd1e1d8 | ||
|
|
6535f64699 | ||
|
|
b15a5d4a45 | ||
|
|
65a5c37ffb | ||
|
|
6cf58c032c | ||
|
|
e0365df6dd | ||
|
|
40ae0c7257 | ||
|
|
aecd4c5266 | ||
|
|
113caf4970 | ||
|
|
da2d57c8e9 | ||
|
|
3aed8b8479 | ||
|
|
ff58a826b1 | ||
|
|
9a0873e404 | ||
|
|
7d9133793c | ||
|
|
f43d9883cf | ||
|
|
067842818e | ||
|
|
8ea70a1b77 | ||
|
|
47207dcead | ||
|
|
235876a4d8 | ||
|
|
af88abb13f | ||
|
|
f13701b120 | ||
|
|
5f7c598a34 | ||
|
|
defd354286 | ||
|
|
f9e6b30550 | ||
|
|
d451af365a | ||
|
|
57a78535f2 | ||
|
|
f824ecb7f9 | ||
|
|
98f848138d | ||
|
|
200a1dc3da | ||
|
|
507e1d2b50 | ||
|
|
0f752e2571 | ||
|
|
ca6cd65d46 | ||
|
|
ddc287a84e | ||
|
|
c92ec031ae | ||
|
|
ef2d4d6b12 | ||
|
|
2753f6c4e5 | ||
|
|
021577d638 | ||
|
|
dd3f8b4717 | ||
|
|
a1fb4a0ac5 | ||
|
|
ebf0c4fae6 | ||
|
|
44a086a27b | ||
|
|
4624075112 | ||
|
|
97a3c8dca1 | ||
|
|
c50b5d93d7 | ||
|
|
08f9176f3f | ||
|
|
f95ca6eac6 | ||
|
|
34165c0d90 | ||
|
|
1f87cf09d7 | ||
|
|
005c7b9cb0 | ||
|
|
2b265bd1de | ||
|
|
3e83216384 | ||
|
|
a9889b5b79 | ||
|
|
2aa5b7917f | ||
|
|
040354501c | ||
|
|
bd46f6d25f | ||
|
|
7e801269af | ||
|
|
2586e2e661 | ||
|
|
fb2a5c2378 | ||
|
|
f490fa6e7d | ||
|
|
df347be672 | ||
|
|
4e518bf70c | ||
|
|
29e90246d2 | ||
|
|
1e62c0d836 | ||
|
|
278ebf4ff2 | ||
|
|
edc58a3496 | ||
|
|
7c96862b19 | ||
|
|
11b18f7468 | ||
|
|
86787b6099 | ||
|
|
12645c19aa | ||
|
|
7e06a57fd9 | ||
|
|
4d7c31cfa1 | ||
|
|
f5e4fc5a3d | ||
|
|
1c4174431e | ||
|
|
60d4f2d6c7 | ||
|
|
5a30a96c0c | ||
|
|
09b454ba6a | ||
|
|
8ea06e84a6 | ||
|
|
ebaf56d964 | ||
|
|
517d2bb1ec | ||
|
|
706d43ee41 | ||
|
|
e537d27e28 | ||
|
|
948f28b0af | ||
|
|
70f7c6a25e | ||
|
|
a0a0cd4f57 | ||
|
|
dfa120339c | ||
|
|
36f194b9bd | ||
|
|
12dd851fc3 | ||
|
|
cc9a5893de | ||
|
|
9d2ac3f2c4 | ||
|
|
9cda61de3d | ||
|
|
060d93d68b | ||
|
|
8d1e8c6699 | ||
|
|
f4865c5206 | ||
|
|
2d44c89149 | ||
|
|
c2050d4314 | ||
|
|
7991605106 | ||
|
|
adeea85c9a | ||
|
|
c32e390184 | ||
|
|
154f61fb11 | ||
|
|
b08bcf041b | ||
|
|
e51f6e1e86 | ||
|
|
62e2a0211f | ||
|
|
5286e7f89c | ||
|
|
e81ba55967 | ||
|
|
25a2689bd0 | ||
|
|
c949eb5491 | ||
|
|
709c5cbd71 | ||
|
|
3ac59a5bc0 | ||
|
|
6894228a63 | ||
|
|
a7b914b84e | ||
|
|
84922e84a3 | ||
|
|
7ee0b2b0a3 | ||
|
|
5c06a241ac | ||
|
|
0cb0128caf | ||
|
|
8661b8074c | ||
|
|
fa52a1a81e | ||
|
|
680fa7a350 | ||
|
|
3850ce88d3 | ||
|
|
a800f1efc7 | ||
|
|
514bbbe8a3 | ||
|
|
700b922350 | ||
|
|
bdfeeb9a41 | ||
|
|
2b80d1a6d8 | ||
|
|
fa6f2061e7 | ||
|
|
ff5f12e4d2 | ||
|
|
9ad6e8142d | ||
|
|
49e3534738 | ||
|
|
4cb7ba83e9 | ||
|
|
9282828ffc | ||
|
|
2f2a2d4bee | ||
|
|
b904e6a889 | ||
|
|
804d5723c2 | ||
|
|
681e3a6865 | ||
|
|
dd75c56404 | ||
|
|
86cee1e339 | ||
|
|
063edc032a | ||
|
|
32c59cb583 | ||
|
|
0242f88d26 | ||
|
|
940a89fa38 | ||
|
|
364a66ad0b | ||
|
|
f714315b0d | ||
|
|
ed83471a13 | ||
|
|
1263aa7884 | ||
|
|
c21afc3f8a | ||
|
|
59af0594dc | ||
|
|
8cf6d4f7d8 | ||
|
|
61ceeb44fb | ||
|
|
995bb921c1 | ||
|
|
e7cab78aad | ||
|
|
1c06bd45ef | ||
|
|
85a3e112e0 | ||
|
|
9c5e054dda | ||
|
|
86932e6da4 | ||
|
|
5f94fdfc93 | ||
|
|
74584dd39e | ||
|
|
18ed5d51a9 | ||
|
|
d7076f5295 | ||
|
|
29a5397491 | ||
|
|
47a4261631 | ||
|
|
a3927218a6 | ||
|
|
7d846a3d0d | ||
|
|
8db1f6d1e2 | ||
|
|
9cb679d545 | ||
|
|
006d705cbd | ||
|
|
a19a14665f | ||
|
|
55bc6f9a00 | ||
|
|
997d31addd | ||
|
|
548390b0d7 | ||
|
|
bd64bdedc3 | ||
|
|
846e09c7cb | ||
|
|
2ba3552578 | ||
|
|
943bb6d15b | ||
|
|
af53e75ae4 | ||
|
|
14ca63571d | ||
|
|
10c5ce68f5 | ||
|
|
d9fb856eb8 | ||
|
|
f5c08158cb | ||
|
|
9ee0311ea9 | ||
|
|
69ed2d2428 | ||
|
|
0c5fae01b5 | ||
|
|
72052925a6 | ||
|
|
dc2d02bf32 | ||
|
|
ee267ea086 | ||
|
|
1e730f3376 | ||
|
|
c230c52af6 | ||
|
|
219beb4a0e | ||
|
|
c4807c44f3 | ||
|
|
7dafd14644 | ||
|
|
57c3e8c51d | ||
|
|
da71eca978 | ||
|
|
7a47af14be | ||
|
|
f67adc53ab | ||
|
|
68e9948493 | ||
|
|
894416c719 | ||
|
|
11650450c8 | ||
|
|
6973d85b10 | ||
|
|
bf5598515e | ||
|
|
cc03c27d17 | ||
|
|
9cd729df71 | ||
|
|
d6ee9fbfac | ||
|
|
b6999f5c67 | ||
|
|
c02f273d57 | ||
|
|
8d87bfb4a3 | ||
|
|
0a7cd3d6e9 | ||
|
|
235699b3b9 | ||
|
|
1aebfbecc1 | ||
|
|
00e47b9afb | ||
|
|
68b94cfcaa | ||
|
|
0068f21a2d | ||
|
|
7a7e639490 | ||
|
|
81bae1441e | ||
|
|
3516e5ae8a | ||
|
|
04bbe3187f | ||
|
|
877cdec4ea | ||
|
|
21ab94c512 | ||
|
|
70f52afb3d | ||
|
|
85f4dbd670 | ||
|
|
bee70e67bc | ||
|
|
7e137f17a5 | ||
|
|
c576f62ca3 | ||
|
|
9c8499e6cd | ||
|
|
f81e7cb78a | ||
|
|
773f3048f7 | ||
|
|
40faaea7f8 | ||
|
|
47b4409f3e | ||
|
|
9ce23c3d61 | ||
|
|
f40ffed069 | ||
|
|
0b223170d9 | ||
|
|
e61f8a512c | ||
|
|
65b43c39ed | ||
|
|
131645f31e | ||
|
|
ca8fc14d36 | ||
|
|
efe693c0c0 | ||
|
|
4eb2d073ac | ||
|
|
fd49c02e18 | ||
|
|
f0e3d492d3 | ||
|
|
3f8ba6be9d | ||
|
|
df4563379d | ||
|
|
f0f9d8faa7 | ||
|
|
031b4b637a | ||
|
|
e206ae3403 | ||
|
|
021c463d80 | ||
|
|
41d75da33f | ||
|
|
c7e7a559a6 | ||
|
|
4f5dfcc65b | ||
|
|
e85208110f | ||
|
|
17bb2f11e4 | ||
|
|
124db5f11f | ||
|
|
6b099d7298 | ||
|
|
7ac2e227b1 | ||
|
|
868c1aa251 | ||
|
|
7283fc89a5 | ||
|
|
f933560934 | ||
|
|
7ee918ad49 | ||
|
|
e30ebd39fd | ||
|
|
7ac6ff828c | ||
|
|
017f5f8e74 | ||
|
|
2c46feb8f8 | ||
|
|
f5171f3f47 | ||
|
|
1a2c28435a | ||
|
|
7221fc2060 | ||
|
|
e17e7ab4ec | ||
|
|
46eb0bc474 | ||
|
|
b03227ea9f | ||
|
|
a1de5e15c5 | ||
|
|
7f2322ba60 | ||
|
|
5c04844461 | ||
|
|
591a185fc2 | ||
|
|
fbc0b60b68 | ||
|
|
325ce8824e | ||
|
|
d54e25bb44 | ||
|
|
740943aee2 | ||
|
|
73ee93335b | ||
|
|
c69c3361ac | ||
|
|
a91d019738 | ||
|
|
dc272a472d | ||
|
|
b265108322 | ||
|
|
6cab6a9646 | ||
|
|
3baf237fa8 | ||
|
|
fa8503546e | ||
|
|
b9d988c712 | ||
|
|
2bbf672094 | ||
|
|
a6f8fe4c95 | ||
|
|
6d7415880a | ||
|
|
479e4588f3 | ||
|
|
821f1bdc2b | ||
|
|
5cdd672e84 | ||
|
|
48fb8d0b92 | ||
|
|
52fae655ba | ||
|
|
3ab6e84275 | ||
|
|
2b5ab6db11 | ||
|
|
a0f6d47153 | ||
|
|
787901ba73 | ||
|
|
37c7167128 | ||
|
|
35e1ddc578 | ||
|
|
d61e7b8729 | ||
|
|
8ef73f9dd2 | ||
|
|
f7448cc2e4 | ||
|
|
6af35b5ec5 | ||
|
|
8f4e5c6064 | ||
|
|
2d76775e40 | ||
|
|
8eb71cbe74 | ||
|
|
9146a8bb21 | ||
|
|
445bca7333 | ||
|
|
6286551ef5 | ||
|
|
1ae6a69c7a | ||
|
|
34851b772f | ||
|
|
4823aa378e | ||
|
|
40a42e86ee | ||
|
|
c518b52243 | ||
|
|
abccc3c3cd | ||
|
|
9786b7139e | ||
|
|
28e8e3434e | ||
|
|
cdf59fba10 | ||
|
|
be8571cb56 | ||
|
|
857715e55c | ||
|
|
5ccc815a47 | ||
|
|
d77c04109b | ||
|
|
1ba8b8b1b1 | ||
|
|
caa349b59b | ||
|
|
9a7350149d | ||
|
|
7f435363f7 | ||
|
|
832cb79f88 | ||
|
|
ba7290fdda | ||
|
|
85ee4a95ec | ||
|
|
eb164c511f | ||
|
|
26e3119ef3 | ||
|
|
6c38b54f7d | ||
|
|
7e6badaf5d | ||
|
|
c104e8e1f0 | ||
|
|
c8d04f3373 | ||
|
|
f64f417711 | ||
|
|
92fe975e3d | ||
|
|
e00731ef8f | ||
|
|
0d7d0664f6 | ||
|
|
b59b0ef041 | ||
|
|
964aa0ecce | ||
|
|
a9ecf06cd4 | ||
|
|
76da6857e7 | ||
|
|
9eef60c93d | ||
|
|
df412bbef7 | ||
|
|
b4c6632162 | ||
|
|
5f2eb6bd32 | ||
|
|
ea532b15fc | ||
|
|
01bd1fde39 | ||
|
|
c6c1c61ff6 | ||
|
|
bbd33c70c1 | ||
|
|
a2592342fe | ||
|
|
db06e12337 | ||
|
|
22139c9650 | ||
|
|
3b1e2e38fb | ||
|
|
6f6da47ebe | ||
|
|
f3237172f3 | ||
|
|
45dc64af5a | ||
|
|
4df71bff7f | ||
|
|
f5003d3505 | ||
|
|
f2f3fab3e2 | ||
|
|
2357e139f0 | ||
|
|
c74eaa47a3 | ||
|
|
591f9fa4c2 | ||
|
|
766ffa3e65 | ||
|
|
78d2c7beaa | ||
|
|
f11c38238a | ||
|
|
6d388d50ee | ||
|
|
9479254562 | ||
|
|
9c9fdaf35d | ||
|
|
a4767591ae | ||
|
|
ecbc50b990 | ||
|
|
dde9cc27d0 | ||
|
|
703c03e84b | ||
|
|
2f831b3e6f | ||
|
|
d54eec0b87 | ||
|
|
bc80554cd3 | ||
|
|
a696d330e5 | ||
|
|
b1479ab3c5 | ||
|
|
e51fb06ceb | ||
|
|
dc0f2bde6b | ||
|
|
eb13f267fe | ||
|
|
8677e73d75 | ||
|
|
fbb919d767 | ||
|
|
1f0f9a2eae | ||
|
|
282b2a0a43 | ||
|
|
6d0e4d5a38 | ||
|
|
43956bbf2c | ||
|
|
18e31b3821 | ||
|
|
0d0acb9d10 | ||
|
|
6a792ce6a0 | ||
|
|
917cea5052 | ||
|
|
c98f0d3c81 | ||
|
|
88d650e638 | ||
|
|
72ebe937fb | ||
|
|
8efa5bc1dc | ||
|
|
9b6d2bce58 | ||
|
|
7bb26a7f07 | ||
|
|
9585b3919a | ||
|
|
f56c9deb00 | ||
|
|
c6221fc60f | ||
|
|
acfe3e912e | ||
|
|
50be0ebe3c | ||
|
|
704dc803b8 | ||
|
|
e2d64e9140 | ||
|
|
bdef0612f7 | ||
|
|
a196b71d36 | ||
|
|
fff8116430 | ||
|
|
2be6fb13d2 | ||
|
|
faa6d7f148 | ||
|
|
982fc2838d | ||
|
|
a8351319f8 | ||
|
|
5b1901708c | ||
|
|
fa8d4f511f | ||
|
|
b4215afe82 | ||
|
|
2ad25e8fbc | ||
|
|
67d0e9d2c2 | ||
|
|
f69aae550f | ||
|
|
2d26acd991 | ||
|
|
8dec1453c4 | ||
|
|
241d1e181f | ||
|
|
f267c597e0 | ||
|
|
192437896d | ||
|
|
d59ae7fce1 | ||
|
|
18b21005f1 | ||
|
|
94ac91cce3 | ||
|
|
46e255bccc | ||
|
|
87de5b5305 | ||
|
|
1ddc923631 | ||
|
|
03f65606fd | ||
|
|
148cf9552b | ||
|
|
bf230322d0 | ||
|
|
758779a8f5 | ||
|
|
55eb39c51d | ||
|
|
13b8475c54 | ||
|
|
d3d52b44ee | ||
|
|
d2886432b7 | ||
|
|
7bb8737ff9 | ||
|
|
3904c36a6e | ||
|
|
c2577df6f7 | ||
|
|
36cb0fb4cd | ||
|
|
ec79793f3d | ||
|
|
188bf76ed1 | ||
|
|
e4e909737c | ||
|
|
d32421c583 | ||
|
|
63cbcdc3ea | ||
|
|
dfd8d0fa3d | ||
|
|
7d7ca11c81 | ||
|
|
ee50a31bba | ||
|
|
179930ad80 | ||
|
|
fdb02da5ed | ||
|
|
5499beb510 | ||
|
|
96046d2ee2 | ||
|
|
a35a209066 | ||
|
|
8139c33b86 | ||
|
|
da40562ee3 | ||
|
|
ce478583ab | ||
|
|
6215af0e5a | ||
|
|
8f0ecac842 | ||
|
|
54dd562d88 | ||
|
|
c24f7a86d4 | ||
|
|
d6b4437664 | ||
|
|
68e74b9830 | ||
|
|
3fa40b2303 | ||
|
|
5feb73c65b | ||
|
|
33d676e1fe | ||
|
|
afb7af287b | ||
|
|
d6291a4c47 | ||
|
|
7228b84bf8 | ||
|
|
2dbf8ebb65 | ||
|
|
2d90844239 | ||
|
|
bf6e66ea47 | ||
|
|
5edaa6ec29 | ||
|
|
881ca67f80 | ||
|
|
1c0ed2a2c1 | ||
|
|
245d27ea71 | ||
|
|
f14d4b8ac3 | ||
|
|
fdc867b9d5 | ||
|
|
8e876d6a99 | ||
|
|
c9de0b4cf2 | ||
|
|
27b3a86155 | ||
|
|
683bdc838d | ||
|
|
4f9f10ddf2 | ||
|
|
6fe3f90a26 | ||
|
|
5bdb7eee85 | ||
|
|
34262a45ca | ||
|
|
7c22110c96 | ||
|
|
6ad9fb8f27 | ||
|
|
4348f4b0d4 | ||
|
|
22529e28d8 | ||
|
|
aa52bcee8c | ||
|
|
d731ab3682 | ||
|
|
7840438bfc | ||
|
|
455a2dba8a | ||
|
|
01c310c913 | ||
|
|
a679d6f2e1 | ||
|
|
e8af56bdbe | ||
|
|
efa099ac5b | ||
|
|
81181aa7e6 | ||
|
|
1ab6640983 | ||
|
|
e5636cde05 | ||
|
|
0a0d00b26e | ||
|
|
6c9afcff81 | ||
|
|
b7933b282b | ||
|
|
653c34758b | ||
|
|
9d18ab795e | ||
|
|
a5c06c67bc | ||
|
|
db2f790bf7 | ||
|
|
5cbc6b5f6a | ||
|
|
f7ecf40633 | ||
|
|
6cd83c60ef | ||
|
|
90ffce63e5 | ||
|
|
2910ebc0fd | ||
|
|
02fab95637 | ||
|
|
22d2209a1b | ||
|
|
e2bea81c64 | ||
|
|
466b8bd1cc | ||
|
|
c5287d2869 | ||
|
|
010502ed9d | ||
|
|
be06e74d94 | ||
|
|
199d2cf851 | ||
|
|
deab1b4962 | ||
|
|
d04411e4a8 | ||
|
|
ce52b57a52 | ||
|
|
c760c19056 | ||
|
|
6b5e469b19 | ||
|
|
8663489ae4 | ||
|
|
877ef1d7ed | ||
|
|
6a81035f10 | ||
|
|
1f7276bbfd | ||
|
|
90e8490a85 | ||
|
|
38d51988d9 | ||
|
|
b8fccd1bac | ||
|
|
ded8e7b916 | ||
|
|
f56ca6318a | ||
|
|
5bd6ba4f36 | ||
|
|
909fb2eb2b | ||
|
|
b2209eaad0 | ||
|
|
dcae3c4acb | ||
|
|
3a3a2ec76d | ||
|
|
5e2ba192c1 | ||
|
|
6d4452bf94 | ||
|
|
998f9491f6 | ||
|
|
fa7efeb283 | ||
|
|
22206b6a99 | ||
|
|
34036ee355 | ||
|
|
2eb2d555ad | ||
|
|
722abf9cab | ||
|
|
357d3b8140 | ||
|
|
01ef79ac33 | ||
|
|
8d2456f238 | ||
|
|
bb164edb55 | ||
|
|
21117eaa17 | ||
|
|
573f823f48 | ||
|
|
47ca3b5d33 | ||
|
|
7334134b45 | ||
|
|
e6be594395 | ||
|
|
e2b6697362 | ||
|
|
f78e11057d | ||
|
|
314ee96525 | ||
|
|
efc1223d45 | ||
|
|
38d9aa4997 | ||
|
|
42c7431416 | ||
|
|
d1e40ee71c | ||
|
|
43169d8bab | ||
|
|
8cbbb52b95 | ||
|
|
807a55fcdc | ||
|
|
8c5351445b | ||
|
|
999c630c5a | ||
|
|
a0186ce8e4 | ||
|
|
9fe336d564 | ||
|
|
34a1d4e6b9 | ||
|
|
bafa548f2f | ||
|
|
fa709a9bdc | ||
|
|
2a1cc7e3ea | ||
|
|
68648b9920 | ||
|
|
b9f297935b | ||
|
|
eb6fc4f8cf | ||
|
|
8a177c34fa | ||
|
|
22a5f411d0 | ||
|
|
f557609e9e | ||
|
|
cde8deaf4b | ||
|
|
48eb1c6d67 | ||
|
|
4db741a87c | ||
|
|
3188ca6884 | ||
|
|
bb9cd171bf | ||
|
|
7a81638258 | ||
|
|
6519db1fe8 | ||
|
|
f313d319d4 | ||
|
|
a8c4e6fedc | ||
|
|
db16458cf5 | ||
|
|
38a9562eaf | ||
|
|
b2327e8bf7 | ||
|
|
aafef107ec | ||
|
|
4b442e75f7 | ||
|
|
e8f103799b | ||
|
|
618685dc05 | ||
|
|
f0d50e53fa | ||
|
|
1b4828f4fa | ||
|
|
56730d67a2 | ||
|
|
b02516b0b3 | ||
|
|
1eb32f86bd | ||
|
|
3b669e64e2 | ||
|
|
fbccd70f7d | ||
|
|
61e5231d99 | ||
|
|
5c101c5a85 | ||
|
|
a6e991923e | ||
|
|
f0c494ecea | ||
|
|
40dfdf9bb1 | ||
|
|
770e0f01f1 | ||
|
|
8448d3e516 | ||
|
|
292a11f942 | ||
|
|
6099986f5b | ||
|
|
53d18d8947 | ||
|
|
f77bdd233b | ||
|
|
dc25a1294c | ||
|
|
8f4bffa950 | ||
|
|
96195fa16a | ||
|
|
4e8a59ad4e | ||
|
|
e42ee6d6be | ||
|
|
f6a04a8b36 | ||
|
|
36b94b81ce | ||
|
|
d66e782152 | ||
|
|
d122d39d3a | ||
|
|
7c3053e8cd | ||
|
|
ecdfa61755 | ||
|
|
7321117c99 | ||
|
|
b50560eadf | ||
|
|
60841e6312 | ||
|
|
66cc61f967 | ||
|
|
1933f4bcc8 | ||
|
|
977f5ca9ce | ||
|
|
e5e529d3d2 | ||
|
|
e1f9d6091c | ||
|
|
a83d8064f2 | ||
|
|
9afb5e7272 | ||
|
|
4c7c2ccc74 | ||
|
|
a6d5686c1c | ||
|
|
8fa1b92deb | ||
|
|
f06e3643b6 | ||
|
|
cd8e59bc9c | ||
|
|
b6eeeea1ea | ||
|
|
aea642fcde | ||
|
|
27bec7ad05 | ||
|
|
80cb3458de | ||
|
|
615048df04 | ||
|
|
4e07b56f3e | ||
|
|
7d18da13a1 | ||
|
|
a49e9e346f | ||
|
|
87fd267183 | ||
|
|
c61fefb55f | ||
|
|
c644031041 | ||
|
|
79f0f52825 | ||
|
|
03ac62044b | ||
|
|
531bc0f887 | ||
|
|
af8b60ca29 | ||
|
|
80c14e9ebd | ||
|
|
3d658eff29 | ||
|
|
8a8a75aa79 | ||
|
|
ea3fe06613 | ||
|
|
92e7f6bd68 | ||
|
|
96b22a00ff | ||
|
|
cfddbc5b3f | ||
|
|
725009d719 | ||
|
|
7f7370f6db | ||
|
|
0fcc1316b2 | ||
|
|
e9933bebe7 | ||
|
|
9810081b11 | ||
|
|
6522d252cb | ||
|
|
a2867cffb7 | ||
|
|
e92c1b53a1 | ||
|
|
52aecb47e7 | ||
|
|
c4652d39fa | ||
|
|
c7b155ccac | ||
|
|
96d18535f8 | ||
|
|
98471e39e1 | ||
|
|
f55fc5776e | ||
|
|
f9a8d1cc40 | ||
|
|
e55a210cf9 | ||
|
|
d19d4406f6 | ||
|
|
9697331abb | ||
|
|
91db02f2da | ||
|
|
b933b30e0a | ||
|
|
2cb9a7c199 | ||
|
|
06ff17ebb2 | ||
|
|
44a573ecd5 | ||
|
|
ffa7952fc1 | ||
|
|
701514a168 | ||
|
|
1565bc9e1a | ||
|
|
0681bad8e6 | ||
|
|
23a21bb39f | ||
|
|
9aabb575c1 | ||
|
|
cf607e892b | ||
|
|
6bf906f2a7 | ||
|
|
7e897d604c | ||
|
|
39887df3ec | ||
|
|
fbb7a684bf | ||
|
|
449ad6cd0d | ||
|
|
cfcd6e5f93 | ||
|
|
73aab88109 | ||
|
|
beb692a3c4 | ||
|
|
fe8385e759 | ||
|
|
58fb331019 | ||
|
|
e4986a6a47 | ||
|
|
fcd47ecec6 | ||
|
|
174e6ad637 | ||
|
|
2ac4097e32 | ||
|
|
dd13ac5cbb | ||
|
|
9c55a898f7 | ||
|
|
bb9018c094 | ||
|
|
b09b4183bb | ||
|
|
3d7bc6583d | ||
|
|
99e8be227e | ||
|
|
b1c38cc793 | ||
|
|
26e4e70fc8 | ||
|
|
04bdf3f26a | ||
|
|
cafeacf69f | ||
|
|
4c2d6d78ea | ||
|
|
ea7d0cdef5 | ||
|
|
47bae63548 | ||
|
|
8470f4f7fb | ||
|
|
242f9d55ed | ||
|
|
236ac52925 | ||
|
|
baab9a9c89 | ||
|
|
3d26e6e340 | ||
|
|
c34ab48972 | ||
|
|
cf0abf21db | ||
|
|
7918b392e8 | ||
|
|
f0ced15e6a | ||
|
|
c0204cb725 | ||
|
|
eb3905447f | ||
|
|
16c7459906 | ||
|
|
eae5f87eed | ||
|
|
d4b85e3b1c | ||
|
|
a989c3b7d0 | ||
|
|
d96ba9fa46 | ||
|
|
2261d655ea | ||
|
|
8b67049863 | ||
|
|
48258dd9dd | ||
|
|
e04c573726 | ||
|
|
4daec3794e | ||
|
|
f0646dde32 | ||
|
|
ec2086e0f7 | ||
|
|
2ac704178c | ||
|
|
7c43c38e28 | ||
|
|
043a8336e5 | ||
|
|
ee27535b82 | ||
|
|
89e6ae2475 | ||
|
|
e51615f520 | ||
|
|
6e59897587 | ||
|
|
bd0644a261 | ||
|
|
d7825e1bf8 | ||
|
|
97956b6c5e | ||
|
|
8150504ea0 | ||
|
|
942dec81c7 | ||
|
|
dcbc377c62 | ||
|
|
7b65233699 | ||
|
|
eabfd8b5c4 | ||
|
|
b7b2799611 | ||
|
|
ece59ac374 | ||
|
|
83cc8b772c | ||
|
|
8b5bc18142 | ||
|
|
e1413baa9a | ||
|
|
03640e6d37 | ||
|
|
2588011524 | ||
|
|
0c16a6804a | ||
|
|
e2021fdf5d | ||
|
|
33b5694d35 | ||
|
|
af7d04fef6 | ||
|
|
14e3419e4c | ||
|
|
f6c5252376 | ||
|
|
78ee77444f | ||
|
|
fb022970b5 | ||
|
|
e5d378dc93 | ||
|
|
5969902263 | ||
|
|
d5894de142 | ||
|
|
059c6baa4e | ||
|
|
bbf9331baf | ||
|
|
a5b084f506 | ||
|
|
3b5471b97c | ||
|
|
fae37fe67d | ||
|
|
1f975efda1 | ||
|
|
3b3b61f52c | ||
|
|
1c1f6e21c5 | ||
|
|
8b60c7cc09 | ||
|
|
d4f9752cd4 | ||
|
|
6332a37f5b | ||
|
|
840a583a0b | ||
|
|
e7ed80d3e0 | ||
|
|
c2b9376313 | ||
|
|
7a8b291189 | ||
|
|
e63f71d3a7 | ||
|
|
061c97caca | ||
|
|
988d28f2fd | ||
|
|
af8a0ea9c0 | ||
|
|
c78e8d8358 | ||
|
|
392f7098bc | ||
|
|
195f918543 | ||
|
|
b2579538fa | ||
|
|
35b97c4f45 | ||
|
|
adaa89a963 | ||
|
|
fc1429fae5 | ||
|
|
4090f95098 | ||
|
|
3189d8d43e | ||
|
|
cd6d10e428 | ||
|
|
7d37236d78 | ||
|
|
7c127acf17 | ||
|
|
0a4ce2350a | ||
|
|
181a70cb1f | ||
|
|
7438545a16 | ||
|
|
9e902a5dd4 | ||
|
|
91e395884f | ||
|
|
7107c68a41 | ||
|
|
86728b79e3 | ||
|
|
e04f901590 | ||
|
|
47ad2b5cfa | ||
|
|
cea0f1766f | ||
|
|
407e57d334 | ||
|
|
c4e66d0c9c | ||
|
|
c54f1ca9b0 | ||
|
|
f9fdc36d0d | ||
|
|
6d546094ef | ||
|
|
8dc5ae4f86 | ||
|
|
fd7b81af10 | ||
|
|
3abd859664 | ||
|
|
6134ce39d4 | ||
|
|
8ea42ea432 | ||
|
|
fd4ff00ee2 | ||
|
|
9d981b09ca | ||
|
|
ed807e0fe5 | ||
|
|
32b962b036 | ||
|
|
8ac476b6bd | ||
|
|
9ab8b84d81 | ||
|
|
05cc4b4bd1 | ||
|
|
b28cf30f47 | ||
|
|
5bf8b0a2b6 | ||
|
|
d2891a49fc | ||
|
|
bec8ba6c2f | ||
|
|
9e097be657 | ||
|
|
b008f55847 | ||
|
|
487d90f260 | ||
|
|
671a745acc | ||
|
|
80880f4d2a | ||
|
|
109fba828b | ||
|
|
0a845fdfa6 | ||
|
|
5a5b8464fc | ||
|
|
86d0b92a66 | ||
|
|
9f75234dac | ||
|
|
a58b129503 | ||
|
|
6d752acb28 | ||
|
|
4486582006 | ||
|
|
ed027fd3ce | ||
|
|
a92cb848c0 | ||
|
|
e573e36aa6 | ||
|
|
fc61753953 | ||
|
|
9b74e19a99 | ||
|
|
e9e39cb985 | ||
|
|
d938f2ea50 | ||
|
|
6c3535951f | ||
|
|
cee78b4ae3 | ||
|
|
1ee646e1ce | ||
|
|
6199dec82f | ||
|
|
59f307bdb3 | ||
|
|
24747355ce | ||
|
|
3d287a2827 | ||
|
|
def28df4dd | ||
|
|
d90e698a15 | ||
|
|
f4d6f88e5c | ||
|
|
799dce4b13 | ||
|
|
a025d028d4 | ||
|
|
8cfa9a891d | ||
|
|
5b44439dd2 | ||
|
|
44fb7dcdaa | ||
|
|
4f5d1ba26b | ||
|
|
0a08b09d70 | ||
|
|
35eedda352 | ||
|
|
05fb8bc742 | ||
|
|
795df2937e | ||
|
|
5607740e77 | ||
|
|
d4287d3046 | ||
|
|
71ef72bae3 | ||
|
|
c310d698ca | ||
|
|
13ce3d1c92 | ||
|
|
122ed79a98 | ||
|
|
6d655242a6 | ||
|
|
09cab9d825 | ||
|
|
d8bd38c124 | ||
|
|
abc8bf0e62 | ||
|
|
24106ac3d2 | ||
|
|
bf506d382f | ||
|
|
84b1a9bbec | ||
|
|
d67afd4396 | ||
|
|
9f2f7eff5b | ||
|
|
c863d5976b | ||
|
|
d6338e9daf | ||
|
|
b393d2666d | ||
|
|
c5b1e73312 | ||
|
|
fa65222228 | ||
|
|
38e57ccd71 | ||
|
|
86d3d26273 | ||
|
|
db8e4a03a8 | ||
|
|
c90db8594a | ||
|
|
855ca77194 | ||
|
|
4f23af070e | ||
|
|
626613b545 | ||
|
|
c26de3bd67 | ||
|
|
c059915bd3 | ||
|
|
d2d70dcb38 | ||
|
|
846292442c | ||
|
|
11283a2199 | ||
|
|
4c8a0b9a63 | ||
|
|
54accbf21f | ||
|
|
08dc0db2e2 | ||
|
|
38c6330a2a | ||
|
|
2f983f42fe | ||
|
|
b9e45c4bb0 | ||
|
|
9d3b1d75d1 | ||
|
|
ac78ddcc82 | ||
|
|
f912d84ab6 | ||
|
|
85548d6e8e | ||
|
|
c74de12ceb | ||
|
|
017a21c17f | ||
|
|
9a63038a5f | ||
|
|
304fc2536b | ||
|
|
365169a9fb | ||
|
|
4b82ead18b | ||
|
|
141d7cc268 | ||
|
|
ee8e94cfb0 | ||
|
|
b50bedef39 | ||
|
|
a689ce4de9 | ||
|
|
ae0478a7e9 | ||
|
|
ee6eed5ac5 | ||
|
|
9140c426c4 | ||
|
|
a41bfabede | ||
|
|
5d26357025 | ||
|
|
644c10e994 | ||
|
|
b3ca0beead | ||
|
|
93300c6821 |
12
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [pascallanger]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted
|
||||
202
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
# Workflow for testing MULTI-Module firmware builds
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
# Trigger the workflow on pushes, except those that are tagged (avoids double-testing releases)
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
tags-ignore:
|
||||
- '**'
|
||||
paths:
|
||||
- '.github/workflows/**'
|
||||
- 'buildroot/bin/**'
|
||||
- 'Multiprotocol/**'
|
||||
|
||||
# Trigger the workflow on pull requests to the master branch
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- '.github/workflows/**'
|
||||
- 'buildroot/bin/**'
|
||||
- 'Multiprotocol/**'
|
||||
|
||||
# Triggers the workflow on release creation
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
|
||||
# Allows the workflow to be triggered manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Configure the board matrix
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
board: [
|
||||
"multi4in1-devel:avr:multiatmega328p:bootloader=none",
|
||||
"multi4in1-devel:avr:multiatmega328p:bootloader=optiboot",
|
||||
"multi4in1-devel:avr:multixmega32d4",
|
||||
"multi4in1-devel:STM32F1:multi5in1t18int",
|
||||
"multi4in1-devel:STM32F1:multistm32f103cb:debug_option=none",
|
||||
"multi4in1-devel:STM32F1:multistm32f103cb:debug_option=native",
|
||||
"multi4in1-devel:STM32F1:multistm32f103cb:debug_option=ftdi",
|
||||
"multi4in1-devel:STM32F1:multistm32f103c8:debug_option=none"
|
||||
]
|
||||
|
||||
# Set the environment variables
|
||||
env:
|
||||
BOARD: ${{ matrix.board }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Arduino CLI
|
||||
uses: arduino/setup-arduino-cli@v1.1.1
|
||||
|
||||
- name: Prepare build environment
|
||||
run: |
|
||||
echo "Github Ref: $GITHUB_REF"
|
||||
echo "Event name: ${{ github.event_name }}"
|
||||
echo "Event action: ${{ github.event.action }}"
|
||||
echo "Tag name: ${{ github.event.release.tag_name }}"
|
||||
|
||||
arduino-cli config init --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json,https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/devel/source/package_multi_4in1_board_devel_index.json
|
||||
arduino-cli core update-index
|
||||
|
||||
if [[ "$BOARD" =~ ":avr:" ]]; then
|
||||
arduino-cli core install arduino:avr;
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:avr" ]]; then
|
||||
arduino-cli core install multi4in1-devel:avr
|
||||
elif [[ "$BOARD" =~ "multi4in1:avr" ]]; then
|
||||
arduino-cli core install multi4in1:avr
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1-devel:STM32F1
|
||||
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1:STM32F1
|
||||
fi
|
||||
|
||||
chmod +x ${GITHUB_WORKSPACE}/buildroot/bin/*
|
||||
echo "${GITHUB_WORKSPACE}/buildroot/bin" >> $GITHUB_PATH
|
||||
|
||||
mkdir ./build
|
||||
mkdir ./binaries
|
||||
|
||||
- name: Configure MULTI-Module firmware options
|
||||
run: |
|
||||
# Load the build functions
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
|
||||
# Get the version
|
||||
getMultiVersion
|
||||
echo "MULTI_VERSION=$(echo $MULTI_VERSION)" >> $GITHUB_ENV
|
||||
|
||||
# Get all the protocols for this board
|
||||
getAllProtocols
|
||||
echo "A7105_PROTOCOLS=$(echo $A7105_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CC2500_PROTOCOLS=$(echo $CC2500_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CYRF6936_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "NRF24L01_PROTOCOLS=$(echo $NRF24L01_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "SX1276_PROTOCOLS=$(echo $SX1276_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CCNRF_INO_PROTOCOLS=$(echo $CCNRF_INO_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "ALL_PROTOCOLS=$(echo $ALL_PROTOCOLS)" >> $GITHUB_ENV
|
||||
|
||||
# Get all the RF modules for this board
|
||||
getAllRFModules
|
||||
echo "ALL_RFMODULES=$(echo $ALL_RFMODULES)" >> $GITHUB_ENV
|
||||
|
||||
# Disable CHECK_FOR_BOOTLOADER when not needed
|
||||
if [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
fi
|
||||
|
||||
# Trim the build down for the Atmega328p board
|
||||
if [[ "$BOARD" =~ ":avr:multiatmega328p:" ]]; then
|
||||
opt_disable $ALL_PROTOCOLS
|
||||
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
|
||||
fi
|
||||
|
||||
# Trim the enabled protocols down for the STM32F103CB board with debugging or the STM32F103C8 board in general
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=ftdi" ]] || [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=native" ]] || [[ "$BOARD" =~ ":STM32F1:multistm32f103c8" ]]; then
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
|
||||
fi
|
||||
|
||||
- name: Save default firmware configuration
|
||||
run: |
|
||||
cat Multiprotocol/_Config.h
|
||||
cp Multiprotocol/_Config.h ./_Config.h.bak
|
||||
|
||||
- name: Build default configuration
|
||||
run: |
|
||||
# Skip the default build for boards where it's too large now
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
printf "Not testing default build for $BOARD.";
|
||||
else
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
buildMulti
|
||||
fi
|
||||
|
||||
- name: Build serial only
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
opt_disable ENABLE_PPM;
|
||||
buildMulti;
|
||||
|
||||
- name: Build PPM only
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
opt_disable ENABLE_SERIAL;
|
||||
buildMulti;
|
||||
|
||||
- name: Build each RF module individually
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
||||
buildEachRFModule;
|
||||
|
||||
- name: Build each protocol individually
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
||||
buildEachProtocol;
|
||||
|
||||
- name: Build release files
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
||||
buildReleaseFiles;
|
||||
ls -al ./binaries;
|
||||
|
||||
NUM_FILES=$(ls -l ./binaries | grep ^- | wc -l);
|
||||
if [ $NUM_FILES -gt 0 ]; then
|
||||
echo "HAVE_FILES=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "HAVE_FILES=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Deploy files to release
|
||||
if: github.event_name == 'release' && github.event.action == 'created' && env.HAVE_FILES == 'true'
|
||||
uses: AButler/upload-release-assets@v2.0
|
||||
with:
|
||||
files: './binaries/*'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: 'Upload Artifacts'
|
||||
if: env.HAVE_FILES == 'true'
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: multi-test-build
|
||||
path: ./binaries/
|
||||
2
BootLoaders/AtmegaEmptyBoot/AtmegaMultiEmpty.hex
Normal file
@@ -0,0 +1,2 @@
|
||||
:02000000FFFF00
|
||||
:00000001FF
|
||||
34
BootLoaders/AtmegaMultiBoot/AtmegaMultiBoot.hex
Normal file
@@ -0,0 +1,34 @@
|
||||
:107E0000112484B714BE9FEF9BB99CE395B991E010
|
||||
:107E100098B98370A9F08AEF80938500109284004E
|
||||
:107E200085E08093810096BBB09BFECF10928100CD
|
||||
:107E300093B186B181709C73892B8D3109F0B3D0D9
|
||||
:107E400082E08093C00088E18093C10086E0809347
|
||||
:107E5000C20081E28093C400259AC0E0D0E093E0A4
|
||||
:107E6000F92EEE24E39425E0D22E31E1C32EA9D0E1
|
||||
:107E7000813481F4A6D08EBBABD08EB3823811F49E
|
||||
:107E800085E006C08EB3813811F484E001C083E040
|
||||
:107E900091D086C0823411F484E103C0853419F492
|
||||
:107EA00085E09DD07DC0853541F48BD0C82F89D029
|
||||
:107EB000D0E0D82BCC0FDD1F72C0863521F484E0D2
|
||||
:107EC0008ED080E0E5CF843609F03DC07AD079D0FD
|
||||
:107ED000B82E77D0C11520E7D20718F000E011E0E6
|
||||
:107EE00004C0FE01F7BEE895F9CF6BD0F80181938D
|
||||
:107EF0008F01BE12FACFCE01905781159E4018F423
|
||||
:107F0000FE01F7BEE89564D0C115FEE7DF0708F073
|
||||
:107F100047C007B600FCFDCFFE01A0E0B1E08D91A7
|
||||
:107F20009D910C01E7BEE89511243296A03821E01E
|
||||
:107F3000B207A9F7FE01D7BEE89507B600FCFDCF52
|
||||
:107F4000C7BEE8952DC08437B1F43BD03AD0B82EE7
|
||||
:107F500038D03ED0FE01AC2EAB0C8F010F5F1F4F0F
|
||||
:107F6000849128D0A01205C02196BA94CB0DD11DC2
|
||||
:107F700017C0F801F2CF853739F42AD08EE11AD034
|
||||
:107F800085E918D08FE084CF813549F421D080E194
|
||||
:107F900011D08091C00086FFFCCF05D001C018D061
|
||||
:107FA00080E108D064CFE0E0F0E084918F3F09F0F9
|
||||
:107FB000099408959091C00095FFFCCF8093C6006E
|
||||
:107FC00008958091C00087FFFCCF8091C60008957E
|
||||
:107FD000F8DF803211F085E1EDDF84E1EBCFCF9364
|
||||
:107FE000C82FEFDFC150E9F7CF91F2CFA8950895E0
|
||||
:0C7FF000E0E6F0E098E1908380830895C3
|
||||
:0400000300007E007B
|
||||
:00000001FF
|
||||
504
BootLoaders/AtmegaMultiBoot/Source/Makefile
Normal file
@@ -0,0 +1,504 @@
|
||||
# Makefile for ATmegaBOOT
|
||||
# E.Lins, 18.7.2005
|
||||
# $Id$
|
||||
#
|
||||
# Instructions
|
||||
#
|
||||
# To make bootloader .hex file:
|
||||
# make diecimila
|
||||
# make lilypad
|
||||
# make ng
|
||||
# etc...
|
||||
#
|
||||
# To burn bootloader .hex file:
|
||||
# make diecimila_isp
|
||||
# make lilypad_isp
|
||||
# make ng_isp
|
||||
# etc...
|
||||
|
||||
# program name should not be changed...
|
||||
PROGRAM = optiboot
|
||||
|
||||
# The default behavior is to build using tools that are in the users
|
||||
# current path variables, but we can also build using an installed
|
||||
# Arduino user IDE setup, or the Arduino source tree.
|
||||
# Uncomment this next lines to build within the arduino environment,
|
||||
# using the arduino-included avrgcc toolset (mac and pc)
|
||||
# ENV ?= arduino
|
||||
# ENV ?= arduinodev
|
||||
# OS ?= macosx
|
||||
# OS ?= windows
|
||||
|
||||
|
||||
# enter the parameters for the avrdude isp tool -b19200
|
||||
#
|
||||
# These are the parameters for a usb-based STK500v2 programmer.
|
||||
# Exact type unknown. (historical Makefile values.)
|
||||
ISPTOOL = stk500v2
|
||||
ISPPORT = usb
|
||||
ISPSPEED = -b 57600
|
||||
#
|
||||
#
|
||||
# These are parameters for using an Arduino with the ArduinoISP sketch
|
||||
# as the programmer. On a mac, for a particular Uno as programmer.
|
||||
#ISPTOOL = stk500v1 -C /Applications/arduino/arduino-0022/hardware/tools/avr/etc/avrdude.conf
|
||||
#ISPPORT = /dev/tty.usbmodemfd3141
|
||||
#ISPSPEED = -b19200
|
||||
|
||||
MCU_TARGET = atmega168
|
||||
LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe
|
||||
|
||||
# Build environments
|
||||
# Start of some ugly makefile-isms to allow optiboot to be built
|
||||
# in several different environments. See the README.TXT file for
|
||||
# details.
|
||||
|
||||
# default
|
||||
fixpath = $(1)
|
||||
|
||||
ifeq ($(ENV), arduino)
|
||||
# For Arduino, we assume that we're connected to the optiboot directory
|
||||
# included with the arduino distribution, which means that the full set
|
||||
# of avr-tools are "right up there" in standard places.
|
||||
TOOLROOT = ../../../tools
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
ifeq ($(OS), windows)
|
||||
# On windows, SOME of the tool paths will need to have backslashes instead
|
||||
# of forward slashes (because they use windows cmd.exe for execution instead
|
||||
# of a unix/mingw shell?) We also have to ensure that a consistent shell
|
||||
# is used even if a unix shell is installed (ie as part of WINAVR)
|
||||
fixpath = $(subst /,\,$1)
|
||||
SHELL = cmd.exe
|
||||
endif
|
||||
|
||||
else ifeq ($(ENV), arduinodev)
|
||||
# Arduino IDE source code environment. Use the unpacked compilers created
|
||||
# by the build (you'll need to do "ant build" first.)
|
||||
ifeq ($(OS), macosx)
|
||||
TOOLROOT = ../../../../build/macosx/work/Arduino.app/Contents/Resources/Java/hardware/tools
|
||||
endif
|
||||
ifeq ($(OS), windows)
|
||||
TOOLROOT = ../../../../build/windows/work/hardware/tools
|
||||
endif
|
||||
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
else
|
||||
GCCROOT =
|
||||
AVRDUDE_CONF =
|
||||
endif
|
||||
#
|
||||
# End of build environment code.
|
||||
|
||||
|
||||
# the efuse should really be 0xf8; since, however, only the lower
|
||||
# three bits of that byte are used on the atmega168, avrdude gets
|
||||
# confused if you specify 1's for the higher bits, see:
|
||||
# http://tinker.it/now/2007/02/24/the-tale-of-avrdude-atmega168-and-extended-bits-fuses/
|
||||
#
|
||||
# similarly, the lock bits should be 0xff instead of 0x3f (to
|
||||
# unlock the bootloader section) and 0xcf instead of 0x2f (to
|
||||
# lock it), but since the high two bits of the lock byte are
|
||||
# unused, avrdude would get confused.
|
||||
|
||||
ISPFUSES = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-e -u -U lock:w:0x3f:m -U efuse:w:0x$(EFUSE):m \
|
||||
-U hfuse:w:0x$(HFUSE):m -U lfuse:w:0x$(LFUSE):m
|
||||
ISPFLASH = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x2f:m
|
||||
|
||||
STK500 = "C:\Program Files\Atmel\AVR Tools\STK500\Stk500.exe"
|
||||
STK500-1 = $(STK500) -e -d$(MCU_TARGET) -pf -vf -if$(PROGRAM)_$(TARGET).hex \
|
||||
-lFF -LFF -f$(HFUSE)$(LFUSE) -EF8 -ms -q -cUSB -I200kHz -s -wt
|
||||
STK500-2 = $(STK500) -d$(MCU_TARGET) -ms -q -lCF -LCF -cUSB -I200kHz -s -wt
|
||||
|
||||
OBJ = $(PROGRAM).o
|
||||
OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types
|
||||
# -mshort-calls
|
||||
|
||||
DEFS =
|
||||
LIBS =
|
||||
|
||||
CC = $(GCCROOT)avr-gcc
|
||||
|
||||
# Override is only needed by avr-lib build system.
|
||||
|
||||
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
|
||||
override LDFLAGS = $(LDSECTIONS) -Wl,--relax -Wl,--gc-sections -nostartfiles -nostdlib
|
||||
|
||||
OBJCOPY = $(GCCROOT)avr-objcopy
|
||||
OBJDUMP = $(call fixpath,$(GCCROOT)avr-objdump)
|
||||
|
||||
SIZE = $(GCCROOT)avr-size
|
||||
|
||||
|
||||
|
||||
#Voice board test
|
||||
# ATmega328
|
||||
#
|
||||
#atmega328: TARGET = atmega328p
|
||||
#atmega328: MCU_TARGET = atmega328p
|
||||
#atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
#atmega328: AVR_FREQ = 12000000L
|
||||
#atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
#atmega328: $(PROGRAM)_atmega328.hex
|
||||
#atmega328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
atmega328: TARGET = atmega328
|
||||
atmega328: MCU_TARGET = atmega328p
|
||||
atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
atmega328: AVR_FREQ = 16000000L
|
||||
atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328: $(PROGRAM)_atmega328_16.hex
|
||||
atmega328: $(PROGRAM)_atmega328_16.lst
|
||||
|
||||
|
||||
xmega32D4: TARGET = atxmega32d4
|
||||
xmega32D4: MCU_TARGET = atxmega32d4
|
||||
xmega32D4: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
xmega32D4: AVR_FREQ = 32000000L
|
||||
xmega32D4: LDSECTIONS = -Wl,--section-start=.text=0x8000
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.hex
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.lst
|
||||
|
||||
|
||||
# Test platforms
|
||||
# Virtual boot block test
|
||||
virboot328: TARGET = atmega328
|
||||
virboot328: MCU_TARGET = atmega328p
|
||||
virboot328: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DVIRTUAL_BOOT'
|
||||
virboot328: AVR_FREQ = 16000000L
|
||||
virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
virboot328: $(PROGRAM)_atmega328.hex
|
||||
virboot328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
# 20MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro20: TARGET = pro_20mhz
|
||||
pro20: MCU_TARGET = atmega168
|
||||
pro20: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro20: AVR_FREQ = 20000000L
|
||||
pro20: $(PROGRAM)_pro_20mhz.hex
|
||||
pro20: $(PROGRAM)_pro_20mhz.lst
|
||||
|
||||
pro20_isp: pro20
|
||||
pro20_isp: TARGET = pro_20mhz
|
||||
# 2.7V brownout
|
||||
pro20_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro20_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro20_isp: EFUSE = 04
|
||||
pro20_isp: isp
|
||||
|
||||
# 16MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro16: TARGET = pro_16MHz
|
||||
pro16: MCU_TARGET = atmega168
|
||||
pro16: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro16: AVR_FREQ = 16000000L
|
||||
pro16: $(PROGRAM)_pro_16MHz.hex
|
||||
pro16: $(PROGRAM)_pro_16MHz.lst
|
||||
|
||||
pro16_isp: pro16
|
||||
pro16_isp: TARGET = pro_16MHz
|
||||
# 2.7V brownout
|
||||
pro16_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro16_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro16_isp: EFUSE = 04
|
||||
pro16_isp: isp
|
||||
|
||||
# Diecimila, Duemilanove with m168, and NG use identical bootloaders
|
||||
# Call it "atmega168" for generality and clarity, keep "diecimila" for
|
||||
# backward compatibility of makefile
|
||||
#
|
||||
atmega168: TARGET = atmega168
|
||||
atmega168: MCU_TARGET = atmega168
|
||||
atmega168: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega168: AVR_FREQ = 12000000L
|
||||
atmega168: $(PROGRAM)_atmega168.hex
|
||||
atmega168: $(PROGRAM)_atmega168.lst
|
||||
|
||||
atmega168_isp: atmega168
|
||||
atmega168_isp: TARGET = atmega168
|
||||
# 2.7V brownout
|
||||
atmega168_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega168_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega168_isp: EFUSE = 04
|
||||
atmega168_isp: isp
|
||||
|
||||
diecimila: TARGET = diecimila
|
||||
diecimila: MCU_TARGET = atmega168
|
||||
diecimila: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
diecimila: AVR_FREQ = 16000000L
|
||||
diecimila: $(PROGRAM)_diecimila.hex
|
||||
diecimila: $(PROGRAM)_diecimila.lst
|
||||
|
||||
diecimila_isp: diecimila
|
||||
diecimila_isp: TARGET = diecimila
|
||||
# 2.7V brownout
|
||||
diecimila_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
diecimila_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
diecimila_isp: EFUSE = 04
|
||||
diecimila_isp: isp
|
||||
|
||||
atmega328_isp: atmega328
|
||||
atmega328_isp: TARGET = atmega328
|
||||
atmega328_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_isp: EFUSE = FD
|
||||
atmega328_isp: isp
|
||||
|
||||
atmega1284: TARGET = atmega1284p
|
||||
atmega1284: MCU_TARGET = atmega1284p
|
||||
atmega1284: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
atmega1284: AVR_FREQ = 16000000L
|
||||
atmega1284: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
atmega1284: $(PROGRAM)_atmega1284p.hex
|
||||
atmega1284: $(PROGRAM)_atmega1284p.lst
|
||||
|
||||
atmega1284_isp: atmega1284
|
||||
atmega1284_isp: TARGET = atmega1284p
|
||||
atmega1284_isp: MCU_TARGET = atmega1284p
|
||||
# 1024 byte boot
|
||||
atmega1284_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega1284_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega1284_isp: EFUSE = FD
|
||||
atmega1284_isp: isp
|
||||
|
||||
# Sanguino has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#
|
||||
sanguino: TARGET = atmega644p
|
||||
sanguino: MCU_TARGET = atmega644p
|
||||
sanguino: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
sanguino: AVR_FREQ = 16000000L
|
||||
sanguino: LDSECTIONS = -Wl,--section-start=.text=0xfc00 -Wl,--section-start=.version=0xfffe
|
||||
sanguino: $(PROGRAM)_atmega644p.hex
|
||||
sanguino: $(PROGRAM)_atmega644p.lst
|
||||
|
||||
sanguino_isp: sanguino
|
||||
sanguino_isp: TARGET = atmega644p
|
||||
sanguino_isp: MCU_TARGET = atmega644p
|
||||
# 1024 byte boot
|
||||
sanguino_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
sanguino_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
sanguino_isp: EFUSE = FD
|
||||
sanguino_isp: isp
|
||||
|
||||
# Mega has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#mega: TARGET = atmega1280
|
||||
mega1280: MCU_TARGET = atmega1280
|
||||
mega1280: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
mega1280: AVR_FREQ = 16000000L
|
||||
mega1280: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
mega1280: $(PROGRAM)_atmega1280.hex
|
||||
mega1280: $(PROGRAM)_atmega1280.lst
|
||||
|
||||
mega1280_isp: mega
|
||||
mega1280_isp: TARGET = atmega1280
|
||||
mega1280_isp: MCU_TARGET = atmega1280
|
||||
# 1024 byte boot
|
||||
mega1280_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
mega1280_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
mega1280_isp: EFUSE = FD
|
||||
mega1280_isp: isp
|
||||
|
||||
# ATmega8
|
||||
#
|
||||
atmega8: TARGET = atmega8
|
||||
atmega8: MCU_TARGET = atmega8
|
||||
atmega8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega8: AVR_FREQ = 16000000L
|
||||
atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega8: $(PROGRAM)_atmega8.hex
|
||||
atmega8: $(PROGRAM)_atmega8.lst
|
||||
|
||||
atmega8_isp: atmega8
|
||||
atmega8_isp: TARGET = atmega8
|
||||
atmega8_isp: MCU_TARGET = atmega8
|
||||
# SPIEN, CKOPT, Bootsize=512B
|
||||
atmega8_isp: HFUSE = CC
|
||||
# 2.7V brownout, Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega8_isp: LFUSE = BF
|
||||
atmega8_isp: isp
|
||||
|
||||
# ATmega88
|
||||
#
|
||||
atmega88: TARGET = atmega88
|
||||
atmega88: MCU_TARGET = atmega88
|
||||
atmega88: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega88: AVR_FREQ = 12000000L
|
||||
atmega88: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega88: $(PROGRAM)_atmega88.hex
|
||||
atmega88: $(PROGRAM)_atmega88.lst
|
||||
|
||||
atmega88_isp: atmega88
|
||||
atmega88_isp: TARGET = atmega88
|
||||
atmega88_isp: MCU_TARGET = atmega88
|
||||
# 2.7V brownout
|
||||
atmega88_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atemga88_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega88_isp: EFUSE = 04
|
||||
atmega88_isp: isp
|
||||
|
||||
|
||||
# 8MHz clocked platforms
|
||||
#
|
||||
# These are capable of 38400 baud
|
||||
#
|
||||
|
||||
lilypad: TARGET = lilypad
|
||||
lilypad: MCU_TARGET = atmega168
|
||||
lilypad: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad: AVR_FREQ = 8000000L
|
||||
lilypad: $(PROGRAM)_lilypad.hex
|
||||
lilypad: $(PROGRAM)_lilypad.lst
|
||||
|
||||
lilypad_isp: lilypad
|
||||
lilypad_isp: TARGET = lilypad
|
||||
# 2.7V brownout
|
||||
lilypad_isp: HFUSE = DD
|
||||
# Internal 8MHz osc (8MHz) Slow rising power
|
||||
lilypad_isp: LFUSE = E2
|
||||
# 512 byte boot
|
||||
lilypad_isp: EFUSE = 04
|
||||
lilypad_isp: isp
|
||||
|
||||
lilypad_resonator: TARGET = lilypad_resonator
|
||||
lilypad_resonator: MCU_TARGET = atmega168
|
||||
lilypad_resonator: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad_resonator: AVR_FREQ = 8000000L
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.hex
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.lst
|
||||
|
||||
lilypad_resonator_isp: lilypad_resonator
|
||||
lilypad_resonator_isp: TARGET = lilypad_resonator
|
||||
# 2.7V brownout
|
||||
lilypad_resonator_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
lilypad_resonator_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
lilypad_resonator_isp: EFUSE = 04
|
||||
lilypad_resonator_isp: isp
|
||||
|
||||
pro8: TARGET = pro_8MHz
|
||||
pro8: MCU_TARGET = atmega168
|
||||
pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro8: AVR_FREQ = 8000000L
|
||||
pro8: $(PROGRAM)_pro_8MHz.hex
|
||||
pro8: $(PROGRAM)_pro_8MHz.lst
|
||||
|
||||
pro8_isp: pro8
|
||||
pro8_isp: TARGET = pro_8MHz
|
||||
# 2.7V brownout
|
||||
pro8_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro8_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro8_isp: EFUSE = 04
|
||||
pro8_isp: isp
|
||||
|
||||
atmega328_pro8: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8: MCU_TARGET = atmega328p
|
||||
atmega328_pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega328_pro8: AVR_FREQ = 8000000L
|
||||
atmega328_pro8: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.hex
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.lst
|
||||
|
||||
atmega328_pro8_isp: atmega328_pro8
|
||||
atmega328_pro8_isp: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_pro8_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_pro8_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_pro8_isp: EFUSE = DE
|
||||
atmega328_pro8_isp: isp
|
||||
|
||||
# 1MHz clocked platforms
|
||||
#
|
||||
# These are capable of 9600 baud
|
||||
#
|
||||
|
||||
luminet: TARGET = luminet
|
||||
luminet: MCU_TARGET = attiny84
|
||||
luminet: CFLAGS += '-DLED_START_FLASHES=3' '-DSOFT_UART' '-DBAUD_RATE=9600'
|
||||
luminet: CFLAGS += '-DVIRTUAL_BOOT_PARTITION'
|
||||
luminet: AVR_FREQ = 1000000L
|
||||
luminet: LDSECTIONS = -Wl,--section-start=.text=0x1d00 -Wl,--section-start=.version=0x1efe
|
||||
luminet: $(PROGRAM)_luminet.hex
|
||||
luminet: $(PROGRAM)_luminet.lst
|
||||
|
||||
luminet_isp: luminet
|
||||
luminet_isp: TARGET = luminet
|
||||
luminet_isp: MCU_TARGET = attiny84
|
||||
# Brownout disabled
|
||||
luminet_isp: HFUSE = DF
|
||||
# 1MHz internal oscillator, slowly rising power
|
||||
luminet_isp: LFUSE = 62
|
||||
# Self-programming enable
|
||||
luminet_isp: EFUSE = FE
|
||||
luminet_isp: isp
|
||||
|
||||
#
|
||||
# Generic build instructions
|
||||
#
|
||||
#
|
||||
|
||||
isp: $(TARGET)
|
||||
$(ISPFUSES)
|
||||
$(ISPFLASH)
|
||||
|
||||
isp-stk500: $(PROGRAM)_$(TARGET).hex
|
||||
$(STK500-1)
|
||||
$(STK500-2)
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(SIZE) $@
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@
|
||||
|
||||
%.srec: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@
|
||||
848
BootLoaders/AtmegaMultiBoot/Source/boot.h
Normal file
@@ -0,0 +1,848 @@
|
||||
/* Modified to use out for SPM access
|
||||
** Peter Knight, Optiboot project http://optiboot.googlecode.com
|
||||
**
|
||||
** Todo: Tidy up
|
||||
**
|
||||
** "_short" routines execute 1 cycle faster and use 1 less word of flash
|
||||
** by using "out" instruction instead of "sts".
|
||||
**
|
||||
** Additional elpm variants that trust the value of RAMPZ
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Eric B. Weddington
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
/* $Id: boot.h,v 1.27.2.3 2008/09/30 13:58:48 arcanum Exp $ */
|
||||
|
||||
#ifndef _AVR_BOOT_H_
|
||||
#define _AVR_BOOT_H_ 1
|
||||
|
||||
/** \file */
|
||||
/** \defgroup avr_boot <avr/boot.h>: Bootloader Support Utilities
|
||||
\code
|
||||
#include <avr/io.h>
|
||||
#include <avr/boot.h>
|
||||
\endcode
|
||||
|
||||
The macros in this module provide a C language interface to the
|
||||
bootloader support functionality of certain AVR processors. These
|
||||
macros are designed to work with all sizes of flash memory.
|
||||
|
||||
Global interrupts are not automatically disabled for these macros. It
|
||||
is left up to the programmer to do this. See the code example below.
|
||||
Also see the processor datasheet for caveats on having global interrupts
|
||||
enabled during writing of the Flash.
|
||||
|
||||
\note Not all AVR processors provide bootloader support. See your
|
||||
processor datasheet to see if it provides bootloader support.
|
||||
|
||||
\todo From email with Marek: On smaller devices (all except ATmega64/128),
|
||||
__SPM_REG is in the I/O space, accessible with the shorter "in" and "out"
|
||||
instructions - since the boot loader has a limited size, this could be an
|
||||
important optimization.
|
||||
|
||||
\par API Usage Example
|
||||
The following code shows typical usage of the boot API.
|
||||
|
||||
\code
|
||||
#include <inttypes.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
void boot_program_page (uint32_t page, uint8_t *buf)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t sreg;
|
||||
|
||||
// Disable interrupts.
|
||||
|
||||
sreg = SREG;
|
||||
cli();
|
||||
|
||||
eeprom_busy_wait ();
|
||||
|
||||
boot_page_erase (page);
|
||||
boot_spm_busy_wait (); // Wait until the memory is erased.
|
||||
|
||||
for (i=0; i<SPM_PAGESIZE; i+=2)
|
||||
{
|
||||
// Set up little-endian word.
|
||||
|
||||
uint16_t w = *buf++;
|
||||
w += (*buf++) << 8;
|
||||
|
||||
boot_page_fill (page + i, w);
|
||||
}
|
||||
|
||||
boot_page_write (page); // Store buffer in flash page.
|
||||
boot_spm_busy_wait(); // Wait until the memory is written.
|
||||
|
||||
// Reenable RWW-section again. We need this if we want to jump back
|
||||
// to the application after bootloading.
|
||||
|
||||
boot_rww_enable ();
|
||||
|
||||
// Re-enable interrupts (if they were ever enabled).
|
||||
|
||||
SREG = sreg;
|
||||
}\endcode */
|
||||
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/io.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Check for SPM Control Register in processor. */
|
||||
#if defined (SPMCSR)
|
||||
# define __SPM_REG SPMCSR
|
||||
#elif defined (SPMCR)
|
||||
# define __SPM_REG SPMCR
|
||||
#else
|
||||
# error AVR processor does not provide bootloader support!
|
||||
#endif
|
||||
|
||||
|
||||
/* Check for SPM Enable bit. */
|
||||
#if defined(SPMEN)
|
||||
# define __SPM_ENABLE SPMEN
|
||||
#elif defined(SELFPRGEN)
|
||||
# define __SPM_ENABLE SELFPRGEN
|
||||
#else
|
||||
# error Cannot find SPM Enable bit definition!
|
||||
#endif
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def BOOTLOADER_SECTION
|
||||
|
||||
Used to declare a function or variable to be placed into a
|
||||
new section called .bootloader. This section and its contents
|
||||
can then be relocated to any address (such as the bootloader
|
||||
NRWW area) at link-time. */
|
||||
|
||||
#define BOOTLOADER_SECTION __attribute__ ((section (".bootloader")))
|
||||
|
||||
/* Create common bit definitions. */
|
||||
#ifdef ASB
|
||||
#define __COMMON_ASB ASB
|
||||
#else
|
||||
#define __COMMON_ASB RWWSB
|
||||
#endif
|
||||
|
||||
#ifdef ASRE
|
||||
#define __COMMON_ASRE ASRE
|
||||
#else
|
||||
#define __COMMON_ASRE RWWSRE
|
||||
#endif
|
||||
|
||||
/* Define the bit positions of the Boot Lock Bits. */
|
||||
|
||||
#define BLB12 5
|
||||
#define BLB11 4
|
||||
#define BLB02 3
|
||||
#define BLB01 2
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_interrupt_enable()
|
||||
Enable the SPM interrupt. */
|
||||
|
||||
#define boot_spm_interrupt_enable() (__SPM_REG |= (uint8_t)_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_interrupt_disable()
|
||||
Disable the SPM interrupt. */
|
||||
|
||||
#define boot_spm_interrupt_disable() (__SPM_REG &= (uint8_t)~_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_is_spm_interrupt()
|
||||
Check if the SPM interrupt is enabled. */
|
||||
|
||||
#define boot_is_spm_interrupt() (__SPM_REG & (uint8_t)_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_rww_busy()
|
||||
Check if the RWW section is busy. */
|
||||
|
||||
#define boot_rww_busy() (__SPM_REG & (uint8_t)_BV(__COMMON_ASB))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_busy()
|
||||
Check if the SPM instruction is busy. */
|
||||
|
||||
#define boot_spm_busy() (__SPM_REG & (uint8_t)_BV(__SPM_ENABLE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_busy_wait()
|
||||
Wait while the SPM instruction is busy. */
|
||||
|
||||
#define boot_spm_busy_wait() do{}while(boot_spm_busy())
|
||||
|
||||
#define __BOOT_PAGE_ERASE (_BV(__SPM_ENABLE) | _BV(PGERS))
|
||||
#define __BOOT_PAGE_WRITE (_BV(__SPM_ENABLE) | _BV(PGWRT))
|
||||
#define __BOOT_PAGE_FILL _BV(__SPM_ENABLE)
|
||||
#define __BOOT_RWW_ENABLE (_BV(__SPM_ENABLE) | _BV(__COMMON_ASRE))
|
||||
#define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(BLBSET))
|
||||
|
||||
#define __boot_page_fill_short(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_normal(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_alternate(address, data)\
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_extended(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %4\n\t" \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"r" ((uint32_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_extended_short(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %4\n\t" \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"r" ((uint32_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
|
||||
#define __boot_page_erase_normal(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_alternate(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_extended(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
#define __boot_page_erase_extended_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_normal(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_alternate(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_extended(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
#define __boot_page_write_extended_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable_short() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable_alternate() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
/* From the mega16/mega128 data sheets (maybe others):
|
||||
|
||||
Bits by SPM To set the Boot Loader Lock bits, write the desired data to
|
||||
R0, write "X0001001" to SPMCR and execute SPM within four clock cycles
|
||||
after writing SPMCR. The only accessible Lock bits are the Boot Lock bits
|
||||
that may prevent the Application and Boot Loader section from any
|
||||
software update by the MCU.
|
||||
|
||||
If bits 5..2 in R0 are cleared (zero), the corresponding Boot Lock bit
|
||||
will be programmed if an SPM instruction is executed within four cycles
|
||||
after BLBSET and SPMEN (or SELFPRGEN) are set in SPMCR. The Z-pointer is
|
||||
don't care during this operation, but for future compatibility it is
|
||||
recommended to load the Z-pointer with $0001 (same as used for reading the
|
||||
Lock bits). For future compatibility It is also recommended to set bits 7,
|
||||
6, 1, and 0 in R0 to 1 when writing the Lock bits. When programming the
|
||||
Lock bits the entire Flash can be read during the operation. */
|
||||
|
||||
#define __boot_lock_bits_set_short(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_lock_bits_set(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_lock_bits_set_alternate(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
/*
|
||||
Reading lock and fuse bits:
|
||||
|
||||
Similarly to writing the lock bits above, set BLBSET and SPMEN (or
|
||||
SELFPRGEN) bits in __SPMREG, and then (within four clock cycles) issue an
|
||||
LPM instruction.
|
||||
|
||||
Z address: contents:
|
||||
0x0000 low fuse bits
|
||||
0x0001 lock bits
|
||||
0x0002 extended fuse bits
|
||||
0x0003 high fuse bits
|
||||
|
||||
Sounds confusing, doesn't it?
|
||||
|
||||
Unlike the macros in pgmspace.h, no need to care for non-enhanced
|
||||
cores here as these old cores do not provide SPM support anyway.
|
||||
*/
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def GET_LOW_FUSE_BITS
|
||||
address to read the low fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_LOW_FUSE_BITS (0x0000)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_LOCK_BITS
|
||||
address to read the lock bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_LOCK_BITS (0x0001)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_EXTENDED_FUSE_BITS
|
||||
address to read the extended fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_EXTENDED_FUSE_BITS (0x0002)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_HIGH_FUSE_BITS
|
||||
address to read the high fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_HIGH_FUSE_BITS (0x0003)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_lock_fuse_bits_get(address)
|
||||
|
||||
Read the lock or fuse bits at \c address.
|
||||
|
||||
Parameter \c address can be any of GET_LOW_FUSE_BITS,
|
||||
GET_LOCK_BITS, GET_EXTENDED_FUSE_BITS, or GET_HIGH_FUSE_BITS.
|
||||
|
||||
\note The lock and fuse bits returned are the physical values,
|
||||
i.e. a bit returned as 0 means the corresponding fuse or lock bit
|
||||
is programmed.
|
||||
*/
|
||||
#define boot_lock_fuse_bits_get_short(address) \
|
||||
(__extension__({ \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, %3\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"out %1, %2\n\t" \
|
||||
"lpm %0, Z\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"M" (address) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
#define boot_lock_fuse_bits_get(address) \
|
||||
(__extension__({ \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, %3\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"sts %1, %2\n\t" \
|
||||
"lpm %0, Z\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"M" (address) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_signature_byte_get(address)
|
||||
|
||||
Read the Signature Row byte at \c address. For some MCU types,
|
||||
this function can also retrieve the factory-stored oscillator
|
||||
calibration bytes.
|
||||
|
||||
Parameter \c address can be 0-0x1f as documented by the datasheet.
|
||||
\note The values are MCU type dependent.
|
||||
*/
|
||||
|
||||
#define __BOOT_SIGROW_READ (_BV(__SPM_ENABLE) | _BV(SIGRD))
|
||||
|
||||
#define boot_signature_byte_get_short(addr) \
|
||||
(__extension__({ \
|
||||
uint16_t __addr16 = (uint16_t)(addr); \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %1, %2\n\t" \
|
||||
"lpm %0, Z" "\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t) __BOOT_SIGROW_READ), \
|
||||
"z" (__addr16) \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
#define boot_signature_byte_get(addr) \
|
||||
(__extension__({ \
|
||||
uint16_t __addr16 = (uint16_t)(addr); \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %1, %2\n\t" \
|
||||
"lpm %0, Z" "\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t) __BOOT_SIGROW_READ), \
|
||||
"z" (__addr16) \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_fill(address, data)
|
||||
|
||||
Fill the bootloader temporary page buffer for flash
|
||||
address with data word.
|
||||
|
||||
\note The address is a byte address. The data is a word. The AVR
|
||||
writes data to the buffer a word at a time, but addresses the buffer
|
||||
per byte! So, increment your address by 2 between calls, and send 2
|
||||
data bytes in a word format! The LSB of the data is written to the lower
|
||||
address; the MSB of the data is written to the higher address.*/
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_erase(address)
|
||||
|
||||
Erase the flash page that contains address.
|
||||
|
||||
\note address is a byte address in flash, not a word address. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_write(address)
|
||||
|
||||
Write the bootloader temporary page buffer
|
||||
to flash page that contains address.
|
||||
|
||||
\note address is a byte address in flash, not a word address. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_rww_enable()
|
||||
|
||||
Enable the Read-While-Write memory section. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_lock_bits_set(lock_bits)
|
||||
|
||||
Set the bootloader lock bits.
|
||||
|
||||
\param lock_bits A mask of which Boot Loader Lock Bits to set.
|
||||
|
||||
\note In this context, a 'set bit' will be written to a zero value.
|
||||
Note also that only BLBxx bits can be programmed by this command.
|
||||
|
||||
For example, to disallow the SPM instruction from writing to the Boot
|
||||
Loader memory section of flash, you would use this macro as such:
|
||||
|
||||
\code
|
||||
boot_lock_bits_set (_BV (BLB11));
|
||||
\endcode
|
||||
|
||||
\note Like any lock bits, the Boot Loader Lock Bits, once set,
|
||||
cannot be cleared again except by a chip erase which will in turn
|
||||
also erase the boot loader itself. */
|
||||
|
||||
/* Normal versions of the macros use 16-bit addresses.
|
||||
Extended versions of the macros use 32-bit addresses.
|
||||
Alternate versions of the macros use 16-bit addresses and require special
|
||||
instruction sequences after LPM.
|
||||
|
||||
FLASHEND is defined in the ioXXXX.h file.
|
||||
USHRT_MAX is defined in <limits.h>. */
|
||||
|
||||
#if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \
|
||||
|| defined(__AVR_ATmega323__)
|
||||
|
||||
/* Alternate: ATmega161/163/323 and 16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_alternate(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_alternate(address)
|
||||
#define boot_page_write(address) __boot_page_write_alternate(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_alternate()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits)
|
||||
|
||||
#elif (FLASHEND > USHRT_MAX)
|
||||
|
||||
/* Extended: >16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_extended_short(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_extended_short(address)
|
||||
#define boot_page_write(address) __boot_page_write_extended_short(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_short()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
|
||||
|
||||
#else
|
||||
|
||||
/* Normal: 16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_short(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_short(address)
|
||||
#define boot_page_write(address) __boot_page_write_short(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_short()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
|
||||
|
||||
#endif
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_fill() except it waits for eeprom and spm operations to
|
||||
complete before filling the page. */
|
||||
|
||||
#define boot_page_fill_safe(address, data) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_fill(address, data); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_erase() except it waits for eeprom and spm operations to
|
||||
complete before erasing the page. */
|
||||
|
||||
#define boot_page_erase_safe(address) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_erase (address); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_write() except it waits for eeprom and spm operations to
|
||||
complete before writing the page. */
|
||||
|
||||
#define boot_page_write_safe(address) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_write (address); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_rww_enable() except waits for eeprom and spm operations to
|
||||
complete before enabling the RWW mameory. */
|
||||
|
||||
#define boot_rww_enable_safe() \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_rww_enable(); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_lock_bits_set() except waits for eeprom and spm operations to
|
||||
complete before setting the lock bits. */
|
||||
|
||||
#define boot_lock_bits_set_safe(lock_bits) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_lock_bits_set (lock_bits); \
|
||||
} while (0)
|
||||
|
||||
#endif /* _AVR_BOOT_H_ */
|
||||
891
BootLoaders/AtmegaMultiBoot/Source/optiboot.c
Normal file
@@ -0,0 +1,891 @@
|
||||
/**********************************************************/
|
||||
/* Optiboot bootloader for Arduino */
|
||||
/* */
|
||||
/* http://optiboot.googlecode.com */
|
||||
/* */
|
||||
/* Arduino-maintained version : See README.TXT */
|
||||
/* http://code.google.com/p/arduino/ */
|
||||
/* It is the intent that changes not relevant to the */
|
||||
/* Arduino production envionment get moved from the */
|
||||
/* optiboot project to the arduino project in "lumps." */
|
||||
/* */
|
||||
/* Heavily optimised bootloader that is faster and */
|
||||
/* smaller than the Arduino standard bootloader */
|
||||
/* */
|
||||
/* Enhancements: */
|
||||
/* Fits in 512 bytes, saving 1.5K of code space */
|
||||
/* Background page erasing speeds up programming */
|
||||
/* Higher baud rate speeds up programming */
|
||||
/* Written almost entirely in C */
|
||||
/* Customisable timeout with accurate timeconstant */
|
||||
/* Optional virtual UART. No hardware UART required. */
|
||||
/* Optional virtual boot partition for devices without. */
|
||||
/* */
|
||||
/* What you lose: */
|
||||
/* Implements a skeleton STK500 protocol which is */
|
||||
/* missing several features including EEPROM */
|
||||
/* programming and non-page-aligned writes */
|
||||
/* High baud rate breaks compatibility with standard */
|
||||
/* Arduino flash settings */
|
||||
/* */
|
||||
/* Fully supported: */
|
||||
/* ATmega168 based devices (Diecimila etc) */
|
||||
/* ATmega328P based devices (Duemilanove etc) */
|
||||
/* */
|
||||
/* Beta test (believed working.) */
|
||||
/* ATmega8 based devices (Arduino legacy) */
|
||||
/* ATmega328 non-picopower devices */
|
||||
/* ATmega644P based devices (Sanguino) */
|
||||
/* ATmega1284P based devices */
|
||||
/* */
|
||||
/* Alpha test */
|
||||
/* ATmega1280 based devices (Arduino Mega) */
|
||||
/* */
|
||||
/* Work in progress: */
|
||||
/* ATtiny84 based devices (Luminet) */
|
||||
/* */
|
||||
/* Does not support: */
|
||||
/* USB based devices (eg. Teensy) */
|
||||
/* */
|
||||
/* Assumptions: */
|
||||
/* The code makes several assumptions that reduce the */
|
||||
/* code size. They are all true after a hardware reset, */
|
||||
/* but may not be true if the bootloader is called by */
|
||||
/* other means or on other hardware. */
|
||||
/* No interrupts can occur */
|
||||
/* UART and Timer 1 are set to their reset state */
|
||||
/* SP points to RAMEND */
|
||||
/* */
|
||||
/* Code builds on code, libraries and optimisations from: */
|
||||
/* stk500boot.c by Jason P. Kyle */
|
||||
/* Arduino bootloader http://arduino.cc */
|
||||
/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
|
||||
/* avr-libc project http://nongnu.org/avr-libc */
|
||||
/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */
|
||||
/* AVR305 Atmel Application Note */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it */
|
||||
/* and/or modify it under the terms of the GNU General */
|
||||
/* Public License as published by the Free Software */
|
||||
/* Foundation; either version 2 of the License, or */
|
||||
/* (at your option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will */
|
||||
/* be useful, but WITHOUT ANY WARRANTY; without even the */
|
||||
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
|
||||
/* PARTICULAR PURPOSE. See the GNU General Public */
|
||||
/* License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General */
|
||||
/* Public License along with this program; if not, write */
|
||||
/* to the Free Software Foundation, Inc., */
|
||||
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
/* */
|
||||
/* Licence can be viewed at */
|
||||
/* http://www.fsf.org/licenses/gpl.txt */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* Optional defines: */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* BIG_BOOT: */
|
||||
/* Build a 1k bootloader, not 512 bytes. This turns on */
|
||||
/* extra functionality. */
|
||||
/* */
|
||||
/* BAUD_RATE: */
|
||||
/* Set bootloader baud rate. */
|
||||
/* */
|
||||
/* LUDICROUS_SPEED: */
|
||||
/* 230400 baud :-) */
|
||||
/* */
|
||||
/* SOFT_UART: */
|
||||
/* Use AVR305 soft-UART instead of hardware UART. */
|
||||
/* */
|
||||
/* LED_START_FLASHES: */
|
||||
/* Number of LED flashes on bootup. */
|
||||
/* */
|
||||
/* LED_DATA_FLASH: */
|
||||
/* Flash LED when transferring data. For boards without */
|
||||
/* TX or RX LEDs, or for people who like blinky lights. */
|
||||
/* */
|
||||
/* SUPPORT_EEPROM: */
|
||||
/* Support reading and writing from EEPROM. This is not */
|
||||
/* used by Arduino, so off by default. */
|
||||
/* */
|
||||
/* TIMEOUT_MS: */
|
||||
/* Bootloader timeout period, in milliseconds. */
|
||||
/* 500,1000,2000,4000,8000 supported. */
|
||||
/* */
|
||||
/* UART: */
|
||||
/* UART number (0..n) for devices with more than */
|
||||
/* one hardware uart (644P, 1284P, etc) */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Version Numbers! */
|
||||
/* */
|
||||
/* Arduino Optiboot now includes this Version number in */
|
||||
/* the source and object code. */
|
||||
/* */
|
||||
/* Version 3 was released as zip from the optiboot */
|
||||
/* repository and was distributed with Arduino 0022. */
|
||||
/* Version 4 starts with the arduino repository commit */
|
||||
/* that brought the arduino repository up-to-date with */
|
||||
/* the optiboot source tree changes since v3. */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Edit History: */
|
||||
/* */
|
||||
/* Nov 2012 */
|
||||
/* Specific version for 9x voice module */
|
||||
/* by Mike Blandford */
|
||||
/* Mar 2012 */
|
||||
/* 4.5 WestfW: add infrastructure for non-zero UARTS. */
|
||||
/* 4.5 WestfW: fix SIGNATURE_2 for m644 (bad in avr-libc) */
|
||||
/* Jan 2012: */
|
||||
/* 4.5 WestfW: fix NRWW value for m1284. */
|
||||
/* 4.4 WestfW: use attribute OS_main instead of naked for */
|
||||
/* main(). This allows optimizations that we */
|
||||
/* count on, which are prohibited in naked */
|
||||
/* functions due to PR42240. (keeps us less */
|
||||
/* than 512 bytes when compiler is gcc4.5 */
|
||||
/* (code from 4.3.2 remains the same.) */
|
||||
/* 4.4 WestfW and Maniacbug: Add m1284 support. This */
|
||||
/* does not change the 328 binary, so the */
|
||||
/* version number didn't change either. (?) */
|
||||
/* June 2011: */
|
||||
/* 4.4 WestfW: remove automatic soft_uart detect (didn't */
|
||||
/* know what it was doing or why.) Added a */
|
||||
/* check of the calculated BRG value instead. */
|
||||
/* Version stays 4.4; existing binaries are */
|
||||
/* not changed. */
|
||||
/* 4.4 WestfW: add initialization of address to keep */
|
||||
/* the compiler happy. Change SC'ed targets. */
|
||||
/* Return the SW version via READ PARAM */
|
||||
/* 4.3 WestfW: catch framing errors in getch(), so that */
|
||||
/* AVRISP works without HW kludges. */
|
||||
/* http://code.google.com/p/arduino/issues/detail?id=368n*/
|
||||
/* 4.2 WestfW: reduce code size, fix timeouts, change */
|
||||
/* verifySpace to use WDT instead of appstart */
|
||||
/* 4.1 WestfW: put version number in binary. */
|
||||
/**********************************************************/
|
||||
|
||||
#define OPTIBOOT_MAJVER 4
|
||||
#define OPTIBOOT_MINVER 5
|
||||
|
||||
#define MULTI_CALLED 1
|
||||
|
||||
#define MAKESTR(a) #a
|
||||
#define MAKEVER(a, b) MAKESTR(a*256+b)
|
||||
|
||||
//asm(" .section .version\n"
|
||||
// "optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n"
|
||||
// " .section .text\n");
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// <avr/boot.h> uses sts instructions, but this version uses out instructions
|
||||
// This saves cycles and program memory.
|
||||
#include "boot.h"
|
||||
|
||||
|
||||
// We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
|
||||
|
||||
#include "pin_defs.h"
|
||||
#include "stk500.h"
|
||||
|
||||
#ifndef LED_START_FLASHES
|
||||
#define LED_START_FLASHES 0
|
||||
#endif
|
||||
|
||||
#ifdef LUDICROUS_SPEED
|
||||
#define BAUD_RATE 230400L
|
||||
#endif
|
||||
|
||||
/* set the UART baud rate defaults */
|
||||
#ifndef BAUD_RATE
|
||||
#if F_CPU >= 8000000L
|
||||
#define BAUD_RATE 38400L // Highest rate Avrdude win32 will support
|
||||
#elsif F_CPU >= 1000000L
|
||||
#define BAUD_RATE 9600L // 19200 also supported, but with significant error
|
||||
#elsif F_CPU >= 128000L
|
||||
#define BAUD_RATE 4800L // Good for 128kHz internal RC
|
||||
#else
|
||||
#define BAUD_RATE 1200L // Good even at 32768Hz
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef UART
|
||||
#define UART 0
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Switch in soft UART for hard baud rates */
|
||||
/*
|
||||
* I don't understand what this was supposed to accomplish, where the
|
||||
* constant "280" came from, or why automatically (and perhaps unexpectedly)
|
||||
* switching to a soft uart is a good thing, so I'm undoing this in favor
|
||||
* of a range check using the same calc used to config the BRG...
|
||||
*/
|
||||
#if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz
|
||||
#ifndef SOFT_UART
|
||||
#define SOFT_UART
|
||||
#endif
|
||||
#endif
|
||||
#else // 0
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250
|
||||
#error Unachievable baud rate (too slow) BAUD_RATE
|
||||
#endif // baud rate slow check
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3
|
||||
#error Unachievable baud rate (too fast) BAUD_RATE
|
||||
#endif // baud rate fastn check
|
||||
#endif
|
||||
|
||||
/* Watchdog settings */
|
||||
#define WATCHDOG_OFF (0)
|
||||
#define WATCHDOG_16MS (_BV(WDE))
|
||||
#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE))
|
||||
#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#ifndef __AVR_ATmega8__
|
||||
#define WATCHDOG_4S (_BV(WDP3) | _BV(WDE))
|
||||
#define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
|
||||
#endif
|
||||
|
||||
/* Function Prototypes */
|
||||
/* The main function is in init9, which removes the interrupt vector table */
|
||||
/* we don't need. It is also 'naked', which means the compiler does not */
|
||||
/* generate any entry or exit code itself. */
|
||||
int main(void) __attribute__ ((OS_main)) __attribute__ ((noreturn)) __attribute__ ((section (".init9")));
|
||||
void putch(char);
|
||||
uint8_t getch(void);
|
||||
static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */
|
||||
void verifySpace();
|
||||
#if LED_START_FLASHES > 0
|
||||
static inline void flash_led(uint8_t);
|
||||
#endif
|
||||
uint8_t getLen();
|
||||
//static inline void watchdogReset();
|
||||
void watchdogConfig(uint8_t x);
|
||||
#ifdef SOFT_UART
|
||||
void uartDelay() __attribute__ ((naked));
|
||||
#endif
|
||||
static void appStart() ; // __attribute__ ((naked));
|
||||
|
||||
/*
|
||||
* NRWW memory
|
||||
* Addresses below NRWW (Non-Read-While-Write) can be programmed while
|
||||
* continuing to run code from flash, slightly speeding up programming
|
||||
* time. Beware that Atmel data sheets specify this as a WORD address,
|
||||
* while optiboot will be comparing against a 16-bit byte address. This
|
||||
* means that on a part with 128kB of memory, the upper part of the lower
|
||||
* 64k will get NRWW processing as well, even though it doesn't need it.
|
||||
* That's OK. In fact, you can disable the overlapping processing for
|
||||
* a part entirely by setting NRWWSTART to zero. This reduces code
|
||||
* space a bit, at the expense of being slightly slower, overall.
|
||||
*
|
||||
* RAMSTART should be self-explanatory. It's bigger on parts with a
|
||||
* lot of peripheral registers.
|
||||
*/
|
||||
#if defined(__AVR_ATmega168__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x3800)
|
||||
#elif defined(__AVR_ATmega328P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined(__AVR_ATmega328__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined (__AVR_ATmega644P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
// correct for a bug in avr-libc
|
||||
#undef SIGNATURE_2
|
||||
#define SIGNATURE_2 0x0A
|
||||
#elif defined (__AVR_ATmega1284P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATtiny84__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x0000)
|
||||
#elif defined(__AVR_ATmega1280__)
|
||||
#define RAMSTART (0x200)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x1800)
|
||||
#endif
|
||||
|
||||
/* C zero initialises all global variables. However, that requires */
|
||||
/* These definitions are NOT zero initialised, but that doesn't matter */
|
||||
/* This allows us to drop the zero init code, saving us memory */
|
||||
#define buff ((uint8_t*)(RAMSTART))
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
#define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4))
|
||||
#define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle devices with up to 4 uarts (eg m1280.) Rather inelegantly.
|
||||
* Note that mega8 still needs special handling, because ubrr is handled
|
||||
* differently.
|
||||
*/
|
||||
#if UART == 0
|
||||
# define UART_SRA UCSR0A
|
||||
# define UART_SRB UCSR0B
|
||||
# define UART_SRC UCSR0C
|
||||
# define UART_SRL UBRR0L
|
||||
# define UART_UDR UDR0
|
||||
#elif UART == 1
|
||||
# define UART_SRA UCSR1A
|
||||
# define UART_SRB UCSR1B
|
||||
# define UART_SRC UCSR1C
|
||||
# define UART_SRL UBRR1L
|
||||
# define UART_UDR UDR1
|
||||
#elif UART == 2
|
||||
# define UART_SRA UCSR2A
|
||||
# define UART_SRB UCSR2B
|
||||
# define UART_SRC UCSR2C
|
||||
# define UART_SRL UBRR2L
|
||||
# define UART_UDR UDR2
|
||||
#elif UART == 3
|
||||
# define UART_SRA UCSR3A
|
||||
# define UART_SRB UCSR3B
|
||||
# define UART_SRC UCSR3C
|
||||
# define UART_SRL UBRR3L
|
||||
# define UART_UDR UDR3
|
||||
#endif
|
||||
|
||||
/* main program starts here */
|
||||
int main(void) {
|
||||
uint8_t ch;
|
||||
|
||||
/*
|
||||
* Making these local and in registers prevents the need for initializing
|
||||
* them, and also saves space because code no longer stores to memory.
|
||||
* (initializing address keeps the compiler happy, but isn't really
|
||||
* necessary, and uses 4 bytes of flash.)
|
||||
*/
|
||||
register uint16_t address = 0;
|
||||
|
||||
// After the zero init loop, this is the first code to run.
|
||||
//
|
||||
// This code makes the following assumptions:
|
||||
// No interrupts will execute
|
||||
// SP points to RAMEND
|
||||
// r1 contains zero
|
||||
//
|
||||
// If not, uncomment the following instructions:
|
||||
// cli();
|
||||
asm volatile ("clr __zero_reg__");
|
||||
#ifdef __AVR_ATmega8__
|
||||
SP=RAMEND; // This is done by hardware reset
|
||||
#endif
|
||||
|
||||
// Adaboot no-wait mod
|
||||
ch = MCUSR;
|
||||
MCUSR = 0;
|
||||
|
||||
// Here, if power on, wait 0.5 secs, then check for
|
||||
// serial Rx signal low, if so, stay in bootloader
|
||||
// else go to application
|
||||
|
||||
PORTD = 0xFF ;
|
||||
PORTB = 0x3C ;
|
||||
PORTC = 1 ;
|
||||
|
||||
if (ch & (_BV(PORF) | (_BV(EXTRF)) ) )
|
||||
{
|
||||
#ifdef MULTI_CALLED
|
||||
#if F_CPU == 12000000L
|
||||
TCNT1H = 256 - 8 ;
|
||||
#else
|
||||
#if F_CPU == 16000000L
|
||||
TCNT1H = 256 - 6 ;
|
||||
#else
|
||||
TCNT1H = 256 - 127 ;
|
||||
#endif
|
||||
TCNT1L = 0 ;
|
||||
#endif
|
||||
#else
|
||||
#if F_CPU == 12000000L
|
||||
TCNT1 = 65535-5859 ;
|
||||
#else
|
||||
#if F_CPU == 16000000L
|
||||
TCNT1 = 65535-7813 ;
|
||||
#else
|
||||
TCNT1 = 65535-32767 ;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
|
||||
TIFR1 = _BV(TOV1);
|
||||
while(!(TIFR1 & _BV(TOV1)))
|
||||
;
|
||||
TCCR1B = 0 ; // Stop timer
|
||||
uint8_t x ;
|
||||
x = PINB & 0x3C ;
|
||||
x |= PINC & 1 ;
|
||||
if ( x != 0x1D )
|
||||
{
|
||||
appStart() ; // Power on, go to voice application
|
||||
// if loaded
|
||||
}
|
||||
}
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
// Set up Timer 1 for timeout counter
|
||||
TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
|
||||
#endif
|
||||
|
||||
#ifndef SOFT_UART
|
||||
UART_SRA = _BV(U2X0); //Double speed mode USART0
|
||||
UART_SRB = _BV(RXEN0) | _BV(TXEN0);
|
||||
UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
|
||||
// UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
|
||||
// Baudrate of 57600
|
||||
#if F_CPU == 12000000L
|
||||
UART_SRL = 25 ;
|
||||
#else
|
||||
#if F_CPU == 16000000L
|
||||
UART_SRL = 33 ;
|
||||
#else
|
||||
#ERROR Baud rate not available
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Set up watchdog to trigger after 500ms
|
||||
|
||||
|
||||
// watchdogConfig(WATCHDOG_1S);
|
||||
|
||||
/* Set LED pin as output */
|
||||
LED_DDR |= _BV(LED);
|
||||
|
||||
#ifdef SOFT_UART
|
||||
/* Set TX pin as output */
|
||||
UART_DDR |= _BV(UART_TX_BIT);
|
||||
#endif
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
/* Flash onboard LED to signal entering of bootloader */
|
||||
flash_led(LED_START_FLASHES * 2);
|
||||
#endif
|
||||
|
||||
/* Forever loop */
|
||||
for (;;)
|
||||
{
|
||||
/* get character from UART */
|
||||
ch = getch();
|
||||
|
||||
if(ch == STK_GET_PARAMETER)
|
||||
{
|
||||
GPIOR0 = getch();
|
||||
verifySpace();
|
||||
if (GPIOR0 == 0x82)
|
||||
{
|
||||
/*
|
||||
* Send optiboot version as "minor SW version"
|
||||
*/
|
||||
putch(OPTIBOOT_MINVER);
|
||||
}
|
||||
else if (GPIOR0 == 0x81)
|
||||
{
|
||||
putch(OPTIBOOT_MAJVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* GET PARAMETER returns a generic 0x03 reply for
|
||||
* other parameters - enough to keep Avrdude happy
|
||||
*/
|
||||
putch(0x03);
|
||||
}
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE) {
|
||||
// SET DEVICE is ignored
|
||||
getNch(20);
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE_EXT)
|
||||
{
|
||||
// SET DEVICE EXT is ignored
|
||||
getNch(5);
|
||||
}
|
||||
else if(ch == STK_LOAD_ADDRESS)
|
||||
{
|
||||
// LOAD ADDRESS
|
||||
uint16_t newAddress;
|
||||
newAddress = getch() ;
|
||||
newAddress = (newAddress & 0xff) | (getch() << 8);
|
||||
#ifdef RAMPZ
|
||||
// Transfer top bit to RAMPZ
|
||||
RAMPZ = (newAddress & 0x8000) ? 1 : 0;
|
||||
#endif
|
||||
newAddress += newAddress; // Convert from word address to byte address
|
||||
address = newAddress;
|
||||
verifySpace();
|
||||
}
|
||||
else if(ch == STK_UNIVERSAL)
|
||||
{
|
||||
// UNIVERSAL command is ignored
|
||||
getNch(4);
|
||||
putch(0x00);
|
||||
}
|
||||
/* Write memory, length is big endian and is in bytes */
|
||||
else if(ch == STK_PROG_PAGE)
|
||||
{
|
||||
// PROGRAM PAGE - we support flash programming only, not EEPROM
|
||||
uint8_t *bufPtr;
|
||||
uint16_t addrPtr;
|
||||
register uint8_t length;
|
||||
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
// If we are in RWW section, immediately start page erase
|
||||
if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
|
||||
// While that is going on, read in page contents
|
||||
bufPtr = buff;
|
||||
do *bufPtr++ = getch();
|
||||
while (--length);
|
||||
|
||||
// If we are in NRWW section, page erase has to be delayed until now.
|
||||
// Todo: Take RAMPZ into account
|
||||
#ifdef MULTI_CALLED
|
||||
if (address < 0x7E00)
|
||||
#endif
|
||||
{
|
||||
if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
}
|
||||
// Read command terminator, start reply
|
||||
verifySpace();
|
||||
|
||||
// If only a partial page is to be programmed, the erase might not be complete.
|
||||
// So check that here
|
||||
#ifdef MULTI_CALLED
|
||||
if (address < 0x7E00)
|
||||
#endif
|
||||
{
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
if ((uint16_t)(void*)address == 0) {
|
||||
// This is the reset vector page. We need to live-patch the code so the
|
||||
// bootloader runs.
|
||||
//
|
||||
// Move RESET vector to WDT vector
|
||||
uint16_t vect = buff[0] | (buff[1]<<8);
|
||||
rstVect = vect;
|
||||
wdtVect = buff[8] | (buff[9]<<8);
|
||||
vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
|
||||
buff[8] = vect & 0xff;
|
||||
buff[9] = vect >> 8;
|
||||
|
||||
// Add jump to bootloader at RESET vector
|
||||
buff[0] = 0x7f;
|
||||
buff[1] = 0xce; // rjmp 0x1d00 instruction
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy buffer into programming buffer
|
||||
bufPtr = buff;
|
||||
addrPtr = (uint16_t)(void*)address;
|
||||
ch = SPM_PAGESIZE / 2;
|
||||
do {
|
||||
uint16_t a;
|
||||
// a = *bufPtr++;
|
||||
// a |= (*bufPtr++) << 8;
|
||||
|
||||
a = *((uint16_t *)bufPtr) ;
|
||||
bufPtr += 2 ;
|
||||
|
||||
__boot_page_fill_short((uint16_t)(void*)addrPtr,a);
|
||||
addrPtr += 2;
|
||||
} while (--ch);
|
||||
|
||||
// Write from programming buffer
|
||||
__boot_page_write_short((uint16_t)(void*)address);
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#if defined(RWWSRE)
|
||||
// Reenable read access to flash
|
||||
boot_rww_enable();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Read memory block mode, length is big endian. */
|
||||
else if(ch == STK_READ_PAGE)
|
||||
{
|
||||
register uint8_t length;
|
||||
// READ PAGE - we only read flash
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
verifySpace();
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
do {
|
||||
// Undo vector patch in bottom page so verify passes
|
||||
if (address == 0) ch=rstVect & 0xff;
|
||||
else if (address == 1) ch=rstVect >> 8;
|
||||
else if (address == 8) ch=wdtVect & 0xff;
|
||||
else if (address == 9) ch=wdtVect >> 8;
|
||||
else ch = pgm_read_byte_near(address);
|
||||
address++;
|
||||
putch(ch);
|
||||
} while (--length);
|
||||
#else
|
||||
#ifdef RAMPZ
|
||||
// Since RAMPZ should already be set, we need to use EPLM directly.
|
||||
// do putch(pgm_read_byte_near(address++));
|
||||
// while (--length);
|
||||
do {
|
||||
uint8_t result;
|
||||
__asm__ ("elpm %0,Z\n":"=r"(result):"z"(address));
|
||||
putch(result);
|
||||
address++;
|
||||
}
|
||||
while (--length);
|
||||
#else
|
||||
do putch(pgm_read_byte_near(address++));
|
||||
while (--length);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get device signature bytes */
|
||||
else if(ch == STK_READ_SIGN)
|
||||
{
|
||||
// READ SIGN - return what Avrdude wants to hear
|
||||
verifySpace();
|
||||
putch(SIGNATURE_0);
|
||||
putch(SIGNATURE_1);
|
||||
putch(SIGNATURE_2);
|
||||
}
|
||||
else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
|
||||
// Adaboot no-wait mod
|
||||
|
||||
// watchdogConfig(WATCHDOG_16MS);
|
||||
|
||||
verifySpace();
|
||||
#ifdef MULTI_CALLED
|
||||
putch(STK_OK);
|
||||
while (!(UART_SRA & _BV(TXC0)));
|
||||
appStart() ;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// This covers the response to commands like STK_ENTER_PROGMODE
|
||||
verifySpace();
|
||||
}
|
||||
putch(STK_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void putch(char ch) {
|
||||
#ifndef SOFT_UART
|
||||
while (!(UART_SRA & _BV(UDRE0)));
|
||||
UART_UDR = ch;
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
" com %[ch]\n" // ones complement, carry set
|
||||
" sec\n"
|
||||
"1: brcc 2f\n"
|
||||
" cbi %[uartPort],%[uartBit]\n"
|
||||
" rjmp 3f\n"
|
||||
"2: sbi %[uartPort],%[uartBit]\n"
|
||||
" nop\n"
|
||||
"3: rcall uartDelay\n"
|
||||
" rcall uartDelay\n"
|
||||
" lsr %[ch]\n"
|
||||
" dec %[bitcnt]\n"
|
||||
" brne 1b\n"
|
||||
:
|
||||
:
|
||||
[bitcnt] "d" (10),
|
||||
[ch] "r" (ch),
|
||||
[uartPort] "I" (_SFR_IO_ADDR(UART_PORT)),
|
||||
[uartBit] "I" (UART_TX_BIT)
|
||||
:
|
||||
"r25"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t getch(void) {
|
||||
uint8_t ch;
|
||||
|
||||
#ifdef LED_DATA_FLASH
|
||||
#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
#else
|
||||
LED_PIN |= _BV(LED);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SOFT_UART
|
||||
__asm__ __volatile__ (
|
||||
"1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge
|
||||
" rjmp 1b\n"
|
||||
" rcall uartDelay\n" // Get to middle of start bit
|
||||
"2: rcall uartDelay\n" // Wait 1 bit period
|
||||
" rcall uartDelay\n" // Wait 1 bit period
|
||||
" clc\n"
|
||||
" sbic %[uartPin],%[uartBit]\n"
|
||||
" sec\n"
|
||||
" dec %[bitCnt]\n"
|
||||
" breq 3f\n"
|
||||
" ror %[ch]\n"
|
||||
" rjmp 2b\n"
|
||||
"3:\n"
|
||||
:
|
||||
[ch] "=r" (ch)
|
||||
:
|
||||
[bitCnt] "d" (9),
|
||||
[uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
|
||||
[uartBit] "I" (UART_RX_BIT)
|
||||
:
|
||||
"r25"
|
||||
);
|
||||
#else
|
||||
while(!(UART_SRA & _BV(RXC0)))
|
||||
|
||||
// watchdogReset()
|
||||
|
||||
;
|
||||
// if (!(UART_SRA & _BV(FE0))) {
|
||||
/*
|
||||
* A Framing Error indicates (probably) that something is talking
|
||||
* to us at the wrong bit rate. Assume that this is because it
|
||||
* expects to be talking to the application, and DON'T reset the
|
||||
* watchdog. This should cause the bootloader to abort and run
|
||||
* the application "soon", if it keeps happening. (Note that we
|
||||
* don't care that an invalid char is returned...)
|
||||
*/
|
||||
// watchdogReset();
|
||||
// }
|
||||
|
||||
ch = UART_UDR;
|
||||
#endif
|
||||
|
||||
#ifdef LED_DATA_FLASH
|
||||
#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
#else
|
||||
LED_PIN |= _BV(LED);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
#ifdef SOFT_UART
|
||||
// AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
|
||||
// Adding 3 to numerator simulates nearest rounding for more accurate baud rates
|
||||
#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
|
||||
#if UART_B_VALUE > 255
|
||||
#error Baud rate too slow for soft UART
|
||||
#endif
|
||||
|
||||
void uartDelay() {
|
||||
__asm__ __volatile__ (
|
||||
"ldi r25,%[count]\n"
|
||||
"1:dec r25\n"
|
||||
"brne 1b\n"
|
||||
"ret\n"
|
||||
::[count] "M" (UART_B_VALUE)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
void getNch(uint8_t count) {
|
||||
do getch(); while (--count);
|
||||
verifySpace();
|
||||
}
|
||||
|
||||
void verifySpace()
|
||||
{
|
||||
if ( getch() != CRC_EOP) {
|
||||
|
||||
putch(STK_NOSYNC);
|
||||
// watchdogConfig(WATCHDOG_16MS); // shorten WD timeout
|
||||
//
|
||||
// while (1) // and busy-loop so that WD causes
|
||||
// ; // a reset and app start.
|
||||
}
|
||||
putch(STK_INSYNC);
|
||||
}
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
void flash_led(uint8_t count) {
|
||||
do {
|
||||
TCNT1 = -(F_CPU/(1024*16));
|
||||
TIFR1 = _BV(TOV1);
|
||||
while(!(TIFR1 & _BV(TOV1)));
|
||||
//#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
watchdogReset();
|
||||
} while (--count);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Watchdog functions. These are only safe with interrupts turned off.
|
||||
void watchdogReset() {
|
||||
__asm__ __volatile__ (
|
||||
"wdr\n"
|
||||
);
|
||||
}
|
||||
|
||||
void watchdogConfig(uint8_t x) {
|
||||
WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||
WDTCSR = x;
|
||||
}
|
||||
|
||||
void appStart()
|
||||
{
|
||||
// watchdogConfig(WATCHDOG_OFF);
|
||||
// __asm__ __volatile__ (
|
||||
//#ifdef VIRTUAL_BOOT_PARTITION
|
||||
// // Jump to WDT vector
|
||||
// "ldi r30,4\n"
|
||||
// "clr r31\n"
|
||||
//#else
|
||||
// // Jump to RST vector
|
||||
// "clr r30\n"
|
||||
// "clr r31\n"
|
||||
//#endif
|
||||
// "ijmp\n"
|
||||
// );
|
||||
|
||||
register void (*p)() ;
|
||||
p = 0 ;
|
||||
|
||||
if ( pgm_read_byte( (uint16_t)p ) != 0xFF )
|
||||
{
|
||||
(*p)() ;
|
||||
}
|
||||
}
|
||||
|
||||
80
BootLoaders/AtmegaMultiBoot/Source/pin_defs.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB5
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega8__)
|
||||
//Name conversion R.Wiersma
|
||||
#define UCSR0A UCSRA
|
||||
#define UDR0 UDR
|
||||
#define UDRE0 UDRE
|
||||
#define RXC0 RXC
|
||||
#define FE0 FE
|
||||
#define TIFR1 TIFR
|
||||
#define WDTCSR WDTCR
|
||||
#endif
|
||||
|
||||
/* Luminet support */
|
||||
#if defined(__AVR_ATtiny84__)
|
||||
/* Red LED is connected to pin PA4 */
|
||||
#define LED_DDR DDRA
|
||||
#define LED_PORT PORTA
|
||||
#define LED_PIN PINA
|
||||
#define LED PINA4
|
||||
/* Ports for soft UART - left port only for now. TX/RX on PA2/PA3 */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTA
|
||||
#define UART_PIN PINA
|
||||
#define UART_DDR DDRA
|
||||
#define UART_TX_BIT 2
|
||||
#define UART_RX_BIT 3
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Sanguino support */
|
||||
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
|
||||
/* Onboard LED is connected to pin PB0 on Sanguino */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB0
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Mega support */
|
||||
#if defined(__AVR_ATmega1280__)
|
||||
/* Onboard LED is connected to pin PB7 on Arduino Mega */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB7
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTE
|
||||
#define UART_PIN PINE
|
||||
#define UART_DDR DDRE
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
39
BootLoaders/AtmegaMultiBoot/Source/stk500.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* STK500 constants list, from AVRDUDE */
|
||||
#define STK_OK 0x10
|
||||
#define STK_FAILED 0x11 // Not used
|
||||
#define STK_UNKNOWN 0x12 // Not used
|
||||
#define STK_NODEVICE 0x13 // Not used
|
||||
#define STK_INSYNC 0x14 // ' '
|
||||
#define STK_NOSYNC 0x15 // Not used
|
||||
#define ADC_CHANNEL_ERROR 0x16 // Not used
|
||||
#define ADC_MEASURE_OK 0x17 // Not used
|
||||
#define PWM_CHANNEL_ERROR 0x18 // Not used
|
||||
#define PWM_ADJUST_OK 0x19 // Not used
|
||||
#define CRC_EOP 0x20 // 'SPACE'
|
||||
#define STK_GET_SYNC 0x30 // '0'
|
||||
#define STK_GET_SIGN_ON 0x31 // '1'
|
||||
#define STK_SET_PARAMETER 0x40 // '@'
|
||||
#define STK_GET_PARAMETER 0x41 // 'A'
|
||||
#define STK_SET_DEVICE 0x42 // 'B'
|
||||
#define STK_SET_DEVICE_EXT 0x45 // 'E'
|
||||
#define STK_ENTER_PROGMODE 0x50 // 'P'
|
||||
#define STK_LEAVE_PROGMODE 0x51 // 'Q'
|
||||
#define STK_CHIP_ERASE 0x52 // 'R'
|
||||
#define STK_CHECK_AUTOINC 0x53 // 'S'
|
||||
#define STK_LOAD_ADDRESS 0x55 // 'U'
|
||||
#define STK_UNIVERSAL 0x56 // 'V'
|
||||
#define STK_PROG_FLASH 0x60 // '`'
|
||||
#define STK_PROG_DATA 0x61 // 'a'
|
||||
#define STK_PROG_FUSE 0x62 // 'b'
|
||||
#define STK_PROG_LOCK 0x63 // 'c'
|
||||
#define STK_PROG_PAGE 0x64 // 'd'
|
||||
#define STK_PROG_FUSE_EXT 0x65 // 'e'
|
||||
#define STK_READ_FLASH 0x70 // 'p'
|
||||
#define STK_READ_DATA 0x71 // 'q'
|
||||
#define STK_READ_FUSE 0x72 // 'r'
|
||||
#define STK_READ_LOCK 0x73 // 's'
|
||||
#define STK_READ_PAGE 0x74 // 't'
|
||||
#define STK_READ_SIGN 0x75 // 'u'
|
||||
#define STK_READ_OSCCAL 0x76 // 'v'
|
||||
#define STK_READ_FUSE_EXT 0x77 // 'w'
|
||||
#define STK_READ_OSCCAL_EXT 0x78 // 'x'
|
||||
5
BootLoaders/Boards/Linux/45-maple.rules
Normal file
@@ -0,0 +1,5 @@
|
||||
ATTRS{idProduct}=="1001", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idProduct}=="1002", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idProduct}=="0003", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
ATTRS{idProduct}=="0004", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
|
||||
11
BootLoaders/Boards/Windows/install_drivers.bat
Normal file
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
|
||||
echo Installing MULTI-Module DFU Bootloader Driver...
|
||||
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0003 --type 2 --name "MULTI-Module DFU Bootloader" --dest "%~dp0MULTI-DFU-Bootloader" -b
|
||||
echo.
|
||||
|
||||
echo Installing MULTI-Module USB Serial Driver...
|
||||
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0004 --type 3 --name "MULTI-Module USB Serial" --dest "%~dp0MULTI-USB-Serial" -b
|
||||
echo.
|
||||
|
||||
pause
|
||||
BIN
BootLoaders/Boards/Windows/wdi-simple.exe
Normal file
47
BootLoaders/OrangeMultiBoot/OrangeMultiBoot.hex
Normal file
@@ -0,0 +1,47 @@
|
||||
:108000001F92CDB7DEB7CFD01124809178009FEFBB
|
||||
:1080100090937800837099F088EA91E680936808DD
|
||||
:108020009093690880E180934C0880914C0884FF0C
|
||||
:10803000FCCF109240088091680682FD8FD082E0CC
|
||||
:1080400080936106C12CD12C97D0813479F494D0DF
|
||||
:10805000898399D08981823811F485E005C08138FF
|
||||
:1080600011F484E001C083E080D075C0823411F443
|
||||
:1080700084E103C0853419F485E08CD06CC085356B
|
||||
:1080800059F47AD0C82E78D0D12CD82A8D2D881FBB
|
||||
:108090008827881F8BBF5EC0863521F484E07AD0A4
|
||||
:1080A00080E0E2CF843641F567D066D0F82E64D008
|
||||
:1080B000C601DCD000E010E25FD0F80181938F01AF
|
||||
:1080C000FE12FACF60D0D7FC46C0CBD0C601DAD0C2
|
||||
:1080D000760100E010E2F801619171918F01C70112
|
||||
:1080E000DBD0F2E0EF0EF11C011581E2180799F7E1
|
||||
:1080F000C601E0D0B6D02FC08437C1F43DD03CD00B
|
||||
:10810000F82E3AD040D0F601EC2CEF0C8F010F5F27
|
||||
:108110001F4F84912AD0E01207C0EFEFCE1ADE0A7B
|
||||
:10812000FA94CF0CD11C17C0F801F0CF853739F481
|
||||
:108130002AD08EE11AD085E918D082E495CF813516
|
||||
:1081400049F421D080E111D08091A10886FFFCCFB5
|
||||
:1081500005D001C018D080E108D076CFE0E0F0E093
|
||||
:1081600084918F3F09F0099408959091A10895FF9B
|
||||
:10817000FCCF8093A00808958091A10887FFFCCFD1
|
||||
:108180008091A0080895F8DF803211F085E1EDDFDD
|
||||
:1081900084E1EBCFCF93C82FEFDFC150E9F7CF9148
|
||||
:1081A000F2CFA895089583EC8093520080915000FF
|
||||
:1081B0008860809350008091510083FFFCCF82EC57
|
||||
:1081C0008093550080915000806180935000809191
|
||||
:1081D000510084FFFCCF88ED84BF1092400084BF23
|
||||
:1081E00024E02093400087E08093A20087E88093FA
|
||||
:1081F0008301109241081092420810924308109295
|
||||
:10820000440810924608109247088FEF9FEF809322
|
||||
:1082100066089093670810926008109261088BE0DE
|
||||
:1082200080934008209365062093620688E180933E
|
||||
:10823000720698E0909345069093410692E29093DF
|
||||
:10824000A6081092A7088093A4088091A3088F7CA9
|
||||
:1082500080618093A30883E08093A5088091A008A3
|
||||
:1082600008958091CF0187FDFCCF08958F939F9350
|
||||
:1082700082E2E0ECF1E08287FF91EF918DE984BF2B
|
||||
:10828000E8950895FC0186E28093CA0188ED84BFD9
|
||||
:1082900081E08093CB0108950F921F92FC01062E7E
|
||||
:1082A000172E83E28093CA018DE984BFE8951F9061
|
||||
:1082B0000F900895FC018EE28093CA018DE984BF7E
|
||||
:0482C000E8950895A0
|
||||
:040000030000800079
|
||||
:00000001FF
|
||||
503
BootLoaders/OrangeMultiBoot/Source/Makefile
Normal file
@@ -0,0 +1,503 @@
|
||||
# Makefile for ATmegaBOOT
|
||||
# E.Lins, 18.7.2005
|
||||
# $Id$
|
||||
#
|
||||
# Instructions
|
||||
#
|
||||
# To make bootloader .hex file:
|
||||
# make diecimila
|
||||
# make lilypad
|
||||
# make ng
|
||||
# etc...
|
||||
#
|
||||
# To burn bootloader .hex file:
|
||||
# make diecimila_isp
|
||||
# make lilypad_isp
|
||||
# make ng_isp
|
||||
# etc...
|
||||
|
||||
# program name should not be changed...
|
||||
PROGRAM = optiboot
|
||||
|
||||
# The default behavior is to build using tools that are in the users
|
||||
# current path variables, but we can also build using an installed
|
||||
# Arduino user IDE setup, or the Arduino source tree.
|
||||
# Uncomment this next lines to build within the arduino environment,
|
||||
# using the arduino-included avrgcc toolset (mac and pc)
|
||||
# ENV ?= arduino
|
||||
# ENV ?= arduinodev
|
||||
# OS ?= macosx
|
||||
# OS ?= windows
|
||||
|
||||
|
||||
# enter the parameters for the avrdude isp tool -b19200
|
||||
#
|
||||
# These are the parameters for a usb-based STK500v2 programmer.
|
||||
# Exact type unknown. (historical Makefile values.)
|
||||
ISPTOOL = stk500v2
|
||||
ISPPORT = usb
|
||||
ISPSPEED = -b 57600
|
||||
#
|
||||
#
|
||||
# These are parameters for using an Arduino with the ArduinoISP sketch
|
||||
# as the programmer. On a mac, for a particular Uno as programmer.
|
||||
#ISPTOOL = stk500v1 -C /Applications/arduino/arduino-0022/hardware/tools/avr/etc/avrdude.conf
|
||||
#ISPPORT = /dev/tty.usbmodemfd3141
|
||||
#ISPSPEED = -b19200
|
||||
|
||||
MCU_TARGET = atmega168
|
||||
LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe
|
||||
|
||||
# Build environments
|
||||
# Start of some ugly makefile-isms to allow optiboot to be built
|
||||
# in several different environments. See the README.TXT file for
|
||||
# details.
|
||||
|
||||
# default
|
||||
fixpath = $(1)
|
||||
|
||||
ifeq ($(ENV), arduino)
|
||||
# For Arduino, we assume that we're connected to the optiboot directory
|
||||
# included with the arduino distribution, which means that the full set
|
||||
# of avr-tools are "right up there" in standard places.
|
||||
TOOLROOT = ../../../tools
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
ifeq ($(OS), windows)
|
||||
# On windows, SOME of the tool paths will need to have backslashes instead
|
||||
# of forward slashes (because they use windows cmd.exe for execution instead
|
||||
# of a unix/mingw shell?) We also have to ensure that a consistent shell
|
||||
# is used even if a unix shell is installed (ie as part of WINAVR)
|
||||
fixpath = $(subst /,\,$1)
|
||||
SHELL = cmd.exe
|
||||
endif
|
||||
|
||||
else ifeq ($(ENV), arduinodev)
|
||||
# Arduino IDE source code environment. Use the unpacked compilers created
|
||||
# by the build (you'll need to do "ant build" first.)
|
||||
ifeq ($(OS), macosx)
|
||||
TOOLROOT = ../../../../build/macosx/work/Arduino.app/Contents/Resources/Java/hardware/tools
|
||||
endif
|
||||
ifeq ($(OS), windows)
|
||||
TOOLROOT = ../../../../build/windows/work/hardware/tools
|
||||
endif
|
||||
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
else
|
||||
GCCROOT =
|
||||
AVRDUDE_CONF =
|
||||
endif
|
||||
#
|
||||
# End of build environment code.
|
||||
|
||||
|
||||
# the efuse should really be 0xf8; since, however, only the lower
|
||||
# three bits of that byte are used on the atmega168, avrdude gets
|
||||
# confused if you specify 1's for the higher bits, see:
|
||||
# http://tinker.it/now/2007/02/24/the-tale-of-avrdude-atmega168-and-extended-bits-fuses/
|
||||
#
|
||||
# similarly, the lock bits should be 0xff instead of 0x3f (to
|
||||
# unlock the bootloader section) and 0xcf instead of 0x2f (to
|
||||
# lock it), but since the high two bits of the lock byte are
|
||||
# unused, avrdude would get confused.
|
||||
|
||||
ISPFUSES = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-e -u -U lock:w:0x3f:m -U efuse:w:0x$(EFUSE):m \
|
||||
-U hfuse:w:0x$(HFUSE):m -U lfuse:w:0x$(LFUSE):m
|
||||
ISPFLASH = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x2f:m
|
||||
|
||||
STK500 = "C:\Program Files\Atmel\AVR Tools\STK500\Stk500.exe"
|
||||
STK500-1 = $(STK500) -e -d$(MCU_TARGET) -pf -vf -if$(PROGRAM)_$(TARGET).hex \
|
||||
-lFF -LFF -f$(HFUSE)$(LFUSE) -EF8 -ms -q -cUSB -I200kHz -s -wt
|
||||
STK500-2 = $(STK500) -d$(MCU_TARGET) -ms -q -lCF -LCF -cUSB -I200kHz -s -wt
|
||||
|
||||
OBJ = $(PROGRAM).o
|
||||
OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types
|
||||
# -mshort-calls
|
||||
|
||||
DEFS =
|
||||
LIBS =
|
||||
|
||||
CC = $(GCCROOT)avr-gcc
|
||||
|
||||
# Override is only needed by avr-lib build system.
|
||||
|
||||
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
|
||||
override LDFLAGS = $(LDSECTIONS) -Wl,--relax -Wl,--gc-sections -nostartfiles -nostdlib
|
||||
|
||||
OBJCOPY = $(GCCROOT)avr-objcopy
|
||||
OBJDUMP = $(call fixpath,$(GCCROOT)avr-objdump)
|
||||
|
||||
SIZE = $(GCCROOT)avr-size
|
||||
|
||||
|
||||
|
||||
#Voice board test
|
||||
# ATmega328
|
||||
#
|
||||
#atmega328: TARGET = atmega328p
|
||||
#atmega328: MCU_TARGET = atmega328p
|
||||
#atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
#atmega328: AVR_FREQ = 12000000L
|
||||
#atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
#atmega328: $(PROGRAM)_atmega328.hex
|
||||
#atmega328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
xmega32D4: TARGET = atxmega32d4
|
||||
xmega32D4: MCU_TARGET = atxmega32d4
|
||||
xmega32D4: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
xmega32D4: AVR_FREQ = 32000000L
|
||||
xmega32D4: LDSECTIONS = -Wl,--section-start=.text=0x8000
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.hex
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.lst
|
||||
|
||||
atmega328: TARGET = atmega328
|
||||
atmega328: MCU_TARGET = atmega328p
|
||||
atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
atmega328: AVR_FREQ = 16000000L
|
||||
atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328: $(PROGRAM)_atmega328_16.hex
|
||||
atmega328: $(PROGRAM)_atmega328_16.lst
|
||||
|
||||
|
||||
# Test platforms
|
||||
# Virtual boot block test
|
||||
virboot328: TARGET = atmega328
|
||||
virboot328: MCU_TARGET = atmega328p
|
||||
virboot328: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DVIRTUAL_BOOT'
|
||||
virboot328: AVR_FREQ = 16000000L
|
||||
virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
virboot328: $(PROGRAM)_atmega328.hex
|
||||
virboot328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
# 20MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro20: TARGET = pro_20mhz
|
||||
pro20: MCU_TARGET = atmega168
|
||||
pro20: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro20: AVR_FREQ = 20000000L
|
||||
pro20: $(PROGRAM)_pro_20mhz.hex
|
||||
pro20: $(PROGRAM)_pro_20mhz.lst
|
||||
|
||||
pro20_isp: pro20
|
||||
pro20_isp: TARGET = pro_20mhz
|
||||
# 2.7V brownout
|
||||
pro20_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro20_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro20_isp: EFUSE = 04
|
||||
pro20_isp: isp
|
||||
|
||||
# 16MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro16: TARGET = pro_16MHz
|
||||
pro16: MCU_TARGET = atmega168
|
||||
pro16: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro16: AVR_FREQ = 16000000L
|
||||
pro16: $(PROGRAM)_pro_16MHz.hex
|
||||
pro16: $(PROGRAM)_pro_16MHz.lst
|
||||
|
||||
pro16_isp: pro16
|
||||
pro16_isp: TARGET = pro_16MHz
|
||||
# 2.7V brownout
|
||||
pro16_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro16_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro16_isp: EFUSE = 04
|
||||
pro16_isp: isp
|
||||
|
||||
# Diecimila, Duemilanove with m168, and NG use identical bootloaders
|
||||
# Call it "atmega168" for generality and clarity, keep "diecimila" for
|
||||
# backward compatibility of makefile
|
||||
#
|
||||
atmega168: TARGET = atmega168
|
||||
atmega168: MCU_TARGET = atmega168
|
||||
atmega168: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega168: AVR_FREQ = 12000000L
|
||||
atmega168: $(PROGRAM)_atmega168.hex
|
||||
atmega168: $(PROGRAM)_atmega168.lst
|
||||
|
||||
atmega168_isp: atmega168
|
||||
atmega168_isp: TARGET = atmega168
|
||||
# 2.7V brownout
|
||||
atmega168_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega168_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega168_isp: EFUSE = 04
|
||||
atmega168_isp: isp
|
||||
|
||||
diecimila: TARGET = diecimila
|
||||
diecimila: MCU_TARGET = atmega168
|
||||
diecimila: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
diecimila: AVR_FREQ = 16000000L
|
||||
diecimila: $(PROGRAM)_diecimila.hex
|
||||
diecimila: $(PROGRAM)_diecimila.lst
|
||||
|
||||
diecimila_isp: diecimila
|
||||
diecimila_isp: TARGET = diecimila
|
||||
# 2.7V brownout
|
||||
diecimila_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
diecimila_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
diecimila_isp: EFUSE = 04
|
||||
diecimila_isp: isp
|
||||
|
||||
atmega328_isp: atmega328
|
||||
atmega328_isp: TARGET = atmega328
|
||||
atmega328_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_isp: EFUSE = FD
|
||||
atmega328_isp: isp
|
||||
|
||||
atmega1284: TARGET = atmega1284p
|
||||
atmega1284: MCU_TARGET = atmega1284p
|
||||
atmega1284: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
atmega1284: AVR_FREQ = 16000000L
|
||||
atmega1284: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
atmega1284: $(PROGRAM)_atmega1284p.hex
|
||||
atmega1284: $(PROGRAM)_atmega1284p.lst
|
||||
|
||||
atmega1284_isp: atmega1284
|
||||
atmega1284_isp: TARGET = atmega1284p
|
||||
atmega1284_isp: MCU_TARGET = atmega1284p
|
||||
# 1024 byte boot
|
||||
atmega1284_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega1284_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega1284_isp: EFUSE = FD
|
||||
atmega1284_isp: isp
|
||||
|
||||
# Sanguino has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#
|
||||
sanguino: TARGET = atmega644p
|
||||
sanguino: MCU_TARGET = atmega644p
|
||||
sanguino: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
sanguino: AVR_FREQ = 16000000L
|
||||
sanguino: LDSECTIONS = -Wl,--section-start=.text=0xfc00 -Wl,--section-start=.version=0xfffe
|
||||
sanguino: $(PROGRAM)_atmega644p.hex
|
||||
sanguino: $(PROGRAM)_atmega644p.lst
|
||||
|
||||
sanguino_isp: sanguino
|
||||
sanguino_isp: TARGET = atmega644p
|
||||
sanguino_isp: MCU_TARGET = atmega644p
|
||||
# 1024 byte boot
|
||||
sanguino_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
sanguino_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
sanguino_isp: EFUSE = FD
|
||||
sanguino_isp: isp
|
||||
|
||||
# Mega has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#mega: TARGET = atmega1280
|
||||
mega1280: MCU_TARGET = atmega1280
|
||||
mega1280: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
mega1280: AVR_FREQ = 16000000L
|
||||
mega1280: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
mega1280: $(PROGRAM)_atmega1280.hex
|
||||
mega1280: $(PROGRAM)_atmega1280.lst
|
||||
|
||||
mega1280_isp: mega
|
||||
mega1280_isp: TARGET = atmega1280
|
||||
mega1280_isp: MCU_TARGET = atmega1280
|
||||
# 1024 byte boot
|
||||
mega1280_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
mega1280_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
mega1280_isp: EFUSE = FD
|
||||
mega1280_isp: isp
|
||||
|
||||
# ATmega8
|
||||
#
|
||||
atmega8: TARGET = atmega8
|
||||
atmega8: MCU_TARGET = atmega8
|
||||
atmega8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega8: AVR_FREQ = 16000000L
|
||||
atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega8: $(PROGRAM)_atmega8.hex
|
||||
atmega8: $(PROGRAM)_atmega8.lst
|
||||
|
||||
atmega8_isp: atmega8
|
||||
atmega8_isp: TARGET = atmega8
|
||||
atmega8_isp: MCU_TARGET = atmega8
|
||||
# SPIEN, CKOPT, Bootsize=512B
|
||||
atmega8_isp: HFUSE = CC
|
||||
# 2.7V brownout, Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega8_isp: LFUSE = BF
|
||||
atmega8_isp: isp
|
||||
|
||||
# ATmega88
|
||||
#
|
||||
atmega88: TARGET = atmega88
|
||||
atmega88: MCU_TARGET = atmega88
|
||||
atmega88: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega88: AVR_FREQ = 12000000L
|
||||
atmega88: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega88: $(PROGRAM)_atmega88.hex
|
||||
atmega88: $(PROGRAM)_atmega88.lst
|
||||
|
||||
atmega88_isp: atmega88
|
||||
atmega88_isp: TARGET = atmega88
|
||||
atmega88_isp: MCU_TARGET = atmega88
|
||||
# 2.7V brownout
|
||||
atmega88_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atemga88_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega88_isp: EFUSE = 04
|
||||
atmega88_isp: isp
|
||||
|
||||
|
||||
# 8MHz clocked platforms
|
||||
#
|
||||
# These are capable of 38400 baud
|
||||
#
|
||||
|
||||
lilypad: TARGET = lilypad
|
||||
lilypad: MCU_TARGET = atmega168
|
||||
lilypad: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad: AVR_FREQ = 8000000L
|
||||
lilypad: $(PROGRAM)_lilypad.hex
|
||||
lilypad: $(PROGRAM)_lilypad.lst
|
||||
|
||||
lilypad_isp: lilypad
|
||||
lilypad_isp: TARGET = lilypad
|
||||
# 2.7V brownout
|
||||
lilypad_isp: HFUSE = DD
|
||||
# Internal 8MHz osc (8MHz) Slow rising power
|
||||
lilypad_isp: LFUSE = E2
|
||||
# 512 byte boot
|
||||
lilypad_isp: EFUSE = 04
|
||||
lilypad_isp: isp
|
||||
|
||||
lilypad_resonator: TARGET = lilypad_resonator
|
||||
lilypad_resonator: MCU_TARGET = atmega168
|
||||
lilypad_resonator: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad_resonator: AVR_FREQ = 8000000L
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.hex
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.lst
|
||||
|
||||
lilypad_resonator_isp: lilypad_resonator
|
||||
lilypad_resonator_isp: TARGET = lilypad_resonator
|
||||
# 2.7V brownout
|
||||
lilypad_resonator_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
lilypad_resonator_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
lilypad_resonator_isp: EFUSE = 04
|
||||
lilypad_resonator_isp: isp
|
||||
|
||||
pro8: TARGET = pro_8MHz
|
||||
pro8: MCU_TARGET = atmega168
|
||||
pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro8: AVR_FREQ = 8000000L
|
||||
pro8: $(PROGRAM)_pro_8MHz.hex
|
||||
pro8: $(PROGRAM)_pro_8MHz.lst
|
||||
|
||||
pro8_isp: pro8
|
||||
pro8_isp: TARGET = pro_8MHz
|
||||
# 2.7V brownout
|
||||
pro8_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro8_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro8_isp: EFUSE = 04
|
||||
pro8_isp: isp
|
||||
|
||||
atmega328_pro8: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8: MCU_TARGET = atmega328p
|
||||
atmega328_pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega328_pro8: AVR_FREQ = 8000000L
|
||||
atmega328_pro8: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.hex
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.lst
|
||||
|
||||
atmega328_pro8_isp: atmega328_pro8
|
||||
atmega328_pro8_isp: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_pro8_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_pro8_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_pro8_isp: EFUSE = DE
|
||||
atmega328_pro8_isp: isp
|
||||
|
||||
# 1MHz clocked platforms
|
||||
#
|
||||
# These are capable of 9600 baud
|
||||
#
|
||||
|
||||
luminet: TARGET = luminet
|
||||
luminet: MCU_TARGET = attiny84
|
||||
luminet: CFLAGS += '-DLED_START_FLASHES=3' '-DSOFT_UART' '-DBAUD_RATE=9600'
|
||||
luminet: CFLAGS += '-DVIRTUAL_BOOT_PARTITION'
|
||||
luminet: AVR_FREQ = 1000000L
|
||||
luminet: LDSECTIONS = -Wl,--section-start=.text=0x1d00 -Wl,--section-start=.version=0x1efe
|
||||
luminet: $(PROGRAM)_luminet.hex
|
||||
luminet: $(PROGRAM)_luminet.lst
|
||||
|
||||
luminet_isp: luminet
|
||||
luminet_isp: TARGET = luminet
|
||||
luminet_isp: MCU_TARGET = attiny84
|
||||
# Brownout disabled
|
||||
luminet_isp: HFUSE = DF
|
||||
# 1MHz internal oscillator, slowly rising power
|
||||
luminet_isp: LFUSE = 62
|
||||
# Self-programming enable
|
||||
luminet_isp: EFUSE = FE
|
||||
luminet_isp: isp
|
||||
|
||||
#
|
||||
# Generic build instructions
|
||||
#
|
||||
#
|
||||
|
||||
isp: $(TARGET)
|
||||
$(ISPFUSES)
|
||||
$(ISPFLASH)
|
||||
|
||||
isp-stk500: $(PROGRAM)_$(TARGET).hex
|
||||
$(STK500-1)
|
||||
$(STK500-2)
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(SIZE) $@
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@
|
||||
|
||||
%.srec: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@
|
||||
980
BootLoaders/OrangeMultiBoot/Source/optiboot.c
Normal file
@@ -0,0 +1,980 @@
|
||||
/**********************************************************/
|
||||
/* Optiboot bootloader for Xmega */
|
||||
/* */
|
||||
/* http://optiboot.googlecode.com */
|
||||
/* */
|
||||
/* Arduino-maintained version : See README.TXT */
|
||||
/* http://code.google.com/p/arduino/ */
|
||||
/* It is the intent that changes not relevant to the */
|
||||
/* Arduino production envionment get moved from the */
|
||||
/* optiboot project to the arduino project in "lumps." */
|
||||
/* */
|
||||
/* Heavily optimised bootloader that is faster and */
|
||||
/* smaller than the Arduino standard bootloader */
|
||||
/* */
|
||||
/* Enhancements: */
|
||||
/* Fits in 512 bytes, saving 1.5K of code space */
|
||||
/* Background page erasing speeds up programming */
|
||||
/* Higher baud rate speeds up programming */
|
||||
/* Written almost entirely in C */
|
||||
/* Customisable timeout with accurate timeconstant */
|
||||
/* Optional virtual UART. No hardware UART required. */
|
||||
/* Optional virtual boot partition for devices without. */
|
||||
/* */
|
||||
/* What you lose: */
|
||||
/* Implements a skeleton STK500 protocol which is */
|
||||
/* missing several features including EEPROM */
|
||||
/* programming and non-page-aligned writes */
|
||||
/* High baud rate breaks compatibility with standard */
|
||||
/* Arduino flash settings */
|
||||
/* */
|
||||
/* Fully supported: */
|
||||
/* ATmega168 based devices (Diecimila etc) */
|
||||
/* ATmega328P based devices (Duemilanove etc) */
|
||||
/* */
|
||||
/* Beta test (believed working.) */
|
||||
/* ATmega8 based devices (Arduino legacy) */
|
||||
/* ATmega328 non-picopower devices */
|
||||
/* ATmega644P based devices (Sanguino) */
|
||||
/* ATmega1284P based devices */
|
||||
/* */
|
||||
/* Alpha test */
|
||||
/* ATmega1280 based devices (Arduino Mega) */
|
||||
/* */
|
||||
/* Work in progress: */
|
||||
/* ATtiny84 based devices (Luminet) */
|
||||
/* */
|
||||
/* Does not support: */
|
||||
/* USB based devices (eg. Teensy) */
|
||||
/* */
|
||||
/* Assumptions: */
|
||||
/* The code makes several assumptions that reduce the */
|
||||
/* code size. They are all true after a hardware reset, */
|
||||
/* but may not be true if the bootloader is called by */
|
||||
/* other means or on other hardware. */
|
||||
/* No interrupts can occur */
|
||||
/* UART and Timer 1 are set to their reset state */
|
||||
/* SP points to RAMEND */
|
||||
/* */
|
||||
/* Code builds on code, libraries and optimisations from: */
|
||||
/* stk500boot.c by Jason P. Kyle */
|
||||
/* Arduino bootloader http://arduino.cc */
|
||||
/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
|
||||
/* avr-libc project http://nongnu.org/avr-libc */
|
||||
/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */
|
||||
/* AVR305 Atmel Application Note */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it */
|
||||
/* and/or modify it under the terms of the GNU General */
|
||||
/* Public License as published by the Free Software */
|
||||
/* Foundation; either version 2 of the License, or */
|
||||
/* (at your option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will */
|
||||
/* be useful, but WITHOUT ANY WARRANTY; without even the */
|
||||
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
|
||||
/* PARTICULAR PURPOSE. See the GNU General Public */
|
||||
/* License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General */
|
||||
/* Public License along with this program; if not, write */
|
||||
/* to the Free Software Foundation, Inc., */
|
||||
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
/* */
|
||||
/* Licence can be viewed at */
|
||||
/* http://www.fsf.org/licenses/gpl.txt */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* Optional defines: */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* BIG_BOOT: */
|
||||
/* Build a 1k bootloader, not 512 bytes. This turns on */
|
||||
/* extra functionality. */
|
||||
/* */
|
||||
/* BAUD_RATE: */
|
||||
/* Set bootloader baud rate. */
|
||||
/* */
|
||||
/* LUDICROUS_SPEED: */
|
||||
/* 230400 baud :-) */
|
||||
/* */
|
||||
/* SOFT_UART: */
|
||||
/* Use AVR305 soft-UART instead of hardware UART. */
|
||||
/* */
|
||||
/* LED_START_FLASHES: */
|
||||
/* Number of LED flashes on bootup. */
|
||||
/* */
|
||||
/* LED_DATA_FLASH: */
|
||||
/* Flash LED when transferring data. For boards without */
|
||||
/* TX or RX LEDs, or for people who like blinky lights. */
|
||||
/* */
|
||||
/* SUPPORT_EEPROM: */
|
||||
/* Support reading and writing from EEPROM. This is not */
|
||||
/* used by Arduino, so off by default. */
|
||||
/* */
|
||||
/* TIMEOUT_MS: */
|
||||
/* Bootloader timeout period, in milliseconds. */
|
||||
/* 500,1000,2000,4000,8000 supported. */
|
||||
/* */
|
||||
/* UART: */
|
||||
/* UART number (0..n) for devices with more than */
|
||||
/* one hardware uart (644P, 1284P, etc) */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Version Numbers! */
|
||||
/* */
|
||||
/* Arduino Optiboot now includes this Version number in */
|
||||
/* the source and object code. */
|
||||
/* */
|
||||
/* Version 3 was released as zip from the optiboot */
|
||||
/* repository and was distributed with Arduino 0022. */
|
||||
/* Version 4 starts with the arduino repository commit */
|
||||
/* that brought the arduino repository up-to-date with */
|
||||
/* the optiboot source tree changes since v3. */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Edit History: */
|
||||
/* */
|
||||
/* Nov 2012 */
|
||||
/* Specific version for 9x voice module */
|
||||
/* by Mike Blandford */
|
||||
/* Mar 2012 */
|
||||
/* 4.5 WestfW: add infrastructure for non-zero UARTS. */
|
||||
/* 4.5 WestfW: fix SIGNATURE_2 for m644 (bad in avr-libc) */
|
||||
/* Jan 2012: */
|
||||
/* 4.5 WestfW: fix NRWW value for m1284. */
|
||||
/* 4.4 WestfW: use attribute OS_main instead of naked for */
|
||||
/* main(). This allows optimizations that we */
|
||||
/* count on, which are prohibited in naked */
|
||||
/* functions due to PR42240. (keeps us less */
|
||||
/* than 512 bytes when compiler is gcc4.5 */
|
||||
/* (code from 4.3.2 remains the same.) */
|
||||
/* 4.4 WestfW and Maniacbug: Add m1284 support. This */
|
||||
/* does not change the 328 binary, so the */
|
||||
/* version number didn't change either. (?) */
|
||||
/* June 2011: */
|
||||
/* 4.4 WestfW: remove automatic soft_uart detect (didn't */
|
||||
/* know what it was doing or why.) Added a */
|
||||
/* check of the calculated BRG value instead. */
|
||||
/* Version stays 4.4; existing binaries are */
|
||||
/* not changed. */
|
||||
/* 4.4 WestfW: add initialization of address to keep */
|
||||
/* the compiler happy. Change SC'ed targets. */
|
||||
/* Return the SW version via READ PARAM */
|
||||
/* 4.3 WestfW: catch framing errors in getch(), so that */
|
||||
/* AVRISP works without HW kludges. */
|
||||
/* http://code.google.com/p/arduino/issues/detail?id=368n*/
|
||||
/* 4.2 WestfW: reduce code size, fix timeouts, change */
|
||||
/* verifySpace to use WDT instead of appstart */
|
||||
/* 4.1 WestfW: put version number in binary. */
|
||||
/**********************************************************/
|
||||
|
||||
#define OPTIBOOT_MAJVER 4
|
||||
#define OPTIBOOT_MINVER 5
|
||||
|
||||
#define MULTI_CALLED 1
|
||||
|
||||
#define MAKESTR(a) #a
|
||||
#define MAKEVER(a, b) MAKESTR(a*256+b)
|
||||
|
||||
// Page Size is 128 words (256 bytes)
|
||||
|
||||
//asm(" .section .version\n"
|
||||
// "optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n"
|
||||
// " .section .text\n");
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// <avr/boot.h> uses sts instructions, but this version uses out instructions
|
||||
// This saves cycles and program memory.
|
||||
//#include "boot.h"
|
||||
|
||||
|
||||
// We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
|
||||
|
||||
#include "pin_defs.h"
|
||||
#include "stk500.h"
|
||||
|
||||
#define BIND_pin 2 //PD2
|
||||
#define BIND_port PORTD
|
||||
#define IS_BIND_BUTTON_on ( (BIND_port.IN & _BV(BIND_pin)) == 0x00 )
|
||||
|
||||
#ifndef LED_START_FLASHES
|
||||
#define LED_START_FLASHES 0
|
||||
#endif
|
||||
|
||||
#ifdef LUDICROUS_SPEED
|
||||
#define BAUD_RATE 230400L
|
||||
#endif
|
||||
|
||||
/* set the UART baud rate defaults */
|
||||
#ifndef BAUD_RATE
|
||||
#if F_CPU >= 8000000L
|
||||
#define BAUD_RATE 38400L // Highest rate Avrdude win32 will support
|
||||
#elsif F_CPU >= 1000000L
|
||||
#define BAUD_RATE 9600L // 19200 also supported, but with significant error
|
||||
#elsif F_CPU >= 128000L
|
||||
#define BAUD_RATE 4800L // Good for 128kHz internal RC
|
||||
#else
|
||||
#define BAUD_RATE 1200L // Good even at 32768Hz
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef UART
|
||||
#define UART 0
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Switch in soft UART for hard baud rates */
|
||||
/*
|
||||
* I don't understand what this was supposed to accomplish, where the
|
||||
* constant "280" came from, or why automatically (and perhaps unexpectedly)
|
||||
* switching to a soft uart is a good thing, so I'm undoing this in favor
|
||||
* of a range check using the same calc used to config the BRG...
|
||||
*/
|
||||
#if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz
|
||||
#ifndef SOFT_UART
|
||||
#define SOFT_UART
|
||||
#endif
|
||||
#endif
|
||||
#else // 0
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250
|
||||
#error Unachievable baud rate (too slow) BAUD_RATE
|
||||
#endif // baud rate slow check
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3
|
||||
#error Unachievable baud rate (too fast) BAUD_RATE
|
||||
#endif // baud rate fastn check
|
||||
#endif
|
||||
|
||||
/* Watchdog settings */
|
||||
#define WATCHDOG_OFF (0)
|
||||
#define WATCHDOG_16MS (_BV(WDE))
|
||||
#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE))
|
||||
#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#ifndef __AVR_ATmega8__
|
||||
#define WATCHDOG_4S (_BV(WDP3) | _BV(WDE))
|
||||
#define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
|
||||
#endif
|
||||
|
||||
/* Function Prototypes */
|
||||
/* The main function is in init9, which removes the interrupt vector table */
|
||||
/* we don't need. It is also 'naked', which means the compiler does not */
|
||||
/* generate any entry or exit code itself. */
|
||||
int main(void) __attribute__ ((OS_main)) __attribute__ ((noreturn)) __attribute__ ((section (".init9")));
|
||||
void putch(char);
|
||||
uint8_t getch(void);
|
||||
static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */
|
||||
void verifySpace();
|
||||
#if LED_START_FLASHES > 0
|
||||
static inline void flash_led(uint8_t);
|
||||
#endif
|
||||
uint8_t getLen();
|
||||
//static inline void watchdogReset();
|
||||
void watchdogConfig(uint8_t x);
|
||||
#ifdef SOFT_UART
|
||||
void uartDelay() __attribute__ ((naked));
|
||||
#endif
|
||||
static void appStart() ; // __attribute__ ((naked));
|
||||
void boot_spm_busy_wait() ;
|
||||
void __boot_page_erase_short( uint16_t address ) ;
|
||||
void __boot_page_fill_short( uint16_t address, uint16_t data) ;
|
||||
void __boot_page_write_short( uint16_t address) ;
|
||||
void __boot_erase_flash_buffer( uint16_t address ) ;
|
||||
void init() ;
|
||||
|
||||
/*
|
||||
* NRWW memory
|
||||
* Addresses below NRWW (Non-Read-While-Write) can be programmed while
|
||||
* continuing to run code from flash, slightly speeding up programming
|
||||
* time. Beware that Atmel data sheets specify this as a WORD address,
|
||||
* while optiboot will be comparing against a 16-bit byte address. This
|
||||
* means that on a part with 128kB of memory, the upper part of the lower
|
||||
* 64k will get NRWW processing as well, even though it doesn't need it.
|
||||
* That's OK. In fact, you can disable the overlapping processing for
|
||||
* a part entirely by setting NRWWSTART to zero. This reduces code
|
||||
* space a bit, at the expense of being slightly slower, overall.
|
||||
*
|
||||
* RAMSTART should be self-explanatory. It's bigger on parts with a
|
||||
* lot of peripheral registers.
|
||||
*/
|
||||
#if defined(__AVR_ATmega168__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x3800)
|
||||
#elif defined(__AVR_ATmega328P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined(__AVR_ATmega328__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined (__AVR_ATmega644P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
// correct for a bug in avr-libc
|
||||
#undef SIGNATURE_2
|
||||
#define SIGNATURE_2 0x0A
|
||||
#elif defined (__AVR_ATmega1284P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATtiny84__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x0000)
|
||||
#elif defined(__AVR_ATmega1280__)
|
||||
#define RAMSTART (0x200)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x1800)
|
||||
#endif
|
||||
|
||||
/* C zero initialises all global variables. However, that requires */
|
||||
/* These definitions are NOT zero initialised, but that doesn't matter */
|
||||
/* This allows us to drop the zero init code, saving us memory */
|
||||
#define buff ((uint8_t*)(RAMSTART))
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
#define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4))
|
||||
#define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle devices with up to 4 uarts (eg m1280.) Rather inelegantly.
|
||||
* Note that mega8 still needs special handling, because ubrr is handled
|
||||
* differently.
|
||||
*/
|
||||
#if UART == 0
|
||||
# define UART_SRA UCSR0A
|
||||
# define UART_SRB UCSR0B
|
||||
# define UART_SRC UCSR0C
|
||||
# define UART_SRL UBRR0L
|
||||
# define UART_UDR UDR0
|
||||
#elif UART == 1
|
||||
# define UART_SRA UCSR1A
|
||||
# define UART_SRB UCSR1B
|
||||
# define UART_SRC UCSR1C
|
||||
# define UART_SRL UBRR1L
|
||||
# define UART_UDR UDR1
|
||||
#elif UART == 2
|
||||
# define UART_SRA UCSR2A
|
||||
# define UART_SRB UCSR2B
|
||||
# define UART_SRC UCSR2C
|
||||
# define UART_SRL UBRR2L
|
||||
# define UART_UDR UDR2
|
||||
#elif UART == 3
|
||||
# define UART_SRA UCSR3A
|
||||
# define UART_SRB UCSR3B
|
||||
# define UART_SRC UCSR3C
|
||||
# define UART_SRL UBRR3L
|
||||
# define UART_UDR UDR3
|
||||
#endif
|
||||
|
||||
|
||||
/* main program starts here */
|
||||
int main(void)
|
||||
{
|
||||
uint8_t ch;
|
||||
uint8_t byte ;
|
||||
|
||||
/*
|
||||
* Making these local and in registers prevents the need for initializing
|
||||
* them, and also saves space because code no longer stores to memory.
|
||||
* (initializing address keeps the compiler happy, but isn't really
|
||||
* necessary, and uses 4 bytes of flash.)
|
||||
*/
|
||||
register uint16_t address = 0;
|
||||
init() ;
|
||||
|
||||
// After the zero init loop, this is the first code to run.
|
||||
//
|
||||
// This code makes the following assumptions:
|
||||
// No interrupts will execute
|
||||
// SP points to RAMEND
|
||||
// r1 contains zero
|
||||
//
|
||||
// If not, uncomment the following instructions:
|
||||
// cli();
|
||||
asm volatile ("clr __zero_reg__");
|
||||
|
||||
ch = RST.STATUS ;
|
||||
RST.STATUS = 0xFF ; // Clear all flags
|
||||
|
||||
// Here, if power on, wait 0.1 secs, then check for
|
||||
// serial Rx signal low, if so, stay in bootloader
|
||||
// else go to application
|
||||
|
||||
if (ch & (RST_EXTRF_bm | RST_PORF_bm ) )
|
||||
{
|
||||
TCC1.CCA = 25000 ;
|
||||
TCC1.INTFLAGS = TC1_CCAIF_bm ;
|
||||
|
||||
while(!(TCC1.INTFLAGS & TC1_CCAIF_bm))
|
||||
;
|
||||
TCC1.CTRLA = 0 ; // Stop timer
|
||||
|
||||
uint8_t x ;
|
||||
x = PORTD.IN & 0x04 ;
|
||||
if ( x != 0 )
|
||||
{
|
||||
appStart() ; // Power on, go to app if loaded
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//#ifndef SOFT_UART
|
||||
// UART_SRA = _BV(U2X0); //Double speed mode USART0
|
||||
// UART_SRB = _BV(RXEN0) | _BV(TXEN0);
|
||||
// UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
|
||||
//// UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
|
||||
//// Baudrate of 57600
|
||||
//#if F_CPU == 12000000L
|
||||
// UART_SRL = 25 ;
|
||||
//#else
|
||||
//#if F_CPU == 16000000L
|
||||
// UART_SRL = 33 ;
|
||||
//#else
|
||||
//#ERROR Baud rate not available
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
//#endif
|
||||
|
||||
// Set up watchdog to trigger after 500ms
|
||||
|
||||
|
||||
// watchdogConfig(WATCHDOG_1S);
|
||||
|
||||
/* Set LED pin as output */
|
||||
#define LED_pin 1 //PD1
|
||||
#define LED_port PORTD
|
||||
LED_port.DIRSET = _BV(LED_pin) ;
|
||||
|
||||
//#ifdef SOFT_UART
|
||||
// /* Set TX pin as output */
|
||||
// UART_DDR |= _BV(UART_TX_BIT);
|
||||
//#endif
|
||||
|
||||
//#if LED_START_FLASHES > 0
|
||||
// /* Flash onboard LED to signal entering of bootloader */
|
||||
// flash_led(LED_START_FLASHES * 2);
|
||||
//#endif
|
||||
|
||||
/* Forever loop */
|
||||
for (;;)
|
||||
{
|
||||
/* get character from UART */
|
||||
ch = getch();
|
||||
|
||||
if(ch == STK_GET_PARAMETER)
|
||||
{
|
||||
byte = getch();
|
||||
verifySpace();
|
||||
if ( byte == 0x82)
|
||||
{
|
||||
/*
|
||||
* Send optiboot version as "minor SW version"
|
||||
*/
|
||||
putch(OPTIBOOT_MINVER);
|
||||
}
|
||||
else if ( byte == 0x81)
|
||||
{
|
||||
putch(OPTIBOOT_MAJVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* GET PARAMETER returns a generic 0x03 reply for
|
||||
* other parameters - enough to keep Avrdude happy
|
||||
*/
|
||||
putch(0x03);
|
||||
}
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE) {
|
||||
// SET DEVICE is ignored
|
||||
getNch(20);
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE_EXT)
|
||||
{
|
||||
// SET DEVICE EXT is ignored
|
||||
getNch(5);
|
||||
}
|
||||
else if(ch == STK_LOAD_ADDRESS)
|
||||
{
|
||||
// LOAD ADDRESS
|
||||
uint16_t newAddress;
|
||||
newAddress = getch() ;
|
||||
newAddress = (newAddress & 0xff) | (getch() << 8);
|
||||
#ifdef RAMPZ
|
||||
// Transfer top bit to RAMPZ
|
||||
RAMPZ = (newAddress & 0x8000) ? 1 : 0;
|
||||
#endif
|
||||
// newAddress += newAddress; // Convert from word address to byte address
|
||||
address = newAddress;
|
||||
verifySpace();
|
||||
}
|
||||
else if(ch == STK_UNIVERSAL)
|
||||
{
|
||||
// UNIVERSAL command is ignored
|
||||
getNch(4);
|
||||
putch(0x00);
|
||||
}
|
||||
/* Write memory, length is big endian and is in bytes */
|
||||
else if(ch == STK_PROG_PAGE)
|
||||
{
|
||||
// PROGRAM PAGE - we support flash programming only, not EEPROM
|
||||
uint8_t *bufPtr;
|
||||
uint16_t addrPtr;
|
||||
register uint8_t length;
|
||||
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
// If we are in RWW section, immediately start page erase
|
||||
// if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
__boot_page_erase_short((uint16_t)(void*)address);
|
||||
|
||||
// While that is going on, read in page contents
|
||||
bufPtr = buff;
|
||||
do *bufPtr++ = getch();
|
||||
while (--length);
|
||||
|
||||
// If we are in NRWW section, page erase has to be delayed until now.
|
||||
// Todo: Take RAMPZ into account
|
||||
//#ifdef MULTI_CALLED
|
||||
// if (address < 0x7E00)
|
||||
//#endif
|
||||
// {
|
||||
// if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
// }
|
||||
// Read command terminator, start reply
|
||||
verifySpace();
|
||||
|
||||
// If only a partial page is to be programmed, the erase might not be complete.
|
||||
// So check that here
|
||||
#ifdef MULTI_CALLED
|
||||
if (address < 0x8000)
|
||||
#endif
|
||||
{
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
if ((uint16_t)(void*)address == 0) {
|
||||
// This is the reset vector page. We need to live-patch the code so the
|
||||
// bootloader runs.
|
||||
//
|
||||
// Move RESET vector to WDT vector
|
||||
uint16_t vect = buff[0] | (buff[1]<<8);
|
||||
rstVect = vect;
|
||||
wdtVect = buff[8] | (buff[9]<<8);
|
||||
vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
|
||||
buff[8] = vect & 0xff;
|
||||
buff[9] = vect >> 8;
|
||||
|
||||
// Add jump to bootloader at RESET vector
|
||||
buff[0] = 0x7f;
|
||||
buff[1] = 0xce; // rjmp 0x1d00 instruction
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy buffer into programming buffer
|
||||
bufPtr = buff;
|
||||
addrPtr = (uint16_t)(void*)address;
|
||||
ch = SPM_PAGESIZE / 2;
|
||||
__boot_erase_flash_buffer((uint16_t)(void*)addrPtr ) ;
|
||||
do {
|
||||
uint16_t a;
|
||||
// a = *bufPtr++;
|
||||
// a |= (*bufPtr++) << 8;
|
||||
|
||||
a = *((uint16_t *)bufPtr) ;
|
||||
bufPtr += 2 ;
|
||||
|
||||
__boot_page_fill_short((uint16_t)(void*)addrPtr,a);
|
||||
addrPtr += 2;
|
||||
} while (--ch);
|
||||
|
||||
// Write from programming buffer
|
||||
__boot_page_write_short((uint16_t)(void*)address);
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#if defined(RWWSRE)
|
||||
// Reenable read access to flash
|
||||
boot_rww_enable();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Read memory block mode, length is big endian. */
|
||||
else if(ch == STK_READ_PAGE)
|
||||
{
|
||||
register uint8_t length;
|
||||
// READ PAGE - we only read flash
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
verifySpace();
|
||||
//#ifdef VIRTUAL_BOOT_PARTITION
|
||||
// do {
|
||||
// // Undo vector patch in bottom page so verify passes
|
||||
// if (address == 0) ch=rstVect & 0xff;
|
||||
// else if (address == 1) ch=rstVect >> 8;
|
||||
// else if (address == 8) ch=wdtVect & 0xff;
|
||||
// else if (address == 9) ch=wdtVect >> 8;
|
||||
// else ch = pgm_read_byte_near(address);
|
||||
// address++;
|
||||
// putch(ch);
|
||||
// } while (--length);
|
||||
//#else
|
||||
//#ifdef RAMPZ
|
||||
//// Since RAMPZ should already be set, we need to use EPLM directly.
|
||||
//// do putch(pgm_read_byte_near(address++));
|
||||
//// while (--length);
|
||||
// do {
|
||||
// uint8_t result;
|
||||
// __asm__ ("elpm %0,Z\n":"=r"(result):"z"(address));
|
||||
// putch(result);
|
||||
// address++;
|
||||
// }
|
||||
// while (--length);
|
||||
//#else
|
||||
do putch(pgm_read_byte_near(address++));
|
||||
while (--length);
|
||||
//#endif
|
||||
//#endif
|
||||
}
|
||||
|
||||
/* Get device signature bytes */
|
||||
else if(ch == STK_READ_SIGN)
|
||||
{
|
||||
// READ SIGN - return what Avrdude wants to hear
|
||||
verifySpace();
|
||||
putch(SIGNATURE_0);
|
||||
putch(SIGNATURE_1);
|
||||
putch(SIGNATURE_2);
|
||||
}
|
||||
else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
|
||||
// Adaboot no-wait mod
|
||||
|
||||
// watchdogConfig(WATCHDOG_16MS);
|
||||
|
||||
verifySpace();
|
||||
#ifdef MULTI_CALLED
|
||||
putch(STK_OK);
|
||||
while(!(USARTC0.STATUS & USART_TXCIF_bm))
|
||||
;
|
||||
appStart() ;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// This covers the response to commands like STK_ENTER_PROGMODE
|
||||
verifySpace();
|
||||
}
|
||||
putch(STK_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void putch(char ch)
|
||||
{
|
||||
//#ifndef SOFT_UART
|
||||
while(!(USARTC0.STATUS & USART_DREIF_bm))
|
||||
;
|
||||
USARTC0.DATA = ch ;
|
||||
//#else
|
||||
// __asm__ __volatile__ (
|
||||
// " com %[ch]\n" // ones complement, carry set
|
||||
// " sec\n"
|
||||
// "1: brcc 2f\n"
|
||||
// " cbi %[uartPort],%[uartBit]\n"
|
||||
// " rjmp 3f\n"
|
||||
// "2: sbi %[uartPort],%[uartBit]\n"
|
||||
// " nop\n"
|
||||
// "3: rcall uartDelay\n"
|
||||
// " rcall uartDelay\n"
|
||||
// " lsr %[ch]\n"
|
||||
// " dec %[bitcnt]\n"
|
||||
// " brne 1b\n"
|
||||
// :
|
||||
// :
|
||||
// [bitcnt] "d" (10),
|
||||
// [ch] "r" (ch),
|
||||
// [uartPort] "I" (_SFR_IO_ADDR(UART_PORT)),
|
||||
// [uartBit] "I" (UART_TX_BIT)
|
||||
// :
|
||||
// "r25"
|
||||
// );
|
||||
//#endif
|
||||
}
|
||||
|
||||
uint8_t getch(void)
|
||||
{
|
||||
uint8_t ch;
|
||||
|
||||
//#ifdef LED_DATA_FLASH
|
||||
//#ifdef __AVR_ATmega8__
|
||||
// LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
//#ifdef SOFT_UART
|
||||
// __asm__ __volatile__ (
|
||||
// "1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge
|
||||
// " rjmp 1b\n"
|
||||
// " rcall uartDelay\n" // Get to middle of start bit
|
||||
// "2: rcall uartDelay\n" // Wait 1 bit period
|
||||
// " rcall uartDelay\n" // Wait 1 bit period
|
||||
// " clc\n"
|
||||
// " sbic %[uartPin],%[uartBit]\n"
|
||||
// " sec\n"
|
||||
// " dec %[bitCnt]\n"
|
||||
// " breq 3f\n"
|
||||
// " ror %[ch]\n"
|
||||
// " rjmp 2b\n"
|
||||
// "3:\n"
|
||||
// :
|
||||
// [ch] "=r" (ch)
|
||||
// :
|
||||
// [bitCnt] "d" (9),
|
||||
// [uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
|
||||
// [uartBit] "I" (UART_RX_BIT)
|
||||
// :
|
||||
// "r25"
|
||||
//);
|
||||
//#else
|
||||
while(!(USARTC0.STATUS & USART_RXCIF_bm))
|
||||
|
||||
// watchdogReset()
|
||||
|
||||
;
|
||||
// if (!(UART_SRA & _BV(FE0))) {
|
||||
/*
|
||||
* A Framing Error indicates (probably) that something is talking
|
||||
* to us at the wrong bit rate. Assume that this is because it
|
||||
* expects to be talking to the application, and DON'T reset the
|
||||
* watchdog. This should cause the bootloader to abort and run
|
||||
* the application "soon", if it keeps happening. (Note that we
|
||||
* don't care that an invalid char is returned...)
|
||||
*/
|
||||
// watchdogReset();
|
||||
// }
|
||||
|
||||
ch = USARTC0.DATA ;
|
||||
//#endif
|
||||
|
||||
//#ifdef LED_DATA_FLASH
|
||||
//#ifdef __AVR_ATmega8__
|
||||
// LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
#ifdef SOFT_UART
|
||||
// AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
|
||||
// Adding 3 to numerator simulates nearest rounding for more accurate baud rates
|
||||
#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
|
||||
#if UART_B_VALUE > 255
|
||||
#error Baud rate too slow for soft UART
|
||||
#endif
|
||||
|
||||
void uartDelay() {
|
||||
__asm__ __volatile__ (
|
||||
"ldi r25,%[count]\n"
|
||||
"1:dec r25\n"
|
||||
"brne 1b\n"
|
||||
"ret\n"
|
||||
::[count] "M" (UART_B_VALUE)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
void getNch(uint8_t count) {
|
||||
do getch(); while (--count);
|
||||
verifySpace();
|
||||
}
|
||||
|
||||
void verifySpace()
|
||||
{
|
||||
if ( getch() != CRC_EOP) {
|
||||
|
||||
putch(STK_NOSYNC);
|
||||
// watchdogConfig(WATCHDOG_16MS); // shorten WD timeout
|
||||
//
|
||||
// while (1) // and busy-loop so that WD causes
|
||||
// ; // a reset and app start.
|
||||
}
|
||||
putch(STK_INSYNC);
|
||||
}
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
void flash_led(uint8_t count) {
|
||||
do {
|
||||
TCNT1 = -(F_CPU/(1024*16));
|
||||
TIFR1 = _BV(TOV1);
|
||||
while(!(TIFR1 & _BV(TOV1)));
|
||||
//#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
watchdogReset();
|
||||
} while (--count);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Watchdog functions. These are only safe with interrupts turned off.
|
||||
void watchdogReset() {
|
||||
__asm__ __volatile__ (
|
||||
"wdr\n"
|
||||
);
|
||||
}
|
||||
|
||||
//void watchdogConfig(uint8_t x) {
|
||||
// WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||
// WDTCSR = x;
|
||||
//}
|
||||
|
||||
void init()
|
||||
{
|
||||
// Enable external oscillator (16MHz)
|
||||
OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_256CLK_gc ;
|
||||
OSC.CTRL |= OSC_XOSCEN_bm ;
|
||||
while( ( OSC.STATUS & OSC_XOSCRDY_bm ) == 0 )
|
||||
/* wait */ ;
|
||||
// Enable PLL (*2 = 32MHz)
|
||||
OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2 ;
|
||||
OSC.CTRL |= OSC_PLLEN_bm ;
|
||||
while( ( OSC.STATUS & OSC_PLLRDY_bm ) == 0 )
|
||||
/* wait */ ;
|
||||
// Switch to PLL clock
|
||||
CPU_CCP = 0xD8 ;
|
||||
CLK.CTRL = CLK_SCLKSEL_RC2M_gc ;
|
||||
CPU_CCP = 0xD8 ;
|
||||
CLK.CTRL = CLK_SCLKSEL_PLL_gc ;
|
||||
|
||||
PMIC.CTRL = 7 ; // Enable all interrupt levels
|
||||
|
||||
|
||||
// Timer1 config
|
||||
// TCC1 16-bit timer, clocked at 0.5uS
|
||||
EVSYS.CH3MUX = 0x80 + 0x07 ; // Prescaler of 128
|
||||
TCC1.CTRLB = 0; TCC1.CTRLC = 0; TCC1.CTRLD = 0; TCC1.CTRLE = 0;
|
||||
TCC1.INTCTRLA = 0 ;
|
||||
TCC1.INTCTRLB = 0 ;
|
||||
TCC1.PER = 0xFFFF ;
|
||||
TCC1.CNT = 0 ;
|
||||
TCC1.CTRLA = 0x0B ; // Event3 (prescale of 16)
|
||||
|
||||
PORTD.OUTSET = 0x04 ;
|
||||
PORTD.DIRCLR = 0x04 ;
|
||||
PORTD.PIN2CTRL = 0x18 ; // Pullup
|
||||
|
||||
PORTC.OUTSET = 0x08 ;
|
||||
PORTC.DIRSET = 0x08 ;
|
||||
|
||||
USARTC0.BAUDCTRLA = 34 ; // 57600
|
||||
USARTC0.BAUDCTRLB = 0 ;
|
||||
|
||||
USARTC0.CTRLB = 0x18 ; // Enable Tx and Rx
|
||||
USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) ;
|
||||
USARTC0.CTRLC = 0x03 ; // 8 bit, no parity, 1 stop
|
||||
USARTC0.DATA ;
|
||||
}
|
||||
|
||||
void boot_spm_busy_wait()
|
||||
{
|
||||
while(NVM.STATUS & NVM_NVMBUSY_bm)
|
||||
;
|
||||
}
|
||||
|
||||
#define A_NVM_CMD 0x1CA
|
||||
|
||||
void __boot_page_erase_short( uint16_t address )
|
||||
{
|
||||
asm( "push r24" ) ;
|
||||
asm( "push r25" ) ;
|
||||
NVM.CMD = NVM_CMD_ERASE_APP_PAGE_gc ;
|
||||
asm( "pop r31" ) ;
|
||||
asm( "pop r30" ) ;
|
||||
CCP = CCP_SPM_gc ;
|
||||
asm( "spm" ) ;
|
||||
}
|
||||
|
||||
void __boot_erase_flash_buffer( uint16_t address )
|
||||
{
|
||||
asm( "movw r30,r24" ) ;
|
||||
asm( "ldi r24,0x26" ) ;
|
||||
asm("sts 0x1CA,r24");
|
||||
CCP = CCP_IOREG_gc ;
|
||||
asm( "ldi r24,1" ) ;
|
||||
asm("sts 0x1CB,r24");
|
||||
}
|
||||
|
||||
void __boot_page_fill_short( uint16_t address, uint16_t data)
|
||||
{
|
||||
asm( "push r0" ) ;
|
||||
asm( "push r1" ) ;
|
||||
asm( "movw r30,r24" ) ;
|
||||
asm( "mov r0,r22" ) ;
|
||||
asm( "mov r1,r23" ) ;
|
||||
asm( "ldi r24,0x23" ) ;
|
||||
asm("sts 0x1CA,r24");
|
||||
CCP = CCP_SPM_gc ;
|
||||
asm( "spm" ) ;
|
||||
asm( "pop r1" ) ;
|
||||
asm( "pop r0" ) ;
|
||||
}
|
||||
|
||||
void __boot_page_write_short( uint16_t address)
|
||||
{
|
||||
asm( "movw r30,r24" ) ;
|
||||
asm( "ldi r24,0x2E" ) ;
|
||||
asm("sts 0x1CA,r24");
|
||||
CCP = CCP_SPM_gc ;
|
||||
asm( "spm" ) ;
|
||||
}
|
||||
|
||||
void appStart()
|
||||
{
|
||||
// watchdogConfig(WATCHDOG_OFF);
|
||||
// __asm__ __volatile__ (
|
||||
//#ifdef VIRTUAL_BOOT_PARTITION
|
||||
// // Jump to WDT vector
|
||||
// "ldi r30,4\n"
|
||||
// "clr r31\n"
|
||||
//#else
|
||||
// // Jump to RST vector
|
||||
// "clr r30\n"
|
||||
// "clr r31\n"
|
||||
//#endif
|
||||
// "ijmp\n"
|
||||
// );
|
||||
|
||||
register void (*p)() ;
|
||||
p = 0 ;
|
||||
|
||||
if ( pgm_read_byte( (uint16_t)p ) != 0xFF )
|
||||
{
|
||||
(*p)() ;
|
||||
}
|
||||
}
|
||||
|
||||
80
BootLoaders/OrangeMultiBoot/Source/pin_defs.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB5
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega8__)
|
||||
//Name conversion R.Wiersma
|
||||
#define UCSR0A UCSRA
|
||||
#define UDR0 UDR
|
||||
#define UDRE0 UDRE
|
||||
#define RXC0 RXC
|
||||
#define FE0 FE
|
||||
#define TIFR1 TIFR
|
||||
#define WDTCSR WDTCR
|
||||
#endif
|
||||
|
||||
/* Luminet support */
|
||||
#if defined(__AVR_ATtiny84__)
|
||||
/* Red LED is connected to pin PA4 */
|
||||
#define LED_DDR DDRA
|
||||
#define LED_PORT PORTA
|
||||
#define LED_PIN PINA
|
||||
#define LED PINA4
|
||||
/* Ports for soft UART - left port only for now. TX/RX on PA2/PA3 */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTA
|
||||
#define UART_PIN PINA
|
||||
#define UART_DDR DDRA
|
||||
#define UART_TX_BIT 2
|
||||
#define UART_RX_BIT 3
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Sanguino support */
|
||||
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
|
||||
/* Onboard LED is connected to pin PB0 on Sanguino */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB0
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Mega support */
|
||||
#if defined(__AVR_ATmega1280__)
|
||||
/* Onboard LED is connected to pin PB7 on Arduino Mega */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB7
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTE
|
||||
#define UART_PIN PINE
|
||||
#define UART_DDR DDRE
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
39
BootLoaders/OrangeMultiBoot/Source/stk500.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* STK500 constants list, from AVRDUDE */
|
||||
#define STK_OK 0x10
|
||||
#define STK_FAILED 0x11 // Not used
|
||||
#define STK_UNKNOWN 0x12 // Not used
|
||||
#define STK_NODEVICE 0x13 // Not used
|
||||
#define STK_INSYNC 0x14 // ' '
|
||||
#define STK_NOSYNC 0x15 // Not used
|
||||
#define ADC_CHANNEL_ERROR 0x16 // Not used
|
||||
#define ADC_MEASURE_OK 0x17 // Not used
|
||||
#define PWM_CHANNEL_ERROR 0x18 // Not used
|
||||
#define PWM_ADJUST_OK 0x19 // Not used
|
||||
#define CRC_EOP 0x20 // 'SPACE'
|
||||
#define STK_GET_SYNC 0x30 // '0'
|
||||
#define STK_GET_SIGN_ON 0x31 // '1'
|
||||
#define STK_SET_PARAMETER 0x40 // '@'
|
||||
#define STK_GET_PARAMETER 0x41 // 'A'
|
||||
#define STK_SET_DEVICE 0x42 // 'B'
|
||||
#define STK_SET_DEVICE_EXT 0x45 // 'E'
|
||||
#define STK_ENTER_PROGMODE 0x50 // 'P'
|
||||
#define STK_LEAVE_PROGMODE 0x51 // 'Q'
|
||||
#define STK_CHIP_ERASE 0x52 // 'R'
|
||||
#define STK_CHECK_AUTOINC 0x53 // 'S'
|
||||
#define STK_LOAD_ADDRESS 0x55 // 'U'
|
||||
#define STK_UNIVERSAL 0x56 // 'V'
|
||||
#define STK_PROG_FLASH 0x60 // '`'
|
||||
#define STK_PROG_DATA 0x61 // 'a'
|
||||
#define STK_PROG_FUSE 0x62 // 'b'
|
||||
#define STK_PROG_LOCK 0x63 // 'c'
|
||||
#define STK_PROG_PAGE 0x64 // 'd'
|
||||
#define STK_PROG_FUSE_EXT 0x65 // 'e'
|
||||
#define STK_READ_FLASH 0x70 // 'p'
|
||||
#define STK_READ_DATA 0x71 // 'q'
|
||||
#define STK_READ_FUSE 0x72 // 'r'
|
||||
#define STK_READ_LOCK 0x73 // 's'
|
||||
#define STK_READ_PAGE 0x74 // 't'
|
||||
#define STK_READ_SIGN 0x75 // 'u'
|
||||
#define STK_READ_OSCCAL 0x76 // 'v'
|
||||
#define STK_READ_FUSE_EXT 0x77 // 'w'
|
||||
#define STK_READ_OSCCAL_EXT 0x78 // 'x'
|
||||
2
BootLoaders/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## Page Moved
|
||||
Moved to [/docs/Arduino_IDE_Boards.md](/docs/Arduino_IDE_Boards.md).
|
||||
1
BootLoaders/StmMultiBoot/README.md
Normal file
@@ -0,0 +1 @@
|
||||
[Source for the StmMultiBooloader](https://github.com/MikeBland/StmMultiBoot)
|
||||
BIN
BootLoaders/StmMultiBoot/StmMultiBoot.bin
Normal file
2
BootLoaders/StmMultiUSB/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
[Source for the StmMultiUSB=STM32duino-bootloader](https://github.com/rogerclarkmelbourne/STM32duino-bootloader)
|
||||
If you want the latest version, you should look for the file generic_boot20_pa1.bin.
|
||||
BIN
BootLoaders/StmMultiUSB/StmMultiUSB.bin
Normal file
657
BootLoaders/package_multi_4in1_board_index.json
Normal file
@@ -0,0 +1,657 @@
|
||||
{
|
||||
"packages": [{
|
||||
"name": "multi4in1",
|
||||
"maintainer": "Pascal Langer",
|
||||
"websiteURL": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module",
|
||||
"email": "pascal_langer@yahoo.fr",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"platforms": [
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.2.tar.gz",
|
||||
"checksum": "SHA-256:b7e2fda37186bf696b7a769b12317737d513181096b33d9ad321ec2fd47f3f80",
|
||||
"size": "164467",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.3.tar.gz",
|
||||
"checksum": "SHA-256:7d4561eebe0d7f6422f06d5719a417e15fcc0aa9cdbfc1c48a57066ce768e33c",
|
||||
"size": "164483",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.4.tar.gz",
|
||||
"checksum": "SHA-256:6c51a4eb09bcd074cc651dab3f2356ea3afd358f6330aba0d8bdfaa75f718dbb",
|
||||
"size": "167975",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.5.tar.gz",
|
||||
"checksum": "SHA-256:0a4754d47cdbb49ca194b15835686331530ed9d36c0db093a29ae5f865e75421",
|
||||
"size": "169830",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.6.tar.gz",
|
||||
"checksum": "SHA-256:4f4cf8820e30bf6c88f280514c67ee67b9dc6649f439597cfb8d0be3a5b13bf5",
|
||||
"size": "169819",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.7.tar.gz",
|
||||
"checksum": "SHA-256:453c9999e433ed1bdda2ba2b12cb7cbba7b547591db969dc6b7efb941b61cf76",
|
||||
"size": "169825",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.8",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.8.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.8.tar.gz",
|
||||
"checksum": "SHA-256:8e58b8733220d56155e10bf5bec0bfe6bf96f8460b3fd49a4b45c7f9fad776cb",
|
||||
"size": "293388",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.9",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.9.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.9.tar.gz",
|
||||
"checksum": "SHA-256:269c4ddcb8018be2b31f5c9e9f0814d120af492e894b8d5098a814486d56faa5",
|
||||
"size": "318437",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.1.0",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.1.0.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.1.0.tar.gz",
|
||||
"checksum": "SHA-256:7bacf2db754ceb890a203de5ce89d97aa787a9e6462debeb44cf04830859687a",
|
||||
"size": "326431",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "MULTI-Module AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.1.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.1.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.1.1.tar.gz",
|
||||
"checksum": "SHA-256:02158258b4dbaca61bedbb6933336200d13b02ad0db981e2dda253682c482e99",
|
||||
"size": "324512",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.1.tar.gz",
|
||||
"checksum": "SHA-256:b522b5d3474308768c197a6897cad037fb54d6fac26c75678415a0908793bae3",
|
||||
"size": "10332875",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.2.tar.gz",
|
||||
"checksum": "SHA-256:26d21dbd2fe80680ac523b8bca24b3ecf2c2016bac626826d20b651e11278287",
|
||||
"size": "10318646",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.3.tar.gz",
|
||||
"checksum": "SHA-256:e48f1f30948b3f7be83e8b1fe2bb5c6b41be7c4d5da02503a0b4827c60926541",
|
||||
"size": "10309833",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.4.tar.gz",
|
||||
"checksum": "SHA-256:388a4dbcd567f9d41b82955e12e8a640d9696217081c0ee6ab8c58a25aedf70f",
|
||||
"size": "10307581",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.5.tar.gz",
|
||||
"checksum": "SHA-256:46d3b4e62fc46e6b8ca4f429974ffd2ee8cde9e29a6e0cda58f85044991a9c2b",
|
||||
"size": "10313436",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.6.tar.gz",
|
||||
"checksum": "SHA-256:ad7a330326069a5ffb2908495b288933f68517b1247cc6636b160eb483a58284",
|
||||
"size": "10319669",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.7.tar.gz",
|
||||
"checksum": "SHA-256:f73fded48beaee55e646a3cf36d24beeedc336873c7824683a4912f2aee9e350",
|
||||
"size": "10322111",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.8",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.8.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.8.tar.gz",
|
||||
"checksum": "SHA-256:f8100272ec615074cf7962c2c8331014ebda78f3e4c17172b88b6dd3d83c4331",
|
||||
"size": "10319134",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.9",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.9.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.9.tar.gz",
|
||||
"checksum": "SHA-256:c3621d1cf6580ca5c943a67dc14dc15a60e2797a4b985548abe1919486bf4a8b",
|
||||
"size": "10324251",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.0",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.0.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.0.tar.gz",
|
||||
"checksum": "SHA-256:919ece2021757686e6892679956dcb8a01c9308a152167d61d9204656b4ed7ee",
|
||||
"size": "10333612",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.1.tar.gz",
|
||||
"checksum": "SHA-256:549dbfa0f48f3e519a9efa96d03e8933cc72989c618826b2b570980d9c382979",
|
||||
"size": "10331547",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.2.tar.gz",
|
||||
"checksum": "SHA-256:debfdc14df3023045a2297bc99daf7104be75f21572fc5a4f57192ffae4028f0",
|
||||
"size": "10322776",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.3.tar.gz",
|
||||
"checksum": "SHA-256:6b9dceb033ccc31f37cebc4f025ddb862cd24a733e7c356ca2fa5719d595af89",
|
||||
"size": "10322145",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.4.tar.gz",
|
||||
"checksum": "SHA-256:16a83a3b4409cb55aead6593396979483996080634d214ae07c8a956db2480fb",
|
||||
"size": "10322152",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.5.tar.gz",
|
||||
"checksum": "SHA-256:2d45c95f59b4fb9fc7f7bf8caca2dd8c13b4258141c20db6169e0c7faf72e5e4",
|
||||
"size": "7930904",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.6.tar.gz",
|
||||
"checksum": "SHA-256:d2d1ef721bbcdc3c680c6f98b4b8ab394478ac0f82d67af2f6c389a4a30789f4",
|
||||
"size": "7962942",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.7.tar.gz",
|
||||
"checksum": "SHA-256:37cccde7eafad3d0587d28d13d5f8b2b3244bf7c83e6819b6cb08f4f468815e2",
|
||||
"size": "7966348",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi X-in-1 STM32 Boards",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.8",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.8.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.8.tar.gz",
|
||||
"checksum": "SHA-256:e9ed8055ebf72abf37e60e1b8d1c6ee5472132ea7c0a3c4a63fbb8442613e4c2",
|
||||
"size": "7481800",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (STM32F103C)"},
|
||||
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
|
||||
],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi X-in-1 STM32 Boards",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.2.0",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.2.0.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.2.0.tar.gz",
|
||||
"checksum": "SHA-256:754f08ca2a553701cc9112b645c079b6041107f1bf863648305e560c136a6ac5",
|
||||
"size": "7496214",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (STM32F103C)"},
|
||||
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
|
||||
],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi X-in-1 STM32 Boards",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.2.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.2.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.2.1.tar.gz",
|
||||
"checksum": "SHA-256:c66d34afadc5b21e9e28c4d477fa03a6d55db0b74b59ff2dcb07b4d6ef06da1a",
|
||||
"size": "7496448",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (STM32F103C)"},
|
||||
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
|
||||
],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "MULTI-Module STM32 Boards",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.2.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.2.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.2.2.tar.gz",
|
||||
"checksum": "SHA-256:0fe4a8899438bbc31dc37714acca13968e43d75a47e59143343d83b634d2e47d",
|
||||
"size": "7485662",
|
||||
"boards": [
|
||||
{"name": "Multi X-in-1 STM32F103CB (128KB)"},
|
||||
{"name": "Multi X-in-1 STM32F103C8 (64KB)"},
|
||||
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
|
||||
],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 OrangeRX Board - DEPRECATED, USE MULTI 4-IN-1 AVR BOARDS PACKAGE INSTEAD",
|
||||
"architecture": "orangerx",
|
||||
"version": "1.0.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_orangerx_board_v1.0.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_orangerx_board_v1.0.1.tar.gz",
|
||||
"checksum": "SHA-256:7287ce61028b754bb8ff947317dd15773fc7eeecd752826c707fa356b9b36dc6",
|
||||
"size": "161615",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (OrangeRX)"
|
||||
}],
|
||||
"toolsDependencies": []
|
||||
}
|
||||
],
|
||||
"tools": []
|
||||
}]
|
||||
}
|
||||
549
Lua_scripts/DSM FwdPrg_05_BW.lua
Normal file
@@ -0,0 +1,549 @@
|
||||
local toolName = "TNS|DSM Forward Prog v0.54 (Text B&W) |TNE"
|
||||
local VERSION = "v0.54"
|
||||
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
------------------------------------------------------------------------------
|
||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
||||
-- separate the GUI from the DSM Forward programming engine/logic
|
||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
||||
|
||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
-- Rewrite/Enhancements By: Francisco Arzu
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local SIMULATION_ON = false -- FALSE: don't show simulation menu (DEFAULT), TRUE: show simulation menu
|
||||
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
|
||||
local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
|
||||
|
||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
||||
|
||||
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON)
|
||||
|
||||
local PHASE = dsmLib.PHASE
|
||||
local LINE_TYPE = dsmLib.LINE_TYPE
|
||||
local DISP_ATTR = dsmLib.DISP_ATTR
|
||||
|
||||
local DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
local IS_EDGETX = false -- DEFAULT until Init changed it
|
||||
|
||||
local LCD_W_USABLE = LCD_W-10
|
||||
-- X for Menu Lines
|
||||
local LCD_X_LINE_MENU = 10
|
||||
-- X offsets for (Title: [Value] debugInfo) lines
|
||||
local LCD_X_LINE_TITLE = 10
|
||||
local LCD_X_LINE_VALUE = 230
|
||||
local LCD_X_LINE_DEBUG = 390
|
||||
|
||||
-- Line Height: make it smaller debugging info tp LCD (some space buttom)
|
||||
local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27
|
||||
-- Y offsets
|
||||
local LCD_Y_MENU_TITLE = 20
|
||||
-- Y offet
|
||||
local LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 30
|
||||
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT
|
||||
|
||||
local LCD_W_BUTTONS = 47
|
||||
local LCD_H_BUTTONS = 25
|
||||
local LCD_X_RIGHT_BUTTONS = LCD_W - LCD_W_BUTTONS - 5
|
||||
|
||||
local TEXT_SIZE = 0 -- NORMAL
|
||||
|
||||
local lastRefresh=0 -- Last time the screen was refreshed
|
||||
local REFRESH_GUI_MS = 500/10 -- 500ms.. Screen Refresh Rate.. to not use unneded CPU time (in 10ms units to be compatible with getTime())
|
||||
local originalValue = nil
|
||||
|
||||
local warningScreenON = true
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_SwitchToRX()
|
||||
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
|
||||
local dsmChannelInfo, description = dsmLib.CreateDSMPortChannelInfo()
|
||||
|
||||
dsmLib.ReleaseConnection()
|
||||
dsmLib.LOG_close()
|
||||
|
||||
SIMULATION_ON = false
|
||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
|
||||
DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library
|
||||
dsmLib.StartConnection()
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function GUI_SwitchToSIM()
|
||||
dsmLib.ReleaseConnection()
|
||||
dsmLib.LOG_close()
|
||||
|
||||
SIMULATION_ON = true
|
||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
|
||||
DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
dsmLib.StartConnection()
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function openTx_lcd_sizeText(s)
|
||||
return string.len(s)*5
|
||||
end
|
||||
|
||||
local function GUI_Diplay_Button(x,y,w,h,text,selected)
|
||||
local attr = (selected) and INVERS or 0 -- INVERS if line Selected
|
||||
if (TEXT_SIZE~=SMLSIZE) then
|
||||
lcd.drawText(x+5,y+2, text, attr + TEXT_SIZE)
|
||||
lcd.drawRectangle(x, y, w, h, LINE_COLOR)
|
||||
else -- SMALL Screen
|
||||
lcd.drawText(x,y, text, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
|
||||
local function GUI_Display_Menu(menu)
|
||||
local ctx = DSM_Context
|
||||
local w= LCD_W_USABLE - LCD_W_BUTTONS - 10 -- usable Width for the Menu/Lines
|
||||
|
||||
-- Center Header
|
||||
local tw = openTx_lcd_sizeText(menu.Text)
|
||||
local x = w/2 - tw/2 -- Center of Screen - Center of Text
|
||||
if (x < 0) then x=0 end -- in case text is too wide
|
||||
|
||||
local bold = BOLD
|
||||
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text,bold + TEXT_SIZE)
|
||||
|
||||
-- Back
|
||||
if menu.BackId ~= 0 then
|
||||
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_MENU_TITLE,LCD_W_BUTTONS,LCD_H_BUTTONS,"Back",ctx.SelLine == dsmLib.BACK_BUTTON)
|
||||
end
|
||||
-- Next ?
|
||||
if menu.NextId ~= 0 then
|
||||
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON)
|
||||
end
|
||||
-- Prev?
|
||||
if menu.PrevId ~= 0 then
|
||||
GUI_Diplay_Button(0,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON)
|
||||
end
|
||||
|
||||
-- Debug into LCD
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),TEXT_SIZE + WARNING_COLOR) end -- Phase we are in
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_MENU,240,dsmLib.menu2String(menu),TEXT_SIZE + WARNING_COLOR) end -- Menu Info
|
||||
end
|
||||
|
||||
local function GUI_Display_Line_Menu(x,y,w,h,line,selected)
|
||||
local attr = (selected and INVERS) or 0 -- INVERS if line Selected
|
||||
local bold = 0
|
||||
local text = line.Text
|
||||
|
||||
if dsmLib.isSelectableLine(line) then
|
||||
-- Menu Line
|
||||
text = text .. " >"
|
||||
else -- SubHeaders and plain text lines
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
||||
local tw = openTx_lcd_sizeText(line.Text)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
||||
local tw = openTx_lcd_sizeText(line.Text)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
if (x < 0) then x=0 end -- in case text is too wide
|
||||
end
|
||||
|
||||
lcd.drawText(x,y, text, attr + bold + TEXT_SIZE)
|
||||
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
||||
local bold = 0
|
||||
|
||||
local y = LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||
local x = LCD_X_LINE_TITLE
|
||||
|
||||
---------- NAME Part
|
||||
local header = line.Text
|
||||
-- ONLY do this for Flight Mode (Right Align or Centered)
|
||||
if (dsmLib.isFlightModeLine(line)) then
|
||||
-- Display Header + Value together
|
||||
header = dsmLib.GetFlightModeValue(line)
|
||||
|
||||
-- Flight mode display attributes
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
||||
local tw = openTx_lcd_sizeText(header)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
||||
local tw = openTx_lcd_sizeText(header)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
if (x < 0) then x=0 end -- in case text is too wide
|
||||
else
|
||||
-- No Flight Mode, no effects here
|
||||
header = header .. ":"
|
||||
end
|
||||
|
||||
lcd.drawText(x, y, header, bold + TEXT_SIZE) -- display Line Header
|
||||
|
||||
--------- VALUE PART, Skip for Flight Mode since already show the value
|
||||
if not dsmLib.isFlightModeLine(line) then
|
||||
local attrib = 0
|
||||
|
||||
if selected then
|
||||
attrib = INVERS
|
||||
if editing then -- blink editing entry
|
||||
attrib = attrib + BLINK
|
||||
value = "[" .. value .. "]"
|
||||
end
|
||||
end
|
||||
|
||||
value = value .. " " .. (line.Format or "") -- Append % if needed
|
||||
lcd.drawText(LCD_X_LINE_VALUE,y, value, attrib + TEXT_SIZE) -- display value
|
||||
end
|
||||
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG,y, line.MinMaxDebug or "", TEXT_SIZE + WARNING_COLOR) end -- display debug
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_ShowBitmap(x,y,imgData)
|
||||
-- imgData format "bitmap.png|alt message"
|
||||
local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|'
|
||||
local imgName, imgMsg = f(), f()
|
||||
|
||||
if (LCD_W > 128) then
|
||||
lcd.drawText(x, y, imgMsg or "", TEXT_SIZE) -- Alternate Image MSG
|
||||
else
|
||||
local f = string.gmatch(imgMsg, '([^%:]+)') -- Iterator over values split by ':'
|
||||
local msg1,msg2 = f(), f()
|
||||
lcd.drawText(x, y, (msg1 or "")..":", TEXT_SIZE) -- Alternate Image MSG
|
||||
lcd.drawText(x, y+10, msg2 or "", TEXT_SIZE) -- Alternate Image MSG
|
||||
end
|
||||
|
||||
-- NO IMAGES in Text B&W
|
||||
--local imgPath = IMAGE_PATH .. (imgName or "")
|
||||
--local bitmap = Bitmap.open(imgPath)
|
||||
--if (bitmap~=nil) then
|
||||
-- lcd.drawBitmap(bitmap, x,y+20)
|
||||
--end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_Display()
|
||||
local ctx = DSM_Context
|
||||
lcd.clear()
|
||||
local header = "DSM Fwrd Programming "
|
||||
|
||||
if (TEXT_SIZE==SMLSIZE) then -- Small Screen no title
|
||||
header = ""
|
||||
end
|
||||
|
||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||
header = header .. ctx.RX.Name.." v"..ctx.RX.Version
|
||||
end
|
||||
|
||||
--Draw title
|
||||
if (TEXT_SIZE~=SMLSIZE) then -- ignore tool title small size screens
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
||||
else -- Small Screen
|
||||
lcd.drawText(20, LCD_Y_LOWER_BUTTONS+1, header, TEXT_SIZE)
|
||||
end
|
||||
--Draw RX Menu
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
if (ctx.isReset) then
|
||||
lcd.drawText(LCD_X_LINE_TITLE,50,dsmLib.Get_Text(0x301), BLINK + TEXT_SIZE) -- Resetting
|
||||
else
|
||||
lcd.drawText(LCD_X_LINE_TITLE,50,dsmLib.Get_Text(0x300), BLINK + TEXT_SIZE) -- Waiting for RX Version
|
||||
end
|
||||
else
|
||||
local menu = ctx.Menu
|
||||
if menu.Text ~= nil then
|
||||
|
||||
GUI_Display_Menu(menu)
|
||||
|
||||
for i = 0, dsmLib.MAX_MENU_LINES do
|
||||
local line = ctx.MenuLines[i]
|
||||
|
||||
if i == ctx.SelLine then
|
||||
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_TITLE,255,dsmLib.menuLine2String(line),TEXT_SIZE + WARNING_COLOR) end
|
||||
end
|
||||
|
||||
if line ~= nil and line.Type ~= 0 then
|
||||
if line.Type == LINE_TYPE.MENU then
|
||||
-- Menu Line
|
||||
GUI_Display_Line_Menu(LCD_X_LINE_MENU,LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*i), 350, LCD_Y_LINE_HEIGHT, line, i == ctx.SelLine)
|
||||
else
|
||||
-- list/value line
|
||||
local value = line.Val
|
||||
if line.Val ~= nil then
|
||||
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
|
||||
value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
||||
local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
|
||||
|
||||
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
||||
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_FIRST+LCD_Y_LINE_HEIGHT, imgData)
|
||||
end
|
||||
end
|
||||
|
||||
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
||||
end
|
||||
end -- if ~MENU
|
||||
end -- if Line[i]~=nil
|
||||
end -- for
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
|
||||
local inc = 0
|
||||
local Speed = getRotEncSpeed()
|
||||
|
||||
if Speed == ROTENC_MIDSPEED then
|
||||
inc = (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then
|
||||
inc = (15 * dir)
|
||||
else
|
||||
inc = dir
|
||||
end
|
||||
|
||||
return inc
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_HandleEvent(event, touchState)
|
||||
local ctx = DSM_Context
|
||||
local menu = ctx.Menu
|
||||
local menuLines = ctx.MenuLines
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
dsmLib.ReleaseConnection()
|
||||
else
|
||||
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
||||
ctx.MenuLines[ctx.EditLine].Val = originalValue
|
||||
dsmLib.Value_Write_Validate(menuLines[ctx.EditLine])
|
||||
else
|
||||
dsmLib.ChangePhase(PHASE.EXIT) -- Exit
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
dsmLib.Value_Add(line, GUI_RotEncVal(1))
|
||||
else -- not editing, move selected line to NEXT
|
||||
dsmLib.MoveSelectionLine(1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
dsmLib.Value_Add(line, GUI_RotEncVal(-1))
|
||||
else -- not editing, move selected line to PREV
|
||||
dsmLib.MoveSelectionLine(-1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER_LONG then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then
|
||||
-- reset the value to default
|
||||
dsmLib.Value_Default( menuLines[ctx.EditLine]) -- Update RX value as needed
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
|
||||
dsmLib.GotoMenu(menu.BackId,0x80)
|
||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
||||
dsmLib.GotoMenu(menu.NextId,0x82)
|
||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
||||
dsmLib.GotoMenu(menu.PrevId,0x81)
|
||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then
|
||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Next menu exist
|
||||
if (menuLines[ctx.SelLine].ValId==0xFFF1) then
|
||||
-- SPECIAL Simulation menu to Simulator
|
||||
GUI_SwitchToSIM()
|
||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
|
||||
-- SPECIAL Simulation menu to go to RX
|
||||
GUI_SwitchToRX()
|
||||
else
|
||||
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
||||
end
|
||||
else
|
||||
-- Editing a Line????
|
||||
if ctx.isEditing() then
|
||||
-- Change the Value and exit edit
|
||||
dsmLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
||||
else
|
||||
-- enter Edit the current line
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = menuLines[ctx.SelLine].Val
|
||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_screen_pos()
|
||||
-- osName in OpenTX is nil, otherwise is EDGETX
|
||||
local ver, radio, maj, minor, rev, osname = getVersion()
|
||||
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
|
||||
|
||||
IS_EDGETX = string.sub(osname,1,1) =='E'
|
||||
|
||||
if LCD_W == 480 then -- TX16
|
||||
-- use defaults in the script header
|
||||
elseif LCD_W == 128 then --TX12 (128x64) -- Still needs some work on the vertical
|
||||
DEBUG_ON_LCD = false -- no space for this
|
||||
TEXT_SIZE = SMLSIZE
|
||||
LCD_W_USABLE = 128
|
||||
|
||||
LCD_W_BUTTONS = 16
|
||||
LCD_H_BUTTONS = 10
|
||||
LCD_X_RIGHT_BUTTONS = 128 - LCD_W_BUTTONS - 3
|
||||
|
||||
LCD_X_LINE_MENU = 0
|
||||
-- X offsets for (Title: [Value] debugInfo) lines
|
||||
LCD_X_LINE_TITLE = 0
|
||||
LCD_X_LINE_VALUE = 75
|
||||
LCD_X_LINE_DEBUG = 110
|
||||
|
||||
LCD_Y_LINE_HEIGHT = 7
|
||||
LCD_Y_MENU_TITLE = 0
|
||||
LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 8
|
||||
LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + (7 * LCD_Y_LINE_HEIGHT)
|
||||
end
|
||||
end
|
||||
|
||||
local function GUI_Warning(event)
|
||||
lcd.clear()
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
--Draw title
|
||||
if (LCD_W > 128) then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, TITLE_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
||||
|
||||
lcd.drawText(100,20,"INFO", BOLD)
|
||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", TEXT_SIZE)
|
||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", TEXT_SIZE)
|
||||
lcd.drawText(5,80,"the TX before your start programming your RX.", TEXT_SIZE)
|
||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", TEXT_SIZE)
|
||||
|
||||
lcd.drawText(5,150,"TX Servo settings are sent to the RX during 'Initial Setup'", TEXT_SIZE)
|
||||
lcd.drawText(5,170,"as well as when using RX menu 'Relearn Servo Settings'", TEXT_SIZE)
|
||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD+TEXT_SIZE)
|
||||
|
||||
lcd.drawText(100,250," OK ", INVERS + BOLD + TEXT_SIZE)
|
||||
else
|
||||
lcd.drawText(0,15,"Make sure you setup your plane", TEXT_SIZE)
|
||||
lcd.drawText(0,22,"first. Wing and Tail type.", TEXT_SIZE)
|
||||
|
||||
lcd.drawText(0,30,"TX Servo settings are sent to ", TEXT_SIZE)
|
||||
lcd.drawText(0,37,"the RX during 'Initial Setup' and ", TEXT_SIZE)
|
||||
lcd.drawText(0,45,"ALWAYS TEST Gyro reactions", TEXT_SIZE)
|
||||
lcd.drawText(0,52,"before flying!!!", TEXT_SIZE)
|
||||
|
||||
lcd.drawText(10,0," OK ", INVERS + BOLD + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER then
|
||||
warningScreenON = false
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
init_screen_pos()
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
return dsmLib.StartConnection()
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
|
||||
|
||||
local function DSM_Run(event)
|
||||
local ctx = DSM_Context
|
||||
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
dsmLib.LOG_close()
|
||||
return 2
|
||||
end
|
||||
|
||||
if (warningScreenON) then
|
||||
return GUI_Warning(event)
|
||||
end
|
||||
|
||||
GUI_HandleEvent(event)
|
||||
|
||||
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
|
||||
|
||||
local refreshInterval = REFRESH_GUI_MS
|
||||
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
|
||||
if (ctx.EditLine or (ctx.Phase == PHASE.RX_VERSION)) then -- Editing or Requesting RX Version?
|
||||
ctx.Refresh_Display=true
|
||||
refreshInterval = 20 -- 200ms
|
||||
end
|
||||
|
||||
if (not IS_EDGETX) then -- OPENTX NEEDS REFRESH ON EVERY CYCLE
|
||||
GUI_Display()
|
||||
-- Refresh display only if needed and no faster than 500ms, utilize more CPU to speedup DSM communications
|
||||
elseif (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
|
||||
GUI_Display()
|
||||
ctx.Refresh_Display=false
|
||||
lastRefresh=getTime()
|
||||
end
|
||||
|
||||
if ctx.Phase == PHASE.EXIT_DONE then
|
||||
dsmLib.LOG_close()
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return { init=DSM_Init, run=DSM_Run }
|
||||
708
Lua_scripts/DSM FwdPrg_05_Color.lua
Normal file
@@ -0,0 +1,708 @@
|
||||
local toolName = "TNS|DSM Forward Prog v0.54 (Color+Touch) |TNE"
|
||||
local VERSION = "v0.54"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
------------------------------------------------------------------------------
|
||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
||||
-- separate the GUI from the DSM Forward programming engine/logic
|
||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
||||
|
||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
-- Rewrite/Enhancements By: Francisco Arzu
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local SIMULATION_ON = false -- FALSE:don't show simulation memu (DEFAULT), TRUE: show simulation menu
|
||||
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
|
||||
local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
|
||||
local USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX)
|
||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
||||
local IMAGE_PATH = DSMLIB_PATH .. "img/"
|
||||
|
||||
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON)
|
||||
|
||||
local PHASE = dsmLib.PHASE
|
||||
local LINE_TYPE = dsmLib.LINE_TYPE
|
||||
local DISP_ATTR = dsmLib.DISP_ATTR
|
||||
local DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
|
||||
local lastRefresh=0 -- Last time the screen was refreshed
|
||||
local REFRESH_GUI_MS = 300/10 -- 300ms.. Screen Refresh Rate.. to not waste CPU time (in 10ms units to be compatible with getTime())
|
||||
local originalValue = nil
|
||||
|
||||
local touchButtonArea = {}
|
||||
local EDIT_BUTTON = { DEFAULT=1001, DEC_10=1002, DEC_1=1003, INC_1=1004, INC_10=5, OK=1006, ESC=1007 }
|
||||
|
||||
local IS_EDGETX = false -- DEFAULT until Init changed it
|
||||
|
||||
local LCD_Y_MENU_TITLE = 20
|
||||
local LCD_W_MENU_TITLE = LCD_W-100
|
||||
|
||||
local LCD_X_LINE_MENU = 30
|
||||
local LCD_W_LINE_MENU = 350
|
||||
|
||||
local LCD_X_LINE_TITLE = 30
|
||||
local LCD_X_LINE_VALUE = 230
|
||||
local LCD_X_LINE_DEBUG = 390
|
||||
|
||||
|
||||
local LCD_Y_LINE_START = LCD_Y_MENU_TITLE + 30
|
||||
local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27
|
||||
|
||||
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT)
|
||||
|
||||
-- TOOL BG COLOR
|
||||
local LCD_TOOL_BGCOLOR = TEXT_BGCOLOR
|
||||
-- TOOL HEADER
|
||||
local LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR
|
||||
local LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR
|
||||
-- MENU HEADER
|
||||
local LCD_MENU_COLOR = MENU_TITLE_COLOR
|
||||
local LCD_MENU_BGCOLOR = MENU_TITLE_BGCOLOR
|
||||
-- LINE SELECTED
|
||||
local LCD_SELECTED_COLOR = TEXT_INVERTED_COLOR
|
||||
local LCD_SELECTED_BGCOLOR = TEXT_INVERTED_BGCOLOR
|
||||
local LCD_EDIT_BGCOLOR = MENU_TITLE_BGCOLOR -- WARNING_COLOR
|
||||
-- NORMAL TEXT
|
||||
local LCD_NORMAL_COLOR = TEXT_COLOR
|
||||
local LCD_DISABLE_COLOR = TEXT_DISABLE_COLOR
|
||||
local LCD_DEBUG_COLOR = LINE_COLOR
|
||||
-- NORMAL BOX FRAME COLOR
|
||||
local LCD_BOX_COLOR = TEXT_DISABLE_COLOR
|
||||
|
||||
|
||||
local warningScreenON = true
|
||||
|
||||
|
||||
--------------------- lcd.sizeText replacement -------------------------------------------------
|
||||
-- EdgeTx dont have lcd.sizeText, so we do an equivalent one using the string length and 5px per character
|
||||
local function my_lcd_sizeText(s)
|
||||
-- return: If IS_EDGETX then lcd.sizeText() else string.len()
|
||||
return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10)
|
||||
end
|
||||
|
||||
|
||||
local function GUI_SwitchToRX()
|
||||
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
|
||||
local dsmChannelInfo, description = dsmLib.CreateDSMPortChannelInfo()
|
||||
|
||||
dsmLib.ReleaseConnection()
|
||||
dsmLib.LOG_close()
|
||||
|
||||
SIMULATION_ON = false
|
||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
|
||||
DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library
|
||||
dsmLib.StartConnection()
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function GUI_SwitchToSIM()
|
||||
dsmLib.ReleaseConnection()
|
||||
dsmLib.LOG_close()
|
||||
|
||||
SIMULATION_ON = true
|
||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
|
||||
DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
dsmLib.StartConnection()
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
|
||||
--------------------- Toucch Button Helpers ------------------------------------------------------------
|
||||
local function GUI_addTouchButton(x,y,w,h,line)
|
||||
-- Add new button info to end of the array
|
||||
touchButtonArea[#touchButtonArea+1] = {x=x, y=y, w=w, h=h, line=line}
|
||||
end
|
||||
|
||||
local function GUI_getTouchButton(x,y)
|
||||
for i = 1, #touchButtonArea do
|
||||
local button = touchButtonArea[i]
|
||||
-- is the coordinate inside the button area??
|
||||
if (x >= button.x and x <= (button.x+button.w) and y >= button.y and (y <= button.y+button.h)) then
|
||||
return button.line
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function GUI_clearTouchButtons()
|
||||
touchButtonArea = {}
|
||||
end
|
||||
|
||||
---------- Return Color to display Menu Lines ----------------------------------------------------------------
|
||||
local function GUI_GetTextColor(lineNum)
|
||||
local ctx = DSM_Context
|
||||
local txtColor = LCD_NORMAL_COLOR
|
||||
-- Gray Out any other line except the one been edited
|
||||
if (ctx.isEditing() and ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
|
||||
return txtColor
|
||||
end
|
||||
|
||||
local function GUI_GetFrameColor(lineNum) -- Frame Color for Value/Menu Boxes
|
||||
local ctx = DSM_Context
|
||||
local txtColor = LCD_BOX_COLOR
|
||||
-- Gray Out any other line except the one been edited
|
||||
if (ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
|
||||
return txtColor
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
-- Display Text inside a Rectangle. Inv: true means solid rectangle, false=only perimeter
|
||||
local function GUI_Display_Boxed_Text(lineNum,x,y,w,h,text,inv, isNumber)
|
||||
local ctx = DSM_Context
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local frameColor = GUI_GetFrameColor(lineNum)
|
||||
-- If editing this lineNum, chose EDIT Color, else SELECTED Color
|
||||
local selectedBGColor = (ctx.EditLine==lineNum and LCD_EDIT_BGCOLOR) or LCD_SELECTED_BGCOLOR
|
||||
|
||||
if (inv) then
|
||||
txtColor = LCD_SELECTED_COLOR
|
||||
lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor)
|
||||
else
|
||||
lcd.drawRectangle(x-5, y-2, w, h, frameColor)
|
||||
end
|
||||
if (isNumber) then
|
||||
lcd.drawNumber(x+w-10 , y, text, txtColor + RIGHT)
|
||||
else
|
||||
lcd.drawText(x , y, text, txtColor)
|
||||
end
|
||||
end
|
||||
|
||||
------ Display Pre/Next/Back buttons
|
||||
local function GUI_Diplay_Button(x,y,w,h,text,selected)
|
||||
GUI_Display_Boxed_Text(-1,x,y,w,h,text,selected, false)
|
||||
end
|
||||
|
||||
------ Display MENU type of lines (Navigation, SubHeaders, and plain text comments)
|
||||
local function GUI_Display_Line_Menu(lineNum,line,selected)
|
||||
-- Menu Lines can be navidation to other Menus (if Selectable)
|
||||
-- Or SubHeaders or Messages
|
||||
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||
local x = LCD_X_LINE_MENU
|
||||
|
||||
if dsmLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes
|
||||
GUI_Display_Boxed_Text(lineNum,x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT, line.Text,selected, false)
|
||||
GUI_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum)
|
||||
else
|
||||
-- Non Selectable Menu Lines, plain text
|
||||
-- Can be use for sub headers or just regular text lines (like warnings)
|
||||
|
||||
local bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
||||
local tw = my_lcd_sizeText(line.Text)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
||||
local tw = my_lcd_sizeText(line.Text)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
|
||||
lcd.drawText(x, y, line.Text, txtColor + bold)
|
||||
end
|
||||
end
|
||||
|
||||
------ Display NAME : VALUES type of lines
|
||||
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
||||
-- This Displays Name and Value Pairs
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local bold = 0
|
||||
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||
local x = LCD_X_LINE_TITLE
|
||||
|
||||
---------- NAME Part
|
||||
local header = line.Text
|
||||
-- ONLY do this for Flight Mode (Right Align or Centered)
|
||||
if (dsmLib.isFlightModeLine(line)) then
|
||||
-- Display Header + Value together
|
||||
header = dsmLib.GetFlightModeValue(line)
|
||||
|
||||
-- Bold Text???
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
||||
local tw = my_lcd_sizeText(header)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
||||
local tw = my_lcd_sizeText(header)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
else
|
||||
-- No Flight Mode, no effects here
|
||||
header = header .. ":"
|
||||
end
|
||||
|
||||
lcd.drawText(x, y, header, txtColor + bold) -- display Line Header
|
||||
|
||||
--------- VALUE PART, Skip for Flight Mode since already show the value
|
||||
if not dsmLib.isFlightModeLine(line) then
|
||||
if dsmLib.isSelectableLine(line) then
|
||||
--if (editing) then -- Any Special color/effect when editing??
|
||||
-- value = "["..value .. "]"
|
||||
--end
|
||||
-- Can select/edit value, Box it
|
||||
local tw = math.max(my_lcd_sizeText(value)+10,45) -- Width of the Text in the lcd
|
||||
GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected, not dsmLib.isListLine(line))
|
||||
GUI_addTouchButton(LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,lineNum)
|
||||
|
||||
lcd.drawText(LCD_X_LINE_VALUE+tw+5, y, (line.Format or ""), txtColor + bold)
|
||||
else -- Not Editable, Plain Text
|
||||
lcd.drawText(LCD_X_LINE_VALUE, y, value, txtColor)
|
||||
end
|
||||
end
|
||||
|
||||
-- Debug info for line Value RANGE when Debug on LCD
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG, y, line.MinMaxDebug or "", SMLSIZE + LCD_DEBUG_COLOR) end -- display debug Min/Max
|
||||
end
|
||||
|
||||
local function GUI_Display_Menu(menu)
|
||||
local ctx = DSM_Context
|
||||
local w= LCD_W_MENU_TITLE
|
||||
|
||||
-- Center Header
|
||||
local tw = my_lcd_sizeText(menu.Text)
|
||||
local x = w/2 - tw/2 -- Center of Screen - Center of Text
|
||||
|
||||
lcd.drawFilledRectangle(0, LCD_Y_MENU_TITLE-2, w, LCD_Y_LINE_HEIGHT-2, LCD_MENU_BGCOLOR)
|
||||
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text, LCD_MENU_COLOR + BOLD)
|
||||
|
||||
-- Back Button
|
||||
if menu.BackId ~= 0 then
|
||||
GUI_Diplay_Button(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,"Back",ctx.SelLine == dsmLib.BACK_BUTTON)
|
||||
GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,dsmLib.BACK_BUTTON)
|
||||
end
|
||||
-- Next Button
|
||||
if menu.NextId ~= 0 then
|
||||
GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON)
|
||||
GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.NEXT_BUTTON)
|
||||
end
|
||||
-- Prev Button
|
||||
if menu.PrevId ~= 0 then
|
||||
GUI_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON)
|
||||
GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.PREV_BUTTON)
|
||||
end
|
||||
|
||||
-- Debug on LCD, Show the menu Indo and Phase we are on
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),SMLSIZE+LCD_DEBUG_COLOR) end -- Phase we are in
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(0,240,dsmLib.menu2String(menu),SMLSIZE+LCD_DEBUG_COLOR) end -- Menu Info
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Display the EDIT mode buttons when editing a value
|
||||
|
||||
local function GUI_Display_Edit_Buttons(line)
|
||||
GUI_clearTouchButtons() -- Only this buttons can be touched
|
||||
local x = 15 -- Inittial X position
|
||||
local w = 55 -- Width of the buttons
|
||||
|
||||
local showPrev = line.Val > line.Min
|
||||
local showNext = line.Val < line.Max
|
||||
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,"ESC",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.ESC)
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," Def",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT)
|
||||
|
||||
x=x+w+10
|
||||
if (not dsmLib.isListLine(line)) then
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," << ",showPrev)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_10)
|
||||
end
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," <",showPrev)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_1)
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >",showNext)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1)
|
||||
|
||||
x=x+w+10
|
||||
if (not dsmLib.isListLine(line)) then
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >>",showNext)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_10)
|
||||
end
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," OK",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.OK)
|
||||
|
||||
end
|
||||
|
||||
local function GUI_ShowBitmap(x,y,imgData)
|
||||
-- imgData format "bitmap.png|alt message"
|
||||
local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|'
|
||||
local imgName, imgMsg = f(), f()
|
||||
|
||||
lcd.drawText(x, y, imgMsg or "") -- Alternate Image MSG
|
||||
|
||||
local imgPath = IMAGE_PATH .. (imgName or "")
|
||||
local bitmap = Bitmap.open(imgPath)
|
||||
if (bitmap~=nil) then
|
||||
lcd.drawBitmap(bitmap, x,y+20)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_Display()
|
||||
local ctx = DSM_Context
|
||||
lcd.clear(LCD_TOOL_BGCOLOR)
|
||||
GUI_clearTouchButtons()
|
||||
|
||||
if LCD_W == 480 then
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||
header = header .. "RX "..ctx.RX.Name.." v"..ctx.RX.Version
|
||||
end
|
||||
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
||||
--Draw RX Menu
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
if (ctx.isReset) then
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x301), BLINK) -- Waiting for Restart
|
||||
else
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x300), BLINK) -- Waiting for RX
|
||||
end
|
||||
else
|
||||
local menu = ctx.Menu
|
||||
|
||||
|
||||
if menu.Text ~= nil then
|
||||
GUI_Display_Menu(menu)
|
||||
|
||||
for i = 0, dsmLib.MAX_MENU_LINES do
|
||||
local line = ctx.MenuLines[i]
|
||||
|
||||
if i == ctx.SelLine then
|
||||
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(0,255,dsmLib.menuLine2String(line),SMLSIZE + LCD_DEBUG_COLOR) end
|
||||
end
|
||||
|
||||
if line ~= nil and line.Type ~= 0 then
|
||||
if line.Type == LINE_TYPE.MENU then
|
||||
GUI_Display_Line_Menu(i, line, i == ctx.SelLine)
|
||||
else
|
||||
if line.Val ~= nil then
|
||||
local value = line.Val
|
||||
|
||||
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
|
||||
value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
||||
local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
|
||||
|
||||
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
||||
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_START, imgData)
|
||||
end
|
||||
end
|
||||
|
||||
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
||||
end
|
||||
end -- if ~MENU
|
||||
end -- if Line[i]~=nil
|
||||
end -- for
|
||||
|
||||
if IS_EDGETX and ctx.isEditing() then
|
||||
-- Display Touch button for Editing values
|
||||
GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine])
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Different Resolution.. Maybe just adjusting some of the constants will work, adjust it in DSM_Init??
|
||||
-- LCD_X_LINE_TITLE, LCD_Y_LINE_START, etc
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,"Only supported in Color Radios of 480 resolution", BLINK)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
|
||||
local inc = 0
|
||||
local Speed = getRotEncSpeed()
|
||||
|
||||
if Speed == ROTENC_MIDSPEED then inc = (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then inc = (15 * dir)
|
||||
else inc = dir end
|
||||
|
||||
return inc
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
-- Translate Tap/Touch of EDIT buttons to equivalent Key events
|
||||
local function GUI_Translate_Edit_Buttons(button)
|
||||
local event = EVT_TOUCH_TAP
|
||||
local editInc = nil
|
||||
|
||||
if (button==EDIT_BUTTON.ESC) then -- ESC
|
||||
event = EVT_VIRTUAL_EXIT
|
||||
elseif (button==EDIT_BUTTON.DEFAULT) then -- Default
|
||||
event = EVT_VIRTUAL_ENTER_LONG
|
||||
elseif (button==EDIT_BUTTON.DEC_10) then -- -10
|
||||
event = EVT_VIRTUAL_PREV
|
||||
editInc = -10
|
||||
elseif (button==EDIT_BUTTON.DEC_1) then -- -1
|
||||
event = EVT_VIRTUAL_PREV
|
||||
editInc = -1
|
||||
elseif (button==EDIT_BUTTON.INC_1) then -- +1
|
||||
event = EVT_VIRTUAL_NEXT
|
||||
editInc = 1
|
||||
elseif (button==EDIT_BUTTON.INC_10) then -- + 10
|
||||
event = EVT_VIRTUAL_NEXT
|
||||
editInc = 10
|
||||
elseif (button==EDIT_BUTTON.OK) then -- OK
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
else
|
||||
|
||||
end
|
||||
|
||||
return event, editInc
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Handle Events comming from the GUI
|
||||
local function GUI_HandleEvent(event, touchState)
|
||||
local ctx = DSM_Context
|
||||
local menu = ctx.Menu
|
||||
local menuLines = ctx.MenuLines
|
||||
local editInc = nil
|
||||
|
||||
if (IS_EDGETX) then
|
||||
if (event == EVT_TOUCH_TAP and ctx.isEditing()) then -- Touch and Editing
|
||||
local button = GUI_getTouchButton(touchState.x, touchState.y)
|
||||
if (button) then
|
||||
event, editInc = GUI_Translate_Edit_Buttons(button)
|
||||
end
|
||||
end
|
||||
|
||||
if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",dsmLib.phase2String(ctx.Phase),touchState.x, touchState.y) end
|
||||
local button = GUI_getTouchButton(touchState.x, touchState.y)
|
||||
if button then
|
||||
-- Found a valid line
|
||||
ctx.SelLine = button
|
||||
ctx.Refresh_Display=true
|
||||
if event == EVT_TOUCH_TAP then -- EVT_TOUCH_FIRST only move focus
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
end
|
||||
end
|
||||
end
|
||||
end -- IS_EDGETX
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
dsmLib.ReleaseConnection() -- Just Exit the Script
|
||||
else
|
||||
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
||||
local line = ctx.MenuLines[ctx.EditLine]
|
||||
line.Val = originalValue
|
||||
dsmLib.Value_Write_Validate(line)
|
||||
else
|
||||
dsmLib.ChangePhase(PHASE.EXIT)
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(1))
|
||||
else -- not editing, move selected line to NEXT
|
||||
dsmLib.MoveSelectionLine(1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(-1))
|
||||
else -- not editing, move selected line to PREV
|
||||
dsmLib.MoveSelectionLine(-1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER_LONG then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then
|
||||
-- reset the value to default
|
||||
dsmLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",dsmLib.phase2String(ctx.Phase), ctx.SelLine) end
|
||||
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
|
||||
dsmLib.GotoMenu(menu.BackId,0x80)
|
||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
||||
dsmLib.GotoMenu(menu.NextId,0x82)
|
||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
||||
dsmLib.GotoMenu(menu.PrevId,0x81)
|
||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value
|
||||
|
||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Navigate to Menu
|
||||
if (menuLines[ctx.SelLine].ValId==0xFFF1) then
|
||||
-- SPECIAL Simulation menu to Simulator
|
||||
GUI_SwitchToSIM()
|
||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
|
||||
-- SPECIAL Simulation menu to go to RX
|
||||
GUI_SwitchToRX()
|
||||
else
|
||||
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
||||
end
|
||||
else -- Enter on a Value
|
||||
if ctx.isEditing() then -- already editing a Line????
|
||||
dsmLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
||||
else -- Edit the current value
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = menuLines[ctx.SelLine].Val
|
||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_colors()
|
||||
-- osName in OpenTX is nil, otherwise is EDGETX
|
||||
local ver, radio, maj, minor, rev, osname = getVersion()
|
||||
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
|
||||
|
||||
IS_EDGETX = string.sub(osname,1,1) == 'E'
|
||||
|
||||
if (IS_EDGETX and USE_SPECKTRUM_COLORS) then
|
||||
-- SPECKTRUM COLORS (only works on EDGETX)
|
||||
LCD_TOOL_BGCOLOR = LIGHTWHITE
|
||||
-- TOOL HEADER
|
||||
LCD_TOOL_HDR_COLOR = WHITE
|
||||
LCD_TOOL_HDR_BGCOLOR = DARKBLUE
|
||||
-- MENU HEADER
|
||||
LCD_MENU_COLOR = WHITE
|
||||
LCD_MENU_BGCOLOR = DARKGREY
|
||||
-- LINE SELECTED
|
||||
LCD_SELECTED_COLOR = WHITE
|
||||
LCD_SELECTED_BGCOLOR = ORANGE
|
||||
LCD_EDIT_BGCOLOR = RED
|
||||
-- NORMAL TEXT
|
||||
LCD_NORMAL_COLOR = BLACK
|
||||
LCD_DISABLE_COLOR = LIGHTGREY
|
||||
LCD_DEBUG_COLOR = BLUE
|
||||
-- NORMAL BOX FRAME COLOR
|
||||
LCD_BOX_COLOR = LIGHTGREY
|
||||
end
|
||||
end
|
||||
|
||||
local function GUI_Warning(event,touchState)
|
||||
lcd.clear(LCD_TOOL_BGCOLOR)
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
||||
|
||||
lcd.drawText(100,20,"INFO", BOLD)
|
||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", 0)
|
||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", 0)
|
||||
lcd.drawText(5,80,"the TX before your start Fwrd programming your RX.", 0)
|
||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", 0)
|
||||
|
||||
lcd.drawText(5,150,"TX Gyro Servo settings are sent to the RX during 'Initial Setup'", 0)
|
||||
lcd.drawText(5,170,"as well as when using RX 'Relearn Servo Settings'", 0)
|
||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD)
|
||||
|
||||
lcd.drawText(100,250," OK ", INVERS + BOLD)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER or event == EVT_TOUCH_TAP then
|
||||
warningScreenON = false
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
init_colors()
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
return dsmLib.StartConnection()
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
local function DSM_Run(event,touchState)
|
||||
local ctx = DSM_Context
|
||||
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
dsmLib.LOG_close()
|
||||
return 2
|
||||
end
|
||||
|
||||
if (warningScreenON) then
|
||||
return GUI_Warning(event,touchState)
|
||||
end
|
||||
|
||||
GUI_HandleEvent(event,touchState)
|
||||
|
||||
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
|
||||
|
||||
local refreshInterval = REFRESH_GUI_MS
|
||||
|
||||
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
|
||||
if (ctx.Phase == PHASE.RX_VERSION) then -- Requesting RX Message Version usea BLINK?
|
||||
ctx.Refresh_Display=true
|
||||
refreshInterval = 20 -- 200ms
|
||||
end
|
||||
|
||||
if (not IS_EDGETX) then -- OPENTX NEEDS REFRESH ON EVERY CYCLE
|
||||
GUI_Display()
|
||||
-- Refresh display only if needed and no faster than 300ms, utilize more CPU to speedup DSM communications
|
||||
elseif (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
|
||||
GUI_Display()
|
||||
ctx.Refresh_Display=false
|
||||
lastRefresh=getTime()
|
||||
end
|
||||
|
||||
if ctx.Phase == PHASE.EXIT_DONE then
|
||||
dsmLib.LOG_close()
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return { init=DSM_Init, run=DSM_Run }
|
||||
932
Lua_scripts/DSM FwdPrg_05_MIN.lua
Normal file
@@ -0,0 +1,932 @@
|
||||
local toolName = "TNS|DSM Frwd Prog v0.54-beta (MIN)|TNE"
|
||||
|
||||
--local ModelParam = ...
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for DSM description
|
||||
-- Multi_Buffer[0..2]=="DSM" -> Lua script is running
|
||||
-- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent
|
||||
-- Multi_Buffer[4..9]=6 bytes of TX to RX data
|
||||
-- Multi_Buffer[10..25]=16 bytes of RX to TX data
|
||||
--
|
||||
-- To start operation:
|
||||
-- Write 0x00 at address 3
|
||||
-- Write 0x00 at address 10
|
||||
-- Write "DSM" at address 0..2
|
||||
--###############################################################################
|
||||
|
||||
local VERSION = "v0.54-MIN"
|
||||
local LANGUAGE = "en"
|
||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
||||
|
||||
local LOG_FILE = "/LOGS/dsm_min_log.txt"
|
||||
local MSG_FILE = DSMLIB_PATH.."msg_fwdp_" .. LANGUAGE .. ".txt"
|
||||
local MSG_FILE_MIN = DSMLIB_PATH.."MIN_msg_fwdp_" .. LANGUAGE .. ".txt"
|
||||
|
||||
-- Phase
|
||||
local PH_RX_VER, PH_TITLE, PH_TX_INFO, PH_LINES, PH_VALUES = 1, 2, 3, 4, 5
|
||||
local PH_VAL_CHANGING, PH_VAL_WAIT, PH_VAL_CHNG_END = 6, 7, 8
|
||||
local PH_WAIT_CMD, PH_EXIT_REQ, PH_EXIT_DONE = 9, 10, 11
|
||||
|
||||
-- Line Types
|
||||
local LT_MENU = 0x1C
|
||||
local LT_LIST, LT_LIST_VALIDATE, LT_LIST_TOG = 0x6C, 0x0C, 0x4C
|
||||
local LT_VALUE_NOCHANGING = 0x60
|
||||
local LT_VALUE_PERCENT, LT_VALUE_DEGREES = 0xC0, 0xE0
|
||||
|
||||
local Phase = PH_RX_VER
|
||||
local Waiting_RX = 0
|
||||
|
||||
local Text = {}
|
||||
local List_Text = {}
|
||||
local List_Text_Img = {}
|
||||
local Flight_Mode = { [0] = "Flight Mode" }
|
||||
local RxName = {}
|
||||
|
||||
local InactivityTime = 0
|
||||
local Value_Change_Step = 0
|
||||
local TX_Info_Step = 0
|
||||
local TX_Info_Type = 0
|
||||
local originalValue = 0
|
||||
|
||||
local ctx = {
|
||||
SelLine = 0, -- Current Selected Line
|
||||
EditLine = nil, -- Current Editing Line
|
||||
CurLine = -1, -- Current Line Requested/Parsed via h message protocol
|
||||
isReset = false -- false when starting from scracts, true when starting from Reset
|
||||
}
|
||||
|
||||
local MODEL = {
|
||||
modelName = "", -- The name of the model comming from OTX/ETX
|
||||
modelOutputChannel = {}, -- Output information from OTX/ETX
|
||||
AirWingTailDesc = "",
|
||||
|
||||
--TX_CH_TEXT = {},
|
||||
--PORT_TEXT = {},
|
||||
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
|
||||
}
|
||||
|
||||
local Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 }
|
||||
local MenuLines = {}
|
||||
local RX = { Name = "", Version = "" }
|
||||
|
||||
local logFile = nil
|
||||
local logCount = 0
|
||||
|
||||
local LCD_X_LINE_TITLE = 0
|
||||
local LCD_X_LINE_VALUE = 75
|
||||
|
||||
local LCD_W_BUTTONS = 19
|
||||
local LCD_H_BUTTONS = 10
|
||||
|
||||
local LCD_X_MAX = 128
|
||||
local LCD_X_RIGHT_BUTTONS = LCD_X_MAX - LCD_W_BUTTONS - 1
|
||||
|
||||
local LCD_Y_LINE_HEIGHT = 7
|
||||
local LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2
|
||||
|
||||
local TEXT_ATTR = SMLSIZE
|
||||
|
||||
local function LOG_open()
|
||||
logFile = io.open(LOG_FILE, "w") -- Truncate Log File
|
||||
end
|
||||
|
||||
local function LOG_write(...)
|
||||
if (logFile == nil) then LOG_open() end
|
||||
local str = string.format(...)
|
||||
io.write(logFile, str)
|
||||
end
|
||||
|
||||
local function LOG_close()
|
||||
if (logFile ~= nil) then io.close(logFile) end
|
||||
end
|
||||
|
||||
---------------- DSM Values <-> Int16 Manipulation --------------------------------------------------------
|
||||
|
||||
local function int16_LSB(number) -- Less Significat byte
|
||||
local r, x = bit32.band(number, 0xFF)
|
||||
return r
|
||||
end
|
||||
|
||||
local function int16_MSB(number) -- Most signifcant byte
|
||||
return bit32.rshift(number, 8)
|
||||
end
|
||||
|
||||
local function Dsm_to_Int16(lsb, msb) -- Componse an Int16 value
|
||||
return bit32.lshift(msb, 8) + lsb
|
||||
end
|
||||
|
||||
local function Dsm_to_SInt16(lsb, msb) -- Componse a SIGNED Int16 value
|
||||
local value = bit32.lshift(msb, 8) + lsb
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function sInt16ToDsm(value) -- Convent to SIGNED DSM Value
|
||||
if value < 0 then
|
||||
value = 0x10000 + value
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function Get_Text(index)
|
||||
local out = Text[index] or string.format("Unknown_%X", index)
|
||||
if (index >= 0x8000) then
|
||||
out = Flight_Mode[0]
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
local function Get_Text_Value(index)
|
||||
local out = List_Text[index] or Get_Text(index)
|
||||
return out
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function Get_RxName(index)
|
||||
local out = RxName[index] or string.format("Unknown_%X", index)
|
||||
return out
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Release()
|
||||
multiBuffer(0, 0)
|
||||
Phase = PH_EXIT_DONE
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Send(...)
|
||||
local arg = { ... }
|
||||
for i = 1, #arg do
|
||||
multiBuffer(3 + i, arg[i])
|
||||
end
|
||||
multiBuffer(3, 0x70 + #arg)
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
|
||||
function ChangePhase(newPhase)
|
||||
Phase = newPhase
|
||||
Waiting_RX = 0
|
||||
end
|
||||
|
||||
local function Value_Add(dir)
|
||||
local line = MenuLines[ctx.SelLine]
|
||||
|
||||
Speed = getRotEncSpeed()
|
||||
if Speed == ROTENC_MIDSPEED then
|
||||
line.Val = line.Val + (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then
|
||||
line.Val = line.Val + (15 * dir)
|
||||
else
|
||||
line.Val = line.Val + dir
|
||||
end
|
||||
|
||||
if line.Val > line.Max then
|
||||
line.Val = line.Max
|
||||
elseif line.Val < line.Min then
|
||||
line.Val = line.Min
|
||||
end
|
||||
|
||||
ChangePhase(PH_VAL_CHANGING)
|
||||
Value_Change_Step = 0
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local function GotoMenu(menuId, lastSelectedLine)
|
||||
Menu.MenuId = menuId
|
||||
ctx.SelLine = lastSelectedLine
|
||||
-- Request to load the menu Again
|
||||
ChangePhase(PH_TITLE)
|
||||
end
|
||||
|
||||
local function isSelectable(line)
|
||||
if (line.TextId == 0x00CD) then return true end -- Exceptiom: Level model and capture attitude
|
||||
if (line.Type == LT_MENU and line.ValId == line.MenuId) then return false end -- Menu to same page
|
||||
if (line.Type ~= LT_MENU and line.Max == 0) then return false end -- Read only data line
|
||||
if (line.Type ~= 0 and line.TextId < 0x8000) then return true end -- Not Flight Mode
|
||||
return false;
|
||||
end
|
||||
|
||||
local function isListLine(line)
|
||||
return line.Type==LT_LIST or line.Type == LT_LIST_VALIDATE or line.Type == LT_LIST_TOG
|
||||
end
|
||||
|
||||
local function DSM_Menu(event)
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if Phase == PH_RX_VER then
|
||||
DSM_Release() -- Exit program
|
||||
else
|
||||
if ctx.EditLine ~= nil then -- Editing a Line, need to restore original value
|
||||
MenuLines[ctx.EditLine].Val = originalValue
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
else
|
||||
ChangePhase(PH_EXIT_REQ)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Phase == PH_RX_VER then return end -- nothing else to do
|
||||
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
if ctx.EditLine ~= nil then
|
||||
Value_Add(1)
|
||||
else
|
||||
-- not changing a value
|
||||
|
||||
if ctx.SelLine < 7 then -- On a regular line
|
||||
local num = ctx.SelLine -- Find the prev selectable
|
||||
for i = ctx.SelLine + 1, 6, 1 do
|
||||
local line = MenuLines[i]
|
||||
if isSelectable(line) then
|
||||
ctx.SelLine = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == ctx.SelLine then -- No Selectable Line
|
||||
if Menu.NextId ~= 0 then
|
||||
ctx.SelLine = 7 -- Next
|
||||
elseif Menu.PrevId ~= 0 then
|
||||
ctx.SelLine = 8 -- Prev
|
||||
end
|
||||
end
|
||||
elseif Menu.PrevId ~= 0 then
|
||||
ctx.SelLine = 8 -- Prev
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
if ctx.EditLine ~= nil then -- In Edit Mode
|
||||
Value_Add(-1)
|
||||
else
|
||||
if ctx.SelLine == 8 and Menu.NextId ~= 0 then
|
||||
ctx.SelLine = 7 -- Next
|
||||
elseif ctx.SelLine > 0 then
|
||||
if ctx.SelLine > 6 then
|
||||
ctx.SelLine = 7 --NEXT
|
||||
end
|
||||
local num = ctx.SelLine -- Find Prev Selectable line
|
||||
for i = ctx.SelLine - 1, 0, -1 do
|
||||
local line = MenuLines[i]
|
||||
if isSelectable(line) then
|
||||
ctx.SelLine = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == ctx.SelLine then -- No Selectable Line
|
||||
if (Menu.BackId > 0) then
|
||||
ctx.SelLine = -1 -- Back
|
||||
end
|
||||
end
|
||||
else
|
||||
ctx.SelLine = -1 -- Back
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER_LONG then
|
||||
if ctx.EditLine ~= nil then
|
||||
-- reset the value to default
|
||||
--if MenuLines[ctx.SelLine].Type ~= LIST_MENU_NOCHANGING then
|
||||
MenuLines[ctx.SelLine].Val = MenuLines[ctx.SelLine].Def
|
||||
ChangePhase(PH_VAL_CHANGING)
|
||||
Value_Change_Step = 0
|
||||
--end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
if ctx.SelLine == -1 then -- Back
|
||||
GotoMenu(Menu.BackId, 0x80)
|
||||
elseif ctx.SelLine == 7 then -- Next
|
||||
GotoMenu(Menu.NextId, 0x82)
|
||||
elseif ctx.SelLine == 8 then -- Prev
|
||||
GotoMenu(Menu.PrevId, 0x81)
|
||||
elseif ctx.SelLine >= 0 and MenuLines[ctx.SelLine].Type == LT_MENU then
|
||||
GotoMenu(MenuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the next menu
|
||||
else
|
||||
-- value entry
|
||||
if ctx.EditLine ~= nil then
|
||||
ctx.EditLine = nil -- Done Editting
|
||||
Value_Change_Step = 0
|
||||
ChangePhase(PH_VAL_CHNG_END)
|
||||
else -- Start Editing
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = MenuLines[ctx.SelLine].Val
|
||||
ChangePhase(PH_VAL_WAIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function SendTxInfo(portNo)
|
||||
-- TxInfo_Type=0 : AR636 Main Menu (Send port/Channel info + SubTrim + Travel)
|
||||
-- TxInfo_Type=1 : AR630-637 Famly Main Menu (Only Send Port/Channel usage Msg 0x20)
|
||||
-- TxInfo_Type=1F : AR630-637 Initial Setup/Relearn Servo Settings (Send port/Channel info + SubTrim + Travel +0x24/Unknown)
|
||||
|
||||
|
||||
if (TX_Info_Step == 0) then
|
||||
-- AR630 family: Both TxInfo_Type (ManinMenu=0x1, Other First Time Configuration = 0x1F)
|
||||
local info = MODEL.DSM_ChannelInfo[portNo]
|
||||
DSM_Send(0x20, 0x06, portNo, portNo, info[0],info[1])
|
||||
LOG_write("DSM_TxInfo_20(Port=#%d, Port Use)\n", portNo)
|
||||
|
||||
if (TX_Info_Type == 0x1F) then
|
||||
TX_Info_Step = 1
|
||||
elseif (TX_Info_Type == 0x00) then
|
||||
TX_Info_Step = 2
|
||||
end
|
||||
elseif (TX_Info_Step == 1) then
|
||||
local info = MODEL.modelOutputChannel[portNo]
|
||||
local leftTravel = math.abs(math.floor(info.min/10))
|
||||
local rightTravel = math.abs(math.floor(info.max/10))
|
||||
|
||||
DSM_Send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel)
|
||||
LOG_write("DSM_TxInfo_23(Port=#%d,ServoTravel(L=%d - R=%d))\n", portNo,leftTravel,rightTravel)
|
||||
|
||||
TX_Info_Step = 2
|
||||
elseif (TX_Info_Step == 2) then
|
||||
local data = {[0]= -- Start at 0
|
||||
{[0]= 0x0, 0x00, 0x07, 0xFF }, -- Ch1 Thr: 0 00 07 FF Subtrim ??
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch2 Ail: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch3 Elev: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch4 Rud: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch5 Gear: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch6 Aux1: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch7 Aux2: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch8 Aux3: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch9 Aux4: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch10 Aux5: 0 8E 07 72 Subtrim 0
|
||||
}
|
||||
local info = data[portNo]
|
||||
local b1,b2,b3,b4 = info[0], info[1], info[2], info[3]
|
||||
|
||||
DSM_Send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it.
|
||||
LOG_write("DSM_TxInfo_21(Port=#%d, SubTrim)\n", portNo)
|
||||
|
||||
if (TX_Info_Type == 0x00) then
|
||||
TX_Info_Step = 5 -- End Step
|
||||
else
|
||||
TX_Info_Step = 3
|
||||
end
|
||||
elseif (TX_Info_Step == 3) then
|
||||
LOG_write("DSM_TxInfo_24?(Port=#%d)\n", portNo)
|
||||
DSM_Send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown
|
||||
TX_Info_Step = 4
|
||||
elseif (TX_Info_Step == 4) then
|
||||
LOG_write("DSM_TxInfo_24?(Port=#%d)\n", portNo)
|
||||
DSM_Send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown
|
||||
TX_Info_Step = 5
|
||||
elseif (TX_Info_Step == 5) then
|
||||
LOG_write("DSM_TxInfo_22(Port=#%d, END of Data)\n", portNo)
|
||||
DSM_Send(0x22, 0x04, 0x00, 0x00)
|
||||
TX_Info_Step = 0 -- Done!!
|
||||
end
|
||||
|
||||
if (TX_Info_Step > 0) then
|
||||
Waiting_RX = 0 -- keep Transmitig
|
||||
end
|
||||
end
|
||||
|
||||
local function DSM_SendRequest()
|
||||
--LOG_write("DSM_SendRequest Phase=%d\n",Phase)
|
||||
-- Need to send a request
|
||||
if Phase == PH_RX_VER then -- request RX version
|
||||
DSM_Send(0x11, 0x06, 0x00, 0x14, 0x00, 0x00)
|
||||
LOG_write("GetVersion()\n")
|
||||
elseif Phase == PH_WAIT_CMD then -- keep connection open
|
||||
DSM_Send(0x00, 0x04, 0x00, 0x00)
|
||||
elseif Phase == PH_TITLE then -- request menu title
|
||||
local menuId = Menu.MenuId
|
||||
if menuId == 0 then
|
||||
DSM_Send(0x12, 0x06, 0x00, 0x14, 0x00, 0x00) -- first menu only
|
||||
else
|
||||
DSM_Send(0x16, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, ctx.SelLine)
|
||||
if (menuId == 0x0001) then -- Executed Save&Reset menu
|
||||
Phase = PH_RX_VER
|
||||
ctx.isReset = true
|
||||
end
|
||||
end
|
||||
LOG_write("GetMenu(M=0x%04X,L=%d)\n", menuId, ctx.SelLine)
|
||||
elseif Phase == PH_TX_INFO then -- TX Info
|
||||
SendTxInfo(ctx.CurLine)
|
||||
elseif Phase == PH_LINES then -- request menu lines
|
||||
local menuId = Menu.MenuId
|
||||
if ctx.CurLine == -1 then
|
||||
DSM_Send(0x13, 0x04, int16_MSB(menuId), int16_LSB(menuId)) -- GetFirstLine
|
||||
else
|
||||
DSM_Send(0x14, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, ctx.CurLine) -- line X
|
||||
end
|
||||
LOG_write("GetLines(LastLine=%d)\n", ctx.CurLine)
|
||||
elseif Phase == PH_VALUES then -- request menu values
|
||||
local menuId = Menu.MenuId
|
||||
local valId = MenuLines[ctx.CurLine].ValId
|
||||
DSM_Send(0x15, 0x06,
|
||||
int16_MSB(menuId), int16_LSB(menuId),
|
||||
int16_MSB(valId), int16_LSB(valId))
|
||||
LOG_write("GetValues(LastVId=0x%04X)\n", valId)
|
||||
elseif Phase == PH_VAL_CHANGING then -- send new value: Two steps, Update & Validate
|
||||
local line = MenuLines[ctx.SelLine]
|
||||
local valId = line.ValId
|
||||
if Value_Change_Step == 0 then
|
||||
local value = sInt16ToDsm(line.Val)
|
||||
DSM_Send(0x18, 0x06,
|
||||
int16_MSB(valId), int16_LSB(valId),
|
||||
int16_MSB(value), int16_LSB(value)) -- send current values
|
||||
LOG_write("ChangeValue(VId=0x%04X,Val=%d)\n", valId, value)
|
||||
|
||||
if line.Type == LT_LIST_VALIDATE then -- Incremental Validation??
|
||||
Value_Change_Step = 1
|
||||
Waiting_RX = 0 -- Do SEND in the next step
|
||||
end
|
||||
else
|
||||
-- Validate Value
|
||||
DSM_Send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId))
|
||||
Value_Change_Step = 0
|
||||
Phase = PH_VAL_WAIT
|
||||
LOG_write("ValidateValue(VId=0x%04X)\n", valId)
|
||||
end
|
||||
elseif Phase == PH_VAL_CHNG_END then
|
||||
DSM_Send(0x1B, 0x04, 0x00, int16_LSB(ctx.SelLine))
|
||||
Value_Change_Step = 0
|
||||
Phase = PH_WAIT_CMD
|
||||
LOG_write("ValueChangeEnd(L=%d)\n", ctx.SelLine)
|
||||
elseif Phase == PH_VAL_WAIT then
|
||||
-- Value Changing Wait
|
||||
DSM_Send(0x1A, 0x04, 0x00, int16_LSB(ctx.SelLine))
|
||||
LOG_write("ValueChangeWait(L=%d)\n", ctx.SelLine)
|
||||
elseif Phase == PH_EXIT_REQ then -- EXIT Request
|
||||
DSM_Send(0x1F, 0x02, 0xAA)
|
||||
end
|
||||
end
|
||||
|
||||
local function DSM_ProcessResponse()
|
||||
local cmd = multiBuffer(11)
|
||||
-- LOG_write("DSM_ProcessResponse BEGIN: Cmd=%x\n",cmd)
|
||||
if cmd == 0x01 then -- read version
|
||||
RX.Name = Get_RxName(multiBuffer(13))
|
||||
RX.Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16)
|
||||
--ctx.isReset = false -- no longer resetting
|
||||
Menu.MenuId = 0
|
||||
Phase = PH_TITLE
|
||||
LOG_write("Version: %s %s\n", RX.Name, RX.Version)
|
||||
elseif cmd == 0x02 then -- read menu title
|
||||
local menu = Menu
|
||||
|
||||
menu.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
|
||||
menu.TextId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15))
|
||||
menu.Text = Get_Text(menu.TextId)
|
||||
menu.PrevId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17))
|
||||
menu.NextId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19))
|
||||
menu.BackId = Dsm_to_Int16(multiBuffer(20), multiBuffer(21))
|
||||
|
||||
for i = 0, 6 do -- clear menu
|
||||
MenuLines[i] = { MenuId = 0, Type = 0, TextId = 0, ValId = 0, Min = 0, Max = 0, Def = 0, Val = nil, Unit, Step }
|
||||
end
|
||||
ctx.CurLine = -1
|
||||
ctx.SelLine = -1 -- highlight Back
|
||||
|
||||
LOG_write("Menu: Mid=0x%04X \"%s\"\n", menu.MenuId, menu.Text)
|
||||
|
||||
if (menu.MenuId == 0x0001) then -- Still in RESETTING MENU???
|
||||
--menu.MenuId = 0
|
||||
Phase = PH_RX_VER
|
||||
else
|
||||
Phase = PH_LINES
|
||||
end
|
||||
elseif cmd == 0x03 then -- read menu lines
|
||||
local i = multiBuffer(14)
|
||||
local type = multiBuffer(15)
|
||||
local line = MenuLines[i]
|
||||
|
||||
ctx.CurLine = i
|
||||
|
||||
line.lineNum = i
|
||||
line.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
|
||||
line.Type = type
|
||||
line.TextId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17))
|
||||
line.Text = Get_Text(line.TextId)
|
||||
line.ValId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19))
|
||||
|
||||
-- Singed int values
|
||||
line.Min = Dsm_to_SInt16(multiBuffer(20), multiBuffer(21))
|
||||
line.Max = Dsm_to_SInt16(multiBuffer(22), multiBuffer(23))
|
||||
line.Def = Dsm_to_SInt16(multiBuffer(24), multiBuffer(25))
|
||||
|
||||
if line.Type == LT_MENU then
|
||||
-- nothing to do on menu entries
|
||||
elseif isListLine(line) then
|
||||
line.Val = nil --line.Def - line.Min -- use default value not sure if needed
|
||||
line.Def = line.Min -- pointer to the start of the list in Text
|
||||
line.Max = line.Max - line.Min -- max index
|
||||
line.Min = 0 -- min index
|
||||
else -- default to numerical value
|
||||
line.Val = nil --line.Def -- use default value not sure if needed
|
||||
if (line.Min == 0 and line.Max == 100) or (line.Min == -100 and line.Max == 100) or
|
||||
(line.Min == 0 and line.Max == 150) or (line.Min == -150 and line.Max == 150) then
|
||||
line.Type = LT_VALUE_PERCENT -- Override to Value Percent
|
||||
end
|
||||
end
|
||||
|
||||
if ctx.SelLine == -1 and isSelectable(line) then -- Auto select first selectable line of the menu
|
||||
ctx.SelLine = ctx.CurLine
|
||||
end
|
||||
|
||||
LOG_write("Line: #%d Vid=0x%04X T=0x%02X \"%s\"\n", i, line.ValId, type, line.Text)
|
||||
Phase = PH_LINES
|
||||
elseif cmd == 0x04 then -- read menu values
|
||||
-- Identify the line and update the value
|
||||
local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15))
|
||||
local value = Dsm_to_SInt16(multiBuffer(16), multiBuffer(17)) --Signed int
|
||||
|
||||
local updatedLine = nil
|
||||
for i = 0, 6 do -- Find the menu line for this value
|
||||
local line = MenuLines[i]
|
||||
if line.Type ~= 0 then
|
||||
if line.Type ~= LT_MENU and line.ValId == valId then -- identifier of ValueId stored in the line
|
||||
line.Val = value
|
||||
ctx.CurLine = i
|
||||
updatedLine = line
|
||||
|
||||
local valueTxt = value
|
||||
if isListLine(line) then
|
||||
valueTxt = Get_Text_Value(line.Def + value) .. " [" .. value .. "]"
|
||||
end
|
||||
|
||||
LOG_write("Update Value: #%d VId=0x%04X Value=%s\n", i, valId, valueTxt)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (updatedLine == nil) then
|
||||
LOG_write("Cannot Find Line for ValueId=%x\n", valId)
|
||||
end
|
||||
Phase = PH_VALUES
|
||||
elseif cmd == 0x05 then -- Request TX info
|
||||
ctx.CurLine = multiBuffer(12)
|
||||
TX_Info_Type = multiBuffer(13)
|
||||
TX_Info_Step = 0
|
||||
Phase = PH_TX_INFO
|
||||
LOG_write("TXInfoReq: Port=%d T=0x%02X\n", ctx.CurLine, TX_Info_Type)
|
||||
elseif cmd == 0xA7 then -- answer to EXIT command
|
||||
DSM_Release()
|
||||
elseif cmd == 0x00 and Phase == PH_VAL_CHANGING then
|
||||
Phase = PH_VAL_WAIT
|
||||
end
|
||||
|
||||
--LOG_write("DSM_ProcessResponse END: Cmd=%x\n",cmd)
|
||||
return cmd
|
||||
end
|
||||
|
||||
|
||||
local function DSM_Send_Receive()
|
||||
if Waiting_RX == 0 then
|
||||
Waiting_RX = 1
|
||||
DSM_SendRequest()
|
||||
multiBuffer(10, 0x00);
|
||||
InactivityTime = getTime() + 200 -- Reset Inactivity timeout
|
||||
-- -- -- -- -- -- -- -- -- -- -- -- receive part -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
elseif multiBuffer(10) == 0x09 then
|
||||
local cmd = DSM_ProcessResponse()
|
||||
-- Data processed
|
||||
multiBuffer(10, 0x00)
|
||||
if (cmd > 0x00) then -- Any non NULL response
|
||||
-- Only change to SEND mode if we received a valid response (Ignore NULL Responses, that are really heartbeat i most cases)
|
||||
Waiting_RX = 0
|
||||
InactivityTime = getTime() + 200 -- Reset Inactivity timeout
|
||||
end
|
||||
else -- No Send or Receive,
|
||||
-- Check if enouth time has passed from last transmit/receive activity
|
||||
if getTime() > InactivityTime then
|
||||
InactivityTime = getTime() + 200
|
||||
Waiting_RX = 0 -- Switch to Send mode to send heartbeat
|
||||
|
||||
if Phase == PH_EXIT_REQ then
|
||||
DSM_Release()
|
||||
end
|
||||
|
||||
if Phase ~= PH_RX_VER and Phase ~= PH_VAL_WAIT then
|
||||
Phase = PH_WAIT_CMD
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local function showBitmap(x, y, imgDesc)
|
||||
local f = string.gmatch(imgDesc, '([^%|]+)') -- Iterator over values split by '|'
|
||||
local imgName, imgMsg = f(), f()
|
||||
|
||||
f = string.gmatch(imgMsg or "", '([^%:]+)') -- Iterator over values split by ':'
|
||||
local p1, p2 = f(), f()
|
||||
|
||||
lcd.drawText(x, y, p1 or "", TEXT_ATTR) -- Alternate Image MSG
|
||||
lcd.drawText(x, y + LCD_Y_LINE_HEIGHT, p2 or "", TEXT_ATTR) -- Alternate Image MSG
|
||||
end
|
||||
|
||||
|
||||
local function drawButton(x, y, text, active)
|
||||
local attr = TEXT_ATTR
|
||||
if (active) then attr = attr + INVERS end
|
||||
lcd.drawText(x, y, text, attr)
|
||||
end
|
||||
|
||||
local ver_rx_count = 0
|
||||
|
||||
local function DSM_Display()
|
||||
lcd.clear()
|
||||
--Draw RX Menu
|
||||
if Phase == PH_RX_VER then
|
||||
lcd.drawText(1, 0, "DSM Frwd Prog "..VERSION, INVERS)
|
||||
|
||||
local msgId = 0x300 -- Waiting for RX
|
||||
if (ctx.isReset) then msgId=0x301 end -- Waiting for Reset
|
||||
lcd.drawText(0, 3 * LCD_Y_LINE_HEIGHT, Get_Text(msgId), BLINK)
|
||||
return
|
||||
end
|
||||
|
||||
-- display Program version or RX version
|
||||
local msg = RX.Name .. " v" .. RX.Version
|
||||
if (ver_rx_count < 100) then
|
||||
msg = RX.Name .. " v" .. RX.Version
|
||||
ver_rx_count = ver_rx_count + 1
|
||||
else
|
||||
msg = "Frwd Prog "..VERSION
|
||||
ver_rx_count = ver_rx_count + 1
|
||||
if (ver_rx_count > 200) then ver_rx_count=0 end
|
||||
end
|
||||
lcd.drawText(30, LCD_Y_LOWER_BUTTONS, msg, TEXT_ATTR)
|
||||
|
||||
if Menu.MenuId == 0 then return end; -- No Title yet
|
||||
|
||||
-- Got a Menu
|
||||
lcd.drawText(1, 0, Menu.Text, TEXT_ATTR + INVERS)
|
||||
|
||||
local y = LCD_Y_LINE_HEIGHT + 2
|
||||
for i = 0, 6 do
|
||||
local attrib = TEXT_ATTR
|
||||
if (i == ctx.SelLine) then attrib = attrib + INVERS end -- Selected Line
|
||||
|
||||
local line = MenuLines[i]
|
||||
|
||||
if line ~= nil and line.Type ~= 0 then
|
||||
local heading = Get_Text(line.TextId)
|
||||
|
||||
if (line.TextId >= 0x8000) then -- Flight mode
|
||||
heading = " " .. Flight_Mode[0] .. " "
|
||||
if (line.Val==nil) then heading = heading .. "--" else heading = heading .. ((line.Val or 0) + 1) end
|
||||
else
|
||||
local text = "-"
|
||||
if line.Type ~= LT_MENU then -- list/value
|
||||
if line.Val ~= nil then
|
||||
if isListLine(line) then
|
||||
local textId = line.Val + line.Def
|
||||
text = Get_Text_Value(textId)
|
||||
|
||||
local imgDesc = List_Text_Img[textId]
|
||||
|
||||
if (imgDesc and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
||||
showBitmap(0, 20, imgDesc)
|
||||
end
|
||||
elseif (line.Type == LT_VALUE_PERCENT) then
|
||||
text = line.Val .. " %"
|
||||
elseif (line.Type == LT_VALUE_DEGREES) then
|
||||
text = line.Val .. " @"
|
||||
else
|
||||
text = line.Val
|
||||
end
|
||||
end -- if is Value
|
||||
|
||||
if (ctx.EditLine == i) then -- Editing a Line
|
||||
attrib = BLINK + INVERS + TEXT_ATTR
|
||||
end
|
||||
lcd.drawText(LCD_X_MAX, y, text, attrib + RIGHT) -- display value
|
||||
attrib = TEXT_ATTR
|
||||
end
|
||||
end -- Flight mode
|
||||
lcd.drawText(0, y, heading, attrib) -- display text
|
||||
end
|
||||
y = y + LCD_Y_LINE_HEIGHT
|
||||
end -- for
|
||||
|
||||
if Menu.BackId ~= 0 then
|
||||
drawButton(LCD_X_RIGHT_BUTTONS, 0, "Back", ctx.SelLine == -1)
|
||||
end
|
||||
|
||||
if Menu.NextId ~= 0 then
|
||||
drawButton(LCD_X_RIGHT_BUTTONS, LCD_Y_LOWER_BUTTONS, "Next", ctx.SelLine == 7)
|
||||
end
|
||||
|
||||
if Menu.PrevId ~= 0 then
|
||||
drawButton(0, LCD_Y_LOWER_BUTTONS, "Prev", ctx.SelLine == 8)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function load_msg_from_file(fileName, mem, Text, List_Text, List_Text_Img, RxName, Flight_Mode)
|
||||
local function rtrim(s)
|
||||
local n = string.len(s)
|
||||
while n > 0 and string.find(s, "^%s", n) do n = n - 1 end
|
||||
return string.sub(s, 1, n)
|
||||
end
|
||||
|
||||
--print(string.format("Loading messages from [%s]",fileName))
|
||||
local dataFile = io.open(fileName, "r") -- read File
|
||||
-- cannot read file???
|
||||
assert(dataFile, "Cannot load Message file:" .. fileName)
|
||||
|
||||
local data = io.read(dataFile, mem * 1024) -- read up to 10k characters (newline char also counts!)
|
||||
io.close(dataFile)
|
||||
|
||||
collectgarbage("collect")
|
||||
|
||||
local lineNo = 0
|
||||
for line in string.gmatch(data, "[^\r\n]+") do
|
||||
lineNo = lineNo + 1
|
||||
--print(string.format("Line [%d]: %s",lineNo,line))
|
||||
|
||||
-- Remove Comments
|
||||
local s = string.find(line, "--", 1, true)
|
||||
if (s ~= nil) then
|
||||
line = string.sub(line, 1, s - 1)
|
||||
end
|
||||
|
||||
line = rtrim(line)
|
||||
|
||||
if (string.len(line) > 0) then
|
||||
local a, b, c = string.match(line, "%s*(%a*)%s*|%s*(%w*)%s*|(.*)%s*")
|
||||
--print(string.format("[%s] [%s] [%s]",a,b,c))
|
||||
if (a ~= nil) then
|
||||
local index = tonumber(b)
|
||||
|
||||
if (index == nil) then
|
||||
assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, lineNo, b))
|
||||
elseif (a == "T") then
|
||||
Text[index] = c
|
||||
elseif (a == "LT") then
|
||||
List_Text[index] = c
|
||||
elseif (a == "LI") then
|
||||
List_Text_Img[index] = c
|
||||
elseif (a == "FM") then
|
||||
Flight_Mode[0] = c
|
||||
elseif (a == "RX") then
|
||||
RxName[index] = c
|
||||
else
|
||||
assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, lineNo, a))
|
||||
end
|
||||
end
|
||||
end
|
||||
if (lineNo % 50 == 0) then
|
||||
collectgarbage("collect")
|
||||
end
|
||||
end -- For
|
||||
|
||||
--print(string.format("Loaded [%d] messages",lineNo))
|
||||
data = nil
|
||||
end
|
||||
|
||||
|
||||
local function clean_msg(Text, Flight_Mode)
|
||||
local function clean_line(c)
|
||||
if (c==nil) then return c end
|
||||
local pos
|
||||
c, pos = string.gsub(c, "/b$", "")
|
||||
c, pos = string.gsub(c, "/c$", "")
|
||||
c, pos = string.gsub(c, "/r$", "")
|
||||
c, pos = string.gsub(c, "/p$", "")
|
||||
c, pos = string.gsub(c, "/m$", "")
|
||||
return c
|
||||
end
|
||||
|
||||
-- Clean the line of special markers that are only used in color vesion
|
||||
for i = 0, 0x0300 do
|
||||
Text[i] = clean_line(Text[i])
|
||||
collectgarbage("collect")
|
||||
end
|
||||
|
||||
for i = 0, #Flight_Mode do
|
||||
-- Clean the line of special markers that are only used in color vesion
|
||||
Flight_Mode[i] = clean_line(Flight_Mode[i])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function DSM_Init_Model()
|
||||
MODEL.DSM_ChannelInfo= {[0]= -- Start array at position 0
|
||||
{[0]= 0x00, 0x40}, -- Ch1 Thr (0x40)
|
||||
{[0]= 0x00, 0x01}, -- Ch2 Ail (0x01)
|
||||
{[0]= 0x00, 0x02}, -- Ch2 ElE (0x02)
|
||||
{[0]= 0x00, 0x04}, -- Ch4 Rud (0x04)
|
||||
{[0]= 0x00, 0x00}, -- Ch5 Gear (0x00)
|
||||
{[0]= 0x00, 0x00}, -- Ch6 Aux1 (0x00)
|
||||
{[0]= 0x00, 0x00}, -- Ch7 Aux2 (0x00)
|
||||
{[0]= 0x00, 0x00}, -- Ch8 Aux3 (0x00)
|
||||
{[0]= 0x00, 0x00}, -- Ch9 Aux4 (0x00)
|
||||
{[0]= 0x00, 0x00} -- Ch10 Aux5 (0x00)
|
||||
}
|
||||
|
||||
MODEL.modelOutputChannel = {[0]=
|
||||
{min=1000, max=1000}, -- Ch1
|
||||
{min=1000, max=1000}, -- Ch2
|
||||
{min=1000, max=1000}, -- Ch3
|
||||
{min=1000, max=1000}, -- Ch4
|
||||
{min=1000, max=1000}, -- Ch5
|
||||
{min=1000, max=1000}, -- Ch6
|
||||
{min=1000, max=1000}, -- Ch7
|
||||
{min=1000, max=1000}, -- Ch8
|
||||
{min=1000, max=1000}, -- Ch9
|
||||
{min=1000, max=1000} -- Ch10
|
||||
}
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
LOG_open()
|
||||
LOG_write("-------- NEW SESSION --------------------\n")
|
||||
|
||||
DSM_Init_Model()
|
||||
|
||||
--[[
|
||||
if (ModelParam~=nil) then
|
||||
LOG_write("Got MODEL PARAMETER... copying\n")
|
||||
MODEL.DSM_ChannelInfo = ModelParam.DSM_ChannelInfo
|
||||
else
|
||||
LOG_write("NO-PARMETER --- Create DEFAULT")
|
||||
end
|
||||
--]]
|
||||
|
||||
collectgarbage("collect")
|
||||
LOG_write("Mem before msg =%d\n",collectgarbage("count"))
|
||||
load_msg_from_file(MSG_FILE, 10, Text, List_Text, List_Text_Img, RxName, Flight_Mode)
|
||||
collectgarbage("collect")
|
||||
LOG_write("Mem after msg =%d\n",collectgarbage("count"))
|
||||
load_msg_from_file(MSG_FILE_MIN, 4, Text, List_Text, List_Text_Img, RxName, Flight_Mode)
|
||||
collectgarbage("collect")
|
||||
LOG_write("Mem after msg2 =%d\n",collectgarbage("count"))
|
||||
clean_msg(Text,Flight_Mode)
|
||||
collectgarbage("collect")
|
||||
|
||||
--Set protocol to talk to
|
||||
multiBuffer(0, string.byte('D'))
|
||||
--test if value has been written
|
||||
if multiBuffer(0) ~= string.byte('D') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
|
||||
--Init TX buffer
|
||||
multiBuffer(3, 0x00)
|
||||
--Init RX buffer
|
||||
multiBuffer(10, 0x00)
|
||||
--Init telemetry
|
||||
multiBuffer(0, string.byte('D'))
|
||||
multiBuffer(1, string.byte('S'))
|
||||
multiBuffer(2, string.byte('M'))
|
||||
|
||||
|
||||
if (LCD_W > 128) then
|
||||
TEXT_ATTR = 0
|
||||
LCD_Y_LINE_HEIGHT = 25
|
||||
LCD_X_MAX = 300
|
||||
LCD_X_RIGHT_BUTTONS = LCD_X_MAX - 30
|
||||
|
||||
LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
local function DSM_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
else
|
||||
DSM_Display()
|
||||
DSM_Menu(event)
|
||||
DSM_Send_Receive()
|
||||
end
|
||||
if Phase == PH_EXIT_DONE then
|
||||
LOG_close()
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init = DSM_Init, run = DSM_Run }
|
||||
467
Lua_scripts/DSMLIB/DSM Fwd Prog Protocol.md
Normal file
@@ -0,0 +1,467 @@
|
||||
# Forward Programing Protocol
|
||||
|
||||
## Introduction
|
||||
DSM, DSMX and DSM Forward Programming are propietary protocol from the **Spektrum** radio brand. Since they don't make this information public, we have to reverse engineer it by analyzing the data exchanged between the RX and TX.
|
||||
|
||||
This document descrives what we know so far.
|
||||
|
||||
Thanks to **Pascal Langer** (Author of the Multi-Module) for the initial reverse engineering of the protocol and first version of the code that has been used for a while (Version 0.2)
|
||||
|
||||
Thanks to **Francisco Arzu** for taking the time to continue the work on reverse engineering, documenting and making the code more understandable.
|
||||
|
||||
New Capabilities in Version 0.5
|
||||
- Log files of the conversation between RX/TX
|
||||
- Improve the GUI (EdgeTX touch screen)
|
||||
- Reversed engineer other things to make it work completly.
|
||||
|
||||
# Menu Title and Lines
|
||||
|
||||
The menu to be displayed is stored at the RX, the GUI only renders the menu title and menu lines received. The tipical conversation with the RX will be to ask for a menu (using the menuId number), and then wait for the data to come. The first thing will be the Menu (header) data, later we request the next 6 lines (one at a time), and optionally the values for each line.
|
||||
|
||||
A typical exchange will look like this in the log:
|
||||
|
||||
SEND DSM_getMenu(MenuId=0x1010 LastSelectedLine=0)
|
||||
RESPONSE Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
||||
SEND DSM_getFirstMenuLine(MenuId=0x1010)
|
||||
RESPONSE MenuLine: L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ]
|
||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=0)
|
||||
RESPONSE MenuLine: L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ]
|
||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=1)
|
||||
RESPONSE MenuLine: L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ]
|
||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=2)
|
||||
RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
|
||||
|
||||
## Menu
|
||||
|
||||
The menu has the following information:
|
||||
|
||||
Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
||||
|
||||
- `MenuId`: The menu ID number of the menu (hex, 16 bit number)
|
||||
- `PrevId`: The menu ID of the previous menu (for navigation), Log show as `"P="`
|
||||
- `NextId`: The menu ID of the next menu (for navigation), Log shows as `"N="`
|
||||
- `BackId`: The menu ID of the back menu (for navigation), Log shows as `"B="`
|
||||
- `TextId`: The message number to display (16 bits, Hex). Log shows as [`0xXX`] after the message.
|
||||
- `Text`: Retrived using the `TextId` from the script message `Text` array.
|
||||
|
||||
## Menu Lines
|
||||
|
||||
The menu lines has the following information:
|
||||
|
||||
L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1021 ]
|
||||
L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ]
|
||||
L[#2 T=LM VId=0x1002 Text="AS3X"[0x1DC] Val=1|"Act" NL=(0->1,0,S=3) [3->4,3] MId=0x1021 ]
|
||||
|
||||
- `MenuId`: of the menu they beling to. Log show as `"MId="` at the end.
|
||||
- `LineNum`: Line number (0..5). The line number in the screen. Log show as # in the beginning
|
||||
- `Type`: Type of Line, Log shows as `"T="` (explanation later)
|
||||
- `TextId`: The message number to display (16 bits, Hex). Log shows as [`0xXXXX`] after the message.
|
||||
- `Text`: Retrived using the `TextId` from the script message `Text` array.
|
||||
- `ValueId`: The value or menu ID of the line. Log shows as `"VId="` (16 bits, Hex).
|
||||
- `Value Range`: Shows as [`Min`->`Max`, `Default`]. This is the RAW data comming from the RX
|
||||
- `NL`: Computed Normalized LIST (0 reference) for List Values. Source is the RAW range. For example, for lines of list of values. `[3->4,3]` is tranlated to `NL=(0->1,0,S=3)` since the value is also normalize to 0. `"S="` means the initial entry in the `List_Text` array
|
||||
- `Val`: Current value for line who hold data. Relative to 0 for List Values. For List Values, the log will show the translation of the value to display text. example: `Val=1|"Act"` that is coming from `List_Value[4]`
|
||||
|
||||
## Type of Menu Lines
|
||||
|
||||
- `LINE_TYPE.MENU (Log: "T=M")`: This could be regular text or a navigation to another menu. if `ValueId` is the same as the current MenuId (`MId=`), is a plain text line (navigation to itself). If the `ValueId` is not the current menuId, then `ValueId` is the MenuId to navigate to.
|
||||
|
||||
We have found only one exception to the plain text rule, a true navigation to itself, in that case, in the text of the menu, you can use the "/M" flag at the end of the text to force it to be a menu button.
|
||||
|
||||
Example, FM_Channel is a navigation to menuId=0x7CA6.
|
||||
|
||||
L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ]
|
||||
|
||||
- `LINE_TYPE.LIST_MENU_NC (Log T=LM_nc)`: This is a line that shows as text in the GUI. The numeric value is translated to the proper text. The range is important, since it descrives the range of posible values. No incremental RX changes, only at the end.
|
||||
|
||||
Example: List of Values, List_Text[] starts at 53, ends at 85, with a default of 85. When normalized to 0, is a range from 0->32 for the numeric value. The Display value `Aux1` is retrive from `List_Text[6+53]`.
|
||||
|
||||
L[#0 T=LM_nc VId=0x1000 Text="FM Channel"[0x78] Val=6|"Aux1" NL=(0->32,0,S=53) [53->85,53] MId=0x7CA6 ]
|
||||
|
||||
- `LINE_TYPE.LIST_MENU_TOG (Log T=L_tog)`: Mostly the same as LIST_MENU_NC, but is just 2 values. (ON/OFF, Ihn/Act, etc). Should be a toggle in the GUI.
|
||||
|
||||
L[#2 T=LM_tog VId=0x1002 Text="AS3X"[0x1DC] Val=1|"Act" NL=(0->1,0,S=3) [3->4,3] MId=0x1021 ]
|
||||
|
||||
- `LINE_TYPE.LIST_MENU (Log T=LM)`: Mostly the same as LIST_MENU_NC, but incremental changes to the RX. Some times, it comes with a strange range `[0->244,Default]`. Usually this means that the values are not contiguos range; usually Ihn + Range. Still haven't found where in the data the correct range comes from.
|
||||
|
||||
Example: Valid Values: 3, 176->177 (Inh, Self-Level/Angle Dem, Envelope)
|
||||
L[#3 T=LM VId=0x1003 Text="Safe Mode"[0x1F8] Val=176|"Self-Level/Angle Dem" NL=(0->244,3,S=0) [0->244,3] MId=0x1021 ]
|
||||
|
||||
- `LINE_TYPE.VALUE_NUM_I8_NC (Log: "T=V_nc")`: This line is editable, but is not updated to the RX incrementally, but only at the end. The Flight Mode line is of this type, so we have to check the TextId to differenciate between Flight mode and an Editable Value.
|
||||
Fligh Mode TextId is between 0x8000 and 0x8003
|
||||
|
||||
Example, Flight mode comes from Variable ValId=0x1000, with current value of 1. Range of the Value is 0..10.
|
||||
|
||||
L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1021 ]
|
||||
|
||||
|
||||
- `LINE_TYPE.VALUE_NUM_I8 (Log T=V_i8)`: 8 bit number (1 byte)
|
||||
- `LINE_TYPE.VALUE_NUM_I16' (Log T=V_i16)`: 16 Bit number (2 bytes)
|
||||
- `LINE_TYPE.VALUE_NUM_SI16 (Log T=V_si16)`: Signed 16 bit number (2 bytes)
|
||||
- `LINE_TYPE.VALUE_PERCENT (Log T=L_%)`: Shows a Percent Value. 1 Byte value.
|
||||
- `LINE_TYPE.VALUE_DEGREES (Log T=L_de)`: Shows a Degrees VAlue. 1 Byte value.
|
||||
|
||||
|
||||
## LIST_TYPE Bitmap
|
||||
TYPE|Sum|Hex|7 Signed|6 Valid Min/Max??|5 No-Inc-Changing|4 Menu|3 List-Menu|2 text / number|1|0 - 16 bits
|
||||
|-|-|-|-|-|-|-|-|-|-|-
|
||||
|MENU|Text|0x1C|0|0|0|1|1|1|0|0
|
||||
|LIST_MENU|Text|0x0C|0|0|0|0|1|1|0|0
|
||||
|LIST_MENU_TOG|Text|0x4C|0|1|0|0|1|1|0|0
|
||||
|LIST_MENU_NC|Text, NC|0x6C|0|1|1|0|1|1|0|0
|
||||
|VALUE_NUM_I8_NC|I8, NC|0x60|0|1|1|0|0|0|0|0
|
||||
|VALUE_PERCENT|S8|0xC0|1|1|0|0|0|0|0|0
|
||||
|VALUE_DEGREES|S8 NC|0xE0|1|1|1|0|0|0|0|0
|
||||
|VALUE_NUM_I8|I8|0x40|0|1|0|0|0|0|0|0
|
||||
|VALUE_NUM_I16|I16|0x41|0|1|0|0|0|0|0|1
|
||||
|VALUE_NUM_SI16|S16|0xC1|1|1|0|0|0|0|0|1
|
||||
|
||||
|
||||
## Important Behavioral differences when updating values
|
||||
|
||||
Values who are editable, are updated to RX as they change. For example, when changing attitude trims, the servo moves as we change the value in real-time.
|
||||
|
||||
LIST_MENU_NC, VALUE_NUM_I8_NC don't update the RX as it changes. It changes only in the GUI, and only update the RX at the end when confirmed the value. (NO-INC-CHANGES Bit)
|
||||
|
||||
After finishing updating a value, a validation command is sent. RX can reject the current value, and will change it to the nearest valid value.
|
||||
|
||||
## Special Menus
|
||||
|
||||
Seems like menuId=0x0001 is special. When you navigate to this menu, the RX reboots.
|
||||
When this happens, we need to start from the beginning as if it was a new connection.
|
||||
|
||||
# Send and Receive messages
|
||||
|
||||
To comunicate with the Multi-Module, Lua scripts in OpenTx/EdgeTx has access to the `Multi_Buffer`. Writting to it will send data to RX, received data will be read from it.
|
||||
|
||||
For our specific case, this is how the Multi_Buffer is used:
|
||||
|
||||
|0..2|3|4..9|10..25
|
||||
|--|--|--|--
|
||||
|DSM|0x70+len|TX->RX data|RX->TX Data
|
||||
|
||||
To write a new DSM Fwd Programing command, write the data to address 4..9, and later set the address 3 with the length.
|
||||
|
||||
When receiving data, address 10 will have the message type we are receiving, or 0 if nothing has been received.
|
||||
|
||||
## Starting a new DSM Forward programming Connection
|
||||
|
||||
- Write 0x00 at address 3
|
||||
- Write 0x00 at address 10
|
||||
- Write "DSM" at address 0..2
|
||||
|
||||
## Disconnect
|
||||
|
||||
- Write 0x00 at address 0
|
||||
|
||||
|
||||
# Request Messages (TX->RX)
|
||||
|
||||
## DSM_sendHeartbeat()
|
||||
keep connection open.. We need to send it every 2-3 seconds, otherwise the RX will force close the connection by sending the TX an Exit_Confirm message.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg| Len? | ?? | ??
|
||||
0x00|0x04|0x00|0x00
|
||||
|
||||
SEND DSM_sendHeartbeat()
|
||||
DSM_SEND: [00 04 00 00 ]
|
||||
|
||||
## DSM_getRxVersion()
|
||||
Request the RX information
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg| Len? | ?? | ?? |??|??
|
||||
0x11|0x06|0x00|0x14|0x00|0x00
|
||||
|
||||
SEND DSM_getRxVersion()
|
||||
DSM_SEND: [11 06 00 14 00 00 ]
|
||||
|
||||
## DSM_getMainMenu()
|
||||
Request data for the main menu of the RX
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg| Len? | ?? | ?? |??|??
|
||||
0x12|0x06|0x00|0x14|0x00|0x00
|
||||
|
||||
SEND DSM_getMainMenu()
|
||||
DSM_SEND: [12 06 00 14 00 00 ]
|
||||
|
||||
|
||||
## DSM_getMenu(menuId, lastSelLine)
|
||||
Request data for Menu with ID=`menuId`. lastSelLine is the line that was selected to navigate to that menu. Most menus works with 0, but for some special "Enter Bind Mode", "Factory Reset", "Save to Backup" they will not work if we send 0, has to be the line who was selected in the confirmation menu line "Apply".
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (line#)??| LSB (line#)
|
||||
0x16|0x06|0x10|0x60|0x00|0x01
|
||||
|
||||
SEND DSM_getMenu(MenuId=0x1060 LastSelectedLine=1)
|
||||
DSM_SEND: [16 06 10 60 00 01 ]
|
||||
|
||||
## DSM_getFirstMenuLine(menuId)
|
||||
Request the first line of a menu identified as `menuId`. The response will be the first line of the menu. Some times, it return lines shown as `'MenuUknownLine_0x05'` that we still are trying to understand what they are for.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (menuId) | LSB (MenuId)
|
||||
0x13|0x04|0x10|0x60
|
||||
|
||||
SEND DSM_getFirstMenuLine(MenuId=0x1000)
|
||||
DSM_SEND: [13 04 10 00 ]
|
||||
|
||||
## DSM_getNextMenuLine(menuId, curLine)
|
||||
Request the retrival of the next line following the current line. Response is either the next line, or the next value, or nothing.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (line#)??| LSB (line#)
|
||||
0x14|0x06|0x10|0x60|0x00|0x01
|
||||
|
||||
SEND DSM_getNextLine(MenuId=0x1000,LastLine=1)
|
||||
DSM_SEND: [14 06 10 00 00 01 ]
|
||||
|
||||
## DSM_getNextMenuValue(menuId, valId, text)
|
||||
Retrive the next value after the last `ValId` of the current `menuId`. text is just for debugging purposes to show the header of the value been retrived.
|
||||
The Response is a Menu Value or nothing if no more data.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (ValId)| LSB (ValId)
|
||||
0x15|0x06|0x10|0x61|0x10|0x00
|
||||
|
||||
SEND DSM_getNextMenuValue(MenuId=0x1061, LastValueId=0x1000) Extra: Text="Outputs"
|
||||
DSM_SEND: [15 06 10 61 10 00 ]
|
||||
|
||||
## DSM_updateMenuValue(valId, val, text, line)
|
||||
Updates the value identified as `valId` with the numeric value `val`. `text` and `line` are there to add debugging info. No response is expected.
|
||||
|
||||
If the value is negative, it has to be translated to the proper DSM negative representaion.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (ValId) | LSB (ValId) | MSB (Value)| LSB (Value)
|
||||
0x18|0x06|0x??|0x??|0x??|0x??
|
||||
|
||||
DSM_updateMenuValue(valId, val, text, line)
|
||||
-->DSM_send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value))
|
||||
|
||||
## DSM_validateMenuValue(valId, text, line)
|
||||
Validates the value identified as `valId`. `text` and `line` are there to add debugging info. The RX can response an Update value if the value is not valid and needs to be corrected.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (ValId) | LSB (ValId)
|
||||
0x19|0x06|0x??|0x??
|
||||
|
||||
|
||||
DSM_validateMenuValue(valId, text, line)
|
||||
-> DSM_send(0x19, 0x06, int16_MSB(valId), int16_LSB(valId))
|
||||
|
||||
## DSM_menuValueChangingWait(valId, text, line)
|
||||
Durin editing, this serves as a heartbeat that we are editing the value. The value identified as `valId`. `text` and `line` are there to add debugging info. The RX can response an Update value or a NUL response.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len?? | MSB (ValId) | LSB (ValId)
|
||||
0x1A|0x06|0x??|0x??
|
||||
|
||||
DSM_menuValueChangingWait(valId, text, line)
|
||||
->DSM_send(0x1A, 0x06, int16_MSB(valId), int16_LSB(valId))
|
||||
|
||||
## DSM_exitRequest()
|
||||
Request to end the DSM Frd Prog connection. Will reponse with an exit confirmation.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len?? | ??
|
||||
0x1F|0x02|0xAA
|
||||
|
||||
CALL DSM_exitRequest()
|
||||
DSM_SEND: [1F 02 AA ]
|
||||
|
||||
# Response Messages (RX->TX)
|
||||
|
||||
All responses will have the a response byte in Multi_Buffer[10]=0x09, and the type of message in Multi_Buffer[11].
|
||||
|
||||
## RX Version Response
|
||||
|
||||
Returns the information about the current RX.
|
||||
|
||||
The Display text of name name of the RX is retrive from the `RX_Name` array.
|
||||
|
||||
|10|11|12|13|14|15|16
|
||||
|--|--|--|--|--|--|--
|
||||
|Resp|Msg|?? |RxId|Major|Minor|Patch
|
||||
|0x09|0x01|0x00|0x1E|0x02|0x26|0x05
|
||||
|
||||
RESPONSE RX: 09 01 00 1E 02 26 05
|
||||
RESPONSE Receiver=AR631 Version 2.38.5
|
||||
|
||||
## Menu Response
|
||||
Returns the menu information to display and navigation.
|
||||
The Display text for the menu is retrive from the `Text` array.
|
||||
|
||||
|
||||
|10|11|12|13|14|15|16|17|18|19|20|21
|
||||
|--|--|--|--|--|--|--|--|--|--|--|--
|
||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|LSB (TextId)|MSB (TextId)|LSB (PrevId)|MSB (PrevId)|LSB (NextId)|MSB (NextId)|LSB (BackId)|MSB (BackId)
|
||||
|0x09|0x02|0x5E|0x10|0x27|0x02|0x00|0x00|0x00|0x00|0x00|0x10
|
||||
|
||||
RESPONSE RX: 09 02 5E 10 27 02 00 00 00 00 00 10 00 00 00 00
|
||||
RESPONSE Menu: M[Id=0x105E P=0x0 N=0x0 B=0x1000 Text="Other settings"[0x227]]
|
||||
|
||||
|
||||
|
||||
## Menu Line Response
|
||||
Returns the menu line information.
|
||||
|
||||
The Display text for the menu line is retrive from the `Text` array.
|
||||
`Min`,`Max` and `Default` can be signed numbers.
|
||||
|
||||
|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25
|
||||
|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
|
||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|Line#|Line Type|LSB (TextId)|MSB (TextId)|LSB (ValId)|MSB (ValId)|LSB (Min)|MSB (Min)|LSB (Max)|MSB (Max)|LSB (Def)|MSB (Def)
|
||||
|0x09|0x03|0x61|0x10|0x00|0x6C|0x50|0x00|0x00|0x10|0x36|0x00|0x49|0x00|0x36|0x00
|
||||
|
||||
RESPONSE RX: 09 03 61 10 00 6C 50 00 00 10 36 00 49 00 36 00
|
||||
RESPONSE MenuLine: L[#0 T=LM_nc VId=0x1000 Text="Outputs"[0x50] Val=nil NL=(0->19,0,S=54) [54->73,54] MId=0x1061 ]
|
||||
|
||||
## Menu Line Value Response
|
||||
Returns the Value for a line.
|
||||
|
||||
The response updates the Value in the line identified by `ValId`.
|
||||
The Display text for the Value, when it is a list, is retrive from the `List_Text` array.
|
||||
|
||||
|10|11|12|13|14|15|16|17
|
||||
|--|--|--|--|--|--|--|--
|
||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|LSB (ValId)|MSB (ValId)|LSB (Value)|MSB (Value)
|
||||
|0x09|0x04|0x61|0x10|0x00|0x10|0x00|0x00
|
||||
|
||||
RESPONSE RX: 09 04 61 10 00 10 00 00
|
||||
RESPONSE MenuValue: UPDATED: L[#0 T=L_m0 VId=0x1000 Text="Outputs"[0x50] Val=0|"Throttle" NL=(0->19,0,S=54) [54->73,54] MId=0x1061 ]
|
||||
|
||||
## Exit Response
|
||||
Response from a Exit Request.
|
||||
|
||||
|10|11
|
||||
|--|--
|
||||
|Resp|Msg
|
||||
|0x09|0x07
|
||||
|
||||
RESPONSE RX: 09 A7
|
||||
RESPONSE Exit Confirm
|
||||
|
||||
## NULL Response
|
||||
Can be use as a response, or heartbeat from the RX to keep the connection open.
|
||||
|
||||
|10|11
|
||||
|--|--
|
||||
|Resp|Msg
|
||||
|0x09|0x00
|
||||
|
||||
RESPONSE RX: 09 00
|
||||
RESPONSE NULL
|
||||
|
||||
|
||||
# Unknown Lines
|
||||
TOTALLY UNKNOWN WHAT THIS ARE FOR.. but only works for the Main Menu..
|
||||
Other menus they just loop on line=0 forever.
|
||||
|
||||
## DSM_getNextUknownLine_0x05(menuId, curLine)
|
||||
|
||||
|
||||
Request the retrival of the next Unknown line following the current line. Response is either the next unknow line, next menu line, or the next value, or nothing.
|
||||
|
||||
|4|5|6|7|8|9| Comment
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | Line# | Line# | 0x00 | Formula(line#)??
|
||||
0x20|0x06|0x00|0x00|0x00|0x40 | LastLineLine=0 retrieval
|
||||
0x20|0x06|0x01|0x01|0x00|0x01| LastLineLine=1 retrieval
|
||||
0x20|0x06|0x02|0x02|0x00|0x02| LastLineLine=2 retrieval
|
||||
0x20|0x06|0x03|0x03|0x00|0x04| LastLineLine=3 retrieval
|
||||
0x20|0x06|0x04|0x04|0x00|0x00| LastLineLine=4 retrieval
|
||||
0x20|0x06|0x05|0x05|0x00|0x00| LastLineLine=5 retrieval
|
||||
|
||||
## Unknown Line Response
|
||||
We still don't know what is this for, but we have to retrive them and skip then. Works for main menu, but when it happens in another menus, usually we stay in an infinite loop retrieving line=0
|
||||
|
||||
|10|11|12|13|14|15|16|17
|
||||
|--|--|--|--|--|--|--|--
|
||||
|Resp|Msg|LSB (line#)
|
||||
|0x09|0x05|0x00|0x01|0x00|0x00|0x00|0x07
|
||||
|0x09|0x05|0x01|0x01|0x00|0x00|0x00|0x07
|
||||
|
||||
## Interaction on Main Menu
|
||||
This is the normal interaction for the main menu. As you can see, it iterates on the 6 Unknow lines (0..5), and afterwards, it starts sending normal menu lines.
|
||||
|
||||
SEND DSM_getFirstMenuLine(MenuId=0x1000)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=1 DATA=RX: 09 05 01 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=1)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=2 DATA=RX: 09 05 02 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=2)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=3 DATA=RX: 09 05 03 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=3)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=4 DATA=RX: 09 05 04 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=4)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=5 DATA=RX: 09 05 05 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=5)
|
||||
RESPONSE MenuLine: L[#0 T=M VId=0x1010 Text="Gyro settings"[0xF9] MId=0x1000 ]
|
||||
|
||||
## Other menus
|
||||
If it hapen on other menus. Usualy stays in an infinite loop until it crash/exits.
|
||||
The screen will show **"Error: Cannot Load Menu Lines from RX"**
|
||||
|
||||
The log will look like:
|
||||
|
||||
DSM_getMenu(MenuId=0x104F LastSelectedLine=1)
|
||||
RESPONSE Menu: M[Id=0x104F P=0x0 N=0x0 B=0x1000 Text="First Time Setup"[0x4A]]
|
||||
SEND DSM_getFirstMenuLine(MenuId=0x104F)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
ERROR: Received Same menu line
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
ERROR: Received Same menu line
|
||||
|
||||
We found that sometimes, Overriding LastSelectedLine to 0 solves the problem for some specific menus. Not for all (for other, is the oposite (0->1)). But at least no unknown lines are returned with this hack for AR631/AR637. Maybe others also needed.
|
||||
|
||||
**Overriding to Zero is not a good solution for every menu. Some menus needs the LastLine to know the behaviour (for example, Factory Reset the RX, Save Backup, Restore Backup, Enter Bind Mode, Some sensor Calibration). Thats why we cannot do it blindly.**
|
||||
|
||||
Here is the current code to fix some of this problems in AR631/AR637.
|
||||
Function `DSM_SelLine_HACK()`
|
||||
|
||||
if (ctx.RX.Id == RX.AR637T or ctx.RX.Id == RX.AR637TA or ctx.RX.Id == RX.AR631) then
|
||||
-- AR631/AR637 Hack for "First time Setup" or
|
||||
-- "First Time AS3X Setup", use 0 instead of the ctx.SelLine=5
|
||||
if (ctx.Menu.MenuId == 0x104F or ctx.Menu.MenuId==0x1055) then
|
||||
LOG_write("First time Setup Menu HACK: Overrideing LastSelectedLine to ZERO\n")
|
||||
ctx.SelLine = 0
|
||||
end
|
||||
-- DID NOT WORK: AR631/AR637 Hack for "Relearn Servo Settings", use 1 instead
|
||||
-- of the ctx.SelLine=0
|
||||
--if (ctx.Menu.MenuId == 0x1023) then
|
||||
-- LOG_write("Relearn Servo Settings HACK: Overrideing LastSelectedLine to 1\n")
|
||||
-- ctx.SelLine = 1
|
||||
--end
|
||||
|
||||
Now it retrives properly the menu:
|
||||
|
||||
Log shows:
|
||||
|
||||
First time Setup Menu HACK: Overrideing LastSelectedLine to ZERO
|
||||
DSM_getMenu(MenuId=0x104F LastSelectedLine=0)
|
||||
RESPONSE Menu: M[Id=0x104F P=0x0 N=0x0 B=0x105E Text="First Time Setup"[0x4A]]
|
||||
SEND DSM_getFirstMenuLine(MenuId=0x104F)
|
||||
.. Good menu data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1638
Lua_scripts/DSMLIB/DsmFwPrgLib.lua
Normal file
1473
Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua
Normal file
1107
Lua_scripts/DSMLIB/DsmSetupLib.lua
Normal file
15
Lua_scripts/DSMLIB/MIN_msg_fwdp_en.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
-- OVERRIDES Messges for MIN 128x64 screns
|
||||
-- FORMAT <LineType>|<Msg#>|<Text>
|
||||
-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX)
|
||||
-- IMPORTANT: NO EMPTY LINES
|
||||
--
|
||||
T |0x0097|DONT USE: Factory Reset
|
||||
T |0x0098|DONT USE: Factory Reset
|
||||
T |0x00A5|DONT USE: First Time Setup
|
||||
T |0x00B0|Self-Lev/Ang Dem
|
||||
T |0x00CD|Level model & capt attitude
|
||||
T |0x0190|DONT USE: Relearn Servo Settings
|
||||
T |0x020D|DONT USE: First Time SAFE Setup
|
||||
T |0x0254|Pos = Up, Neg = Down
|
||||
T |0x0267|Pos = Nose Up/Roll Right
|
||||
T |0x0268|Neg = Nose Down/Roll Left
|
||||
BIN
Lua_scripts/DSMLIB/img/rx_pos_1.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_10.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_11.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_12.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_13.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_14.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_15.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_16.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_17.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_18.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_19.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_2.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_20.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_21.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_22.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_23.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_24.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_25.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_3.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_4.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_5.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_6.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_7.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_8.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_9.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_1rud.png
Normal file
|
After Width: | Height: | Size: 728 B |
BIN
Lua_scripts/DSMLIB/img/tt_1rud_1ele.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_1rud_2ele.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_2rud_1ele.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_2rud_2ele.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_traileron.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_vtail.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/wt_1ail.png
Normal file
|
After Width: | Height: | Size: 721 B |
BIN
Lua_scripts/DSMLIB/img/wt_1ail_1flp.png
Normal file
|
After Width: | Height: | Size: 803 B |
BIN
Lua_scripts/DSMLIB/img/wt_2ail.png
Normal file
|
After Width: | Height: | Size: 679 B |
BIN
Lua_scripts/DSMLIB/img/wt_2ail_1flp.png
Normal file
|
After Width: | Height: | Size: 755 B |
BIN
Lua_scripts/DSMLIB/img/wt_2ail_2flp.png
Normal file
|
After Width: | Height: | Size: 817 B |
BIN
Lua_scripts/DSMLIB/img/wt_elevon.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
Lua_scripts/DSMLIB/img/wt_flaperon.png
Normal file
|
After Width: | Height: | Size: 679 B |
375
Lua_scripts/DSMLIB/msg_fwdp_en.txt
Normal file
@@ -0,0 +1,375 @@
|
||||
-- FORMAT <LineType>|<Msg#>|<Text>
|
||||
-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX)
|
||||
-- NO EMPTY LINES
|
||||
-- Formmatting at end of line: /c=Center, /r=Right, /b=Bold, /m=menu
|
||||
LT|0x0001|Off
|
||||
LT|0x0002|On
|
||||
-- Ihn/Act List Options
|
||||
LT|0x0003|Inh
|
||||
LT|0x0004|Act
|
||||
--
|
||||
-- Channel selection for SAFE MODE and GAINS on FC6250HX
|
||||
LT|0x000C|Inhibit?
|
||||
LT|0x000D|Ch5
|
||||
LT|0x000E|Ch6
|
||||
LT|0x000F|Ch7
|
||||
LT|0x0010|Ch8
|
||||
LT|0x0011|Ch9
|
||||
LT|0x0012|Ch10
|
||||
LT|0x0013|Ch11
|
||||
LT|0x0014|Ch12
|
||||
--
|
||||
-- Servo Output values
|
||||
LT|0x002D|5.5ms
|
||||
LT|0x002E|11ms
|
||||
LT|0x002F|22ms
|
||||
--
|
||||
-- Gain Multiplier Values
|
||||
LT|0x0032|1 X
|
||||
LT|0x0033|2 X
|
||||
LT|0x0034|4 X
|
||||
--
|
||||
LT|0x0035|Inh?
|
||||
LT|0x0036|Thr
|
||||
LT|0x0037|Ail
|
||||
LT|0x0038|Ele
|
||||
LT|0x0039|Rud
|
||||
LT|0x003A|Ch5
|
||||
LT|0x003B|Ch6
|
||||
LT|0x003C|Ch7
|
||||
LT|0x003D|Ch8
|
||||
LT|0x003E|Ch9
|
||||
LT|0x003F|Ch10
|
||||
LT|0x0040|Ch11
|
||||
LT|0x0041|Ch12
|
||||
LT|0x0042|Ch13
|
||||
LT|0x0043|Ch14
|
||||
LT|0x0044|Ch15
|
||||
LT|0x0045|Ch16
|
||||
LT|0x0046|Ch17
|
||||
LT|0x0047|Ch18
|
||||
LT|0x0048|Ch19
|
||||
LT|0x0049|Ch20
|
||||
--
|
||||
T |0x0040|Roll
|
||||
T |0x0041|Pitch
|
||||
T |0x0042|Yaw
|
||||
T |0x0043|Gain/c/b
|
||||
T |0x0045|Differential
|
||||
T |0x0046|Priority
|
||||
T |0x0049|Output Setup
|
||||
T |0x004A|Failsafe
|
||||
T |0x004B|Main Menu
|
||||
T |0x004E|Position
|
||||
--
|
||||
T |0x0050|Outputs
|
||||
T |0x0051|Output Channel 1
|
||||
T |0x0052|Output Channel 2
|
||||
T |0x0053|Output Channel 3
|
||||
T |0x0054|Output Channel 4
|
||||
T |0x0055|Output Channel 5
|
||||
T |0x0056|Output Channel 6
|
||||
--
|
||||
-- FailSafe Options
|
||||
--LT|0x005E|Inhibit
|
||||
LT|0x005F|Hold Last
|
||||
LT|0x0060|Preset
|
||||
--LT|0x0061|Custom
|
||||
--
|
||||
T |0x0071|Proportional
|
||||
T |0x0072|Integral
|
||||
T |0x0073|Derivate
|
||||
--
|
||||
T |0x0078|FM Channel
|
||||
--
|
||||
T |0x0080|Orientation
|
||||
T |0x0082|Heading
|
||||
T |0x0085|Frame Rate
|
||||
T |0x0086|System Setup
|
||||
T |0x0087|F-Mode Setup
|
||||
T |0x0088|Enabled F-Modes
|
||||
T |0x0089|Gain Channel
|
||||
T |0x008A|Gain Sensitivity/r -- Right Align
|
||||
T |0x008B|Panic
|
||||
T |0x008E|Panic Delay
|
||||
--
|
||||
LT|0x008D|560hz
|
||||
--
|
||||
-- FC6250HX: Callibration Menu -> Begin..Start, Complete, Done
|
||||
T |0x0091|Begin
|
||||
T |0x0090|Apply
|
||||
T |0x0092|Start
|
||||
T |0x0093|Complete
|
||||
T |0x0094|Done
|
||||
--
|
||||
T |0x0097|Factory Reset
|
||||
T |0x0098|Factory Reset
|
||||
--
|
||||
T |0x0099|Advanced Setup
|
||||
T |0x009A|Capture Failsafe Positions
|
||||
T |0x009C|Custom Failsafe
|
||||
--
|
||||
T |0x009F|Save Settings -- Save & Reboot RX
|
||||
--
|
||||
T |0x00A5|First Time Setup
|
||||
T |0x00AA|Capture Gyro Gains
|
||||
T |0x00AD|Gain Channel Select
|
||||
T |0x00AF|Dynamic
|
||||
T |0x00B0|Self-Level/Angle Dem
|
||||
T |0x00B1|Envelope
|
||||
--
|
||||
-- Flight Modes List Options
|
||||
LT|0x00B5|Inhibit
|
||||
LT|0x00B6|FM1
|
||||
LT|0x00B7|FM2
|
||||
LT|0x00B8|FM3
|
||||
LT|0x00B9|FM4
|
||||
LT|0x00BA|FM5
|
||||
LT|0x00BB|FM6
|
||||
LT|0x00BC|FM7
|
||||
LT|0x00BD|FM8
|
||||
LT|0x00BE|FM9
|
||||
LT|0x00BF|FM10
|
||||
--
|
||||
T |0x00BE|Unknown_BE -- Used in Reset menu (0x0001) while the RX is rebooting
|
||||
--
|
||||
T |0x00C7|Calibrate Sensor
|
||||
T |0x00CA|SAFE/Panic Mode Setup
|
||||
--
|
||||
T |0x00CD|Level model and capture attitude/m -- SPECIAL MENU to itself who is not a comment
|
||||
--
|
||||
-- RX Orientations for AR631/AR637, Optionally attach an Image + Alt Text to display
|
||||
LT|0x00CB|Pos 1
|
||||
LI|0x00CB|rx_pos_1.png|Pilot View: RX Label Up, Pins Back
|
||||
LT|0x00CC|Pos 2
|
||||
LI|0x00CC|rx_pos_2.png|Pilot View: RX Label Left, Pins Back
|
||||
LT|0x00CD|Pos 3
|
||||
LI|0x00CD|rx_pos_3.png|Pilot View: RX Label Down, Pins Back
|
||||
LT|0x00CE|Pos 4
|
||||
LI|0x00CE|rx_pos_4.png|Pilot View: RX Label Right, Pins Back
|
||||
LT|0x00CF|Pos 5
|
||||
LI|0x00CF|rx_pos_5.png|Pilot View: RX Label UP, Pins to Front
|
||||
LT|0x00D0|Pos 6
|
||||
LI|0x00D0|rx_pos_6.png|Pilot View: RX Label Left, Pins Front
|
||||
LT|0x00D1|Pos 7
|
||||
LI|0x00D1|rx_pos_7.png|Pilot View: RX Label Down, Pins Front
|
||||
LT|0x00D2|Pos 8
|
||||
LI|0x00D2|rx_pos_8.png|Pilot View: RX Label Right, Pins Front
|
||||
LT|0x00D3|Pos 9
|
||||
LI|0x00D3|rx_pos_9.png|Pilot View: RX Label Up, Pins Left
|
||||
LT|0x00D4|Pos 10
|
||||
LI|0x00D4|rx_pos_10.png|Pilot View: RX Label Back, Pins Left
|
||||
LT|0x00D5|Pos 11
|
||||
LI|0x00D5|rx_pos_11.png|Pilot View: RX Label Down, Pins Left
|
||||
LT|0x00D6|Pos 12
|
||||
LI|0x00D6|rx_pos_12.png|Pilot View: RX Label Front, Pins Left
|
||||
LT|0x00D7|Pos 13
|
||||
LI|0x00D7|rx_pos_13.png|Pilot View: RX Label Up, Pins Right
|
||||
LT|0x00D8|Pos 14
|
||||
LI|0x00D8|rx_pos_14.png|Pilot View: RX Label Back, Pins Right
|
||||
LT|0x00D9|Pos 15
|
||||
LI|0x00D9|rx_pos_15.png|Pilot View: RX Label Down, Pins Right
|
||||
LT|0x00DA|Pos 16
|
||||
LI|0x00DA|rx_pos_16.png|Pilot View: RX Label Front, Pins Right
|
||||
LT|0x00DB|Pos 17
|
||||
LI|0x00DB|rx_pos_17.png|Pilot View: RX Label Back, Pins Down
|
||||
LT|0x00DC|Pos 18
|
||||
LI|0x00DC|rx_pos_18.png|Pilot View: RX Label Left, Pins Down
|
||||
LT|0x00DD|Pos 19
|
||||
LI|0x00DD|rx_pos_19.png|Pilot View: RX Label Front, Pins Down
|
||||
LT|0x00DE|Pos 20
|
||||
LI|0x00DE|rx_pos_20.png|Pilot View: RX Label Right, Pins Down
|
||||
LT|0x00DF|Pos 21
|
||||
LI|0x00DF|rx_pos_21.png|Pilot View: RX Label Back, Pins Up
|
||||
LT|0x00E0|Pos 22
|
||||
LI|0x00E0|rx_pos_22.png|Pilot View: RX Label Left, Pins Up
|
||||
LT|0x00E1|Pos 23
|
||||
LI|0x00E1|rx_pos_23.png|Pilot View: RX Label Front, Pins Up
|
||||
LT|0x00E2|Pos 24
|
||||
LI|0x00E2|rx_pos_24.png|Pilot View: RX Label Right, Pins Up
|
||||
LT|0x00E3|Pos Invalid
|
||||
LI|0x00E3|rx_pos_25.png|Cannot detect orientation of RX
|
||||
--
|
||||
T |0x00D1|Receiver will Reboot/b
|
||||
T |0x00D2|Panic Channel
|
||||
T |0x00D3|Swashplate
|
||||
T |0x00D5|Agility
|
||||
T |0x00D8|Stop
|
||||
T |0x00DA|SAFE/c/b -- Center + Bold
|
||||
T |0x00DB|Stability
|
||||
T |0x00DC|@ per sec
|
||||
T |0x00DD|Tail rotor
|
||||
T |0x00DE|Setup
|
||||
T |0x00DF|AFR
|
||||
T |0x00E0|Collective
|
||||
T |0x00E1|Subtrim
|
||||
T |0x00E2|Phasing
|
||||
T |0x00E4|E-Ring
|
||||
T |0x00E5|Swash Type
|
||||
T |0x00E6|Travel
|
||||
T |0x00E7|Left
|
||||
T |0x00E8|Right
|
||||
--
|
||||
LT|0x00F2|Fixed
|
||||
LT|0x00F3|Adjustable
|
||||
--
|
||||
T |0x00F6|Direction
|
||||
T |0x00F8|Settings -- ?? validate on a Spektrum radio
|
||||
T |0x00F9|Gyro settings
|
||||
T |0x00FE|Stick Priority/c/b
|
||||
--
|
||||
T |0x0100|Make sure the model has been
|
||||
T |0x0101|configured, including wing type,
|
||||
T |0x0102|reversing, travel, trimmed, etc.
|
||||
T |0x0103|before continuing setup.
|
||||
T |0x0104| -- Blank
|
||||
--
|
||||
T |0x0106|Any wing type, channel assignment,
|
||||
T |0x0107|subtrim, or servo reversing changes
|
||||
T |0x0108|require running through initial
|
||||
T |0x0109|setup again.
|
||||
T |0x010A| -- Blank
|
||||
--
|
||||
T |0x0190|Relearn Servo Settings
|
||||
T |0x019C|Enter Receiver Bind Mode
|
||||
T |0x01AA|Offset
|
||||
T |0x01D7|SAFE Select Channel
|
||||
T |0x01DC|AS3X/c/b -- Center + Bold
|
||||
T |0x01DD|AS3X Settings
|
||||
T |0x01DE|AS3X Gains
|
||||
T |0x01E0|Rate Gains/c/b
|
||||
T |0x01E2|SAFE Settings
|
||||
T |0x01E3|SAFE Gains
|
||||
T |0x01E6|Attitude Trim/c/b
|
||||
T |0x01E7|Envelope
|
||||
T |0x01E9|Roll Right
|
||||
T |0x01EA|Roll Left
|
||||
T |0x01EB|Pitch Down
|
||||
T |0x01EC|Pitch Up
|
||||
T |0x01EE|Thr to Pitch
|
||||
T |0x01EF|Low Thr to Pitch/c/b
|
||||
T |0x01F0|High Thr to Pitch/c/b
|
||||
T |0x01F3|Threshold
|
||||
T |0x01F4|Angle
|
||||
T |0x01F6|Failsafe Angles/c/b
|
||||
T |0x01F8|Safe Mode
|
||||
T |0x01F9|SAFE Select
|
||||
T |0x01FC|Panic F-Mode
|
||||
T |0x01FD|FailSafe Flight Mode -- Safe Flight Mode
|
||||
T |0x0201|Throttle
|
||||
T |0x0204|Hover
|
||||
T |0x0208|Decay
|
||||
T |0x0209|Save to Backup
|
||||
T |0x020A|Restore from Backup
|
||||
T |0x020D|First Time SAFE Setup
|
||||
--
|
||||
-- First time safe setup Page 3 :
|
||||
T |0x020E|AS3X gains must be tuned
|
||||
T |0x020F|and active in SAFE Flight Modes
|
||||
T |0x0210|to help reduce wobble.
|
||||
T |0x0211| -- Blank
|
||||
T |0x0212| -- Blank
|
||||
T |0x0213| -- Blank
|
||||
--
|
||||
-- AS3X orientation Setting menu (Level)
|
||||
T |0x021A|Set the model level,
|
||||
T |0x021B|and press Continue.
|
||||
T |0x021C| -- Blank
|
||||
T |0x021D| -- Blank
|
||||
--
|
||||
-- AS3X orientation Setting menu (Nose down)
|
||||
T |0x021F|Set the model on its nose,
|
||||
T |0x0220|and press Continue. If the
|
||||
T |0x0221|orientation on the next
|
||||
T |0x0222|screen is wrong go back
|
||||
T |0x0223|and try again.
|
||||
--
|
||||
T |0x0224|Continue
|
||||
T |0x0226|Angle Limits/c/b
|
||||
T |0x0227|Other settings
|
||||
T |0x0229|Set Orientation Manually
|
||||
--
|
||||
-- Factory Default Warning
|
||||
T |0x022B|WARNING!
|
||||
T |0x022C|This will reset the
|
||||
T |0x022D|configuration to factory
|
||||
T |0x022E|defaults. This does not
|
||||
T |0x022F|affect the backup config.
|
||||
T |0x0230| -- Blank
|
||||
--
|
||||
-- Backup Warning
|
||||
T |0x0231|This will overwrite the
|
||||
T |0x0232|backup memory with your
|
||||
T |0x0233|current configuartion.
|
||||
T |0x0234| -- Blank
|
||||
T |0x0235| -- Blank
|
||||
--
|
||||
-- Restore from Backup Warning
|
||||
T |0x0236|This will overwrite the
|
||||
T |0x0237|current config with
|
||||
T |0x0238|that which is in
|
||||
T |0x0239|the backup memory.
|
||||
T |0x023A| -- blank line
|
||||
--
|
||||
-- Utilities Copy flight modes
|
||||
T |0x023D|Copy F-Mode Settings
|
||||
T |0x023E|Source F-Mode
|
||||
T |0x023F|Target F-Mode
|
||||
--
|
||||
T |0x0240|Utilities
|
||||
--
|
||||
-- Gain Capture Page
|
||||
T |0x024C|Gains will be captured on
|
||||
T |0x024D|Captured gains will be
|
||||
T |0x024E|Gains on
|
||||
T |0x024F|were captured and changed
|
||||
T |0x0250|from Adjustable to Fixed
|
||||
--
|
||||
-- Utilities, Copy flight mode (Copy Confirmation, oveerriding FM)
|
||||
T |0x0251|Are you sure you want to ovewrite the "Target"
|
||||
T |0x0252|with the "Source" ?
|
||||
T |0x0253| -- Blank
|
||||
--
|
||||
T |0x0254|Postive = Up, Negative = Down
|
||||
--
|
||||
-- First time safe setup Page 1 (maybe ask to select Flight Mode cannel)
|
||||
T |0x0255|Before setting up SAFE
|
||||
T |0x0256|a Flight Mode channel
|
||||
T |0x0257|most be configured.
|
||||
--
|
||||
-- First time safe setup Page 2 (something related for flight mode)
|
||||
T |0x025A|Select the desired flight mode
|
||||
T |0x025B|switch position to adjust settings
|
||||
T |0x025C|for each flight mode
|
||||
T |0x025D| -- Blank
|
||||
T |0x025E| -- Blank
|
||||
--
|
||||
-- Utilities, Copy flight mode (Confirm)
|
||||
T |0x0259|YES
|
||||
T |0x0260|WARNING: "Target"
|
||||
T |0x0261|F-Mode will be overwritten
|
||||
T |0x0262|by "Source"
|
||||
--
|
||||
T |0x0263|Fixed/Adjustable Gains/c/b
|
||||
T |0x0266|Heading Gain/c/b
|
||||
T |0x0267|Positive = Nose Up/Roll Right
|
||||
T |0x0268|Negative = Nose Down/Roll Left
|
||||
T |0x0269|SAFE - Thr to Pitch
|
||||
T |0x026A|Use CAUTION for Yaw gain!/b
|
||||
--
|
||||
T |0x0300|No compatible DSM RX...
|
||||
T |0x0301|Waiting for RX to Restart
|
||||
--
|
||||
FM|0x8000|Flight Mode/c/b
|
||||
--
|
||||
RX|0x0001|AR636
|
||||
RX|0x0014|SPM4651T
|
||||
RX|0x0015|AR637T
|
||||
RX|0x0016|AR637TA
|
||||
RX|0x0018|FC6250HX
|
||||
RX|0x0019|AR630
|
||||
RX|0x001A|AR8360T
|
||||
RX|0x001B|AR8020T
|
||||
RX|0x001C|AR10360T
|
||||
RX|0x001E|AR631
|
||||
|
||||
227
Lua_scripts/DSMLIB/readme.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# Credits
|
||||
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
Rewrite/Enhancements by: Francisco Arzu
|
||||
|
||||
Thanks to all the people volunteered to test it.
|
||||
|
||||
# Introduction (v0.54)
|
||||
|
||||
This script library enhances the original DSM Forward Programming tool. DSM Forward Programming is needed to setup many of the new Spektrum Receivers with Gyro AS3X/SAFE features. For the Gyro (/Safe) to correct the plane in flight, it needs to move the right surfaces therefore the RX needs to know the configuration of the plane (Wing Type, Tail Type, Mixers, Servo Assignments, Servo Reverse). That info tells the RX where the aileron(s) are (one or two), where the elevator(s) are (one or two), V-Tail, Delta Wing, etc.
|
||||
|
||||
Since EdgeTx/OpenTx doesn’t have an equivalent setup that is stored in the radio, we have to create our own version. This info is stored inside the `/MODELS/DSMDATA` directory/folder (which needs to be created by manually).
|
||||
|
||||
During `"Gyro Settings->initial setup"`, the RX asks the TX for model information behind the scenes. After setup, `"Gyro Settings->System Tools-> Relearn Servo Settings"` requests the TX configuration and stores it in the RX.
|
||||
|
||||
# Deployment
|
||||
Make sure to manually create `/MODELS/DSMDATA` . The script will complain at startup if it does not exist. Here the script saves the Spektrun settings for each of your models.
|
||||
|
||||
Uncompress the Zip file (ZIP version) into your local computer.
|
||||
In another window, open your TX SDCard and go to /SCRIPTS/TOOLS.
|
||||
|
||||
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first)
|
||||
|
||||
Copy the entire DSMLIB folder.
|
||||
Copy the main script you want to use (Color or B&W).
|
||||
|
||||
|
||||
Your TX SDCard should looks like this:
|
||||
|
||||
/SCRIPTS/TOOLS
|
||||
DSM FwdPrg_05_BW.lua -- black/white text only
|
||||
DSM FwdPrg_05_Color.lua -- Color and touch radios
|
||||
DSM FwdPrg_05_MIN.lua -- `NEW!` Minimalistic version for radios with LOW memory (cannot setup new planes)
|
||||
|
||||
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
|
||||
DsmFwPrgLib.lua -- DSM Protocol Message and Menu engine
|
||||
DsmFwPrgSIMLib.lua -- Simulation of AR631, FC6250HX (For GUI development)
|
||||
SetupLib.lua -- Model Setup Screens
|
||||
msg_fwdp_en.txt -- `NEW!` Messages for forward programing externalized. To support other langs
|
||||
|
||||
/SCRIPTS/TOOLS/DSMLIB/img -- Images for RX orientations
|
||||
|
||||
Other Directories
|
||||
|
||||
/MODELS/DSMDATA --(ALL CAPITALS) Data of model config (Wing Type, Servo Assignments)
|
||||
/LOGS/dsm_log.txt --Readable log of the last RX/TX session, usefull for debugging problems
|
||||
|
||||
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first)
|
||||
|
||||
# Common Questions
|
||||
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
|
||||
V0.53 and newer: The RX is listening to channel changes for this options. Configure the Switch to the channel, togling once the switch will select the channel on the menu field.
|
||||
|
||||
2. `Why Ch1 says Ch1 (TX:Ch3/Thr)?`:
|
||||
Radios with Multi-Module are usually configured to work the standard AETR convention. Spektrum uses TAER. The multi-module does the conversion when transmitting the signals. So `Spektrum Ch1 (Throttle)` really comes from the `TX Ch3`. We show both information (+name from the TX output). If your multi-module/radio is setup as TAER, the script will not do the re-arrangement.
|
||||
|
||||
3. `If i change the model name, the original model settings are lost.` This is correct, the model name is used to generate the file name (inside /MODEL/DSMDATA) who stores the model configuration. Currently EdgeTx and OpenTX has differt features where i could get either the Model Name or the YAML file where the EdgeTX model configuration is stored.. to keep the code compatible, the model name is used.
|
||||
|
||||
4. `Reversing a channel in my TX do not reverse the AS3X/SAFE reaction.` Correct, the channel stick direction and the Gyro direction are two separate things.
|
||||
|
||||
4.1: First, you have setup your model so that the sticks and switches moves the surfaces in the right direction.
|
||||
|
||||
4.2: Go to the script, `Model Setup` and setup your wing type, tail type, and select the channel assigment for each surface. Leave the servo settings the same as the values in the TX to start.
|
||||
|
||||
4.3: AR63X family: Go to `Forward programming->Gyro Setting->Initial Setup` (New/factory reset), or `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` (not new RX). This will load your current Gyro servo settings into the plane's RX.
|
||||
|
||||
4.4: Verify that the AS3X and SAFE reacts in the proper direction. You can use the Flight mode confugured as "Safe Mode: Auto-Level" to see if it moves the surfaces in the right direction.
|
||||
|
||||
4.5: If a surface don't move in the right direction, go to the `Model Setup->Gyro Channel Reverse` to reverse the Gyro on the channels needed, and do again the `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` to tranfer the new settings to the RX.
|
||||
|
||||
4.6: Specktrum TX always passes the TX servo reverse as the Gyro Reverse, but on many OpenTX/EdgeTX radios, the Rud/Ail are usually reversed by default compared to Specktrum. So far i don't think that i can use this as a rule, that is why the `Gyro Channel Reverse` page exist.
|
||||
|
||||
---
|
||||
---
|
||||
|
||||
# Changes and fixes
|
||||
V0.54:
|
||||
1. Fix a problem in the Attitude Trim page (`Gyro Settings->System Setup->SAFE/Panic Setup->Attitude Trim`). It was not saving the values after exiting the menu. This is to change what SAFE considers "Level" flying.
|
||||
2. Wings 2-Ail 2-Flaps had a bug on the 2nd flap.
|
||||
3. New Minimalistic script (`DsmFwdPrg_05_MIN.lua`): For radios with very low memory (FrSky QX7, RM Zorro, others). It can only change existing settings, but does not have the Plane Setup menus to setup a completly new plane. In some radios, the very first time it runs (compile + run), it might give you a `not enouth memory` error.. try to run it again.
|
||||
4. External menu message file (DSMLIB/msg_en.txt and msg_MIN_es.txt). Intial work to do localization and different languages.
|
||||
|
||||
V0.53:
|
||||
1. Improved channel selection (Flight mode, Panic Channel, Gains Channel). Now during editing a channel, you can select any channel (>Ch4). Also, of you toggle the switch/channel it will populate the screen.
|
||||
2. Support for smaller screens (128x64) in B&W. The problem with this older radios is memory. In some, it does not have enouth memory to load the additional DSMLIB libraries.
|
||||
3. Fix formatting problem with some TX channel names who could affect the screen.. for example, rud channel should show "Ch4/rud", but shows "Ch4ud" because /r is for right justify formatting on messages. Now the formatting is only if it appears at the end of the message.
|
||||
|
||||
V0.52:
|
||||
1. Menus to be able to configure Plane in a similar way as Spektrum Radio (v0.52)
|
||||
2. Make "Gyro Settings"->"Initial Setup" works (Tested on AR631,AR637xx with PLANE type of aircraft)
|
||||
3. Properly reset and restart after initial configuration and SAFE changes.
|
||||
4. Write Log of the conversation between RX/TX. To be used for debugging a problem is reported.
|
||||
5. Provide a simulation of RX to do GUI development in Companion, and understand patterns of how the data is organized.
|
||||
|
||||
# Tested Hardware
|
||||
- AR631/AR637xx
|
||||
- FC6250HX (Blade 230S V2 Helicopter)
|
||||
- AR636 (Blade 230S V1 Heli firmware 4.40)
|
||||
|
||||
- Radiomaster TX16S (All versions)
|
||||
- FrSky QX7, Radimaster Boxter (Minimalistic version)
|
||||
|
||||
Please report if you have tested it with other receivers to allow us to update the documentation. Code should work up to 10 channels for the main surfaces (Ail/Ele/etc). All Spektrum RX are internally 20 channels, so you can use Ch7 for Flight Mode even if your RX is only 6 channels (See common Questions)
|
||||
|
||||
|
||||
# Messages Displayed in the GUI
|
||||
|
||||
If in a screen you get text that looks like `Unknown_XX` (ex: Unknown_D3), that message has not been setup in the script in english. If you can determine what the proper message is, you can send us a message to be added to the library.
|
||||
The `XX` represents a Hex Number (0..9,A..F) message ID.
|
||||
|
||||
|
||||
### Version 0.53 and older:
|
||||
If you want to fix it in your local copy, all messages are towards the end in the file `SCRIPT\TOOS\DSMLIB\DsmFwPrgLib.lua`. Messages for Headers are stored in `Text` and messages for Options are stored in `List_Text`. Lua scripts are text files, and can be edited with Notepad or equivalent.
|
||||
|
||||
Portion of DsmFwPrgLib.lua:
|
||||
|
||||
Text[0x0097] = "Factory Reset"
|
||||
Text[0x0098] = "Factory Reset" -- FC6250HX: Title
|
||||
Text[0x0099] = "Advanced Setup"
|
||||
Text[0x009A] = "Capture Failsafe Positions"
|
||||
Text[0x009C] = "Custom Failsafe"
|
||||
|
||||
Text[0x009F] = "Save & Reset RX" -- TODO: Find the Proper Spektrum Value ??
|
||||
|
||||
Text[0x00A5] = "First Time Setup"
|
||||
Text[0x00AA] = "Capture Gyro Gains"
|
||||
Text[0x00AD] = "Gain Channel Select"
|
||||
|
||||
-- Safe mode options, Inhibit + the values
|
||||
local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope
|
||||
List_Text[0x00B0] = "Self-Level/Angle Dem"
|
||||
List_Text[0x00B1] = "Envelope"
|
||||
|
||||
For example, if you get `Unknown_9D` in the GUI and your now that it should say **NEW Text**, you can edit the lua script to look like this:
|
||||
|
||||
Text[0x009A] = "Capture Failsafe Positions"
|
||||
Text[0x009C] = "Custom Failsafe"
|
||||
|
||||
Text[0x009D] = "NEW Text" -- NEW Text added for AR98xx
|
||||
|
||||
Text[0x009F] = "Save & Reset RX" -- TODO: Find the proper Spektrum text
|
||||
|
||||
### Version 0.54 and newer:
|
||||
The menu messages are stored in DSMLIB/msg_fwdp_en.txt (For english). Just add the message there. MIN_msg_fwdp_en.txt has shorter messages overrides for screens who are smaller (for minimalistic 128x64 version). The reference to the message file is at the file `/DSMLIB/DsmFwPrgLib.lua` if you want to change to use another language.
|
||||
|
||||
T |0x0097|Factory Reset
|
||||
LT|0x00B0|Self-Level/Angle Dem
|
||||
LT|0x00B1|Envelope
|
||||
|
||||
# LOG File
|
||||
|
||||
The log file of the last use of the script is located at `/LOGS/dsm_log.txt`. **It is overridden on every start to avoid filling up the SD card**. So if you want to keep it, copy or rename it before starting the script again. (it can be renamed in the TX by browsing the SD card)
|
||||
|
||||
The log is human readable. The first number is the number of seconds since the start, and then what is the current state of the Library, and what has been sent and received. The info in the log can be easily used to create a new simulation for that RX in the future.
|
||||
|
||||
Example Log:
|
||||
|
||||
5.340 WAIT_CMD: DSM_GotoMenu(0x1010,LastSelectedLine=0)
|
||||
5.350 MENU_TITLE: SEND DSM_getMenu(MenuId=0x1010 LastSelectedLine=0)
|
||||
5.440 MENU_TITLE: RESPONSE Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
||||
5.490 MENU_LINES: SEND DSM_getFirstMenuLine(MenuId=0x1010)
|
||||
5.590 MENU_LINES: RESPONSE MenuLine: L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ]
|
||||
5.640 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=0)
|
||||
5.740 MENU_LINES: RESPONSE MenuLine: L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ]
|
||||
5.790 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=1)
|
||||
5.850 MENU_LINES: RESPONSE MenuLine: L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ]
|
||||
5.910 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=2)
|
||||
5.970 MENU_LINES: RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
|
||||
6.020 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=3
|
||||
|
||||
# Validation of data by the RX
|
||||
|
||||
The RX validates the data. if you change to an invalid channel or do a invalid number range, the RX will change it at the end of editing the field.
|
||||
|
||||
---
|
||||
# Version 0.53
|
||||
- Improve Channel selection in menus
|
||||
- Support smaller screens 128x64 in the black/white mode.
|
||||
|
||||
# Version 0.52
|
||||
- Fix Reversing of Servos
|
||||
- Properly detect Multimodule Ch settings AETR
|
||||
---
|
||||
|
||||
# Version 0.51 (volunteer testing version, not for production)
|
||||
- New Screens to Configure Model (Wing Type/Tail Tail, etc)
|
||||
- Finally got understanding that the previous unknown 0x05 lines are to send Model/Servo data to RX.
|
||||
- Fix use of AR636B (Firmware version 4.40.0 for Blade 230 heli, is the only one with Forward Programming)
|
||||
- Aircraft types: Tested With Plane type only.. Glider and other in progress
|
||||
|
||||
### Known Problems:
|
||||
- 4-Servo Wing type (Dual Ail/Tail) in planes give conflicting servo assignments by defaults.. Solution choose your own Ch.
|
||||
- Glider, Heli, Drone: Still in development. In glider, only a few wing type works.. needs to restrict menu options for the only valid one.
|
||||
|
||||
|
||||
# Version 0.5
|
||||
|
||||
- Make the code more readable and understandable
|
||||
- Separate the DSM Forwards Programming logic from the GUI
|
||||
- Log the communication with the RX on a /LOGS/dsm_log.txt to allow to debug it easier
|
||||
and see the exchange of data between the RX/TX
|
||||
- Created a black/white Text only version with only Key/Roller Inputs
|
||||
- Created a nicer GUI for EdgeTX touch screen color Radios
|
||||
- RX simulation for GUI development: turn on `SIMULATION_ON=true` in the beginning of the lua file
|
||||
- Test it on AR631, AR637xx, FC6250HX (Helicopter)
|
||||
|
||||
|
||||
### Some settings that can change (top of Lua file):
|
||||
SIMULATION_ON = false -- FALSE: hide similation menu (DEFAULT), TRUE: show RX simulation menu
|
||||
DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm_log.txt)
|
||||
USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX, OpenTX handle colors different)
|
||||
|
||||
|
||||
### Known Problems:
|
||||
1. **Incorrect List Value Options:** Some Menu List line (`LINE_TYPE.LIST_MENU1` or `L_m1` in logs), the range (min/max) of valid values seems to be incorrect, but the RX corrects the values.
|
||||
in the MINimalistic version, the RX is doing all the range validation, and will show invalid options temporarilly. In an Spektrum radio, it happens so fast, that you don't notice it, but in LUA scripts who are slower, you can see it in the screen.
|
||||
In the COLOR version, The code has hardcoded the valid ranges to avoid this problem.
|
||||
|
||||
|
||||
|
||||
2. Glider/Heli/Drone wing types not ready.
|
||||
|
||||
For Helicopter, use airplane normal wing and normal tail
|
||||
|
||||
|
||||
# Version 0.2
|
||||
Original Version from Pascal Langer
|
||||
|
||||
683
Lua_scripts/DSM_AR636_Tel.lua
Normal file
@@ -0,0 +1,683 @@
|
||||
local toolName = "TNS|DSM AR636 Telemetry|TNE"
|
||||
---- ######################################################################### #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Developer: Francisco Arzu
|
||||
-- Original idea taken from DsmPID.lua.. don't know who is the author
|
||||
--
|
||||
|
||||
local DEBUG_ON = false
|
||||
--
|
||||
|
||||
local TEXT_SIZE = 0 -- NORMAL
|
||||
local X_COL1_HEADER = 6
|
||||
local X_COL1_DATA = 60
|
||||
local X_COL2_HEADER = 170
|
||||
local X_COL2_DATA = 220
|
||||
local Y_LINE_HEIGHT = 20
|
||||
local Y_HEADER = 0
|
||||
local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2
|
||||
local X_DATA_LEN = 80
|
||||
local X_DATA_SPACE = 5
|
||||
|
||||
|
||||
local function getPage(iParam)
|
||||
-- get page from 0-based index
|
||||
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
|
||||
local res = (math.floor(iParam/4)==0) and 0 or 1
|
||||
return res
|
||||
end
|
||||
|
||||
local function round(v)
|
||||
-- round float
|
||||
local factor = 100
|
||||
return math.floor(v * factor + 0.5) / factor
|
||||
end
|
||||
|
||||
|
||||
local function readValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
--v = round(v)
|
||||
return v
|
||||
end
|
||||
|
||||
local function readValueById(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return nil end
|
||||
|
||||
local v = getValue(i.id)
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function readBatValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
if (v==nil) then return "--" end
|
||||
|
||||
return string.format("%2.2f",v)
|
||||
end
|
||||
|
||||
local function readActiveParamValue(sensor)
|
||||
-- read and return a validated active parameter value
|
||||
local v = getValue(sensor)
|
||||
if (v<1 or v>8) then
|
||||
return -1
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
local function drawPIDScreen()
|
||||
-- draw labels and params on screen
|
||||
|
||||
local pageId = getValue("FLss")
|
||||
|
||||
lcd.clear()
|
||||
-- if active gain does not validate then assume
|
||||
-- Gain Adjustment Mode is disabled
|
||||
if not (pageId==4401 or pageId==4402) then
|
||||
lcd.drawText(0,0,"BLADE Gain Adjustment", TEXT_SIZE +INVERS)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Gain Adjustment Mode",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/R + Low/R + Panic (3 sec)",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: Right Stk: Up/Down to select, Left/Right change value",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE)
|
||||
return
|
||||
end
|
||||
|
||||
local activePage = (pageId % 100)-1 --Last 2 digits, make it zero base
|
||||
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Cyclic (0-200)", TEXT_SIZE + INVERS)
|
||||
lcd.drawText (X_COL2_HEADER, Y_HEADER, "Tail (0-200)", TEXT_SIZE + INVERS)
|
||||
|
||||
|
||||
|
||||
local p = readValue("FdeA")
|
||||
local i = readValue("FdeB")
|
||||
local d = readValue("FdeL")
|
||||
local r = readValue("FdeR")
|
||||
|
||||
local titles = {[0]="P:", "I:", "D:", "Resp:", "P:","I:","D:", "Filt:"}
|
||||
local values = {[0]=p,i,d,r,p,i,d,r}
|
||||
|
||||
local activeParam = readActiveParamValue("Hold")-1
|
||||
|
||||
for iParam=0,7 do
|
||||
-- highlight selected parameter
|
||||
local attr = (activeParam==iParam) and INVERS or 0
|
||||
-- circular index (per page)
|
||||
local perPageIndx = (iParam % 4)
|
||||
|
||||
-- set y draw coord
|
||||
local y = (perPageIndx+1)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- check if displaying cyclic params.
|
||||
local isCyclicPage = (getPage(iParam)==0)
|
||||
|
||||
-- labels
|
||||
local x = isCyclicPage and X_COL1_HEADER or X_COL2_HEADER
|
||||
-- labels are P,I,D for both pages except for last param
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- gains
|
||||
-- set all params for non-active page to '--' rather than 'last value'
|
||||
val = (getPage(iParam)==activePage) and values[iParam] or '--'
|
||||
x = isCyclicPage and X_COL1_DATA or X_COL2_DATA
|
||||
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function drawFlightLogScreen()
|
||||
-- draw labels and params on screen
|
||||
local h = getValue("Hold")
|
||||
local activeParam = h-1 -- H
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS)
|
||||
|
||||
-- read and return parameters
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
local r = getValue("FdeR")
|
||||
local f = getValue("FLss")
|
||||
|
||||
local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"}
|
||||
local values = {[0]=a,b,l,r,f,h}
|
||||
|
||||
local y = Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
for iParam=0,3 do -- A,B,L,R
|
||||
-- highlight selected parameter (rund)
|
||||
local attr = ((activeParam%4)==iParam) and INVERS or 0
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA + X_DATA_LEN
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_LINE_HEIGHT+Y_DATA
|
||||
for iParam=4,5 do -- F, H
|
||||
-- labels
|
||||
local x = X_COL2_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + BOLD)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL2_DATA + X_DATA_LEN
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
local bat = readBatValue("A2") or "--"
|
||||
lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE)
|
||||
|
||||
end
|
||||
|
||||
local function servoAdjustScreen()
|
||||
-- draw labels and params on screen
|
||||
local pageId = getValue("FLss") -- FLss
|
||||
local activeParam = getValue("Hold")-1 -- Hold
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0, Y_HEADER, "BLADE Servo SubTrim", TEXT_SIZE + INVERS)
|
||||
|
||||
if pageId~=1234 then
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Servo Adjustment Mode",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/L + Low/R + Panic (3 sec)",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: R Stk: Up/Down to select, Left/Right change value",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE)
|
||||
return
|
||||
end
|
||||
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
|
||||
local titles = {[0]="Servo1:", "Servo2:", "Servo3:"}
|
||||
local values = {[0]=a,b,l}
|
||||
|
||||
for iParam=0,#values do -- S1,S2,S3
|
||||
-- highlight selected parameter
|
||||
local attr = (activeParam==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam+1)*Y_LINE_HEIGHT+Y_HEADER
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Unsigned_to_SInt16(value)
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function getDegreesValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%0.1f o",vs/10)
|
||||
end
|
||||
|
||||
|
||||
local function getDecHexValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%d (0x%04X)",vs,v)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function drawVersionScreen()
|
||||
local paramV = getValue("FdeA")
|
||||
local B = getValue("FdeB")
|
||||
local rxId = getValue("FdeL")
|
||||
local firmware = getValue("FLss")
|
||||
local prodId = getValue("Hold")
|
||||
local bat = readBatValue("A2")
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0, Y_HEADER, "BLADE Version", TEXT_SIZE + INVERS)
|
||||
|
||||
--Product ID
|
||||
local val = "ID_".. prodId
|
||||
|
||||
if (prodId==243) then val = "Blade 230 V1"
|
||||
elseif (prodId==250) then val = "Blade 230 V2 (not Smart)"
|
||||
elseif (prodId==149) then val = "Blade 250 CFX"
|
||||
end
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
lcd.drawText (X_COL1_HEADER, y, "Prod:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- RX
|
||||
val = "ID_"..rxId
|
||||
if (rxId==1) then val = "AR636"
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "RX:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- Firmware
|
||||
val = string.format("%0.2f",firmware/100)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Firmware:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- ParamV
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Params:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, paramV, TEXT_SIZE)
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, bat, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText(X_COL1_HEADER,y,"Press Panic for 3s",TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText(X_COL1_HEADER,y,"Usually Panic is Ch7 on a switch and Revesed",TEXT_SIZE)
|
||||
|
||||
end
|
||||
|
||||
local function parseFlightMode(v)
|
||||
-- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0= off, 1=init, 2=Hold, 3=Running) GG=???
|
||||
if v==nil then return "---" end
|
||||
local fm = bit32.rshift(v, 12)
|
||||
local status = bit32.band(bit32.rshift(v, 8),0xF)
|
||||
|
||||
local res = " "..fm.." "
|
||||
|
||||
if (fm==0) then res = res .. " NORMAL"
|
||||
elseif (fm==1) then res = res .. " INTERMEDIATE"
|
||||
elseif (fm==2) then res = res .. " ADVANCED"
|
||||
elseif (fm==5) then res = res .. " PANIC"
|
||||
end
|
||||
|
||||
if (status==2) then res=res .. " HOLD" end
|
||||
|
||||
if (DEBUG_ON) then
|
||||
res = res .. string.format(" (0x%04X)",v)
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
|
||||
local function drawAlpha6Monitor()
|
||||
lcd.clear()
|
||||
|
||||
local RxStatus = readValueById("2402") -- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0=init, 2=Ready, 3=Sensor Fault) GG=???
|
||||
|
||||
local ARoll = getDegreesValue("2406") --Att Roll
|
||||
local APitch = getDegreesValue("2408") --Att Pitch
|
||||
local AYaw = getDegreesValue("240B") --Att Yaw
|
||||
|
||||
|
||||
lcd.drawText (0,0, "BLADE Alpha6 Monitor", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL1_DATA+X_DATA_LEN*2
|
||||
local x_data3 = X_COL1_DATA+X_DATA_LEN*3
|
||||
|
||||
-- Flight Mode
|
||||
lcd.drawText (0,y, "F-Mode:"..parseFlightMode(RxStatus), TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (x_data1,y, "Attitude", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data2,y, "Gyro", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data3,y, "Gain", TEXT_SIZE+BOLD + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Rol:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, ARoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, APitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, AYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT + Y_LINE_HEIGHT
|
||||
lcd.drawText (0,y, "Bat: "..readBatValue("A2").." v", TEXT_SIZE)
|
||||
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local s2400 = getDecHexValue("2400")
|
||||
local s2402 = getDecHexValue("2402")
|
||||
local s2404 = getDecHexValue("2404")
|
||||
|
||||
local s240D = getDecHexValue("240D")
|
||||
|
||||
local s1G00 = getDecHexValue("1G00")
|
||||
local s1G02 = getDecHexValue("1G02")
|
||||
local s1G04 = getDecHexValue("1G04")
|
||||
local s1G06 = getDecHexValue("1G06")
|
||||
local s1G08 = getDecHexValue("1G08")
|
||||
local s1G0B = getDecHexValue("1G0B")
|
||||
local s1G0D = getDecHexValue("1G0D")
|
||||
|
||||
local titles = {[0]=
|
||||
"2400","2402/FM-S-?",
|
||||
"2404","240D",
|
||||
"1G00","1G02","1G04",
|
||||
"1G06","1G08","1G0B","1G0D"}
|
||||
|
||||
local values = {[0]=
|
||||
s2400,s2402,s2404,s240D,
|
||||
s1G00,s1G02,s1G04,
|
||||
s1G06,s1G08,s1G0B,s1G0D}
|
||||
|
||||
|
||||
-- draw labels and params on screen
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#titles do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+220
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function readAlpha3arameters()
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function drawAS3XMonitor()
|
||||
lcd.clear()
|
||||
local s1G00 = getDecHexValue("1G00")
|
||||
local s1G02 = getDecHexValue("1G02")
|
||||
local s1G04 = getDecHexValue("1G04")
|
||||
local s1G06 = getDecHexValue("1G06")
|
||||
local s1G08 = getDecHexValue("1G08")
|
||||
local s1G0B = getDecHexValue("1G0B")
|
||||
local s1G0D = getDecHexValue("1G0D")
|
||||
|
||||
local s6C00 = getDecHexValue("6C00")
|
||||
local s6C02 = getDecHexValue("6C02")
|
||||
local s6C04 = getDecHexValue("6C04")
|
||||
|
||||
|
||||
|
||||
local RRoll = bit32.rshift(getValue("1G00") or 0,8)
|
||||
local RPitch = bit32.band(getValue("1G00") or 0,0xFF)
|
||||
local RYaw = bit32.rshift(getValue("1G02") or 0,8)
|
||||
|
||||
local HRoll = bit32.band(getValue("1G02") or 0,0xFF)
|
||||
local HPitch = bit32.rshift(getValue("1G04") or 0,8)
|
||||
local HYaw = bit32.band(getValue("1G04") or 0,0xFF)
|
||||
|
||||
local ARoll = bit32.rshift(getValue("1G06") or 0,8)
|
||||
local APitch = bit32.band(getValue("1G06") or 0,0xFF)
|
||||
local AYaw = bit32.rshift(getValue("1G08") or 0,8)
|
||||
|
||||
|
||||
lcd.drawText (0,0, "Plane AR636 AS3X Gains", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL1_DATA+X_DATA_LEN*2
|
||||
local x_data3 = X_COL1_DATA+X_DATA_LEN*3.1
|
||||
|
||||
-- Flight Mode
|
||||
--lcd.drawText (0,y, "F-Mode: "..(nil or "--"), TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (x_data1,y, "Rate", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data2,y, "Head", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data3+X_DATA_SPACE*3,y, "Actual", TEXT_SIZE+BOLD + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RRoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HRoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, ARoll, TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RPitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HPitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, APitch, TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, AYaw, TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local Alpha3Tags = {[0]=
|
||||
"1G00/RA+RE","1G02/RY+HA","1G04R HP+HY","1G06/AR+AP","1G08/AY+?","1G0B","1G0D","6C00","6C02","6C04"}
|
||||
|
||||
local params = {[0]=
|
||||
s1G00,s1G02,s1G04,s1G06,s1G08,s1G0B,s1G0D,s6C00,s6C02,s6C04 }
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#Alpha3Tags do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+220
|
||||
local val = Alpha3Tags[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = params[iParam]
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function openTelemetryRaw(i2cId)
|
||||
--Init telemetry (Spectrun Telemetry Raw STR)
|
||||
multiBuffer( 0, string.byte('S') )
|
||||
multiBuffer( 1, string.byte('T') )
|
||||
multiBuffer( 2, string.byte('R') )
|
||||
multiBuffer( 3, i2cId ) -- Monitor this teemetry data
|
||||
multiBuffer( 4, 0 ) -- Allow to get Data
|
||||
end
|
||||
|
||||
local function closeTelemetryRaw()
|
||||
multiBuffer(0, 0) -- Destroy the STR header
|
||||
multiBuffer(3, 0) -- Not requesting any Telementry ID
|
||||
end
|
||||
|
||||
local lineText = {nil}
|
||||
local I2C_TEXT_GEN = 0x0C
|
||||
|
||||
local function drawTextGen(event)
|
||||
if (multiBuffer(0)~=string.byte('S')) then -- First time run???
|
||||
openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN
|
||||
lineText = {nil}
|
||||
end
|
||||
|
||||
-- Proces TEXT GEN Telementry message
|
||||
if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received
|
||||
local instanceNo = multiBuffer( 5 )
|
||||
local lineNo = multiBuffer( 6 )
|
||||
local line = ""
|
||||
for i=0,13 do
|
||||
line = line .. string.char(multiBuffer( 7 + i ))
|
||||
end
|
||||
|
||||
multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message
|
||||
lineText[lineNo]=line
|
||||
end
|
||||
|
||||
lcd.clear()
|
||||
-- Header
|
||||
if (lineText[0]) then
|
||||
lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS)
|
||||
else
|
||||
lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS)
|
||||
end
|
||||
|
||||
-- Menu lines
|
||||
local y = Y_DATA
|
||||
for i=1,8 do
|
||||
if (lineText[i]) then
|
||||
lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data
|
||||
closeTelemetryRaw()
|
||||
end
|
||||
end
|
||||
|
||||
local telPage = 1
|
||||
local telPageSelected = 0
|
||||
local pageTitle = {[0]="Main", "Blade Version", "Blade Servo Adjust","Blade Gyro Adjust", "Blade Alpha6 Monitor", "Plane AS3X Monitor", "TextGen", "Flight Log"}
|
||||
|
||||
local function drawMainScreen(event)
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (AR636)", TEXT_SIZE + INVERS)
|
||||
|
||||
for iParam=1,#pageTitle do
|
||||
-- highlight selected parameter
|
||||
local attr = (telPage==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam-1)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = pageTitle[iParam]
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
if (telPage>1) then telPage = telPage - 1 end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
if (telPage<#pageTitle) then telPage = telPage + 1 end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
telPageSelected = telPage
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local pageDraw = {[0]=drawMainScreen, drawVersionScreen, servoAdjustScreen,drawPIDScreen, drawAlpha6Monitor, drawAS3XMonitor, drawTextGen, drawFlightLogScreen}
|
||||
|
||||
local function run_func(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
end
|
||||
|
||||
-- draw specific page
|
||||
pageDraw[telPageSelected](event)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if (telPageSelected==0) then return 1 end -- on Main?? Exit Script
|
||||
telPageSelected = 0 -- any page, return to Main
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function init_func()
|
||||
|
||||
if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens
|
||||
TEXT_SIZE = SMLSIZE
|
||||
X_COL1_HEADER = 0
|
||||
X_COL1_DATA = 20
|
||||
|
||||
X_COL2_HEADER = 60
|
||||
X_COL2_DATA = 90
|
||||
|
||||
X_DATA_LEN = 28
|
||||
X_DATA_SPACE = 1
|
||||
|
||||
|
||||
Y_LINE_HEIGHT = 8
|
||||
Y_DATA = Y_HEADER + Y_LINE_HEIGHT
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return { run=run_func, init=init_func }
|
||||
603
Lua_scripts/DSM_SmartRX_Tel.lua
Normal file
@@ -0,0 +1,603 @@
|
||||
local toolName = "TNS|DSM Smart RX Telemetry|TNE"
|
||||
---- ######################################################################### #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Developer: Francisco Arzu
|
||||
|
||||
|
||||
local DEBUG_ON = false
|
||||
--
|
||||
|
||||
local TEXT_SIZE = 0 -- NORMAL
|
||||
local X_COL1_HEADER = 6
|
||||
local X_COL1_DATA = 60
|
||||
local X_COL2_HEADER = 170
|
||||
local X_COL2_DATA = 220
|
||||
local Y_LINE_HEIGHT = 20
|
||||
local Y_HEADER = 0
|
||||
local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2
|
||||
local X_DATA_LEN = 80
|
||||
local X_DATA_SPACE = 5
|
||||
|
||||
|
||||
|
||||
|
||||
local function getPage(iParam)
|
||||
-- get page from 0-based index
|
||||
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
|
||||
local res = (math.floor(iParam/4)==0) and 0 or 1
|
||||
return res
|
||||
end
|
||||
|
||||
local function round(v)
|
||||
-- round float
|
||||
local factor = 100
|
||||
return math.floor(v * factor + 0.5) / factor
|
||||
end
|
||||
|
||||
|
||||
local function readValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
--v = round(v)
|
||||
return v
|
||||
end
|
||||
|
||||
local function readValueById(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return nil end
|
||||
|
||||
local v = getValue(i.id)
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function readBatValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
if (v==nil) then return v end
|
||||
|
||||
return string.format("%2.2f",v)
|
||||
end
|
||||
|
||||
local function readActiveParamValue(sensor)
|
||||
-- read and return a validated active parameter value
|
||||
local v = getValue(sensor)
|
||||
if (v<1 or v>8) then
|
||||
return -1
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function drawFlightLogScreen(event)
|
||||
-- draw labels and params on screen
|
||||
local h = getValue("Hold")
|
||||
local activeParam = h-1 -- H
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS)
|
||||
|
||||
-- read and return parameters
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
local r = getValue("FdeR")
|
||||
local f = getValue("FLss")
|
||||
|
||||
local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"}
|
||||
local values = {[0]=a,b,l,r,f,h}
|
||||
|
||||
local y = Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
for iParam=0,3 do -- A,B,L,R
|
||||
-- highlight selected parameter (rund)
|
||||
local attr = ((activeParam%4)==iParam) and INVERS or 0
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA + X_DATA_LEN
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_LINE_HEIGHT+Y_DATA
|
||||
for iParam=4,5 do -- F, H
|
||||
-- labels
|
||||
local x = X_COL2_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + BOLD)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL2_DATA + X_DATA_LEN
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
local bat = readBatValue("A2") or "--"
|
||||
lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE)
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local function Unsigned_to_SInt16(value)
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function getDegreesValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%0.1f o",vs/10)
|
||||
end
|
||||
|
||||
|
||||
local function getDecHexValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%d (0x%04X)",vs,v)
|
||||
end
|
||||
|
||||
local as3xData = {[0]=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
||||
local function drawAS3XSettings(event, page)
|
||||
local s0500 = getDecHexValue("0500")
|
||||
local s0502 = getDecHexValue("0502")
|
||||
local s0504 = getDecHexValue("0504")
|
||||
local s0506 = getDecHexValue("0506")
|
||||
local s0508 = getDecHexValue("0508")
|
||||
local s050B = getDecHexValue("050B")
|
||||
local s050D = getDecHexValue("050D")
|
||||
|
||||
local d0500 = readValueById("0500") or 0
|
||||
local flags = bit32.rshift(d0500,8)
|
||||
local state = bit32.band(d0500,0xFF)
|
||||
|
||||
local flagsMsg=""
|
||||
-- flags bits: Safe Envelop, ?, Angle Demand, Stab
|
||||
if (bit32.band(flags,0x1)~=0) then flagsMsg=flagsMsg.."AS3X Stab" end
|
||||
-- This one, only one should show
|
||||
if (bit32.band(flags,0x2)~=0) then flagsMsg=flagsMsg..", Angle Demand"
|
||||
elseif (bit32.band(flags,0x8)~=0) then flagsMsg=flagsMsg..", Safe Envelope"
|
||||
elseif (bit32.band(flags,0x4)~=0) then flagsMsg=flagsMsg..", AS3X Heading" end
|
||||
|
||||
local d0502 = readValueById("0502") or 0 -- 0x?F?S
|
||||
local fm = bit32.band(bit32.rshift(d0502,8),0xF) -- 0,1,2
|
||||
|
||||
local axis = bit32.band(d0502,0xF) -- 0=Gains,1=Headings,2=Angle Limits (cointinus iterating to provide all values)
|
||||
|
||||
local d0504 = readValueById("0504") or 0
|
||||
local d0506 = readValueById("0506") or 0
|
||||
local d0508 = readValueById("0508") or 0
|
||||
|
||||
local d0 = bit32.rshift(d0504,8)
|
||||
local d1 = bit32.band(d0504,0xFF)
|
||||
local d2 = bit32.rshift(d0506,8)
|
||||
local d3 = bit32.band(d0506,0xFF)
|
||||
local d4 = bit32.rshift(d0508,8)
|
||||
local d5 = bit32.band(d0508,0xFF)
|
||||
|
||||
--axis: 0=Gains+Headings (RG,PG,YG,RH,PH,YH), 1=Safe Gains (R,P,Y),2=Angle Limits(L,R,U,D)
|
||||
--Constantly changing from 0..2 to represent different data, thats why we have to store the values
|
||||
--in a script/global variable, and not local to the function
|
||||
local s = axis*6
|
||||
as3xData[s+0] = d0
|
||||
as3xData[s+1] = d1
|
||||
as3xData[s+2] = d2
|
||||
as3xData[s+3] = d3
|
||||
as3xData[s+4] = d4
|
||||
as3xData[s+5] = d5
|
||||
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0,0, "AS3X/SAFE Settings", TEXT_SIZE + INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
-- Flight Mode
|
||||
lcd.drawText (X_COL1_HEADER,y, "FM: "..(fm+1), TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN*0.3,y, "Flags: "..flags, TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "State: "..state, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, flagsMsg, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
|
||||
if (page==1) then
|
||||
lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "AS3X Gains", TEXT_SIZE+BOLD)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "AS3X Headings", TEXT_SIZE+BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[0], TEXT_SIZE + RIGHT) -- Roll G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[3], TEXT_SIZE + RIGHT) -- Roll H
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y,as3xData[1], TEXT_SIZE + RIGHT) -- Pitch G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[4], TEXT_SIZE + RIGHT) -- Pitch H
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[2], TEXT_SIZE + RIGHT) -- Yaw G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[5], TEXT_SIZE + RIGHT) -- Yaw H
|
||||
end
|
||||
|
||||
|
||||
if (page==2) then
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL2_HEADER+X_DATA_LEN*1.6
|
||||
|
||||
lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "SAFE Gains", TEXT_SIZE+BOLD)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.1,y, "Angle Limits", TEXT_SIZE+BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, as3xData[6], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Roll R:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[12], TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y,as3xData[7], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Roll L:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y,as3xData[13], TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, as3xData[8], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Pitch U:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[14], TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL2_HEADER,y, "Pitch D:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[15], TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local titles = {[0]=
|
||||
"0500","0502","0504","0506","0508","050B","050D"}
|
||||
|
||||
local values = {[0]=
|
||||
s0500,s0502,s0504,s0506,s0508,s050B,s050D }
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#titles do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+250
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam] or "--"
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function drawAS3XSettingsP1(event)
|
||||
drawAS3XSettings(event, 1)
|
||||
end
|
||||
|
||||
local function drawAS3XSettingsP2(event)
|
||||
drawAS3XSettings(event, 2)
|
||||
end
|
||||
|
||||
|
||||
local function doFloat(v)
|
||||
if v==nil then return 0.0 end
|
||||
|
||||
local vs = string.format("%1.2f",v)
|
||||
|
||||
return vs + 0.0
|
||||
end
|
||||
|
||||
|
||||
local ESC_Title={[0]="","RPM:","Volts:","Motor:","Mot Out:","Throttle:","FET Temp:", "BEC V:", "BEC T:", "BEC A:"}
|
||||
local ESC_uom={[0]="","","V","A","%","%","C", "V","C","A"}
|
||||
local ESC_Status={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local ESC_Min={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local ESC_Max={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
|
||||
local function drawESCStatus(event)
|
||||
lcd.clear()
|
||||
ESC_Status[1] = getValue("Erpm") -- RPM
|
||||
ESC_Status[2] = doFloat(getValue("EVIN")) -- Volts
|
||||
ESC_Status[3] = doFloat(getValue("ECUR")) -- Current
|
||||
ESC_Status[4] = doFloat(getValue("EOUT")) -- % Output
|
||||
ESC_Status[5] = doFloat(getValue("ETHR")) -- Throttle % (EOUT)
|
||||
ESC_Status[6] = getValue("TFET") -- Temp FET
|
||||
|
||||
ESC_Status[7] = doFloat(getValue("VBEC")) -- Volts BEC
|
||||
ESC_Status[8] = getValue("TBEC") -- Temp BEC
|
||||
ESC_Status[9] = doFloat(getValue("CBEC")) -- Current BEC
|
||||
|
||||
for i=1,9 do
|
||||
if (ESC_Status~=nil) then
|
||||
if (ESC_Min[i]==0) then
|
||||
ESC_Min[i]=ESC_Status[i]
|
||||
else
|
||||
ESC_Min[i] = math.min(ESC_Min[i],ESC_Status[i])
|
||||
end
|
||||
|
||||
ESC_Max[i] = math.max(ESC_Max[i],ESC_Status[i])
|
||||
end
|
||||
end
|
||||
|
||||
lcd.drawText (0,0, "ESC", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = 0
|
||||
local x_data = X_COL1_DATA+X_DATA_LEN*1.5
|
||||
local x_data2 = X_COL2_DATA+X_DATA_LEN*0.5
|
||||
local x_data3 = x_data2 + X_DATA_LEN*0.8
|
||||
|
||||
|
||||
lcd.drawText (x_data,y , "Status", TEXT_SIZE+BOLD+RIGHT)
|
||||
lcd.drawText (x_data2,y, "Min", TEXT_SIZE+BOLD+RIGHT)
|
||||
lcd.drawText (x_data3,y, "Max", TEXT_SIZE+BOLD+RIGHT)
|
||||
|
||||
y = Y_DATA
|
||||
for i=1,9 do
|
||||
lcd.drawText (X_COL1_HEADER,y, ESC_Title[i], TEXT_SIZE + BOLD)
|
||||
|
||||
lcd.drawText (x_data,y, ESC_Status[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data + X_DATA_SPACE,y, ESC_uom[i], TEXT_SIZE)
|
||||
|
||||
lcd.drawText (x_data2,y, ESC_Min[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, ESC_Max[i] or "--", TEXT_SIZE + RIGHT)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function drawBATStatus(event)
|
||||
local Title={[0]="","Bat:","Temp:","Rem :","Curr:","Used:","Imbal:","Cycles:", "RX:", "BCpT?:"}
|
||||
local uom={[0]="","V","C","%","mAh","mAh","mV","", "V",""}
|
||||
local Values={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local CellValues={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
|
||||
lcd.clear()
|
||||
|
||||
local ESC_Volts = getValue("EVIN") or 0 -- Volts
|
||||
local ESC_Current = getValue("ECUR") or 0 -- Current
|
||||
|
||||
Values[1] = 0 -- compute later
|
||||
Values[2] = getValue("BTmp") -- Current (C)
|
||||
Values[3] = nil -- Remaining???
|
||||
Values[4] = getValue("BCur") -- Current (mAh)
|
||||
Values[5] = getValue("BUse") -- Current Used (mAh)
|
||||
Values[6] = getValue("CLMa") -- 0.0 (mV) Imbalance
|
||||
Values[7] = getValue("Cycl") -- Cycles
|
||||
Values[8] = readBatValue("A2") -- v
|
||||
Values[9] = getValue("BCpT") -- Current (mAh) ????
|
||||
|
||||
|
||||
--- Total Voltange Calculation
|
||||
local VTotal=0
|
||||
for i=1,10 do
|
||||
CellValues[i] = getValue("Cel"..i)
|
||||
VTotal = VTotal + CellValues[i]
|
||||
end
|
||||
|
||||
if (VTotal==0) then -- No Inteligent Battery,use intelligent ESC if any
|
||||
VTotal = ESC_Volts
|
||||
Values[4] = string.format("%d",ESC_Current * 1000)
|
||||
end
|
||||
|
||||
Values[1] = string.format("%2.2f",VTotal)
|
||||
|
||||
--- SCREEN
|
||||
|
||||
lcd.drawText (X_COL1_HEADER,0, "Battery Stats", TEXT_SIZE+INVERS)
|
||||
|
||||
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data = X_COL1_DATA+X_DATA_LEN+X_DATA_SPACE*3
|
||||
for i=2,9 do
|
||||
lcd.drawText (X_COL1_HEADER, y, Title[i], TEXT_SIZE + BOLD)
|
||||
lcd.drawText (x_data, y, Values[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE, y, uom[i], TEXT_SIZE)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_DATA
|
||||
x_data = X_COL2_DATA+X_DATA_LEN+X_DATA_SPACE*5
|
||||
for i=1,8 do
|
||||
if ((CellValues[i] or 0) > 0) then
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,y, "Cel "..i..":", TEXT_SIZE + BOLD)
|
||||
lcd.drawText (x_data,y, string.format("%2.2f",CellValues[i] or 0), TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE,y, "v", TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,0, Title[1], TEXT_SIZE + INVERS + BOLD)
|
||||
lcd.drawText (x_data,0, string.format("%2.2f",Values[1] or 0), TEXT_SIZE + INVERS+ RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE, 0, uom[1], TEXT_SIZE + INVERS)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function openTelemetryRaw(i2cId)
|
||||
--Init telemetry (Spectrun Telemetry Raw STR)
|
||||
multiBuffer( 0, string.byte('S') )
|
||||
multiBuffer( 1, string.byte('T') )
|
||||
multiBuffer( 2, string.byte('R') )
|
||||
multiBuffer( 3, i2cId ) -- Monitor this teemetry data
|
||||
multiBuffer( 4, 0 ) -- Allow to get Data
|
||||
end
|
||||
|
||||
local function closeTelemetryRaw()
|
||||
multiBuffer(0, 0) -- Destroy the STR header
|
||||
multiBuffer(3, 0) -- Not requesting any Telementry ID
|
||||
end
|
||||
|
||||
local lineText = {nil}
|
||||
local I2C_TEXT_GEN = 0x0C
|
||||
local function drawTextGen(event)
|
||||
if (multiBuffer(0)~=string.byte('S')) then -- First time run???
|
||||
openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN
|
||||
lineText = {nil}
|
||||
end
|
||||
|
||||
-- Proces TEXT GEN Telementry message
|
||||
if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received
|
||||
local instanceNo = multiBuffer( 5 )
|
||||
local lineNo = multiBuffer( 6 )
|
||||
|
||||
local line = ""
|
||||
for i=0,13 do
|
||||
line = line .. string.char(multiBuffer( 7 + i ))
|
||||
end
|
||||
|
||||
multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message
|
||||
lineText[lineNo]=line
|
||||
end
|
||||
|
||||
lcd.clear()
|
||||
-- Header
|
||||
if (lineText[0]) then
|
||||
lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS)
|
||||
else
|
||||
lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS)
|
||||
end
|
||||
|
||||
-- Menu lines
|
||||
local y = Y_DATA
|
||||
for i=1,8 do
|
||||
if (lineText[i]) then
|
||||
lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data
|
||||
closeTelemetryRaw()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local telPage = 1
|
||||
local telPageSelected = 0
|
||||
local pageTitle = {[0]="Main", "AS3X Settings", "SAFE Settings", "ESC Status", "Battery Status","TextGen","Flight Log"}
|
||||
|
||||
local function drawMainScreen(event)
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (Smart RXs)", TEXT_SIZE + INVERS)
|
||||
|
||||
for iParam=1,#pageTitle do
|
||||
-- highlight selected parameter
|
||||
local attr = (telPage==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = pageTitle[iParam]
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
if (telPage>1) then telPage = telPage - 1 end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
if (telPage<#pageTitle) then telPage = telPage + 1 end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
telPageSelected = telPage
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local pageDraw = {[0]=drawMainScreen, drawAS3XSettingsP1, drawAS3XSettingsP2, drawESCStatus, drawBATStatus, drawTextGen, drawFlightLogScreen}
|
||||
|
||||
local function run_func(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
end
|
||||
|
||||
-- draw specific page
|
||||
pageDraw[telPageSelected](event)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if (telPageSelected==0) then return 1 end -- on Main?? Exit Script
|
||||
telPageSelected = 0 -- any page, return to Main
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function init_func()
|
||||
|
||||
if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens
|
||||
TEXT_SIZE = SMLSIZE
|
||||
X_COL1_HEADER = 0
|
||||
X_COL1_DATA = 20
|
||||
|
||||
X_COL2_HEADER = 60
|
||||
X_COL2_DATA = 90
|
||||
|
||||
X_DATA_LEN = 28
|
||||
X_DATA_SPACE = 1
|
||||
|
||||
|
||||
Y_LINE_HEIGHT = 8
|
||||
Y_DATA = Y_HEADER + Y_LINE_HEIGHT
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return { run=run_func, init=init_func }
|
||||
167
Lua_scripts/Graupner HoTT Model Locator.lua
Normal file
@@ -0,0 +1,167 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Telemetry Widget script for FrSky Horus/Radio Master TX16s #
|
||||
---- # Copyright (C) EdgeTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
-- Model Locator by RSSI
|
||||
-- Offer Shmuely (based on code from Scott Bauer 6/21/2015)
|
||||
-- Date: 2021
|
||||
-- ver: 0.1
|
||||
|
||||
-- MHA (based on code from Offer Shmuely)
|
||||
-- Date: 2022
|
||||
-- ver: 0.11
|
||||
-- changes: made version for Graupner HoTT. Uses real Rssi data scaled -15db to -115db to 100..0
|
||||
|
||||
-- This widget help to find a lost/crashed model based on the RSSI (if still available)
|
||||
-- The widget produce audio representation (variometer style) of the RSSI from the lost model
|
||||
-- The widget also display the RSSI in a visible colorized bar (0-100%)
|
||||
|
||||
-- There are two way to use it
|
||||
-- 1. The simple way:
|
||||
-- walk toward the quad/plane that crashed,
|
||||
-- as you get closer to your model the beeps will become more frequent with higher pitch (and a visual bar graph as well)
|
||||
-- until you get close enough to find it visually
|
||||
|
||||
-- 2. the more accurate way:
|
||||
-- turn the antenna straight away (i.e. to point from you, straight away)
|
||||
-- try to find the weakest signal! (not the highest), i.e. the lowest RSSI you can find, this is the direction to the model.
|
||||
-- now walk to the side (not toward the model), find again the weakest signal, this is also the direction to your model
|
||||
-- triangulate the two lines, and it will be :-)
|
||||
|
||||
local delayMillis = 100
|
||||
local nextPlayTime = getTime()
|
||||
local img = Bitmap.open("/SCRIPTS/TOOLS/Model Locator (by RSSI).png")
|
||||
|
||||
--------------------------------------------------------------
|
||||
local function log(s)
|
||||
--return;
|
||||
print("locator: " .. s)
|
||||
end
|
||||
--------------------------------------------------------------
|
||||
|
||||
|
||||
-- init_func is called once when model is loaded
|
||||
local function init()
|
||||
return 0
|
||||
end
|
||||
|
||||
-- bg_func is called periodically when screen is not visible
|
||||
local function bg()
|
||||
return 0
|
||||
end
|
||||
|
||||
-- This function returns green at gvalue, red at rvalue and graduate in between
|
||||
local function getRangeColor(value, red_value, green_value)
|
||||
local range = math.abs(green_value - red_value)
|
||||
if range == 0 then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
if value == nil then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
|
||||
if green_value > red_value then
|
||||
if value > green_value then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
if value < red_value then
|
||||
return lcd.RGB(0xdf, 0, 0)
|
||||
end
|
||||
g = math.floor(0xdf * (value - red_value) / range)
|
||||
r = 0xdf - g
|
||||
return lcd.RGB(r, g, 0)
|
||||
else
|
||||
if value > green_value then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
if value < red_value then
|
||||
return lcd.RGB(0xdf, 0, 0)
|
||||
end
|
||||
r = math.floor(0xdf * (value - green_value) / range)
|
||||
g = 0xdf - r
|
||||
return lcd.RGB(r, g, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local function main(event)
|
||||
|
||||
lcd.clear()
|
||||
|
||||
-- fetch uplink rssi (HoTT sensor Rssi)
|
||||
local rssi = getValue("Rssi")
|
||||
|
||||
-- calculate a percentage for the color bar (range -115db to -15db)
|
||||
local rssiP = rssi
|
||||
|
||||
if(rssi ~= 0) then -- rssi < 0 -> telemtry data received
|
||||
if(rssi >= -15) then -- -15db to -1db => 100%
|
||||
rssiP = 100
|
||||
else
|
||||
if(rssi >= -115) then -- between -115db and -15db => 0% to 100%
|
||||
rssiP = 100+rssi+15
|
||||
else
|
||||
rssiP = 0 -- less than -115 => 0%
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
lcd.drawBitmap(img, 250, 50, 40)
|
||||
|
||||
-- Title
|
||||
lcd.drawText(3, 3, "Graupner HoTT Rssi Model Locator", 0)
|
||||
myColor = getRangeColor(rssi, 0, 100)
|
||||
lcd.setColor(CUSTOM_COLOR, myColor)
|
||||
|
||||
-- draw current value
|
||||
local dx = 0
|
||||
if rssi < -99 then
|
||||
dx = -33
|
||||
end
|
||||
|
||||
if rssi == 0 then
|
||||
lcd.drawText(115, 73, "no telemetry", DBLSIZE + CUSTOM_COLOR)
|
||||
else
|
||||
lcd.drawNumber(180+dx, 30, rssi, XXLSIZE + CUSTOM_COLOR)
|
||||
lcd.drawText(275, 73, "db", 0 + CUSTOM_COLOR)
|
||||
end
|
||||
|
||||
-- draw main bar
|
||||
lcd.setColor(CUSTOM_COLOR, YELLOW) -- RED / YELLOW
|
||||
local xMin = 0
|
||||
local yMin = 270
|
||||
local xMax = 480
|
||||
local yMax = 200
|
||||
local h = 0
|
||||
local rssiAsX = (rssiP * xMax) / 100
|
||||
|
||||
for xx = xMin, rssiAsX, 20 do
|
||||
lcd.setColor(CUSTOM_COLOR, getRangeColor(xx, xMin, xMax - 40))
|
||||
h = h + 10
|
||||
lcd.drawFilledRectangle(xx, yMin - h, 15, h, CUSTOM_COLOR)
|
||||
end
|
||||
|
||||
-- beep
|
||||
if getTime() >= nextPlayTime then
|
||||
playFile("/SCRIPTS/TOOLS/Model Locator (by RSSI).wav")
|
||||
nextPlayTime = getTime() + delayMillis - rssiP
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
return {init = init,run = main,background = bg}
|
||||
|
||||
171
Lua_scripts/Graupner HoTT.lua
Normal file
@@ -0,0 +1,171 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for HoTT description
|
||||
-- To start operation:
|
||||
-- Write "HoTT" at address 0..3
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write 0x0F at address 5
|
||||
-- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters
|
||||
-- by 8 lines
|
||||
-- Write at address 5 sends an order to the RX: 0xXF=start, 0xX7=prev page,
|
||||
-- 0xXE=next page, 0xX9=enter, 0xXD=next or 0xXB=prev with X being the sensor
|
||||
-- to request data from 8=RX only, 9=Vario, A=GPS, B=Cust, C=ESC, D=GAM, E=EAM
|
||||
-- Write at address 4 the value 0xFF will request the buffer to be cleared
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
HoTT_Sensor = 0
|
||||
Timer_128 = 100
|
||||
|
||||
local function HoTT_Release()
|
||||
multiBuffer( 0, 0 )
|
||||
end
|
||||
|
||||
local function HoTT_Send(button)
|
||||
multiBuffer( 5, 0x80+(HoTT_Sensor*16) + button)
|
||||
end
|
||||
|
||||
local function HoTT_Sensor_Inc()
|
||||
local detected_sensors=multiBuffer( 4 )
|
||||
local a
|
||||
if detected_sensors ~= 0xFF then
|
||||
repeat
|
||||
HoTT_Sensor=(HoTT_Sensor+1)%7 -- Switch to next sensor
|
||||
if HoTT_Sensor ~= 0 then
|
||||
a = math.floor(detected_sensors/ (2^(HoTT_Sensor-1))) -- shift right
|
||||
end
|
||||
until HoTT_Sensor==0 or a % 2 == 1
|
||||
HoTT_Send( 0x0F )
|
||||
end
|
||||
end
|
||||
|
||||
local function HoTT_Draw_LCD()
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local result
|
||||
local offset=0
|
||||
|
||||
local sensor_name = { "", "+Vario", "+GPS", "+Cust", "+ESC", "+GAM", "+EAM" }
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Graupner HoTT: config RX" .. sensor_name[HoTT_Sensor+1] .. " - Menu cycle Sensors", MENU_TITLE_COLOR)
|
||||
--Draw RX Menu
|
||||
if multiBuffer( 4 ) == 0xFF then
|
||||
lcd.drawText(10,50,"No HoTT telemetry...", BLINK)
|
||||
else
|
||||
for line = 0, 7, 1 do
|
||||
for i = 0, 21-1, 1 do
|
||||
value=multiBuffer( line*21+6+i )
|
||||
if value > 0x80 then
|
||||
value = value - 0x80
|
||||
lcd.drawText(10+i*16,32+20*line,string.char(value).." ",INVERS)
|
||||
else
|
||||
lcd.drawText(10+i*16,32+20*line,string.char(value))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
--Draw RX Menu on LCD_W=128
|
||||
if multiBuffer( 4 ) == 0xFF then
|
||||
lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE)
|
||||
else
|
||||
if Timer_128 ~= 0 then
|
||||
--Intro page
|
||||
Timer_128 = Timer_128 - 1
|
||||
lcd.drawScreenTitle("Graupner Hott",0,0)
|
||||
lcd.drawText(2,17,"Configuration of RX" .. sensor_name[HoTT_Sensor+1] ,SMLSIZE)
|
||||
lcd.drawText(2,37,"Press menu to cycle Sensors" ,SMLSIZE)
|
||||
else
|
||||
--Menu page
|
||||
for line = 0, 7, 1 do
|
||||
for i = 0, 21-1, 1 do
|
||||
value=multiBuffer( line*21+6+i )
|
||||
if value > 0x80 then
|
||||
value = value - 0x80
|
||||
lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS)
|
||||
else
|
||||
lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function HoTT_Init()
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('H') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('H') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('T') )
|
||||
multiBuffer( 3, string.byte('T') )
|
||||
--Request init of the RX buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
--Request RX to send the config menu
|
||||
HoTT_Send( 0x0F )
|
||||
HoTT_Sensor = 0;
|
||||
HoTT_Detected_Sensors=0;
|
||||
Timer_128 = 100
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function HoTT_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
HoTT_Release()
|
||||
return 2
|
||||
else
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event)
|
||||
HoTT_Send( 0x07 )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
HoTT_Send( 0x09 )
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
HoTT_Send( 0x0B )
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
HoTT_Send( 0x0D )
|
||||
elseif event == EVT_VIRTUAL_NEXT_PAGE then
|
||||
HoTT_Send( 0x0E )
|
||||
elseif event == EVT_VIRTUAL_MENU then
|
||||
Timer_128 = 100
|
||||
HoTT_Sensor_Inc()
|
||||
else
|
||||
HoTT_Send( 0x0F )
|
||||
end
|
||||
HoTT_Draw_LCD()
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=HoTT_Init, run=HoTT_Run }
|
||||
209
Lua_scripts/MultiChan.txt
Normal file
@@ -0,0 +1,209 @@
|
||||
24,0,Assan,Std,0,CH5,CH6,CH7,CH8
|
||||
14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
|
||||
14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
|
||||
14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
|
||||
14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
14,5,Bayang,QX100,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
59,1,BayangRX,CPPM,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
|
||||
34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
|
||||
13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
|
||||
37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
|
||||
37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
|
||||
37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
|
||||
12,0,CX10,Green,1,Flip,Rate
|
||||
12,1,CX10,Blue,1,Flip,Rate,Pict,Video
|
||||
12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
|
||||
12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
|
||||
12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
|
||||
12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
|
||||
7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
|
||||
7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
|
||||
7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
7,3,Devo,6CH,0,CH5,CH6
|
||||
7,4,Devo,7CH,0,CH5,CH6,CH7
|
||||
33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
|
||||
6,0,DSM,2_1F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,1,DSM,2_2F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,2,DSM,X_1F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,3,DSM,X_2F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,5,DSM,R_1F,0,AUX3,AUX4,AUX5
|
||||
70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
70,1,DSM_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
|
||||
45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
|
||||
16,0,ESKY,Std,0,Gyro,Pitch
|
||||
16,1,ESKY,ET4,0,Gyro,Pitch
|
||||
35,0,ESKY150,4CH,0
|
||||
35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
|
||||
69,0,ESKY150V2,Std,0,CH5_RA,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
1,0,Flysky,Flysky,0,CH5,CH6,CH7,CH8
|
||||
1,1,Flysky,V9x9,1,Flip,Light,Pict,Video
|
||||
1,2,Flysky,V6x6,1,Flip,Light,Pict,Video,HLess,RTH,XCAL,YCAL
|
||||
1,3,Flysky,V912,1,BtmBtn,TopBtn
|
||||
1,4,Flysky,CX20,0,CH5,CH6,CH7
|
||||
28,0,Flysky_AFHDS2A,PWM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,6,Flysky_AFHDS2A,PWM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,7,Flysky_AFHDS2A,PPM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
56,1,Flysky2A_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
53,0,Height,5ch,0,Gear
|
||||
53,1,Height,8ch,0,Gear,Gyro,Flap,Light
|
||||
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
|
||||
3,0,FrSkyD,D8,0,CH5,CH6,CH7,CH8
|
||||
3,0,FrSkyD,D8Cloned,0,CH5,CH6,CH7,CH8
|
||||
67,0,FrSkyL,LR12,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
67,1,FrSkyL,LR12_6CH,0,CH5,CH6
|
||||
15,0,FrSkyX,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
15,1,FrSkyX,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
|
||||
15,2,FrSkyX,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
15,3,FrSkyX,D16_8CH_LBT,0,CH5,CH6,CH7,CH8
|
||||
15,4,FrSkyX,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
15,5,FrSkyX,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,0,FrSkyX2,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,1,FrSkyX2,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
|
||||
64,2,FrSkyX2,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,3,FrSkyX2,D16_8CH_LBT,1,CH5,CH6,CH7,CH8
|
||||
64,4,FrSkyX2,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,5,FrSkyX2,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
|
||||
65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
|
||||
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
55,1,FrSkyRX,CloneTX,0
|
||||
55,2,FrSkyRX,EraseTX,0
|
||||
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
58,0,FX,816,1
|
||||
58,1,FX,620,1
|
||||
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
||||
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
|
||||
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
|
||||
47,0,GD00x,V1,1,Trim,LED,Rate
|
||||
47,1,GD00x,V2,1,Trim,LED,Rate
|
||||
32,0,GW008,FY326,1,Flip
|
||||
36,0,H8_3D,Std,1,Flip,Light,Pict,Video,RTH,FlMode,Cal1
|
||||
36,1,H8_3D,H20H,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
36,2,H8_3D,H20,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
36,3,H8_3D,H30,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
4,0,Hisky,Std,0,Gear,Pitch,Gyro,CH8
|
||||
4,1,Hisky,HK310,0,Aux
|
||||
39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
|
||||
39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
|
||||
39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
|
||||
26,0,Hontai,Std,1,Flip,LED,Pict,Video,HLess,RTH,Calib
|
||||
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
|
||||
2,1,Hubsan,H301,0,RTH,Light,Stab,Video
|
||||
2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
|
||||
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
71,0,JJRC345,JJRC345,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
49,0,KF606,KF606,1,Trim
|
||||
49,1,KF606,MIG320,1,Trim,LED
|
||||
49,2,KF606,ZCZ50,1,Trim,UNK
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
18,0,MJXQ,WHL08,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,3,MJXQ,H26D,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess
|
||||
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess
|
||||
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
|
||||
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
|
||||
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
|
||||
17,5,MT99XX,A180,0,3D_6G
|
||||
17,6,MT99XX,Dragon,0,Mode,RTH
|
||||
17,7,MT99XX,F949G,0,6G_3D,Light
|
||||
44,0,NCC1701,Std,1,Warp
|
||||
77,0,OMP,M2,0,THold,IdleUp,6G_3D
|
||||
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
||||
60,1,Pelikan,LITE_V4,0,CH5,CH6,CH7,CH8
|
||||
60,2,Pelikan,SCX24,0
|
||||
51,0,Potensic,A20,1,TakLan,Emerg,Mode,HLess
|
||||
66,0,Propel,74-Z,1,LEDs,RollCW,RolCCW,Fire,Weapon,Calib,AltHol,TakeOf,Land,Train
|
||||
29,0,Q2x2,Q222,1,Flip,LED,Mod2,Mod1,HLess,RTH,XCal,YCal
|
||||
29,1,Q2x2,Q242,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
|
||||
29,2,Q2x2,Q282,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
|
||||
31,0,Q303,Q303,1,AltHol,Flip,Pict,Video,HLess,RTH,Gimbal
|
||||
31,1,Q303,C35,1,Arm,VTX,Pict,Video,n-a,RTH,Gimbal
|
||||
31,2,Q303,CX10D,1,Arm,Flip
|
||||
31,3,Q303,CX10WD,1,Arm,Flip
|
||||
72,0,Q90C,Std,0,FMode,VTX+
|
||||
74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
74,2,RadioLink,DumboRC,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,UNK
|
||||
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
21,0,Futaba,SFHSS,0,CH5,CH6,CH7,CH8
|
||||
19,0,Shenqi,Cycle,1
|
||||
68,0,Skyartec,Std,0,CH5,CH6,CH7
|
||||
11,0,SLT,V1,0,Gear,Pitch
|
||||
11,1,SLT,V2,0,CH5,CH6,CH7,CH8
|
||||
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
|
||||
11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib
|
||||
11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict
|
||||
10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
|
||||
10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess
|
||||
61,0,Tiger,Std,1,Flip,Light
|
||||
43,0,Traxxas,6519,0
|
||||
5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY
|
||||
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
|
||||
48,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
48,2,V761,TOPRC,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
46,0,V911s,V911s,1,Calib,Rate
|
||||
46,1,V911s,E119,1,Calib,Rate,6G_3D
|
||||
22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
|
||||
30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
|
||||
30,1,WK2x01,WK2401,0
|
||||
30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
|
||||
30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
|
||||
30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
|
||||
30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
|
||||
62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
|
||||
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
|
||||
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
|
||||
8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess
|
||||
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
|
||||
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
|
||||
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
|
||||
52,0,ZSX,280,1,Light
|
||||
78,0,M-Link,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
79,0,WFLY2,RF20x,0,CH5,CH6,CH7,CH8,CH9,CH10
|
||||
80,0,E016Hv2,E016Hv2,1,TakLan,EmStop,Flip,Calib,HLess,RTH
|
||||
81,0,E010r5,E010r5,1,Flip,LED,CALIB,HLess,RTH,GLIDE
|
||||
82,0,LOLI,Std,0,CH5,CH6,CH7,CH8,1SwSePpPw,2SwSePw,3SwSe,4SwSe,5SwSeSb,6SwSe,7SwSePw,8SwSe
|
||||
83,0,E129,E129,1,TakLan,EmStop,TrimA,TrimE,TrimR
|
||||
83,1,E129,C186,1,TakLan,EmStop,TrimA,TrimE,TrimR
|
||||
84,0,JOYSWAY,Std,0
|
||||
85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH
|
||||
87,0,IKEA
|
||||
89,0,LOSI
|
||||
90,0,MouldKg,Analog,0
|
||||
90,1,MouldKg,Digit,0
|
||||
91,0,Xerall,Tank,0,FlTa,TakLan,Rate,HLess,Photo,Video,TrimR,TrimE,TrimA
|
||||
92,0,MT99xx2,PA18,0,MODE,FLIP,RTH
|
||||
93,0,Kyosho2,KT-17,0
|
||||
327
Lua_scripts/MultiChannelsUpdater.lua
Normal file
@@ -0,0 +1,327 @@
|
||||
|
||||
local toolName = "TNS|Multi chan namer|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local protocol_name = ""
|
||||
local sub_protocol_name = ""
|
||||
local bind_ch = 0
|
||||
local module_conf = {}
|
||||
local module_pos = "Internal"
|
||||
local file_ok = 0
|
||||
local done = 0
|
||||
local protocol = 0
|
||||
local sub_protocol = 0
|
||||
local f_seek = 0
|
||||
local channel_names={}
|
||||
local num_search = "Searching"
|
||||
|
||||
local function drawScreenTitle(title)
|
||||
if LCD_W == 480 then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawScreenTitle(title, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Multi_Draw_LCD(event)
|
||||
local line = 0
|
||||
|
||||
lcd.clear()
|
||||
drawScreenTitle("Multi channels namer")
|
||||
|
||||
--Display settings
|
||||
local lcd_opt = 0
|
||||
if LCD_W == 480 then
|
||||
x_pos = 10
|
||||
y_pos = 32
|
||||
y_inc = 20
|
||||
else
|
||||
x_pos = 0
|
||||
y_pos = 9
|
||||
y_inc = 8
|
||||
lcd_opt = SMLSIZE
|
||||
end
|
||||
|
||||
--Multi Module detection
|
||||
if module_conf["Type"] ~= 6 then
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,50,"No Multi module configured...", BLINK)
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(2,17,"No Multi module configured...",SMLSIZE)
|
||||
end
|
||||
return
|
||||
else
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,module_pos .. " Multi detected.", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
--Channel order
|
||||
if (ch_order == -1) then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Channels order can't be read from Multi...", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
--Can't open file MultiChan.txt
|
||||
if file_ok == 0 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Can't read MultiChan.txt file...", lcd_opt)
|
||||
return
|
||||
end
|
||||
|
||||
if ( protocol_name == "" or sub_protocol_name == "" ) and f_seek ~=-1 then
|
||||
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
|
||||
if f == nil then return end
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,num_search, lcd_opt)
|
||||
num_search = num_search .. "."
|
||||
if #num_search > 15 then
|
||||
num_search = string.sub(num_search,1,9)
|
||||
end
|
||||
local proto = 0
|
||||
local sub_proto = 0
|
||||
local proto_name = ""
|
||||
local sub_proto_name = ""
|
||||
local channels = ""
|
||||
local nbr_try = 0
|
||||
local nbr_car = 0
|
||||
repeat
|
||||
io.seek(f, f_seek)
|
||||
local data = io.read(f, 100) -- read 100 characters
|
||||
if #data ==0 then
|
||||
f_seek = -1 -- end of file
|
||||
break
|
||||
end
|
||||
proto, sub_proto, proto_name, sub_proto_name, bind_ch, channels = string.match(data,'(%d+),(%d),([%w-_ ]+),([%w-_ ]+),(%d)(.+)')
|
||||
if proto ~= nil and sub_proto ~= nil and protocol_name ~= nil and sub_protocol_name ~= nil and bind_ch ~= nil then
|
||||
if tonumber(proto) == protocol and tonumber(sub_proto) == sub_protocol then
|
||||
protocol_name = proto_name
|
||||
sub_protocol_name = sub_proto_name
|
||||
bind_ch = tonumber(bind_ch)
|
||||
if channels ~= nil then
|
||||
--extract channel names
|
||||
nbr_car = string.find(channels, "\r")
|
||||
if nbr_car == nil then nbr_car = string.find(channels, "\n") end
|
||||
if nbr_car ~= nil then
|
||||
channels = string.sub(channels,1,nbr_car-1)
|
||||
end
|
||||
local i = 5
|
||||
for k in string.gmatch(channels, ",([%w-_ ]+)") do
|
||||
channel_names[i] = k
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
f_seek = -1 -- protocol found
|
||||
break
|
||||
end
|
||||
end
|
||||
if f_seek ~= -1 then
|
||||
nbr_car = string.find(data, "\n")
|
||||
if nbr_car == nil then nbr_car = string.find(data, "\r") end
|
||||
if nbr_car == nil then
|
||||
f_seek = -1 -- end of file
|
||||
break
|
||||
end
|
||||
f_seek = f_seek + nbr_car -- seek to next line
|
||||
nbr_try = nbr_try + 1
|
||||
end
|
||||
until nbr_try > 20 or f_seek == -1
|
||||
io.close(f)
|
||||
end
|
||||
|
||||
if f_seek ~= -1 then
|
||||
return -- continue searching...
|
||||
end
|
||||
|
||||
--Protocol & Sub_protocol
|
||||
if protocol_name == "" or sub_protocol_name == "" then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Unknown protocol "..tostring(protocol).."/"..tostring(sub_protocol).." ...", lcd_opt)
|
||||
return
|
||||
elseif LCD_W > 128 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name .. " / SubProtocol: " .. sub_protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
else
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"SubProtocol: " .. sub_protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
text1=""
|
||||
text2=""
|
||||
for i,v in ipairs(channel_names) do
|
||||
if i<=8 then
|
||||
if i==1 then
|
||||
text1 = v
|
||||
else
|
||||
text1=text1 .. "," .. v
|
||||
end
|
||||
else
|
||||
if i==9 then
|
||||
text2 = v
|
||||
else
|
||||
text2=text2 .. "," .. v
|
||||
end
|
||||
end
|
||||
end
|
||||
if LCD_W > 128 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Channels: " .. text1, lcd_opt)
|
||||
line = line + 1
|
||||
if text2 ~= "" then
|
||||
lcd.drawText(x_pos*9, y_pos+y_inc*line,text2, lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
end
|
||||
|
||||
if event ~= EVT_VIRTUAL_ENTER and done == 0 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"<ENT> Save", lcd_opt + INVERS + BLINK)
|
||||
return
|
||||
end
|
||||
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Setting channel names.", lcd_opt)
|
||||
line = line + 1
|
||||
local output, nbr
|
||||
if done == 0 then
|
||||
for i,v in ipairs(channel_names) do
|
||||
output = model.getOutput(i-1)
|
||||
output["name"] = v
|
||||
model.setOutput(i-1,output)
|
||||
nbr = i
|
||||
end
|
||||
for i = nbr, 15 do
|
||||
output = model.getOutput(i)
|
||||
output["name"] = "n-a"
|
||||
model.setOutput(i,output)
|
||||
end
|
||||
if bind_ch == 1 then
|
||||
output = model.getOutput(15)
|
||||
output["name"] = "BindCH"
|
||||
model.setOutput(15,output)
|
||||
end
|
||||
done = 1
|
||||
end
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Done!", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Multi_Init()
|
||||
module_conf = model.getModule(0)
|
||||
if module_conf["Type"] ~= 6 then
|
||||
module_pos = "External"
|
||||
module_conf = model.getModule(1)
|
||||
if module_conf["Type"] ~= 6 then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
protocol = module_conf["protocol"]
|
||||
sub_protocol = module_conf["subProtocol"]
|
||||
|
||||
--Exceptions on first 4 channels...
|
||||
local stick_names = { "Rud", "Ele", "Thr", "Ail" }
|
||||
if ( protocol == 4 and sub_protocol == 1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
|
||||
stick_names[2] = "n-a"
|
||||
stick_names[4] = "n-a"
|
||||
elseif protocol == 43 then -- Traxxas
|
||||
stick_names[2] = "Aux4"
|
||||
stick_names[4] = "Aux3"
|
||||
elseif ( protocol == 48 and sub_protocol == 0 ) then -- V761 3CH
|
||||
stick_names[4] = "n-a"
|
||||
elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816
|
||||
stick_names[1] = "n-a"
|
||||
stick_names[2] = "n-a"
|
||||
end
|
||||
|
||||
--Determine fist 4 channels order
|
||||
local ch_order=module_conf["channelsOrder"]
|
||||
if (ch_order == -1) then
|
||||
channel_names[1] = stick_names[defaultChannel(0)+1]
|
||||
channel_names[2] = stick_names[defaultChannel(1)+1]
|
||||
channel_names[3] = stick_names[defaultChannel(2)+1]
|
||||
channel_names[4] = stick_names[defaultChannel(3)+1]
|
||||
else
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[4]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[2]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[3]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[1]
|
||||
end
|
||||
|
||||
--Exceptions on first 4 channels...
|
||||
if ( protocol == 73 or (protocol == 74 and sub_protocol == 0) or (protocol == 60 and sub_protocol == 2) or protocol == 89) then -- Kyosho or RadioLink Surface or Pelikan/SCX24 or Losi
|
||||
channel_names[1] = "ST"
|
||||
channel_names[2] = "THR"
|
||||
channel_names[3] = "CH3"
|
||||
if(protocol == 60 and sub_protocol == 2) then
|
||||
channel_names[4] = "n-a"
|
||||
else
|
||||
channel_names[4] = "CH4"
|
||||
end
|
||||
end
|
||||
if ( protocol == 6 and sub_protocol == 5 ) then -- DSMR
|
||||
channel_names[1] = "ST"
|
||||
channel_names[2] = "THR"
|
||||
channel_names[3] = "AUX1"
|
||||
channel_names[4] = "AUX2"
|
||||
end
|
||||
if ( protocol == 90 ) then -- Mould King
|
||||
channel_names[1] = "A"
|
||||
channel_names[2] = "B"
|
||||
channel_names[3] = "C"
|
||||
channel_names[4] = "D"
|
||||
end
|
||||
|
||||
--Check MultiChan.txt
|
||||
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
|
||||
if f == nil then return end
|
||||
file_ok = 1
|
||||
io.close(f)
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Multi_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
else
|
||||
Multi_Draw_LCD(event)
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
return 2
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
return { init=Multi_Init, run=Multi_Run }
|
||||
529
Lua_scripts/MultiConfig.lua
Normal file
@@ -0,0 +1,529 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for Config description
|
||||
-- To start operation:
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write "Conf" at address 0..3
|
||||
-- Read
|
||||
-- Read at address 12 gives the current config page
|
||||
-- Read at address 13..172 gives the current data of the page = 8 lines * 20 caracters
|
||||
-- Write
|
||||
-- Write at address 5..11 the command
|
||||
-- Write 0x01 at address 4 will send the command to the module
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
local Version = "v0.2"
|
||||
local Focus = -1
|
||||
local Page = 0
|
||||
local Edit = -1
|
||||
local Edit_pos = 1
|
||||
local Menu = { {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""} }
|
||||
local Menu_value = {}
|
||||
local Blink = 0
|
||||
local ModuleNumber = 0
|
||||
local ModuleType = ""
|
||||
local Module = {}
|
||||
local InitialProtocol = 0
|
||||
local InitialSubProtocol = 0
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Config_Send(page, line, value)
|
||||
local i
|
||||
i = (page*16) + line
|
||||
multiBuffer( 5, i )
|
||||
for i = 1 , 6 , 1 do
|
||||
multiBuffer( 5+i, value[i] )
|
||||
end
|
||||
multiBuffer( 4, 1 )
|
||||
end
|
||||
|
||||
local function Config_Release()
|
||||
--Set the protocol back to what it was
|
||||
Module.protocol = InitialProtocol
|
||||
Module.subProtocol = InitialSubProtocol
|
||||
model.setModule(ModuleNumber, Module)
|
||||
|
||||
--Stop requesting updates
|
||||
local i
|
||||
for i = 3 , 0 , -1 do
|
||||
multiBuffer( i, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Page( )
|
||||
Config_Send(Page, 0, { 0, 0, 0, 0, 0, 0 })
|
||||
end
|
||||
|
||||
local function Config_Draw_Edit( event )
|
||||
local i
|
||||
local text
|
||||
|
||||
if Menu[Focus].field_type == 0xD0 then
|
||||
-- Editable Hex value
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 1
|
||||
Blink = 0
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
Menu_value[i] = Menu[Focus].field_value[i]
|
||||
end
|
||||
end
|
||||
if Edit == 0 then
|
||||
-- Not editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
if Edit_pos > Menu[Focus].field_len then
|
||||
-- Save or Cancel
|
||||
Edit = -1
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
-- Save
|
||||
Config_Send(Page, Focus, Menu_value)
|
||||
end
|
||||
return
|
||||
else
|
||||
-- Switch to edit mode
|
||||
Edit = 1
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < Menu[Focus].field_len + 2 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
else
|
||||
-- Editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- End edit
|
||||
Edit = 0
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1
|
||||
end
|
||||
--Blink
|
||||
Blink = Blink + 1
|
||||
if Blink > 30 then
|
||||
Blink = 0
|
||||
end
|
||||
end
|
||||
--Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
if i==Edit_pos and (Edit ~= 1 or Blink > 15) then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170+12*2*(i-1), 110, string.format('%02X', Menu_value[i]), attrib)
|
||||
else
|
||||
lcd.drawText(17+6*2*(i-1), 10, string.format('%02X', Menu_value[i]), attrib + SMLSIZE)
|
||||
end
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Save", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Save", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "Cancel", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "Cancel", attrib + SMLSIZE)
|
||||
end
|
||||
|
||||
elseif Menu[Focus].field_type == 0x90 then
|
||||
-- Action text
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 2
|
||||
end
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- Exit
|
||||
Edit = -1
|
||||
if Edit_pos == 1 then
|
||||
-- Yes
|
||||
Config_Send(Page, Focus, { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA } )
|
||||
end
|
||||
return
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Switch to Yes
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < 2 then
|
||||
-- Switch to No
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
-- Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 110, Menu[Focus].field_text .. "?")
|
||||
else
|
||||
lcd.drawText(17, 10, Menu[Focus].field_text .. "?", SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Yes", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Yes", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "No", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "No", attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Next_Prev( event )
|
||||
-- Next Prev on main menu
|
||||
local line
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
for line = Focus - 1, 1, -1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
for line = Focus + 1, 7, 1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Draw_Menu()
|
||||
-- Main menu
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local length
|
||||
local text
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Multi Config " .. Version, MENU_TITLE_COLOR)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(10,50,"No Config telemetry...", BLINK)
|
||||
end
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(1, 0, "Multi Config " .. Version, SMLSIZE)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(2,17,"No Config telemetry...",SMLSIZE)
|
||||
end
|
||||
end
|
||||
|
||||
if multiBuffer(13) ~= 0x00 then
|
||||
if LCD_W == 480 then
|
||||
--Draw firmware version and channels order
|
||||
local ch_order = multiBuffer(17)
|
||||
local channel_names = {}
|
||||
channel_names[bitand(ch_order,3)+1] = "A"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "E"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "T"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "R"
|
||||
lcd.drawText(150, 5, ModuleType.." v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4], MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawText(76, 0, "/Fw" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16),SMLSIZE) -- .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4])
|
||||
end
|
||||
|
||||
--Draw Menu
|
||||
for line = 1, 7, 1 do
|
||||
--Clear line info
|
||||
Menu[line].text = ""
|
||||
Menu[line].field_type = 0
|
||||
Menu[line].field_len = 0
|
||||
for i = 1, 7, 1 do
|
||||
Menu[line].field_value[i] = 0
|
||||
end
|
||||
Menu[line].field_text = ""
|
||||
length = 0
|
||||
--Read line from buffer
|
||||
for i = 0, 20-1, 1 do
|
||||
value=multiBuffer( line*20+13+i )
|
||||
if value == 0 then
|
||||
break -- end of line
|
||||
end
|
||||
if value > 0x80 and Menu[line].field_type == 0 then
|
||||
-- Read field type
|
||||
Menu[line].field_type = bitand(value, 0xF0)
|
||||
Menu[line].field_len = bitand(value, 0x0F)
|
||||
length = Menu[line].field_len
|
||||
if Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 and Focus == -1 then
|
||||
-- First actionnable field if nothing was selected
|
||||
Focus = line;
|
||||
end
|
||||
else
|
||||
if Menu[line].field_type == 0 then
|
||||
-- Text
|
||||
Menu[line].text = Menu[line].text .. string.char(value)
|
||||
else
|
||||
-- Menu specific fields
|
||||
length = length - 1
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
Menu[line].field_text = Menu[line].field_text .. string.char(value)
|
||||
else
|
||||
Menu[line].field_value[Menu[line].field_len-length] = value
|
||||
end
|
||||
if length == 0 then
|
||||
-- End of fields
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Display menu text
|
||||
if Menu[line].text ~= "" then
|
||||
if Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 or Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
Menu[line].text = Menu[line].text .. ":"
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,32+20*line,Menu[line].text )
|
||||
else
|
||||
lcd.drawText(2,1+8*line,Menu[line].text,SMLSIZE)
|
||||
end
|
||||
end
|
||||
-- Display specific fields
|
||||
if line == Focus then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
-- Text
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, Menu[line].field_text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, Menu[line].field_text, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 then
|
||||
-- Decimal value
|
||||
value = 0
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
value = value*256 + value
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, value, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, value, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
-- Hex value
|
||||
text=""
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
text = text .. string.format('%02X ', Menu[line].field_value[i])
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, text, SMLSIZE + attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Config_Init()
|
||||
--Find Multi module
|
||||
Module_int = model.getModule(0)
|
||||
Module_ext = model.getModule(1)
|
||||
if Module_int["Type"] ~= 6 and Module_ext["Type"] ~= 6 then
|
||||
error("No Multi module detected...")
|
||||
return 2
|
||||
end
|
||||
if Module_int["Type"] == 6 and Module_ext["Type"] == 6 then
|
||||
error("Two Multi modules detected, turn on only the one to be configured.")
|
||||
return 2
|
||||
end
|
||||
if Module_int["Type"] == 6 then
|
||||
ModuleNumber = 0
|
||||
ModuleType = "Internal"
|
||||
else
|
||||
ModuleNumber = 1
|
||||
ModuleType = "External"
|
||||
end
|
||||
--Get Module settings and set it to config protocol
|
||||
Module = model.getModule(ModuleNumber)
|
||||
InitialProtocol = Module.protocol
|
||||
InitialSubProtocol = Module.subProtocol
|
||||
Module.protocol = 86
|
||||
Module.subProtocol = 0
|
||||
model.setModule(ModuleNumber, Module)
|
||||
--pause while waiting for the module to switch to config
|
||||
for i = 0, 10, 1 do end
|
||||
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('C') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('C') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
|
||||
--Request init of the buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
multiBuffer(13, 0x00 )
|
||||
|
||||
--Continue buffer init
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('n') )
|
||||
multiBuffer( 3, string.byte('f') )
|
||||
|
||||
-- Test set
|
||||
-- multiBuffer( 12, 0 )
|
||||
-- multiBuffer( 13, 1 )
|
||||
-- multiBuffer( 14, 3 )
|
||||
-- multiBuffer( 15, 2 )
|
||||
-- multiBuffer( 16, 62 )
|
||||
-- multiBuffer( 17, 0 + 1*4 + 2*16 + 3*64)
|
||||
|
||||
-- multiBuffer( 33, string.byte('G') )
|
||||
-- multiBuffer( 34, string.byte('l') )
|
||||
-- multiBuffer( 35, string.byte('o') )
|
||||
-- multiBuffer( 36, string.byte('b') )
|
||||
-- multiBuffer( 37, string.byte('a') )
|
||||
-- multiBuffer( 38, string.byte('l') )
|
||||
-- multiBuffer( 39, string.byte(' ') )
|
||||
-- multiBuffer( 40, string.byte('I') )
|
||||
-- multiBuffer( 41, string.byte('D') )
|
||||
-- multiBuffer( 42, 0xD0 + 4 )
|
||||
-- multiBuffer( 43, 0x12 )
|
||||
-- multiBuffer( 44, 0x34 )
|
||||
-- multiBuffer( 45, 0x56 )
|
||||
-- multiBuffer( 46, 0x78 )
|
||||
-- multiBuffer( 47, 0x9A )
|
||||
-- multiBuffer( 48, 0xBC )
|
||||
|
||||
-- multiBuffer( 53, 0x90 + 9 )
|
||||
-- multiBuffer( 54, string.byte('R') )
|
||||
-- multiBuffer( 55, string.byte('e') )
|
||||
-- multiBuffer( 56, string.byte('s') )
|
||||
-- multiBuffer( 57, string.byte('e') )
|
||||
-- multiBuffer( 58, string.byte('t') )
|
||||
-- multiBuffer( 59, string.byte(' ') )
|
||||
-- multiBuffer( 60, string.byte('G') )
|
||||
-- multiBuffer( 61, string.byte('I') )
|
||||
-- multiBuffer( 62, string.byte('D') )
|
||||
-- multiBuffer( 63, 0x00 )
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Config_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
Config_Release()
|
||||
return 2
|
||||
else
|
||||
Config_Draw_Menu()
|
||||
if ( event == EVT_VIRTUAL_PREV_PAGE or event == EVT_VIRTUAL_NEXT_PAGE ) and Edit < 1 then
|
||||
-- Not editing, ok to change page
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event)
|
||||
if Page > 0 then
|
||||
--Page = Page - 1
|
||||
--Config_Page()
|
||||
end
|
||||
else
|
||||
--Page = Page + 1
|
||||
--Config_Page()
|
||||
end
|
||||
end
|
||||
if Focus > 0 then
|
||||
-- At least one line has an action
|
||||
if Edit >= 0 then
|
||||
-- Currently editing
|
||||
Config_Draw_Edit( event )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
-- Switch to edit
|
||||
Config_Draw_Edit( 0 )
|
||||
elseif event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_NEXT then
|
||||
-- Main menu selection
|
||||
Config_Next_Prev( event )
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=Config_Init, run=Config_Run }
|
||||
221
Lua_scripts/MultiLOLI.lua
Normal file
@@ -0,0 +1,221 @@
|
||||
|
||||
local toolName = "TNS|Multi LOLI RX config|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local loli_nok = false
|
||||
local channels={ { 768, "PWM", 100, 102, "PPM", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH1
|
||||
{ 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH2
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH3
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH4
|
||||
{ 102, "SBUS", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH5
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH6
|
||||
{ 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH7
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 } } -- CH8
|
||||
|
||||
local sel = 1
|
||||
local edit = false
|
||||
|
||||
local blink = 0
|
||||
local BLINK_SPEED = 15
|
||||
|
||||
local function drawScreenTitle(title)
|
||||
if LCD_W == 480 then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawScreenTitle(title, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local function LOLI_Draw_LCD(event)
|
||||
local line = 0
|
||||
|
||||
lcd.clear()
|
||||
|
||||
--Display settings
|
||||
local lcd_opt = 0
|
||||
if LCD_W == 480 then
|
||||
drawScreenTitle("Multi - LOLI RX configuration tool")
|
||||
x_pos = 152
|
||||
x_inc = 90
|
||||
y_pos = 40
|
||||
y_inc = 20
|
||||
else
|
||||
x_pos = 5
|
||||
x_inc = 30
|
||||
y_pos = 1
|
||||
y_inc = 8
|
||||
lcd_opt = SMLSIZE
|
||||
end
|
||||
|
||||
--Multi Module detection
|
||||
if loli_nok then
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,50,"The LOLI protocol is not selected...", lcd_opt)
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(2,17,"LOLI protocol not selected...",SMLSIZE)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
--Display current config
|
||||
if LCD_W == 480 then
|
||||
line = line + 1
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line -2, "Channel", lcd_opt)
|
||||
lcd.drawText(x_pos+x_inc, y_pos+y_inc*line -2, "Function", lcd_opt)
|
||||
lcd.drawRectangle(x_pos-4, y_pos+y_inc*line -4 , 2*x_inc +2, 188)
|
||||
lcd.drawLine(x_pos-4, y_pos+y_inc*line +18, x_pos-4 +2*x_inc +1, y_pos+y_inc*line +18, SOLID, 0)
|
||||
lcd.drawLine(x_pos+x_inc -5, y_pos+y_inc*line -4, x_pos+x_inc -5, y_pos+y_inc*line -5 +188, SOLID, 0)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
local out
|
||||
for i = 1, 8 do
|
||||
out = getValue("ch"..(i+8))
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line, "CH"..i, lcd_opt)
|
||||
for j = 1, #channels[i], 3 do
|
||||
if out > channels[i][j] then
|
||||
if sel == i then
|
||||
invert = INVERS
|
||||
if edit == true then
|
||||
blink = blink + 1
|
||||
if blink > BLINK_SPEED then
|
||||
invert = 0
|
||||
if blink > BLINK_SPEED * 2 then
|
||||
blink = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
invert = 0
|
||||
end
|
||||
lcd.drawText(x_pos+x_inc, y_pos+y_inc*line, channels[i][j+1], lcd_opt + invert)
|
||||
break
|
||||
end
|
||||
end
|
||||
line = line + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function LOLI_Change_Value(dir)
|
||||
local pos = 0
|
||||
local out
|
||||
--look for the current position
|
||||
out = getValue("ch"..(sel+8))
|
||||
for j = 1, #channels[sel], 3 do
|
||||
if out > channels[sel][j] then
|
||||
pos = j
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
--decrement or increment
|
||||
if dir < 0 and pos > 1 then
|
||||
pos = pos - 3
|
||||
elseif dir > 0 and pos + 3 < #channels[sel] then
|
||||
pos = pos + 3
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
--delete all mixers for the selected channel
|
||||
local num_mix = model.getMixesCount(sel-1 +8)
|
||||
for i = 1, num_mix do
|
||||
model.deleteMix(sel-1 +8, 0);
|
||||
end
|
||||
|
||||
--create new mixer
|
||||
local source_max = getFieldInfo("cyc1")
|
||||
|
||||
local val = { name = channels[sel][pos+1],
|
||||
source = source_max.id - 1, -- MAX=100 on TX16S
|
||||
weight = channels[sel][pos+2],
|
||||
offset = 0,
|
||||
switch = 0,
|
||||
multiplex = 0,
|
||||
curveType = 0,
|
||||
curveValue = 0,
|
||||
flightModes = 0,
|
||||
carryTrim = false,
|
||||
mixWarn = 0,
|
||||
delayUp = 0,
|
||||
delayDown = 0,
|
||||
speedUp = 0,
|
||||
speedDown = 0 }
|
||||
model.insertMix(sel-1 +8, 0, val)
|
||||
end
|
||||
|
||||
local function LOLI_Menu(event)
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
if edit == false then
|
||||
-- not changing a value
|
||||
if sel < 8 then
|
||||
sel = sel + 1
|
||||
end
|
||||
else
|
||||
-- need to inc the value
|
||||
LOLI_Change_Value(1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
if edit == false then
|
||||
-- not changing a value
|
||||
if sel > 1 then
|
||||
sel = sel - 1
|
||||
end
|
||||
else
|
||||
-- need to dec the value
|
||||
LOLI_Change_Value(-1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
if edit == false then
|
||||
edit = true
|
||||
blink = BLINK_SPEED
|
||||
else
|
||||
edit = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function LOLI_Init()
|
||||
local module_conf = model.getModule(0)
|
||||
if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then
|
||||
module_conf = model.getModule(1)
|
||||
if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then
|
||||
loli_nok = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function LOLI_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
return 2
|
||||
else
|
||||
LOLI_Menu(event)
|
||||
LOLI_Draw_LCD(event)
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=LOLI_Init, run=LOLI_Run }
|
||||
75
Lua_scripts/README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Multiprotocol TX Module OpenTX LUA scripts
|
||||
<img align="right" width=300 src="../docs/images/multi.png" />
|
||||
|
||||
If you like this project and want to support further development please consider making a [donation](../docs/Donations.md).
|
||||
|
||||
<table cellspacing=0>
|
||||
<tr>
|
||||
<td align=center width=200><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol¤cy_code=EUR&amount=5&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"><img src="../docs/images/donate_button.png" border="0" name="submit" title="PayPal - Donate €5" alt="Donate €5"/></a><br><b>€5</b></td>
|
||||
<td align=center width=200><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol¤cy_code=EUR&amount=10&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"><img src="../docs/images/donate_button.png" border="0" name="submit" title="PayPal - Donate €10" alt="Donate €10"/></a><br><b>€10</b></td>
|
||||
<td align=center width=200><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol¤cy_code=EUR&amount=15&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"><img src="../docs/images/donate_button.png" border="0" name="submit" title="PayPal - Donate €15" alt="Donate €10"/></a><br><b>€15</b></td>
|
||||
<td align=center width=200><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol¤cy_code=EUR&amount=25&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"><img src="../docs/images/donate_button.png" border="0" name="submit" title="PayPal - Donate €25" alt="Donate €25"/></a><br><b>€25</b></td>
|
||||
<td align=center width=200><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"><img src="../docs/images/donate_button.png" border="0" name="submit" title="PayPal - Donate" alt="Donate"/></a><br><b>Other</b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## MultiConfig
|
||||
|
||||
Enables to modify on a Multi module the Global ID, Cyrf ID or format the EEPROM.
|
||||
|
||||
Matching the ID of 2 Multi modules enable them to control the same receivers without rebinding. Be carefull the 2 modules should not be used at the same time unless you know what you are doing.
|
||||
|
||||
Notes:
|
||||
- Supported from Multi v1.3.2.85 or above and OpenTX 2.3.12 or above
|
||||
- The Multi module to be configured must be active, if there is a second Multi module in the radio it must be off
|
||||
- Located on the radio SD card under \SCRIPTS\TOOLS
|
||||
|
||||
[](https://www.youtube.com/watch?v=lGyCV2kpqHU)
|
||||
|
||||
## MultiChannelsUpdater
|
||||
|
||||
Automatically name the channels based on the loaded Multi protocol and sub protocol including the module channel order convention.
|
||||
|
||||
Need OpenTX 2.3.9 or above. Located on the radio SD card under \SCRIPTS\TOOLS. This script needs MultiChan.txt to be present in the same folder.
|
||||
|
||||
[](https://www.youtube.com/watch?v=L58ayXuewyA)
|
||||
|
||||
## MultiLOLI
|
||||
|
||||
Script to set the channels function (switch, servo, pwm, ppm, sbus) on a [LOLI RX](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md#loli---82)
|
||||
|
||||
[](https://www.youtube.com/watch?v=e698pQxfv-A)
|
||||
|
||||
## Graupner HoTT
|
||||
|
||||
Enable text configuration of the HoTT RX and sensors: Vario, GPS, ESC, GAM and EAM.
|
||||
|
||||
Need OpenTX 2.3.9 or above. Located on the radio SD card under \SCRIPTS\TOOLS.
|
||||
|
||||
Notes:
|
||||
- Menu/MDL/Model is used to cycle through the detected sensors.
|
||||
- It's normal to lose the telemetry feed while using the text mode configuration. Telemetry will resume properly if the script is exited by doing a short press on the exit button.
|
||||
|
||||
[](https://www.youtube.com/watch?v=81wd8NlF3Qw)
|
||||
|
||||
## Graupner HoTT Model Locator
|
||||
|
||||
This is the Graupner HoTT adapted version of the Model Locator script using RSSI.
|
||||
|
||||
The OpenTX sensor "RSSI" is populated by the individual OpenTX telemetry protocol implementations and returns a value from 0..100 (percent) originating from the early FrSky implementation. It turns out that FrSky did not really provide a genuine signal strength indicator in units of dbm but a link quality indicator in 0..100%. With Graupner HoTT the link quality indicator is not a good basis for the model locator as it is very non-linear and doesn't change much with distance. Using the Graupner HoTT telemetry sensor "Rssi" which is a true signal strength indicator serves the purpose of locating a model much better as it varies much more with distance.
|
||||
|
||||
## DSM Forward Programming
|
||||
|
||||
This is a work in progress. It's available for color(+touch) and B&W screens.
|
||||
|
||||
Work on OpenTX and EdgeTX. Located on the radio SD card under \SCRIPTS\TOOLS, make sure to copy the DSMLIB folder along with DSM FwdPrg_05_Color.lua or DSM FwdPrg_05_BW.lua.
|
||||
|
||||
[](https://www.youtube.com/watch?v=sjIaDw5j9nE)
|
||||
|
||||
If some text appears as Unknown_xxx, please report xxx and what the exact text display should be.
|
||||
|
||||
## DSM PID Flight log gain parameters for Blade micros
|
||||
|
||||
Lua telemetry script from [feathering on RCGroups](https://www.rcgroups.com/forums/showpost.php?p=46033341&postcount=20728) to facilitate setting the Gain Parameters on the Blade 150S FBL. It doesn't use Forward Programming but instead it just reads telemetry data from the Multi-module and displays it on a telemetry display.
|
||||
|
||||
It is very similar to the Telemetry Based Text Generator functionality on Spektrum transmitters where one doesn't need to rely on the angle of the swashplate to determine selection/value.
|
||||
127
Lua_scripts/pidDsm.lua
Normal file
@@ -0,0 +1,127 @@
|
||||
--
|
||||
-- This telemetry script displays the Flight Log Gain
|
||||
-- Parameters streamed from the Blade 150S Spektrum AR6335A
|
||||
-- Flybarless Controller.
|
||||
|
||||
-- The script facilitates the setting of the FBL's
|
||||
-- Gain Parameters including PID for both
|
||||
-- cyclic and tail. It is similar to the Telemetry Based
|
||||
-- Text Generator available on Spektrum transmitters.
|
||||
|
||||
-- Supporting similar Blade micros such as the Fusion 180
|
||||
-- would possibly require minor modifications to this script.
|
||||
|
||||
-- This script reads telemetry data from the Spektrum
|
||||
-- receiver and thus functionality relies on data being
|
||||
-- captured by the OpenTX transmitter. A DSM
|
||||
-- telemetry-ready module is required. Please see the
|
||||
-- MULTI-Module project at https://www.multi-module.org/.
|
||||
|
||||
-- The only supported display is the Taranis'. It may work
|
||||
-- with higher res screens.
|
||||
--
|
||||
|
||||
|
||||
-- Sensor names
|
||||
local PSensor = "FdeA"
|
||||
local ISensor = "FdeB"
|
||||
local DSensor = "FdeL"
|
||||
local RSensor = "FdeR"
|
||||
local ActiveParamSensor = "Hold"
|
||||
|
||||
local tags = {"P", "I", "D"}
|
||||
|
||||
|
||||
local function getPage(iParam)
|
||||
-- get page from 0-based index
|
||||
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
|
||||
local res = (math.floor(iParam/4)==0) and 1 or 2
|
||||
return res
|
||||
end
|
||||
|
||||
function round(v)
|
||||
-- round float
|
||||
local factor = 100
|
||||
return math.floor(v * factor + 0.5) / factor
|
||||
end
|
||||
|
||||
|
||||
local function readValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
v = round(v)
|
||||
return v
|
||||
end
|
||||
|
||||
local function readActiveParamValue(sensor)
|
||||
-- read and return a validated active parameter value
|
||||
local v = getValue(sensor)
|
||||
if (v<1 or v>8) then
|
||||
return nil
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
local function readParameters()
|
||||
-- read and return parameters
|
||||
local p = readValue(PSensor)
|
||||
local i = readValue(ISensor)
|
||||
local d = readValue(DSensor)
|
||||
local r = readValue(RSensor)
|
||||
local a = readActiveParamValue(ActiveParamSensor)
|
||||
return {p,i,d,r,a}
|
||||
end
|
||||
|
||||
local function drawParameters()
|
||||
-- draw labels and params on screen
|
||||
local params = readParameters()
|
||||
local activeParam = params[5]
|
||||
|
||||
-- if active gain does not validate then assume
|
||||
-- Gain Adjustment Mode is disabled
|
||||
if not activeParam then
|
||||
lcd.clear()
|
||||
lcd.drawText(20,30,"Please enter Gain Adjustment Mode")
|
||||
return
|
||||
end
|
||||
|
||||
local activePage = getPage(activeParam-1)
|
||||
for iParam=0,7 do
|
||||
-- highlight selected parameter
|
||||
local attr = (activeParam==iParam+1) and 2 or 0
|
||||
-- circular index (per page)
|
||||
local perPageIndx = iParam % 4 + 1
|
||||
-- check if displaying cyclic params.
|
||||
local isCyclicPage = (getPage(iParam)==1)
|
||||
-- set y draw coord
|
||||
local y = perPageIndx*10+2
|
||||
|
||||
-- labels
|
||||
local x = isCyclicPage and 6 or 120
|
||||
-- labels are P,I,D for both pages except for last param
|
||||
local val = iParam==3 and "Response" or
|
||||
(iParam==7 and "Filtering" or tags[perPageIndx])
|
||||
lcd.drawText (x, y, val, attr)
|
||||
|
||||
-- gains
|
||||
-- set all params for non-active page to '--' rather than 'last value'
|
||||
val = (getPage(iParam)==activePage) and params[perPageIndx] or '--'
|
||||
x = isCyclicPage and 70 or 180
|
||||
lcd.drawText (x, y, val, attr)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function run_func(event)
|
||||
-- TODO: calling clear() on every function call redrawing all labels is not ideal
|
||||
lcd.clear()
|
||||
lcd.drawText (8, 2, "Cyclic (0...200)")
|
||||
lcd.drawText (114, 2, "Tail (0...200)")
|
||||
drawParameters()
|
||||
end
|
||||
|
||||
local function init_func() end
|
||||
local function bg_func() end
|
||||
|
||||
|
||||
return { run=run_func, background=bg_func, init=init_func }
|
||||
@@ -12,108 +12,85 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//-------------------------------
|
||||
//-------------------------------
|
||||
//A7105 SPI routines
|
||||
//-------------------------------
|
||||
//-------------------------------
|
||||
/********************/
|
||||
/** A7105 routines **/
|
||||
/********************/
|
||||
#ifdef A7105_INSTALLED
|
||||
#include "iface_a7105.h"
|
||||
|
||||
void A7105_WriteData(uint8_t len, uint8_t channel)
|
||||
{
|
||||
uint8_t i;
|
||||
CS_off;
|
||||
A7105_Write(A7105_RST_WRPTR);
|
||||
A7105_Write(0x05);
|
||||
A7105_CSN_off;
|
||||
SPI_Write(A7105_RST_WRPTR);
|
||||
SPI_Write(A7105_05_FIFO_DATA);
|
||||
for (i = 0; i < len; i++)
|
||||
A7105_Write(packet[i]);
|
||||
CS_on;
|
||||
A7105_WriteReg(0x0F, channel);
|
||||
A7105_Strobe(A7105_TX);
|
||||
SPI_Write(packet[i]);
|
||||
A7105_CSN_on;
|
||||
if(protocol!=PROTO_WFLY2)
|
||||
{
|
||||
if(!(protocol==PROTO_FLYSKY || (protocol==PROTO_KYOSHO && sub_protocol==KYOSHO_HYPE)))
|
||||
{
|
||||
A7105_Strobe(A7105_STANDBY); //Force standby mode, ie cancel any TX or RX...
|
||||
A7105_SetTxRxMode(TX_EN); //Switch to PA
|
||||
}
|
||||
A7105_WriteReg(A7105_0F_PLL_I, channel);
|
||||
A7105_Strobe(A7105_TX);
|
||||
}
|
||||
}
|
||||
|
||||
void A7105_ReadData() {
|
||||
void A7105_ReadData(uint8_t len)
|
||||
{
|
||||
uint8_t i;
|
||||
A7105_Strobe(0xF0); //A7105_RST_RDPTR
|
||||
CS_off;
|
||||
A7105_Write(0x45);
|
||||
for (i=0;i<16;i++)
|
||||
packet[i]=A7105_Read();
|
||||
CS_on;
|
||||
A7105_Strobe(A7105_RST_RDPTR);
|
||||
A7105_CSN_off;
|
||||
SPI_Write(0x40 | A7105_05_FIFO_DATA); //bit 6 =1 for reading
|
||||
for (i=0;i<len;i++)
|
||||
packet[i]=SPI_SDI_Read();
|
||||
A7105_CSN_on;
|
||||
}
|
||||
|
||||
void A7105_WriteReg(uint8_t address, uint8_t data) {
|
||||
CS_off;
|
||||
A7105_Write(address);
|
||||
A7105_CSN_off;
|
||||
SPI_Write(address);
|
||||
NOP();
|
||||
A7105_Write(data);
|
||||
CS_on;
|
||||
SPI_Write(data);
|
||||
A7105_CSN_on;
|
||||
}
|
||||
|
||||
uint8_t A7105_ReadReg(uint8_t address) {
|
||||
uint8_t A7105_ReadReg(uint8_t address)
|
||||
{
|
||||
uint8_t result;
|
||||
CS_off;
|
||||
A7105_Write(address |=0x40); //bit 6 =1 for reading
|
||||
result = A7105_Read();
|
||||
CS_on;
|
||||
A7105_CSN_off;
|
||||
SPI_Write(address |=0x40); //bit 6 =1 for reading
|
||||
result = SPI_SDI_Read();
|
||||
A7105_CSN_on;
|
||||
return(result);
|
||||
}
|
||||
|
||||
void A7105_Write(uint8_t command) {
|
||||
uint8_t n=8;
|
||||
|
||||
SCK_off;//SCK start low
|
||||
SDI_off;
|
||||
while(n--) {
|
||||
if(command&0x80)
|
||||
SDI_on;
|
||||
else
|
||||
SDI_off;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
command = command << 1;
|
||||
}
|
||||
SDI_on;
|
||||
}
|
||||
|
||||
uint8_t A7105_Read(void) {
|
||||
uint8_t result=0;
|
||||
uint8_t i;
|
||||
|
||||
SDI_SET_INPUT;
|
||||
for(i=0;i<8;i++) {
|
||||
if(SDI_1) ///if SDIO =1
|
||||
result=(result<<1)|0x01;
|
||||
else
|
||||
result=result<<1;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
NOP();
|
||||
}
|
||||
SDI_SET_OUTPUT;
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------
|
||||
void A7105_SetTxRxMode(uint8_t mode)
|
||||
{
|
||||
if(mode == TX_EN) {
|
||||
if(mode == TX_EN)
|
||||
{
|
||||
A7105_WriteReg(A7105_0B_GPIO1_PIN1, 0x33);
|
||||
A7105_WriteReg(A7105_0C_GPIO2_PIN_II, 0x31);
|
||||
} else if (mode == RX_EN) {
|
||||
A7105_WriteReg(A7105_0B_GPIO1_PIN1, 0x31);
|
||||
A7105_WriteReg(A7105_0C_GPIO2_PIN_II, 0x33);
|
||||
} else {
|
||||
//The A7105 seems to some with a cross-wired power-amp (A7700)
|
||||
//On the XL7105-D03, TX_EN -> RXSW and RX_EN -> TXSW
|
||||
//This means that sleep mode is wired as RX_EN = 1 and TX_EN = 1
|
||||
//If there are other amps in use, we'll need to fix this
|
||||
A7105_WriteReg(A7105_0B_GPIO1_PIN1, 0x33);
|
||||
A7105_WriteReg(A7105_0C_GPIO2_PIN_II, 0x33);
|
||||
}
|
||||
else
|
||||
if (mode == RX_EN)
|
||||
{
|
||||
A7105_WriteReg(A7105_0B_GPIO1_PIN1, 0x31);
|
||||
A7105_WriteReg(A7105_0C_GPIO2_PIN_II, 0x33);
|
||||
}
|
||||
else
|
||||
{
|
||||
//The A7105 seems to some with a cross-wired power-amp (A7700)
|
||||
//On the XL7105-D03, TX_EN -> RXSW and RX_EN -> TXSW
|
||||
//This means that sleep mode is wired as RX_EN = 1 and TX_EN = 1
|
||||
//If there are other amps in use, we'll need to fix this
|
||||
A7105_WriteReg(A7105_0B_GPIO1_PIN1, 0x33);
|
||||
A7105_WriteReg(A7105_0C_GPIO2_PIN_II, 0x33);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------
|
||||
@@ -121,23 +98,23 @@ uint8_t A7105_Reset()
|
||||
{
|
||||
uint8_t result;
|
||||
|
||||
delay(10); //wait 10ms for A7105 wakeup
|
||||
A7105_WriteReg(0x00, 0x00);
|
||||
delay(1000);
|
||||
A7105_SetTxRxMode(TXRX_OFF); //Set both GPIO as output and low
|
||||
result=A7105_ReadReg(0x10) == 0x9E; //check if is reset.
|
||||
A7105_WriteReg(A7105_00_MODE, 0x00);
|
||||
delayMilliseconds(1);
|
||||
A7105_SetTxRxMode(TXRX_OFF); //Set both GPIO as output and low
|
||||
result=A7105_ReadReg(A7105_10_PLL_II) == 0x9E; //check if is reset.
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
return result;
|
||||
}
|
||||
|
||||
void A7105_WriteID(uint32_t ida) {
|
||||
CS_off;
|
||||
A7105_Write(0x06);//ex id=0x5475c52a ;txid3txid2txid1txid0
|
||||
A7105_Write((ida>>24)&0xff);//53
|
||||
A7105_Write((ida>>16)&0xff);//75
|
||||
A7105_Write((ida>>8)&0xff);//c5
|
||||
A7105_Write((ida>>0)&0xff);//2a
|
||||
CS_on;
|
||||
void A7105_WriteID(uint32_t ida)
|
||||
{
|
||||
A7105_CSN_off;
|
||||
SPI_Write(A7105_06_ID_DATA); //ex id=0x5475c52a ;txid3txid2txid1txid0
|
||||
SPI_Write((ida>>24)&0xff); //54
|
||||
SPI_Write((ida>>16)&0xff); //75
|
||||
SPI_Write((ida>>8)&0xff); //c5
|
||||
SPI_Write((ida>>0)&0xff); //2a
|
||||
A7105_CSN_on;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -171,85 +148,382 @@ static void A7105_SetPower_Value(int power)
|
||||
void A7105_SetPower()
|
||||
{
|
||||
uint8_t power=A7105_BIND_POWER;
|
||||
if(IS_BIND_DONE_on)
|
||||
power=IS_POWER_FLAG_on?A7105_HIGH_POWER:A7105_LOW_POWER;
|
||||
if(IS_BIND_DONE)
|
||||
#ifdef A7105_ENABLE_LOW_POWER
|
||||
power=IS_POWER_FLAG_on?A7105_HIGH_POWER:A7105_LOW_POWER;
|
||||
#else
|
||||
power=A7105_HIGH_POWER;
|
||||
#endif
|
||||
if(IS_RANGE_FLAG_on)
|
||||
power=A7105_RANGE_POWER;
|
||||
A7105_WriteReg(0x28, power);
|
||||
if(prev_power != power)
|
||||
{
|
||||
A7105_WriteReg(A7105_28_TX_TEST, power);
|
||||
prev_power=power;
|
||||
}
|
||||
}
|
||||
|
||||
void A7105_Strobe(uint8_t address) {
|
||||
CS_off;
|
||||
A7105_Write(address);
|
||||
CS_on;
|
||||
A7105_CSN_off;
|
||||
SPI_Write(address);
|
||||
A7105_CSN_on;
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM HUBSAN_A7105_regs[] = {
|
||||
0xFF, 0x63, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x04, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0x62, 0x80, 0xFF, 0xFF, 0x0A, 0xFF, 0xFF, 0x07,
|
||||
0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF
|
||||
};
|
||||
const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x14, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50,
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f,
|
||||
0x13, 0xc3, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00,
|
||||
0x01, 0x0f, 0xff
|
||||
};
|
||||
#define ID_NORMAL 0x55201041
|
||||
#define ID_PLUS 0xAA201041
|
||||
void A7105_Init(uint8_t protocol)
|
||||
// Fine tune A7105 LO base frequency
|
||||
// this is required for some A7105 modules and/or RXs with inaccurate crystal oscillator
|
||||
void A7105_AdjustLOBaseFreq(uint8_t cmd)
|
||||
{
|
||||
void *A7105_Regs;
|
||||
|
||||
if(protocol==INIT_FLYSKY)
|
||||
static int16_t old_offset=2048;
|
||||
int16_t offset=1024;
|
||||
if(cmd==0)
|
||||
{ // Called at init of the A7105
|
||||
old_offset=2048;
|
||||
switch(protocol)
|
||||
{
|
||||
case PROTO_HUBSAN:
|
||||
#ifdef FORCE_HUBSAN_TUNING
|
||||
offset=(int16_t)FORCE_HUBSAN_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_BUGS:
|
||||
#ifdef FORCE_BUGS_TUNING
|
||||
offset=(int16_t)FORCE_BUGS_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_FLYSKY:
|
||||
#ifdef FORCE_FLYSKY_TUNING
|
||||
offset=(int16_t)FORCE_FLYSKY_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_HEIGHT:
|
||||
#ifdef FORCE_HEIGHT_TUNING
|
||||
offset=(int16_t)FORCE_HEIGHT_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_PELIKAN:
|
||||
#ifdef FORCE_PELIKAN_TUNING
|
||||
offset=(int16_t)FORCE_PELIKAN_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_KYOSHO:
|
||||
#ifdef FORCE_KYOSHO_TUNING
|
||||
offset=(int16_t)FORCE_KYOSHO_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_JOYSWAY:
|
||||
#ifdef FORCE_JOYSWAY_TUNING
|
||||
offset=(int16_t)FORCE_JOYSWAY_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_WFLY2:
|
||||
#ifdef FORCE_WFLY2_TUNING
|
||||
offset=(int16_t)FORCE_WFLY2_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_AFHDS2A:
|
||||
case PROTO_AFHDS2A_RX:
|
||||
#ifdef FORCE_AFHDS2A_TUNING
|
||||
offset=(int16_t)FORCE_AFHDS2A_TUNING;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(offset==1024) // Use channel 15 as an input
|
||||
offset=convert_channel_16b_nolimit(CH15,-300,300,false);
|
||||
|
||||
if(old_offset==offset) // offset is the same as before...
|
||||
return;
|
||||
old_offset=offset;
|
||||
|
||||
// LO base frequency = 32e6*(bip+(bfp/(2^16)))
|
||||
uint8_t bip; // LO base frequency integer part
|
||||
uint16_t bfp; // LO base frequency fractional part
|
||||
offset++; // as per datasheet, not sure why recommended, but that's a +1kHz drift only ...
|
||||
offset<<=1;
|
||||
if(offset < 0)
|
||||
{
|
||||
A7105_WriteID(0x5475c52A);//0x2Ac57554
|
||||
A7105_Regs=(void *)FLYSKY_A7105_regs;
|
||||
bip = 0x4a; // 2368 MHz
|
||||
bfp = 0xffff + offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
A7105_WriteID(ID_NORMAL);
|
||||
A7105_Regs=(void *)HUBSAN_A7105_regs;
|
||||
bip = 0x4b; // 2400 MHz (default)
|
||||
bfp = offset;
|
||||
}
|
||||
for (uint8_t i = 0; i < 0x33; i++){
|
||||
if( pgm_read_byte_near((uint16_t)(A7105_Regs)+i) != 0xFF)
|
||||
A7105_WriteReg(i, pgm_read_byte_near((uint16_t)(A7105_Regs)+i));
|
||||
A7105_WriteReg( A7105_11_PLL_III, bip);
|
||||
A7105_WriteReg( A7105_12_PLL_IV, (bfp >> 8) & 0xff);
|
||||
A7105_WriteReg( A7105_13_PLL_V, bfp & 0xff);
|
||||
//debugln("Channel: %d, offset: %d, bip: %2x, bfp: %4x", Channel_data[14], offset, bip, bfp);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) A7105_SetVCOBand(uint8_t vb1, uint8_t vb2)
|
||||
{ // Set calibration band value to best match
|
||||
uint8_t diff1, diff2;
|
||||
|
||||
if (vb1 >= 4)
|
||||
diff1 = vb1 - 4;
|
||||
else
|
||||
diff1 = 4 - vb1;
|
||||
|
||||
if (vb2 >= 4)
|
||||
diff2 = vb2 - 4;
|
||||
else
|
||||
diff2 = 4 - vb2;
|
||||
|
||||
if (diff1 == diff2 || diff1 > diff2)
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I, vb1 | 0x08);
|
||||
else
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I, vb2 | 0x08);
|
||||
}
|
||||
|
||||
#if defined(AFHDS2A_A7105_INO) || defined(AFHDS2A_RX_A7105_INO)
|
||||
const uint8_t PROGMEM AFHDS2A_A7105_regs[] = {
|
||||
0xFF, 0x42 | (1<<5), 0x00, 0x25, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3c, 0x05, 0x00, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x4f, 0x62, 0x80, 0xFF, 0xFF, 0x2a, 0x32, 0xc3, 0x1f, // 10 - 1f
|
||||
0x1e, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef BUGS_A7105_INO
|
||||
const uint8_t PROGMEM BUGS_A7105_regs[] = {
|
||||
0xFF, 0x42, 0x00, 0x15, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0x01, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x40, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, // 10 - 1f
|
||||
0x16, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3b, 0x00, 0x0b, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef FLYSKY_A7105_INO
|
||||
const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x14, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, // 10 - 1f
|
||||
0x13, 0xc3, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef HEIGHT_A7105_INO
|
||||
const uint8_t PROGMEM HEIGHT_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x07, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x01, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x1f, // 10 - 1f
|
||||
0x12, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3a, 0x00, 0x3f, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef HUBSAN_A7105_INO
|
||||
const uint8_t PROGMEM HUBSAN_A7105_regs[] = {
|
||||
0xFF, 0x63, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x04, 0xFF, // 00 - 0f
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0x62, 0x80, 0xFF, 0xFF, 0x0A, 0xFF, 0xFF, 0x07, // 10 - 1f
|
||||
0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 20 - 2f
|
||||
0xFF, 0xFF // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef PELIKAN_A7105_INO
|
||||
const uint8_t PROGMEM PELIKAN_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x0F, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x01, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x07, // 10 - 1f
|
||||
0x16, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x1f, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef KYOSHO_A7105_INO
|
||||
const uint8_t PROGMEM KYOSHO_A7105_regs[] = {
|
||||
0xff, 0x42, 0xff, 0x25, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x40, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0x03, 0x1f, // 10 - 1f
|
||||
0x1e, 0x00, 0x00, 0xff, 0x00, 0x00, 0x23, 0x70, 0x1F, 0x47, 0x80, 0x57, 0x01, 0x45, 0x19, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
const uint8_t PROGMEM KYOSHO_HYPE_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x10, 0xC0, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x05, 0x01, 0x04, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x96, 0xc2, 0x1f, // 10 - 1f
|
||||
0x12, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3a, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef WFLY2_A7105_INO //A7106 values
|
||||
const uint8_t PROGMEM WFLY2_A7105_regs[] = {
|
||||
0xff, 0x62, 0xff, 0x1F, 0x40, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x05, 0x00, 0x64, // 00 - 0f Changes: 0B:19->33, 0C:01,33
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x40, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0x03, 0x0f, // 10 - 1f 1C:4A->0A
|
||||
0x12, 0x00, 0x00, 0xff, 0x00, 0x00, 0x23, 0x70, 0x15, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f 2B:77->03, 2E:19->18
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef JOYSWAY_A7105_INO
|
||||
const uint8_t PROGMEM JOYSWAY_A7105_regs[] = {
|
||||
0xff, 0x62, 0xff, 0x0F, 0x00, 0xff, 0xff ,0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0xF5, 0x00, 0x15, // 00 - 0f
|
||||
0x9E, 0x4B, 0x00, 0x03, 0x56, 0x2B, 0x12, 0x4A, 0x02, 0x80, 0x80, 0x00, 0x0E, 0x91, 0x03, 0x0F, // 10 - 1f
|
||||
0x16, 0x2A, 0x00, 0xff, 0xff, 0xff, 0x3A, 0x06, 0x1F, 0x47, 0x80, 0x01, 0x05, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
|
||||
#define ID_NORMAL 0x55201041
|
||||
#define ID_PLUS 0xAA201041
|
||||
void A7105_Init(void)
|
||||
{
|
||||
uint8_t *A7105_Regs=0;
|
||||
uint8_t vco_calibration0, vco_calibration1;
|
||||
|
||||
#ifdef JOYSWAY_A7105_INO
|
||||
if(protocol==PROTO_JOYSWAY)
|
||||
{
|
||||
A7105_Regs=(uint8_t*)JOYSWAY_A7105_regs;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef WFLY2_A7105_INO
|
||||
if(protocol==PROTO_WFLY2)
|
||||
{
|
||||
A7105_Regs=(uint8_t*)WFLY2_A7105_regs;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef HEIGHT_A7105_INO
|
||||
if(protocol==PROTO_HEIGHT)
|
||||
{
|
||||
A7105_Regs=(uint8_t*)HEIGHT_A7105_regs;
|
||||
A7105_WriteID(0x25A53C45);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef PELIKAN_A7105_INO
|
||||
if(protocol==PROTO_PELIKAN)
|
||||
{
|
||||
A7105_Regs=(uint8_t*)PELIKAN_A7105_regs;
|
||||
A7105_WriteID(0x06230623);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef BUGS_A7105_INO
|
||||
if(protocol==PROTO_BUGS)
|
||||
A7105_Regs=(uint8_t*)BUGS_A7105_regs;
|
||||
else
|
||||
#endif
|
||||
#ifdef HUBSAN_A7105_INO
|
||||
if(protocol==PROTO_HUBSAN)
|
||||
{
|
||||
A7105_WriteID(ID_NORMAL);
|
||||
A7105_Regs=(uint8_t*)HUBSAN_A7105_regs;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
A7105_WriteID(0x5475c52A);//0x2Ac57554
|
||||
#ifdef FLYSKY_A7105_INO
|
||||
if(protocol==PROTO_FLYSKY)
|
||||
A7105_Regs=(uint8_t*)FLYSKY_A7105_regs;
|
||||
#endif
|
||||
#if defined(AFHDS2A_A7105_INO) || defined(AFHDS2A_RX_A7105_INO)
|
||||
if(protocol==PROTO_AFHDS2A || protocol==PROTO_AFHDS2A_RX)
|
||||
A7105_Regs=(uint8_t*)AFHDS2A_A7105_regs;
|
||||
#endif
|
||||
#ifdef KYOSHO_A7105_INO
|
||||
if(protocol==PROTO_KYOSHO)
|
||||
{
|
||||
if(sub_protocol==KYOSHO_FHSS)
|
||||
A7105_Regs=(uint8_t*)KYOSHO_A7105_regs;
|
||||
else
|
||||
A7105_Regs=(uint8_t*)KYOSHO_HYPE_A7105_regs;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 0x32; i++)
|
||||
{
|
||||
uint8_t val=pgm_read_byte_near(&A7105_Regs[i]);
|
||||
#ifdef FLYSKY_A7105_INO
|
||||
if(protocol==PROTO_FLYSKY && sub_protocol==CX20)
|
||||
{
|
||||
if(i==0x0E) val=0x01;
|
||||
if(i==0x1F) val=0x1F;
|
||||
if(i==0x20) val=0x1E;
|
||||
}
|
||||
#endif
|
||||
#ifdef HEIGHT_A7105_INO
|
||||
if(protocol==PROTO_HEIGHT && sub_protocol==HEIGHT_8CH)
|
||||
if(i==0x03) val=0x0A;
|
||||
#endif
|
||||
if( val != 0xff)
|
||||
A7105_WriteReg(i, val);
|
||||
}
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
|
||||
//IF Filter Bank Calibration
|
||||
A7105_WriteReg(A7105_02_CALC,1);
|
||||
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
|
||||
// A7105_ReadReg(A7105_22_IF_CALIB_I);
|
||||
// A7105_ReadReg(A7105_24_VCO_CURCAL);
|
||||
|
||||
if(protocol==INIT_FLYSKY)
|
||||
{
|
||||
//VCO Current Calibration
|
||||
A7105_WriteReg(A7105_24_VCO_CURCAL,0x13); //Recommended calibration from A7105 Datasheet
|
||||
//VCO Bank Calibration
|
||||
A7105_WriteReg(A7105_26_VCO_SBCAL_II,0x3b); //Recommended calibration from A7105 Datasheet
|
||||
if(protocol==PROTO_KYOSHO && sub_protocol==KYOSHO_FHSS)
|
||||
{//strange calibration...
|
||||
//IF Filter Bank Calibration
|
||||
A7105_WriteReg(A7105_02_CALC,0x0F);
|
||||
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
|
||||
// A7105_ReadReg(A7105_22_IF_CALIB_I);
|
||||
// A7105_ReadReg(A7105_24_VCO_CURCAL);
|
||||
// A7105_ReadReg(25_VCO_SBCAL_I);
|
||||
// A7105_ReadReg(1A_RX_GAIN_II);
|
||||
// A7105_ReadReg(1B_RX_GAIN_III);
|
||||
}
|
||||
else
|
||||
{
|
||||
//IF Filter Bank Calibration
|
||||
A7105_WriteReg(A7105_02_CALC,1);
|
||||
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
|
||||
// A7105_ReadReg(A7105_22_IF_CALIB_I);
|
||||
// A7105_ReadReg(A7105_24_VCO_CURCAL);
|
||||
|
||||
//VCO Bank Calibrate channel 0
|
||||
A7105_WriteReg(A7105_0F_CHANNEL, 0);
|
||||
A7105_WriteReg(A7105_02_CALC,2);
|
||||
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
|
||||
// A7105_ReadReg(A7105_25_VCO_SBCAL_I);
|
||||
|
||||
//VCO Bank Calibrate channel A0
|
||||
A7105_WriteReg(A7105_0F_CHANNEL, 0xa0);
|
||||
A7105_WriteReg(A7105_02_CALC, 2);
|
||||
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
|
||||
// A7105_ReadReg(A7105_25_VCO_SBCAL_I);
|
||||
if(protocol!=PROTO_HUBSAN)
|
||||
{
|
||||
//VCO Current Calibration
|
||||
A7105_WriteReg(A7105_24_VCO_CURCAL,0x13); //Recommended calibration from A7105 Datasheet
|
||||
//VCO Bank Calibration
|
||||
A7105_WriteReg(A7105_26_VCO_SBCAL_II,0x3b); //Recommended calibration from A7105 Datasheet
|
||||
}
|
||||
|
||||
//Reset VCO Band calibration
|
||||
if(protocol==INIT_FLYSKY)
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I,0x08);
|
||||
//VCO Bank Calibrate channel 0
|
||||
A7105_WriteReg(A7105_0F_CHANNEL, 0);
|
||||
A7105_WriteReg(A7105_02_CALC,2);
|
||||
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
|
||||
vco_calibration0 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
|
||||
|
||||
//VCO Bank Calibrate channel A0
|
||||
A7105_WriteReg(A7105_0F_CHANNEL, 0xa0);
|
||||
A7105_WriteReg(A7105_02_CALC, 2);
|
||||
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
|
||||
vco_calibration1 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
|
||||
|
||||
if(protocol==PROTO_BUGS || protocol==PROTO_WFLY2)
|
||||
A7105_SetVCOBand(vco_calibration0 & 0x07, vco_calibration1 & 0x07); // Set calibration band value to best match
|
||||
else
|
||||
if(protocol!=PROTO_HUBSAN)
|
||||
{
|
||||
switch(protocol)
|
||||
{
|
||||
case PROTO_FLYSKY:
|
||||
vco_calibration1=0x08;
|
||||
break;
|
||||
case PROTO_HEIGHT:
|
||||
vco_calibration1=0x02;
|
||||
break;
|
||||
case PROTO_PELIKAN:
|
||||
if(sub_protocol == PELIKAN_SCX24)
|
||||
{
|
||||
vco_calibration1=0x0A;
|
||||
break;
|
||||
}
|
||||
case PROTO_KYOSHO: //sub_protocol Hype
|
||||
vco_calibration1=0x0C;
|
||||
break;
|
||||
case PROTO_JOYSWAY:
|
||||
vco_calibration1=0x09;
|
||||
break;
|
||||
default:
|
||||
vco_calibration1=0x0A;
|
||||
break;
|
||||
}
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I,vco_calibration1); //Reset VCO Band calibration
|
||||
}
|
||||
}
|
||||
A7105_SetTxRxMode(TX_EN);
|
||||
A7105_SetPower();
|
||||
|
||||
#ifdef USE_A7105_CH15_TUNING
|
||||
A7105_AdjustLOBaseFreq(0);
|
||||
#endif
|
||||
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
}
|
||||
#endif
|
||||
228
Multiprotocol/AFHDS2A_Rx_a7105.ino
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(AFHDS2A_RX_A7105_INO)
|
||||
|
||||
#include "iface_a7105.h"
|
||||
|
||||
#define AFHDS2A_RX_TXPACKET_SIZE 38
|
||||
#define AFHDS2A_RX_RXPACKET_SIZE 37
|
||||
#define AFHDS2A_RX_NUMFREQ 16
|
||||
|
||||
enum {
|
||||
AFHDS2A_RX_BIND1,
|
||||
AFHDS2A_RX_BIND2,
|
||||
AFHDS2A_RX_BIND3,
|
||||
AFHDS2A_RX_DATA
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) AFHDS2A_RX_build_telemetry_packet()
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
uint8_t bitsavailable = 0;
|
||||
uint8_t idx = 0;
|
||||
|
||||
packet_in[idx++] = RX_LQI; // 0 - 130
|
||||
packet_in[idx++] = RX_RSSI;
|
||||
packet_in[idx++] = 0; // start channel
|
||||
packet_in[idx++] = 14; // number of channels in packet
|
||||
// pack channels
|
||||
for (uint8_t i = 0; i < 14; i++) {
|
||||
uint32_t val = packet[9+i*2] | (((packet[10+i*2])&0x0F) << 8);
|
||||
if (val < 860)
|
||||
val = 860;
|
||||
// convert ppm (860-2140) to Multi (0-2047)
|
||||
val = min(((val-860)<<3)/5, 2047);
|
||||
|
||||
bits |= val << bitsavailable;
|
||||
bitsavailable += 11;
|
||||
while (bitsavailable >= 8) {
|
||||
packet_in[idx++] = bits & 0xff;
|
||||
bits >>= 8;
|
||||
bitsavailable -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) AFHDS2A_RX_data_ready()
|
||||
{
|
||||
// check if FECF+CRCF Ok
|
||||
return !(A7105_ReadReg(A7105_00_MODE) & (1 << 5 | 1 << 6 | 1 << 0));
|
||||
}
|
||||
|
||||
void AFHDS2A_RX_init()
|
||||
{
|
||||
uint8_t i;
|
||||
A7105_Init();
|
||||
hopping_frequency_no = 0;
|
||||
packet_count = 0;
|
||||
rx_data_started = false;
|
||||
rx_disable_lna = IS_POWER_FLAG_on;
|
||||
A7105_SetTxRxMode(rx_disable_lna ? TXRX_OFF : RX_EN);
|
||||
A7105_Strobe(A7105_RX);
|
||||
|
||||
if (IS_BIND_IN_PROGRESS) {
|
||||
phase = AFHDS2A_RX_BIND1;
|
||||
}
|
||||
else {
|
||||
uint16_t temp = AFHDS2A_RX_EEPROM_OFFSET;
|
||||
for (i = 0; i < 4; i++)
|
||||
rx_id[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
for (i = 0; i < AFHDS2A_RX_NUMFREQ; i++)
|
||||
hopping_frequency[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
phase = AFHDS2A_RX_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
#define AFHDS2A_RX_WAIT_WRITE 0x80
|
||||
|
||||
uint16_t AFHDS2A_RX_callback()
|
||||
{
|
||||
static int8_t read_retry;
|
||||
int16_t temp;
|
||||
uint8_t i;
|
||||
|
||||
#ifndef FORCE_AFHDS2A_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
if (rx_disable_lna != IS_POWER_FLAG_on) {
|
||||
rx_disable_lna = IS_POWER_FLAG_on;
|
||||
A7105_SetTxRxMode(rx_disable_lna ? TXRX_OFF : RX_EN);
|
||||
}
|
||||
|
||||
switch(phase) {
|
||||
case AFHDS2A_RX_BIND1:
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
AFHDS2A_RX_init(); // Abort bind
|
||||
break;
|
||||
}
|
||||
debugln("bind p=%d", phase+1);
|
||||
if (AFHDS2A_RX_data_ready()) {
|
||||
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
|
||||
if ((packet[0] == 0xbb && packet[9] == 0x01) || (packet[0] == 0xbc && packet[9] <= 0x02)) {
|
||||
memcpy(rx_id, &packet[1], 4); // TX id actually
|
||||
memcpy(hopping_frequency, &packet[11], AFHDS2A_RX_NUMFREQ);
|
||||
phase = AFHDS2A_RX_BIND2;
|
||||
debugln("phase bind2");
|
||||
}
|
||||
}
|
||||
A7105_WriteReg(A7105_0F_PLL_I, (packet_count++ & 1) ? 0x0D : 0x8C); // bind channels
|
||||
A7105_Strobe(A7105_RX);
|
||||
return 10000;
|
||||
|
||||
case AFHDS2A_RX_BIND2:
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
AFHDS2A_RX_init(); // Abort bind
|
||||
break;
|
||||
}
|
||||
// got 2nd bind packet from tx ?
|
||||
if (AFHDS2A_RX_data_ready()) {
|
||||
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
|
||||
if ((packet[0] == 0xBC && packet[9] == 0x02 && packet[10] == 0x00) &&
|
||||
(memcmp(rx_id, &packet[1], 4) == 0) &&
|
||||
(memcmp(rx_tx_addr, &packet[5], 4) == 0)) {
|
||||
// save tx info to eeprom
|
||||
temp = AFHDS2A_RX_EEPROM_OFFSET;
|
||||
for (i = 0; i < 4; i++)
|
||||
eeprom_write_byte((EE_ADDR)temp++, rx_id[i]);
|
||||
for (i = 0; i < AFHDS2A_RX_NUMFREQ; i++)
|
||||
eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[i]);
|
||||
phase = AFHDS2A_RX_BIND3;
|
||||
debugln("phase bind3");
|
||||
packet_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
case AFHDS2A_RX_BIND3:
|
||||
debugln("bind p=%d", phase+1);
|
||||
// transmit response packet
|
||||
packet[0] = 0xBC;
|
||||
memcpy(&packet[1], rx_id, 4);
|
||||
memcpy(&packet[5], rx_tx_addr, 4);
|
||||
//packet[9] = 0x01;
|
||||
packet[10] = 0x00;
|
||||
memset(&packet[11], 0xFF, 26);
|
||||
A7105_SetTxRxMode(TX_EN);
|
||||
rx_disable_lna = !IS_POWER_FLAG_on;
|
||||
A7105_WriteData(AFHDS2A_RX_RXPACKET_SIZE, packet_count++ & 1 ? 0x0D : 0x8C);
|
||||
if(phase == AFHDS2A_RX_BIND3 && packet_count > 20)
|
||||
{
|
||||
debugln("done");
|
||||
BIND_DONE;
|
||||
AFHDS2A_RX_init(); // Restart protocol
|
||||
break;
|
||||
}
|
||||
phase |= AFHDS2A_RX_WAIT_WRITE;
|
||||
return 1700;
|
||||
|
||||
case AFHDS2A_RX_BIND2 | AFHDS2A_RX_WAIT_WRITE:
|
||||
//Wait for TX completion
|
||||
pps_timer = micros();
|
||||
while ((uint32_t)(micros() - pps_timer) < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
|
||||
if (!(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_Strobe(A7105_RX);
|
||||
case AFHDS2A_RX_BIND3 | AFHDS2A_RX_WAIT_WRITE:
|
||||
phase &= ~AFHDS2A_RX_WAIT_WRITE;
|
||||
return 10000;
|
||||
|
||||
case AFHDS2A_RX_DATA:
|
||||
if (AFHDS2A_RX_data_ready()) {
|
||||
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
|
||||
if (memcmp(&packet[1], rx_id, 4) == 0 && memcmp(&packet[5], rx_tx_addr, 4) == 0) {
|
||||
if (packet[0] == 0x58 && packet[37] == 0x00 && (telemetry_link&0x7F) == 0) { // standard packet, send channels to TX
|
||||
int rssi = min(A7105_ReadReg(A7105_1D_RSSI_THOLD),160);
|
||||
RX_RSSI = map16b(rssi, 160, 8, 0, 128);
|
||||
AFHDS2A_RX_build_telemetry_packet();
|
||||
telemetry_link = 1;
|
||||
#ifdef SEND_CPPM
|
||||
if(sub_protocol>0)
|
||||
telemetry_link |= 0x80; // Disable telemetry output
|
||||
#endif
|
||||
}
|
||||
rx_data_started = true;
|
||||
read_retry = 10; // hop to next channel
|
||||
pps_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
// packets per second
|
||||
if (millis() - pps_timer >= 1000) {
|
||||
pps_timer = millis();
|
||||
debugln("%d pps", pps_counter);
|
||||
RX_LQI = pps_counter / 2;
|
||||
pps_counter = 0;
|
||||
}
|
||||
|
||||
// frequency hopping
|
||||
if (read_retry++ >= 10) {
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no >= AFHDS2A_RX_NUMFREQ)
|
||||
hopping_frequency_no = 0;
|
||||
A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no]);
|
||||
A7105_Strobe(A7105_RX);
|
||||
if (rx_data_started)
|
||||
read_retry = 0;
|
||||
else
|
||||
read_retry = -127; // retry longer until first packet is catched
|
||||
}
|
||||
return 385;
|
||||
}
|
||||
return 3850; // never reached
|
||||
}
|
||||
|
||||
#endif
|
||||
456
Multiprotocol/AFHDS2A_a7105.ino
Normal file
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with hexfet new_protocols/flysky_a7105.c dated 2015-09-28
|
||||
|
||||
#ifdef AFHDS2A_A7105_INO
|
||||
|
||||
#define AFHDS2A_TXPACKET_SIZE 38
|
||||
#define AFHDS2A_RXPACKET_SIZE 37
|
||||
#define AFHDS2A_NUMFREQ 16
|
||||
|
||||
#if not defined TELEMETRY
|
||||
uint8_t RX_LQI=0;
|
||||
#endif
|
||||
|
||||
enum{
|
||||
AFHDS2A_PACKET_STICKS,
|
||||
AFHDS2A_PACKET_SETTINGS,
|
||||
AFHDS2A_PACKET_FAILSAFE,
|
||||
};
|
||||
|
||||
enum{
|
||||
AFHDS2A_BIND1,
|
||||
AFHDS2A_BIND2,
|
||||
AFHDS2A_BIND3,
|
||||
AFHDS2A_BIND4,
|
||||
AFHDS2A_DATA_INIT,
|
||||
AFHDS2A_DATA,
|
||||
};
|
||||
|
||||
static void AFHDS2A_calc_channels()
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint32_t rnd = MProtocol_id;
|
||||
while (idx < AFHDS2A_NUMFREQ)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t band_no = ((((idx<<1) | ((idx>>1) & 0b01)) + rx_tx_addr[3]) & 0b11);
|
||||
rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
|
||||
|
||||
uint8_t next_ch = band_no*41 + 1 + ((rnd >> idx) % 41); // Channel range: 1..164
|
||||
|
||||
for (i = 0; i < idx; i++)
|
||||
{
|
||||
// Keep the distance 5 between the channels
|
||||
uint8_t distance;
|
||||
if (next_ch > hopping_frequency[i])
|
||||
distance = next_ch - hopping_frequency[i];
|
||||
else
|
||||
distance = hopping_frequency[i] - next_ch;
|
||||
|
||||
if (distance < 5) break;
|
||||
}
|
||||
|
||||
if (i != idx) continue;
|
||||
|
||||
hopping_frequency[idx++] = next_ch;
|
||||
}
|
||||
}
|
||||
|
||||
// telemetry sensors ID
|
||||
enum{
|
||||
AFHDS2A_SENSOR_RX_VOLTAGE = 0x00,
|
||||
AFHDS2A_SENSOR_RX_ERR_RATE = 0xfe,
|
||||
AFHDS2A_SENSOR_RX_RSSI = 0xfc,
|
||||
AFHDS2A_SENSOR_RX_NOISE = 0xfb,
|
||||
AFHDS2A_SENSOR_RX_SNR = 0xfa,
|
||||
AFHDS2A_SENSOR_A3_VOLTAGE = 0x03,
|
||||
};
|
||||
|
||||
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
|
||||
static void AFHDS2A_update_telemetry()
|
||||
{
|
||||
// Read TX RSSI
|
||||
int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less
|
||||
if(temp<0) temp=0;
|
||||
else if(temp>255) temp=255;
|
||||
TX_RSSI=temp;
|
||||
// AA | TXID | rx_id | sensor id | sensor # | value 16 bit big endian | sensor id ......
|
||||
// AC | TXID | rx_id | sensor id | sensor # | length | bytes | sensor id ......
|
||||
#ifdef AFHDS2A_FW_TELEMETRY
|
||||
if (option & 0x80)
|
||||
{// forward 0xAA and 0xAC telemetry to TX, skip rx and tx id to save space
|
||||
packet_in[0]= TX_RSSI;
|
||||
debug("T(%02X)=",packet[0]);
|
||||
for(uint8_t i=9;i < AFHDS2A_RXPACKET_SIZE; i++)
|
||||
{
|
||||
packet_in[i-8]=packet[i];
|
||||
debug(" %02X",packet[i]);
|
||||
}
|
||||
packet_in[29]=packet[0]; // 0xAA Normal telemetry, 0xAC Extended telemetry
|
||||
telemetry_link=2;
|
||||
debugln("");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef AFHDS2A_HUB_TELEMETRY
|
||||
if(packet[0]==0xAA)
|
||||
{ // 0xAA Normal telemetry, 0xAC Extended telemetry not decoded here
|
||||
for(uint8_t sensor=0; sensor<7; sensor++)
|
||||
{
|
||||
// Send FrSkyD telemetry to TX
|
||||
uint8_t index = 9+(4*sensor);
|
||||
switch(packet[index])
|
||||
{
|
||||
case AFHDS2A_SENSOR_RX_VOLTAGE:
|
||||
//v_lipo1 = packet[index+3]<<8 | packet[index+2];
|
||||
v_lipo1 = packet[index+2];
|
||||
telemetry_link=1;
|
||||
break;
|
||||
case AFHDS2A_SENSOR_A3_VOLTAGE:
|
||||
v_lipo2 = (packet[index+3]<<5) | (packet[index+2]>>3); // allows to read voltage up to 4S
|
||||
telemetry_link=1;
|
||||
break;
|
||||
case AFHDS2A_SENSOR_RX_ERR_RATE:
|
||||
if(packet[index+2]<=100)
|
||||
RX_LQI=packet[index+2];
|
||||
break;
|
||||
case AFHDS2A_SENSOR_RX_RSSI:
|
||||
RX_RSSI = -packet[index+2];
|
||||
break;
|
||||
case 0xff: // end of data
|
||||
return;
|
||||
/*default:
|
||||
// unknown sensor ID
|
||||
break;*/
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void AFHDS2A_build_bind_packet()
|
||||
{
|
||||
uint8_t ch;
|
||||
memcpy( &packet[1], rx_tx_addr, 4);
|
||||
memset( &packet[5], 0xff, 4);
|
||||
packet[10]= 0x00;
|
||||
for(ch=0; ch<AFHDS2A_NUMFREQ; ch++)
|
||||
packet[11+ch] = hopping_frequency[ch];
|
||||
memset( &packet[27], 0xff, 10);
|
||||
packet[37] = 0x00;
|
||||
switch(phase)
|
||||
{
|
||||
case AFHDS2A_BIND1:
|
||||
packet[0] = 0xbb;
|
||||
packet[9] = 0x01;
|
||||
break;
|
||||
case AFHDS2A_BIND2:
|
||||
case AFHDS2A_BIND3:
|
||||
case AFHDS2A_BIND4:
|
||||
packet[0] = 0xbc;
|
||||
if(phase == AFHDS2A_BIND4)
|
||||
{
|
||||
memcpy( &packet[5], &rx_id, 4);
|
||||
memset( &packet[11], 0xff, 16);
|
||||
}
|
||||
packet[9] = phase-1;
|
||||
if(packet[9] > 0x02)
|
||||
packet[9] = 0x02;
|
||||
packet[27]= 0x01;
|
||||
packet[28]= 0x80;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void AFHDS2A_build_packet(uint8_t type)
|
||||
{
|
||||
uint16_t val;
|
||||
memcpy( &packet[1], rx_tx_addr, 4);
|
||||
memcpy( &packet[5], rx_id, 4);
|
||||
switch(type)
|
||||
{
|
||||
case AFHDS2A_PACKET_STICKS:
|
||||
packet[0] = 0x58;
|
||||
//16 channels + RX_LQI on channel 17
|
||||
for(uint8_t ch=0; ch<num_ch; ch++)
|
||||
{
|
||||
if(ch == 16 // CH17=RX_LQI
|
||||
#ifdef AFHDS2A_LQI_CH
|
||||
|| ch == (AFHDS2A_LQI_CH-1) // override channel with LQI
|
||||
#endif
|
||||
)
|
||||
val = 2000 - 10*RX_LQI;
|
||||
else
|
||||
val = convert_channel_ppm(CH_AETR[ch]);
|
||||
if(ch<14)
|
||||
{
|
||||
packet[9 + ch*2] = val;
|
||||
packet[10 + ch*2] = (val>>8)&0x0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[10 + (ch-14)*6] |= (val)<<4;
|
||||
packet[12 + (ch-14)*6] |= (val)&0xF0;
|
||||
packet[14 + (ch-14)*6] |= (val>>4)&0xF0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AFHDS2A_PACKET_FAILSAFE:
|
||||
packet[0] = 0x56;
|
||||
for(uint8_t ch=0; ch<num_ch; ch++)
|
||||
{
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(ch<16)
|
||||
val = Failsafe_data[CH_AETR[ch]];
|
||||
else
|
||||
val = FAILSAFE_CHANNEL_NOPULSES;
|
||||
if(val!=FAILSAFE_CHANNEL_HOLD && val!=FAILSAFE_CHANNEL_NOPULSES)
|
||||
{ // Failsafe values
|
||||
val = (((val<<2)+val)>>3)+860;
|
||||
if(ch<14)
|
||||
{
|
||||
packet[9 + ch*2] = val;
|
||||
packet[10 + ch*2] = (val>>8)&0x0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[10 + (ch-14)*6] &= 0x0F;
|
||||
packet[10 + (ch-14)*6] |= (val)<<4;
|
||||
packet[12 + (ch-14)*6] &= 0x0F;
|
||||
packet[12 + (ch-14)*6] |= (val)&0xF0;
|
||||
packet[14 + (ch-14)*6] &= 0x0F;
|
||||
packet[14 + (ch-14)*6] |= (val>>4)&0xF0;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(ch<14)
|
||||
{ // no values
|
||||
packet[9 + ch*2] = 0xff;
|
||||
packet[10+ ch*2] = 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AFHDS2A_PACKET_SETTINGS:
|
||||
packet[0] = 0xaa;
|
||||
packet[9] = 0xfd;
|
||||
packet[10]= 0xff;
|
||||
val=5*(option & 0x7f)+50; // option value should be between 0 and 70 which gives a value between 50 and 400Hz
|
||||
if(val<50 || val>400) val=50; // default is 50Hz
|
||||
packet[11]= val;
|
||||
packet[12]= val >> 8;
|
||||
packet[13] = sub_protocol & 0x01; // 1 -> PPM output enabled
|
||||
packet[14]= 0x00;
|
||||
for(uint8_t i=15; i<37; i++)
|
||||
packet[i] = 0xff;
|
||||
packet[18] = 0x05; // ?
|
||||
packet[19] = 0xdc; // ?
|
||||
packet[20] = 0x05; // ?
|
||||
if(sub_protocol&2)
|
||||
packet[21] = 0xdd; // SBUS output enabled
|
||||
else
|
||||
packet[21] = 0xde; // IBUS
|
||||
break;
|
||||
}
|
||||
packet[37] = 0x00;
|
||||
}
|
||||
|
||||
#define AFHDS2A_WAIT_WRITE 0x80
|
||||
|
||||
#ifdef STM32_BOARD
|
||||
#define AFHDS2A_WRITE_TIME 1550
|
||||
#else
|
||||
#define AFHDS2A_WRITE_TIME 1700
|
||||
#endif
|
||||
|
||||
uint16_t AFHDS2A_callback()
|
||||
{
|
||||
static uint8_t packet_type;
|
||||
static uint16_t packet_counter;
|
||||
uint8_t data_rx=0;
|
||||
uint16_t start;
|
||||
#ifndef FORCE_AFHDS2A_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
switch(phase)
|
||||
{
|
||||
case AFHDS2A_BIND1:
|
||||
case AFHDS2A_BIND2:
|
||||
case AFHDS2A_BIND3:
|
||||
AFHDS2A_build_bind_packet();
|
||||
data_rx=A7105_ReadReg(A7105_00_MODE); // Check if something has been received...
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, packet_count%2 ? 0x0d : 0x8c);
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5)) && !(data_rx & 1)) // removed FECF check due to issues with fs-x6b -> & (1<<5 | 1<<6)
|
||||
{ // RX+CRCF Ok
|
||||
A7105_ReadData(AFHDS2A_RXPACKET_SIZE);
|
||||
#if 0
|
||||
debug("RX");
|
||||
for(uint8_t i=0; i<AFHDS2A_RXPACKET_SIZE ; i++)
|
||||
debug(" %02X", packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
if(packet[0] == 0xbc && packet[9] == 0x01)
|
||||
{
|
||||
uint16_t addr;
|
||||
if(RX_num<16)
|
||||
addr=AFHDS2A_EEPROM_OFFSET+RX_num*4;
|
||||
else
|
||||
addr=AFHDS2A_EEPROM_OFFSET2+(RX_num-16)*4;
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
{
|
||||
rx_id[i] = packet[5+i];
|
||||
eeprom_write_byte((EE_ADDR)(addr+i),rx_id[i]);
|
||||
}
|
||||
phase = AFHDS2A_BIND4;
|
||||
packet_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
packet_count++;
|
||||
if(IS_BIND_DONE)
|
||||
{ // exit bind if asked to do so from the GUI
|
||||
phase = AFHDS2A_BIND4;
|
||||
break;
|
||||
}
|
||||
phase |= AFHDS2A_WAIT_WRITE;
|
||||
return AFHDS2A_WRITE_TIME;
|
||||
case AFHDS2A_BIND1|AFHDS2A_WAIT_WRITE:
|
||||
case AFHDS2A_BIND2|AFHDS2A_WAIT_WRITE:
|
||||
case AFHDS2A_BIND3|AFHDS2A_WAIT_WRITE:
|
||||
//Wait for TX completion
|
||||
start=micros();
|
||||
while ((uint16_t)((uint16_t)micros()-start) < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_SetPower();
|
||||
A7105_SetTxRxMode((packet_count & 0x40) ? TXRX_OFF : RX_EN); // Turn LNA off time to time since we are in near range and we want to prevent swamping
|
||||
A7105_Strobe(A7105_RX);
|
||||
phase &= ~AFHDS2A_WAIT_WRITE;
|
||||
phase++;
|
||||
if(phase > AFHDS2A_BIND3)
|
||||
phase = AFHDS2A_BIND1;
|
||||
return 3850-AFHDS2A_WRITE_TIME;
|
||||
case AFHDS2A_BIND4:
|
||||
AFHDS2A_build_bind_packet();
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, packet_count%2 ? 0x0d : 0x8c);
|
||||
packet_count++;
|
||||
bind_phase++;
|
||||
if(bind_phase>=4)
|
||||
{
|
||||
hopping_frequency_no=1;
|
||||
phase = AFHDS2A_DATA_INIT;
|
||||
BIND_DONE;
|
||||
}
|
||||
break;
|
||||
case AFHDS2A_DATA_INIT:
|
||||
packet_counter=0;
|
||||
packet_type = AFHDS2A_PACKET_STICKS;
|
||||
phase = AFHDS2A_DATA;
|
||||
case AFHDS2A_DATA:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(3850);
|
||||
#endif
|
||||
AFHDS2A_build_packet(packet_type);
|
||||
data_rx=A7105_ReadReg(A7105_00_MODE); // Check if something has been received...
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, hopping_frequency[hopping_frequency_no++]);
|
||||
if(hopping_frequency_no >= AFHDS2A_NUMFREQ)
|
||||
hopping_frequency_no = 0;
|
||||
if(!(packet_counter % 1313))
|
||||
packet_type = AFHDS2A_PACKET_SETTINGS;
|
||||
else
|
||||
{
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(!(packet_counter % 1569) && IS_FAILSAFE_VALUES_on)
|
||||
{
|
||||
packet_type = AFHDS2A_PACKET_FAILSAFE;
|
||||
FAILSAFE_VALUES_off;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
packet_type = AFHDS2A_PACKET_STICKS; // todo : check for settings changes
|
||||
}
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5)) && !(data_rx & 1)) // removed FECF check due to issues with fs-x6b -> & (1<<5 | 1<<6)
|
||||
{ // RX+CRCF Ok
|
||||
A7105_ReadData(AFHDS2A_RXPACKET_SIZE);
|
||||
if(packet[0] == 0xAA && packet[9] == 0xFC)
|
||||
packet_type=AFHDS2A_PACKET_SETTINGS; // RX is asking for settings
|
||||
else
|
||||
if((packet[0] == 0xAA && packet[9]!=0xFD) || packet[0] == 0xAC)
|
||||
{// Normal telemetry packet, ignore packets which contain the RX configuration: AA FD FF 32 00 01 00 FF FF FF 05 DC 05 DE FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
if(!memcmp(&packet[1], rx_tx_addr, 4))
|
||||
{ // TX address validated
|
||||
for(uint8_t sensor=0; sensor<7; sensor++)
|
||||
{//read LQI value for RX output
|
||||
uint8_t index = 9+(4*sensor);
|
||||
if(packet[index]==AFHDS2A_SENSOR_RX_ERR_RATE && packet[index+2]<=100)
|
||||
{
|
||||
RX_LQI=packet[index+2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
|
||||
AFHDS2A_update_telemetry();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
packet_counter++;
|
||||
phase |= AFHDS2A_WAIT_WRITE;
|
||||
return AFHDS2A_WRITE_TIME;
|
||||
case AFHDS2A_DATA|AFHDS2A_WAIT_WRITE:
|
||||
//Wait for TX completion
|
||||
start=micros();
|
||||
while ((uint16_t)((uint16_t)micros()-start) < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_SetPower();
|
||||
A7105_SetTxRxMode(RX_EN);
|
||||
A7105_Strobe(A7105_RX);
|
||||
phase &= ~AFHDS2A_WAIT_WRITE;
|
||||
return 3850-AFHDS2A_WRITE_TIME;
|
||||
}
|
||||
return 3850;
|
||||
}
|
||||
|
||||
void AFHDS2A_init()
|
||||
{
|
||||
A7105_Init();
|
||||
|
||||
AFHDS2A_calc_channels();
|
||||
packet_count = 0;
|
||||
bind_phase = 0;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
phase = AFHDS2A_BIND1;
|
||||
else
|
||||
{
|
||||
phase = AFHDS2A_DATA_INIT;
|
||||
//Read RX ID from EEPROM based on RX_num, RX_num must be uniq for each RX
|
||||
uint16_t addr;
|
||||
if(RX_num<16)
|
||||
addr=AFHDS2A_EEPROM_OFFSET+RX_num*4;
|
||||
else
|
||||
addr=AFHDS2A_EEPROM_OFFSET2+(RX_num-16)*4;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
rx_id[i]=eeprom_read_byte((EE_ADDR)(addr+i));
|
||||
}
|
||||
hopping_frequency_no = 0;
|
||||
if(sub_protocol&0x04)
|
||||
num_ch=17;
|
||||
else
|
||||
num_ch=14;
|
||||
}
|
||||
#endif
|
||||
179
Multiprotocol/ASSAN_nrf24l01.ino
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(ASSAN_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define ASSAN_PACKET_SIZE 20
|
||||
#define ASSAN_RF_BIND_CHANNEL 0x03
|
||||
#define ASSAN_ADDRESS_LENGTH 4
|
||||
|
||||
enum {
|
||||
ASSAN_BIND0=0,
|
||||
ASSAN_BIND1,
|
||||
ASSAN_BIND2,
|
||||
ASSAN_DATA0,
|
||||
ASSAN_DATA1,
|
||||
ASSAN_DATA2,
|
||||
ASSAN_DATA3,
|
||||
ASSAN_DATA4,
|
||||
ASSAN_DATA5
|
||||
};
|
||||
|
||||
void ASSAN_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
//Specifics to ASSAN
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x02); // 4 bytes rx/tx address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x80\x80\x80\xB8", ASSAN_ADDRESS_LENGTH); // Bind address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x80\x80\x80\xB8", ASSAN_ADDRESS_LENGTH); // Bind address
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, ASSAN_PACKET_SIZE);
|
||||
}
|
||||
|
||||
void ASSAN_send_packet()
|
||||
{
|
||||
for(uint8_t i=0;i<8;i++)
|
||||
{
|
||||
uint16_t val=Channel_data[i];
|
||||
val=((val<<2)+val)+(860<<3); // PPM value <<3
|
||||
|
||||
packet[2*i]=val>>8;
|
||||
packet[2*i+1]=val;
|
||||
}
|
||||
for(uint8_t i=0;i<ASSAN_ADDRESS_LENGTH;i++)
|
||||
packet[16+i]=packet[23-i];
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, ASSAN_PACKET_SIZE);
|
||||
}
|
||||
|
||||
uint16_t ASSAN_callback()
|
||||
{
|
||||
switch (phase)
|
||||
{
|
||||
// Bind
|
||||
case ASSAN_BIND0:
|
||||
//Config RX @1M
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, ASSAN_RF_BIND_CHANNEL);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
phase++;
|
||||
case ASSAN_BIND1:
|
||||
//Wait for receiver to send the frames
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ //Something has been received
|
||||
NRF24L01_ReadPayload(packet, ASSAN_PACKET_SIZE);
|
||||
if(packet[19]==0x13)
|
||||
{ //Last frame received
|
||||
phase++;
|
||||
//Switch to TX
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
//Prepare bind packet
|
||||
memset(packet,0x05,ASSAN_PACKET_SIZE-5);
|
||||
packet[15]=0x99;
|
||||
for(uint8_t i=0;i<ASSAN_ADDRESS_LENGTH;i++)
|
||||
packet[16+i]=packet[23-i];
|
||||
packet_count=0;
|
||||
delayMilliseconds(260);
|
||||
return 10000; // Wait 270ms in total...
|
||||
}
|
||||
}
|
||||
return 1000;
|
||||
case ASSAN_BIND2:
|
||||
// Send 20 packets
|
||||
packet_count++;
|
||||
if(packet_count==20)
|
||||
packet[15]=0x13; // different value for last packet
|
||||
NRF24L01_WritePayload(packet, ASSAN_PACKET_SIZE);
|
||||
if(packet_count==20)
|
||||
{
|
||||
phase++;
|
||||
delayMilliseconds(2165);
|
||||
}
|
||||
return 22520;
|
||||
// Normal operation
|
||||
case ASSAN_DATA0:
|
||||
// Bind Done
|
||||
BIND_DONE;
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
case ASSAN_DATA1:
|
||||
case ASSAN_DATA4:
|
||||
// Change ID and RF channel
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR,packet+20+4*hopping_frequency_no, ASSAN_ADDRESS_LENGTH);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
hopping_frequency_no^=0x01;
|
||||
NRF24L01_SetPower();
|
||||
phase=ASSAN_DATA2;
|
||||
return 2000;
|
||||
case ASSAN_DATA2:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(12000);
|
||||
#endif
|
||||
case ASSAN_DATA3:
|
||||
ASSAN_send_packet();
|
||||
phase++; // DATA 3 or 4
|
||||
return 5000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ASSAN_initialize_txid()
|
||||
{
|
||||
/* //Renaud TXID with Freq=36 and alternate Freq 67 or 68 or 69 or 70 or 71 or 73 or 74 or 75 or 78 and may be more...
|
||||
packet[23]=0x22;
|
||||
packet[22]=0x37;
|
||||
packet[21]=0xFA;
|
||||
packet[20]=0x53; */
|
||||
// Using packet[20..23] to store the ID1 and packet[24..27] to store the ID2
|
||||
uint8_t freq=0,freq2;
|
||||
for(uint8_t i=0;i<ASSAN_ADDRESS_LENGTH;i++)
|
||||
{
|
||||
uint8_t temp=rx_tx_addr[i];
|
||||
packet[i+20]=temp;
|
||||
packet[i+24]=temp+1;
|
||||
freq+=temp;
|
||||
}
|
||||
|
||||
// Main frequency
|
||||
freq=((freq%25)+2)<<1;
|
||||
if(freq&0x02) freq|=0x01;
|
||||
hopping_frequency[0]=freq;
|
||||
// Alternate frequency has some random
|
||||
do
|
||||
{
|
||||
freq2=random(0xfefefefe)%9;
|
||||
freq2+=freq*2-5;
|
||||
}
|
||||
while( (freq2>118) || (freq2<freq+1) || (freq2==2*freq) );
|
||||
hopping_frequency[1]=freq2;
|
||||
}
|
||||
|
||||
void ASSAN_init()
|
||||
{
|
||||
ASSAN_initialize_txid();
|
||||
ASSAN_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
phase=ASSAN_BIND0;
|
||||
else
|
||||
phase=ASSAN_DATA0;
|
||||
}
|
||||
|
||||
#endif
|
||||
159
Multiprotocol/Arduino.ino
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/************************************/
|
||||
/************************************/
|
||||
/** Arduino replacement routines **/
|
||||
/************************************/
|
||||
// replacement map()
|
||||
int16_t map16b( int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max)
|
||||
{
|
||||
// return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
long y ;
|
||||
x -= in_min ;
|
||||
y = out_max - out_min ;
|
||||
y *= x ;
|
||||
x = y / (in_max - in_min) ;
|
||||
return x + out_min ;
|
||||
}
|
||||
|
||||
#ifndef STM32_BOARD
|
||||
int16_t map( int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max)
|
||||
{
|
||||
// return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
long y ;
|
||||
x -= in_min ;
|
||||
y = out_max - out_min ;
|
||||
y *= x ;
|
||||
x = y / (in_max - in_min) ;
|
||||
return x + out_min ;
|
||||
}
|
||||
|
||||
// replacement millis() and micros()
|
||||
// These work polled, no interrupts
|
||||
// micros() MUST be called at least once every 32 milliseconds
|
||||
uint16_t MillisPrecount ;
|
||||
uint16_t lastTimerValue ;
|
||||
uint32_t TotalMicros ;
|
||||
uint32_t TotalMillis ;
|
||||
uint8_t Correction ;
|
||||
|
||||
uint32_t micros()
|
||||
{
|
||||
uint16_t elapsed ;
|
||||
uint8_t millisToAdd ;
|
||||
uint8_t oldSREG = SREG ;
|
||||
cli() ;
|
||||
uint16_t time = TCNT1 ; // Read timer 1
|
||||
SREG = oldSREG ;
|
||||
|
||||
elapsed = time - lastTimerValue ;
|
||||
elapsed += Correction ;
|
||||
Correction = elapsed & 0x01 ;
|
||||
elapsed >>= 1 ;
|
||||
|
||||
uint32_t ltime = TotalMicros ;
|
||||
ltime += elapsed ;
|
||||
cli() ;
|
||||
TotalMicros = ltime ; // Done this way for RPM to work correctly
|
||||
lastTimerValue = time ;
|
||||
SREG = oldSREG ; // Still valid from above
|
||||
|
||||
elapsed += MillisPrecount;
|
||||
millisToAdd = 0 ;
|
||||
|
||||
if ( elapsed > 15999 )
|
||||
{
|
||||
millisToAdd = 16 ;
|
||||
elapsed -= 16000 ;
|
||||
}
|
||||
if ( elapsed > 7999 )
|
||||
{
|
||||
millisToAdd += 8 ;
|
||||
elapsed -= 8000 ;
|
||||
}
|
||||
if ( elapsed > 3999 )
|
||||
{
|
||||
millisToAdd += 4 ;
|
||||
elapsed -= 4000 ;
|
||||
}
|
||||
if ( elapsed > 1999 )
|
||||
{
|
||||
millisToAdd += 2 ;
|
||||
elapsed -= 2000 ;
|
||||
}
|
||||
if ( elapsed > 999 )
|
||||
{
|
||||
millisToAdd += 1 ;
|
||||
elapsed -= 1000 ;
|
||||
}
|
||||
TotalMillis += millisToAdd ;
|
||||
MillisPrecount = elapsed ;
|
||||
return TotalMicros ;
|
||||
}
|
||||
|
||||
uint32_t millis()
|
||||
{
|
||||
micros() ;
|
||||
return TotalMillis ;
|
||||
}
|
||||
|
||||
void delayMilliseconds(unsigned long ms)
|
||||
{
|
||||
uint16_t start = (uint16_t)micros();
|
||||
uint16_t lms = ms ;
|
||||
|
||||
while (lms > 0) {
|
||||
if ((uint16_t)((uint16_t)micros() - start) >= 1000) {
|
||||
lms--;
|
||||
start += 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Important notes:
|
||||
- Max value is 16000µs
|
||||
- delay is not accurate due to interrupts happening */
|
||||
void delayMicroseconds(unsigned int us)
|
||||
{
|
||||
if (--us == 0)
|
||||
return;
|
||||
us <<= 2; // * 4
|
||||
us -= 2; // - 2
|
||||
#ifdef ORANGE_TX
|
||||
__asm__ __volatile__ (
|
||||
"1: sbiw %0,1" "\n\t" // 2 cycles
|
||||
"nop \n"
|
||||
"nop \n"
|
||||
"nop \n"
|
||||
"nop \n"
|
||||
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
|
||||
);
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"1: sbiw %0,1" "\n\t" // 2 cycles
|
||||
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef ORANGE_TX
|
||||
void init()
|
||||
{
|
||||
// this needs to be called before setup() or some functions won't work there
|
||||
sei();
|
||||
}
|
||||
#endif //ORANGE_TX
|
||||
|
||||
#endif //STM32_BOARD
|
||||
364
Multiprotocol/BUGSMINI_nrf24l01.ino
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// compatible with MJX Bugs 3 Mini and Bugs 3H
|
||||
|
||||
#if defined(BUGSMINI_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define BUGSMINI_INITIAL_WAIT 500
|
||||
#define BUGSMINI_PACKET_INTERVAL 6840
|
||||
#define BUGSMINI_WRITE_WAIT 2000
|
||||
#define BUGSMINI_TX_PAYLOAD_SIZE 24
|
||||
#define BUGSMINI_RX_PAYLOAD_SIZE 16
|
||||
#define BUGSMINI_NUM_RF_CHANNELS 15
|
||||
#define BUGSMINI_ADDRESS_SIZE 5
|
||||
|
||||
static uint8_t BUGSMINI_txid[3];
|
||||
static uint8_t BUGSMINI_txhash;
|
||||
|
||||
enum {
|
||||
BUGSMINI_BIND1,
|
||||
BUGSMINI_BIND2,
|
||||
BUGSMINI_DATA1,
|
||||
BUGSMINI_DATA2
|
||||
};
|
||||
|
||||
#define BUGSMINI_CH_SW_ARM CH5_SW
|
||||
#define BUGSMINI_CH_SW_ANGLE CH6_SW
|
||||
#define BUGSMINI_CH_SW_FLIP CH7_SW
|
||||
#define BUGSMINI_CH_SW_PICTURE CH8_SW
|
||||
#define BUGSMINI_CH_SW_VIDEO CH9_SW
|
||||
#define BUGSMINI_CH_SW_LED CH10_SW
|
||||
#define BUGSMINI_CH_SW_ALTHOLD CH11_SW
|
||||
|
||||
// flags packet[12]
|
||||
#define BUGSMINI_FLAG_FLIP 0x08 // automatic flip
|
||||
#define BUGSMINI_FLAG_MODE 0x04 // low/high speed select (set is high speed)
|
||||
#define BUGSMINI_FLAG_VIDEO 0x02 // toggle video
|
||||
#define BUGSMINI_FLAG_PICTURE 0x01 // toggle picture
|
||||
|
||||
// flags packet[13]
|
||||
#define BUGSMINI_FLAG_LED 0x80 // enable LEDs
|
||||
#define BUGSMINI_FLAG_ARM 0x40 // arm (toggle to turn on motors)
|
||||
#define BUGSMINI_FLAG_DISARM 0x20 // disarm (toggle to turn off motors)
|
||||
#define BUGSMINI_FLAG_ANGLE 0x02 // angle/acro mode (set is angle mode)
|
||||
#define BUGSMINI_FLAG_ALTHOLD 0x04 // angle/altitude hold mode (set is altitude mode)
|
||||
|
||||
static void __attribute__((unused)) BUGSMINI_RF_init()
|
||||
{
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
//XN297_HoppingCalib(BUGSMINI_NUM_RF_CHANNELS*2);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGSMINI_check_arming()
|
||||
{
|
||||
uint8_t arm_channel = BUGSMINI_CH_SW_ARM;
|
||||
|
||||
if (arm_channel != arm_channel_previous)
|
||||
{
|
||||
arm_channel_previous = arm_channel;
|
||||
if (arm_channel)
|
||||
{
|
||||
armed = 1;
|
||||
arm_flags ^= BUGSMINI_FLAG_ARM;
|
||||
}
|
||||
else
|
||||
{
|
||||
armed = 0;
|
||||
arm_flags ^= BUGSMINI_FLAG_DISARM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGSMINI_send_packet()
|
||||
{
|
||||
BUGSMINI_check_arming(); // sets globals arm_flags and armed
|
||||
|
||||
uint16_t aileron = convert_channel_16b_limit(AILERON,500,0);
|
||||
uint16_t elevator = convert_channel_16b_limit(ELEVATOR,0,500);
|
||||
uint16_t throttle = armed ? convert_channel_16b_limit(THROTTLE,0,500) : 0;
|
||||
uint16_t rudder = convert_channel_16b_limit(RUDDER,500,0);
|
||||
|
||||
packet[1] = BUGSMINI_txid[0];
|
||||
packet[2] = BUGSMINI_txid[1];
|
||||
packet[3] = BUGSMINI_txid[2];
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[4] = 0x00;
|
||||
packet[5] = 0x7d;
|
||||
packet[6] = 0x7d;
|
||||
packet[7] = 0x7d;
|
||||
packet[8] = 0x20;
|
||||
packet[9] = 0x20;
|
||||
packet[10]= 0x20;
|
||||
packet[11]= 0x40;
|
||||
packet[12]^= 0x40; // alternating freq hopping flag
|
||||
packet[13]= 0x60;
|
||||
packet[14]= 0x00;
|
||||
packet[15]= 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[4] = throttle >> 1;
|
||||
packet[5] = rudder >> 1;
|
||||
packet[6] = elevator >> 1;
|
||||
packet[7] = aileron >> 1;
|
||||
packet[8] = (((aileron / 5) >> 1) + 7) // dynamic trim 0x07 - 0x39
|
||||
| (aileron << 7);
|
||||
packet[9] = (((elevator / 5) >> 1) + 7) // dynamic trim 0x07 - 0x39
|
||||
| (elevator << 7);
|
||||
packet[10]= (((rudder / 5) >> 1) + 7) // dynamic trim 0x07 - 0x39
|
||||
| (rudder << 7);
|
||||
packet[11]= 0x40 | (throttle << 7);
|
||||
packet[12]= 0x80 | ((packet[12] ^ 0x40) & 0x40)
|
||||
| BUGSMINI_FLAG_MODE
|
||||
| GET_FLAG(BUGSMINI_CH_SW_PICTURE, BUGSMINI_FLAG_PICTURE)
|
||||
| GET_FLAG(BUGSMINI_CH_SW_VIDEO, BUGSMINI_FLAG_VIDEO);
|
||||
if(armed)
|
||||
packet[12] |= GET_FLAG(BUGSMINI_CH_SW_FLIP, BUGSMINI_FLAG_FLIP);
|
||||
packet[13] = arm_flags
|
||||
| GET_FLAG(BUGSMINI_CH_SW_LED, BUGSMINI_FLAG_LED)
|
||||
| GET_FLAG(BUGSMINI_CH_SW_ALTHOLD, BUGSMINI_FLAG_ALTHOLD)
|
||||
| GET_FLAG(BUGSMINI_CH_SW_ANGLE, BUGSMINI_FLAG_ANGLE);
|
||||
// BUGS3H althold -> BUGSMINI_FLAG_ALTHOLD|BUGSMINI_FLAG_ANGLE , angle -> 0
|
||||
packet[14] = 0;
|
||||
packet[15] = 0; // a lot of 0x53 and some 0x52 on bugs 3H
|
||||
}
|
||||
uint8_t checksum = 0x6d;
|
||||
for(uint8_t i=1; i < BUGSMINI_TX_PAYLOAD_SIZE; i++)
|
||||
checksum ^= packet[i];
|
||||
packet[0] = checksum;
|
||||
|
||||
if(!(packet[12]&0x40))
|
||||
{
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no >= BUGSMINI_NUM_RF_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
XN297_Hopping(IS_BIND_IN_PROGRESS ? hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS : hopping_frequency_no);
|
||||
}
|
||||
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, BUGSMINI_TX_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
// compute final address for the rxid received during bind
|
||||
// thanks to Pascal for the function!
|
||||
const uint8_t PROGMEM BUGSMINI_end []= {
|
||||
0x2d,0x9e ,0x95,0xa4 ,0x9c,0x5c ,0xb4,0xa6 ,0xa9,0xce ,0x56,0x2b ,0x3e,0x73 ,0xb8,0x95 ,0x6a,0x82,
|
||||
0x94,0x37 ,0x3d,0x5a ,0x4b,0xb2 ,0x69,0x49 ,0xc2,0x24 ,0x6b,0x3d ,0x23,0xc6 ,0x9e,0xa3 ,0xa4,0x98,
|
||||
0x5c,0x9e ,0xa6,0x52 ,0xce,0x76 ,0x2b,0x4b ,0x73,0x3a };
|
||||
static void __attribute__((unused)) BUGSMINI_make_address()
|
||||
{
|
||||
uint8_t start, length, index;
|
||||
|
||||
//read rxid
|
||||
uint8_t base_adr=BUGSMINI_EEPROM_OFFSET+(RX_num&0x0F)*2;
|
||||
uint8_t rxid_high = eeprom_read_byte((EE_ADDR)(base_adr+0));
|
||||
uint8_t rxid_low = eeprom_read_byte((EE_ADDR)(base_adr+1));
|
||||
|
||||
if(rxid_high==0x00 || rxid_high==0xFF)
|
||||
rx_tx_addr[0]=0x52;
|
||||
else
|
||||
rx_tx_addr[0]=rxid_high;
|
||||
|
||||
rx_tx_addr[1]=BUGSMINI_txhash;
|
||||
|
||||
if(rxid_low==0x00 || rxid_low==0xFF)
|
||||
rx_tx_addr[2]=0x66;
|
||||
else
|
||||
rx_tx_addr[2]=rxid_low;
|
||||
|
||||
for(uint8_t end_idx=0;end_idx<23;end_idx++)
|
||||
{
|
||||
//calculate sequence start
|
||||
if(end_idx<=7)
|
||||
start=end_idx;
|
||||
else
|
||||
start=(end_idx-7)*16+7;
|
||||
//calculate sequence length
|
||||
if(end_idx>6)
|
||||
{
|
||||
if(end_idx>15)
|
||||
length=(23-end_idx)<<1;
|
||||
else
|
||||
length=16;
|
||||
}
|
||||
else
|
||||
length=(end_idx+1)<<1;
|
||||
//calculate first index
|
||||
index=start-rxid_high;
|
||||
//scan for a possible match using the current end
|
||||
for(uint8_t i=0;i<length;i++)
|
||||
{
|
||||
if(index==rxid_low)
|
||||
{ //match found
|
||||
rx_tx_addr[3]=pgm_read_byte_near( &BUGSMINI_end[end_idx<<1] );
|
||||
rx_tx_addr[4]=pgm_read_byte_near( &BUGSMINI_end[(end_idx<<1)+1] );
|
||||
return;
|
||||
}
|
||||
index+=i&1?7:8; //increment index
|
||||
}
|
||||
}
|
||||
// Something wrong happened if we arrive here....
|
||||
}
|
||||
|
||||
#if defined(BUGS_HUB_TELEMETRY)
|
||||
static void __attribute__((unused)) BUGSMINI_update_telemetry()
|
||||
{
|
||||
uint8_t checksum = 0x6d;
|
||||
for(uint8_t i=1; i<12; i++)
|
||||
checksum += packet_in[i];
|
||||
if(packet_in[0] == checksum)
|
||||
{
|
||||
RX_RSSI = packet_in[3];
|
||||
if(sub_protocol==BUGS3H)
|
||||
{
|
||||
if(packet_in[11] & 0x40)
|
||||
v_lipo1 = 0x40; // Warning
|
||||
else if(packet_in[11] & 0x80)
|
||||
v_lipo1 = 0x20; // Critical
|
||||
else
|
||||
v_lipo1 = 0x80; // Ok
|
||||
}
|
||||
else
|
||||
{
|
||||
if(packet_in[11] & 0x80)
|
||||
v_lipo1 = 0x80; // Ok
|
||||
else if(packet_in[11] & 0x40)
|
||||
v_lipo1 = 0x40; // Warning
|
||||
else
|
||||
v_lipo1 = 0x20; // Critical
|
||||
}
|
||||
telemetry_link=1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t BUGSMINI_callback()
|
||||
{
|
||||
uint8_t base_adr;
|
||||
switch(phase)
|
||||
{
|
||||
case BUGSMINI_BIND1:
|
||||
if( XN297_IsRX() )
|
||||
{ // RX fifo data ready
|
||||
XN297_ReadPayload(packet, BUGSMINI_RX_PAYLOAD_SIZE); // Not checking the CRC??
|
||||
base_adr=BUGSMINI_EEPROM_OFFSET+(RX_num&0x0F)*2;
|
||||
eeprom_write_byte((EE_ADDR)(base_adr+0),packet[1]); // Save rxid in EEPROM
|
||||
eeprom_write_byte((EE_ADDR)(base_adr+1),packet[2]); // Save rxid in EEPROM
|
||||
BUGSMINI_make_address();
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
XN297_SetRXAddr(rx_tx_addr, BUGSMINI_RX_PAYLOAD_SIZE);
|
||||
phase = BUGSMINI_DATA1;
|
||||
BIND_DONE;
|
||||
break;
|
||||
}
|
||||
BUGSMINI_send_packet();
|
||||
phase = BUGSMINI_BIND2;
|
||||
return BUGSMINI_WRITE_WAIT;
|
||||
case BUGSMINI_BIND2:
|
||||
// switch to RX mode
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
phase = BUGSMINI_BIND1;
|
||||
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
|
||||
case BUGSMINI_DATA1:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(BUGSMINI_PACKET_INTERVAL);
|
||||
#endif
|
||||
#if defined(BUGS_HUB_TELEMETRY)
|
||||
if( XN297_IsRX() )
|
||||
{
|
||||
XN297_ReadPayload(packet_in, BUGSMINI_RX_PAYLOAD_SIZE); // Not checking the CRC??
|
||||
BUGSMINI_update_telemetry();
|
||||
}
|
||||
#endif
|
||||
BUGSMINI_send_packet();
|
||||
#if not defined(BUGS_HUB_TELEMETRY)
|
||||
break;
|
||||
#else
|
||||
phase = BUGSMINI_DATA2;
|
||||
return BUGSMINI_WRITE_WAIT;
|
||||
case BUGSMINI_DATA2:
|
||||
// switch to RX mode
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
phase = BUGSMINI_DATA1;
|
||||
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
|
||||
#endif
|
||||
}
|
||||
return BUGSMINI_PACKET_INTERVAL;
|
||||
}
|
||||
|
||||
#define BUGSMINI_NUM_TX_RF_MAPS 4
|
||||
// haven't figured out BUGSMINI_txid<-->rf channel mapping yet
|
||||
const uint8_t PROGMEM BUGSMINI_RF_chans[BUGSMINI_NUM_TX_RF_MAPS][BUGSMINI_NUM_RF_CHANNELS] = {
|
||||
{0x22,0x2f,0x3a,0x14,0x20,0x2d,0x38,0x18,0x26,0x32,0x11,0x1d,0x29,0x35,0x17},
|
||||
{0x3d,0x34,0x2b,0x22,0x19,0x40,0x37,0x2e,0x25,0x1c,0x3a,0x31,0x28,0x1f,0x16},
|
||||
{0x12,0x20,0x2f,0x1a,0x28,0x38,0x14,0x23,0x32,0x1c,0x2c,0x3b,0x17,0x26,0x34},
|
||||
{0x13,0x25,0x37,0x1F,0x31,0x17,0x28,0x3A,0x1C,0x2E,0x22,0x33,0x19,0x2B,0x3D} };
|
||||
const uint8_t PROGMEM BUGSMINI_bind_chans[BUGSMINI_NUM_RF_CHANNELS] = {
|
||||
0x1A,0x23,0x2C,0x35,0x3E,0x17,0x20,0x29,0x32,0x3B,0x14,0x1D,0x26,0x2F,0x38}; // bugs 3 mini bind channels
|
||||
const uint8_t PROGMEM BUGSMINI_tx_id[BUGSMINI_NUM_TX_RF_MAPS][3] = {
|
||||
{0xA8,0xE6,0x32},
|
||||
{0xdd,0xab,0xfd},
|
||||
{0x90,0x9e,0x4a},
|
||||
{0x20,0x28,0xBA} };
|
||||
const uint8_t PROGMEM BUGSMINI_tx_hash[BUGSMINI_NUM_TX_RF_MAPS] = { // 2nd byte of final address
|
||||
0x6c,0x9e,0x3d,0xb3};
|
||||
|
||||
static void __attribute__((unused)) BUGSMINI_initialize_txid()
|
||||
{
|
||||
// load hopping_frequency with tx channels in low part and bind channels in high part
|
||||
for(uint8_t i=0; i<BUGSMINI_NUM_RF_CHANNELS;i++)
|
||||
{
|
||||
hopping_frequency[i]=pgm_read_byte_near( &BUGSMINI_RF_chans[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS][i] );
|
||||
hopping_frequency[i+BUGSMINI_NUM_RF_CHANNELS]=pgm_read_byte_near( &BUGSMINI_bind_chans[i] );
|
||||
}
|
||||
// load txid
|
||||
for(uint8_t i=0; i<sizeof(BUGSMINI_txid);i++)
|
||||
BUGSMINI_txid[i]=pgm_read_byte_near( &BUGSMINI_tx_id[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS][i] );
|
||||
//load tx_hash
|
||||
BUGSMINI_txhash = pgm_read_byte_near( &BUGSMINI_tx_hash[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS] );
|
||||
}
|
||||
|
||||
void BUGSMINI_init()
|
||||
{
|
||||
BUGSMINI_initialize_txid();
|
||||
BUGSMINI_RF_init();
|
||||
memset(packet, (uint8_t)0, BUGSMINI_TX_PAYLOAD_SIZE);
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
XN297_SetTXAddr((const uint8_t*)"mjxRC", 5);
|
||||
XN297_SetRXAddr((const uint8_t*)"mjxRC", BUGSMINI_RX_PAYLOAD_SIZE);
|
||||
phase = BUGSMINI_BIND1;
|
||||
}
|
||||
else
|
||||
{
|
||||
BUGSMINI_make_address();
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
XN297_SetRXAddr(rx_tx_addr, BUGSMINI_RX_PAYLOAD_SIZE);
|
||||
phase = BUGSMINI_DATA1;
|
||||
}
|
||||
armed = 0;
|
||||
arm_flags = BUGSMINI_FLAG_DISARM; // initial value from captures
|
||||
arm_channel_previous = BUGSMINI_CH_SW_ARM;
|
||||
}
|
||||
|
||||
#endif
|
||||
204
Multiprotocol/Bayang_Rx_nrf24l01.ino
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(BAYANG_RX_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define BAYANG_RX_PACKET_SIZE 15
|
||||
#define BAYANG_RX_RF_NUM_CHANNELS 4
|
||||
#define BAYANG_RX_RF_BIND_CHANNEL 0
|
||||
#define BAYANG_RX_ADDRESS_LENGTH 5
|
||||
|
||||
enum {
|
||||
BAYANG_RX_BIND = 0,
|
||||
BAYANG_RX_DATA
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) Bayang_Rx_RF_init()
|
||||
{
|
||||
const uint8_t bind_address[BAYANG_RX_ADDRESS_LENGTH] = { 0,0,0,0,0 };
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
XN297_SetTXAddr(bind_address, BAYANG_RX_ADDRESS_LENGTH);
|
||||
XN297_SetRXAddr(bind_address, BAYANG_RX_PACKET_SIZE);
|
||||
XN297_RFChannel(BAYANG_RX_RF_BIND_CHANNEL);
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) Bayang_Rx_check_validity() {
|
||||
uint8_t sum = packet[0];
|
||||
for (uint8_t i = 1; i < BAYANG_RX_PACKET_SIZE - 1; i++)
|
||||
sum += packet[i];
|
||||
return sum == packet[14];
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) Bayang_Rx_build_telemetry_packet()
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
uint8_t bitsavailable = 0;
|
||||
uint8_t idx = 0;
|
||||
|
||||
packet_in[idx++] = RX_LQI;
|
||||
packet_in[idx++] = RX_LQI>>1; // no RSSI: 125..0
|
||||
packet_in[idx++] = 0; // start channel
|
||||
packet_in[idx++] = 10; // number of channels in packet
|
||||
|
||||
// convert & pack channels
|
||||
for (uint8_t i = 0; i < packet_in[3]; i++) {
|
||||
uint32_t val = CHANNEL_MIN_100;
|
||||
if (i < 4) {
|
||||
// AETR
|
||||
//val = (((packet[4 + i * 2] & ~0x7C) << 8) | packet[5 + i * 2]) << 1;
|
||||
val=packet[4 + i * 2]&0x03;
|
||||
val=(val<<8)+packet[5 + i * 2];
|
||||
val=((val+128)<<3)/5;
|
||||
} else if (i == 4 || i == 5) {
|
||||
val=packet[i==4?1:13];
|
||||
val=((val+32)<<5)/5; // extra analog channel
|
||||
} else if (((i == 6) && (packet[2] & 0x08)) || // flip
|
||||
((i == 7) && (packet[2] & 0x01)) || // rth
|
||||
((i == 8) && (packet[2] & 0x20)) || // picture
|
||||
((i == 9) && (packet[2] & 0x10))) { // video
|
||||
// set channel to 100% if feature is enabled
|
||||
val = CHANNEL_MAX_100;
|
||||
}
|
||||
bits |= val << bitsavailable;
|
||||
bitsavailable += 11;
|
||||
while (bitsavailable >= 8) {
|
||||
packet_in[idx++] = bits & 0xff;
|
||||
bits >>= 8;
|
||||
bitsavailable -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BAYANG_RX_init()
|
||||
{
|
||||
uint8_t i;
|
||||
Bayang_Rx_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
rx_data_started = false;
|
||||
rx_data_received = false;
|
||||
|
||||
if (IS_BIND_IN_PROGRESS) {
|
||||
phase = BAYANG_RX_BIND;
|
||||
}
|
||||
else {
|
||||
uint16_t temp = BAYANG_RX_EEPROM_OFFSET;
|
||||
for (i = 0; i < 5; i++)
|
||||
rx_tx_addr[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
for (i = 0; i < BAYANG_RX_RF_NUM_CHANNELS; i++)
|
||||
hopping_frequency[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
//XN297_HoppingCalib(BAYANG_RX_RF_NUM_CHANNELS);
|
||||
XN297_SetTXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
|
||||
XN297_SetRXAddr(rx_tx_addr, BAYANG_RX_PACKET_SIZE);
|
||||
phase = BAYANG_RX_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t BAYANG_RX_callback()
|
||||
{
|
||||
uint8_t i;
|
||||
static int8_t read_retry;
|
||||
|
||||
switch (phase)
|
||||
{
|
||||
case BAYANG_RX_BIND:
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
BAYANG_RX_init(); // Abort bind
|
||||
break;
|
||||
}
|
||||
if ( XN297_IsRX() )
|
||||
{
|
||||
debugln("RX");
|
||||
// data received from TX
|
||||
if (XN297_ReadPayload(packet, BAYANG_RX_PACKET_SIZE) && ( packet[0] == 0xA4 || packet[0] == 0xA2 ) && Bayang_Rx_check_validity())
|
||||
{
|
||||
// store tx info into eeprom
|
||||
uint16_t temp = BAYANG_RX_EEPROM_OFFSET;
|
||||
for (i = 0; i < 5; i++) {
|
||||
rx_tx_addr[i] = packet[i + 1];
|
||||
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[i]);
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
hopping_frequency[i] = packet[i + 6];
|
||||
eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[i]);
|
||||
}
|
||||
//XN297_HoppingCalib(BAYANG_RX_RF_NUM_CHANNELS);
|
||||
XN297_SetTXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
|
||||
XN297_SetRXAddr(rx_tx_addr, BAYANG_RX_PACKET_SIZE);
|
||||
BIND_DONE;
|
||||
phase = BAYANG_RX_DATA;
|
||||
}
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
}
|
||||
break;
|
||||
case BAYANG_RX_DATA:
|
||||
if ( XN297_IsRX() ) {
|
||||
if (XN297_ReadPayload(packet, BAYANG_RX_PACKET_SIZE) && packet[0] == 0xA5 && Bayang_Rx_check_validity()) {
|
||||
if ((telemetry_link & 0x7F) == 0) {
|
||||
Bayang_Rx_build_telemetry_packet();
|
||||
telemetry_link = 1;
|
||||
#ifdef SEND_CPPM
|
||||
if(sub_protocol>0)
|
||||
telemetry_link |= 0x80; // Disable telemetry output
|
||||
#endif
|
||||
}
|
||||
rx_data_started = true;
|
||||
rx_data_received = true;
|
||||
read_retry = 8;
|
||||
pps_counter++;
|
||||
}
|
||||
}
|
||||
// packets per second
|
||||
if (millis() - pps_timer >= 1000) {
|
||||
pps_timer = millis();
|
||||
debugln("%d pps", pps_counter);
|
||||
RX_LQI = pps_counter >> 1;
|
||||
pps_counter = 0;
|
||||
}
|
||||
// frequency hopping
|
||||
if (read_retry++ >= 8) {
|
||||
hopping_frequency_no++;
|
||||
if (hopping_frequency_no >= BAYANG_RX_RF_NUM_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
XN297_Hopping(hopping_frequency_no);
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
if (rx_data_started)
|
||||
{
|
||||
if(rx_data_received)
|
||||
{ // In sync
|
||||
rx_data_received = false;
|
||||
read_retry = 5;
|
||||
return 1500;
|
||||
}
|
||||
else
|
||||
{ // packet lost
|
||||
read_retry = 0;
|
||||
if(RX_LQI==0) // communication lost
|
||||
rx_data_started=false;
|
||||
}
|
||||
}
|
||||
else
|
||||
read_retry = -16; // retry longer until first packet is caught
|
||||
}
|
||||
return 250;
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -17,154 +17,332 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
|
||||
#if defined(BAYANG_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define BAYANG_BIND_COUNT 1000
|
||||
#define BAYANG_PACKET_PERIOD 2000
|
||||
#define BAYANG_PACKET_TELEM_PERIOD 5000
|
||||
#define BAYANG_INITIAL_WAIT 500
|
||||
#define BAYANG_PACKET_SIZE 15
|
||||
#define BAYANG_RF_NUM_CHANNELS 4
|
||||
#define BAYANG_RF_BIND_CHANNEL 0
|
||||
#define BAYANG_RF_BIND_CHANNEL_X16_AH 10
|
||||
#define BAYANG_ADDRESS_LENGTH 5
|
||||
|
||||
enum BAYANG_FLAGS {
|
||||
// flags going to packet[2]
|
||||
BAYANG_FLAG_RTH = 0x01,
|
||||
BAYANG_FLAG_HEADLESS = 0x02,
|
||||
BAYANG_FLAG_FLIP = 0x08,
|
||||
BAYANG_FLAG_VIDEO = 0x10,
|
||||
BAYANG_FLAG_PICTURE = 0x20,
|
||||
// flags going to packet[3]
|
||||
BAYANG_FLAG_INVERTED = 0x80 // inverted flight on Floureon H101
|
||||
// flags going to packet[2]
|
||||
BAYANG_FLAG_RTH = 0x01,
|
||||
BAYANG_FLAG_HEADLESS = 0x02,
|
||||
BAYANG_FLAG_FLIP = 0x08,
|
||||
BAYANG_FLAG_VIDEO = 0x10,
|
||||
BAYANG_FLAG_PICTURE = 0x20,
|
||||
// flags going to packet[3]
|
||||
BAYANG_FLAG_INVERTED = 0x80, // inverted flight on Floureon H101
|
||||
BAYANG_FLAG_TAKE_OFF = 0x20, // take off / landing on X16 AH
|
||||
BAYANG_FLAG_EMG_STOP = 0x04|0x08, // 0x08 for VISUO XS809H-W-HD-G
|
||||
};
|
||||
|
||||
static void BAYANG_send_packet(uint8_t bind)
|
||||
enum BAYANG_OPTION_FLAGS {
|
||||
BAYANG_OPTION_FLAG_TELEMETRY = 0x01,
|
||||
BAYANG_OPTION_FLAG_ANALOGAUX = 0x02,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) BAYANG_send_packet()
|
||||
{
|
||||
uint8_t i;
|
||||
if (bind)
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[0]= 0xA4;
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
if(option & BAYANG_OPTION_FLAG_TELEMETRY)
|
||||
if(option & BAYANG_OPTION_FLAG_ANALOGAUX)
|
||||
packet[0]= 0xA1; // telemetry and analog aux are enabled
|
||||
else
|
||||
packet[0]= 0xA3; // telemetry is enabled
|
||||
else if(option & BAYANG_OPTION_FLAG_ANALOGAUX)
|
||||
packet[0]= 0xA2; // analog aux is enabled
|
||||
else
|
||||
#else
|
||||
if(option & BAYANG_OPTION_FLAG_ANALOGAUX)
|
||||
packet[0]= 0xA2; // analog aux is enabled
|
||||
else
|
||||
#endif
|
||||
packet[0]= 0xA4;
|
||||
if(sub_protocol==QX100)
|
||||
packet[0] = 0x53;
|
||||
|
||||
for(i=0;i<5;i++)
|
||||
packet[i+1]=rx_tx_addr[i];
|
||||
for(i=0;i<4;i++)
|
||||
packet[i+6]=hopping_frequency[i];
|
||||
packet[10] = rx_tx_addr[0]; // txid[0]
|
||||
packet[11] = rx_tx_addr[1]; // txid[1]
|
||||
switch (sub_protocol)
|
||||
{
|
||||
case QX100:
|
||||
case X16_AH:
|
||||
packet[10] = 0x00;
|
||||
packet[11] = 0x00;
|
||||
break;
|
||||
case IRDRONE:
|
||||
packet[10] = 0x30;
|
||||
packet[11] = 0x01;
|
||||
break;
|
||||
case DHD_D4:
|
||||
packet[10] = 0xC8;
|
||||
packet[11] = 0x99;
|
||||
break;
|
||||
default:
|
||||
packet[10] = rx_tx_addr[0]; // txid[0]
|
||||
packet[11] = rx_tx_addr[1]; // txid[1]
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
hopping_frequency_no%=BAYANG_RF_NUM_CHANNELS;
|
||||
uint16_t val;
|
||||
packet[0] = 0xA5;
|
||||
packet[1] = 0xFA; // normal mode is 0xf7, expert 0xfa
|
||||
uint8_t dyntrim = 1;
|
||||
switch (sub_protocol)
|
||||
{
|
||||
case X16_AH:
|
||||
case IRDRONE:
|
||||
packet[0] = 0xA6;
|
||||
break;
|
||||
default:
|
||||
packet[0] = 0xA5;
|
||||
break;
|
||||
}
|
||||
if (option & BAYANG_OPTION_FLAG_ANALOGAUX)
|
||||
{
|
||||
// Analog aux channel 1 (channel 14)
|
||||
packet[1] = convert_channel_8b(CH14);
|
||||
}
|
||||
else
|
||||
packet[1] = 0xFA; // normal mode is 0xF7, expert 0xFa , D4 normal is 0xF4
|
||||
|
||||
//Flags packet[2]
|
||||
packet[2] = 0x00;
|
||||
if(Servo_AUX1)
|
||||
if(CH5_SW)
|
||||
packet[2] = BAYANG_FLAG_FLIP;
|
||||
if(Servo_AUX2)
|
||||
if(CH6_SW)
|
||||
packet[2] |= BAYANG_FLAG_RTH;
|
||||
if(Servo_AUX3)
|
||||
if(CH7_SW)
|
||||
packet[2] |= BAYANG_FLAG_PICTURE;
|
||||
if(Servo_AUX4)
|
||||
if(CH8_SW)
|
||||
packet[2] |= BAYANG_FLAG_VIDEO;
|
||||
if(Servo_AUX5)
|
||||
if(CH9_SW)
|
||||
{
|
||||
packet[2] |= BAYANG_FLAG_HEADLESS;
|
||||
dyntrim = 0;
|
||||
}
|
||||
//Flags packet[3]
|
||||
packet[3] = 0x00;
|
||||
if(Servo_AUX6)
|
||||
if(CH10_SW)
|
||||
packet[3] = BAYANG_FLAG_INVERTED;
|
||||
|
||||
if(CH11_SW)
|
||||
dyntrim = 0;
|
||||
if(CH12_SW)
|
||||
packet[3] |= BAYANG_FLAG_TAKE_OFF;
|
||||
if(CH13_SW)
|
||||
packet[3] |= BAYANG_FLAG_EMG_STOP;
|
||||
//Aileron
|
||||
val = convert_channel_10b(AILERON);
|
||||
packet[4] = (val>>8) + ((val>>2) & 0xFC);
|
||||
val = convert_channel_10b(AILERON, false);
|
||||
packet[4] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
|
||||
packet[5] = val & 0xFF;
|
||||
//Elevator
|
||||
val = convert_channel_10b(ELEVATOR);
|
||||
packet[6] = (val>>8) + ((val>>2) & 0xFC);
|
||||
val = convert_channel_10b(ELEVATOR, false);
|
||||
packet[6] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
|
||||
packet[7] = val & 0xFF;
|
||||
//Throttle
|
||||
val = convert_channel_10b(THROTTLE);
|
||||
val = convert_channel_10b(THROTTLE, false);
|
||||
packet[8] = (val>>8) + 0x7C;
|
||||
packet[9] = val & 0xFF;
|
||||
//Rudder
|
||||
val = convert_channel_10b(RUDDER);
|
||||
packet[10] = (val>>8) + (val>>2 & 0xFC);
|
||||
val = convert_channel_10b(RUDDER, false);
|
||||
packet[10] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
|
||||
packet[11] = val & 0xFF;
|
||||
}
|
||||
packet[12] = rx_tx_addr[2]; // txid[2]
|
||||
packet[13] = 0x0A;
|
||||
switch (sub_protocol)
|
||||
{
|
||||
case H8S3D:
|
||||
packet[12] = rx_tx_addr[2]; // txid[2]
|
||||
packet[13] = 0x34;
|
||||
break;
|
||||
case QX100:
|
||||
case X16_AH:
|
||||
packet[12] = 0;
|
||||
packet[13] = 0;
|
||||
break;
|
||||
case IRDRONE:
|
||||
packet[12] = 0xE0;
|
||||
packet[13] = 0x2E;
|
||||
break;
|
||||
case DHD_D4:
|
||||
packet[12] = 0x37; //0x17 during bind
|
||||
packet[13] = 0xED;
|
||||
break;
|
||||
default:
|
||||
packet[12] = rx_tx_addr[2]; // txid[2]
|
||||
if (option & BAYANG_OPTION_FLAG_ANALOGAUX)
|
||||
{ // Analog aux channel 2 (channel 15)
|
||||
packet[13] = convert_channel_8b(CH15);
|
||||
}
|
||||
else
|
||||
packet[13] = 0x0A;
|
||||
break;
|
||||
}
|
||||
packet[14] = 0;
|
||||
for (uint8_t i=0; i < BAYANG_PACKET_SIZE-1; i++)
|
||||
for (uint8_t i=0; i < BAYANG_PACKET_SIZE-1; i++)
|
||||
packet[14] += packet[i];
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? BAYANG_RF_BIND_CHANNEL:hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no%=BAYANG_RF_NUM_CHANNELS;
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, BAYANG_PACKET_SIZE);
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void BAYANG_init()
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
static void __attribute__((unused)) BAYANG_check_rx(void)
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
XN297_SetTXAddr((uint8_t *)"\x00\x00\x00\x00\x00", BAYANG_ADDRESS_LENGTH);
|
||||
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
if( XN297_IsRX() )
|
||||
{ // data received from model
|
||||
XN297_ReadPayload(packet, BAYANG_PACKET_SIZE); // Strange can't test the CRC since it seems to be disabled on telemetry packets...
|
||||
uint8_t check = packet[0];
|
||||
for (uint8_t i=1; i < BAYANG_PACKET_SIZE-1; i++)
|
||||
check += packet[i];
|
||||
// decode data , check sum is ok as well, since there is no crc
|
||||
if (packet[0] == 0x85 && packet[14] == check && telemetry_link == 0)
|
||||
{
|
||||
// uncompensated battery volts*100/2
|
||||
v_lipo1 = (packet[3]<<7) + (packet[4]>>1);
|
||||
// compensated battery volts*100/2
|
||||
v_lipo2 = (packet[5]<<7) + (packet[6]>>1);
|
||||
// reception in packets / sec
|
||||
RX_LQI = packet[7];
|
||||
RX_RSSI = RX_LQI;
|
||||
//Flags
|
||||
//uint8_t flags = packet[3] >> 3;
|
||||
// battery low: flags & 1
|
||||
telemetry_link=1;
|
||||
#if defined HUB_TELEMETRY
|
||||
// Multiplexed P, I, D values in packet[8] and packet[9].
|
||||
// The two most significant bits specify which term is sent.
|
||||
// Remaining 14 bits represent the value: 0 .. 16383
|
||||
frsky_send_user_frame(0x24+(packet[8]>>6), packet[9], packet[8] & 0x3F ); //0x24 = ACCEL_X_ID, so ACCEL_X_ID=P, ACCEL_Y_ID=I, ACCEL_Z_ID=D
|
||||
#endif
|
||||
telemetry_counter++;
|
||||
if(telemetry_lost)
|
||||
telemetry_link=0; // Don't send anything yet
|
||||
}
|
||||
}
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __attribute__((unused)) BAYANG_RF_init()
|
||||
{
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
XN297_SetTXAddr((uint8_t *)"\x00\x00\x00\x00\x00", BAYANG_ADDRESS_LENGTH);
|
||||
//XN297_HoppingCalib(BAYANG_RF_NUM_CHANNELS);
|
||||
|
||||
//Set bind channel
|
||||
uint8_t ch = BAYANG_RF_BIND_CHANNEL;
|
||||
if(sub_protocol == X16_AH || sub_protocol == IRDRONE)
|
||||
ch = BAYANG_RF_BIND_CHANNEL_X16_AH;
|
||||
XN297_RFChannel(ch);
|
||||
}
|
||||
|
||||
enum {
|
||||
BAYANG_BIND=0,
|
||||
BAYANG_WRITE,
|
||||
BAYANG_CHECK,
|
||||
BAYANG_READ,
|
||||
};
|
||||
|
||||
#define BAYANG_CHECK_DELAY 1000 // Time after write phase to check write complete
|
||||
#define BAYANG_READ_DELAY 600 // Time before read phase
|
||||
|
||||
uint16_t BAYANG_callback()
|
||||
{
|
||||
if(IS_BIND_DONE_on)
|
||||
BAYANG_send_packet(0);
|
||||
else
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
uint16_t start;
|
||||
#endif
|
||||
switch(phase)
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
BAYANG_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
case BAYANG_BIND:
|
||||
if (--bind_counter == 0)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
XN297_SetRXAddr(rx_tx_addr, BAYANG_PACKET_SIZE);
|
||||
#endif
|
||||
BIND_DONE;
|
||||
phase++; //WRITE
|
||||
}
|
||||
else
|
||||
BAYANG_send_packet();
|
||||
break;
|
||||
case BAYANG_WRITE:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync((option & BAYANG_OPTION_FLAG_TELEMETRY)?BAYANG_PACKET_TELEM_PERIOD:BAYANG_PACKET_PERIOD);
|
||||
#endif
|
||||
BAYANG_send_packet();
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
if (option & BAYANG_OPTION_FLAG_TELEMETRY)
|
||||
{ // telemetry is enabled
|
||||
state++;
|
||||
if (state > 200)
|
||||
{
|
||||
state = 0;
|
||||
//telemetry reception packet rate - packets per second
|
||||
TX_LQI = telemetry_counter>>1;
|
||||
telemetry_counter = 0;
|
||||
telemetry_lost=0;
|
||||
}
|
||||
phase++; //CHECK
|
||||
return BAYANG_CHECK_DELAY;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
case BAYANG_CHECK:
|
||||
// switch radio to rx as soon as packet is sent
|
||||
start=(uint16_t)micros();
|
||||
while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 1000) // Wait max 1ms
|
||||
if(XN297_IsPacketSent())
|
||||
break;
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
phase++; // READ
|
||||
return BAYANG_PACKET_TELEM_PERIOD - BAYANG_CHECK_DELAY - BAYANG_READ_DELAY;
|
||||
case BAYANG_READ:
|
||||
BAYANG_check_rx();
|
||||
phase=BAYANG_WRITE;
|
||||
return BAYANG_READ_DELAY;
|
||||
#endif
|
||||
}
|
||||
return BAYANG_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
static void BAYANG_initialize_txid()
|
||||
static void __attribute__((unused)) BAYANG_initialize_txid()
|
||||
{
|
||||
//Could be using txid[0..2] but using rx_tx_addr everywhere instead...
|
||||
hopping_frequency[0]=0;
|
||||
hopping_frequency[1]=(rx_tx_addr[0]&0x1F)+0x10;
|
||||
if(sub_protocol==DHD_D4)
|
||||
hopping_frequency[0]=(rx_tx_addr[2]&0x07)|0x01;
|
||||
else
|
||||
hopping_frequency[0]=0;
|
||||
hopping_frequency[1]=(rx_tx_addr[3]&0x1F)+0x10;
|
||||
hopping_frequency[2]=hopping_frequency[1]+0x20;
|
||||
hopping_frequency[3]=hopping_frequency[2]+0x20;
|
||||
hopping_frequency_no=0;
|
||||
}
|
||||
|
||||
uint16_t initBAYANG(void)
|
||||
void BAYANG_init(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
phase=BAYANG_BIND;
|
||||
bind_counter = BAYANG_BIND_COUNT;
|
||||
BAYANG_initialize_txid();
|
||||
BAYANG_init();
|
||||
return BAYANG_INITIAL_WAIT+BAYANG_PACKET_PERIOD;
|
||||
BAYANG_RF_init();
|
||||
packet_count=0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
202
Multiprotocol/Binary_Signature.ino
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/************************/
|
||||
/** Firmware Signature **/
|
||||
/************************/
|
||||
|
||||
/*
|
||||
The firmware signature is appended to the compiled binary image in order to provide information
|
||||
about the options used to compile the firmware file. This information is then used by Multi-module
|
||||
flashing tools to verify that the image is correct / valid.
|
||||
|
||||
In order for the build process to determine the options used to build the firmware this file conditionally
|
||||
declares 'flag' variables for the options we are interested in.
|
||||
|
||||
When the pre-compiler parses the source code these variables are either present or not in the parsed cpp file,
|
||||
typically '$build_dir$/preproc/ctags_target_for_gcc_minus_e.cpp'.
|
||||
|
||||
Once the .bin file is created an additional command-line build tool scans the parsed cpp file, detects the
|
||||
flags, assembles the signature, and finally appends the signature to the end of the binary file.
|
||||
|
||||
The signature is 24 bytes long:
|
||||
multi-x[8-byte hex code]-[8-byte version number]
|
||||
|
||||
For example:
|
||||
multi-x1234abcd-01020199
|
||||
|
||||
The 8-byte hex code is a 32-bit bitmask value indicating the configuration options, currently:
|
||||
|
||||
Bit(s) Bitmask Option Comment
|
||||
1-2 0x3 Module type Read as a two-bit value indicating a number from 0-3 which maps to a module type (AVR, STM32, OrangeRX)
|
||||
3-7 0x7C Channel order Read as a five-bit value indicating a number from 0-23 which maps to as channel order (AETR, TAER, RETA, etc) (right-shift two bits to read)
|
||||
8 0x80 Bootloader support Indicates whether or not the firmware was built with support for the bootloader
|
||||
9 0x100 CHECK_FOR_BOOTLOADER Indicates if CHECK_FOR_BOOTLOADER is defined
|
||||
10 0x200 INVERT_TELEMETRY Indicates if INVERT_TELEMETRY is defined
|
||||
11 0x400 MULTI_STATUS Indicates if MULTI_STATUS is defined
|
||||
12 0x800 MULTI_TELEMETRY Indicates if MULTI_TELEMETRY is defined
|
||||
13 0x1000 DEBUG_SERIAL Indicates if DEBUG_SERIAL is defined
|
||||
14-16 0xE000 Module sub-type Reads as a three-bit value indicating a number from 0-7 which maps to a module sub-type (right-shift 13 bits to read)
|
||||
|
||||
The 8-byte version number is the version number zero-padded to a fixed width of two-bytes per segment and no separator.
|
||||
E.g. 1.2.3.45 becomes 01020345.
|
||||
|
||||
Multi Telemetery Type can be read from bits 11 and 12 using the bitmask 0xC00 and right-shifting ten bits:
|
||||
Telemetry Type Decimal Value Binary Value
|
||||
Undefined 0 00
|
||||
erSkyTX 1 01
|
||||
OpenTX 2 10
|
||||
|
||||
Module types are mapped to the following decimal / binary values:
|
||||
Module Type Decimal Value Binary Valsue
|
||||
AVR (Atmega328p) 0 00
|
||||
STM32 (F103) 1 01
|
||||
OrangeRX (Xmega) 2 10
|
||||
|
||||
Module sub-type is currently used for STM32F103 only and is mapped as follows:
|
||||
Module Type Sub Type Decimal Value Binary Value
|
||||
STM32 (F103) STM32F103CB 0 000
|
||||
STM32 (F103) STM32F103C8 1 001
|
||||
STM32 (F103) T18 5in1 2 010
|
||||
|
||||
Channel orders are mapped to the following decimal / binary values:
|
||||
Channel Order Decimal Value Binary Value
|
||||
AETR 0 00000
|
||||
AERT 1 00001
|
||||
ARET 2 00010
|
||||
ARTE 3 00011
|
||||
ATRE 4 00100
|
||||
ATER 5 00101
|
||||
EATR 6 00110
|
||||
EART 7 00111
|
||||
ERAT 8 01000
|
||||
ERTA 9 01001
|
||||
ETRA 10 01010
|
||||
ETAR 11 01011
|
||||
TEAR 12 01100
|
||||
TERA 13 01101
|
||||
TREA 14 01110
|
||||
TRAE 15 01111
|
||||
TARE 16 10000
|
||||
TAER 17 10001
|
||||
RETA 18 10010
|
||||
REAT 19 10011
|
||||
RAET 20 10100
|
||||
RATE 21 10101
|
||||
RTAE 22 10110
|
||||
RTEA 23 10111
|
||||
*/
|
||||
|
||||
// Set the flags for detecting and writing the firmware signature
|
||||
#if defined (CHECK_FOR_BOOTLOADER)
|
||||
bool firmwareFlag_CHECK_FOR_BOOTLOADER = true;
|
||||
#endif
|
||||
#if defined (INVERT_TELEMETRY)
|
||||
bool firmwareFlag_INVERT_TELEMETRY = true;
|
||||
#endif
|
||||
#if defined (MULTI_STATUS)
|
||||
bool firmwareFlag_MULTI_STATUS = true;
|
||||
#endif
|
||||
#if defined (MULTI_TELEMETRY)
|
||||
bool firmwareFlag_MULTI_TELEMETRY = true;
|
||||
#endif
|
||||
#if defined (DEBUG_SERIAL)
|
||||
bool firmwareFlag_DEBUG_SERIAL = true;
|
||||
#endif
|
||||
|
||||
// STM32 Module sub-type flags
|
||||
#if defined (MCU_STM32F103CB)
|
||||
bool firmwareFlag_MCU_STM32F103CB = true;
|
||||
#endif
|
||||
#if defined (MCU_STM32F103C8)
|
||||
bool firmwareFlag_MCU_STM32F103C8 = true;
|
||||
#endif
|
||||
#if defined (MULTI_5IN1_INTERNAL)
|
||||
bool firmwareFlag_MULTI_5IN1_INTERNAL = true;
|
||||
#endif
|
||||
|
||||
// Channel order flags
|
||||
#if defined (AETR)
|
||||
bool firmwareFlag_ChannelOrder_AETR = true;
|
||||
#endif
|
||||
#if defined (AERT)
|
||||
bool firmwareFlag_ChannelOrder_AERT = true;
|
||||
#endif
|
||||
#if defined (ARET)
|
||||
bool firmwareFlag_ChannelOrder_ARET = true;
|
||||
#endif
|
||||
#if defined (ARTE)
|
||||
bool firmwareFlag_ChannelOrder_ARTE = true;
|
||||
#endif
|
||||
#if defined (ATRE)
|
||||
bool firmwareFlag_ChannelOrder_ATRE = true;
|
||||
#endif
|
||||
#if defined (ATER)
|
||||
bool firmwareFlag_ChannelOrder_ATER = true;
|
||||
#endif
|
||||
#if defined (EATR)
|
||||
bool firmwareFlag_ChannelOrder_EATR = true;
|
||||
#endif
|
||||
#if defined (EART)
|
||||
bool firmwareFlag_ChannelOrder_EART = true;
|
||||
#endif
|
||||
#if defined (ERAT)
|
||||
bool firmwareFlag_ChannelOrder_ERAT = true;
|
||||
#endif
|
||||
#if defined (ERTA)
|
||||
bool firmwareFlag_ChannelOrder_ERTA = true;
|
||||
#endif
|
||||
#if defined (ETRA)
|
||||
bool firmwareFlag_ChannelOrder_ETRA = true;
|
||||
#endif
|
||||
#if defined (ETAR)
|
||||
bool firmwareFlag_ChannelOrder_ETAR = true;
|
||||
#endif
|
||||
#if defined (TEAR)
|
||||
bool firmwareFlag_ChannelOrder_TEAR = true;
|
||||
#endif
|
||||
#if defined (TERA)
|
||||
bool firmwareFlag_ChannelOrder_TERA = true;
|
||||
#endif
|
||||
#if defined (TREA)
|
||||
bool firmwareFlag_ChannelOrder_TREA = true;
|
||||
#endif
|
||||
#if defined (TRAE)
|
||||
bool firmwareFlag_ChannelOrder_TRAE = true;
|
||||
#endif
|
||||
#if defined (TARE)
|
||||
bool firmwareFlag_ChannelOrder_TARE = true;
|
||||
#endif
|
||||
#if defined (TAER)
|
||||
bool firmwareFlag_ChannelOrder_TAER = true;
|
||||
#endif
|
||||
#if defined (RETA)
|
||||
bool firmwareFlag_ChannelOrder_RETA = true;
|
||||
#endif
|
||||
#if defined (REAT)
|
||||
bool firmwareFlag_ChannelOrder_REAT = true;
|
||||
#endif
|
||||
#if defined (RAET)
|
||||
bool firmwareFlag_ChannelOrder_RAET = true;
|
||||
#endif
|
||||
#if defined (RATE)
|
||||
bool firmwareFlag_ChannelOrder_RATE = true;
|
||||
#endif
|
||||
#if defined (RTAE)
|
||||
bool firmwareFlag_ChannelOrder_RTAE = true;
|
||||
#endif
|
||||
#if defined (RTEA)
|
||||
bool firmwareFlag_ChannelOrder_RTEA = true;
|
||||
#endif
|
||||
464
Multiprotocol/Bugs_a7105.ino
Normal file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef BUGS_A7105_INO
|
||||
|
||||
//////////// rxid -> radioid algorithm //////////////////////////////
|
||||
// Hex digit 1 is periodic with length 2, and hex digit 2 is periodic
|
||||
// with length 16. However, storing the byte of those 2 digits
|
||||
// instead of manipulating bits results simpler code and smaller binary.
|
||||
const uint8_t PROGMEM BUGS_most_popular_67_cycle[]= {
|
||||
0x34, 0xc5, 0x6a, 0xb4, 0x29, 0xd5, 0x2c, 0xd3, 0x91, 0xb3, 0x6c, 0x49,
|
||||
0x52, 0x9c, 0x4d, 0x65, 0xc3, 0x4a, 0x5b, 0xd6, 0x92, 0x6d, 0x94, 0xa6,
|
||||
0x55, 0xcd, 0x2b, 0x9a, 0x36, 0x95, 0x4b, 0xd4, 0x35, 0x8d, 0x96, 0xb2,
|
||||
0xa3 };
|
||||
|
||||
static uint8_t __attribute__((unused)) BUGS_most_popular_67(uint8_t i)
|
||||
{
|
||||
uint8_t ii;
|
||||
if (i == 0)
|
||||
return 0xd2;
|
||||
else if (i == 1)
|
||||
return 0xda;
|
||||
else if (i % 16 < 2)
|
||||
{
|
||||
ii = 2 * (i / 16) + i % 16 - 2;
|
||||
if (ii % 2 == 0)
|
||||
ii += 7;
|
||||
}
|
||||
else
|
||||
ii=2 * (i / 16) + (i % 16 - 2) % 7;
|
||||
return pgm_read_byte_near( &BUGS_most_popular_67_cycle[ii]);
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) BUGS_most_popular_45(uint8_t i)
|
||||
{
|
||||
if (i == 0)
|
||||
return 0xa3;
|
||||
else if (i == 1)
|
||||
return 0x86;
|
||||
else
|
||||
{
|
||||
if (i % 8 == 1)
|
||||
i -= 8;
|
||||
else
|
||||
i--;
|
||||
return BUGS_most_popular_67(i);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) BUGS_most_popular_23(uint8_t i)
|
||||
{
|
||||
if (i == 0)
|
||||
return 0xb2;
|
||||
else if (i == 1)
|
||||
return 0xcb;
|
||||
else
|
||||
{
|
||||
if (i % 8 == 1)
|
||||
i -= 8;
|
||||
else
|
||||
i--;
|
||||
return BUGS_most_popular_45(i);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM BUGS_most_popular_01[] = {
|
||||
0x52, 0xac, 0x59, 0xa4, 0x53, 0xab, 0x57, 0xa9,
|
||||
0x56, 0xa5, 0x5b, 0xa7, 0x5d, 0xa6, 0x58, 0xad};
|
||||
|
||||
static uint32_t __attribute__((unused)) BUGS_most_popular(uint8_t i)
|
||||
{
|
||||
i += !(i <= 127);
|
||||
uint8_t mp01=pgm_read_byte_near( &BUGS_most_popular_01[i % 16] );
|
||||
return (uint32_t) mp01 << 24 |
|
||||
(uint32_t) BUGS_most_popular_23(i) << 16 |
|
||||
(uint32_t) BUGS_most_popular_45(i) << 8 |
|
||||
BUGS_most_popular_67(i);
|
||||
}
|
||||
|
||||
static uint32_t __attribute__((unused)) BUGS_second_most_popular(uint8_t i)
|
||||
{
|
||||
if (i < 127)
|
||||
return BUGS_most_popular(i + 1);
|
||||
else if (i > 128)
|
||||
return BUGS_most_popular(i - 1);
|
||||
else
|
||||
return 0x52d6926d;
|
||||
}
|
||||
|
||||
// The 22 irregular values do not match the above periodicities. They might be
|
||||
// errors from the readout, but let us try them here as long as it is not
|
||||
// proven.
|
||||
#define BUGS_NBR_IRREGULAR 22
|
||||
const uint16_t PROGMEM BUGS_irregular_keys[BUGS_NBR_IRREGULAR] = {
|
||||
1131, 1287, 2842, 4668, 5311, 11594, 13122, 13813,
|
||||
20655, 22975, 25007, 25068, 28252, 33309, 35364, 35765,
|
||||
37731, 40296, 43668, 46540, 49868, 65535 };
|
||||
|
||||
const uint32_t PROGMEM BUGS_irregular_values[BUGS_NBR_IRREGULAR] = {
|
||||
0x52d6926d, 0xa586da34, 0x5329d52c, 0xa66c4952,
|
||||
0x536c4952, 0x524a5bd6, 0x534d65c3, 0xa9d391b3,
|
||||
0x5249529c, 0xa555cd2b, 0xac9a3695, 0x58d391b3,
|
||||
0xa791b36c, 0x53926d94, 0xa7926d94, 0xa72cd391,
|
||||
0xa9b429d5, 0x5629d52c, 0xad2b9a36, 0xa74d65c3,
|
||||
0x526d94a6, 0xad96b2a3 };
|
||||
|
||||
static uint32_t __attribute__((unused)) BUGS_is_irregular(uint16_t i)
|
||||
{
|
||||
for (uint8_t j = 0; j < BUGS_NBR_IRREGULAR; ++j)
|
||||
if (pgm_read_word_near( &BUGS_irregular_keys[j]) == i)
|
||||
return pgm_read_dword_near( &BUGS_irregular_values[j]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t __attribute__((unused)) BUGS_rxid_to_radioid(uint16_t rxid)
|
||||
{
|
||||
uint8_t block = rxid / 256;
|
||||
uint8_t second_seq_size;
|
||||
bool use_most_popular;
|
||||
|
||||
if (rxid < 32768)
|
||||
{
|
||||
second_seq_size = 128 - block;
|
||||
use_most_popular = rxid % 256 >= second_seq_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
second_seq_size = block - 127;
|
||||
use_most_popular = 255 - rxid % 256 >= second_seq_size;
|
||||
}
|
||||
uint32_t v = BUGS_is_irregular(rxid);
|
||||
if (!v)
|
||||
{
|
||||
if (use_most_popular)
|
||||
v = BUGS_most_popular(rxid % 255);
|
||||
else
|
||||
v = BUGS_second_most_popular(rxid % 255);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
//////////// rxid -> radioid algorithm //////////////////////////////
|
||||
|
||||
// For code readability
|
||||
#define BUGS_CH_SW_ARM CH5_SW
|
||||
#define BUGS_CH_SW_ANGLE CH6_SW
|
||||
#define BUGS_CH_SW_FLIP CH7_SW
|
||||
#define BUGS_CH_SW_PICTURE CH8_SW
|
||||
#define BUGS_CH_SW_VIDEO CH9_SW
|
||||
#define BUGS_CH_SW_LED CH10_SW
|
||||
|
||||
// flags packet byte 4
|
||||
#define BUGS_FLAG_FLIP 0x08 // automatic flip
|
||||
#define BUGS_FLAG_MODE 0x04 // low/high speed select (set is high speed)
|
||||
#define BUGS_FLAG_VIDEO 0x02 // toggle video
|
||||
#define BUGS_FLAG_PICTURE 0x01 // toggle picture
|
||||
|
||||
// flags packet byte 5
|
||||
#define BUGS_FLAG_LED 0x80 // enable LEDs
|
||||
#define BUGS_FLAG_ARM 0x40 // arm (toggle to turn on motors)
|
||||
#define BUGS_FLAG_DISARM 0x20 // disarm (toggle to turn off motors)
|
||||
#define BUGS_FLAG_ANGLE 0x04 // angle/acro mode (set is angle mode)
|
||||
|
||||
#define BUGS_PACKET_SIZE 22
|
||||
#define BUGS_NUM_RFCHAN 16
|
||||
|
||||
enum {
|
||||
BUGS_BIND_1,
|
||||
BUGS_BIND_2,
|
||||
BUGS_BIND_3,
|
||||
BUGS_DATA_1,
|
||||
BUGS_DATA_2,
|
||||
BUGS_DATA_3,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) BUGS_check_arming()
|
||||
{
|
||||
uint8_t arm_channel = BUGS_CH_SW_ARM;
|
||||
|
||||
if (arm_channel != arm_channel_previous)
|
||||
{
|
||||
arm_channel_previous = arm_channel;
|
||||
if (arm_channel)
|
||||
{
|
||||
armed = 1;
|
||||
arm_flags ^= BUGS_FLAG_ARM;
|
||||
}
|
||||
else
|
||||
{
|
||||
armed = 0;
|
||||
arm_flags ^= BUGS_FLAG_DISARM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGS_build_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t force_values = bind | !armed;
|
||||
uint8_t change_channel = ((packet_count & 0x1) << 6);
|
||||
uint16_t aileron = convert_channel_16b_limit(AILERON,800,0);
|
||||
uint16_t elevator = convert_channel_16b_limit(ELEVATOR,800,0);
|
||||
uint16_t throttle = convert_channel_16b_limit(THROTTLE,0,800);
|
||||
uint16_t rudder = convert_channel_16b_limit(RUDDER,800,0);
|
||||
|
||||
memset(packet, 0, BUGS_PACKET_SIZE);
|
||||
packet[1] = 0x76; // txid (rx uses to know hopping frequencies)
|
||||
packet[2] = 0x71;
|
||||
packet[3] = 0x94;
|
||||
|
||||
BUGS_check_arming(); // sets globals arm_flags and armed
|
||||
if(bind)
|
||||
{
|
||||
packet[4] = change_channel | 0x80;
|
||||
packet[5] = 0x02 | arm_flags
|
||||
| GET_FLAG(BUGS_CH_SW_ANGLE, BUGS_FLAG_ANGLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[4] = change_channel | BUGS_FLAG_MODE
|
||||
| GET_FLAG(BUGS_CH_SW_FLIP, BUGS_FLAG_FLIP)
|
||||
| GET_FLAG(BUGS_CH_SW_PICTURE, BUGS_FLAG_PICTURE)
|
||||
| GET_FLAG(BUGS_CH_SW_VIDEO, BUGS_FLAG_VIDEO);
|
||||
packet[5] = 0x02 | arm_flags
|
||||
| GET_FLAG(BUGS_CH_SW_ANGLE, BUGS_FLAG_ANGLE)
|
||||
| GET_FLAG(BUGS_CH_SW_LED, BUGS_FLAG_LED);
|
||||
}
|
||||
|
||||
packet[6] = force_values ? 100 : (aileron >> 2);
|
||||
packet[7] = force_values ? 100 : (elevator >> 2);
|
||||
packet[8] = force_values ? 0 : (throttle >> 2);
|
||||
packet[9] = force_values ? 100 : (rudder >> 2);
|
||||
packet[10] = 100;
|
||||
packet[11] = 100;
|
||||
packet[12] = 100;
|
||||
packet[13] = 100;
|
||||
|
||||
packet[14] = ((aileron << 6) & 0xc0)
|
||||
| ((elevator << 4) & 0x30)
|
||||
| ((throttle << 2) & 0x0c)
|
||||
| ((rudder ) & 0x03);
|
||||
|
||||
// packet[15] = 0;
|
||||
|
||||
// driven trims
|
||||
packet[16] = aileron / 8 + 14;
|
||||
packet[17] = elevator / 8 + 14;
|
||||
packet[18] = 64;
|
||||
packet[19] = rudder / 8 + 14;
|
||||
|
||||
// packet[20] = 0;
|
||||
// packet[21] = 0;
|
||||
|
||||
uint8_t check = 0x6d;
|
||||
for (uint8_t i=1; i < BUGS_PACKET_SIZE; i++)
|
||||
check ^= packet[i];
|
||||
packet[0] = check;
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM BUGS_hop []= {
|
||||
0x1d, 0x3b, 0x4d, 0x29, 0x11, 0x2d, 0x0b, 0x3d, 0x59, 0x48, 0x17, 0x41, 0x23, 0x4e, 0x2a, 0x63, // bind phase ID=0xac59a453
|
||||
0x4b, 0x19, 0x35, 0x1e, 0x63, 0x0f, 0x45, 0x21, 0x51, 0x3a, 0x5d, 0x25, 0x0a, 0x44, 0x61, 0x27, // data phase ID=0xA4C56AB4 for txid 767194 if rx responds C6 BB 57 7F 00 00 00 00 00 00 FF 87 40 00 00 00
|
||||
};
|
||||
|
||||
static void __attribute__((unused))BUGS_set_radio_data()
|
||||
{ // captured radio data for bugs rx/tx version A2
|
||||
// it appears that the hopping frequencies are determined by the txid
|
||||
// and the data phase radio id is determined by the first 2 bytes of the
|
||||
// rx bind packet
|
||||
uint8_t offset=0;
|
||||
uint32_t radio_id=0xac59a453; // bind phase ID=0xac59a453
|
||||
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
offset=BUGS_NUM_RFCHAN;
|
||||
// Read radio_id from EEPROM
|
||||
uint8_t base_adr=BUGS_EEPROM_OFFSET+(RX_num&0x0F)*2;
|
||||
uint16_t rxid=0;
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
rxid|=eeprom_read_byte((EE_ADDR)(base_adr+i))<<(i*8);
|
||||
radio_id = BUGS_rxid_to_radioid(rxid);
|
||||
}
|
||||
A7105_WriteID(radio_id);
|
||||
|
||||
for(uint8_t i=0; i<BUGS_NUM_RFCHAN;i++)
|
||||
hopping_frequency[i]=pgm_read_byte_near( &BUGS_hop[i+offset] );
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGS_increment_counts()
|
||||
{ // this logic works with the use of packet_count in BUGS_build_packet
|
||||
// to properly indicate channel changes to rx
|
||||
packet_count += 1;
|
||||
if ((packet_count & 1) == 0)
|
||||
{
|
||||
hopping_frequency_no += 1;
|
||||
hopping_frequency_no %= BUGS_NUM_RFCHAN;
|
||||
}
|
||||
}
|
||||
|
||||
#define BUGS_PACKET_PERIOD 6100
|
||||
#define BUGS_DELAY_TX 2000
|
||||
#define BUGS_DELAY_POST_RX 1500
|
||||
#define BUGS_DELAY_BIND_RST 200
|
||||
|
||||
// FIFO config is one less than desired value
|
||||
#define BUGS_FIFO_SIZE_RX 15
|
||||
#define BUGS_FIFO_SIZE_TX 21
|
||||
uint16_t BUGS_callback(void)
|
||||
{
|
||||
uint8_t mode, base_adr;
|
||||
uint16_t rxid;
|
||||
uint16_t start;
|
||||
|
||||
// keep frequency tuning updated
|
||||
#ifndef FORCE_FLYSKY_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
|
||||
switch(phase)
|
||||
{
|
||||
case BUGS_BIND_1:
|
||||
BUGS_build_packet(1);
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_TX);
|
||||
A7105_WriteData(BUGS_PACKET_SIZE, hopping_frequency[hopping_frequency_no]);
|
||||
phase = BUGS_BIND_2;
|
||||
packet_period = BUGS_DELAY_TX;
|
||||
break;
|
||||
|
||||
case BUGS_BIND_2:
|
||||
//Wait for TX completion
|
||||
start=micros();
|
||||
while ((uint16_t)((uint16_t)micros()-start) < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_SetTxRxMode(RX_EN);
|
||||
A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no] - 2);
|
||||
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_RX);
|
||||
A7105_Strobe(A7105_RX);
|
||||
|
||||
BUGS_increment_counts();
|
||||
phase = BUGS_BIND_3;
|
||||
packet_period = BUGS_PACKET_PERIOD-BUGS_DELAY_TX-BUGS_DELAY_POST_RX;
|
||||
break;
|
||||
|
||||
case BUGS_BIND_3:
|
||||
mode = A7105_ReadReg(A7105_00_MODE);
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
A7105_SetTxRxMode(TX_EN);
|
||||
if (mode & 0x01)
|
||||
{
|
||||
phase = BUGS_BIND_1;
|
||||
packet_period = BUGS_DELAY_BIND_RST; // No received data so restart binding procedure.
|
||||
break;
|
||||
}
|
||||
A7105_ReadData(16);
|
||||
if ((packet[0] + packet[1] + packet[2] + packet[3]) == 0)
|
||||
{
|
||||
phase = BUGS_BIND_1;
|
||||
packet_period = BUGS_DELAY_BIND_RST; // No received data so restart binding procedure.
|
||||
break;
|
||||
}
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
BIND_DONE;
|
||||
// set radio_id
|
||||
rxid = (packet[1] << 8) + packet[2];
|
||||
base_adr=BUGS_EEPROM_OFFSET+(RX_num&0x0F)*2;
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
eeprom_write_byte((EE_ADDR)(base_adr+i),rxid>>(i*8)); // Save rxid in EEPROM
|
||||
BUGS_set_radio_data();
|
||||
phase = BUGS_DATA_1;
|
||||
packet_count = 0;
|
||||
hopping_frequency_no = 0;
|
||||
packet_period = BUGS_DELAY_POST_RX;
|
||||
break;
|
||||
|
||||
case BUGS_DATA_1:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(BUGS_PACKET_PERIOD);
|
||||
#endif
|
||||
A7105_SetPower();
|
||||
BUGS_build_packet(0);
|
||||
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_TX);
|
||||
A7105_WriteData(BUGS_PACKET_SIZE, hopping_frequency[hopping_frequency_no]);
|
||||
phase = BUGS_DATA_2;
|
||||
packet_period = BUGS_DELAY_TX;
|
||||
break;
|
||||
|
||||
case BUGS_DATA_2:
|
||||
//Wait for TX completion
|
||||
start=micros();
|
||||
while ((uint16_t)((uint16_t)micros()-start) < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_SetTxRxMode(RX_EN);
|
||||
A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no] - 2);
|
||||
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_RX);
|
||||
A7105_Strobe(A7105_RX);
|
||||
|
||||
BUGS_increment_counts();
|
||||
phase = BUGS_DATA_3;
|
||||
packet_period = BUGS_PACKET_PERIOD-BUGS_DELAY_TX-BUGS_DELAY_POST_RX;
|
||||
break;
|
||||
|
||||
case BUGS_DATA_3:
|
||||
mode = A7105_ReadReg(A7105_00_MODE);
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
A7105_SetTxRxMode(TX_EN);
|
||||
if (!(mode & 0x01))
|
||||
{
|
||||
A7105_ReadData(16);
|
||||
#if defined(BUGS_HUB_TELEMETRY)
|
||||
v_lipo1=packet[10] == 0xff ? 0xff : 0x00; // Voltage in this case is only an alert on level good or bad.
|
||||
RX_RSSI=packet[3];
|
||||
// Read TX RSSI
|
||||
int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // Value from A7105 is between 8 for maximum signal strength to 160 or less
|
||||
if(temp<0) temp=0;
|
||||
else if(temp>255) temp=255;
|
||||
TX_RSSI=temp;
|
||||
telemetry_link=1;
|
||||
#endif
|
||||
}
|
||||
phase = BUGS_DATA_1;
|
||||
packet_period = BUGS_DELAY_POST_RX;
|
||||
break;
|
||||
}
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
void BUGS_init(void)
|
||||
{
|
||||
uint16_t rxid=0;
|
||||
uint8_t base_adr=BUGS_EEPROM_OFFSET+(RX_num&0x0F)*2;
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
rxid|=eeprom_read_byte((EE_ADDR)(base_adr+i))<<(i*8);
|
||||
if(rxid==0xffff)
|
||||
BIND_IN_PROGRESS;
|
||||
|
||||
BUGS_set_radio_data();
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
phase = BUGS_BIND_1;
|
||||
else
|
||||
phase = BUGS_DATA_1;
|
||||
|
||||
A7105_Init();
|
||||
|
||||
hopping_frequency_no = 0;
|
||||
packet_count = 0;
|
||||
armed = 0;
|
||||
arm_flags = BUGS_FLAG_DISARM; // initial value from captures
|
||||
arm_channel_previous = BUGS_CH_SW_ARM;
|
||||
}
|
||||
|
||||
#endif
|
||||
415
Multiprotocol/CABELL_nrf224l01.ino
Normal file
@@ -0,0 +1,415 @@
|
||||
/*
|
||||
Protocol by Dennis Cabell, 2017
|
||||
KE8FZX
|
||||
|
||||
To use this software, you must adhere to the license terms described below, and assume all responsibility for the use
|
||||
of the software. The user is responsible for all consequences or damage that may result from using this software.
|
||||
The user is responsible for ensuring that the hardware used to run this software complies with local regulations and that
|
||||
any radio signal generated or received from use of this software is legal for that user to generate. The author(s) of this software
|
||||
assume no liability whatsoever. The author(s) of this software is not responsible for legal or civil consequences of
|
||||
using this software, including, but not limited to, any damages cause by lost control of a vehicle using this software.
|
||||
If this software is copied or modified, this disclaimer must accompany all copies.
|
||||
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// The Receiver for this protocol is available at: https://github.com/soligen2010/RC_RX_CABELL_V3_FHSS
|
||||
|
||||
#if defined(CABELL_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define CABELL_BIND_COUNT 2000 // At least 2000 so that if TX toggles the serial bind flag then bind mode is never exited
|
||||
#define CABELL_PACKET_PERIOD 3000 // Do not set too low or else next packet may not be finished transmitting before the channel is changed next time around
|
||||
|
||||
#define CABELL_NUM_CHANNELS 16 // The maximum number of RC channels that can be sent in one packet
|
||||
#define CABELL_MIN_CHANNELS 4 // The minimum number of channels that must be included in a packet, the number of channels cannot be reduced any further than this
|
||||
#define CABELL_PAYLOAD_BYTES 24 // 12 bits per value * 16 channels
|
||||
|
||||
#define CABELL_RADIO_CHANNELS 9 // This is 1/5 of the total number of radio channels used for FHSS
|
||||
#define CABELL_RADIO_MIN_CHANNEL_NUM 3 // Channel 0 is right on the boarder of allowed frequency range, so move up to avoid bleeding over
|
||||
#define CABELL_TELEMETRY_PACKET_LENGTH 4
|
||||
|
||||
#define CABELL_BIND_RADIO_ADDR 0xA4B7C123F7LL
|
||||
|
||||
#define CABELL_OPTION_MASK_CHANNEL_REDUCTION 0x0F
|
||||
#define CABELL_OPTION_MASK_RECIEVER_OUTPUT_MODE 0x30
|
||||
#define CABELL_OPTION_SHIFT_RECIEVER_OUTPUT_MODE 4
|
||||
#define CABELL_OPTION_MASK_MAX_POWER_OVERRIDE 0x40
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum RxMode_t : uint8_t
|
||||
{ // Note bit 8 is used to indicate if the packet is the first of 2 on the channel. Mask out this bit before using the enum
|
||||
normal = 0,
|
||||
bind = 1,
|
||||
setFailSafe = 2,
|
||||
normalWithTelemetry = 3,
|
||||
telemetryResponse = 4,
|
||||
unBind = 127
|
||||
} RxMode;
|
||||
uint8_t reserved = 0;
|
||||
uint8_t option;
|
||||
/* mask 0x0F : Channel reduction. The number of channels to not send (subtracted from the 16 max channels) at least 4 are always sent
|
||||
* mask 0x30>>4 : Receiver output mode
|
||||
* 0 (00) = Single PPM on individual pins for each channel
|
||||
* 1 (01) = SUM PPM on channel 1 pin
|
||||
* 2 (10) = Future use. Reserved for SBUS output
|
||||
* 3 (11) = Unused
|
||||
* mask 0x40>>6 Contains max power override flag for Multi-protocol TX module. Also sent to RX
|
||||
* mask 0x80>>7 Unused
|
||||
*/
|
||||
uint8_t modelNum;
|
||||
uint8_t checkSum_LSB;
|
||||
uint8_t checkSum_MSB;
|
||||
uint8_t payloadValue [CABELL_PAYLOAD_BYTES] = {0}; //12 bits per channel value, unsigned
|
||||
} CABELL_RxTxPacket_t;
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static uint8_t __attribute__((unused)) CABELL_getNextChannel (uint8_t seqArray[], uint8_t seqArraySize, uint8_t prevChannel)
|
||||
{
|
||||
/* Possible channels are in 5 bands, each band comprised of seqArraySize channels
|
||||
* seqArray contains seqArraySize elements in the relative order in which we should progress through the band
|
||||
*
|
||||
* Each time the channel is changes, bands change in a way so that the next channel will be in a
|
||||
* different non-adjacent band. Both the band changes and the index in seqArray is incremented.
|
||||
*/
|
||||
prevChannel -= CABELL_RADIO_MIN_CHANNEL_NUM; // Subtract CABELL_RADIO_MIN_CHANNEL_NUM because it was added to the return value
|
||||
if(prevChannel>(seqArraySize * 5))
|
||||
prevChannel=seqArraySize * 5; // Constrain the values just in case something bogus was sent in.
|
||||
|
||||
uint8_t currBand = prevChannel / seqArraySize;
|
||||
uint8_t nextBand = (currBand + 3) % 5;
|
||||
|
||||
uint8_t prevChannalSeqArrayValue = prevChannel % seqArraySize;
|
||||
uint8_t prevChannalSeqArrayPosition = 0;
|
||||
for (int x = 0; x < seqArraySize; x++)
|
||||
{ // Find the position of the previous channel in the array
|
||||
if (seqArray[x] == prevChannalSeqArrayValue)
|
||||
prevChannalSeqArrayPosition = x;
|
||||
}
|
||||
uint8_t nextChannalSeqArrayPosition = prevChannalSeqArrayPosition + 1;
|
||||
if (nextChannalSeqArrayPosition >= seqArraySize)
|
||||
nextChannalSeqArrayPosition = 0;
|
||||
|
||||
return (seqArraySize * nextBand) + seqArray[nextChannalSeqArrayPosition] + CABELL_RADIO_MIN_CHANNEL_NUM; // Add CABELL_RADIO_MIN_CHANNEL_NUM so we dont use channel 0 as it may bleed below 2.400 GHz
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
#if defined CABELL_HUB_TELEMETRY
|
||||
static void __attribute__((unused)) CABELL_get_telemetry()
|
||||
{
|
||||
// calculate TX rssi based on past 250 expected telemetry packets. Cannot use full second count because telemetry_counter is not large enough
|
||||
state++;
|
||||
if (state > 250)
|
||||
{
|
||||
TX_RSSI = telemetry_counter;
|
||||
telemetry_counter = 0;
|
||||
state = 0;
|
||||
telemetry_lost=0;
|
||||
}
|
||||
|
||||
// Process incoming telemetry packet of it was received
|
||||
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // data received from model
|
||||
NRF24L01_ReadPayload(packet, CABELL_TELEMETRY_PACKET_LENGTH);
|
||||
if ((packet[0] & 0x7F) == CABELL_RxTxPacket_t::telemetryResponse) // ignore high order bit in compare because it toggles with each packet
|
||||
{
|
||||
RX_RSSI = packet[1]; // Packet rate 0 to 255 where 255 is 100% packet rate
|
||||
v_lipo1 = packet[2]; // Directly from analog input of receiver, but reduced to 8-bit depth (0 to 255). Scaling depends on the input to the analog pin of the receiver.
|
||||
v_lipo2 = packet[3]; // Directly from analog input of receiver, but reduced to 8-bit depth (0 to 255). Scaling depends on the input to the analog pin of the receiver.
|
||||
telemetry_counter++;
|
||||
if(telemetry_lost==0)
|
||||
telemetry_link=1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no telemetry packet was received then delay by the typical telemetry packet processing time
|
||||
// This is done to try to keep the sendPacket process timing more consistent. Since the SPI payload read takes some time
|
||||
delayMicroseconds(50);
|
||||
}
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_FlushRx();
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
|
||||
{
|
||||
#if defined CABELL_HUB_TELEMETRY
|
||||
if (!bindMode && (sub_protocol == CABELL_V3_TELEMETRY)) // check for incoming packet and switch radio back to TX mode if we were listening for telemetry
|
||||
CABELL_get_telemetry();
|
||||
#endif
|
||||
|
||||
CABELL_RxTxPacket_t TxPacket;
|
||||
|
||||
uint8_t channelReduction = constrain((option & CABELL_OPTION_MASK_CHANNEL_REDUCTION),0,CABELL_NUM_CHANNELS-CABELL_MIN_CHANNELS); // Max 12 - cannot reduce below 4 channels
|
||||
if (bindMode)
|
||||
channelReduction = 0; // Send full packet to bind as higher channels will contain bind info
|
||||
|
||||
uint8_t packetSize = sizeof(TxPacket) - ((((channelReduction - (channelReduction%2))/ 2)) * 3); // reduce 3 bytes per 2 channels, but not last channel if it is odd
|
||||
uint8_t maxPayloadValueIndex = sizeof(TxPacket.payloadValue) - (sizeof(TxPacket) - packetSize);
|
||||
|
||||
if ((sub_protocol == CABELL_UNBIND) && !bindMode)
|
||||
{
|
||||
TxPacket.RxMode = CABELL_RxTxPacket_t::unBind;
|
||||
TxPacket.option = option;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sub_protocol == CABELL_SET_FAIL_SAFE && !bindMode)
|
||||
TxPacket.RxMode = CABELL_RxTxPacket_t::setFailSafe;
|
||||
else
|
||||
{
|
||||
if (bindMode)
|
||||
TxPacket.RxMode = CABELL_RxTxPacket_t::bind;
|
||||
else
|
||||
{
|
||||
switch (sub_protocol)
|
||||
{
|
||||
case CABELL_V3_TELEMETRY:
|
||||
TxPacket.RxMode = CABELL_RxTxPacket_t::normalWithTelemetry;
|
||||
break;
|
||||
default:
|
||||
TxPacket.RxMode = CABELL_RxTxPacket_t::normal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
TxPacket.option = (bindMode) ? (option & (~CABELL_OPTION_MASK_CHANNEL_REDUCTION)) : option; //remove channel reduction if in bind mode
|
||||
}
|
||||
|
||||
rf_ch_num = CABELL_getNextChannel (hopping_frequency,CABELL_RADIO_CHANNELS, rf_ch_num);
|
||||
TxPacket.reserved = rf_ch_num & 0x3F;
|
||||
TxPacket.modelNum = RX_num;
|
||||
uint16_t checkSum = TxPacket.modelNum + TxPacket.option + TxPacket.RxMode + TxPacket.reserved; // Start Calculate checksum
|
||||
|
||||
int adjusted_x;
|
||||
int payloadIndex = 0;
|
||||
uint16_t holdValue;
|
||||
|
||||
for (int x = 0;(x < CABELL_NUM_CHANNELS - channelReduction); x++)
|
||||
{
|
||||
switch (x)
|
||||
{
|
||||
case 0 : adjusted_x = ELEVATOR; break;
|
||||
case 1 : adjusted_x = AILERON; break;
|
||||
case 2 : adjusted_x = RUDDER; break;
|
||||
case 3 : adjusted_x = THROTTLE; break;
|
||||
default : adjusted_x = x; break;
|
||||
}
|
||||
holdValue = convert_channel_16b_limit(adjusted_x,1000,2000); // valid channel values are 1000 to 2000
|
||||
if (bindMode)
|
||||
{
|
||||
switch (adjusted_x)
|
||||
{
|
||||
case THROTTLE : holdValue = 1000; break; // always set throttle to off when binding for safety
|
||||
//tx address sent for bind
|
||||
case 11 : holdValue = 1000 + rx_tx_addr[0]; break;
|
||||
case 12 : holdValue = 1000 + rx_tx_addr[1]; break;
|
||||
case 13 : holdValue = 1000 + rx_tx_addr[2]; break;
|
||||
case 14 : holdValue = 1000 + rx_tx_addr[3]; break;
|
||||
case 15 : holdValue = 1000 + rx_tx_addr[4]; break;
|
||||
}
|
||||
}
|
||||
|
||||
// use 12 bits per value
|
||||
if (x % 2)
|
||||
{ //output channel number is ODD
|
||||
holdValue = holdValue<<4;
|
||||
payloadIndex--;
|
||||
}
|
||||
else
|
||||
holdValue &= 0x0FFF;
|
||||
TxPacket.payloadValue[payloadIndex] |= (uint8_t)(holdValue & 0x00FF);
|
||||
payloadIndex++;
|
||||
TxPacket.payloadValue[payloadIndex] |= (uint8_t)((holdValue>>8) & 0x00FF);
|
||||
payloadIndex++;
|
||||
}
|
||||
|
||||
for(int x = 0; x < maxPayloadValueIndex ; x++)
|
||||
checkSum += TxPacket.payloadValue[x]; // Finish Calculate checksum
|
||||
|
||||
TxPacket.checkSum_MSB = checkSum >> 8;
|
||||
TxPacket.checkSum_LSB = checkSum & 0x00FF;
|
||||
|
||||
// Set channel for next transmission
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH,rf_ch_num);
|
||||
|
||||
//NRF24L01_FlushTx(); //just in case things got hung up
|
||||
//NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(&TxPacket.RxMode);
|
||||
*p &= 0x7F; // Make sure 8th bit is clear
|
||||
*p |= (packet_count++)<<7; // This causes the 8th bit of the first byte to toggle with each xmit so consecutive payloads are not identical.
|
||||
// This is a work around for a reported bug in clone NRF24L01 chips that mis-took this case for a re-transmit of the same packet.
|
||||
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WritePayload((uint8_t*)&TxPacket, packetSize);
|
||||
|
||||
#if defined CABELL_HUB_TELEMETRY
|
||||
if (!bindMode && (sub_protocol == CABELL_V3_TELEMETRY))
|
||||
{ // switch radio to rx as soon as packet is sent
|
||||
// calculate transmit time based on packet size and data rate of 1MB per sec
|
||||
// This is done because polling the status register during xmit caused issues.
|
||||
// bits = packst_size * 8 + 73 bits overhead
|
||||
// at 250 Kbs per sec, one bit is 4 uS
|
||||
// then add 140 uS which is 130 uS to begin the xmit and 10 uS fudge factor
|
||||
delayMicroseconds(((((unsigned long)packetSize * 8ul) + 73ul) * 4ul) + 140ul) ;
|
||||
packet_period = CABELL_PACKET_PERIOD + (constrain(((int16_t)(CABELL_NUM_CHANNELS - channelReduction) - (int16_t)6 ),(int16_t)0 ,(int16_t)10 ) * (int16_t)100); // increase packet period by 100 us for each channel over 6
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); // RX mode with 16 bit CRC
|
||||
}
|
||||
else
|
||||
#endif
|
||||
packet_period = CABELL_PACKET_PERIOD; // Standard packet period when not in telemetry mode.
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) CABELL_getChannelSequence (uint8_t outArray[], uint8_t numChannels, uint64_t permutation)
|
||||
{
|
||||
/* This procedure initializes an array with the sequence progression of channels.
|
||||
* This is not the actual channels itself, but the sequence base to be used within bands of
|
||||
* channels.
|
||||
*
|
||||
* There are numChannels! permutations for arranging the channels
|
||||
* one of these permutations will be calculated based on the permutation input
|
||||
* permutation should be between 1 and numChannels! but the routine will constrain it
|
||||
* if these bounds are exceeded. Typically the radio's unique TX ID should be used.
|
||||
*
|
||||
* The maximum numChannels is 20. Anything larger than this will cause the uint64_t
|
||||
* variables to overflow, yielding unknown results (possibly infinite loop?). Therefor
|
||||
* this routine constrains the value.
|
||||
*/
|
||||
uint8_t i; //iterator counts numChannels
|
||||
uint32_t indexOfNextSequenceValue;
|
||||
uint32_t numChannelsFactorial=1;
|
||||
uint32_t perm32 ;
|
||||
uint8_t sequenceValue;
|
||||
|
||||
numChannels = constrain(numChannels,1,9);
|
||||
|
||||
for (i = 1; i <= numChannels;i++)
|
||||
{
|
||||
numChannelsFactorial *= i; // Calculate n!
|
||||
outArray[i-1] = i-1; // Initialize array with the sequence
|
||||
}
|
||||
|
||||
perm32 = permutation >> 8 ; // Shift 40 bit input to 32 bit
|
||||
perm32 = (perm32 % numChannelsFactorial); // permutation must be between 1 and n! or this algorithm will infinite loop
|
||||
perm32 <<= 8 ; // Shift back 8 bits
|
||||
perm32 += permutation & 0x00FF ; // Tack on least 8 bits
|
||||
perm32 = (perm32 % numChannelsFactorial) + 1; // permutation must be between 1 and n! or this algorithm will infinite loop
|
||||
|
||||
//Rearrange the array elements based on the permutation selected
|
||||
for (i=0, perm32--; i<numChannels; i++ )
|
||||
{
|
||||
numChannelsFactorial /= numChannels-i;
|
||||
indexOfNextSequenceValue = i+(perm32/numChannelsFactorial);
|
||||
perm32 %= numChannelsFactorial;
|
||||
|
||||
//Copy the value in the selected array position
|
||||
sequenceValue = outArray[indexOfNextSequenceValue];
|
||||
|
||||
//Shift the unused elements in the array to make room to move in the one just selected
|
||||
for( ; indexOfNextSequenceValue > i; indexOfNextSequenceValue--)
|
||||
outArray[indexOfNextSequenceValue] = outArray[indexOfNextSequenceValue-1];
|
||||
|
||||
// Copy the selected value into it's new array slot
|
||||
outArray[i] = sequenceValue;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) CABELL_setAddress()
|
||||
{
|
||||
uint64_t CABELL_addr;
|
||||
|
||||
// Serial.print("NORM ID: ");Serial.print((uint32_t)(CABELL_normal_addr>>32)); Serial.print(" ");Serial.println((uint32_t)((CABELL_normal_addr<<32)>>32));
|
||||
|
||||
if (IS_BIND_DONE)
|
||||
{
|
||||
CABELL_addr = (((uint64_t)rx_tx_addr[0]) << 32) +
|
||||
(((uint64_t)rx_tx_addr[1]) << 24) +
|
||||
(((uint64_t)rx_tx_addr[2]) << 16) +
|
||||
(((uint64_t)rx_tx_addr[3]) << 8) +
|
||||
(((uint64_t)rx_tx_addr[4])); // Address to use after binding
|
||||
}
|
||||
else
|
||||
CABELL_addr = CABELL_BIND_RADIO_ADDR; // Static addr for binding
|
||||
|
||||
CABELL_getChannelSequence(hopping_frequency,CABELL_RADIO_CHANNELS,CABELL_addr); // Get the sequence for hopping through channels
|
||||
rf_ch_num = CABELL_RADIO_MIN_CHANNEL_NUM; // Initialize the channel sequence
|
||||
|
||||
packet_count=0;
|
||||
|
||||
uint64_t CABELL_Telemetry_addr = ~CABELL_addr; // Invert bits for reading so that telemetry packets have a different address.
|
||||
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, reinterpret_cast<uint8_t*>(&CABELL_Telemetry_addr), 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, reinterpret_cast<uint8_t*>(&CABELL_Telemetry_addr), 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, reinterpret_cast<uint8_t*>(&CABELL_addr), 5);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) CABELL_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // slower data rate gives better range/reliability
|
||||
CABELL_setAddress();
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x20); // 32 byte packet length
|
||||
NRF24L01_WriteReg(NRF24L01_12_RX_PW_P1, 0x20); // 32 byte packet length
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F); // Enable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x04); // Enable dynamic Payload Length
|
||||
|
||||
NRF24L01_SetTxRxMode(TX_EN); // Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
uint16_t CABELL_callback()
|
||||
{
|
||||
if (IS_BIND_DONE)
|
||||
{
|
||||
CABELL_send_packet(0); // packet_period is set/adjusted in CABELL_send_packet
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
return packet_period;
|
||||
}
|
||||
else if (bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
CABELL_RF_init(); // non-bind address
|
||||
}
|
||||
else
|
||||
{
|
||||
CABELL_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
return CABELL_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
void CABELL_init(void)
|
||||
{
|
||||
if (IS_BIND_DONE)
|
||||
bind_counter = 0;
|
||||
else
|
||||
bind_counter = CABELL_BIND_COUNT;
|
||||
CABELL_RF_init();
|
||||
|
||||
packet_period = CABELL_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -17,127 +18,110 @@
|
||||
//CC2500 SPI routines
|
||||
//-------------------------------
|
||||
//-------------------------------
|
||||
#ifdef CC2500_INSTALLED
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
void cc2500_readFifo(uint8_t *dpbuffer, uint8_t len)
|
||||
{
|
||||
ReadRegisterMulti(CC2500_3F_RXFIFO | CC2500_READ_BURST, dpbuffer, len);
|
||||
}
|
||||
|
||||
//----------------------
|
||||
static void ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length)
|
||||
//----------------------------
|
||||
void CC2500_WriteReg(uint8_t address, uint8_t data)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
cc2500_spi_write(address);
|
||||
SPI_Write(address);
|
||||
NOP();
|
||||
SPI_Write(data);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
//----------------------
|
||||
static void CC2500_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
SPI_Write(CC2500_READ_BURST | address);
|
||||
for(uint8_t i = 0; i < length; i++)
|
||||
data[i] = cc2500_spi_read();
|
||||
data[i] = SPI_Read();
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
//--------------------------------------------
|
||||
static uint8_t CC2500_ReadReg(uint8_t address)
|
||||
{
|
||||
uint8_t result;
|
||||
CC25_CSN_off;
|
||||
SPI_Write(CC2500_READ_SINGLE | address);
|
||||
result = SPI_Read();
|
||||
CC25_CSN_on;
|
||||
return(result);
|
||||
}
|
||||
|
||||
//------------------------
|
||||
void CC2500_ReadData(uint8_t *dpbuffer, uint8_t len)
|
||||
{
|
||||
CC2500_ReadRegisterMulti(CC2500_3F_RXFIFO, dpbuffer, len);
|
||||
}
|
||||
|
||||
//*********************************************
|
||||
void CC2500_Strobe(uint8_t state)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
SPI_Write(state);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
static void CC2500_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8_t length)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
cc2500_spi_write(CC2500_WRITE_BURST | address);
|
||||
SPI_Write(CC2500_WRITE_BURST | address);
|
||||
for(uint8_t i = 0; i < length; i++)
|
||||
cc2500_spi_write(data[i]);
|
||||
SPI_Write(data[i]);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
void cc2500_writeFifo(uint8_t *dpbuffer, uint8_t len)
|
||||
void CC2500_WriteData(uint8_t *dpbuffer, uint8_t len)
|
||||
{
|
||||
cc2500_strobe(CC2500_SFTX);//0x3B
|
||||
CC2500_Strobe(CC2500_SFTX);
|
||||
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, dpbuffer, len);
|
||||
cc2500_strobe(CC2500_STX);//0x35
|
||||
CC2500_Strobe(CC2500_STX);
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
static void cc2500_spi_write(uint8_t command) {
|
||||
uint8_t n=8;
|
||||
|
||||
SCK_off;//SCK start low
|
||||
SDI_off;
|
||||
while(n--)
|
||||
{
|
||||
if(command&0x80)
|
||||
SDI_on;
|
||||
else
|
||||
SDI_off;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
command = command << 1;
|
||||
}
|
||||
SDI_on;
|
||||
}
|
||||
|
||||
//----------------------------
|
||||
void cc2500_writeReg(uint8_t address, uint8_t data) {//same as 7105
|
||||
CC25_CSN_off;
|
||||
cc2500_spi_write(address);
|
||||
NOP();
|
||||
cc2500_spi_write(data);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
static uint8_t cc2500_spi_read(void)
|
||||
void CC2500_SetTxRxMode(uint8_t mode)
|
||||
{
|
||||
uint8_t result;
|
||||
uint8_t i;
|
||||
result=0;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
if(SDO_1) ///
|
||||
result=(result<<1)|0x01;
|
||||
if(mode == TX_EN)
|
||||
{//from deviation firmware
|
||||
CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F);
|
||||
CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F | 0x40);
|
||||
}
|
||||
else
|
||||
if (mode == RX_EN)
|
||||
{
|
||||
CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F);
|
||||
CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F | 0x40);
|
||||
}
|
||||
else
|
||||
result=result<<1;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
NOP();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------
|
||||
static uint8_t cc2500_readReg(uint8_t address)
|
||||
{
|
||||
uint8_t result;
|
||||
CC25_CSN_off;
|
||||
address |=0x80; //bit 7 =1 for reading
|
||||
cc2500_spi_write(address);
|
||||
result = cc2500_spi_read();
|
||||
CC25_CSN_on;
|
||||
return(result);
|
||||
}
|
||||
//------------------------
|
||||
void cc2500_strobe(uint8_t address)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
cc2500_spi_write(address);
|
||||
CC25_CSN_on;
|
||||
{
|
||||
CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F);
|
||||
CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------
|
||||
/*static void cc2500_resetChip(void)
|
||||
{
|
||||
// Toggle chip select signal
|
||||
CC25_CSN_on;
|
||||
_delay_us(30);
|
||||
delayMicroseconds(30);
|
||||
CC25_CSN_off;
|
||||
_delay_us(30);
|
||||
delayMicroseconds(30);
|
||||
CC25_CSN_on;
|
||||
_delay_us(45);
|
||||
cc2500_strobe(CC2500_SRES);
|
||||
delayMicroseconds(45);
|
||||
CC2500_Strobe(CC2500_SRES);
|
||||
_delay_ms(100);
|
||||
}
|
||||
*/
|
||||
uint8_t CC2500_Reset()
|
||||
{
|
||||
cc2500_strobe(CC2500_SRES);
|
||||
_delay_us(1000);
|
||||
CC2500_Strobe(CC2500_SRES);
|
||||
delayMilliseconds(1);
|
||||
CC2500_SetTxRxMode(TXRX_OFF);
|
||||
return cc2500_readReg(CC2500_0E_FREQ1) == 0xC4;//check if reset
|
||||
return CC2500_ReadReg(CC2500_0E_FREQ1) == 0xC4;//check if reset
|
||||
}
|
||||
/*
|
||||
static void CC2500_SetPower_Value(uint8_t power)
|
||||
@@ -154,35 +138,153 @@ static void CC2500_SetPower_Value(uint8_t power)
|
||||
};
|
||||
if (power > 7)
|
||||
power = 7;
|
||||
cc2500_writeReg(CC2500_3E_PATABLE, patable[power]);
|
||||
CC2500_WriteReg(CC2500_3E_PATABLE, patable[power]);
|
||||
}
|
||||
*/
|
||||
void CC2500_SetPower()
|
||||
{
|
||||
uint8_t power=CC2500_BIND_POWER;
|
||||
if(IS_BIND_DONE_on)
|
||||
power=IS_POWER_FLAG_on?CC2500_HIGH_POWER:CC2500_LOW_POWER;
|
||||
if(IS_BIND_DONE)
|
||||
#ifdef CC2500_ENABLE_LOW_POWER
|
||||
power=IS_POWER_FLAG_on?CC2500_HIGH_POWER:CC2500_LOW_POWER;
|
||||
#else
|
||||
power=CC2500_HIGH_POWER;
|
||||
#endif
|
||||
if(IS_LBT_POWER_on)
|
||||
{
|
||||
power=CC2500_LBT_POWER;
|
||||
LBT_POWER_off; // Only accept once
|
||||
}
|
||||
if(IS_RANGE_FLAG_on)
|
||||
power=CC2500_RANGE_POWER;
|
||||
cc2500_writeReg(CC2500_3E_PATABLE, power);
|
||||
if(prev_power != power)
|
||||
{
|
||||
CC2500_WriteReg(CC2500_3E_PATABLE, power);
|
||||
prev_power=power;
|
||||
}
|
||||
}
|
||||
|
||||
void CC2500_SetTxRxMode(uint8_t mode)
|
||||
void __attribute__((unused)) CC2500_SetFreqOffset()
|
||||
{
|
||||
if(mode == TX_EN)
|
||||
{//from deviation firmware
|
||||
cc2500_writeReg(CC2500_02_IOCFG0, 0x2F | 0x40);
|
||||
cc2500_writeReg(CC2500_00_IOCFG2, 0x2F);
|
||||
if(prev_option != option)
|
||||
{
|
||||
prev_option = option;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
}
|
||||
else
|
||||
if (mode == RX_EN)
|
||||
{
|
||||
cc2500_writeReg(CC2500_02_IOCFG0, 0x2F);
|
||||
cc2500_writeReg(CC2500_00_IOCFG2, 0x2F | 0x40);
|
||||
}
|
||||
else
|
||||
{
|
||||
cc2500_writeReg(CC2500_02_IOCFG0, 0x2F);
|
||||
cc2500_writeReg(CC2500_00_IOCFG2, 0x2F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __attribute__((unused)) CC2500_250K_Init()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
|
||||
// Address Config = No address check
|
||||
// Base Frequency = 2400
|
||||
// CRC Autoflush = false
|
||||
// CRC Enable = false
|
||||
// Channel Spacing = 333.251953
|
||||
// Data Format = Normal mode
|
||||
// Data Rate = 249.939
|
||||
// Deviation = 126.953125
|
||||
// Device Address = 0
|
||||
// Manchester Enable = false
|
||||
// Modulated = true
|
||||
// Modulation Format = GFSK
|
||||
// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word
|
||||
// RX Filter BW = 203.125000
|
||||
// Sync Word Qualifier Mode = No preamble/sync
|
||||
// TX Power = 0
|
||||
// Whitening = false
|
||||
// Fast Frequency Hopping - no PLL auto calibration
|
||||
/* //Previous config
|
||||
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x01); // Packet Automation Control
|
||||
CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x0A); // Frequency Synthesizer Control
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option); // Frequency offset hack
|
||||
CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // Frequency Control Word, High Byte
|
||||
CC2500_WriteReg(CC2500_0E_FREQ1, 0x4E); // Frequency Control Word, Middle Byte
|
||||
CC2500_WriteReg(CC2500_0F_FREQ0, 0xC3); // Frequency Control Word, Low Byte
|
||||
CC2500_WriteReg(CC2500_10_MDMCFG4, 0x8D); // Modem Configuration
|
||||
CC2500_WriteReg(CC2500_11_MDMCFG3, 0x3B); // Modem Configuration
|
||||
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x10); // Modem Configuration
|
||||
CC2500_WriteReg(CC2500_13_MDMCFG1, 0x23); // Modem Configuration
|
||||
CC2500_WriteReg(CC2500_14_MDMCFG0, 0xA4); // Modem Configuration
|
||||
CC2500_WriteReg(CC2500_15_DEVIATN, 0x62); // Modem Deviation Setting
|
||||
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // Main Radio Control State Machine Configuration
|
||||
CC2500_WriteReg(CC2500_19_FOCCFG, 0x1D); // Frequency Offset Compensation Configuration
|
||||
CC2500_WriteReg(CC2500_1A_BSCFG, 0x1C); // Bit Synchronization Configuration
|
||||
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0xC7); // AGC Control
|
||||
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x00); // AGC Control
|
||||
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xB0); // AGC Control
|
||||
CC2500_WriteReg(CC2500_21_FREND1, 0xB6); // Front End RX Configuration
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, 0xEA); // Frequency Synthesizer Calibration
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, 0x00); // Frequency Synthesizer Calibration
|
||||
CC2500_WriteReg(CC2500_26_FSCAL0, 0x11); // Frequency Synthesizer Calibration
|
||||
*/
|
||||
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // Packet Automation Control, address check true auto append RSSI & LQI
|
||||
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x00); // Packet Automation Control, fixed packet len
|
||||
CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x0A); // Frequency Synthesizer Control (IF Frequency)
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, 0x00); // Frequency Synthesizer Control
|
||||
CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // Frequency Control Word, High Byte
|
||||
CC2500_WriteReg(CC2500_0E_FREQ1, 0x4E); // Frequency Control Word, Middle Byte
|
||||
CC2500_WriteReg(CC2500_0F_FREQ0, 0xC5); // Frequency Control Word, Low Byte
|
||||
CC2500_WriteReg(CC2500_10_MDMCFG4, 0x3D); // Modem Configuration Set to 406kHz BW filter
|
||||
CC2500_WriteReg(CC2500_11_MDMCFG3, 0x3B); // Modem Configuration
|
||||
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x10); // Modem Configuration, GFSK, no preambule and no sync word -> TX by default
|
||||
CC2500_WriteReg(CC2500_13_MDMCFG1, 0x03); // Modem Configuration, 2 bytes of preamble
|
||||
CC2500_WriteReg(CC2500_14_MDMCFG0, 0xA4); // Modem Configuration
|
||||
CC2500_WriteReg(CC2500_15_DEVIATN, 0x62); // Modem Deviation Setting
|
||||
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // Main Radio Control State Machine Configuration
|
||||
CC2500_WriteReg(CC2500_19_FOCCFG, 0x1D); // Frequency Offset Compensation Configuration
|
||||
CC2500_WriteReg(CC2500_1A_BSCFG, 0x1C); // Bit Synchronization Configuration
|
||||
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0xC7); // AGC Control
|
||||
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x00); // AGC Control
|
||||
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xB0); // AGC Control
|
||||
CC2500_WriteReg(CC2500_21_FREND1, 0xB6); // Front End RX Configuration
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, 0xEA); // Frequency Synthesizer Calibration
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, 0x00); // Frequency Synthesizer Calibration
|
||||
CC2500_WriteReg(CC2500_26_FSCAL0, 0x11); // Frequency Synthesizer Calibration
|
||||
|
||||
//Prep RX
|
||||
// Set first 3 bytes of rx addr in [0]->SYNC1, [1]->SYNC0 and [2]->ADDR
|
||||
// CC2500_WriteReg(CC2500_04_SYNC1, [0]); // Sync word, high byte
|
||||
// CC2500_WriteReg(CC2500_05_SYNC0, [1]); // Sync word, low byte
|
||||
// CC2500_WriteReg(CC2500_09_ADDR, [2]); // Set addr
|
||||
//RX
|
||||
// CC2500_WriteReg(CC2500_12_MDMCFG2, 0x12); // Modem Configuration, GFSK, 16/16 Sync Word TX&RX
|
||||
//TX
|
||||
// CC2500_WriteReg(CC2500_12_MDMCFG2, 0x10); // Modem Configuration, GFSK, no preambule and no sync word
|
||||
// need to set packet length before sending/receiving
|
||||
// CC2500_WriteReg(CC2500_06_PKTLEN, cc2500_packet_len); // Packet len, fix packet len
|
||||
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
}
|
||||
void __attribute__((unused)) CC2500_250K_HoppingCalib(uint8_t num_freq)
|
||||
{
|
||||
for (uint8_t i = 0; i < num_freq; i++)
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
// spacing is 333.25 kHz, must multiply channel by 3
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[i]*3);
|
||||
// calibrate
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);
|
||||
calData[i]=CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
}
|
||||
}
|
||||
void __attribute__((unused)) CC2500_250K_Hopping(uint8_t index)
|
||||
{
|
||||
// spacing is 333.25 kHz, must multiply channel by 3
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[index] * 3);
|
||||
// set PLL calibration
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[index]);
|
||||
}
|
||||
void __attribute__((unused)) CC2500_250K_RFChannel(uint8_t number)
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
// spacing is 333.25 kHz, must multiply channel by 3
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, number*3);
|
||||
// calibrate
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);
|
||||
}
|
||||
#endif
|
||||
845
Multiprotocol/CFlie_nrf24l01.ino
Normal file
@@ -0,0 +1,845 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Most of this code was ported from theseankelly's related DeviationTX work.
|
||||
|
||||
#if defined(CFLIE_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define CFLIE_BIND_COUNT 60
|
||||
|
||||
//=============================================================================
|
||||
// CRTP (Crazy RealTime Protocol) Implementation
|
||||
//=============================================================================
|
||||
|
||||
// Port IDs
|
||||
enum {
|
||||
CRTP_PORT_CONSOLE = 0x00,
|
||||
CRTP_PORT_PARAM = 0x02,
|
||||
CRTP_PORT_SETPOINT = 0x03,
|
||||
CRTP_PORT_MEM = 0x04,
|
||||
CRTP_PORT_LOG = 0x05,
|
||||
CRTP_PORT_POSITION = 0x06,
|
||||
CRTP_PORT_SETPOINT_GENERIC = 0x07,
|
||||
CRTP_PORT_PLATFORM = 0x0D,
|
||||
CRTP_PORT_LINK = 0x0F,
|
||||
};
|
||||
|
||||
// Channel definitions for the LOG port
|
||||
enum {
|
||||
CRTP_LOG_CHAN_TOC = 0x00,
|
||||
CRTP_LOG_CHAN_SETTINGS = 0x01,
|
||||
CRTP_LOG_CHAN_LOGDATA = 0x02,
|
||||
};
|
||||
|
||||
// Command definitions for the LOG port's TOC channel
|
||||
enum {
|
||||
CRTP_LOG_TOC_CMD_ELEMENT = 0x00,
|
||||
CRTP_LOG_TOC_CMD_INFO = 0x01,
|
||||
};
|
||||
|
||||
// Command definitions for the LOG port's CMD channel
|
||||
enum {
|
||||
CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK = 0x00,
|
||||
CRTP_LOG_SETTINGS_CMD_APPEND_BLOCK = 0x01,
|
||||
CRTP_LOG_SETTINGS_CMD_DELETE_BLOCK = 0x02,
|
||||
CRTP_LOG_SETTINGS_CMD_START_LOGGING = 0x03,
|
||||
CRTP_LOG_SETTINGS_CMD_STOP_LOGGING = 0x04,
|
||||
CRTP_LOG_SETTINGS_CMD_RESET_LOGGING = 0x05,
|
||||
};
|
||||
|
||||
// Log variables types
|
||||
enum {
|
||||
LOG_UINT8 = 0x01,
|
||||
LOG_UINT16 = 0x02,
|
||||
LOG_UINT32 = 0x03,
|
||||
LOG_INT8 = 0x04,
|
||||
LOG_INT16 = 0x05,
|
||||
LOG_INT32 = 0x06,
|
||||
LOG_FLOAT = 0x07,
|
||||
LOG_FP16 = 0x08,
|
||||
};
|
||||
|
||||
#define CFLIE_TELEM_LOG_BLOCK_ID 0x01
|
||||
#define CFLIE_TELEM_LOG_BLOCK_PERIOD_10MS 50 // 50*10 = 500ms
|
||||
|
||||
// Setpoint type definitions for the generic setpoint channel
|
||||
enum {
|
||||
CRTP_SETPOINT_GENERIC_STOP_TYPE = 0x00,
|
||||
CRTP_SETPOINT_GENERIC_VELOCITY_WORLD_TYPE = 0x01,
|
||||
CRTP_SETPOINT_GENERIC_Z_DISTANCE_TYPE = 0x02,
|
||||
CRTP_SETPOINT_GENERIC_CPPM_EMU_TYPE = 0x03,
|
||||
};
|
||||
|
||||
static inline uint8_t crtp_create_header(uint8_t port, uint8_t channel)
|
||||
{
|
||||
return ((port)&0x0F)<<4 | (channel & 0x03);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// End CRTP implementation
|
||||
//=============================================================================
|
||||
|
||||
// Address size
|
||||
#define TX_ADDR_SIZE 5
|
||||
|
||||
// Timeout for callback in uSec, 10ms=10000us for Crazyflie
|
||||
#define CFLIE_PACKET_PERIOD 10000
|
||||
|
||||
#define MAX_PACKET_SIZE 32 // CRTP is 32 bytes
|
||||
|
||||
// CPPM CRTP supports up to 10 aux channels but deviation only
|
||||
// supports a total of 12 channels. R,P,Y,T leaves 8 aux channels left
|
||||
#define MAX_CPPM_AUX_CHANNELS 8
|
||||
|
||||
static uint8_t tx_payload_len = 0; // Length of the packet stored in packet
|
||||
static uint8_t rx_payload_len = 0; // Length of the packet stored in rx_packet
|
||||
static uint8_t rx_packet[MAX_PACKET_SIZE]; // For reading in ACK payloads
|
||||
|
||||
static uint8_t data_rate;
|
||||
|
||||
enum {
|
||||
CFLIE_INIT_SEARCH = 0,
|
||||
CFLIE_INIT_CRTP_LOG,
|
||||
CFLIE_INIT_DATA,
|
||||
CFLIE_SEARCH,
|
||||
CFLIE_DATA
|
||||
};
|
||||
|
||||
static uint8_t crtp_log_setup_state;
|
||||
enum {
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_INIT = 0,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_INFO,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_ITEM,
|
||||
// It might be a good idea to add a state here
|
||||
// to send the command to reset the logging engine
|
||||
// to avoid log block ID conflicts. However, there
|
||||
// is not a conflict with the current defaults in
|
||||
// cfclient and I'd rather be able to log from the Tx
|
||||
// and cfclient simultaneously
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_START_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_COMPLETE,
|
||||
};
|
||||
|
||||
// State variables for the crtp_log_setup_state_machine
|
||||
static uint8_t toc_size; // Size of the TOC read from the crazyflie
|
||||
static uint8_t next_toc_variable; // State variable keeping track of the next var to read
|
||||
static uint8_t vbat_var_id; // ID of the vbatMV variable
|
||||
static uint8_t extvbat_var_id; // ID of the extVbatMV variable
|
||||
static uint8_t rssi_var_id; // ID of the RSSI variable
|
||||
|
||||
// Constants used for finding var IDs from the toc
|
||||
static const char* pm_group_name = "pm";
|
||||
static const char* vbat_var_name = "vbatMV";
|
||||
static const uint8_t vbat_var_type = LOG_UINT16;
|
||||
static const char* extvbat_var_name = "extVbatMV";
|
||||
static const uint8_t extvbat_var_type = LOG_UINT16;
|
||||
static const char* radio_group_name = "radio";
|
||||
static const char* rssi_var_name = "rssi";
|
||||
static const uint8_t rssi_var_type = LOG_UINT8;
|
||||
|
||||
// Repurposing DSM Telemetry fields
|
||||
#define TELEM_CFLIE_INTERNAL_VBAT TELEM_DSM_FLOG_VOLT2 // Onboard voltage
|
||||
#define TELEM_CFLIE_EXTERNAL_VBAT TELEM_DSM_FLOG_VOLT1 // Voltage from external pin (BigQuad)
|
||||
#define TELEM_CFLIE_RSSI TELEM_DSM_FLOG_FADESA // Repurpose FADESA for RSSI
|
||||
|
||||
enum {
|
||||
PROTOOPTS_TELEMETRY = 0,
|
||||
PROTOOPTS_CRTP_MODE = 1,
|
||||
LAST_PROTO_OPT,
|
||||
};
|
||||
|
||||
#define TELEM_OFF 0
|
||||
#define TELEM_ON_ACKPKT 1
|
||||
#define TELEM_ON_CRTPLOG 2
|
||||
|
||||
#define CRTP_MODE_RPYT 0
|
||||
#define CRTP_MODE_CPPM 1
|
||||
|
||||
// Bit vector from bit position
|
||||
#define BV(bit) (1 << bit)
|
||||
|
||||
#define PACKET_CHKTIME 500 // time to wait if packet not yet acknowledged or timed out
|
||||
|
||||
// Helper for sending a packet
|
||||
// Assumes packet data has been put in packet
|
||||
// and tx_payload_len has been set correctly
|
||||
static void send_packet()
|
||||
{
|
||||
// clear packet status bits and Tx/Rx FIFOs
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (_BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
|
||||
// Transmit the payload
|
||||
NRF24L01_WritePayload(packet, tx_payload_len);
|
||||
|
||||
// // Check and adjust transmission power.
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static uint16_t dbg_cnt = 0;
|
||||
static uint8_t packet_ack()
|
||||
{
|
||||
if (++dbg_cnt > 50)
|
||||
{
|
||||
// debugln("S: %02x\n", NRF24L01_ReadReg(NRF24L01_07_STATUS));
|
||||
dbg_cnt = 0;
|
||||
}
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)))
|
||||
{
|
||||
case BV(NRF24L01_07_TX_DS):
|
||||
rx_payload_len = NRF24L01_GetDynamicPayloadSize();
|
||||
if (rx_payload_len > MAX_PACKET_SIZE)
|
||||
rx_payload_len = MAX_PACKET_SIZE;
|
||||
NRF24L01_ReadPayload(rx_packet, rx_payload_len);
|
||||
return PKT_ACKED;
|
||||
case BV(NRF24L01_07_MAX_RT):
|
||||
return PKT_TIMEOUT;
|
||||
}
|
||||
return PKT_PENDING;
|
||||
}
|
||||
|
||||
static void set_rate_channel(uint8_t rate, uint8_t channel)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel); // Defined by model id
|
||||
NRF24L01_SetBitrate(rate); // Defined by model id
|
||||
}
|
||||
|
||||
static void send_search_packet()
|
||||
{
|
||||
uint8_t buf[1];
|
||||
buf[0] = 0xff;
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if (rf_ch_num++ > 125)
|
||||
{
|
||||
rf_ch_num = 0;
|
||||
switch(data_rate)
|
||||
{
|
||||
case NRF24L01_BR_250K:
|
||||
data_rate = NRF24L01_BR_1M;
|
||||
break;
|
||||
case NRF24L01_BR_1M:
|
||||
data_rate = NRF24L01_BR_2M;
|
||||
break;
|
||||
case NRF24L01_BR_2M:
|
||||
data_rate = NRF24L01_BR_250K;
|
||||
break;
|
||||
}
|
||||
}
|
||||
set_rate_channel(data_rate, rf_ch_num);
|
||||
|
||||
NRF24L01_WritePayload(buf, sizeof(buf));
|
||||
|
||||
}
|
||||
|
||||
// Frac 16.16
|
||||
#define FRAC_MANTISSA 16 // This means, not IEEE 754...
|
||||
#define FRAC_SCALE (1 << FRAC_MANTISSA)
|
||||
|
||||
// Convert fractional 16.16 to float32
|
||||
static void frac2float(int32_t n, float* res)
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
*res = 0.0;
|
||||
return;
|
||||
}
|
||||
uint32_t m = n < 0 ? -n : n; // Figure out mantissa?
|
||||
int i;
|
||||
for (i = (31-FRAC_MANTISSA); (m & 0x80000000) == 0; i--, m <<= 1);
|
||||
m <<= 1; // Clear implicit leftmost 1
|
||||
m >>= 9;
|
||||
uint32_t e = 127 + i;
|
||||
if (n < 0) m |= 0x80000000;
|
||||
m |= e << 23;
|
||||
*((uint32_t *) res) = m;
|
||||
}
|
||||
|
||||
static void send_crtp_rpyt_packet()
|
||||
{
|
||||
int32_t f_roll;
|
||||
int32_t f_pitch;
|
||||
int32_t f_yaw;
|
||||
uint16_t thrust;
|
||||
|
||||
uint16_t val;
|
||||
|
||||
struct CommanderPacketRPYT
|
||||
{
|
||||
float roll;
|
||||
float pitch;
|
||||
float yaw;
|
||||
uint16_t thrust;
|
||||
}__attribute__((packed)) cpkt;
|
||||
|
||||
// Channels in AETR order
|
||||
// Roll, aka aileron, float +- 50.0 in degrees
|
||||
// float roll = -(float) Channels[0]*50.0/10000;
|
||||
val = convert_channel_16b_limit(AILERON, -10000, 10000);
|
||||
// f_roll = -Channels[0] * FRAC_SCALE / (10000 / 50);
|
||||
f_roll = val * FRAC_SCALE / (10000 / 50);
|
||||
|
||||
frac2float(f_roll, &cpkt.roll); // TODO: Remove this and use the correct Mode switch below...
|
||||
// debugln("Roll: raw, converted: %d, %d, %d, %0.2f", Channel_data[AILERON], val, f_roll, cpkt.roll);
|
||||
|
||||
// Pitch, aka elevator, float +- 50.0 degrees
|
||||
//float pitch = -(float) Channels[1]*50.0/10000;
|
||||
val = convert_channel_16b_limit(ELEVATOR, -10000, 10000);
|
||||
// f_pitch = -Channels[1] * FRAC_SCALE / (10000 / 50);
|
||||
f_pitch = -val * FRAC_SCALE / (10000 / 50);
|
||||
|
||||
frac2float(f_pitch, &cpkt.pitch); // TODO: Remove this and use the correct Mode switch below...
|
||||
// debugln("Pitch: raw, converted: %d, %d, %d, %0.2f", Channel_data[ELEVATOR], val, f_pitch, cpkt.pitch);
|
||||
|
||||
// Thrust, aka throttle 0..65535, working range 5535..65535
|
||||
// Android Crazyflie app puts out a throttle range of 0-80%: 0..52000
|
||||
thrust = convert_channel_16b_limit(THROTTLE, 0, 32767) * 2;
|
||||
|
||||
// Crazyflie needs zero thrust to unlock
|
||||
if (thrust < 900)
|
||||
cpkt.thrust = 0;
|
||||
else
|
||||
cpkt.thrust = thrust;
|
||||
|
||||
// debugln("Thrust: raw, converted: %d, %u, %u", Channel_data[THROTTLE], thrust, cpkt.thrust);
|
||||
|
||||
// Yaw, aka rudder, float +- 400.0 deg/s
|
||||
// float yaw = -(float) Channels[3]*400.0/10000;
|
||||
val = convert_channel_16b_limit(RUDDER, -10000, 10000);
|
||||
// f_yaw = - Channels[3] * FRAC_SCALE / (10000 / 400);
|
||||
f_yaw = val * FRAC_SCALE / (10000 / 400);
|
||||
frac2float(f_yaw, &cpkt.yaw);
|
||||
|
||||
// debugln("Yaw: raw, converted: %d, %d, %d, %0.2f", Channel_data[RUDDER], val, f_yaw, cpkt.yaw);
|
||||
|
||||
// Switch on/off?
|
||||
// TODO: Get X or + mode working again:
|
||||
// if (Channels[4] >= 0) {
|
||||
// frac2float(f_roll, &cpkt.roll);
|
||||
// frac2float(f_pitch, &cpkt.pitch);
|
||||
// } else {
|
||||
// // Rotate 45 degrees going from X to + mode or opposite.
|
||||
// // 181 / 256 = 0.70703125 ~= sqrt(2) / 2
|
||||
// int32_t f_x_roll = (f_roll + f_pitch) * 181 / 256;
|
||||
// frac2float(f_x_roll, &cpkt.roll);
|
||||
// int32_t f_x_pitch = (f_pitch - f_roll) * 181 / 256;
|
||||
// frac2float(f_x_pitch, &cpkt.pitch);
|
||||
// }
|
||||
|
||||
// Construct and send packet
|
||||
packet[0] = crtp_create_header(CRTP_PORT_SETPOINT, 0); // Commander packet to channel 0
|
||||
memcpy(&packet[1], (char*) &cpkt, sizeof(cpkt));
|
||||
tx_payload_len = 1 + sizeof(cpkt);
|
||||
send_packet();
|
||||
}
|
||||
|
||||
/*static void send_crtp_cppm_emu_packet()
|
||||
{
|
||||
struct CommanderPacketCppmEmu {
|
||||
struct {
|
||||
uint8_t numAuxChannels : 4; // Set to 0 through MAX_AUX_RC_CHANNELS
|
||||
uint8_t reserved : 4;
|
||||
} hdr;
|
||||
uint16_t channelRoll;
|
||||
uint16_t channelPitch;
|
||||
uint16_t channelYaw;
|
||||
uint16_t channelThrust;
|
||||
uint16_t channelAux[10];
|
||||
} __attribute__((packed)) cpkt;
|
||||
|
||||
// To emulate PWM RC signals, rescale channels from (-10000,10000) to (1000,2000)
|
||||
// This is done by dividing by 20 to get a total range of 1000 (-500,500)
|
||||
// and then adding 1500 to to rebase the offset
|
||||
#define RESCALE_RC_CHANNEL_TO_PWM(chan) ((chan / 20) + 1500)
|
||||
|
||||
// Make sure the number of aux channels in use is capped to MAX_CPPM_AUX_CHANNELS
|
||||
// uint8_t numAuxChannels = Model.num_channels - 4;
|
||||
uint8_t numAuxChannels = 2; // TODO: Figure this out correctly
|
||||
if(numAuxChannels > MAX_CPPM_AUX_CHANNELS)
|
||||
{
|
||||
numAuxChannels = MAX_CPPM_AUX_CHANNELS;
|
||||
}
|
||||
|
||||
cpkt.hdr.numAuxChannels = numAuxChannels;
|
||||
|
||||
// Remap AETR to AERT (RPYT)
|
||||
cpkt.channelRoll = convert_channel_16b_limit(AILERON,1000,2000);
|
||||
cpkt.channelPitch = convert_channel_16b_limit(ELEVATOR,1000,2000);
|
||||
// Note: T & R Swapped:
|
||||
cpkt.channelYaw = convert_channel_16b_limit(RUDDER, 1000, 2000);
|
||||
cpkt.channelThrust = convert_channel_16b_limit(THROTTLE, 1000, 2000);
|
||||
|
||||
// Rescale the rest of the aux channels - RC channel 4 and up
|
||||
for (uint8_t i = 4; i < 14; i++)
|
||||
{
|
||||
cpkt.channelAux[i] = convert_channel_16b_limit(i, 1000, 2000);
|
||||
}
|
||||
|
||||
// Total size of the commander packet is a 1-byte header, 4 2-byte channels and
|
||||
// a variable number of 2-byte auxiliary channels
|
||||
uint8_t commanderPacketSize = 1 + 8 + (2*numAuxChannels);
|
||||
|
||||
// Construct and send packet
|
||||
packet[0] = crtp_create_header(CRTP_PORT_SETPOINT_GENERIC, 0); // Generic setpoint packet to channel 0
|
||||
packet[1] = CRTP_SETPOINT_GENERIC_CPPM_EMU_TYPE;
|
||||
|
||||
// Copy the header (1) plus 4 2-byte channels (8) plus whatever number of 2-byte aux channels are in use
|
||||
memcpy(&packet[2], (char*)&cpkt, commanderPacketSize); // Why not use sizeof(cpkt) here??
|
||||
tx_payload_len = 2 + commanderPacketSize; // CRTP header, commander type, and packet
|
||||
send_packet();
|
||||
}*/
|
||||
|
||||
static void send_cmd_packet()
|
||||
{
|
||||
// TODO: Fix this so we can actually configure the packet type
|
||||
// switch(Model.proto_opts[PROTOOPTS_CRTP_MODE])
|
||||
// {
|
||||
// case CRTP_MODE_CPPM:
|
||||
// send_crtp_cppm_emu_packet();
|
||||
// break;
|
||||
// case CRTP_MODE_RPYT:
|
||||
// send_crtp_rpyt_packet();
|
||||
// break;
|
||||
// default:
|
||||
// send_crtp_rpyt_packet();
|
||||
// }
|
||||
|
||||
// send_crtp_cppm_emu_packet(); // oh maAAAn
|
||||
send_crtp_rpyt_packet();
|
||||
}
|
||||
|
||||
// State machine for setting up CRTP logging
|
||||
// returns 1 when the state machine has completed, 0 otherwise
|
||||
static uint8_t crtp_log_setup_state_machine()
|
||||
{
|
||||
uint8_t state_machine_completed = 0;
|
||||
// A note on the design of this state machine:
|
||||
//
|
||||
// Responses from the crazyflie come in the form of ACK payloads.
|
||||
// There is no retry logic associated with ACK payloads, so it is possible
|
||||
// to miss a response from the crazyflie. To avoid this, the request
|
||||
// packet must be re-sent until the expected response is received. However,
|
||||
// re-sending the same request generates another response in the crazyflie
|
||||
// Rx queue, which can produce large backlogs of duplicate responses.
|
||||
//
|
||||
// To avoid this backlog but still guard against dropped ACK payloads,
|
||||
// transmit cmd packets (which don't generate responses themselves)
|
||||
// until an empty ACK payload is received (the crazyflie alternates between
|
||||
// 0xF3 and 0xF7 for empty ACK payloads) which indicates the Rx queue on the
|
||||
// crazyflie has been drained. If the queue has been drained and the
|
||||
// desired ACK has still not been received, it was likely dropped and the
|
||||
// request should be re-transmit.
|
||||
|
||||
switch (crtp_log_setup_state) {
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_INIT:
|
||||
toc_size = 0;
|
||||
next_toc_variable = 0;
|
||||
vbat_var_id = 0;
|
||||
extvbat_var_id = 0;
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO;
|
||||
// fallthrough
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_INFO;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC);
|
||||
packet[1] = CRTP_LOG_TOC_CMD_INFO;
|
||||
tx_payload_len = 2;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_INFO:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 3
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC)
|
||||
&& rx_packet[1] == CRTP_LOG_TOC_CMD_INFO) {
|
||||
// Received the ACK payload. Save the toc_size
|
||||
// and advance to the next state
|
||||
toc_size = rx_packet[2];
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM;
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_ITEM;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC);
|
||||
packet[1] = CRTP_LOG_TOC_CMD_ELEMENT;
|
||||
packet[2] = next_toc_variable;
|
||||
tx_payload_len = 3;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_ITEM:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 3
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC)
|
||||
&& rx_packet[1] == CRTP_LOG_TOC_CMD_ELEMENT
|
||||
&& rx_packet[2] == next_toc_variable) {
|
||||
// For every element in the TOC we must compare its
|
||||
// type (rx_packet[3]), group and name (back to back
|
||||
// null terminated strings starting with the fifth byte)
|
||||
// and see if it matches any of the variables we need
|
||||
// for logging
|
||||
//
|
||||
// Currently enabled for logging:
|
||||
// - vbatMV (LOG_UINT16)
|
||||
// - extVbatMV (LOG_UINT16)
|
||||
// - rssi (LOG_UINT8)
|
||||
if(rx_packet[3] == vbat_var_type
|
||||
&& (0 == strcmp((char*)&rx_packet[4], pm_group_name))
|
||||
&& (0 == strcmp((char*)&rx_packet[4 + strlen(pm_group_name) + 1], vbat_var_name))) {
|
||||
// Found the vbat element - save it for later
|
||||
vbat_var_id = next_toc_variable;
|
||||
}
|
||||
|
||||
if(rx_packet[3] == extvbat_var_type
|
||||
&& (0 == strcmp((char*)&rx_packet[4], pm_group_name))
|
||||
&& (0 == strcmp((char*)&rx_packet[4 + strlen(pm_group_name) + 1], extvbat_var_name))) {
|
||||
// Found the extvbat element - save it for later
|
||||
extvbat_var_id = next_toc_variable;
|
||||
}
|
||||
|
||||
if(rx_packet[3] == rssi_var_type
|
||||
&& (0 == strcmp((char*)&rx_packet[4], radio_group_name))
|
||||
&& (0 == strcmp((char*)&rx_packet[4 + strlen(radio_group_name) + 1], rssi_var_name))) {
|
||||
// Found the rssi element - save it for later
|
||||
rssi_var_id = next_toc_variable;
|
||||
}
|
||||
|
||||
// Advance the toc variable counter
|
||||
// If there are more variables, read them
|
||||
// If not, move on to the next state
|
||||
next_toc_variable += 1;
|
||||
if(next_toc_variable >= toc_size) {
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK;
|
||||
} else {
|
||||
// There are more TOC elements to get
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM;
|
||||
}
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS);
|
||||
packet[1] = CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK;
|
||||
packet[2] = CFLIE_TELEM_LOG_BLOCK_ID; // Log block ID
|
||||
packet[3] = vbat_var_type; // Variable type
|
||||
packet[4] = vbat_var_id; // ID of the VBAT variable
|
||||
packet[5] = extvbat_var_type; // Variable type
|
||||
packet[6] = extvbat_var_id; // ID of the ExtVBat variable
|
||||
packet[7] = rssi_var_type; // Variable type
|
||||
packet[8] = rssi_var_id; // ID of the RSSI variable
|
||||
tx_payload_len = 9;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 2
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS)
|
||||
&& rx_packet[1] == CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK) {
|
||||
// Received the ACK payload. Advance to the next state
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK;
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_START_BLOCK;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS);
|
||||
packet[1] = CRTP_LOG_SETTINGS_CMD_START_LOGGING;
|
||||
packet[2] = CFLIE_TELEM_LOG_BLOCK_ID; // Log block ID 1
|
||||
packet[3] = CFLIE_TELEM_LOG_BLOCK_PERIOD_10MS; // Log frequency in 10ms units
|
||||
tx_payload_len = 4;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_START_BLOCK:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 2
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS)
|
||||
&& rx_packet[1] == CRTP_LOG_SETTINGS_CMD_START_LOGGING) {
|
||||
// Received the ACK payload. Advance to the next state
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_COMPLETE;
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_COMPLETE:
|
||||
state_machine_completed = 1;
|
||||
return state_machine_completed;
|
||||
break;
|
||||
}
|
||||
|
||||
return state_machine_completed;
|
||||
}
|
||||
|
||||
static void CFLIE_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
|
||||
// CRC, radio on
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x01); // Auto Acknowledgement for data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x13); // 3 retransmits, 500us delay
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num); // Defined in initialize_rx_tx_addr
|
||||
NRF24L01_SetBitrate(data_rate); // Defined in initialize_rx_tx_addr
|
||||
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, TX_ADDR_SIZE);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, TX_ADDR_SIZE);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x01); // Enable Dynamic Payload Length on pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x06); // Enable Dynamic Payload Length, enable Payload with ACK
|
||||
|
||||
NRF24L01_SetTxRxMode(TX_EN); // Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
|
||||
}
|
||||
|
||||
// TODO: Fix telemetry
|
||||
|
||||
// Update telemetry using the CRTP logging framework
|
||||
// static void update_telemetry_crtplog()
|
||||
// {
|
||||
// static uint8_t frameloss = 0;
|
||||
|
||||
// // Read and reset count of dropped packets
|
||||
// frameloss += NRF24L01_ReadReg(NRF24L01_08_OBSERVE_TX) >> 4;
|
||||
// NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num); // reset packet loss counter
|
||||
// Telemetry.value[TELEM_DSM_FLOG_FRAMELOSS] = frameloss;
|
||||
// TELEMETRY_SetUpdated(TELEM_DSM_FLOG_FRAMELOSS);
|
||||
|
||||
// if (packet_ack() == PKT_ACKED) {
|
||||
// // See if the ACK packet is a cflie log packet
|
||||
// // A log data packet is a minimum of 5 bytes. Ignore anything less.
|
||||
// if (rx_payload_len >= 5) {
|
||||
// // Port 5 = log, Channel 2 = data
|
||||
// if (rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_LOGDATA)) {
|
||||
// // The log block ID
|
||||
// if (rx_packet[1] == CFLIE_TELEM_LOG_BLOCK_ID) {
|
||||
// // Bytes 5 and 6 are the Vbat in mV units
|
||||
// uint16_t vBat;
|
||||
// memcpy(&vBat, &rx_packet[5], sizeof(uint16_t));
|
||||
// Telemetry.value[TELEM_CFLIE_INTERNAL_VBAT] = (int32_t) (vBat / 10); // The log value expects centivolts
|
||||
// TELEMETRY_SetUpdated(TELEM_CFLIE_INTERNAL_VBAT);
|
||||
|
||||
// // Bytes 7 and 8 are the ExtVbat in mV units
|
||||
// uint16_t extVBat;
|
||||
// memcpy(&extVBat, &rx_packet[7], sizeof(uint16_t));
|
||||
// Telemetry.value[TELEM_CFLIE_EXTERNAL_VBAT] = (int32_t) (extVBat / 10); // The log value expects centivolts
|
||||
// TELEMETRY_SetUpdated(TELEM_CFLIE_EXTERNAL_VBAT);
|
||||
|
||||
// // Byte 9 is the RSSI
|
||||
// Telemetry.value[TELEM_CFLIE_RSSI] = rx_packet[9];
|
||||
// TELEMETRY_SetUpdated(TELEM_CFLIE_RSSI);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Update telemetry using the ACK packet payload
|
||||
// static void update_telemetry_ackpkt()
|
||||
// {
|
||||
// static uint8_t frameloss = 0;
|
||||
|
||||
// // Read and reset count of dropped packets
|
||||
// frameloss += NRF24L01_ReadReg(NRF24L01_08_OBSERVE_TX) >> 4;
|
||||
// NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num); // reset packet loss counter
|
||||
// Telemetry.value[TELEM_DSM_FLOG_FRAMELOSS] = frameloss;
|
||||
// TELEMETRY_SetUpdated(TELEM_DSM_FLOG_FRAMELOSS);
|
||||
|
||||
// if (packet_ack() == PKT_ACKED) {
|
||||
// // Make sure this is an ACK packet (first byte will alternate between 0xF3 and 0xF7
|
||||
// if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// // If ACK packet contains RSSI (proper length and byte 1 is 0x01)
|
||||
// if(rx_payload_len >= 3 && rx_packet[1] == 0x01) {
|
||||
// Telemetry.value[TELEM_CFLIE_RSSI] = rx_packet[2];
|
||||
// TELEMETRY_SetUpdated(TELEM_CFLIE_RSSI);
|
||||
// }
|
||||
// // If ACK packet contains VBAT (proper length and byte 3 is 0x02)
|
||||
// if(rx_payload_len >= 8 && rx_packet[3] == 0x02) {
|
||||
// uint32_t vBat = 0;
|
||||
// memcpy(&vBat, &rx_packet[4], sizeof(uint32_t));
|
||||
// Telemetry.value[TELEM_CFLIE_INTERNAL_VBAT] = (int32_t)(vBat / 10); // The log value expects centivolts
|
||||
// TELEMETRY_SetUpdated(TELEM_CFLIE_INTERNAL_VBAT);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
static uint16_t CFLIE_callback()
|
||||
{
|
||||
switch (phase) {
|
||||
case CFLIE_INIT_SEARCH:
|
||||
send_search_packet();
|
||||
phase = CFLIE_SEARCH;
|
||||
break;
|
||||
case CFLIE_INIT_CRTP_LOG:
|
||||
if (crtp_log_setup_state_machine()) {
|
||||
phase = CFLIE_INIT_DATA;
|
||||
}
|
||||
break;
|
||||
case CFLIE_INIT_DATA:
|
||||
send_cmd_packet();
|
||||
phase = CFLIE_DATA;
|
||||
break;
|
||||
case CFLIE_SEARCH:
|
||||
switch (packet_ack()) {
|
||||
case PKT_PENDING:
|
||||
return PACKET_CHKTIME; // packet send not yet complete
|
||||
case PKT_ACKED:
|
||||
phase = CFLIE_DATA;
|
||||
// PROTOCOL_SetBindState(0);
|
||||
// MUSIC_Play(MUSIC_DONE_BINDING);
|
||||
BIND_DONE;
|
||||
break;
|
||||
case PKT_TIMEOUT:
|
||||
send_search_packet();
|
||||
}
|
||||
break;
|
||||
|
||||
case CFLIE_DATA:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(CFLIE_PACKET_PERIOD);
|
||||
#endif
|
||||
// if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_CRTPLOG) {
|
||||
// update_telemetry_crtplog();
|
||||
// } else if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_ACKPKT) {
|
||||
// update_telemetry_ackpkt();
|
||||
// }
|
||||
|
||||
if (packet_ack() == PKT_PENDING)
|
||||
return PACKET_CHKTIME; // packet send not yet complete
|
||||
send_cmd_packet();
|
||||
break;
|
||||
}
|
||||
return CFLIE_PACKET_PERIOD; // Packet at standard protocol interval
|
||||
}
|
||||
|
||||
// Generate address to use from TX id and manufacturer id (STM32 unique id)
|
||||
static uint8_t CFLIE_initialize_rx_tx_addr()
|
||||
{
|
||||
rx_tx_addr[0] =
|
||||
rx_tx_addr[1] =
|
||||
rx_tx_addr[2] =
|
||||
rx_tx_addr[3] =
|
||||
rx_tx_addr[4] = 0xE7; // CFlie uses fixed address
|
||||
|
||||
// if (Model.fixed_id) {
|
||||
// rf_ch_num = Model.fixed_id % 100;
|
||||
// switch (Model.fixed_id / 100) {
|
||||
// case 0:
|
||||
// data_rate = NRF24L01_BR_250K;
|
||||
// break;
|
||||
// case 1:
|
||||
// data_rate = NRF24L01_BR_1M;
|
||||
// break;
|
||||
// case 2:
|
||||
// data_rate = NRF24L01_BR_2M;
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_CRTPLOG) {
|
||||
// return CFLIE_INIT_CRTP_LOG;
|
||||
// } else {
|
||||
// return CFLIE_INIT_DATA;
|
||||
// }
|
||||
// } else {
|
||||
// data_rate = NRF24L01_BR_250K;
|
||||
// rf_ch_num = 10;
|
||||
// return CFLIE_INIT_SEARCH;
|
||||
// }
|
||||
|
||||
// Default 1
|
||||
data_rate = NRF24L01_BR_1M;
|
||||
rf_ch_num = 10;
|
||||
|
||||
// Default 2
|
||||
// data_rate = NRF24L01_BR_2M;
|
||||
// rf_ch_num = 110;
|
||||
return CFLIE_INIT_SEARCH;
|
||||
}
|
||||
|
||||
void CFLIE_init(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
|
||||
phase = CFLIE_initialize_rx_tx_addr();
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_INIT;
|
||||
packet_count=0;
|
||||
|
||||
CFLIE_RF_init();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -13,23 +13,17 @@
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// compatible with EAchine 3D X4, CG023/CG031, Attop YD-822/YD-829/YD-829C and H8_3D/JJRC H20/H22
|
||||
// Merged CG023 and H8_3D protocols
|
||||
// Last sync with hexfet new_protocols/cg023_nrf24l01.c dated 2015-10-03
|
||||
// Last sync with hexfet new_protocols/h8_3d_nrf24l01.c dated 2015-11-18
|
||||
|
||||
#if defined(CG023_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define CG023_PACKET_PERIOD 8200 // Timeout for callback in uSec
|
||||
#define CG023_INITIAL_WAIT 500
|
||||
#define CG023_PACKET_SIZE 15 // packets have 15-byte payload
|
||||
#define CG023_RF_BIND_CHANNEL 0x2D
|
||||
#define CG023_BIND_COUNT 1000 // 8 seconds
|
||||
#define CG023_BIND_COUNT 500 // 4 seconds
|
||||
#define YD829_PACKET_PERIOD 4100 // Timeout for callback in uSec
|
||||
#define H8_3D_PACKET_PERIOD 1800 // Timeout for callback in uSec
|
||||
#define H8_3D_PACKET_SIZE 20
|
||||
#define H8_3D_RF_NUM_CHANNELS 4
|
||||
|
||||
|
||||
enum CG023_FLAGS {
|
||||
@@ -55,232 +49,112 @@ enum YD829_FLAGS {
|
||||
YD829_FLAG_STILL = 0x80,
|
||||
};
|
||||
|
||||
enum H8_3D_FLAGS {
|
||||
// flags going to packet[17]
|
||||
H8_3D_FLAG_FLIP = 0x01,
|
||||
H8_3D_FLAG_RATE_MID = 0x02,
|
||||
H8_3D_FLAG_RATE_HIGH = 0x04,
|
||||
H8_3D_FLAG_LIGTH = 0x08, // Light on H22
|
||||
H8_3D_FLAG_HEADLESS = 0x10, // RTH + headless on H8, headless on JJRC H20, RTH on H22
|
||||
H8_3D_FLAG_RTH = 0x20, // 360 flip mode on H8 3D and H22, RTH on JJRC H20
|
||||
};
|
||||
|
||||
enum H8_3D_FLAGS_2 {
|
||||
// flags going to packet[18]
|
||||
H8_3D_FLAG_CALIBRATE = 0x20, // accelerometer calibration
|
||||
};
|
||||
|
||||
static void CG023_send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) CG023_send_packet()
|
||||
{
|
||||
// throttle : 0x00 - 0xFF
|
||||
throttle=convert_channel_8b(THROTTLE);
|
||||
// rudder
|
||||
rudder = convert_channel_8b_scale(RUDDER,0x44,0xBC); // yaw right : 0x80 (neutral) - 0xBC (right)
|
||||
rudder = convert_channel_16b_limit(RUDDER,0x44,0xBC); // yaw right : 0x80 (neutral) - 0xBC (right)
|
||||
if (rudder<=0x80)
|
||||
rudder=0x80-rudder; // yaw left : 0x00 (neutral) - 0x3C (left)
|
||||
// elevator : 0xBB - 0x7F - 0x43
|
||||
elevator = convert_channel_8b_scale(ELEVATOR, 0x43, 0xBB);
|
||||
elevator = convert_channel_16b_limit(ELEVATOR, 0x43, 0xBB);
|
||||
// aileron : 0x43 - 0x7F - 0xBB
|
||||
aileron = convert_channel_8b_scale(AILERON, 0x43, 0xBB);
|
||||
aileron = convert_channel_16b_limit(AILERON, 0x43, 0xBB);
|
||||
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[0]= 0xaa;
|
||||
XN297_RFChannel(CG023_RF_BIND_CHANNEL);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0]= 0x55;
|
||||
XN297_RFChannel(hopping_frequency_no);
|
||||
}
|
||||
// transmitter id
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
if(sub_protocol==H8_3D)
|
||||
// unknown
|
||||
packet[3] = 0x00;
|
||||
packet[4] = 0x00;
|
||||
packet[5] = throttle;
|
||||
packet[6] = rudder;
|
||||
packet[7] = elevator;
|
||||
packet[8] = aileron;
|
||||
// throttle trim : 0x30 - 0x20 - 0x10
|
||||
packet[9] = 0x20; // neutral
|
||||
// neutral trims
|
||||
packet[10] = 0x20;
|
||||
packet[11] = 0x40;
|
||||
packet[12] = 0x40;
|
||||
if(sub_protocol==CG023)
|
||||
{
|
||||
packet[0] = 0x13;
|
||||
packet[3] = rx_tx_addr[2];
|
||||
packet[4] = rx_tx_addr[3];
|
||||
packet[8] = rx_tx_addr[0]+rx_tx_addr[1]+rx_tx_addr[2]+rx_tx_addr[3]; // txid checksum
|
||||
memset(&packet[9], 0, 10);
|
||||
if (bind)
|
||||
{
|
||||
packet[5] = 0x00;
|
||||
packet[6] = 0x00;
|
||||
packet[7] = 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[5] = hopping_frequency_no;
|
||||
packet[6] = 0x08;
|
||||
packet[7] = 0x03;
|
||||
packet[9] = throttle;
|
||||
packet[10] = rudder;
|
||||
packet[11] = elevator;
|
||||
packet[12] = aileron;
|
||||
// neutral trims
|
||||
packet[13] = 0x20;
|
||||
packet[14] = 0x20;
|
||||
packet[15] = 0x20;
|
||||
packet[16] = 0x20;
|
||||
packet[17] = H8_3D_FLAG_RATE_HIGH;
|
||||
if(Servo_AUX1)
|
||||
packet[17] |= H8_3D_FLAG_FLIP;
|
||||
if(Servo_AUX2)
|
||||
packet[17] |= H8_3D_FLAG_LIGTH; //H22 light
|
||||
if(Servo_AUX3)
|
||||
packet[17] |= H8_3D_FLAG_HEADLESS;
|
||||
if(Servo_AUX4)
|
||||
packet[17] |= H8_3D_FLAG_RTH; // 180/360 flip mode on H8 3D
|
||||
if(Servo_AUX5)
|
||||
packet[18] = H8_3D_FLAG_CALIBRATE;
|
||||
}
|
||||
uint8_t sum = packet[9];
|
||||
for (uint8_t i=10; i < H8_3D_PACKET_SIZE-1; i++)
|
||||
sum += packet[i];
|
||||
packet[19] = sum; // data checksum
|
||||
// rate
|
||||
packet[13] = CG023_FLAG_RATE_HIGH
|
||||
| GET_FLAG(CH5_SW,CG023_FLAG_FLIP)
|
||||
| GET_FLAG(CH6_SW,CG023_FLAG_LED_OFF)
|
||||
| GET_FLAG(CH7_SW,CG023_FLAG_STILL)
|
||||
| GET_FLAG(CH8_SW,CG023_FLAG_VIDEO)
|
||||
| GET_FLAG(CH9_SW,CG023_FLAG_EASY);
|
||||
}
|
||||
else
|
||||
{ // CG023 and YD829
|
||||
if (bind)
|
||||
packet[0]= 0xaa;
|
||||
else
|
||||
packet[0]= 0x55;
|
||||
// transmitter id
|
||||
// unknown
|
||||
packet[3] = 0x00;
|
||||
packet[4] = 0x00;
|
||||
packet[5] = throttle;
|
||||
packet[6] = rudder;
|
||||
packet[7] = elevator;
|
||||
packet[8] = aileron;
|
||||
// throttle trim : 0x30 - 0x20 - 0x10
|
||||
packet[9] = 0x20; // neutral
|
||||
// neutral trims
|
||||
packet[10] = 0x20;
|
||||
packet[11] = 0x40;
|
||||
packet[12] = 0x40;
|
||||
if(sub_protocol==CG023)
|
||||
{
|
||||
// rate
|
||||
packet[13] = CG023_FLAG_RATE_HIGH;
|
||||
// flags
|
||||
if(Servo_AUX1)
|
||||
packet[13] |= CG023_FLAG_FLIP;
|
||||
if(Servo_AUX2)
|
||||
packet[13] |= CG023_FLAG_LED_OFF;
|
||||
if(Servo_AUX3)
|
||||
packet[13] |= CG023_FLAG_STILL;
|
||||
if(Servo_AUX4)
|
||||
packet[13] |= CG023_FLAG_VIDEO;
|
||||
if(Servo_AUX5)
|
||||
packet[13] |= CG023_FLAG_EASY;
|
||||
}
|
||||
else
|
||||
{// YD829
|
||||
// rate
|
||||
packet[13] = YD829_FLAG_RATE_HIGH;
|
||||
// flags
|
||||
if(Servo_AUX1)
|
||||
packet[13] |= YD829_FLAG_FLIP;
|
||||
if(Servo_AUX3)
|
||||
packet[13] |= YD829_FLAG_STILL;
|
||||
if(Servo_AUX4)
|
||||
packet[13] |= YD829_FLAG_VIDEO;
|
||||
if(Servo_AUX5)
|
||||
packet[13] |= YD829_FLAG_HEADLESS;
|
||||
}
|
||||
packet[14] = 0;
|
||||
{// YD829
|
||||
// rate
|
||||
packet[13] = YD829_FLAG_RATE_HIGH
|
||||
| GET_FLAG(CH5_SW,YD829_FLAG_FLIP)
|
||||
| GET_FLAG(CH7_SW,YD829_FLAG_STILL)
|
||||
| GET_FLAG(CH8_SW,YD829_FLAG_VIDEO)
|
||||
| GET_FLAG(CH9_SW,YD829_FLAG_HEADLESS);
|
||||
}
|
||||
packet[14] = 0;
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
if (bind)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, sub_protocol==H8_3D?hopping_frequency[0]:CG023_RF_BIND_CHANNEL);
|
||||
else
|
||||
{
|
||||
if(sub_protocol==H8_3D)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no %= H8_3D_RF_NUM_CHANNELS;
|
||||
}
|
||||
else // CG023 and YD829
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency_no);
|
||||
}
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WritePayload(packet, sub_protocol==H8_3D ? H8_3D_PACKET_SIZE:CG023_PACKET_SIZE);
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
// Send
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_SetPower();
|
||||
XN297_WritePayload(packet, CG023_PACKET_SIZE);
|
||||
}
|
||||
|
||||
static void CG023_init()
|
||||
static void __attribute__((unused)) CG023_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
if(sub_protocol==H8_3D)
|
||||
XN297_SetTXAddr((uint8_t *)"\xC4\x57\x09\x65\x21", 5);
|
||||
else // CG023 and YD829
|
||||
XN297_SetTXAddr((uint8_t *)"\x26\xA8\x67\x35\xCC", 5);
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
XN297_SetTXAddr((uint8_t *)"\x26\xA8\x67\x35\xCC", 5);
|
||||
}
|
||||
|
||||
uint16_t CG023_callback()
|
||||
{
|
||||
if(IS_BIND_DONE_on)
|
||||
CG023_send_packet(0);
|
||||
else
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
if(bind_counter)
|
||||
{
|
||||
bind_counter--;
|
||||
if (bind_counter == 0)
|
||||
BIND_DONE;
|
||||
else
|
||||
{
|
||||
CG023_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
|
||||
if(sub_protocol==CG023)
|
||||
return CG023_PACKET_PERIOD;
|
||||
else
|
||||
if(sub_protocol==YD829)
|
||||
return YD829_PACKET_PERIOD;
|
||||
return H8_3D_PACKET_PERIOD;
|
||||
CG023_send_packet();
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
static void CG023_initialize_txid()
|
||||
static void __attribute__((unused)) CG023_initialize_txid()
|
||||
{
|
||||
if(sub_protocol==H8_3D)
|
||||
{
|
||||
rx_tx_addr[0] = 0xa0 + (rx_tx_addr[0] % 0x10);
|
||||
rx_tx_addr[1] = 0xb0 + (rx_tx_addr[1] % 0x20);
|
||||
rx_tx_addr[2] = rx_tx_addr[2] % 0x20;
|
||||
rx_tx_addr[3] = rx_tx_addr[3] % 0x11;
|
||||
|
||||
hopping_frequency[0] = 0x06 + (rx_tx_addr[0]&0x0f);
|
||||
hopping_frequency[1] = 0x15 + (rx_tx_addr[1]&0x0f);
|
||||
hopping_frequency[2] = 0x24 + (rx_tx_addr[2]&0x0f);
|
||||
hopping_frequency[3] = 0x33 + (rx_tx_addr[3]&0x0f);
|
||||
}
|
||||
else
|
||||
{ // CG023 and YD829
|
||||
rx_tx_addr[0]= 0x80 | (rx_tx_addr[0] % 0x40);
|
||||
if( rx_tx_addr[0] == 0xAA) // avoid using same freq for bind and data channel
|
||||
rx_tx_addr[0] ++;
|
||||
hopping_frequency_no = rx_tx_addr[0] - 0x7D; // rf channel for data packets
|
||||
}
|
||||
rx_tx_addr[0]= 0x80 | (rx_tx_addr[0] % 0x40);
|
||||
if( rx_tx_addr[0] == 0xAA) // avoid using same freq for bind and data channel
|
||||
rx_tx_addr[0] ++;
|
||||
hopping_frequency_no = rx_tx_addr[0] - 0x7D; // rf channel for data packets
|
||||
}
|
||||
|
||||
uint16_t initCG023(void)
|
||||
void CG023_init(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = CG023_BIND_COUNT;
|
||||
CG023_initialize_txid();
|
||||
CG023_init();
|
||||
CG023_RF_init();
|
||||
if(sub_protocol==CG023)
|
||||
return CG023_INITIAL_WAIT+CG023_PACKET_PERIOD;
|
||||
else
|
||||
if(sub_protocol==YD829)
|
||||
return CG023_INITIAL_WAIT+YD829_PACKET_PERIOD;
|
||||
return CG023_INITIAL_WAIT+H8_3D_PACKET_PERIOD;
|
||||
packet_period=CG023_PACKET_PERIOD;
|
||||
else // YD829
|
||||
packet_period=YD829_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,24 +12,24 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// compatible with Cheerson CX-10 blue & newer red pcb, CX-10A, CX11, CX-10 green pcb, DM007, Floureon FX-10, CX-Stars
|
||||
// compatible with Cheerson CX-10 blue & newer red pcb, CX-10A, CX11, CX-10 green pcb, DM007, Floureon FX-10, JXD 509 (Q282), Q222, Q242 and Q282
|
||||
// Last sync with hexfet new_protocols/cx10_nrf24l01.c dated 2015-11-26
|
||||
|
||||
#if defined(CX10_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define CX10_BIND_COUNT 4360 // 6 seconds
|
||||
#define CX10_PACKET_SIZE 15
|
||||
#define CX10A_PACKET_SIZE 19 // CX10 blue board packets have 19-byte payload
|
||||
#define Q282_PACKET_SIZE 21
|
||||
#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
|
||||
#define CX10A_PACKET_PERIOD 6000
|
||||
#define CX10_BIND_COUNT 4360 // 6 seconds
|
||||
#define CX10_PACKET_SIZE 15
|
||||
#define CX10A_PACKET_SIZE 19 // CX10 blue board packets have 19-byte payload
|
||||
#define Q2X2_PACKET_SIZE 21
|
||||
#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
|
||||
#define CX10A_PACKET_PERIOD 6000
|
||||
|
||||
#define INITIAL_WAIT 500
|
||||
#define CX10_INITIAL_WAIT 500
|
||||
|
||||
// flags
|
||||
#define CX10_FLAG_FLIP 0x10 // goes to rudder channel
|
||||
#define CX10_FLAG_FLIP 0x10 // goes to rudder channel
|
||||
#define CX10_FLAG_MODE_MASK 0x03
|
||||
#define CX10_FLAG_HEADLESS 0x04
|
||||
// flags2
|
||||
@@ -37,8 +37,8 @@
|
||||
#define CX10_FLAG_SNAPSHOT 0x04
|
||||
|
||||
// frequency channel management
|
||||
#define RF_BIND_CHANNEL 0x02
|
||||
#define NUM_RF_CHANNELS 4
|
||||
#define CX10_RF_BIND_CHANNEL 0x02
|
||||
#define CX10_NUM_RF_CHANNELS 4
|
||||
|
||||
enum {
|
||||
CX10_BIND1 = 0,
|
||||
@@ -46,132 +46,132 @@ enum {
|
||||
CX10_DATA
|
||||
};
|
||||
|
||||
static void CX10_Write_Packet(uint8_t bind)
|
||||
static void __attribute__((unused)) CX10_Write_Packet()
|
||||
{
|
||||
uint8_t offset = 0;
|
||||
if(sub_protocol == CX10_BLUE)
|
||||
offset = 4;
|
||||
packet[0] = bind ? 0xAA : 0x55;
|
||||
packet[0] = IS_BIND_IN_PROGRESS ? 0xAA : 0x55;
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
packet[3] = rx_tx_addr[2];
|
||||
packet[4] = rx_tx_addr[3];
|
||||
// packet[5] to [8] (aircraft id) is filled during bind for blue board
|
||||
packet[5+offset] = lowByte(Servo_data[AILERON]);
|
||||
packet[6+offset]= highByte(Servo_data[AILERON]);
|
||||
packet[7+offset]= lowByte(Servo_data[ELEVATOR]);
|
||||
packet[8+offset]= highByte(Servo_data[ELEVATOR]);
|
||||
packet[9+offset]= lowByte(Servo_data[THROTTLE]);
|
||||
packet[10+offset]= highByte(Servo_data[THROTTLE]);
|
||||
packet[11+offset]= lowByte(Servo_data[RUDDER]);
|
||||
packet[12+offset]= highByte(Servo_data[RUDDER]);
|
||||
|
||||
uint16_t aileron= convert_channel_16b_limit(AILERON ,1000,2000);
|
||||
uint16_t elevator=convert_channel_16b_limit(ELEVATOR,2000,1000);
|
||||
uint16_t throttle=convert_channel_16b_limit(THROTTLE,1000,2000);
|
||||
uint16_t rudder= convert_channel_16b_limit(RUDDER ,2000,1000);
|
||||
// Channel 5 - flip flag
|
||||
if(Servo_AUX1)
|
||||
packet[12+offset] |= CX10_FLAG_FLIP; // flip flag
|
||||
|
||||
//flags=0; // packet 13
|
||||
uint8_t flags2=0; // packet 14
|
||||
packet[12+offset] = GET_FLAG(CH5_SW,CX10_FLAG_FLIP); // flip flag applied on rudder
|
||||
|
||||
// Channel 6 - rate mode is 2 lsb of packet 13
|
||||
if(Servo_data[AUX2] > PPM_MAX_COMMAND) // rate 3 / headless on CX-10A
|
||||
if(CH6_SW) // rate 3 / headless on CX-10A
|
||||
flags = 0x02;
|
||||
else
|
||||
if(Servo_data[AUX2] < PPM_MIN_COMMAND)
|
||||
flags = 0x00; // rate 1
|
||||
if(Channel_data[CH6] < CHANNEL_MIN_COMMAND)
|
||||
flags = 0x00; // rate 1
|
||||
else
|
||||
flags = 0x01; // rate 2
|
||||
flags = 0x01; // rate 2
|
||||
uint8_t flags2=0; // packet 14
|
||||
|
||||
uint8_t video_state=packet[14] & 0x21;
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case CX10_BLUE:
|
||||
if(Servo_AUX3) flags |= 0x10; // Channel 7 - picture
|
||||
if(Servo_AUX4) flags |= 0x08; // Channel 8 - video
|
||||
flags |= GET_FLAG(!CH7_SW, 0x10) // Channel 7 - picture
|
||||
|GET_FLAG( CH8_SW, 0x08); // Channel 8 - video
|
||||
break;
|
||||
case Q282:
|
||||
case F_Q282:
|
||||
case F_Q242:
|
||||
case F_Q222:
|
||||
memcpy(&packet[15], "\x10\x10\xaa\xaa\x00\x00", 6);
|
||||
//FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL
|
||||
if(Servo_AUX1) flags2 =0x80; // Channel 5 - FLIP
|
||||
if(Servo_AUX2) flags2|=0x40; // Channel 6 - LED
|
||||
if(Servo_AUX3) flags2|=0x10; // Channel 7 - picture
|
||||
if(Servo_AUX4) // Channel 8 - video
|
||||
flags2 = GET_FLAG(CH5_SW, 0x80) // Channel 5 - FLIP
|
||||
|GET_FLAG(!CH6_SW, 0x40) // Channel 6 - LED
|
||||
|GET_FLAG(CH9_SW, 0x08) // Channel 9 - HEADLESS
|
||||
|GET_FLAG(CH11_SW, 0x04) // Channel 11 - XCAL
|
||||
|GET_FLAG(CH12_SW, 0x02); // Channel 12 - YCAL or Start/Stop motors on JXD 509
|
||||
|
||||
if(sub_protocol==F_Q242)
|
||||
{
|
||||
if (!(video_state & 0x20)) video_state ^= 0x21;
|
||||
flags=2;
|
||||
flags2|= GET_FLAG(CH7_SW,0x01) // Channel 7 - picture
|
||||
|GET_FLAG(CH8_SW,0x10); // Channel 8 - video
|
||||
packet[17]=0x00;
|
||||
packet[18]=0x00;
|
||||
}
|
||||
else
|
||||
if (video_state & 0x20) video_state &= 0x01;
|
||||
flags2 |= video_state;
|
||||
|
||||
if(Servo_AUX5) flags2|=0x08; // Channel 9 - HEADLESS
|
||||
flags=3;
|
||||
if(Servo_AUX6) flags |=0x80; // Channel 10 - RTH
|
||||
if(Servo_AUX7) flags2|=0x04; // Channel 11 - XCAL
|
||||
if(Servo_AUX8) flags2|=0x02; // Channel 12 - YCAL
|
||||
memcpy(&packet[15], "\x10\x10\xaa\xaa\x00\x00", 6);
|
||||
{ // F_Q282 & F_Q222
|
||||
flags=3; // expert
|
||||
if(CH8_SW) // Channel 8 - F_Q282 video / F_Q222 Module 1
|
||||
{
|
||||
if (!(video_state & 0x20)) video_state ^= 0x21;
|
||||
}
|
||||
else
|
||||
if (video_state & 0x20) video_state &= 0x01;
|
||||
flags2 |= video_state
|
||||
|GET_FLAG(CH7_SW,0x10); // Channel 7 - F_Q282 picture / F_Q222 Module 2
|
||||
}
|
||||
if(CH10_SW) flags |=0x80; // Channel 10 - RTH
|
||||
break;
|
||||
case DM007:
|
||||
aileron = 3000 - aileron;
|
||||
//FLIP|MODE|PICTURE|VIDEO|HEADLESS
|
||||
if(Servo_AUX3) flags2 = CX10_FLAG_SNAPSHOT; // Channel 7 - picture
|
||||
if(Servo_AUX4) flags2|= CX10_FLAG_VIDEO; // Channel 8 - video
|
||||
if(Servo_AUX5) flags |= CX10_FLAG_HEADLESS; // Channel 9 - headless
|
||||
break;
|
||||
case JC3015_1:
|
||||
//FLIP|MODE|PICTURE|VIDEO
|
||||
if(Servo_AUX3) flags2 = _BV(3); // Channel 7 - picture
|
||||
if(Servo_AUX4) flags2|= _BV(4); // Channel 8 - video
|
||||
flags2= GET_FLAG(CH7_SW,CX10_FLAG_SNAPSHOT) // Channel 7 - picture
|
||||
|GET_FLAG(CH8_SW,CX10_FLAG_VIDEO); // Channel 8 - video
|
||||
if(CH9_SW) flags |= CX10_FLAG_HEADLESS; // Channel 9 - headless
|
||||
break;
|
||||
case JC3015_2:
|
||||
aileron = 3000 - aileron;
|
||||
elevator = 3000 - elevator;
|
||||
//FLIP|MODE|LED|DFLIP
|
||||
if(Servo_AUX3) flags2 = _BV(3); // Channel 7 - LED
|
||||
if(Servo_AUX4) flags2|= _BV(4); // Channel 8 - DFLIP
|
||||
if(CH8_SW) packet[12] &= ~CX10_FLAG_FLIP;
|
||||
case JC3015_1:
|
||||
//FLIP|MODE|PICTURE|VIDEO
|
||||
flags2= GET_FLAG(CH7_SW,_BV(3)) // Channel 7
|
||||
|GET_FLAG(CH8_SW,_BV(4)); // Channel 8
|
||||
break;
|
||||
case MK33041:
|
||||
elevator = 3000 - elevator;
|
||||
//FLIP|MODE|PICTURE|VIDEO|HEADLESS|RTH
|
||||
if(Servo_AUX3) flags |= _BV(7); // Channel 7 - picture
|
||||
if(Servo_AUX4) flags2 = _BV(0); // Channel 8 - video
|
||||
if(Servo_AUX5) flags2|= _BV(5); // Channel 9 - headless
|
||||
if(Servo_AUX6) flags |= _BV(2); // Channel 10 - rth
|
||||
flags|=GET_FLAG(CH7_SW,_BV(7)) // Channel 7 - picture
|
||||
|GET_FLAG(CH10_SW,_BV(2)); // Channel 10 - rth
|
||||
flags2=GET_FLAG(CH8_SW,_BV(0)) // Channel 8 - video
|
||||
|GET_FLAG(CH9_SW,_BV(5)); // Channel 9 - headless
|
||||
break;
|
||||
}
|
||||
packet[5+offset] = lowByte(aileron);
|
||||
packet[6+offset] = highByte(aileron);
|
||||
packet[7+offset] = lowByte(elevator);
|
||||
packet[8+offset] = highByte(elevator);
|
||||
packet[9+offset] = lowByte(throttle);
|
||||
packet[10+offset]= highByte(throttle);
|
||||
packet[11+offset]= lowByte(rudder);
|
||||
packet[12+offset]|= highByte(rudder);
|
||||
packet[13+offset]=flags;
|
||||
packet[14+offset]=flags2;
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
if (bind)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL);
|
||||
else
|
||||
|
||||
// Send
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no %= NUM_RF_CHANNELS;
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
hopping_frequency_no %= CX10_NUM_RF_CHANNELS;
|
||||
}
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, packet_length);
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void CX10_init()
|
||||
static void __attribute__((unused)) CX10_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc",5);
|
||||
XN297_SetRXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc",5);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // rx pipe 0 (used only for blue board)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
|
||||
XN297_SetRXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", packet_length);
|
||||
XN297_RFChannel(CX10_RF_BIND_CHANNEL);
|
||||
}
|
||||
|
||||
uint16_t CX10_callback() {
|
||||
uint16_t CX10_callback()
|
||||
{
|
||||
switch (phase) {
|
||||
case CX10_BIND1:
|
||||
if (bind_counter == 0)
|
||||
@@ -181,48 +181,56 @@ uint16_t CX10_callback() {
|
||||
}
|
||||
else
|
||||
{
|
||||
CX10_Write_Packet(1);
|
||||
CX10_Write_Packet();
|
||||
bind_counter--;
|
||||
}
|
||||
break;
|
||||
case CX10_BIND2:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR))
|
||||
// switch to TX mode
|
||||
if( XN297_IsRX() )
|
||||
{ // RX fifo data ready
|
||||
XN297_ReadPayload(packet, packet_length);
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
if(packet[9] == 1)
|
||||
phase = CX10_BIND1;
|
||||
debugln("RX");
|
||||
if(XN297_ReadPayload(packet, packet_length) && packet[9] == 1)
|
||||
{
|
||||
BIND_DONE;
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
phase = CX10_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
CX10_Write_Packet(1);
|
||||
delay(1); // used to be 300µs in deviation but not working so 1ms now
|
||||
// switch to RX mode
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP) | BV(NRF24L01_00_PRIM_RX));
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
CX10_Write_Packet();
|
||||
// wait for packet to be sent
|
||||
while( !XN297_IsPacketSent()); //delayMicroseconds(400);
|
||||
}
|
||||
// switch to RX mode
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
break;
|
||||
case CX10_DATA:
|
||||
CX10_Write_Packet(0);
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
CX10_Write_Packet();
|
||||
break;
|
||||
}
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
static void initialize_txid()
|
||||
static void __attribute__((unused)) CX10_initialize_txid()
|
||||
{
|
||||
rx_tx_addr[1]%= 0x30;
|
||||
if(sub_protocol==Q282)
|
||||
if(sub_protocol&0x08) //F_Q2X2 protocols
|
||||
{
|
||||
hopping_frequency[0] = 0x46;
|
||||
hopping_frequency[1] = 0x48;
|
||||
hopping_frequency[2] = 0x4a;
|
||||
hopping_frequency[3] = 0x4c;
|
||||
uint8_t offset=0; //F_Q282
|
||||
if(sub_protocol==F_Q242)
|
||||
offset=2;
|
||||
if(sub_protocol==F_Q222)
|
||||
offset=3;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
hopping_frequency[i]=0x46+2*i+offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -233,32 +241,36 @@ static void initialize_txid()
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initCX10(void)
|
||||
void CX10_init(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
|
||||
if(protocol == PROTO_Q2X2)
|
||||
sub_protocol|=0x08; // Increase the number of sub_protocols for CX-10
|
||||
|
||||
if(sub_protocol==CX10_BLUE)
|
||||
{
|
||||
packet_length = CX10A_PACKET_SIZE;
|
||||
packet_period = CX10A_PACKET_PERIOD;
|
||||
|
||||
phase = CX10_BIND2;
|
||||
bind_counter=0;
|
||||
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
packet[5+i] = 0xff; // clear aircraft id
|
||||
packet[9] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sub_protocol==Q282)
|
||||
packet_length = Q282_PACKET_SIZE;
|
||||
if(sub_protocol&0x08) //F_Q2X2 protocols
|
||||
packet_length = Q2X2_PACKET_SIZE;
|
||||
else
|
||||
packet_length = CX10_PACKET_SIZE;
|
||||
packet_period = CX10_PACKET_PERIOD;
|
||||
phase = CX10_BIND1;
|
||||
bind_counter = CX10_BIND_COUNT;
|
||||
}
|
||||
initialize_txid();
|
||||
CX10_init();
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
return INITIAL_WAIT+packet_period;
|
||||
CX10_initialize_txid();
|
||||
CX10_RF_init();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,50 +12,14 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef CYRF6936_INSTALLED
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
static void cyrf_spi_write(uint8_t command)
|
||||
{
|
||||
uint8_t n=8;
|
||||
SCK_off;//SCK start low
|
||||
SDI_off;
|
||||
while(n--) {
|
||||
if(command&0x80)
|
||||
SDI_on;
|
||||
else
|
||||
SDI_off;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
command = command << 1;
|
||||
}
|
||||
SDI_on;
|
||||
}
|
||||
|
||||
static uint8_t cyrf_spi_read()
|
||||
{
|
||||
uint8_t result;
|
||||
uint8_t i;
|
||||
result=0;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
if(SDO_1) ///
|
||||
result=(result<<1)|0x01;
|
||||
else
|
||||
result=result<<1;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
NOP();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CYRF_WriteRegister(uint8_t address, uint8_t data)
|
||||
{
|
||||
CYRF_CSN_off;
|
||||
cyrf_spi_write(0x80 | address);
|
||||
cyrf_spi_write(data);
|
||||
SPI_Write(0x80 | address);
|
||||
SPI_Write(data);
|
||||
CYRF_CSN_on;
|
||||
}
|
||||
|
||||
@@ -64,9 +28,9 @@ static void CYRF_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8
|
||||
uint8_t i;
|
||||
|
||||
CYRF_CSN_off;
|
||||
cyrf_spi_write(0x80 | address);
|
||||
SPI_Write(0x80 | address);
|
||||
for(i = 0; i < length; i++)
|
||||
cyrf_spi_write(data[i]);
|
||||
SPI_Write(data[i]);
|
||||
CYRF_CSN_on;
|
||||
}
|
||||
|
||||
@@ -75,9 +39,9 @@ static void CYRF_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t leng
|
||||
uint8_t i;
|
||||
|
||||
CYRF_CSN_off;
|
||||
cyrf_spi_write(address);
|
||||
SPI_Write(address);
|
||||
for(i = 0; i < length; i++)
|
||||
data[i] = cyrf_spi_read();
|
||||
data[i] = SPI_Read();
|
||||
CYRF_CSN_on;
|
||||
}
|
||||
|
||||
@@ -85,8 +49,8 @@ uint8_t CYRF_ReadRegister(uint8_t address)
|
||||
{
|
||||
uint8_t data;
|
||||
CYRF_CSN_off;
|
||||
cyrf_spi_write(address);
|
||||
data = cyrf_spi_read();
|
||||
SPI_Write(address);
|
||||
data = SPI_Read();
|
||||
CYRF_CSN_on;
|
||||
return data;
|
||||
}
|
||||
@@ -94,17 +58,19 @@ uint8_t CYRF_ReadRegister(uint8_t address)
|
||||
|
||||
uint8_t CYRF_Reset()
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x01);//software reset
|
||||
_delay_us(200);//
|
||||
// RS_HI;
|
||||
// _delay_us(100);
|
||||
// RS_LO;
|
||||
// _delay_us(100);
|
||||
CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); //Enable XOUT as GPIO
|
||||
CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); //Enable PACTL as GPIO
|
||||
#ifdef CYRF_RST_HI
|
||||
CYRF_RST_HI; //Hardware reset
|
||||
delayMicroseconds(100);
|
||||
CYRF_RST_LO;
|
||||
delayMicroseconds(100);
|
||||
#endif
|
||||
CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x01); //Software reset
|
||||
delayMicroseconds(200);
|
||||
CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); //Enable XOUT as GPIO
|
||||
CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); //Enable PACTL as GPIO
|
||||
CYRF_SetTxRxMode(TXRX_OFF);
|
||||
//Verify the CYRD chip is responding
|
||||
return (CYRF_ReadRegister(CYRF_10_FRAMING_CFG) == 0xa5);//return if reset
|
||||
//Verify the CYRF chip is responding
|
||||
return (CYRF_ReadRegister(CYRF_10_FRAMING_CFG) == 0xa5);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -112,13 +78,28 @@ uint8_t CYRF_Reset()
|
||||
*/
|
||||
void CYRF_GetMfgData(uint8_t data[])
|
||||
{
|
||||
/* Fuses power on */
|
||||
CYRF_WriteRegister(CYRF_25_MFG_ID, 0xFF);
|
||||
#ifndef FORCE_CYRF_ID
|
||||
if(eeprom_read_byte((EE_ADDR)EEPROM_CID_INIT_OFFSET)==0xf0)
|
||||
{//read Cyrf ID from EEPROM
|
||||
for(uint8_t i=0;i<6;i++)
|
||||
data[i] = eeprom_read_byte((EE_ADDR)EEPROM_CID_OFFSET+i);
|
||||
}
|
||||
else
|
||||
{//read Cyrf ID and store it EEPROM
|
||||
/* Fuses power on */
|
||||
CYRF_WriteRegister(CYRF_25_MFG_ID, 0xFF);
|
||||
|
||||
CYRF_ReadRegisterMulti(CYRF_25_MFG_ID, data, 6);
|
||||
CYRF_ReadRegisterMulti(CYRF_25_MFG_ID, data, 6);
|
||||
for(uint8_t i=0;i<6;i++)
|
||||
eeprom_write_byte((EE_ADDR)EEPROM_CID_OFFSET+i, data[i]);
|
||||
eeprom_write_byte((EE_ADDR)EEPROM_CID_INIT_OFFSET, 0xf0);
|
||||
|
||||
/* Fuses power off */
|
||||
CYRF_WriteRegister(CYRF_25_MFG_ID, 0x00);
|
||||
/* Fuses power off */
|
||||
CYRF_WriteRegister(CYRF_25_MFG_ID, 0x00);
|
||||
}
|
||||
#else
|
||||
memcpy(data,FORCE_CYRF_ID,6);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -128,17 +109,25 @@ void CYRF_SetTxRxMode(uint8_t mode)
|
||||
{
|
||||
if(mode==TXRX_OFF)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // 4=IDLE, 8=TX, C=RX
|
||||
if( protocol!=PROTO_WFLY && protocol!=PROTO_MLINK )
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // 4=IDLE, 8=TX, C=RX
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x00); // XOUT=0 PACTL=0
|
||||
}
|
||||
else
|
||||
{
|
||||
//Set the post tx/rx state
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, mode == TX_EN ? 0x28 : 0x2C); // 4=IDLE, 8=TX, C=RX
|
||||
if( protocol!=PROTO_WFLY && protocol!=PROTO_MLINK )
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, mode == TX_EN ? 0x28 : 0x2C); // 4=IDLE, 8=TX, C=RX
|
||||
if(mode == TX_EN)
|
||||
#ifdef ORANGE_TX_BLUE
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x20); // XOUT=1, PACTL=0
|
||||
else
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x80); // XOUT=0, PACTL=1
|
||||
#else
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x80); // XOUT=1, PACTL=0
|
||||
else
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x20); // XOUT=0, PACTL=1
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -160,20 +149,40 @@ static void CYRF_SetPower_Value(uint8_t power)
|
||||
void CYRF_SetPower(uint8_t val)
|
||||
{
|
||||
uint8_t power=CYRF_BIND_POWER;
|
||||
if(IS_BIND_DONE_on)
|
||||
power=IS_POWER_FLAG_on?CYRF_HIGH_POWER:CYRF_LOW_POWER;
|
||||
if(IS_BIND_DONE)
|
||||
#ifdef CYRF6936_ENABLE_LOW_POWER
|
||||
power=IS_POWER_FLAG_on?CYRF_HIGH_POWER:CYRF_LOW_POWER;
|
||||
#else
|
||||
power=CYRF_HIGH_POWER;
|
||||
#endif
|
||||
if(IS_RANGE_FLAG_on)
|
||||
power=CYRF_RANGE_POWER;
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, val | power);
|
||||
power|=val;
|
||||
if(prev_power != power)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG,power);
|
||||
prev_power=power;
|
||||
}
|
||||
|
||||
#ifdef USE_CYRF6936_CH15_TUNING
|
||||
static uint16_t Channel15=1024;
|
||||
if(Channel15!=Channel_data[CH15])
|
||||
{ // adjust frequency
|
||||
Channel15=Channel_data[CH15]+0x155; // default value is 0x555 = 0x400 + 0x155
|
||||
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, Channel15&0xFF);
|
||||
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, Channel15>>8);
|
||||
Channel15-=0x155;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void CYRF_ConfigCRCSeed(uint16_t crc)
|
||||
void CYRF_ConfigCRCSeed(uint16_t crc_seed)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB,crc & 0xff);
|
||||
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB,crc >> 8);
|
||||
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB,crc_seed & 0xff);
|
||||
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB,crc_seed >> 8);
|
||||
}
|
||||
/*
|
||||
* these are the recommended sop codes from Cyrpress
|
||||
@@ -196,36 +205,31 @@ void CYRF_ConfigDataCode(const uint8_t *datacodes, uint8_t len)
|
||||
void CYRF_WritePreamble(uint32_t preamble)
|
||||
{
|
||||
CYRF_CSN_off;
|
||||
cyrf_spi_write(0x80 | 0x24);
|
||||
cyrf_spi_write(preamble & 0xff);
|
||||
cyrf_spi_write((preamble >> 8) & 0xff);
|
||||
cyrf_spi_write((preamble >> 16) & 0xff);
|
||||
SPI_Write(0x80 | 0x24);
|
||||
SPI_Write(preamble & 0xff);
|
||||
SPI_Write((preamble >> 8) & 0xff);
|
||||
SPI_Write((preamble >> 16) & 0xff);
|
||||
CYRF_CSN_on;
|
||||
}
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void CYRF_StartReceive()
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL,0x87);
|
||||
}
|
||||
|
||||
/*static void CYRF_ReadDataPacket(uint8_t dpbuffer[])
|
||||
{
|
||||
CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, 0x10);
|
||||
}
|
||||
*/
|
||||
/*static void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length)
|
||||
void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length)
|
||||
{
|
||||
ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length);
|
||||
CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length);
|
||||
}
|
||||
*/
|
||||
|
||||
static void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_01_TX_LENGTH, len);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x43); // 0x40
|
||||
CYRF_WriteRegisterMulti(CYRF_20_TX_BUFFER, dpbuffer, len);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0xBF);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x83); // 0xBF
|
||||
}
|
||||
|
||||
void CYRF_WriteDataPacket(const uint8_t dpbuffer[])
|
||||
@@ -262,14 +266,18 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin
|
||||
CYRF_ConfigCRCSeed(0x0000);
|
||||
CYRF_SetTxRxMode(RX_EN);
|
||||
//Wait for pre-amp to switch from send to receive
|
||||
_delay_us(1000);
|
||||
delayMilliseconds(1);
|
||||
for(i = 0; i < NUM_FREQ; i++)
|
||||
{
|
||||
CYRF_ConfigRFChannel(i);
|
||||
CYRF_ReadRegister(CYRF_13_RSSI);
|
||||
CYRF_StartReceive();
|
||||
_delay_us(10);
|
||||
rssi[i] = CYRF_ReadRegister(CYRF_13_RSSI);
|
||||
CYRF_ConfigRFChannel(protocol==PROTO_LOSI?i|1:i);
|
||||
delayMicroseconds(270); //slow channel require 270usec for synthesizer to settle
|
||||
if( !(CYRF_ReadRegister(CYRF_05_RX_CTRL) & 0x80)) {
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80); //Prepare to receive
|
||||
delayMicroseconds(15);
|
||||
CYRF_ReadRegister(CYRF_13_RSSI); //dummy read
|
||||
delayMicroseconds(15); //The conversion can occur as often as once every 12us
|
||||
}
|
||||
rssi[i] = CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
@@ -285,5 +293,108 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin
|
||||
rssi[j] = 0xff;
|
||||
}
|
||||
}
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX
|
||||
}
|
||||
|
||||
#if defined(DEVO_CYRF6936_INO) || defined(J6PRO_CYRF6936_INO)
|
||||
const uint8_t PROGMEM DEVO_j6pro_sopcodes[][8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
{0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91},
|
||||
{0x9B, 0xC5, 0xA1, 0x0F, 0xAD, 0x39, 0xA2, 0x0F},
|
||||
{0xEF, 0x64, 0xB0, 0x2A, 0xD2, 0x8F, 0xB1, 0x2A},
|
||||
{0x66, 0xCD, 0x7C, 0x50, 0xDD, 0x26, 0x7C, 0x50},
|
||||
{0x5C, 0xE1, 0xF6, 0x44, 0xAD, 0x16, 0xF6, 0x44},
|
||||
{0x5A, 0xCC, 0xAE, 0x46, 0xB6, 0x31, 0xAE, 0x46},
|
||||
{0xA1, 0x78, 0xDC, 0x3C, 0x9E, 0x82, 0xDC, 0x3C},
|
||||
{0xB9, 0x8E, 0x19, 0x74, 0x6F, 0x65, 0x18, 0x74},
|
||||
{0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49},
|
||||
{0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72},
|
||||
#if defined(J6PRO_CYRF6936_INO)
|
||||
{0x82, 0xC7, 0x90, 0x36, 0x21, 0x03, 0xFF, 0x17},
|
||||
{0xE2, 0xF8, 0xCC, 0x91, 0x3C, 0x37, 0xCC, 0x91}, //Note: the '03' was '9E' in the Cypress recommended table
|
||||
{0xAD, 0x39, 0xA2, 0x0F, 0x9B, 0xC5, 0xA1, 0x0F}, //The following are the same as the 1st 8 above,
|
||||
{0xD2, 0x8F, 0xB1, 0x2A, 0xEF, 0x64, 0xB0, 0x2A}, //but with the upper and lower word swapped
|
||||
{0xDD, 0x26, 0x7C, 0x50, 0x66, 0xCD, 0x7C, 0x50},
|
||||
{0xAD, 0x16, 0xF6, 0x44, 0x5C, 0xE1, 0xF6, 0x44},
|
||||
{0xB6, 0x31, 0xAE, 0x46, 0x5A, 0xCC, 0xAE, 0x46},
|
||||
{0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C},
|
||||
{0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74},
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
static void __attribute__((unused)) CYRF_PROGMEM_ConfigSOPCode(const uint8_t *data)
|
||||
{
|
||||
uint8_t code[8];
|
||||
for(uint8_t i=0;i<8;i++)
|
||||
code[i]=pgm_read_byte_near(&data[i]);
|
||||
CYRF_ConfigSOPCode(code);
|
||||
}
|
||||
|
||||
//CYRF GFSK 1Mb functions
|
||||
const uint8_t PROGMEM CYRF_GFSK1M_init_vals[][2] = {
|
||||
{CYRF_02_TX_CTRL, 0x00}, // transmit err & complete interrupts disabled
|
||||
{CYRF_05_RX_CTRL, 0x00}, // receive err & complete interrupts disabled
|
||||
{CYRF_28_CLK_EN, 0x02}, // Force Receive Clock Enable, MUST be set
|
||||
{CYRF_32_AUTO_CAL_TIME, 0x3c}, // must be set to 3C
|
||||
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // must be set to 14
|
||||
{CYRF_06_RX_CFG, 0x48}, // LNA manual control, Rx Fast Turn Mode Enable
|
||||
{CYRF_1B_TX_OFFSET_LSB, 0x00}, // Tx frequency offset LSB
|
||||
{CYRF_1C_TX_OFFSET_MSB, 0x00}, // Tx frequency offset MSB
|
||||
{CYRF_0F_XACT_CFG, 0x24}, // Force End State, transaction end state = idle
|
||||
{CYRF_03_TX_CFG, 0x00}, // GFSK mode
|
||||
{CYRF_12_DATA64_THOLD, 0x0a}, // 64 Chip Data PN Code Correlator Threshold = 10
|
||||
{CYRF_0F_XACT_CFG, 0x04}, // Transaction End State = idle
|
||||
{CYRF_39_ANALOG_CTRL, 0x01}, // synth setting time for all channels is the same as for slow channels
|
||||
{CYRF_0F_XACT_CFG, 0x24}, //Force IDLE
|
||||
{CYRF_29_RX_ABORT, 0x00}, //Clear RX abort
|
||||
{CYRF_12_DATA64_THOLD, 0x0a}, //set pn correlation threshold
|
||||
{CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold
|
||||
{CYRF_29_RX_ABORT, 0x0f}, //Clear RX abort?
|
||||
{CYRF_03_TX_CFG, 0x00}, // GFSK mode
|
||||
{CYRF_10_FRAMING_CFG, 0x4a}, // 0b11000000 //set sop len and threshold
|
||||
{CYRF_1F_TX_OVERRIDE, 0x04}, //disable tx CRC
|
||||
{CYRF_1E_RX_OVERRIDE, 0x14}, //disable rx crc
|
||||
{CYRF_14_EOP_CTRL, 0x00}, //set EOP sync == 0
|
||||
};
|
||||
static void __attribute__((unused)) CYRF_GFSK1M_Init(uint8_t payload_length, uint8_t preamble_len)
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(CYRF_GFSK1M_init_vals) / 2; i++)
|
||||
CYRF_WriteRegister(pgm_read_byte_near(&CYRF_GFSK1M_init_vals[i][0]), pgm_read_byte_near(&CYRF_GFSK1M_init_vals[i][1]));
|
||||
|
||||
|
||||
CYRF_WriteRegister(CYRF_01_TX_LENGTH, payload_length);
|
||||
|
||||
CYRF_WritePreamble(0xAAAA00 | preamble_len);
|
||||
|
||||
CYRF_SetPower(0x00);
|
||||
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
}
|
||||
static void __attribute__((unused)) CYRF_GFSK1M_SendPayload(uint8_t *buffer, uint8_t len)
|
||||
{
|
||||
uint8_t send=len>16 ? 16 : len;
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
|
||||
CYRF_WriteRegisterMulti(CYRF_20_TX_BUFFER, buffer, send); // Fill the buffer with 16 bytes max
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x80); // Start send
|
||||
buffer += send;
|
||||
len -= send;
|
||||
|
||||
while(len>8)
|
||||
{
|
||||
while((CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS)&0x10) == 0); // Wait that half of the buffer is empty
|
||||
CYRF_WriteRegisterMulti(CYRF_20_TX_BUFFER, buffer, 8); // Add 8 bytes to the buffer
|
||||
buffer+=8;
|
||||
len-=8;
|
||||
}
|
||||
|
||||
if(len)
|
||||
{
|
||||
while((CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS)&0x10) == 0); // Wait that half of the buffer is empty
|
||||
CYRF_WriteRegisterMulti(CYRF_20_TX_BUFFER, buffer, len); // Add the remaining bytes to the buffer
|
||||
}
|
||||
}
|
||||
#define CYRF_GFSK1M_SetPower() CYRF_SetPower(0x00)
|
||||
#endif
|
||||
176
Multiprotocol/Convert.ino
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/************************/
|
||||
/** Convert routines **/
|
||||
/************************/
|
||||
// Reverse a channel and store it
|
||||
void reverse_channel(uint8_t num)
|
||||
{
|
||||
uint16_t val=2048-Channel_data[num];
|
||||
if(val>=2048) val=2047;
|
||||
Channel_data[num]=val;
|
||||
}
|
||||
|
||||
// Channel value is converted to ppm 860<->2140 -125%<->+125% and 988<->2012 -100%<->+100%
|
||||
uint16_t convert_channel_ppm(uint8_t num)
|
||||
{
|
||||
uint16_t val=Channel_data[num];
|
||||
return (((val<<2)+val)>>3)+860; //value range 860<->2140 -125%<->+125%
|
||||
}
|
||||
|
||||
// Channel value 100% is converted to 10bit values 0<->1023
|
||||
uint16_t convert_channel_10b(uint8_t num, bool failsafe)
|
||||
{
|
||||
uint16_t val;
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(failsafe)
|
||||
val=Failsafe_data[num]; // 0<->2047
|
||||
else
|
||||
#endif
|
||||
val=Channel_data[num];
|
||||
val=((val<<2)+val)>>3;
|
||||
if(val<=128) return 0;
|
||||
if(val>=1152) return 1023;
|
||||
return val-128;
|
||||
}
|
||||
|
||||
// Channel value 100% is converted to 8bit values 0<->255
|
||||
uint8_t convert_channel_8b(uint8_t num)
|
||||
{
|
||||
uint16_t val=Channel_data[num];
|
||||
val=((val<<2)+val)>>5;
|
||||
if(val<=32) return 0;
|
||||
if(val>=288) return 255;
|
||||
return val-32;
|
||||
}
|
||||
|
||||
// Channel value 100% is converted to 8b with deadband
|
||||
uint8_t convert_channel_8b_limit_deadband(uint8_t num,uint8_t min,uint8_t mid, uint8_t max, uint8_t deadband)
|
||||
{
|
||||
uint16_t val=limit_channel_100(num); // 204<->1844
|
||||
uint16_t db_low=CHANNEL_MID-deadband, db_high=CHANNEL_MID+deadband; // 1024+-deadband
|
||||
int32_t calc;
|
||||
uint8_t out;
|
||||
if(val>=db_low && val<=db_high)
|
||||
return mid;
|
||||
else if(val<db_low)
|
||||
{
|
||||
val-=CHANNEL_MIN_100;
|
||||
calc=mid-min;
|
||||
calc*=val;
|
||||
calc/=(db_low-CHANNEL_MIN_100);
|
||||
out=calc;
|
||||
out+=min;
|
||||
}
|
||||
else
|
||||
{
|
||||
val-=db_high;
|
||||
calc=max-mid;
|
||||
calc*=val;
|
||||
calc/=(CHANNEL_MAX_100-db_high+1);
|
||||
out=calc;
|
||||
out+=mid;
|
||||
if(max>min) out++; else out--;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Channel value 100% is converted to value scaled
|
||||
int16_t convert_channel_16b_limit(uint8_t num,int16_t min,int16_t max)
|
||||
{
|
||||
int32_t val=limit_channel_100(num); // 204<->1844
|
||||
val=(val-CHANNEL_MIN_100)*(max-min)/(CHANNEL_MAX_100-CHANNEL_MIN_100)+min;
|
||||
return (uint16_t)val;
|
||||
}
|
||||
|
||||
// Channel value -125%<->125% is scaled to 16bit value with no limit
|
||||
int16_t convert_channel_16b_nolimit(uint8_t num, int16_t min, int16_t max, bool failsafe)
|
||||
{
|
||||
int32_t val;
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(failsafe)
|
||||
val=Failsafe_data[num]; // 0<->2047
|
||||
else
|
||||
#endif
|
||||
val=Channel_data[num]; // 0<->2047
|
||||
val=(val-CHANNEL_MIN_100)*(max-min)/(CHANNEL_MAX_100-CHANNEL_MIN_100)+min;
|
||||
return (uint16_t)val;
|
||||
}
|
||||
|
||||
// Channel value is converted sign + magnitude 8bit values
|
||||
uint8_t convert_channel_s8b(uint8_t num)
|
||||
{
|
||||
uint8_t ch;
|
||||
ch = convert_channel_8b(num);
|
||||
return (ch < 128 ? 127-ch : ch);
|
||||
}
|
||||
|
||||
// Channel value is limited to 100%
|
||||
uint16_t limit_channel_100(uint8_t num)
|
||||
{
|
||||
if(Channel_data[num]>=CHANNEL_MAX_100)
|
||||
return CHANNEL_MAX_100;
|
||||
if (Channel_data[num]<=CHANNEL_MIN_100)
|
||||
return CHANNEL_MIN_100;
|
||||
return Channel_data[num];
|
||||
}
|
||||
|
||||
// Channel value is converted for HK310
|
||||
void convert_channel_HK310(uint8_t num, uint8_t *low, uint8_t *high)
|
||||
{
|
||||
uint16_t temp=0xFFFF-(3440+((Channel_data[num]*5)>>1))/3;
|
||||
*low=(uint8_t)(temp&0xFF);
|
||||
*high=(uint8_t)(temp>>8);
|
||||
}
|
||||
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
// Failsafe value is converted for HK310
|
||||
void convert_failsafe_HK310(uint8_t num, uint8_t *low, uint8_t *high)
|
||||
{
|
||||
uint16_t temp=0xFFFF-(3440+((Failsafe_data[num]*5)>>1))/3;
|
||||
*low=(uint8_t)(temp&0xFF);
|
||||
*high=(uint8_t)(temp>>8);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Channel value for FrSky (PPM is multiplied by 1.5)
|
||||
uint16_t convert_channel_frsky(uint8_t num)
|
||||
{
|
||||
uint16_t val=Channel_data[num];
|
||||
return ((val*15)>>4)+1290;
|
||||
}
|
||||
|
||||
// 0-2047, 0 = 817, 1024 = 1500, 2047 = 2182
|
||||
//64=860,1024=1500,1984=2140//Taranis 125%
|
||||
static uint16_t __attribute__((unused)) FrSkyX_scaleForPXX( uint8_t i, uint8_t num_chan=8)
|
||||
{ //mapped 860,2140(125%) range to 64,1984(PXX values);
|
||||
uint16_t chan_val=convert_channel_frsky(i)-1226;
|
||||
if(i>=num_chan) chan_val|=2048; // upper channels offset
|
||||
return chan_val;
|
||||
}
|
||||
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
static uint16_t __attribute__((unused)) FrSkyX_scaleForPXX_FS( uint8_t i, uint8_t num_chan=8)
|
||||
{ //mapped 1,2046(125%) range to 64,1984(PXX values);
|
||||
uint16_t chan_val=((Failsafe_data[i]*15)>>4)+64;
|
||||
if(Failsafe_data[i]==FAILSAFE_CHANNEL_NOPULSES)
|
||||
chan_val=FAILSAFE_CHANNEL_NOPULSES;
|
||||
else if(Failsafe_data[i]==FAILSAFE_CHANNEL_HOLD)
|
||||
chan_val=FAILSAFE_CHANNEL_HOLD;
|
||||
if(i>=num_chan) chan_val|=2048; // upper channels offset
|
||||
return chan_val;
|
||||
}
|
||||
#endif
|
||||
300
Multiprotocol/Corona_cc2500.ino
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(CORONA_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
//#define CORONA_FORCE_ID
|
||||
|
||||
#define CORONA_RF_NUM_CHANNELS 3
|
||||
#define CORONA_ADDRESS_LENGTH 4
|
||||
#define CORONA_BIND_CHANNEL_V1 0xD1 // also Flydream V3
|
||||
#define CORONA_BIND_CHANNEL_V2 0xB8
|
||||
#define CORONA_COARSE 0x00
|
||||
#define FDV3_BIND_PERIOD 5000
|
||||
#define FDV3_CHANNEL_PERIOD 4000
|
||||
|
||||
const PROGMEM uint8_t CORONA_init_values[] = {
|
||||
/* 00 */ 0x29, 0x2E, 0x06, 0x07, 0xD3, 0x91, 0xFF, 0x04,
|
||||
/* 08 */ 0x05, 0x00, CORONA_BIND_CHANNEL_V1, 0x06, 0x00, 0x5C, 0x4E, 0xC4 + CORONA_COARSE,
|
||||
/* 10 */ 0x5B, 0xF8, 0x03, 0x23, 0xF8, 0x47, 0x07, 0x30,
|
||||
/* 18 */ 0x18, 0x16, 0x6C, 0x43, 0x40, 0x91, 0x87, 0x6B,
|
||||
/* 20 */ 0xF8, 0x56, 0x10, 0xA9, 0x0A, 0x00, 0x11, 0x41,
|
||||
/* 28 */ 0x00, 0x59, 0x7F, 0x3F, 0x81, 0x35, 0x0B
|
||||
};
|
||||
|
||||
uint8_t fdv3_id_send;
|
||||
|
||||
static void __attribute__((unused)) CORONA_rf_init()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
|
||||
for (uint8_t i = 0; i <= 0x2E; ++i)
|
||||
CC2500_WriteReg(i, pgm_read_byte_near(&CORONA_init_values[i]));
|
||||
if(sub_protocol==COR_V2)
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, CORONA_BIND_CHANNEL_V2);
|
||||
CC2500_WriteReg(CC2500_0E_FREQ1, 0x80);
|
||||
CC2500_WriteReg(CC2500_0F_FREQ0, 0x00 + CORONA_COARSE);
|
||||
CC2500_WriteReg(CC2500_15_DEVIATN, 0x50);
|
||||
CC2500_WriteReg(CC2500_17_MCSM1, 0x00);
|
||||
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0x67);
|
||||
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0xFB);
|
||||
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xDC);
|
||||
}
|
||||
else if(sub_protocol==FD_V3)
|
||||
{
|
||||
// Flydream receiver captures have deviation 50, tx captures show 47
|
||||
CC2500_WriteReg(CC2500_15_DEVIATN, 0x50);
|
||||
}
|
||||
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
|
||||
//not sure what they are doing to the PATABLE since basically only the first byte is used and it's only 8 bytes long. So I think they end up filling the PATABLE fully with 0xFF
|
||||
CC2500_WriteRegisterMulti(CC2500_3E_PATABLE,(const uint8_t *)"\x08\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 13);
|
||||
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
}
|
||||
|
||||
// Generate id and hopping freq
|
||||
static void __attribute__((unused)) CORONA_TXID_init()
|
||||
{
|
||||
#ifdef CORONA_FORCE_ID
|
||||
// Example of ID and channels taken from dumps
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case COR_V1:
|
||||
memcpy((void *)rx_tx_addr,(void *)"\x1F\xFE\x6C\x35",CORONA_ADDRESS_LENGTH);
|
||||
memcpy((void *)hopping_frequency,(void *)"\x17\x0D\x03\x49",CORONA_RF_NUM_CHANNELS+1);
|
||||
break;
|
||||
case COR_V2:
|
||||
memcpy((void *)rx_tx_addr,(void *)"\xFE\xFE\x02\xFB",CORONA_ADDRESS_LENGTH);
|
||||
memcpy((void *)hopping_frequency,(void *)"\x14\x3D\x35",CORONA_RF_NUM_CHANNELS);
|
||||
case FD_V3:
|
||||
memcpy((void *)rx_tx_addr,(void *)"\x02\xFA\x38\x38",CORONA_ADDRESS_LENGTH);
|
||||
memcpy((void *)hopping_frequency,(void *)"\x71\xB9\x30",CORONA_RF_NUM_CHANNELS);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// From dumps channels are anything between 0x00 and 0xC5 on V1.
|
||||
// But 0x00 and 0xB8 should be avoided on V2 since they are used for bind.
|
||||
// Below code make sure channels are between 0x02 and 0xA0, spaced with
|
||||
// a minimum of 2 and not ordered (RX only use the 1st channel unless there is an issue).
|
||||
// Extra hopping frequency used for Flydream V3 id packets.
|
||||
uint8_t order=rx_tx_addr[3]&0x03;
|
||||
for(uint8_t i=0; i<CORONA_RF_NUM_CHANNELS+1; i++)
|
||||
hopping_frequency[i^order]=2+rx_tx_addr[3-i]%39+(i<<5)+(i<<3);
|
||||
|
||||
if(sub_protocol!=FD_V3)
|
||||
{
|
||||
// ID looks random but on the 15 V1 dumps they all show the same odd/even rule
|
||||
if(rx_tx_addr[3]&0x01)
|
||||
{ // If [3] is odd then [0] is odd and [2] is even
|
||||
rx_tx_addr[0]|=0x01;
|
||||
rx_tx_addr[2]&=0xFE;
|
||||
}
|
||||
else
|
||||
{ // If [3] is even then [0] is even and [2] is odd
|
||||
rx_tx_addr[0]&=0xFE;
|
||||
rx_tx_addr[2]|=0x01;
|
||||
}
|
||||
rx_tx_addr[1]=0xFE; // Always FE in the dumps of V1 and V2
|
||||
}
|
||||
else
|
||||
{
|
||||
rx_tx_addr[1]=0xFA; // Always FA for Flydream V3
|
||||
rx_tx_addr[3]=hopping_frequency[CORONA_RF_NUM_CHANNELS]; // channel used for id/freq packets
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint16_t __attribute__((unused)) CORONA_build_bind_pkt()
|
||||
{
|
||||
if(sub_protocol==COR_V1)
|
||||
{ // V1
|
||||
if(bind_counter&1)
|
||||
{ // Send TX ID
|
||||
packet[0]=0x04; // 5 bytes to follow
|
||||
for(uint8_t i=0; i<CORONA_ADDRESS_LENGTH; i++)
|
||||
packet[i+1]=rx_tx_addr[i];
|
||||
packet[5]=0xCD; // Unknown but seems to be always the same value for V1
|
||||
return 3689;
|
||||
}
|
||||
else
|
||||
{ // Send hopping freq
|
||||
packet[0]=0x03; // 4 bytes to follow
|
||||
for(uint8_t i=0; i<CORONA_RF_NUM_CHANNELS+1; i++)
|
||||
packet[i+1]=hopping_frequency[i];
|
||||
// Only the first 3 channels of hopping_frequency used for data
|
||||
return 3438;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // V2 and FDV3
|
||||
packet[0]=0x04; // 5 bytes to follow
|
||||
for(uint8_t i=0; i<CORONA_ADDRESS_LENGTH; i++)
|
||||
packet[i+1]=rx_tx_addr[i];
|
||||
packet[5]=0x00; // Unknown but seems to be always the same value for V2 and FDV3
|
||||
if(sub_protocol==FD_V3)
|
||||
return FDV3_BIND_PERIOD;
|
||||
else
|
||||
return 26791;
|
||||
}
|
||||
}
|
||||
|
||||
// 8 Channels with direct values from PPM
|
||||
static uint16_t __attribute__((unused)) CORONA_build_packet()
|
||||
{
|
||||
CC2500_SetPower();
|
||||
if(state && sub_protocol==COR_V2)
|
||||
{ // Send identifier packet for 2.65sec. This is how the RX learns the hopping table after a bind. Why it's not part of the bind like V1 is a mistery...
|
||||
// Set channel
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, 0x00);
|
||||
state--;
|
||||
packet[0]=0x07; // 8 bytes to follow
|
||||
// Send hopping freq
|
||||
for(uint8_t i=0; i<CORONA_RF_NUM_CHANNELS; i++)
|
||||
packet[i+1]=hopping_frequency[i];
|
||||
// Send TX ID
|
||||
for(uint8_t i=0; i<CORONA_ADDRESS_LENGTH; i++)
|
||||
packet[i+4]=rx_tx_addr[i];
|
||||
packet[8]=0;
|
||||
return 6647;
|
||||
}
|
||||
|
||||
// Flydream every fourth packet is identifier packet and is on channel number
|
||||
// that is last byte of rx_tx_addr
|
||||
if (fdv3_id_send)
|
||||
{
|
||||
fdv3_id_send = 0;
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, rx_tx_addr[CORONA_ADDRESS_LENGTH-1]);
|
||||
packet[0] = 0x07; // 8 bytes to follow
|
||||
// Send TX ID
|
||||
for(uint8_t i = 0; i < CORONA_ADDRESS_LENGTH; i++)
|
||||
packet[i+1] = rx_tx_addr[i];
|
||||
// Send hopping freq
|
||||
for(uint8_t i = 0; i < CORONA_RF_NUM_CHANNELS; i++)
|
||||
packet[i+1+CORONA_ADDRESS_LENGTH] = hopping_frequency[i];
|
||||
packet[8] = 0;
|
||||
return 2*FDV3_CHANNEL_PERIOD; // extra delay after id packet according to captures
|
||||
}
|
||||
|
||||
// Set RF channel
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[hopping_frequency_no]);
|
||||
|
||||
// Build packet
|
||||
packet[0] = 0x10; // 17 bytes to follow
|
||||
|
||||
// Channels
|
||||
memset(packet+9, 0x00, 4);
|
||||
for (uint8_t i=0; i<8; i++)
|
||||
{ // Channel values are packed
|
||||
uint16_t val=convert_channel_ppm(i);
|
||||
packet[i+1] = val;
|
||||
packet[9 + (i>>1)] |= (i&0x01)?(val>>4)&0xF0:(val>>8)&0x0F;
|
||||
}
|
||||
|
||||
// TX ID
|
||||
for (uint8_t i=0; i < CORONA_ADDRESS_LENGTH; i++)
|
||||
packet[i+13] = rx_tx_addr[i];
|
||||
|
||||
packet[17] = 0x00;
|
||||
|
||||
if (sub_protocol!=FD_V3)
|
||||
{
|
||||
// Packet period is based on hopping
|
||||
switch (hopping_frequency_no)
|
||||
{
|
||||
case 0:
|
||||
packet_period = sub_protocol == COR_V1
|
||||
? 4991
|
||||
: 4248;
|
||||
break;
|
||||
case 1:
|
||||
packet_period = sub_protocol == COR_V1
|
||||
? 4991
|
||||
: 4345;
|
||||
break;
|
||||
case 2:
|
||||
packet_period = sub_protocol == COR_V1
|
||||
? 12520
|
||||
: 13468;
|
||||
if (sub_protocol == COR_V2)
|
||||
packet[17] = 0x03;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hopping_frequency_no++;
|
||||
|
||||
if (sub_protocol == FD_V3)
|
||||
{
|
||||
if (hopping_frequency_no == CORONA_RF_NUM_CHANNELS)
|
||||
{
|
||||
fdv3_id_send = 1;
|
||||
packet_period = 6000; // extra delay before id packet according to captures
|
||||
}
|
||||
else
|
||||
packet_period = FDV3_CHANNEL_PERIOD;
|
||||
}
|
||||
|
||||
hopping_frequency_no %= CORONA_RF_NUM_CHANNELS;
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t CORONA_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(22000);
|
||||
#endif
|
||||
// Tune frequency if it has been changed
|
||||
CC2500_SetFreqOffset();
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
if (bind_counter-- == 0) BIND_DONE;
|
||||
packet_period=CORONA_build_bind_pkt();
|
||||
}
|
||||
else
|
||||
packet_period=CORONA_build_packet();
|
||||
|
||||
// Send packet
|
||||
CC2500_WriteData(packet, packet[0]+2);
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
void CORONA_init()
|
||||
{
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case COR_V1:
|
||||
bind_counter=1400; // Stay in bind mode for 5s
|
||||
break;
|
||||
case COR_V2:
|
||||
bind_counter=187; // Stay in bind mode for 5s
|
||||
break;
|
||||
case FD_V3:
|
||||
bind_counter = 2000; // Stay in bind mode for 10s
|
||||
break;
|
||||
}
|
||||
state=400; // Used by V2 to send RF channels + ID for 2.65s at startup
|
||||
hopping_frequency_no=0;
|
||||
fdv3_id_send = 0;
|
||||
CORONA_TXID_init();
|
||||
CORONA_rf_init();
|
||||
}
|
||||
|
||||
#endif
|
||||