Compare commits
677 Commits
1.3.0.47
...
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 |
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/
|
||||
334
.travis.yml
@@ -1,334 +0,0 @@
|
||||
dist: bionic
|
||||
sudo: true
|
||||
language: c
|
||||
|
||||
env:
|
||||
global:
|
||||
- IDE_VERSION=1.8.9
|
||||
matrix:
|
||||
- BOARD="multi4in1:avr:multiatmega328p:bootloader=none"
|
||||
- BOARD="multi4in1:avr:multiatmega328p:bootloader=optiboot"
|
||||
- BOARD="multi4in1:avr:multixmega32d4"
|
||||
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=none"
|
||||
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=native"
|
||||
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=ftdi"
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
before_install:
|
||||
# Fetch the tag information for the current branch
|
||||
- git fetch origin --tags
|
||||
|
||||
# Publish the buildroot script folder
|
||||
- chmod +x ${TRAVIS_BUILD_DIR}/buildroot/bin/*
|
||||
- export PATH=${TRAVIS_BUILD_DIR}/buildroot/bin/:${PATH}
|
||||
|
||||
# Arduino IDE adds a lot of noise caused by network traffic; firewall it
|
||||
- sudo iptables -P INPUT DROP
|
||||
- sudo iptables -P FORWARD DROP
|
||||
- sudo iptables -P OUTPUT ACCEPT
|
||||
- sudo iptables -A INPUT -i lo -j ACCEPT
|
||||
- sudo iptables -A OUTPUT -o lo -j ACCEPT
|
||||
- sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
# Helper functions for the builds
|
||||
- buildMulti() { start_fold config_diff; travis_time_start; git diff Multiprotocol/_Config.h; end_fold config_diff; exitcode=0; BUILDCMD="arduino --verify --board $BOARD Multiprotocol/Multiprotocol.ino --pref build.path=./build/"; echo $BUILDCMD; $BUILDCMD; if [ $? -ne 0 ]; then exitcode=1; fi; echo; return $exitcode; }
|
||||
- buildProtocol() { exitcode=0; opt_disable $ALL_PROTOCOLS; opt_enable $1; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
|
||||
- buildEachProtocol() { exitcodesum=0; for PROTOCOL in $ALL_PROTOCOLS ; do printf "\e[33;1mBuilding $PROTOCOL\e[0m"; buildProtocol $PROTOCOL; if [ $? -ne 0 ]; then exitcodesum=$((exitcodesum + 1)); fi; done; return $exitcodesum; }
|
||||
- buildRFModule() { exitcode=0; opt_disable $ALL_RFMODULES; opt_enable $1; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
|
||||
- buildEachRFModule() { exitcodesum=0; for RFMODULE in $ALL_RFMODULES; do printf "\e[33;1mBuilding $RFMODULE\e[0m"; buildRFModule $RFMODULE; if [ $? -ne 0 ]; then exitcodesum=$((exitcodesum + 1)); fi; done; return $exitcodesum; }
|
||||
- buildDefault() { exitcode=0; printf "\n\e[33;1mBuilding default configuration\e[0m\n"; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
|
||||
- buildSerialOnly() { exitcode=0; printf "\n\e[33;1mBuilding serial mode only\e[0m\n"; opt_disable ENABLE_PPM; opt_enable ENABLE_SERIAL; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
|
||||
- buildPPMOnly() { exitcode=0; printf "\n\e[33;1mBuilding PPM mode only\e[0m\n"; opt_enable ENABLE_PPM; opt_disable ENABLE_SERIAL; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
|
||||
|
||||
# Function to build the release files - dependent on board type
|
||||
- if [[ "$BOARD" == "multi4in1:avr:multixmega32d4" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-orangerx-aetr-green-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
opt_disable ORANGE_TX_BLUE;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-orangerx-aetr-green-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-orangerx-aetr-blue-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable ORANGE_TX_BLUE;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-orangerx-aetr-blue-inv-v$MULTI_VERSION.bin;
|
||||
cp Multiprotocol/Multi.txt ./binaries/Multi.txt; };
|
||||
elif [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=none" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-avr-usbasp-aetr-A7105-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $A7105_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-usbasp-aetr-A7105-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-avr-usbasp-aetr-CC2500-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CC2500_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-usbasp-aetr-CC2500-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CYRF6936_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin; };
|
||||
elif [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=optiboot" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-avr-txflash-aetr-A7105-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $A7105_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-txflash-aetr-A7105-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-avr-txflash-aetr-CC2500-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CC2500_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-txflash-aetr-CC2500-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CYRF6936_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin; };
|
||||
elif [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103c:debug_option=none" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-aetr-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
opt_enable MULTI_STATUS;
|
||||
opt_disable MULTI_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-aetr-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-taer-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-taer-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-reta-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-reta-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-aetr-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace RETA AETR;
|
||||
opt_disable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-aetr-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-taer-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-taer-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-reta-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-reta-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-aetr-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace RETA AETR;
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_enable MULTI_TELEMETRY;
|
||||
opt_enable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-aetr-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-taer-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-taer-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-reta-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-reta-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-aetr-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace RETA AETR;
|
||||
opt_disable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-aetr-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-taer-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-taer-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-reta-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-reta-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-ppm-aetr-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace RETA AETR;
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_disable MULTI_TELEMETRY;
|
||||
opt_set NBR_BANKS 5;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-ppm-aetr-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-ppm-taer-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-ppm-taer-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-ppm-reta-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-ppm-reta-noinv-v$MULTI_VERSION.bin; };
|
||||
elif [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103c:debug_option=native" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-xn297dump-inv-usbdebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_add XN297DUMP_NRF24L01_INO;
|
||||
opt_enable MULTI_STATUS;
|
||||
opt_disable MULTI_TELEMETRY;
|
||||
opt_enable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-xn297dump-inv-usbdebug-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-xn297dump-inv-usbdebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_enable MULTI_TELEMETRY;
|
||||
opt_enable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-xn297dump-inv-usbdebug-v$MULTI_VERSION.bin; };
|
||||
elif [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103c:debug_option=ftdi" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-xn297dump-inv-ftdidebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_add XN297DUMP_NRF24L01_INO;
|
||||
opt_enable MULTI_STATUS;
|
||||
opt_disable MULTI_TELEMETRY;
|
||||
opt_enable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-xn297dump-inv-ftdidebug-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-xn297dump-inv-ftdidebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_enable MULTI_TELEMETRY;
|
||||
opt_enable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-xn297dump-inv-ftdidebug-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-aetr-inv-ftdidebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
opt_enable MULTI_STATUS;
|
||||
opt_disable MULTI_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-aetr-inv-ftdidebug-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-aetr-inv-ftdidebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_enable MULTI_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-aetr-inv-ftdidebug-v$MULTI_VERSION.bin; };
|
||||
else
|
||||
buildReleaseFiles() { echo "No release files for this board."; };
|
||||
fi
|
||||
|
||||
install:
|
||||
# Install Arduino IDE
|
||||
- wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz
|
||||
- tar xf arduino-$IDE_VERSION-linux64.tar.xz
|
||||
- mv arduino-$IDE_VERSION $HOME/arduino-ide
|
||||
- export PATH=$PATH:$HOME/arduino-ide
|
||||
|
||||
# Set the Multi boards package URL
|
||||
- arduino --pref "boardsmanager.additional.urls=https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json" --save-prefs
|
||||
|
||||
# Install the STM32 board if needed
|
||||
- if [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
arduino --install-boards multi4in1:STM32F1;
|
||||
fi
|
||||
|
||||
# Install the AVR board if needed
|
||||
- if [[ "$BOARD" =~ "multi4in1:avr:" ]]; then
|
||||
arduino --install-boards multi4in1:avr;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
# Change current working directory to the build dir
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
|
||||
# Create somwhere to put the exported binaries
|
||||
- mkdir ./binaries
|
||||
|
||||
# Log the initial Multi config
|
||||
- cat Multiprotocol/_Config.h
|
||||
|
||||
# Back up the configuration
|
||||
- cp Multiprotocol/_Config.h ./_Config.h.bak
|
||||
|
||||
# Get the firmware version number from the source
|
||||
- MAJOR_VERSION=$(grep "VERSION_MAJOR" "Multiprotocol/Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
|
||||
- MINOR_VERSION=$(grep "VERSION_MINOR" "Multiprotocol/Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
|
||||
- REVISION_VERSION=$(grep "VERSION_REVISION" "Multiprotocol//Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
|
||||
- PATCH_VERSION=$(grep "VERSION_PATCH" "Multiprotocol//Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
|
||||
- MULTI_VERSION=$MAJOR_VERSION.$MINOR_VERSION.$REVISION_VERSION.$PATCH_VERSION
|
||||
|
||||
# Derive the Multi protocols from the Multi source
|
||||
- A7105_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_A7105_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
|
||||
- CC2500_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CC2500_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
|
||||
- CYRF6936_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CYRF6936_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
|
||||
- NRF24L01_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_NRF24L01_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
|
||||
- if [[ "$BOARD" =~ "multi4in1:avr:multixmega32d4" ]]; then
|
||||
ALL_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS);
|
||||
else
|
||||
ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS);
|
||||
fi
|
||||
- echo $ALL_PROTOCOLS
|
||||
|
||||
# Declare all the installed modules
|
||||
- ALL_RFMODULES=$(echo A7105_INSTALLED CYRF6936_INSTALLED CC2500_INSTALLED NRF24L01_INSTALLED);
|
||||
|
||||
# Disable CHECK_FOR_BOOTLOADER when not needed
|
||||
- if [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=none" ]]; then
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
fi
|
||||
|
||||
# Trim the enabled protocols down for the STM32 board with USB debugging
|
||||
- if [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103c:debug_option=native" ]]; then
|
||||
opt_disable AFHDS2A_RX_A7105_INO FRSKY_RX_CC2500_INO SCANNER_CC2500_INO WK2x01_CYRF6936_INO HUBSAN_A7105_INO;
|
||||
fi
|
||||
|
||||
# Trim the enabled protocols down for the Atmega328p board
|
||||
- if [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
|
||||
fi
|
||||
|
||||
# Useful Travis functions
|
||||
- export -f travis_fold
|
||||
- export -f travis_nanoseconds
|
||||
- export -f travis_time_start
|
||||
- export -f travis_time_finish
|
||||
- start_fold() { echo -e "travis_fold:start:$1"; }
|
||||
- end_fold() { echo -e "\ntravis_fold:end:$1\r"; }
|
||||
|
||||
script:
|
||||
# Build with default configuration - all protocols are enabled for STM32; a subset of protocols for Atmega
|
||||
- buildDefault
|
||||
|
||||
# Serial only
|
||||
- buildSerialOnly
|
||||
|
||||
# PPM only
|
||||
- buildPPMOnly
|
||||
|
||||
# Re-enable PPM and serial
|
||||
- opt_enable ENABLE_SERIAL
|
||||
- opt_enable ENABLE_PPM
|
||||
|
||||
# Build for each RF module individually
|
||||
- buildEachRFModule
|
||||
|
||||
# Restore the default configuration
|
||||
- cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
|
||||
# Build each protocol individually
|
||||
- buildEachProtocol
|
||||
|
||||
# Restore the default configuration
|
||||
- cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
|
||||
# Builds the files for a release - always built, but only copied to Github if the test is tagged as a release
|
||||
- buildReleaseFiles
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: KGXaoqvd8rbZ3AZtL9Rrn1JYiocGsPaihRUyR8gM8vTfvH9WYAE1+h6SzROQOuJSwr89MvTo3SBOTlM/0PDBnEGLec9Irt7cwO0xf9xM2vPuUG8DYcUzmJJzME9dkn/7qHof1JGgRpp1duUAN1triE9NxhKxL1hbs+tUUbDPAejxwoFNfnta/T4PfD6xmkZNJbneIfYFuFgyLpwwFhuUy9JP7s1AFOiT+fCHxPaZrPn5GsXqAi95Cb7Q3w1iVSt3BmrGxL2j3CeNpWzFY1RrMdc8ay+ppOhSPEIl2vyM7VeLRRBL3EVeFWkiS4ywevqw70wOivTczluv3OeuIJAe5o2UU+w5+59c7+i44Nih23PDAZBhAG5JkLUYUN0XUJpXJ5ZlZsb8IS8sI1txlZa5tNVoXO9+soGEY4rKSpZaPptuENm792CzzAjcaUI9pOFJ/0CBoSCbu5MpM/plkJCMd8fY27EE8cNYvolMuRATNlXs7h9mURGR69pmcR1jFShH+A7Kyp1S1sH19sGCEU16rt2aAtf2FadFg/gKACC2y9rB3wBb4Qnapu2AwNRlTYNuU1+G+kb2FXRwMl04q+38S+cIBHH9NHfdftp9MRPf8Ekatojs92be/Ux21S+hcA7sx/DV22Dl45V6l4mXzR7U4x1nQcdn1SGuy5I4lL6IYCk=
|
||||
skip_cleanup: true
|
||||
file_glob: true
|
||||
file: binaries/*
|
||||
on:
|
||||
tags: true
|
||||
@@ -1,11 +1,11 @@
|
||||
@echo off
|
||||
|
||||
echo Installing Maple DFU driver...
|
||||
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0003 --type 1 --name "Maple DFU" --dest "%~dp0maple-dfu"
|
||||
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 Maple Serial driver...
|
||||
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0004 --type 3 --name "Maple Serial" --dest "%~dp0maple-serial"
|
||||
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
|
||||
|
||||
@@ -170,6 +170,24 @@
|
||||
],
|
||||
"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",
|
||||
@@ -527,6 +545,95 @@
|
||||
"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",
|
||||
|
||||
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 }
|
||||
@@ -27,13 +27,16 @@ void A7105_WriteData(uint8_t len, uint8_t channel)
|
||||
for (i = 0; i < len; i++)
|
||||
SPI_Write(packet[i]);
|
||||
A7105_CSN_on;
|
||||
if(protocol!=PROTO_FLYSKY)
|
||||
if(protocol!=PROTO_WFLY2)
|
||||
{
|
||||
A7105_Strobe(A7105_STANDBY); //Force standby mode, ie cancel any TX or RX...
|
||||
A7105_SetTxRxMode(TX_EN); //Switch to PA
|
||||
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);
|
||||
}
|
||||
A7105_WriteReg(A7105_0F_PLL_I, channel);
|
||||
A7105_Strobe(A7105_TX);
|
||||
}
|
||||
|
||||
void A7105_ReadData(uint8_t len)
|
||||
@@ -107,7 +110,7 @@ void A7105_WriteID(uint32_t ida)
|
||||
{
|
||||
A7105_CSN_off;
|
||||
SPI_Write(A7105_06_ID_DATA); //ex id=0x5475c52a ;txid3txid2txid1txid0
|
||||
SPI_Write((ida>>24)&0xff); //53
|
||||
SPI_Write((ida>>24)&0xff); //54
|
||||
SPI_Write((ida>>16)&0xff); //75
|
||||
SPI_Write((ida>>8)&0xff); //c5
|
||||
SPI_Write((ida>>0)&0xff); //2a
|
||||
@@ -192,9 +195,29 @@ void A7105_AdjustLOBaseFreq(uint8_t cmd)
|
||||
offset=(int16_t)FORCE_FLYSKY_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_FLYZONE:
|
||||
#ifdef FORCE_FLYZONE_TUNING
|
||||
offset=(int16_t)FORCE_FLYZONE_TUNING;
|
||||
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:
|
||||
@@ -206,7 +229,7 @@ void A7105_AdjustLOBaseFreq(uint8_t cmd)
|
||||
}
|
||||
}
|
||||
if(offset==1024) // Use channel 15 as an input
|
||||
offset=convert_channel_16b_nolimit(CH15,-300,300);
|
||||
offset=convert_channel_16b_nolimit(CH15,-300,300,false);
|
||||
|
||||
if(old_offset==offset) // offset is the same as before...
|
||||
return;
|
||||
@@ -277,8 +300,8 @@ const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef FLYZONE_A7105_INO
|
||||
const uint8_t PROGMEM FLYZONE_A7105_regs[] = {
|
||||
#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
|
||||
@@ -293,6 +316,44 @@ const uint8_t PROGMEM HUBSAN_A7105_regs[] = {
|
||||
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
|
||||
@@ -301,14 +362,36 @@ void A7105_Init(void)
|
||||
uint8_t *A7105_Regs=0;
|
||||
uint8_t vco_calibration0, vco_calibration1;
|
||||
|
||||
#ifdef FLYZONE_A7105_INO
|
||||
if(protocol==PROTO_FLYZONE)
|
||||
#ifdef JOYSWAY_A7105_INO
|
||||
if(protocol==PROTO_JOYSWAY)
|
||||
{
|
||||
A7105_Regs=(uint8_t*)FLYZONE_A7105_regs;
|
||||
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;
|
||||
@@ -327,13 +410,20 @@ void A7105_Init(void)
|
||||
#ifdef FLYSKY_A7105_INO
|
||||
if(protocol==PROTO_FLYSKY)
|
||||
A7105_Regs=(uint8_t*)FLYSKY_A7105_regs;
|
||||
else
|
||||
#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 defined(AFHDS2A_A7105_INO) || defined(AFHDS2A_RX_A7105_INO)
|
||||
A7105_Regs=(uint8_t*)AFHDS2A_A7105_regs;
|
||||
#endif
|
||||
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++)
|
||||
@@ -347,61 +437,92 @@ void A7105_Init(void)
|
||||
if(i==0x20) val=0x1E;
|
||||
}
|
||||
#endif
|
||||
if( val != 0xFF)
|
||||
#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!=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
|
||||
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);
|
||||
}
|
||||
|
||||
//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)
|
||||
A7105_SetVCOBand(vco_calibration0 & 0x07, vco_calibration1 & 0x07); // Set calibration band value to best match
|
||||
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);
|
||||
|
||||
if(protocol!=PROTO_HUBSAN)
|
||||
{
|
||||
switch(protocol)
|
||||
{
|
||||
case PROTO_FLYSKY:
|
||||
vco_calibration1=0x08;
|
||||
break;
|
||||
case PROTO_FLYZONE:
|
||||
vco_calibration1=0x02;
|
||||
break;
|
||||
default:
|
||||
vco_calibration1=0x0A;
|
||||
break;
|
||||
}
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I,vco_calibration1); //Reset VCO Band calibration
|
||||
//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
|
||||
}
|
||||
|
||||
//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();
|
||||
|
||||
A7105_AdjustLOBaseFreq(0);
|
||||
#ifdef USE_A7105_CH15_TUNING
|
||||
A7105_AdjustLOBaseFreq(0);
|
||||
#endif
|
||||
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
}
|
||||
|
||||
@@ -24,10 +24,11 @@
|
||||
enum {
|
||||
AFHDS2A_RX_BIND1,
|
||||
AFHDS2A_RX_BIND2,
|
||||
AFHDS2A_RX_BIND3,
|
||||
AFHDS2A_RX_DATA
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) AFHDS2A_Rx_build_telemetry_packet()
|
||||
static void __attribute__((unused)) AFHDS2A_RX_build_telemetry_packet()
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
uint8_t bitsavailable = 0;
|
||||
@@ -39,7 +40,7 @@ static void __attribute__((unused)) AFHDS2A_Rx_build_telemetry_packet()
|
||||
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] << 8);
|
||||
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)
|
||||
@@ -55,13 +56,13 @@ static void __attribute__((unused)) AFHDS2A_Rx_build_telemetry_packet()
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) AFHDS2A_Rx_data_ready()
|
||||
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));
|
||||
}
|
||||
|
||||
uint16_t initAFHDS2A_Rx()
|
||||
void AFHDS2A_RX_init()
|
||||
{
|
||||
uint8_t i;
|
||||
A7105_Init();
|
||||
@@ -83,15 +84,12 @@ uint16_t initAFHDS2A_Rx()
|
||||
hopping_frequency[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
phase = AFHDS2A_RX_DATA;
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
#define AFHDS2A_RX_WAIT_WRITE 0x80
|
||||
|
||||
uint16_t AFHDS2A_Rx_callback()
|
||||
uint16_t AFHDS2A_RX_callback()
|
||||
{
|
||||
static uint32_t pps_timer = 0;
|
||||
static uint16_t pps_counter = 0;
|
||||
static int8_t read_retry;
|
||||
int16_t temp;
|
||||
uint8_t i;
|
||||
@@ -106,22 +104,33 @@ uint16_t AFHDS2A_Rx_callback()
|
||||
|
||||
switch(phase) {
|
||||
case AFHDS2A_RX_BIND1:
|
||||
if (AFHDS2A_Rx_data_ready()) {
|
||||
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_SetTxRxMode(RX_EN);
|
||||
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()) {
|
||||
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) &&
|
||||
@@ -132,42 +141,58 @@ uint16_t AFHDS2A_Rx_callback()
|
||||
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]);
|
||||
BIND_DONE;
|
||||
phase = AFHDS2A_RX_DATA;
|
||||
return 3850;
|
||||
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[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 (micros() - pps_timer < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
|
||||
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()) {
|
||||
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 == 0) { // standard packet, send channels to TX
|
||||
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();
|
||||
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
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#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,
|
||||
@@ -65,7 +69,6 @@ static void AFHDS2A_calc_channels()
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
|
||||
// telemetry sensors ID
|
||||
enum{
|
||||
AFHDS2A_SENSOR_RX_VOLTAGE = 0x00,
|
||||
@@ -76,10 +79,9 @@ enum{
|
||||
AFHDS2A_SENSOR_A3_VOLTAGE = 0x03,
|
||||
};
|
||||
|
||||
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
|
||||
static void AFHDS2A_update_telemetry()
|
||||
{
|
||||
if(packet[0]==0xAA && packet[9]==0xFD)
|
||||
return; // ignore packets which contain the RX configuration: 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
|
||||
// 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;
|
||||
@@ -183,37 +185,64 @@ static void AFHDS2A_build_packet(uint8_t type)
|
||||
{
|
||||
case AFHDS2A_PACKET_STICKS:
|
||||
packet[0] = 0x58;
|
||||
for(uint8_t ch=0; ch<14; ch++)
|
||||
//16 channels + RX_LQI on channel 17
|
||||
for(uint8_t ch=0; ch<num_ch; ch++)
|
||||
{
|
||||
uint16_t channelMicros = convert_channel_ppm(CH_AETR[ch]);
|
||||
packet[9 + ch*2] = channelMicros&0xFF;
|
||||
packet[10 + ch*2] = (channelMicros>>8)&0xFF;
|
||||
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;
|
||||
}
|
||||
}
|
||||
#ifdef AFHDS2A_LQI_CH
|
||||
// override channel with LQI
|
||||
val = 2000 - 10*RX_LQI;
|
||||
packet[9+((AFHDS2A_LQI_CH-1)*2)] = val & 0xff;
|
||||
packet[10+((AFHDS2A_LQI_CH-1)*2)] = (val >> 8) & 0xff;
|
||||
#endif
|
||||
break;
|
||||
case AFHDS2A_PACKET_FAILSAFE:
|
||||
packet[0] = 0x56;
|
||||
for(uint8_t ch=0; ch<14; ch++)
|
||||
for(uint8_t ch=0; ch<num_ch; ch++)
|
||||
{
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
uint16_t failsafeMicros = Failsafe_data[CH_AETR[ch]];
|
||||
if( failsafeMicros!=FAILSAFE_CHANNEL_HOLD && failsafeMicros!=FAILSAFE_CHANNEL_NOPULSES)
|
||||
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
|
||||
failsafeMicros = (((failsafeMicros<<2)+failsafeMicros)>>3)+860;
|
||||
packet[9 + ch*2] = failsafeMicros & 0xff;
|
||||
packet[10+ ch*2] = ( failsafeMicros >> 8) & 0xff;
|
||||
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
|
||||
{ // no values
|
||||
packet[9 + ch*2] = 0xff;
|
||||
packet[10+ ch*2] = 0xff;
|
||||
}
|
||||
if(ch<14)
|
||||
{ // no values
|
||||
packet[9 + ch*2] = 0xff;
|
||||
packet[10+ ch*2] = 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AFHDS2A_PACKET_SETTINGS:
|
||||
@@ -224,17 +253,14 @@ static void AFHDS2A_build_packet(uint8_t type)
|
||||
if(val<50 || val>400) val=50; // default is 50Hz
|
||||
packet[11]= val;
|
||||
packet[12]= val >> 8;
|
||||
if(sub_protocol == PPM_IBUS || sub_protocol == PPM_SBUS)
|
||||
packet[13] = 0x01; // PPM output enabled
|
||||
else
|
||||
packet[13] = 0x00;
|
||||
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 == PWM_SBUS || sub_protocol == PPM_SBUS)
|
||||
if(sub_protocol&2)
|
||||
packet[21] = 0xdd; // SBUS output enabled
|
||||
else
|
||||
packet[21] = 0xde; // IBUS
|
||||
@@ -244,11 +270,18 @@ static void AFHDS2A_build_packet(uint8_t type)
|
||||
}
|
||||
|
||||
#define AFHDS2A_WAIT_WRITE 0x80
|
||||
uint16_t ReadAFHDS2A()
|
||||
|
||||
#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;
|
||||
uint8_t data_rx=0;
|
||||
uint16_t start;
|
||||
#ifndef FORCE_AFHDS2A_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
@@ -259,13 +292,20 @@ uint16_t ReadAFHDS2A()
|
||||
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 | 1<<6)))
|
||||
{ // FECF+CRCF Ok
|
||||
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)
|
||||
{
|
||||
uint8_t addr;
|
||||
uint16_t addr;
|
||||
if(RX_num<16)
|
||||
addr=AFHDS2A_EEPROM_OFFSET+RX_num*4;
|
||||
else
|
||||
@@ -277,33 +317,33 @@ uint16_t ReadAFHDS2A()
|
||||
}
|
||||
phase = AFHDS2A_BIND4;
|
||||
packet_count++;
|
||||
return 3850;
|
||||
break;
|
||||
}
|
||||
}
|
||||
packet_count++;
|
||||
if(IS_BIND_DONE)
|
||||
{ // exit bind if asked to do so from the GUI
|
||||
phase = AFHDS2A_BIND4;
|
||||
return 3850;
|
||||
break;
|
||||
}
|
||||
phase |= AFHDS2A_WAIT_WRITE;
|
||||
return 1700;
|
||||
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)micros()-start < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
|
||||
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(TXRX_OFF); // Turn LNA off since we are in near range and we want to prevent swamping
|
||||
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 2150;
|
||||
return 3850-AFHDS2A_WRITE_TIME;
|
||||
case AFHDS2A_BIND4:
|
||||
AFHDS2A_build_bind_packet();
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, packet_count%2 ? 0x0d : 0x8c);
|
||||
@@ -315,7 +355,7 @@ uint16_t ReadAFHDS2A()
|
||||
phase = AFHDS2A_DATA_INIT;
|
||||
BIND_DONE;
|
||||
}
|
||||
return 3850;
|
||||
break;
|
||||
case AFHDS2A_DATA_INIT:
|
||||
packet_counter=0;
|
||||
packet_type = AFHDS2A_PACKET_STICKS;
|
||||
@@ -325,10 +365,7 @@ uint16_t ReadAFHDS2A()
|
||||
telemetry_set_input_sync(3850);
|
||||
#endif
|
||||
AFHDS2A_build_packet(packet_type);
|
||||
if((A7105_ReadReg(A7105_00_MODE) & 0x01)) // Check if something has been received...
|
||||
data_rx=0;
|
||||
else
|
||||
data_rx=1; // Yes
|
||||
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;
|
||||
@@ -344,32 +381,27 @@ uint16_t ReadAFHDS2A()
|
||||
}
|
||||
else
|
||||
#endif
|
||||
packet_type = AFHDS2A_PACKET_STICKS; // todo : check for settings changes
|
||||
packet_type = AFHDS2A_PACKET_STICKS; // todo : check for settings changes
|
||||
}
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5 | 1<<6)) && data_rx==1)
|
||||
{ // RX+FECF+CRCF Ok
|
||||
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
|
||||
packet_type=AFHDS2A_PACKET_SETTINGS; // RX is asking for settings
|
||||
else
|
||||
if(packet[0] == 0xAA || packet[0] == 0xAC)
|
||||
{
|
||||
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
|
||||
#ifdef AFHDS2A_LQI_CH
|
||||
if(packet[0]==0xAA && packet[9]!=0xFD)
|
||||
{// Normal telemetry packet
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
|
||||
AFHDS2A_update_telemetry();
|
||||
#endif
|
||||
@@ -378,23 +410,23 @@ uint16_t ReadAFHDS2A()
|
||||
}
|
||||
packet_counter++;
|
||||
phase |= AFHDS2A_WAIT_WRITE;
|
||||
return 1700;
|
||||
return AFHDS2A_WRITE_TIME;
|
||||
case AFHDS2A_DATA|AFHDS2A_WAIT_WRITE:
|
||||
//Wait for TX completion
|
||||
start=micros();
|
||||
while ((uint16_t)micros()-start < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
|
||||
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 2150;
|
||||
return 3850-AFHDS2A_WRITE_TIME;
|
||||
}
|
||||
return 3850; // never reached, please the compiler
|
||||
return 3850;
|
||||
}
|
||||
|
||||
uint16_t initAFHDS2A()
|
||||
void AFHDS2A_init()
|
||||
{
|
||||
A7105_Init();
|
||||
|
||||
@@ -407,7 +439,7 @@ uint16_t initAFHDS2A()
|
||||
{
|
||||
phase = AFHDS2A_DATA_INIT;
|
||||
//Read RX ID from EEPROM based on RX_num, RX_num must be uniq for each RX
|
||||
uint8_t addr;
|
||||
uint16_t addr;
|
||||
if(RX_num<16)
|
||||
addr=AFHDS2A_EEPROM_OFFSET+RX_num*4;
|
||||
else
|
||||
@@ -416,6 +448,9 @@ uint16_t initAFHDS2A()
|
||||
rx_id[i]=eeprom_read_byte((EE_ADDR)(addr+i));
|
||||
}
|
||||
hopping_frequency_no = 0;
|
||||
return 50000;
|
||||
if(sub_protocol&0x04)
|
||||
num_ch=17;
|
||||
else
|
||||
num_ch=14;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -33,19 +33,14 @@ enum {
|
||||
ASSAN_DATA5
|
||||
};
|
||||
|
||||
void ASSAN_init()
|
||||
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_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_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_WriteReg(NRF24L01_11_RX_PW_P0, ASSAN_PACKET_SIZE);
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
void ASSAN_send_packet()
|
||||
@@ -169,17 +164,16 @@ static void __attribute__((unused)) ASSAN_initialize_txid()
|
||||
hopping_frequency[1]=freq2;
|
||||
}
|
||||
|
||||
uint16_t initASSAN()
|
||||
void ASSAN_init()
|
||||
{
|
||||
ASSAN_initialize_txid();
|
||||
ASSAN_init();
|
||||
ASSAN_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
phase=ASSAN_BIND0;
|
||||
else
|
||||
phase=ASSAN_DATA0;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -115,7 +115,7 @@ void delayMilliseconds(unsigned long ms)
|
||||
uint16_t lms = ms ;
|
||||
|
||||
while (lms > 0) {
|
||||
if (((uint16_t)micros() - start) >= 1000) {
|
||||
if ((uint16_t)((uint16_t)micros() - start) >= 1000) {
|
||||
lms--;
|
||||
start += 1000;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#if defined(BUGSMINI_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define BUGSMINI_INITIAL_WAIT 500
|
||||
#define BUGSMINI_PACKET_INTERVAL 6840
|
||||
@@ -57,22 +57,10 @@ enum {
|
||||
#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_init()
|
||||
static void __attribute__((unused)) BUGSMINI_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
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_WriteReg(NRF24L01_11_RX_PW_P0, BUGSMINI_RX_PAYLOAD_SIZE); // bytes of data payload for rx pipe 1
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x07);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M);
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00); // Set feature bits on
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
//XN297_HoppingCalib(BUGSMINI_NUM_RF_CHANNELS*2);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGSMINI_check_arming()
|
||||
@@ -95,7 +83,7 @@ static void __attribute__((unused)) BUGSMINI_check_arming()
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) BUGSMINI_send_packet()
|
||||
{
|
||||
BUGSMINI_check_arming(); // sets globals arm_flags and armed
|
||||
|
||||
@@ -107,7 +95,7 @@ static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind)
|
||||
packet[1] = BUGSMINI_txid[0];
|
||||
packet[2] = BUGSMINI_txid[1];
|
||||
packet[3] = BUGSMINI_txid[2];
|
||||
if(bind)
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[4] = 0x00;
|
||||
packet[5] = 0x7d;
|
||||
@@ -159,15 +147,14 @@ static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind)
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no >= BUGSMINI_NUM_RF_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? hopping_frequency[hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS] : hopping_frequency[hopping_frequency_no]);
|
||||
XN297_Hopping(IS_BIND_IN_PROGRESS ? hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS : hopping_frequency_no);
|
||||
}
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, BUGSMINI_TX_PAYLOAD_SIZE);
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
// compute final address for the rxid received during bind
|
||||
@@ -231,37 +218,37 @@ static void __attribute__((unused)) BUGSMINI_make_address()
|
||||
// Something wrong happened if we arrive here....
|
||||
}
|
||||
|
||||
#if defined(BUGS_HUB_TELEMETRY)
|
||||
static void __attribute__((unused)) BUGSMINI_update_telemetry()
|
||||
{
|
||||
#if defined(BUGS_HUB_TELEMETRY)
|
||||
uint8_t checksum = 0x6d;
|
||||
for(uint8_t i=1; i<12; i++)
|
||||
checksum += packet[i];
|
||||
if(packet[0] == checksum)
|
||||
checksum += packet_in[i];
|
||||
if(packet_in[0] == checksum)
|
||||
{
|
||||
RX_RSSI = packet[3];
|
||||
RX_RSSI = packet_in[3];
|
||||
if(sub_protocol==BUGS3H)
|
||||
{
|
||||
if(packet[11] & 0x40)
|
||||
if(packet_in[11] & 0x40)
|
||||
v_lipo1 = 0x40; // Warning
|
||||
else if(packet[11] & 0x80)
|
||||
else if(packet_in[11] & 0x80)
|
||||
v_lipo1 = 0x20; // Critical
|
||||
else
|
||||
v_lipo1 = 0x80; // Ok
|
||||
}
|
||||
else
|
||||
{
|
||||
if(packet[11] & 0x80)
|
||||
if(packet_in[11] & 0x80)
|
||||
v_lipo1 = 0x80; // Ok
|
||||
else if(packet[11] & 0x40)
|
||||
else if(packet_in[11] & 0x40)
|
||||
v_lipo1 = 0x40; // Warning
|
||||
else
|
||||
v_lipo1 = 0x20; // Critical
|
||||
}
|
||||
telemetry_link=1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t BUGSMINI_callback()
|
||||
{
|
||||
@@ -269,58 +256,52 @@ uint16_t BUGSMINI_callback()
|
||||
switch(phase)
|
||||
{
|
||||
case BUGSMINI_BIND1:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
if( XN297_IsRX() )
|
||||
{ // RX fifo data ready
|
||||
XN297_ReadPayload(packet, BUGSMINI_RX_PAYLOAD_SIZE);
|
||||
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
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
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, 5);
|
||||
XN297_SetRXAddr(rx_tx_addr, BUGSMINI_RX_PAYLOAD_SIZE);
|
||||
phase = BUGSMINI_DATA1;
|
||||
BIND_DONE;
|
||||
return BUGSMINI_PACKET_INTERVAL;
|
||||
break;
|
||||
}
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
BUGSMINI_send_packet(1);
|
||||
BUGSMINI_send_packet();
|
||||
phase = BUGSMINI_BIND2;
|
||||
return BUGSMINI_WRITE_WAIT;
|
||||
case BUGSMINI_BIND2:
|
||||
// switch to RX mode
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
NRF24L01_FlushRx();
|
||||
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);
|
||||
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( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready => read only 12 bytes to not overwrite channel change flag
|
||||
XN297_ReadPayload(packet, 12);
|
||||
BUGSMINI_update_telemetry();
|
||||
}
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
BUGSMINI_send_packet(0);
|
||||
#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
|
||||
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);
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
phase = BUGSMINI_DATA1;
|
||||
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
|
||||
#endif
|
||||
}
|
||||
return BUGSMINI_PACKET_INTERVAL;
|
||||
}
|
||||
@@ -357,28 +338,27 @@ static void __attribute__((unused)) BUGSMINI_initialize_txid()
|
||||
BUGSMINI_txhash = pgm_read_byte_near( &BUGSMINI_tx_hash[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS] );
|
||||
}
|
||||
|
||||
uint16_t initBUGSMINI()
|
||||
void BUGSMINI_init()
|
||||
{
|
||||
BUGSMINI_initialize_txid();
|
||||
BUGSMINI_RF_init();
|
||||
memset(packet, (uint8_t)0, BUGSMINI_TX_PAYLOAD_SIZE);
|
||||
BUGSMINI_init();
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
XN297_SetTXAddr((const uint8_t*)"mjxRC", 5);
|
||||
XN297_SetRXAddr((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, 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;
|
||||
return BUGSMINI_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
|
||||
#if defined(BAYANG_RX_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define BAYANG_RX_PACKET_SIZE 15
|
||||
#define BAYANG_RX_RF_NUM_CHANNELS 4
|
||||
@@ -27,28 +27,15 @@ enum {
|
||||
BAYANG_RX_DATA
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) Bayang_Rx_init_nrf24l01()
|
||||
static void __attribute__((unused)) Bayang_Rx_RF_init()
|
||||
{
|
||||
const uint8_t bind_address[BAYANG_RX_ADDRESS_LENGTH] = { 0,0,0,0,0 };
|
||||
NRF24L01_Initialize();
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
XN297_SetTXAddr(bind_address, BAYANG_RX_ADDRESS_LENGTH);
|
||||
XN297_SetRXAddr(bind_address, BAYANG_RX_ADDRESS_LENGTH);
|
||||
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_WriteReg(NRF24L01_11_RX_PW_P0, BAYANG_RX_PACKET_SIZE + 2); // 2 extra bytes for xn297 crc
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, BAYANG_RX_RF_BIND_CHANNEL);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
|
||||
NRF24L01_Activate(0x73);
|
||||
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_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() {
|
||||
@@ -98,10 +85,10 @@ static void __attribute__((unused)) Bayang_Rx_build_telemetry_packet()
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initBayang_Rx()
|
||||
void BAYANG_RX_init()
|
||||
{
|
||||
uint8_t i;
|
||||
Bayang_Rx_init_nrf24l01();
|
||||
Bayang_Rx_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
rx_data_started = false;
|
||||
rx_data_received = false;
|
||||
@@ -115,91 +102,101 @@ uint16_t initBayang_Rx()
|
||||
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_ADDRESS_LENGTH);
|
||||
XN297_SetRXAddr(rx_tx_addr, BAYANG_RX_PACKET_SIZE);
|
||||
phase = BAYANG_RX_DATA;
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
uint16_t Bayang_Rx_callback()
|
||||
uint16_t BAYANG_RX_callback()
|
||||
{
|
||||
uint8_t i;
|
||||
static int8_t read_retry;
|
||||
static uint16_t pps_counter;
|
||||
static uint32_t pps_timer = 0;
|
||||
|
||||
switch (phase) {
|
||||
case BAYANG_RX_BIND:
|
||||
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) {
|
||||
// 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_SetTXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
|
||||
XN297_SetRXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
|
||||
BIND_DONE;
|
||||
phase = BAYANG_RX_DATA;
|
||||
}
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
}
|
||||
break;
|
||||
case BAYANG_RX_DATA:
|
||||
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) {
|
||||
if (XN297_ReadPayload(packet, BAYANG_RX_PACKET_SIZE) && packet[0] == 0xA5 && Bayang_Rx_check_validity()) {
|
||||
if (telemetry_link == 0) {
|
||||
Bayang_Rx_build_telemetry_packet();
|
||||
telemetry_link = 1;
|
||||
}
|
||||
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;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
if (rx_data_started)
|
||||
switch (phase)
|
||||
{
|
||||
case BAYANG_RX_BIND:
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
if(rx_data_received)
|
||||
{ // In sync
|
||||
rx_data_received = false;
|
||||
read_retry = 5;
|
||||
return 1500;
|
||||
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
|
||||
{ // packet lost
|
||||
read_retry = 0;
|
||||
if(RX_LQI==0) // communication lost
|
||||
rx_data_started=false;
|
||||
}
|
||||
read_retry = -16; // retry longer until first packet is caught
|
||||
}
|
||||
else
|
||||
read_retry = -16; // retry longer until first packet is caught
|
||||
}
|
||||
return 250;
|
||||
return 250;
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,11 @@ 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 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
|
||||
@@ -46,10 +47,10 @@ enum BAYANG_OPTION_FLAGS {
|
||||
BAYANG_OPTION_FLAG_ANALOGAUX = 0x02,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) BAYANG_send_packet()
|
||||
{
|
||||
uint8_t i;
|
||||
if (bind)
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
if(option & BAYANG_OPTION_FLAG_TELEMETRY)
|
||||
@@ -66,12 +67,16 @@ static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
|
||||
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];
|
||||
switch (sub_protocol)
|
||||
{
|
||||
case QX100:
|
||||
case X16_AH:
|
||||
packet[10] = 0x00;
|
||||
packet[11] = 0x00;
|
||||
@@ -92,6 +97,8 @@ static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
|
||||
}
|
||||
else
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
hopping_frequency_no%=BAYANG_RF_NUM_CHANNELS;
|
||||
uint16_t val;
|
||||
uint8_t dyntrim = 1;
|
||||
switch (sub_protocol)
|
||||
@@ -138,19 +145,19 @@ static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
|
||||
if(CH13_SW)
|
||||
packet[3] |= BAYANG_FLAG_EMG_STOP;
|
||||
//Aileron
|
||||
val = convert_channel_10b(AILERON);
|
||||
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);
|
||||
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);
|
||||
val = convert_channel_10b(RUDDER, false);
|
||||
packet[10] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
|
||||
packet[11] = val & 0xFF;
|
||||
}
|
||||
@@ -160,6 +167,7 @@ static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
|
||||
packet[12] = rx_tx_addr[2]; // txid[2]
|
||||
packet[13] = 0x34;
|
||||
break;
|
||||
case QX100:
|
||||
case X16_AH:
|
||||
packet[12] = 0;
|
||||
packet[13] = 0;
|
||||
@@ -186,150 +194,130 @@ static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
|
||||
for (uint8_t i=0; i < BAYANG_PACKET_SIZE-1; i++)
|
||||
packet[14] += packet[i];
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? rf_ch_num: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_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
// 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));
|
||||
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
if (option & BAYANG_OPTION_FLAG_TELEMETRY)
|
||||
{ // switch radio to rx as soon as packet is sent
|
||||
while (!(NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS)));
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x03);
|
||||
}
|
||||
#endif
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
static void __attribute__((unused)) BAYANG_check_rx(void)
|
||||
{
|
||||
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
if( XN297_IsRX() )
|
||||
{ // data received from model
|
||||
XN297_ReadPayload(packet, BAYANG_PACKET_SIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 255);
|
||||
|
||||
NRF24L01_FlushRx();
|
||||
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)
|
||||
if (packet[0] == 0x85 && packet[14] == check && telemetry_link == 0)
|
||||
{
|
||||
// uncompensated battery volts*100/2
|
||||
v_lipo1 = (packet[3]<<7) + (packet[4]>>2);
|
||||
v_lipo1 = (packet[3]<<7) + (packet[4]>>1);
|
||||
// compensated battery volts*100/2
|
||||
v_lipo2 = (packet[5]<<7) + (packet[6]>>2);
|
||||
v_lipo2 = (packet[5]<<7) + (packet[6]>>1);
|
||||
// reception in packets / sec
|
||||
RX_RSSI = packet[7];
|
||||
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==0)
|
||||
telemetry_link=1;
|
||||
if(telemetry_lost)
|
||||
telemetry_link=0; // Don't send anything yet
|
||||
}
|
||||
}
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __attribute__((unused)) BAYANG_init()
|
||||
static void __attribute__((unused)) BAYANG_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
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_WriteReg(NRF24L01_11_RX_PW_P0, BAYANG_PACKET_SIZE);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // No retransmits
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
|
||||
NRF24L01_Activate(0x73);
|
||||
//XN297_HoppingCalib(BAYANG_RF_NUM_CHANNELS);
|
||||
|
||||
switch (sub_protocol)
|
||||
{
|
||||
case X16_AH:
|
||||
case IRDRONE:
|
||||
rf_ch_num = BAYANG_RF_BIND_CHANNEL_X16_AH;
|
||||
break;
|
||||
default:
|
||||
rf_ch_num = BAYANG_RF_BIND_CHANNEL;
|
||||
break;
|
||||
}
|
||||
//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)
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
uint16_t start;
|
||||
#endif
|
||||
switch(phase)
|
||||
{
|
||||
if(packet_count==0)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync((option & BAYANG_OPTION_FLAG_TELEMETRY)?5*BAYANG_PACKET_PERIOD:2*BAYANG_PACKET_PERIOD);
|
||||
#endif
|
||||
BAYANG_send_packet(0);
|
||||
}
|
||||
packet_count++;
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
if (option & BAYANG_OPTION_FLAG_TELEMETRY)
|
||||
{ // telemetry is enabled
|
||||
state++;
|
||||
if (state > 1000)
|
||||
{
|
||||
//calculate telemetry reception packet rate - packets per 1000ms
|
||||
TX_RSSI = telemetry_counter;
|
||||
telemetry_counter = 0;
|
||||
state = 0;
|
||||
telemetry_lost=0;
|
||||
}
|
||||
|
||||
if (packet_count > 1)
|
||||
BAYANG_check_rx();
|
||||
|
||||
packet_count %= 5;
|
||||
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
|
||||
#endif
|
||||
packet_count%=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
XN297_SetRXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
|
||||
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
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(packet_count==0)
|
||||
BAYANG_send_packet(1);
|
||||
packet_count++;
|
||||
packet_count%=4;
|
||||
bind_counter--;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -347,14 +335,14 @@ static void __attribute__((unused)) BAYANG_initialize_txid()
|
||||
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();
|
||||
BAYANG_RF_init();
|
||||
packet_count=0;
|
||||
return BAYANG_INITIAL_WAIT+BAYANG_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -48,6 +48,7 @@ Bit(s) Bitmask Option Comment
|
||||
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.
|
||||
@@ -60,9 +61,15 @@ OpenTX 2 10
|
||||
|
||||
Module types are mapped to the following decimal / binary values:
|
||||
Module Type Decimal Value Binary Valsue
|
||||
AVR 0 00
|
||||
STM32 1 01
|
||||
OrangeRX 2 10
|
||||
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
|
||||
@@ -109,6 +116,17 @@ RTEA 23 10111
|
||||
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;
|
||||
|
||||
@@ -315,7 +315,7 @@ static void __attribute__((unused)) BUGS_increment_counts()
|
||||
// FIFO config is one less than desired value
|
||||
#define BUGS_FIFO_SIZE_RX 15
|
||||
#define BUGS_FIFO_SIZE_TX 21
|
||||
uint16_t ReadBUGS(void)
|
||||
uint16_t BUGS_callback(void)
|
||||
{
|
||||
uint8_t mode, base_adr;
|
||||
uint16_t rxid;
|
||||
@@ -340,7 +340,7 @@ uint16_t ReadBUGS(void)
|
||||
case BUGS_BIND_2:
|
||||
//Wait for TX completion
|
||||
start=micros();
|
||||
while ((uint16_t)micros()-start < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
|
||||
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);
|
||||
@@ -399,7 +399,7 @@ uint16_t ReadBUGS(void)
|
||||
case BUGS_DATA_2:
|
||||
//Wait for TX completion
|
||||
start=micros();
|
||||
while ((uint16_t)micros()-start < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
|
||||
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);
|
||||
@@ -437,7 +437,7 @@ uint16_t ReadBUGS(void)
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initBUGS(void)
|
||||
void BUGS_init(void)
|
||||
{
|
||||
uint16_t rxid=0;
|
||||
uint8_t base_adr=BUGS_EEPROM_OFFSET+(RX_num&0x0F)*2;
|
||||
@@ -459,8 +459,6 @@ uint16_t initBUGS(void)
|
||||
armed = 0;
|
||||
arm_flags = BUGS_FLAG_DISARM; // initial value from captures
|
||||
arm_channel_previous = BUGS_CH_SW_ARM;
|
||||
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -190,7 +190,9 @@ static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
|
||||
}
|
||||
TxPacket.option = (bindMode) ? (option & (~CABELL_OPTION_MASK_CHANNEL_REDUCTION)) : option; //remove channel reduction if in bind mode
|
||||
}
|
||||
TxPacket.reserved = 0;
|
||||
|
||||
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
|
||||
|
||||
@@ -244,7 +246,6 @@ static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
|
||||
TxPacket.checkSum_LSB = checkSum & 0x00FF;
|
||||
|
||||
// Set channel for next transmission
|
||||
rf_ch_num = CABELL_getNextChannel (hopping_frequency,CABELL_RADIO_CHANNELS, rf_ch_num);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH,rf_ch_num);
|
||||
|
||||
//NRF24L01_FlushTx(); //just in case things got hung up
|
||||
@@ -255,7 +256,7 @@ static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
|
||||
*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.
|
||||
|
||||
CABELL_SetPower();
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WritePayload((uint8_t*)&TxPacket, packetSize);
|
||||
|
||||
#if defined CABELL_HUB_TELEMETRY
|
||||
@@ -279,39 +280,44 @@ static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
|
||||
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
|
||||
* 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
|
||||
uint64_t indexOfNextSequenceValue;
|
||||
uint64_t numChannelsFactorial=1;
|
||||
uint32_t indexOfNextSequenceValue;
|
||||
uint32_t numChannelsFactorial=1;
|
||||
uint32_t perm32 ;
|
||||
uint8_t sequenceValue;
|
||||
|
||||
numChannels = constrain(numChannels,1,20);
|
||||
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
|
||||
numChannelsFactorial *= i; // Calculate n!
|
||||
outArray[i-1] = i-1; // Initialize array with the sequence
|
||||
}
|
||||
|
||||
permutation = (permutation % numChannelsFactorial) + 1; // permutation must be between 1 and n! or this algorithm will infinite loop
|
||||
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, permutation--; i<numChannels; i++ )
|
||||
for (i=0, perm32--; i<numChannels; i++ )
|
||||
{
|
||||
numChannelsFactorial /= ((uint64_t)numChannels)-i;
|
||||
indexOfNextSequenceValue = i+(permutation/numChannelsFactorial);
|
||||
permutation %= numChannelsFactorial;
|
||||
numChannelsFactorial /= numChannels-i;
|
||||
indexOfNextSequenceValue = i+(perm32/numChannelsFactorial);
|
||||
perm32 %= numChannelsFactorial;
|
||||
|
||||
//Copy the value in the selected array position
|
||||
sequenceValue = outArray[indexOfNextSequenceValue];
|
||||
@@ -356,48 +362,18 @@ static void __attribute__((unused)) CABELL_setAddress()
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) CABELL_init()
|
||||
static void __attribute__((unused)) CABELL_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
CABELL_SetPower();
|
||||
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // slower data rate gives better range/reliability
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes
|
||||
NRF24L01_SetTxRxMode(TX_EN); //Power up and 16 bit CRC
|
||||
|
||||
CABELL_setAddress();
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01);
|
||||
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_03_SETUP_AW, 0x03);
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x5F); // no retransmits
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F); // Enable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x04); // Enable dynamic Payload Length
|
||||
NRF24L01_Activate(0x73);
|
||||
prev_power = NRF_POWER_0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static void CABELL_SetPower() // This over-ride the standard Set Power to allow an flag in option to indicate max power setting
|
||||
// Note that on many modules max power may actually be worse than the normal high power setting
|
||||
// test and only use max if it helps the range
|
||||
{
|
||||
if(IS_BIND_DONE && !IS_RANGE_FLAG_on && ((option & CABELL_OPTION_MASK_MAX_POWER_OVERRIDE) != 0))
|
||||
{ // If we are not in range or bind mode and power setting override is in effect, then set max power, else standard power logic
|
||||
if(prev_power != NRF_POWER_3) // prev_power is global variable for NRF24L01; NRF_POWER_3 is max power
|
||||
{
|
||||
uint8_t rf_setup = NRF24L01_ReadReg(NRF24L01_06_RF_SETUP);
|
||||
rf_setup = (rf_setup & 0xF9) | (NRF_POWER_3 << 1);
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup);
|
||||
prev_power=NRF_POWER_3;
|
||||
}
|
||||
}
|
||||
else
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_SetTxRxMode(TX_EN); // Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
@@ -414,7 +390,7 @@ uint16_t CABELL_callback()
|
||||
else if (bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
CABELL_init(); // non-bind address
|
||||
CABELL_RF_init(); // non-bind address
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -425,17 +401,15 @@ uint16_t CABELL_callback()
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
uint16_t initCABELL(void)
|
||||
void CABELL_init(void)
|
||||
{
|
||||
if (IS_BIND_DONE)
|
||||
bind_counter = 0;
|
||||
else
|
||||
bind_counter = CABELL_BIND_COUNT;
|
||||
CABELL_init();
|
||||
CABELL_RF_init();
|
||||
|
||||
packet_period = CABELL_PACKET_PERIOD;
|
||||
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -150,6 +150,11 @@ void CC2500_SetPower()
|
||||
#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;
|
||||
if(prev_power != power)
|
||||
@@ -158,4 +163,128 @@ void CC2500_SetPower()
|
||||
prev_power=power;
|
||||
}
|
||||
}
|
||||
|
||||
void __attribute__((unused)) CC2500_SetFreqOffset()
|
||||
{
|
||||
if(prev_option != option)
|
||||
{
|
||||
prev_option = option;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -644,37 +644,24 @@ static uint8_t crtp_log_setup_state_machine()
|
||||
return state_machine_completed;
|
||||
}
|
||||
|
||||
static int cflie_init()
|
||||
static void CFLIE_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
|
||||
// CRC, radio on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x01); // Auto Acknowledgement for data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, TX_ADDR_SIZE-2); // 5-byte RX/TX address
|
||||
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_SetPower();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
|
||||
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);
|
||||
|
||||
// this sequence necessary for module from stock tx
|
||||
NRF24L01_ReadReg(NRF24L01_1D_FEATURE);
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_ReadReg(NRF24L01_1D_FEATURE);
|
||||
|
||||
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
|
||||
|
||||
// 50ms delay in callback
|
||||
return 50000;
|
||||
NRF24L01_SetTxRxMode(TX_EN); // Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
|
||||
}
|
||||
|
||||
// TODO: Fix telemetry
|
||||
@@ -749,7 +736,7 @@ static int cflie_init()
|
||||
// }
|
||||
// }
|
||||
|
||||
static uint16_t cflie_callback()
|
||||
static uint16_t CFLIE_callback()
|
||||
{
|
||||
switch (phase) {
|
||||
case CFLIE_INIT_SEARCH:
|
||||
@@ -799,7 +786,7 @@ static uint16_t cflie_callback()
|
||||
}
|
||||
|
||||
// Generate address to use from TX id and manufacturer id (STM32 unique id)
|
||||
static uint8_t initialize_rx_tx_addr()
|
||||
static uint8_t CFLIE_initialize_rx_tx_addr()
|
||||
{
|
||||
rx_tx_addr[0] =
|
||||
rx_tx_addr[1] =
|
||||
@@ -844,19 +831,15 @@ static uint8_t initialize_rx_tx_addr()
|
||||
return CFLIE_INIT_SEARCH;
|
||||
}
|
||||
|
||||
uint16_t initCFlie(void)
|
||||
void CFLIE_init(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
|
||||
phase = initialize_rx_tx_addr();
|
||||
phase = CFLIE_initialize_rx_tx_addr();
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_INIT;
|
||||
packet_count=0;
|
||||
|
||||
int delay = cflie_init();
|
||||
|
||||
// debugln("CFlie init!");
|
||||
|
||||
return delay;
|
||||
CFLIE_RF_init();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#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
|
||||
@@ -49,7 +49,7 @@ enum YD829_FLAGS {
|
||||
YD829_FLAG_STILL = 0x80,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) CG023_send_packet()
|
||||
{
|
||||
// throttle : 0x00 - 0xFF
|
||||
throttle=convert_channel_8b(THROTTLE);
|
||||
@@ -62,10 +62,16 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
|
||||
// aileron : 0x43 - 0x7F - 0xBB
|
||||
aileron = convert_channel_16b_limit(AILERON, 0x43, 0xBB);
|
||||
|
||||
if (bind)
|
||||
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];
|
||||
@@ -85,7 +91,7 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
|
||||
if(sub_protocol==CG023)
|
||||
{
|
||||
// rate
|
||||
packet[13] = CG023_FLAG_RATE_HIGH
|
||||
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)
|
||||
@@ -95,7 +101,7 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
|
||||
else
|
||||
{// YD829
|
||||
// rate
|
||||
packet[13] = YD829_FLAG_RATE_HIGH
|
||||
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)
|
||||
@@ -103,79 +109,52 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
|
||||
}
|
||||
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, CG023_RF_BIND_CHANNEL);
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency_no);
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
// Send
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_SetPower();
|
||||
XN297_WritePayload(packet, CG023_PACKET_SIZE);
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) CG023_init()
|
||||
static void __attribute__((unused)) CG023_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
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_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
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)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
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--;
|
||||
}
|
||||
}
|
||||
CG023_send_packet();
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) CG023_initialize_txid()
|
||||
{
|
||||
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
|
||||
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)
|
||||
packet_period=CG023_PACKET_PERIOD;
|
||||
else // YD829
|
||||
packet_period=YD829_PACKET_PERIOD;
|
||||
return CG023_INITIAL_WAIT+YD829_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,19 +17,19 @@
|
||||
|
||||
#if defined(CX10_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define CX10_BIND_COUNT 4360 // 6 seconds
|
||||
#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 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 CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
|
||||
#define CX10A_PACKET_PERIOD 6000
|
||||
|
||||
#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
|
||||
@@ -46,12 +46,12 @@ enum {
|
||||
CX10_DATA
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) 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];
|
||||
@@ -62,57 +62,57 @@ static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind)
|
||||
uint16_t throttle=convert_channel_16b_limit(THROTTLE,1000,2000);
|
||||
uint16_t rudder= convert_channel_16b_limit(RUDDER ,2000,1000);
|
||||
// Channel 5 - flip flag
|
||||
packet[12+offset] = GET_FLAG(CH5_SW,CX10_FLAG_FLIP); // flip flag applied on rudder
|
||||
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(CH6_SW) // rate 3 / headless on CX-10A
|
||||
if(CH6_SW) // rate 3 / headless on CX-10A
|
||||
flags = 0x02;
|
||||
else
|
||||
if(Channel_data[CH6] < CHANNEL_MIN_COMMAND)
|
||||
flags = 0x00; // rate 1
|
||||
flags = 0x00; // rate 1
|
||||
else
|
||||
flags = 0x01; // rate 2
|
||||
uint8_t flags2=0; // packet 14
|
||||
flags = 0x01; // rate 2
|
||||
uint8_t flags2=0; // packet 14
|
||||
|
||||
uint8_t video_state=packet[14] & 0x21;
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case CX10_BLUE:
|
||||
flags |= GET_FLAG(!CH7_SW, 0x10) // Channel 7 - picture
|
||||
|GET_FLAG( CH8_SW, 0x08); // Channel 8 - video
|
||||
flags |= GET_FLAG(!CH7_SW, 0x10) // Channel 7 - picture
|
||||
|GET_FLAG( CH8_SW, 0x08); // Channel 8 - video
|
||||
break;
|
||||
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
|
||||
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
|
||||
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)
|
||||
{
|
||||
flags=2;
|
||||
flags2|= GET_FLAG(CH7_SW,0x01) // Channel 7 - picture
|
||||
|GET_FLAG(CH8_SW,0x10); // Channel 8 - video
|
||||
flags2|= GET_FLAG(CH7_SW,0x01) // Channel 7 - picture
|
||||
|GET_FLAG(CH8_SW,0x10); // Channel 8 - video
|
||||
packet[17]=0x00;
|
||||
packet[18]=0x00;
|
||||
}
|
||||
else
|
||||
{ // F_Q282 & F_Q222
|
||||
flags=3; // expert
|
||||
if(CH8_SW) // Channel 8 - F_Q282 video / F_Q222 Module 1
|
||||
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
|
||||
|GET_FLAG(CH7_SW,0x10); // Channel 7 - F_Q282 picture / F_Q222 Module 2
|
||||
}
|
||||
if(CH10_SW) flags |=0x80; // Channel 10 - RTH
|
||||
if(CH10_SW) flags |=0x80; // Channel 10 - RTH
|
||||
break;
|
||||
case DM007:
|
||||
aileron = 3000 - aileron;
|
||||
@@ -128,16 +128,16 @@ static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind)
|
||||
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
|
||||
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
|
||||
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
|
||||
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);
|
||||
@@ -151,39 +151,23 @@ static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind)
|
||||
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, CX10_RF_BIND_CHANNEL);
|
||||
else
|
||||
// Send
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
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 __attribute__((unused)) 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, CX10_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()
|
||||
@@ -197,42 +181,39 @@ 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)
|
||||
debugln("RX");
|
||||
if(XN297_ReadPayload(packet, packet_length) && packet[9] == 1)
|
||||
{
|
||||
BIND_DONE;
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
phase = CX10_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// switch to TX mode
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
CX10_Write_Packet(1);
|
||||
delayMicroseconds(400);
|
||||
// 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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
CX10_Write_Packet(0);
|
||||
CX10_Write_Packet();
|
||||
break;
|
||||
}
|
||||
return packet_period;
|
||||
@@ -260,9 +241,13 @@ static void __attribute__((unused)) CX10_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;
|
||||
@@ -285,8 +270,7 @@ uint16_t initCX10(void)
|
||||
bind_counter = CX10_BIND_COUNT;
|
||||
}
|
||||
CX10_initialize_txid();
|
||||
CX10_init();
|
||||
return CX10_INITIAL_WAIT+packet_period;
|
||||
CX10_RF_init();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -79,13 +79,24 @@ uint8_t CYRF_Reset()
|
||||
void CYRF_GetMfgData(uint8_t data[])
|
||||
{
|
||||
#ifndef FORCE_CYRF_ID
|
||||
/* Fuses power on */
|
||||
CYRF_WriteRegister(CYRF_25_MFG_ID, 0xFF);
|
||||
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
|
||||
@@ -98,14 +109,14 @@ void CYRF_SetTxRxMode(uint8_t mode)
|
||||
{
|
||||
if(mode==TXRX_OFF)
|
||||
{
|
||||
if(protocol!=PROTO_WFLY)
|
||||
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
|
||||
if(protocol!=PROTO_WFLY)
|
||||
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
|
||||
@@ -168,10 +179,10 @@ void CYRF_SetPower(uint8_t val)
|
||||
/*
|
||||
*
|
||||
*/
|
||||
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
|
||||
@@ -258,7 +269,7 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin
|
||||
delayMilliseconds(1);
|
||||
for(i = 0; i < NUM_FREQ; i++)
|
||||
{
|
||||
CYRF_ConfigRFChannel(i);
|
||||
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
|
||||
@@ -284,7 +295,7 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin
|
||||
}
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Clear abort RX
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX
|
||||
}
|
||||
|
||||
#if defined(DEVO_CYRF6936_INO) || defined(J6PRO_CYRF6936_INO)
|
||||
@@ -313,6 +324,7 @@ const uint8_t PROGMEM DEVO_j6pro_sopcodes[][8] = {
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
static void __attribute__((unused)) CYRF_PROGMEM_ConfigSOPCode(const uint8_t *data)
|
||||
{
|
||||
uint8_t code[8];
|
||||
@@ -320,4 +332,69 @@ static void __attribute__((unused)) CYRF_PROGMEM_ConfigSOPCode(const uint8_t *da
|
||||
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
|
||||
@@ -32,9 +32,15 @@ uint16_t convert_channel_ppm(uint8_t num)
|
||||
}
|
||||
|
||||
// Channel value 100% is converted to 10bit values 0<->1023
|
||||
uint16_t convert_channel_10b(uint8_t num)
|
||||
uint16_t convert_channel_10b(uint8_t num, bool failsafe)
|
||||
{
|
||||
uint16_t val=Channel_data[num];
|
||||
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;
|
||||
@@ -91,9 +97,15 @@ int16_t convert_channel_16b_limit(uint8_t num,int16_t min,int16_t max)
|
||||
}
|
||||
|
||||
// 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)
|
||||
int16_t convert_channel_16b_nolimit(uint8_t num, int16_t min, int16_t max, bool failsafe)
|
||||
{
|
||||
int32_t val=Channel_data[num]; // 0<->2047
|
||||
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;
|
||||
}
|
||||
@@ -140,3 +152,25 @@ 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
|
||||
|
||||
@@ -61,7 +61,6 @@ static void __attribute__((unused)) CORONA_rf_init()
|
||||
CC2500_WriteReg(CC2500_15_DEVIATN, 0x50);
|
||||
}
|
||||
|
||||
prev_option = option;
|
||||
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
|
||||
@@ -72,7 +71,7 @@ static void __attribute__((unused)) CORONA_rf_init()
|
||||
}
|
||||
|
||||
// Generate id and hopping freq
|
||||
static void __attribute__((unused)) CORONA_init()
|
||||
static void __attribute__((unused)) CORONA_TXID_init()
|
||||
{
|
||||
#ifdef CORONA_FORCE_ID
|
||||
// Example of ID and channels taken from dumps
|
||||
@@ -256,17 +255,13 @@ static uint16_t __attribute__((unused)) CORONA_build_packet()
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t ReadCORONA()
|
||||
uint16_t CORONA_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(22000);
|
||||
#endif
|
||||
// Tune frequency if it has been changed
|
||||
if ( prev_option != option )
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
prev_option = option ;
|
||||
}
|
||||
CC2500_SetFreqOffset();
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
@@ -281,7 +276,7 @@ uint16_t ReadCORONA()
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initCORONA()
|
||||
void CORONA_init()
|
||||
{
|
||||
switch(sub_protocol)
|
||||
{
|
||||
@@ -298,9 +293,8 @@ uint16_t initCORONA()
|
||||
state=400; // Used by V2 to send RF channels + ID for 2.65s at startup
|
||||
hopping_frequency_no=0;
|
||||
fdv3_id_send = 0;
|
||||
CORONA_init();
|
||||
CORONA_TXID_init();
|
||||
CORONA_rf_init();
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#if defined(DM002_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define DM002_PACKET_PERIOD 6100 // Timeout for callback in uSec
|
||||
#define DM002_INITIAL_WAIT 500
|
||||
@@ -24,7 +24,6 @@
|
||||
#define DM002_RF_BIND_CHANNEL 0x27
|
||||
#define DM002_BIND_COUNT 655 // 4 seconds
|
||||
|
||||
|
||||
enum DM002_FLAGS {
|
||||
// flags going to packet[9]
|
||||
DM002_FLAG_FLIP = 0x01,
|
||||
@@ -37,10 +36,10 @@ enum DM002_FLAGS {
|
||||
DM002_FLAG_CAMERA2 = 0x80,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) DM002_send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) DM002_send_packet()
|
||||
{
|
||||
memcpy(packet+5,(uint8_t *)"\x00\x7F\x7F\x7F\x00\x00\x00",7);
|
||||
if(bind)
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[0] = 0xAA;
|
||||
packet[1] = rx_tx_addr[0];
|
||||
@@ -75,63 +74,40 @@ static void __attribute__((unused)) DM002_send_packet(uint8_t bind)
|
||||
packet_count&=0x0F;
|
||||
packet[10] = packet_count;
|
||||
packet_count++;
|
||||
XN297_Hopping(hopping_frequency_no);
|
||||
}
|
||||
//CRC
|
||||
for(uint8_t i=0;i<DM002_PACKET_SIZE-1;i++)
|
||||
packet[11]+=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));
|
||||
if (bind)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, DM002_RF_BIND_CHANNEL);
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
// 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, DM002_PACKET_SIZE);
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DM002_init()
|
||||
static void __attribute__((unused)) DM002_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
XN297_SetTXAddr((uint8_t *)"\x26\xA8\x67\x35\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 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_RFChannel(DM002_RF_BIND_CHANNEL);
|
||||
}
|
||||
|
||||
uint16_t DM002_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(DM002_PACKET_PERIOD);
|
||||
#endif
|
||||
DM002_send_packet(0);
|
||||
}
|
||||
else
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(DM002_PACKET_PERIOD);
|
||||
#endif
|
||||
if (bind_counter)
|
||||
{
|
||||
bind_counter--;
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
DM002_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
DM002_send_packet();
|
||||
return DM002_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
@@ -155,13 +131,12 @@ static void __attribute__((unused)) DM002_initialize_txid()
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initDM002(void)
|
||||
void DM002_init(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = DM002_BIND_COUNT;
|
||||
DM002_initialize_txid();
|
||||
DM002_init();
|
||||
return DM002_INITIAL_WAIT;
|
||||
DM002_RF_init();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
188
Multiprotocol/DSM.ino
Normal file
@@ -0,0 +1,188 @@
|
||||
#if defined(DSM_CYRF6936_INO) || defined(DSM_RX_CYRF6936_INO)
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
uint8_t sop_col;
|
||||
|
||||
const uint8_t PROGMEM DSM_pncodes[5][9][8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
{ /* Row 0 */
|
||||
/* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8},
|
||||
/* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6},
|
||||
/* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9},
|
||||
/* Col 3 */ {0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4},
|
||||
/* Col 4 */ {0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0},
|
||||
/* Col 5 */ {0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8},
|
||||
/* Col 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D},
|
||||
/* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1},
|
||||
/* Col 8 */ {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86}
|
||||
},
|
||||
{ /* Row 1 */
|
||||
/* Col 0 */ {0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3},
|
||||
/* Col 1 */ {0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9},
|
||||
/* Col 2 */ {0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82},
|
||||
/* Col 3 */ {0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB},
|
||||
/* Col 4 */ {0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7},
|
||||
/* Col 5 */ {0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95},
|
||||
/* Col 6 */ {0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4},
|
||||
/* Col 7 */ {0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF},
|
||||
/* Col 8 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97}
|
||||
},
|
||||
{ /* Row 2 */
|
||||
/* Col 0 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97},
|
||||
/* Col 1 */ {0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA},
|
||||
/* Col 2 */ {0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE},
|
||||
/* Col 3 */ {0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD},
|
||||
/* Col 4 */ {0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD},
|
||||
/* Col 5 */ {0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9},
|
||||
/* Col 6 */ {0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3},
|
||||
/* Col 7 */ {0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0},
|
||||
/* Col 8 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E}
|
||||
},
|
||||
{ /* Row 3 */
|
||||
/* Col 0 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E},
|
||||
/* Col 1 */ {0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7},
|
||||
/* Col 2 */ {0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1},
|
||||
/* Col 3 */ {0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4},
|
||||
/* Col 4 */ {0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6},
|
||||
/* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80},
|
||||
/* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88},
|
||||
/* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88},
|
||||
/* Col 8 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}
|
||||
// Wrong values used by Orange TX/RX
|
||||
// /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40}
|
||||
},
|
||||
{ /* Row 4 */
|
||||
/* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93},
|
||||
/* Col 1 */ {0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C},
|
||||
/* Col 2 */ {0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA},
|
||||
/* Col 3 */ {0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC},
|
||||
/* Col 4 */ {0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84},
|
||||
/* Col 5 */ {0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7},
|
||||
/* Col 6 */ {0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0},
|
||||
/* Col 7 */ {0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1},
|
||||
/* Col 8 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}
|
||||
},
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) DSM_read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len)
|
||||
{
|
||||
for(uint8_t i=0;i<len;i++)
|
||||
buf[i]=pgm_read_byte_near( &DSM_pncodes[row][col][i] );
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM DSM_init_vals[][2] = {
|
||||
{CYRF_02_TX_CTRL, 0x00}, // All TX interrupt disabled
|
||||
{CYRF_05_RX_CTRL, 0x00}, // All RX interrupt disabled
|
||||
{CYRF_28_CLK_EN, 0x02}, // Force receive clock enable
|
||||
{CYRF_32_AUTO_CAL_TIME, 0x3c}, // Default init value
|
||||
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
|
||||
{CYRF_26_XTAL_CFG, 0x08}, // Start delay
|
||||
{CYRF_06_RX_CFG, 0x4A}, // LNA enabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
|
||||
{CYRF_1B_TX_OFFSET_LSB, 0x55}, // Default init value
|
||||
{CYRF_1C_TX_OFFSET_MSB, 0x05}, // Default init value
|
||||
{CYRF_39_ANALOG_CTRL, 0x01}, // All slow for synth setting time
|
||||
{CYRF_01_TX_LENGTH, 0x10}, // 16 bytes packet
|
||||
{CYRF_14_EOP_CTRL, 0x02}, // Set EOP Symbol Count to 2
|
||||
{CYRF_12_DATA64_THOLD, 0x0a}, // 64 Chip Data PN corelator threshold, default datasheet value is 0x0E
|
||||
//Below is for bind only
|
||||
{CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //64 chip codes, SDR mode
|
||||
{CYRF_10_FRAMING_CFG, 0x4a}, // SOP disabled, no LEN field and SOP correlator of 0x0a but since SOP is disabled...
|
||||
{CYRF_1F_TX_OVERRIDE, 0x04}, // Disable TX CRC, no ACK, use TX synthesizer
|
||||
{CYRF_1E_RX_OVERRIDE, 0x14}, // Disable RX CRC, Force receive data rate, use RX synthesizer
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM DSM_data_vals[][2] = {
|
||||
{CYRF_29_RX_ABORT, 0x20}, // Abort RX operation in case we are coming from bind
|
||||
{CYRF_0F_XACT_CFG, 0x24}, // Force Idle
|
||||
{CYRF_29_RX_ABORT, 0x00}, // Clear abort RX
|
||||
{CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER}, // 64 chip codes, 8DR mode
|
||||
{CYRF_10_FRAMING_CFG, 0xea}, // SOP enabled, SOP_CODE_ADR 64 chips, Packet len enabled, SOP correlator 0x0A
|
||||
{CYRF_1F_TX_OVERRIDE, 0x00}, // CRC16 enabled, no ACK
|
||||
{CYRF_1E_RX_OVERRIDE, 0x00}, // CRC16 enabled, no ACK
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) DSM_cyrf_config()
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(DSM_init_vals) / 2; i++)
|
||||
CYRF_WriteRegister(pgm_read_byte_near(&DSM_init_vals[i][0]), pgm_read_byte_near(&DSM_init_vals[i][1]));
|
||||
CYRF_WritePreamble(0x333304);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_cyrf_configdata()
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(DSM_data_vals) / 2; i++)
|
||||
CYRF_WriteRegister(pgm_read_byte_near(&DSM_data_vals[i][0]), pgm_read_byte_near(&DSM_data_vals[i][1]));
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) DSM_get_pn_row(uint8_t channel, bool dsmx)
|
||||
{
|
||||
if(protocol == PROTO_DSM && sub_protocol == DSMR)
|
||||
return (channel + 2) % 5;
|
||||
return (dsmx ? (channel - 2) % 5 : channel % 5);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_set_sop_data_crc(bool ch2, bool dsmx)
|
||||
{
|
||||
//The crc for channel '1' is NOT(mfgid[0] << 8 + mfgid[1])
|
||||
//The crc for channel '2' is (mfgid[0] << 8 + mfgid[1])
|
||||
if(ch2)
|
||||
CYRF_ConfigCRCSeed(seed); //CH2
|
||||
else
|
||||
CYRF_ConfigCRCSeed(~seed); //CH1, DSMR only use CH1
|
||||
|
||||
uint8_t pn_row = DSM_get_pn_row(hopping_frequency[hopping_frequency_no], dsmx);
|
||||
uint8_t code[16];
|
||||
#if 0
|
||||
debug_time();
|
||||
debug(" crc:%04X,row:%d,col:%d,rf:%02X",(~seed)&0xffff,pn_row,sop_col,hopping_frequency[hopping_frequency_no]);
|
||||
#endif
|
||||
DSM_read_code(code,pn_row,sop_col,8); // pn_row between 0 and 4, sop_col between 1 and 7
|
||||
CYRF_ConfigSOPCode(code);
|
||||
DSM_read_code(code,pn_row,7 - sop_col,8); // 7-sop_col between 0 and 6
|
||||
DSM_read_code(code+8,pn_row,7 - sop_col + 1,8); // 7-sop_col+1 between 1 and 7
|
||||
CYRF_ConfigDataCode(code, 16);
|
||||
|
||||
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
|
||||
hopping_frequency_no++;
|
||||
if(dsmx)
|
||||
hopping_frequency_no %=23;
|
||||
else
|
||||
hopping_frequency_no %=2;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_calc_dsmx_channel()
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint32_t id = ~(((uint32_t)cyrfmfg_id[0] << 24) | ((uint32_t)cyrfmfg_id[1] << 16) | ((uint32_t)cyrfmfg_id[2] << 8) | (cyrfmfg_id[3] << 0));
|
||||
uint32_t id_tmp = id;
|
||||
while(idx < 23)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t count_3_27 = 0, count_28_51 = 0, count_52_76 = 0;
|
||||
id_tmp = id_tmp * 0x0019660D + 0x3C6EF35F; // Randomization
|
||||
uint8_t next_ch = ((id_tmp >> 8) % 0x49) + 3; // Use least-significant byte and must be larger than 3
|
||||
if ( (next_ch ^ cyrfmfg_id[3]) & 0x01 )
|
||||
continue;
|
||||
for (i = 0; i < idx; i++)
|
||||
{
|
||||
if(hopping_frequency[i] == next_ch)
|
||||
break;
|
||||
if(hopping_frequency[i] <= 27)
|
||||
count_3_27++;
|
||||
else
|
||||
if (hopping_frequency[i] <= 51)
|
||||
count_28_51++;
|
||||
else
|
||||
count_52_76++;
|
||||
}
|
||||
if (i != idx)
|
||||
continue;
|
||||
if ((next_ch < 28 && count_3_27 < 8)
|
||||
||(next_ch >= 28 && next_ch < 52 && count_28_51 < 7)
|
||||
||(next_ch >= 52 && count_52_76 < 8))
|
||||
hopping_frequency[idx++] = next_ch;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
491
Multiprotocol/DSM_Rx_cyrf6936.ino
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
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(DSM_RX_CYRF6936_INO)
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
//#define DSM_DEBUG_RF
|
||||
//#define DSM_DEBUG_CH
|
||||
|
||||
uint8_t DSM_rx_type;
|
||||
|
||||
enum {
|
||||
DSM_RX_BIND1 = 0,
|
||||
DSM_RX_BIND2,
|
||||
DSM_RX_DATA_PREP,
|
||||
DSM2_RX_SCAN,
|
||||
DSM_RX_DATA_CH1,
|
||||
DSM_RX_DATA_CH2,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) DSM_RX_RF_init()
|
||||
{
|
||||
DSM_cyrf_config();
|
||||
rx_disable_lna = IS_POWER_FLAG_on;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
//64 SDR Mode is configured so only the 8 first values are needed but need to write 16 values...
|
||||
uint8_t code[16];
|
||||
DSM_read_code(code,0,8,8);
|
||||
CYRF_ConfigDataCode(code, 16);
|
||||
CYRF_ConfigRFChannel(1);
|
||||
CYRF_SetTxRxMode(RX_EN); // Force end state read
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive
|
||||
}
|
||||
else
|
||||
{
|
||||
DSM_cyrf_configdata();
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, rx_disable_lna ? 0x0A:0x4A); // AGC disabled, LNA disabled/enabled, Attenuator disabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t convert_channel_DSM_nolimit(int32_t val)
|
||||
{
|
||||
val=(val-0x150)*(CHANNEL_MAX_100-CHANNEL_MIN_100)/(0x6B0-0x150)+CHANNEL_MIN_100;
|
||||
if(val<0)
|
||||
val=0;
|
||||
else
|
||||
if(val>2047)
|
||||
val=2047;
|
||||
return (uint16_t)val;
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) DSM_RX_check_packet()
|
||||
{
|
||||
uint8_t rx_status=CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx_status & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
|
||||
rx_status |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx_status & 0x07) == 0x02)
|
||||
{ // data received with no errors
|
||||
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
||||
#ifdef DSM_DEBUG_RF
|
||||
debugln("l=%d",len);
|
||||
#endif
|
||||
if(len>=2 && len<=16)
|
||||
{
|
||||
// Read packet
|
||||
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // Need to set RXOW before data read
|
||||
CYRF_ReadDataPacketLen(packet, len);
|
||||
|
||||
// Check packet ID
|
||||
if ((DSM_rx_type&0x80) == 0)
|
||||
{//DSM2
|
||||
packet[0] ^= 0xff;
|
||||
packet[1] ^= 0xff;
|
||||
}
|
||||
#ifdef DSM_DEBUG_CH
|
||||
for(uint8_t i=0;i<len;i++)
|
||||
debug("%02X ",packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
if(packet[0] == cyrfmfg_id[2] && packet[1] == cyrfmfg_id[3])
|
||||
return 0x02; // Packet ok
|
||||
}
|
||||
return 0x00; // Wrong size or ID -> nothing received
|
||||
}
|
||||
return rx_status; // Return error code
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_RX_build_telemetry_packet()
|
||||
{
|
||||
uint8_t nbr_bits = 11;
|
||||
if((DSM_rx_type&0xF0) == 0x00)
|
||||
nbr_bits=10; // Only DSM_22 is using a resolution of 1024
|
||||
|
||||
// Use packet length to calculate the number of channels
|
||||
len -= 2; // Remove header length
|
||||
len >>= 1; // Channels are on 2 bytes
|
||||
if(len==0) return; // No channels...
|
||||
|
||||
// Extract channels
|
||||
uint8_t idx;
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
{
|
||||
uint16_t value=(packet[i*2+2]<<8) | packet[i*2+3];
|
||||
if(value!=0xFFFF)
|
||||
{
|
||||
idx=(value&0x7FFF)>>nbr_bits; // retrieve channel index
|
||||
#ifdef DSM_DEBUG_CH
|
||||
debugln("i=%d,v=%d,u=%X",idx,value&0x7FF,value&0x8000);
|
||||
#endif
|
||||
if(idx<13)
|
||||
{
|
||||
if(nbr_bits==10) value <<= 1; // switch to 11 bits
|
||||
value &= 0x7FF;
|
||||
rx_rc_chan[CH_TAER[idx]]=convert_channel_DSM_nolimit(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Buid telemetry packet
|
||||
idx=0;
|
||||
packet_in[idx++] = RX_LQI;
|
||||
packet_in[idx++] = RX_LQI;
|
||||
packet_in[idx++] = 0; // start channel
|
||||
packet_in[idx++] = 12; // number of channels in packet
|
||||
|
||||
// Pack channels
|
||||
uint32_t bits = 0;
|
||||
uint8_t bitsavailable = 0;
|
||||
for (uint8_t i = 0; i < 12; i++)
|
||||
{
|
||||
bits |= ((uint32_t)rx_rc_chan[i]) << bitsavailable;
|
||||
bitsavailable += 11;
|
||||
while (bitsavailable >= 8)
|
||||
{
|
||||
packet_in[idx++] = bits & 0xff;
|
||||
bits >>= 8;
|
||||
bitsavailable -= 8;
|
||||
}
|
||||
}
|
||||
if(bitsavailable)
|
||||
packet_in[idx++] = bits & 0xff;
|
||||
// Send telemetry
|
||||
telemetry_link = 1;
|
||||
#ifdef SEND_CPPM
|
||||
if(sub_protocol>0)
|
||||
telemetry_link |= 0x80; // Disable telemetry output
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool __attribute__((unused)) DSM_RX_bind_check_validity()
|
||||
{
|
||||
uint16_t sum = 384 - 0x10;//
|
||||
for(uint8_t i = 0; i < 8; i++)
|
||||
sum += packet_in[i];
|
||||
if( packet_in[8] != (sum>>8) || packet_in[9] != (sum&0xFF)) //Checksum
|
||||
return false;
|
||||
for(uint8_t i = 8; i < 14; i++)
|
||||
sum += packet_in[i];
|
||||
if( packet_in[14] != (sum>>8) || packet_in[15] != (sum&0xFF)) //Checksum
|
||||
return false;
|
||||
if(memcmp(packet_in,packet_in+4,4)) //Check ID
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_RX_build_bind_packet()
|
||||
{
|
||||
uint16_t sum = 384 - 0x10;//
|
||||
packet[0] = 0xff ^ cyrfmfg_id[0]; // ID
|
||||
packet[1] = 0xff ^ cyrfmfg_id[1];
|
||||
packet[2] = 0xff ^ cyrfmfg_id[2];
|
||||
packet[3] = 0xff ^ cyrfmfg_id[3];
|
||||
packet[4] = 0x01; // RX version
|
||||
packet[5] = num_ch; // Number of channels
|
||||
packet[6] = DSM_rx_type; // DSM type, let's just send back whatever the TX gave us...
|
||||
packet[7] = 0x00; // Unknown
|
||||
for(uint8_t i = 0; i < 8; i++)
|
||||
sum += packet[i];
|
||||
packet[8] = sum >> 8;
|
||||
packet[9] = sum & 0xff;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_abort_channel_rx(uint8_t ch)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||
CYRF_SetTxRxMode(IS_POWER_FLAG_on ? TXRX_OFF:RX_EN); // Force end state read
|
||||
if (rx_disable_lna != IS_POWER_FLAG_on && IS_BIND_DONE)
|
||||
{
|
||||
rx_disable_lna = IS_POWER_FLAG_on;
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, rx_disable_lna ? 0x0A:0x4A); // AGC disabled, LNA disabled/enabled, Attenuator disabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
|
||||
}
|
||||
if(ch&0x02) DSM_set_sop_data_crc(true ,DSM_rx_type&0x80); // Set sop data,crc seed and rf channel using CH1, DSM2/X
|
||||
if(ch&0x01) DSM_set_sop_data_crc(false,DSM_rx_type&0x80); // Set sop data,crc seed and rf channel using CH1, DSM2/X
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive
|
||||
}
|
||||
|
||||
uint16_t DSM_RX_callback()
|
||||
{
|
||||
uint8_t rx_status;
|
||||
static uint8_t read_retry=0;
|
||||
|
||||
switch (phase)
|
||||
{
|
||||
case DSM_RX_BIND1:
|
||||
if(IS_BIND_DONE) // Abort bind
|
||||
{
|
||||
phase = DSM_RX_DATA_PREP;
|
||||
break;
|
||||
}
|
||||
if(packet_count==0)
|
||||
read_retry=0;
|
||||
//Check received data
|
||||
rx_status = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx_status & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
|
||||
rx_status |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx_status & 0x07) == 0x02)
|
||||
{ // data received with no errors
|
||||
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // Need to set RXOW before data read
|
||||
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
||||
debugln("RX:%d, CH:%d",len,hopping_frequency_no);
|
||||
if(len==16)
|
||||
{
|
||||
CYRF_ReadDataPacketLen(packet_in, 16);
|
||||
if(DSM_RX_bind_check_validity())
|
||||
{
|
||||
// store tx info into eeprom
|
||||
uint16_t temp = DSM_RX_EEPROM_OFFSET;
|
||||
debug("ID=");
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
{
|
||||
cyrfmfg_id[i]=packet_in[i]^0xFF;
|
||||
eeprom_write_byte((EE_ADDR)temp++, cyrfmfg_id[i]);
|
||||
debug(" %02X", cyrfmfg_id[i]);
|
||||
}
|
||||
// save num_ch
|
||||
num_ch=packet_in[11];
|
||||
// store DSM_rx_type
|
||||
/*packet[12] 1 byte -> max DSM type allowed:
|
||||
0x01 => 22ms 1024 DSM2 1 packet => number of channels is <8
|
||||
0x02 => 22ms 1024 DSM2 2 packets => either a number of channel >7
|
||||
0x12 => 11ms 2048 DSM2 2 packets => can be any number of channels
|
||||
0xA2 => 22ms 2048 DSMX 1 packet => number of channels is <8
|
||||
0xB2 => 11ms 2048 DSMX => can be any number of channels
|
||||
(0x01 or 0xA2) and num_ch < 7 => 22ms else 11ms
|
||||
&0x80 => false=DSM2, true=DSMX
|
||||
&0xF0 => false=1024, true=2048 */
|
||||
DSM_rx_type=packet_in[12];
|
||||
debugln(", num_ch=%d, type=%02X",num_ch, DSM_rx_type);
|
||||
eeprom_write_byte((EE_ADDR)temp, DSM_rx_type);
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||
CYRF_SetTxRxMode(TX_EN); // Force end state TX
|
||||
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84", 16);
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX
|
||||
DSM_RX_build_bind_packet();
|
||||
bind_counter=500;
|
||||
phase++; // DSM_RX_BIND2;
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
DSM_abort_channel_rx(0); // Abort RX operation and receive
|
||||
if(read_retry==0)
|
||||
read_retry=8;
|
||||
}
|
||||
else
|
||||
if(rx_status & 0x02) // RX error
|
||||
DSM_abort_channel_rx(0); // Abort RX operation and receive
|
||||
packet_count++;
|
||||
if(packet_count>12)
|
||||
{
|
||||
packet_count=1;
|
||||
if(read_retry)
|
||||
read_retry--;
|
||||
if(read_retry==0)
|
||||
{
|
||||
packet_count=0;
|
||||
hopping_frequency_no++; // Change channel
|
||||
hopping_frequency_no %= 0x50;
|
||||
hopping_frequency_no |= 0x01; // Odd channels only
|
||||
CYRF_ConfigRFChannel(hopping_frequency_no);
|
||||
DSM_abort_channel_rx(0); // Abort RX operation and receive
|
||||
}
|
||||
}
|
||||
return 1000;
|
||||
case DSM_RX_BIND2:
|
||||
//Transmit settings back
|
||||
CYRF_WriteDataPacketLen(packet,10); // Send packet
|
||||
if(bind_counter--==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
phase++; // DSM_RX_DATA_PREP
|
||||
}
|
||||
break;
|
||||
case DSM_RX_DATA_PREP:
|
||||
hopping_frequency_no = 0;
|
||||
read_retry=0;
|
||||
rx_data_started = false;
|
||||
pps_counter = 0;
|
||||
RX_LQI = 100;
|
||||
DSM_cyrf_configdata();
|
||||
pps_timer=millis();
|
||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
|
||||
seed = (cyrfmfg_id[0] << 8) + cyrfmfg_id[1];
|
||||
if(DSM_rx_type&0x80)
|
||||
{ // DSMX
|
||||
DSM_calc_dsmx_channel(); // Build hop table
|
||||
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
|
||||
phase=DSM_RX_DATA_CH1;
|
||||
}
|
||||
else
|
||||
{ // DSM2
|
||||
rf_ch_num=0;
|
||||
hopping_frequency_no = 0;
|
||||
hopping_frequency[0] = 3;
|
||||
hopping_frequency[1] = 0;
|
||||
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
|
||||
phase=DSM2_RX_SCAN;
|
||||
}
|
||||
break;
|
||||
case DSM2_RX_SCAN: // Scan for DSM2 frequencies
|
||||
//Received something ?
|
||||
rx_status = DSM_RX_check_packet();
|
||||
if(rx_status == 0x02)
|
||||
{ // data received with no errors
|
||||
debugln("CH%d:Found %d",rf_ch_num+1,hopping_frequency[rf_ch_num]);
|
||||
read_retry=0;
|
||||
if(rf_ch_num)
|
||||
{ // Both CH1 and CH2 found
|
||||
read_retry=0;
|
||||
hopping_frequency_no=0;
|
||||
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
|
||||
pps_timer=millis();
|
||||
phase++; // DSM_RX_DATA_CH1
|
||||
}
|
||||
else
|
||||
{
|
||||
rf_ch_num++; // CH1 found, scan for CH2
|
||||
hopping_frequency_no = 1;
|
||||
if(hopping_frequency[1] < 3) // If no CH2 keep then restart from current
|
||||
hopping_frequency[1]=hopping_frequency[0]+1;
|
||||
DSM_abort_channel_rx(2); // Abort RX operation, set sop&data&seed&rf using CH2, DSM2/X and receive
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
read_retry++;
|
||||
if(read_retry>50) // After 50ms
|
||||
{ // Try next channel
|
||||
debugln("CH%d:Next channel",rf_ch_num+1);
|
||||
read_retry=0;
|
||||
hopping_frequency_no = rf_ch_num;
|
||||
hopping_frequency[rf_ch_num]++;
|
||||
if(hopping_frequency[rf_ch_num] > 73) hopping_frequency[rf_ch_num] = 3;
|
||||
DSM_abort_channel_rx(rf_ch_num+1); // Abort RX operation, set sop&data&seed&rf using CH1/2, DSM2/X and receive
|
||||
}
|
||||
else if(rx_status & 0x02)
|
||||
{ // data received with errors
|
||||
if((rx_status & 0x01) && rf_ch_num==0)
|
||||
hopping_frequency[1] = hopping_frequency[0];// Might be CH2 since it's a CRC error so keep it
|
||||
debugln("CH%d:RX error",rf_ch_num+1);
|
||||
DSM_abort_channel_rx(0); // Abort RX operation and receive
|
||||
}
|
||||
}
|
||||
return 1000;
|
||||
case DSM_RX_DATA_CH1:
|
||||
//Packets per second
|
||||
if (millis() - pps_timer >= 1000)
|
||||
{//182pps @11ms, 91pps @22ms
|
||||
pps_timer = millis();
|
||||
if(DSM_rx_type!=0xA2 && DSM_rx_type!=0x01) // if 11ms
|
||||
pps_counter >>=1; // then /2
|
||||
debugln("%d pps", pps_counter);
|
||||
RX_LQI = pps_counter; // max=91pps
|
||||
pps_counter = 0;
|
||||
}
|
||||
//Received something ?
|
||||
rx_status = DSM_RX_check_packet();
|
||||
if(rx_status == 0x02)
|
||||
{ // data received with no errors
|
||||
#ifdef DSM_DEBUG_RF
|
||||
debugln("CH1:RX");
|
||||
#endif
|
||||
DSM_RX_build_telemetry_packet();
|
||||
rx_data_started = true;
|
||||
pps_counter++;
|
||||
DSM_abort_channel_rx(2); // Abort RX operation, set sop&data&seed&rf using CH2, DSM2/X and receive
|
||||
phase++;
|
||||
return 5000;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_retry++;
|
||||
if(rx_data_started && read_retry>6) // After 6*500=3ms
|
||||
{ // skip to CH2
|
||||
#ifdef DSM_DEBUG_RF
|
||||
debugln("CH1:Skip to CH2");
|
||||
#endif
|
||||
DSM_abort_channel_rx(2); // Abort RX operation, set sop&data&seed&rf using CH2, DSM2/X and receive
|
||||
phase++;
|
||||
return 4000;
|
||||
}
|
||||
if(rx_data_started && RX_LQI==0)
|
||||
{ // communication lost
|
||||
#ifdef DSM_DEBUG_RF
|
||||
debugln("CH1:Restart...");
|
||||
#endif
|
||||
phase=DSM_RX_DATA_PREP;
|
||||
return 1000;
|
||||
}
|
||||
if(read_retry>250)
|
||||
{ // move to next RF channel
|
||||
#ifdef DSM_DEBUG_RF
|
||||
debugln("CH1:Scan");
|
||||
#endif
|
||||
DSM_abort_channel_rx(3); // Abort RX operation, set sop&data&seed&rf using CH2 then CH1, DSM2/X and receive
|
||||
read_retry=0;
|
||||
}
|
||||
else if(rx_status & 0x02)
|
||||
{ // data received with errors
|
||||
#ifdef DSM_DEBUG_RF
|
||||
debugln("CH1:RX error %02X",rx_status);
|
||||
#endif
|
||||
DSM_abort_channel_rx(0); // Abort RX operation and receive
|
||||
}
|
||||
}
|
||||
return 500;
|
||||
case DSM_RX_DATA_CH2:
|
||||
rx_status = DSM_RX_check_packet();
|
||||
if(rx_status == 0x02)
|
||||
{ // data received with no errors
|
||||
#ifdef DSM_DEBUG_RF
|
||||
debugln("CH2:RX");
|
||||
#endif
|
||||
DSM_RX_build_telemetry_packet();
|
||||
pps_counter++;
|
||||
}
|
||||
#ifdef DSM_DEBUG_RF
|
||||
else
|
||||
debugln("CH2:No RX");
|
||||
#endif
|
||||
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
|
||||
read_retry=0;
|
||||
phase=DSM_RX_DATA_CH1;
|
||||
if(DSM_rx_type==0xA2) //|| DSM_rx_type==0x01 -> not needed for DSM2 since we are ok to listen even if there will be nothing
|
||||
return 15000; //22ms
|
||||
else
|
||||
return 4000; //11ms
|
||||
}
|
||||
return 10000;
|
||||
}
|
||||
|
||||
void DSM_RX_init()
|
||||
{
|
||||
DSM_RX_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet_count=0;
|
||||
phase = DSM_RX_BIND1;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t temp = DSM_RX_EEPROM_OFFSET;
|
||||
debug("ID=");
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
{
|
||||
cyrfmfg_id[i]=eeprom_read_byte((EE_ADDR)temp++);
|
||||
debug(" %02X", cyrfmfg_id[i]);
|
||||
}
|
||||
DSM_rx_type=eeprom_read_byte((EE_ADDR)temp);
|
||||
debugln(", type=%02X", DSM_rx_type);
|
||||
phase = DSM_RX_DATA_PREP;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -17,6 +17,10 @@
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
//#define DSM_DEBUG_FWD_PGM
|
||||
|
||||
//#define DSM_GR300
|
||||
|
||||
#define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel
|
||||
|
||||
//During binding we will send BIND_COUNT/2 packets
|
||||
@@ -41,10 +45,10 @@ enum {
|
||||
};
|
||||
|
||||
//
|
||||
uint8_t sop_col;
|
||||
uint8_t ch_map[14];
|
||||
const uint8_t PROGMEM DSM_ch_map_progmem[][14] = {
|
||||
//22+11ms for 4..7 channels
|
||||
//22+11ms for 3..7 channels
|
||||
{1, 0, 2, 0xff, 0xff, 0xff, 0xff, 1, 0, 2, 0xff, 0xff, 0xff, 0xff}, //3ch - Guess
|
||||
{1, 0, 2, 3, 0xff, 0xff, 0xff, 1, 0, 2, 3, 0xff, 0xff, 0xff}, //4ch - Guess
|
||||
{1, 0, 2, 3, 4, 0xff, 0xff, 1, 0, 2, 3, 4, 0xff, 0xff}, //5ch - Guess
|
||||
{1, 5, 2, 3, 0, 4, 0xff, 1, 5, 2, 3, 0, 4, 0xff}, //6ch - HP6DSM
|
||||
@@ -54,123 +58,14 @@ const uint8_t PROGMEM DSM_ch_map_progmem[][14] = {
|
||||
{1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 8, 0xff, 0xff, 0xff}, //9ch - Guess
|
||||
{1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 8, 9, 0xff, 0xff}, //10ch - Guess
|
||||
{1, 5, 2, 3, 6, 10, 0xff, 4, 0, 7, 8, 9, 0xff, 0xff}, //11ch - Guess
|
||||
{1, 5, 2, 4, 6, 10, 0xff, 0, 7, 3, 8, 9 , 11 , 0xff}, //12ch - DX18
|
||||
//11ms for 8..12 channels
|
||||
{1, 5, 2, 4, 6, 10, 0xff, 0, 7, 3, 8, 9 , 11 , 0xff}, //12ch - DX18/DX8G2
|
||||
//11ms for 8..11 channels
|
||||
{1, 5, 2, 3, 6, 7, 0xff, 1, 5, 2, 4, 0, 0xff, 0xff}, //8ch - DX7
|
||||
{1, 5, 2, 3, 6, 7, 0xff, 1, 5, 2, 4, 0, 8, 0xff}, //9ch - Guess
|
||||
{1, 5, 2, 3, 4, 8, 9, 1, 5, 2, 3, 0, 7, 6 }, //10ch - DX18
|
||||
{1, 5, 2, 3, 4, 8, 9, 1, 5, 2, 3, 0, 7, 6 }, //10ch - DX18
|
||||
{1, 5, 2, 3, 4, 8, 9, 1, 10, 2, 3, 0, 7, 6 }, //11ch - Guess
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM DSM_pncodes[5][8][8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
{ /* Row 0 */
|
||||
/* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8},
|
||||
/* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6},
|
||||
/* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9},
|
||||
/* Col 3 */ {0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4},
|
||||
/* Col 4 */ {0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0},
|
||||
/* Col 5 */ {0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8},
|
||||
/* Col 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D},
|
||||
/* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1},
|
||||
/* Col 8 {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86}*/
|
||||
},
|
||||
{ /* Row 1 */
|
||||
/* Col 0 */ {0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3},
|
||||
/* Col 1 */ {0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9},
|
||||
/* Col 2 */ {0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82},
|
||||
/* Col 3 */ {0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB},
|
||||
/* Col 4 */ {0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7},
|
||||
/* Col 5 */ {0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95},
|
||||
/* Col 6 */ {0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4},
|
||||
/* Col 7 */ {0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF},
|
||||
/* Col 8 {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97} */
|
||||
},
|
||||
{ /* Row 2 */
|
||||
/* Col 0 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97},
|
||||
/* Col 1 */ {0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA},
|
||||
/* Col 2 */ {0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE},
|
||||
/* Col 3 */ {0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD},
|
||||
/* Col 4 */ {0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD},
|
||||
/* Col 5 */ {0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9},
|
||||
/* Col 6 */ {0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3},
|
||||
/* Col 7 */ {0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0},
|
||||
/* Col 8 {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E} */
|
||||
},
|
||||
{ /* Row 3 */
|
||||
/* Col 0 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E},
|
||||
/* Col 1 */ {0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7},
|
||||
/* Col 2 */ {0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1},
|
||||
/* Col 3 */ {0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4},
|
||||
/* Col 4 */ {0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6},
|
||||
/* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80},
|
||||
/* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88},
|
||||
/* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88},
|
||||
/* Col 8 {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93} */
|
||||
// Wrong values used by Orange TX/RX
|
||||
// /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40}
|
||||
},
|
||||
{ /* Row 4 */
|
||||
/* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93},
|
||||
/* Col 1 */ {0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C},
|
||||
/* Col 2 */ {0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA},
|
||||
/* Col 3 */ {0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC},
|
||||
/* Col 4 */ {0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84},
|
||||
/* Col 5 */ {0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7},
|
||||
/* Col 6 */ {0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0},
|
||||
/* Col 7 */ {0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1},
|
||||
/* Col 8 {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8} */
|
||||
},
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) DSM_read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len)
|
||||
{
|
||||
for(uint8_t i=0;i<len;i++)
|
||||
buf[i]=pgm_read_byte_near( &DSM_pncodes[row][col][i] );
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) DSM_get_pn_row(uint8_t channel)
|
||||
{
|
||||
return ((sub_protocol == DSMX_11 || sub_protocol == DSMX_22 )? (channel - 2) % 5 : channel % 5);
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM DSM_init_vals[][2] = {
|
||||
{CYRF_02_TX_CTRL, 0x00}, // All TX interrupt disabled
|
||||
{CYRF_05_RX_CTRL, 0x00}, // All RX interrupt disabled
|
||||
{CYRF_28_CLK_EN, 0x02}, // Force receive clock enable
|
||||
{CYRF_32_AUTO_CAL_TIME, 0x3c}, // Default init value
|
||||
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
|
||||
{CYRF_06_RX_CFG, 0x4A}, // LNA enabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
|
||||
{CYRF_1B_TX_OFFSET_LSB, 0x55}, // Default init value
|
||||
{CYRF_1C_TX_OFFSET_MSB, 0x05}, // Default init value
|
||||
{CYRF_39_ANALOG_CTRL, 0x01}, // All slow for synth setting time
|
||||
{CYRF_01_TX_LENGTH, 0x10}, // 16 bytes packet
|
||||
{CYRF_14_EOP_CTRL, 0x02}, // Set EOP Symbol Count to 2
|
||||
{CYRF_12_DATA64_THOLD, 0x0a}, // 64 Chip Data PN corelator threshold, default datasheet value is 0x0E
|
||||
//Below is for bind only
|
||||
{CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //64 chip codes, SDR mode
|
||||
{CYRF_10_FRAMING_CFG, 0x4a}, // SOP disabled, no LEN field and SOP correlator of 0x0a but since SOP is disabled...
|
||||
{CYRF_1F_TX_OVERRIDE, 0x04}, // Disable TX CRC, no ACK, use TX synthesizer
|
||||
{CYRF_1E_RX_OVERRIDE, 0x14}, // Disable RX CRC, Force receive data rate, use RX synthesizer
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM DSM_data_vals[][2] = {
|
||||
{CYRF_29_RX_ABORT, 0x20}, // Abort RX operation in case we are coming from bind
|
||||
{CYRF_0F_XACT_CFG, 0x24}, // Force Idle
|
||||
{CYRF_29_RX_ABORT, 0x00}, // Clear abort RX
|
||||
{CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER}, // 64 chip codes, 8DR mode
|
||||
{CYRF_10_FRAMING_CFG, 0xea}, // SOP enabled, SOP_CODE_ADR 64 chips, Packet len enabled, SOP correlator 0x0A
|
||||
{CYRF_1F_TX_OVERRIDE, 0x00}, // CRC16 enabled, no ACK
|
||||
{CYRF_1E_RX_OVERRIDE, 0x00}, // CRC16 enabled, no ACK
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) DSM_cyrf_config()
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(DSM_init_vals) / 2; i++)
|
||||
CYRF_WriteRegister(pgm_read_byte_near(&DSM_init_vals[i][0]), pgm_read_byte_near(&DSM_init_vals[i][1]));
|
||||
CYRF_WritePreamble(0x333304);
|
||||
CYRF_ConfigRFChannel(0x61);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_build_bind_packet()
|
||||
{
|
||||
uint8_t i;
|
||||
@@ -187,23 +82,29 @@ static void __attribute__((unused)) DSM_build_bind_packet()
|
||||
sum += packet[i];
|
||||
packet[8] = sum >> 8;
|
||||
packet[9] = sum & 0xff;
|
||||
packet[10] = 0x01; //???
|
||||
packet[11] = num_ch;
|
||||
packet[10] = 0x01; // ???
|
||||
if(sub_protocol==DSM_AUTO)
|
||||
packet[11] = 12;
|
||||
else
|
||||
packet[11] = num_ch; // DX5 DSMR sends 0x48...
|
||||
|
||||
if (sub_protocol==DSM2_22)
|
||||
packet[12]=num_ch<8?0x01:0x02; // DSM2/1024 1 or 2 packets depending on the number of channels
|
||||
if(sub_protocol==DSM2_11)
|
||||
packet[12]=0x12; // DSM2/2048 2 packets
|
||||
if(sub_protocol==DSMX_22)
|
||||
if (sub_protocol==DSMR)
|
||||
packet[12] = 0xa2;
|
||||
else if (sub_protocol==DSM2_1F)
|
||||
packet[12] = num_ch<8?0x01:0x02; // DSM2/1024 1 or 2 packets depending on the number of channels
|
||||
else if(sub_protocol==DSM2_2F)
|
||||
packet[12] = 0x12; // DSM2/2048 2 packets
|
||||
else if(sub_protocol==DSMX_1F)
|
||||
#if defined DSM_TELEMETRY
|
||||
packet[12] = 0xb2; // DSMX/2048 2 packets
|
||||
#else
|
||||
packet[12] = num_ch<8? 0xa2 : 0xb2; // DSMX/2048 1 or 2 packets depending on the number of channels
|
||||
#endif
|
||||
if(sub_protocol==DSMX_11 || sub_protocol==DSM_AUTO) // Force DSMX/1024 in mode Auto
|
||||
packet[12]=0xb2; // DSMX/1024 2 packets
|
||||
else // DSMX_2F && DSM_AUTO
|
||||
packet[12] = 0xb2; // DSMX/2048 2 packets
|
||||
|
||||
packet[13] = 0x00; //???
|
||||
|
||||
packet[13] = 0x00; //???
|
||||
for(i = 8; i < 14; i++)
|
||||
sum += packet[i];
|
||||
packet[14] = sum >> 8;
|
||||
@@ -214,30 +115,27 @@ static void __attribute__((unused)) DSM_initialize_bind_phase()
|
||||
{
|
||||
CYRF_ConfigRFChannel(DSM_BIND_CHANNEL); //This seems to be random?
|
||||
//64 SDR Mode is configured so only the 8 first values are needed but need to write 16 values...
|
||||
CYRF_ConfigDataCode((const uint8_t*)"\xD7\xA1\x54\xB1\x5E\x89\xAE\x86\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 16);
|
||||
uint8_t code[16];
|
||||
DSM_read_code(code,0,8,8);
|
||||
CYRF_ConfigDataCode(code, 16);
|
||||
DSM_build_bind_packet();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_cyrf_configdata()
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(DSM_data_vals) / 2; i++)
|
||||
CYRF_WriteRegister(pgm_read_byte_near(&DSM_data_vals[i][0]), pgm_read_byte_near(&DSM_data_vals[i][1]));
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_update_channels()
|
||||
{
|
||||
prev_option=option;
|
||||
if(sub_protocol==DSM_AUTO)
|
||||
num_ch=12; // Force 12 channels in mode Auto
|
||||
else
|
||||
num_ch=option & 0x7F; // Remove the Max Throw flag
|
||||
if(num_ch<4 || num_ch>12)
|
||||
num_ch=option & 0x0F; // Remove flags 0x80=max_throw, 0x40=11ms
|
||||
|
||||
if(num_ch<3 || num_ch>12)
|
||||
num_ch=6; // Default to 6 channels if invalid choice...
|
||||
|
||||
if(sub_protocol==DSMR && num_ch>7)
|
||||
num_ch=7; // Max 7 channels in DSMR
|
||||
|
||||
// Create channel map based on number of channels and refresh rate
|
||||
uint8_t idx=num_ch-4;
|
||||
if(num_ch>7 && num_ch<11 && (sub_protocol==DSM2_11 || sub_protocol==DSMX_11))
|
||||
idx+=5; // In 11ms mode change index only for channels 8..10
|
||||
uint8_t idx=num_ch-3;
|
||||
if((option & 0x40) && num_ch>7 && num_ch<12)
|
||||
idx+=5; // In 11ms mode change index only for channels 8..11
|
||||
for(uint8_t i=0;i<14;i++)
|
||||
ch_map[i]=pgm_read_byte_near(&DSM_ch_map_progmem[idx][i]);
|
||||
}
|
||||
@@ -249,25 +147,41 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
|
||||
if(prev_option!=option)
|
||||
DSM_update_channels();
|
||||
|
||||
if (sub_protocol==DSMX_11 || sub_protocol==DSMX_22 )
|
||||
{
|
||||
if (sub_protocol==DSMX_2F || sub_protocol==DSMX_1F)
|
||||
{//DSMX
|
||||
packet[0] = cyrfmfg_id[2];
|
||||
packet[1] = cyrfmfg_id[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
{//DSM2 && DSMR
|
||||
packet[0] = (0xff ^ cyrfmfg_id[2]);
|
||||
packet[1] = (0xff ^ cyrfmfg_id[3]);
|
||||
if(sub_protocol==DSM2_22)
|
||||
bits=10; // Only DSM_22 is using a resolution of 1024
|
||||
if(sub_protocol==DSM2_1F)
|
||||
bits=10; // Only DSM2_1F is using a resolution of 1024
|
||||
}
|
||||
|
||||
if(sub_protocol == DSMR)
|
||||
{
|
||||
for (uint8_t i = 0; i < 7; i++)
|
||||
{
|
||||
uint16_t value = 0x0000;
|
||||
if(i < num_ch)
|
||||
value=Channel_data[i]<<1;
|
||||
packet[i*2+2] = (value >> 8) & 0xff;
|
||||
packet[i*2+3] = (value >> 0) & 0xff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DSM_THROTTLE_KILL_CH
|
||||
uint16_t kill_ch=Channel_data[DSM_THROTTLE_KILL_CH-1];
|
||||
#endif
|
||||
for (uint8_t i = 0; i < 7; i++)
|
||||
{
|
||||
uint8_t idx = ch_map[(upper?7:0) + i];//1,5,2,3,0,4
|
||||
uint16_t value = 0xffff;;
|
||||
uint8_t idx = ch_map[(upper?7:0) + i]; // 1,5,2,3,0,4
|
||||
uint16_t value = 0xffff;
|
||||
if((option&0x40) == 0 && num_ch < 8 && upper)
|
||||
idx=0xff; // in 22ms do not transmit upper channels if <8, is it the right method???
|
||||
if (idx != 0xff)
|
||||
{
|
||||
/* Spektrum own remotes transmit normal values during bind and actually use this (e.g. Nano CP X) to
|
||||
@@ -275,7 +189,7 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
|
||||
#ifdef DSM_THROTTLE_KILL_CH
|
||||
if(idx==CH1 && kill_ch<=604)
|
||||
{//Activate throttle kill only if channel is throttle and DSM_THROTTLE_KILL_CH below -50%
|
||||
if(kill_ch<CHANNEL_MIN_100) // restrict val to 0...400
|
||||
if(kill_ch<CHANNEL_MIN_100) // restrict val to 0...400
|
||||
kill_ch=0;
|
||||
else
|
||||
kill_ch-=CHANNEL_MIN_100;
|
||||
@@ -284,84 +198,41 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
|
||||
else
|
||||
#endif
|
||||
#ifdef DSM_MAX_THROW
|
||||
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
|
||||
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
|
||||
#else
|
||||
if(option & 0x80)
|
||||
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
|
||||
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
|
||||
else
|
||||
value=convert_channel_16b_nolimit(CH_TAER[idx],0x150,0x6B0); // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on Redcon 6 channel DSM2 RX
|
||||
value=convert_channel_16b_nolimit(CH_TAER[idx],0x156,0x6AA,false); // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on a DX8 G2 dump
|
||||
#endif
|
||||
if(bits==10) value>>=1;
|
||||
value |= (upper && i==0 ? 0x8000 : 0) | (idx << bits);
|
||||
}
|
||||
packet[i*2+2] = (value >> 8) & 0xff;
|
||||
packet[i*2+3] = (value >> 0) & 0xff;
|
||||
packet[i*2+2] = value >> 8;
|
||||
packet[i*2+3] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_set_sop_data_crc()
|
||||
{
|
||||
//The crc for channel '1' is NOT(mfgid[0] << 8 + mfgid[1])
|
||||
//The crc for channel '2' is (mfgid[0] << 8 + mfgid[1])
|
||||
uint16_t crc = (cyrfmfg_id[0] << 8) + cyrfmfg_id[1];
|
||||
if(phase==DSM_CH1_CHECK_A||phase==DSM_CH1_CHECK_B)
|
||||
CYRF_ConfigCRCSeed(crc); //CH2
|
||||
else
|
||||
CYRF_ConfigCRCSeed(~crc); //CH1
|
||||
|
||||
uint8_t pn_row = DSM_get_pn_row(hopping_frequency[hopping_frequency_no]);
|
||||
uint8_t code[16];
|
||||
DSM_read_code(code,pn_row,sop_col,8); // pn_row between 0 and 4, sop_col between 1 and 7
|
||||
CYRF_ConfigSOPCode(code);
|
||||
DSM_read_code(code,pn_row,7 - sop_col,8); // 7-sop_col between 0 and 6
|
||||
DSM_read_code(code+8,pn_row,7 - sop_col + 1,8); // 7-sop_col+1 between 1 and 7
|
||||
CYRF_ConfigDataCode(code, 16);
|
||||
|
||||
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
|
||||
hopping_frequency_no++;
|
||||
if(sub_protocol == DSMX_11 || sub_protocol == DSMX_22)
|
||||
hopping_frequency_no %=23;
|
||||
else
|
||||
hopping_frequency_no %=2;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_calc_dsmx_channel()
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint32_t id = ~(((uint32_t)cyrfmfg_id[0] << 24) | ((uint32_t)cyrfmfg_id[1] << 16) | ((uint32_t)cyrfmfg_id[2] << 8) | (cyrfmfg_id[3] << 0));
|
||||
uint32_t id_tmp = id;
|
||||
while(idx < 23)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t count_3_27 = 0, count_28_51 = 0, count_52_76 = 0;
|
||||
id_tmp = id_tmp * 0x0019660D + 0x3C6EF35F; // Randomization
|
||||
uint8_t next_ch = ((id_tmp >> 8) % 0x49) + 3; // Use least-significant byte and must be larger than 3
|
||||
if ( (next_ch ^ cyrfmfg_id[3]) & 0x01 )
|
||||
continue;
|
||||
for (i = 0; i < idx; i++)
|
||||
{
|
||||
if(hopping_frequency[i] == next_ch)
|
||||
break;
|
||||
if(hopping_frequency[i] <= 27)
|
||||
count_3_27++;
|
||||
else
|
||||
if (hopping_frequency[i] <= 51)
|
||||
count_28_51++;
|
||||
else
|
||||
count_52_76++;
|
||||
#ifdef DSM_FWD_PGM
|
||||
if(upper==0 && DSM_SerialRX && (DSM_SerialRX_val[0]&0xF8)==0x70 )
|
||||
{ // Send forward programming data if available
|
||||
for(uint8_t i=0; i<(DSM_SerialRX_val[0]&0x07);i++)
|
||||
{
|
||||
packet[i*2+4]=0x70+i;
|
||||
packet[i*2+5]=DSM_SerialRX_val[i+1];
|
||||
}
|
||||
DSM_SerialRX=false;
|
||||
#ifdef DSM_DEBUG_FWD_PGM
|
||||
debug("FWD=");
|
||||
for(uint8_t i=4; i<16;i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
}
|
||||
if (i != idx)
|
||||
continue;
|
||||
if ((next_ch < 28 && count_3_27 < 8)
|
||||
||(next_ch >= 28 && next_ch < 52 && count_28_51 < 7)
|
||||
||(next_ch >= 52 && count_52_76 < 8))
|
||||
hopping_frequency[idx++] = next_ch;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) DSM_Check_RX_packet()
|
||||
{
|
||||
uint8_t result=1; // assume good packet
|
||||
uint8_t result=1; // assume good packet
|
||||
|
||||
uint16_t sum = 384 - 0x10;
|
||||
for(uint8_t i = 1; i < 9; i++)
|
||||
@@ -369,15 +240,19 @@ static uint8_t __attribute__((unused)) DSM_Check_RX_packet()
|
||||
sum += packet_in[i];
|
||||
if(i<5)
|
||||
if(packet_in[i] != (0xff ^ cyrfmfg_id[i-1]))
|
||||
result=0; // bad packet
|
||||
result=0; // bad packet
|
||||
}
|
||||
if( packet_in[9] != (sum>>8) && packet_in[10] != (uint8_t)sum )
|
||||
result=0;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t ReadDsm()
|
||||
uint16_t DSM_callback()
|
||||
{
|
||||
#if defined MULTI_EU
|
||||
if(sub_protocol == DSM2_1F || sub_protocol == DSM2_2F)
|
||||
return 11000;
|
||||
#endif
|
||||
#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
|
||||
#ifdef STM32_BOARD
|
||||
#define DSM_WRITE_DELAY 1600 // Time after write to verify write complete
|
||||
@@ -390,46 +265,62 @@ uint16_t ReadDsm()
|
||||
uint8_t len;
|
||||
#endif
|
||||
uint8_t start;
|
||||
|
||||
#ifdef DSM_GR300
|
||||
uint16_t timing=5000+(convert_channel_8b(CH13)*100);
|
||||
debugln("T=%u",timing);
|
||||
#endif
|
||||
|
||||
switch(phase)
|
||||
{
|
||||
case DSM_BIND_WRITE:
|
||||
if(bind_counter--==0)
|
||||
#if defined DSM_TELEMETRY
|
||||
phase=DSM_BIND_CHECK; //Check RX answer
|
||||
phase=DSM_BIND_CHECK; //Check RX answer
|
||||
#else
|
||||
phase=DSM_CHANSEL; //Switch to normal mode
|
||||
phase=DSM_CHANSEL; //Switch to normal mode
|
||||
#endif
|
||||
CYRF_WriteDataPacket(packet);
|
||||
return 10000;
|
||||
#if defined DSM_TELEMETRY
|
||||
case DSM_BIND_CHECK:
|
||||
//64 SDR Mode is configured so only the 8 first values are needed but we need to write 16 values...
|
||||
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84\xC9\x2C\x06\x93\x86\xB9\x9E\xD7", 16);
|
||||
CYRF_SetTxRxMode(RX_EN); //Receive mode
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //Prepare to receive
|
||||
bind_counter=2*DSM_BIND_COUNT; //Timeout of 4.2s if no packet received
|
||||
phase++; // change from BIND_CHECK to BIND_READ
|
||||
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84", 16);
|
||||
CYRF_SetTxRxMode(RX_EN); //Receive mode
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //Prepare to receive
|
||||
bind_counter=2*DSM_BIND_COUNT; //Timeout of 4.2s if no packet received
|
||||
phase++; // change from BIND_CHECK to BIND_READ
|
||||
return 2000;
|
||||
case DSM_BIND_READ:
|
||||
//Read data from RX
|
||||
rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
|
||||
if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
|
||||
rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx_phase & 0x07) == 0x02)
|
||||
{ // data received with no errors
|
||||
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
|
||||
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
||||
if(len>TELEMETRY_BUFFER_SIZE-2)
|
||||
len=TELEMETRY_BUFFER_SIZE-2;
|
||||
CYRF_ReadDataPacketLen(packet_in+1, len);
|
||||
if(len==10 && DSM_Check_RX_packet())
|
||||
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80);// Need to set RXOW before data read
|
||||
if(CYRF_ReadRegister(CYRF_09_RX_COUNT)==10) // Len
|
||||
{
|
||||
packet_in[0]=0x80;
|
||||
telemetry_link=1; // send received data on serial
|
||||
phase++;
|
||||
return 2000;
|
||||
CYRF_ReadDataPacketLen(packet_in+1, 10);
|
||||
if(DSM_Check_RX_packet())
|
||||
{
|
||||
debug("Bind");
|
||||
for(uint8_t i=0;i<10;i++)
|
||||
debug(" %02X",packet_in[i+1]);
|
||||
debugln("");
|
||||
packet_in[0]=0x80;
|
||||
packet_in[6]&=0x0F; // It looks like there is a flag 0x40 being added by some receivers
|
||||
if(packet_in[6]>12) packet_in[6]=12;
|
||||
else if(packet_in[6]<3) packet_in[6]=6;
|
||||
telemetry_link=1; // Send received data on serial
|
||||
phase++;
|
||||
return 2000;
|
||||
}
|
||||
}
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||
CYRF_SetTxRxMode(RX_EN); // Force end state read
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive
|
||||
}
|
||||
else
|
||||
if((rx_phase & 0x02) != 0x02)
|
||||
@@ -441,7 +332,7 @@ uint16_t ReadDsm()
|
||||
}
|
||||
if( --bind_counter == 0 )
|
||||
{ // Exit if no answer has been received for some time
|
||||
phase++; // DSM_CHANSEL
|
||||
phase++; // DSM_CHANSEL
|
||||
return 7000 ;
|
||||
}
|
||||
return 7000;
|
||||
@@ -451,20 +342,32 @@ uint16_t ReadDsm()
|
||||
DSM_cyrf_configdata();
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
hopping_frequency_no = 0;
|
||||
phase = DSM_CH1_WRITE_A; // in fact phase++
|
||||
DSM_set_sop_data_crc();
|
||||
phase = DSM_CH1_WRITE_A; // in fact phase++
|
||||
if(sub_protocol == DSMR)
|
||||
DSM_set_sop_data_crc(false, true);
|
||||
else
|
||||
DSM_set_sop_data_crc(true, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F); //prep CH1
|
||||
return 10000;
|
||||
case DSM_CH1_WRITE_A:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(11000); // Always request 11ms spacing even if we don't use half of it in 22ms mode
|
||||
telemetry_set_input_sync(11000); // Always request 11ms spacing even if we don't use half of it in 22ms mode
|
||||
#endif
|
||||
if(sub_protocol == DSMR)
|
||||
CYRF_SetPower(0x08); //Keep transmit power in sync
|
||||
else
|
||||
CYRF_SetPower(0x28); //Keep transmit power in sync
|
||||
case DSM_CH1_WRITE_B:
|
||||
DSM_build_data_packet(phase == DSM_CH1_WRITE_B); // build lower or upper channels
|
||||
case DSM_CH2_WRITE_A:
|
||||
case DSM_CH2_WRITE_B:
|
||||
DSM_build_data_packet(phase == DSM_CH1_WRITE_B||phase == DSM_CH2_WRITE_B); // build lower or upper channels
|
||||
CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags
|
||||
CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags
|
||||
CYRF_WriteDataPacket(packet);
|
||||
phase++; // change from WRITE to CHECK mode
|
||||
#if 0
|
||||
for(uint8_t i=0;i<16;i++)
|
||||
debug(" %02X", packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
phase++; // change from WRITE to CHECK mode
|
||||
return DSM_WRITE_DELAY;
|
||||
case DSM_CH1_CHECK_A:
|
||||
case DSM_CH1_CHECK_B:
|
||||
@@ -475,7 +378,7 @@ uint16_t ReadDsm()
|
||||
if((CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80) == 0x00)
|
||||
break;
|
||||
|
||||
if(phase==DSM_CH1_CHECK_A || phase==DSM_CH1_CHECK_B)
|
||||
if((phase==DSM_CH1_CHECK_A || phase==DSM_CH1_CHECK_B) && sub_protocol!=DSMR)
|
||||
{
|
||||
#if defined DSM_TELEMETRY
|
||||
// reset cyrf6936 if freezed after switching from TX to RX
|
||||
@@ -487,16 +390,23 @@ uint16_t ReadDsm()
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
}
|
||||
#endif
|
||||
DSM_set_sop_data_crc();
|
||||
phase++; // change from CH1_CHECK to CH2_WRITE
|
||||
DSM_set_sop_data_crc(true, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F); // prep CH2
|
||||
phase++; // change from CH1_CHECK to CH2_WRITE
|
||||
return DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY;
|
||||
}
|
||||
if (phase == DSM_CH2_CHECK_A)
|
||||
CYRF_SetPower(0x28); //Keep transmit power in sync
|
||||
#if defined DSM_TELEMETRY
|
||||
phase++; // change from CH2_CHECK to CH2_READ
|
||||
CYRF_SetTxRxMode(RX_EN); //Receive mode
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
|
||||
if(sub_protocol==DSMR)
|
||||
{
|
||||
phase = DSM_CH2_READ_B;
|
||||
return 11000 - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
||||
}
|
||||
#ifdef DSM_GR300
|
||||
if(num_ch==3)
|
||||
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
||||
#endif
|
||||
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
||||
case DSM_CH2_READ_A:
|
||||
case DSM_CH2_READ_B:
|
||||
@@ -511,16 +421,29 @@ uint16_t ReadDsm()
|
||||
if(len>TELEMETRY_BUFFER_SIZE-2)
|
||||
len=TELEMETRY_BUFFER_SIZE-2;
|
||||
CYRF_ReadDataPacketLen(packet_in+1, len);
|
||||
#ifdef DSM_DEBUG_FWD_PGM
|
||||
//debug(" %02X", packet_in[1]);
|
||||
if(packet_in[1]==9)
|
||||
{
|
||||
for(uint8_t i=0;i<len;i++)
|
||||
debug(" %02X", packet_in[i+1]);
|
||||
debugln("");
|
||||
}
|
||||
#endif
|
||||
packet_in[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;// store RSSI of the received telemetry signal
|
||||
telemetry_link=1;
|
||||
}
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||
if (phase == DSM_CH2_READ_A && (sub_protocol==DSM2_22 || sub_protocol==DSMX_22) && num_ch < 8) // 22ms mode
|
||||
if (phase == DSM_CH2_READ_A && (sub_protocol==DSM2_1F || sub_protocol==DSMX_1F) && num_ch < 8) // 22ms mode
|
||||
{
|
||||
CYRF_SetTxRxMode(RX_EN); // Force end state read
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
|
||||
phase = DSM_CH2_READ_B;
|
||||
#ifdef DSM_GR300
|
||||
if(num_ch==3)
|
||||
return timing;
|
||||
#endif
|
||||
return 11000;
|
||||
}
|
||||
if (phase == DSM_CH2_READ_A)
|
||||
@@ -529,46 +452,96 @@ uint16_t ReadDsm()
|
||||
phase = DSM_CH1_WRITE_A; //Transmit lower
|
||||
CYRF_SetTxRxMode(TX_EN); //TX mode
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); //Clear abort RX operation
|
||||
DSM_set_sop_data_crc();
|
||||
DSM_set_sop_data_crc(false, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F||sub_protocol==DSMR);
|
||||
return DSM_READ_DELAY;
|
||||
#else
|
||||
// No telemetry
|
||||
DSM_set_sop_data_crc();
|
||||
DSM_set_sop_data_crc(phase==DSM_CH1_CHECK_A||phase==DSM_CH1_CHECK_B, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F);
|
||||
if (phase == DSM_CH2_CHECK_A)
|
||||
{
|
||||
if(num_ch > 7 || sub_protocol==DSM2_11 || sub_protocol==DSMX_11)
|
||||
if(num_ch > 7 || sub_protocol==DSM2_2F || sub_protocol==DSMX_2F)
|
||||
phase = DSM_CH1_WRITE_B; //11ms mode or upper to transmit change from CH2_CHECK_A to CH1_WRITE_A
|
||||
else
|
||||
{ //Normal mode 22ms
|
||||
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
|
||||
#ifdef DSM_GR300
|
||||
if(num_ch==3)
|
||||
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
||||
#endif
|
||||
return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
||||
}
|
||||
}
|
||||
else
|
||||
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower)
|
||||
#ifdef DSM_GR300
|
||||
if(num_ch==3)
|
||||
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
||||
#endif
|
||||
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t initDsm()
|
||||
|
||||
const uint8_t PROGMEM DSMR_ID_FREQ[][4 + 23] = {
|
||||
{ 0x71, 0x74, 0x1c, 0xe4, 0x11, 0x2f, 0x17, 0x3d, 0x23, 0x3b, 0x0f, 0x21, 0x25, 0x49, 0x1d, 0x13, 0x4d, 0x1f, 0x41, 0x4b, 0x47, 0x05, 0x27, 0x15, 0x19, 0x3f, 0x07 },
|
||||
{ 0xfe, 0xfe, 0xfe, 0xfe, 0x45, 0x31, 0x33, 0x4b, 0x11, 0x29, 0x49, 0x3f, 0x09, 0x13, 0x47, 0x21, 0x1d, 0x43, 0x1f, 0x05, 0x41, 0x19, 0x1b, 0x2d, 0x15, 0x4d, 0x0f },
|
||||
{ 0xfe, 0xff, 0xff, 0xff, 0x2a, 0x06, 0x22, 0x28, 0x16, 0x24, 0x38, 0x0e, 0x32, 0x2e, 0x14, 0x3a, 0x04, 0x44, 0x0c, 0x42, 0x1c, 0x4a, 0x10, 0x36, 0x3c, 0x48, 0x26 },
|
||||
{ 0xff, 0xfe, 0xff, 0xff, 0x28, 0x34, 0x48, 0x46, 0x3a, 0x12, 0x18, 0x32, 0x14, 0x42, 0x16, 0x40, 0x22, 0x44, 0x1c, 0x0a, 0x36, 0x20, 0x10, 0x0c, 0x3c, 0x26, 0x2e },
|
||||
{ 0xff, 0xff, 0xfe, 0xff, 0x3c, 0x16, 0x04, 0x48, 0x1e, 0x4a, 0x10, 0x18, 0x22, 0x28, 0x38, 0x40, 0x20, 0x06, 0x3e, 0x42, 0x30, 0x1a, 0x2c, 0x1c, 0x46, 0x14, 0x34 },
|
||||
{ 0xff, 0xff, 0xff, 0xfe, 0x4d, 0x39, 0x1b, 0x13, 0x45, 0x2f, 0x0d, 0x3d, 0x0b, 0x11, 0x47, 0x2d, 0x19, 0x1d, 0x23, 0x35, 0x33, 0x3b, 0x21, 0x31, 0x17, 0x0f, 0x43 },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0x14, 0x28, 0x2e, 0x32, 0x3e, 0x10, 0x38, 0x0e, 0x12, 0x06, 0x2c, 0x26, 0x30, 0x4c, 0x34, 0x16, 0x04, 0x3a, 0x42, 0x48, 0x36, 0x46, 0x1a },
|
||||
{ 0x00, 0xff, 0xff, 0xff, 0x3e, 0x30, 0x42, 0x24, 0x06, 0x0e, 0x14, 0x1c, 0x08, 0x10, 0x20, 0x22, 0x04, 0x32, 0x0c, 0x44, 0x3c, 0x46, 0x4a, 0x26, 0x4c, 0x48, 0x1e },
|
||||
{ 0xff, 0x00, 0xff, 0xff, 0x38, 0x0e, 0x22, 0x2a, 0x44, 0x3a, 0x4a, 0x3e, 0x16, 0x20, 0x36, 0x24, 0x46, 0x18, 0x1e, 0x12, 0x1c, 0x30, 0x2c, 0x14, 0x06, 0x0c, 0x40 },
|
||||
{ 0x00, 0x00, 0xff, 0xff, 0x06, 0x4c, 0x26, 0x08, 0x46, 0x3e, 0x30, 0x12, 0x38, 0x1c, 0x04, 0x4a, 0x2c, 0x1a, 0x20, 0x3a, 0x18, 0x36, 0x28, 0x2e, 0x22, 0x40, 0x10 },
|
||||
{ 0xff, 0xff, 0x00, 0xff, 0x12, 0x06, 0x3c, 0x2a, 0x22, 0x38, 0x48, 0x4c, 0x32, 0x44, 0x26, 0x16, 0x0c, 0x28, 0x2c, 0x36, 0x1c, 0x1a, 0x42, 0x10, 0x08, 0x4a, 0x34 },
|
||||
{ 0x00, 0xff, 0x00, 0xff, 0x04, 0x4c, 0x4a, 0x28, 0x2a, 0x24, 0x14, 0x1e, 0x40, 0x48, 0x44, 0x2c, 0x2e, 0x1a, 0x12, 0x46, 0x3a, 0x0e, 0x18, 0x1c, 0x20, 0x10, 0x42 },
|
||||
{ 0xff, 0x00, 0x00, 0xff, 0x06, 0x10, 0x14, 0x16, 0x48, 0x18, 0x44, 0x2c, 0x0a, 0x26, 0x24, 0x42, 0x36, 0x30, 0x38, 0x3e, 0x0c, 0x3c, 0x34, 0x46, 0x2a, 0x32, 0x0e },
|
||||
{ 0x00, 0x00, 0x00, 0xff, 0x2c, 0x0a, 0x46, 0x28, 0x38, 0x24, 0x14, 0x06, 0x04, 0x10, 0x18, 0x30, 0x12, 0x20, 0x3a, 0x1a, 0x32, 0x3c, 0x3e, 0x4a, 0x1e, 0x44, 0x36 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x45, 0x23, 0x07, 0x37, 0x4b, 0x13, 0x3d, 0x31, 0x19, 0x2b, 0x2f, 0x2d, 0x1f, 0x4d, 0x3f, 0x1b, 0x43, 0x27, 0x3b, 0x11, 0x05, 0x0d, 0x17 },
|
||||
{ 0xff, 0xff, 0xff, 0x00, 0x0b, 0x4b, 0x1d, 0x39, 0x09, 0x0f, 0x49, 0x25, 0x07, 0x35, 0x3b, 0x05, 0x33, 0x17, 0x2d, 0x11, 0x2b, 0x29, 0x1f, 0x45, 0x1b, 0x41, 0x47 },
|
||||
{ 0x00, 0xff, 0xff, 0x00, 0x41, 0x35, 0x11, 0x25, 0x29, 0x27, 0x33, 0x47, 0x4d, 0x31, 0x05, 0x37, 0x15, 0x1f, 0x23, 0x07, 0x1b, 0x0f, 0x3b, 0x49, 0x19, 0x3f, 0x0b },
|
||||
{ 0xff, 0x00, 0xff, 0x00, 0x25, 0x47, 0x05, 0x0b, 0x45, 0x1f, 0x2b, 0x27, 0x2d, 0x09, 0x07, 0x43, 0x49, 0x29, 0x4d, 0x39, 0x33, 0x41, 0x17, 0x0f, 0x15, 0x19, 0x3b },
|
||||
{ 0x00, 0x00, 0xff, 0x00, 0x3b, 0x05, 0x21, 0x0d, 0x1b, 0x43, 0x17, 0x2d, 0x1d, 0x25, 0x4b, 0x35, 0x4d, 0x3f, 0x07, 0x09, 0x37, 0x41, 0x15, 0x1f, 0x0f, 0x27, 0x29 },
|
||||
{ 0xff, 0xff, 0x00, 0x00, 0x2b, 0x35, 0x1b, 0x1d, 0x0f, 0x47, 0x09, 0x0d, 0x45, 0x41, 0x21, 0x11, 0x2f, 0x43, 0x27, 0x33, 0x4b, 0x37, 0x13, 0x19, 0x4d, 0x23, 0x17 },
|
||||
{ 0x00, 0xff, 0x00, 0x00, 0x1b, 0x1d, 0x33, 0x13, 0x2b, 0x27, 0x09, 0x41, 0x25, 0x17, 0x19, 0x2d, 0x4b, 0x37, 0x45, 0x11, 0x21, 0x0d, 0x3d, 0x4d, 0x07, 0x39, 0x43 },
|
||||
{ 0xff, 0x00, 0x00, 0x00, 0x37, 0x27, 0x43, 0x4b, 0x39, 0x13, 0x07, 0x0d, 0x25, 0x17, 0x29, 0x1b, 0x1d, 0x45, 0x19, 0x2d, 0x0b, 0x3d, 0x15, 0x47, 0x1f, 0x21, 0x4d } };
|
||||
|
||||
void DSM_init()
|
||||
{
|
||||
CYRF_GetMfgData(cyrfmfg_id);
|
||||
//Model match
|
||||
cyrfmfg_id[3]^=RX_num;
|
||||
if(sub_protocol == DSMR)
|
||||
{
|
||||
uint8_t row = rx_tx_addr[3]%22;
|
||||
for(uint8_t i=0; i< 4; i++)
|
||||
cyrfmfg_id[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i]);
|
||||
for(uint8_t i=0; i< 23; i++)
|
||||
hopping_frequency[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i+4]);
|
||||
}
|
||||
else
|
||||
{
|
||||
CYRF_GetMfgData(cyrfmfg_id);
|
||||
//Model match
|
||||
cyrfmfg_id[3]^=RX_num;
|
||||
}
|
||||
|
||||
//Calc sop_col
|
||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
|
||||
|
||||
//Fix for OrangeRX using wrong DSM_pncodes by preventing access to "Col 8"
|
||||
if(sop_col==0)
|
||||
if(sop_col==0 && sub_protocol != DSMR)
|
||||
{
|
||||
cyrfmfg_id[rx_tx_addr[0]%3]^=0x01; //Change a bit so sop_col will be different from 0
|
||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
|
||||
}
|
||||
|
||||
//Calc CRC seed
|
||||
seed = (cyrfmfg_id[0] << 8) + cyrfmfg_id[1];
|
||||
|
||||
//Hopping frequencies
|
||||
if (sub_protocol == DSMX_11 || sub_protocol == DSMX_22)
|
||||
if (sub_protocol == DSMX_2F || sub_protocol == DSMX_1F)
|
||||
DSM_calc_dsmx_channel();
|
||||
else
|
||||
else if(sub_protocol != DSMR)
|
||||
{
|
||||
uint8_t tmpch[10];
|
||||
CYRF_FindBestChannels(tmpch, 10, 5, 3, 75);
|
||||
@@ -583,6 +556,7 @@ uint16_t initDsm()
|
||||
}
|
||||
hopping_frequency[1] = tmpch[idx];
|
||||
}
|
||||
|
||||
//
|
||||
DSM_cyrf_config();
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
@@ -597,7 +571,6 @@ uint16_t initDsm()
|
||||
}
|
||||
else
|
||||
phase = DSM_CHANSEL;//
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -55,14 +55,14 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix()
|
||||
{
|
||||
uint8_t bind_state;
|
||||
#ifdef ENABLE_PPM
|
||||
if(mode_select && option==0 && IS_BIND_DONE) //PPM mode and option not already set and bind is finished
|
||||
if(mode_select && (option&0x01)==0 && IS_BIND_DONE) //PPM mode and option not already set and bind is finished
|
||||
{
|
||||
BIND_SET_INPUT;
|
||||
BIND_SET_PULLUP; // set pullup
|
||||
if(IS_BIND_BUTTON_on)
|
||||
{
|
||||
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num),0x01); // Set fixed id mode for the current model
|
||||
option=1;
|
||||
option |= 0x01;
|
||||
}
|
||||
BIND_SET_OUTPUT;
|
||||
}
|
||||
@@ -72,7 +72,7 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix()
|
||||
MProtocol_id = RX_num + MProtocol_id_master;
|
||||
bind_counter=DEVO_BIND_COUNT;
|
||||
}
|
||||
if (option)
|
||||
if (option&0x01)
|
||||
{
|
||||
if (bind_counter > 0)
|
||||
bind_state = 0xc0;
|
||||
@@ -146,7 +146,7 @@ static void __attribute__((unused)) DEVO_build_data_pkt()
|
||||
uint8_t sign = 0x0b;
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
int16_t value=convert_channel_16b_nolimit(CH_EATR[ch_idx * 4 + i],-1600,1600);//range -1600..+1600
|
||||
int16_t value=convert_channel_16b_nolimit(CH_EATR[ch_idx * 4 + i],-1600,1600,false);//range -1600..+1600
|
||||
if(value < 0)
|
||||
{
|
||||
value = -value;
|
||||
@@ -162,6 +162,165 @@ static void __attribute__((unused)) DEVO_build_data_pkt()
|
||||
DEVO_add_pkt_suffix();
|
||||
}
|
||||
|
||||
#if defined DEVO_HUB_TELEMETRY
|
||||
static uint32_t __attribute__((unused)) DEVO_text_to_int(uint8_t *ptr, uint8_t len)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
for(uint8_t i = 0; i < len; i++)
|
||||
value = value * 10 + (ptr[i] - '0');
|
||||
return value;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DEVO_float_to_ints(uint8_t *ptr, uint16_t *value, uint16_t *decimal)
|
||||
{
|
||||
bool seen_decimal = false;
|
||||
*value = 0;
|
||||
*decimal = 0;
|
||||
for(uint8_t i = 0; i < 7; i++)
|
||||
{
|
||||
if(ptr[i] == '.')
|
||||
{
|
||||
seen_decimal = true;
|
||||
continue;
|
||||
}
|
||||
if(ptr[i] < '0' || ptr[i] > '9')
|
||||
{
|
||||
if(*value != 0 || seen_decimal)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(seen_decimal)
|
||||
*decimal = *decimal * 10 + (ptr[i] - '0');
|
||||
else
|
||||
*value = *value * 10 + (ptr[i] - '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DEVO_parse_telemetry_packet()
|
||||
{ // Telemetry packets every 2.4ms
|
||||
DEVO_scramble_pkt(); //This will unscramble the packet
|
||||
|
||||
debugln("RX");
|
||||
if ((((uint32_t)packet[15] << 16) | ((uint32_t)packet[14] << 8) | packet[13]) != (MProtocol_id & 0x00ffffff))
|
||||
return; // ID does not match
|
||||
|
||||
if((telemetry_link & 3) != 0)
|
||||
{
|
||||
debugln("S%d",telemetry_link);
|
||||
return; // Previous telemetry not sent yet...
|
||||
}
|
||||
|
||||
//Debug telem RX
|
||||
//for(uint8_t i=0;i<12;i++)
|
||||
// debug("%02X ",packet[i]);
|
||||
//debugln("");
|
||||
|
||||
#if defined HUB_TELEMETRY
|
||||
//Telemetry https://github.com/DeviationTX/deviation/blob/5efb6a28bea697af9a61b5a0ed2528cc8d203f90/src/protocol/devo_cyrf6936.c#L232
|
||||
uint16_t val, dec;
|
||||
uint32_t val32;
|
||||
switch(packet[0])
|
||||
{
|
||||
case 0x30: // Volt and RPM packet
|
||||
//RSSI and voltage
|
||||
TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI) & 0x1F;
|
||||
TX_RSSI = (TX_RSSI << 1) + TX_RSSI;
|
||||
RX_RSSI = TX_RSSI;
|
||||
telemetry_link |= 1;
|
||||
v_lipo1 = packet[1] << 1;
|
||||
v_lipo2 = packet[3] << 1;
|
||||
//packet[5] = 127; // 12.7V
|
||||
if(packet[5] != 0)
|
||||
{
|
||||
val = (packet[5]*11)/21; // OpenTX strange transformation??
|
||||
dec = val;
|
||||
val /= 10;
|
||||
dec -= val*10;
|
||||
frsky_send_user_frame(0x3A, val, 0x00); // volt3
|
||||
frsky_send_user_frame(0x3B, dec, 0x00); // volt3
|
||||
}
|
||||
val = packet[7] * 120; // change to RPM
|
||||
frsky_send_user_frame(0x03, val, val>>8); // RPM
|
||||
break;
|
||||
case 0x31: // Temperature packet
|
||||
//memcpy(&packet[1],"\x29\x2A\x2B\x00\x00\x00\x00\x00\x00\x00\x00\x00",12); // 21°, 22°, 23°
|
||||
for(uint8_t i=0; i<2;i++)
|
||||
if(packet[i+1]!=0xff)
|
||||
{
|
||||
val = packet[i+1];
|
||||
val -= 20;
|
||||
frsky_send_user_frame(0x02 + i*3, val, val>>8); // temp 1 & 2
|
||||
}
|
||||
break;
|
||||
// GPS Data
|
||||
case 0x32: // Longitude
|
||||
//memcpy(&packet[1],"\x30\x33\x30\x32\x30\x2e\x38\x32\x37\x30\x45\xfb",12); // 030°20.8270E in ddmm.mmmm
|
||||
//memcpy(&packet[1],"\x31\x31\x37\x31\x31\x2e\x35\x39\x34\x37\x57\xfb",12); // RX705 sends 117°11.5947W which should be 11706.95685W in ddmm.mmmm
|
||||
val = DEVO_text_to_int(&packet[1], 3)*100; // dd00
|
||||
val32 = DEVO_text_to_int(&packet[4], 2) * 10000 + DEVO_text_to_int(&packet[7], 4); // mmmmmm
|
||||
if(option&0x02) // if RX705 GPS format
|
||||
val32 = (val32*3)/5; // then * 6/10 correction
|
||||
dec = val32/10000;
|
||||
val = val + dec; // dddmm
|
||||
frsky_send_user_frame(0x12 , val, val>>8);
|
||||
val = val32 - dec*10000; // .mmmm
|
||||
frsky_send_user_frame(0x12+8, val, val>>8);
|
||||
frsky_send_user_frame(0x1A+8, packet[11], 0x00); // 'E'/'W'
|
||||
break;
|
||||
case 0x33: // Latitude
|
||||
//memcpy(&packet[1],"\x35\x39\x35\x34\x2e\x37\x37\x37\x36\x4e\x07\x00",12); // 59°54.776N in ddmm.mmmm
|
||||
//memcpy(&packet[1],"\x31\x37\x31\x31\x2e\x35\x39\x34\x37\x4e\xfb\x00",12); // RX705 sends 17°11.5947N which should be 1706.95685N in ddmm.mmmm
|
||||
val = DEVO_text_to_int(&packet[1], 2)*100; // dd00
|
||||
val32 = DEVO_text_to_int(&packet[3], 2) * 10000 + DEVO_text_to_int(&packet[6], 4); // mmmmmm
|
||||
if(option&0x02) // if RX705 GPS format
|
||||
val32 = (val32*3)/5; // then * 6/10 correction
|
||||
dec = val32/10000;
|
||||
val = val + dec; // dddmm
|
||||
frsky_send_user_frame(0x13 , val, val>>8);
|
||||
val = val32 - dec*10000; // .mmmm
|
||||
frsky_send_user_frame(0x13+8, val, val>>8);
|
||||
frsky_send_user_frame(0x1B+8, packet[10], 0x00); // 'N'/'S'
|
||||
break;
|
||||
case 0x34: // Altitude
|
||||
//memcpy(&packet[1],"\x31\x32\x2e\x38\x00\x00\x00\x4d\x4d\x4e\x45\xfb",12); // 12.8 MMNE
|
||||
DEVO_float_to_ints(&packet[1], &val, &dec);
|
||||
frsky_send_user_frame(0x10, val, val>>8);
|
||||
frsky_send_user_frame(0x21, dec, dec>>8);
|
||||
break;
|
||||
case 0x35: // Speed
|
||||
//memcpy(&packet[1],"\x00\x00\x00\x00\x00\x00\x30\x2e\x30\x30\x00\x00",12); // 0.0
|
||||
DEVO_float_to_ints(&packet[1], &val, &dec);
|
||||
frsky_send_user_frame(0x11 , val, val>>8);
|
||||
frsky_send_user_frame(0x11+8, dec, dec>>8);
|
||||
break;
|
||||
case 0x36: // Time
|
||||
//memcpy(&packet[1],"\x31\x38\x32\x35\x35\x32\x31\x35\x31\x30\x31\x32",12); // "182552151012" = 2012-10-15 18:25:52 (UTC)
|
||||
if(packet[1]!=0)
|
||||
{
|
||||
frsky_send_user_frame(0x15, DEVO_text_to_int(&packet[9], 2), DEVO_text_to_int(&packet[7], 2)); // month, day
|
||||
val = 2000 + DEVO_text_to_int(&packet[11], 2); // year
|
||||
frsky_send_user_frame(0x16, val, val>>8);
|
||||
frsky_send_user_frame(0x17, DEVO_text_to_int(&packet[1], 2), DEVO_text_to_int(&packet[3], 2)); // hour, min
|
||||
frsky_send_user_frame(0x18, DEVO_text_to_int(&packet[5], 2), 0x00); // second
|
||||
}
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if(packet[0] == 0x30)
|
||||
{
|
||||
TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI) & 0x1F;
|
||||
TX_RSSI = (TX_RSSI << 1) + TX_RSSI;
|
||||
RX_RSSI = TX_RSSI;
|
||||
telemetry_link |= 1;
|
||||
v_lipo1 = packet[1] << 1;
|
||||
v_lipo2 = packet[3] << 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code()
|
||||
{
|
||||
/* crc == 0 isn't allowed, so use 1 if the math results in 0 */
|
||||
@@ -267,9 +426,85 @@ static void __attribute__((unused)) DEVO_BuildPacket()
|
||||
packet_count = 0;
|
||||
}
|
||||
|
||||
uint16_t devo_callback()
|
||||
uint16_t DEVO_callback()
|
||||
{
|
||||
static uint8_t txState=0;
|
||||
|
||||
#if defined DEVO_HUB_TELEMETRY
|
||||
int delay;
|
||||
|
||||
if (txState == 0)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(2400);
|
||||
#endif
|
||||
DEVO_BuildPacket();
|
||||
CYRF_WriteDataPacket(packet);
|
||||
txState = 1;
|
||||
return 900;
|
||||
}
|
||||
if (txState == 1)
|
||||
{
|
||||
int i = 0;
|
||||
uint8_t reg;
|
||||
while (! ((reg = CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS)) & 0x02))
|
||||
{
|
||||
if (++i >= DEVO_NUM_WAIT_LOOPS)
|
||||
break;
|
||||
}
|
||||
if (((reg & 0x22) == 0x20) || (CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80))
|
||||
{
|
||||
CYRF_Reset();
|
||||
DEVO_cyrf_init();
|
||||
DEVO_cyrf_set_bound_sop_code();
|
||||
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
|
||||
//printf("Rst CYRF\n");
|
||||
delay = 1500;
|
||||
txState = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (phase == DEVO_BOUND)
|
||||
{
|
||||
/* exit binding state */
|
||||
phase = DEVO_BOUND_3;
|
||||
DEVO_cyrf_set_bound_sop_code();
|
||||
}
|
||||
if((packet_count != 0) && (bind_counter == 0))
|
||||
{
|
||||
CYRF_SetTxRxMode(RX_EN); //Receive mode
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
|
||||
txState = 2;
|
||||
return 1300;
|
||||
}
|
||||
}
|
||||
if(packet_count == 0)
|
||||
{
|
||||
CYRF_SetPower(0x08); //Keep tx power updated
|
||||
hopping_frequency_ptr = hopping_frequency_ptr == &hopping_frequency[2] ? hopping_frequency : hopping_frequency_ptr + 1;
|
||||
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
|
||||
}
|
||||
delay = 1500;
|
||||
}
|
||||
if(txState == 2)
|
||||
{
|
||||
uint8_t rx_state = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx_state & 0x03) == 0x02)
|
||||
{ // RXC=1, RXE=0 then 2nd check is required (debouncing)
|
||||
rx_state |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
}
|
||||
if((rx_state & 0x07) == 0x02)
|
||||
{ // good data (complete with no errors)
|
||||
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
|
||||
CYRF_ReadDataPacketLen(packet, CYRF_ReadRegister(CYRF_09_RX_COUNT));
|
||||
DEVO_parse_telemetry_packet();
|
||||
}
|
||||
CYRF_SetTxRxMode(TX_EN); //Write mode
|
||||
delay = 200;
|
||||
}
|
||||
txState = 0;
|
||||
return delay;
|
||||
#else
|
||||
if (txState == 0)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
@@ -298,10 +533,26 @@ uint16_t devo_callback()
|
||||
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
|
||||
}
|
||||
return 1200;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t DevoInit()
|
||||
void DEVO_init()
|
||||
{
|
||||
#ifdef ENABLE_PPM
|
||||
if(mode_select) //PPM mode
|
||||
{
|
||||
if(IS_BIND_BUTTON_FLAG_on)
|
||||
{
|
||||
option &= 0xFE;
|
||||
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num),option); // reset to autobind mode for the current model
|
||||
}
|
||||
else
|
||||
{
|
||||
option=eeprom_read_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num)); // load previous mode: autobind or fixed id
|
||||
if(option > 3) option = 0; // if invalid then it should be autobind
|
||||
}
|
||||
}
|
||||
#endif //ENABLE_PPM
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case 1:
|
||||
@@ -332,8 +583,13 @@ uint16_t DevoInit()
|
||||
|
||||
packet_count = 0;
|
||||
|
||||
prev_option=option;
|
||||
if(option==0)
|
||||
if(option&0x01)
|
||||
{
|
||||
phase = DEVO_BOUND_1;
|
||||
bind_counter = 0;
|
||||
DEVO_cyrf_set_bound_sop_code();
|
||||
}
|
||||
else
|
||||
{
|
||||
MProtocol_id = ((uint32_t)(hopping_frequency[0] ^ cyrfmfg_id[0] ^ cyrfmfg_id[3]) << 16)
|
||||
| ((uint32_t)(hopping_frequency[1] ^ cyrfmfg_id[1] ^ cyrfmfg_id[4]) << 8)
|
||||
@@ -343,13 +599,6 @@ uint16_t DevoInit()
|
||||
phase = DEVO_BIND;
|
||||
BIND_IN_PROGRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
phase = DEVO_BOUND_1;
|
||||
bind_counter = 0;
|
||||
DEVO_cyrf_set_bound_sop_code();
|
||||
}
|
||||
return 2400;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
151
Multiprotocol/E010R5_cyrf6936.ino
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
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(E010R5_CYRF6936_INO)
|
||||
|
||||
#include "iface_rf2500.h"
|
||||
|
||||
#define E010R5_FORCE_ID
|
||||
|
||||
#define E010R5_PAYLOAD_SIZE 14
|
||||
|
||||
|
||||
static void __attribute__((unused)) E010R5_build_data_packet()
|
||||
{
|
||||
packet[ 0] = 0x0D; // Packet length
|
||||
packet[ 1] = convert_channel_8b(THROTTLE);
|
||||
packet[ 2] = convert_channel_s8b(RUDDER);
|
||||
packet[ 3] = convert_channel_s8b(ELEVATOR);
|
||||
packet[ 4] = convert_channel_s8b(AILERON);
|
||||
packet[ 5] = 0x20; // Trim Rudder
|
||||
packet[ 6] = 0x20; // Trim Elevator
|
||||
packet[ 7] = 0x20; // Trim Aileron
|
||||
packet[ 8] = 0x01 // Flags: high=0x01, low=0x00
|
||||
| GET_FLAG(CH5_SW, 0x04) // flip=0x04
|
||||
| GET_FLAG(CH6_SW, 0x08) // led=0x08
|
||||
| GET_FLAG(CH8_SW, 0x10) // headless=0x10
|
||||
| GET_FLAG(CH9_SW, 0x20); // one key return=0x20
|
||||
packet[ 9] = IS_BIND_IN_PROGRESS ? 0x80 : 0x00 // Flags: bind=0x80
|
||||
| GET_FLAG(CH7_SW, 0x20) // calib=0x20
|
||||
| GET_FLAG(CH10_SW, 0x01); // strange effect=0x01=long press on right button
|
||||
packet[10] = rx_tx_addr[0];
|
||||
packet[11] = rx_tx_addr[1];
|
||||
packet[12] = rx_tx_addr[2];
|
||||
packet[13] = 0x9D; // Check
|
||||
for(uint8_t i=0;i<13;i++)
|
||||
packet[13] += packet[i];
|
||||
|
||||
RF2500_BuildPayload(packet);
|
||||
}
|
||||
|
||||
uint16_t E010R5_callback()
|
||||
{
|
||||
//Bind
|
||||
if(bind_counter)
|
||||
if(--bind_counter==0)
|
||||
BIND_DONE;
|
||||
|
||||
//Send packet
|
||||
RF2500_SendPayload();
|
||||
|
||||
//Timing and hopping
|
||||
packet_count++;
|
||||
switch(packet_count)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 5:
|
||||
return 1183;
|
||||
default:
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no &= 3;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
rf_ch_num = 0x30 + (hopping_frequency_no<<3);
|
||||
else
|
||||
rf_ch_num = hopping_frequency[hopping_frequency_no];
|
||||
RF2500_RFChannel(rf_ch_num);
|
||||
RF2500_SetPower();
|
||||
packet_count = 0;
|
||||
case 3:
|
||||
E010R5_build_data_packet();
|
||||
return 3400;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void E010R5_init()
|
||||
{
|
||||
BIND_IN_PROGRESS; // Autobind protocol
|
||||
bind_counter = 2600;
|
||||
|
||||
//RF2500 emu init
|
||||
RF2500_Init(E010R5_PAYLOAD_SIZE, false); // 14 bytes, not scrambled
|
||||
RF2500_SetTXAddr((uint8_t*)"\x0E\x54\x96\xEE"); // Same address for bind and normal packets
|
||||
|
||||
rx_tx_addr[0]=0x00;
|
||||
hopping_frequency[0]=0x35; //53
|
||||
#ifdef E010R5_FORCE_ID
|
||||
switch(rx_tx_addr[3]%5)
|
||||
{
|
||||
case 0:
|
||||
//TX1
|
||||
//hopping_frequency[0]=0x35; //53
|
||||
hopping_frequency[1]=0x30; //48
|
||||
rx_tx_addr[1]=0x45;
|
||||
rx_tx_addr[2]=0x46;
|
||||
break;
|
||||
case 1:
|
||||
//TX2
|
||||
//hopping_frequency[0]=0x35; //53
|
||||
hopping_frequency[1]=0x3C; //60
|
||||
rx_tx_addr[1]=0x1B;
|
||||
rx_tx_addr[2]=0x9E;
|
||||
break;
|
||||
case 2:
|
||||
//TX4
|
||||
hopping_frequency[0]=0x30; //48
|
||||
hopping_frequency[1]=0x38; //56
|
||||
rx_tx_addr[1]=0x2E;
|
||||
rx_tx_addr[2]=0xAE;
|
||||
break;
|
||||
case 3:
|
||||
//TX5
|
||||
//hopping_frequency[0]=0x35; //53
|
||||
hopping_frequency[1]=0x41; //65
|
||||
rx_tx_addr[0]=0x0D;
|
||||
rx_tx_addr[1]=0xB9;
|
||||
rx_tx_addr[2]=0xFC;
|
||||
break;
|
||||
default:
|
||||
//TX3
|
||||
hopping_frequency[0]=0x30; //48
|
||||
hopping_frequency[1]=0x38; //56
|
||||
rx_tx_addr[1]=0x17;
|
||||
rx_tx_addr[2]=0x0D;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
// This is the same as the E010 v1...
|
||||
hopping_frequency[2]=hopping_frequency[0]+0x10;
|
||||
hopping_frequency[3]=hopping_frequency[1]+0x10;
|
||||
|
||||
E010R5_build_data_packet();
|
||||
RF2500_RFChannel(hopping_frequency[0]);
|
||||
hopping_frequency_no=0;
|
||||
packet_count=0;
|
||||
}
|
||||
|
||||
#endif
|
||||
157
Multiprotocol/E016HV2_cc2500.ino
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
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(E016HV2_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
//#define FORCE_E016HV2_ORIGINAL_ID
|
||||
|
||||
#define E016HV2_INITIAL_WAIT 500
|
||||
#define E016HV2_PACKET_PERIOD 10000
|
||||
#define E016HV2_RF_BIND_CHANNEL 5
|
||||
#define E016HV2_PAYLOAD_SIZE 11
|
||||
#define E016HV2_BIND_COUNT 300 //3sec
|
||||
|
||||
static void __attribute__((unused)) E016HV2_send_packet()
|
||||
{
|
||||
//payload length (after this byte)
|
||||
packet[0 ] = 0x0A;
|
||||
|
||||
//bind indicator
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[1 ] = 0x02;
|
||||
if(bind_counter)
|
||||
bind_counter--;
|
||||
else
|
||||
{
|
||||
BIND_DONE;
|
||||
CC2500_250K_RFChannel(rf_ch_num); // Set main channel
|
||||
}
|
||||
}
|
||||
else
|
||||
packet[1 ] = 0x20;
|
||||
|
||||
//ID
|
||||
packet[2 ] = rx_tx_addr[2];
|
||||
packet[3 ] = rx_tx_addr[3];
|
||||
|
||||
//channels TREA
|
||||
uint8_t channel;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
channel=0x64; // Throttle must be centered during bind
|
||||
else
|
||||
channel=convert_channel_8b_limit_deadband(THROTTLE,0x00,0x64,0xC8, 20);
|
||||
packet[4 ] = channel;
|
||||
channel=convert_channel_16b_limit(RUDDER,0x00,0xC8);
|
||||
packet[5 ] = channel;
|
||||
channel=convert_channel_16b_limit(ELEVATOR,0x00,0xC8);
|
||||
packet[6 ] = channel;
|
||||
channel=convert_channel_16b_limit(AILERON,0x00,0xC8);
|
||||
packet[7 ] = channel;
|
||||
|
||||
//flags
|
||||
if(CH8_SW && !phase) //toggle calib flag
|
||||
flags ^= 0x40;
|
||||
phase=CH8_SW;
|
||||
|
||||
packet[8 ] = GET_FLAG(CH7_SW, 0x01) // 0x01=Flip
|
||||
| GET_FLAG(CH9_SW, 0x02) // 0x02=Headless
|
||||
| GET_FLAG(CH10_SW, 0x04) // 0x04=One Key Return
|
||||
| flags; // 0x40=Calib
|
||||
|
||||
packet[9 ] = 0x02; // Speed control 0x00:low, 0x01:medium, 0x02:high
|
||||
|
||||
packet[10] = GET_FLAG(CH5_SW, 0x01) // 0x01=TakeOff/Land (momentary switch)
|
||||
| GET_FLAG(CH6_SW, 0x04); // 0x04=Emergeny Stop (momentary switch)
|
||||
|
||||
CC2500_SetPower(); // Set tx_power
|
||||
CC2500_SetFreqOffset(); // Set frequency offset
|
||||
|
||||
//Build real packet and send it
|
||||
static uint8_t pid=0;
|
||||
crc=0;
|
||||
|
||||
// stop TX/RX
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
// flush tx FIFO
|
||||
CC2500_Strobe(CC2500_SFTX);
|
||||
// packet length
|
||||
CC2500_WriteReg(CC2500_3F_TXFIFO, 6 + 4 + 1 + 11 + 2); // preamble + address + packet_control + payload + crc
|
||||
|
||||
// preamble+address
|
||||
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, (uint8_t*)"\xAA\xAA\xAA\xAA\xAA\xAA\xE7\xE7\xE7\xE7", 10);
|
||||
|
||||
// packet control
|
||||
CC2500_WriteReg(CC2500_3F_TXFIFO, 0x50+(pid<<2));
|
||||
pid++;
|
||||
|
||||
// payload
|
||||
//debug("P:")
|
||||
for (uint8_t i = 0; i < E016HV2_PAYLOAD_SIZE; ++i)
|
||||
{
|
||||
uint8_t byte = (bit_reverse(packet[i])<<1) | (packet[i+1]&0x01);
|
||||
//debug(" %02X",byte)
|
||||
CC2500_WriteReg(CC2500_3F_TXFIFO,byte);
|
||||
crc16_update(byte, 8);
|
||||
}
|
||||
|
||||
// crc
|
||||
CC2500_WriteReg(CC2500_3F_TXFIFO,crc >> 8);
|
||||
CC2500_WriteReg(CC2500_3F_TXFIFO,crc);
|
||||
//debugln(" %04X",crc)
|
||||
|
||||
// transmit
|
||||
CC2500_Strobe(CC2500_STX);
|
||||
}
|
||||
|
||||
uint16_t E016HV2_callback()
|
||||
{
|
||||
E016HV2_send_packet();
|
||||
return E016HV2_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
void E016HV2_init()
|
||||
{
|
||||
//Config CC2500
|
||||
CC2500_250K_Init();
|
||||
CC2500_250K_RFChannel(E016HV2_RF_BIND_CHANNEL); // Set bind channel
|
||||
|
||||
#ifdef FORCE_E016HV2_ORIGINAL_ID
|
||||
rx_tx_addr[2]=0x27;
|
||||
rx_tx_addr[3]=0x1B;
|
||||
//rf_ch_num = 44;
|
||||
#endif
|
||||
//General ID
|
||||
//3F1B -> 68,2C1B -> 49,2B1B -> 48,2A1B -> 47,291B -> 46,281B -> 45,271B -> 44,261B -> 43,251B -> 42
|
||||
//241B -> no bind,231B -> no bind,221B -> 71,211B -> 70,201B -> 69,1F1B -> 68,1E1B -> 67,1D1B -> 66,1C1B -> 65,1B1B -> 64,1A1B -> 63,191B -> 62,181B -> 61,171B -> 60,161B -> 59
|
||||
//0C1B -> 49,051B -> 42,041B -> no bind,031B -> no bind,021B -> 71,011B -> 70,001B -> no bind
|
||||
if(rx_tx_addr[2]<3) rx_tx_addr[2]+=3; // rx_tx_addr[2]=0 is invalid
|
||||
if(rx_tx_addr[3]==0) rx_tx_addr[3]+=64; // rx_tx_addr[3]=0 is invalid
|
||||
rf_ch_num = (rx_tx_addr[2] + rx_tx_addr[3]) % 32 + 42;
|
||||
if(rf_ch_num>71) // channels 72 and 73 are invalid
|
||||
{
|
||||
rx_tx_addr[2]-=2;
|
||||
rf_ch_num-=2;
|
||||
}
|
||||
|
||||
phase=CH8_SW;
|
||||
flags=0;
|
||||
bind_counter = E016HV2_BIND_COUNT;
|
||||
BIND_IN_PROGRESS; // Autobind protocol
|
||||
}
|
||||
|
||||
#endif
|
||||
154
Multiprotocol/E016H_nrf24l01.ino
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
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 E016H
|
||||
|
||||
#if defined(E016H_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297.h"
|
||||
|
||||
//Protocols constants
|
||||
#define E016H_BIND_COUNT 500
|
||||
#define E016H_ADDRESS_LENGTH 5
|
||||
|
||||
#define E016H_PACKET_PERIOD 4080
|
||||
#define E016H_PACKET_SIZE 10
|
||||
#define E016H_BIND_CHANNEL 80
|
||||
#define E016H_NUM_CHANNELS 4
|
||||
|
||||
//Channels
|
||||
#define E016H_STOP_SW CH5_SW
|
||||
#define E016H_FLIP_SW CH6_SW
|
||||
#define E016H_HEADLESS_SW CH8_SW
|
||||
#define E016H_RTH_SW CH9_SW
|
||||
|
||||
// E016H flags packet[1]
|
||||
#define E016H_FLAG_CALIBRATE 0x80
|
||||
#define E016H_FLAG_STOP 0x20
|
||||
#define E016H_FLAG_FLIP 0x04
|
||||
// E016H flags packet[3]
|
||||
#define E016H_FLAG_HEADLESS 0x10
|
||||
#define E016H_FLAG_RTH 0x04
|
||||
// E016H flags packet[7]
|
||||
#define E016H_FLAG_TAKEOFF 0x80
|
||||
#define E016H_FLAG_HIGHRATE 0x08
|
||||
|
||||
static void __attribute__((unused)) E016H_send_packet()
|
||||
{
|
||||
uint8_t can_flip = 0, calibrate = 1;
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
memcpy(packet, &rx_tx_addr[1], 4);
|
||||
memcpy(&packet[4], hopping_frequency, 4);
|
||||
packet[8] = 0x23;
|
||||
}
|
||||
else
|
||||
{
|
||||
// trim commands
|
||||
packet[0] = 0;
|
||||
// aileron
|
||||
uint16_t val = convert_channel_16b_limit(AILERON, 0, 0x3ff);
|
||||
can_flip |= (val < 0x100) || (val > 0x300);
|
||||
packet[1] = val >> 8;
|
||||
packet[2] = val & 0xff;
|
||||
if(val < 0x300) calibrate = 0;
|
||||
// elevator
|
||||
val = convert_channel_16b_limit(ELEVATOR, 0x3ff, 0);
|
||||
can_flip |= (val < 0x100) || (val > 0x300);
|
||||
packet[3] = val >> 8;
|
||||
packet[4] = val & 0xff;
|
||||
if(val < 0x300) calibrate = 0;
|
||||
// throttle
|
||||
val = convert_channel_16b_limit(THROTTLE, 0, 0x3ff);
|
||||
packet[5] = val >> 8;
|
||||
packet[6] = val & 0xff;
|
||||
if(val > 0x100) calibrate = 0;
|
||||
// rudder
|
||||
val = convert_channel_16b_limit(RUDDER, 0, 0x3ff);
|
||||
packet[7] = val >> 8;
|
||||
packet[8] = val & 0xff;
|
||||
if(val > 0x100) calibrate = 0;
|
||||
// flags
|
||||
packet[1] |= GET_FLAG(E016H_STOP_SW, E016H_FLAG_STOP)
|
||||
| (can_flip ? GET_FLAG(E016H_FLIP_SW, E016H_FLAG_FLIP) : 0)
|
||||
| (calibrate ? E016H_FLAG_CALIBRATE : 0);
|
||||
packet[3] |= GET_FLAG(E016H_HEADLESS_SW, E016H_FLAG_HEADLESS)
|
||||
| GET_FLAG(E016H_RTH_SW, E016H_FLAG_RTH);
|
||||
packet[7] |= E016H_FLAG_HIGHRATE;
|
||||
// frequency hopping
|
||||
XN297_Hopping(hopping_frequency_no++ & 0x03);
|
||||
}
|
||||
// checksum
|
||||
packet[9] = packet[0];
|
||||
for (uint8_t i=1; i < E016H_PACKET_SIZE-1; i++)
|
||||
packet[9] += packet[i];
|
||||
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, E016H_PACKET_SIZE);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E016H_RF_init()
|
||||
{
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
XN297_SetTXAddr((uint8_t *)"\x5a\x53\x46\x30\x31", 5); // bind address
|
||||
//XN297_HoppingCalib(E016H_NUM_CHANNELS);
|
||||
XN297_RFChannel(E016H_BIND_CHANNEL);
|
||||
}
|
||||
|
||||
uint16_t E016H_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
if(bind_counter)
|
||||
{
|
||||
bind_counter--;
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, E016H_ADDRESS_LENGTH);
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
E016H_send_packet();
|
||||
return E016H_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E016H_initialize_txid()
|
||||
{
|
||||
// tx id
|
||||
rx_tx_addr[0] = 0xa5;
|
||||
rx_tx_addr[1] = 0x00;
|
||||
|
||||
// rf channels
|
||||
uint32_t lfsr=random(0xfefefefe);
|
||||
for(uint8_t i=0; i<E016H_NUM_CHANNELS; i++)
|
||||
{
|
||||
hopping_frequency[i] = (lfsr & 0xFF) % 80;
|
||||
lfsr>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
void E016H_init()
|
||||
{
|
||||
BIND_IN_PROGRESS;
|
||||
E016H_initialize_txid();
|
||||
E016H_RF_init();
|
||||
bind_counter = E016H_BIND_COUNT;
|
||||
hopping_frequency_no = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
239
Multiprotocol/E01X_cyrf6936.ino
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
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 E012 and E015
|
||||
|
||||
#if defined(E01X_CYRF6936_INO)
|
||||
|
||||
#include "iface_hs6200.h"
|
||||
|
||||
//Protocols constants
|
||||
#define E01X_BIND_COUNT 500
|
||||
#define E01X_INITIAL_WAIT 500
|
||||
#define E01X_ADDRESS_LENGTH 5
|
||||
|
||||
#define E012_PACKET_PERIOD 4525
|
||||
#define E012_RF_BIND_CHANNEL 0x3c
|
||||
#define E012_NUM_RF_CHANNELS 4
|
||||
#define E012_PACKET_SIZE 15
|
||||
|
||||
//#define E015_FORCE_ID
|
||||
#define E015_PACKET_PERIOD 9000
|
||||
#define E015_RF_CHANNEL 0x2d // 2445 MHz
|
||||
#define E015_PACKET_SIZE 10
|
||||
#define E015_BIND_PACKET_SIZE 9
|
||||
|
||||
//Channels
|
||||
#define E01X_ARM_SW CH5_SW
|
||||
#define E016H_STOP_SW CH5_SW
|
||||
#define E01X_FLIP_SW CH6_SW
|
||||
#define E01X_LED_SW CH7_SW
|
||||
#define E01X_HEADLESS_SW CH8_SW
|
||||
#define E01X_RTH_SW CH9_SW
|
||||
|
||||
// E012 flags packet[1]
|
||||
#define E012_FLAG_FLIP 0x40
|
||||
#define E012_FLAG_HEADLESS 0x10
|
||||
#define E012_FLAG_RTH 0x04
|
||||
// E012 flags packet[7]
|
||||
#define E012_FLAG_EXPERT 0x02
|
||||
|
||||
// E015 flags packet[6]
|
||||
#define E015_FLAG_DISARM 0x80
|
||||
#define E015_FLAG_ARM 0x40
|
||||
// E015 flags packet[7]
|
||||
#define E015_FLAG_FLIP 0x80
|
||||
#define E015_FLAG_HEADLESS 0x10
|
||||
#define E015_FLAG_RTH 0x08
|
||||
#define E015_FLAG_LED 0x04
|
||||
#define E015_FLAG_EXPERT 0x02
|
||||
#define E015_FLAG_INTERMEDIATE 0x01
|
||||
|
||||
static void __attribute__((unused)) E015_check_arming()
|
||||
{
|
||||
uint8_t arm_channel = E01X_ARM_SW;
|
||||
|
||||
if (arm_channel != arm_channel_previous)
|
||||
{
|
||||
arm_channel_previous = arm_channel;
|
||||
if (arm_channel)
|
||||
{
|
||||
armed = 1;
|
||||
arm_flags ^= E015_FLAG_ARM;
|
||||
}
|
||||
else
|
||||
{
|
||||
armed = 0;
|
||||
arm_flags ^= E015_FLAG_DISARM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E01X_send_packet()
|
||||
{
|
||||
if(sub_protocol==E012)
|
||||
{
|
||||
packet_length=E012_PACKET_SIZE;
|
||||
packet[0] = rx_tx_addr[1];
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
rf_ch_num = E012_RF_BIND_CHANNEL;
|
||||
packet[1] = 0xaa;
|
||||
memcpy(&packet[2], hopping_frequency, E012_NUM_RF_CHANNELS);
|
||||
memcpy(&packet[6], rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
rf_ch_num = hopping_frequency[hopping_frequency_no++];
|
||||
hopping_frequency_no %= E012_NUM_RF_CHANNELS;
|
||||
packet[1] = 0x01
|
||||
| GET_FLAG(E01X_RTH_SW, E012_FLAG_RTH)
|
||||
| GET_FLAG(E01X_HEADLESS_SW, E012_FLAG_HEADLESS)
|
||||
| GET_FLAG(E01X_FLIP_SW, E012_FLAG_FLIP);
|
||||
packet[2] = convert_channel_16b_limit(AILERON, 0xc8, 0x00); // aileron
|
||||
packet[3] = convert_channel_16b_limit(ELEVATOR, 0x00, 0xc8); // elevator
|
||||
packet[4] = convert_channel_16b_limit(RUDDER, 0xc8, 0x00); // rudder
|
||||
packet[5] = convert_channel_16b_limit(THROTTLE, 0x00, 0xc8); // throttle
|
||||
packet[6] = 0xaa;
|
||||
packet[7] = E012_FLAG_EXPERT; // rate (0-2)
|
||||
packet[8] = 0x00;
|
||||
packet[9] = 0x00;
|
||||
packet[10]= 0x00;
|
||||
}
|
||||
packet[11] = 0x00;
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x56;
|
||||
packet[14] = rx_tx_addr[2];
|
||||
}
|
||||
else
|
||||
{ // E015
|
||||
rf_ch_num = E015_RF_CHANNEL;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[0] = 0x18;
|
||||
packet[1] = 0x04;
|
||||
packet[2] = 0x06;
|
||||
// data phase address
|
||||
memcpy(&packet[3], rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
packet[8] = 0x63; // unknown calculation
|
||||
// checksum
|
||||
//packet[8] = packet[3];
|
||||
//for(uint8_t i=4; i<8; i++)
|
||||
// packet[8] += packet[i];
|
||||
packet_length=E015_BIND_PACKET_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
E015_check_arming();
|
||||
packet[0] = convert_channel_16b_limit(THROTTLE, 0, 225); // throttle
|
||||
packet[1] = convert_channel_16b_limit(RUDDER, 225, 0); // rudder
|
||||
packet[2] = convert_channel_16b_limit(AILERON, 0, 225); // aileron
|
||||
packet[3] = convert_channel_16b_limit(ELEVATOR, 225, 0); // elevator
|
||||
packet[4] = 0x20; // elevator trim
|
||||
packet[5] = 0x20; // aileron trim
|
||||
packet[6] = arm_flags;
|
||||
packet[7] = E015_FLAG_EXPERT
|
||||
| GET_FLAG(E01X_FLIP_SW, E015_FLAG_FLIP)
|
||||
| GET_FLAG(E01X_LED_SW, E015_FLAG_LED)
|
||||
| GET_FLAG(E01X_HEADLESS_SW,E015_FLAG_HEADLESS)
|
||||
| GET_FLAG(E01X_RTH_SW, E015_FLAG_RTH);
|
||||
packet[8] = 0;
|
||||
// checksum
|
||||
packet[9] = packet[0];
|
||||
for(uint8_t i=1; i<9; i++)
|
||||
packet[9] += packet[i];
|
||||
packet_length=E015_PACKET_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
HS6200_RFChannel(rf_ch_num);
|
||||
HS6200_SetPower();
|
||||
delayMicroseconds(270); // Wait for RF channel to settle
|
||||
HS6200_SendPayload(packet, packet_length);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E01X_RF_init()
|
||||
{
|
||||
HS6200_Init(true); // CRC enabled
|
||||
|
||||
if(sub_protocol==E012)
|
||||
HS6200_SetTXAddr((uint8_t *)"\x55\x42\x9C\x8F\xC9", E01X_ADDRESS_LENGTH);
|
||||
else //E015
|
||||
HS6200_SetTXAddr((uint8_t *)"\x62\x54\x79\x38\x53", E01X_ADDRESS_LENGTH);
|
||||
}
|
||||
|
||||
uint16_t E01X_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
if(bind_counter)
|
||||
{
|
||||
bind_counter--;
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
HS6200_SetTXAddr(rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
E01X_send_packet();
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E012_initialize_txid()
|
||||
{
|
||||
// rf channels
|
||||
uint32_t lfsr=random(0xfefefefe);
|
||||
for(uint8_t i=0; i<E012_NUM_RF_CHANNELS; i++)
|
||||
{
|
||||
hopping_frequency[i] = 0x10 + ((lfsr & 0xff) % 0x32);
|
||||
lfsr>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
void E01X_init()
|
||||
{
|
||||
BIND_IN_PROGRESS;
|
||||
if(sub_protocol==E012)
|
||||
{
|
||||
E012_initialize_txid();
|
||||
packet_period=E012_PACKET_PERIOD;
|
||||
}
|
||||
else //E015
|
||||
{
|
||||
#ifdef E015_FORCE_ID
|
||||
rx_tx_addr[0] = 0x06;
|
||||
rx_tx_addr[1] = 0xC6;
|
||||
rx_tx_addr[2] = 0xB7;
|
||||
rx_tx_addr[3] = 0x56;
|
||||
rx_tx_addr[4] = 0x8A;
|
||||
#endif
|
||||
|
||||
//force the sum to give 0x63 since the id calculation is unknown
|
||||
uint8_t sum=0x63;
|
||||
for(uint8_t i=0; i < 4; i++)
|
||||
sum -= rx_tx_addr[i];
|
||||
rx_tx_addr[4] = sum;
|
||||
|
||||
packet_period=E015_PACKET_PERIOD;
|
||||
armed = 0;
|
||||
arm_flags = 0;
|
||||
arm_channel_previous = E01X_ARM_SW;
|
||||
}
|
||||
E01X_RF_init();
|
||||
bind_counter = E01X_BIND_COUNT;
|
||||
hopping_frequency_no = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
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 E012 and E015
|
||||
|
||||
#if defined(E01X_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
//Protocols constants
|
||||
#define E01X_BIND_COUNT 500
|
||||
#define E01X_INITIAL_WAIT 500
|
||||
#define E01X_ADDRESS_LENGTH 5
|
||||
|
||||
#define E012_PACKET_PERIOD 4525
|
||||
#define E012_RF_BIND_CHANNEL 0x3c
|
||||
#define E012_NUM_RF_CHANNELS 4
|
||||
#define E012_PACKET_SIZE 15
|
||||
|
||||
#define E015_PACKET_PERIOD 4500 // stock Tx=9000, but let's send more packets ...
|
||||
#define E015_RF_CHANNEL 0x2d // 2445 MHz
|
||||
#define E015_PACKET_SIZE 10
|
||||
#define E015_BIND_PACKET_SIZE 9
|
||||
|
||||
#define E016H_PACKET_PERIOD 4080
|
||||
#define E016H_PACKET_SIZE 10
|
||||
#define E016H_BIND_CHANNEL 80
|
||||
#define E016H_NUM_CHANNELS 4
|
||||
|
||||
//Channels
|
||||
#define E01X_ARM_SW CH5_SW
|
||||
#define E016H_STOP_SW CH5_SW
|
||||
#define E01X_FLIP_SW CH6_SW
|
||||
#define E01X_LED_SW CH7_SW
|
||||
#define E01X_HEADLESS_SW CH8_SW
|
||||
#define E01X_RTH_SW CH9_SW
|
||||
|
||||
// E012 flags packet[1]
|
||||
#define E012_FLAG_FLIP 0x40
|
||||
#define E012_FLAG_HEADLESS 0x10
|
||||
#define E012_FLAG_RTH 0x04
|
||||
// E012 flags packet[7]
|
||||
#define E012_FLAG_EXPERT 0x02
|
||||
|
||||
// E015 flags packet[6]
|
||||
#define E015_FLAG_DISARM 0x80
|
||||
#define E015_FLAG_ARM 0x40
|
||||
// E015 flags packet[7]
|
||||
#define E015_FLAG_FLIP 0x80
|
||||
#define E015_FLAG_HEADLESS 0x10
|
||||
#define E015_FLAG_RTH 0x08
|
||||
#define E015_FLAG_LED 0x04
|
||||
#define E015_FLAG_EXPERT 0x02
|
||||
#define E015_FLAG_INTERMEDIATE 0x01
|
||||
|
||||
// E016H flags packet[1]
|
||||
#define E016H_FLAG_CALIBRATE 0x80
|
||||
#define E016H_FLAG_STOP 0x20
|
||||
#define E016H_FLAG_FLIP 0x04
|
||||
// E016H flags packet[3]
|
||||
#define E016H_FLAG_HEADLESS 0x10
|
||||
#define E016H_FLAG_RTH 0x04
|
||||
// E016H flags packet[7]
|
||||
#define E016H_FLAG_TAKEOFF 0x80
|
||||
#define E016H_FLAG_HIGHRATE 0x08
|
||||
|
||||
static void __attribute__((unused)) E015_check_arming()
|
||||
{
|
||||
uint8_t arm_channel = E01X_ARM_SW;
|
||||
|
||||
if (arm_channel != arm_channel_previous)
|
||||
{
|
||||
arm_channel_previous = arm_channel;
|
||||
if (arm_channel)
|
||||
{
|
||||
armed = 1;
|
||||
arm_flags ^= E015_FLAG_ARM;
|
||||
}
|
||||
else
|
||||
{
|
||||
armed = 0;
|
||||
arm_flags ^= E015_FLAG_DISARM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E01X_send_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t can_flip = 0, calibrate = 1;
|
||||
if(sub_protocol==E012)
|
||||
{
|
||||
packet_length=E012_PACKET_SIZE;
|
||||
packet[0] = rx_tx_addr[1];
|
||||
if(bind)
|
||||
{
|
||||
packet[1] = 0xaa;
|
||||
memcpy(&packet[2], hopping_frequency, E012_NUM_RF_CHANNELS);
|
||||
memcpy(&packet[6], rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
rf_ch_num=E012_RF_BIND_CHANNEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[1] = 0x01
|
||||
| GET_FLAG(E01X_RTH_SW, E012_FLAG_RTH)
|
||||
| GET_FLAG(E01X_HEADLESS_SW, E012_FLAG_HEADLESS)
|
||||
| GET_FLAG(E01X_FLIP_SW, E012_FLAG_FLIP);
|
||||
packet[2] = convert_channel_16b_limit(AILERON, 0xc8, 0x00); // aileron
|
||||
packet[3] = convert_channel_16b_limit(ELEVATOR, 0x00, 0xc8); // elevator
|
||||
packet[4] = convert_channel_16b_limit(RUDDER, 0xc8, 0x00); // rudder
|
||||
packet[5] = convert_channel_16b_limit(THROTTLE, 0x00, 0xc8); // throttle
|
||||
packet[6] = 0xaa;
|
||||
packet[7] = E012_FLAG_EXPERT; // rate (0-2)
|
||||
packet[8] = 0x00;
|
||||
packet[9] = 0x00;
|
||||
packet[10]= 0x00;
|
||||
rf_ch_num=hopping_frequency[hopping_frequency_no++];
|
||||
hopping_frequency_no %= E012_NUM_RF_CHANNELS;
|
||||
}
|
||||
packet[11] = 0x00;
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x56;
|
||||
packet[14] = rx_tx_addr[2];
|
||||
}
|
||||
else if(sub_protocol==E015)
|
||||
{ // E015
|
||||
if(bind)
|
||||
{
|
||||
packet[0] = 0x18;
|
||||
packet[1] = 0x04;
|
||||
packet[2] = 0x06;
|
||||
// data phase address
|
||||
memcpy(&packet[3], rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
// checksum
|
||||
packet[8] = packet[3];
|
||||
for(uint8_t i=4; i<8; i++)
|
||||
packet[8] += packet[i];
|
||||
packet_length=E015_BIND_PACKET_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
E015_check_arming();
|
||||
packet[0] = convert_channel_16b_limit(THROTTLE, 0, 225); // throttle
|
||||
packet[1] = convert_channel_16b_limit(RUDDER, 225, 0); // rudder
|
||||
packet[2] = convert_channel_16b_limit(AILERON, 0, 225); // aileron
|
||||
packet[3] = convert_channel_16b_limit(ELEVATOR, 225, 0); // elevator
|
||||
packet[4] = 0x20; // elevator trim
|
||||
packet[5] = 0x20; // aileron trim
|
||||
packet[6] = arm_flags;
|
||||
packet[7] = E015_FLAG_EXPERT
|
||||
| GET_FLAG(E01X_FLIP_SW, E015_FLAG_FLIP)
|
||||
| GET_FLAG(E01X_LED_SW, E015_FLAG_LED)
|
||||
| GET_FLAG(E01X_HEADLESS_SW,E015_FLAG_HEADLESS)
|
||||
| GET_FLAG(E01X_RTH_SW, E015_FLAG_RTH);
|
||||
packet[8] = 0;
|
||||
// checksum
|
||||
packet[9] = packet[0];
|
||||
for(uint8_t i=1; i<9; i++)
|
||||
packet[9] += packet[i];
|
||||
packet_length=E015_PACKET_SIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // E016H
|
||||
packet_length=E016H_PACKET_SIZE;
|
||||
if(bind)
|
||||
{
|
||||
rf_ch_num=E016H_BIND_CHANNEL;
|
||||
memcpy(packet, &rx_tx_addr[1], 4);
|
||||
memcpy(&packet[4], hopping_frequency, 4);
|
||||
packet[8] = 0x23;
|
||||
}
|
||||
else
|
||||
{
|
||||
// trim commands
|
||||
packet[0] = 0;
|
||||
// aileron
|
||||
uint16_t val = convert_channel_16b_limit(AILERON, 0, 0x3ff);
|
||||
can_flip |= (val < 0x100) || (val > 0x300);
|
||||
packet[1] = val >> 8;
|
||||
packet[2] = val & 0xff;
|
||||
if(val < 0x300) calibrate = 0;
|
||||
// elevator
|
||||
val = convert_channel_16b_limit(ELEVATOR, 0x3ff, 0);
|
||||
can_flip |= (val < 0x100) || (val > 0x300);
|
||||
packet[3] = val >> 8;
|
||||
packet[4] = val & 0xff;
|
||||
if(val < 0x300) calibrate = 0;
|
||||
// throttle
|
||||
val = convert_channel_16b_limit(THROTTLE, 0, 0x3ff);
|
||||
packet[5] = val >> 8;
|
||||
packet[6] = val & 0xff;
|
||||
if(val > 0x100) calibrate = 0;
|
||||
// rudder
|
||||
val = convert_channel_16b_limit(RUDDER, 0, 0x3ff);
|
||||
packet[7] = val >> 8;
|
||||
packet[8] = val & 0xff;
|
||||
if(val > 0x100) calibrate = 0;
|
||||
// flags
|
||||
packet[1] |= GET_FLAG(E016H_STOP_SW, E016H_FLAG_STOP)
|
||||
| (can_flip ? GET_FLAG(E01X_FLIP_SW, E016H_FLAG_FLIP) : 0)
|
||||
| (calibrate ? E016H_FLAG_CALIBRATE : 0);
|
||||
packet[3] |= GET_FLAG(E01X_HEADLESS_SW, E016H_FLAG_HEADLESS)
|
||||
| GET_FLAG(E01X_RTH_SW, E016H_FLAG_RTH);
|
||||
packet[7] |= E016H_FLAG_HIGHRATE;
|
||||
// frequency hopping
|
||||
rf_ch_num=hopping_frequency[hopping_frequency_no++ & 0x03];
|
||||
}
|
||||
// checksum
|
||||
packet[9] = packet[0];
|
||||
for (uint8_t i=1; i < E016H_PACKET_SIZE-1; i++)
|
||||
packet[9] += packet[i];
|
||||
}
|
||||
|
||||
// Power on, TX mode, CRC enabled
|
||||
if(sub_protocol==E016H)
|
||||
XN297_Configure( _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
else //E012 & E015
|
||||
HS6200_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if(sub_protocol==E016H)
|
||||
XN297_WritePayload(packet, packet_length);
|
||||
else
|
||||
HS6200_WritePayload(packet, packet_length);
|
||||
|
||||
// Check and adjust transmission power. We do this after
|
||||
// transmission to not bother with timeout after power
|
||||
// settings change - we have plenty of time until next
|
||||
// packet.
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E01X_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
if(sub_protocol==E012)
|
||||
HS6200_SetTXAddr((uint8_t *)"\x55\x42\x9C\x8F\xC9", E01X_ADDRESS_LENGTH);
|
||||
else if(sub_protocol==E015)
|
||||
HS6200_SetTXAddr((uint8_t *)"\x62\x54\x79\x38\x53", E01X_ADDRESS_LENGTH);
|
||||
else //E016H
|
||||
XN297_SetTXAddr((uint8_t *)"\x5a\x53\x46\x30\x31", 5); // bind address
|
||||
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_03_SETUP_AW, 0x03);
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1 Mbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01); // Set feature bits on
|
||||
NRF24L01_Activate(0x73);
|
||||
}
|
||||
|
||||
uint16_t E01X_callback()
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
if(sub_protocol==E016H)
|
||||
XN297_SetTXAddr(rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
else
|
||||
HS6200_SetTXAddr(rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
E01X_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
E01X_send_packet(0);
|
||||
}
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E012_initialize_txid()
|
||||
{
|
||||
// rf channels
|
||||
uint32_t lfsr=random(0xfefefefe);
|
||||
for(uint8_t i=0; i<E012_NUM_RF_CHANNELS; i++)
|
||||
{
|
||||
hopping_frequency[i] = 0x10 + ((lfsr & 0xff) % 0x32);
|
||||
lfsr>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E016H_initialize_txid()
|
||||
{
|
||||
// tx id
|
||||
rx_tx_addr[0] = 0xa5;
|
||||
rx_tx_addr[1] = 0x00;
|
||||
|
||||
// rf channels
|
||||
uint32_t lfsr=random(0xfefefefe);
|
||||
for(uint8_t i=0; i<E016H_NUM_CHANNELS; i++)
|
||||
{
|
||||
hopping_frequency[i] = (lfsr & 0xFF) % 80;
|
||||
lfsr>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initE01X()
|
||||
{
|
||||
BIND_IN_PROGRESS;
|
||||
if(sub_protocol==E012)
|
||||
{
|
||||
E012_initialize_txid();
|
||||
packet_period=E012_PACKET_PERIOD;
|
||||
}
|
||||
else if(sub_protocol==E015)
|
||||
{
|
||||
packet_period=E015_PACKET_PERIOD;
|
||||
rf_ch_num=E015_RF_CHANNEL;
|
||||
armed = 0;
|
||||
arm_flags = 0;
|
||||
arm_channel_previous = E01X_ARM_SW;
|
||||
}
|
||||
else
|
||||
{ // E016H
|
||||
E016H_initialize_txid();
|
||||
packet_period=E016H_PACKET_PERIOD;
|
||||
}
|
||||
E01X_init();
|
||||
bind_counter = E01X_BIND_COUNT;
|
||||
hopping_frequency_no = 0;
|
||||
return E01X_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
177
Multiprotocol/E129_cyrf6936.ino
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
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(E129_CYRF6936_INO)
|
||||
|
||||
#include "iface_rf2500.h"
|
||||
|
||||
//#define E129_FORCE_ID
|
||||
//#define C186_FORCE_ID
|
||||
|
||||
#define E129_BIND_CH 0x2D //45
|
||||
#define E129_PAYLOAD_SIZE 16
|
||||
#define C186_PAYLOAD_SIZE 19
|
||||
|
||||
static void __attribute__((unused)) E129_build_data_packet()
|
||||
{
|
||||
//Build the packet
|
||||
memset(packet,0,packet_length);
|
||||
packet[ 0] = packet_length - 1; // Packet length
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[ 1] = 0xA4;
|
||||
packet[ 2] = bit_reverse(rx_tx_addr[2]);
|
||||
packet[ 3] = bit_reverse(rx_tx_addr[3]);
|
||||
packet[ 4] = bit_reverse(rx_tx_addr[0]);
|
||||
packet[ 5] = bit_reverse(rx_tx_addr[1]);
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
packet[6+i]=hopping_frequency[i]-2;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[ 1] = 0xA6;
|
||||
//Flags
|
||||
if(sub_protocol == E129_E129)
|
||||
packet[ 2] = 0xF7; // High rate 0xF7, low 0xF4
|
||||
else //C186
|
||||
{
|
||||
packet[ 2] = 0xFA; // High rate 0xFA, medium 0xF7, low 0xF4
|
||||
packet[13] = bit_reverse(rx_tx_addr[2]);
|
||||
packet[14] = bit_reverse(rx_tx_addr[3]);
|
||||
packet[15] = bit_reverse(rx_tx_addr[0]);
|
||||
packet[16] = bit_reverse(rx_tx_addr[1]);
|
||||
}
|
||||
//packet[ 3] = 0x00; // E129 Mode: short press=0x20->0x00->0x20->..., long press=0x10->0x30->0x10->... => C186 throttle trim is doing the same:up=short press and down=long press
|
||||
packet[ 4] = GET_FLAG(CH5_SW, 0x20) // Take off/Land 0x20
|
||||
| GET_FLAG(CH6_SW, 0x04); // Emergency stop 0x04
|
||||
//Channels and trims
|
||||
uint16_t val = convert_channel_10b(AILERON,false);
|
||||
uint8_t trim = convert_channel_8b(CH7) & 0xFC;
|
||||
packet[ 5] = trim | (val >>8); // Trim (0x00..0x1F..0x3E) << 2 | channel >> 8
|
||||
packet[ 6] = val; // channel (0x000...0x200...0x3FF)
|
||||
val = convert_channel_10b(ELEVATOR,false);
|
||||
trim = convert_channel_8b(CH8) & 0xFC;
|
||||
packet[ 7] = trim | (val >>8); // Trim (0x00..0x1F..0x3E) << 2 | channel >> 8
|
||||
packet[ 8] = val; // channel (0x000...0x200...0x3FF)
|
||||
if(packet_count>200)
|
||||
val = convert_channel_10b(THROTTLE,false);
|
||||
else
|
||||
{//Allow bind to complete with throttle not centered
|
||||
packet_count++;
|
||||
val=0x200;
|
||||
}
|
||||
packet[ 9] = (0x1F<<2) | (val >>8); // Trim (0x00..0x1F..0x3E) << 2 | channel >> 8
|
||||
packet[10] = val; // channel (0x000...0x200...0x3FF)
|
||||
val = convert_channel_10b(RUDDER,false);
|
||||
trim = convert_channel_8b(CH9) & 0xFC;
|
||||
packet[11] = trim | (val >>8); // Trim (0x00..0x1F..0x3E) << 2 | channel >> 8
|
||||
packet[12] = val; // channel (0x000...0x200...0x3FF)
|
||||
}
|
||||
//Check
|
||||
if(sub_protocol == E129_E129)
|
||||
packet[packet_length-2] = packet[0] + packet[1];
|
||||
else
|
||||
packet[packet_length-2] = 0x24 + packet[0] + (packet[1]&0x03); // ??
|
||||
for(uint8_t i=2;i<packet_length-2;i++)
|
||||
packet[packet_length-2] += packet[i];
|
||||
|
||||
RF2500_BuildPayload(packet);
|
||||
}
|
||||
|
||||
uint16_t E129_callback()
|
||||
{
|
||||
//Set RF channel
|
||||
if(phase==0)
|
||||
RF2500_RFChannel(IS_BIND_IN_PROGRESS ? E129_BIND_CH : hopping_frequency[hopping_frequency_no]);
|
||||
|
||||
//Send packet
|
||||
RF2500_SendPayload();
|
||||
|
||||
//E129 sends twice on same channel, not the C186 but there is a bug somewhere if I don't send the packets back to back
|
||||
if(phase==0)
|
||||
{
|
||||
phase++;
|
||||
return 1260;
|
||||
}
|
||||
|
||||
//Bind
|
||||
if(bind_counter)
|
||||
if(--bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
RF2500_SetTXAddr(rx_tx_addr); // 4 bytes of address
|
||||
}
|
||||
|
||||
//Build packet
|
||||
E129_build_data_packet();
|
||||
|
||||
//Set power
|
||||
RF2500_SetPower();
|
||||
|
||||
//Hopp
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no &= 3;
|
||||
|
||||
phase=0;
|
||||
if(sub_protocol==E129_E129)
|
||||
return 5200-1260;
|
||||
return 5500-1260; //E129_C186
|
||||
}
|
||||
|
||||
void E129_init()
|
||||
{
|
||||
BIND_IN_PROGRESS; // Autobind protocol
|
||||
bind_counter = 384; // ~2sec
|
||||
|
||||
//RF2500 emu init
|
||||
packet_length = sub_protocol == E129_E129?E129_PAYLOAD_SIZE:C186_PAYLOAD_SIZE;
|
||||
RF2500_Init(packet_length, true); // 16/19 bytes, Scrambled
|
||||
|
||||
//Freq hopping
|
||||
calc_fh_channels(4);
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
if(hopping_frequency[i]==E129_BIND_CH)
|
||||
hopping_frequency[i]++;
|
||||
|
||||
#ifdef E129_FORCE_ID
|
||||
rx_tx_addr[0]=0xC1;
|
||||
rx_tx_addr[1]=0x22;
|
||||
rx_tx_addr[2]=0x05;
|
||||
rx_tx_addr[3]=0xA3;
|
||||
hopping_frequency[0]=0x3C; //60
|
||||
hopping_frequency[1]=0x49; //73
|
||||
hopping_frequency[2]=0x4B; //75
|
||||
hopping_frequency[3]=0x41; //65
|
||||
#endif
|
||||
#ifdef C186_FORCE_ID
|
||||
rx_tx_addr[0]=0x91;
|
||||
rx_tx_addr[1]=0x02;
|
||||
rx_tx_addr[2]=0x5D;
|
||||
rx_tx_addr[3]=0x33;
|
||||
hopping_frequency[0]=0x44 + 2;
|
||||
hopping_frequency[1]=0x41 + 2;
|
||||
hopping_frequency[2]=0x43 + 2;
|
||||
hopping_frequency[3]=0x49 + 2;
|
||||
#endif
|
||||
|
||||
RF2500_SetTXAddr((uint8_t*)"\xE2\x32\xE0\xC8"); // 4 bytes of bind address
|
||||
|
||||
E129_build_data_packet();
|
||||
hopping_frequency_no=0;
|
||||
packet_count=0;
|
||||
phase=0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -23,7 +23,7 @@
|
||||
#define ESKY150_BINDING_PACKET_PERIOD 2000
|
||||
#define ESKY150_SENDING_PACKET_PERIOD 4800
|
||||
|
||||
static void __attribute__((unused)) ESKY150_init()
|
||||
static void __attribute__((unused)) ESKY150_RF_init()
|
||||
{
|
||||
//Original TX always sets for channelx 0x22 and 0x4a
|
||||
// Use channels 2..79
|
||||
@@ -31,25 +31,16 @@ static void __attribute__((unused)) ESKY150_init()
|
||||
hopping_frequency[1] = hopping_frequency[0] + 40;
|
||||
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)));
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x02); // 4-byte RX/TX address
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // Disable retransmit
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_2M);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, ESKY150_PAYLOADSIZE); // bytes of data payload for pipe 0
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, ESKY150_TX_ADDRESS_SIZE);
|
||||
|
||||
NRF24L01_Activate(0x73);
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
|
||||
// Enable: Dynamic Payload Length, Payload with ACK , W_TX_PAYLOAD_NOACK
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, _BV(NRF2401_1D_EN_DPL) | _BV(NRF2401_1D_EN_ACK_PAY) | _BV(NRF2401_1D_EN_DYN_ACK));
|
||||
NRF24L01_Activate(0x73);
|
||||
NRF24L01_FlushTx();
|
||||
// Turn radio power on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
NRF24L01_SetTxRxMode(TX_EN); // Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ESKY150_bind_init()
|
||||
@@ -171,16 +162,15 @@ uint16_t ESKY150_callback()
|
||||
return ESKY150_SENDING_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initESKY150(void)
|
||||
void ESKY150_init(void)
|
||||
{
|
||||
ESKY150_init();
|
||||
ESKY150_RF_init();
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
bind_counter=3000;
|
||||
ESKY150_bind_init();
|
||||
}
|
||||
hopping_frequency_no=0;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
138
Multiprotocol/ESky150v2_cc2500.ino
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
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(ESKY150V2_CC2500_INO)
|
||||
|
||||
#include "iface_nrf250k.h"
|
||||
|
||||
//#define ESKY150V2_FORCE_ID
|
||||
|
||||
#define ESKY150V2_PAYLOADSIZE 40
|
||||
#define ESKY150V2_BINDPAYLOADSIZE 150
|
||||
#define ESKY150V2_NFREQCHANNELS 70
|
||||
#define ESKY150V2_TXID_SIZE 4
|
||||
#define ESKY150V2_BIND_CHANNEL 0x00
|
||||
#define ESKY150V2_PACKET_PERIOD 10000
|
||||
#define ESKY150V2_BINDING_PACKET_PERIOD 57000
|
||||
|
||||
#ifdef ESKY150V2_FORCE_ID
|
||||
const uint8_t PROGMEM ESKY150V2_hop[ESKY150V2_NFREQCHANNELS]= {
|
||||
0x07, 0x47, 0x09, 0x27, 0x0B, 0x42, 0x0D, 0x35, 0x17, 0x40, 0x26, 0x3D, 0x16, 0x43, 0x06, 0x2A, 0x24, 0x44,
|
||||
0x0E, 0x38, 0x20, 0x48, 0x22, 0x2D, 0x2B, 0x39, 0x0F, 0x36, 0x23, 0x46, 0x14, 0x3B, 0x1A, 0x41, 0x10, 0x2E,
|
||||
0x1E, 0x28, 0x0C, 0x49, 0x1D, 0x3E, 0x29, 0x2C, 0x25, 0x30, 0x1C, 0x2F, 0x1B, 0x33, 0x13, 0x31, 0x0A, 0x37,
|
||||
0x12, 0x3C, 0x18, 0x4B, 0x11, 0x45, 0x21, 0x4A, 0x1F, 0x3F, 0x15, 0x32, 0x08, 0x3A, 0x19, 0x34 };
|
||||
/*const uint8_t PROGMEM ESKY150V2_hop2[40]= {
|
||||
0x19, 0x23, 0x13, 0x1B, 0x09, 0x22, 0x14, 0x27, 0x06, 0x26, 0x16, 0x24, 0x0B, 0x2A, 0x0E, 0x1C, 0x11, 0x1E,
|
||||
0x08, 0x29, 0x0D, 0x28, 0x18, 0x2D, 0x12, 0x20, 0x0C, 0x1A, 0x10, 0x1D, 0x07, 0x2C, 0x0A, 0x2B, 0x0F, 0x25,
|
||||
0x15, 0x1F, 0x17, 0x21 };*/
|
||||
#endif
|
||||
|
||||
static void __attribute__((unused)) ESKY150V2_set_freq(void)
|
||||
{
|
||||
calc_fh_channels(ESKY150V2_NFREQCHANNELS);
|
||||
|
||||
#ifdef ESKY150V2_FORCE_ID
|
||||
for(uint8_t i=0; i<ESKY150V2_NFREQCHANNELS; i++)
|
||||
hopping_frequency[i]=pgm_read_byte_near( &ESKY150V2_hop[i] );
|
||||
#endif
|
||||
|
||||
//Bind channel
|
||||
hopping_frequency[ESKY150V2_NFREQCHANNELS]=ESKY150V2_BIND_CHANNEL;
|
||||
|
||||
//Calib all channels
|
||||
CC2500_SetFreqOffset(); // Set frequency offset
|
||||
CC2500_250K_HoppingCalib(ESKY150V2_NFREQCHANNELS+1);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ESKY150V2_send_packet()
|
||||
{
|
||||
CC2500_SetFreqOffset(); // Set frequency offset
|
||||
CC2500_250K_Hopping(hopping_frequency_no);
|
||||
if (++hopping_frequency_no >= ESKY150V2_NFREQCHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
CC2500_SetPower(); //Set power level
|
||||
|
||||
packet[0] = 0xFA; // Unknown
|
||||
packet[1] = 0x41; // Unknown
|
||||
packet[2] = 0x08; // Unknown
|
||||
packet[3] = 0x00; // Unknown
|
||||
for(uint8_t i=0;i<16;i++)
|
||||
{
|
||||
uint16_t channel=convert_channel_16b_limit(CH_TAER[i],200,1000);
|
||||
packet[4+2*i] = channel;
|
||||
packet[5+2*i] = channel>>8;
|
||||
}
|
||||
NRF250K_WritePayload(packet, ESKY150V2_PAYLOADSIZE);
|
||||
}
|
||||
|
||||
uint16_t ESKY150V2_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(ESKY150V2_PACKET_PERIOD);
|
||||
#endif
|
||||
ESKY150V2_send_packet();
|
||||
}
|
||||
else
|
||||
{
|
||||
BIND_DONE; //Need full power for bind to work...
|
||||
CC2500_SetPower(); //Set power level
|
||||
BIND_IN_PROGRESS;
|
||||
NRF250K_WritePayload(packet, ESKY150V2_BINDPAYLOADSIZE);
|
||||
if (--bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
// Change TX address from bind to normal mode
|
||||
NRF250K_SetTXAddr(rx_tx_addr, ESKY150V2_TXID_SIZE);
|
||||
memset(packet,0x00,ESKY150V2_PAYLOADSIZE);
|
||||
}
|
||||
return 30000; //ESKY150V2_BINDING_PACKET_PERIOD;
|
||||
}
|
||||
return ESKY150V2_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
void ESKY150V2_init()
|
||||
{
|
||||
CC2500_250K_Init();
|
||||
ESKY150V2_set_freq();
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
#ifdef ESKY150V2_FORCE_ID // ID taken from TX dump
|
||||
rx_tx_addr[0]=0x87;rx_tx_addr[1]=0x5B;rx_tx_addr[2]=0x2C;rx_tx_addr[3]=0x5D;
|
||||
#endif
|
||||
|
||||
memset(packet,0x00,ESKY150V2_BINDPAYLOADSIZE);
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
NRF250K_SetTXAddr((uint8_t *)"\x73\x73\x74\x63", ESKY150V2_TXID_SIZE); //Bind address
|
||||
CC2500_250K_Hopping(ESKY150V2_NFREQCHANNELS); //Bind channel
|
||||
memcpy(packet,"\x73\x73\x74\x63", ESKY150V2_TXID_SIZE);
|
||||
memcpy(&packet[ESKY150V2_TXID_SIZE],rx_tx_addr, ESKY150V2_TXID_SIZE);
|
||||
packet[8]=0x41; //Unknown
|
||||
packet[9]=0x88; //Unknown
|
||||
packet[10]=0x41; //Unknown
|
||||
memset(&packet[11],0xAA,4); //Unknown
|
||||
memcpy(&packet[15],hopping_frequency,ESKY150V2_NFREQCHANNELS); // hop table
|
||||
//for(uint8_t i=0; i<40; i++) // Does not seem to be needed
|
||||
// packet[i+85]=pgm_read_byte_near( &ESKY150V2_hop2[i] );
|
||||
bind_counter=100;
|
||||
}
|
||||
else
|
||||
NRF250K_SetTXAddr(rx_tx_addr, ESKY150V2_TXID_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -18,8 +18,13 @@
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
//#define ESKY_ET4_FORCE_ID
|
||||
|
||||
#define ESKY_BIND_COUNT 1000
|
||||
#define ESKY_PACKET_PERIOD 3333
|
||||
#define ESKY_STD_PACKET_PERIOD 3333
|
||||
#define ESKY_ET4_PACKET_PERIOD 1190
|
||||
#define ESKY_ET4_TOTAL_PACKET_PERIOD 20300
|
||||
#define ESKY_ET4_BIND_PACKET_PERIOD 5000
|
||||
#define ESKY_PAYLOAD_SIZE 13
|
||||
#define ESKY_PACKET_CHKTIME 100 // Time to wait for packet to be sent (no ACK, so very short)
|
||||
|
||||
@@ -30,14 +35,10 @@ static void __attribute__((unused)) ESKY_set_data_address()
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ESKY_init()
|
||||
static void __attribute__((unused)) ESKY_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
|
||||
// 2-bytes CRC, radio off
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3-byte RX/TX address for bind packets
|
||||
@@ -46,11 +47,7 @@ static void __attribute__((unused)) ESKY_init()
|
||||
}
|
||||
else
|
||||
ESKY_set_data_address();
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // No auto retransmission
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 50); // Channel 50 for bind packets
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, ESKY_PAYLOAD_SIZE); // bytes of data payload for pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_12_RX_PW_P1, ESKY_PAYLOAD_SIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_13_RX_PW_P2, ESKY_PAYLOAD_SIZE);
|
||||
@@ -60,31 +57,40 @@ static void __attribute__((unused)) ESKY_init()
|
||||
NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ESKY_init2()
|
||||
static void __attribute__((unused)) ESKY_TXID_init()
|
||||
{
|
||||
NRF24L01_FlushTx();
|
||||
hopping_frequency_no = 0;
|
||||
uint16_t channel_ord = rx_tx_addr[0] % 74;
|
||||
hopping_frequency[12] = 10 + (uint8_t)channel_ord; //channel_code
|
||||
uint8_t channel1, channel2;
|
||||
channel1 = 10 + (uint8_t)((37 + channel_ord*5) % 74);
|
||||
channel2 = 10 + (uint8_t)(( channel_ord*5) % 74) ;
|
||||
if(sub_protocol==ESKY_STD)
|
||||
{
|
||||
uint16_t channel_ord = rx_tx_addr[0] % 74;
|
||||
hopping_frequency[12] = 10 + (uint8_t)channel_ord; //channel_code
|
||||
uint8_t channel1, channel2;
|
||||
channel1 = 10 + (uint8_t)((37 + channel_ord*5) % 74);
|
||||
channel2 = 10 + (uint8_t)(( channel_ord*5) % 74) ;
|
||||
|
||||
hopping_frequency[0] = channel1;
|
||||
hopping_frequency[1] = channel1;
|
||||
hopping_frequency[2] = channel1;
|
||||
hopping_frequency[3] = channel2;
|
||||
hopping_frequency[4] = channel2;
|
||||
hopping_frequency[5] = channel2;
|
||||
|
||||
//end_bytes
|
||||
hopping_frequency[6] = 6;
|
||||
hopping_frequency[7] = channel1*2;
|
||||
hopping_frequency[8] = channel2*2;
|
||||
hopping_frequency[9] = 6;
|
||||
hopping_frequency[10] = channel1*2;
|
||||
hopping_frequency[11] = channel2*2;
|
||||
hopping_frequency[0] = channel1;
|
||||
hopping_frequency[1] = channel1;
|
||||
hopping_frequency[2] = channel1;
|
||||
hopping_frequency[3] = channel2;
|
||||
hopping_frequency[4] = channel2;
|
||||
hopping_frequency[5] = channel2;
|
||||
|
||||
//end_bytes
|
||||
hopping_frequency[6] = 6;
|
||||
hopping_frequency[7] = channel1*2;
|
||||
hopping_frequency[8] = channel2*2;
|
||||
hopping_frequency[9] = 6;
|
||||
hopping_frequency[10] = channel1*2;
|
||||
hopping_frequency[11] = channel2*2;
|
||||
}
|
||||
else
|
||||
{ // ESKY_ET4
|
||||
hopping_frequency[0] = 0x29; //41
|
||||
hopping_frequency[1] = 0x12; //18
|
||||
hopping_frequency[6] = 0x87; //135 payload end byte
|
||||
hopping_frequency[12] = 0x84; //132 indicates which channels to use
|
||||
}
|
||||
|
||||
// Turn radio power on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
}
|
||||
@@ -111,20 +117,32 @@ static void __attribute__((unused)) ESKY_send_packet(uint8_t bind)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Regular packet
|
||||
// Each data packet is repeated 3 times on one channel, and 3 times on another channel
|
||||
// For arithmetic simplicity, channels are repeated in rf_channels array
|
||||
if (hopping_frequency_no == 0)
|
||||
if (packet_count == 0)
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
{
|
||||
uint16_t val=convert_channel_ppm(CH_AETR[i]);
|
||||
packet[i*2] = val>>8; //high byte of servo timing(1000-2000us)
|
||||
packet[i*2+1] = val&0xFF; //low byte of servo timing(1000-2000us)
|
||||
}
|
||||
rf_ch = hopping_frequency[hopping_frequency_no];
|
||||
packet[12] = hopping_frequency[hopping_frequency_no+6]; // end_bytes
|
||||
hopping_frequency_no++;
|
||||
if (hopping_frequency_no > 6) hopping_frequency_no = 0;
|
||||
if(sub_protocol==ESKY_STD)
|
||||
{
|
||||
// Regular packet
|
||||
// Each data packet is repeated 3 times on one channel, and 3 times on another channel
|
||||
// For arithmetic simplicity, channels are repeated in rf_channels array
|
||||
rf_ch = hopping_frequency[packet_count];
|
||||
packet[12] = hopping_frequency[packet_count+6]; // end_bytes
|
||||
packet_count++;
|
||||
if (packet_count > 6) packet_count = 0;
|
||||
}
|
||||
else
|
||||
{ // ESKY_ET4
|
||||
// Regular packet
|
||||
// Each data packet is repeated 14 times alternating between 2 channels
|
||||
rf_ch = hopping_frequency[packet_count&1];
|
||||
packet_count++;
|
||||
if(packet_count>14) packet_count=0;
|
||||
packet[12] = hopping_frequency[6]; // end_byte
|
||||
}
|
||||
}
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
|
||||
NRF24L01_FlushTx();
|
||||
@@ -137,9 +155,17 @@ uint16_t ESKY_callback()
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(ESKY_PACKET_PERIOD);
|
||||
if(packet_count==0)
|
||||
telemetry_set_input_sync(sub_protocol==ESKY_STD?ESKY_STD_PACKET_PERIOD*6:ESKY_ET4_TOTAL_PACKET_PERIOD);
|
||||
#endif
|
||||
ESKY_send_packet(0);
|
||||
if(sub_protocol==ESKY_ET4)
|
||||
{
|
||||
if(packet_count==0)
|
||||
return ESKY_ET4_TOTAL_PACKET_PERIOD-ESKY_ET4_PACKET_PERIOD*13;
|
||||
else
|
||||
return ESKY_ET4_PACKET_PERIOD;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -150,17 +176,25 @@ uint16_t ESKY_callback()
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
return ESKY_PACKET_PERIOD;
|
||||
return ESKY_STD_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initESKY(void)
|
||||
void ESKY_init(void)
|
||||
{
|
||||
bind_counter = ESKY_BIND_COUNT;
|
||||
rx_tx_addr[2] = rx_tx_addr[3]; // Model match
|
||||
#ifdef ESKY_ET4_FORCE_ID
|
||||
if(sub_protocol==ESKY_ET4)
|
||||
{
|
||||
rx_tx_addr[0]=0x72;
|
||||
rx_tx_addr[1]=0xBB;
|
||||
rx_tx_addr[2]=0xCC;
|
||||
}
|
||||
#endif
|
||||
rx_tx_addr[3] = 0xBB;
|
||||
ESKY_init();
|
||||
ESKY_init2();
|
||||
return 50000;
|
||||
ESKY_RF_init();
|
||||
ESKY_TXID_init();
|
||||
packet_count=0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -52,24 +52,18 @@ static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, ui
|
||||
header[0] = (addr[4] >> 7);
|
||||
|
||||
// calculate the crc
|
||||
union
|
||||
{
|
||||
uint8_t bytes[2];
|
||||
uint16_t val;
|
||||
} crc;
|
||||
|
||||
crc.val=0x3c18;
|
||||
crc=0x3c18;
|
||||
for (i = 0; i < 7; ++i)
|
||||
crc.val=crc16_update(crc.val,header[i],8);
|
||||
crc16_update(header[i],8);
|
||||
for (i = 0; i < *len; ++i)
|
||||
crc.val=crc16_update(crc.val,payload[i],8);
|
||||
crc16_update(payload[i],8);
|
||||
|
||||
// encode payload and crc
|
||||
// xor with this:
|
||||
for (i = 0; i < *len; ++i)
|
||||
payload[i] ^= ssv_xor[i];
|
||||
crc.bytes[1] ^= ssv_xor[i++];
|
||||
crc.bytes[0] ^= ssv_xor[i++];
|
||||
crc ^= ssv_xor[i++]<<8;
|
||||
crc ^= ssv_xor[i++];
|
||||
|
||||
// pack the pcf, payload, and crc into packed_payload
|
||||
packed_payload[0] = pcf >> 1;
|
||||
@@ -78,20 +72,20 @@ static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, ui
|
||||
for (i = 0; i < *len - 1; ++i)
|
||||
packed_payload[i+2] = (payload[i] << 7) | (payload[i+1] >> 1);
|
||||
|
||||
packed_payload[i+2] = (payload[i] << 7) | (crc.val >> 9);
|
||||
packed_payload[i+2] = (payload[i] << 7) | (crc >> 9);
|
||||
++i;
|
||||
packed_payload[i+2] = (crc.val >> 1 & 0x80 ) | (crc.val >> 1 & 0x7F);
|
||||
packed_payload[i+2] = (crc >> 1 & 0x80 ) | (crc >> 1 & 0x7F);
|
||||
++i;
|
||||
packed_payload[i+2] = (crc.val << 7);
|
||||
packed_payload[i+2] = (crc << 7);
|
||||
|
||||
*len += 4;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) FQ777_send_packet()
|
||||
{
|
||||
uint8_t packet_len = FQ777_PACKET_SIZE;
|
||||
uint8_t packet_ori[8];
|
||||
if (bind)
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
// 4,5,6 = address fields
|
||||
// last field is checksum of address fields
|
||||
@@ -144,7 +138,7 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
|
||||
packet_count++;
|
||||
}
|
||||
|
||||
ssv_pack_dpl( (0 == bind) ? rx_tx_addr : FQ777_bind_addr, hopping_frequency_no, &packet_len, packet_ori, packet);
|
||||
ssv_pack_dpl( IS_BIND_IN_PROGRESS ? FQ777_bind_addr : rx_tx_addr, hopping_frequency_no, &packet_len, packet_ori, packet);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG,_BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
@@ -156,30 +150,21 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
|
||||
NRF24L01_WritePayload(packet, packet_len);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FQ777_init()
|
||||
static void __attribute__((unused)) FQ777_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, FQ777_bind_addr, 5);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x00);
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K);
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
|
||||
NRF24L01_Activate(0x73);
|
||||
}
|
||||
|
||||
uint16_t FQ777_callback()
|
||||
{
|
||||
if(bind_counter!=0)
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(FQ777_PACKET_PERIOD);
|
||||
#endif
|
||||
if(bind_counter)
|
||||
{
|
||||
FQ777_send_packet(1);
|
||||
bind_counter--;
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
@@ -187,17 +172,11 @@ uint16_t FQ777_callback()
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(FQ777_PACKET_PERIOD);
|
||||
#endif
|
||||
FQ777_send_packet(0);
|
||||
}
|
||||
FQ777_send_packet();
|
||||
return FQ777_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initFQ777(void)
|
||||
void FQ777_init(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = FQ777_BIND_COUNT;
|
||||
@@ -210,8 +189,7 @@ uint16_t initFQ777(void)
|
||||
rx_tx_addr[2] = 0x00;
|
||||
rx_tx_addr[3] = 0xe7;
|
||||
rx_tx_addr[4] = 0x67;
|
||||
FQ777_init();
|
||||
return FQ777_INITIAL_WAIT;
|
||||
FQ777_RF_init();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
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 FEI XIONG P38 plane.
|
||||
|
||||
#if defined(FX816_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define FX816_INITIAL_WAIT 500
|
||||
#define FX816_PACKET_PERIOD 10000
|
||||
#define FX816_RF_BIND_CHANNEL 0x28 //40
|
||||
#define FX816_RF_NUM_CHANNELS 4
|
||||
#define FX816_PAYLOAD_SIZE 6
|
||||
#define FX816_BIND_COUNT 300 //3sec
|
||||
|
||||
static void __attribute__((unused)) FX816_send_packet()
|
||||
{
|
||||
packet[0] = IS_BIND_IN_PROGRESS?0x55:0xAA;
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
uint8_t val=convert_channel_8b(AILERON);
|
||||
#define FX816_SWITCH 20
|
||||
if(val>127+FX816_SWITCH)
|
||||
packet[3] = 1;
|
||||
else if(val<127-FX816_SWITCH)
|
||||
packet[3] = 2;
|
||||
else
|
||||
packet[3] = 0;
|
||||
packet[4] = convert_channel_16b_limit(THROTTLE,0,100);
|
||||
val=0;
|
||||
for(uint8_t i=0;i<FX816_PAYLOAD_SIZE-1;i++)
|
||||
val+=packet[i];
|
||||
packet[5]=val;
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, IS_BIND_IN_PROGRESS ? FX816_RF_BIND_CHANNEL:hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no%=FX816_RF_NUM_CHANNELS;
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WritePayload(packet, FX816_PAYLOAD_SIZE);
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX816_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
XN297_SetTXAddr((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 Acknowldgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // No retransmits
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
|
||||
NRF24L01_Activate(0x73);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX816_initialize_txid()
|
||||
{
|
||||
//Only 8 IDs: the RX led does not indicate frame loss.
|
||||
//I didn't open the plane to find out if I could connect there so this is the best I came up with with few trial and errors...
|
||||
rx_tx_addr[0]=0x35+(rx_tx_addr[3]&0x07); //Original dump=0x35
|
||||
rx_tx_addr[1]=0x09; //Original dump=0x09
|
||||
memcpy(hopping_frequency,"\x09\x1B\x30\x42",FX816_RF_NUM_CHANNELS); //Original dump=9=0x09,27=0x1B,48=0x30,66=0x42
|
||||
for(uint8_t i=0;i<FX816_RF_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
|
||||
}
|
||||
|
||||
uint16_t FX816_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(FX816_PACKET_PERIOD);
|
||||
#endif
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
if(--bind_counter==0)
|
||||
BIND_DONE;
|
||||
FX816_send_packet();
|
||||
return FX816_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initFX816()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
FX816_initialize_txid();
|
||||
FX816_init();
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter=FX816_BIND_COUNT;
|
||||
return FX816_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
240
Multiprotocol/FX_nrf24l01.ino
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
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 FEI XIONG P38 plane.
|
||||
|
||||
#if defined(FX_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define FX_BIND_COUNT 300 //3sec
|
||||
#define FX_SWITCH 20
|
||||
#define FX_NUM_CHANNELS 4
|
||||
|
||||
#define FX816_PACKET_PERIOD 10000
|
||||
#define FX816_BIND_CHANNEL 40
|
||||
#define FX816_PAYLOAD_SIZE 6
|
||||
#define FX816_CH_OFFSET 3
|
||||
|
||||
#define FX620_PACKET_PERIOD 3250
|
||||
#define FX620_BIND_PACKET_PERIOD 4500
|
||||
#define FX620_BIND_CHANNEL 18
|
||||
#define FX620_PAYLOAD_SIZE 7
|
||||
#define FX620_CH_OFFSET 1
|
||||
|
||||
#define FX9630_PACKET_PERIOD 8124
|
||||
#define FX9630_BIND_PACKET_PERIOD 8124
|
||||
#define FX9630_BIND_CHANNEL 51
|
||||
#define FX9630_PAYLOAD_SIZE 8
|
||||
#define FX9630_NUM_CHANNELS 3
|
||||
|
||||
//#define FORCE_FX620_ID
|
||||
//#define FORCE_FX9630_ID
|
||||
|
||||
static void __attribute__((unused)) FX_send_packet()
|
||||
{
|
||||
//Hopp
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
if(sub_protocol == FX9630)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, 4);
|
||||
if (hopping_frequency_no > FX9630_NUM_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
}
|
||||
else // FX816 and FX620
|
||||
{
|
||||
hopping_frequency_no &= 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
memset(packet,0x00,packet_length);
|
||||
|
||||
//Channels
|
||||
uint8_t val;
|
||||
if (sub_protocol == FX9630)
|
||||
{
|
||||
packet[0] = convert_channel_8b(THROTTLE);
|
||||
packet[1] = convert_channel_8b(AILERON);
|
||||
packet[2] = 0xFF - convert_channel_8b(ELEVATOR);
|
||||
packet[3] = convert_channel_8b(RUDDER);
|
||||
packet[4] = 0x20;
|
||||
packet[5] = GET_FLAG(CH5_SW, 0x01); // DR toggle swich: 0 small throw, 1 large throw
|
||||
packet[5] |= (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x02 : 0x01)) << 1; // Mode A(0) : 6D small throw, B(1) : 6D large throw, C(2) : 3D
|
||||
}
|
||||
else // FX816 and FX620
|
||||
{
|
||||
uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET;
|
||||
val=convert_channel_8b(AILERON);
|
||||
if(val>127+FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 1:0xFF;
|
||||
else if(val<127-FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 2:0x00;
|
||||
else
|
||||
packet[offset] = sub_protocol == FX816 ? 0:0x7F;
|
||||
packet[offset+1] = convert_channel_16b_limit(THROTTLE,0,100); //FX816:0x00..0x63, FX620:0x00..0x5E but that should work
|
||||
}
|
||||
|
||||
//Bind and specifics
|
||||
if(sub_protocol == FX816)
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
packet[0] = 0x55;
|
||||
else
|
||||
packet[0] = 0xAA;
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
}
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
memcpy(packet,rx_tx_addr,3);
|
||||
packet[3] = hopping_frequency[0];
|
||||
if(bind_counter > (FX_BIND_COUNT >> 1))
|
||||
packet[5] = 0x78;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0] = 0x1F; // Is it based on ID??
|
||||
packet[5] = 0xAB; // Is it based on ID??
|
||||
}
|
||||
}
|
||||
else // FX9630
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
memcpy(packet,rx_tx_addr, 4);
|
||||
packet[4] = hopping_frequency[1];
|
||||
packet[5] = hopping_frequency[2];
|
||||
packet[7] = 0x55;
|
||||
}
|
||||
}
|
||||
|
||||
//Check
|
||||
uint8_t last_packet_idx = packet_length-1;
|
||||
if (sub_protocol == FX9630 && IS_BIND_IN_PROGRESS)
|
||||
last_packet_idx--;
|
||||
val=0;
|
||||
for(uint8_t i=0;i<last_packet_idx;i++)
|
||||
val+=packet[i];
|
||||
if (sub_protocol == FX9630)
|
||||
val = val ^ 0xFF;
|
||||
packet[last_packet_idx]=val;
|
||||
|
||||
//Debug
|
||||
#if 0
|
||||
for(uint8_t i=0;i<packet_length;i++)
|
||||
debug("%02X ",packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, packet_length);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX_RF_init()
|
||||
{
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
if(sub_protocol == FX816)
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
|
||||
XN297_RFChannel(FX816_BIND_CHANNEL);
|
||||
packet_period = FX816_PACKET_PERIOD;
|
||||
packet_length = FX816_PAYLOAD_SIZE;
|
||||
}
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\xaa\xbb\xcc", 3);
|
||||
XN297_RFChannel(FX620_BIND_CHANNEL);
|
||||
packet_period = FX620_BIND_PACKET_PERIOD;
|
||||
packet_length = FX620_PAYLOAD_SIZE;
|
||||
}
|
||||
else // FX9630
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\x56\x78\x90\x12", 4);
|
||||
XN297_RFChannel(FX9630_BIND_CHANNEL);
|
||||
packet_period = FX9630_BIND_PACKET_PERIOD;
|
||||
packet_length = FX9630_PAYLOAD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX_initialize_txid()
|
||||
{
|
||||
if(sub_protocol == FX816)
|
||||
{
|
||||
//Only 8 IDs: the RX led does not indicate frame loss.
|
||||
//I didn't open the plane to find out if I could connect there so this is the best I came up with with few trial and errors...
|
||||
rx_tx_addr[0]=0x35+(rx_tx_addr[3]&0x07); //Original dump=0x35
|
||||
rx_tx_addr[1]=0x09; //Original dump=0x09
|
||||
memcpy(hopping_frequency,"\x09\x1B\x30\x42",FX_NUM_CHANNELS); //Original dump=9=0x09,27=0x1B,48=0x30,66=0x42
|
||||
for(uint8_t i=0;i<FX_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
|
||||
}
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
rx_tx_addr[0] = rx_tx_addr[3];
|
||||
hopping_frequency[0] = 0x18 + rx_tx_addr[3]&0x07; // just to try something
|
||||
#ifdef FORCE_FX620_ID
|
||||
memcpy(rx_tx_addr,(uint8_t*)"\x34\xA9\x32",3);
|
||||
hopping_frequency[0] = 0x18; //on dump: 24 34 44 54
|
||||
#endif
|
||||
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i] = i*10 + hopping_frequency[0];
|
||||
}
|
||||
else // FX9630
|
||||
{
|
||||
#ifdef FORCE_FX9630_ID
|
||||
memcpy(rx_tx_addr,(uint8_t*)"\xCE\x31\x9B\x73", 4);
|
||||
memcpy(hopping_frequency,"\x13\x1A\x38", FX9630_NUM_CHANNELS); //Original dump=19=0x13,26=0x1A,56=0x38
|
||||
#else
|
||||
hopping_frequency[0] = 0x13; // constant
|
||||
hopping_frequency[1] = RX_num & 0x0F + 0x1A;
|
||||
hopping_frequency[2] = rx_tx_addr[3] & 0x0F + 0x38;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t FX_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
if(bind_counter)
|
||||
if(--bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
if(sub_protocol == FX620)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, 3);
|
||||
packet_period = FX620_PACKET_PERIOD;
|
||||
}
|
||||
}
|
||||
FX_send_packet();
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
void FX_init()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
FX_initialize_txid();
|
||||
FX_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter=FX_BIND_COUNT;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -88,34 +88,25 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FY326_init()
|
||||
static void __attribute__((unused)) FY326_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
if(sub_protocol==FY319)
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // Five-byte rx/tx address
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x15\x59\x23\xc6\x29", 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x15\x59\x23\xc6\x29", 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 Acknowledgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, FY326_PACKET_SIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, FY326_RF_BIND_CHANNEL);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K);
|
||||
NRF24L01_SetPower();
|
||||
|
||||
NRF24L01_Activate(0x73);
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f);
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
|
||||
NRF24L01_Activate(0x73);
|
||||
|
||||
//Switch to RX
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
}
|
||||
|
||||
@@ -209,20 +200,19 @@ static void __attribute__((unused)) FY326_initialize_txid()
|
||||
hopping_frequency[i]=rx_tx_addr[0] & ~0x80;
|
||||
}
|
||||
|
||||
uint16_t initFY326(void)
|
||||
void FY326_init(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
rxid = 0xAA;
|
||||
bind_counter = FY326_BIND_COUNT;
|
||||
FY326_initialize_txid();
|
||||
FY326_init();
|
||||
FY326_RF_init();
|
||||
if(sub_protocol==FY319)
|
||||
{
|
||||
phase=FY319_BIND1;
|
||||
}
|
||||
else
|
||||
phase=FY326_BIND1;
|
||||
return FY326_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||