mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-11-25 13:29:40 +00:00
Compare commits
1433 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
541a96e7b4 | ||
|
|
5b234a9cbc | ||
|
|
24c3a62f3a | ||
|
|
23756a387a | ||
|
|
efbd350dfd | ||
|
|
072e95c84e | ||
|
|
4be26e7202 | ||
|
|
a616cbb95c | ||
|
|
8aea9aa3dd | ||
|
|
e4992bc917 | ||
|
|
000b3e97c7 | ||
|
|
cb91e19413 | ||
|
|
c72e690085 | ||
|
|
f1a4e659e7 | ||
|
|
0d56d17d52 | ||
|
|
96c89c8c97 | ||
|
|
7df5a1f211 | ||
|
|
8ae8e028c7 | ||
|
|
581ad5f8f4 | ||
|
|
977bae3750 | ||
|
|
8a0161607e | ||
|
|
cd6a7bfc3a | ||
|
|
4671700b7d | ||
|
|
840ca74407 | ||
|
|
0d8a7e46de | ||
|
|
8b9940b0f0 | ||
|
|
521b819b8a | ||
|
|
208e9ef64b | ||
|
|
a7ea8e012e | ||
|
|
d940a7e49a | ||
|
|
9d50171034 | ||
|
|
701a5b9e28 | ||
|
|
d11785ef2d | ||
|
|
f4a4d91ef8 | ||
|
|
9514e47ed3 | ||
|
|
9461f2d632 | ||
|
|
f6064d03e1 | ||
|
|
0d917e0dc5 | ||
|
|
9408af8d08 | ||
|
|
862ab48bbc | ||
|
|
f498347c53 | ||
|
|
3f77f59c8a | ||
|
|
e96186015d | ||
|
|
1fa6e4526b | ||
|
|
3853d585a0 | ||
|
|
e8c6225ef0 | ||
|
|
17c67cc780 | ||
|
|
dcc4236833 | ||
|
|
6a7c735924 | ||
|
|
3c40cd853e | ||
|
|
5357660b68 | ||
|
|
a15a911f8e | ||
|
|
ded0487ce6 | ||
|
|
e7b079ece7 | ||
|
|
0cbe4de920 | ||
|
|
5c3bf30fe7 | ||
|
|
56b8694fd5 | ||
|
|
c9fecafada | ||
|
|
f3ca7ad644 | ||
|
|
c3b48c78af | ||
|
|
18dcc29a0d | ||
|
|
c3a5c263d3 | ||
|
|
ccdf60d525 | ||
|
|
443e1cec75 | ||
|
|
aa540514b8 | ||
|
|
fda7e2e5b6 | ||
|
|
fb4d5cf437 | ||
|
|
9fc2898a56 | ||
|
|
2e24323adf | ||
|
|
77abc1ed7c | ||
|
|
259d550d04 | ||
|
|
1a8f9c5a12 | ||
|
|
1916eb3095 | ||
|
|
fc3eec7ae1 | ||
|
|
8d10c9b004 | ||
|
|
511f77f5e7 | ||
|
|
a58d7a4d79 | ||
|
|
6748f6ce78 | ||
|
|
2dcb6b1987 | ||
|
|
2b4ac41142 | ||
|
|
2b47958207 | ||
|
|
5538d4d1c4 | ||
|
|
467756df48 | ||
|
|
534ebb26c0 | ||
|
|
21790a9725 | ||
|
|
6bc22c8ac4 | ||
|
|
ac1c422f14 | ||
|
|
efa1860104 | ||
|
|
c673b4254f | ||
|
|
96db173694 | ||
|
|
1d5be624fe | ||
|
|
56f9672896 | ||
|
|
303b3f08b8 | ||
|
|
150e3fd92e | ||
|
|
840b01273c | ||
|
|
8a7beda339 | ||
|
|
65606f7083 | ||
|
|
0095071ebf | ||
|
|
ae4ee9061d | ||
|
|
6ba06bc006 | ||
|
|
00f247eae1 | ||
|
|
c250c91ab4 | ||
|
|
b1ac10a4c4 | ||
|
|
af4185fbea | ||
|
|
aa85d4d797 | ||
|
|
74cc63e6dd | ||
|
|
04ed613ca3 | ||
|
|
9ea157b9b6 | ||
|
|
536d7f6124 | ||
|
|
869a01b57f | ||
|
|
ea982b23c2 | ||
|
|
15dfe8cead | ||
|
|
b50027150e | ||
|
|
103acb8294 | ||
|
|
aca23b8bca | ||
|
|
aaffbbc5be | ||
|
|
e0002c9488 | ||
|
|
687d6d914c | ||
|
|
9a61b2701e | ||
|
|
d8224ebefe | ||
|
|
cc2af73a05 | ||
|
|
aecd44ada6 | ||
|
|
72593c4d99 | ||
|
|
52ca258616 | ||
|
|
04412667ff | ||
|
|
4124ec80ec | ||
|
|
693ea75e95 | ||
|
|
9e3c1ab059 | ||
|
|
5fc860702f | ||
|
|
6ad2ee5a47 | ||
|
|
b0f64297cb | ||
|
|
f99a63dbc0 | ||
|
|
9261e8fe94 | ||
|
|
52bb116e24 | ||
|
|
7006c36101 | ||
|
|
f7d452e3f1 | ||
|
|
598e50a40f | ||
|
|
eadfa26c3b | ||
|
|
b03491fdf7 | ||
|
|
42911c63b3 | ||
|
|
43462757ed | ||
|
|
0eee1c5d15 | ||
|
|
3a21bf69f1 | ||
|
|
7d4c8f7f07 | ||
|
|
866d19d649 | ||
|
|
c27ec2475c | ||
|
|
1d64cbfaa0 | ||
|
|
5d1baa89e4 | ||
|
|
e846ce7e98 | ||
|
|
300b3582a6 | ||
|
|
3a7ffe62b0 | ||
|
|
d990ebe49e | ||
|
|
bd78739217 | ||
|
|
6c7312a09c | ||
|
|
1525e564cb | ||
|
|
7fb4bbbf3c | ||
|
|
2553d44d32 | ||
|
|
dc902b7a61 | ||
|
|
b992cbd92e | ||
|
|
22711fad28 | ||
|
|
a9df0abed3 | ||
|
|
fd65550f8d | ||
|
|
b910ad3386 | ||
|
|
fb9f094365 | ||
|
|
05470446a0 | ||
|
|
903982afb7 | ||
|
|
8bea5b125b | ||
|
|
c658a892f2 | ||
|
|
3f0d6cfcf1 | ||
|
|
c6657c199c | ||
|
|
cf6d980b8b | ||
|
|
c3ff49e86e | ||
|
|
e51f91f041 | ||
|
|
2589c67f6c | ||
|
|
2f4f19b52b | ||
|
|
b3ed7563dc | ||
|
|
ea96c328fc | ||
|
|
f42da14413 | ||
|
|
2149149723 | ||
|
|
f1916b3d0b | ||
|
|
10788976b6 | ||
|
|
567d26a385 | ||
|
|
220eb8f6f4 | ||
|
|
b40e7d6e97 | ||
|
|
97dd90a718 | ||
|
|
75ba6401a4 | ||
|
|
5cf8d8d263 | ||
|
|
058e09c413 | ||
|
|
63fb1b1f36 | ||
|
|
7c0b9ce3c6 | ||
|
|
c153d236f2 | ||
|
|
3b3a3c275c | ||
|
|
f4691d08cc | ||
|
|
e5d9471b33 | ||
|
|
ab9525c507 | ||
|
|
b1fb3a5470 | ||
|
|
b2194790eb | ||
|
|
8901310ed4 | ||
|
|
09c6adaa95 | ||
|
|
5fe1e9674e | ||
|
|
601116bd59 | ||
|
|
27dc02fdec | ||
|
|
03f417546e | ||
|
|
3b9aa79201 | ||
|
|
5aa4936c0e | ||
|
|
1e65d58113 | ||
|
|
e2a66bdd1f | ||
|
|
4f9c30505a | ||
|
|
1ec817c96c | ||
|
|
41528ae7b6 | ||
|
|
77d248df0b | ||
|
|
c6cb13b332 | ||
|
|
d67108fa8b | ||
|
|
b7447f055a | ||
|
|
3902ed19b7 | ||
|
|
51ba7cf75c | ||
|
|
82fb5dd0da | ||
|
|
2ac20cb575 | ||
|
|
3f33e5b2a8 | ||
|
|
655ea98bf1 | ||
|
|
238260612c | ||
|
|
cd26c2d8e6 | ||
|
|
814e28b86a | ||
|
|
f515ba79af | ||
|
|
e6f16700e4 | ||
|
|
f38e7c35da | ||
|
|
b3576b7162 | ||
|
|
d9914e95d9 | ||
|
|
64c79626b4 | ||
|
|
e047a76855 | ||
|
|
e7449897f9 | ||
|
|
db093cf25b | ||
|
|
4bb4bd9792 | ||
|
|
c16654c8cf | ||
|
|
817ff7e239 | ||
|
|
685de52538 | ||
|
|
1dc52773f4 | ||
|
|
fbb04ea88a | ||
|
|
23da318645 | ||
|
|
30b77931d7 | ||
|
|
39327b2b27 | ||
|
|
13c3af96a6 | ||
|
|
4411732022 | ||
|
|
0c08b8b93b | ||
|
|
838755aabf | ||
|
|
2bca104e33 | ||
|
|
cf857f3256 | ||
|
|
1647d3d841 | ||
|
|
2f5252ab88 | ||
|
|
eb89b5be1b | ||
|
|
e80fe29dba | ||
|
|
74ab2a4bd7 | ||
|
|
edd4f740e0 | ||
|
|
d0c9bc801b | ||
|
|
73dd63caa1 | ||
|
|
cc4703ea40 | ||
|
|
f105d7c7eb | ||
|
|
e85ad00a46 | ||
|
|
658dfa4290 | ||
|
|
df75036501 | ||
|
|
9ab5353122 | ||
|
|
5345ece322 | ||
|
|
9f09c81ef4 | ||
|
|
c8dea20865 | ||
|
|
bf09177916 | ||
|
|
d71640ad7e | ||
|
|
68afcc0c44 | ||
|
|
9b30a3d72a | ||
|
|
789cd21618 | ||
|
|
d9f343e20b | ||
|
|
0b8ff15133 | ||
|
|
27a4748111 | ||
|
|
18efaef38c | ||
|
|
35137b87ed | ||
|
|
9019c46102 | ||
|
|
52d0869c50 | ||
|
|
236b375669 | ||
|
|
9502b5a12a | ||
|
|
ad18856f7a | ||
|
|
9015b78aaf | ||
|
|
8cc7a4f693 | ||
|
|
ac298fee61 | ||
|
|
457fc5296e | ||
|
|
b8f3cd1ad8 | ||
|
|
f9f265271a | ||
|
|
dde5f6e119 | ||
|
|
add3fb13ef | ||
|
|
51c1936c24 | ||
|
|
07adeaf60d | ||
|
|
811913bf89 | ||
|
|
8906c85d06 | ||
|
|
7df5894ca4 | ||
|
|
fa9e559195 | ||
|
|
81f408ee77 | ||
|
|
aa8a059553 | ||
|
|
8c7918577d | ||
|
|
7219885196 | ||
|
|
9f8915239f | ||
|
|
83401f6e1a | ||
|
|
dd686ad9d1 | ||
|
|
7d04005c72 | ||
|
|
cdbaeb1c6c | ||
|
|
6bf432a112 | ||
|
|
f6ef136502 | ||
|
|
4a9d295f1a | ||
|
|
105e0bb7a4 | ||
|
|
ab27ee50b0 | ||
|
|
f4a4f67453 | ||
|
|
fb88eebc2f | ||
|
|
6fea0c2a93 | ||
|
|
301c8da9eb | ||
|
|
4facdf0932 | ||
|
|
ce489887db | ||
|
|
55e30bd4aa | ||
|
|
eb0d03d420 | ||
|
|
db1da2d9cf | ||
|
|
6fa3b8597f | ||
|
|
c8da89f0d3 | ||
|
|
c3c89801e9 | ||
|
|
eb3f8b0d91 | ||
|
|
d3285f002e | ||
|
|
e81ee38fa5 | ||
|
|
499e854275 | ||
|
|
cd235bbcde | ||
|
|
984aa3f413 | ||
|
|
11287cb9c0 | ||
|
|
5cc49a8862 | ||
|
|
fabda76e98 | ||
|
|
70db505dd9 | ||
|
|
29fd1c800b | ||
|
|
d70d8f62a4 | ||
|
|
bef562964d | ||
|
|
fc5495b6d1 | ||
|
|
f3838ae4b0 | ||
|
|
b3eccf55ba | ||
|
|
835cc3d0a2 | ||
|
|
b49584ec16 | ||
|
|
334e49c4ca | ||
|
|
3fc5be111b | ||
|
|
1bc2dd2964 | ||
|
|
68dcc75949 | ||
|
|
dc9f738f30 | ||
|
|
4171d2f93b | ||
|
|
64fb90960b | ||
|
|
93e277bb0f | ||
|
|
337216efac | ||
|
|
f1f5b68821 | ||
|
|
8f941e6d12 | ||
|
|
6a4dcbd6e1 | ||
|
|
7e773dfe1b | ||
|
|
465ae75ffc | ||
|
|
8da03940e8 | ||
|
|
f280779528 | ||
|
|
5c568da125 | ||
|
|
f46b8366b0 | ||
|
|
1d9c052c01 | ||
|
|
544927b9b7 | ||
|
|
8b5bb0d358 | ||
|
|
6031f1e3b8 | ||
|
|
c297df76ef | ||
|
|
122e9f4fca | ||
|
|
748ed01252 | ||
|
|
56188328fb | ||
|
|
880e463b01 | ||
|
|
a53046bf12 | ||
|
|
a8050fd8a1 | ||
|
|
6ae819e8d5 | ||
|
|
79c73444ab | ||
|
|
8cc1b07456 | ||
|
|
0d43614ac3 | ||
|
|
19f879da7f | ||
|
|
ed42bf311f | ||
|
|
fd4346cb64 | ||
|
|
6e458ebd4a | ||
|
|
0f0be60245 | ||
|
|
27783677c2 | ||
|
|
4418cab3a5 | ||
|
|
b3cddfe2d4 | ||
|
|
a19ac87a04 | ||
|
|
3ba951fd91 | ||
|
|
824f23c3d6 | ||
|
|
fc49a32008 | ||
|
|
5ca0d31606 | ||
|
|
ebd44d9628 | ||
|
|
329fa1c2a5 | ||
|
|
9a5bf7999b | ||
|
|
7debad6c67 | ||
|
|
dc9b84ea8b | ||
|
|
199c254838 | ||
|
|
7ff482dafe | ||
|
|
9376019198 | ||
|
|
cec654a75b | ||
|
|
3e004d01ec | ||
|
|
21266d0a17 | ||
|
|
2b62b8dab3 | ||
|
|
b24564ffe9 | ||
|
|
f57d436640 | ||
|
|
762613bd7f | ||
|
|
e2ed752b51 | ||
|
|
2610926f47 | ||
|
|
cf1a74e532 | ||
|
|
f55b451d9b | ||
|
|
ae51e389ca | ||
|
|
6f71ef1d03 | ||
|
|
94a9e4db05 | ||
|
|
82dc0c4f32 | ||
|
|
bb5827629e | ||
|
|
76f7cb7126 | ||
|
|
d5005323d4 | ||
|
|
9bc1a9963f | ||
|
|
cefbf2ee70 | ||
|
|
e10dc6dcec | ||
|
|
e4f4d278a8 | ||
|
|
3dd9df558e | ||
|
|
87c2216d0f | ||
|
|
8cd5ff6bd6 | ||
|
|
28868e4c78 | ||
|
|
01bef23ac9 | ||
|
|
9379bd1792 | ||
|
|
63a479b6b6 | ||
|
|
49b0d92c75 | ||
|
|
277402a25d | ||
|
|
cc83177542 | ||
|
|
5a342cf8e6 | ||
|
|
7d5dabde82 | ||
|
|
e3917226cc | ||
|
|
4e3c1edd52 | ||
|
|
e52b7ea7ff | ||
|
|
6f60d87f85 | ||
|
|
049db615e3 | ||
|
|
e557155b17 | ||
|
|
9bf5b0c9a7 | ||
|
|
ea860f24a1 | ||
|
|
5e89d49bd9 | ||
|
|
cb1ba0e00c | ||
|
|
0f965b6800 | ||
|
|
486c2170cd | ||
|
|
83641a4f54 | ||
|
|
5cb2326ea7 | ||
|
|
84d7986353 | ||
|
|
a3c2628359 | ||
|
|
8ae34bdd9d | ||
|
|
4a9374936d | ||
|
|
110378e3b4 | ||
|
|
bd60feff60 | ||
|
|
2181d0b33c | ||
|
|
2afa7ea691 | ||
|
|
d0f76117cd | ||
|
|
e25060a16e | ||
|
|
5e6da326f6 | ||
|
|
981a8f8d2c | ||
|
|
5c7e592e1e | ||
|
|
2a25f76b56 | ||
|
|
41d579dc23 | ||
|
|
7d41017850 | ||
|
|
daeba0d43a | ||
|
|
24fd5ba361 | ||
|
|
3353637c8f | ||
|
|
9601e6942d | ||
|
|
4b32a93f27 | ||
|
|
9e8978166e | ||
|
|
6bf873f4db | ||
|
|
1318f1a29b | ||
|
|
d9282ac750 | ||
|
|
205d728798 | ||
|
|
bd9c772a52 | ||
|
|
76e9002995 | ||
|
|
e990d44bb6 | ||
|
|
2ffa2d7b73 | ||
|
|
0e4583f8e2 | ||
|
|
3802722bb1 | ||
|
|
41f0a712fd | ||
|
|
4633c37380 | ||
|
|
b779becf8c | ||
|
|
35089febab | ||
|
|
a95fd1e1d8 | ||
|
|
6535f64699 | ||
|
|
b15a5d4a45 | ||
|
|
65a5c37ffb | ||
|
|
6cf58c032c | ||
|
|
e0365df6dd | ||
|
|
40ae0c7257 | ||
|
|
aecd4c5266 | ||
|
|
113caf4970 | ||
|
|
da2d57c8e9 | ||
|
|
3aed8b8479 | ||
|
|
ff58a826b1 | ||
|
|
9a0873e404 | ||
|
|
7d9133793c | ||
|
|
f43d9883cf | ||
|
|
067842818e | ||
|
|
8ea70a1b77 | ||
|
|
47207dcead | ||
|
|
235876a4d8 | ||
|
|
af88abb13f | ||
|
|
f13701b120 | ||
|
|
5f7c598a34 | ||
|
|
defd354286 | ||
|
|
f9e6b30550 | ||
|
|
d451af365a | ||
|
|
57a78535f2 | ||
|
|
f824ecb7f9 | ||
|
|
98f848138d | ||
|
|
200a1dc3da | ||
|
|
507e1d2b50 | ||
|
|
0f752e2571 | ||
|
|
ca6cd65d46 | ||
|
|
ddc287a84e | ||
|
|
c92ec031ae | ||
|
|
ef2d4d6b12 | ||
|
|
2753f6c4e5 | ||
|
|
021577d638 | ||
|
|
dd3f8b4717 | ||
|
|
a1fb4a0ac5 | ||
|
|
ebf0c4fae6 | ||
|
|
44a086a27b | ||
|
|
4624075112 | ||
|
|
97a3c8dca1 | ||
|
|
c50b5d93d7 | ||
|
|
08f9176f3f | ||
|
|
f95ca6eac6 | ||
|
|
34165c0d90 | ||
|
|
1f87cf09d7 | ||
|
|
005c7b9cb0 | ||
|
|
2b265bd1de | ||
|
|
3e83216384 | ||
|
|
a9889b5b79 | ||
|
|
2aa5b7917f | ||
|
|
040354501c | ||
|
|
bd46f6d25f | ||
|
|
7e801269af | ||
|
|
2586e2e661 | ||
|
|
fb2a5c2378 | ||
|
|
f490fa6e7d | ||
|
|
df347be672 | ||
|
|
4e518bf70c | ||
|
|
29e90246d2 | ||
|
|
1e62c0d836 | ||
|
|
278ebf4ff2 | ||
|
|
edc58a3496 | ||
|
|
7c96862b19 | ||
|
|
11b18f7468 | ||
|
|
86787b6099 | ||
|
|
12645c19aa | ||
|
|
7e06a57fd9 | ||
|
|
4d7c31cfa1 | ||
|
|
f5e4fc5a3d | ||
|
|
1c4174431e | ||
|
|
60d4f2d6c7 | ||
|
|
5a30a96c0c | ||
|
|
09b454ba6a | ||
|
|
8ea06e84a6 | ||
|
|
ebaf56d964 | ||
|
|
517d2bb1ec | ||
|
|
706d43ee41 | ||
|
|
e537d27e28 | ||
|
|
948f28b0af | ||
|
|
70f7c6a25e | ||
|
|
a0a0cd4f57 | ||
|
|
dfa120339c | ||
|
|
36f194b9bd | ||
|
|
12dd851fc3 | ||
|
|
cc9a5893de | ||
|
|
9d2ac3f2c4 | ||
|
|
9cda61de3d | ||
|
|
060d93d68b | ||
|
|
8d1e8c6699 | ||
|
|
f4865c5206 | ||
|
|
2d44c89149 | ||
|
|
c2050d4314 | ||
|
|
7991605106 | ||
|
|
adeea85c9a | ||
|
|
c32e390184 | ||
|
|
154f61fb11 | ||
|
|
b08bcf041b | ||
|
|
e51f6e1e86 | ||
|
|
62e2a0211f | ||
|
|
5286e7f89c | ||
|
|
e81ba55967 | ||
|
|
25a2689bd0 | ||
|
|
c949eb5491 | ||
|
|
709c5cbd71 | ||
|
|
3ac59a5bc0 | ||
|
|
6894228a63 | ||
|
|
a7b914b84e | ||
|
|
84922e84a3 | ||
|
|
7ee0b2b0a3 | ||
|
|
5c06a241ac | ||
|
|
0cb0128caf | ||
|
|
8661b8074c | ||
|
|
fa52a1a81e | ||
|
|
680fa7a350 | ||
|
|
3850ce88d3 | ||
|
|
a800f1efc7 | ||
|
|
514bbbe8a3 | ||
|
|
700b922350 | ||
|
|
bdfeeb9a41 | ||
|
|
2b80d1a6d8 | ||
|
|
fa6f2061e7 | ||
|
|
ff5f12e4d2 | ||
|
|
9ad6e8142d | ||
|
|
49e3534738 | ||
|
|
4cb7ba83e9 | ||
|
|
9282828ffc | ||
|
|
2f2a2d4bee | ||
|
|
b904e6a889 | ||
|
|
804d5723c2 | ||
|
|
681e3a6865 | ||
|
|
dd75c56404 | ||
|
|
86cee1e339 | ||
|
|
063edc032a | ||
|
|
32c59cb583 | ||
|
|
0242f88d26 | ||
|
|
940a89fa38 | ||
|
|
364a66ad0b | ||
|
|
f714315b0d | ||
|
|
ed83471a13 | ||
|
|
1263aa7884 | ||
|
|
c21afc3f8a | ||
|
|
59af0594dc | ||
|
|
8cf6d4f7d8 | ||
|
|
61ceeb44fb | ||
|
|
995bb921c1 | ||
|
|
e7cab78aad | ||
|
|
1c06bd45ef | ||
|
|
85a3e112e0 | ||
|
|
9c5e054dda | ||
|
|
86932e6da4 | ||
|
|
5f94fdfc93 | ||
|
|
74584dd39e | ||
|
|
18ed5d51a9 | ||
|
|
d7076f5295 | ||
|
|
29a5397491 | ||
|
|
47a4261631 | ||
|
|
a3927218a6 | ||
|
|
7d846a3d0d | ||
|
|
8db1f6d1e2 | ||
|
|
9cb679d545 | ||
|
|
006d705cbd | ||
|
|
a19a14665f | ||
|
|
55bc6f9a00 | ||
|
|
997d31addd | ||
|
|
548390b0d7 | ||
|
|
bd64bdedc3 | ||
|
|
846e09c7cb | ||
|
|
2ba3552578 | ||
|
|
943bb6d15b | ||
|
|
af53e75ae4 | ||
|
|
14ca63571d | ||
|
|
10c5ce68f5 | ||
|
|
d9fb856eb8 | ||
|
|
f5c08158cb | ||
|
|
9ee0311ea9 | ||
|
|
69ed2d2428 | ||
|
|
0c5fae01b5 | ||
|
|
72052925a6 | ||
|
|
dc2d02bf32 | ||
|
|
ee267ea086 | ||
|
|
1e730f3376 | ||
|
|
c230c52af6 | ||
|
|
219beb4a0e | ||
|
|
c4807c44f3 | ||
|
|
7dafd14644 | ||
|
|
57c3e8c51d | ||
|
|
da71eca978 | ||
|
|
7a47af14be | ||
|
|
f67adc53ab | ||
|
|
68e9948493 | ||
|
|
894416c719 | ||
|
|
11650450c8 | ||
|
|
6973d85b10 | ||
|
|
bf5598515e | ||
|
|
cc03c27d17 | ||
|
|
9cd729df71 | ||
|
|
d6ee9fbfac | ||
|
|
b6999f5c67 | ||
|
|
c02f273d57 | ||
|
|
8d87bfb4a3 | ||
|
|
0a7cd3d6e9 | ||
|
|
235699b3b9 | ||
|
|
1aebfbecc1 | ||
|
|
00e47b9afb | ||
|
|
68b94cfcaa | ||
|
|
0068f21a2d | ||
|
|
7a7e639490 | ||
|
|
81bae1441e | ||
|
|
3516e5ae8a | ||
|
|
04bbe3187f | ||
|
|
877cdec4ea | ||
|
|
21ab94c512 | ||
|
|
70f52afb3d | ||
|
|
85f4dbd670 | ||
|
|
bee70e67bc | ||
|
|
7e137f17a5 | ||
|
|
c576f62ca3 | ||
|
|
9c8499e6cd | ||
|
|
f81e7cb78a | ||
|
|
773f3048f7 | ||
|
|
40faaea7f8 | ||
|
|
47b4409f3e | ||
|
|
9ce23c3d61 | ||
|
|
f40ffed069 | ||
|
|
0b223170d9 | ||
|
|
e61f8a512c | ||
|
|
65b43c39ed | ||
|
|
131645f31e | ||
|
|
ca8fc14d36 | ||
|
|
efe693c0c0 | ||
|
|
4eb2d073ac | ||
|
|
fd49c02e18 | ||
|
|
f0e3d492d3 | ||
|
|
3f8ba6be9d | ||
|
|
df4563379d | ||
|
|
f0f9d8faa7 | ||
|
|
031b4b637a | ||
|
|
e206ae3403 | ||
|
|
021c463d80 | ||
|
|
41d75da33f | ||
|
|
c7e7a559a6 | ||
|
|
4f5dfcc65b | ||
|
|
e85208110f | ||
|
|
17bb2f11e4 | ||
|
|
124db5f11f | ||
|
|
6b099d7298 | ||
|
|
7ac2e227b1 | ||
|
|
868c1aa251 | ||
|
|
7283fc89a5 | ||
|
|
f933560934 | ||
|
|
7ee918ad49 | ||
|
|
e30ebd39fd | ||
|
|
7ac6ff828c | ||
|
|
017f5f8e74 | ||
|
|
2c46feb8f8 | ||
|
|
f5171f3f47 | ||
|
|
1a2c28435a | ||
|
|
7221fc2060 | ||
|
|
e17e7ab4ec | ||
|
|
46eb0bc474 | ||
|
|
b03227ea9f | ||
|
|
a1de5e15c5 | ||
|
|
7f2322ba60 | ||
|
|
5c04844461 | ||
|
|
591a185fc2 | ||
|
|
fbc0b60b68 | ||
|
|
325ce8824e | ||
|
|
d54e25bb44 | ||
|
|
740943aee2 | ||
|
|
73ee93335b | ||
|
|
c69c3361ac | ||
|
|
a91d019738 | ||
|
|
dc272a472d | ||
|
|
b265108322 | ||
|
|
6cab6a9646 | ||
|
|
3baf237fa8 | ||
|
|
fa8503546e | ||
|
|
b9d988c712 | ||
|
|
2bbf672094 | ||
|
|
a6f8fe4c95 | ||
|
|
6d7415880a | ||
|
|
479e4588f3 | ||
|
|
821f1bdc2b | ||
|
|
5cdd672e84 | ||
|
|
48fb8d0b92 | ||
|
|
52fae655ba | ||
|
|
3ab6e84275 | ||
|
|
2b5ab6db11 | ||
|
|
a0f6d47153 | ||
|
|
787901ba73 | ||
|
|
37c7167128 | ||
|
|
35e1ddc578 | ||
|
|
d61e7b8729 | ||
|
|
8ef73f9dd2 | ||
|
|
f7448cc2e4 | ||
|
|
6af35b5ec5 | ||
|
|
8f4e5c6064 | ||
|
|
2d76775e40 | ||
|
|
8eb71cbe74 | ||
|
|
9146a8bb21 | ||
|
|
445bca7333 | ||
|
|
6286551ef5 | ||
|
|
1ae6a69c7a | ||
|
|
34851b772f | ||
|
|
4823aa378e | ||
|
|
40a42e86ee | ||
|
|
c518b52243 | ||
|
|
abccc3c3cd | ||
|
|
9786b7139e | ||
|
|
28e8e3434e | ||
|
|
cdf59fba10 | ||
|
|
be8571cb56 | ||
|
|
857715e55c | ||
|
|
5ccc815a47 | ||
|
|
d77c04109b | ||
|
|
1ba8b8b1b1 | ||
|
|
caa349b59b | ||
|
|
9a7350149d | ||
|
|
7f435363f7 | ||
|
|
832cb79f88 | ||
|
|
ba7290fdda | ||
|
|
85ee4a95ec | ||
|
|
eb164c511f | ||
|
|
26e3119ef3 | ||
|
|
6c38b54f7d | ||
|
|
7e6badaf5d | ||
|
|
c104e8e1f0 | ||
|
|
c8d04f3373 | ||
|
|
f64f417711 | ||
|
|
92fe975e3d | ||
|
|
e00731ef8f | ||
|
|
0d7d0664f6 | ||
|
|
b59b0ef041 | ||
|
|
964aa0ecce | ||
|
|
a9ecf06cd4 | ||
|
|
76da6857e7 | ||
|
|
9eef60c93d | ||
|
|
df412bbef7 | ||
|
|
b4c6632162 | ||
|
|
5f2eb6bd32 | ||
|
|
ea532b15fc | ||
|
|
01bd1fde39 | ||
|
|
c6c1c61ff6 | ||
|
|
bbd33c70c1 | ||
|
|
a2592342fe | ||
|
|
db06e12337 | ||
|
|
22139c9650 | ||
|
|
3b1e2e38fb | ||
|
|
6f6da47ebe | ||
|
|
f3237172f3 | ||
|
|
45dc64af5a | ||
|
|
4df71bff7f | ||
|
|
f5003d3505 | ||
|
|
f2f3fab3e2 | ||
|
|
2357e139f0 | ||
|
|
c74eaa47a3 | ||
|
|
591f9fa4c2 | ||
|
|
766ffa3e65 | ||
|
|
78d2c7beaa | ||
|
|
f11c38238a | ||
|
|
6d388d50ee | ||
|
|
9479254562 | ||
|
|
9c9fdaf35d | ||
|
|
a4767591ae | ||
|
|
ecbc50b990 | ||
|
|
dde9cc27d0 | ||
|
|
703c03e84b | ||
|
|
2f831b3e6f | ||
|
|
d54eec0b87 | ||
|
|
bc80554cd3 | ||
|
|
a696d330e5 | ||
|
|
b1479ab3c5 | ||
|
|
e51fb06ceb | ||
|
|
dc0f2bde6b | ||
|
|
eb13f267fe | ||
|
|
8677e73d75 | ||
|
|
fbb919d767 | ||
|
|
1f0f9a2eae | ||
|
|
282b2a0a43 | ||
|
|
6d0e4d5a38 | ||
|
|
43956bbf2c | ||
|
|
18e31b3821 | ||
|
|
0d0acb9d10 | ||
|
|
6a792ce6a0 | ||
|
|
917cea5052 | ||
|
|
c98f0d3c81 | ||
|
|
88d650e638 | ||
|
|
72ebe937fb | ||
|
|
8efa5bc1dc | ||
|
|
9b6d2bce58 | ||
|
|
7bb26a7f07 | ||
|
|
9585b3919a | ||
|
|
f56c9deb00 | ||
|
|
c6221fc60f | ||
|
|
acfe3e912e | ||
|
|
50be0ebe3c | ||
|
|
704dc803b8 | ||
|
|
e2d64e9140 | ||
|
|
bdef0612f7 | ||
|
|
a196b71d36 | ||
|
|
fff8116430 | ||
|
|
2be6fb13d2 | ||
|
|
faa6d7f148 | ||
|
|
982fc2838d | ||
|
|
a8351319f8 | ||
|
|
5b1901708c | ||
|
|
fa8d4f511f | ||
|
|
b4215afe82 | ||
|
|
2ad25e8fbc | ||
|
|
67d0e9d2c2 | ||
|
|
f69aae550f | ||
|
|
2d26acd991 | ||
|
|
8dec1453c4 | ||
|
|
241d1e181f | ||
|
|
f267c597e0 | ||
|
|
192437896d | ||
|
|
d59ae7fce1 | ||
|
|
18b21005f1 | ||
|
|
94ac91cce3 | ||
|
|
46e255bccc | ||
|
|
87de5b5305 | ||
|
|
1ddc923631 | ||
|
|
03f65606fd | ||
|
|
148cf9552b | ||
|
|
bf230322d0 | ||
|
|
758779a8f5 | ||
|
|
55eb39c51d | ||
|
|
13b8475c54 | ||
|
|
d3d52b44ee | ||
|
|
d2886432b7 | ||
|
|
7bb8737ff9 | ||
|
|
3904c36a6e | ||
|
|
c2577df6f7 | ||
|
|
36cb0fb4cd | ||
|
|
ec79793f3d | ||
|
|
188bf76ed1 | ||
|
|
e4e909737c | ||
|
|
d32421c583 | ||
|
|
63cbcdc3ea | ||
|
|
dfd8d0fa3d | ||
|
|
7d7ca11c81 | ||
|
|
ee50a31bba | ||
|
|
179930ad80 | ||
|
|
fdb02da5ed | ||
|
|
5499beb510 | ||
|
|
96046d2ee2 | ||
|
|
a35a209066 | ||
|
|
8139c33b86 | ||
|
|
da40562ee3 | ||
|
|
ce478583ab | ||
|
|
6215af0e5a | ||
|
|
8f0ecac842 | ||
|
|
54dd562d88 | ||
|
|
c24f7a86d4 | ||
|
|
d6b4437664 | ||
|
|
68e74b9830 | ||
|
|
3fa40b2303 | ||
|
|
5feb73c65b | ||
|
|
33d676e1fe | ||
|
|
afb7af287b | ||
|
|
d6291a4c47 | ||
|
|
7228b84bf8 | ||
|
|
2dbf8ebb65 | ||
|
|
2d90844239 | ||
|
|
bf6e66ea47 | ||
|
|
5edaa6ec29 | ||
|
|
881ca67f80 | ||
|
|
1c0ed2a2c1 | ||
|
|
245d27ea71 | ||
|
|
f14d4b8ac3 | ||
|
|
fdc867b9d5 | ||
|
|
8e876d6a99 | ||
|
|
c9de0b4cf2 | ||
|
|
27b3a86155 | ||
|
|
683bdc838d | ||
|
|
4f9f10ddf2 | ||
|
|
6fe3f90a26 | ||
|
|
5bdb7eee85 | ||
|
|
34262a45ca | ||
|
|
7c22110c96 | ||
|
|
6ad9fb8f27 | ||
|
|
4348f4b0d4 | ||
|
|
22529e28d8 | ||
|
|
aa52bcee8c | ||
|
|
d731ab3682 | ||
|
|
7840438bfc | ||
|
|
455a2dba8a | ||
|
|
01c310c913 | ||
|
|
a679d6f2e1 | ||
|
|
e8af56bdbe | ||
|
|
efa099ac5b | ||
|
|
81181aa7e6 | ||
|
|
1ab6640983 | ||
|
|
e5636cde05 | ||
|
|
0a0d00b26e | ||
|
|
6c9afcff81 | ||
|
|
b7933b282b | ||
|
|
653c34758b | ||
|
|
9d18ab795e | ||
|
|
a5c06c67bc | ||
|
|
db2f790bf7 | ||
|
|
5cbc6b5f6a | ||
|
|
f7ecf40633 | ||
|
|
6cd83c60ef | ||
|
|
90ffce63e5 | ||
|
|
2910ebc0fd | ||
|
|
02fab95637 | ||
|
|
22d2209a1b | ||
|
|
e2bea81c64 | ||
|
|
466b8bd1cc | ||
|
|
c5287d2869 | ||
|
|
010502ed9d | ||
|
|
be06e74d94 | ||
|
|
199d2cf851 | ||
|
|
deab1b4962 | ||
|
|
d04411e4a8 | ||
|
|
ce52b57a52 | ||
|
|
c760c19056 | ||
|
|
6b5e469b19 | ||
|
|
8663489ae4 | ||
|
|
877ef1d7ed | ||
|
|
6a81035f10 | ||
|
|
1f7276bbfd | ||
|
|
90e8490a85 | ||
|
|
38d51988d9 | ||
|
|
b8fccd1bac | ||
|
|
ded8e7b916 | ||
|
|
f56ca6318a | ||
|
|
5bd6ba4f36 | ||
|
|
909fb2eb2b | ||
|
|
b2209eaad0 | ||
|
|
dcae3c4acb | ||
|
|
3a3a2ec76d | ||
|
|
5e2ba192c1 | ||
|
|
6d4452bf94 | ||
|
|
998f9491f6 | ||
|
|
fa7efeb283 | ||
|
|
22206b6a99 | ||
|
|
34036ee355 | ||
|
|
2eb2d555ad | ||
|
|
722abf9cab | ||
|
|
357d3b8140 | ||
|
|
01ef79ac33 | ||
|
|
8d2456f238 | ||
|
|
bb164edb55 | ||
|
|
21117eaa17 | ||
|
|
573f823f48 | ||
|
|
47ca3b5d33 | ||
|
|
7334134b45 | ||
|
|
e6be594395 | ||
|
|
e2b6697362 | ||
|
|
f78e11057d | ||
|
|
314ee96525 | ||
|
|
efc1223d45 | ||
|
|
38d9aa4997 | ||
|
|
42c7431416 | ||
|
|
d1e40ee71c | ||
|
|
43169d8bab | ||
|
|
8cbbb52b95 | ||
|
|
807a55fcdc | ||
|
|
8c5351445b | ||
|
|
999c630c5a | ||
|
|
a0186ce8e4 | ||
|
|
9fe336d564 | ||
|
|
34a1d4e6b9 | ||
|
|
bafa548f2f | ||
|
|
fa709a9bdc | ||
|
|
2a1cc7e3ea | ||
|
|
68648b9920 | ||
|
|
b9f297935b | ||
|
|
eb6fc4f8cf | ||
|
|
8a177c34fa | ||
|
|
22a5f411d0 | ||
|
|
f557609e9e | ||
|
|
cde8deaf4b | ||
|
|
48eb1c6d67 | ||
|
|
4db741a87c | ||
|
|
3188ca6884 | ||
|
|
bb9cd171bf | ||
|
|
7a81638258 | ||
|
|
6519db1fe8 | ||
|
|
f313d319d4 | ||
|
|
a8c4e6fedc | ||
|
|
db16458cf5 | ||
|
|
38a9562eaf | ||
|
|
b2327e8bf7 | ||
|
|
aafef107ec | ||
|
|
4b442e75f7 | ||
|
|
e8f103799b | ||
|
|
618685dc05 | ||
|
|
f0d50e53fa | ||
|
|
1b4828f4fa | ||
|
|
56730d67a2 | ||
|
|
b02516b0b3 | ||
|
|
1eb32f86bd | ||
|
|
3b669e64e2 | ||
|
|
fbccd70f7d | ||
|
|
61e5231d99 | ||
|
|
5c101c5a85 | ||
|
|
a6e991923e | ||
|
|
f0c494ecea | ||
|
|
40dfdf9bb1 | ||
|
|
770e0f01f1 | ||
|
|
8448d3e516 | ||
|
|
292a11f942 | ||
|
|
6099986f5b | ||
|
|
53d18d8947 | ||
|
|
f77bdd233b | ||
|
|
dc25a1294c | ||
|
|
8f4bffa950 | ||
|
|
96195fa16a | ||
|
|
4e8a59ad4e | ||
|
|
e42ee6d6be | ||
|
|
f6a04a8b36 | ||
|
|
36b94b81ce | ||
|
|
d66e782152 | ||
|
|
d122d39d3a | ||
|
|
7c3053e8cd | ||
|
|
ecdfa61755 | ||
|
|
7321117c99 | ||
|
|
b50560eadf | ||
|
|
60841e6312 | ||
|
|
66cc61f967 | ||
|
|
1933f4bcc8 | ||
|
|
977f5ca9ce | ||
|
|
e5e529d3d2 | ||
|
|
e1f9d6091c | ||
|
|
a83d8064f2 | ||
|
|
9afb5e7272 | ||
|
|
4c7c2ccc74 | ||
|
|
a6d5686c1c | ||
|
|
8fa1b92deb | ||
|
|
f06e3643b6 | ||
|
|
cd8e59bc9c | ||
|
|
b6eeeea1ea | ||
|
|
aea642fcde | ||
|
|
27bec7ad05 | ||
|
|
80cb3458de | ||
|
|
615048df04 | ||
|
|
4e07b56f3e | ||
|
|
7d18da13a1 | ||
|
|
a49e9e346f | ||
|
|
87fd267183 | ||
|
|
c61fefb55f | ||
|
|
c644031041 | ||
|
|
79f0f52825 | ||
|
|
03ac62044b | ||
|
|
531bc0f887 | ||
|
|
af8b60ca29 | ||
|
|
80c14e9ebd | ||
|
|
3d658eff29 | ||
|
|
8a8a75aa79 | ||
|
|
ea3fe06613 | ||
|
|
92e7f6bd68 | ||
|
|
96b22a00ff | ||
|
|
cfddbc5b3f | ||
|
|
725009d719 | ||
|
|
7f7370f6db | ||
|
|
0fcc1316b2 | ||
|
|
e9933bebe7 | ||
|
|
9810081b11 | ||
|
|
6522d252cb | ||
|
|
a2867cffb7 | ||
|
|
e92c1b53a1 | ||
|
|
52aecb47e7 | ||
|
|
c4652d39fa | ||
|
|
c7b155ccac | ||
|
|
96d18535f8 | ||
|
|
98471e39e1 | ||
|
|
f55fc5776e | ||
|
|
f9a8d1cc40 | ||
|
|
e55a210cf9 | ||
|
|
d19d4406f6 | ||
|
|
9697331abb | ||
|
|
91db02f2da | ||
|
|
b933b30e0a | ||
|
|
2cb9a7c199 | ||
|
|
06ff17ebb2 | ||
|
|
44a573ecd5 | ||
|
|
ffa7952fc1 | ||
|
|
701514a168 | ||
|
|
1565bc9e1a | ||
|
|
0681bad8e6 | ||
|
|
23a21bb39f | ||
|
|
9aabb575c1 | ||
|
|
cf607e892b | ||
|
|
6bf906f2a7 | ||
|
|
7e897d604c | ||
|
|
39887df3ec | ||
|
|
fbb7a684bf | ||
|
|
449ad6cd0d | ||
|
|
cfcd6e5f93 | ||
|
|
73aab88109 | ||
|
|
beb692a3c4 | ||
|
|
fe8385e759 | ||
|
|
58fb331019 | ||
|
|
e4986a6a47 | ||
|
|
fcd47ecec6 | ||
|
|
174e6ad637 | ||
|
|
2ac4097e32 | ||
|
|
dd13ac5cbb | ||
|
|
9c55a898f7 | ||
|
|
bb9018c094 | ||
|
|
b09b4183bb | ||
|
|
3d7bc6583d | ||
|
|
99e8be227e | ||
|
|
b1c38cc793 | ||
|
|
26e4e70fc8 | ||
|
|
04bdf3f26a | ||
|
|
cafeacf69f | ||
|
|
4c2d6d78ea | ||
|
|
ea7d0cdef5 | ||
|
|
47bae63548 | ||
|
|
8470f4f7fb | ||
|
|
242f9d55ed | ||
|
|
236ac52925 | ||
|
|
baab9a9c89 | ||
|
|
3d26e6e340 | ||
|
|
c34ab48972 | ||
|
|
cf0abf21db | ||
|
|
7918b392e8 | ||
|
|
f0ced15e6a | ||
|
|
c0204cb725 | ||
|
|
eb3905447f | ||
|
|
16c7459906 | ||
|
|
eae5f87eed | ||
|
|
d4b85e3b1c | ||
|
|
a989c3b7d0 | ||
|
|
d96ba9fa46 | ||
|
|
2261d655ea | ||
|
|
8b67049863 | ||
|
|
48258dd9dd | ||
|
|
e04c573726 | ||
|
|
4daec3794e | ||
|
|
f0646dde32 | ||
|
|
ec2086e0f7 | ||
|
|
2ac704178c | ||
|
|
7c43c38e28 | ||
|
|
043a8336e5 | ||
|
|
ee27535b82 | ||
|
|
89e6ae2475 | ||
|
|
e51615f520 | ||
|
|
6e59897587 | ||
|
|
bd0644a261 | ||
|
|
d7825e1bf8 | ||
|
|
97956b6c5e | ||
|
|
8150504ea0 | ||
|
|
942dec81c7 | ||
|
|
dcbc377c62 | ||
|
|
7b65233699 | ||
|
|
eabfd8b5c4 | ||
|
|
b7b2799611 | ||
|
|
ece59ac374 | ||
|
|
83cc8b772c | ||
|
|
8b5bc18142 | ||
|
|
e1413baa9a | ||
|
|
03640e6d37 | ||
|
|
2588011524 | ||
|
|
0c16a6804a | ||
|
|
e2021fdf5d | ||
|
|
33b5694d35 | ||
|
|
af7d04fef6 | ||
|
|
14e3419e4c | ||
|
|
f6c5252376 | ||
|
|
78ee77444f | ||
|
|
fb022970b5 | ||
|
|
e5d378dc93 | ||
|
|
5969902263 | ||
|
|
d5894de142 | ||
|
|
059c6baa4e | ||
|
|
bbf9331baf | ||
|
|
a5b084f506 | ||
|
|
3b5471b97c | ||
|
|
fae37fe67d | ||
|
|
1f975efda1 | ||
|
|
3b3b61f52c | ||
|
|
1c1f6e21c5 | ||
|
|
8b60c7cc09 | ||
|
|
d4f9752cd4 | ||
|
|
6332a37f5b | ||
|
|
840a583a0b | ||
|
|
e7ed80d3e0 | ||
|
|
c2b9376313 | ||
|
|
7a8b291189 | ||
|
|
e63f71d3a7 | ||
|
|
061c97caca | ||
|
|
988d28f2fd | ||
|
|
af8a0ea9c0 | ||
|
|
c78e8d8358 | ||
|
|
392f7098bc | ||
|
|
195f918543 | ||
|
|
b2579538fa | ||
|
|
35b97c4f45 | ||
|
|
adaa89a963 | ||
|
|
fc1429fae5 | ||
|
|
4090f95098 | ||
|
|
3189d8d43e | ||
|
|
cd6d10e428 | ||
|
|
7d37236d78 | ||
|
|
7c127acf17 | ||
|
|
0a4ce2350a | ||
|
|
181a70cb1f | ||
|
|
7438545a16 | ||
|
|
9e902a5dd4 | ||
|
|
91e395884f | ||
|
|
7107c68a41 | ||
|
|
86728b79e3 | ||
|
|
e04f901590 | ||
|
|
47ad2b5cfa | ||
|
|
cea0f1766f | ||
|
|
407e57d334 | ||
|
|
c4e66d0c9c | ||
|
|
c54f1ca9b0 | ||
|
|
f9fdc36d0d | ||
|
|
6d546094ef | ||
|
|
8dc5ae4f86 | ||
|
|
fd7b81af10 | ||
|
|
3abd859664 | ||
|
|
6134ce39d4 | ||
|
|
8ea42ea432 | ||
|
|
fd4ff00ee2 | ||
|
|
9d981b09ca | ||
|
|
ed807e0fe5 | ||
|
|
32b962b036 | ||
|
|
8ac476b6bd | ||
|
|
9ab8b84d81 | ||
|
|
05cc4b4bd1 | ||
|
|
b28cf30f47 | ||
|
|
5bf8b0a2b6 | ||
|
|
d2891a49fc | ||
|
|
bec8ba6c2f | ||
|
|
9e097be657 | ||
|
|
b008f55847 | ||
|
|
487d90f260 | ||
|
|
671a745acc | ||
|
|
80880f4d2a | ||
|
|
109fba828b | ||
|
|
0a845fdfa6 | ||
|
|
5a5b8464fc | ||
|
|
86d0b92a66 | ||
|
|
9f75234dac | ||
|
|
a58b129503 | ||
|
|
6d752acb28 | ||
|
|
4486582006 | ||
|
|
ed027fd3ce | ||
|
|
a92cb848c0 | ||
|
|
e573e36aa6 | ||
|
|
fc61753953 | ||
|
|
9b74e19a99 | ||
|
|
e9e39cb985 | ||
|
|
d938f2ea50 | ||
|
|
6c3535951f | ||
|
|
cee78b4ae3 | ||
|
|
1ee646e1ce | ||
|
|
6199dec82f | ||
|
|
59f307bdb3 | ||
|
|
24747355ce | ||
|
|
3d287a2827 | ||
|
|
def28df4dd | ||
|
|
d90e698a15 | ||
|
|
f4d6f88e5c | ||
|
|
799dce4b13 | ||
|
|
a025d028d4 | ||
|
|
8cfa9a891d | ||
|
|
5b44439dd2 | ||
|
|
44fb7dcdaa | ||
|
|
4f5d1ba26b | ||
|
|
0a08b09d70 | ||
|
|
35eedda352 | ||
|
|
05fb8bc742 | ||
|
|
795df2937e | ||
|
|
5607740e77 | ||
|
|
d4287d3046 | ||
|
|
71ef72bae3 | ||
|
|
c310d698ca | ||
|
|
13ce3d1c92 | ||
|
|
122ed79a98 | ||
|
|
6d655242a6 | ||
|
|
09cab9d825 | ||
|
|
d8bd38c124 | ||
|
|
abc8bf0e62 | ||
|
|
24106ac3d2 | ||
|
|
bf506d382f | ||
|
|
84b1a9bbec | ||
|
|
d67afd4396 | ||
|
|
9f2f7eff5b | ||
|
|
c863d5976b | ||
|
|
d6338e9daf | ||
|
|
b393d2666d | ||
|
|
c5b1e73312 | ||
|
|
fa65222228 | ||
|
|
38e57ccd71 | ||
|
|
86d3d26273 | ||
|
|
db8e4a03a8 | ||
|
|
c90db8594a | ||
|
|
855ca77194 | ||
|
|
4f23af070e | ||
|
|
626613b545 | ||
|
|
c26de3bd67 | ||
|
|
c059915bd3 | ||
|
|
d2d70dcb38 | ||
|
|
846292442c | ||
|
|
11283a2199 | ||
|
|
4c8a0b9a63 | ||
|
|
54accbf21f | ||
|
|
08dc0db2e2 | ||
|
|
38c6330a2a | ||
|
|
2f983f42fe | ||
|
|
b9e45c4bb0 | ||
|
|
9d3b1d75d1 | ||
|
|
ac78ddcc82 | ||
|
|
f912d84ab6 | ||
|
|
85548d6e8e | ||
|
|
c74de12ceb | ||
|
|
017a21c17f | ||
|
|
9a63038a5f | ||
|
|
304fc2536b | ||
|
|
365169a9fb | ||
|
|
4b82ead18b | ||
|
|
141d7cc268 | ||
|
|
ee8e94cfb0 | ||
|
|
b50bedef39 | ||
|
|
a689ce4de9 | ||
|
|
ae0478a7e9 | ||
|
|
ee6eed5ac5 | ||
|
|
9140c426c4 | ||
|
|
a41bfabede | ||
|
|
5d26357025 | ||
|
|
644c10e994 | ||
|
|
b3ca0beead | ||
|
|
93300c6821 | ||
|
|
2bd8d7ee32 | ||
|
|
95c339ef74 | ||
|
|
76ad1d5ef7 | ||
|
|
151e82a2c3 | ||
|
|
3fcaf93788 | ||
|
|
b8927d66e9 | ||
|
|
9273f364fc | ||
|
|
bc42dbf88a | ||
|
|
481d4c15d6 | ||
|
|
563030e732 | ||
|
|
4f9137d009 | ||
|
|
ed1b4d1885 | ||
|
|
6bbcd9020e | ||
|
|
0ba916a7d6 | ||
|
|
cf498462eb | ||
|
|
e8b8b861a4 | ||
|
|
4afb045234 | ||
|
|
ef5c876085 | ||
|
|
7fbcfeec9c | ||
|
|
2981a8ef83 | ||
|
|
b1e8bfe2ab | ||
|
|
623d568eb9 | ||
|
|
3625834be3 | ||
|
|
925a4f4a57 |
177
.travis.yml
Normal file
177
.travis.yml
Normal file
@@ -0,0 +1,177 @@
|
||||
dist: trusty
|
||||
sudo: true
|
||||
#
|
||||
language: c
|
||||
#
|
||||
env:
|
||||
global:
|
||||
- IDE_VERSION=1.8.1
|
||||
matrix:
|
||||
- BOARD="multi4in1:STM32F1:multistm32f103c:upload_method=serialMethod"
|
||||
- BOARD="multi4in1:STM32F1:multistm32f103c:upload_method=TxFlashMethod"
|
||||
- BOARD="multi4in1:avr:multixmega32d4"
|
||||
- BOARD="multi4in1:avr:multiatmega328p:bootloader=none"
|
||||
- BOARD="multi4in1:avr:multiatmega328p:bootloader=optiboot"
|
||||
#
|
||||
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}
|
||||
#
|
||||
# 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
|
||||
#
|
||||
- if [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
arduino --install-boards multi4in1:STM32F1;
|
||||
fi
|
||||
#
|
||||
- if [[ "$BOARD" =~ "multi4in1:avr:" ]]; then
|
||||
arduino --install-boards multi4in1:avr;
|
||||
fi
|
||||
#
|
||||
- buildMulti() { BUILDCMD="arduino --verify --board $BOARD Multiprotocol/Multiprotocol.ino --pref build.path=./build/"; echo $BUILDCMD; $BUILDCMD; echo; }
|
||||
- buildProtocol() { opt_disable $ALL_PROTOCOLS; opt_enable $1; buildMulti; }
|
||||
- buildEachProtocol() { exitcode=0; for PROTOCOL in $ALL_PROTOCOLS ; do echo Building $PROTOCOL; buildProtocol $PROTOCOL; if [ $? -ne 0 ]; then exitcode=1; fi; done; return $exitcode; }
|
||||
#
|
||||
install: true
|
||||
before_script:
|
||||
#
|
||||
# Change current working directory to the build dir
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
# Log the initial Multi config
|
||||
- cat Multiprotocol/_Config.h
|
||||
# Back up the configuration
|
||||
- cp Multiprotocol/_Config.h ./_Config.h.bak
|
||||
# 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
|
||||
#
|
||||
# Enable CHECK_FOR_BOOTLOADER when needed
|
||||
- if [[ "$BOARD" =~ ":upload_method=TxFlashMethod" ]] || [[ "$BOARD" =~ ":bootloader=optiboot" ]]; then
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
fi
|
||||
#
|
||||
# Trim the build 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
|
||||
#
|
||||
script:
|
||||
# Build with all protocols enabled for STM32; a subset of protocols for Atmega
|
||||
- buildMulti
|
||||
#
|
||||
# Serial only
|
||||
- opt_disable ENABLE_PPM
|
||||
- opt_enable ENABLE_SERIAL
|
||||
- buildMulti
|
||||
#
|
||||
# PPM only
|
||||
- opt_enable ENABLE_PPM
|
||||
- opt_disable ENABLE_SERIAL
|
||||
- buildMulti
|
||||
#
|
||||
# Re-enable PPM and serial
|
||||
- opt_enable ENABLE_SERIAL
|
||||
- opt_enable ENABLE_PPM
|
||||
#
|
||||
# Build each protocol individually
|
||||
- buildEachProtocol
|
||||
before_deploy:
|
||||
# Create somwhere to put the binaries
|
||||
- mkdir ./binaries
|
||||
# Restore the default configuration
|
||||
- cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
# Build the release files for OrangeRX
|
||||
- if [[ "$BOARD" =~ "multi4in1:avr:multixmega32d4" ]]; then
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
opt_disable ORANGE_TX_BLUE;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.hex ./binaries/Multi-OrangeRX_Green_INV-$TRAVIS_TAG.hex;
|
||||
opt_enable ORANGE_TX_BLUE;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.hex ./binaries/Multi-OrangeRX_Blue_INV-$TRAVIS_TAG.hex;
|
||||
fi
|
||||
# Build the release files for AVR without bootloader
|
||||
- if [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:bootloader=none" ]]; then
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $A7105_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.hex ./binaries/Multi-AVR_USBASP_A7105_INV-$TRAVIS_TAG.hex;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CC2500_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.hex ./binaries/Multi-AVR_USBASP_CC2500_INV-$TRAVIS_TAG.hex;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CYRF6936_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.hex ./binaries/Multi-AVR_USBASP_CYRF6936_INV-$TRAVIS_TAG.hex;
|
||||
fi
|
||||
# Build the release files for AVR with bootloader
|
||||
- if [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:bootloader=optiboot" ]]; then
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $A7105_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.hex ./binaries/Multi-AVR_TXFLASH_A7105_INV-$TRAVIS_TAG.hex;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CC2500_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.hex ./binaries/Multi-AVR_TXFLASH_CC2500_INV-$TRAVIS_TAG.hex;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CYRF6936_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.hex ./binaries/Multi-AVR_TXFLASH_CYRF6936_INV-$TRAVIS_TAG.hex;
|
||||
fi
|
||||
# Build the release files for STM32 without bootloader
|
||||
- if [[ "$BOARD" =~ "multi4in1:STM32F1:multistm32f103c:upload_method=serialMethod" ]]; then
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/Multi-STM_FTDI_INV-$TRAVIS_TAG.bin;
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_enable MULTI_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/Multi-STM_FTDI_INV_OPENTX-$TRAVIS_TAG.bin;
|
||||
fi
|
||||
# Build the release files for STM32 with bootloader
|
||||
- if [[ "$BOARD" =~ "multi4in1:STM32F1:multistm32f103c:upload_method=TxFlashMethod" ]]; then
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/Multi-STM_TXFLASH_INV-$TRAVIS_TAG.bin;
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_enable MULTI_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/Multi-STM_TXFLASH_INV_OPENTX-$TRAVIS_TAG.bin;
|
||||
fi
|
||||
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
|
||||
2
BootLoaders/AtmegaEmptyBoot/AtmegaMultiEmpty.hex
Normal file
2
BootLoaders/AtmegaEmptyBoot/AtmegaMultiEmpty.hex
Normal file
@@ -0,0 +1,2 @@
|
||||
:02000000FFFF00
|
||||
:00000001FF
|
||||
34
BootLoaders/AtmegaMultiBoot/AtmegaMultiBoot.hex
Normal file
34
BootLoaders/AtmegaMultiBoot/AtmegaMultiBoot.hex
Normal file
@@ -0,0 +1,34 @@
|
||||
:107E0000112484B714BE9FEF9BB99CE395B991E010
|
||||
:107E100098B98370A9F08AEF80938500109284004E
|
||||
:107E200085E08093810096BBB09BFECF10928100CD
|
||||
:107E300093B186B181709C73892B8D3109F0B3D0D9
|
||||
:107E400082E08093C00088E18093C10086E0809347
|
||||
:107E5000C20081E28093C400259AC0E0D0E093E0A4
|
||||
:107E6000F92EEE24E39425E0D22E31E1C32EA9D0E1
|
||||
:107E7000813481F4A6D08EBBABD08EB3823811F49E
|
||||
:107E800085E006C08EB3813811F484E001C083E040
|
||||
:107E900091D086C0823411F484E103C0853419F492
|
||||
:107EA00085E09DD07DC0853541F48BD0C82F89D029
|
||||
:107EB000D0E0D82BCC0FDD1F72C0863521F484E0D2
|
||||
:107EC0008ED080E0E5CF843609F03DC07AD079D0FD
|
||||
:107ED000B82E77D0C11520E7D20718F000E011E0E6
|
||||
:107EE00004C0FE01F7BEE895F9CF6BD0F80181938D
|
||||
:107EF0008F01BE12FACFCE01905781159E4018F423
|
||||
:107F0000FE01F7BEE89564D0C115FEE7DF0708F073
|
||||
:107F100047C007B600FCFDCFFE01A0E0B1E08D91A7
|
||||
:107F20009D910C01E7BEE89511243296A03821E01E
|
||||
:107F3000B207A9F7FE01D7BEE89507B600FCFDCF52
|
||||
:107F4000C7BEE8952DC08437B1F43BD03AD0B82EE7
|
||||
:107F500038D03ED0FE01AC2EAB0C8F010F5F1F4F0F
|
||||
:107F6000849128D0A01205C02196BA94CB0DD11DC2
|
||||
:107F700017C0F801F2CF853739F42AD08EE11AD034
|
||||
:107F800085E918D08FE084CF813549F421D080E194
|
||||
:107F900011D08091C00086FFFCCF05D001C018D061
|
||||
:107FA00080E108D064CFE0E0F0E084918F3F09F0F9
|
||||
:107FB000099408959091C00095FFFCCF8093C6006E
|
||||
:107FC00008958091C00087FFFCCF8091C60008957E
|
||||
:107FD000F8DF803211F085E1EDDF84E1EBCFCF9364
|
||||
:107FE000C82FEFDFC150E9F7CF91F2CFA8950895E0
|
||||
:0C7FF000E0E6F0E098E1908380830895C3
|
||||
:0400000300007E007B
|
||||
:00000001FF
|
||||
504
BootLoaders/AtmegaMultiBoot/Source/Makefile
Normal file
504
BootLoaders/AtmegaMultiBoot/Source/Makefile
Normal file
@@ -0,0 +1,504 @@
|
||||
# Makefile for ATmegaBOOT
|
||||
# E.Lins, 18.7.2005
|
||||
# $Id$
|
||||
#
|
||||
# Instructions
|
||||
#
|
||||
# To make bootloader .hex file:
|
||||
# make diecimila
|
||||
# make lilypad
|
||||
# make ng
|
||||
# etc...
|
||||
#
|
||||
# To burn bootloader .hex file:
|
||||
# make diecimila_isp
|
||||
# make lilypad_isp
|
||||
# make ng_isp
|
||||
# etc...
|
||||
|
||||
# program name should not be changed...
|
||||
PROGRAM = optiboot
|
||||
|
||||
# The default behavior is to build using tools that are in the users
|
||||
# current path variables, but we can also build using an installed
|
||||
# Arduino user IDE setup, or the Arduino source tree.
|
||||
# Uncomment this next lines to build within the arduino environment,
|
||||
# using the arduino-included avrgcc toolset (mac and pc)
|
||||
# ENV ?= arduino
|
||||
# ENV ?= arduinodev
|
||||
# OS ?= macosx
|
||||
# OS ?= windows
|
||||
|
||||
|
||||
# enter the parameters for the avrdude isp tool -b19200
|
||||
#
|
||||
# These are the parameters for a usb-based STK500v2 programmer.
|
||||
# Exact type unknown. (historical Makefile values.)
|
||||
ISPTOOL = stk500v2
|
||||
ISPPORT = usb
|
||||
ISPSPEED = -b 57600
|
||||
#
|
||||
#
|
||||
# These are parameters for using an Arduino with the ArduinoISP sketch
|
||||
# as the programmer. On a mac, for a particular Uno as programmer.
|
||||
#ISPTOOL = stk500v1 -C /Applications/arduino/arduino-0022/hardware/tools/avr/etc/avrdude.conf
|
||||
#ISPPORT = /dev/tty.usbmodemfd3141
|
||||
#ISPSPEED = -b19200
|
||||
|
||||
MCU_TARGET = atmega168
|
||||
LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe
|
||||
|
||||
# Build environments
|
||||
# Start of some ugly makefile-isms to allow optiboot to be built
|
||||
# in several different environments. See the README.TXT file for
|
||||
# details.
|
||||
|
||||
# default
|
||||
fixpath = $(1)
|
||||
|
||||
ifeq ($(ENV), arduino)
|
||||
# For Arduino, we assume that we're connected to the optiboot directory
|
||||
# included with the arduino distribution, which means that the full set
|
||||
# of avr-tools are "right up there" in standard places.
|
||||
TOOLROOT = ../../../tools
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
ifeq ($(OS), windows)
|
||||
# On windows, SOME of the tool paths will need to have backslashes instead
|
||||
# of forward slashes (because they use windows cmd.exe for execution instead
|
||||
# of a unix/mingw shell?) We also have to ensure that a consistent shell
|
||||
# is used even if a unix shell is installed (ie as part of WINAVR)
|
||||
fixpath = $(subst /,\,$1)
|
||||
SHELL = cmd.exe
|
||||
endif
|
||||
|
||||
else ifeq ($(ENV), arduinodev)
|
||||
# Arduino IDE source code environment. Use the unpacked compilers created
|
||||
# by the build (you'll need to do "ant build" first.)
|
||||
ifeq ($(OS), macosx)
|
||||
TOOLROOT = ../../../../build/macosx/work/Arduino.app/Contents/Resources/Java/hardware/tools
|
||||
endif
|
||||
ifeq ($(OS), windows)
|
||||
TOOLROOT = ../../../../build/windows/work/hardware/tools
|
||||
endif
|
||||
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
else
|
||||
GCCROOT =
|
||||
AVRDUDE_CONF =
|
||||
endif
|
||||
#
|
||||
# End of build environment code.
|
||||
|
||||
|
||||
# the efuse should really be 0xf8; since, however, only the lower
|
||||
# three bits of that byte are used on the atmega168, avrdude gets
|
||||
# confused if you specify 1's for the higher bits, see:
|
||||
# http://tinker.it/now/2007/02/24/the-tale-of-avrdude-atmega168-and-extended-bits-fuses/
|
||||
#
|
||||
# similarly, the lock bits should be 0xff instead of 0x3f (to
|
||||
# unlock the bootloader section) and 0xcf instead of 0x2f (to
|
||||
# lock it), but since the high two bits of the lock byte are
|
||||
# unused, avrdude would get confused.
|
||||
|
||||
ISPFUSES = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-e -u -U lock:w:0x3f:m -U efuse:w:0x$(EFUSE):m \
|
||||
-U hfuse:w:0x$(HFUSE):m -U lfuse:w:0x$(LFUSE):m
|
||||
ISPFLASH = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x2f:m
|
||||
|
||||
STK500 = "C:\Program Files\Atmel\AVR Tools\STK500\Stk500.exe"
|
||||
STK500-1 = $(STK500) -e -d$(MCU_TARGET) -pf -vf -if$(PROGRAM)_$(TARGET).hex \
|
||||
-lFF -LFF -f$(HFUSE)$(LFUSE) -EF8 -ms -q -cUSB -I200kHz -s -wt
|
||||
STK500-2 = $(STK500) -d$(MCU_TARGET) -ms -q -lCF -LCF -cUSB -I200kHz -s -wt
|
||||
|
||||
OBJ = $(PROGRAM).o
|
||||
OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types
|
||||
# -mshort-calls
|
||||
|
||||
DEFS =
|
||||
LIBS =
|
||||
|
||||
CC = $(GCCROOT)avr-gcc
|
||||
|
||||
# Override is only needed by avr-lib build system.
|
||||
|
||||
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
|
||||
override LDFLAGS = $(LDSECTIONS) -Wl,--relax -Wl,--gc-sections -nostartfiles -nostdlib
|
||||
|
||||
OBJCOPY = $(GCCROOT)avr-objcopy
|
||||
OBJDUMP = $(call fixpath,$(GCCROOT)avr-objdump)
|
||||
|
||||
SIZE = $(GCCROOT)avr-size
|
||||
|
||||
|
||||
|
||||
#Voice board test
|
||||
# ATmega328
|
||||
#
|
||||
#atmega328: TARGET = atmega328p
|
||||
#atmega328: MCU_TARGET = atmega328p
|
||||
#atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
#atmega328: AVR_FREQ = 12000000L
|
||||
#atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
#atmega328: $(PROGRAM)_atmega328.hex
|
||||
#atmega328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
atmega328: TARGET = atmega328
|
||||
atmega328: MCU_TARGET = atmega328p
|
||||
atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
atmega328: AVR_FREQ = 16000000L
|
||||
atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328: $(PROGRAM)_atmega328_16.hex
|
||||
atmega328: $(PROGRAM)_atmega328_16.lst
|
||||
|
||||
|
||||
xmega32D4: TARGET = atxmega32d4
|
||||
xmega32D4: MCU_TARGET = atxmega32d4
|
||||
xmega32D4: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
xmega32D4: AVR_FREQ = 32000000L
|
||||
xmega32D4: LDSECTIONS = -Wl,--section-start=.text=0x8000
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.hex
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.lst
|
||||
|
||||
|
||||
# Test platforms
|
||||
# Virtual boot block test
|
||||
virboot328: TARGET = atmega328
|
||||
virboot328: MCU_TARGET = atmega328p
|
||||
virboot328: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DVIRTUAL_BOOT'
|
||||
virboot328: AVR_FREQ = 16000000L
|
||||
virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
virboot328: $(PROGRAM)_atmega328.hex
|
||||
virboot328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
# 20MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro20: TARGET = pro_20mhz
|
||||
pro20: MCU_TARGET = atmega168
|
||||
pro20: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro20: AVR_FREQ = 20000000L
|
||||
pro20: $(PROGRAM)_pro_20mhz.hex
|
||||
pro20: $(PROGRAM)_pro_20mhz.lst
|
||||
|
||||
pro20_isp: pro20
|
||||
pro20_isp: TARGET = pro_20mhz
|
||||
# 2.7V brownout
|
||||
pro20_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro20_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro20_isp: EFUSE = 04
|
||||
pro20_isp: isp
|
||||
|
||||
# 16MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro16: TARGET = pro_16MHz
|
||||
pro16: MCU_TARGET = atmega168
|
||||
pro16: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro16: AVR_FREQ = 16000000L
|
||||
pro16: $(PROGRAM)_pro_16MHz.hex
|
||||
pro16: $(PROGRAM)_pro_16MHz.lst
|
||||
|
||||
pro16_isp: pro16
|
||||
pro16_isp: TARGET = pro_16MHz
|
||||
# 2.7V brownout
|
||||
pro16_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro16_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro16_isp: EFUSE = 04
|
||||
pro16_isp: isp
|
||||
|
||||
# Diecimila, Duemilanove with m168, and NG use identical bootloaders
|
||||
# Call it "atmega168" for generality and clarity, keep "diecimila" for
|
||||
# backward compatibility of makefile
|
||||
#
|
||||
atmega168: TARGET = atmega168
|
||||
atmega168: MCU_TARGET = atmega168
|
||||
atmega168: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega168: AVR_FREQ = 12000000L
|
||||
atmega168: $(PROGRAM)_atmega168.hex
|
||||
atmega168: $(PROGRAM)_atmega168.lst
|
||||
|
||||
atmega168_isp: atmega168
|
||||
atmega168_isp: TARGET = atmega168
|
||||
# 2.7V brownout
|
||||
atmega168_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega168_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega168_isp: EFUSE = 04
|
||||
atmega168_isp: isp
|
||||
|
||||
diecimila: TARGET = diecimila
|
||||
diecimila: MCU_TARGET = atmega168
|
||||
diecimila: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
diecimila: AVR_FREQ = 16000000L
|
||||
diecimila: $(PROGRAM)_diecimila.hex
|
||||
diecimila: $(PROGRAM)_diecimila.lst
|
||||
|
||||
diecimila_isp: diecimila
|
||||
diecimila_isp: TARGET = diecimila
|
||||
# 2.7V brownout
|
||||
diecimila_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
diecimila_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
diecimila_isp: EFUSE = 04
|
||||
diecimila_isp: isp
|
||||
|
||||
atmega328_isp: atmega328
|
||||
atmega328_isp: TARGET = atmega328
|
||||
atmega328_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_isp: EFUSE = FD
|
||||
atmega328_isp: isp
|
||||
|
||||
atmega1284: TARGET = atmega1284p
|
||||
atmega1284: MCU_TARGET = atmega1284p
|
||||
atmega1284: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
atmega1284: AVR_FREQ = 16000000L
|
||||
atmega1284: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
atmega1284: $(PROGRAM)_atmega1284p.hex
|
||||
atmega1284: $(PROGRAM)_atmega1284p.lst
|
||||
|
||||
atmega1284_isp: atmega1284
|
||||
atmega1284_isp: TARGET = atmega1284p
|
||||
atmega1284_isp: MCU_TARGET = atmega1284p
|
||||
# 1024 byte boot
|
||||
atmega1284_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega1284_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega1284_isp: EFUSE = FD
|
||||
atmega1284_isp: isp
|
||||
|
||||
# Sanguino has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#
|
||||
sanguino: TARGET = atmega644p
|
||||
sanguino: MCU_TARGET = atmega644p
|
||||
sanguino: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
sanguino: AVR_FREQ = 16000000L
|
||||
sanguino: LDSECTIONS = -Wl,--section-start=.text=0xfc00 -Wl,--section-start=.version=0xfffe
|
||||
sanguino: $(PROGRAM)_atmega644p.hex
|
||||
sanguino: $(PROGRAM)_atmega644p.lst
|
||||
|
||||
sanguino_isp: sanguino
|
||||
sanguino_isp: TARGET = atmega644p
|
||||
sanguino_isp: MCU_TARGET = atmega644p
|
||||
# 1024 byte boot
|
||||
sanguino_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
sanguino_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
sanguino_isp: EFUSE = FD
|
||||
sanguino_isp: isp
|
||||
|
||||
# Mega has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#mega: TARGET = atmega1280
|
||||
mega1280: MCU_TARGET = atmega1280
|
||||
mega1280: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
mega1280: AVR_FREQ = 16000000L
|
||||
mega1280: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
mega1280: $(PROGRAM)_atmega1280.hex
|
||||
mega1280: $(PROGRAM)_atmega1280.lst
|
||||
|
||||
mega1280_isp: mega
|
||||
mega1280_isp: TARGET = atmega1280
|
||||
mega1280_isp: MCU_TARGET = atmega1280
|
||||
# 1024 byte boot
|
||||
mega1280_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
mega1280_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
mega1280_isp: EFUSE = FD
|
||||
mega1280_isp: isp
|
||||
|
||||
# ATmega8
|
||||
#
|
||||
atmega8: TARGET = atmega8
|
||||
atmega8: MCU_TARGET = atmega8
|
||||
atmega8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega8: AVR_FREQ = 16000000L
|
||||
atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega8: $(PROGRAM)_atmega8.hex
|
||||
atmega8: $(PROGRAM)_atmega8.lst
|
||||
|
||||
atmega8_isp: atmega8
|
||||
atmega8_isp: TARGET = atmega8
|
||||
atmega8_isp: MCU_TARGET = atmega8
|
||||
# SPIEN, CKOPT, Bootsize=512B
|
||||
atmega8_isp: HFUSE = CC
|
||||
# 2.7V brownout, Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega8_isp: LFUSE = BF
|
||||
atmega8_isp: isp
|
||||
|
||||
# ATmega88
|
||||
#
|
||||
atmega88: TARGET = atmega88
|
||||
atmega88: MCU_TARGET = atmega88
|
||||
atmega88: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega88: AVR_FREQ = 12000000L
|
||||
atmega88: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega88: $(PROGRAM)_atmega88.hex
|
||||
atmega88: $(PROGRAM)_atmega88.lst
|
||||
|
||||
atmega88_isp: atmega88
|
||||
atmega88_isp: TARGET = atmega88
|
||||
atmega88_isp: MCU_TARGET = atmega88
|
||||
# 2.7V brownout
|
||||
atmega88_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atemga88_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega88_isp: EFUSE = 04
|
||||
atmega88_isp: isp
|
||||
|
||||
|
||||
# 8MHz clocked platforms
|
||||
#
|
||||
# These are capable of 38400 baud
|
||||
#
|
||||
|
||||
lilypad: TARGET = lilypad
|
||||
lilypad: MCU_TARGET = atmega168
|
||||
lilypad: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad: AVR_FREQ = 8000000L
|
||||
lilypad: $(PROGRAM)_lilypad.hex
|
||||
lilypad: $(PROGRAM)_lilypad.lst
|
||||
|
||||
lilypad_isp: lilypad
|
||||
lilypad_isp: TARGET = lilypad
|
||||
# 2.7V brownout
|
||||
lilypad_isp: HFUSE = DD
|
||||
# Internal 8MHz osc (8MHz) Slow rising power
|
||||
lilypad_isp: LFUSE = E2
|
||||
# 512 byte boot
|
||||
lilypad_isp: EFUSE = 04
|
||||
lilypad_isp: isp
|
||||
|
||||
lilypad_resonator: TARGET = lilypad_resonator
|
||||
lilypad_resonator: MCU_TARGET = atmega168
|
||||
lilypad_resonator: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad_resonator: AVR_FREQ = 8000000L
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.hex
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.lst
|
||||
|
||||
lilypad_resonator_isp: lilypad_resonator
|
||||
lilypad_resonator_isp: TARGET = lilypad_resonator
|
||||
# 2.7V brownout
|
||||
lilypad_resonator_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
lilypad_resonator_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
lilypad_resonator_isp: EFUSE = 04
|
||||
lilypad_resonator_isp: isp
|
||||
|
||||
pro8: TARGET = pro_8MHz
|
||||
pro8: MCU_TARGET = atmega168
|
||||
pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro8: AVR_FREQ = 8000000L
|
||||
pro8: $(PROGRAM)_pro_8MHz.hex
|
||||
pro8: $(PROGRAM)_pro_8MHz.lst
|
||||
|
||||
pro8_isp: pro8
|
||||
pro8_isp: TARGET = pro_8MHz
|
||||
# 2.7V brownout
|
||||
pro8_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro8_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro8_isp: EFUSE = 04
|
||||
pro8_isp: isp
|
||||
|
||||
atmega328_pro8: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8: MCU_TARGET = atmega328p
|
||||
atmega328_pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega328_pro8: AVR_FREQ = 8000000L
|
||||
atmega328_pro8: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.hex
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.lst
|
||||
|
||||
atmega328_pro8_isp: atmega328_pro8
|
||||
atmega328_pro8_isp: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_pro8_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_pro8_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_pro8_isp: EFUSE = DE
|
||||
atmega328_pro8_isp: isp
|
||||
|
||||
# 1MHz clocked platforms
|
||||
#
|
||||
# These are capable of 9600 baud
|
||||
#
|
||||
|
||||
luminet: TARGET = luminet
|
||||
luminet: MCU_TARGET = attiny84
|
||||
luminet: CFLAGS += '-DLED_START_FLASHES=3' '-DSOFT_UART' '-DBAUD_RATE=9600'
|
||||
luminet: CFLAGS += '-DVIRTUAL_BOOT_PARTITION'
|
||||
luminet: AVR_FREQ = 1000000L
|
||||
luminet: LDSECTIONS = -Wl,--section-start=.text=0x1d00 -Wl,--section-start=.version=0x1efe
|
||||
luminet: $(PROGRAM)_luminet.hex
|
||||
luminet: $(PROGRAM)_luminet.lst
|
||||
|
||||
luminet_isp: luminet
|
||||
luminet_isp: TARGET = luminet
|
||||
luminet_isp: MCU_TARGET = attiny84
|
||||
# Brownout disabled
|
||||
luminet_isp: HFUSE = DF
|
||||
# 1MHz internal oscillator, slowly rising power
|
||||
luminet_isp: LFUSE = 62
|
||||
# Self-programming enable
|
||||
luminet_isp: EFUSE = FE
|
||||
luminet_isp: isp
|
||||
|
||||
#
|
||||
# Generic build instructions
|
||||
#
|
||||
#
|
||||
|
||||
isp: $(TARGET)
|
||||
$(ISPFUSES)
|
||||
$(ISPFLASH)
|
||||
|
||||
isp-stk500: $(PROGRAM)_$(TARGET).hex
|
||||
$(STK500-1)
|
||||
$(STK500-2)
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(SIZE) $@
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@
|
||||
|
||||
%.srec: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@
|
||||
848
BootLoaders/AtmegaMultiBoot/Source/boot.h
Normal file
848
BootLoaders/AtmegaMultiBoot/Source/boot.h
Normal file
@@ -0,0 +1,848 @@
|
||||
/* Modified to use out for SPM access
|
||||
** Peter Knight, Optiboot project http://optiboot.googlecode.com
|
||||
**
|
||||
** Todo: Tidy up
|
||||
**
|
||||
** "_short" routines execute 1 cycle faster and use 1 less word of flash
|
||||
** by using "out" instruction instead of "sts".
|
||||
**
|
||||
** Additional elpm variants that trust the value of RAMPZ
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Eric B. Weddington
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
/* $Id: boot.h,v 1.27.2.3 2008/09/30 13:58:48 arcanum Exp $ */
|
||||
|
||||
#ifndef _AVR_BOOT_H_
|
||||
#define _AVR_BOOT_H_ 1
|
||||
|
||||
/** \file */
|
||||
/** \defgroup avr_boot <avr/boot.h>: Bootloader Support Utilities
|
||||
\code
|
||||
#include <avr/io.h>
|
||||
#include <avr/boot.h>
|
||||
\endcode
|
||||
|
||||
The macros in this module provide a C language interface to the
|
||||
bootloader support functionality of certain AVR processors. These
|
||||
macros are designed to work with all sizes of flash memory.
|
||||
|
||||
Global interrupts are not automatically disabled for these macros. It
|
||||
is left up to the programmer to do this. See the code example below.
|
||||
Also see the processor datasheet for caveats on having global interrupts
|
||||
enabled during writing of the Flash.
|
||||
|
||||
\note Not all AVR processors provide bootloader support. See your
|
||||
processor datasheet to see if it provides bootloader support.
|
||||
|
||||
\todo From email with Marek: On smaller devices (all except ATmega64/128),
|
||||
__SPM_REG is in the I/O space, accessible with the shorter "in" and "out"
|
||||
instructions - since the boot loader has a limited size, this could be an
|
||||
important optimization.
|
||||
|
||||
\par API Usage Example
|
||||
The following code shows typical usage of the boot API.
|
||||
|
||||
\code
|
||||
#include <inttypes.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
void boot_program_page (uint32_t page, uint8_t *buf)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t sreg;
|
||||
|
||||
// Disable interrupts.
|
||||
|
||||
sreg = SREG;
|
||||
cli();
|
||||
|
||||
eeprom_busy_wait ();
|
||||
|
||||
boot_page_erase (page);
|
||||
boot_spm_busy_wait (); // Wait until the memory is erased.
|
||||
|
||||
for (i=0; i<SPM_PAGESIZE; i+=2)
|
||||
{
|
||||
// Set up little-endian word.
|
||||
|
||||
uint16_t w = *buf++;
|
||||
w += (*buf++) << 8;
|
||||
|
||||
boot_page_fill (page + i, w);
|
||||
}
|
||||
|
||||
boot_page_write (page); // Store buffer in flash page.
|
||||
boot_spm_busy_wait(); // Wait until the memory is written.
|
||||
|
||||
// Reenable RWW-section again. We need this if we want to jump back
|
||||
// to the application after bootloading.
|
||||
|
||||
boot_rww_enable ();
|
||||
|
||||
// Re-enable interrupts (if they were ever enabled).
|
||||
|
||||
SREG = sreg;
|
||||
}\endcode */
|
||||
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/io.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Check for SPM Control Register in processor. */
|
||||
#if defined (SPMCSR)
|
||||
# define __SPM_REG SPMCSR
|
||||
#elif defined (SPMCR)
|
||||
# define __SPM_REG SPMCR
|
||||
#else
|
||||
# error AVR processor does not provide bootloader support!
|
||||
#endif
|
||||
|
||||
|
||||
/* Check for SPM Enable bit. */
|
||||
#if defined(SPMEN)
|
||||
# define __SPM_ENABLE SPMEN
|
||||
#elif defined(SELFPRGEN)
|
||||
# define __SPM_ENABLE SELFPRGEN
|
||||
#else
|
||||
# error Cannot find SPM Enable bit definition!
|
||||
#endif
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def BOOTLOADER_SECTION
|
||||
|
||||
Used to declare a function or variable to be placed into a
|
||||
new section called .bootloader. This section and its contents
|
||||
can then be relocated to any address (such as the bootloader
|
||||
NRWW area) at link-time. */
|
||||
|
||||
#define BOOTLOADER_SECTION __attribute__ ((section (".bootloader")))
|
||||
|
||||
/* Create common bit definitions. */
|
||||
#ifdef ASB
|
||||
#define __COMMON_ASB ASB
|
||||
#else
|
||||
#define __COMMON_ASB RWWSB
|
||||
#endif
|
||||
|
||||
#ifdef ASRE
|
||||
#define __COMMON_ASRE ASRE
|
||||
#else
|
||||
#define __COMMON_ASRE RWWSRE
|
||||
#endif
|
||||
|
||||
/* Define the bit positions of the Boot Lock Bits. */
|
||||
|
||||
#define BLB12 5
|
||||
#define BLB11 4
|
||||
#define BLB02 3
|
||||
#define BLB01 2
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_interrupt_enable()
|
||||
Enable the SPM interrupt. */
|
||||
|
||||
#define boot_spm_interrupt_enable() (__SPM_REG |= (uint8_t)_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_interrupt_disable()
|
||||
Disable the SPM interrupt. */
|
||||
|
||||
#define boot_spm_interrupt_disable() (__SPM_REG &= (uint8_t)~_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_is_spm_interrupt()
|
||||
Check if the SPM interrupt is enabled. */
|
||||
|
||||
#define boot_is_spm_interrupt() (__SPM_REG & (uint8_t)_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_rww_busy()
|
||||
Check if the RWW section is busy. */
|
||||
|
||||
#define boot_rww_busy() (__SPM_REG & (uint8_t)_BV(__COMMON_ASB))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_busy()
|
||||
Check if the SPM instruction is busy. */
|
||||
|
||||
#define boot_spm_busy() (__SPM_REG & (uint8_t)_BV(__SPM_ENABLE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_busy_wait()
|
||||
Wait while the SPM instruction is busy. */
|
||||
|
||||
#define boot_spm_busy_wait() do{}while(boot_spm_busy())
|
||||
|
||||
#define __BOOT_PAGE_ERASE (_BV(__SPM_ENABLE) | _BV(PGERS))
|
||||
#define __BOOT_PAGE_WRITE (_BV(__SPM_ENABLE) | _BV(PGWRT))
|
||||
#define __BOOT_PAGE_FILL _BV(__SPM_ENABLE)
|
||||
#define __BOOT_RWW_ENABLE (_BV(__SPM_ENABLE) | _BV(__COMMON_ASRE))
|
||||
#define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(BLBSET))
|
||||
|
||||
#define __boot_page_fill_short(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_normal(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_alternate(address, data)\
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_extended(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %4\n\t" \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"r" ((uint32_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_extended_short(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %4\n\t" \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"r" ((uint32_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
|
||||
#define __boot_page_erase_normal(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_alternate(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_extended(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
#define __boot_page_erase_extended_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_normal(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_alternate(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_extended(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
#define __boot_page_write_extended_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable_short() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable_alternate() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
/* From the mega16/mega128 data sheets (maybe others):
|
||||
|
||||
Bits by SPM To set the Boot Loader Lock bits, write the desired data to
|
||||
R0, write "X0001001" to SPMCR and execute SPM within four clock cycles
|
||||
after writing SPMCR. The only accessible Lock bits are the Boot Lock bits
|
||||
that may prevent the Application and Boot Loader section from any
|
||||
software update by the MCU.
|
||||
|
||||
If bits 5..2 in R0 are cleared (zero), the corresponding Boot Lock bit
|
||||
will be programmed if an SPM instruction is executed within four cycles
|
||||
after BLBSET and SPMEN (or SELFPRGEN) are set in SPMCR. The Z-pointer is
|
||||
don't care during this operation, but for future compatibility it is
|
||||
recommended to load the Z-pointer with $0001 (same as used for reading the
|
||||
Lock bits). For future compatibility It is also recommended to set bits 7,
|
||||
6, 1, and 0 in R0 to 1 when writing the Lock bits. When programming the
|
||||
Lock bits the entire Flash can be read during the operation. */
|
||||
|
||||
#define __boot_lock_bits_set_short(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_lock_bits_set(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_lock_bits_set_alternate(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
/*
|
||||
Reading lock and fuse bits:
|
||||
|
||||
Similarly to writing the lock bits above, set BLBSET and SPMEN (or
|
||||
SELFPRGEN) bits in __SPMREG, and then (within four clock cycles) issue an
|
||||
LPM instruction.
|
||||
|
||||
Z address: contents:
|
||||
0x0000 low fuse bits
|
||||
0x0001 lock bits
|
||||
0x0002 extended fuse bits
|
||||
0x0003 high fuse bits
|
||||
|
||||
Sounds confusing, doesn't it?
|
||||
|
||||
Unlike the macros in pgmspace.h, no need to care for non-enhanced
|
||||
cores here as these old cores do not provide SPM support anyway.
|
||||
*/
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def GET_LOW_FUSE_BITS
|
||||
address to read the low fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_LOW_FUSE_BITS (0x0000)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_LOCK_BITS
|
||||
address to read the lock bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_LOCK_BITS (0x0001)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_EXTENDED_FUSE_BITS
|
||||
address to read the extended fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_EXTENDED_FUSE_BITS (0x0002)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_HIGH_FUSE_BITS
|
||||
address to read the high fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_HIGH_FUSE_BITS (0x0003)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_lock_fuse_bits_get(address)
|
||||
|
||||
Read the lock or fuse bits at \c address.
|
||||
|
||||
Parameter \c address can be any of GET_LOW_FUSE_BITS,
|
||||
GET_LOCK_BITS, GET_EXTENDED_FUSE_BITS, or GET_HIGH_FUSE_BITS.
|
||||
|
||||
\note The lock and fuse bits returned are the physical values,
|
||||
i.e. a bit returned as 0 means the corresponding fuse or lock bit
|
||||
is programmed.
|
||||
*/
|
||||
#define boot_lock_fuse_bits_get_short(address) \
|
||||
(__extension__({ \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, %3\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"out %1, %2\n\t" \
|
||||
"lpm %0, Z\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"M" (address) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
#define boot_lock_fuse_bits_get(address) \
|
||||
(__extension__({ \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, %3\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"sts %1, %2\n\t" \
|
||||
"lpm %0, Z\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"M" (address) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_signature_byte_get(address)
|
||||
|
||||
Read the Signature Row byte at \c address. For some MCU types,
|
||||
this function can also retrieve the factory-stored oscillator
|
||||
calibration bytes.
|
||||
|
||||
Parameter \c address can be 0-0x1f as documented by the datasheet.
|
||||
\note The values are MCU type dependent.
|
||||
*/
|
||||
|
||||
#define __BOOT_SIGROW_READ (_BV(__SPM_ENABLE) | _BV(SIGRD))
|
||||
|
||||
#define boot_signature_byte_get_short(addr) \
|
||||
(__extension__({ \
|
||||
uint16_t __addr16 = (uint16_t)(addr); \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %1, %2\n\t" \
|
||||
"lpm %0, Z" "\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t) __BOOT_SIGROW_READ), \
|
||||
"z" (__addr16) \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
#define boot_signature_byte_get(addr) \
|
||||
(__extension__({ \
|
||||
uint16_t __addr16 = (uint16_t)(addr); \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %1, %2\n\t" \
|
||||
"lpm %0, Z" "\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t) __BOOT_SIGROW_READ), \
|
||||
"z" (__addr16) \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_fill(address, data)
|
||||
|
||||
Fill the bootloader temporary page buffer for flash
|
||||
address with data word.
|
||||
|
||||
\note The address is a byte address. The data is a word. The AVR
|
||||
writes data to the buffer a word at a time, but addresses the buffer
|
||||
per byte! So, increment your address by 2 between calls, and send 2
|
||||
data bytes in a word format! The LSB of the data is written to the lower
|
||||
address; the MSB of the data is written to the higher address.*/
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_erase(address)
|
||||
|
||||
Erase the flash page that contains address.
|
||||
|
||||
\note address is a byte address in flash, not a word address. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_write(address)
|
||||
|
||||
Write the bootloader temporary page buffer
|
||||
to flash page that contains address.
|
||||
|
||||
\note address is a byte address in flash, not a word address. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_rww_enable()
|
||||
|
||||
Enable the Read-While-Write memory section. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_lock_bits_set(lock_bits)
|
||||
|
||||
Set the bootloader lock bits.
|
||||
|
||||
\param lock_bits A mask of which Boot Loader Lock Bits to set.
|
||||
|
||||
\note In this context, a 'set bit' will be written to a zero value.
|
||||
Note also that only BLBxx bits can be programmed by this command.
|
||||
|
||||
For example, to disallow the SPM instruction from writing to the Boot
|
||||
Loader memory section of flash, you would use this macro as such:
|
||||
|
||||
\code
|
||||
boot_lock_bits_set (_BV (BLB11));
|
||||
\endcode
|
||||
|
||||
\note Like any lock bits, the Boot Loader Lock Bits, once set,
|
||||
cannot be cleared again except by a chip erase which will in turn
|
||||
also erase the boot loader itself. */
|
||||
|
||||
/* Normal versions of the macros use 16-bit addresses.
|
||||
Extended versions of the macros use 32-bit addresses.
|
||||
Alternate versions of the macros use 16-bit addresses and require special
|
||||
instruction sequences after LPM.
|
||||
|
||||
FLASHEND is defined in the ioXXXX.h file.
|
||||
USHRT_MAX is defined in <limits.h>. */
|
||||
|
||||
#if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \
|
||||
|| defined(__AVR_ATmega323__)
|
||||
|
||||
/* Alternate: ATmega161/163/323 and 16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_alternate(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_alternate(address)
|
||||
#define boot_page_write(address) __boot_page_write_alternate(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_alternate()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits)
|
||||
|
||||
#elif (FLASHEND > USHRT_MAX)
|
||||
|
||||
/* Extended: >16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_extended_short(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_extended_short(address)
|
||||
#define boot_page_write(address) __boot_page_write_extended_short(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_short()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
|
||||
|
||||
#else
|
||||
|
||||
/* Normal: 16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_short(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_short(address)
|
||||
#define boot_page_write(address) __boot_page_write_short(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_short()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
|
||||
|
||||
#endif
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_fill() except it waits for eeprom and spm operations to
|
||||
complete before filling the page. */
|
||||
|
||||
#define boot_page_fill_safe(address, data) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_fill(address, data); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_erase() except it waits for eeprom and spm operations to
|
||||
complete before erasing the page. */
|
||||
|
||||
#define boot_page_erase_safe(address) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_erase (address); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_write() except it waits for eeprom and spm operations to
|
||||
complete before writing the page. */
|
||||
|
||||
#define boot_page_write_safe(address) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_write (address); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_rww_enable() except waits for eeprom and spm operations to
|
||||
complete before enabling the RWW mameory. */
|
||||
|
||||
#define boot_rww_enable_safe() \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_rww_enable(); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_lock_bits_set() except waits for eeprom and spm operations to
|
||||
complete before setting the lock bits. */
|
||||
|
||||
#define boot_lock_bits_set_safe(lock_bits) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_lock_bits_set (lock_bits); \
|
||||
} while (0)
|
||||
|
||||
#endif /* _AVR_BOOT_H_ */
|
||||
891
BootLoaders/AtmegaMultiBoot/Source/optiboot.c
Normal file
891
BootLoaders/AtmegaMultiBoot/Source/optiboot.c
Normal file
@@ -0,0 +1,891 @@
|
||||
/**********************************************************/
|
||||
/* Optiboot bootloader for Arduino */
|
||||
/* */
|
||||
/* http://optiboot.googlecode.com */
|
||||
/* */
|
||||
/* Arduino-maintained version : See README.TXT */
|
||||
/* http://code.google.com/p/arduino/ */
|
||||
/* It is the intent that changes not relevant to the */
|
||||
/* Arduino production envionment get moved from the */
|
||||
/* optiboot project to the arduino project in "lumps." */
|
||||
/* */
|
||||
/* Heavily optimised bootloader that is faster and */
|
||||
/* smaller than the Arduino standard bootloader */
|
||||
/* */
|
||||
/* Enhancements: */
|
||||
/* Fits in 512 bytes, saving 1.5K of code space */
|
||||
/* Background page erasing speeds up programming */
|
||||
/* Higher baud rate speeds up programming */
|
||||
/* Written almost entirely in C */
|
||||
/* Customisable timeout with accurate timeconstant */
|
||||
/* Optional virtual UART. No hardware UART required. */
|
||||
/* Optional virtual boot partition for devices without. */
|
||||
/* */
|
||||
/* What you lose: */
|
||||
/* Implements a skeleton STK500 protocol which is */
|
||||
/* missing several features including EEPROM */
|
||||
/* programming and non-page-aligned writes */
|
||||
/* High baud rate breaks compatibility with standard */
|
||||
/* Arduino flash settings */
|
||||
/* */
|
||||
/* Fully supported: */
|
||||
/* ATmega168 based devices (Diecimila etc) */
|
||||
/* ATmega328P based devices (Duemilanove etc) */
|
||||
/* */
|
||||
/* Beta test (believed working.) */
|
||||
/* ATmega8 based devices (Arduino legacy) */
|
||||
/* ATmega328 non-picopower devices */
|
||||
/* ATmega644P based devices (Sanguino) */
|
||||
/* ATmega1284P based devices */
|
||||
/* */
|
||||
/* Alpha test */
|
||||
/* ATmega1280 based devices (Arduino Mega) */
|
||||
/* */
|
||||
/* Work in progress: */
|
||||
/* ATtiny84 based devices (Luminet) */
|
||||
/* */
|
||||
/* Does not support: */
|
||||
/* USB based devices (eg. Teensy) */
|
||||
/* */
|
||||
/* Assumptions: */
|
||||
/* The code makes several assumptions that reduce the */
|
||||
/* code size. They are all true after a hardware reset, */
|
||||
/* but may not be true if the bootloader is called by */
|
||||
/* other means or on other hardware. */
|
||||
/* No interrupts can occur */
|
||||
/* UART and Timer 1 are set to their reset state */
|
||||
/* SP points to RAMEND */
|
||||
/* */
|
||||
/* Code builds on code, libraries and optimisations from: */
|
||||
/* stk500boot.c by Jason P. Kyle */
|
||||
/* Arduino bootloader http://arduino.cc */
|
||||
/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
|
||||
/* avr-libc project http://nongnu.org/avr-libc */
|
||||
/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */
|
||||
/* AVR305 Atmel Application Note */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it */
|
||||
/* and/or modify it under the terms of the GNU General */
|
||||
/* Public License as published by the Free Software */
|
||||
/* Foundation; either version 2 of the License, or */
|
||||
/* (at your option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will */
|
||||
/* be useful, but WITHOUT ANY WARRANTY; without even the */
|
||||
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
|
||||
/* PARTICULAR PURPOSE. See the GNU General Public */
|
||||
/* License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General */
|
||||
/* Public License along with this program; if not, write */
|
||||
/* to the Free Software Foundation, Inc., */
|
||||
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
/* */
|
||||
/* Licence can be viewed at */
|
||||
/* http://www.fsf.org/licenses/gpl.txt */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* Optional defines: */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* BIG_BOOT: */
|
||||
/* Build a 1k bootloader, not 512 bytes. This turns on */
|
||||
/* extra functionality. */
|
||||
/* */
|
||||
/* BAUD_RATE: */
|
||||
/* Set bootloader baud rate. */
|
||||
/* */
|
||||
/* LUDICROUS_SPEED: */
|
||||
/* 230400 baud :-) */
|
||||
/* */
|
||||
/* SOFT_UART: */
|
||||
/* Use AVR305 soft-UART instead of hardware UART. */
|
||||
/* */
|
||||
/* LED_START_FLASHES: */
|
||||
/* Number of LED flashes on bootup. */
|
||||
/* */
|
||||
/* LED_DATA_FLASH: */
|
||||
/* Flash LED when transferring data. For boards without */
|
||||
/* TX or RX LEDs, or for people who like blinky lights. */
|
||||
/* */
|
||||
/* SUPPORT_EEPROM: */
|
||||
/* Support reading and writing from EEPROM. This is not */
|
||||
/* used by Arduino, so off by default. */
|
||||
/* */
|
||||
/* TIMEOUT_MS: */
|
||||
/* Bootloader timeout period, in milliseconds. */
|
||||
/* 500,1000,2000,4000,8000 supported. */
|
||||
/* */
|
||||
/* UART: */
|
||||
/* UART number (0..n) for devices with more than */
|
||||
/* one hardware uart (644P, 1284P, etc) */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Version Numbers! */
|
||||
/* */
|
||||
/* Arduino Optiboot now includes this Version number in */
|
||||
/* the source and object code. */
|
||||
/* */
|
||||
/* Version 3 was released as zip from the optiboot */
|
||||
/* repository and was distributed with Arduino 0022. */
|
||||
/* Version 4 starts with the arduino repository commit */
|
||||
/* that brought the arduino repository up-to-date with */
|
||||
/* the optiboot source tree changes since v3. */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Edit History: */
|
||||
/* */
|
||||
/* Nov 2012 */
|
||||
/* Specific version for 9x voice module */
|
||||
/* by Mike Blandford */
|
||||
/* Mar 2012 */
|
||||
/* 4.5 WestfW: add infrastructure for non-zero UARTS. */
|
||||
/* 4.5 WestfW: fix SIGNATURE_2 for m644 (bad in avr-libc) */
|
||||
/* Jan 2012: */
|
||||
/* 4.5 WestfW: fix NRWW value for m1284. */
|
||||
/* 4.4 WestfW: use attribute OS_main instead of naked for */
|
||||
/* main(). This allows optimizations that we */
|
||||
/* count on, which are prohibited in naked */
|
||||
/* functions due to PR42240. (keeps us less */
|
||||
/* than 512 bytes when compiler is gcc4.5 */
|
||||
/* (code from 4.3.2 remains the same.) */
|
||||
/* 4.4 WestfW and Maniacbug: Add m1284 support. This */
|
||||
/* does not change the 328 binary, so the */
|
||||
/* version number didn't change either. (?) */
|
||||
/* June 2011: */
|
||||
/* 4.4 WestfW: remove automatic soft_uart detect (didn't */
|
||||
/* know what it was doing or why.) Added a */
|
||||
/* check of the calculated BRG value instead. */
|
||||
/* Version stays 4.4; existing binaries are */
|
||||
/* not changed. */
|
||||
/* 4.4 WestfW: add initialization of address to keep */
|
||||
/* the compiler happy. Change SC'ed targets. */
|
||||
/* Return the SW version via READ PARAM */
|
||||
/* 4.3 WestfW: catch framing errors in getch(), so that */
|
||||
/* AVRISP works without HW kludges. */
|
||||
/* http://code.google.com/p/arduino/issues/detail?id=368n*/
|
||||
/* 4.2 WestfW: reduce code size, fix timeouts, change */
|
||||
/* verifySpace to use WDT instead of appstart */
|
||||
/* 4.1 WestfW: put version number in binary. */
|
||||
/**********************************************************/
|
||||
|
||||
#define OPTIBOOT_MAJVER 4
|
||||
#define OPTIBOOT_MINVER 5
|
||||
|
||||
#define MULTI_CALLED 1
|
||||
|
||||
#define MAKESTR(a) #a
|
||||
#define MAKEVER(a, b) MAKESTR(a*256+b)
|
||||
|
||||
//asm(" .section .version\n"
|
||||
// "optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n"
|
||||
// " .section .text\n");
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// <avr/boot.h> uses sts instructions, but this version uses out instructions
|
||||
// This saves cycles and program memory.
|
||||
#include "boot.h"
|
||||
|
||||
|
||||
// We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
|
||||
|
||||
#include "pin_defs.h"
|
||||
#include "stk500.h"
|
||||
|
||||
#ifndef LED_START_FLASHES
|
||||
#define LED_START_FLASHES 0
|
||||
#endif
|
||||
|
||||
#ifdef LUDICROUS_SPEED
|
||||
#define BAUD_RATE 230400L
|
||||
#endif
|
||||
|
||||
/* set the UART baud rate defaults */
|
||||
#ifndef BAUD_RATE
|
||||
#if F_CPU >= 8000000L
|
||||
#define BAUD_RATE 38400L // Highest rate Avrdude win32 will support
|
||||
#elsif F_CPU >= 1000000L
|
||||
#define BAUD_RATE 9600L // 19200 also supported, but with significant error
|
||||
#elsif F_CPU >= 128000L
|
||||
#define BAUD_RATE 4800L // Good for 128kHz internal RC
|
||||
#else
|
||||
#define BAUD_RATE 1200L // Good even at 32768Hz
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef UART
|
||||
#define UART 0
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Switch in soft UART for hard baud rates */
|
||||
/*
|
||||
* I don't understand what this was supposed to accomplish, where the
|
||||
* constant "280" came from, or why automatically (and perhaps unexpectedly)
|
||||
* switching to a soft uart is a good thing, so I'm undoing this in favor
|
||||
* of a range check using the same calc used to config the BRG...
|
||||
*/
|
||||
#if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz
|
||||
#ifndef SOFT_UART
|
||||
#define SOFT_UART
|
||||
#endif
|
||||
#endif
|
||||
#else // 0
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250
|
||||
#error Unachievable baud rate (too slow) BAUD_RATE
|
||||
#endif // baud rate slow check
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3
|
||||
#error Unachievable baud rate (too fast) BAUD_RATE
|
||||
#endif // baud rate fastn check
|
||||
#endif
|
||||
|
||||
/* Watchdog settings */
|
||||
#define WATCHDOG_OFF (0)
|
||||
#define WATCHDOG_16MS (_BV(WDE))
|
||||
#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE))
|
||||
#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#ifndef __AVR_ATmega8__
|
||||
#define WATCHDOG_4S (_BV(WDP3) | _BV(WDE))
|
||||
#define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
|
||||
#endif
|
||||
|
||||
/* Function Prototypes */
|
||||
/* The main function is in init9, which removes the interrupt vector table */
|
||||
/* we don't need. It is also 'naked', which means the compiler does not */
|
||||
/* generate any entry or exit code itself. */
|
||||
int main(void) __attribute__ ((OS_main)) __attribute__ ((noreturn)) __attribute__ ((section (".init9")));
|
||||
void putch(char);
|
||||
uint8_t getch(void);
|
||||
static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */
|
||||
void verifySpace();
|
||||
#if LED_START_FLASHES > 0
|
||||
static inline void flash_led(uint8_t);
|
||||
#endif
|
||||
uint8_t getLen();
|
||||
//static inline void watchdogReset();
|
||||
void watchdogConfig(uint8_t x);
|
||||
#ifdef SOFT_UART
|
||||
void uartDelay() __attribute__ ((naked));
|
||||
#endif
|
||||
static void appStart() ; // __attribute__ ((naked));
|
||||
|
||||
/*
|
||||
* NRWW memory
|
||||
* Addresses below NRWW (Non-Read-While-Write) can be programmed while
|
||||
* continuing to run code from flash, slightly speeding up programming
|
||||
* time. Beware that Atmel data sheets specify this as a WORD address,
|
||||
* while optiboot will be comparing against a 16-bit byte address. This
|
||||
* means that on a part with 128kB of memory, the upper part of the lower
|
||||
* 64k will get NRWW processing as well, even though it doesn't need it.
|
||||
* That's OK. In fact, you can disable the overlapping processing for
|
||||
* a part entirely by setting NRWWSTART to zero. This reduces code
|
||||
* space a bit, at the expense of being slightly slower, overall.
|
||||
*
|
||||
* RAMSTART should be self-explanatory. It's bigger on parts with a
|
||||
* lot of peripheral registers.
|
||||
*/
|
||||
#if defined(__AVR_ATmega168__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x3800)
|
||||
#elif defined(__AVR_ATmega328P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined(__AVR_ATmega328__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined (__AVR_ATmega644P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
// correct for a bug in avr-libc
|
||||
#undef SIGNATURE_2
|
||||
#define SIGNATURE_2 0x0A
|
||||
#elif defined (__AVR_ATmega1284P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATtiny84__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x0000)
|
||||
#elif defined(__AVR_ATmega1280__)
|
||||
#define RAMSTART (0x200)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x1800)
|
||||
#endif
|
||||
|
||||
/* C zero initialises all global variables. However, that requires */
|
||||
/* These definitions are NOT zero initialised, but that doesn't matter */
|
||||
/* This allows us to drop the zero init code, saving us memory */
|
||||
#define buff ((uint8_t*)(RAMSTART))
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
#define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4))
|
||||
#define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle devices with up to 4 uarts (eg m1280.) Rather inelegantly.
|
||||
* Note that mega8 still needs special handling, because ubrr is handled
|
||||
* differently.
|
||||
*/
|
||||
#if UART == 0
|
||||
# define UART_SRA UCSR0A
|
||||
# define UART_SRB UCSR0B
|
||||
# define UART_SRC UCSR0C
|
||||
# define UART_SRL UBRR0L
|
||||
# define UART_UDR UDR0
|
||||
#elif UART == 1
|
||||
# define UART_SRA UCSR1A
|
||||
# define UART_SRB UCSR1B
|
||||
# define UART_SRC UCSR1C
|
||||
# define UART_SRL UBRR1L
|
||||
# define UART_UDR UDR1
|
||||
#elif UART == 2
|
||||
# define UART_SRA UCSR2A
|
||||
# define UART_SRB UCSR2B
|
||||
# define UART_SRC UCSR2C
|
||||
# define UART_SRL UBRR2L
|
||||
# define UART_UDR UDR2
|
||||
#elif UART == 3
|
||||
# define UART_SRA UCSR3A
|
||||
# define UART_SRB UCSR3B
|
||||
# define UART_SRC UCSR3C
|
||||
# define UART_SRL UBRR3L
|
||||
# define UART_UDR UDR3
|
||||
#endif
|
||||
|
||||
/* main program starts here */
|
||||
int main(void) {
|
||||
uint8_t ch;
|
||||
|
||||
/*
|
||||
* Making these local and in registers prevents the need for initializing
|
||||
* them, and also saves space because code no longer stores to memory.
|
||||
* (initializing address keeps the compiler happy, but isn't really
|
||||
* necessary, and uses 4 bytes of flash.)
|
||||
*/
|
||||
register uint16_t address = 0;
|
||||
|
||||
// After the zero init loop, this is the first code to run.
|
||||
//
|
||||
// This code makes the following assumptions:
|
||||
// No interrupts will execute
|
||||
// SP points to RAMEND
|
||||
// r1 contains zero
|
||||
//
|
||||
// If not, uncomment the following instructions:
|
||||
// cli();
|
||||
asm volatile ("clr __zero_reg__");
|
||||
#ifdef __AVR_ATmega8__
|
||||
SP=RAMEND; // This is done by hardware reset
|
||||
#endif
|
||||
|
||||
// Adaboot no-wait mod
|
||||
ch = MCUSR;
|
||||
MCUSR = 0;
|
||||
|
||||
// Here, if power on, wait 0.5 secs, then check for
|
||||
// serial Rx signal low, if so, stay in bootloader
|
||||
// else go to application
|
||||
|
||||
PORTD = 0xFF ;
|
||||
PORTB = 0x3C ;
|
||||
PORTC = 1 ;
|
||||
|
||||
if (ch & (_BV(PORF) | (_BV(EXTRF)) ) )
|
||||
{
|
||||
#ifdef MULTI_CALLED
|
||||
#if F_CPU == 12000000L
|
||||
TCNT1H = 256 - 8 ;
|
||||
#else
|
||||
#if F_CPU == 16000000L
|
||||
TCNT1H = 256 - 6 ;
|
||||
#else
|
||||
TCNT1H = 256 - 127 ;
|
||||
#endif
|
||||
TCNT1L = 0 ;
|
||||
#endif
|
||||
#else
|
||||
#if F_CPU == 12000000L
|
||||
TCNT1 = 65535-5859 ;
|
||||
#else
|
||||
#if F_CPU == 16000000L
|
||||
TCNT1 = 65535-7813 ;
|
||||
#else
|
||||
TCNT1 = 65535-32767 ;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
|
||||
TIFR1 = _BV(TOV1);
|
||||
while(!(TIFR1 & _BV(TOV1)))
|
||||
;
|
||||
TCCR1B = 0 ; // Stop timer
|
||||
uint8_t x ;
|
||||
x = PINB & 0x3C ;
|
||||
x |= PINC & 1 ;
|
||||
if ( x != 0x1D )
|
||||
{
|
||||
appStart() ; // Power on, go to voice application
|
||||
// if loaded
|
||||
}
|
||||
}
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
// Set up Timer 1 for timeout counter
|
||||
TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
|
||||
#endif
|
||||
|
||||
#ifndef SOFT_UART
|
||||
UART_SRA = _BV(U2X0); //Double speed mode USART0
|
||||
UART_SRB = _BV(RXEN0) | _BV(TXEN0);
|
||||
UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
|
||||
// UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
|
||||
// Baudrate of 57600
|
||||
#if F_CPU == 12000000L
|
||||
UART_SRL = 25 ;
|
||||
#else
|
||||
#if F_CPU == 16000000L
|
||||
UART_SRL = 33 ;
|
||||
#else
|
||||
#ERROR Baud rate not available
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Set up watchdog to trigger after 500ms
|
||||
|
||||
|
||||
// watchdogConfig(WATCHDOG_1S);
|
||||
|
||||
/* Set LED pin as output */
|
||||
LED_DDR |= _BV(LED);
|
||||
|
||||
#ifdef SOFT_UART
|
||||
/* Set TX pin as output */
|
||||
UART_DDR |= _BV(UART_TX_BIT);
|
||||
#endif
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
/* Flash onboard LED to signal entering of bootloader */
|
||||
flash_led(LED_START_FLASHES * 2);
|
||||
#endif
|
||||
|
||||
/* Forever loop */
|
||||
for (;;)
|
||||
{
|
||||
/* get character from UART */
|
||||
ch = getch();
|
||||
|
||||
if(ch == STK_GET_PARAMETER)
|
||||
{
|
||||
GPIOR0 = getch();
|
||||
verifySpace();
|
||||
if (GPIOR0 == 0x82)
|
||||
{
|
||||
/*
|
||||
* Send optiboot version as "minor SW version"
|
||||
*/
|
||||
putch(OPTIBOOT_MINVER);
|
||||
}
|
||||
else if (GPIOR0 == 0x81)
|
||||
{
|
||||
putch(OPTIBOOT_MAJVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* GET PARAMETER returns a generic 0x03 reply for
|
||||
* other parameters - enough to keep Avrdude happy
|
||||
*/
|
||||
putch(0x03);
|
||||
}
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE) {
|
||||
// SET DEVICE is ignored
|
||||
getNch(20);
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE_EXT)
|
||||
{
|
||||
// SET DEVICE EXT is ignored
|
||||
getNch(5);
|
||||
}
|
||||
else if(ch == STK_LOAD_ADDRESS)
|
||||
{
|
||||
// LOAD ADDRESS
|
||||
uint16_t newAddress;
|
||||
newAddress = getch() ;
|
||||
newAddress = (newAddress & 0xff) | (getch() << 8);
|
||||
#ifdef RAMPZ
|
||||
// Transfer top bit to RAMPZ
|
||||
RAMPZ = (newAddress & 0x8000) ? 1 : 0;
|
||||
#endif
|
||||
newAddress += newAddress; // Convert from word address to byte address
|
||||
address = newAddress;
|
||||
verifySpace();
|
||||
}
|
||||
else if(ch == STK_UNIVERSAL)
|
||||
{
|
||||
// UNIVERSAL command is ignored
|
||||
getNch(4);
|
||||
putch(0x00);
|
||||
}
|
||||
/* Write memory, length is big endian and is in bytes */
|
||||
else if(ch == STK_PROG_PAGE)
|
||||
{
|
||||
// PROGRAM PAGE - we support flash programming only, not EEPROM
|
||||
uint8_t *bufPtr;
|
||||
uint16_t addrPtr;
|
||||
register uint8_t length;
|
||||
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
// If we are in RWW section, immediately start page erase
|
||||
if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
|
||||
// While that is going on, read in page contents
|
||||
bufPtr = buff;
|
||||
do *bufPtr++ = getch();
|
||||
while (--length);
|
||||
|
||||
// If we are in NRWW section, page erase has to be delayed until now.
|
||||
// Todo: Take RAMPZ into account
|
||||
#ifdef MULTI_CALLED
|
||||
if (address < 0x7E00)
|
||||
#endif
|
||||
{
|
||||
if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
}
|
||||
// Read command terminator, start reply
|
||||
verifySpace();
|
||||
|
||||
// If only a partial page is to be programmed, the erase might not be complete.
|
||||
// So check that here
|
||||
#ifdef MULTI_CALLED
|
||||
if (address < 0x7E00)
|
||||
#endif
|
||||
{
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
if ((uint16_t)(void*)address == 0) {
|
||||
// This is the reset vector page. We need to live-patch the code so the
|
||||
// bootloader runs.
|
||||
//
|
||||
// Move RESET vector to WDT vector
|
||||
uint16_t vect = buff[0] | (buff[1]<<8);
|
||||
rstVect = vect;
|
||||
wdtVect = buff[8] | (buff[9]<<8);
|
||||
vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
|
||||
buff[8] = vect & 0xff;
|
||||
buff[9] = vect >> 8;
|
||||
|
||||
// Add jump to bootloader at RESET vector
|
||||
buff[0] = 0x7f;
|
||||
buff[1] = 0xce; // rjmp 0x1d00 instruction
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy buffer into programming buffer
|
||||
bufPtr = buff;
|
||||
addrPtr = (uint16_t)(void*)address;
|
||||
ch = SPM_PAGESIZE / 2;
|
||||
do {
|
||||
uint16_t a;
|
||||
// a = *bufPtr++;
|
||||
// a |= (*bufPtr++) << 8;
|
||||
|
||||
a = *((uint16_t *)bufPtr) ;
|
||||
bufPtr += 2 ;
|
||||
|
||||
__boot_page_fill_short((uint16_t)(void*)addrPtr,a);
|
||||
addrPtr += 2;
|
||||
} while (--ch);
|
||||
|
||||
// Write from programming buffer
|
||||
__boot_page_write_short((uint16_t)(void*)address);
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#if defined(RWWSRE)
|
||||
// Reenable read access to flash
|
||||
boot_rww_enable();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Read memory block mode, length is big endian. */
|
||||
else if(ch == STK_READ_PAGE)
|
||||
{
|
||||
register uint8_t length;
|
||||
// READ PAGE - we only read flash
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
verifySpace();
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
do {
|
||||
// Undo vector patch in bottom page so verify passes
|
||||
if (address == 0) ch=rstVect & 0xff;
|
||||
else if (address == 1) ch=rstVect >> 8;
|
||||
else if (address == 8) ch=wdtVect & 0xff;
|
||||
else if (address == 9) ch=wdtVect >> 8;
|
||||
else ch = pgm_read_byte_near(address);
|
||||
address++;
|
||||
putch(ch);
|
||||
} while (--length);
|
||||
#else
|
||||
#ifdef RAMPZ
|
||||
// Since RAMPZ should already be set, we need to use EPLM directly.
|
||||
// do putch(pgm_read_byte_near(address++));
|
||||
// while (--length);
|
||||
do {
|
||||
uint8_t result;
|
||||
__asm__ ("elpm %0,Z\n":"=r"(result):"z"(address));
|
||||
putch(result);
|
||||
address++;
|
||||
}
|
||||
while (--length);
|
||||
#else
|
||||
do putch(pgm_read_byte_near(address++));
|
||||
while (--length);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get device signature bytes */
|
||||
else if(ch == STK_READ_SIGN)
|
||||
{
|
||||
// READ SIGN - return what Avrdude wants to hear
|
||||
verifySpace();
|
||||
putch(SIGNATURE_0);
|
||||
putch(SIGNATURE_1);
|
||||
putch(SIGNATURE_2);
|
||||
}
|
||||
else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
|
||||
// Adaboot no-wait mod
|
||||
|
||||
// watchdogConfig(WATCHDOG_16MS);
|
||||
|
||||
verifySpace();
|
||||
#ifdef MULTI_CALLED
|
||||
putch(STK_OK);
|
||||
while (!(UART_SRA & _BV(TXC0)));
|
||||
appStart() ;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// This covers the response to commands like STK_ENTER_PROGMODE
|
||||
verifySpace();
|
||||
}
|
||||
putch(STK_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void putch(char ch) {
|
||||
#ifndef SOFT_UART
|
||||
while (!(UART_SRA & _BV(UDRE0)));
|
||||
UART_UDR = ch;
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
" com %[ch]\n" // ones complement, carry set
|
||||
" sec\n"
|
||||
"1: brcc 2f\n"
|
||||
" cbi %[uartPort],%[uartBit]\n"
|
||||
" rjmp 3f\n"
|
||||
"2: sbi %[uartPort],%[uartBit]\n"
|
||||
" nop\n"
|
||||
"3: rcall uartDelay\n"
|
||||
" rcall uartDelay\n"
|
||||
" lsr %[ch]\n"
|
||||
" dec %[bitcnt]\n"
|
||||
" brne 1b\n"
|
||||
:
|
||||
:
|
||||
[bitcnt] "d" (10),
|
||||
[ch] "r" (ch),
|
||||
[uartPort] "I" (_SFR_IO_ADDR(UART_PORT)),
|
||||
[uartBit] "I" (UART_TX_BIT)
|
||||
:
|
||||
"r25"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t getch(void) {
|
||||
uint8_t ch;
|
||||
|
||||
#ifdef LED_DATA_FLASH
|
||||
#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
#else
|
||||
LED_PIN |= _BV(LED);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SOFT_UART
|
||||
__asm__ __volatile__ (
|
||||
"1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge
|
||||
" rjmp 1b\n"
|
||||
" rcall uartDelay\n" // Get to middle of start bit
|
||||
"2: rcall uartDelay\n" // Wait 1 bit period
|
||||
" rcall uartDelay\n" // Wait 1 bit period
|
||||
" clc\n"
|
||||
" sbic %[uartPin],%[uartBit]\n"
|
||||
" sec\n"
|
||||
" dec %[bitCnt]\n"
|
||||
" breq 3f\n"
|
||||
" ror %[ch]\n"
|
||||
" rjmp 2b\n"
|
||||
"3:\n"
|
||||
:
|
||||
[ch] "=r" (ch)
|
||||
:
|
||||
[bitCnt] "d" (9),
|
||||
[uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
|
||||
[uartBit] "I" (UART_RX_BIT)
|
||||
:
|
||||
"r25"
|
||||
);
|
||||
#else
|
||||
while(!(UART_SRA & _BV(RXC0)))
|
||||
|
||||
// watchdogReset()
|
||||
|
||||
;
|
||||
// if (!(UART_SRA & _BV(FE0))) {
|
||||
/*
|
||||
* A Framing Error indicates (probably) that something is talking
|
||||
* to us at the wrong bit rate. Assume that this is because it
|
||||
* expects to be talking to the application, and DON'T reset the
|
||||
* watchdog. This should cause the bootloader to abort and run
|
||||
* the application "soon", if it keeps happening. (Note that we
|
||||
* don't care that an invalid char is returned...)
|
||||
*/
|
||||
// watchdogReset();
|
||||
// }
|
||||
|
||||
ch = UART_UDR;
|
||||
#endif
|
||||
|
||||
#ifdef LED_DATA_FLASH
|
||||
#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
#else
|
||||
LED_PIN |= _BV(LED);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
#ifdef SOFT_UART
|
||||
// AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
|
||||
// Adding 3 to numerator simulates nearest rounding for more accurate baud rates
|
||||
#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
|
||||
#if UART_B_VALUE > 255
|
||||
#error Baud rate too slow for soft UART
|
||||
#endif
|
||||
|
||||
void uartDelay() {
|
||||
__asm__ __volatile__ (
|
||||
"ldi r25,%[count]\n"
|
||||
"1:dec r25\n"
|
||||
"brne 1b\n"
|
||||
"ret\n"
|
||||
::[count] "M" (UART_B_VALUE)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
void getNch(uint8_t count) {
|
||||
do getch(); while (--count);
|
||||
verifySpace();
|
||||
}
|
||||
|
||||
void verifySpace()
|
||||
{
|
||||
if ( getch() != CRC_EOP) {
|
||||
|
||||
putch(STK_NOSYNC);
|
||||
// watchdogConfig(WATCHDOG_16MS); // shorten WD timeout
|
||||
//
|
||||
// while (1) // and busy-loop so that WD causes
|
||||
// ; // a reset and app start.
|
||||
}
|
||||
putch(STK_INSYNC);
|
||||
}
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
void flash_led(uint8_t count) {
|
||||
do {
|
||||
TCNT1 = -(F_CPU/(1024*16));
|
||||
TIFR1 = _BV(TOV1);
|
||||
while(!(TIFR1 & _BV(TOV1)));
|
||||
//#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
watchdogReset();
|
||||
} while (--count);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Watchdog functions. These are only safe with interrupts turned off.
|
||||
void watchdogReset() {
|
||||
__asm__ __volatile__ (
|
||||
"wdr\n"
|
||||
);
|
||||
}
|
||||
|
||||
void watchdogConfig(uint8_t x) {
|
||||
WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||
WDTCSR = x;
|
||||
}
|
||||
|
||||
void appStart()
|
||||
{
|
||||
// watchdogConfig(WATCHDOG_OFF);
|
||||
// __asm__ __volatile__ (
|
||||
//#ifdef VIRTUAL_BOOT_PARTITION
|
||||
// // Jump to WDT vector
|
||||
// "ldi r30,4\n"
|
||||
// "clr r31\n"
|
||||
//#else
|
||||
// // Jump to RST vector
|
||||
// "clr r30\n"
|
||||
// "clr r31\n"
|
||||
//#endif
|
||||
// "ijmp\n"
|
||||
// );
|
||||
|
||||
register void (*p)() ;
|
||||
p = 0 ;
|
||||
|
||||
if ( pgm_read_byte( (uint16_t)p ) != 0xFF )
|
||||
{
|
||||
(*p)() ;
|
||||
}
|
||||
}
|
||||
|
||||
80
BootLoaders/AtmegaMultiBoot/Source/pin_defs.h
Normal file
80
BootLoaders/AtmegaMultiBoot/Source/pin_defs.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB5
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega8__)
|
||||
//Name conversion R.Wiersma
|
||||
#define UCSR0A UCSRA
|
||||
#define UDR0 UDR
|
||||
#define UDRE0 UDRE
|
||||
#define RXC0 RXC
|
||||
#define FE0 FE
|
||||
#define TIFR1 TIFR
|
||||
#define WDTCSR WDTCR
|
||||
#endif
|
||||
|
||||
/* Luminet support */
|
||||
#if defined(__AVR_ATtiny84__)
|
||||
/* Red LED is connected to pin PA4 */
|
||||
#define LED_DDR DDRA
|
||||
#define LED_PORT PORTA
|
||||
#define LED_PIN PINA
|
||||
#define LED PINA4
|
||||
/* Ports for soft UART - left port only for now. TX/RX on PA2/PA3 */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTA
|
||||
#define UART_PIN PINA
|
||||
#define UART_DDR DDRA
|
||||
#define UART_TX_BIT 2
|
||||
#define UART_RX_BIT 3
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Sanguino support */
|
||||
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
|
||||
/* Onboard LED is connected to pin PB0 on Sanguino */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB0
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Mega support */
|
||||
#if defined(__AVR_ATmega1280__)
|
||||
/* Onboard LED is connected to pin PB7 on Arduino Mega */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB7
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTE
|
||||
#define UART_PIN PINE
|
||||
#define UART_DDR DDRE
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
39
BootLoaders/AtmegaMultiBoot/Source/stk500.h
Normal file
39
BootLoaders/AtmegaMultiBoot/Source/stk500.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* STK500 constants list, from AVRDUDE */
|
||||
#define STK_OK 0x10
|
||||
#define STK_FAILED 0x11 // Not used
|
||||
#define STK_UNKNOWN 0x12 // Not used
|
||||
#define STK_NODEVICE 0x13 // Not used
|
||||
#define STK_INSYNC 0x14 // ' '
|
||||
#define STK_NOSYNC 0x15 // Not used
|
||||
#define ADC_CHANNEL_ERROR 0x16 // Not used
|
||||
#define ADC_MEASURE_OK 0x17 // Not used
|
||||
#define PWM_CHANNEL_ERROR 0x18 // Not used
|
||||
#define PWM_ADJUST_OK 0x19 // Not used
|
||||
#define CRC_EOP 0x20 // 'SPACE'
|
||||
#define STK_GET_SYNC 0x30 // '0'
|
||||
#define STK_GET_SIGN_ON 0x31 // '1'
|
||||
#define STK_SET_PARAMETER 0x40 // '@'
|
||||
#define STK_GET_PARAMETER 0x41 // 'A'
|
||||
#define STK_SET_DEVICE 0x42 // 'B'
|
||||
#define STK_SET_DEVICE_EXT 0x45 // 'E'
|
||||
#define STK_ENTER_PROGMODE 0x50 // 'P'
|
||||
#define STK_LEAVE_PROGMODE 0x51 // 'Q'
|
||||
#define STK_CHIP_ERASE 0x52 // 'R'
|
||||
#define STK_CHECK_AUTOINC 0x53 // 'S'
|
||||
#define STK_LOAD_ADDRESS 0x55 // 'U'
|
||||
#define STK_UNIVERSAL 0x56 // 'V'
|
||||
#define STK_PROG_FLASH 0x60 // '`'
|
||||
#define STK_PROG_DATA 0x61 // 'a'
|
||||
#define STK_PROG_FUSE 0x62 // 'b'
|
||||
#define STK_PROG_LOCK 0x63 // 'c'
|
||||
#define STK_PROG_PAGE 0x64 // 'd'
|
||||
#define STK_PROG_FUSE_EXT 0x65 // 'e'
|
||||
#define STK_READ_FLASH 0x70 // 'p'
|
||||
#define STK_READ_DATA 0x71 // 'q'
|
||||
#define STK_READ_FUSE 0x72 // 'r'
|
||||
#define STK_READ_LOCK 0x73 // 's'
|
||||
#define STK_READ_PAGE 0x74 // 't'
|
||||
#define STK_READ_SIGN 0x75 // 'u'
|
||||
#define STK_READ_OSCCAL 0x76 // 'v'
|
||||
#define STK_READ_FUSE_EXT 0x77 // 'w'
|
||||
#define STK_READ_OSCCAL_EXT 0x78 // 'x'
|
||||
5
BootLoaders/Boards/Linux/45-maple.rules
Normal file
5
BootLoaders/Boards/Linux/45-maple.rules
Normal file
@@ -0,0 +1,5 @@
|
||||
ATTRS{idProduct}=="1001", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idProduct}=="1002", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idProduct}=="0003", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
ATTRS{idProduct}=="0004", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
|
||||
11
BootLoaders/Boards/Windows/install_drivers.bat
Normal file
11
BootLoaders/Boards/Windows/install_drivers.bat
Normal file
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
|
||||
echo Installing Maple DFU driver...
|
||||
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0003 --type 1 --name "Maple DFU" --dest "%~dp0maple-dfu"
|
||||
echo.
|
||||
|
||||
echo Installing Maple Serial driver...
|
||||
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0004 --type 3 --name "Maple Serial" --dest "%~dp0maple-serial"
|
||||
echo.
|
||||
|
||||
pause
|
||||
BIN
BootLoaders/Boards/Windows/wdi-simple.exe
Normal file
BIN
BootLoaders/Boards/Windows/wdi-simple.exe
Normal file
Binary file not shown.
47
BootLoaders/OrangeMultiBoot/OrangeMultiBoot.hex
Normal file
47
BootLoaders/OrangeMultiBoot/OrangeMultiBoot.hex
Normal file
@@ -0,0 +1,47 @@
|
||||
:108000001F92CDB7DEB7CFD01124809178009FEFBB
|
||||
:1080100090937800837099F088EA91E680936808DD
|
||||
:108020009093690880E180934C0880914C0884FF0C
|
||||
:10803000FCCF109240088091680682FD8FD082E0CC
|
||||
:1080400080936106C12CD12C97D0813479F494D0DF
|
||||
:10805000898399D08981823811F485E005C08138FF
|
||||
:1080600011F484E001C083E080D075C0823411F443
|
||||
:1080700084E103C0853419F485E08CD06CC085356B
|
||||
:1080800059F47AD0C82E78D0D12CD82A8D2D881FBB
|
||||
:108090008827881F8BBF5EC0863521F484E07AD0A4
|
||||
:1080A00080E0E2CF843641F567D066D0F82E64D008
|
||||
:1080B000C601DCD000E010E25FD0F80181938F01AF
|
||||
:1080C000FE12FACF60D0D7FC46C0CBD0C601DAD0C2
|
||||
:1080D000760100E010E2F801619171918F01C70112
|
||||
:1080E000DBD0F2E0EF0EF11C011581E2180799F7E1
|
||||
:1080F000C601E0D0B6D02FC08437C1F43DD03CD00B
|
||||
:10810000F82E3AD040D0F601EC2CEF0C8F010F5F27
|
||||
:108110001F4F84912AD0E01207C0EFEFCE1ADE0A7B
|
||||
:10812000FA94CF0CD11C17C0F801F0CF853739F481
|
||||
:108130002AD08EE11AD085E918D082E495CF813516
|
||||
:1081400049F421D080E111D08091A10886FFFCCFB5
|
||||
:1081500005D001C018D080E108D076CFE0E0F0E093
|
||||
:1081600084918F3F09F0099408959091A10895FF9B
|
||||
:10817000FCCF8093A00808958091A10887FFFCCFD1
|
||||
:108180008091A0080895F8DF803211F085E1EDDFDD
|
||||
:1081900084E1EBCFCF93C82FEFDFC150E9F7CF9148
|
||||
:1081A000F2CFA895089583EC8093520080915000FF
|
||||
:1081B0008860809350008091510083FFFCCF82EC57
|
||||
:1081C0008093550080915000806180935000809191
|
||||
:1081D000510084FFFCCF88ED84BF1092400084BF23
|
||||
:1081E00024E02093400087E08093A20087E88093FA
|
||||
:1081F0008301109241081092420810924308109295
|
||||
:10820000440810924608109247088FEF9FEF809322
|
||||
:1082100066089093670810926008109261088BE0DE
|
||||
:1082200080934008209365062093620688E180933E
|
||||
:10823000720698E0909345069093410692E29093DF
|
||||
:10824000A6081092A7088093A4088091A3088F7CA9
|
||||
:1082500080618093A30883E08093A5088091A008A3
|
||||
:1082600008958091CF0187FDFCCF08958F939F9350
|
||||
:1082700082E2E0ECF1E08287FF91EF918DE984BF2B
|
||||
:10828000E8950895FC0186E28093CA0188ED84BFD9
|
||||
:1082900081E08093CB0108950F921F92FC01062E7E
|
||||
:1082A000172E83E28093CA018DE984BFE8951F9061
|
||||
:1082B0000F900895FC018EE28093CA018DE984BF7E
|
||||
:0482C000E8950895A0
|
||||
:040000030000800079
|
||||
:00000001FF
|
||||
503
BootLoaders/OrangeMultiBoot/Source/Makefile
Normal file
503
BootLoaders/OrangeMultiBoot/Source/Makefile
Normal file
@@ -0,0 +1,503 @@
|
||||
# Makefile for ATmegaBOOT
|
||||
# E.Lins, 18.7.2005
|
||||
# $Id$
|
||||
#
|
||||
# Instructions
|
||||
#
|
||||
# To make bootloader .hex file:
|
||||
# make diecimila
|
||||
# make lilypad
|
||||
# make ng
|
||||
# etc...
|
||||
#
|
||||
# To burn bootloader .hex file:
|
||||
# make diecimila_isp
|
||||
# make lilypad_isp
|
||||
# make ng_isp
|
||||
# etc...
|
||||
|
||||
# program name should not be changed...
|
||||
PROGRAM = optiboot
|
||||
|
||||
# The default behavior is to build using tools that are in the users
|
||||
# current path variables, but we can also build using an installed
|
||||
# Arduino user IDE setup, or the Arduino source tree.
|
||||
# Uncomment this next lines to build within the arduino environment,
|
||||
# using the arduino-included avrgcc toolset (mac and pc)
|
||||
# ENV ?= arduino
|
||||
# ENV ?= arduinodev
|
||||
# OS ?= macosx
|
||||
# OS ?= windows
|
||||
|
||||
|
||||
# enter the parameters for the avrdude isp tool -b19200
|
||||
#
|
||||
# These are the parameters for a usb-based STK500v2 programmer.
|
||||
# Exact type unknown. (historical Makefile values.)
|
||||
ISPTOOL = stk500v2
|
||||
ISPPORT = usb
|
||||
ISPSPEED = -b 57600
|
||||
#
|
||||
#
|
||||
# These are parameters for using an Arduino with the ArduinoISP sketch
|
||||
# as the programmer. On a mac, for a particular Uno as programmer.
|
||||
#ISPTOOL = stk500v1 -C /Applications/arduino/arduino-0022/hardware/tools/avr/etc/avrdude.conf
|
||||
#ISPPORT = /dev/tty.usbmodemfd3141
|
||||
#ISPSPEED = -b19200
|
||||
|
||||
MCU_TARGET = atmega168
|
||||
LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe
|
||||
|
||||
# Build environments
|
||||
# Start of some ugly makefile-isms to allow optiboot to be built
|
||||
# in several different environments. See the README.TXT file for
|
||||
# details.
|
||||
|
||||
# default
|
||||
fixpath = $(1)
|
||||
|
||||
ifeq ($(ENV), arduino)
|
||||
# For Arduino, we assume that we're connected to the optiboot directory
|
||||
# included with the arduino distribution, which means that the full set
|
||||
# of avr-tools are "right up there" in standard places.
|
||||
TOOLROOT = ../../../tools
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
ifeq ($(OS), windows)
|
||||
# On windows, SOME of the tool paths will need to have backslashes instead
|
||||
# of forward slashes (because they use windows cmd.exe for execution instead
|
||||
# of a unix/mingw shell?) We also have to ensure that a consistent shell
|
||||
# is used even if a unix shell is installed (ie as part of WINAVR)
|
||||
fixpath = $(subst /,\,$1)
|
||||
SHELL = cmd.exe
|
||||
endif
|
||||
|
||||
else ifeq ($(ENV), arduinodev)
|
||||
# Arduino IDE source code environment. Use the unpacked compilers created
|
||||
# by the build (you'll need to do "ant build" first.)
|
||||
ifeq ($(OS), macosx)
|
||||
TOOLROOT = ../../../../build/macosx/work/Arduino.app/Contents/Resources/Java/hardware/tools
|
||||
endif
|
||||
ifeq ($(OS), windows)
|
||||
TOOLROOT = ../../../../build/windows/work/hardware/tools
|
||||
endif
|
||||
|
||||
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||
|
||||
else
|
||||
GCCROOT =
|
||||
AVRDUDE_CONF =
|
||||
endif
|
||||
#
|
||||
# End of build environment code.
|
||||
|
||||
|
||||
# the efuse should really be 0xf8; since, however, only the lower
|
||||
# three bits of that byte are used on the atmega168, avrdude gets
|
||||
# confused if you specify 1's for the higher bits, see:
|
||||
# http://tinker.it/now/2007/02/24/the-tale-of-avrdude-atmega168-and-extended-bits-fuses/
|
||||
#
|
||||
# similarly, the lock bits should be 0xff instead of 0x3f (to
|
||||
# unlock the bootloader section) and 0xcf instead of 0x2f (to
|
||||
# lock it), but since the high two bits of the lock byte are
|
||||
# unused, avrdude would get confused.
|
||||
|
||||
ISPFUSES = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-e -u -U lock:w:0x3f:m -U efuse:w:0x$(EFUSE):m \
|
||||
-U hfuse:w:0x$(HFUSE):m -U lfuse:w:0x$(LFUSE):m
|
||||
ISPFLASH = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||
-U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x2f:m
|
||||
|
||||
STK500 = "C:\Program Files\Atmel\AVR Tools\STK500\Stk500.exe"
|
||||
STK500-1 = $(STK500) -e -d$(MCU_TARGET) -pf -vf -if$(PROGRAM)_$(TARGET).hex \
|
||||
-lFF -LFF -f$(HFUSE)$(LFUSE) -EF8 -ms -q -cUSB -I200kHz -s -wt
|
||||
STK500-2 = $(STK500) -d$(MCU_TARGET) -ms -q -lCF -LCF -cUSB -I200kHz -s -wt
|
||||
|
||||
OBJ = $(PROGRAM).o
|
||||
OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types
|
||||
# -mshort-calls
|
||||
|
||||
DEFS =
|
||||
LIBS =
|
||||
|
||||
CC = $(GCCROOT)avr-gcc
|
||||
|
||||
# Override is only needed by avr-lib build system.
|
||||
|
||||
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
|
||||
override LDFLAGS = $(LDSECTIONS) -Wl,--relax -Wl,--gc-sections -nostartfiles -nostdlib
|
||||
|
||||
OBJCOPY = $(GCCROOT)avr-objcopy
|
||||
OBJDUMP = $(call fixpath,$(GCCROOT)avr-objdump)
|
||||
|
||||
SIZE = $(GCCROOT)avr-size
|
||||
|
||||
|
||||
|
||||
#Voice board test
|
||||
# ATmega328
|
||||
#
|
||||
#atmega328: TARGET = atmega328p
|
||||
#atmega328: MCU_TARGET = atmega328p
|
||||
#atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
#atmega328: AVR_FREQ = 12000000L
|
||||
#atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
#atmega328: $(PROGRAM)_atmega328.hex
|
||||
#atmega328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
xmega32D4: TARGET = atxmega32d4
|
||||
xmega32D4: MCU_TARGET = atxmega32d4
|
||||
xmega32D4: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
xmega32D4: AVR_FREQ = 32000000L
|
||||
xmega32D4: LDSECTIONS = -Wl,--section-start=.text=0x8000
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.hex
|
||||
xmega32D4: $(PROGRAM)_xmega32d4.lst
|
||||
|
||||
atmega328: TARGET = atmega328
|
||||
atmega328: MCU_TARGET = atmega328p
|
||||
atmega328: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=57600'
|
||||
atmega328: AVR_FREQ = 16000000L
|
||||
atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328: $(PROGRAM)_atmega328_16.hex
|
||||
atmega328: $(PROGRAM)_atmega328_16.lst
|
||||
|
||||
|
||||
# Test platforms
|
||||
# Virtual boot block test
|
||||
virboot328: TARGET = atmega328
|
||||
virboot328: MCU_TARGET = atmega328p
|
||||
virboot328: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DVIRTUAL_BOOT'
|
||||
virboot328: AVR_FREQ = 16000000L
|
||||
virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
virboot328: $(PROGRAM)_atmega328.hex
|
||||
virboot328: $(PROGRAM)_atmega328.lst
|
||||
|
||||
# 20MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro20: TARGET = pro_20mhz
|
||||
pro20: MCU_TARGET = atmega168
|
||||
pro20: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro20: AVR_FREQ = 20000000L
|
||||
pro20: $(PROGRAM)_pro_20mhz.hex
|
||||
pro20: $(PROGRAM)_pro_20mhz.lst
|
||||
|
||||
pro20_isp: pro20
|
||||
pro20_isp: TARGET = pro_20mhz
|
||||
# 2.7V brownout
|
||||
pro20_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro20_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro20_isp: EFUSE = 04
|
||||
pro20_isp: isp
|
||||
|
||||
# 16MHz clocked platforms
|
||||
#
|
||||
# These are capable of 230400 baud, or 38400 baud on PC (Arduino Avrdude issue)
|
||||
#
|
||||
|
||||
pro16: TARGET = pro_16MHz
|
||||
pro16: MCU_TARGET = atmega168
|
||||
pro16: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro16: AVR_FREQ = 16000000L
|
||||
pro16: $(PROGRAM)_pro_16MHz.hex
|
||||
pro16: $(PROGRAM)_pro_16MHz.lst
|
||||
|
||||
pro16_isp: pro16
|
||||
pro16_isp: TARGET = pro_16MHz
|
||||
# 2.7V brownout
|
||||
pro16_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro16_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro16_isp: EFUSE = 04
|
||||
pro16_isp: isp
|
||||
|
||||
# Diecimila, Duemilanove with m168, and NG use identical bootloaders
|
||||
# Call it "atmega168" for generality and clarity, keep "diecimila" for
|
||||
# backward compatibility of makefile
|
||||
#
|
||||
atmega168: TARGET = atmega168
|
||||
atmega168: MCU_TARGET = atmega168
|
||||
atmega168: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega168: AVR_FREQ = 12000000L
|
||||
atmega168: $(PROGRAM)_atmega168.hex
|
||||
atmega168: $(PROGRAM)_atmega168.lst
|
||||
|
||||
atmega168_isp: atmega168
|
||||
atmega168_isp: TARGET = atmega168
|
||||
# 2.7V brownout
|
||||
atmega168_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega168_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega168_isp: EFUSE = 04
|
||||
atmega168_isp: isp
|
||||
|
||||
diecimila: TARGET = diecimila
|
||||
diecimila: MCU_TARGET = atmega168
|
||||
diecimila: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
diecimila: AVR_FREQ = 16000000L
|
||||
diecimila: $(PROGRAM)_diecimila.hex
|
||||
diecimila: $(PROGRAM)_diecimila.lst
|
||||
|
||||
diecimila_isp: diecimila
|
||||
diecimila_isp: TARGET = diecimila
|
||||
# 2.7V brownout
|
||||
diecimila_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
diecimila_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
diecimila_isp: EFUSE = 04
|
||||
diecimila_isp: isp
|
||||
|
||||
atmega328_isp: atmega328
|
||||
atmega328_isp: TARGET = atmega328
|
||||
atmega328_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_isp: EFUSE = FD
|
||||
atmega328_isp: isp
|
||||
|
||||
atmega1284: TARGET = atmega1284p
|
||||
atmega1284: MCU_TARGET = atmega1284p
|
||||
atmega1284: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
atmega1284: AVR_FREQ = 16000000L
|
||||
atmega1284: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
atmega1284: $(PROGRAM)_atmega1284p.hex
|
||||
atmega1284: $(PROGRAM)_atmega1284p.lst
|
||||
|
||||
atmega1284_isp: atmega1284
|
||||
atmega1284_isp: TARGET = atmega1284p
|
||||
atmega1284_isp: MCU_TARGET = atmega1284p
|
||||
# 1024 byte boot
|
||||
atmega1284_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega1284_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega1284_isp: EFUSE = FD
|
||||
atmega1284_isp: isp
|
||||
|
||||
# Sanguino has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#
|
||||
sanguino: TARGET = atmega644p
|
||||
sanguino: MCU_TARGET = atmega644p
|
||||
sanguino: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
sanguino: AVR_FREQ = 16000000L
|
||||
sanguino: LDSECTIONS = -Wl,--section-start=.text=0xfc00 -Wl,--section-start=.version=0xfffe
|
||||
sanguino: $(PROGRAM)_atmega644p.hex
|
||||
sanguino: $(PROGRAM)_atmega644p.lst
|
||||
|
||||
sanguino_isp: sanguino
|
||||
sanguino_isp: TARGET = atmega644p
|
||||
sanguino_isp: MCU_TARGET = atmega644p
|
||||
# 1024 byte boot
|
||||
sanguino_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
sanguino_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
sanguino_isp: EFUSE = FD
|
||||
sanguino_isp: isp
|
||||
|
||||
# Mega has a minimum boot size of 1024 bytes, so enable extra functions
|
||||
#mega: TARGET = atmega1280
|
||||
mega1280: MCU_TARGET = atmega1280
|
||||
mega1280: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400' '-DBIGBOOT'
|
||||
mega1280: AVR_FREQ = 16000000L
|
||||
mega1280: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
|
||||
mega1280: $(PROGRAM)_atmega1280.hex
|
||||
mega1280: $(PROGRAM)_atmega1280.lst
|
||||
|
||||
mega1280_isp: mega
|
||||
mega1280_isp: TARGET = atmega1280
|
||||
mega1280_isp: MCU_TARGET = atmega1280
|
||||
# 1024 byte boot
|
||||
mega1280_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
mega1280_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
mega1280_isp: EFUSE = FD
|
||||
mega1280_isp: isp
|
||||
|
||||
# ATmega8
|
||||
#
|
||||
atmega8: TARGET = atmega8
|
||||
atmega8: MCU_TARGET = atmega8
|
||||
atmega8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega8: AVR_FREQ = 16000000L
|
||||
atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega8: $(PROGRAM)_atmega8.hex
|
||||
atmega8: $(PROGRAM)_atmega8.lst
|
||||
|
||||
atmega8_isp: atmega8
|
||||
atmega8_isp: TARGET = atmega8
|
||||
atmega8_isp: MCU_TARGET = atmega8
|
||||
# SPIEN, CKOPT, Bootsize=512B
|
||||
atmega8_isp: HFUSE = CC
|
||||
# 2.7V brownout, Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega8_isp: LFUSE = BF
|
||||
atmega8_isp: isp
|
||||
|
||||
# ATmega88
|
||||
#
|
||||
atmega88: TARGET = atmega88
|
||||
atmega88: MCU_TARGET = atmega88
|
||||
atmega88: CFLAGS += '-DLED_START_FLASHES=0' '-DBAUD_RATE=38400'
|
||||
atmega88: AVR_FREQ = 12000000L
|
||||
atmega88: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||
atmega88: $(PROGRAM)_atmega88.hex
|
||||
atmega88: $(PROGRAM)_atmega88.lst
|
||||
|
||||
atmega88_isp: atmega88
|
||||
atmega88_isp: TARGET = atmega88
|
||||
atmega88_isp: MCU_TARGET = atmega88
|
||||
# 2.7V brownout
|
||||
atmega88_isp: HFUSE = DD
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atemga88_isp: LFUSE = FF
|
||||
# 512 byte boot
|
||||
atmega88_isp: EFUSE = 04
|
||||
atmega88_isp: isp
|
||||
|
||||
|
||||
# 8MHz clocked platforms
|
||||
#
|
||||
# These are capable of 38400 baud
|
||||
#
|
||||
|
||||
lilypad: TARGET = lilypad
|
||||
lilypad: MCU_TARGET = atmega168
|
||||
lilypad: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad: AVR_FREQ = 8000000L
|
||||
lilypad: $(PROGRAM)_lilypad.hex
|
||||
lilypad: $(PROGRAM)_lilypad.lst
|
||||
|
||||
lilypad_isp: lilypad
|
||||
lilypad_isp: TARGET = lilypad
|
||||
# 2.7V brownout
|
||||
lilypad_isp: HFUSE = DD
|
||||
# Internal 8MHz osc (8MHz) Slow rising power
|
||||
lilypad_isp: LFUSE = E2
|
||||
# 512 byte boot
|
||||
lilypad_isp: EFUSE = 04
|
||||
lilypad_isp: isp
|
||||
|
||||
lilypad_resonator: TARGET = lilypad_resonator
|
||||
lilypad_resonator: MCU_TARGET = atmega168
|
||||
lilypad_resonator: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
lilypad_resonator: AVR_FREQ = 8000000L
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.hex
|
||||
lilypad_resonator: $(PROGRAM)_lilypad_resonator.lst
|
||||
|
||||
lilypad_resonator_isp: lilypad_resonator
|
||||
lilypad_resonator_isp: TARGET = lilypad_resonator
|
||||
# 2.7V brownout
|
||||
lilypad_resonator_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
lilypad_resonator_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
lilypad_resonator_isp: EFUSE = 04
|
||||
lilypad_resonator_isp: isp
|
||||
|
||||
pro8: TARGET = pro_8MHz
|
||||
pro8: MCU_TARGET = atmega168
|
||||
pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
pro8: AVR_FREQ = 8000000L
|
||||
pro8: $(PROGRAM)_pro_8MHz.hex
|
||||
pro8: $(PROGRAM)_pro_8MHz.lst
|
||||
|
||||
pro8_isp: pro8
|
||||
pro8_isp: TARGET = pro_8MHz
|
||||
# 2.7V brownout
|
||||
pro8_isp: HFUSE = DD
|
||||
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||
pro8_isp: LFUSE = C6
|
||||
# 512 byte boot
|
||||
pro8_isp: EFUSE = 04
|
||||
pro8_isp: isp
|
||||
|
||||
atmega328_pro8: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8: MCU_TARGET = atmega328p
|
||||
atmega328_pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=38400'
|
||||
atmega328_pro8: AVR_FREQ = 8000000L
|
||||
atmega328_pro8: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.hex
|
||||
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.lst
|
||||
|
||||
atmega328_pro8_isp: atmega328_pro8
|
||||
atmega328_pro8_isp: TARGET = atmega328_pro_8MHz
|
||||
atmega328_pro8_isp: MCU_TARGET = atmega328p
|
||||
# 512 byte boot, SPIEN
|
||||
atmega328_pro8_isp: HFUSE = DE
|
||||
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||
atmega328_pro8_isp: LFUSE = FF
|
||||
# 2.7V brownout
|
||||
atmega328_pro8_isp: EFUSE = DE
|
||||
atmega328_pro8_isp: isp
|
||||
|
||||
# 1MHz clocked platforms
|
||||
#
|
||||
# These are capable of 9600 baud
|
||||
#
|
||||
|
||||
luminet: TARGET = luminet
|
||||
luminet: MCU_TARGET = attiny84
|
||||
luminet: CFLAGS += '-DLED_START_FLASHES=3' '-DSOFT_UART' '-DBAUD_RATE=9600'
|
||||
luminet: CFLAGS += '-DVIRTUAL_BOOT_PARTITION'
|
||||
luminet: AVR_FREQ = 1000000L
|
||||
luminet: LDSECTIONS = -Wl,--section-start=.text=0x1d00 -Wl,--section-start=.version=0x1efe
|
||||
luminet: $(PROGRAM)_luminet.hex
|
||||
luminet: $(PROGRAM)_luminet.lst
|
||||
|
||||
luminet_isp: luminet
|
||||
luminet_isp: TARGET = luminet
|
||||
luminet_isp: MCU_TARGET = attiny84
|
||||
# Brownout disabled
|
||||
luminet_isp: HFUSE = DF
|
||||
# 1MHz internal oscillator, slowly rising power
|
||||
luminet_isp: LFUSE = 62
|
||||
# Self-programming enable
|
||||
luminet_isp: EFUSE = FE
|
||||
luminet_isp: isp
|
||||
|
||||
#
|
||||
# Generic build instructions
|
||||
#
|
||||
#
|
||||
|
||||
isp: $(TARGET)
|
||||
$(ISPFUSES)
|
||||
$(ISPFLASH)
|
||||
|
||||
isp-stk500: $(PROGRAM)_$(TARGET).hex
|
||||
$(STK500-1)
|
||||
$(STK500-2)
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(SIZE) $@
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@
|
||||
|
||||
%.srec: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@
|
||||
980
BootLoaders/OrangeMultiBoot/Source/optiboot.c
Normal file
980
BootLoaders/OrangeMultiBoot/Source/optiboot.c
Normal file
@@ -0,0 +1,980 @@
|
||||
/**********************************************************/
|
||||
/* Optiboot bootloader for Xmega */
|
||||
/* */
|
||||
/* http://optiboot.googlecode.com */
|
||||
/* */
|
||||
/* Arduino-maintained version : See README.TXT */
|
||||
/* http://code.google.com/p/arduino/ */
|
||||
/* It is the intent that changes not relevant to the */
|
||||
/* Arduino production envionment get moved from the */
|
||||
/* optiboot project to the arduino project in "lumps." */
|
||||
/* */
|
||||
/* Heavily optimised bootloader that is faster and */
|
||||
/* smaller than the Arduino standard bootloader */
|
||||
/* */
|
||||
/* Enhancements: */
|
||||
/* Fits in 512 bytes, saving 1.5K of code space */
|
||||
/* Background page erasing speeds up programming */
|
||||
/* Higher baud rate speeds up programming */
|
||||
/* Written almost entirely in C */
|
||||
/* Customisable timeout with accurate timeconstant */
|
||||
/* Optional virtual UART. No hardware UART required. */
|
||||
/* Optional virtual boot partition for devices without. */
|
||||
/* */
|
||||
/* What you lose: */
|
||||
/* Implements a skeleton STK500 protocol which is */
|
||||
/* missing several features including EEPROM */
|
||||
/* programming and non-page-aligned writes */
|
||||
/* High baud rate breaks compatibility with standard */
|
||||
/* Arduino flash settings */
|
||||
/* */
|
||||
/* Fully supported: */
|
||||
/* ATmega168 based devices (Diecimila etc) */
|
||||
/* ATmega328P based devices (Duemilanove etc) */
|
||||
/* */
|
||||
/* Beta test (believed working.) */
|
||||
/* ATmega8 based devices (Arduino legacy) */
|
||||
/* ATmega328 non-picopower devices */
|
||||
/* ATmega644P based devices (Sanguino) */
|
||||
/* ATmega1284P based devices */
|
||||
/* */
|
||||
/* Alpha test */
|
||||
/* ATmega1280 based devices (Arduino Mega) */
|
||||
/* */
|
||||
/* Work in progress: */
|
||||
/* ATtiny84 based devices (Luminet) */
|
||||
/* */
|
||||
/* Does not support: */
|
||||
/* USB based devices (eg. Teensy) */
|
||||
/* */
|
||||
/* Assumptions: */
|
||||
/* The code makes several assumptions that reduce the */
|
||||
/* code size. They are all true after a hardware reset, */
|
||||
/* but may not be true if the bootloader is called by */
|
||||
/* other means or on other hardware. */
|
||||
/* No interrupts can occur */
|
||||
/* UART and Timer 1 are set to their reset state */
|
||||
/* SP points to RAMEND */
|
||||
/* */
|
||||
/* Code builds on code, libraries and optimisations from: */
|
||||
/* stk500boot.c by Jason P. Kyle */
|
||||
/* Arduino bootloader http://arduino.cc */
|
||||
/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
|
||||
/* avr-libc project http://nongnu.org/avr-libc */
|
||||
/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */
|
||||
/* AVR305 Atmel Application Note */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it */
|
||||
/* and/or modify it under the terms of the GNU General */
|
||||
/* Public License as published by the Free Software */
|
||||
/* Foundation; either version 2 of the License, or */
|
||||
/* (at your option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will */
|
||||
/* be useful, but WITHOUT ANY WARRANTY; without even the */
|
||||
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
|
||||
/* PARTICULAR PURPOSE. See the GNU General Public */
|
||||
/* License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General */
|
||||
/* Public License along with this program; if not, write */
|
||||
/* to the Free Software Foundation, Inc., */
|
||||
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
/* */
|
||||
/* Licence can be viewed at */
|
||||
/* http://www.fsf.org/licenses/gpl.txt */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* Optional defines: */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
/* */
|
||||
/* BIG_BOOT: */
|
||||
/* Build a 1k bootloader, not 512 bytes. This turns on */
|
||||
/* extra functionality. */
|
||||
/* */
|
||||
/* BAUD_RATE: */
|
||||
/* Set bootloader baud rate. */
|
||||
/* */
|
||||
/* LUDICROUS_SPEED: */
|
||||
/* 230400 baud :-) */
|
||||
/* */
|
||||
/* SOFT_UART: */
|
||||
/* Use AVR305 soft-UART instead of hardware UART. */
|
||||
/* */
|
||||
/* LED_START_FLASHES: */
|
||||
/* Number of LED flashes on bootup. */
|
||||
/* */
|
||||
/* LED_DATA_FLASH: */
|
||||
/* Flash LED when transferring data. For boards without */
|
||||
/* TX or RX LEDs, or for people who like blinky lights. */
|
||||
/* */
|
||||
/* SUPPORT_EEPROM: */
|
||||
/* Support reading and writing from EEPROM. This is not */
|
||||
/* used by Arduino, so off by default. */
|
||||
/* */
|
||||
/* TIMEOUT_MS: */
|
||||
/* Bootloader timeout period, in milliseconds. */
|
||||
/* 500,1000,2000,4000,8000 supported. */
|
||||
/* */
|
||||
/* UART: */
|
||||
/* UART number (0..n) for devices with more than */
|
||||
/* one hardware uart (644P, 1284P, etc) */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Version Numbers! */
|
||||
/* */
|
||||
/* Arduino Optiboot now includes this Version number in */
|
||||
/* the source and object code. */
|
||||
/* */
|
||||
/* Version 3 was released as zip from the optiboot */
|
||||
/* repository and was distributed with Arduino 0022. */
|
||||
/* Version 4 starts with the arduino repository commit */
|
||||
/* that brought the arduino repository up-to-date with */
|
||||
/* the optiboot source tree changes since v3. */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
/**********************************************************/
|
||||
/* Edit History: */
|
||||
/* */
|
||||
/* Nov 2012 */
|
||||
/* Specific version for 9x voice module */
|
||||
/* by Mike Blandford */
|
||||
/* Mar 2012 */
|
||||
/* 4.5 WestfW: add infrastructure for non-zero UARTS. */
|
||||
/* 4.5 WestfW: fix SIGNATURE_2 for m644 (bad in avr-libc) */
|
||||
/* Jan 2012: */
|
||||
/* 4.5 WestfW: fix NRWW value for m1284. */
|
||||
/* 4.4 WestfW: use attribute OS_main instead of naked for */
|
||||
/* main(). This allows optimizations that we */
|
||||
/* count on, which are prohibited in naked */
|
||||
/* functions due to PR42240. (keeps us less */
|
||||
/* than 512 bytes when compiler is gcc4.5 */
|
||||
/* (code from 4.3.2 remains the same.) */
|
||||
/* 4.4 WestfW and Maniacbug: Add m1284 support. This */
|
||||
/* does not change the 328 binary, so the */
|
||||
/* version number didn't change either. (?) */
|
||||
/* June 2011: */
|
||||
/* 4.4 WestfW: remove automatic soft_uart detect (didn't */
|
||||
/* know what it was doing or why.) Added a */
|
||||
/* check of the calculated BRG value instead. */
|
||||
/* Version stays 4.4; existing binaries are */
|
||||
/* not changed. */
|
||||
/* 4.4 WestfW: add initialization of address to keep */
|
||||
/* the compiler happy. Change SC'ed targets. */
|
||||
/* Return the SW version via READ PARAM */
|
||||
/* 4.3 WestfW: catch framing errors in getch(), so that */
|
||||
/* AVRISP works without HW kludges. */
|
||||
/* http://code.google.com/p/arduino/issues/detail?id=368n*/
|
||||
/* 4.2 WestfW: reduce code size, fix timeouts, change */
|
||||
/* verifySpace to use WDT instead of appstart */
|
||||
/* 4.1 WestfW: put version number in binary. */
|
||||
/**********************************************************/
|
||||
|
||||
#define OPTIBOOT_MAJVER 4
|
||||
#define OPTIBOOT_MINVER 5
|
||||
|
||||
#define MULTI_CALLED 1
|
||||
|
||||
#define MAKESTR(a) #a
|
||||
#define MAKEVER(a, b) MAKESTR(a*256+b)
|
||||
|
||||
// Page Size is 128 words (256 bytes)
|
||||
|
||||
//asm(" .section .version\n"
|
||||
// "optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n"
|
||||
// " .section .text\n");
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// <avr/boot.h> uses sts instructions, but this version uses out instructions
|
||||
// This saves cycles and program memory.
|
||||
//#include "boot.h"
|
||||
|
||||
|
||||
// We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
|
||||
|
||||
#include "pin_defs.h"
|
||||
#include "stk500.h"
|
||||
|
||||
#define BIND_pin 2 //PD2
|
||||
#define BIND_port PORTD
|
||||
#define IS_BIND_BUTTON_on ( (BIND_port.IN & _BV(BIND_pin)) == 0x00 )
|
||||
|
||||
#ifndef LED_START_FLASHES
|
||||
#define LED_START_FLASHES 0
|
||||
#endif
|
||||
|
||||
#ifdef LUDICROUS_SPEED
|
||||
#define BAUD_RATE 230400L
|
||||
#endif
|
||||
|
||||
/* set the UART baud rate defaults */
|
||||
#ifndef BAUD_RATE
|
||||
#if F_CPU >= 8000000L
|
||||
#define BAUD_RATE 38400L // Highest rate Avrdude win32 will support
|
||||
#elsif F_CPU >= 1000000L
|
||||
#define BAUD_RATE 9600L // 19200 also supported, but with significant error
|
||||
#elsif F_CPU >= 128000L
|
||||
#define BAUD_RATE 4800L // Good for 128kHz internal RC
|
||||
#else
|
||||
#define BAUD_RATE 1200L // Good even at 32768Hz
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef UART
|
||||
#define UART 0
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Switch in soft UART for hard baud rates */
|
||||
/*
|
||||
* I don't understand what this was supposed to accomplish, where the
|
||||
* constant "280" came from, or why automatically (and perhaps unexpectedly)
|
||||
* switching to a soft uart is a good thing, so I'm undoing this in favor
|
||||
* of a range check using the same calc used to config the BRG...
|
||||
*/
|
||||
#if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz
|
||||
#ifndef SOFT_UART
|
||||
#define SOFT_UART
|
||||
#endif
|
||||
#endif
|
||||
#else // 0
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250
|
||||
#error Unachievable baud rate (too slow) BAUD_RATE
|
||||
#endif // baud rate slow check
|
||||
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3
|
||||
#error Unachievable baud rate (too fast) BAUD_RATE
|
||||
#endif // baud rate fastn check
|
||||
#endif
|
||||
|
||||
/* Watchdog settings */
|
||||
#define WATCHDOG_OFF (0)
|
||||
#define WATCHDOG_16MS (_BV(WDE))
|
||||
#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE))
|
||||
#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#ifndef __AVR_ATmega8__
|
||||
#define WATCHDOG_4S (_BV(WDP3) | _BV(WDE))
|
||||
#define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
|
||||
#endif
|
||||
|
||||
/* Function Prototypes */
|
||||
/* The main function is in init9, which removes the interrupt vector table */
|
||||
/* we don't need. It is also 'naked', which means the compiler does not */
|
||||
/* generate any entry or exit code itself. */
|
||||
int main(void) __attribute__ ((OS_main)) __attribute__ ((noreturn)) __attribute__ ((section (".init9")));
|
||||
void putch(char);
|
||||
uint8_t getch(void);
|
||||
static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */
|
||||
void verifySpace();
|
||||
#if LED_START_FLASHES > 0
|
||||
static inline void flash_led(uint8_t);
|
||||
#endif
|
||||
uint8_t getLen();
|
||||
//static inline void watchdogReset();
|
||||
void watchdogConfig(uint8_t x);
|
||||
#ifdef SOFT_UART
|
||||
void uartDelay() __attribute__ ((naked));
|
||||
#endif
|
||||
static void appStart() ; // __attribute__ ((naked));
|
||||
void boot_spm_busy_wait() ;
|
||||
void __boot_page_erase_short( uint16_t address ) ;
|
||||
void __boot_page_fill_short( uint16_t address, uint16_t data) ;
|
||||
void __boot_page_write_short( uint16_t address) ;
|
||||
void __boot_erase_flash_buffer( uint16_t address ) ;
|
||||
void init() ;
|
||||
|
||||
/*
|
||||
* NRWW memory
|
||||
* Addresses below NRWW (Non-Read-While-Write) can be programmed while
|
||||
* continuing to run code from flash, slightly speeding up programming
|
||||
* time. Beware that Atmel data sheets specify this as a WORD address,
|
||||
* while optiboot will be comparing against a 16-bit byte address. This
|
||||
* means that on a part with 128kB of memory, the upper part of the lower
|
||||
* 64k will get NRWW processing as well, even though it doesn't need it.
|
||||
* That's OK. In fact, you can disable the overlapping processing for
|
||||
* a part entirely by setting NRWWSTART to zero. This reduces code
|
||||
* space a bit, at the expense of being slightly slower, overall.
|
||||
*
|
||||
* RAMSTART should be self-explanatory. It's bigger on parts with a
|
||||
* lot of peripheral registers.
|
||||
*/
|
||||
#if defined(__AVR_ATmega168__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x3800)
|
||||
#elif defined(__AVR_ATmega328P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined(__AVR_ATmega328__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x7000)
|
||||
#elif defined (__AVR_ATmega644P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
// correct for a bug in avr-libc
|
||||
#undef SIGNATURE_2
|
||||
#define SIGNATURE_2 0x0A
|
||||
#elif defined (__AVR_ATmega1284P__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATtiny84__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x0000)
|
||||
#elif defined(__AVR_ATmega1280__)
|
||||
#define RAMSTART (0x200)
|
||||
#define NRWWSTART (0xE000)
|
||||
#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
#define RAMSTART (0x100)
|
||||
#define NRWWSTART (0x1800)
|
||||
#endif
|
||||
|
||||
/* C zero initialises all global variables. However, that requires */
|
||||
/* These definitions are NOT zero initialised, but that doesn't matter */
|
||||
/* This allows us to drop the zero init code, saving us memory */
|
||||
#define buff ((uint8_t*)(RAMSTART))
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
#define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4))
|
||||
#define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle devices with up to 4 uarts (eg m1280.) Rather inelegantly.
|
||||
* Note that mega8 still needs special handling, because ubrr is handled
|
||||
* differently.
|
||||
*/
|
||||
#if UART == 0
|
||||
# define UART_SRA UCSR0A
|
||||
# define UART_SRB UCSR0B
|
||||
# define UART_SRC UCSR0C
|
||||
# define UART_SRL UBRR0L
|
||||
# define UART_UDR UDR0
|
||||
#elif UART == 1
|
||||
# define UART_SRA UCSR1A
|
||||
# define UART_SRB UCSR1B
|
||||
# define UART_SRC UCSR1C
|
||||
# define UART_SRL UBRR1L
|
||||
# define UART_UDR UDR1
|
||||
#elif UART == 2
|
||||
# define UART_SRA UCSR2A
|
||||
# define UART_SRB UCSR2B
|
||||
# define UART_SRC UCSR2C
|
||||
# define UART_SRL UBRR2L
|
||||
# define UART_UDR UDR2
|
||||
#elif UART == 3
|
||||
# define UART_SRA UCSR3A
|
||||
# define UART_SRB UCSR3B
|
||||
# define UART_SRC UCSR3C
|
||||
# define UART_SRL UBRR3L
|
||||
# define UART_UDR UDR3
|
||||
#endif
|
||||
|
||||
|
||||
/* main program starts here */
|
||||
int main(void)
|
||||
{
|
||||
uint8_t ch;
|
||||
uint8_t byte ;
|
||||
|
||||
/*
|
||||
* Making these local and in registers prevents the need for initializing
|
||||
* them, and also saves space because code no longer stores to memory.
|
||||
* (initializing address keeps the compiler happy, but isn't really
|
||||
* necessary, and uses 4 bytes of flash.)
|
||||
*/
|
||||
register uint16_t address = 0;
|
||||
init() ;
|
||||
|
||||
// After the zero init loop, this is the first code to run.
|
||||
//
|
||||
// This code makes the following assumptions:
|
||||
// No interrupts will execute
|
||||
// SP points to RAMEND
|
||||
// r1 contains zero
|
||||
//
|
||||
// If not, uncomment the following instructions:
|
||||
// cli();
|
||||
asm volatile ("clr __zero_reg__");
|
||||
|
||||
ch = RST.STATUS ;
|
||||
RST.STATUS = 0xFF ; // Clear all flags
|
||||
|
||||
// Here, if power on, wait 0.1 secs, then check for
|
||||
// serial Rx signal low, if so, stay in bootloader
|
||||
// else go to application
|
||||
|
||||
if (ch & (RST_EXTRF_bm | RST_PORF_bm ) )
|
||||
{
|
||||
TCC1.CCA = 25000 ;
|
||||
TCC1.INTFLAGS = TC1_CCAIF_bm ;
|
||||
|
||||
while(!(TCC1.INTFLAGS & TC1_CCAIF_bm))
|
||||
;
|
||||
TCC1.CTRLA = 0 ; // Stop timer
|
||||
|
||||
uint8_t x ;
|
||||
x = PORTD.IN & 0x04 ;
|
||||
if ( x != 0 )
|
||||
{
|
||||
appStart() ; // Power on, go to app if loaded
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//#ifndef SOFT_UART
|
||||
// UART_SRA = _BV(U2X0); //Double speed mode USART0
|
||||
// UART_SRB = _BV(RXEN0) | _BV(TXEN0);
|
||||
// UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
|
||||
//// UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
|
||||
//// Baudrate of 57600
|
||||
//#if F_CPU == 12000000L
|
||||
// UART_SRL = 25 ;
|
||||
//#else
|
||||
//#if F_CPU == 16000000L
|
||||
// UART_SRL = 33 ;
|
||||
//#else
|
||||
//#ERROR Baud rate not available
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
//#endif
|
||||
|
||||
// Set up watchdog to trigger after 500ms
|
||||
|
||||
|
||||
// watchdogConfig(WATCHDOG_1S);
|
||||
|
||||
/* Set LED pin as output */
|
||||
#define LED_pin 1 //PD1
|
||||
#define LED_port PORTD
|
||||
LED_port.DIRSET = _BV(LED_pin) ;
|
||||
|
||||
//#ifdef SOFT_UART
|
||||
// /* Set TX pin as output */
|
||||
// UART_DDR |= _BV(UART_TX_BIT);
|
||||
//#endif
|
||||
|
||||
//#if LED_START_FLASHES > 0
|
||||
// /* Flash onboard LED to signal entering of bootloader */
|
||||
// flash_led(LED_START_FLASHES * 2);
|
||||
//#endif
|
||||
|
||||
/* Forever loop */
|
||||
for (;;)
|
||||
{
|
||||
/* get character from UART */
|
||||
ch = getch();
|
||||
|
||||
if(ch == STK_GET_PARAMETER)
|
||||
{
|
||||
byte = getch();
|
||||
verifySpace();
|
||||
if ( byte == 0x82)
|
||||
{
|
||||
/*
|
||||
* Send optiboot version as "minor SW version"
|
||||
*/
|
||||
putch(OPTIBOOT_MINVER);
|
||||
}
|
||||
else if ( byte == 0x81)
|
||||
{
|
||||
putch(OPTIBOOT_MAJVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* GET PARAMETER returns a generic 0x03 reply for
|
||||
* other parameters - enough to keep Avrdude happy
|
||||
*/
|
||||
putch(0x03);
|
||||
}
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE) {
|
||||
// SET DEVICE is ignored
|
||||
getNch(20);
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE_EXT)
|
||||
{
|
||||
// SET DEVICE EXT is ignored
|
||||
getNch(5);
|
||||
}
|
||||
else if(ch == STK_LOAD_ADDRESS)
|
||||
{
|
||||
// LOAD ADDRESS
|
||||
uint16_t newAddress;
|
||||
newAddress = getch() ;
|
||||
newAddress = (newAddress & 0xff) | (getch() << 8);
|
||||
#ifdef RAMPZ
|
||||
// Transfer top bit to RAMPZ
|
||||
RAMPZ = (newAddress & 0x8000) ? 1 : 0;
|
||||
#endif
|
||||
// newAddress += newAddress; // Convert from word address to byte address
|
||||
address = newAddress;
|
||||
verifySpace();
|
||||
}
|
||||
else if(ch == STK_UNIVERSAL)
|
||||
{
|
||||
// UNIVERSAL command is ignored
|
||||
getNch(4);
|
||||
putch(0x00);
|
||||
}
|
||||
/* Write memory, length is big endian and is in bytes */
|
||||
else if(ch == STK_PROG_PAGE)
|
||||
{
|
||||
// PROGRAM PAGE - we support flash programming only, not EEPROM
|
||||
uint8_t *bufPtr;
|
||||
uint16_t addrPtr;
|
||||
register uint8_t length;
|
||||
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
// If we are in RWW section, immediately start page erase
|
||||
// if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
__boot_page_erase_short((uint16_t)(void*)address);
|
||||
|
||||
// While that is going on, read in page contents
|
||||
bufPtr = buff;
|
||||
do *bufPtr++ = getch();
|
||||
while (--length);
|
||||
|
||||
// If we are in NRWW section, page erase has to be delayed until now.
|
||||
// Todo: Take RAMPZ into account
|
||||
//#ifdef MULTI_CALLED
|
||||
// if (address < 0x7E00)
|
||||
//#endif
|
||||
// {
|
||||
// if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||
// }
|
||||
// Read command terminator, start reply
|
||||
verifySpace();
|
||||
|
||||
// If only a partial page is to be programmed, the erase might not be complete.
|
||||
// So check that here
|
||||
#ifdef MULTI_CALLED
|
||||
if (address < 0x8000)
|
||||
#endif
|
||||
{
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
if ((uint16_t)(void*)address == 0) {
|
||||
// This is the reset vector page. We need to live-patch the code so the
|
||||
// bootloader runs.
|
||||
//
|
||||
// Move RESET vector to WDT vector
|
||||
uint16_t vect = buff[0] | (buff[1]<<8);
|
||||
rstVect = vect;
|
||||
wdtVect = buff[8] | (buff[9]<<8);
|
||||
vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
|
||||
buff[8] = vect & 0xff;
|
||||
buff[9] = vect >> 8;
|
||||
|
||||
// Add jump to bootloader at RESET vector
|
||||
buff[0] = 0x7f;
|
||||
buff[1] = 0xce; // rjmp 0x1d00 instruction
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy buffer into programming buffer
|
||||
bufPtr = buff;
|
||||
addrPtr = (uint16_t)(void*)address;
|
||||
ch = SPM_PAGESIZE / 2;
|
||||
__boot_erase_flash_buffer((uint16_t)(void*)addrPtr ) ;
|
||||
do {
|
||||
uint16_t a;
|
||||
// a = *bufPtr++;
|
||||
// a |= (*bufPtr++) << 8;
|
||||
|
||||
a = *((uint16_t *)bufPtr) ;
|
||||
bufPtr += 2 ;
|
||||
|
||||
__boot_page_fill_short((uint16_t)(void*)addrPtr,a);
|
||||
addrPtr += 2;
|
||||
} while (--ch);
|
||||
|
||||
// Write from programming buffer
|
||||
__boot_page_write_short((uint16_t)(void*)address);
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#if defined(RWWSRE)
|
||||
// Reenable read access to flash
|
||||
boot_rww_enable();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Read memory block mode, length is big endian. */
|
||||
else if(ch == STK_READ_PAGE)
|
||||
{
|
||||
register uint8_t length;
|
||||
// READ PAGE - we only read flash
|
||||
getch(); /* getlen() */
|
||||
length = getch();
|
||||
getch();
|
||||
|
||||
verifySpace();
|
||||
//#ifdef VIRTUAL_BOOT_PARTITION
|
||||
// do {
|
||||
// // Undo vector patch in bottom page so verify passes
|
||||
// if (address == 0) ch=rstVect & 0xff;
|
||||
// else if (address == 1) ch=rstVect >> 8;
|
||||
// else if (address == 8) ch=wdtVect & 0xff;
|
||||
// else if (address == 9) ch=wdtVect >> 8;
|
||||
// else ch = pgm_read_byte_near(address);
|
||||
// address++;
|
||||
// putch(ch);
|
||||
// } while (--length);
|
||||
//#else
|
||||
//#ifdef RAMPZ
|
||||
//// Since RAMPZ should already be set, we need to use EPLM directly.
|
||||
//// do putch(pgm_read_byte_near(address++));
|
||||
//// while (--length);
|
||||
// do {
|
||||
// uint8_t result;
|
||||
// __asm__ ("elpm %0,Z\n":"=r"(result):"z"(address));
|
||||
// putch(result);
|
||||
// address++;
|
||||
// }
|
||||
// while (--length);
|
||||
//#else
|
||||
do putch(pgm_read_byte_near(address++));
|
||||
while (--length);
|
||||
//#endif
|
||||
//#endif
|
||||
}
|
||||
|
||||
/* Get device signature bytes */
|
||||
else if(ch == STK_READ_SIGN)
|
||||
{
|
||||
// READ SIGN - return what Avrdude wants to hear
|
||||
verifySpace();
|
||||
putch(SIGNATURE_0);
|
||||
putch(SIGNATURE_1);
|
||||
putch(SIGNATURE_2);
|
||||
}
|
||||
else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
|
||||
// Adaboot no-wait mod
|
||||
|
||||
// watchdogConfig(WATCHDOG_16MS);
|
||||
|
||||
verifySpace();
|
||||
#ifdef MULTI_CALLED
|
||||
putch(STK_OK);
|
||||
while(!(USARTC0.STATUS & USART_TXCIF_bm))
|
||||
;
|
||||
appStart() ;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// This covers the response to commands like STK_ENTER_PROGMODE
|
||||
verifySpace();
|
||||
}
|
||||
putch(STK_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void putch(char ch)
|
||||
{
|
||||
//#ifndef SOFT_UART
|
||||
while(!(USARTC0.STATUS & USART_DREIF_bm))
|
||||
;
|
||||
USARTC0.DATA = ch ;
|
||||
//#else
|
||||
// __asm__ __volatile__ (
|
||||
// " com %[ch]\n" // ones complement, carry set
|
||||
// " sec\n"
|
||||
// "1: brcc 2f\n"
|
||||
// " cbi %[uartPort],%[uartBit]\n"
|
||||
// " rjmp 3f\n"
|
||||
// "2: sbi %[uartPort],%[uartBit]\n"
|
||||
// " nop\n"
|
||||
// "3: rcall uartDelay\n"
|
||||
// " rcall uartDelay\n"
|
||||
// " lsr %[ch]\n"
|
||||
// " dec %[bitcnt]\n"
|
||||
// " brne 1b\n"
|
||||
// :
|
||||
// :
|
||||
// [bitcnt] "d" (10),
|
||||
// [ch] "r" (ch),
|
||||
// [uartPort] "I" (_SFR_IO_ADDR(UART_PORT)),
|
||||
// [uartBit] "I" (UART_TX_BIT)
|
||||
// :
|
||||
// "r25"
|
||||
// );
|
||||
//#endif
|
||||
}
|
||||
|
||||
uint8_t getch(void)
|
||||
{
|
||||
uint8_t ch;
|
||||
|
||||
//#ifdef LED_DATA_FLASH
|
||||
//#ifdef __AVR_ATmega8__
|
||||
// LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
//#ifdef SOFT_UART
|
||||
// __asm__ __volatile__ (
|
||||
// "1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge
|
||||
// " rjmp 1b\n"
|
||||
// " rcall uartDelay\n" // Get to middle of start bit
|
||||
// "2: rcall uartDelay\n" // Wait 1 bit period
|
||||
// " rcall uartDelay\n" // Wait 1 bit period
|
||||
// " clc\n"
|
||||
// " sbic %[uartPin],%[uartBit]\n"
|
||||
// " sec\n"
|
||||
// " dec %[bitCnt]\n"
|
||||
// " breq 3f\n"
|
||||
// " ror %[ch]\n"
|
||||
// " rjmp 2b\n"
|
||||
// "3:\n"
|
||||
// :
|
||||
// [ch] "=r" (ch)
|
||||
// :
|
||||
// [bitCnt] "d" (9),
|
||||
// [uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
|
||||
// [uartBit] "I" (UART_RX_BIT)
|
||||
// :
|
||||
// "r25"
|
||||
//);
|
||||
//#else
|
||||
while(!(USARTC0.STATUS & USART_RXCIF_bm))
|
||||
|
||||
// watchdogReset()
|
||||
|
||||
;
|
||||
// if (!(UART_SRA & _BV(FE0))) {
|
||||
/*
|
||||
* A Framing Error indicates (probably) that something is talking
|
||||
* to us at the wrong bit rate. Assume that this is because it
|
||||
* expects to be talking to the application, and DON'T reset the
|
||||
* watchdog. This should cause the bootloader to abort and run
|
||||
* the application "soon", if it keeps happening. (Note that we
|
||||
* don't care that an invalid char is returned...)
|
||||
*/
|
||||
// watchdogReset();
|
||||
// }
|
||||
|
||||
ch = USARTC0.DATA ;
|
||||
//#endif
|
||||
|
||||
//#ifdef LED_DATA_FLASH
|
||||
//#ifdef __AVR_ATmega8__
|
||||
// LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
#ifdef SOFT_UART
|
||||
// AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
|
||||
// Adding 3 to numerator simulates nearest rounding for more accurate baud rates
|
||||
#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
|
||||
#if UART_B_VALUE > 255
|
||||
#error Baud rate too slow for soft UART
|
||||
#endif
|
||||
|
||||
void uartDelay() {
|
||||
__asm__ __volatile__ (
|
||||
"ldi r25,%[count]\n"
|
||||
"1:dec r25\n"
|
||||
"brne 1b\n"
|
||||
"ret\n"
|
||||
::[count] "M" (UART_B_VALUE)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
void getNch(uint8_t count) {
|
||||
do getch(); while (--count);
|
||||
verifySpace();
|
||||
}
|
||||
|
||||
void verifySpace()
|
||||
{
|
||||
if ( getch() != CRC_EOP) {
|
||||
|
||||
putch(STK_NOSYNC);
|
||||
// watchdogConfig(WATCHDOG_16MS); // shorten WD timeout
|
||||
//
|
||||
// while (1) // and busy-loop so that WD causes
|
||||
// ; // a reset and app start.
|
||||
}
|
||||
putch(STK_INSYNC);
|
||||
}
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
void flash_led(uint8_t count) {
|
||||
do {
|
||||
TCNT1 = -(F_CPU/(1024*16));
|
||||
TIFR1 = _BV(TOV1);
|
||||
while(!(TIFR1 & _BV(TOV1)));
|
||||
//#ifdef __AVR_ATmega8__
|
||||
LED_PORT ^= _BV(LED);
|
||||
//#else
|
||||
// LED_PIN |= _BV(LED);
|
||||
//#endif
|
||||
watchdogReset();
|
||||
} while (--count);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Watchdog functions. These are only safe with interrupts turned off.
|
||||
void watchdogReset() {
|
||||
__asm__ __volatile__ (
|
||||
"wdr\n"
|
||||
);
|
||||
}
|
||||
|
||||
//void watchdogConfig(uint8_t x) {
|
||||
// WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||
// WDTCSR = x;
|
||||
//}
|
||||
|
||||
void init()
|
||||
{
|
||||
// Enable external oscillator (16MHz)
|
||||
OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_256CLK_gc ;
|
||||
OSC.CTRL |= OSC_XOSCEN_bm ;
|
||||
while( ( OSC.STATUS & OSC_XOSCRDY_bm ) == 0 )
|
||||
/* wait */ ;
|
||||
// Enable PLL (*2 = 32MHz)
|
||||
OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2 ;
|
||||
OSC.CTRL |= OSC_PLLEN_bm ;
|
||||
while( ( OSC.STATUS & OSC_PLLRDY_bm ) == 0 )
|
||||
/* wait */ ;
|
||||
// Switch to PLL clock
|
||||
CPU_CCP = 0xD8 ;
|
||||
CLK.CTRL = CLK_SCLKSEL_RC2M_gc ;
|
||||
CPU_CCP = 0xD8 ;
|
||||
CLK.CTRL = CLK_SCLKSEL_PLL_gc ;
|
||||
|
||||
PMIC.CTRL = 7 ; // Enable all interrupt levels
|
||||
|
||||
|
||||
// Timer1 config
|
||||
// TCC1 16-bit timer, clocked at 0.5uS
|
||||
EVSYS.CH3MUX = 0x80 + 0x07 ; // Prescaler of 128
|
||||
TCC1.CTRLB = 0; TCC1.CTRLC = 0; TCC1.CTRLD = 0; TCC1.CTRLE = 0;
|
||||
TCC1.INTCTRLA = 0 ;
|
||||
TCC1.INTCTRLB = 0 ;
|
||||
TCC1.PER = 0xFFFF ;
|
||||
TCC1.CNT = 0 ;
|
||||
TCC1.CTRLA = 0x0B ; // Event3 (prescale of 16)
|
||||
|
||||
PORTD.OUTSET = 0x04 ;
|
||||
PORTD.DIRCLR = 0x04 ;
|
||||
PORTD.PIN2CTRL = 0x18 ; // Pullup
|
||||
|
||||
PORTC.OUTSET = 0x08 ;
|
||||
PORTC.DIRSET = 0x08 ;
|
||||
|
||||
USARTC0.BAUDCTRLA = 34 ; // 57600
|
||||
USARTC0.BAUDCTRLB = 0 ;
|
||||
|
||||
USARTC0.CTRLB = 0x18 ; // Enable Tx and Rx
|
||||
USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) ;
|
||||
USARTC0.CTRLC = 0x03 ; // 8 bit, no parity, 1 stop
|
||||
USARTC0.DATA ;
|
||||
}
|
||||
|
||||
void boot_spm_busy_wait()
|
||||
{
|
||||
while(NVM.STATUS & NVM_NVMBUSY_bm)
|
||||
;
|
||||
}
|
||||
|
||||
#define A_NVM_CMD 0x1CA
|
||||
|
||||
void __boot_page_erase_short( uint16_t address )
|
||||
{
|
||||
asm( "push r24" ) ;
|
||||
asm( "push r25" ) ;
|
||||
NVM.CMD = NVM_CMD_ERASE_APP_PAGE_gc ;
|
||||
asm( "pop r31" ) ;
|
||||
asm( "pop r30" ) ;
|
||||
CCP = CCP_SPM_gc ;
|
||||
asm( "spm" ) ;
|
||||
}
|
||||
|
||||
void __boot_erase_flash_buffer( uint16_t address )
|
||||
{
|
||||
asm( "movw r30,r24" ) ;
|
||||
asm( "ldi r24,0x26" ) ;
|
||||
asm("sts 0x1CA,r24");
|
||||
CCP = CCP_IOREG_gc ;
|
||||
asm( "ldi r24,1" ) ;
|
||||
asm("sts 0x1CB,r24");
|
||||
}
|
||||
|
||||
void __boot_page_fill_short( uint16_t address, uint16_t data)
|
||||
{
|
||||
asm( "push r0" ) ;
|
||||
asm( "push r1" ) ;
|
||||
asm( "movw r30,r24" ) ;
|
||||
asm( "mov r0,r22" ) ;
|
||||
asm( "mov r1,r23" ) ;
|
||||
asm( "ldi r24,0x23" ) ;
|
||||
asm("sts 0x1CA,r24");
|
||||
CCP = CCP_SPM_gc ;
|
||||
asm( "spm" ) ;
|
||||
asm( "pop r1" ) ;
|
||||
asm( "pop r0" ) ;
|
||||
}
|
||||
|
||||
void __boot_page_write_short( uint16_t address)
|
||||
{
|
||||
asm( "movw r30,r24" ) ;
|
||||
asm( "ldi r24,0x2E" ) ;
|
||||
asm("sts 0x1CA,r24");
|
||||
CCP = CCP_SPM_gc ;
|
||||
asm( "spm" ) ;
|
||||
}
|
||||
|
||||
void appStart()
|
||||
{
|
||||
// watchdogConfig(WATCHDOG_OFF);
|
||||
// __asm__ __volatile__ (
|
||||
//#ifdef VIRTUAL_BOOT_PARTITION
|
||||
// // Jump to WDT vector
|
||||
// "ldi r30,4\n"
|
||||
// "clr r31\n"
|
||||
//#else
|
||||
// // Jump to RST vector
|
||||
// "clr r30\n"
|
||||
// "clr r31\n"
|
||||
//#endif
|
||||
// "ijmp\n"
|
||||
// );
|
||||
|
||||
register void (*p)() ;
|
||||
p = 0 ;
|
||||
|
||||
if ( pgm_read_byte( (uint16_t)p ) != 0xFF )
|
||||
{
|
||||
(*p)() ;
|
||||
}
|
||||
}
|
||||
|
||||
80
BootLoaders/OrangeMultiBoot/Source/pin_defs.h
Normal file
80
BootLoaders/OrangeMultiBoot/Source/pin_defs.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||
/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB5
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega8__)
|
||||
//Name conversion R.Wiersma
|
||||
#define UCSR0A UCSRA
|
||||
#define UDR0 UDR
|
||||
#define UDRE0 UDRE
|
||||
#define RXC0 RXC
|
||||
#define FE0 FE
|
||||
#define TIFR1 TIFR
|
||||
#define WDTCSR WDTCR
|
||||
#endif
|
||||
|
||||
/* Luminet support */
|
||||
#if defined(__AVR_ATtiny84__)
|
||||
/* Red LED is connected to pin PA4 */
|
||||
#define LED_DDR DDRA
|
||||
#define LED_PORT PORTA
|
||||
#define LED_PIN PINA
|
||||
#define LED PINA4
|
||||
/* Ports for soft UART - left port only for now. TX/RX on PA2/PA3 */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTA
|
||||
#define UART_PIN PINA
|
||||
#define UART_DDR DDRA
|
||||
#define UART_TX_BIT 2
|
||||
#define UART_RX_BIT 3
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Sanguino support */
|
||||
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
|
||||
/* Onboard LED is connected to pin PB0 on Sanguino */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB0
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Mega support */
|
||||
#if defined(__AVR_ATmega1280__)
|
||||
/* Onboard LED is connected to pin PB7 on Arduino Mega */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB7
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTE
|
||||
#define UART_PIN PINE
|
||||
#define UART_DDR DDRE
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
39
BootLoaders/OrangeMultiBoot/Source/stk500.h
Normal file
39
BootLoaders/OrangeMultiBoot/Source/stk500.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* STK500 constants list, from AVRDUDE */
|
||||
#define STK_OK 0x10
|
||||
#define STK_FAILED 0x11 // Not used
|
||||
#define STK_UNKNOWN 0x12 // Not used
|
||||
#define STK_NODEVICE 0x13 // Not used
|
||||
#define STK_INSYNC 0x14 // ' '
|
||||
#define STK_NOSYNC 0x15 // Not used
|
||||
#define ADC_CHANNEL_ERROR 0x16 // Not used
|
||||
#define ADC_MEASURE_OK 0x17 // Not used
|
||||
#define PWM_CHANNEL_ERROR 0x18 // Not used
|
||||
#define PWM_ADJUST_OK 0x19 // Not used
|
||||
#define CRC_EOP 0x20 // 'SPACE'
|
||||
#define STK_GET_SYNC 0x30 // '0'
|
||||
#define STK_GET_SIGN_ON 0x31 // '1'
|
||||
#define STK_SET_PARAMETER 0x40 // '@'
|
||||
#define STK_GET_PARAMETER 0x41 // 'A'
|
||||
#define STK_SET_DEVICE 0x42 // 'B'
|
||||
#define STK_SET_DEVICE_EXT 0x45 // 'E'
|
||||
#define STK_ENTER_PROGMODE 0x50 // 'P'
|
||||
#define STK_LEAVE_PROGMODE 0x51 // 'Q'
|
||||
#define STK_CHIP_ERASE 0x52 // 'R'
|
||||
#define STK_CHECK_AUTOINC 0x53 // 'S'
|
||||
#define STK_LOAD_ADDRESS 0x55 // 'U'
|
||||
#define STK_UNIVERSAL 0x56 // 'V'
|
||||
#define STK_PROG_FLASH 0x60 // '`'
|
||||
#define STK_PROG_DATA 0x61 // 'a'
|
||||
#define STK_PROG_FUSE 0x62 // 'b'
|
||||
#define STK_PROG_LOCK 0x63 // 'c'
|
||||
#define STK_PROG_PAGE 0x64 // 'd'
|
||||
#define STK_PROG_FUSE_EXT 0x65 // 'e'
|
||||
#define STK_READ_FLASH 0x70 // 'p'
|
||||
#define STK_READ_DATA 0x71 // 'q'
|
||||
#define STK_READ_FUSE 0x72 // 'r'
|
||||
#define STK_READ_LOCK 0x73 // 's'
|
||||
#define STK_READ_PAGE 0x74 // 't'
|
||||
#define STK_READ_SIGN 0x75 // 'u'
|
||||
#define STK_READ_OSCCAL 0x76 // 'v'
|
||||
#define STK_READ_FUSE_EXT 0x77 // 'w'
|
||||
#define STK_READ_OSCCAL_EXT 0x78 // 'x'
|
||||
2
BootLoaders/README.md
Normal file
2
BootLoaders/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## Page Moved
|
||||
Moved to [/docs/Arduino_IDE_Boards.md](/docs/Arduino_IDE_Boards.md).
|
||||
1
BootLoaders/StmMultiBoot/README.md
Normal file
1
BootLoaders/StmMultiBoot/README.md
Normal file
@@ -0,0 +1 @@
|
||||
[Source for the StmMultiBooloader](https://github.com/MikeBland/StmMultiBoot)
|
||||
BIN
BootLoaders/StmMultiBoot/StmMultiBoot.bin
Normal file
BIN
BootLoaders/StmMultiBoot/StmMultiBoot.bin
Normal file
Binary file not shown.
2
BootLoaders/StmMultiUSB/README.md
Normal file
2
BootLoaders/StmMultiUSB/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
[Source for the StmMultiUSB=STM32duino-bootloader](https://github.com/rogerclarkmelbourne/STM32duino-bootloader)
|
||||
If you want the latest version, you should look for the file generic_boot20_pa1.bin.
|
||||
BIN
BootLoaders/StmMultiUSB/StmMultiUSB.bin
Normal file
BIN
BootLoaders/StmMultiUSB/StmMultiUSB.bin
Normal file
Binary file not shown.
433
BootLoaders/package_multi_4in1_board_index.json
Normal file
433
BootLoaders/package_multi_4in1_board_index.json
Normal file
@@ -0,0 +1,433 @@
|
||||
{
|
||||
"packages": [{
|
||||
"name": "multi4in1",
|
||||
"maintainer": "Pascal Langer",
|
||||
"websiteURL": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module",
|
||||
"email": "pascal_langer@yahoo.fr",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"platforms": [
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.2.tar.gz",
|
||||
"checksum": "SHA-256:b7e2fda37186bf696b7a769b12317737d513181096b33d9ad321ec2fd47f3f80",
|
||||
"size": "164467",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.3.tar.gz",
|
||||
"checksum": "SHA-256:7d4561eebe0d7f6422f06d5719a417e15fcc0aa9cdbfc1c48a57066ce768e33c",
|
||||
"size": "164483",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.4.tar.gz",
|
||||
"checksum": "SHA-256:6c51a4eb09bcd074cc651dab3f2356ea3afd358f6330aba0d8bdfaa75f718dbb",
|
||||
"size": "167975",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.5.tar.gz",
|
||||
"checksum": "SHA-256:0a4754d47cdbb49ca194b15835686331530ed9d36c0db093a29ae5f865e75421",
|
||||
"size": "169830",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.6.tar.gz",
|
||||
"checksum": "SHA-256:4f4cf8820e30bf6c88f280514c67ee67b9dc6649f439597cfb8d0be3a5b13bf5",
|
||||
"size": "169819",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.7.tar.gz",
|
||||
"checksum": "SHA-256:453c9999e433ed1bdda2ba2b12cb7cbba7b547591db969dc6b7efb941b61cf76",
|
||||
"size": "169825",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.1.tar.gz",
|
||||
"checksum": "SHA-256:b522b5d3474308768c197a6897cad037fb54d6fac26c75678415a0908793bae3",
|
||||
"size": "10332875",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.2.tar.gz",
|
||||
"checksum": "SHA-256:26d21dbd2fe80680ac523b8bca24b3ecf2c2016bac626826d20b651e11278287",
|
||||
"size": "10318646",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.3.tar.gz",
|
||||
"checksum": "SHA-256:e48f1f30948b3f7be83e8b1fe2bb5c6b41be7c4d5da02503a0b4827c60926541",
|
||||
"size": "10309833",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.4.tar.gz",
|
||||
"checksum": "SHA-256:388a4dbcd567f9d41b82955e12e8a640d9696217081c0ee6ab8c58a25aedf70f",
|
||||
"size": "10307581",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.5.tar.gz",
|
||||
"checksum": "SHA-256:46d3b4e62fc46e6b8ca4f429974ffd2ee8cde9e29a6e0cda58f85044991a9c2b",
|
||||
"size": "10313436",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.6.tar.gz",
|
||||
"checksum": "SHA-256:ad7a330326069a5ffb2908495b288933f68517b1247cc6636b160eb483a58284",
|
||||
"size": "10319669",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.7.tar.gz",
|
||||
"checksum": "SHA-256:f73fded48beaee55e646a3cf36d24beeedc336873c7824683a4912f2aee9e350",
|
||||
"size": "10322111",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.8",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.8.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.8.tar.gz",
|
||||
"checksum": "SHA-256:f8100272ec615074cf7962c2c8331014ebda78f3e4c17172b88b6dd3d83c4331",
|
||||
"size": "10319134",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.9",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.9.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.9.tar.gz",
|
||||
"checksum": "SHA-256:c3621d1cf6580ca5c943a67dc14dc15a60e2797a4b985548abe1919486bf4a8b",
|
||||
"size": "10324251",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.0",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.0.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.0.tar.gz",
|
||||
"checksum": "SHA-256:919ece2021757686e6892679956dcb8a01c9308a152167d61d9204656b4ed7ee",
|
||||
"size": "10333612",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.1.tar.gz",
|
||||
"checksum": "SHA-256:549dbfa0f48f3e519a9efa96d03e8933cc72989c618826b2b570980d9c382979",
|
||||
"size": "10331547",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.2.tar.gz",
|
||||
"checksum": "SHA-256:debfdc14df3023045a2297bc99daf7104be75f21572fc5a4f57192ffae4028f0",
|
||||
"size": "10322776",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.3.tar.gz",
|
||||
"checksum": "SHA-256:6b9dceb033ccc31f37cebc4f025ddb862cd24a733e7c356ca2fa5719d595af89",
|
||||
"size": "10322145",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.4.tar.gz",
|
||||
"checksum": "SHA-256:16a83a3b4409cb55aead6593396979483996080634d214ae07c8a956db2480fb",
|
||||
"size": "10322152",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 OrangeRX Board - DEPRECATED, USE MULTI 4-IN-1 AVR BOARDS PACKAGE INSTEAD",
|
||||
"architecture": "orangerx",
|
||||
"version": "1.0.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_orangerx_board_v1.0.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_orangerx_board_v1.0.1.tar.gz",
|
||||
"checksum": "SHA-256:7287ce61028b754bb8ff947317dd15773fc7eeecd752826c707fa356b9b36dc6",
|
||||
"size": "161615",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (OrangeRX)"
|
||||
}],
|
||||
"toolsDependencies": []
|
||||
}
|
||||
],
|
||||
"tools": []
|
||||
}]
|
||||
}
|
||||
@@ -12,108 +12,82 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//-------------------------------
|
||||
//-------------------------------
|
||||
//A7105 SPI routines
|
||||
//-------------------------------
|
||||
//-------------------------------
|
||||
/********************/
|
||||
/** A7105 routines **/
|
||||
/********************/
|
||||
#ifdef A7105_INSTALLED
|
||||
#include "iface_a7105.h"
|
||||
|
||||
void A7105_WriteData(uint8_t len, uint8_t channel)
|
||||
{
|
||||
uint8_t i;
|
||||
CS_off;
|
||||
A7105_Write(A7105_RST_WRPTR);
|
||||
A7105_Write(0x05);
|
||||
A7105_CSN_off;
|
||||
SPI_Write(A7105_RST_WRPTR);
|
||||
SPI_Write(A7105_05_FIFO_DATA);
|
||||
for (i = 0; i < len; i++)
|
||||
A7105_Write(packet[i]);
|
||||
CS_on;
|
||||
A7105_WriteReg(0x0F, channel);
|
||||
SPI_Write(packet[i]);
|
||||
A7105_CSN_on;
|
||||
if(protocol!=PROTO_FLYSKY)
|
||||
{
|
||||
A7105_Strobe(A7105_STANDBY); //Force standby mode, ie cancel any TX or RX...
|
||||
A7105_SetTxRxMode(TX_EN); //Switch to PA
|
||||
}
|
||||
A7105_WriteReg(A7105_0F_PLL_I, channel);
|
||||
A7105_Strobe(A7105_TX);
|
||||
}
|
||||
|
||||
void A7105_ReadData() {
|
||||
void A7105_ReadData(uint8_t len)
|
||||
{
|
||||
uint8_t i;
|
||||
A7105_Strobe(0xF0); //A7105_RST_RDPTR
|
||||
CS_off;
|
||||
A7105_Write(0x45);
|
||||
for (i=0;i<16;i++)
|
||||
packet[i]=A7105_Read();
|
||||
CS_on;
|
||||
A7105_Strobe(A7105_RST_RDPTR);
|
||||
A7105_CSN_off;
|
||||
SPI_Write(0x40 | A7105_05_FIFO_DATA); //bit 6 =1 for reading
|
||||
for (i=0;i<len;i++)
|
||||
packet[i]=SPI_SDI_Read();
|
||||
A7105_CSN_on;
|
||||
}
|
||||
|
||||
void A7105_WriteReg(uint8_t address, uint8_t data) {
|
||||
CS_off;
|
||||
A7105_Write(address);
|
||||
A7105_CSN_off;
|
||||
SPI_Write(address);
|
||||
NOP();
|
||||
A7105_Write(data);
|
||||
CS_on;
|
||||
SPI_Write(data);
|
||||
A7105_CSN_on;
|
||||
}
|
||||
|
||||
uint8_t A7105_ReadReg(uint8_t address) {
|
||||
uint8_t A7105_ReadReg(uint8_t address)
|
||||
{
|
||||
uint8_t result;
|
||||
CS_off;
|
||||
A7105_Write(address |=0x40); //bit 6 =1 for reading
|
||||
result = A7105_Read();
|
||||
CS_on;
|
||||
A7105_CSN_off;
|
||||
SPI_Write(address |=0x40); //bit 6 =1 for reading
|
||||
result = SPI_SDI_Read();
|
||||
A7105_CSN_on;
|
||||
return(result);
|
||||
}
|
||||
|
||||
void A7105_Write(uint8_t command) {
|
||||
uint8_t n=8;
|
||||
|
||||
SCK_off;//SCK start low
|
||||
SDI_off;
|
||||
while(n--) {
|
||||
if(command&0x80)
|
||||
SDI_on;
|
||||
else
|
||||
SDI_off;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
command = command << 1;
|
||||
}
|
||||
SDI_on;
|
||||
}
|
||||
|
||||
uint8_t A7105_Read(void) {
|
||||
uint8_t result=0;
|
||||
uint8_t i;
|
||||
|
||||
SDI_SET_INPUT;
|
||||
for(i=0;i<8;i++) {
|
||||
if(SDI_1) ///if SDIO =1
|
||||
result=(result<<1)|0x01;
|
||||
else
|
||||
result=result<<1;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
NOP();
|
||||
}
|
||||
SDI_SET_OUTPUT;
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------
|
||||
void A7105_SetTxRxMode(uint8_t mode)
|
||||
{
|
||||
if(mode == TX_EN) {
|
||||
if(mode == TX_EN)
|
||||
{
|
||||
A7105_WriteReg(A7105_0B_GPIO1_PIN1, 0x33);
|
||||
A7105_WriteReg(A7105_0C_GPIO2_PIN_II, 0x31);
|
||||
} else if (mode == RX_EN) {
|
||||
A7105_WriteReg(A7105_0B_GPIO1_PIN1, 0x31);
|
||||
A7105_WriteReg(A7105_0C_GPIO2_PIN_II, 0x33);
|
||||
} else {
|
||||
//The A7105 seems to some with a cross-wired power-amp (A7700)
|
||||
//On the XL7105-D03, TX_EN -> RXSW and RX_EN -> TXSW
|
||||
//This means that sleep mode is wired as RX_EN = 1 and TX_EN = 1
|
||||
//If there are other amps in use, we'll need to fix this
|
||||
A7105_WriteReg(A7105_0B_GPIO1_PIN1, 0x33);
|
||||
A7105_WriteReg(A7105_0C_GPIO2_PIN_II, 0x33);
|
||||
}
|
||||
else
|
||||
if (mode == RX_EN)
|
||||
{
|
||||
A7105_WriteReg(A7105_0B_GPIO1_PIN1, 0x31);
|
||||
A7105_WriteReg(A7105_0C_GPIO2_PIN_II, 0x33);
|
||||
}
|
||||
else
|
||||
{
|
||||
//The A7105 seems to some with a cross-wired power-amp (A7700)
|
||||
//On the XL7105-D03, TX_EN -> RXSW and RX_EN -> TXSW
|
||||
//This means that sleep mode is wired as RX_EN = 1 and TX_EN = 1
|
||||
//If there are other amps in use, we'll need to fix this
|
||||
A7105_WriteReg(A7105_0B_GPIO1_PIN1, 0x33);
|
||||
A7105_WriteReg(A7105_0C_GPIO2_PIN_II, 0x33);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------
|
||||
@@ -121,38 +95,37 @@ uint8_t A7105_Reset()
|
||||
{
|
||||
uint8_t result;
|
||||
|
||||
delay(10); //wait 10ms for A7105 wakeup
|
||||
A7105_WriteReg(0x00, 0x00);
|
||||
delay(1000);
|
||||
A7105_SetTxRxMode(TXRX_OFF); //Set both GPIO as output and low
|
||||
result=A7105_ReadReg(0x10) == 0x9E; //check if is reset.
|
||||
A7105_WriteReg(A7105_00_MODE, 0x00);
|
||||
delayMilliseconds(1);
|
||||
A7105_SetTxRxMode(TXRX_OFF); //Set both GPIO as output and low
|
||||
result=A7105_ReadReg(A7105_10_PLL_II) == 0x9E; //check if is reset.
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
return result;
|
||||
}
|
||||
|
||||
void A7105_WriteID(uint32_t ida) {
|
||||
CS_off;
|
||||
A7105_Write(0x06);//ex id=0x5475c52a ;txid3txid2txid1txid0
|
||||
A7105_Write((ida>>24)&0xff);//53
|
||||
A7105_Write((ida>>16)&0xff);//75
|
||||
A7105_Write((ida>>8)&0xff);//c5
|
||||
A7105_Write((ida>>0)&0xff);//2a
|
||||
CS_on;
|
||||
void A7105_WriteID(uint32_t ida)
|
||||
{
|
||||
A7105_CSN_off;
|
||||
SPI_Write(A7105_06_ID_DATA); //ex id=0x5475c52a ;txid3txid2txid1txid0
|
||||
SPI_Write((ida>>24)&0xff); //53
|
||||
SPI_Write((ida>>16)&0xff); //75
|
||||
SPI_Write((ida>>8)&0xff); //c5
|
||||
SPI_Write((ida>>0)&0xff); //2a
|
||||
A7105_CSN_on;
|
||||
}
|
||||
|
||||
void A7105_SetPower_Value(int power)
|
||||
/*
|
||||
static void A7105_SetPower_Value(int power)
|
||||
{
|
||||
/*
|
||||
Power amp is ~+16dBm so:
|
||||
TXPOWER_100uW = -23dBm == PAC=0 TBG=0
|
||||
TXPOWER_300uW = -20dBm == PAC=0 TBG=1
|
||||
TXPOWER_1mW = -16dBm == PAC=0 TBG=2
|
||||
TXPOWER_3mW = -11dBm == PAC=0 TBG=4
|
||||
TXPOWER_10mW = -6dBm == PAC=1 TBG=5
|
||||
TXPOWER_30mW = 0dBm == PAC=2 TBG=7
|
||||
TXPOWER_100mW = 1dBm == PAC=3 TBG=7
|
||||
TXPOWER_150mW = 1dBm == PAC=3 TBG=7
|
||||
*/
|
||||
//Power amp is ~+16dBm so:
|
||||
//TXPOWER_100uW = -23dBm == PAC=0 TBG=0
|
||||
//TXPOWER_300uW = -20dBm == PAC=0 TBG=1
|
||||
//TXPOWER_1mW = -16dBm == PAC=0 TBG=2
|
||||
//TXPOWER_3mW = -11dBm == PAC=0 TBG=4
|
||||
//TXPOWER_10mW = -6dBm == PAC=1 TBG=5
|
||||
//TXPOWER_30mW = 0dBm == PAC=2 TBG=7
|
||||
//TXPOWER_100mW = 1dBm == PAC=3 TBG=7
|
||||
//TXPOWER_150mW = 1dBm == PAC=3 TBG=7
|
||||
uint8_t pac, tbg;
|
||||
switch(power) {
|
||||
case 0: pac = 0; tbg = 0; break;
|
||||
@@ -167,87 +140,233 @@ void A7105_SetPower_Value(int power)
|
||||
};
|
||||
A7105_WriteReg(0x28, (pac << 3) | tbg);
|
||||
}
|
||||
*/
|
||||
|
||||
void A7105_SetPower()
|
||||
{
|
||||
uint8_t power=A7105_BIND_POWER;
|
||||
if(IS_BIND_DONE_on)
|
||||
power=IS_POWER_FLAG_on?A7105_HIGH_POWER:A7105_LOW_POWER;
|
||||
if(IS_BIND_DONE)
|
||||
#ifdef A7105_ENABLE_LOW_POWER
|
||||
power=IS_POWER_FLAG_on?A7105_HIGH_POWER:A7105_LOW_POWER;
|
||||
#else
|
||||
power=A7105_HIGH_POWER;
|
||||
#endif
|
||||
if(IS_RANGE_FLAG_on)
|
||||
power=A7105_RANGE_POWER;
|
||||
A7105_WriteReg(0x28, power);
|
||||
if(prev_power != power)
|
||||
{
|
||||
A7105_WriteReg(A7105_28_TX_TEST, power);
|
||||
prev_power=power;
|
||||
}
|
||||
}
|
||||
|
||||
void A7105_Strobe(uint8_t address) {
|
||||
CS_off;
|
||||
A7105_Write(address);
|
||||
CS_on;
|
||||
A7105_CSN_off;
|
||||
SPI_Write(address);
|
||||
A7105_CSN_on;
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM HUBSAN_A7105_regs[] = {
|
||||
0xFF, 0x63, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x04, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0x62, 0x80, 0xFF, 0xFF, 0x0A, 0xFF, 0xFF, 0x07,
|
||||
0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF
|
||||
};
|
||||
const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x14, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50,
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f,
|
||||
0x13, 0xc3, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00,
|
||||
0x01, 0x0f, 0xff
|
||||
};
|
||||
void A7105_Init(uint8_t protocol)
|
||||
// Fine tune A7105 LO base frequency
|
||||
// this is required for some A7105 modules and/or RXs with inaccurate crystal oscillator
|
||||
void A7105_AdjustLOBaseFreq(uint8_t cmd)
|
||||
{
|
||||
void *A7105_Regs;
|
||||
|
||||
if(protocol==INIT_FLYSKY)
|
||||
static int16_t old_offset=2048;
|
||||
int16_t offset=1024;
|
||||
if(cmd==0)
|
||||
{ // Called at init of the A7105
|
||||
old_offset=2048;
|
||||
switch(protocol)
|
||||
{
|
||||
case PROTO_HUBSAN:
|
||||
#ifdef FORCE_HUBSAN_TUNING
|
||||
offset=(int16_t)FORCE_HUBSAN_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_BUGS:
|
||||
#ifdef FORCE_HUBSAN_TUNING
|
||||
offset=(int16_t)FORCE_HUBSAN_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_FLYSKY:
|
||||
#ifdef FORCE_FLYSKY_TUNING
|
||||
offset=(int16_t)FORCE_FLYSKY_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_AFHDS2A:
|
||||
#ifdef FORCE_AFHDS2A_TUNING
|
||||
offset=(int16_t)FORCE_AFHDS2A_TUNING;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(offset==1024) // Use channel 15 as an input
|
||||
offset=convert_channel_16b_nolimit(CH15,-300,300);
|
||||
|
||||
if(old_offset==offset) // offset is the same as before...
|
||||
return;
|
||||
old_offset=offset;
|
||||
|
||||
// LO base frequency = 32e6*(bip+(bfp/(2^16)))
|
||||
uint8_t bip; // LO base frequency integer part
|
||||
uint16_t bfp; // LO base frequency fractional part
|
||||
offset++; // as per datasheet, not sure why recommended, but that's a +1kHz drift only ...
|
||||
offset<<=1;
|
||||
if(offset < 0)
|
||||
{
|
||||
A7105_WriteID(0x5475c52A);//0x2Ac57554
|
||||
A7105_Regs=(void *)FLYSKY_A7105_regs;
|
||||
bip = 0x4a; // 2368 MHz
|
||||
bfp = 0xffff + offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
A7105_WriteID(0x55201041);
|
||||
A7105_Regs=(void *)HUBSAN_A7105_regs;
|
||||
bip = 0x4b; // 2400 MHz (default)
|
||||
bfp = offset;
|
||||
}
|
||||
for (uint8_t i = 0; i < 0x33; i++){
|
||||
if( pgm_read_byte_near((uint16_t)(A7105_Regs)+i) != 0xFF)
|
||||
A7105_WriteReg(i, pgm_read_byte_near((uint16_t)(A7105_Regs)+i));
|
||||
A7105_WriteReg( A7105_11_PLL_III, bip);
|
||||
A7105_WriteReg( A7105_12_PLL_IV, (bfp >> 8) & 0xff);
|
||||
A7105_WriteReg( A7105_13_PLL_V, bfp & 0xff);
|
||||
//debugln("Channel: %d, offset: %d, bip: %2x, bfp: %4x", Channel_data[14], offset, bip, bfp);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) A7105_SetVCOBand(uint8_t vb1, uint8_t vb2)
|
||||
{ // Set calibration band value to best match
|
||||
uint8_t diff1, diff2;
|
||||
|
||||
if (vb1 >= 4)
|
||||
diff1 = vb1 - 4;
|
||||
else
|
||||
diff1 = 4 - vb1;
|
||||
|
||||
if (vb2 >= 4)
|
||||
diff2 = vb2 - 4;
|
||||
else
|
||||
diff2 = 4 - vb2;
|
||||
|
||||
if (diff1 == diff2 || diff1 > diff2)
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I, vb1 | 0x08);
|
||||
else
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I, vb2 | 0x08);
|
||||
}
|
||||
|
||||
#ifdef HUBSAN_A7105_INO
|
||||
const uint8_t PROGMEM HUBSAN_A7105_regs[] = {
|
||||
0xFF, 0x63, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x04, 0xFF, // 00 - 0f
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0x62, 0x80, 0xFF, 0xFF, 0x0A, 0xFF, 0xFF, 0x07, // 10 - 1f
|
||||
0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 20 - 2f
|
||||
0xFF, 0xFF // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef FLYSKY_A7105_INO
|
||||
const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x14, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, // 10 - 1f
|
||||
0x13, 0xc3, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef AFHDS2A_A7105_INO
|
||||
const uint8_t PROGMEM AFHDS2A_A7105_regs[] = {
|
||||
0xFF, 0x42 | (1<<5), 0x00, 0x25, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3c, 0x05, 0x00, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x4f, 0x62, 0x80, 0xFF, 0xFF, 0x2a, 0x32, 0xc3, 0x1f, // 10 - 1f
|
||||
0x1e, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef BUGS_A7105_INO
|
||||
const uint8_t PROGMEM BUGS_A7105_regs[] = {
|
||||
0xFF, 0x42, 0x00, 0x15, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0x01, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x40, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, // 10 - 1f
|
||||
0x16, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3b, 0x00, 0x0b, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
|
||||
#define ID_NORMAL 0x55201041
|
||||
#define ID_PLUS 0xAA201041
|
||||
void A7105_Init(void)
|
||||
{
|
||||
uint8_t *A7105_Regs=0;
|
||||
uint8_t vco_calibration0, vco_calibration1;
|
||||
|
||||
#ifdef BUGS_A7105_INO
|
||||
if(protocol==PROTO_BUGS)
|
||||
A7105_Regs=(uint8_t*)BUGS_A7105_regs;
|
||||
else
|
||||
#endif
|
||||
#ifdef HUBSAN_A7105_INO
|
||||
if(protocol==PROTO_HUBSAN)
|
||||
{
|
||||
A7105_WriteID(ID_NORMAL);
|
||||
A7105_Regs=(uint8_t*)HUBSAN_A7105_regs;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
A7105_WriteID(0x5475c52A);//0x2Ac57554
|
||||
#ifdef FLYSKY_A7105_INO
|
||||
if(protocol==PROTO_FLYSKY)
|
||||
A7105_Regs=(uint8_t*)FLYSKY_A7105_regs;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef AFHDS2A_A7105_INO
|
||||
A7105_Regs=(uint8_t*)AFHDS2A_A7105_regs;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 0x32; i++)
|
||||
{
|
||||
uint8_t val=pgm_read_byte_near(&A7105_Regs[i]);
|
||||
#ifdef FLYSKY_A7105_INO
|
||||
if(protocol==PROTO_FLYSKY && sub_protocol==CX20)
|
||||
{
|
||||
if(i==0x0E) val=0x01;
|
||||
if(i==0x1F) val=0x1F;
|
||||
if(i==0x20) val=0x1E;
|
||||
}
|
||||
#endif
|
||||
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
|
||||
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
|
||||
// A7105_ReadReg(A7105_22_IF_CALIB_I);
|
||||
// A7105_ReadReg(A7105_24_VCO_CURCAL);
|
||||
|
||||
if(protocol==INIT_FLYSKY)
|
||||
if(protocol!=PROTO_HUBSAN)
|
||||
{
|
||||
//VCO Current Calibration
|
||||
A7105_WriteReg(A7105_24_VCO_CURCAL,0x13); //Recommended calibration from A7105 Datasheet
|
||||
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
|
||||
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
|
||||
// A7105_ReadReg(A7105_25_VCO_SBCAL_I);
|
||||
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
|
||||
// A7105_ReadReg(A7105_25_VCO_SBCAL_I);
|
||||
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
|
||||
vco_calibration1 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
|
||||
|
||||
//Reset VCO Band calibration
|
||||
if(protocol==INIT_FLYSKY)
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I,0x08);
|
||||
if(protocol==PROTO_BUGS)
|
||||
A7105_SetVCOBand(vco_calibration0 & 0x07, vco_calibration1 & 0x07); // Set calibration band value to best match
|
||||
else
|
||||
if(protocol!=PROTO_HUBSAN)
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I,protocol==PROTO_FLYSKY?0x08:0x0A); //Reset VCO Band calibration
|
||||
|
||||
A7105_SetTxRxMode(TX_EN);
|
||||
A7105_SetPower();
|
||||
|
||||
A7105_AdjustLOBaseFreq(0);
|
||||
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
}
|
||||
#endif
|
||||
400
Multiprotocol/AFHDS2A_a7105.ino
Normal file
400
Multiprotocol/AFHDS2A_a7105.ino
Normal file
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with hexfet new_protocols/flysky_a7105.c dated 2015-09-28
|
||||
|
||||
#ifdef AFHDS2A_A7105_INO
|
||||
|
||||
#define AFHDS2A_TXPACKET_SIZE 38
|
||||
#define AFHDS2A_RXPACKET_SIZE 37
|
||||
#define AFHDS2A_NUMFREQ 16
|
||||
|
||||
enum{
|
||||
AFHDS2A_PACKET_STICKS,
|
||||
AFHDS2A_PACKET_SETTINGS,
|
||||
AFHDS2A_PACKET_FAILSAFE,
|
||||
};
|
||||
|
||||
enum{
|
||||
AFHDS2A_BIND1,
|
||||
AFHDS2A_BIND2,
|
||||
AFHDS2A_BIND3,
|
||||
AFHDS2A_BIND4,
|
||||
AFHDS2A_DATA_INIT,
|
||||
AFHDS2A_DATA,
|
||||
};
|
||||
|
||||
static void AFHDS2A_calc_channels()
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint32_t rnd = MProtocol_id;
|
||||
while (idx < AFHDS2A_NUMFREQ)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t band_no = ((((idx<<1) | ((idx>>1) & 0b01)) + rx_tx_addr[3]) & 0b11);
|
||||
rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
|
||||
|
||||
uint8_t next_ch = band_no*41 + 1 + ((rnd >> idx) % 41); // Channel range: 1..164
|
||||
|
||||
for (i = 0; i < idx; i++)
|
||||
{
|
||||
// Keep the distance 5 between the channels
|
||||
uint8_t distance;
|
||||
if (next_ch > hopping_frequency[i])
|
||||
distance = next_ch - hopping_frequency[i];
|
||||
else
|
||||
distance = hopping_frequency[i] - next_ch;
|
||||
|
||||
if (distance < 5) break;
|
||||
}
|
||||
|
||||
if (i != idx) continue;
|
||||
|
||||
hopping_frequency[idx++] = next_ch;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
|
||||
// telemetry sensors ID
|
||||
enum{
|
||||
AFHDS2A_SENSOR_RX_VOLTAGE = 0x00,
|
||||
AFHDS2A_SENSOR_RX_ERR_RATE = 0xfe,
|
||||
AFHDS2A_SENSOR_RX_RSSI = 0xfc,
|
||||
AFHDS2A_SENSOR_RX_NOISE = 0xfb,
|
||||
AFHDS2A_SENSOR_RX_SNR = 0xfa,
|
||||
AFHDS2A_SENSOR_A3_VOLTAGE = 0x03,
|
||||
};
|
||||
|
||||
static void AFHDS2A_update_telemetry()
|
||||
{
|
||||
// Read TX RSSI
|
||||
int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less
|
||||
if(temp<0) temp=0;
|
||||
else if(temp>255) temp=255;
|
||||
TX_RSSI=temp;
|
||||
// AA | TXID | rx_id | sensor id | sensor # | value 16 bit big endian | sensor id ......
|
||||
// max 7 sensors per packet
|
||||
#ifdef AFHDS2A_FW_TELEMETRY
|
||||
if (option & 0x80)
|
||||
{// forward 0xAA and 0xAC telemetry to TX, skip rx and tx id to save space
|
||||
pkt[0]= TX_RSSI;
|
||||
debug("T=");
|
||||
for(int i=9;i < AFHDS2A_RXPACKET_SIZE; i++)
|
||||
{
|
||||
pkt[i-8]=packet[i];
|
||||
debug(" %02X",packet[i]);
|
||||
}
|
||||
telemetry_link=2;
|
||||
debugln("");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef AFHDS2A_HUB_TELEMETRY
|
||||
if(packet[0]==0xAA)
|
||||
{ // 0xAA Normal telemetry, 0xAC Extended telemetry not decoded here
|
||||
for(uint8_t sensor=0; sensor<7; sensor++)
|
||||
{
|
||||
// Send FrSkyD telemetry to TX
|
||||
uint8_t index = 9+(4*sensor);
|
||||
switch(packet[index])
|
||||
{
|
||||
case AFHDS2A_SENSOR_RX_VOLTAGE:
|
||||
//v_lipo1 = packet[index+3]<<8 | packet[index+2];
|
||||
v_lipo1 = packet[index+2];
|
||||
telemetry_link=1;
|
||||
break;
|
||||
case AFHDS2A_SENSOR_A3_VOLTAGE:
|
||||
v_lipo2 = (packet[index+3]<<5) | (packet[index+2]>>3); // allows to read voltage up to 4S
|
||||
telemetry_link=1;
|
||||
break;
|
||||
case AFHDS2A_SENSOR_RX_ERR_RATE:
|
||||
RX_LQI=packet[index+2];
|
||||
break;
|
||||
case AFHDS2A_SENSOR_RX_RSSI:
|
||||
RX_RSSI = -packet[index+2];
|
||||
break;
|
||||
case 0xff: // end of data
|
||||
return;
|
||||
/*default:
|
||||
// unknown sensor ID
|
||||
break;*/
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void AFHDS2A_build_bind_packet()
|
||||
{
|
||||
uint8_t ch;
|
||||
memcpy( &packet[1], rx_tx_addr, 4);
|
||||
memset( &packet[5], 0xff, 4);
|
||||
packet[10]= 0x00;
|
||||
for(ch=0; ch<AFHDS2A_NUMFREQ; ch++)
|
||||
packet[11+ch] = hopping_frequency[ch];
|
||||
memset( &packet[27], 0xff, 10);
|
||||
packet[37] = 0x00;
|
||||
switch(phase)
|
||||
{
|
||||
case AFHDS2A_BIND1:
|
||||
packet[0] = 0xbb;
|
||||
packet[9] = 0x01;
|
||||
break;
|
||||
case AFHDS2A_BIND2:
|
||||
case AFHDS2A_BIND3:
|
||||
case AFHDS2A_BIND4:
|
||||
packet[0] = 0xbc;
|
||||
if(phase == AFHDS2A_BIND4)
|
||||
{
|
||||
memcpy( &packet[5], &rx_id, 4);
|
||||
memset( &packet[11], 0xff, 16);
|
||||
}
|
||||
packet[9] = phase-1;
|
||||
if(packet[9] > 0x02)
|
||||
packet[9] = 0x02;
|
||||
packet[27]= 0x01;
|
||||
packet[28]= 0x80;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void AFHDS2A_build_packet(uint8_t type)
|
||||
{
|
||||
uint16_t val;
|
||||
memcpy( &packet[1], rx_tx_addr, 4);
|
||||
memcpy( &packet[5], rx_id, 4);
|
||||
switch(type)
|
||||
{
|
||||
case AFHDS2A_PACKET_STICKS:
|
||||
packet[0] = 0x58;
|
||||
for(uint8_t ch=0; ch<14; ch++)
|
||||
{
|
||||
uint16_t channelMicros = convert_channel_ppm(CH_AETR[ch]);
|
||||
packet[9 + ch*2] = channelMicros&0xFF;
|
||||
packet[10 + ch*2] = (channelMicros>>8)&0xFF;
|
||||
}
|
||||
#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++)
|
||||
{
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
uint16_t failsafeMicros = Failsafe_data[CH_AETR[ch]];
|
||||
if( failsafeMicros!=FAILSAFE_CHANNEL_HOLD && failsafeMicros!=FAILSAFE_CHANNEL_NOPULSES)
|
||||
{ // Failsafe values
|
||||
failsafeMicros = (((failsafeMicros<<2)+failsafeMicros)>>3)+860;
|
||||
packet[9 + ch*2] = failsafeMicros & 0xff;
|
||||
packet[10+ ch*2] = ( failsafeMicros >> 8) & 0xff;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{ // no values
|
||||
packet[9 + ch*2] = 0xff;
|
||||
packet[10+ ch*2] = 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AFHDS2A_PACKET_SETTINGS:
|
||||
packet[0] = 0xaa;
|
||||
packet[9] = 0xfd;
|
||||
packet[10]= 0xff;
|
||||
val=5*(option & 0x7f)+50; // option value should be between 0 and 70 which gives a value between 50 and 400Hz
|
||||
if(val<50 || val>400) val=50; // default is 50Hz
|
||||
packet[11]= val;
|
||||
packet[12]= val >> 8;
|
||||
if(sub_protocol == PPM_IBUS || sub_protocol == PPM_SBUS)
|
||||
packet[13] = 0x01; // PPM output enabled
|
||||
else
|
||||
packet[13] = 0x00;
|
||||
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)
|
||||
packet[21] = 0xdd; // SBUS output enabled
|
||||
else
|
||||
packet[21] = 0xde; // IBUS
|
||||
break;
|
||||
}
|
||||
packet[37] = 0x00;
|
||||
}
|
||||
|
||||
#define AFHDS2A_WAIT_WRITE 0x80
|
||||
uint16_t ReadAFHDS2A()
|
||||
{
|
||||
static uint8_t packet_type;
|
||||
static uint16_t packet_counter;
|
||||
uint8_t data_rx;
|
||||
uint16_t start;
|
||||
#ifndef FORCE_AFHDS2A_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
switch(phase)
|
||||
{
|
||||
case AFHDS2A_BIND1:
|
||||
case AFHDS2A_BIND2:
|
||||
case AFHDS2A_BIND3:
|
||||
AFHDS2A_build_bind_packet();
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, packet_count%2 ? 0x0d : 0x8c);
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5 | 1<<6)))
|
||||
{ // FECF+CRCF Ok
|
||||
A7105_ReadData(AFHDS2A_RXPACKET_SIZE);
|
||||
if(packet[0] == 0xbc && packet[9] == 0x01)
|
||||
{
|
||||
uint8_t temp=AFHDS2A_EEPROM_OFFSET+RX_num*4;
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
{
|
||||
rx_id[i] = packet[5+i];
|
||||
eeprom_write_byte((EE_ADDR)(temp+i),rx_id[i]);
|
||||
}
|
||||
phase = AFHDS2A_BIND4;
|
||||
packet_count++;
|
||||
return 3850;
|
||||
}
|
||||
}
|
||||
packet_count++;
|
||||
if(IS_BIND_DONE)
|
||||
{ // exit bind if asked to do so from the GUI
|
||||
phase = AFHDS2A_BIND4;
|
||||
return 3850;
|
||||
}
|
||||
phase |= AFHDS2A_WAIT_WRITE;
|
||||
return 1700;
|
||||
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
|
||||
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_Strobe(A7105_RX);
|
||||
phase &= ~AFHDS2A_WAIT_WRITE;
|
||||
phase++;
|
||||
if(phase > AFHDS2A_BIND3)
|
||||
phase = AFHDS2A_BIND1;
|
||||
return 2150;
|
||||
case AFHDS2A_BIND4:
|
||||
AFHDS2A_build_bind_packet();
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, packet_count%2 ? 0x0d : 0x8c);
|
||||
packet_count++;
|
||||
bind_phase++;
|
||||
if(bind_phase>=4)
|
||||
{
|
||||
hopping_frequency_no=1;
|
||||
phase = AFHDS2A_DATA_INIT;
|
||||
BIND_DONE;
|
||||
}
|
||||
return 3850;
|
||||
case AFHDS2A_DATA_INIT:
|
||||
packet_counter=0;
|
||||
packet_type = AFHDS2A_PACKET_STICKS;
|
||||
phase = AFHDS2A_DATA;
|
||||
case AFHDS2A_DATA:
|
||||
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
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, hopping_frequency[hopping_frequency_no++]);
|
||||
if(hopping_frequency_no >= AFHDS2A_NUMFREQ)
|
||||
hopping_frequency_no = 0;
|
||||
if(!(packet_counter % 1313))
|
||||
packet_type = AFHDS2A_PACKET_SETTINGS;
|
||||
else
|
||||
{
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(!(packet_counter % 1569) && IS_FAILSAFE_VALUES_on)
|
||||
packet_type = AFHDS2A_PACKET_FAILSAFE;
|
||||
else
|
||||
#endif
|
||||
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
|
||||
A7105_ReadData(AFHDS2A_RXPACKET_SIZE);
|
||||
if(packet[0] == 0xAA && packet[9] == 0xFC)
|
||||
packet_type=AFHDS2A_PACKET_SETTINGS; // RX is asking for settings
|
||||
else
|
||||
if(packet[0] == 0xAA || packet[0] == 0xAC)
|
||||
{
|
||||
if(!memcmp(&packet[1], rx_tx_addr, 4))
|
||||
{ // Validate TX address
|
||||
#ifdef AFHDS2A_LQI_CH
|
||||
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)
|
||||
RX_LQI=packet[index+2];
|
||||
}
|
||||
#endif
|
||||
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
|
||||
AFHDS2A_update_telemetry();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
packet_counter++;
|
||||
phase |= AFHDS2A_WAIT_WRITE;
|
||||
return 1700;
|
||||
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
|
||||
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; // never reached, please the compiler
|
||||
}
|
||||
|
||||
uint16_t initAFHDS2A()
|
||||
{
|
||||
A7105_Init();
|
||||
|
||||
AFHDS2A_calc_channels();
|
||||
packet_count = 0;
|
||||
bind_phase = 0;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
phase = AFHDS2A_BIND1;
|
||||
else
|
||||
{
|
||||
phase = AFHDS2A_DATA_INIT;
|
||||
//Read RX ID from EEPROM based on RX_num, RX_num must be uniq for each RX
|
||||
uint8_t temp=AFHDS2A_EEPROM_OFFSET+RX_num*4;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
rx_id[i]=eeprom_read_byte((EE_ADDR)(temp+i));
|
||||
}
|
||||
hopping_frequency_no = 0;
|
||||
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
|
||||
init_frskyd_link_telemetry();
|
||||
#endif
|
||||
return 50000;
|
||||
}
|
||||
#endif
|
||||
182
Multiprotocol/ASSAN_nrf24l01.ino
Normal file
182
Multiprotocol/ASSAN_nrf24l01.ino
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(ASSAN_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define ASSAN_PACKET_SIZE 20
|
||||
#define ASSAN_RF_BIND_CHANNEL 0x03
|
||||
#define ASSAN_ADDRESS_LENGTH 4
|
||||
|
||||
enum {
|
||||
ASSAN_BIND0=0,
|
||||
ASSAN_BIND1,
|
||||
ASSAN_BIND2,
|
||||
ASSAN_DATA0,
|
||||
ASSAN_DATA1,
|
||||
ASSAN_DATA2,
|
||||
ASSAN_DATA3,
|
||||
ASSAN_DATA4,
|
||||
ASSAN_DATA5
|
||||
};
|
||||
|
||||
void ASSAN_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x02); // 4 bytes rx/tx address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x80\x80\x80\xB8", ASSAN_ADDRESS_LENGTH); // Bind address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x80\x80\x80\xB8", ASSAN_ADDRESS_LENGTH); // Bind address
|
||||
NRF24L01_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()
|
||||
{
|
||||
for(uint8_t i=0;i<8;i++)
|
||||
{
|
||||
uint16_t val=Channel_data[i];
|
||||
val=((val<<2)+val)+(860<<3); // PPM value <<3
|
||||
|
||||
packet[2*i]=val>>8;
|
||||
packet[2*i+1]=val;
|
||||
}
|
||||
for(uint8_t i=0;i<ASSAN_ADDRESS_LENGTH;i++)
|
||||
packet[16+i]=packet[23-i];
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, ASSAN_PACKET_SIZE);
|
||||
}
|
||||
|
||||
uint16_t ASSAN_callback()
|
||||
{
|
||||
switch (phase)
|
||||
{
|
||||
// Bind
|
||||
case ASSAN_BIND0:
|
||||
//Config RX @1M
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, ASSAN_RF_BIND_CHANNEL);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
phase++;
|
||||
case ASSAN_BIND1:
|
||||
//Wait for receiver to send the frames
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ //Something has been received
|
||||
NRF24L01_ReadPayload(packet, ASSAN_PACKET_SIZE);
|
||||
if(packet[19]==0x13)
|
||||
{ //Last frame received
|
||||
phase++;
|
||||
//Switch to TX
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
//Prepare bind packet
|
||||
memset(packet,0x05,ASSAN_PACKET_SIZE-5);
|
||||
packet[15]=0x99;
|
||||
for(uint8_t i=0;i<ASSAN_ADDRESS_LENGTH;i++)
|
||||
packet[16+i]=packet[23-i];
|
||||
packet_count=0;
|
||||
delayMilliseconds(260);
|
||||
return 10000; // Wait 270ms in total...
|
||||
}
|
||||
}
|
||||
return 1000;
|
||||
case ASSAN_BIND2:
|
||||
// Send 20 packets
|
||||
packet_count++;
|
||||
if(packet_count==20)
|
||||
packet[15]=0x13; // different value for last packet
|
||||
NRF24L01_WritePayload(packet, ASSAN_PACKET_SIZE);
|
||||
if(packet_count==20)
|
||||
{
|
||||
phase++;
|
||||
delayMilliseconds(2165);
|
||||
}
|
||||
return 22520;
|
||||
// Normal operation
|
||||
case ASSAN_DATA0:
|
||||
// Bind Done
|
||||
BIND_DONE;
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
case ASSAN_DATA1:
|
||||
case ASSAN_DATA4:
|
||||
// Change ID and RF channel
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR,packet+20+4*hopping_frequency_no, ASSAN_ADDRESS_LENGTH);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
hopping_frequency_no^=0x01;
|
||||
NRF24L01_SetPower();
|
||||
phase=ASSAN_DATA2;
|
||||
return 2000;
|
||||
case ASSAN_DATA2:
|
||||
case ASSAN_DATA3:
|
||||
ASSAN_send_packet();
|
||||
phase++; // DATA 3 or 4
|
||||
return 5000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ASSAN_initialize_txid()
|
||||
{
|
||||
/* //Renaud TXID with Freq=36 and alternate Freq 67 or 68 or 69 or 70 or 71 or 73 or 74 or 75 or 78 and may be more...
|
||||
packet[23]=0x22;
|
||||
packet[22]=0x37;
|
||||
packet[21]=0xFA;
|
||||
packet[20]=0x53; */
|
||||
// Using packet[20..23] to store the ID1 and packet[24..27] to store the ID2
|
||||
uint8_t freq=0,freq2;
|
||||
for(uint8_t i=0;i<ASSAN_ADDRESS_LENGTH;i++)
|
||||
{
|
||||
uint8_t temp=rx_tx_addr[i];
|
||||
packet[i+20]=temp;
|
||||
packet[i+24]=temp+1;
|
||||
freq+=temp;
|
||||
}
|
||||
|
||||
// Main frequency
|
||||
freq=((freq%25)+2)<<1;
|
||||
if(freq&0x02) freq|=0x01;
|
||||
hopping_frequency[0]=freq;
|
||||
// Alternate frequency has some random
|
||||
do
|
||||
{
|
||||
freq2=random(0xfefefefe)%9;
|
||||
freq2+=freq*2-5;
|
||||
}
|
||||
while( (freq2>118) || (freq2<freq+1) || (freq2==2*freq) );
|
||||
hopping_frequency[1]=freq2;
|
||||
}
|
||||
|
||||
uint16_t initASSAN()
|
||||
{
|
||||
ASSAN_initialize_txid();
|
||||
ASSAN_init();
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
phase=ASSAN_BIND0;
|
||||
else
|
||||
phase=ASSAN_DATA0;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
#endif
|
||||
159
Multiprotocol/Arduino.ino
Normal file
159
Multiprotocol/Arduino.ino
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/************************************/
|
||||
/************************************/
|
||||
/** Arduino replacement routines **/
|
||||
/************************************/
|
||||
// replacement map()
|
||||
int16_t map16b( int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max)
|
||||
{
|
||||
// return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
long y ;
|
||||
x -= in_min ;
|
||||
y = out_max - out_min ;
|
||||
y *= x ;
|
||||
x = y / (in_max - in_min) ;
|
||||
return x + out_min ;
|
||||
}
|
||||
|
||||
#ifndef STM32_BOARD
|
||||
int16_t map( int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max)
|
||||
{
|
||||
// return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
long y ;
|
||||
x -= in_min ;
|
||||
y = out_max - out_min ;
|
||||
y *= x ;
|
||||
x = y / (in_max - in_min) ;
|
||||
return x + out_min ;
|
||||
}
|
||||
|
||||
// replacement millis() and micros()
|
||||
// These work polled, no interrupts
|
||||
// micros() MUST be called at least once every 32 milliseconds
|
||||
uint16_t MillisPrecount ;
|
||||
uint16_t lastTimerValue ;
|
||||
uint32_t TotalMicros ;
|
||||
uint32_t TotalMillis ;
|
||||
uint8_t Correction ;
|
||||
|
||||
uint32_t micros()
|
||||
{
|
||||
uint16_t elapsed ;
|
||||
uint8_t millisToAdd ;
|
||||
uint8_t oldSREG = SREG ;
|
||||
cli() ;
|
||||
uint16_t time = TCNT1 ; // Read timer 1
|
||||
SREG = oldSREG ;
|
||||
|
||||
elapsed = time - lastTimerValue ;
|
||||
elapsed += Correction ;
|
||||
Correction = elapsed & 0x01 ;
|
||||
elapsed >>= 1 ;
|
||||
|
||||
uint32_t ltime = TotalMicros ;
|
||||
ltime += elapsed ;
|
||||
cli() ;
|
||||
TotalMicros = ltime ; // Done this way for RPM to work correctly
|
||||
lastTimerValue = time ;
|
||||
SREG = oldSREG ; // Still valid from above
|
||||
|
||||
elapsed += MillisPrecount;
|
||||
millisToAdd = 0 ;
|
||||
|
||||
if ( elapsed > 15999 )
|
||||
{
|
||||
millisToAdd = 16 ;
|
||||
elapsed -= 16000 ;
|
||||
}
|
||||
if ( elapsed > 7999 )
|
||||
{
|
||||
millisToAdd += 8 ;
|
||||
elapsed -= 8000 ;
|
||||
}
|
||||
if ( elapsed > 3999 )
|
||||
{
|
||||
millisToAdd += 4 ;
|
||||
elapsed -= 4000 ;
|
||||
}
|
||||
if ( elapsed > 1999 )
|
||||
{
|
||||
millisToAdd += 2 ;
|
||||
elapsed -= 2000 ;
|
||||
}
|
||||
if ( elapsed > 999 )
|
||||
{
|
||||
millisToAdd += 1 ;
|
||||
elapsed -= 1000 ;
|
||||
}
|
||||
TotalMillis += millisToAdd ;
|
||||
MillisPrecount = elapsed ;
|
||||
return TotalMicros ;
|
||||
}
|
||||
|
||||
uint32_t millis()
|
||||
{
|
||||
micros() ;
|
||||
return TotalMillis ;
|
||||
}
|
||||
|
||||
void delayMilliseconds(unsigned long ms)
|
||||
{
|
||||
uint16_t start = (uint16_t)micros();
|
||||
uint16_t lms = ms ;
|
||||
|
||||
while (lms > 0) {
|
||||
if (((uint16_t)micros() - start) >= 1000) {
|
||||
lms--;
|
||||
start += 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Important notes:
|
||||
- Max value is 16000µs
|
||||
- delay is not accurate due to interrupts happening */
|
||||
void delayMicroseconds(unsigned int us)
|
||||
{
|
||||
if (--us == 0)
|
||||
return;
|
||||
us <<= 2; // * 4
|
||||
us -= 2; // - 2
|
||||
#ifdef ORANGE_TX
|
||||
__asm__ __volatile__ (
|
||||
"1: sbiw %0,1" "\n\t" // 2 cycles
|
||||
"nop \n"
|
||||
"nop \n"
|
||||
"nop \n"
|
||||
"nop \n"
|
||||
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
|
||||
);
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"1: sbiw %0,1" "\n\t" // 2 cycles
|
||||
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef ORANGE_TX
|
||||
void init()
|
||||
{
|
||||
// this needs to be called before setup() or some functions won't work there
|
||||
sei();
|
||||
}
|
||||
#endif //ORANGE_TX
|
||||
|
||||
#endif //STM32_BOARD
|
||||
384
Multiprotocol/BUGSMINI_nrf24l01.ino
Normal file
384
Multiprotocol/BUGSMINI_nrf24l01.ino
Normal file
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// compatible with MJX Bugs 3 Mini and Bugs 3H
|
||||
|
||||
#if defined(BUGSMINI_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BUGSMINI_INITIAL_WAIT 500
|
||||
#define BUGSMINI_PACKET_INTERVAL 6840
|
||||
#define BUGSMINI_WRITE_WAIT 2000
|
||||
#define BUGSMINI_TX_PAYLOAD_SIZE 24
|
||||
#define BUGSMINI_RX_PAYLOAD_SIZE 16
|
||||
#define BUGSMINI_NUM_RF_CHANNELS 15
|
||||
#define BUGSMINI_ADDRESS_SIZE 5
|
||||
|
||||
static uint8_t BUGSMINI_txid[3];
|
||||
static uint8_t BUGSMINI_txhash;
|
||||
|
||||
enum {
|
||||
BUGSMINI_BIND1,
|
||||
BUGSMINI_BIND2,
|
||||
BUGSMINI_DATA1,
|
||||
BUGSMINI_DATA2
|
||||
};
|
||||
|
||||
#define BUGSMINI_CH_SW_ARM CH5_SW
|
||||
#define BUGSMINI_CH_SW_ANGLE CH6_SW
|
||||
#define BUGSMINI_CH_SW_FLIP CH7_SW
|
||||
#define BUGSMINI_CH_SW_PICTURE CH8_SW
|
||||
#define BUGSMINI_CH_SW_VIDEO CH9_SW
|
||||
#define BUGSMINI_CH_SW_LED CH10_SW
|
||||
#define BUGSMINI_CH_SW_ALTHOLD CH11_SW
|
||||
|
||||
// flags packet[12]
|
||||
#define BUGSMINI_FLAG_FLIP 0x08 // automatic flip
|
||||
#define BUGSMINI_FLAG_MODE 0x04 // low/high speed select (set is high speed)
|
||||
#define BUGSMINI_FLAG_VIDEO 0x02 // toggle video
|
||||
#define BUGSMINI_FLAG_PICTURE 0x01 // toggle picture
|
||||
|
||||
// flags packet[13]
|
||||
#define BUGSMINI_FLAG_LED 0x80 // enable LEDs
|
||||
#define BUGSMINI_FLAG_ARM 0x40 // arm (toggle to turn on motors)
|
||||
#define BUGSMINI_FLAG_DISARM 0x20 // disarm (toggle to turn off motors)
|
||||
#define BUGSMINI_FLAG_ANGLE 0x02 // angle/acro mode (set is angle mode)
|
||||
#define BUGSMINI_FLAG_ALTHOLD 0x04 // angle/altitude hold mode (set is altitude mode)
|
||||
|
||||
static void __attribute__((unused)) BUGSMINI_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
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGSMINI_check_arming()
|
||||
{
|
||||
uint8_t arm_channel = BUGSMINI_CH_SW_ARM;
|
||||
|
||||
if (arm_channel != arm_channel_previous)
|
||||
{
|
||||
arm_channel_previous = arm_channel;
|
||||
if (arm_channel)
|
||||
{
|
||||
armed = 1;
|
||||
arm_flags ^= BUGSMINI_FLAG_ARM;
|
||||
}
|
||||
else
|
||||
{
|
||||
armed = 0;
|
||||
arm_flags ^= BUGSMINI_FLAG_DISARM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind)
|
||||
{
|
||||
BUGSMINI_check_arming(); // sets globals arm_flags and armed
|
||||
|
||||
uint16_t aileron = convert_channel_16b_limit(AILERON,500,0);
|
||||
uint16_t elevator = convert_channel_16b_limit(ELEVATOR,0,500);
|
||||
uint16_t throttle = armed ? convert_channel_16b_limit(THROTTLE,0,500) : 0;
|
||||
uint16_t rudder = convert_channel_16b_limit(RUDDER,500,0);
|
||||
|
||||
packet[1] = BUGSMINI_txid[0];
|
||||
packet[2] = BUGSMINI_txid[1];
|
||||
packet[3] = BUGSMINI_txid[2];
|
||||
if(bind)
|
||||
{
|
||||
packet[4] = 0x00;
|
||||
packet[5] = 0x7d;
|
||||
packet[6] = 0x7d;
|
||||
packet[7] = 0x7d;
|
||||
packet[8] = 0x20;
|
||||
packet[9] = 0x20;
|
||||
packet[10]= 0x20;
|
||||
packet[11]= 0x40;
|
||||
packet[12]^= 0x40; // alternating freq hopping flag
|
||||
packet[13]= 0x60;
|
||||
packet[14]= 0x00;
|
||||
packet[15]= 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[4] = throttle >> 1;
|
||||
packet[5] = rudder >> 1;
|
||||
packet[6] = elevator >> 1;
|
||||
packet[7] = aileron >> 1;
|
||||
packet[8] = (((aileron / 5) >> 1) + 7) // dynamic trim 0x07 - 0x39
|
||||
| (aileron << 7);
|
||||
packet[9] = (((elevator / 5) >> 1) + 7) // dynamic trim 0x07 - 0x39
|
||||
| (elevator << 7);
|
||||
packet[10]= (((rudder / 5) >> 1) + 7) // dynamic trim 0x07 - 0x39
|
||||
| (rudder << 7);
|
||||
packet[11]= 0x40 | (throttle << 7);
|
||||
packet[12]= 0x80 | ((packet[12] ^ 0x40) & 0x40)
|
||||
| BUGSMINI_FLAG_MODE
|
||||
| GET_FLAG(BUGSMINI_CH_SW_PICTURE, BUGSMINI_FLAG_PICTURE)
|
||||
| GET_FLAG(BUGSMINI_CH_SW_VIDEO, BUGSMINI_FLAG_VIDEO);
|
||||
if(armed)
|
||||
packet[12] |= GET_FLAG(BUGSMINI_CH_SW_FLIP, BUGSMINI_FLAG_FLIP);
|
||||
packet[13] = arm_flags
|
||||
| GET_FLAG(BUGSMINI_CH_SW_LED, BUGSMINI_FLAG_LED)
|
||||
| GET_FLAG(BUGSMINI_CH_SW_ALTHOLD, BUGSMINI_FLAG_ALTHOLD)
|
||||
| GET_FLAG(BUGSMINI_CH_SW_ANGLE, BUGSMINI_FLAG_ANGLE);
|
||||
// BUGS3H althold -> BUGSMINI_FLAG_ALTHOLD|BUGSMINI_FLAG_ANGLE , angle -> 0
|
||||
packet[14] = 0;
|
||||
packet[15] = 0; // a lot of 0x53 and some 0x52 on bugs 3H
|
||||
}
|
||||
uint8_t checksum = 0x6d;
|
||||
for(uint8_t i=1; i < BUGSMINI_TX_PAYLOAD_SIZE; i++)
|
||||
checksum ^= packet[i];
|
||||
packet[0] = checksum;
|
||||
|
||||
if(!(packet[12]&0x40))
|
||||
{
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no >= BUGSMINI_NUM_RF_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? hopping_frequency[hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS] : hopping_frequency[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();
|
||||
XN297_WritePayload(packet, BUGSMINI_TX_PAYLOAD_SIZE);
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
// compute final address for the rxid received during bind
|
||||
// thanks to Pascal for the function!
|
||||
const uint8_t PROGMEM BUGSMINI_end []= {
|
||||
0x2d,0x9e ,0x95,0xa4 ,0x9c,0x5c ,0xb4,0xa6 ,0xa9,0xce ,0x56,0x2b ,0x3e,0x73 ,0xb8,0x95 ,0x6a,0x82,
|
||||
0x94,0x37 ,0x3d,0x5a ,0x4b,0xb2 ,0x69,0x49 ,0xc2,0x24 ,0x6b,0x3d ,0x23,0xc6 ,0x9e,0xa3 ,0xa4,0x98,
|
||||
0x5c,0x9e ,0xa6,0x52 ,0xce,0x76 ,0x2b,0x4b ,0x73,0x3a };
|
||||
static void __attribute__((unused)) BUGSMINI_make_address()
|
||||
{
|
||||
uint8_t start, length, index;
|
||||
|
||||
//read rxid
|
||||
uint8_t base_adr=BUGSMINI_EEPROM_OFFSET+RX_num*2;
|
||||
uint8_t rxid_high = eeprom_read_byte((EE_ADDR)(base_adr+0));
|
||||
uint8_t rxid_low = eeprom_read_byte((EE_ADDR)(base_adr+1));
|
||||
|
||||
if(rxid_high==0x00 || rxid_high==0xFF)
|
||||
rx_tx_addr[0]=0x52;
|
||||
else
|
||||
rx_tx_addr[0]=rxid_high;
|
||||
|
||||
rx_tx_addr[1]=BUGSMINI_txhash;
|
||||
|
||||
if(rxid_low==0x00 || rxid_low==0xFF)
|
||||
rx_tx_addr[2]=0x66;
|
||||
else
|
||||
rx_tx_addr[2]=rxid_low;
|
||||
|
||||
for(uint8_t end_idx=0;end_idx<23;end_idx++)
|
||||
{
|
||||
//calculate sequence start
|
||||
if(end_idx<=7)
|
||||
start=end_idx;
|
||||
else
|
||||
start=(end_idx-7)*16+7;
|
||||
//calculate sequence length
|
||||
if(end_idx>6)
|
||||
{
|
||||
if(end_idx>15)
|
||||
length=(23-end_idx)<<1;
|
||||
else
|
||||
length=16;
|
||||
}
|
||||
else
|
||||
length=(end_idx+1)<<1;
|
||||
//calculate first index
|
||||
index=start-rxid_high;
|
||||
//scan for a possible match using the current end
|
||||
for(uint8_t i=0;i<length;i++)
|
||||
{
|
||||
if(index==rxid_low)
|
||||
{ //match found
|
||||
rx_tx_addr[3]=pgm_read_byte_near( &BUGSMINI_end[end_idx<<1] );
|
||||
rx_tx_addr[4]=pgm_read_byte_near( &BUGSMINI_end[(end_idx<<1)+1] );
|
||||
return;
|
||||
}
|
||||
index+=i&1?7:8; //increment index
|
||||
}
|
||||
}
|
||||
// Something wrong happened if we arrive here....
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
RX_RSSI = packet[3];
|
||||
if(sub_protocol==BUGS3H)
|
||||
{
|
||||
if(packet[11] & 0x40)
|
||||
v_lipo1 = 0x40; // Warning
|
||||
else if(packet[11] & 0x80)
|
||||
v_lipo1 = 0x20; // Critical
|
||||
else
|
||||
v_lipo1 = 0x80; // Ok
|
||||
}
|
||||
else
|
||||
{
|
||||
if(packet[11] & 0x80)
|
||||
v_lipo1 = 0x80; // Ok
|
||||
else if(packet[11] & 0x40)
|
||||
v_lipo1 = 0x40; // Warning
|
||||
else
|
||||
v_lipo1 = 0x20; // Critical
|
||||
}
|
||||
telemetry_link=1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t BUGSMINI_callback()
|
||||
{
|
||||
uint8_t base_adr;
|
||||
switch(phase)
|
||||
{
|
||||
case BUGSMINI_BIND1:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready
|
||||
XN297_ReadPayload(packet, BUGSMINI_RX_PAYLOAD_SIZE);
|
||||
base_adr=BUGSMINI_EEPROM_OFFSET+RX_num*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);
|
||||
BUGSMINI_make_address();
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
XN297_SetRXAddr(rx_tx_addr, 5);
|
||||
phase = BUGSMINI_DATA1;
|
||||
BIND_DONE;
|
||||
return BUGSMINI_PACKET_INTERVAL;
|
||||
}
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
BUGSMINI_send_packet(1);
|
||||
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));
|
||||
phase = BUGSMINI_BIND1;
|
||||
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
|
||||
case BUGSMINI_DATA1:
|
||||
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);
|
||||
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));
|
||||
phase = BUGSMINI_DATA1;
|
||||
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
|
||||
}
|
||||
return BUGSMINI_PACKET_INTERVAL;
|
||||
}
|
||||
|
||||
#define BUGSMINI_NUM_TX_RF_MAPS 4
|
||||
// haven't figured out BUGSMINI_txid<-->rf channel mapping yet
|
||||
const uint8_t PROGMEM BUGSMINI_RF_chans[BUGSMINI_NUM_TX_RF_MAPS][BUGSMINI_NUM_RF_CHANNELS] = {
|
||||
{0x22,0x2f,0x3a,0x14,0x20,0x2d,0x38,0x18,0x26,0x32,0x11,0x1d,0x29,0x35,0x17},
|
||||
{0x3d,0x34,0x2b,0x22,0x19,0x40,0x37,0x2e,0x25,0x1c,0x3a,0x31,0x28,0x1f,0x16},
|
||||
{0x12,0x20,0x2f,0x1a,0x28,0x38,0x14,0x23,0x32,0x1c,0x2c,0x3b,0x17,0x26,0x34},
|
||||
{0x13,0x25,0x37,0x1F,0x31,0x17,0x28,0x3A,0x1C,0x2E,0x22,0x33,0x19,0x2B,0x3D} };
|
||||
const uint8_t PROGMEM BUGSMINI_bind_chans[BUGSMINI_NUM_RF_CHANNELS] = {
|
||||
0x1A,0x23,0x2C,0x35,0x3E,0x17,0x20,0x29,0x32,0x3B,0x14,0x1D,0x26,0x2F,0x38}; // bugs 3 mini bind channels
|
||||
const uint8_t PROGMEM BUGSMINI_tx_id[BUGSMINI_NUM_TX_RF_MAPS][3] = {
|
||||
{0xA8,0xE6,0x32},
|
||||
{0xdd,0xab,0xfd},
|
||||
{0x90,0x9e,0x4a},
|
||||
{0x20,0x28,0xBA} };
|
||||
const uint8_t PROGMEM BUGSMINI_tx_hash[BUGSMINI_NUM_TX_RF_MAPS] = { // 2nd byte of final address
|
||||
0x6c,0x9e,0x3d,0xb3};
|
||||
|
||||
static void __attribute__((unused)) BUGSMINI_initialize_txid()
|
||||
{
|
||||
// load hopping_frequency with tx channels in low part and bind channels in high part
|
||||
for(uint8_t i=0; i<BUGSMINI_NUM_RF_CHANNELS;i++)
|
||||
{
|
||||
hopping_frequency[i]=pgm_read_byte_near( &BUGSMINI_RF_chans[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS][i] );
|
||||
hopping_frequency[i+BUGSMINI_NUM_RF_CHANNELS]=pgm_read_byte_near( &BUGSMINI_bind_chans[i] );
|
||||
}
|
||||
// load txid
|
||||
for(uint8_t i=0; i<sizeof(BUGSMINI_txid);i++)
|
||||
BUGSMINI_txid[i]=pgm_read_byte_near( &BUGSMINI_tx_id[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS][i] );
|
||||
//load tx_hash
|
||||
BUGSMINI_txhash = pgm_read_byte_near( &BUGSMINI_tx_hash[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS] );
|
||||
}
|
||||
|
||||
uint16_t initBUGSMINI()
|
||||
{
|
||||
BUGSMINI_initialize_txid();
|
||||
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);
|
||||
phase = BUGSMINI_BIND1;
|
||||
}
|
||||
else
|
||||
{
|
||||
BUGSMINI_make_address();
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
XN297_SetRXAddr(rx_tx_addr, 5);
|
||||
phase = BUGSMINI_DATA1;
|
||||
}
|
||||
armed = 0;
|
||||
arm_flags = BUGSMINI_FLAG_DISARM; // initial value from captures
|
||||
arm_channel_previous = BUGSMINI_CH_SW_ARM;
|
||||
#ifdef BUGS_HUB_TELEMETRY
|
||||
init_frskyd_link_telemetry();
|
||||
#endif
|
||||
return BUGSMINI_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -4,7 +4,7 @@
|
||||
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,
|
||||
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.
|
||||
@@ -12,69 +12,138 @@
|
||||
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 EAchine H8 mini, H10, BayangToys X6/X7/X9, JJRC JJ850 ...
|
||||
// Compatible with EAchine H8 mini, H10, BayangToys X6/X7/X9, JJRC JJ850 ...
|
||||
// Last sync with hexfet new_protocols/bayang_nrf24l01.c dated 2015-12-22
|
||||
|
||||
#if defined(BAYANG_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BAYANG_BIND_COUNT 1000
|
||||
#define BAYANG_PACKET_PERIOD 2000
|
||||
#define BAYANG_PACKET_PERIOD 1000
|
||||
#define BAYANG_INITIAL_WAIT 500
|
||||
#define BAYANG_PACKET_SIZE 15
|
||||
#define BAYANG_RF_NUM_CHANNELS 4
|
||||
#define BAYANG_RF_BIND_CHANNEL 0
|
||||
#define BAYANG_RF_BIND_CHANNEL_X16_AH 10
|
||||
#define BAYANG_ADDRESS_LENGTH 5
|
||||
|
||||
enum BAYANG_FLAGS {
|
||||
// flags going to packet[2]
|
||||
BAYANG_FLAG_RTH = 0x01,
|
||||
BAYANG_FLAG_HEADLESS = 0x02,
|
||||
BAYANG_FLAG_FLIP = 0x08
|
||||
// flags going to packet[2]
|
||||
BAYANG_FLAG_RTH = 0x01,
|
||||
BAYANG_FLAG_HEADLESS = 0x02,
|
||||
BAYANG_FLAG_FLIP = 0x08,
|
||||
BAYANG_FLAG_VIDEO = 0x10,
|
||||
BAYANG_FLAG_PICTURE = 0x20,
|
||||
// flags going to packet[3]
|
||||
BAYANG_FLAG_INVERTED = 0x80, // inverted flight on Floureon H101
|
||||
BAYANG_FLAG_TAKE_OFF = 0x20, // take off / landing on X16 AH
|
||||
BAYANG_FLAG_EMG_STOP = 0x04|0x08, // 0x08 for VISUO XS809H-W-HD-G
|
||||
};
|
||||
|
||||
enum BAYANG_PHASES {
|
||||
BAYANG_BIND = 0,
|
||||
BAYANG_DATA
|
||||
enum BAYANG_OPTION_FLAGS {
|
||||
BAYANG_OPTION_FLAG_TELEMETRY = 0x01,
|
||||
BAYANG_OPTION_FLAG_ANALOGAUX = 0x02,
|
||||
};
|
||||
|
||||
void BAYANG_send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t i;
|
||||
if (bind)
|
||||
{
|
||||
packet[0]= 0xA4;
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
if(option & BAYANG_OPTION_FLAG_TELEMETRY)
|
||||
if(option & BAYANG_OPTION_FLAG_ANALOGAUX)
|
||||
packet[0]= 0xA1; // telemetry and analog aux are enabled
|
||||
else
|
||||
packet[0]= 0xA3; // telemetry is enabled
|
||||
else if(option & BAYANG_OPTION_FLAG_ANALOGAUX)
|
||||
packet[0]= 0xA2; // analog aux is enabled
|
||||
else
|
||||
#else
|
||||
if(option & BAYANG_OPTION_FLAG_ANALOGAUX)
|
||||
packet[0]= 0xA2; // analog aux is enabled
|
||||
else
|
||||
#endif
|
||||
packet[0]= 0xA4;
|
||||
for(i=0;i<5;i++)
|
||||
packet[i+1]=rx_tx_addr[i];
|
||||
for(i=0;i<4;i++)
|
||||
packet[i+6]=hopping_frequency[i];
|
||||
packet[10] = rx_tx_addr[0];
|
||||
packet[11] = rx_tx_addr[1];
|
||||
switch (sub_protocol)
|
||||
{
|
||||
case X16_AH:
|
||||
packet[10] = 0x00;
|
||||
packet[11] = 0x00;
|
||||
break;
|
||||
case IRDRONE:
|
||||
packet[10] = 0x30;
|
||||
packet[11] = 0x01;
|
||||
break;
|
||||
case DHD_D4:
|
||||
packet[10] = 0xC8;
|
||||
packet[11] = 0x99;
|
||||
break;
|
||||
default:
|
||||
packet[10] = rx_tx_addr[0]; // txid[0]
|
||||
packet[11] = rx_tx_addr[1]; // txid[1]
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t val;
|
||||
packet[0] = 0xA5;
|
||||
packet[1] = 0xFA; // normal mode is 0xf7, expert 0xfa
|
||||
uint8_t dyntrim = 1;
|
||||
switch (sub_protocol)
|
||||
{
|
||||
case X16_AH:
|
||||
case IRDRONE:
|
||||
packet[0] = 0xA6;
|
||||
break;
|
||||
default:
|
||||
packet[0] = 0xA5;
|
||||
break;
|
||||
}
|
||||
if (option & BAYANG_OPTION_FLAG_ANALOGAUX)
|
||||
{
|
||||
// Analog aux channel 1 (channel 14)
|
||||
packet[1] = convert_channel_8b(CH14);
|
||||
}
|
||||
else
|
||||
packet[1] = 0xFA; // normal mode is 0xF7, expert 0xFa , D4 normal is 0xF4
|
||||
|
||||
//Flags
|
||||
packet[2] =0x00;
|
||||
if(Servo_data[AUX1] > PPM_SWITCH)
|
||||
packet[2] |= BAYANG_FLAG_FLIP;
|
||||
if(Servo_data[AUX2] > PPM_SWITCH)
|
||||
packet[2] |= BAYANG_FLAG_HEADLESS;
|
||||
if(Servo_data[AUX3] > PPM_SWITCH)
|
||||
//Flags packet[2]
|
||||
packet[2] = 0x00;
|
||||
if(CH5_SW)
|
||||
packet[2] = BAYANG_FLAG_FLIP;
|
||||
if(CH6_SW)
|
||||
packet[2] |= BAYANG_FLAG_RTH;
|
||||
|
||||
if(CH7_SW)
|
||||
packet[2] |= BAYANG_FLAG_PICTURE;
|
||||
if(CH8_SW)
|
||||
packet[2] |= BAYANG_FLAG_VIDEO;
|
||||
if(CH9_SW)
|
||||
{
|
||||
packet[2] |= BAYANG_FLAG_HEADLESS;
|
||||
dyntrim = 0;
|
||||
}
|
||||
//Flags packet[3]
|
||||
packet[3] = 0x00;
|
||||
|
||||
if(CH10_SW)
|
||||
packet[3] = BAYANG_FLAG_INVERTED;
|
||||
if(CH11_SW)
|
||||
dyntrim = 0;
|
||||
if(CH12_SW)
|
||||
packet[3] |= BAYANG_FLAG_TAKE_OFF;
|
||||
if(CH13_SW)
|
||||
packet[3] |= BAYANG_FLAG_EMG_STOP;
|
||||
//Aileron
|
||||
val = convert_channel_10b(AILERON);
|
||||
packet[4] = (val>>8) + ((val>>2) & 0xFC);
|
||||
packet[4] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
|
||||
packet[5] = val & 0xFF;
|
||||
//Elevator
|
||||
val = convert_channel_10b(ELEVATOR);
|
||||
packet[6] = (val>>8) + ((val>>2) & 0xFC);
|
||||
packet[6] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
|
||||
packet[7] = val & 0xFF;
|
||||
//Throttle
|
||||
val = convert_channel_10b(THROTTLE);
|
||||
@@ -82,34 +151,101 @@ void BAYANG_send_packet(uint8_t bind)
|
||||
packet[9] = val & 0xFF;
|
||||
//Rudder
|
||||
val = convert_channel_10b(RUDDER);
|
||||
packet[10] = (val>>8) + (val>>2 & 0xFC);
|
||||
packet[10] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
|
||||
packet[11] = val & 0xFF;
|
||||
}
|
||||
packet[12] = rx_tx_addr[2];
|
||||
packet[13] = 0x0A;
|
||||
switch (sub_protocol)
|
||||
{
|
||||
case H8S3D:
|
||||
packet[12] = rx_tx_addr[2]; // txid[2]
|
||||
packet[13] = 0x34;
|
||||
break;
|
||||
case X16_AH:
|
||||
packet[12] = 0;
|
||||
packet[13] = 0;
|
||||
break;
|
||||
case IRDRONE:
|
||||
packet[12] = 0xE0;
|
||||
packet[13] = 0x2E;
|
||||
break;
|
||||
case DHD_D4:
|
||||
packet[12] = 0x37; //0x17 during bind
|
||||
packet[13] = 0xED;
|
||||
break;
|
||||
default:
|
||||
packet[12] = rx_tx_addr[2]; // txid[2]
|
||||
if (option & BAYANG_OPTION_FLAG_ANALOGAUX)
|
||||
{ // Analog aux channel 2 (channel 15)
|
||||
packet[13] = convert_channel_8b(CH15);
|
||||
}
|
||||
else
|
||||
packet[13] = 0x0A;
|
||||
break;
|
||||
}
|
||||
packet[14] = 0;
|
||||
for (uint8_t i=0; i < BAYANG_PACKET_SIZE-1; i++)
|
||||
for (uint8_t i=0; i < BAYANG_PACKET_SIZE-1; i++)
|
||||
packet[14] += packet[i];
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
|
||||
if (bind)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, BAYANG_RF_BIND_CHANNEL);
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
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();
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
void BAYANG_init()
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
static void __attribute__((unused)) BAYANG_check_rx(void)
|
||||
{
|
||||
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // data received from model
|
||||
XN297_ReadPayload(packet, BAYANG_PACKET_SIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 255);
|
||||
|
||||
NRF24L01_FlushRx();
|
||||
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)
|
||||
{
|
||||
// uncompensated battery volts*100/2
|
||||
v_lipo1 = (packet[3]<<7) + (packet[4]>>2);
|
||||
// compensated battery volts*100/2
|
||||
v_lipo2 = (packet[5]<<7) + (packet[6]>>2);
|
||||
// reception in packets / sec
|
||||
RX_RSSI = packet[7];
|
||||
//Flags
|
||||
//uint8_t flags = packet[3] >> 3;
|
||||
// battery low: flags & 1
|
||||
telemetry_counter++;
|
||||
if(telemetry_lost==0)
|
||||
telemetry_link=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __attribute__((unused)) BAYANG_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
@@ -118,49 +254,91 @@ void BAYANG_init()
|
||||
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
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_03_SETUP_AW, 0x03);
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
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);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t BAYANG_callback()
|
||||
{
|
||||
switch (phase)
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
case BAYANG_BIND:
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
|
||||
phase = BAYANG_DATA;
|
||||
BIND_DONE;
|
||||
if(packet_count==0)
|
||||
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;
|
||||
}
|
||||
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);
|
||||
#endif
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(packet_count==0)
|
||||
BAYANG_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
break;
|
||||
case BAYANG_DATA:
|
||||
BAYANG_send_packet(0);
|
||||
break;
|
||||
packet_count++;
|
||||
packet_count%=4;
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
return BAYANG_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
void BAYANG_initialize_txid()
|
||||
static void __attribute__((unused)) BAYANG_initialize_txid()
|
||||
{
|
||||
// Strange txid, rx_tx_addr and rf_channels could be anything so I will use on rx_tx_addr for all of them...
|
||||
// Strange also that there is no check of duplicated rf channels... I think we need to implement that later...
|
||||
for(uint8_t i=0; i<BAYANG_RF_NUM_CHANNELS; i++)
|
||||
hopping_frequency[i]=rx_tx_addr[i]%42;
|
||||
//Could be using txid[0..2] but using rx_tx_addr everywhere instead...
|
||||
if(sub_protocol==DHD_D4)
|
||||
hopping_frequency[0]=(rx_tx_addr[2]&0x07)|0x01;
|
||||
else
|
||||
hopping_frequency[0]=0;
|
||||
hopping_frequency[1]=(rx_tx_addr[3]&0x1F)+0x10;
|
||||
hopping_frequency[2]=hopping_frequency[1]+0x20;
|
||||
hopping_frequency[3]=hopping_frequency[2]+0x20;
|
||||
hopping_frequency_no=0;
|
||||
}
|
||||
|
||||
@@ -169,9 +347,13 @@ uint16_t initBAYANG(void)
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = BAYANG_BIND_COUNT;
|
||||
BAYANG_initialize_txid();
|
||||
phase=BAYANG_BIND;
|
||||
BAYANG_init();
|
||||
packet_count=0;
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
init_frskyd_link_telemetry();
|
||||
telemetry_lost=1; // do not send telemetry to TX right away until we have a TX_RSSI value to prevent warning message...
|
||||
#endif
|
||||
return BAYANG_INITIAL_WAIT+BAYANG_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
466
Multiprotocol/Bugs_a7105.ino
Normal file
466
Multiprotocol/Bugs_a7105.ino
Normal file
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef BUGS_A7105_INO
|
||||
|
||||
//////////// rxid -> radioid algorithm //////////////////////////////
|
||||
// Hex digit 1 is periodic with length 2, and hex digit 2 is periodic
|
||||
// with length 16. However, storing the byte of those 2 digits
|
||||
// instead of manipulating bits results simpler code and smaller binary.
|
||||
const uint8_t PROGMEM BUGS_most_popular_67_cycle[]= {
|
||||
0x34, 0xc5, 0x6a, 0xb4, 0x29, 0xd5, 0x2c, 0xd3, 0x91, 0xb3, 0x6c, 0x49,
|
||||
0x52, 0x9c, 0x4d, 0x65, 0xc3, 0x4a, 0x5b, 0xd6, 0x92, 0x6d, 0x94, 0xa6,
|
||||
0x55, 0xcd, 0x2b, 0x9a, 0x36, 0x95, 0x4b, 0xd4, 0x35, 0x8d, 0x96, 0xb2,
|
||||
0xa3 };
|
||||
|
||||
static uint8_t __attribute__((unused)) BUGS_most_popular_67(uint8_t i)
|
||||
{
|
||||
uint8_t ii;
|
||||
if (i == 0)
|
||||
return 0xd2;
|
||||
else if (i == 1)
|
||||
return 0xda;
|
||||
else if (i % 16 < 2)
|
||||
{
|
||||
ii = 2 * (i / 16) + i % 16 - 2;
|
||||
if (ii % 2 == 0)
|
||||
ii += 7;
|
||||
}
|
||||
else
|
||||
ii=2 * (i / 16) + (i % 16 - 2) % 7;
|
||||
return pgm_read_byte_near( &BUGS_most_popular_67_cycle[ii]);
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) BUGS_most_popular_45(uint8_t i)
|
||||
{
|
||||
if (i == 0)
|
||||
return 0xa3;
|
||||
else if (i == 1)
|
||||
return 0x86;
|
||||
else
|
||||
{
|
||||
if (i % 8 == 1)
|
||||
i -= 8;
|
||||
else
|
||||
i--;
|
||||
return BUGS_most_popular_67(i);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) BUGS_most_popular_23(uint8_t i)
|
||||
{
|
||||
if (i == 0)
|
||||
return 0xb2;
|
||||
else if (i == 1)
|
||||
return 0xcb;
|
||||
else
|
||||
{
|
||||
if (i % 8 == 1)
|
||||
i -= 8;
|
||||
else
|
||||
i--;
|
||||
return BUGS_most_popular_45(i);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM BUGS_most_popular_01[] = {
|
||||
0x52, 0xac, 0x59, 0xa4, 0x53, 0xab, 0x57, 0xa9,
|
||||
0x56, 0xa5, 0x5b, 0xa7, 0x5d, 0xa6, 0x58, 0xad};
|
||||
|
||||
static uint32_t __attribute__((unused)) BUGS_most_popular(uint8_t i)
|
||||
{
|
||||
i += !(i <= 127);
|
||||
uint8_t mp01=pgm_read_byte_near( &BUGS_most_popular_01[i % 16] );
|
||||
return (uint32_t) mp01 << 24 |
|
||||
(uint32_t) BUGS_most_popular_23(i) << 16 |
|
||||
(uint32_t) BUGS_most_popular_45(i) << 8 |
|
||||
BUGS_most_popular_67(i);
|
||||
}
|
||||
|
||||
static uint32_t __attribute__((unused)) BUGS_second_most_popular(uint8_t i)
|
||||
{
|
||||
if (i < 127)
|
||||
return BUGS_most_popular(i + 1);
|
||||
else if (i > 128)
|
||||
return BUGS_most_popular(i - 1);
|
||||
else
|
||||
return 0x52d6926d;
|
||||
}
|
||||
|
||||
// The 22 irregular values do not match the above periodicities. They might be
|
||||
// errors from the readout, but let us try them here as long as it is not
|
||||
// proven.
|
||||
#define BUGS_NBR_IRREGULAR 22
|
||||
const uint16_t PROGMEM BUGS_irregular_keys[BUGS_NBR_IRREGULAR] = {
|
||||
1131, 1287, 2842, 4668, 5311, 11594, 13122, 13813,
|
||||
20655, 22975, 25007, 25068, 28252, 33309, 35364, 35765,
|
||||
37731, 40296, 43668, 46540, 49868, 65535 };
|
||||
|
||||
const uint32_t PROGMEM BUGS_irregular_values[BUGS_NBR_IRREGULAR] = {
|
||||
0x52d6926d, 0xa586da34, 0x5329d52c, 0xa66c4952,
|
||||
0x536c4952, 0x524a5bd6, 0x534d65c3, 0xa9d391b3,
|
||||
0x5249529c, 0xa555cd2b, 0xac9a3695, 0x58d391b3,
|
||||
0xa791b36c, 0x53926d94, 0xa7926d94, 0xa72cd391,
|
||||
0xa9b429d5, 0x5629d52c, 0xad2b9a36, 0xa74d65c3,
|
||||
0x526d94a6, 0xad96b2a3 };
|
||||
|
||||
static uint32_t __attribute__((unused)) BUGS_is_irregular(uint16_t i)
|
||||
{
|
||||
for (uint8_t j = 0; j < BUGS_NBR_IRREGULAR; ++j)
|
||||
if (pgm_read_word_near( &BUGS_irregular_keys[j]) == i)
|
||||
return pgm_read_dword_near( &BUGS_irregular_values[j]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t __attribute__((unused)) BUGS_rxid_to_radioid(uint16_t rxid)
|
||||
{
|
||||
uint8_t block = rxid / 256;
|
||||
uint8_t second_seq_size;
|
||||
bool use_most_popular;
|
||||
|
||||
if (rxid < 32768)
|
||||
{
|
||||
second_seq_size = 128 - block;
|
||||
use_most_popular = rxid % 256 >= second_seq_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
second_seq_size = block - 127;
|
||||
use_most_popular = 255 - rxid % 256 >= second_seq_size;
|
||||
}
|
||||
uint32_t v = BUGS_is_irregular(rxid);
|
||||
if (!v)
|
||||
{
|
||||
if (use_most_popular)
|
||||
v = BUGS_most_popular(rxid % 255);
|
||||
else
|
||||
v = BUGS_second_most_popular(rxid % 255);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
//////////// rxid -> radioid algorithm //////////////////////////////
|
||||
|
||||
// For code readability
|
||||
#define BUGS_CH_SW_ARM CH5_SW
|
||||
#define BUGS_CH_SW_ANGLE CH6_SW
|
||||
#define BUGS_CH_SW_FLIP CH7_SW
|
||||
#define BUGS_CH_SW_PICTURE CH8_SW
|
||||
#define BUGS_CH_SW_VIDEO CH9_SW
|
||||
#define BUGS_CH_SW_LED CH10_SW
|
||||
|
||||
// flags packet byte 4
|
||||
#define BUGS_FLAG_FLIP 0x08 // automatic flip
|
||||
#define BUGS_FLAG_MODE 0x04 // low/high speed select (set is high speed)
|
||||
#define BUGS_FLAG_VIDEO 0x02 // toggle video
|
||||
#define BUGS_FLAG_PICTURE 0x01 // toggle picture
|
||||
|
||||
// flags packet byte 5
|
||||
#define BUGS_FLAG_LED 0x80 // enable LEDs
|
||||
#define BUGS_FLAG_ARM 0x40 // arm (toggle to turn on motors)
|
||||
#define BUGS_FLAG_DISARM 0x20 // disarm (toggle to turn off motors)
|
||||
#define BUGS_FLAG_ANGLE 0x04 // angle/acro mode (set is angle mode)
|
||||
|
||||
#define BUGS_PACKET_SIZE 22
|
||||
#define BUGS_NUM_RFCHAN 16
|
||||
|
||||
enum {
|
||||
BUGS_BIND_1,
|
||||
BUGS_BIND_2,
|
||||
BUGS_BIND_3,
|
||||
BUGS_DATA_1,
|
||||
BUGS_DATA_2,
|
||||
BUGS_DATA_3,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) BUGS_check_arming()
|
||||
{
|
||||
uint8_t arm_channel = BUGS_CH_SW_ARM;
|
||||
|
||||
if (arm_channel != arm_channel_previous)
|
||||
{
|
||||
arm_channel_previous = arm_channel;
|
||||
if (arm_channel)
|
||||
{
|
||||
armed = 1;
|
||||
arm_flags ^= BUGS_FLAG_ARM;
|
||||
}
|
||||
else
|
||||
{
|
||||
armed = 0;
|
||||
arm_flags ^= BUGS_FLAG_DISARM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGS_build_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t force_values = bind | !armed;
|
||||
uint8_t change_channel = ((packet_count & 0x1) << 6);
|
||||
uint16_t aileron = convert_channel_16b_limit(AILERON,800,0);
|
||||
uint16_t elevator = convert_channel_16b_limit(ELEVATOR,800,0);
|
||||
uint16_t throttle = convert_channel_16b_limit(THROTTLE,0,800);
|
||||
uint16_t rudder = convert_channel_16b_limit(RUDDER,800,0);
|
||||
|
||||
memset(packet, 0, BUGS_PACKET_SIZE);
|
||||
packet[1] = 0x76; // txid (rx uses to know hopping frequencies)
|
||||
packet[2] = 0x71;
|
||||
packet[3] = 0x94;
|
||||
|
||||
BUGS_check_arming(); // sets globals arm_flags and armed
|
||||
if(bind)
|
||||
{
|
||||
packet[4] = change_channel | 0x80;
|
||||
packet[5] = 0x02 | arm_flags
|
||||
| GET_FLAG(BUGS_CH_SW_ANGLE, BUGS_FLAG_ANGLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[4] = change_channel | BUGS_FLAG_MODE
|
||||
| GET_FLAG(BUGS_CH_SW_FLIP, BUGS_FLAG_FLIP)
|
||||
| GET_FLAG(BUGS_CH_SW_PICTURE, BUGS_FLAG_PICTURE)
|
||||
| GET_FLAG(BUGS_CH_SW_VIDEO, BUGS_FLAG_VIDEO);
|
||||
packet[5] = 0x02 | arm_flags
|
||||
| GET_FLAG(BUGS_CH_SW_ANGLE, BUGS_FLAG_ANGLE)
|
||||
| GET_FLAG(BUGS_CH_SW_LED, BUGS_FLAG_LED);
|
||||
}
|
||||
|
||||
packet[6] = force_values ? 100 : (aileron >> 2);
|
||||
packet[7] = force_values ? 100 : (elevator >> 2);
|
||||
packet[8] = force_values ? 0 : (throttle >> 2);
|
||||
packet[9] = force_values ? 100 : (rudder >> 2);
|
||||
packet[10] = 100;
|
||||
packet[11] = 100;
|
||||
packet[12] = 100;
|
||||
packet[13] = 100;
|
||||
|
||||
packet[14] = ((aileron << 6) & 0xc0)
|
||||
| ((elevator << 4) & 0x30)
|
||||
| ((throttle << 2) & 0x0c)
|
||||
| ((rudder ) & 0x03);
|
||||
|
||||
// packet[15] = 0;
|
||||
|
||||
// driven trims
|
||||
packet[16] = aileron / 8 + 14;
|
||||
packet[17] = elevator / 8 + 14;
|
||||
packet[18] = 64;
|
||||
packet[19] = rudder / 8 + 14;
|
||||
|
||||
// packet[20] = 0;
|
||||
// packet[21] = 0;
|
||||
|
||||
uint8_t check = 0x6d;
|
||||
for (uint8_t i=1; i < BUGS_PACKET_SIZE; i++)
|
||||
check ^= packet[i];
|
||||
packet[0] = check;
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM BUGS_hop []= {
|
||||
0x1d, 0x3b, 0x4d, 0x29, 0x11, 0x2d, 0x0b, 0x3d, 0x59, 0x48, 0x17, 0x41, 0x23, 0x4e, 0x2a, 0x63, // bind phase ID=0xac59a453
|
||||
0x4b, 0x19, 0x35, 0x1e, 0x63, 0x0f, 0x45, 0x21, 0x51, 0x3a, 0x5d, 0x25, 0x0a, 0x44, 0x61, 0x27, // data phase ID=0xA4C56AB4 for txid 767194 if rx responds C6 BB 57 7F 00 00 00 00 00 00 FF 87 40 00 00 00
|
||||
};
|
||||
|
||||
static void __attribute__((unused))BUGS_set_radio_data()
|
||||
{ // captured radio data for bugs rx/tx version A2
|
||||
// it appears that the hopping frequencies are determined by the txid
|
||||
// and the data phase radio id is determined by the first 2 bytes of the
|
||||
// rx bind packet
|
||||
uint8_t offset=0;
|
||||
uint32_t radio_id=0xac59a453; // bind phase ID=0xac59a453
|
||||
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
offset=BUGS_NUM_RFCHAN;
|
||||
// Read radio_id from EEPROM
|
||||
uint8_t base_adr=BUGS_EEPROM_OFFSET+RX_num*2;
|
||||
uint16_t rxid=0;
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
rxid|=eeprom_read_byte((EE_ADDR)(base_adr+i))<<(i*8);
|
||||
radio_id = BUGS_rxid_to_radioid(rxid);
|
||||
}
|
||||
A7105_WriteID(radio_id);
|
||||
|
||||
for(uint8_t i=0; i<BUGS_NUM_RFCHAN;i++)
|
||||
hopping_frequency[i]=pgm_read_byte_near( &BUGS_hop[i+offset] );
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGS_increment_counts()
|
||||
{ // this logic works with the use of packet_count in BUGS_build_packet
|
||||
// to properly indicate channel changes to rx
|
||||
packet_count += 1;
|
||||
if ((packet_count & 1) == 0)
|
||||
{
|
||||
hopping_frequency_no += 1;
|
||||
hopping_frequency_no %= BUGS_NUM_RFCHAN;
|
||||
}
|
||||
}
|
||||
|
||||
#define BUGS_PACKET_PERIOD 6100
|
||||
#define BUGS_DELAY_TX 2000
|
||||
#define BUGS_DELAY_POST_RX 1500
|
||||
#define BUGS_DELAY_BIND_RST 200
|
||||
|
||||
// FIFO config is one less than desired value
|
||||
#define BUGS_FIFO_SIZE_RX 15
|
||||
#define BUGS_FIFO_SIZE_TX 21
|
||||
uint16_t ReadBUGS(void)
|
||||
{
|
||||
uint8_t mode, base_adr;
|
||||
uint16_t rxid;
|
||||
uint16_t start;
|
||||
|
||||
// keep frequency tuning updated
|
||||
#ifndef FORCE_FLYSKY_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
|
||||
switch(phase)
|
||||
{
|
||||
case BUGS_BIND_1:
|
||||
BUGS_build_packet(1);
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_TX);
|
||||
A7105_WriteData(BUGS_PACKET_SIZE, hopping_frequency[hopping_frequency_no]);
|
||||
phase = BUGS_BIND_2;
|
||||
packet_period = BUGS_DELAY_TX;
|
||||
break;
|
||||
|
||||
case BUGS_BIND_2:
|
||||
//Wait for TX completion
|
||||
start=micros();
|
||||
while ((uint16_t)micros()-start < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_SetTxRxMode(RX_EN);
|
||||
A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no] - 2);
|
||||
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_RX);
|
||||
A7105_Strobe(A7105_RX);
|
||||
|
||||
BUGS_increment_counts();
|
||||
phase = BUGS_BIND_3;
|
||||
packet_period = BUGS_PACKET_PERIOD-BUGS_DELAY_TX-BUGS_DELAY_POST_RX;
|
||||
break;
|
||||
|
||||
case BUGS_BIND_3:
|
||||
mode = A7105_ReadReg(A7105_00_MODE);
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
A7105_SetTxRxMode(TX_EN);
|
||||
if (mode & 0x01)
|
||||
{
|
||||
phase = BUGS_BIND_1;
|
||||
packet_period = BUGS_DELAY_BIND_RST; // No received data so restart binding procedure.
|
||||
break;
|
||||
}
|
||||
A7105_ReadData(16);
|
||||
if ((packet[0] + packet[1] + packet[2] + packet[3]) == 0)
|
||||
{
|
||||
phase = BUGS_BIND_1;
|
||||
packet_period = BUGS_DELAY_BIND_RST; // No received data so restart binding procedure.
|
||||
break;
|
||||
}
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
BIND_DONE;
|
||||
// set radio_id
|
||||
rxid = (packet[1] << 8) + packet[2];
|
||||
base_adr=BUGS_EEPROM_OFFSET+RX_num*2;
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
eeprom_write_byte((EE_ADDR)(base_adr+i),rxid>>(i*8)); // Save rxid in EEPROM
|
||||
BUGS_set_radio_data();
|
||||
phase = BUGS_DATA_1;
|
||||
packet_count = 0;
|
||||
hopping_frequency_no = 0;
|
||||
packet_period = BUGS_DELAY_POST_RX;
|
||||
break;
|
||||
|
||||
case BUGS_DATA_1:
|
||||
A7105_SetPower();
|
||||
BUGS_build_packet(0);
|
||||
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_TX);
|
||||
A7105_WriteData(BUGS_PACKET_SIZE, hopping_frequency[hopping_frequency_no]);
|
||||
phase = BUGS_DATA_2;
|
||||
packet_period = BUGS_DELAY_TX;
|
||||
break;
|
||||
|
||||
case BUGS_DATA_2:
|
||||
//Wait for TX completion
|
||||
start=micros();
|
||||
while ((uint16_t)micros()-start < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_SetTxRxMode(RX_EN);
|
||||
A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no] - 2);
|
||||
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_RX);
|
||||
A7105_Strobe(A7105_RX);
|
||||
|
||||
BUGS_increment_counts();
|
||||
phase = BUGS_DATA_3;
|
||||
packet_period = BUGS_PACKET_PERIOD-BUGS_DELAY_TX-BUGS_DELAY_POST_RX;
|
||||
break;
|
||||
|
||||
case BUGS_DATA_3:
|
||||
mode = A7105_ReadReg(A7105_00_MODE);
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
A7105_SetTxRxMode(TX_EN);
|
||||
if (!(mode & 0x01))
|
||||
{
|
||||
A7105_ReadData(16);
|
||||
#if defined(BUGS_HUB_TELEMETRY)
|
||||
v_lipo1=packet[10] == 0xff ? 0xff : 0x00; // Voltage in this case is only an alert on level good or bad.
|
||||
RX_RSSI=packet[3];
|
||||
// Read TX RSSI
|
||||
int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // Value from A7105 is between 8 for maximum signal strength to 160 or less
|
||||
if(temp<0) temp=0;
|
||||
else if(temp>255) temp=255;
|
||||
TX_RSSI=temp;
|
||||
telemetry_link=1;
|
||||
#endif
|
||||
}
|
||||
phase = BUGS_DATA_1;
|
||||
packet_period = BUGS_DELAY_POST_RX;
|
||||
break;
|
||||
}
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initBUGS(void)
|
||||
{
|
||||
uint16_t rxid=0;
|
||||
uint8_t base_adr=BUGS_EEPROM_OFFSET+RX_num*2;
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
rxid|=eeprom_read_byte((EE_ADDR)(base_adr+i))<<(i*8);
|
||||
if(rxid==0xffff)
|
||||
BIND_IN_PROGRESS;
|
||||
|
||||
BUGS_set_radio_data();
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
phase = BUGS_BIND_1;
|
||||
else
|
||||
phase = BUGS_DATA_1;
|
||||
|
||||
A7105_Init();
|
||||
|
||||
hopping_frequency_no = 0;
|
||||
packet_count = 0;
|
||||
armed = 0;
|
||||
arm_flags = BUGS_FLAG_DISARM; // initial value from captures
|
||||
arm_channel_previous = BUGS_CH_SW_ARM;
|
||||
#ifdef BUGS_HUB_TELEMETRY
|
||||
init_frskyd_link_telemetry();
|
||||
#endif
|
||||
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
442
Multiprotocol/CABELL_nrf224l01.ino
Normal file
442
Multiprotocol/CABELL_nrf224l01.ino
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
Protocol by Dennis Cabell, 2017
|
||||
KE8FZX
|
||||
|
||||
To use this software, you must adhere to the license terms described below, and assume all responsibility for the use
|
||||
of the software. The user is responsible for all consequences or damage that may result from using this software.
|
||||
The user is responsible for ensuring that the hardware used to run this software complies with local regulations and that
|
||||
any radio signal generated or received from use of this software is legal for that user to generate. The author(s) of this software
|
||||
assume no liability whatsoever. The author(s) of this software is not responsible for legal or civil consequences of
|
||||
using this software, including, but not limited to, any damages cause by lost control of a vehicle using this software.
|
||||
If this software is copied or modified, this disclaimer must accompany all copies.
|
||||
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// The Receiver for this protocol is available at: https://github.com/soligen2010/RC_RX_CABELL_V3_FHSS
|
||||
|
||||
#if defined(CABELL_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define CABELL_BIND_COUNT 2000 // At least 2000 so that if TX toggles the serial bind flag then bind mode is never exited
|
||||
#define CABELL_PACKET_PERIOD 3000 // Do not set too low or else next packet may not be finished transmitting before the channel is changed next time around
|
||||
|
||||
#define CABELL_NUM_CHANNELS 16 // The maximum number of RC channels that can be sent in one packet
|
||||
#define CABELL_MIN_CHANNELS 4 // The minimum number of channels that must be included in a packet, the number of channels cannot be reduced any further than this
|
||||
#define CABELL_PAYLOAD_BYTES 24 // 12 bits per value * 16 channels
|
||||
|
||||
#define CABELL_RADIO_CHANNELS 9 // This is 1/5 of the total number of radio channels used for FHSS
|
||||
#define CABELL_RADIO_MIN_CHANNEL_NUM 3 // Channel 0 is right on the boarder of allowed frequency range, so move up to avoid bleeding over
|
||||
#define CABELL_TELEMETRY_PACKET_LENGTH 4
|
||||
|
||||
#define CABELL_BIND_RADIO_ADDR 0xA4B7C123F7LL
|
||||
|
||||
#define CABELL_OPTION_MASK_CHANNEL_REDUCTION 0x0F
|
||||
#define CABELL_OPTION_MASK_RECIEVER_OUTPUT_MODE 0x30
|
||||
#define CABELL_OPTION_SHIFT_RECIEVER_OUTPUT_MODE 4
|
||||
#define CABELL_OPTION_MASK_MAX_POWER_OVERRIDE 0x40
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum RxMode_t : uint8_t
|
||||
{ // Note bit 8 is used to indicate if the packet is the first of 2 on the channel. Mask out this bit before using the enum
|
||||
normal = 0,
|
||||
bind = 1,
|
||||
setFailSafe = 2,
|
||||
normalWithTelemetry = 3,
|
||||
telemetryResponse = 4,
|
||||
unBind = 127
|
||||
} RxMode;
|
||||
uint8_t reserved = 0;
|
||||
uint8_t option;
|
||||
/* mask 0x0F : Channel reduction. The number of channels to not send (subtracted from the 16 max channels) at least 4 are always sent
|
||||
* mask 0x30>>4 : Receiver output mode
|
||||
* 0 (00) = Single PPM on individual pins for each channel
|
||||
* 1 (01) = SUM PPM on channel 1 pin
|
||||
* 2 (10) = Future use. Reserved for SBUS output
|
||||
* 3 (11) = Unused
|
||||
* mask 0x40>>6 Contains max power override flag for Multi-protocol TX module. Also sent to RX
|
||||
* mask 0x80>>7 Unused
|
||||
*/
|
||||
uint8_t modelNum;
|
||||
uint8_t checkSum_LSB;
|
||||
uint8_t checkSum_MSB;
|
||||
uint8_t payloadValue [CABELL_PAYLOAD_BYTES] = {0}; //12 bits per channel value, unsigned
|
||||
} CABELL_RxTxPacket_t;
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static uint8_t __attribute__((unused)) CABELL_getNextChannel (uint8_t seqArray[], uint8_t seqArraySize, uint8_t prevChannel)
|
||||
{
|
||||
/* Possible channels are in 5 bands, each band comprised of seqArraySize channels
|
||||
* seqArray contains seqArraySize elements in the relative order in which we should progress through the band
|
||||
*
|
||||
* Each time the channel is changes, bands change in a way so that the next channel will be in a
|
||||
* different non-adjacent band. Both the band changes and the index in seqArray is incremented.
|
||||
*/
|
||||
prevChannel -= CABELL_RADIO_MIN_CHANNEL_NUM; // Subtract CABELL_RADIO_MIN_CHANNEL_NUM because it was added to the return value
|
||||
if(prevChannel>(seqArraySize * 5))
|
||||
prevChannel=seqArraySize * 5; // Constrain the values just in case something bogus was sent in.
|
||||
|
||||
uint8_t currBand = prevChannel / seqArraySize;
|
||||
uint8_t nextBand = (currBand + 3) % 5;
|
||||
|
||||
uint8_t prevChannalSeqArrayValue = prevChannel % seqArraySize;
|
||||
uint8_t prevChannalSeqArrayPosition = 0;
|
||||
for (int x = 0; x < seqArraySize; x++)
|
||||
{ // Find the position of the previous channel in the array
|
||||
if (seqArray[x] == prevChannalSeqArrayValue)
|
||||
prevChannalSeqArrayPosition = x;
|
||||
}
|
||||
uint8_t nextChannalSeqArrayPosition = prevChannalSeqArrayPosition + 1;
|
||||
if (nextChannalSeqArrayPosition >= seqArraySize)
|
||||
nextChannalSeqArrayPosition = 0;
|
||||
|
||||
return (seqArraySize * nextBand) + seqArray[nextChannalSeqArrayPosition] + CABELL_RADIO_MIN_CHANNEL_NUM; // Add CABELL_RADIO_MIN_CHANNEL_NUM so we dont use channel 0 as it may bleed below 2.400 GHz
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
#if defined CABELL_HUB_TELEMETRY
|
||||
static void __attribute__((unused)) CABELL_get_telemetry()
|
||||
{
|
||||
// calculate TX rssi based on past 250 expected telemetry packets. Cannot use full second count because telemetry_counter is not large enough
|
||||
state++;
|
||||
if (state > 250)
|
||||
{
|
||||
TX_RSSI = telemetry_counter;
|
||||
telemetry_counter = 0;
|
||||
state = 0;
|
||||
telemetry_lost=0;
|
||||
}
|
||||
|
||||
// Process incoming telemetry packet of it was received
|
||||
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // data received from model
|
||||
NRF24L01_ReadPayload(packet, CABELL_TELEMETRY_PACKET_LENGTH);
|
||||
if ((packet[0] & 0x7F) == CABELL_RxTxPacket_t::telemetryResponse) // ignore high order bit in compare because it toggles with each packet
|
||||
{
|
||||
RX_RSSI = packet[1]; // Packet rate 0 to 255 where 255 is 100% packet rate
|
||||
v_lipo1 = packet[2]; // Directly from analog input of receiver, but reduced to 8-bit depth (0 to 255). Scaling depends on the input to the analog pin of the receiver.
|
||||
v_lipo2 = packet[3]; // Directly from analog input of receiver, but reduced to 8-bit depth (0 to 255). Scaling depends on the input to the analog pin of the receiver.
|
||||
telemetry_counter++;
|
||||
if(telemetry_lost==0)
|
||||
telemetry_link=1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no telemetry packet was received then delay by the typical telemetry packet processing time
|
||||
// This is done to try to keep the sendPacket process timing more consistent. Since the SPI payload read takes some time
|
||||
delayMicroseconds(50);
|
||||
}
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_FlushRx();
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
|
||||
{
|
||||
#if defined CABELL_HUB_TELEMETRY
|
||||
if (!bindMode && (sub_protocol == CABELL_V3_TELEMETRY)) // check for incoming packet and switch radio back to TX mode if we were listening for telemetry
|
||||
CABELL_get_telemetry();
|
||||
#endif
|
||||
|
||||
CABELL_RxTxPacket_t TxPacket;
|
||||
|
||||
uint8_t channelReduction = constrain((option & CABELL_OPTION_MASK_CHANNEL_REDUCTION),0,CABELL_NUM_CHANNELS-CABELL_MIN_CHANNELS); // Max 12 - cannot reduce below 4 channels
|
||||
if (bindMode)
|
||||
channelReduction = 0; // Send full packet to bind as higher channels will contain bind info
|
||||
|
||||
uint8_t packetSize = sizeof(TxPacket) - ((((channelReduction - (channelReduction%2))/ 2)) * 3); // reduce 3 bytes per 2 channels, but not last channel if it is odd
|
||||
uint8_t maxPayloadValueIndex = sizeof(TxPacket.payloadValue) - (sizeof(TxPacket) - packetSize);
|
||||
|
||||
if ((sub_protocol == CABELL_UNBIND) && !bindMode)
|
||||
{
|
||||
TxPacket.RxMode = CABELL_RxTxPacket_t::unBind;
|
||||
TxPacket.option = option;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sub_protocol == CABELL_SET_FAIL_SAFE && !bindMode)
|
||||
TxPacket.RxMode = CABELL_RxTxPacket_t::setFailSafe;
|
||||
else
|
||||
{
|
||||
if (bindMode)
|
||||
TxPacket.RxMode = CABELL_RxTxPacket_t::bind;
|
||||
else
|
||||
{
|
||||
switch (sub_protocol)
|
||||
{
|
||||
case CABELL_V3_TELEMETRY:
|
||||
TxPacket.RxMode = CABELL_RxTxPacket_t::normalWithTelemetry;
|
||||
break;
|
||||
default:
|
||||
TxPacket.RxMode = CABELL_RxTxPacket_t::normal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
TxPacket.option = (bindMode) ? (option & (~CABELL_OPTION_MASK_CHANNEL_REDUCTION)) : option; //remove channel reduction if in bind mode
|
||||
}
|
||||
TxPacket.reserved = 0;
|
||||
TxPacket.modelNum = RX_num;
|
||||
uint16_t checkSum = TxPacket.modelNum + TxPacket.option + TxPacket.RxMode + TxPacket.reserved; // Start Calculate checksum
|
||||
|
||||
int adjusted_x;
|
||||
int payloadIndex = 0;
|
||||
uint16_t holdValue;
|
||||
|
||||
for (int x = 0;(x < CABELL_NUM_CHANNELS - channelReduction); x++)
|
||||
{
|
||||
switch (x)
|
||||
{
|
||||
case 0 : adjusted_x = ELEVATOR; break;
|
||||
case 1 : adjusted_x = AILERON; break;
|
||||
case 2 : adjusted_x = RUDDER; break;
|
||||
case 3 : adjusted_x = THROTTLE; break;
|
||||
default : adjusted_x = x; break;
|
||||
}
|
||||
holdValue = convert_channel_16b_limit(adjusted_x,1000,2000); // valid channel values are 1000 to 2000
|
||||
if (bindMode)
|
||||
{
|
||||
switch (adjusted_x)
|
||||
{
|
||||
case THROTTLE : holdValue = 1000; break; // always set throttle to off when binding for safety
|
||||
//tx address sent for bind
|
||||
case 11 : holdValue = 1000 + rx_tx_addr[0]; break;
|
||||
case 12 : holdValue = 1000 + rx_tx_addr[1]; break;
|
||||
case 13 : holdValue = 1000 + rx_tx_addr[2]; break;
|
||||
case 14 : holdValue = 1000 + rx_tx_addr[3]; break;
|
||||
case 15 : holdValue = 1000 + rx_tx_addr[4]; break;
|
||||
}
|
||||
}
|
||||
|
||||
// use 12 bits per value
|
||||
if (x % 2)
|
||||
{ //output channel number is ODD
|
||||
holdValue = holdValue<<4;
|
||||
payloadIndex--;
|
||||
}
|
||||
else
|
||||
holdValue &= 0x0FFF;
|
||||
TxPacket.payloadValue[payloadIndex] |= (uint8_t)(holdValue & 0x00FF);
|
||||
payloadIndex++;
|
||||
TxPacket.payloadValue[payloadIndex] |= (uint8_t)((holdValue>>8) & 0x00FF);
|
||||
payloadIndex++;
|
||||
}
|
||||
|
||||
for(int x = 0; x < maxPayloadValueIndex ; x++)
|
||||
checkSum += TxPacket.payloadValue[x]; // Finish Calculate checksum
|
||||
|
||||
TxPacket.checkSum_MSB = checkSum >> 8;
|
||||
TxPacket.checkSum_LSB = checkSum & 0x00FF;
|
||||
|
||||
// Set channel for next transmission
|
||||
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
|
||||
//NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(&TxPacket.RxMode);
|
||||
*p &= 0x7F; // Make sure 8th bit is clear
|
||||
*p |= (packet_count++)<<7; // This causes the 8th bit of the first byte to toggle with each xmit so consecutive payloads are not identical.
|
||||
// This is a work around for a reported bug in clone NRF24L01 chips that mis-took this case for a re-transmit of the same packet.
|
||||
|
||||
CABELL_SetPower();
|
||||
NRF24L01_WritePayload((uint8_t*)&TxPacket, packetSize);
|
||||
|
||||
#if defined CABELL_HUB_TELEMETRY
|
||||
if (!bindMode && (sub_protocol == CABELL_V3_TELEMETRY))
|
||||
{ // switch radio to rx as soon as packet is sent
|
||||
// calculate transmit time based on packet size and data rate of 1MB per sec
|
||||
// This is done because polling the status register during xmit caused issues.
|
||||
// bits = packst_size * 8 + 73 bits overhead
|
||||
// at 250 Kbs per sec, one bit is 4 uS
|
||||
// then add 140 uS which is 130 uS to begin the xmit and 10 uS fudge factor
|
||||
delayMicroseconds(((((unsigned long)packetSize * 8ul) + 73ul) * 4ul) + 140ul) ;
|
||||
packet_period = CABELL_PACKET_PERIOD + (constrain(((int16_t)(CABELL_NUM_CHANNELS - channelReduction) - (int16_t)6 ),(int16_t)0 ,(int16_t)10 ) * (int16_t)100); // increase packet period by 100 us for each channel over 6
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); // RX mode with 16 bit CRC
|
||||
}
|
||||
else
|
||||
#endif
|
||||
packet_period = CABELL_PACKET_PERIOD; // Standard packet period when not in telemetry mode.
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) CABELL_getChannelSequence (uint8_t outArray[], uint8_t numChannels, uint64_t permutation)
|
||||
{
|
||||
/* This procedure initializes an array with the sequence progression of channels.
|
||||
* This is not the actual channels itself, but the sequence base to be used within bands of
|
||||
* channels.
|
||||
*
|
||||
* There are numChannels! permutations for arranging the channels
|
||||
* one of these permutations will be calculated based on the permutation input
|
||||
* permutation should be between 1 and numChannels! but the routine will constrain it
|
||||
* if these bounds are exceeded. Typically the radio's unique TX ID should be used.
|
||||
*
|
||||
* The maximum numChannels is 20. Anything larger than this will cause the uint64_t
|
||||
* variables to overflow, yielding unknown results (possibly infinite loop?). Therefor
|
||||
* this routine constrains the value.
|
||||
*/
|
||||
uint8_t i; //iterator counts numChannels
|
||||
uint64_t indexOfNextSequenceValue;
|
||||
uint64_t numChannelsFactorial=1;
|
||||
uint8_t sequenceValue;
|
||||
|
||||
numChannels = constrain(numChannels,1,20);
|
||||
|
||||
for (i = 1; i <= numChannels;i++)
|
||||
{
|
||||
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
|
||||
|
||||
//Rearrange the array elements based on the permutation selected
|
||||
for (i=0, permutation--; i<numChannels; i++ )
|
||||
{
|
||||
numChannelsFactorial /= ((uint64_t)numChannels)-i;
|
||||
indexOfNextSequenceValue = i+(permutation/numChannelsFactorial);
|
||||
permutation %= numChannelsFactorial;
|
||||
|
||||
//Copy the value in the selected array position
|
||||
sequenceValue = outArray[indexOfNextSequenceValue];
|
||||
|
||||
//Shift the unused elements in the array to make room to move in the one just selected
|
||||
for( ; indexOfNextSequenceValue > i; indexOfNextSequenceValue--)
|
||||
outArray[indexOfNextSequenceValue] = outArray[indexOfNextSequenceValue-1];
|
||||
|
||||
// Copy the selected value into it's new array slot
|
||||
outArray[i] = sequenceValue;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) CABELL_setAddress()
|
||||
{
|
||||
uint64_t CABELL_addr;
|
||||
|
||||
// Serial.print("NORM ID: ");Serial.print((uint32_t)(CABELL_normal_addr>>32)); Serial.print(" ");Serial.println((uint32_t)((CABELL_normal_addr<<32)>>32));
|
||||
|
||||
if (IS_BIND_DONE)
|
||||
{
|
||||
CABELL_addr = (((uint64_t)rx_tx_addr[0]) << 32) +
|
||||
(((uint64_t)rx_tx_addr[1]) << 24) +
|
||||
(((uint64_t)rx_tx_addr[2]) << 16) +
|
||||
(((uint64_t)rx_tx_addr[3]) << 8) +
|
||||
(((uint64_t)rx_tx_addr[4])); // Address to use after binding
|
||||
}
|
||||
else
|
||||
CABELL_addr = CABELL_BIND_RADIO_ADDR; // Static addr for binding
|
||||
|
||||
CABELL_getChannelSequence(hopping_frequency,CABELL_RADIO_CHANNELS,CABELL_addr); // Get the sequence for hopping through channels
|
||||
rf_ch_num = CABELL_RADIO_MIN_CHANNEL_NUM; // Initialize the channel sequence
|
||||
|
||||
packet_count=0;
|
||||
|
||||
uint64_t CABELL_Telemetry_addr = ~CABELL_addr; // Invert bits for reading so that telemetry packets have a different address.
|
||||
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, reinterpret_cast<uint8_t*>(&CABELL_Telemetry_addr), 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, reinterpret_cast<uint8_t*>(&CABELL_Telemetry_addr), 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, reinterpret_cast<uint8_t*>(&CABELL_addr), 5);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) CABELL_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();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
uint16_t CABELL_callback()
|
||||
{
|
||||
if (IS_BIND_DONE)
|
||||
{
|
||||
CABELL_send_packet(0); // packet_period is set/adjusted in CABELL_send_packet
|
||||
return packet_period;
|
||||
}
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
CABELL_init(); // non-bind address
|
||||
}
|
||||
else
|
||||
{
|
||||
CABELL_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
return CABELL_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
uint16_t initCABELL(void)
|
||||
{
|
||||
if (IS_BIND_DONE)
|
||||
bind_counter = 0;
|
||||
else
|
||||
bind_counter = CABELL_BIND_COUNT;
|
||||
CABELL_init();
|
||||
#if defined CABELL_HUB_TELEMETRY
|
||||
init_frskyd_link_telemetry();
|
||||
telemetry_lost=1; // do not send telemetry to TX right away until we have a TX_RSSI value to prevent warning message...
|
||||
#endif
|
||||
|
||||
packet_period = CABELL_PACKET_PERIOD;
|
||||
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -17,130 +18,113 @@
|
||||
//CC2500 SPI routines
|
||||
//-------------------------------
|
||||
//-------------------------------
|
||||
#ifdef CC2500_INSTALLED
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
void cc2500_readFifo(uint8_t *dpbuffer, uint8_t len)
|
||||
{
|
||||
ReadRegisterMulti(CC2500_3F_RXFIFO | CC2500_READ_BURST, dpbuffer, len);
|
||||
}
|
||||
|
||||
//----------------------
|
||||
static void ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
cc2500_spi_write(address);
|
||||
for(uint8_t i = 0; i < length; i++)
|
||||
data[i] = cc2500_spi_read();
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
//*********************************************
|
||||
|
||||
void CC2500_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8_t length)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
cc2500_spi_write(CC2500_WRITE_BURST | address);
|
||||
for(uint8_t i = 0; i < length; i++)
|
||||
cc2500_spi_write(data[i]);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
void cc2500_writeFifo(uint8_t *dpbuffer, uint8_t len)
|
||||
{
|
||||
cc2500_strobe(CC2500_SFTX);//0x3B
|
||||
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, dpbuffer, len);
|
||||
cc2500_strobe(CC2500_STX);//0x35
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
void cc2500_spi_write(uint8_t command) {
|
||||
uint8_t n=8;
|
||||
|
||||
SCK_off;//SCK start low
|
||||
SDI_off;
|
||||
while(n--)
|
||||
{
|
||||
if(command&0x80)
|
||||
SDI_on;
|
||||
else
|
||||
SDI_off;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
command = command << 1;
|
||||
}
|
||||
SDI_on;
|
||||
}
|
||||
|
||||
//----------------------------
|
||||
void cc2500_writeReg(uint8_t address, uint8_t data) {//same as 7105
|
||||
void CC2500_WriteReg(uint8_t address, uint8_t data)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
cc2500_spi_write(address);
|
||||
SPI_Write(address);
|
||||
NOP();
|
||||
cc2500_spi_write(data);
|
||||
SPI_Write(data);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
uint8_t cc2500_spi_read(void)
|
||||
//----------------------
|
||||
static void CC2500_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length)
|
||||
{
|
||||
uint8_t result;
|
||||
uint8_t i;
|
||||
result=0;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
if(SDO_1) ///
|
||||
result=(result<<1)|0x01;
|
||||
else
|
||||
result=result<<1;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
NOP();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CC25_CSN_off;
|
||||
SPI_Write(CC2500_READ_BURST | address);
|
||||
for(uint8_t i = 0; i < length; i++)
|
||||
data[i] = SPI_Read();
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
//--------------------------------------------
|
||||
uint8_t cc2500_readReg(uint8_t address)
|
||||
static uint8_t CC2500_ReadReg(uint8_t address)
|
||||
{
|
||||
uint8_t result;
|
||||
CC25_CSN_off;
|
||||
address |=0x80; //bit 7 =1 for reading
|
||||
cc2500_spi_write(address);
|
||||
result = cc2500_spi_read();
|
||||
SPI_Write(CC2500_READ_SINGLE | address);
|
||||
result = SPI_Read();
|
||||
CC25_CSN_on;
|
||||
return(result);
|
||||
}
|
||||
|
||||
//------------------------
|
||||
void cc2500_strobe(uint8_t address)
|
||||
void CC2500_ReadData(uint8_t *dpbuffer, uint8_t len)
|
||||
{
|
||||
CC2500_ReadRegisterMulti(CC2500_3F_RXFIFO, dpbuffer, len);
|
||||
}
|
||||
|
||||
//*********************************************
|
||||
void CC2500_Strobe(uint8_t state)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
cc2500_spi_write(address);
|
||||
SPI_Write(state);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
static void CC2500_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8_t length)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
SPI_Write(CC2500_WRITE_BURST | address);
|
||||
for(uint8_t i = 0; i < length; i++)
|
||||
SPI_Write(data[i]);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
void CC2500_WriteData(uint8_t *dpbuffer, uint8_t len)
|
||||
{
|
||||
CC2500_Strobe(CC2500_SFTX);
|
||||
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, dpbuffer, len);
|
||||
CC2500_Strobe(CC2500_STX);
|
||||
}
|
||||
|
||||
void CC2500_SetTxRxMode(uint8_t mode)
|
||||
{
|
||||
if(mode == TX_EN)
|
||||
{//from deviation firmware
|
||||
CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F);
|
||||
CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F | 0x40);
|
||||
}
|
||||
else
|
||||
if (mode == RX_EN)
|
||||
{
|
||||
CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F);
|
||||
CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F | 0x40);
|
||||
}
|
||||
else
|
||||
{
|
||||
CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F);
|
||||
CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------
|
||||
void cc2500_resetChip(void)
|
||||
/*static void cc2500_resetChip(void)
|
||||
{
|
||||
// Toggle chip select signal
|
||||
CC25_CSN_on;
|
||||
_delay_us(30);
|
||||
delayMicroseconds(30);
|
||||
CC25_CSN_off;
|
||||
_delay_us(30);
|
||||
delayMicroseconds(30);
|
||||
CC25_CSN_on;
|
||||
_delay_us(45);
|
||||
cc2500_strobe(CC2500_SRES);
|
||||
delayMicroseconds(45);
|
||||
CC2500_Strobe(CC2500_SRES);
|
||||
_delay_ms(100);
|
||||
}
|
||||
|
||||
*/
|
||||
uint8_t CC2500_Reset()
|
||||
{
|
||||
cc2500_strobe(CC2500_SRES);
|
||||
_delay_us(1000);
|
||||
CC2500_Strobe(CC2500_SRES);
|
||||
delayMilliseconds(1);
|
||||
CC2500_SetTxRxMode(TXRX_OFF);
|
||||
return cc2500_readReg(CC2500_0E_FREQ1) == 0xC4;//check if reset
|
||||
return CC2500_ReadReg(CC2500_0E_FREQ1) == 0xC4;//check if reset
|
||||
}
|
||||
|
||||
void CC2500_SetPower_Value(uint8_t power)
|
||||
/*
|
||||
static void CC2500_SetPower_Value(uint8_t power)
|
||||
{
|
||||
const unsigned char patable[8]= {
|
||||
0xC5, // -12dbm
|
||||
@@ -154,35 +138,24 @@ void CC2500_SetPower_Value(uint8_t power)
|
||||
};
|
||||
if (power > 7)
|
||||
power = 7;
|
||||
cc2500_writeReg(CC2500_3E_PATABLE, patable[power]);
|
||||
CC2500_WriteReg(CC2500_3E_PATABLE, patable[power]);
|
||||
}
|
||||
|
||||
*/
|
||||
void CC2500_SetPower()
|
||||
{
|
||||
uint8_t power=CC2500_BIND_POWER;
|
||||
if(IS_BIND_DONE_on)
|
||||
power=IS_POWER_FLAG_on?CC2500_HIGH_POWER:CC2500_LOW_POWER;
|
||||
if(IS_BIND_DONE)
|
||||
#ifdef CC2500_ENABLE_LOW_POWER
|
||||
power=IS_POWER_FLAG_on?CC2500_HIGH_POWER:CC2500_LOW_POWER;
|
||||
#else
|
||||
power=CC2500_HIGH_POWER;
|
||||
#endif
|
||||
if(IS_RANGE_FLAG_on)
|
||||
power=CC2500_RANGE_POWER;
|
||||
cc2500_writeReg(CC2500_3E_PATABLE, power);
|
||||
}
|
||||
|
||||
void CC2500_SetTxRxMode(uint8_t mode)
|
||||
{
|
||||
if(mode == TX_EN)
|
||||
{//from deviation firmware
|
||||
cc2500_writeReg(CC2500_02_IOCFG0, 0x2F | 0x40);
|
||||
cc2500_writeReg(CC2500_00_IOCFG2, 0x2F);
|
||||
if(prev_power != power)
|
||||
{
|
||||
CC2500_WriteReg(CC2500_3E_PATABLE, power);
|
||||
prev_power=power;
|
||||
}
|
||||
else
|
||||
if (mode == RX_EN)
|
||||
{
|
||||
cc2500_writeReg(CC2500_02_IOCFG0, 0x2F);
|
||||
cc2500_writeReg(CC2500_00_IOCFG2, 0x2F | 0x40);
|
||||
}
|
||||
else
|
||||
{
|
||||
cc2500_writeReg(CC2500_02_IOCFG0, 0x2F);
|
||||
cc2500_writeReg(CC2500_00_IOCFG2, 0x2F);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
859
Multiprotocol/CFlie_nrf24l01.ino
Normal file
859
Multiprotocol/CFlie_nrf24l01.ino
Normal file
@@ -0,0 +1,859 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Most of this code was ported from theseankelly's related DeviationTX work.
|
||||
|
||||
#if defined(CFLIE_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define CFLIE_BIND_COUNT 60
|
||||
|
||||
//=============================================================================
|
||||
// CRTP (Crazy RealTime Protocol) Implementation
|
||||
//=============================================================================
|
||||
|
||||
// Port IDs
|
||||
enum {
|
||||
CRTP_PORT_CONSOLE = 0x00,
|
||||
CRTP_PORT_PARAM = 0x02,
|
||||
CRTP_PORT_SETPOINT = 0x03,
|
||||
CRTP_PORT_MEM = 0x04,
|
||||
CRTP_PORT_LOG = 0x05,
|
||||
CRTP_PORT_POSITION = 0x06,
|
||||
CRTP_PORT_SETPOINT_GENERIC = 0x07,
|
||||
CRTP_PORT_PLATFORM = 0x0D,
|
||||
CRTP_PORT_LINK = 0x0F,
|
||||
};
|
||||
|
||||
// Channel definitions for the LOG port
|
||||
enum {
|
||||
CRTP_LOG_CHAN_TOC = 0x00,
|
||||
CRTP_LOG_CHAN_SETTINGS = 0x01,
|
||||
CRTP_LOG_CHAN_LOGDATA = 0x02,
|
||||
};
|
||||
|
||||
// Command definitions for the LOG port's TOC channel
|
||||
enum {
|
||||
CRTP_LOG_TOC_CMD_ELEMENT = 0x00,
|
||||
CRTP_LOG_TOC_CMD_INFO = 0x01,
|
||||
};
|
||||
|
||||
// Command definitions for the LOG port's CMD channel
|
||||
enum {
|
||||
CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK = 0x00,
|
||||
CRTP_LOG_SETTINGS_CMD_APPEND_BLOCK = 0x01,
|
||||
CRTP_LOG_SETTINGS_CMD_DELETE_BLOCK = 0x02,
|
||||
CRTP_LOG_SETTINGS_CMD_START_LOGGING = 0x03,
|
||||
CRTP_LOG_SETTINGS_CMD_STOP_LOGGING = 0x04,
|
||||
CRTP_LOG_SETTINGS_CMD_RESET_LOGGING = 0x05,
|
||||
};
|
||||
|
||||
// Log variables types
|
||||
enum {
|
||||
LOG_UINT8 = 0x01,
|
||||
LOG_UINT16 = 0x02,
|
||||
LOG_UINT32 = 0x03,
|
||||
LOG_INT8 = 0x04,
|
||||
LOG_INT16 = 0x05,
|
||||
LOG_INT32 = 0x06,
|
||||
LOG_FLOAT = 0x07,
|
||||
LOG_FP16 = 0x08,
|
||||
};
|
||||
|
||||
#define CFLIE_TELEM_LOG_BLOCK_ID 0x01
|
||||
#define CFLIE_TELEM_LOG_BLOCK_PERIOD_10MS 50 // 50*10 = 500ms
|
||||
|
||||
// Setpoint type definitions for the generic setpoint channel
|
||||
enum {
|
||||
CRTP_SETPOINT_GENERIC_STOP_TYPE = 0x00,
|
||||
CRTP_SETPOINT_GENERIC_VELOCITY_WORLD_TYPE = 0x01,
|
||||
CRTP_SETPOINT_GENERIC_Z_DISTANCE_TYPE = 0x02,
|
||||
CRTP_SETPOINT_GENERIC_CPPM_EMU_TYPE = 0x03,
|
||||
};
|
||||
|
||||
static inline uint8_t crtp_create_header(uint8_t port, uint8_t channel)
|
||||
{
|
||||
return ((port)&0x0F)<<4 | (channel & 0x03);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// End CRTP implementation
|
||||
//=============================================================================
|
||||
|
||||
// Address size
|
||||
#define TX_ADDR_SIZE 5
|
||||
|
||||
// Timeout for callback in uSec, 10ms=10000us for Crazyflie
|
||||
#define PACKET_PERIOD 10000
|
||||
|
||||
#define MAX_PACKET_SIZE 32 // CRTP is 32 bytes
|
||||
|
||||
// CPPM CRTP supports up to 10 aux channels but deviation only
|
||||
// supports a total of 12 channels. R,P,Y,T leaves 8 aux channels left
|
||||
#define MAX_CPPM_AUX_CHANNELS 8
|
||||
|
||||
static uint8_t tx_payload_len = 0; // Length of the packet stored in packet
|
||||
static uint8_t rx_payload_len = 0; // Length of the packet stored in rx_packet
|
||||
static uint8_t rx_packet[MAX_PACKET_SIZE]; // For reading in ACK payloads
|
||||
|
||||
static uint8_t data_rate;
|
||||
|
||||
enum {
|
||||
CFLIE_INIT_SEARCH = 0,
|
||||
CFLIE_INIT_CRTP_LOG,
|
||||
CFLIE_INIT_DATA,
|
||||
CFLIE_SEARCH,
|
||||
CFLIE_DATA
|
||||
};
|
||||
|
||||
static uint8_t crtp_log_setup_state;
|
||||
enum {
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_INIT = 0,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_INFO,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_ITEM,
|
||||
// It might be a good idea to add a state here
|
||||
// to send the command to reset the logging engine
|
||||
// to avoid log block ID conflicts. However, there
|
||||
// is not a conflict with the current defaults in
|
||||
// cfclient and I'd rather be able to log from the Tx
|
||||
// and cfclient simultaneously
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_START_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_COMPLETE,
|
||||
};
|
||||
|
||||
// State variables for the crtp_log_setup_state_machine
|
||||
static uint8_t toc_size; // Size of the TOC read from the crazyflie
|
||||
static uint8_t next_toc_variable; // State variable keeping track of the next var to read
|
||||
static uint8_t vbat_var_id; // ID of the vbatMV variable
|
||||
static uint8_t extvbat_var_id; // ID of the extVbatMV variable
|
||||
static uint8_t rssi_var_id; // ID of the RSSI variable
|
||||
|
||||
// Constants used for finding var IDs from the toc
|
||||
static const char* pm_group_name = "pm";
|
||||
static const char* vbat_var_name = "vbatMV";
|
||||
static const uint8_t vbat_var_type = LOG_UINT16;
|
||||
static const char* extvbat_var_name = "extVbatMV";
|
||||
static const uint8_t extvbat_var_type = LOG_UINT16;
|
||||
static const char* radio_group_name = "radio";
|
||||
static const char* rssi_var_name = "rssi";
|
||||
static const uint8_t rssi_var_type = LOG_UINT8;
|
||||
|
||||
// Repurposing DSM Telemetry fields
|
||||
#define TELEM_CFLIE_INTERNAL_VBAT TELEM_DSM_FLOG_VOLT2 // Onboard voltage
|
||||
#define TELEM_CFLIE_EXTERNAL_VBAT TELEM_DSM_FLOG_VOLT1 // Voltage from external pin (BigQuad)
|
||||
#define TELEM_CFLIE_RSSI TELEM_DSM_FLOG_FADESA // Repurpose FADESA for RSSI
|
||||
|
||||
enum {
|
||||
PROTOOPTS_TELEMETRY = 0,
|
||||
PROTOOPTS_CRTP_MODE = 1,
|
||||
LAST_PROTO_OPT,
|
||||
};
|
||||
|
||||
#define TELEM_OFF 0
|
||||
#define TELEM_ON_ACKPKT 1
|
||||
#define TELEM_ON_CRTPLOG 2
|
||||
|
||||
#define CRTP_MODE_RPYT 0
|
||||
#define CRTP_MODE_CPPM 1
|
||||
|
||||
// Bit vector from bit position
|
||||
#define BV(bit) (1 << bit)
|
||||
|
||||
#define PACKET_CHKTIME 500 // time to wait if packet not yet acknowledged or timed out
|
||||
|
||||
// Helper for sending a packet
|
||||
// Assumes packet data has been put in packet
|
||||
// and tx_payload_len has been set correctly
|
||||
static void send_packet()
|
||||
{
|
||||
// clear packet status bits and Tx/Rx FIFOs
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (_BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
|
||||
// Transmit the payload
|
||||
NRF24L01_WritePayload(packet, tx_payload_len);
|
||||
|
||||
// // Check and adjust transmission power.
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static uint16_t dbg_cnt = 0;
|
||||
static uint8_t packet_ack()
|
||||
{
|
||||
if (++dbg_cnt > 50)
|
||||
{
|
||||
// debugln("S: %02x\n", NRF24L01_ReadReg(NRF24L01_07_STATUS));
|
||||
dbg_cnt = 0;
|
||||
}
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)))
|
||||
{
|
||||
case BV(NRF24L01_07_TX_DS):
|
||||
rx_payload_len = NRF24L01_GetDynamicPayloadSize();
|
||||
if (rx_payload_len > MAX_PACKET_SIZE)
|
||||
rx_payload_len = MAX_PACKET_SIZE;
|
||||
NRF24L01_ReadPayload(rx_packet, rx_payload_len);
|
||||
return PKT_ACKED;
|
||||
case BV(NRF24L01_07_MAX_RT):
|
||||
return PKT_TIMEOUT;
|
||||
}
|
||||
return PKT_PENDING;
|
||||
}
|
||||
|
||||
static void set_rate_channel(uint8_t rate, uint8_t channel)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel); // Defined by model id
|
||||
NRF24L01_SetBitrate(rate); // Defined by model id
|
||||
}
|
||||
|
||||
static void send_search_packet()
|
||||
{
|
||||
uint8_t buf[1];
|
||||
buf[0] = 0xff;
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if (rf_ch_num++ > 125)
|
||||
{
|
||||
rf_ch_num = 0;
|
||||
switch(data_rate)
|
||||
{
|
||||
case NRF24L01_BR_250K:
|
||||
data_rate = NRF24L01_BR_1M;
|
||||
break;
|
||||
case NRF24L01_BR_1M:
|
||||
data_rate = NRF24L01_BR_2M;
|
||||
break;
|
||||
case NRF24L01_BR_2M:
|
||||
data_rate = NRF24L01_BR_250K;
|
||||
break;
|
||||
}
|
||||
}
|
||||
set_rate_channel(data_rate, rf_ch_num);
|
||||
|
||||
NRF24L01_WritePayload(buf, sizeof(buf));
|
||||
|
||||
}
|
||||
|
||||
// Frac 16.16
|
||||
#define FRAC_MANTISSA 16 // This means, not IEEE 754...
|
||||
#define FRAC_SCALE (1 << FRAC_MANTISSA)
|
||||
|
||||
// Convert fractional 16.16 to float32
|
||||
static void frac2float(int32_t n, float* res)
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
*res = 0.0;
|
||||
return;
|
||||
}
|
||||
uint32_t m = n < 0 ? -n : n; // Figure out mantissa?
|
||||
int i;
|
||||
for (i = (31-FRAC_MANTISSA); (m & 0x80000000) == 0; i--, m <<= 1);
|
||||
m <<= 1; // Clear implicit leftmost 1
|
||||
m >>= 9;
|
||||
uint32_t e = 127 + i;
|
||||
if (n < 0) m |= 0x80000000;
|
||||
m |= e << 23;
|
||||
*((uint32_t *) res) = m;
|
||||
}
|
||||
|
||||
static void send_crtp_rpyt_packet()
|
||||
{
|
||||
int32_t f_roll;
|
||||
int32_t f_pitch;
|
||||
int32_t f_yaw;
|
||||
uint16_t thrust;
|
||||
|
||||
uint16_t val;
|
||||
|
||||
struct CommanderPacketRPYT
|
||||
{
|
||||
float roll;
|
||||
float pitch;
|
||||
float yaw;
|
||||
uint16_t thrust;
|
||||
}__attribute__((packed)) cpkt;
|
||||
|
||||
// Channels in AETR order
|
||||
// Roll, aka aileron, float +- 50.0 in degrees
|
||||
// float roll = -(float) Channels[0]*50.0/10000;
|
||||
val = convert_channel_16b_limit(AILERON, -10000, 10000);
|
||||
// f_roll = -Channels[0] * FRAC_SCALE / (10000 / 50);
|
||||
f_roll = val * FRAC_SCALE / (10000 / 50);
|
||||
|
||||
frac2float(f_roll, &cpkt.roll); // TODO: Remove this and use the correct Mode switch below...
|
||||
// debugln("Roll: raw, converted: %d, %d, %d, %0.2f", Channel_data[AILERON], val, f_roll, cpkt.roll);
|
||||
|
||||
// Pitch, aka elevator, float +- 50.0 degrees
|
||||
//float pitch = -(float) Channels[1]*50.0/10000;
|
||||
val = convert_channel_16b_limit(ELEVATOR, -10000, 10000);
|
||||
// f_pitch = -Channels[1] * FRAC_SCALE / (10000 / 50);
|
||||
f_pitch = -val * FRAC_SCALE / (10000 / 50);
|
||||
|
||||
frac2float(f_pitch, &cpkt.pitch); // TODO: Remove this and use the correct Mode switch below...
|
||||
// debugln("Pitch: raw, converted: %d, %d, %d, %0.2f", Channel_data[ELEVATOR], val, f_pitch, cpkt.pitch);
|
||||
|
||||
// Thrust, aka throttle 0..65535, working range 5535..65535
|
||||
// Android Crazyflie app puts out a throttle range of 0-80%: 0..52000
|
||||
thrust = convert_channel_16b_limit(THROTTLE, 0, 32767) * 2;
|
||||
|
||||
// Crazyflie needs zero thrust to unlock
|
||||
if (thrust < 900)
|
||||
cpkt.thrust = 0;
|
||||
else
|
||||
cpkt.thrust = thrust;
|
||||
|
||||
// debugln("Thrust: raw, converted: %d, %u, %u", Channel_data[THROTTLE], thrust, cpkt.thrust);
|
||||
|
||||
// Yaw, aka rudder, float +- 400.0 deg/s
|
||||
// float yaw = -(float) Channels[3]*400.0/10000;
|
||||
val = convert_channel_16b_limit(RUDDER, -10000, 10000);
|
||||
// f_yaw = - Channels[3] * FRAC_SCALE / (10000 / 400);
|
||||
f_yaw = val * FRAC_SCALE / (10000 / 400);
|
||||
frac2float(f_yaw, &cpkt.yaw);
|
||||
|
||||
// debugln("Yaw: raw, converted: %d, %d, %d, %0.2f", Channel_data[RUDDER], val, f_yaw, cpkt.yaw);
|
||||
|
||||
// Switch on/off?
|
||||
// TODO: Get X or + mode working again:
|
||||
// if (Channels[4] >= 0) {
|
||||
// frac2float(f_roll, &cpkt.roll);
|
||||
// frac2float(f_pitch, &cpkt.pitch);
|
||||
// } else {
|
||||
// // Rotate 45 degrees going from X to + mode or opposite.
|
||||
// // 181 / 256 = 0.70703125 ~= sqrt(2) / 2
|
||||
// int32_t f_x_roll = (f_roll + f_pitch) * 181 / 256;
|
||||
// frac2float(f_x_roll, &cpkt.roll);
|
||||
// int32_t f_x_pitch = (f_pitch - f_roll) * 181 / 256;
|
||||
// frac2float(f_x_pitch, &cpkt.pitch);
|
||||
// }
|
||||
|
||||
// Construct and send packet
|
||||
packet[0] = crtp_create_header(CRTP_PORT_SETPOINT, 0); // Commander packet to channel 0
|
||||
memcpy(&packet[1], (char*) &cpkt, sizeof(cpkt));
|
||||
tx_payload_len = 1 + sizeof(cpkt);
|
||||
send_packet();
|
||||
}
|
||||
|
||||
/*static void send_crtp_cppm_emu_packet()
|
||||
{
|
||||
struct CommanderPacketCppmEmu {
|
||||
struct {
|
||||
uint8_t numAuxChannels : 4; // Set to 0 through MAX_AUX_RC_CHANNELS
|
||||
uint8_t reserved : 4;
|
||||
} hdr;
|
||||
uint16_t channelRoll;
|
||||
uint16_t channelPitch;
|
||||
uint16_t channelYaw;
|
||||
uint16_t channelThrust;
|
||||
uint16_t channelAux[10];
|
||||
} __attribute__((packed)) cpkt;
|
||||
|
||||
// To emulate PWM RC signals, rescale channels from (-10000,10000) to (1000,2000)
|
||||
// This is done by dividing by 20 to get a total range of 1000 (-500,500)
|
||||
// and then adding 1500 to to rebase the offset
|
||||
#define RESCALE_RC_CHANNEL_TO_PWM(chan) ((chan / 20) + 1500)
|
||||
|
||||
// Make sure the number of aux channels in use is capped to MAX_CPPM_AUX_CHANNELS
|
||||
// uint8_t numAuxChannels = Model.num_channels - 4;
|
||||
uint8_t numAuxChannels = 2; // TODO: Figure this out correctly
|
||||
if(numAuxChannels > MAX_CPPM_AUX_CHANNELS)
|
||||
{
|
||||
numAuxChannels = MAX_CPPM_AUX_CHANNELS;
|
||||
}
|
||||
|
||||
cpkt.hdr.numAuxChannels = numAuxChannels;
|
||||
|
||||
// Remap AETR to AERT (RPYT)
|
||||
cpkt.channelRoll = convert_channel_16b_limit(AILERON,1000,2000);
|
||||
cpkt.channelPitch = convert_channel_16b_limit(ELEVATOR,1000,2000);
|
||||
// Note: T & R Swapped:
|
||||
cpkt.channelYaw = convert_channel_16b_limit(RUDDER, 1000, 2000);
|
||||
cpkt.channelThrust = convert_channel_16b_limit(THROTTLE, 1000, 2000);
|
||||
|
||||
// Rescale the rest of the aux channels - RC channel 4 and up
|
||||
for (uint8_t i = 4; i < 14; i++)
|
||||
{
|
||||
cpkt.channelAux[i] = convert_channel_16b_limit(i, 1000, 2000);
|
||||
}
|
||||
|
||||
// Total size of the commander packet is a 1-byte header, 4 2-byte channels and
|
||||
// a variable number of 2-byte auxiliary channels
|
||||
uint8_t commanderPacketSize = 1 + 8 + (2*numAuxChannels);
|
||||
|
||||
// Construct and send packet
|
||||
packet[0] = crtp_create_header(CRTP_PORT_SETPOINT_GENERIC, 0); // Generic setpoint packet to channel 0
|
||||
packet[1] = CRTP_SETPOINT_GENERIC_CPPM_EMU_TYPE;
|
||||
|
||||
// Copy the header (1) plus 4 2-byte channels (8) plus whatever number of 2-byte aux channels are in use
|
||||
memcpy(&packet[2], (char*)&cpkt, commanderPacketSize); // Why not use sizeof(cpkt) here??
|
||||
tx_payload_len = 2 + commanderPacketSize; // CRTP header, commander type, and packet
|
||||
send_packet();
|
||||
}*/
|
||||
|
||||
static void send_cmd_packet()
|
||||
{
|
||||
// TODO: Fix this so we can actually configure the packet type
|
||||
// switch(Model.proto_opts[PROTOOPTS_CRTP_MODE])
|
||||
// {
|
||||
// case CRTP_MODE_CPPM:
|
||||
// send_crtp_cppm_emu_packet();
|
||||
// break;
|
||||
// case CRTP_MODE_RPYT:
|
||||
// send_crtp_rpyt_packet();
|
||||
// break;
|
||||
// default:
|
||||
// send_crtp_rpyt_packet();
|
||||
// }
|
||||
|
||||
// send_crtp_cppm_emu_packet(); // oh maAAAn
|
||||
send_crtp_rpyt_packet();
|
||||
}
|
||||
|
||||
// State machine for setting up CRTP logging
|
||||
// returns 1 when the state machine has completed, 0 otherwise
|
||||
static uint8_t crtp_log_setup_state_machine()
|
||||
{
|
||||
uint8_t state_machine_completed = 0;
|
||||
// A note on the design of this state machine:
|
||||
//
|
||||
// Responses from the crazyflie come in the form of ACK payloads.
|
||||
// There is no retry logic associated with ACK payloads, so it is possible
|
||||
// to miss a response from the crazyflie. To avoid this, the request
|
||||
// packet must be re-sent until the expected response is received. However,
|
||||
// re-sending the same request generates another response in the crazyflie
|
||||
// Rx queue, which can produce large backlogs of duplicate responses.
|
||||
//
|
||||
// To avoid this backlog but still guard against dropped ACK payloads,
|
||||
// transmit cmd packets (which don't generate responses themselves)
|
||||
// until an empty ACK payload is received (the crazyflie alternates between
|
||||
// 0xF3 and 0xF7 for empty ACK payloads) which indicates the Rx queue on the
|
||||
// crazyflie has been drained. If the queue has been drained and the
|
||||
// desired ACK has still not been received, it was likely dropped and the
|
||||
// request should be re-transmit.
|
||||
|
||||
switch (crtp_log_setup_state) {
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_INIT:
|
||||
toc_size = 0;
|
||||
next_toc_variable = 0;
|
||||
vbat_var_id = 0;
|
||||
extvbat_var_id = 0;
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO;
|
||||
// fallthrough
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_INFO;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC);
|
||||
packet[1] = CRTP_LOG_TOC_CMD_INFO;
|
||||
tx_payload_len = 2;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_INFO:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 3
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC)
|
||||
&& rx_packet[1] == CRTP_LOG_TOC_CMD_INFO) {
|
||||
// Received the ACK payload. Save the toc_size
|
||||
// and advance to the next state
|
||||
toc_size = rx_packet[2];
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM;
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_ITEM;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC);
|
||||
packet[1] = CRTP_LOG_TOC_CMD_ELEMENT;
|
||||
packet[2] = next_toc_variable;
|
||||
tx_payload_len = 3;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_ITEM:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 3
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC)
|
||||
&& rx_packet[1] == CRTP_LOG_TOC_CMD_ELEMENT
|
||||
&& rx_packet[2] == next_toc_variable) {
|
||||
// For every element in the TOC we must compare its
|
||||
// type (rx_packet[3]), group and name (back to back
|
||||
// null terminated strings starting with the fifth byte)
|
||||
// and see if it matches any of the variables we need
|
||||
// for logging
|
||||
//
|
||||
// Currently enabled for logging:
|
||||
// - vbatMV (LOG_UINT16)
|
||||
// - extVbatMV (LOG_UINT16)
|
||||
// - rssi (LOG_UINT8)
|
||||
if(rx_packet[3] == vbat_var_type
|
||||
&& (0 == strcmp((char*)&rx_packet[4], pm_group_name))
|
||||
&& (0 == strcmp((char*)&rx_packet[4 + strlen(pm_group_name) + 1], vbat_var_name))) {
|
||||
// Found the vbat element - save it for later
|
||||
vbat_var_id = next_toc_variable;
|
||||
}
|
||||
|
||||
if(rx_packet[3] == extvbat_var_type
|
||||
&& (0 == strcmp((char*)&rx_packet[4], pm_group_name))
|
||||
&& (0 == strcmp((char*)&rx_packet[4 + strlen(pm_group_name) + 1], extvbat_var_name))) {
|
||||
// Found the extvbat element - save it for later
|
||||
extvbat_var_id = next_toc_variable;
|
||||
}
|
||||
|
||||
if(rx_packet[3] == rssi_var_type
|
||||
&& (0 == strcmp((char*)&rx_packet[4], radio_group_name))
|
||||
&& (0 == strcmp((char*)&rx_packet[4 + strlen(radio_group_name) + 1], rssi_var_name))) {
|
||||
// Found the rssi element - save it for later
|
||||
rssi_var_id = next_toc_variable;
|
||||
}
|
||||
|
||||
// Advance the toc variable counter
|
||||
// If there are more variables, read them
|
||||
// If not, move on to the next state
|
||||
next_toc_variable += 1;
|
||||
if(next_toc_variable >= toc_size) {
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK;
|
||||
} else {
|
||||
// There are more TOC elements to get
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM;
|
||||
}
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS);
|
||||
packet[1] = CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK;
|
||||
packet[2] = CFLIE_TELEM_LOG_BLOCK_ID; // Log block ID
|
||||
packet[3] = vbat_var_type; // Variable type
|
||||
packet[4] = vbat_var_id; // ID of the VBAT variable
|
||||
packet[5] = extvbat_var_type; // Variable type
|
||||
packet[6] = extvbat_var_id; // ID of the ExtVBat variable
|
||||
packet[7] = rssi_var_type; // Variable type
|
||||
packet[8] = rssi_var_id; // ID of the RSSI variable
|
||||
tx_payload_len = 9;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 2
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS)
|
||||
&& rx_packet[1] == CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK) {
|
||||
// Received the ACK payload. Advance to the next state
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK;
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_START_BLOCK;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS);
|
||||
packet[1] = CRTP_LOG_SETTINGS_CMD_START_LOGGING;
|
||||
packet[2] = CFLIE_TELEM_LOG_BLOCK_ID; // Log block ID 1
|
||||
packet[3] = CFLIE_TELEM_LOG_BLOCK_PERIOD_10MS; // Log frequency in 10ms units
|
||||
tx_payload_len = 4;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_START_BLOCK:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 2
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS)
|
||||
&& rx_packet[1] == CRTP_LOG_SETTINGS_CMD_START_LOGGING) {
|
||||
// Received the ACK payload. Advance to the next state
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_COMPLETE;
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_COMPLETE:
|
||||
state_machine_completed = 1;
|
||||
return state_machine_completed;
|
||||
break;
|
||||
}
|
||||
|
||||
return state_machine_completed;
|
||||
}
|
||||
|
||||
static int cflie_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;
|
||||
}
|
||||
|
||||
// TODO: Fix telemetry
|
||||
|
||||
// Update telemetry using the CRTP logging framework
|
||||
// static void update_telemetry_crtplog()
|
||||
// {
|
||||
// static uint8_t frameloss = 0;
|
||||
|
||||
// // Read and reset count of dropped packets
|
||||
// frameloss += NRF24L01_ReadReg(NRF24L01_08_OBSERVE_TX) >> 4;
|
||||
// NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num); // reset packet loss counter
|
||||
// Telemetry.value[TELEM_DSM_FLOG_FRAMELOSS] = frameloss;
|
||||
// TELEMETRY_SetUpdated(TELEM_DSM_FLOG_FRAMELOSS);
|
||||
|
||||
// if (packet_ack() == PKT_ACKED) {
|
||||
// // See if the ACK packet is a cflie log packet
|
||||
// // A log data packet is a minimum of 5 bytes. Ignore anything less.
|
||||
// if (rx_payload_len >= 5) {
|
||||
// // Port 5 = log, Channel 2 = data
|
||||
// if (rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_LOGDATA)) {
|
||||
// // The log block ID
|
||||
// if (rx_packet[1] == CFLIE_TELEM_LOG_BLOCK_ID) {
|
||||
// // Bytes 5 and 6 are the Vbat in mV units
|
||||
// uint16_t vBat;
|
||||
// memcpy(&vBat, &rx_packet[5], sizeof(uint16_t));
|
||||
// Telemetry.value[TELEM_CFLIE_INTERNAL_VBAT] = (int32_t) (vBat / 10); // The log value expects centivolts
|
||||
// TELEMETRY_SetUpdated(TELEM_CFLIE_INTERNAL_VBAT);
|
||||
|
||||
// // Bytes 7 and 8 are the ExtVbat in mV units
|
||||
// uint16_t extVBat;
|
||||
// memcpy(&extVBat, &rx_packet[7], sizeof(uint16_t));
|
||||
// Telemetry.value[TELEM_CFLIE_EXTERNAL_VBAT] = (int32_t) (extVBat / 10); // The log value expects centivolts
|
||||
// TELEMETRY_SetUpdated(TELEM_CFLIE_EXTERNAL_VBAT);
|
||||
|
||||
// // Byte 9 is the RSSI
|
||||
// Telemetry.value[TELEM_CFLIE_RSSI] = rx_packet[9];
|
||||
// TELEMETRY_SetUpdated(TELEM_CFLIE_RSSI);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Update telemetry using the ACK packet payload
|
||||
// static void update_telemetry_ackpkt()
|
||||
// {
|
||||
// static uint8_t frameloss = 0;
|
||||
|
||||
// // Read and reset count of dropped packets
|
||||
// frameloss += NRF24L01_ReadReg(NRF24L01_08_OBSERVE_TX) >> 4;
|
||||
// NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num); // reset packet loss counter
|
||||
// Telemetry.value[TELEM_DSM_FLOG_FRAMELOSS] = frameloss;
|
||||
// TELEMETRY_SetUpdated(TELEM_DSM_FLOG_FRAMELOSS);
|
||||
|
||||
// if (packet_ack() == PKT_ACKED) {
|
||||
// // Make sure this is an ACK packet (first byte will alternate between 0xF3 and 0xF7
|
||||
// if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// // If ACK packet contains RSSI (proper length and byte 1 is 0x01)
|
||||
// if(rx_payload_len >= 3 && rx_packet[1] == 0x01) {
|
||||
// Telemetry.value[TELEM_CFLIE_RSSI] = rx_packet[2];
|
||||
// TELEMETRY_SetUpdated(TELEM_CFLIE_RSSI);
|
||||
// }
|
||||
// // If ACK packet contains VBAT (proper length and byte 3 is 0x02)
|
||||
// if(rx_payload_len >= 8 && rx_packet[3] == 0x02) {
|
||||
// uint32_t vBat = 0;
|
||||
// memcpy(&vBat, &rx_packet[4], sizeof(uint32_t));
|
||||
// Telemetry.value[TELEM_CFLIE_INTERNAL_VBAT] = (int32_t)(vBat / 10); // The log value expects centivolts
|
||||
// TELEMETRY_SetUpdated(TELEM_CFLIE_INTERNAL_VBAT);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
static uint16_t cflie_callback()
|
||||
{
|
||||
switch (phase) {
|
||||
case CFLIE_INIT_SEARCH:
|
||||
send_search_packet();
|
||||
phase = CFLIE_SEARCH;
|
||||
break;
|
||||
case CFLIE_INIT_CRTP_LOG:
|
||||
if (crtp_log_setup_state_machine()) {
|
||||
phase = CFLIE_INIT_DATA;
|
||||
}
|
||||
break;
|
||||
case CFLIE_INIT_DATA:
|
||||
send_cmd_packet();
|
||||
phase = CFLIE_DATA;
|
||||
break;
|
||||
case CFLIE_SEARCH:
|
||||
switch (packet_ack()) {
|
||||
case PKT_PENDING:
|
||||
return PACKET_CHKTIME; // packet send not yet complete
|
||||
case PKT_ACKED:
|
||||
phase = CFLIE_DATA;
|
||||
// PROTOCOL_SetBindState(0);
|
||||
// MUSIC_Play(MUSIC_DONE_BINDING);
|
||||
BIND_DONE;
|
||||
break;
|
||||
case PKT_TIMEOUT:
|
||||
send_search_packet();
|
||||
}
|
||||
break;
|
||||
|
||||
case CFLIE_DATA:
|
||||
// if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_CRTPLOG) {
|
||||
// update_telemetry_crtplog();
|
||||
// } else if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_ACKPKT) {
|
||||
// update_telemetry_ackpkt();
|
||||
// }
|
||||
|
||||
if (packet_ack() == PKT_PENDING)
|
||||
return PACKET_CHKTIME; // packet send not yet complete
|
||||
send_cmd_packet();
|
||||
break;
|
||||
}
|
||||
return PACKET_PERIOD; // Packet at standard protocol interval
|
||||
}
|
||||
|
||||
// Generate address to use from TX id and manufacturer id (STM32 unique id)
|
||||
static uint8_t initialize_rx_tx_addr()
|
||||
{
|
||||
rx_tx_addr[0] =
|
||||
rx_tx_addr[1] =
|
||||
rx_tx_addr[2] =
|
||||
rx_tx_addr[3] =
|
||||
rx_tx_addr[4] = 0xE7; // CFlie uses fixed address
|
||||
|
||||
// if (Model.fixed_id) {
|
||||
// rf_ch_num = Model.fixed_id % 100;
|
||||
// switch (Model.fixed_id / 100) {
|
||||
// case 0:
|
||||
// data_rate = NRF24L01_BR_250K;
|
||||
// break;
|
||||
// case 1:
|
||||
// data_rate = NRF24L01_BR_1M;
|
||||
// break;
|
||||
// case 2:
|
||||
// data_rate = NRF24L01_BR_2M;
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_CRTPLOG) {
|
||||
// return CFLIE_INIT_CRTP_LOG;
|
||||
// } else {
|
||||
// return CFLIE_INIT_DATA;
|
||||
// }
|
||||
// } else {
|
||||
// data_rate = NRF24L01_BR_250K;
|
||||
// rf_ch_num = 10;
|
||||
// return CFLIE_INIT_SEARCH;
|
||||
// }
|
||||
|
||||
// Default 1
|
||||
data_rate = NRF24L01_BR_1M;
|
||||
rf_ch_num = 10;
|
||||
|
||||
// Default 2
|
||||
// data_rate = NRF24L01_BR_2M;
|
||||
// rf_ch_num = 110;
|
||||
return CFLIE_INIT_SEARCH;
|
||||
}
|
||||
|
||||
uint16_t initCFlie(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
|
||||
phase = 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;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -12,8 +12,7 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Merged CG023 and H8_3D protocols
|
||||
// compatible with EAchine 3D X4, CG023/CG031, Attop YD-822/YD-829/YD-829C and H8_3D/JJRC H20
|
||||
// compatible with EAchine 3D X4, CG023/CG031, Attop YD-822/YD-829/YD-829C and H8_3D/JJRC H20/H22
|
||||
|
||||
#if defined(CG023_NRF24L01_INO)
|
||||
|
||||
@@ -23,11 +22,8 @@
|
||||
#define CG023_INITIAL_WAIT 500
|
||||
#define CG023_PACKET_SIZE 15 // packets have 15-byte payload
|
||||
#define CG023_RF_BIND_CHANNEL 0x2D
|
||||
#define CG023_BIND_COUNT 1000 // 8 seconds
|
||||
#define CG023_BIND_COUNT 500 // 4 seconds
|
||||
#define YD829_PACKET_PERIOD 4100 // Timeout for callback in uSec
|
||||
#define H8_3D_PACKET_PERIOD 1800 // Timeout for callback in uSec
|
||||
#define H8_3D_PACKET_SIZE 20
|
||||
#define H8_3D_RF_NUM_CHANNELS 4
|
||||
|
||||
|
||||
enum CG023_FLAGS {
|
||||
@@ -53,227 +49,115 @@ enum YD829_FLAGS {
|
||||
YD829_FLAG_STILL = 0x80,
|
||||
};
|
||||
|
||||
enum H8_3D_FLAGS {
|
||||
// flags going to packet[17]
|
||||
H8_3D_FLAG_FLIP = 0x01,
|
||||
H8_3D_FLAG_RATE_MID = 0x02,
|
||||
H8_3D_FLAG_RATE_HIGH = 0x04,
|
||||
H8_3D_FLAG_HEADLESS = 0x10, // RTH + headless on H8, headless on JJRC H20
|
||||
H8_3D_FLAG_RTH = 0x40, // 360 flip mode on H8 3D, RTH on JJRC H20
|
||||
};
|
||||
|
||||
enum H8_3D_FLAGS_2 {
|
||||
// flags going to packet[18]
|
||||
H8_3D_FLAG_CALIBRATE = 0x20, // accelerometer calibration
|
||||
};
|
||||
|
||||
enum CG023_PHASES {
|
||||
CG023_BIND = 0,
|
||||
CG023_DATA
|
||||
};
|
||||
|
||||
void CG023_send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
|
||||
{
|
||||
// throttle : 0x00 - 0xFF
|
||||
throttle=convert_channel_8b(THROTTLE);
|
||||
// rudder
|
||||
rudder = convert_channel_8b_scale(RUDDER,0x44,0xBC); // yaw right : 0x80 (neutral) - 0xBC (right)
|
||||
rudder = convert_channel_16b_limit(RUDDER,0x44,0xBC); // yaw right : 0x80 (neutral) - 0xBC (right)
|
||||
if (rudder<=0x80)
|
||||
rudder=0x80-rudder; // yaw left : 0x00 (neutral) - 0x3C (left)
|
||||
// elevator : 0xBB - 0x7F - 0x43
|
||||
elevator = convert_channel_8b_scale(ELEVATOR, 0x43, 0xBB);
|
||||
elevator = convert_channel_16b_limit(ELEVATOR, 0x43, 0xBB);
|
||||
// aileron : 0x43 - 0x7F - 0xBB
|
||||
aileron = convert_channel_8b_scale(AILERON, 0x43, 0xBB);
|
||||
aileron = convert_channel_16b_limit(AILERON, 0x43, 0xBB);
|
||||
|
||||
if (bind)
|
||||
packet[0]= 0xaa;
|
||||
else
|
||||
packet[0]= 0x55;
|
||||
// transmitter id
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
if(sub_protocol==H8_3D)
|
||||
// unknown
|
||||
packet[3] = 0x00;
|
||||
packet[4] = 0x00;
|
||||
packet[5] = throttle;
|
||||
packet[6] = rudder;
|
||||
packet[7] = elevator;
|
||||
packet[8] = aileron;
|
||||
// throttle trim : 0x30 - 0x20 - 0x10
|
||||
packet[9] = 0x20; // neutral
|
||||
// neutral trims
|
||||
packet[10] = 0x20;
|
||||
packet[11] = 0x40;
|
||||
packet[12] = 0x40;
|
||||
if(sub_protocol==CG023)
|
||||
{
|
||||
packet[0] = 0x13;
|
||||
packet[3] = rx_tx_addr[2];
|
||||
packet[4] = rx_tx_addr[3];
|
||||
packet[8] = (rx_tx_addr[0]+rx_tx_addr[1]+rx_tx_addr[2]+rx_tx_addr[3]) & 0xff; // txid checksum
|
||||
memset(&packet[9], 0, 10);
|
||||
if (bind)
|
||||
{
|
||||
packet[5] = 0x00;
|
||||
packet[6] = 0x00;
|
||||
packet[7] = 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[5] = hopping_frequency_no;
|
||||
packet[6] = 0x08;
|
||||
packet[7] = 0x03;
|
||||
packet[9] = throttle;
|
||||
packet[10] = rudder;
|
||||
packet[11] = elevator;
|
||||
packet[12] = aileron;
|
||||
// neutral trims
|
||||
packet[13] = 0x20;
|
||||
packet[14] = 0x20;
|
||||
packet[15] = 0x20;
|
||||
packet[16] = 0x20;
|
||||
packet[17] = H8_3D_FLAG_RATE_HIGH;
|
||||
if(Servo_data[AUX1] > PPM_SWITCH)
|
||||
packet[17] |= H8_3D_FLAG_FLIP;
|
||||
if(Servo_data[AUX2] > PPM_SWITCH)
|
||||
packet[17] |= H8_3D_FLAG_HEADLESS;
|
||||
if(Servo_data[AUX3] > PPM_SWITCH)
|
||||
packet[17] |= H8_3D_FLAG_RTH; // 180/360 flip mode on H8 3D
|
||||
|
||||
// both sticks bottom left: calibrate acc
|
||||
if(packet[9] <= 0x05 && packet[10] >= 0xa7 && packet[11] <= 0x57 && packet[12] >= 0xa7)
|
||||
packet[18] = H8_3D_FLAG_CALIBRATE;
|
||||
}
|
||||
uint8_t sum = packet[9];
|
||||
for (uint8_t i=10; i < H8_3D_PACKET_SIZE-1; i++)
|
||||
sum += packet[i];
|
||||
packet[19] = sum; // data checksum
|
||||
// rate
|
||||
packet[13] = CG023_FLAG_RATE_HIGH
|
||||
| GET_FLAG(CH5_SW,CG023_FLAG_FLIP)
|
||||
| GET_FLAG(CH6_SW,CG023_FLAG_LED_OFF)
|
||||
| GET_FLAG(CH7_SW,CG023_FLAG_STILL)
|
||||
| GET_FLAG(CH8_SW,CG023_FLAG_VIDEO)
|
||||
| GET_FLAG(CH9_SW,CG023_FLAG_EASY);
|
||||
}
|
||||
else
|
||||
{ // CG023 and YD829
|
||||
if (bind)
|
||||
packet[0]= 0xaa;
|
||||
else
|
||||
packet[0]= 0x55;
|
||||
// transmitter id
|
||||
// unknown
|
||||
packet[3] = 0x00;
|
||||
packet[4] = 0x00;
|
||||
packet[5] = throttle;
|
||||
packet[6] = rudder;
|
||||
packet[7] = elevator;
|
||||
packet[8] = aileron;
|
||||
// throttle trim : 0x30 - 0x20 - 0x10
|
||||
packet[9] = 0x20; // neutral
|
||||
// neutral trims
|
||||
packet[10] = 0x20;
|
||||
packet[11] = 0x40;
|
||||
packet[12] = 0x40;
|
||||
if(sub_protocol==CG023)
|
||||
{
|
||||
// rate
|
||||
packet[13] = CG023_FLAG_RATE_HIGH;
|
||||
// flags
|
||||
if(Servo_data[AUX1] > PPM_SWITCH)
|
||||
packet[13] |= CG023_FLAG_FLIP;
|
||||
if(Servo_data[AUX2] > PPM_SWITCH)
|
||||
packet[13] |= CG023_FLAG_LED_OFF;
|
||||
if(Servo_data[AUX3] > PPM_SWITCH)
|
||||
packet[13] |= CG023_FLAG_STILL;
|
||||
if(Servo_data[AUX4] > PPM_SWITCH)
|
||||
packet[13] |= CG023_FLAG_VIDEO;
|
||||
if(Servo_data[AUX5] > PPM_SWITCH)
|
||||
packet[13] |= CG023_FLAG_EASY;
|
||||
}
|
||||
else
|
||||
{// YD829
|
||||
// rate
|
||||
packet[13] = YD829_FLAG_RATE_HIGH;
|
||||
// flags
|
||||
if(Servo_data[AUX1] > PPM_SWITCH)
|
||||
packet[13] |= YD829_FLAG_FLIP;
|
||||
if(Servo_data[AUX3] > PPM_SWITCH)
|
||||
packet[13] |= YD829_FLAG_STILL;
|
||||
if(Servo_data[AUX4] > PPM_SWITCH)
|
||||
packet[13] |= YD829_FLAG_VIDEO;
|
||||
if(Servo_data[AUX5] > PPM_SWITCH)
|
||||
packet[13] |= YD829_FLAG_HEADLESS;
|
||||
}
|
||||
packet[14] = 0;
|
||||
{// YD829
|
||||
// rate
|
||||
packet[13] = YD829_FLAG_RATE_HIGH
|
||||
| GET_FLAG(CH5_SW,YD829_FLAG_FLIP)
|
||||
| GET_FLAG(CH7_SW,YD829_FLAG_STILL)
|
||||
| GET_FLAG(CH8_SW,YD829_FLAG_VIDEO)
|
||||
| GET_FLAG(CH9_SW,YD829_FLAG_HEADLESS);
|
||||
}
|
||||
packet[14] = 0;
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
if (bind)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, sub_protocol==H8_3D?hopping_frequency[0]:CG023_RF_BIND_CHANNEL);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, CG023_RF_BIND_CHANNEL);
|
||||
else
|
||||
{
|
||||
if(sub_protocol==H8_3D)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no %= H8_3D_RF_NUM_CHANNELS;
|
||||
}
|
||||
else // CG023 and YD829
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency_no);
|
||||
}
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency_no);
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WritePayload(packet, sub_protocol==H8_3D ? H8_3D_PACKET_SIZE:CG023_PACKET_SIZE);
|
||||
XN297_WritePayload(packet, CG023_PACKET_SIZE);
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
void CG023_init()
|
||||
static void __attribute__((unused)) CG023_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
if(sub_protocol==H8_3D)
|
||||
XN297_SetTXAddr((uint8_t *)"\xC4\x57\x09\x65\x21", 5);
|
||||
else // CG023 and YD829
|
||||
XN297_SetTXAddr((uint8_t *)"\x26\xA8\x67\x35\xCC", 5);
|
||||
XN297_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_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
uint16_t CG023_callback()
|
||||
{
|
||||
switch (phase)
|
||||
{
|
||||
case CG023_BIND:
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
phase = CG023_DATA;
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
CG023_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
break;
|
||||
case CG023_DATA:
|
||||
CG023_send_packet(0);
|
||||
break;
|
||||
}
|
||||
if(sub_protocol==CG023)
|
||||
return CG023_PACKET_PERIOD;
|
||||
if(IS_BIND_DONE)
|
||||
CG023_send_packet(0);
|
||||
else
|
||||
if(sub_protocol==YD829)
|
||||
return YD829_PACKET_PERIOD;
|
||||
return H8_3D_PACKET_PERIOD;
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
BIND_DONE;
|
||||
else
|
||||
{
|
||||
CG023_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
void CG023_initialize_txid()
|
||||
static void __attribute__((unused)) CG023_initialize_txid()
|
||||
{
|
||||
if(sub_protocol==H8_3D)
|
||||
{
|
||||
rx_tx_addr[0] = 0xa0 + (rx_tx_addr[0] % 0x10);
|
||||
rx_tx_addr[1] = 0xb0 + (rx_tx_addr[1] % 0x20);
|
||||
rx_tx_addr[2] = rx_tx_addr[2] % 0x20;
|
||||
rx_tx_addr[3] = rx_tx_addr[3] % 0x11;
|
||||
|
||||
hopping_frequency[0] = 0x06 + (((rx_tx_addr[0]>>8) + (rx_tx_addr[0]&0x0f)) % 0x0f);
|
||||
hopping_frequency[1] = 0x15 + (((rx_tx_addr[1]>>8) + (rx_tx_addr[1]&0x0f)) % 0x0f);
|
||||
hopping_frequency[2] = 0x24 + (((rx_tx_addr[2]>>8) + (rx_tx_addr[2]&0x0f)) % 0x0f);
|
||||
hopping_frequency[3] = 0x33 + (((rx_tx_addr[3]>>8) + (rx_tx_addr[3]&0x0f)) % 0x0f);
|
||||
}
|
||||
else
|
||||
{ // CG023 and YD829
|
||||
rx_tx_addr[0]= 0x80 | (rx_tx_addr[0] % 0x40);
|
||||
if( rx_tx_addr[0] == 0xAA) // avoid using same freq for bind and data channel
|
||||
rx_tx_addr[0] ++;
|
||||
hopping_frequency_no = rx_tx_addr[0] - 0x7D; // rf channel for data packets
|
||||
}
|
||||
rx_tx_addr[0]= 0x80 | (rx_tx_addr[0] % 0x40);
|
||||
if( rx_tx_addr[0] == 0xAA) // avoid using same freq for bind and data channel
|
||||
rx_tx_addr[0] ++;
|
||||
hopping_frequency_no = rx_tx_addr[0] - 0x7D; // rf channel for data packets
|
||||
}
|
||||
|
||||
uint16_t initCG023(void)
|
||||
@@ -282,13 +166,11 @@ uint16_t initCG023(void)
|
||||
bind_counter = CG023_BIND_COUNT;
|
||||
CG023_initialize_txid();
|
||||
CG023_init();
|
||||
phase=CG023_BIND;
|
||||
if(sub_protocol==CG023)
|
||||
return CG023_INITIAL_WAIT+CG023_PACKET_PERIOD;
|
||||
else
|
||||
if(sub_protocol==YD829)
|
||||
return CG023_INITIAL_WAIT+YD829_PACKET_PERIOD;
|
||||
return CG023_INITIAL_WAIT+H8_3D_PACKET_PERIOD;
|
||||
packet_period=CG023_PACKET_PERIOD;
|
||||
else // YD829
|
||||
packet_period=YD829_PACKET_PERIOD;
|
||||
return CG023_INITIAL_WAIT+YD829_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,19 +12,21 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// compatible with Cheerson CX-10 blue & newer red pcb, CX-10A, CX11, CX-10 green pcb, DM007, Floureon FX-10, CX-Stars
|
||||
// compatible with Cheerson CX-10 blue & newer red pcb, CX-10A, CX11, CX-10 green pcb, DM007, Floureon FX-10, JXD 509 (Q282), Q222, Q242 and Q282
|
||||
// Last sync with hexfet new_protocols/cx10_nrf24l01.c dated 2015-11-26
|
||||
|
||||
#if defined(CX10_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#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 CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
|
||||
#define CX10A_PACKET_PERIOD 6000
|
||||
#define CX10_BIND_COUNT 4360 // 6 seconds
|
||||
#define CX10_PACKET_SIZE 15
|
||||
#define CX10A_PACKET_SIZE 19 // CX10 blue board packets have 19-byte payload
|
||||
#define Q2X2_PACKET_SIZE 21
|
||||
#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
|
||||
#define CX10A_PACKET_PERIOD 6000
|
||||
|
||||
#define INITIAL_WAIT 500
|
||||
#define CX10_INITIAL_WAIT 500
|
||||
|
||||
// flags
|
||||
#define CX10_FLAG_FLIP 0x10 // goes to rudder channel
|
||||
@@ -35,17 +37,16 @@
|
||||
#define CX10_FLAG_SNAPSHOT 0x04
|
||||
|
||||
// frequency channel management
|
||||
#define RF_BIND_CHANNEL 0x02
|
||||
#define NUM_RF_CHANNELS 4
|
||||
#define CX10_RF_BIND_CHANNEL 0x02
|
||||
#define CX10_NUM_RF_CHANNELS 4
|
||||
|
||||
enum {
|
||||
CX10_INIT1 = 0,
|
||||
CX10_BIND1,
|
||||
CX10_BIND1 = 0,
|
||||
CX10_BIND2,
|
||||
CX10_DATA
|
||||
};
|
||||
|
||||
void CX10_Write_Packet(uint8_t bind)
|
||||
static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind)
|
||||
{
|
||||
uint8_t offset = 0;
|
||||
if(sub_protocol == CX10_BLUE)
|
||||
@@ -56,52 +57,109 @@ void CX10_Write_Packet(uint8_t bind)
|
||||
packet[3] = rx_tx_addr[2];
|
||||
packet[4] = rx_tx_addr[3];
|
||||
// packet[5] to [8] (aircraft id) is filled during bind for blue board
|
||||
packet[5+offset] = lowByte(Servo_data[AILERON]);
|
||||
packet[6+offset]= highByte(Servo_data[AILERON]);
|
||||
packet[7+offset]= lowByte(Servo_data[ELEVATOR]);
|
||||
packet[8+offset]= highByte(Servo_data[ELEVATOR]);
|
||||
packet[9+offset]= lowByte(Servo_data[THROTTLE]);
|
||||
packet[10+offset]= highByte(Servo_data[THROTTLE]);
|
||||
packet[11+offset]= lowByte(Servo_data[RUDDER]);
|
||||
packet[12+offset]= highByte(Servo_data[RUDDER]);
|
||||
|
||||
uint16_t aileron= convert_channel_16b_limit(AILERON ,1000,2000);
|
||||
uint16_t elevator=convert_channel_16b_limit(ELEVATOR,2000,1000);
|
||||
uint16_t throttle=convert_channel_16b_limit(THROTTLE,1000,2000);
|
||||
uint16_t rudder= convert_channel_16b_limit(RUDDER ,2000,1000);
|
||||
// Channel 5 - flip flag
|
||||
if(Servo_data[AUX1] > PPM_SWITCH)
|
||||
packet[12+offset] |= CX10_FLAG_FLIP; // flip flag
|
||||
packet[12+offset] = GET_FLAG(CH5_SW,CX10_FLAG_FLIP); // flip flag applied on rudder
|
||||
|
||||
// Channel 6 - mode
|
||||
if(Servo_data[AUX2] > PPM_MAX_COMMAND) // mode 3 / headless on CX-10A
|
||||
packet[13+offset] = 0x02;
|
||||
// Channel 6 - rate mode is 2 lsb of packet 13
|
||||
if(CH6_SW) // rate 3 / headless on CX-10A
|
||||
flags = 0x02;
|
||||
else
|
||||
if(Servo_data[AUX2] < PPM_MIN_COMMAND)
|
||||
packet[13+offset] = 0x00; // mode 1
|
||||
if(Channel_data[CH6] < CHANNEL_MIN_COMMAND)
|
||||
flags = 0x00; // rate 1
|
||||
else
|
||||
packet[13+offset] = 0x01; // mode 2
|
||||
flags = 0x01; // rate 2
|
||||
uint8_t flags2=0; // packet 14
|
||||
|
||||
flags=0;
|
||||
if(sub_protocol == DM007)
|
||||
uint8_t video_state=packet[14] & 0x21;
|
||||
switch(sub_protocol)
|
||||
{
|
||||
// Channel 7 - snapshot
|
||||
if(Servo_data[AUX3] > PPM_SWITCH)
|
||||
flags |= CX10_FLAG_SNAPSHOT;
|
||||
// Channel 8 - video
|
||||
if(Servo_data[AUX4] > PPM_SWITCH)
|
||||
flags |= CX10_FLAG_VIDEO;
|
||||
// Channel 9 - headless
|
||||
if(Servo_data[AUX5] > PPM_SWITCH)
|
||||
packet[13+offset] |= CX10_FLAG_HEADLESS;
|
||||
case CX10_BLUE:
|
||||
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
|
||||
|
||||
if(sub_protocol==F_Q242)
|
||||
{
|
||||
flags=2;
|
||||
flags2|= GET_FLAG(CH7_SW,0x01) // Channel 7 - picture
|
||||
|GET_FLAG(CH8_SW,0x10); // Channel 8 - video
|
||||
packet[17]=0x00;
|
||||
packet[18]=0x00;
|
||||
}
|
||||
else
|
||||
{ // F_Q282 & F_Q222
|
||||
flags=3; // expert
|
||||
if(CH8_SW) // Channel 8 - F_Q282 video / F_Q222 Module 1
|
||||
{
|
||||
if (!(video_state & 0x20)) video_state ^= 0x21;
|
||||
}
|
||||
else
|
||||
if (video_state & 0x20) video_state &= 0x01;
|
||||
flags2 |= video_state
|
||||
|GET_FLAG(CH7_SW,0x10); // Channel 7 - F_Q282 picture / F_Q222 Module 2
|
||||
}
|
||||
if(CH10_SW) flags |=0x80; // Channel 10 - RTH
|
||||
break;
|
||||
case DM007:
|
||||
aileron = 3000 - aileron;
|
||||
//FLIP|MODE|PICTURE|VIDEO|HEADLESS
|
||||
flags2= GET_FLAG(CH7_SW,CX10_FLAG_SNAPSHOT) // Channel 7 - picture
|
||||
|GET_FLAG(CH8_SW,CX10_FLAG_VIDEO); // Channel 8 - video
|
||||
if(CH9_SW) flags |= CX10_FLAG_HEADLESS; // Channel 9 - headless
|
||||
break;
|
||||
case JC3015_2:
|
||||
aileron = 3000 - aileron;
|
||||
elevator = 3000 - elevator;
|
||||
//FLIP|MODE|LED|DFLIP
|
||||
if(CH8_SW) packet[12] &= ~CX10_FLAG_FLIP;
|
||||
case JC3015_1:
|
||||
//FLIP|MODE|PICTURE|VIDEO
|
||||
flags2= GET_FLAG(CH7_SW,_BV(3)) // Channel 7
|
||||
|GET_FLAG(CH8_SW,_BV(4)); // Channel 8
|
||||
break;
|
||||
case MK33041:
|
||||
elevator = 3000 - elevator;
|
||||
//FLIP|MODE|PICTURE|VIDEO|HEADLESS|RTH
|
||||
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[14+offset] = flags;
|
||||
|
||||
packet[5+offset] = lowByte(aileron);
|
||||
packet[6+offset] = highByte(aileron);
|
||||
packet[7+offset] = lowByte(elevator);
|
||||
packet[8+offset] = highByte(elevator);
|
||||
packet[9+offset] = lowByte(throttle);
|
||||
packet[10+offset]= highByte(throttle);
|
||||
packet[11+offset]= lowByte(rudder);
|
||||
packet[12+offset]|= highByte(rudder);
|
||||
packet[13+offset]=flags;
|
||||
packet[14+offset]=flags2;
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
if (bind)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, CX10_RF_BIND_CHANNEL);
|
||||
else
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no %= NUM_RF_CHANNELS;
|
||||
hopping_frequency_no %= CX10_NUM_RF_CHANNELS;
|
||||
}
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
@@ -111,7 +169,7 @@ void CX10_Write_Packet(uint8_t bind)
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
void CX10_init()
|
||||
static void __attribute__((unused)) CX10_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
@@ -123,16 +181,14 @@ void CX10_init()
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // rx pipe 0 (used only for blue board)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, CX10_RF_BIND_CHANNEL);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
uint16_t CX10_callback() {
|
||||
uint16_t CX10_callback()
|
||||
{
|
||||
switch (phase) {
|
||||
case CX10_INIT1:
|
||||
phase = bind_phase;
|
||||
break;
|
||||
case CX10_BIND1:
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
@@ -146,25 +202,30 @@ uint16_t CX10_callback() {
|
||||
}
|
||||
break;
|
||||
case CX10_BIND2:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR))
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready
|
||||
XN297_ReadPayload(packet, packet_length);
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
if(packet[9] == 1)
|
||||
phase = CX10_BIND1;
|
||||
{
|
||||
BIND_DONE;
|
||||
phase = CX10_DATA;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// switch to TX mode
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
CX10_Write_Packet(1);
|
||||
delay(1); // used to be 300µs in deviation but not working so 1ms now
|
||||
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_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
|
||||
}
|
||||
break;
|
||||
case CX10_DATA:
|
||||
@@ -174,41 +235,55 @@ uint16_t CX10_callback() {
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
void initialize_txid()
|
||||
static void __attribute__((unused)) CX10_initialize_txid()
|
||||
{
|
||||
rx_tx_addr[1]%= 0x30;
|
||||
hopping_frequency[0] = 0x03 + (rx_tx_addr[0] & 0x0F);
|
||||
hopping_frequency[1] = 0x16 + (rx_tx_addr[0] >> 4);
|
||||
hopping_frequency[2] = 0x2D + (rx_tx_addr[1] & 0x0F);
|
||||
hopping_frequency[3] = 0x40 + (rx_tx_addr[1] >> 4);
|
||||
if(sub_protocol&0x08) //F_Q2X2 protocols
|
||||
{
|
||||
uint8_t offset=0; //F_Q282
|
||||
if(sub_protocol==F_Q242)
|
||||
offset=2;
|
||||
if(sub_protocol==F_Q222)
|
||||
offset=3;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
hopping_frequency[i]=0x46+2*i+offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
hopping_frequency[0] = 0x03 + (rx_tx_addr[0] & 0x0F);
|
||||
hopping_frequency[1] = 0x16 + (rx_tx_addr[0] >> 4);
|
||||
hopping_frequency[2] = 0x2D + (rx_tx_addr[1] & 0x0F);
|
||||
hopping_frequency[3] = 0x40 + (rx_tx_addr[1] >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initCX10(void)
|
||||
{
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case CX10_GREEN:
|
||||
case DM007:
|
||||
packet_length = CX10_PACKET_SIZE;
|
||||
packet_period = CX10_PACKET_PERIOD;
|
||||
bind_phase = CX10_BIND1;
|
||||
bind_counter = CX10_BIND_COUNT;
|
||||
break;
|
||||
case CX10_BLUE:
|
||||
packet_length = CX10A_PACKET_SIZE;
|
||||
packet_period = CX10A_PACKET_PERIOD;
|
||||
bind_phase = CX10_BIND2;
|
||||
bind_counter=0;
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
packet[5+i] = 0xff; // clear aircraft id
|
||||
packet[9] = 0;
|
||||
break;
|
||||
}
|
||||
initialize_txid();
|
||||
CX10_init();
|
||||
phase = CX10_INIT1;
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
return INITIAL_WAIT;
|
||||
if(sub_protocol==CX10_BLUE)
|
||||
{
|
||||
packet_length = CX10A_PACKET_SIZE;
|
||||
packet_period = CX10A_PACKET_PERIOD;
|
||||
|
||||
phase = CX10_BIND2;
|
||||
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
packet[5+i] = 0xff; // clear aircraft id
|
||||
packet[9] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sub_protocol&0x08) //F_Q2X2 protocols
|
||||
packet_length = Q2X2_PACKET_SIZE;
|
||||
else
|
||||
packet_length = CX10_PACKET_SIZE;
|
||||
packet_period = CX10_PACKET_PERIOD;
|
||||
phase = CX10_BIND1;
|
||||
bind_counter = CX10_BIND_COUNT;
|
||||
}
|
||||
CX10_initialize_txid();
|
||||
CX10_init();
|
||||
return CX10_INITIAL_WAIT+packet_period;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,72 +12,36 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef CYRF6936_INSTALLED
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
void cyrf_spi_write(uint8_t command)
|
||||
{
|
||||
uint8_t n=8;
|
||||
SCK_off;//SCK start low
|
||||
SDI_off;
|
||||
while(n--) {
|
||||
if(command&0x80)
|
||||
SDI_on;
|
||||
else
|
||||
SDI_off;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
command = command << 1;
|
||||
}
|
||||
SDI_on;
|
||||
}
|
||||
|
||||
uint8_t cyrf_spi_read()
|
||||
{
|
||||
uint8_t result;
|
||||
uint8_t i;
|
||||
result=0;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
if(SDO_1) ///
|
||||
result=(result<<1)|0x01;
|
||||
else
|
||||
result=result<<1;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
NOP();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CYRF_WriteRegister(uint8_t address, uint8_t data)
|
||||
{
|
||||
CYRF_CSN_off;
|
||||
cyrf_spi_write(0x80 | address);
|
||||
cyrf_spi_write(data);
|
||||
SPI_Write(0x80 | address);
|
||||
SPI_Write(data);
|
||||
CYRF_CSN_on;
|
||||
}
|
||||
|
||||
void CYRF_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8_t length)
|
||||
static void CYRF_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8_t length)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
CYRF_CSN_off;
|
||||
cyrf_spi_write(0x80 | address);
|
||||
SPI_Write(0x80 | address);
|
||||
for(i = 0; i < length; i++)
|
||||
cyrf_spi_write(data[i]);
|
||||
SPI_Write(data[i]);
|
||||
CYRF_CSN_on;
|
||||
}
|
||||
|
||||
void CYRF_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length)
|
||||
static void CYRF_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
CYRF_CSN_off;
|
||||
cyrf_spi_write(address);
|
||||
SPI_Write(address);
|
||||
for(i = 0; i < length; i++)
|
||||
data[i] = cyrf_spi_read();
|
||||
data[i] = SPI_Read();
|
||||
CYRF_CSN_on;
|
||||
}
|
||||
|
||||
@@ -85,8 +49,8 @@ uint8_t CYRF_ReadRegister(uint8_t address)
|
||||
{
|
||||
uint8_t data;
|
||||
CYRF_CSN_off;
|
||||
cyrf_spi_write(address);
|
||||
data = cyrf_spi_read();
|
||||
SPI_Write(address);
|
||||
data = SPI_Read();
|
||||
CYRF_CSN_on;
|
||||
return data;
|
||||
}
|
||||
@@ -94,17 +58,19 @@ uint8_t CYRF_ReadRegister(uint8_t address)
|
||||
|
||||
uint8_t CYRF_Reset()
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x01);//software reset
|
||||
_delay_us(200);//
|
||||
// RS_HI;
|
||||
// _delay_us(100);
|
||||
// RS_LO;
|
||||
// _delay_us(100);
|
||||
CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); //Enable XOUT as GPIO
|
||||
CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); //Enable PACTL as GPIO
|
||||
#ifdef CYRF_RST_HI
|
||||
CYRF_RST_HI; //Hardware reset
|
||||
delayMicroseconds(100);
|
||||
CYRF_RST_LO;
|
||||
delayMicroseconds(100);
|
||||
#endif
|
||||
CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x01); //Software reset
|
||||
delayMicroseconds(200);
|
||||
CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); //Enable XOUT as GPIO
|
||||
CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); //Enable PACTL as GPIO
|
||||
CYRF_SetTxRxMode(TXRX_OFF);
|
||||
//Verify the CYRD chip is responding
|
||||
return (CYRF_ReadRegister(CYRF_10_FRAMING_CFG) == 0xa5);//return if reset
|
||||
//Verify the CYRF chip is responding
|
||||
return (CYRF_ReadRegister(CYRF_10_FRAMING_CFG) == 0xa5);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -112,6 +78,7 @@ uint8_t CYRF_Reset()
|
||||
*/
|
||||
void CYRF_GetMfgData(uint8_t data[])
|
||||
{
|
||||
#ifndef FORCE_CYRF_ID
|
||||
/* Fuses power on */
|
||||
CYRF_WriteRegister(CYRF_25_MFG_ID, 0xFF);
|
||||
|
||||
@@ -119,6 +86,9 @@ void CYRF_GetMfgData(uint8_t data[])
|
||||
|
||||
/* Fuses power off */
|
||||
CYRF_WriteRegister(CYRF_25_MFG_ID, 0x00);
|
||||
#else
|
||||
memcpy(data,FORCE_CYRF_ID,6);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -128,17 +98,25 @@ void CYRF_SetTxRxMode(uint8_t mode)
|
||||
{
|
||||
if(mode==TXRX_OFF)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // 4=IDLE, 8=TX, C=RX
|
||||
if(protocol!=PROTO_WFLY)
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // 4=IDLE, 8=TX, C=RX
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x00); // XOUT=0 PACTL=0
|
||||
}
|
||||
else
|
||||
{
|
||||
//Set the post tx/rx state
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, mode == TX_EN ? 0x28 : 0x2C); // 4=IDLE, 8=TX, C=RX
|
||||
if(protocol!=PROTO_WFLY)
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, mode == TX_EN ? 0x28 : 0x2C); // 4=IDLE, 8=TX, C=RX
|
||||
if(mode == TX_EN)
|
||||
#ifdef ORANGE_TX_BLUE
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x20); // XOUT=1, PACTL=0
|
||||
else
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x80); // XOUT=0, PACTL=1
|
||||
#else
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x80); // XOUT=1, PACTL=0
|
||||
else
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x20); // XOUT=0, PACTL=1
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -149,20 +127,31 @@ void CYRF_ConfigRFChannel(uint8_t ch)
|
||||
CYRF_WriteRegister(CYRF_00_CHANNEL,ch);
|
||||
}
|
||||
|
||||
void CYRF_SetPower_Value(uint8_t power)
|
||||
/*
|
||||
static void CYRF_SetPower_Value(uint8_t power)
|
||||
{
|
||||
uint8_t val = CYRF_ReadRegister(CYRF_03_TX_CFG) & 0xF8;
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, val | (power & 0x07));
|
||||
}
|
||||
*/
|
||||
|
||||
void CYRF_SetPower(uint8_t val)
|
||||
{
|
||||
uint8_t power=CYRF_BIND_POWER;
|
||||
if(IS_BIND_DONE_on)
|
||||
power=IS_POWER_FLAG_on?CYRF_HIGH_POWER:CYRF_LOW_POWER;
|
||||
if(IS_BIND_DONE)
|
||||
#ifdef CYRF6936_ENABLE_LOW_POWER
|
||||
power=IS_POWER_FLAG_on?CYRF_HIGH_POWER:CYRF_LOW_POWER;
|
||||
#else
|
||||
power=CYRF_HIGH_POWER;
|
||||
#endif
|
||||
if(IS_RANGE_FLAG_on)
|
||||
power=CYRF_RANGE_POWER;
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, val | power);
|
||||
power|=val;
|
||||
if(prev_power != power)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG,power);
|
||||
prev_power=power;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -194,36 +183,31 @@ void CYRF_ConfigDataCode(const uint8_t *datacodes, uint8_t len)
|
||||
void CYRF_WritePreamble(uint32_t preamble)
|
||||
{
|
||||
CYRF_CSN_off;
|
||||
cyrf_spi_write(0x80 | 0x24);
|
||||
cyrf_spi_write(preamble & 0xff);
|
||||
cyrf_spi_write((preamble >> 8) & 0xff);
|
||||
cyrf_spi_write((preamble >> 16) & 0xff);
|
||||
SPI_Write(0x80 | 0x24);
|
||||
SPI_Write(preamble & 0xff);
|
||||
SPI_Write((preamble >> 8) & 0xff);
|
||||
SPI_Write((preamble >> 16) & 0xff);
|
||||
CYRF_CSN_on;
|
||||
}
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void CYRF_StartReceive()
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL,0x87);
|
||||
}
|
||||
|
||||
void CYRF_ReadDataPacket(uint8_t dpbuffer[])
|
||||
/*static void CYRF_ReadDataPacket(uint8_t dpbuffer[])
|
||||
{
|
||||
CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, 0x10);
|
||||
}
|
||||
|
||||
*/
|
||||
void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length)
|
||||
{
|
||||
ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length);
|
||||
CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length);
|
||||
}
|
||||
|
||||
void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len)
|
||||
static void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_01_TX_LENGTH, len);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x43); // 0x40
|
||||
CYRF_WriteRegisterMulti(CYRF_20_TX_BUFFER, dpbuffer, len);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0xBF);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x83); // 0xBF
|
||||
}
|
||||
|
||||
void CYRF_WriteDataPacket(const uint8_t dpbuffer[])
|
||||
@@ -231,7 +215,7 @@ void CYRF_WriteDataPacket(const uint8_t dpbuffer[])
|
||||
CYRF_WriteDataPacketLen(dpbuffer, 16);
|
||||
}
|
||||
|
||||
uint8_t CYRF_ReadRSSI(uint8_t dodummyread)
|
||||
/*static uint8_t CYRF_ReadRSSI(uint8_t dodummyread)
|
||||
{
|
||||
uint8_t result;
|
||||
if(dodummyread)
|
||||
@@ -241,7 +225,7 @@ uint8_t CYRF_ReadRSSI(uint8_t dodummyread)
|
||||
result = CYRF_ReadRegister(CYRF_13_RSSI);
|
||||
return (result & 0x0F);
|
||||
}
|
||||
|
||||
*/
|
||||
//NOTE: This routine will reset the CRC Seed
|
||||
void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uint8_t min, uint8_t max)
|
||||
{
|
||||
@@ -260,14 +244,18 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin
|
||||
CYRF_ConfigCRCSeed(0x0000);
|
||||
CYRF_SetTxRxMode(RX_EN);
|
||||
//Wait for pre-amp to switch from send to receive
|
||||
_delay_us(1000);
|
||||
delayMilliseconds(1);
|
||||
for(i = 0; i < NUM_FREQ; i++)
|
||||
{
|
||||
CYRF_ConfigRFChannel(i);
|
||||
CYRF_ReadRegister(CYRF_13_RSSI);
|
||||
CYRF_StartReceive();
|
||||
_delay_us(10);
|
||||
rssi[i] = CYRF_ReadRegister(CYRF_13_RSSI);
|
||||
delayMicroseconds(270); //slow channel require 270usec for synthesizer to settle
|
||||
if( !(CYRF_ReadRegister(CYRF_05_RX_CTRL) & 0x80)) {
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80); //Prepare to receive
|
||||
delayMicroseconds(15);
|
||||
CYRF_ReadRegister(CYRF_13_RSSI); //dummy read
|
||||
delayMicroseconds(15); //The conversion can occur as often as once every 12us
|
||||
}
|
||||
rssi[i] = CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
@@ -283,5 +271,42 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin
|
||||
rssi[j] = 0xff;
|
||||
}
|
||||
}
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Clear abort RX
|
||||
}
|
||||
|
||||
#if defined(DEVO_CYRF6936_INO) || defined(J6PRO_CYRF6936_INO)
|
||||
const uint8_t PROGMEM DEVO_j6pro_sopcodes[][8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
{0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91},
|
||||
{0x9B, 0xC5, 0xA1, 0x0F, 0xAD, 0x39, 0xA2, 0x0F},
|
||||
{0xEF, 0x64, 0xB0, 0x2A, 0xD2, 0x8F, 0xB1, 0x2A},
|
||||
{0x66, 0xCD, 0x7C, 0x50, 0xDD, 0x26, 0x7C, 0x50},
|
||||
{0x5C, 0xE1, 0xF6, 0x44, 0xAD, 0x16, 0xF6, 0x44},
|
||||
{0x5A, 0xCC, 0xAE, 0x46, 0xB6, 0x31, 0xAE, 0x46},
|
||||
{0xA1, 0x78, 0xDC, 0x3C, 0x9E, 0x82, 0xDC, 0x3C},
|
||||
{0xB9, 0x8E, 0x19, 0x74, 0x6F, 0x65, 0x18, 0x74},
|
||||
{0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49},
|
||||
{0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72},
|
||||
#if defined(J6PRO_CYRF6936_INO)
|
||||
{0x82, 0xC7, 0x90, 0x36, 0x21, 0x03, 0xFF, 0x17},
|
||||
{0xE2, 0xF8, 0xCC, 0x91, 0x3C, 0x37, 0xCC, 0x91}, //Note: the '03' was '9E' in the Cypress recommended table
|
||||
{0xAD, 0x39, 0xA2, 0x0F, 0x9B, 0xC5, 0xA1, 0x0F}, //The following are the same as the 1st 8 above,
|
||||
{0xD2, 0x8F, 0xB1, 0x2A, 0xEF, 0x64, 0xB0, 0x2A}, //but with the upper and lower word swapped
|
||||
{0xDD, 0x26, 0x7C, 0x50, 0x66, 0xCD, 0x7C, 0x50},
|
||||
{0xAD, 0x16, 0xF6, 0x44, 0x5C, 0xE1, 0xF6, 0x44},
|
||||
{0xB6, 0x31, 0xAE, 0x46, 0x5A, 0xCC, 0xAE, 0x46},
|
||||
{0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C},
|
||||
{0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74},
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
static void __attribute__((unused)) CYRF_PROGMEM_ConfigSOPCode(const uint8_t *data)
|
||||
{
|
||||
uint8_t code[8];
|
||||
for(uint8_t i=0;i<8;i++)
|
||||
code[i]=pgm_read_byte_near(&data[i]);
|
||||
CYRF_ConfigSOPCode(code);
|
||||
}
|
||||
#endif
|
||||
353
Multiprotocol/Common.ino
Normal file
353
Multiprotocol/Common.ino
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
//Convert from percentage to failsafe value
|
||||
#define FAILSAFE_THROTTLE_LOW_VAL (((FAILSAFE_THROTTLE_LOW+125)*1024)/125)
|
||||
#if FAILSAFE_THROTTLE_LOW_VAL <= 0
|
||||
#undef FAILSAFE_THROTTLE_LOW_VAL
|
||||
#define FAILSAFE_THROTTLE_LOW_VAL 1
|
||||
#elif (FAILSAFE_THROTTLE_LOW_VAL) >= 2046
|
||||
#undef FAILSAFE_THROTTLE_LOW_VAL
|
||||
#define FAILSAFE_THROTTLE_LOW_VAL 2046
|
||||
#endif
|
||||
void InitFailsafe()
|
||||
{
|
||||
for(uint8_t i=0;i<NUM_CHN;i++)
|
||||
Failsafe_data[i]=1024;
|
||||
Failsafe_data[THROTTLE]=(uint16_t)FAILSAFE_THROTTLE_LOW_VAL; //1=-125%, 204=-100%
|
||||
FAILSAFE_VALUES_on;
|
||||
#ifdef FAILSAFE_SERIAL_ONLY
|
||||
if(mode_select == MODE_SERIAL)
|
||||
FAILSAFE_VALUES_off;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_PPM
|
||||
void InitPPM()
|
||||
{
|
||||
for(uint8_t i=0;i<NUM_CHN;i++)
|
||||
PPM_data[i]=PPM_MAX_100+PPM_MIN_100;
|
||||
PPM_data[THROTTLE]=PPM_MIN_100*2;
|
||||
}
|
||||
#endif
|
||||
void InitChannel()
|
||||
{
|
||||
for(uint8_t i=0;i<NUM_CHN;i++)
|
||||
Channel_data[i]=1024;
|
||||
#ifdef FAILSAFE_THROTTLE_LOW_VAL
|
||||
Channel_data[THROTTLE]=(uint16_t)FAILSAFE_THROTTLE_LOW_VAL; //0=-125%, 204=-100%
|
||||
#else
|
||||
Channel_data[THROTTLE]=204;
|
||||
#endif
|
||||
}
|
||||
/************************/
|
||||
/** Convert routines **/
|
||||
/************************/
|
||||
// Convert channel 8b with limit and deadband
|
||||
uint8_t convert_channel_8b_limit_deadband(uint8_t num,uint8_t min,uint8_t mid, uint8_t max, uint8_t deadband)
|
||||
{
|
||||
uint16_t val=limit_channel_100(num); // 204<->1844
|
||||
uint16_t db_low=CHANNEL_MID-deadband, db_high=CHANNEL_MID+deadband; // 1024+-deadband
|
||||
if(val>=db_low && val<=db_high)
|
||||
return mid;
|
||||
else if(val<db_low)
|
||||
val=min+(val-CHANNEL_MIN_100)*(mid-min)/(db_low-CHANNEL_MIN_100);
|
||||
else
|
||||
val=mid+(val-db_high)*(max-mid)/(CHANNEL_MAX_100-1-db_high);
|
||||
return val;
|
||||
}
|
||||
|
||||
// Revert a channel and store it
|
||||
void reverse_channel(uint8_t num)
|
||||
{
|
||||
uint16_t val=2048-Channel_data[num];
|
||||
if(val>=2048) val=2047;
|
||||
Channel_data[num]=val;
|
||||
}
|
||||
// Channel value is converted to ppm 860<->2140 -125%<->+125% and 988<->2012 -100%<->+100%
|
||||
uint16_t convert_channel_ppm(uint8_t num)
|
||||
{
|
||||
uint16_t val=Channel_data[num];
|
||||
return (((val<<2)+val)>>3)+860; //value range 860<->2140 -125%<->+125%
|
||||
}
|
||||
// Channel value 100% is converted to 10bit values 0<->1023
|
||||
uint16_t convert_channel_10b(uint8_t num)
|
||||
{
|
||||
uint16_t val=Channel_data[num];
|
||||
val=((val<<2)+val)>>3;
|
||||
if(val<=128) return 0;
|
||||
if(val>=1152) return 1023;
|
||||
return val-128;
|
||||
}
|
||||
// Channel value 100% is converted to 8bit values 0<->255
|
||||
uint8_t convert_channel_8b(uint8_t num)
|
||||
{
|
||||
uint16_t val=Channel_data[num];
|
||||
val=((val<<2)+val)>>5;
|
||||
if(val<=32) return 0;
|
||||
if(val>=288) return 255;
|
||||
return val-32;
|
||||
}
|
||||
|
||||
// Channel value 100% is converted to value scaled
|
||||
int16_t convert_channel_16b_limit(uint8_t num,int16_t min,int16_t max)
|
||||
{
|
||||
int32_t val=limit_channel_100(num); // 204<->1844
|
||||
val=(val-CHANNEL_MIN_100)*(max-min)/(CHANNEL_MAX_100-CHANNEL_MIN_100)+min;
|
||||
return (uint16_t)val;
|
||||
}
|
||||
|
||||
// Channel value -125%<->125% is scaled to 16bit value with no limit
|
||||
int16_t convert_channel_16b_nolimit(uint8_t num, int16_t min, int16_t max)
|
||||
{
|
||||
int32_t val=Channel_data[num]; // 0<->2047
|
||||
val=(val-CHANNEL_MIN_100)*(max-min)/(CHANNEL_MAX_100-CHANNEL_MIN_100)+min;
|
||||
return (uint16_t)val;
|
||||
}
|
||||
|
||||
// Channel value is converted sign + magnitude 8bit values
|
||||
uint8_t convert_channel_s8b(uint8_t num)
|
||||
{
|
||||
uint8_t ch;
|
||||
ch = convert_channel_8b(num);
|
||||
return (ch < 128 ? 127-ch : ch);
|
||||
}
|
||||
|
||||
// Channel value is limited to 100%
|
||||
uint16_t limit_channel_100(uint8_t num)
|
||||
{
|
||||
if(Channel_data[num]>=CHANNEL_MAX_100)
|
||||
return CHANNEL_MAX_100;
|
||||
if (Channel_data[num]<=CHANNEL_MIN_100)
|
||||
return CHANNEL_MIN_100;
|
||||
return Channel_data[num];
|
||||
}
|
||||
|
||||
// Channel value is converted for HK310
|
||||
void convert_channel_HK310(uint8_t num, uint8_t *low, uint8_t *high)
|
||||
{
|
||||
uint16_t temp=0xFFFF-(3440+((Channel_data[num]*5)>>1))/3;
|
||||
*low=(uint8_t)(temp&0xFF);
|
||||
*high=(uint8_t)(temp>>8);
|
||||
}
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
// Failsafe value is converted for HK310
|
||||
void convert_failsafe_HK310(uint8_t num, uint8_t *low, uint8_t *high)
|
||||
{
|
||||
uint16_t temp=0xFFFF-(3440+((Failsafe_data[num]*5)>>1))/3;
|
||||
*low=(uint8_t)(temp&0xFF);
|
||||
*high=(uint8_t)(temp>>8);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Channel value for FrSky (PPM is multiplied by 1.5)
|
||||
uint16_t convert_channel_frsky(uint8_t num)
|
||||
{
|
||||
uint16_t val=Channel_data[num];
|
||||
return ((val*15)>>4)+1290;
|
||||
}
|
||||
|
||||
/******************************/
|
||||
/** FrSky D and X routines **/
|
||||
/******************************/
|
||||
#if defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO)
|
||||
enum {
|
||||
FRSKY_BIND = 0,
|
||||
FRSKY_BIND_DONE = 1000,
|
||||
FRSKY_DATA1,
|
||||
FRSKY_DATA2,
|
||||
FRSKY_DATA3,
|
||||
FRSKY_DATA4,
|
||||
FRSKY_DATA5
|
||||
};
|
||||
|
||||
void Frsky_init_hop(void)
|
||||
{
|
||||
uint8_t val;
|
||||
uint8_t channel = rx_tx_addr[0]&0x07;
|
||||
uint8_t channel_spacing = rx_tx_addr[1];
|
||||
//Filter bad tables
|
||||
if(channel_spacing<0x02) channel_spacing+=0x02;
|
||||
if(channel_spacing>0xE9) channel_spacing-=0xE7;
|
||||
if(channel_spacing%0x2F==0) channel_spacing++;
|
||||
|
||||
hopping_frequency[0]=channel;
|
||||
for(uint8_t i=1;i<50;i++)
|
||||
{
|
||||
channel=(channel+channel_spacing) % 0xEB;
|
||||
val=channel;
|
||||
if((val==0x00) || (val==0x5A) || (val==0xDC))
|
||||
val++;
|
||||
hopping_frequency[i]=i>46?0:val;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/******************************/
|
||||
/** FrSky V, D and X routines **/
|
||||
/******************************/
|
||||
#if defined(FRSKYV_CC2500_INO) || defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO)
|
||||
const PROGMEM uint8_t FRSKY_common_startreg_cc2500_conf[]= {
|
||||
CC2500_02_IOCFG0 ,
|
||||
CC2500_00_IOCFG2 ,
|
||||
CC2500_17_MCSM1 ,
|
||||
CC2500_18_MCSM0 ,
|
||||
CC2500_06_PKTLEN ,
|
||||
CC2500_07_PKTCTRL1 ,
|
||||
CC2500_08_PKTCTRL0 ,
|
||||
CC2500_3E_PATABLE ,
|
||||
CC2500_0B_FSCTRL1 ,
|
||||
CC2500_0C_FSCTRL0 , // replaced by option value
|
||||
CC2500_0D_FREQ2 ,
|
||||
CC2500_0E_FREQ1 ,
|
||||
CC2500_0F_FREQ0 ,
|
||||
CC2500_10_MDMCFG4 ,
|
||||
CC2500_11_MDMCFG3 ,
|
||||
CC2500_12_MDMCFG2 ,
|
||||
CC2500_13_MDMCFG1 ,
|
||||
CC2500_14_MDMCFG0 ,
|
||||
CC2500_15_DEVIATN };
|
||||
|
||||
#if defined(FRSKYV_CC2500_INO)
|
||||
const PROGMEM uint8_t FRSKYV_cc2500_conf[]= {
|
||||
/*02_IOCFG0*/ 0x06 ,
|
||||
/*00_IOCFG2*/ 0x06 ,
|
||||
/*17_MCSM1*/ 0x0c ,
|
||||
/*18_MCSM0*/ 0x18 ,
|
||||
/*06_PKTLEN*/ 0xff ,
|
||||
/*07_PKTCTRL1*/ 0x04 ,
|
||||
/*08_PKTCTRL0*/ 0x05 ,
|
||||
/*3E_PATABLE*/ 0xfe ,
|
||||
/*0B_FSCTRL1*/ 0x08 ,
|
||||
/*0C_FSCTRL0*/ 0x00 ,
|
||||
/*0D_FREQ2*/ 0x5c ,
|
||||
/*0E_FREQ1*/ 0x58 ,
|
||||
/*0F_FREQ0*/ 0x9d ,
|
||||
/*10_MDMCFG4*/ 0xAA ,
|
||||
/*11_MDMCFG3*/ 0x10 ,
|
||||
/*12_MDMCFG2*/ 0x93 ,
|
||||
/*13_MDMCFG1*/ 0x23 ,
|
||||
/*14_MDMCFG0*/ 0x7a ,
|
||||
/*15_DEVIATN*/ 0x41 };
|
||||
#endif
|
||||
|
||||
#if defined(FRSKYD_CC2500_INO)
|
||||
const PROGMEM uint8_t FRSKYD_cc2500_conf[]= {
|
||||
/*02_IOCFG0*/ 0x06 ,
|
||||
/*00_IOCFG2*/ 0x06 ,
|
||||
/*17_MCSM1*/ 0x0c ,
|
||||
/*18_MCSM0*/ 0x18 ,
|
||||
/*06_PKTLEN*/ 0x19 ,
|
||||
/*07_PKTCTRL1*/ 0x04 ,
|
||||
/*08_PKTCTRL0*/ 0x05 ,
|
||||
/*3E_PATABLE*/ 0xff ,
|
||||
/*0B_FSCTRL1*/ 0x08 ,
|
||||
/*0C_FSCTRL0*/ 0x00 ,
|
||||
/*0D_FREQ2*/ 0x5c ,
|
||||
/*0E_FREQ1*/ 0x76 ,
|
||||
/*0F_FREQ0*/ 0x27 ,
|
||||
/*10_MDMCFG4*/ 0xAA ,
|
||||
/*11_MDMCFG3*/ 0x39 ,
|
||||
/*12_MDMCFG2*/ 0x11 ,
|
||||
/*13_MDMCFG1*/ 0x23 ,
|
||||
/*14_MDMCFG0*/ 0x7a ,
|
||||
/*15_DEVIATN*/ 0x42 };
|
||||
#endif
|
||||
|
||||
#if defined(FRSKYX_CC2500_INO)
|
||||
const PROGMEM uint8_t FRSKYX_cc2500_conf[]= {
|
||||
//FRSKYX
|
||||
/*02_IOCFG0*/ 0x06 ,
|
||||
/*00_IOCFG2*/ 0x06 ,
|
||||
/*17_MCSM1*/ 0x0c ,
|
||||
/*18_MCSM0*/ 0x18 ,
|
||||
/*06_PKTLEN*/ 0x1E ,
|
||||
/*07_PKTCTRL1*/ 0x04 ,
|
||||
/*08_PKTCTRL0*/ 0x01 ,
|
||||
/*3E_PATABLE*/ 0xff ,
|
||||
/*0B_FSCTRL1*/ 0x0A ,
|
||||
/*0C_FSCTRL0*/ 0x00 ,
|
||||
/*0D_FREQ2*/ 0x5c ,
|
||||
/*0E_FREQ1*/ 0x76 ,
|
||||
/*0F_FREQ0*/ 0x27 ,
|
||||
/*10_MDMCFG4*/ 0x7B ,
|
||||
/*11_MDMCFG3*/ 0x61 ,
|
||||
/*12_MDMCFG2*/ 0x13 ,
|
||||
/*13_MDMCFG1*/ 0x23 ,
|
||||
/*14_MDMCFG0*/ 0x7a ,
|
||||
/*15_DEVIATN*/ 0x51 };
|
||||
const PROGMEM uint8_t FRSKYXEU_cc2500_conf[]= {
|
||||
/*02_IOCFG0*/ 0x06 ,
|
||||
/*00_IOCFG2*/ 0x06 ,
|
||||
/*17_MCSM1*/ 0x0E ,
|
||||
/*18_MCSM0*/ 0x18 ,
|
||||
/*06_PKTLEN*/ 0x23 ,
|
||||
/*07_PKTCTRL1*/ 0x04 ,
|
||||
/*08_PKTCTRL0*/ 0x01 ,
|
||||
/*3E_PATABLE*/ 0xff ,
|
||||
/*0B_FSCTRL1*/ 0x08 ,
|
||||
/*0C_FSCTRL0*/ 0x00 ,
|
||||
/*0D_FREQ2*/ 0x5c ,
|
||||
/*0E_FREQ1*/ 0x80 ,
|
||||
/*0F_FREQ0*/ 0x00 ,
|
||||
/*10_MDMCFG4*/ 0x7B ,
|
||||
/*11_MDMCFG3*/ 0xF8 ,
|
||||
/*12_MDMCFG2*/ 0x03 ,
|
||||
/*13_MDMCFG1*/ 0x23 ,
|
||||
/*14_MDMCFG0*/ 0x7a ,
|
||||
/*15_DEVIATN*/ 0x53 };
|
||||
#endif
|
||||
|
||||
const PROGMEM uint8_t FRSKY_common_end_cc2500_conf[][2]= {
|
||||
{ CC2500_19_FOCCFG, 0x16 },
|
||||
{ CC2500_1A_BSCFG, 0x6c },
|
||||
{ CC2500_1B_AGCCTRL2, 0x43 },
|
||||
{ CC2500_1C_AGCCTRL1, 0x40 },
|
||||
{ CC2500_1D_AGCCTRL0, 0x91 },
|
||||
{ CC2500_21_FREND1, 0x56 },
|
||||
{ CC2500_22_FREND0, 0x10 },
|
||||
{ CC2500_23_FSCAL3, 0xa9 },
|
||||
{ CC2500_24_FSCAL2, 0x0A },
|
||||
{ CC2500_25_FSCAL1, 0x00 },
|
||||
{ CC2500_26_FSCAL0, 0x11 },
|
||||
{ CC2500_29_FSTEST, 0x59 },
|
||||
{ CC2500_2C_TEST2, 0x88 },
|
||||
{ CC2500_2D_TEST1, 0x31 },
|
||||
{ CC2500_2E_TEST0, 0x0B },
|
||||
{ CC2500_03_FIFOTHR, 0x07 },
|
||||
{ CC2500_09_ADDR, 0x00 } };
|
||||
|
||||
void FRSKY_init_cc2500(const uint8_t *ptr)
|
||||
{
|
||||
for(uint8_t i=0;i<19;i++)
|
||||
{
|
||||
uint8_t reg=pgm_read_byte_near(&FRSKY_common_startreg_cc2500_conf[i]);
|
||||
uint8_t val=pgm_read_byte_near(&ptr[i]);
|
||||
if(reg==CC2500_0C_FSCTRL0)
|
||||
val=option;
|
||||
CC2500_WriteReg(reg,val);
|
||||
}
|
||||
prev_option = option ; // Save option to monitor FSCTRL0 change
|
||||
for(uint8_t i=0;i<17;i++)
|
||||
{
|
||||
uint8_t reg=pgm_read_byte_near(&FRSKY_common_end_cc2500_conf[i][0]);
|
||||
uint8_t val=pgm_read_byte_near(&FRSKY_common_end_cc2500_conf[i][1]);
|
||||
CC2500_WriteReg(reg,val);
|
||||
}
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
CC2500_Strobe(CC2500_SIDLE); // Go to idle...
|
||||
}
|
||||
#endif
|
||||
303
Multiprotocol/Corona_cc2500.ino
Normal file
303
Multiprotocol/Corona_cc2500.ino
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(CORONA_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
//#define CORONA_FORCE_ID
|
||||
|
||||
#define CORONA_RF_NUM_CHANNELS 3
|
||||
#define CORONA_ADDRESS_LENGTH 4
|
||||
#define CORONA_BIND_CHANNEL_V1 0xD1 // also Flydream V3
|
||||
#define CORONA_BIND_CHANNEL_V2 0xB8
|
||||
#define CORONA_COARSE 0x00
|
||||
#define FDV3_BIND_PERIOD 5000
|
||||
#define FDV3_CHANNEL_PERIOD 4000
|
||||
|
||||
const PROGMEM uint8_t CORONA_init_values[] = {
|
||||
/* 00 */ 0x29, 0x2E, 0x06, 0x07, 0xD3, 0x91, 0xFF, 0x04,
|
||||
/* 08 */ 0x05, 0x00, CORONA_BIND_CHANNEL_V1, 0x06, 0x00, 0x5C, 0x4E, 0xC4 + CORONA_COARSE,
|
||||
/* 10 */ 0x5B, 0xF8, 0x03, 0x23, 0xF8, 0x47, 0x07, 0x30,
|
||||
/* 18 */ 0x18, 0x16, 0x6C, 0x43, 0x40, 0x91, 0x87, 0x6B,
|
||||
/* 20 */ 0xF8, 0x56, 0x10, 0xA9, 0x0A, 0x00, 0x11, 0x41,
|
||||
/* 28 */ 0x00, 0x59, 0x7F, 0x3F, 0x81, 0x35, 0x0B
|
||||
};
|
||||
|
||||
uint8_t fdv3_id_send;
|
||||
|
||||
static void __attribute__((unused)) CORONA_rf_init()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
|
||||
for (uint8_t i = 0; i <= 0x2E; ++i)
|
||||
CC2500_WriteReg(i, pgm_read_byte_near(&CORONA_init_values[i]));
|
||||
if(sub_protocol==COR_V2)
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, CORONA_BIND_CHANNEL_V2);
|
||||
CC2500_WriteReg(CC2500_0E_FREQ1, 0x80);
|
||||
CC2500_WriteReg(CC2500_0F_FREQ0, 0x00 + CORONA_COARSE);
|
||||
CC2500_WriteReg(CC2500_15_DEVIATN, 0x50);
|
||||
CC2500_WriteReg(CC2500_17_MCSM1, 0x00);
|
||||
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0x67);
|
||||
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0xFB);
|
||||
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xDC);
|
||||
}
|
||||
else if(sub_protocol==FD_V3)
|
||||
{
|
||||
// Flydream receiver captures have deviation 50, tx captures show 47
|
||||
CC2500_WriteReg(CC2500_15_DEVIATN, 0x50);
|
||||
}
|
||||
|
||||
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
|
||||
CC2500_WriteRegisterMulti(CC2500_3E_PATABLE,(const uint8_t *)"\x08\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 13);
|
||||
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
}
|
||||
|
||||
// Generate id and hopping freq
|
||||
static void __attribute__((unused)) CORONA_init()
|
||||
{
|
||||
#ifdef CORONA_FORCE_ID
|
||||
// Example of ID and channels taken from dumps
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case COR_V1:
|
||||
memcpy((void *)rx_tx_addr,(void *)"\x1F\xFE\x6C\x35",CORONA_ADDRESS_LENGTH);
|
||||
memcpy((void *)hopping_frequency,(void *)"\x17\x0D\x03\x49",CORONA_RF_NUM_CHANNELS+1);
|
||||
break;
|
||||
case COR_V2:
|
||||
memcpy((void *)rx_tx_addr,(void *)"\xFE\xFE\x02\xFB",CORONA_ADDRESS_LENGTH);
|
||||
memcpy((void *)hopping_frequency,(void *)"\x14\x3D\x35",CORONA_RF_NUM_CHANNELS);
|
||||
case FD_V3:
|
||||
memcpy((void *)rx_tx_addr,(void *)"\x02\xFA\x38\x38",CORONA_ADDRESS_LENGTH);
|
||||
memcpy((void *)hopping_frequency,(void *)"\x71\xB9\x30",CORONA_RF_NUM_CHANNELS);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// From dumps channels are anything between 0x00 and 0xC5 on V1.
|
||||
// But 0x00 and 0xB8 should be avoided on V2 since they are used for bind.
|
||||
// Below code make sure channels are between 0x02 and 0xA0, spaced with
|
||||
// a minimum of 2 and not ordered (RX only use the 1st channel unless there is an issue).
|
||||
// Extra hopping frequency used for Flydream V3 id packets.
|
||||
uint8_t order=rx_tx_addr[3]&0x03;
|
||||
for(uint8_t i=0; i<CORONA_RF_NUM_CHANNELS+1; i++)
|
||||
hopping_frequency[i^order]=2+rx_tx_addr[3-i]%39+(i<<5)+(i<<3);
|
||||
|
||||
if(sub_protocol!=FD_V3)
|
||||
{
|
||||
// ID looks random but on the 15 V1 dumps they all show the same odd/even rule
|
||||
if(rx_tx_addr[3]&0x01)
|
||||
{ // If [3] is odd then [0] is odd and [2] is even
|
||||
rx_tx_addr[0]|=0x01;
|
||||
rx_tx_addr[2]&=0xFE;
|
||||
}
|
||||
else
|
||||
{ // If [3] is even then [0] is even and [2] is odd
|
||||
rx_tx_addr[0]&=0xFE;
|
||||
rx_tx_addr[2]|=0x01;
|
||||
}
|
||||
rx_tx_addr[1]=0xFE; // Always FE in the dumps of V1 and V2
|
||||
}
|
||||
else
|
||||
{
|
||||
rx_tx_addr[1]=0xFA; // Always FA for Flydream V3
|
||||
rx_tx_addr[3]=hopping_frequency[CORONA_RF_NUM_CHANNELS]; // channel used for id/freq packets
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint16_t __attribute__((unused)) CORONA_build_bind_pkt()
|
||||
{
|
||||
if(sub_protocol==COR_V1)
|
||||
{ // V1
|
||||
if(bind_counter&1)
|
||||
{ // Send TX ID
|
||||
packet[0]=0x04; // 5 bytes to follow
|
||||
for(uint8_t i=0; i<CORONA_ADDRESS_LENGTH; i++)
|
||||
packet[i+1]=rx_tx_addr[i];
|
||||
packet[5]=0xCD; // Unknown but seems to be always the same value for V1
|
||||
return 3689;
|
||||
}
|
||||
else
|
||||
{ // Send hopping freq
|
||||
packet[0]=0x03; // 4 bytes to follow
|
||||
for(uint8_t i=0; i<CORONA_RF_NUM_CHANNELS+1; i++)
|
||||
packet[i+1]=hopping_frequency[i];
|
||||
// Only the first 3 channels of hopping_frequency used for data
|
||||
return 3438;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // V2 and FDV3
|
||||
packet[0]=0x04; // 5 bytes to follow
|
||||
for(uint8_t i=0; i<CORONA_ADDRESS_LENGTH; i++)
|
||||
packet[i+1]=rx_tx_addr[i];
|
||||
packet[5]=0x00; // Unknown but seems to be always the same value for V2 and FDV3
|
||||
if(sub_protocol==FD_V3)
|
||||
return FDV3_BIND_PERIOD;
|
||||
else
|
||||
return 26791;
|
||||
}
|
||||
}
|
||||
|
||||
// 8 Channels with direct values from PPM
|
||||
static uint16_t __attribute__((unused)) CORONA_build_packet()
|
||||
{
|
||||
CC2500_SetPower();
|
||||
if(state && sub_protocol==COR_V2)
|
||||
{ // Send identifier packet for 2.65sec. This is how the RX learns the hopping table after a bind. Why it's not part of the bind like V1 is a mistery...
|
||||
// Set channel
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, 0x00);
|
||||
state--;
|
||||
packet[0]=0x07; // 8 bytes to follow
|
||||
// Send hopping freq
|
||||
for(uint8_t i=0; i<CORONA_RF_NUM_CHANNELS; i++)
|
||||
packet[i+1]=hopping_frequency[i];
|
||||
// Send TX ID
|
||||
for(uint8_t i=0; i<CORONA_ADDRESS_LENGTH; i++)
|
||||
packet[i+4]=rx_tx_addr[i];
|
||||
packet[8]=0;
|
||||
return 6647;
|
||||
}
|
||||
|
||||
// Flydream every fourth packet is identifier packet and is on channel number
|
||||
// that is last byte of rx_tx_addr
|
||||
if (fdv3_id_send)
|
||||
{
|
||||
fdv3_id_send = 0;
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, rx_tx_addr[CORONA_ADDRESS_LENGTH-1]);
|
||||
packet[0] = 0x07; // 8 bytes to follow
|
||||
// Send TX ID
|
||||
for(uint8_t i = 0; i < CORONA_ADDRESS_LENGTH; i++)
|
||||
packet[i+1] = rx_tx_addr[i];
|
||||
// Send hopping freq
|
||||
for(uint8_t i = 0; i < CORONA_RF_NUM_CHANNELS; i++)
|
||||
packet[i+1+CORONA_ADDRESS_LENGTH] = hopping_frequency[i];
|
||||
packet[8] = 0;
|
||||
return 2*FDV3_CHANNEL_PERIOD; // extra delay after id packet according to captures
|
||||
}
|
||||
|
||||
// Set RF channel
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[hopping_frequency_no]);
|
||||
|
||||
// Build packet
|
||||
packet[0] = 0x10; // 17 bytes to follow
|
||||
|
||||
// Channels
|
||||
memset(packet+9, 0x00, 4);
|
||||
for (uint8_t i=0; i<8; i++)
|
||||
{ // Channel values are packed
|
||||
uint16_t val=convert_channel_ppm(i);
|
||||
packet[i+1] = val;
|
||||
packet[9 + (i>>1)] |= (i&0x01)?(val>>4)&0xF0:(val>>8)&0x0F;
|
||||
}
|
||||
|
||||
// TX ID
|
||||
for (uint8_t i=0; i < CORONA_ADDRESS_LENGTH; i++)
|
||||
packet[i+13] = rx_tx_addr[i];
|
||||
|
||||
packet[17] = 0x00;
|
||||
|
||||
if (sub_protocol!=FD_V3)
|
||||
{
|
||||
// Packet period is based on hopping
|
||||
switch (hopping_frequency_no)
|
||||
{
|
||||
case 0:
|
||||
packet_period = sub_protocol == COR_V1
|
||||
? 4991
|
||||
: 4248;
|
||||
break;
|
||||
case 1:
|
||||
packet_period = sub_protocol == COR_V1
|
||||
? 4991
|
||||
: 4345;
|
||||
break;
|
||||
case 2:
|
||||
packet_period = sub_protocol == COR_V1
|
||||
? 12520
|
||||
: 13468;
|
||||
if (sub_protocol == COR_V2)
|
||||
packet[17] = 0x03;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hopping_frequency_no++;
|
||||
|
||||
if (sub_protocol == FD_V3)
|
||||
{
|
||||
if (hopping_frequency_no == CORONA_RF_NUM_CHANNELS)
|
||||
{
|
||||
fdv3_id_send = 1;
|
||||
packet_period = 6000; // extra delay before id packet according to captures
|
||||
}
|
||||
else
|
||||
packet_period = FDV3_CHANNEL_PERIOD;
|
||||
}
|
||||
|
||||
hopping_frequency_no %= CORONA_RF_NUM_CHANNELS;
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t ReadCORONA()
|
||||
{
|
||||
// Tune frequency if it has been changed
|
||||
if ( prev_option != option )
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
prev_option = option ;
|
||||
}
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
if (bind_counter-- == 0) BIND_DONE;
|
||||
packet_period=CORONA_build_bind_pkt();
|
||||
}
|
||||
else
|
||||
packet_period=CORONA_build_packet();
|
||||
|
||||
// Send packet
|
||||
CC2500_WriteData(packet, packet[0]+2);
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initCORONA()
|
||||
{
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case COR_V1:
|
||||
bind_counter=1400; // Stay in bind mode for 5s
|
||||
break;
|
||||
case COR_V2:
|
||||
bind_counter=187; // Stay in bind mode for 5s
|
||||
break;
|
||||
case FD_V3:
|
||||
bind_counter = 2000; // Stay in bind mode for 10s
|
||||
break;
|
||||
}
|
||||
state=400; // Used by V2 to send RF channels + ID for 2.65s at startup
|
||||
hopping_frequency_no=0;
|
||||
fdv3_id_send = 0;
|
||||
CORONA_init();
|
||||
CORONA_rf_init();
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
162
Multiprotocol/DM002_nrf24l01.ino
Normal file
162
Multiprotocol/DM002_nrf24l01.ino
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
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 DM002
|
||||
|
||||
#if defined(DM002_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define DM002_PACKET_PERIOD 6100 // Timeout for callback in uSec
|
||||
#define DM002_INITIAL_WAIT 500
|
||||
#define DM002_PACKET_SIZE 12 // packets have 12-byte payload
|
||||
#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,
|
||||
DM002_FLAG_LED = 0x02,
|
||||
DM002_FLAG_MEDIUM = 0x04,
|
||||
DM002_FLAG_HIGH = 0x08,
|
||||
DM002_FLAG_RTH = 0x10,
|
||||
DM002_FLAG_HEADLESS = 0x20,
|
||||
DM002_FLAG_CAMERA1 = 0x40,
|
||||
DM002_FLAG_CAMERA2 = 0x80,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) DM002_send_packet(uint8_t bind)
|
||||
{
|
||||
memcpy(packet+5,(uint8_t *)"\x00\x7F\x7F\x7F\x00\x00\x00",7);
|
||||
if(bind)
|
||||
{
|
||||
packet[0] = 0xAA;
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
packet[3] = rx_tx_addr[2];
|
||||
packet[4] = rx_tx_addr[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0]=0x55;
|
||||
// Throttle : 0 .. 200
|
||||
packet[1]=convert_channel_16b_limit(THROTTLE,0,200);
|
||||
// Other channels min 0x57, mid 0x7F, max 0xA7
|
||||
packet[2] = convert_channel_16b_limit(RUDDER,0x57,0xA7);
|
||||
packet[3] = convert_channel_16b_limit(AILERON, 0x57,0xA7);
|
||||
packet[4] = convert_channel_16b_limit(ELEVATOR, 0xA7, 0x57);
|
||||
// Features
|
||||
packet[9] = GET_FLAG(CH5_SW,DM002_FLAG_FLIP)
|
||||
| GET_FLAG(!CH6_SW,DM002_FLAG_LED)
|
||||
| GET_FLAG(CH7_SW,DM002_FLAG_CAMERA1)
|
||||
| GET_FLAG(CH8_SW,DM002_FLAG_CAMERA2)
|
||||
| GET_FLAG(CH9_SW,DM002_FLAG_HEADLESS)
|
||||
| GET_FLAG(CH10_SW,DM002_FLAG_RTH)
|
||||
| GET_FLAG(!CH11_SW,DM002_FLAG_HIGH);
|
||||
// Packet counter
|
||||
if(packet_count&0x03)
|
||||
{
|
||||
packet_count++;
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no&=4;
|
||||
}
|
||||
packet_count&=0x0F;
|
||||
packet[10] = packet_count;
|
||||
packet_count++;
|
||||
}
|
||||
//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();
|
||||
XN297_WritePayload(packet, DM002_PACKET_SIZE);
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DM002_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
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();
|
||||
}
|
||||
|
||||
uint16_t DM002_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
DM002_send_packet(0);
|
||||
else
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
DM002_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
return DM002_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DM002_initialize_txid()
|
||||
{
|
||||
// Only 3 IDs/RFs are available, RX_NUM is used to switch between them
|
||||
switch(rx_tx_addr[3]%3)
|
||||
{
|
||||
case 0:
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x34\x39\x43\x48",4);
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\x47\x93\x00\x00\xD5",5);
|
||||
break;
|
||||
case 1:
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x35\x39\x3B\x3D",4);
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\xAC\xA1\x00\x00\xD5",5);
|
||||
break;
|
||||
case 2:
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x32\x37\x41\x46",4);
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\x92\x45\x01\x00\xD5",5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initDM002(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = DM002_BIND_COUNT;
|
||||
DM002_initialize_txid();
|
||||
DM002_init();
|
||||
return DM002_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,535 +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/>.
|
||||
*/
|
||||
|
||||
#if defined(DSM2_CYRF6936_INO)
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
#define DSM2_NUM_CHANNELS 7
|
||||
#define RANDOM_CHANNELS 0 // disabled
|
||||
//#define RANDOM_CHANNELS 1 // enabled
|
||||
#define BIND_CHANNEL 0x0d //13 This can be any odd channel
|
||||
#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
|
||||
|
||||
//During binding we will send BIND_COUNT/2 packets
|
||||
//One packet each 10msec
|
||||
#define BIND_COUNT1 600
|
||||
|
||||
enum {
|
||||
DSM2_BIND = 0,
|
||||
DSM2_CHANSEL = BIND_COUNT1 + 0,
|
||||
DSM2_CH1_WRITE_A = BIND_COUNT1 + 1,
|
||||
DSM2_CH1_CHECK_A = BIND_COUNT1 + 2,
|
||||
DSM2_CH2_WRITE_A = BIND_COUNT1 + 3,
|
||||
DSM2_CH2_CHECK_A = BIND_COUNT1 + 4,
|
||||
DSM2_CH2_READ_A = BIND_COUNT1 + 5,
|
||||
DSM2_CH1_WRITE_B = BIND_COUNT1 + 6,
|
||||
DSM2_CH1_CHECK_B = BIND_COUNT1 + 7,
|
||||
DSM2_CH2_WRITE_B = BIND_COUNT1 + 8,
|
||||
DSM2_CH2_CHECK_B = BIND_COUNT1 + 9,
|
||||
DSM2_CH2_READ_B = BIND_COUNT1 + 10,
|
||||
};
|
||||
|
||||
|
||||
const uint8_t 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 */ {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}
|
||||
},
|
||||
};
|
||||
|
||||
//
|
||||
uint8_t chidx;
|
||||
uint8_t sop_col;
|
||||
uint8_t data_col;
|
||||
uint16_t cyrf_state;
|
||||
uint8_t crcidx;
|
||||
uint8_t binding;
|
||||
uint16_t crc;
|
||||
uint8_t model;
|
||||
|
||||
/*
|
||||
#ifdef USE_FIXED_MFGID
|
||||
const uint8_t cyrfmfg_id[6] = {0x5e, 0x28, 0xa3, 0x1b, 0x00, 0x00}; //dx8
|
||||
const uint8_t cyrfmfg_id[6] = {0xd4, 0x62, 0xd6, 0xad, 0xd3, 0xff}; //dx6i
|
||||
#else
|
||||
//uint8_t cyrfmfg_id[6];
|
||||
#endif
|
||||
*/
|
||||
|
||||
void build_bind_packet()
|
||||
{
|
||||
uint8_t i;
|
||||
uint16_t sum = 384 - 0x10;//
|
||||
packet[0] = crc >> 8;
|
||||
packet[1] = crc & 0xff;
|
||||
packet[2] = 0xff ^ cyrfmfg_id[2];
|
||||
packet[3] = (0xff ^ cyrfmfg_id[3]) + model;
|
||||
packet[4] = packet[0];
|
||||
packet[5] = packet[1];
|
||||
packet[6] = packet[2];
|
||||
packet[7] = packet[3];
|
||||
for(i = 0; i < 8; i++)
|
||||
sum += packet[i];
|
||||
packet[8] = sum >> 8;
|
||||
packet[9] = sum & 0xff;
|
||||
packet[10] = 0x01; //???
|
||||
packet[11] = DSM2_NUM_CHANNELS;
|
||||
if(sub_protocol==DSMX) //DSMX type
|
||||
packet[12] = 0xb2; // Telemetry off: packet[12] = num_channels < 8 && Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_OFF ? 0xa2 : 0xb2;
|
||||
else
|
||||
#if DSM2_NUM_CHANNELS < 8
|
||||
packet[12] = 0x01;
|
||||
#else
|
||||
packet[12] = 0x02;
|
||||
#endif
|
||||
packet[13] = 0x00; //???
|
||||
for(i = 8; i < 14; i++)
|
||||
sum += packet[i];
|
||||
packet[14] = sum >> 8;
|
||||
packet[15] = sum & 0xff;
|
||||
}
|
||||
|
||||
void build_data_packet(uint8_t upper)//
|
||||
{
|
||||
#if DSM2_NUM_CHANNELS==4
|
||||
const uint8_t ch_map[] = {0, 1, 2, 3, 0xff, 0xff, 0xff}; //Guess
|
||||
#elif DSM2_NUM_CHANNELS==5
|
||||
const uint8_t ch_map[] = {0, 1, 2, 3, 4, 0xff, 0xff}; //Guess
|
||||
#elif DSM2_NUM_CHANNELS==6
|
||||
const uint8_t ch_map[] = {1, 5, 2, 3, 0, 4, 0xff}; //HP6DSM
|
||||
#elif DSM2_NUM_CHANNELS==7
|
||||
const uint8_t ch_map[] = {1, 5, 2, 4, 3, 6, 0}; //DX6i
|
||||
#elif DSM2_NUM_CHANNELS==8
|
||||
const uint8_t ch_map[] = {1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 0xff, 0xff, 0xff, 0xff}; //DX8
|
||||
#elif DSM2_NUM_CHANNELS==9
|
||||
const uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xff, 0xff, 0xff, 0xff, 0xff}; //DM9
|
||||
#elif DSM2_NUM_CHANNELS==10
|
||||
const uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 0xff, 0xff, 0xff, 0xff};
|
||||
#elif DSM2_NUM_CHANNELS==11
|
||||
const uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 10, 0xff, 0xff, 0xff};
|
||||
#elif DSM2_NUM_CHANNELS==12
|
||||
const uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 10, 11, 0xff, 0xff};
|
||||
#endif
|
||||
|
||||
uint8_t i;
|
||||
uint8_t bits;
|
||||
//
|
||||
if( binding && PROTOCOL_SticksMoved(0) )
|
||||
{
|
||||
//BIND_DONE;
|
||||
binding = 0;
|
||||
}
|
||||
if (sub_protocol==DSMX)
|
||||
{
|
||||
packet[0] = cyrfmfg_id[2];
|
||||
packet[1] = cyrfmfg_id[3] + model;
|
||||
bits=11;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0] = (0xff ^ cyrfmfg_id[2]);
|
||||
packet[1] = (0xff ^ cyrfmfg_id[3]) + model;
|
||||
bits=10;
|
||||
}
|
||||
//
|
||||
uint16_t max = 1 << bits;//max=2048 for DSMX & 1024 for DSM2 less than 8 ch and 2048 otherwise
|
||||
//uint16_t pct_100 = (uint32_t)max * 100 / 150;//682 1024*100/150
|
||||
//
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
uint8_t idx = ch_map[upper * 7 + i];//1,5,2,3,0,4
|
||||
uint16_t value;
|
||||
if (idx == 0xff)
|
||||
value = 0xffff;
|
||||
else
|
||||
{
|
||||
if (binding)
|
||||
{ // Failsafe position during binding
|
||||
value=max/2; //all channels to middle
|
||||
if(idx==0)
|
||||
value=1; //except throttle
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(idx)
|
||||
{
|
||||
case 0:
|
||||
value=Servo_data[THROTTLE];//85.75-938.25=125%//171-853=100%
|
||||
break;
|
||||
case 1:
|
||||
value=Servo_data[AILERON];
|
||||
break;
|
||||
case 2:
|
||||
value=Servo_data[ELEVATOR];
|
||||
break;
|
||||
case 3:
|
||||
value=Servo_data[RUDDER];
|
||||
break;
|
||||
case 4:
|
||||
value=Servo_data[AUX1];
|
||||
break;
|
||||
case 5:
|
||||
value=Servo_data[AUX2];
|
||||
break;
|
||||
case 6:
|
||||
value=Servo_data[AUX3];
|
||||
break;
|
||||
case 7:
|
||||
value=Servo_data[AUX4];
|
||||
break;
|
||||
}
|
||||
value=map(value,PPM_MIN,PPM_MAX,0,max-1);
|
||||
}
|
||||
value |= (upper && i == 0 ? 0x8000 : 0) | (idx << bits);
|
||||
}
|
||||
packet[i*2+2] = (value >> 8) & 0xff;
|
||||
packet[i*2+3] = (value >> 0) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t PROTOCOL_SticksMoved(uint8_t init)
|
||||
{
|
||||
#define STICK_MOVEMENT 15*(PPM_MAX-PPM_MIN)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %)
|
||||
static uint16_t ele_start, ail_start;
|
||||
uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR));
|
||||
uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON));
|
||||
if(init) {
|
||||
ele_start = ele;
|
||||
ail_start = ail;
|
||||
return 0;
|
||||
}
|
||||
uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele);
|
||||
uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail);
|
||||
return ((ele_diff + ail_diff) > STICK_MOVEMENT);//
|
||||
}
|
||||
|
||||
uint8_t get_pn_row(uint8_t channel)
|
||||
{
|
||||
return (sub_protocol == DSMX ? (channel - 2) % 5 : channel % 5);
|
||||
}
|
||||
|
||||
const uint8_t init_vals[][2] = {
|
||||
{CYRF_02_TX_CTRL, 0x00},
|
||||
{CYRF_05_RX_CTRL, 0x00},
|
||||
{CYRF_28_CLK_EN, 0x02},
|
||||
{CYRF_32_AUTO_CAL_TIME, 0x3c},
|
||||
{CYRF_35_AUTOCAL_OFFSET, 0x14},
|
||||
{CYRF_06_RX_CFG, 0x4A},
|
||||
{CYRF_1B_TX_OFFSET_LSB, 0x55},
|
||||
{CYRF_1C_TX_OFFSET_MSB, 0x05},
|
||||
{CYRF_0F_XACT_CFG, 0x24}, // Force Idle
|
||||
{CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode
|
||||
{CYRF_12_DATA64_THOLD, 0x0a},
|
||||
{CYRF_0F_XACT_CFG, 0x04}, // Idle
|
||||
{CYRF_39_ANALOG_CTRL, 0x01},
|
||||
{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, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode
|
||||
{CYRF_10_FRAMING_CFG, 0x4a}, //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, 0x02}, //set EOP sync == 2
|
||||
{CYRF_01_TX_LENGTH, 0x10}, //16byte packet
|
||||
};
|
||||
|
||||
void cyrf_config()
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++)
|
||||
CYRF_WriteRegister(init_vals[i][0], init_vals[i][1]);
|
||||
CYRF_WritePreamble(0x333304);
|
||||
CYRF_ConfigRFChannel(0x61);
|
||||
}
|
||||
|
||||
void initialize_bind_state()
|
||||
{
|
||||
const uint8_t pn_bind[] = { 0xc6,0x94,0x22,0xfe,0x48,0xe6,0x57,0x4e };
|
||||
uint8_t data_code[32];
|
||||
CYRF_ConfigRFChannel(BIND_CHANNEL); //This seems to be random?
|
||||
uint8_t pn_row = get_pn_row(BIND_CHANNEL);
|
||||
//printf("Ch: %d Row: %d SOP: %d Data: %d\n", BIND_CHANNEL, pn_row, sop_col, data_col);
|
||||
CYRF_ConfigCRCSeed(crc);
|
||||
CYRF_ConfigSOPCode(pncodes[pn_row][sop_col]);
|
||||
memcpy(data_code, pncodes[pn_row][data_col], 16);
|
||||
memcpy(data_code + 16, pncodes[0][8], 8);
|
||||
memcpy(data_code + 24, pn_bind, 8);
|
||||
CYRF_ConfigDataCode(data_code, 32);
|
||||
build_bind_packet();
|
||||
}
|
||||
|
||||
const uint8_t data_vals[][2] = {
|
||||
{CYRF_05_RX_CTRL, 0x83}, //Initialize for reading RSSI
|
||||
{CYRF_29_RX_ABORT, 0x20},
|
||||
{CYRF_0F_XACT_CFG, 0x24},
|
||||
{CYRF_29_RX_ABORT, 0x00},
|
||||
{CYRF_03_TX_CFG, 0x08 | CYRF_HIGH_POWER},
|
||||
{CYRF_10_FRAMING_CFG, 0xea},
|
||||
{CYRF_1F_TX_OVERRIDE, 0x00},
|
||||
{CYRF_1E_RX_OVERRIDE, 0x00},
|
||||
{CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER},
|
||||
{CYRF_12_DATA64_THOLD, 0x3f},
|
||||
{CYRF_10_FRAMING_CFG, 0xff},
|
||||
{CYRF_0F_XACT_CFG, 0x24}, //Switch from reading RSSI to Writing
|
||||
{CYRF_29_RX_ABORT, 0x00},
|
||||
{CYRF_12_DATA64_THOLD, 0x0a},
|
||||
{CYRF_10_FRAMING_CFG, 0xea},
|
||||
};
|
||||
|
||||
void cyrf_configdata()
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++)
|
||||
CYRF_WriteRegister(data_vals[i][0], data_vals[i][1]);
|
||||
}
|
||||
|
||||
void set_sop_data_crc()
|
||||
{
|
||||
uint8_t pn_row = get_pn_row(hopping_frequency[chidx]);
|
||||
//printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[chidx], pn_row, sop_col, data_col);
|
||||
CYRF_ConfigRFChannel(hopping_frequency[chidx]);
|
||||
CYRF_ConfigCRCSeed(crcidx ? ~crc : crc);
|
||||
CYRF_ConfigSOPCode(pncodes[pn_row][sop_col]);
|
||||
CYRF_ConfigDataCode(pncodes[pn_row][data_col], 16);
|
||||
if(sub_protocol == DSMX)
|
||||
chidx = (chidx + 1) % 23;
|
||||
else
|
||||
chidx = (chidx + 1) % 2;
|
||||
crcidx = !crcidx;
|
||||
}
|
||||
|
||||
void 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 ^ id) & 0x01 )== 0)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t ReadDsm2()
|
||||
{
|
||||
#define CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
|
||||
#define WRITE_DELAY 1650 // 1550 original, Time after write to verify write complete
|
||||
#define READ_DELAY 400 // Time before write to check read state, and switch channels
|
||||
uint8_t i = 0;
|
||||
|
||||
switch(cyrf_state)
|
||||
{
|
||||
default:
|
||||
//Binding
|
||||
cyrf_state++;
|
||||
if(cyrf_state & 1)
|
||||
{
|
||||
//Send packet on even states
|
||||
//Note state has already incremented,
|
||||
// so this is actually 'even' state
|
||||
CYRF_WriteDataPacket(packet);
|
||||
return 8500;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Check status on odd states
|
||||
CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS);
|
||||
return 1500;
|
||||
}
|
||||
case DSM2_CHANSEL:
|
||||
BIND_DONE;
|
||||
//Select channels and configure for writing data
|
||||
//CYRF_FindBestChannels(ch, 2, 10, 1, 79);
|
||||
cyrf_configdata();
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
chidx = 0;
|
||||
crcidx = 0;
|
||||
cyrf_state = DSM2_CH1_WRITE_A; // in fact cyrf_state++
|
||||
set_sop_data_crc();
|
||||
return 10000;
|
||||
case DSM2_CH1_WRITE_A:
|
||||
case DSM2_CH1_WRITE_B:
|
||||
build_data_packet(cyrf_state == DSM2_CH1_WRITE_B);//compare state and DSM2_CH1_WRITE_B return 0 or 1
|
||||
case DSM2_CH2_WRITE_A:
|
||||
case DSM2_CH2_WRITE_B:
|
||||
CYRF_WriteDataPacket(packet);
|
||||
cyrf_state++; // change from WRITE to CHECK mode
|
||||
return WRITE_DELAY;
|
||||
case DSM2_CH1_CHECK_A:
|
||||
case DSM2_CH1_CHECK_B:
|
||||
while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02))
|
||||
if(++i > NUM_WAIT_LOOPS)
|
||||
break;
|
||||
set_sop_data_crc();
|
||||
cyrf_state++; // change from CH1_CHECK to CH2_WRITE
|
||||
return CH1_CH2_DELAY - WRITE_DELAY;
|
||||
case DSM2_CH2_CHECK_A:
|
||||
case DSM2_CH2_CHECK_B:
|
||||
while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02))
|
||||
if(++i > NUM_WAIT_LOOPS)
|
||||
break;
|
||||
if (cyrf_state == DSM2_CH2_CHECK_A)
|
||||
CYRF_SetPower(0x28); //Keep transmit power in sync
|
||||
// No telemetry...
|
||||
set_sop_data_crc();
|
||||
if (cyrf_state == DSM2_CH2_CHECK_A)
|
||||
{
|
||||
#if DSM2_NUM_CHANNELS < 8
|
||||
cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
|
||||
return 11000 - CH1_CH2_DELAY - WRITE_DELAY ; // Original is 22000 from deviation but it works better this way
|
||||
#else
|
||||
cyrf_state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper)
|
||||
#endif
|
||||
}
|
||||
else
|
||||
cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower)
|
||||
return 11000 - CH1_CH2_DELAY - WRITE_DELAY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t initDsm2()
|
||||
{
|
||||
CYRF_Reset();
|
||||
CYRF_GetMfgData(cyrfmfg_id);//
|
||||
|
||||
cyrf_config();
|
||||
|
||||
if (sub_protocol ==DSMX)
|
||||
calc_dsmx_channel();
|
||||
else
|
||||
{
|
||||
#if RANDOM_CHANNELS == 1
|
||||
uint8_t tmpch[10];
|
||||
CYRF_FindBestChannels(tmpch, 10, 5, 3, 75);
|
||||
//
|
||||
randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed
|
||||
uint8_t idx = random(0xfefefefe) % 10;
|
||||
hopping_frequency[0] = tmpch[idx];
|
||||
while(1)
|
||||
{
|
||||
idx = random(0xfefefefe) % 10;
|
||||
if (tmpch[idx] != hopping_frequency[0])
|
||||
break;
|
||||
}
|
||||
hopping_frequency[1] = tmpch[idx];
|
||||
#else
|
||||
hopping_frequency[0] = (cyrfmfg_id[0] + cyrfmfg_id[2] + cyrfmfg_id[4]) % 39 + 1;
|
||||
hopping_frequency[1] = (cyrfmfg_id[1] + cyrfmfg_id[3] + cyrfmfg_id[5]) % 40 + 40;
|
||||
#endif
|
||||
}
|
||||
|
||||
///}
|
||||
crc = ~((cyrfmfg_id[0] << 8) + cyrfmfg_id[1]); //The crc for channel 'a' is NOT(mfgid[1] << 8 + mfgid[0])
|
||||
crcidx = 0;//The crc for channel 'b' is (mfgid[1] << 8 + mfgid[0])
|
||||
//
|
||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;//Ok
|
||||
data_col = 7 - sop_col;//ok
|
||||
|
||||
model=MProtocol_id-MProtocol_id_master; // RxNum for serial or 0 for ppm
|
||||
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
//
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
{
|
||||
cyrf_state = DSM2_BIND;
|
||||
PROTOCOL_SticksMoved(1); //Initialize Stick position
|
||||
initialize_bind_state();
|
||||
binding = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cyrf_state = DSM2_CHANSEL;//
|
||||
binding = 0;
|
||||
}
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
592
Multiprotocol/DSM_cyrf6936.ino
Normal file
592
Multiprotocol/DSM_cyrf6936.ino
Normal file
@@ -0,0 +1,592 @@
|
||||
/*
|
||||
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_CYRF6936_INO)
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
#define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel
|
||||
|
||||
//During binding we will send BIND_COUNT/2 packets
|
||||
//One packet each 10msec
|
||||
#define DSM_BIND_COUNT 300
|
||||
|
||||
enum {
|
||||
DSM_BIND_WRITE=0,
|
||||
DSM_BIND_CHECK,
|
||||
DSM_BIND_READ,
|
||||
DSM_CHANSEL,
|
||||
DSM_CH1_WRITE_A,
|
||||
DSM_CH1_CHECK_A,
|
||||
DSM_CH2_WRITE_A,
|
||||
DSM_CH2_CHECK_A,
|
||||
DSM_CH2_READ_A,
|
||||
DSM_CH1_WRITE_B,
|
||||
DSM_CH1_CHECK_B,
|
||||
DSM_CH2_WRITE_B,
|
||||
DSM_CH2_CHECK_B,
|
||||
DSM_CH2_READ_B,
|
||||
};
|
||||
|
||||
//
|
||||
uint8_t sop_col;
|
||||
uint8_t ch_map[14];
|
||||
const uint8_t PROGMEM DSM_ch_map_progmem[][14] = {
|
||||
//22+11ms for 4..7 channels
|
||||
{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
|
||||
{1, 5, 2, 4, 3, 6, 0, 1, 5, 2, 4, 3, 6, 0 }, //7ch - DX6i
|
||||
//22ms for 8..12 channels
|
||||
{1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 0xff, 0xff, 0xff, 0xff}, //8ch - DX8/DX7
|
||||
{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, 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
|
||||
};
|
||||
|
||||
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;
|
||||
uint16_t sum = 384 - 0x10;//
|
||||
packet[0] = 0xff ^ cyrfmfg_id[0];
|
||||
packet[1] = 0xff ^ cyrfmfg_id[1];
|
||||
packet[2] = 0xff ^ cyrfmfg_id[2];
|
||||
packet[3] = 0xff ^ cyrfmfg_id[3];
|
||||
packet[4] = packet[0];
|
||||
packet[5] = packet[1];
|
||||
packet[6] = packet[2];
|
||||
packet[7] = packet[3];
|
||||
for(i = 0; i < 8; i++)
|
||||
sum += packet[i];
|
||||
packet[8] = sum >> 8;
|
||||
packet[9] = sum & 0xff;
|
||||
packet[10] = 0x01; //???
|
||||
packet[11] = num_ch;
|
||||
|
||||
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 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
|
||||
|
||||
packet[13] = 0x00; //???
|
||||
for(i = 8; i < 14; i++)
|
||||
sum += packet[i];
|
||||
packet[14] = sum >> 8;
|
||||
packet[15] = sum & 0xff;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
if(num_ch<4 || num_ch>12)
|
||||
num_ch=6; // Default to 6 channels if invalid choice...
|
||||
|
||||
// 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
|
||||
for(uint8_t i=0;i<14;i++)
|
||||
ch_map[i]=pgm_read_byte_near(&DSM_ch_map_progmem[idx][i]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
|
||||
{
|
||||
uint8_t bits = 11;
|
||||
|
||||
if(prev_option!=option)
|
||||
DSM_update_channels();
|
||||
|
||||
if (sub_protocol==DSMX_11 || sub_protocol==DSMX_22 )
|
||||
{
|
||||
packet[0] = cyrfmfg_id[2];
|
||||
packet[1] = cyrfmfg_id[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
}
|
||||
#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;;
|
||||
if (idx != 0xff)
|
||||
{
|
||||
/* Spektrum own remotes transmit normal values during bind and actually use this (e.g. Nano CP X) to
|
||||
select the transmitter mode (e.g. computer vs non-computer radio), so always send normal output */
|
||||
#ifdef DSM_THROTTLE_KILL_CH
|
||||
if(CH_TAER[idx]==THROTTLE && kill_ch<=604)
|
||||
{//Activate throttle kill only if DSM_THROTTLE_KILL_CH below -50%
|
||||
if(kill_ch<CHANNEL_MIN_100) // restrict val to 0...400
|
||||
kill_ch=0;
|
||||
else
|
||||
kill_ch-=CHANNEL_MIN_100;
|
||||
value=(kill_ch*21)/25; // kill channel -100%->904us ... -50%->1100us *0x150/400
|
||||
}
|
||||
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
|
||||
#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
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) DSM_Check_RX_packet()
|
||||
{
|
||||
uint8_t result=1; // assume good packet
|
||||
|
||||
uint16_t sum = 384 - 0x10;
|
||||
for(uint8_t i = 1; i < 9; i++)
|
||||
{
|
||||
sum += pkt[i];
|
||||
if(i<5)
|
||||
if(pkt[i] != (0xff ^ cyrfmfg_id[i-1]))
|
||||
result=0; // bad packet
|
||||
}
|
||||
if( pkt[9] != (sum>>8) && pkt[10] != (uint8_t)sum )
|
||||
result=0;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t ReadDsm()
|
||||
{
|
||||
#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
|
||||
#define DSM_WRITE_DELAY 1950 // Time after write to verify write complete
|
||||
#define DSM_READ_DELAY 600 // Time before write to check read phase, and switch channels. Was 400 but 600 seems what the 328p needs to read a packet
|
||||
#if defined DSM_TELEMETRY
|
||||
uint8_t rx_phase;
|
||||
uint8_t len;
|
||||
#endif
|
||||
uint8_t start;
|
||||
|
||||
switch(phase)
|
||||
{
|
||||
case DSM_BIND_WRITE:
|
||||
if(bind_counter--==0)
|
||||
#if defined DSM_TELEMETRY
|
||||
phase=DSM_BIND_CHECK; //Check RX answer
|
||||
#else
|
||||
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
|
||||
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)
|
||||
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>MAX_PKT-2)
|
||||
len=MAX_PKT-2;
|
||||
CYRF_ReadDataPacketLen(pkt+1, len);
|
||||
if(len==10 && DSM_Check_RX_packet())
|
||||
{
|
||||
pkt[0]=0x80;
|
||||
telemetry_link=1; // send received data on serial
|
||||
phase++;
|
||||
return 2000;
|
||||
}
|
||||
}
|
||||
else
|
||||
if((rx_phase & 0x02) != 0x02)
|
||||
{ // data received with errors
|
||||
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
|
||||
}
|
||||
if( --bind_counter == 0 )
|
||||
{ // Exit if no answer has been received for some time
|
||||
phase++; // DSM_CHANSEL
|
||||
return 7000 ;
|
||||
}
|
||||
return 7000;
|
||||
#endif
|
||||
case DSM_CHANSEL:
|
||||
BIND_DONE;
|
||||
DSM_cyrf_configdata();
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
hopping_frequency_no = 0;
|
||||
phase = DSM_CH1_WRITE_A; // in fact phase++
|
||||
DSM_set_sop_data_crc();
|
||||
return 10000;
|
||||
case DSM_CH1_WRITE_A:
|
||||
case DSM_CH1_WRITE_B:
|
||||
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_WriteDataPacket(packet);
|
||||
phase++; // change from WRITE to CHECK mode
|
||||
return DSM_WRITE_DELAY;
|
||||
case DSM_CH1_CHECK_A:
|
||||
case DSM_CH1_CHECK_B:
|
||||
case DSM_CH2_CHECK_A:
|
||||
case DSM_CH2_CHECK_B:
|
||||
start=(uint8_t)micros();
|
||||
while ((uint8_t)((uint8_t)micros()-(uint8_t)start) < 100) // Wait max 100µs, max I've seen is 50µs
|
||||
if((CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80) == 0x00)
|
||||
break;
|
||||
if(phase==DSM_CH1_CHECK_A || phase==DSM_CH1_CHECK_B)
|
||||
{
|
||||
#if defined DSM_TELEMETRY
|
||||
// reset cyrf6936 if freezed after switching from TX to RX
|
||||
if (((CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x22) == 0x20) || (CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80))
|
||||
{
|
||||
CYRF_Reset();
|
||||
DSM_cyrf_config();
|
||||
DSM_cyrf_configdata();
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
}
|
||||
#endif
|
||||
DSM_set_sop_data_crc();
|
||||
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
|
||||
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
||||
case DSM_CH2_READ_A:
|
||||
case DSM_CH2_READ_B:
|
||||
//Read telemetry
|
||||
rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
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)
|
||||
{ // good data (complete 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>MAX_PKT-2)
|
||||
len=MAX_PKT-2;
|
||||
CYRF_ReadDataPacketLen(pkt+1, len);
|
||||
pkt[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
|
||||
{
|
||||
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;
|
||||
return 11000;
|
||||
}
|
||||
if (phase == DSM_CH2_READ_A)
|
||||
phase = DSM_CH1_WRITE_B; //Transmit upper
|
||||
else
|
||||
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();
|
||||
return DSM_READ_DELAY;
|
||||
#else
|
||||
// No telemetry
|
||||
DSM_set_sop_data_crc();
|
||||
if (phase == DSM_CH2_CHECK_A)
|
||||
{
|
||||
if(num_ch > 7 || sub_protocol==DSM2_11 || sub_protocol==DSMX_11)
|
||||
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)
|
||||
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)
|
||||
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t initDsm()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
//Hopping frequencies
|
||||
if (sub_protocol == DSMX_11 || sub_protocol == DSMX_22)
|
||||
DSM_calc_dsmx_channel();
|
||||
else
|
||||
{
|
||||
uint8_t tmpch[10];
|
||||
CYRF_FindBestChannels(tmpch, 10, 5, 3, 75);
|
||||
//
|
||||
uint8_t idx = random(0xfefefefe) % 10;
|
||||
hopping_frequency[0] = tmpch[idx];
|
||||
while(1)
|
||||
{
|
||||
idx = random(0xfefefefe) % 10;
|
||||
if (tmpch[idx] != hopping_frequency[0])
|
||||
break;
|
||||
}
|
||||
hopping_frequency[1] = tmpch[idx];
|
||||
}
|
||||
//
|
||||
DSM_cyrf_config();
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
//
|
||||
DSM_update_channels();
|
||||
//
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
DSM_initialize_bind_phase();
|
||||
phase = DSM_BIND_WRITE;
|
||||
bind_counter=DSM_BIND_COUNT;
|
||||
}
|
||||
else
|
||||
phase = DSM_CHANSEL;//
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -17,20 +17,15 @@
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
#define DEVO_NUM_CHANNELS 8
|
||||
|
||||
//For Debug
|
||||
//#define NO_SCRAMBLE
|
||||
#define PKTS_PER_CHANNEL 4
|
||||
#define DEVO_BIND_COUNT 0x1388
|
||||
//#define TELEMETRY_ENABLE 0x30
|
||||
#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
|
||||
//
|
||||
//#define TELEM_ON 0
|
||||
//#define TELEM_OFF 1
|
||||
|
||||
enum Devo_PhaseState
|
||||
{
|
||||
#define DEVO_PKTS_PER_CHANNEL 4
|
||||
#define DEVO_BIND_COUNT 0x1388
|
||||
|
||||
#define DEVO_NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
|
||||
|
||||
enum {
|
||||
DEVO_BIND,
|
||||
DEVO_BIND_SENDCH,
|
||||
DEVO_BOUND,
|
||||
@@ -46,79 +41,86 @@ enum Devo_PhaseState
|
||||
DEVO_BOUND_10,
|
||||
};
|
||||
|
||||
const uint8_t sopcodes[][8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
/* 0 */ {0x3C,0x37,0xCC,0x91,0xE2,0xF8,0xCC,0x91}, //0x91CCF8E291CC373C
|
||||
/* 1 */ {0x9B,0xC5,0xA1,0x0F,0xAD,0x39,0xA2,0x0F}, //0x0FA239AD0FA1C59B
|
||||
/* 2 */ {0xEF,0x64,0xB0,0x2A,0xD2,0x8F,0xB1,0x2A}, //0x2AB18FD22AB064EF
|
||||
/* 3 */ {0x66,0xCD,0x7C,0x50,0xDD,0x26,0x7C,0x50}, //0x507C26DD507CCD66
|
||||
/* 4 */ {0x5C,0xE1,0xF6,0x44,0xAD,0x16,0xF6,0x44}, //0x44F616AD44F6E15C
|
||||
/* 5 */ {0x5A,0xCC,0xAE,0x46,0xB6,0x31,0xAE,0x46}, //0x46AE31B646AECC5A
|
||||
/* 6 */ {0xA1,0x78,0xDC,0x3C,0x9E,0x82,0xDC,0x3C}, //0x3CDC829E3CDC78A1
|
||||
/* 7 */ {0xB9,0x8E,0x19,0x74,0x6F,0x65,0x18,0x74}, //0x7418656F74198EB9
|
||||
/* 8 */ {0xDF,0xB1,0xC0,0x49,0x62,0xDF,0xC1,0x49}, //0x49C1DF6249C0B1DF
|
||||
/* 9 */ {0x97,0xE5,0x14,0x72,0x7F,0x1A,0x14,0x72}, //0x72141A7F7214E597
|
||||
};
|
||||
|
||||
uint8_t txState;
|
||||
uint8_t pkt_num;
|
||||
uint8_t ch_idx;
|
||||
uint8_t use_fixed_id;
|
||||
uint8_t failsafe_pkt;
|
||||
|
||||
void scramble_pkt()
|
||||
static void __attribute__((unused)) DEVO_scramble_pkt()
|
||||
{
|
||||
#ifdef NO_SCRAMBLE
|
||||
return;
|
||||
#else
|
||||
uint8_t i;
|
||||
for(i = 0; i < 15; i++)
|
||||
for(uint8_t i = 0; i < 15; i++)
|
||||
packet[i + 1] ^= cyrfmfg_id[i % 4];
|
||||
#endif
|
||||
}
|
||||
|
||||
void add_pkt_suffix()
|
||||
static void __attribute__((unused)) DEVO_add_pkt_suffix()
|
||||
{
|
||||
uint8_t bind_state;
|
||||
if (use_fixed_id)
|
||||
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 (bind_counter > 0)
|
||||
bind_state = 0xc0;
|
||||
else
|
||||
bind_state = 0x80;
|
||||
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;
|
||||
}
|
||||
BIND_SET_OUTPUT;
|
||||
}
|
||||
#endif //ENABLE_PPM
|
||||
if(prev_option!=option && IS_BIND_DONE)
|
||||
{
|
||||
MProtocol_id = RX_num + MProtocol_id_master;
|
||||
bind_counter=DEVO_BIND_COUNT;
|
||||
}
|
||||
if (option)
|
||||
{
|
||||
if (bind_counter > 0)
|
||||
bind_state = 0xc0;
|
||||
else
|
||||
bind_state = 0x80;
|
||||
}
|
||||
else
|
||||
bind_state = 0x00;
|
||||
packet[10] = bind_state | (PKTS_PER_CHANNEL - pkt_num - 1);
|
||||
bind_state = 0x00;
|
||||
packet[10] = bind_state | (DEVO_PKTS_PER_CHANNEL - packet_count - 1);
|
||||
packet[11] = *(hopping_frequency_ptr + 1);
|
||||
packet[12] = *(hopping_frequency_ptr + 2);
|
||||
packet[13] = fixed_id & 0xff;
|
||||
packet[14] = (fixed_id >> 8) & 0xff;
|
||||
packet[15] = (fixed_id >> 16) & 0xff;
|
||||
packet[13] = MProtocol_id & 0xff;
|
||||
packet[14] = (MProtocol_id >> 8) & 0xff;
|
||||
packet[15] = (MProtocol_id >> 16) & 0xff;
|
||||
}
|
||||
|
||||
void build_beacon_pkt(uint8_t upper)
|
||||
static void __attribute__((unused)) DEVO_build_beacon_pkt(uint8_t upper)
|
||||
{
|
||||
packet[0] = ((DEVO_NUM_CHANNELS << 4) | 0x07);
|
||||
// uint8_t enable = 0;
|
||||
uint8_t max = 8;
|
||||
// int offset = 0;
|
||||
packet[0] = (num_ch << 4) | 0x07;
|
||||
uint8_t max = 8, offset = 0, enable = 0;
|
||||
if (upper)
|
||||
{
|
||||
packet[0] += 1;
|
||||
max = 4;
|
||||
// offset = 8;
|
||||
offset = 8;
|
||||
}
|
||||
for(uint8_t i = 0; i < max; i++)
|
||||
packet[i+1] = 0;
|
||||
// packet[9] = enable;
|
||||
packet[9] = 0;
|
||||
add_pkt_suffix();
|
||||
{
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
uint16_t failsafe=Failsafe_data[CH_EATR[i+offset]];
|
||||
if(i + offset < num_ch && failsafe!=FAILSAFE_CHANNEL_HOLD && IS_FAILSAFE_VALUES_on)
|
||||
{
|
||||
enable |= 0x80 >> i;
|
||||
packet[i+1] = ((failsafe*25)>>8)-100;
|
||||
}
|
||||
else
|
||||
#else
|
||||
(void)offset;
|
||||
#endif
|
||||
packet[i+1] = 0;
|
||||
}
|
||||
packet[9] = enable;
|
||||
DEVO_add_pkt_suffix();
|
||||
}
|
||||
|
||||
void build_bind_pkt()
|
||||
static void __attribute__((unused)) DEVO_build_bind_pkt()
|
||||
{
|
||||
packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x0a;
|
||||
packet[0] = (num_ch << 4) | 0x0a;
|
||||
packet[1] = bind_counter & 0xff;
|
||||
packet[2] = (bind_counter >> 8);
|
||||
packet[3] = *hopping_frequency_ptr;
|
||||
@@ -128,7 +130,7 @@ void build_bind_pkt()
|
||||
packet[7] = cyrfmfg_id[1];
|
||||
packet[8] = cyrfmfg_id[2];
|
||||
packet[9] = cyrfmfg_id[3];
|
||||
add_pkt_suffix();
|
||||
DEVO_add_pkt_suffix();
|
||||
//The fixed-id portion is scrambled in the bind packet
|
||||
//I assume it is ignored
|
||||
packet[13] ^= cyrfmfg_id[0];
|
||||
@@ -136,16 +138,15 @@ void build_bind_pkt()
|
||||
packet[15] ^= cyrfmfg_id[2];
|
||||
}
|
||||
|
||||
void build_data_pkt()
|
||||
static void __attribute__((unused)) DEVO_build_data_pkt()
|
||||
{
|
||||
uint8_t i;
|
||||
packet[0] = (DEVO_NUM_CHANNELS << 4) | (0x0b + ch_idx);
|
||||
static uint8_t ch_idx=0;
|
||||
|
||||
packet[0] = (num_ch << 4) | (0x0b + ch_idx);
|
||||
uint8_t sign = 0x0b;
|
||||
for (i = 0; i < 4; i++)
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
//
|
||||
int16_t value= map(Servo_data[ch_idx * 4 + i],PPM_MIN,PPM_MAX,-1600,1600);//range -1600...+1600
|
||||
//s32 value = (s32)Channels[ch_idx * 4 + i] * 0x640 / CHAN_MAX_VALUE;//10000
|
||||
int16_t value=convert_channel_16b_nolimit(CH_EATR[ch_idx * 4 + i],-1600,1600);//range -1600..+1600
|
||||
if(value < 0)
|
||||
{
|
||||
value = -value;
|
||||
@@ -155,13 +156,13 @@ void build_data_pkt()
|
||||
packet[2 * i + 2] = (value >> 8) & 0xff;
|
||||
}
|
||||
packet[9] = sign;
|
||||
ch_idx = ch_idx + 1;
|
||||
if (ch_idx * 4 >= DEVO_NUM_CHANNELS)
|
||||
ch_idx++;
|
||||
if (ch_idx * 4 >= num_ch)
|
||||
ch_idx = 0;
|
||||
add_pkt_suffix();
|
||||
DEVO_add_pkt_suffix();
|
||||
}
|
||||
|
||||
void cyrf_set_bound_sop_code()
|
||||
static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code()
|
||||
{
|
||||
/* crc == 0 isn't allowed, so use 1 if the math results in 0 */
|
||||
uint8_t crc = (cyrfmfg_id[0] + (cyrfmfg_id[1] >> 6) + cyrfmfg_id[2]);
|
||||
@@ -170,68 +171,62 @@ void cyrf_set_bound_sop_code()
|
||||
uint8_t sopidx = (0xff &((cyrfmfg_id[0] << 2) + cyrfmfg_id[1] + cyrfmfg_id[2])) % 10;
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
CYRF_ConfigCRCSeed((crc << 8) + crc);
|
||||
CYRF_ConfigSOPCode(sopcodes[sopidx]);
|
||||
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[sopidx]);
|
||||
CYRF_SetPower(0x08);
|
||||
}
|
||||
|
||||
void cyrf_init()
|
||||
const uint8_t PROGMEM DEVO_init_vals[][2] = {
|
||||
{ CYRF_1D_MODE_OVERRIDE, 0x38 },
|
||||
{ CYRF_03_TX_CFG, 0x08 },
|
||||
{ CYRF_06_RX_CFG, 0x4A },
|
||||
{ CYRF_0B_PWR_CTRL, 0x00 },
|
||||
{ CYRF_10_FRAMING_CFG, 0xA4 },
|
||||
{ CYRF_11_DATA32_THOLD, 0x05 },
|
||||
{ CYRF_12_DATA64_THOLD, 0x0E },
|
||||
{ CYRF_1B_TX_OFFSET_LSB, 0x55 },
|
||||
{ CYRF_1C_TX_OFFSET_MSB, 0x05 },
|
||||
{ CYRF_32_AUTO_CAL_TIME, 0x3C },
|
||||
{ CYRF_35_AUTOCAL_OFFSET, 0x14 },
|
||||
{ CYRF_39_ANALOG_CTRL, 0x01 },
|
||||
{ CYRF_1E_RX_OVERRIDE, 0x10 },
|
||||
{ CYRF_1F_TX_OVERRIDE, 0x00 },
|
||||
{ CYRF_01_TX_LENGTH, 0x10 },
|
||||
{ CYRF_0F_XACT_CFG, 0x10 },
|
||||
{ CYRF_27_CLK_OVERRIDE, 0x02 },
|
||||
{ CYRF_28_CLK_EN, 0x02 },
|
||||
{ CYRF_0F_XACT_CFG, 0x28 }
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) DEVO_cyrf_init()
|
||||
{
|
||||
/* Initialise CYRF chip */
|
||||
CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x39);
|
||||
CYRF_SetPower(0x08);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A);
|
||||
CYRF_WriteRegister(CYRF_0B_PWR_CTRL, 0x00);
|
||||
CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04);
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL, 0x20);
|
||||
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xA4);
|
||||
CYRF_WriteRegister(CYRF_11_DATA32_THOLD, 0x05);
|
||||
CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0E);
|
||||
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
|
||||
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
|
||||
CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C);
|
||||
CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
|
||||
CYRF_WriteRegister(CYRF_39_ANALOG_CTRL, 0x01);
|
||||
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x10);
|
||||
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
|
||||
CYRF_WriteRegister(CYRF_01_TX_LENGTH, 0x10);
|
||||
CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x10);
|
||||
CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x02);
|
||||
CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28);
|
||||
for(uint8_t i = 0; i < sizeof(DEVO_init_vals) / 2; i++)
|
||||
CYRF_WriteRegister(pgm_read_byte( &DEVO_init_vals[i][0]), pgm_read_byte( &DEVO_init_vals[i][1]) );
|
||||
}
|
||||
|
||||
void set_radio_channels()
|
||||
static void __attribute__((unused)) DEVO_set_radio_channels()
|
||||
{
|
||||
//int i;
|
||||
CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80);
|
||||
//printf("Radio Channels:");
|
||||
// for (i = 0; i < 3; i++) {
|
||||
// printf(" %02x", radio_ch[i]);
|
||||
|
||||
//Serial.print(radio_ch[i]);
|
||||
// }
|
||||
// printf("\n");
|
||||
//Makes code a little easier to duplicate these here
|
||||
hopping_frequency[3] = hopping_frequency[0];
|
||||
hopping_frequency[4] = hopping_frequency[1];
|
||||
}
|
||||
|
||||
void DEVO_BuildPacket()
|
||||
static void __attribute__((unused)) DEVO_BuildPacket()
|
||||
{
|
||||
static uint8_t failsafe_pkt=0;
|
||||
switch(phase)
|
||||
{
|
||||
case DEVO_BIND:
|
||||
if(bind_counter>0)
|
||||
if(bind_counter)
|
||||
bind_counter--;
|
||||
build_bind_pkt();
|
||||
DEVO_build_bind_pkt();
|
||||
phase = DEVO_BIND_SENDCH;
|
||||
break;
|
||||
case DEVO_BIND_SENDCH:
|
||||
if(bind_counter>0)
|
||||
if(bind_counter)
|
||||
bind_counter--;
|
||||
build_data_pkt();
|
||||
scramble_pkt();
|
||||
DEVO_build_data_pkt();
|
||||
DEVO_scramble_pkt();
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
phase = DEVO_BOUND;
|
||||
@@ -250,10 +245,10 @@ void DEVO_BuildPacket()
|
||||
case DEVO_BOUND_7:
|
||||
case DEVO_BOUND_8:
|
||||
case DEVO_BOUND_9:
|
||||
build_data_pkt();
|
||||
scramble_pkt();
|
||||
DEVO_build_data_pkt();
|
||||
DEVO_scramble_pkt();
|
||||
phase++;
|
||||
if (bind_counter > 0)
|
||||
if (bind_counter)
|
||||
{
|
||||
bind_counter--;
|
||||
if (bind_counter == 0)
|
||||
@@ -261,19 +256,20 @@ void DEVO_BuildPacket()
|
||||
}
|
||||
break;
|
||||
case DEVO_BOUND_10:
|
||||
build_beacon_pkt(DEVO_NUM_CHANNELS > 8 ? failsafe_pkt : 0);
|
||||
DEVO_build_beacon_pkt(num_ch > 8 ? failsafe_pkt : 0);
|
||||
failsafe_pkt = failsafe_pkt ? 0 : 1;
|
||||
scramble_pkt();
|
||||
DEVO_scramble_pkt();
|
||||
phase = DEVO_BOUND_1;
|
||||
break;
|
||||
}
|
||||
pkt_num++;
|
||||
if(pkt_num == PKTS_PER_CHANNEL)
|
||||
pkt_num = 0;
|
||||
packet_count++;
|
||||
if(packet_count == DEVO_PKTS_PER_CHANNEL)
|
||||
packet_count = 0;
|
||||
}
|
||||
|
||||
uint16_t devo_callback()
|
||||
{
|
||||
static uint8_t txState=0;
|
||||
if (txState == 0)
|
||||
{
|
||||
txState = 1;
|
||||
@@ -284,107 +280,72 @@ uint16_t devo_callback()
|
||||
txState = 0;
|
||||
uint8_t i = 0;
|
||||
while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02))
|
||||
if(++i > NUM_WAIT_LOOPS)
|
||||
if(++i > DEVO_NUM_WAIT_LOOPS)
|
||||
return 1200;
|
||||
if (phase == DEVO_BOUND)
|
||||
{
|
||||
/* exit binding state */
|
||||
phase = DEVO_BOUND_3;
|
||||
cyrf_set_bound_sop_code();
|
||||
DEVO_cyrf_set_bound_sop_code();
|
||||
}
|
||||
if(pkt_num == 0)
|
||||
if(packet_count == 0)
|
||||
{
|
||||
//Keep tx power updated
|
||||
CYRF_SetPower(0x08);
|
||||
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);
|
||||
}
|
||||
return 1200;
|
||||
}
|
||||
|
||||
void devo_bind()
|
||||
{
|
||||
fixed_id = Model_fixed_id;
|
||||
bind_counter = DEVO_BIND_COUNT;
|
||||
use_fixed_id = 1;
|
||||
//PROTOCOL_SetBindState(0x1388 * 2400 / 1000); //msecs 12000ms
|
||||
}
|
||||
|
||||
/*
|
||||
void generate_fixed_id_bind(){
|
||||
if(BIND_0){
|
||||
//randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed
|
||||
uint8_t txid[4];
|
||||
//Model_fixed_id = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16);
|
||||
Model_fixed_id=0x332211;
|
||||
txid[0]= (id &0xFF);
|
||||
txid[1] = ((id >> 8) & 0xFF);
|
||||
txid[2] = ((id >> 16) & 0xFF);
|
||||
//txid[3] = ((id >> 24) & 0xFF);
|
||||
eeprom_write_block((const void*)txid,(void*)40,3);
|
||||
devo_bind();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
uint16_t DevoInit()
|
||||
{
|
||||
CYRF_Reset();
|
||||
cyrf_init();
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case 1:
|
||||
num_ch=10;
|
||||
break;
|
||||
case 2:
|
||||
num_ch=12;
|
||||
break;
|
||||
case 3:
|
||||
num_ch=6;
|
||||
break;
|
||||
case 4:
|
||||
num_ch=7;
|
||||
break;
|
||||
default:
|
||||
num_ch=8;
|
||||
break;
|
||||
}
|
||||
DEVO_cyrf_init();
|
||||
CYRF_GetMfgData(cyrfmfg_id);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
CYRF_ConfigCRCSeed(0x0000);
|
||||
CYRF_ConfigSOPCode(sopcodes[0]);
|
||||
set_radio_channels();
|
||||
use_fixed_id = 0;
|
||||
failsafe_pkt = 0;
|
||||
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[0]);
|
||||
DEVO_set_radio_channels();
|
||||
|
||||
hopping_frequency_ptr = hopping_frequency;
|
||||
//
|
||||
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
|
||||
//FIXME: Properly setnumber of channels;
|
||||
pkt_num = 0;
|
||||
ch_idx = 0;
|
||||
txState = 0;
|
||||
//uint8_t txid[4];
|
||||
//
|
||||
|
||||
/*
|
||||
if(BIND_0){
|
||||
Model_fixed_id=0;
|
||||
eeprom_write_block((const void*)0,(void*)40,4);
|
||||
while(1){
|
||||
LED_ON;
|
||||
delay(100);
|
||||
LED_OFF;
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
else{
|
||||
eeprom_read_block((void*)txid,(const void*)40,3);
|
||||
Model_fixed_id=(txid[0] | ((uint32_t)txid[1]<<8) | ((uint32_t)txid[2]<<16));
|
||||
}
|
||||
*/
|
||||
|
||||
if(! Model_fixed_id)
|
||||
{//model fixed ID =0
|
||||
fixed_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)
|
||||
| ((uint32_t)(hopping_frequency[2] ^ cyrfmfg_id[2] ^ cyrfmfg_id[5]) << 0);
|
||||
fixed_id = fixed_id % 1000000;
|
||||
|
||||
packet_count = 0;
|
||||
|
||||
prev_option=option;
|
||||
if(option==0)
|
||||
{
|
||||
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)
|
||||
| ((uint32_t)(hopping_frequency[2] ^ cyrfmfg_id[2] ^ cyrfmfg_id[5]) << 0);
|
||||
MProtocol_id %= 1000000;
|
||||
bind_counter = DEVO_BIND_COUNT;
|
||||
phase = DEVO_BIND;
|
||||
//PROTOCOL_SetBindState(0x1388 * 2400 / 1000); //msecs
|
||||
BIND_IN_PROGRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed_id = Model_fixed_id;
|
||||
use_fixed_id = 1;
|
||||
phase = DEVO_BOUND_1;
|
||||
bind_counter = 0;
|
||||
cyrf_set_bound_sop_code();
|
||||
DEVO_cyrf_set_bound_sop_code();
|
||||
}
|
||||
|
||||
return 2400;
|
||||
}
|
||||
|
||||
|
||||
347
Multiprotocol/E01X_nrf24l01.ino
Normal file
347
Multiprotocol/E01X_nrf24l01.ino
Normal file
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
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
|
||||
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
|
||||
181
Multiprotocol/ESky150_nrf24l01.ino
Normal file
181
Multiprotocol/ESky150_nrf24l01.ino
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
// ESky protocol for small models since 2014 (150, 300, 150X, ...)
|
||||
|
||||
#if defined(ESKY150_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define ESKY150_PAYLOADSIZE 15
|
||||
#define ESKY150_TX_ADDRESS_SIZE 4
|
||||
#define ESKY150_BINDING_PACKET_PERIOD 2000
|
||||
#define ESKY150_SENDING_PACKET_PERIOD 4800
|
||||
|
||||
static void __attribute__((unused)) ESKY150_init()
|
||||
{
|
||||
//Original TX always sets for channelx 0x22 and 0x4a
|
||||
// Use channels 2..79
|
||||
hopping_frequency[0] = rx_tx_addr[3]%37+2;
|
||||
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);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ESKY150_bind_init()
|
||||
{
|
||||
uint8_t ESKY150_addr[ESKY150_TX_ADDRESS_SIZE] = { 0x73, 0x73, 0x74, 0x63 }; //This RX address "sstc" is fixed for ESky2
|
||||
|
||||
// Build packet
|
||||
packet[0] = rx_tx_addr[0];
|
||||
packet[1] = rx_tx_addr[1];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = rx_tx_addr[3];
|
||||
packet[4] = ESKY150_addr[0];
|
||||
packet[5] = ESKY150_addr[1];
|
||||
packet[6] = ESKY150_addr[2];
|
||||
packet[7] = ESKY150_addr[3];
|
||||
packet[8] = rx_tx_addr[0];
|
||||
packet[9] = rx_tx_addr[1];
|
||||
packet[10] = rx_tx_addr[2];
|
||||
packet[11] = rx_tx_addr[3];
|
||||
packet[12] = 0;
|
||||
packet[13] = 0;
|
||||
packet[14] = 0;
|
||||
|
||||
// Bind address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, ESKY150_addr, ESKY150_TX_ADDRESS_SIZE);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, ESKY150_addr, ESKY150_TX_ADDRESS_SIZE);
|
||||
|
||||
// Bind Channel 1
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 1);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ESKY150_send_packet()
|
||||
{
|
||||
// Build packet
|
||||
uint16_t throttle=convert_channel_16b_limit(THROTTLE,1000,2000);
|
||||
uint16_t aileron=convert_channel_16b_limit(AILERON,1000,2000);
|
||||
uint16_t elevator=convert_channel_16b_limit(ELEVATOR,1000,2000);
|
||||
uint16_t rudder=convert_channel_16b_limit(RUDDER,1000,2000);
|
||||
//set unused channels to zero, for compatibility with older 4 channel models
|
||||
uint8_t flight_mode=0;
|
||||
uint16_t aux_ch6=0;
|
||||
uint8_t aux_ch7=0;
|
||||
if(option==1)
|
||||
{
|
||||
flight_mode=ESKY150_convert_2bit_channel(CH5);
|
||||
aux_ch6=convert_channel_16b_limit(CH6,1000,2000);
|
||||
aux_ch7=ESKY150_convert_2bit_channel(CH7);
|
||||
}
|
||||
packet[0] = hopping_frequency[0];
|
||||
packet[1] = hopping_frequency[1];
|
||||
packet[2] = ((flight_mode << 6) & 0xC0) | ((aux_ch7 << 4) & 0x30) | ((throttle >> 8) & 0xFF);
|
||||
packet[3] = throttle & 0xFF;
|
||||
packet[4] = ((aux_ch6 >> 4) & 0xF0) | ((aileron >> 8) & 0xFF); //and 0xFF works as values are anyways not bigger than 12 bits, but faster code like that
|
||||
packet[5] = aileron & 0xFF;
|
||||
packet[6] = (aux_ch6 & 0xF0) | ((elevator >> 8) & 0xFF); //and 0xFF works as values are anyways not bigger than 12 bits, but faster code like that
|
||||
packet[7] = elevator & 0xFF;
|
||||
packet[8] = ((aux_ch6 << 4) & 0xF0) | ((rudder >> 8) & 0xFF); //and 0xFF works as values are anyways not bigger than 12 bits, but faster code like that
|
||||
packet[9] = rudder & 0xFF;
|
||||
// The next 4 Bytes are sint8 trim values (TAER). As trims are already included within normal outputs, these values are set to zero.
|
||||
packet[10] = 0x00;
|
||||
packet[11] = 0x00;
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x00;
|
||||
// Calculate checksum:
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 0; i < 14; ++i)
|
||||
sum += packet[i];
|
||||
packet[14] = sum;
|
||||
|
||||
// Hop on 2 channels
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no&=0x01;
|
||||
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 packet
|
||||
NRF24L01_WritePayload(packet, ESKY150_PAYLOADSIZE);
|
||||
|
||||
//Keep transmit power updated
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
uint8_t ESKY150_convert_2bit_channel(uint8_t num)
|
||||
{
|
||||
if(Channel_data[num] > CHANNEL_MAX_COMMAND)
|
||||
return 0x03;
|
||||
else
|
||||
if(Channel_data[num] < CHANNEL_MIN_COMMAND)
|
||||
return 0x00;
|
||||
else
|
||||
if(Channel_data[num] > CHANNEL_SWITCH)
|
||||
return 0x02;
|
||||
return 0x01;
|
||||
}
|
||||
|
||||
uint16_t ESKY150_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
ESKY150_send_packet();
|
||||
else
|
||||
{
|
||||
NRF24L01_WritePayload(packet, ESKY150_PAYLOADSIZE);
|
||||
if (--bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
// Change TX address from bind to normal mode
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, ESKY150_TX_ADDRESS_SIZE);
|
||||
}
|
||||
return ESKY150_BINDING_PACKET_PERIOD;
|
||||
}
|
||||
return ESKY150_SENDING_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initESKY150(void)
|
||||
{
|
||||
ESKY150_init();
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
bind_counter=3000;
|
||||
ESKY150_bind_init();
|
||||
}
|
||||
hopping_frequency_no=0;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
161
Multiprotocol/ESky_nrf24l01.ino
Normal file
161
Multiprotocol/ESky_nrf24l01.ino
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with hexfet new_protocols/esky_nrf24l01.c dated 2015-02-13
|
||||
|
||||
#if defined(ESKY_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define ESKY_BIND_COUNT 1000
|
||||
#define ESKY_PACKET_PERIOD 3333
|
||||
#define ESKY_PAYLOAD_SIZE 13
|
||||
#define ESKY_PACKET_CHKTIME 100 // Time to wait for packet to be sent (no ACK, so very short)
|
||||
|
||||
static void __attribute__((unused)) ESKY_set_data_address()
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x02); // 4-byte RX/TX address for regular packets
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 4);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ESKY_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
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x00\x00\x00", 3);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\x00\x00\x00", 3);
|
||||
}
|
||||
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);
|
||||
NRF24L01_WriteReg(NRF24L01_14_RX_PW_P3, ESKY_PAYLOAD_SIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_15_RX_PW_P4, ESKY_PAYLOAD_SIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_16_RX_PW_P5, ESKY_PAYLOAD_SIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ESKY_init2()
|
||||
{
|
||||
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) ;
|
||||
|
||||
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;
|
||||
|
||||
// Turn radio power on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ESKY_send_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t rf_ch = 50; // bind channel
|
||||
if (bind)
|
||||
{
|
||||
// Bind packet
|
||||
packet[0] = rx_tx_addr[2];
|
||||
packet[1] = rx_tx_addr[1];
|
||||
packet[2] = rx_tx_addr[0];
|
||||
packet[3] = hopping_frequency[12]; // channel_code encodes pair of channels to transmit on
|
||||
packet[4] = 0x18;
|
||||
packet[5] = 0x29;
|
||||
packet[6] = 0;
|
||||
packet[7] = 0;
|
||||
packet[8] = 0;
|
||||
packet[9] = 0;
|
||||
packet[10] = 0;
|
||||
packet[11] = 0;
|
||||
packet[12] = 0;
|
||||
}
|
||||
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)
|
||||
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;
|
||||
}
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, ESKY_PAYLOAD_SIZE);
|
||||
NRF24L01_SetPower(); //Keep transmit power updated
|
||||
}
|
||||
|
||||
uint16_t ESKY_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
ESKY_send_packet(0);
|
||||
else
|
||||
{
|
||||
ESKY_send_packet(1);
|
||||
if (--bind_counter == 0)
|
||||
{
|
||||
ESKY_set_data_address();
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
return ESKY_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initESKY(void)
|
||||
{
|
||||
bind_counter = ESKY_BIND_COUNT;
|
||||
rx_tx_addr[2] = rx_tx_addr[3]; // Model match
|
||||
rx_tx_addr[3] = 0xBB;
|
||||
ESKY_init();
|
||||
ESKY_init2();
|
||||
return 50000;
|
||||
}
|
||||
|
||||
#endif
|
||||
212
Multiprotocol/FQ777_nrf24l01.ino
Normal file
212
Multiprotocol/FQ777_nrf24l01.ino
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with bikemike FQ777-124.ino
|
||||
|
||||
#if defined(FQ777_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define FQ777_INITIAL_WAIT 500
|
||||
#define FQ777_PACKET_PERIOD 2000
|
||||
#define FQ777_PACKET_SIZE 8
|
||||
#define FQ777_BIND_COUNT 1000
|
||||
#define FQ777_NUM_RF_CHANNELS 4
|
||||
|
||||
enum {
|
||||
FQ777_FLAG_RETURN = 0x40, // 0x40 when not off, !0x40 when one key return
|
||||
FQ777_FLAG_HEADLESS = 0x04,
|
||||
FQ777_FLAG_EXPERT = 0x01,
|
||||
FQ777_FLAG_FLIP = 0x80,
|
||||
};
|
||||
|
||||
const uint8_t ssv_xor[] = {0x80,0x44,0x64,0x75,0x6C,0x71,0x2A,0x36,0x7C,0xF1,0x6E,0x52,0x9,0x9D,0x1F,0x78,0x3F,0xE1,0xEE,0x16,0x6D,0xE8,0x73,0x9,0x15,0xD7,0x92,0xE7,0x3,0xBA};
|
||||
uint8_t FQ777_bind_addr [] = {0xe7,0xe7,0xe7,0xe7,0x67};
|
||||
|
||||
static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, uint8_t* len, uint8_t* payload, uint8_t* packed_payload)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
||||
uint16_t pcf = (*len & 0x3f) << 3;
|
||||
pcf |= (pid & 0x3) << 1;
|
||||
pcf |= 0x00; // noack field
|
||||
|
||||
uint8_t header[7] = {0};
|
||||
header[6] = pcf;
|
||||
header[5] = (pcf >> 7) | (addr[0] << 1);
|
||||
header[4] = (addr[0] >> 7) | (addr[1] << 1);
|
||||
header[3] = (addr[1] >> 7) | (addr[2] << 1);
|
||||
header[2] = (addr[2] >> 7) | (addr[3] << 1);
|
||||
header[1] = (addr[3] >> 7) | (addr[4] << 1);
|
||||
header[0] = (addr[4] >> 7);
|
||||
|
||||
// calculate the crc
|
||||
union
|
||||
{
|
||||
uint8_t bytes[2];
|
||||
uint16_t val;
|
||||
} crc;
|
||||
|
||||
crc.val=0x3c18;
|
||||
for (i = 0; i < 7; ++i)
|
||||
crc.val=crc16_update(crc.val,header[i],8);
|
||||
for (i = 0; i < *len; ++i)
|
||||
crc.val=crc16_update(crc.val,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++];
|
||||
|
||||
// pack the pcf, payload, and crc into packed_payload
|
||||
packed_payload[0] = pcf >> 1;
|
||||
packed_payload[1] = (pcf << 7) | (payload[0] >> 1);
|
||||
|
||||
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);
|
||||
++i;
|
||||
packed_payload[i+2] = (crc.val >> 1 & 0x80 ) | (crc.val >> 1 & 0x7F);
|
||||
++i;
|
||||
packed_payload[i+2] = (crc.val << 7);
|
||||
|
||||
*len += 4;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t packet_len = FQ777_PACKET_SIZE;
|
||||
uint8_t packet_ori[8];
|
||||
if (bind)
|
||||
{
|
||||
// 4,5,6 = address fields
|
||||
// last field is checksum of address fields
|
||||
packet_ori[0] = 0x20;
|
||||
packet_ori[1] = 0x15;
|
||||
packet_ori[2] = 0x05;
|
||||
packet_ori[3] = 0x06;
|
||||
packet_ori[4] = rx_tx_addr[0];
|
||||
packet_ori[5] = rx_tx_addr[1];
|
||||
packet_ori[6] = rx_tx_addr[2];
|
||||
packet_ori[7] = packet_ori[4] + packet_ori[5] + packet_ori[6];
|
||||
}
|
||||
else
|
||||
{
|
||||
// throt, yaw, pitch, roll, trims, flags/left button,00,right button
|
||||
//0-3 0x00-0x64
|
||||
//4 roll/pitch/yaw trims. cycles through one trim at a time - 0-40 trim1, 40-80 trim2, 80-C0 trim3 (center: A0 20 60)
|
||||
//5 flags for throttle button, two buttons above throttle - def: 0x40
|
||||
//6 00 ??
|
||||
//7 checksum - add values in other fields
|
||||
|
||||
|
||||
// Trims are usually done through the radio configuration but leaving the code here just in case...
|
||||
uint8_t trim_mod = packet_count % 144;
|
||||
uint8_t trim_val = 0;
|
||||
if (36 <= trim_mod && trim_mod < 72) // yaw
|
||||
trim_val = 0x20; // don't modify yaw trim
|
||||
else
|
||||
if (108 < trim_mod && trim_mod) // pitch
|
||||
trim_val = 0xA0;
|
||||
else // roll
|
||||
trim_val = 0x60;
|
||||
|
||||
packet_ori[0] = convert_channel_16b_limit(THROTTLE,0,0x64);
|
||||
packet_ori[1] = convert_channel_16b_limit(RUDDER,0,0x64);
|
||||
packet_ori[2] = convert_channel_16b_limit(ELEVATOR,0,0x64);
|
||||
packet_ori[3] = convert_channel_16b_limit(AILERON,0,0x64);
|
||||
packet_ori[4] = trim_val; // calculated above
|
||||
packet_ori[5] = GET_FLAG(CH5_SW, FQ777_FLAG_FLIP)
|
||||
| GET_FLAG(CH7_SW, FQ777_FLAG_HEADLESS)
|
||||
| GET_FLAG(!CH6_SW, FQ777_FLAG_RETURN)
|
||||
| GET_FLAG(CH8_SW,FQ777_FLAG_EXPERT);
|
||||
packet_ori[6] = 0x00;
|
||||
// calculate checksum
|
||||
uint8_t checksum = 0;
|
||||
for (int i = 0; i < 7; ++i)
|
||||
checksum += packet_ori[i];
|
||||
packet_ori[7] = checksum;
|
||||
|
||||
packet_count++;
|
||||
}
|
||||
|
||||
ssv_pack_dpl( (0 == bind) ? rx_tx_addr : FQ777_bind_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++]);
|
||||
hopping_frequency_no %= FQ777_NUM_RF_CHANNELS;
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, packet_len);
|
||||
NRF24L01_WritePayload(packet, packet_len);
|
||||
NRF24L01_WritePayload(packet, packet_len);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FQ777_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)
|
||||
{
|
||||
FQ777_send_packet(1);
|
||||
bind_counter--;
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
FQ777_send_packet(0);
|
||||
return FQ777_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initFQ777(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = FQ777_BIND_COUNT;
|
||||
packet_count=0;
|
||||
hopping_frequency[0] = 0x4D;
|
||||
hopping_frequency[1] = 0x43;
|
||||
hopping_frequency[2] = 0x27;
|
||||
hopping_frequency[3] = 0x07;
|
||||
hopping_frequency_no=0;
|
||||
rx_tx_addr[2] = 0x00;
|
||||
rx_tx_addr[3] = 0xe7;
|
||||
rx_tx_addr[4] = 0x67;
|
||||
FQ777_init();
|
||||
return FQ777_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
225
Multiprotocol/FY326_nrf24l01.ino
Normal file
225
Multiprotocol/FY326_nrf24l01.ino
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with hexfet new_protocols/fy326_nrf24l01.c dated 2015-07-29
|
||||
|
||||
#if defined(FY326_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define FY326_INITIAL_WAIT 500
|
||||
#define FY326_PACKET_PERIOD 1500
|
||||
#define FY326_PACKET_CHKTIME 300
|
||||
#define FY326_PACKET_SIZE 15
|
||||
#define FY326_BIND_COUNT 16
|
||||
#define FY326_RF_BIND_CHANNEL 0x17
|
||||
#define FY326_NUM_RF_CHANNELS 5
|
||||
|
||||
enum {
|
||||
FY326_BIND1=0,
|
||||
FY326_BIND2,
|
||||
FY326_DATA,
|
||||
FY319_BIND1,
|
||||
FY319_BIND2,
|
||||
};
|
||||
|
||||
#define rxid channel
|
||||
|
||||
#define CHAN_TO_TRIM(chanval) ((chanval/10)-10)
|
||||
static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
|
||||
{
|
||||
packet[0] = rx_tx_addr[3];
|
||||
if(bind)
|
||||
packet[1] = 0x55;
|
||||
else
|
||||
packet[1] = GET_FLAG(CH7_SW, 0x80) // Headless
|
||||
| GET_FLAG(CH6_SW, 0x40) // RTH
|
||||
| GET_FLAG(CH5_SW, 0x02) // Flip
|
||||
| GET_FLAG(CH9_SW, 0x01) // Calibrate
|
||||
| GET_FLAG(CH8_SW, 0x04); // Expert
|
||||
packet[2] = convert_channel_16b_limit(AILERON, 0, 200); // aileron
|
||||
packet[3] = convert_channel_16b_limit(ELEVATOR, 0, 200); // elevator
|
||||
packet[4] = convert_channel_16b_limit(RUDDER, 0, 200); // rudder
|
||||
packet[5] = convert_channel_16b_limit(THROTTLE, 0, 200); // throttle
|
||||
if(sub_protocol==FY319)
|
||||
{
|
||||
packet[6] = convert_channel_8b(AILERON);
|
||||
packet[7] = convert_channel_8b(ELEVATOR);
|
||||
packet[8] = convert_channel_8b(RUDDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[6] = rx_tx_addr[0];
|
||||
packet[7] = rx_tx_addr[1];
|
||||
packet[8] = rx_tx_addr[2];
|
||||
}
|
||||
packet[9] = CHAN_TO_TRIM(packet[2]); // aileron_trim;
|
||||
packet[10] = CHAN_TO_TRIM(packet[3]); // elevator_trim;
|
||||
packet[11] = CHAN_TO_TRIM(packet[4]); // rudder_trim;
|
||||
packet[12] = 0; // throttle_trim;
|
||||
packet[13] = rxid;
|
||||
packet[14] = rx_tx_addr[4];
|
||||
|
||||
if (bind)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, FY326_RF_BIND_CHANNEL);
|
||||
else
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no %= FY326_NUM_RF_CHANNELS;
|
||||
}
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
NRF24L01_WritePayload(packet, FY326_PACKET_SIZE);
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FY326_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);
|
||||
}
|
||||
|
||||
uint16_t FY326_callback()
|
||||
{
|
||||
switch (phase)
|
||||
{
|
||||
case FY319_BIND1:
|
||||
if(NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{
|
||||
NRF24L01_ReadPayload(packet, FY326_PACKET_SIZE);
|
||||
rxid = packet[13];
|
||||
packet[0] = rx_tx_addr[3];
|
||||
packet[1] = 0x80;
|
||||
packet[14]= rx_tx_addr[4];
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
bind_counter = 255;
|
||||
for(uint8_t i=2; i<6; i++)
|
||||
packet[i] = hopping_frequency[0];
|
||||
phase = FY319_BIND2;
|
||||
}
|
||||
return FY326_PACKET_CHKTIME;
|
||||
break;
|
||||
case FY319_BIND2:
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, FY326_PACKET_SIZE);
|
||||
if(bind_counter == 250)
|
||||
packet[1] = 0x40;
|
||||
if(--bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
phase = FY326_DATA;
|
||||
}
|
||||
break;
|
||||
case FY326_BIND1:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready
|
||||
NRF24L01_ReadPayload(packet, FY326_PACKET_SIZE);
|
||||
rxid = packet[13];
|
||||
rx_tx_addr[0] = 0xAA;
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
BIND_DONE;
|
||||
phase = FY326_DATA;
|
||||
}
|
||||
else
|
||||
if (bind_counter-- == 0)
|
||||
{
|
||||
bind_counter = FY326_BIND_COUNT;
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
FY326_send_packet(1);
|
||||
phase = FY326_BIND2;
|
||||
return FY326_PACKET_CHKTIME;
|
||||
}
|
||||
break;
|
||||
case FY326_BIND2:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS))
|
||||
{ // TX data sent -> switch to RX mode
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
phase = FY326_BIND1;
|
||||
}
|
||||
else
|
||||
return FY326_PACKET_CHKTIME;
|
||||
break;
|
||||
case FY326_DATA:
|
||||
FY326_send_packet(0);
|
||||
break;
|
||||
}
|
||||
return FY326_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FY326_initialize_txid()
|
||||
{
|
||||
hopping_frequency[0] = (rx_tx_addr[0]&0x0f);
|
||||
hopping_frequency[1] = 0x10 + (rx_tx_addr[0] >> 4);
|
||||
hopping_frequency[2] = 0x20 + (rx_tx_addr[1]&0x0f);
|
||||
hopping_frequency[3] = 0x30 + (rx_tx_addr[1] >> 4);
|
||||
hopping_frequency[4] = 0x40 + (rx_tx_addr[2] >> 4);
|
||||
if(sub_protocol==FY319)
|
||||
for(uint8_t i=0;i<5;i++)
|
||||
hopping_frequency[i]=rx_tx_addr[0] & ~0x80;
|
||||
}
|
||||
|
||||
uint16_t initFY326(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
rxid = 0xAA;
|
||||
bind_counter = FY326_BIND_COUNT;
|
||||
FY326_initialize_txid();
|
||||
FY326_init();
|
||||
if(sub_protocol==FY319)
|
||||
{
|
||||
phase=FY319_BIND1;
|
||||
}
|
||||
else
|
||||
phase=FY326_BIND1;
|
||||
return FY326_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -12,6 +12,7 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with hexfet new_protocols/flysky_a7105.c dated 2015-09-28
|
||||
|
||||
#if defined(FLYSKY_A7105_INO)
|
||||
|
||||
@@ -20,31 +21,12 @@
|
||||
//FlySky constants & variables
|
||||
#define FLYSKY_BIND_COUNT 2500
|
||||
|
||||
const uint8_t PROGMEM tx_channels[] = {
|
||||
0x0a, 0x5a, 0x14, 0x64, 0x1e, 0x6e, 0x28, 0x78, 0x32, 0x82, 0x3c, 0x8c, 0x46, 0x96, 0x50, 0xa0,
|
||||
0xa0, 0x50, 0x96, 0x46, 0x8c, 0x3c, 0x82, 0x32, 0x78, 0x28, 0x6e, 0x1e, 0x64, 0x14, 0x5a, 0x0a,
|
||||
0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x46, 0x96, 0x1e, 0x6e, 0x3c, 0x8c, 0x28, 0x78, 0x32, 0x82,
|
||||
0x82, 0x32, 0x78, 0x28, 0x8c, 0x3c, 0x6e, 0x1e, 0x96, 0x46, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a,
|
||||
0x28, 0x78, 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96,
|
||||
0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, 0x78, 0x28,
|
||||
0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, 0x14, 0x64,
|
||||
0x64, 0x14, 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50,
|
||||
0x50, 0xa0, 0x46, 0x96, 0x3c, 0x8c, 0x28, 0x78, 0x0a, 0x5a, 0x32, 0x82, 0x1e, 0x6e, 0x14, 0x64,
|
||||
0x64, 0x14, 0x6e, 0x1e, 0x82, 0x32, 0x5a, 0x0a, 0x78, 0x28, 0x8c, 0x3c, 0x96, 0x46, 0xa0, 0x50,
|
||||
0x46, 0x96, 0x3c, 0x8c, 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64,
|
||||
0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, 0x8c, 0x3c, 0x96, 0x46,
|
||||
0x46, 0x96, 0x0a, 0x5a, 0x3c, 0x8c, 0x14, 0x64, 0x50, 0xa0, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82,
|
||||
0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0xa0, 0x50, 0x64, 0x14, 0x8c, 0x3c, 0x5a, 0x0a, 0x96, 0x46,
|
||||
0x46, 0x96, 0x0a, 0x5a, 0x50, 0xa0, 0x3c, 0x8c, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64,
|
||||
0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0x8c, 0x3c, 0xa0, 0x50, 0x5a, 0x0a, 0x96, 0x46
|
||||
};
|
||||
|
||||
enum {
|
||||
// flags going to byte 10
|
||||
FLAG_V9X9_VIDEO = 0x40,
|
||||
FLAG_V9X9_CAMERA= 0x80,
|
||||
// flags going to byte 12
|
||||
FLAG_V9X9_UNK = 0x10, // undocumented ?
|
||||
FLAG_V9X9_FLIP = 0x10,
|
||||
FLAG_V9X9_LED = 0x20,
|
||||
};
|
||||
|
||||
@@ -68,48 +50,45 @@ enum {
|
||||
FLAG_V912_BTMBTN= 0x80,
|
||||
};
|
||||
|
||||
uint8_t chanrow;
|
||||
uint8_t chancol;
|
||||
uint8_t chanoffset;
|
||||
const uint8_t PROGMEM V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ?
|
||||
0x49, 0x49, 0x49, 0x49, 0x49, };
|
||||
|
||||
void flysky_apply_extension_flags()
|
||||
static void __attribute__((unused)) flysky_apply_extension_flags()
|
||||
{
|
||||
const uint8_t V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ?
|
||||
0x49, 0x49, 0x49, 0x49, 0x49, };
|
||||
static uint8_t seq_counter;
|
||||
switch(sub_protocol) {
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case V9X9:
|
||||
if(Servo_data[AUX1] > PPM_SWITCH)
|
||||
packet[12] |= FLAG_V9X9_UNK;
|
||||
if(Servo_data[AUX2] > PPM_SWITCH)
|
||||
if(CH5_SW)
|
||||
packet[12] |= FLAG_V9X9_FLIP;
|
||||
if(CH6_SW)
|
||||
packet[12] |= FLAG_V9X9_LED;
|
||||
if(Servo_data[AUX3] > PPM_SWITCH)
|
||||
if(CH7_SW)
|
||||
packet[10] |= FLAG_V9X9_CAMERA;
|
||||
if(Servo_data[AUX4] > PPM_SWITCH)
|
||||
if(CH8_SW)
|
||||
packet[10] |= FLAG_V9X9_VIDEO;
|
||||
break;
|
||||
|
||||
case V6X6:
|
||||
packet[13] = 0x03; // 3 = 100% rate (0=40%, 1=60%, 2=80%)
|
||||
packet[14] = 0x00;
|
||||
if(Servo_data[AUX1] > PPM_SWITCH)
|
||||
if(CH5_SW)
|
||||
packet[14] |= FLAG_V6X6_FLIP;
|
||||
if(Servo_data[AUX2] > PPM_SWITCH)
|
||||
if(CH6_SW)
|
||||
packet[14] |= FLAG_V6X6_LED;
|
||||
if(Servo_data[AUX3] > PPM_SWITCH)
|
||||
if(CH7_SW)
|
||||
packet[14] |= FLAG_V6X6_CAMERA;
|
||||
if(Servo_data[AUX4] > PPM_SWITCH)
|
||||
if(CH8_SW)
|
||||
packet[14] |= FLAG_V6X6_VIDEO;
|
||||
if(Servo_data[AUX5] > PPM_SWITCH)
|
||||
if(CH9_SW)
|
||||
{
|
||||
packet[13] |= FLAG_V6X6_HLESS1;
|
||||
packet[14] |= FLAG_V6X6_HLESS2;
|
||||
}
|
||||
if(Servo_data[AUX6] > PPM_SWITCH) //use option to manipulate these bytes
|
||||
if(CH10_SW)
|
||||
packet[14] |= FLAG_V6X6_RTH;
|
||||
if(Servo_data[AUX7] > PPM_SWITCH)
|
||||
if(CH11_SW)
|
||||
packet[14] |= FLAG_V6X6_XCAL;
|
||||
if(Servo_data[AUX8] > PPM_SWITCH)
|
||||
if(CH12_SW)
|
||||
packet[14] |= FLAG_V6X6_YCAL;
|
||||
packet[15] = 0x10; // unknown
|
||||
packet[16] = 0x10; // unknown
|
||||
@@ -120,20 +99,20 @@ void flysky_apply_extension_flags()
|
||||
break;
|
||||
|
||||
case V912:
|
||||
seq_counter++;
|
||||
if( seq_counter > 9)
|
||||
seq_counter = 0;
|
||||
packet_count++;
|
||||
if( packet_count > 9)
|
||||
packet_count = 0;
|
||||
packet[12] |= 0x20; // bit 6 is always set ?
|
||||
packet[13] = 0x00; // unknown
|
||||
packet[14] = 0x00;
|
||||
if(Servo_data[AUX1] > PPM_SWITCH)
|
||||
packet[14] |= FLAG_V912_BTMBTN;
|
||||
if(Servo_data[AUX2] > PPM_SWITCH)
|
||||
if(CH5_SW)
|
||||
packet[14] = FLAG_V912_BTMBTN;
|
||||
if(CH6_SW)
|
||||
packet[14] |= FLAG_V912_TOPBTN;
|
||||
packet[15] = 0x27; // [15] and [16] apparently hold an analog channel with a value lower than 1000
|
||||
packet[16] = 0x03; // maybe it's there for a pitch channel for a CP copter ?
|
||||
packet[17] = V912_X17_SEQ[seq_counter]; // not sure what [17] & [18] are for
|
||||
if(seq_counter == 0) // V912 Rx does not even read those bytes... [17-20]
|
||||
packet[17] = pgm_read_byte( &V912_X17_SEQ[packet_count] ) ; // not sure what [17] & [18] are for
|
||||
if(packet_count == 0) // V912 Rx does not even read those bytes... [17-20]
|
||||
packet[18] = 0x02;
|
||||
else
|
||||
packet[18] = 0x00;
|
||||
@@ -141,70 +120,125 @@ void flysky_apply_extension_flags()
|
||||
packet[20] = 0x00; // unknown
|
||||
break;
|
||||
|
||||
case CX20:
|
||||
packet[19] = 0x00; // unknown
|
||||
packet[20] = (hopping_frequency_no<<4)|0x0A;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void flysky_build_packet(uint8_t init)
|
||||
static void __attribute__((unused)) flysky_build_packet(uint8_t init)
|
||||
{
|
||||
uint8_t i;
|
||||
//servodata timing range for flysky.
|
||||
////-100% =~ 0x03e8//=1000us(min)
|
||||
//-100% =~ 0x03e8//=1000us(min)
|
||||
//+100% =~ 0x07ca//=1994us(max)
|
||||
//Center = 0x5d9//=1497us(center)
|
||||
//channel order AIL;ELE;THR;RUD;AUX1;AUX2;AUX3;AUX4
|
||||
//channel order AIL;ELE;THR;RUD;CH5;CH6;CH7;CH8
|
||||
packet[0] = init ? 0xaa : 0x55;
|
||||
packet[1] = rx_tx_addr[3];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = rx_tx_addr[1];
|
||||
packet[4] = rx_tx_addr[0];
|
||||
uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4};
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
packet[5+2*i]=lowByte(Servo_data[ch[i]]); //low byte of servo timing(1000-2000us)
|
||||
packet[6+2*i]=highByte(Servo_data[ch[i]]); //high byte of servo timing(1000-2000us)
|
||||
uint16_t temp=convert_channel_ppm(CH_AETR[i]);
|
||||
if(sub_protocol == CX20 && CH_AETR[i]==ELEVATOR)
|
||||
temp=3000-temp;
|
||||
packet[5 + i*2]=temp&0xFF; //low byte of servo timing(1000-2000us)
|
||||
packet[6 + i*2]=(temp>>8)&0xFF; //high byte of servo timing(1000-2000us)
|
||||
}
|
||||
flysky_apply_extension_flags();
|
||||
}
|
||||
|
||||
uint16_t ReadFlySky()
|
||||
{
|
||||
if (bind_counter)
|
||||
#ifndef FORCE_FLYSKY_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
flysky_build_packet(1);
|
||||
A7105_WriteData(21, 1);
|
||||
bind_counter--;
|
||||
if (! bind_counter)
|
||||
BIND_DONE;
|
||||
}
|
||||
flysky_build_packet(1);
|
||||
A7105_WriteData(21, 1);
|
||||
bind_counter--;
|
||||
if (bind_counter==0)
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
flysky_build_packet(0);
|
||||
A7105_WriteData(21, pgm_read_byte_near(&tx_channels[chanrow*16+chancol])-chanoffset);
|
||||
chancol = (chancol + 1) % 16;
|
||||
if (! chancol) //Keep transmit power updated
|
||||
A7105_SetPower();
|
||||
}
|
||||
return 1460;
|
||||
flysky_build_packet(0);
|
||||
A7105_WriteData(21, hopping_frequency[hopping_frequency_no & 0x0F]);
|
||||
A7105_SetPower();
|
||||
}
|
||||
hopping_frequency_no++;
|
||||
|
||||
if(sub_protocol==CX20)
|
||||
return 3984;
|
||||
else
|
||||
return 1510; //1460 on deviation but not working with the latest V911 bricks... Turnigy 9X v2 is 1533, Flysky TX for 9XR/9XR Pro is 1510, V911 TX is 1490.
|
||||
}
|
||||
|
||||
uint16_t initFlySky() {
|
||||
//A7105_Reset();
|
||||
A7105_Init(INIT_FLYSKY); //flysky_init();
|
||||
|
||||
if (rx_tx_addr[3] > 0x90) // limit offset to 9 as higher values don't work with some RX (ie V912)
|
||||
rx_tx_addr[3] = rx_tx_addr[3] - 0x70;
|
||||
chanrow=rx_tx_addr[3] % 16;
|
||||
chancol=0;
|
||||
chanoffset=rx_tx_addr[3] / 16;
|
||||
|
||||
const uint8_t PROGMEM tx_channels[8][4] = {
|
||||
{ 0x12, 0x34, 0x56, 0x78},
|
||||
{ 0x18, 0x27, 0x36, 0x45},
|
||||
{ 0x41, 0x82, 0x36, 0x57},
|
||||
{ 0x84, 0x13, 0x65, 0x72},
|
||||
{ 0x87, 0x64, 0x15, 0x32},
|
||||
{ 0x76, 0x84, 0x13, 0x52},
|
||||
{ 0x71, 0x62, 0x84, 0x35},
|
||||
{ 0x71, 0x86, 0x43, 0x52}
|
||||
};
|
||||
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
uint16_t initFlySky()
|
||||
{
|
||||
uint8_t chanrow;
|
||||
uint8_t chanoffset;
|
||||
uint8_t temp;
|
||||
|
||||
A7105_Init();
|
||||
|
||||
// limit offset to 9 as higher values don't work with some RX (ie V912)
|
||||
// limit offset to 9 as CX20 repeats the same channels after that
|
||||
if ((rx_tx_addr[3]&0xF0) > 0x90)
|
||||
rx_tx_addr[3]=rx_tx_addr[3]-0x70;
|
||||
|
||||
// Build frequency hop table
|
||||
chanrow=rx_tx_addr[3] & 0x0F;
|
||||
chanoffset=rx_tx_addr[3]/16;
|
||||
for(uint8_t i=0;i<16;i++)
|
||||
{
|
||||
temp=pgm_read_byte_near(&tx_channels[chanrow>>1][i>>2]);
|
||||
if(i&0x02)
|
||||
temp&=0x0F;
|
||||
else
|
||||
temp>>=4;
|
||||
temp*=0x0A;
|
||||
if(i&0x01)
|
||||
temp+=0x50;
|
||||
if(sub_protocol==CX20)
|
||||
{
|
||||
if(temp==0x0A)
|
||||
temp+=0x37;
|
||||
if(temp==0xA0)
|
||||
{
|
||||
if (chanoffset<4)
|
||||
temp=0x37;
|
||||
else if (chanoffset<9)
|
||||
temp=0x2D;
|
||||
else
|
||||
temp=0x29;
|
||||
}
|
||||
}
|
||||
hopping_frequency[((chanrow&1)?15-i:i)]=temp-chanoffset;
|
||||
}
|
||||
hopping_frequency_no=0;
|
||||
packet_count=0;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
bind_counter = FLYSKY_BIND_COUNT;
|
||||
else
|
||||
bind_counter = 0;
|
||||
return 2400;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
202
Multiprotocol/FrSkyD_cc2500.ino
Normal file
202
Multiprotocol/FrSkyD_cc2500.ino
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(FRSKYD_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
static void __attribute__((unused)) frsky2way_init(uint8_t bind)
|
||||
{
|
||||
FRSKY_init_cc2500(FRSKYD_cc2500_conf);
|
||||
|
||||
CC2500_WriteReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]);
|
||||
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05);
|
||||
CC2500_Strobe(CC2500_SIDLE); // Go to idle...
|
||||
//
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, 0x00);
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
//#######END INIT########
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frsky2way_build_bind_packet()
|
||||
{
|
||||
//11 03 01 d7 2d 00 00 1e 3c 5b 78 00 00 00 00 00 00 01
|
||||
//11 03 01 19 3e 00 02 8e 2f bb 5c 00 00 00 00 00 00 01
|
||||
packet[0] = 0x11;
|
||||
packet[1] = 0x03;
|
||||
packet[2] = 0x01;
|
||||
packet[3] = rx_tx_addr[3];
|
||||
packet[4] = rx_tx_addr[2];
|
||||
uint16_t idx = ((state -FRSKY_BIND) % 10) * 5;
|
||||
packet[5] = idx;
|
||||
packet[6] = hopping_frequency[idx++];
|
||||
packet[7] = hopping_frequency[idx++];
|
||||
packet[8] = hopping_frequency[idx++];
|
||||
packet[9] = hopping_frequency[idx++];
|
||||
packet[10] = hopping_frequency[idx++];
|
||||
packet[11] = 0x00;
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x00;
|
||||
packet[14] = 0x00;
|
||||
packet[15] = 0x00;
|
||||
packet[16] = 0x00;
|
||||
packet[17] = 0x01;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frsky2way_data_frame()
|
||||
{//pachet[4] is telemetry user frame counter(hub)
|
||||
//11 d7 2d 22 00 01 c9 c9 ca ca 88 88 ca ca c9 ca 88 88
|
||||
//11 57 12 00 00 01 f2 f2 f2 f2 06 06 ca ca ca ca 18 18
|
||||
packet[0] = 0x11; //Length
|
||||
packet[1] = rx_tx_addr[3];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = counter;//
|
||||
#if defined TELEMETRY
|
||||
packet[4] = telemetry_counter;
|
||||
#else
|
||||
packet[4] = 0x00;
|
||||
#endif
|
||||
|
||||
packet[5] = 0x01;
|
||||
//
|
||||
packet[10] = 0;
|
||||
packet[11] = 0;
|
||||
packet[16] = 0;
|
||||
packet[17] = 0;
|
||||
for(uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
uint16_t value;
|
||||
value = convert_channel_frsky(i);
|
||||
if(i < 4)
|
||||
{
|
||||
packet[6+i] = value & 0xff;
|
||||
packet[10+(i>>1)] |= ((value >> 8) & 0x0f) << (4 *(i & 0x01));
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[8+i] = value & 0xff;
|
||||
packet[16+((i-4)>>1)] |= ((value >> 8) & 0x0f) << (4 * ((i-4) & 0x01));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initFrSky_2way()
|
||||
{
|
||||
Frsky_init_hop();
|
||||
packet_count=0;
|
||||
#if defined TELEMETRY
|
||||
init_frskyd_link_telemetry();
|
||||
#endif
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
frsky2way_init(1);
|
||||
state = FRSKY_BIND;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = FRSKY_BIND_DONE;
|
||||
}
|
||||
return 10000;
|
||||
}
|
||||
|
||||
uint16_t ReadFrSky_2way()
|
||||
{
|
||||
if (state < FRSKY_BIND_DONE)
|
||||
{
|
||||
frsky2way_build_bind_packet();
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, 0x00);
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
|
||||
CC2500_Strobe(CC2500_SFRX);//0x3A
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
if(IS_BIND_DONE)
|
||||
state = FRSKY_BIND_DONE;
|
||||
else
|
||||
state++;
|
||||
return 9000;
|
||||
}
|
||||
if (state == FRSKY_BIND_DONE)
|
||||
{
|
||||
state = FRSKY_DATA2;
|
||||
frsky2way_init(0);
|
||||
counter = 0;
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
if (state == FRSKY_DATA5)
|
||||
{
|
||||
CC2500_Strobe(CC2500_SRX);//0x34 RX enable
|
||||
state = FRSKY_DATA1;
|
||||
return 9200;
|
||||
}
|
||||
counter = (counter + 1) % 188;
|
||||
if (state == FRSKY_DATA4)
|
||||
{ //telemetry receive
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[counter % 47]);
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
|
||||
state++;
|
||||
return 1300;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state == FRSKY_DATA1)
|
||||
{
|
||||
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if (len && len<=(0x11+3))// 20bytes
|
||||
{
|
||||
CC2500_ReadData(pkt, len); //received telemetry packets
|
||||
#if defined(TELEMETRY)
|
||||
if(pkt[len-1] & 0x80)
|
||||
{//with valid crc
|
||||
packet_count=0;
|
||||
frsky_check_telemetry(pkt,len); //check if valid telemetry packets and buffer them.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_count++;
|
||||
// restart sequence on missed packet - might need count or timeout instead of one missed
|
||||
if(packet_count>100)
|
||||
{//~1sec
|
||||
packet_count=0;
|
||||
#if defined TELEMETRY
|
||||
telemetry_link=0;//no link frames
|
||||
pkt[6]=0;//no user frames.
|
||||
#endif
|
||||
}
|
||||
}
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower(); // Set tx_power
|
||||
}
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[counter % 47]);
|
||||
if ( prev_option != option )
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
|
||||
prev_option = option ;
|
||||
}
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
frsky2way_data_frame();
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
state++;
|
||||
}
|
||||
return state == FRSKY_DATA4 ? 7500 : 9000;
|
||||
}
|
||||
#endif
|
||||
165
Multiprotocol/FrSkyV_cc2500.ino
Normal file
165
Multiprotocol/FrSkyV_cc2500.ino
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
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(FRSKYV_CC2500_INO)
|
||||
|
||||
#define FRSKYV_BIND_COUNT 200
|
||||
|
||||
enum {
|
||||
FRSKYV_DATA1=0,
|
||||
FRSKYV_DATA2,
|
||||
FRSKYV_DATA3,
|
||||
FRSKYV_DATA4,
|
||||
FRSKYV_DATA5
|
||||
};
|
||||
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
static uint8_t __attribute__((unused)) FRSKYV_crc8(uint8_t result, uint8_t *data, uint8_t len)
|
||||
{
|
||||
for(uint8_t i = 0; i < len; i++)
|
||||
{
|
||||
result = result ^ data[i];
|
||||
for(uint8_t j = 0; j < 8; j++)
|
||||
if(result & 0x80)
|
||||
result = (result << 1) ^ 0x07;
|
||||
else
|
||||
result = result << 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) FRSKYV_crc8_le(uint8_t *data, uint8_t len)
|
||||
{
|
||||
uint8_t result = 0xD6;
|
||||
|
||||
for(uint8_t i = 0; i < len; i++)
|
||||
{
|
||||
result = result ^ data[i];
|
||||
for(uint8_t j = 0; j < 8; j++)
|
||||
if(result & 0x01)
|
||||
result = (result >> 1) ^ 0x83;
|
||||
else
|
||||
result = result >> 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FRSKYV_build_bind_packet()
|
||||
{
|
||||
//0e 03 01 57 12 00 06 0b 10 15 1a 00 00 00 61
|
||||
packet[0] = 0x0e; //Length
|
||||
packet[1] = 0x03; //Packet type
|
||||
packet[2] = 0x01; //Packet type
|
||||
packet[3] = rx_tx_addr[3];
|
||||
packet[4] = rx_tx_addr[2];
|
||||
packet[5] = (binding_idx % 10) * 5;
|
||||
packet[6] = packet[5] * 5 + 6;
|
||||
packet[7] = packet[5] * 5 + 11;
|
||||
packet[8] = packet[5] * 5 + 16;
|
||||
packet[9] = packet[5] * 5 + 21;
|
||||
packet[10] = packet[5] * 5 + 26;
|
||||
packet[11] = 0x00;
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x00;
|
||||
packet[14] = FRSKYV_crc8(0x93, packet, 14);
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) FRSKYV_calc_channel()
|
||||
{
|
||||
uint32_t temp=seed;
|
||||
temp = (temp * 0xaa) % 0x7673;
|
||||
seed = temp;
|
||||
return (seed & 0xff) % 0x32;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FRSKYV_build_data_packet()
|
||||
{
|
||||
uint8_t idx = 0; // transmit lower channels
|
||||
|
||||
packet[0] = 0x0e;
|
||||
packet[1] = rx_tx_addr[3];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = seed & 0xff;
|
||||
packet[4] = seed >> 8;
|
||||
if (phase == FRSKYV_DATA1 || phase == FRSKYV_DATA3)
|
||||
packet[5] = 0x0f;
|
||||
else
|
||||
if(phase == FRSKYV_DATA2 || phase == FRSKYV_DATA4)
|
||||
{
|
||||
packet[5] = 0xf0;
|
||||
idx=4; // transmit upper channels
|
||||
}
|
||||
else
|
||||
packet[5] = 0x00;
|
||||
for(uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
uint16_t value = convert_channel_frsky(i+idx);
|
||||
packet[2*i + 6] = value & 0xff;
|
||||
packet[2*i + 7] = value >> 8;
|
||||
}
|
||||
packet[14] = FRSKYV_crc8(crc8, packet, 14);
|
||||
}
|
||||
|
||||
uint16_t ReadFRSKYV()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
{ // Normal operation
|
||||
uint8_t chan = FRSKYV_calc_channel();
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
if (option != prev_option)
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
prev_option=option;
|
||||
}
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, chan * 5 + 6);
|
||||
FRSKYV_build_data_packet();
|
||||
|
||||
if (phase == FRSKYV_DATA5)
|
||||
{
|
||||
CC2500_SetPower();
|
||||
phase = FRSKYV_DATA1;
|
||||
}
|
||||
else
|
||||
phase++;
|
||||
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
return 9006;
|
||||
}
|
||||
// Bind mode
|
||||
FRSKYV_build_bind_packet();
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, 0x00);
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
binding_idx++;
|
||||
if(binding_idx>=FRSKYV_BIND_COUNT)
|
||||
BIND_DONE;
|
||||
return 53460;
|
||||
}
|
||||
|
||||
uint16_t initFRSKYV()
|
||||
{
|
||||
//ID is 15 bits. Using rx_tx_addr[2] and rx_tx_addr[3] since we want to use RX_Num for model match
|
||||
rx_tx_addr[2]&=0x7F;
|
||||
crc8 = FRSKYV_crc8_le(rx_tx_addr+2, 2);
|
||||
|
||||
FRSKY_init_cc2500(FRSKYV_cc2500_conf);
|
||||
seed = 1;
|
||||
binding_idx=0;
|
||||
phase = FRSKYV_DATA1;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,21 +1,358 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/* **************************
|
||||
* By Midelic on RCGroups *
|
||||
**************************
|
||||
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(FRSKYX_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
uint8_t FrX_chanskip;
|
||||
uint8_t FrX_send_seq ;
|
||||
uint8_t FrX_receive_seq ;
|
||||
|
||||
#define FRX_FAILSAFE_TIMEOUT 1032
|
||||
|
||||
static void __attribute__((unused)) frskyX_set_start(uint8_t ch )
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[ch]);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[ch]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frskyX_init()
|
||||
{
|
||||
FRSKY_init_cc2500((sub_protocol&2)?FRSKYXEU_cc2500_conf:FRSKYX_cc2500_conf); // LBT or FCC
|
||||
//
|
||||
for(uint8_t c=0;c < 48;c++)
|
||||
{//calibrate hop channels
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR,hopping_frequency[c]);
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);//
|
||||
calData[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
}
|
||||
//#######END INIT########
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frskyX_initialize_data(uint8_t adr)
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
|
||||
CC2500_WriteReg(CC2500_18_MCSM0, 0x8);
|
||||
CC2500_WriteReg(CC2500_09_ADDR, adr ? 0x03 : rx_tx_addr[3]);
|
||||
CC2500_WriteReg(CC2500_07_PKTCTRL1,0x05);
|
||||
}
|
||||
|
||||
//**CRC**
|
||||
const uint16_t PROGMEM frskyX_CRC_Short[]={
|
||||
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
|
||||
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7 };
|
||||
static uint16_t __attribute__((unused)) frskyX_CRCTable(uint8_t val)
|
||||
{
|
||||
uint16_t word ;
|
||||
word = pgm_read_word(&frskyX_CRC_Short[val&0x0F]) ;
|
||||
val /= 16 ;
|
||||
return word ^ (0x1081 * val) ;
|
||||
}
|
||||
static uint16_t __attribute__((unused)) frskyX_crc_x(uint8_t *data, uint8_t len)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
for(uint8_t i=0; i < len; i++)
|
||||
crc = (crc<<8) ^ frskyX_CRCTable((uint8_t)(crc>>8) ^ *data++);
|
||||
return crc;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frskyX_build_bind_packet()
|
||||
{
|
||||
packet[0] = (sub_protocol & 2 ) ? 0x20 : 0x1D ; // LBT or FCC
|
||||
packet[1] = 0x03;
|
||||
packet[2] = 0x01;
|
||||
//
|
||||
packet[3] = rx_tx_addr[3];
|
||||
packet[4] = rx_tx_addr[2];
|
||||
int idx = ((state -FRSKY_BIND) % 10) * 5;
|
||||
packet[5] = idx;
|
||||
packet[6] = hopping_frequency[idx++];
|
||||
packet[7] = hopping_frequency[idx++];
|
||||
packet[8] = hopping_frequency[idx++];
|
||||
packet[9] = hopping_frequency[idx++];
|
||||
packet[10] = hopping_frequency[idx++];
|
||||
packet[11] = 0x02;
|
||||
packet[12] = RX_num;
|
||||
//
|
||||
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
|
||||
memset(&packet[13], 0, limit - 13);
|
||||
uint16_t lcrc = frskyX_crc_x(&packet[3], limit-3);
|
||||
//
|
||||
packet[limit++] = lcrc >> 8;
|
||||
packet[limit] = lcrc;
|
||||
//
|
||||
}
|
||||
|
||||
// 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 )
|
||||
{ //mapped 860,2140(125%) range to 64,1984(PXX values);
|
||||
uint16_t chan_val=convert_channel_frsky(i)-1226;
|
||||
if(i>7) chan_val|=2048; // upper channels offset
|
||||
return chan_val;
|
||||
}
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
static uint16_t __attribute__((unused)) frskyX_scaleForPXX_FS( uint8_t i )
|
||||
{ //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>7) chan_val|=2048; // upper channels offset
|
||||
return chan_val;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define FRX_FAILSAFE_TIME 1032
|
||||
static void __attribute__((unused)) frskyX_data_frame()
|
||||
{
|
||||
//0x1D 0xB3 0xFD 0x02 0x56 0x07 0x15 0x00 0x00 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x96 0x12
|
||||
//
|
||||
static uint8_t chan_offset=0;
|
||||
uint16_t chan_0 ;
|
||||
uint16_t chan_1 ;
|
||||
//
|
||||
// data frames sent every 9ms; failsafe every 9 seconds
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
static uint16_t failsafe_count=0;
|
||||
static uint8_t FS_flag=0,failsafe_chan=0;
|
||||
if (FS_flag == 0 && failsafe_count > FRX_FAILSAFE_TIME && chan_offset == 0 && IS_FAILSAFE_VALUES_on)
|
||||
{
|
||||
FS_flag = 0x10;
|
||||
failsafe_chan = 0;
|
||||
} else if (FS_flag & 0x10 && failsafe_chan < (sub_protocol & 0x01 ? 8-1:16-1))
|
||||
{
|
||||
FS_flag = 0x10 | ((FS_flag + 2) & 0x0F); //10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
|
||||
failsafe_chan ++;
|
||||
} else if (FS_flag & 0x10)
|
||||
{
|
||||
FS_flag = 0;
|
||||
failsafe_count = 0;
|
||||
}
|
||||
failsafe_count++;
|
||||
#endif
|
||||
|
||||
packet[0] = (sub_protocol & 0x02 ) ? 0x20 : 0x1D ; // LBT or FCC
|
||||
packet[1] = rx_tx_addr[3];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = 0x02;
|
||||
//
|
||||
packet[4] = (FrX_chanskip<<6)|hopping_frequency_no;
|
||||
packet[5] = FrX_chanskip>>2;
|
||||
packet[6] = RX_num;
|
||||
//packet[7] = FLAGS 00 - standard packet
|
||||
//10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
|
||||
//20 - range check packet
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
packet[7] = FS_flag;
|
||||
#else
|
||||
packet[7] = 0;
|
||||
#endif
|
||||
packet[8] = 0;
|
||||
//
|
||||
uint8_t startChan = chan_offset; for(uint8_t i = 0; i <12 ; i+=3)
|
||||
{//12 bytes of channel data
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if( (FS_flag & 0x10) && ((failsafe_chan & 0x07) == (startChan & 0x07)) )
|
||||
chan_0 = frskyX_scaleForPXX_FS(failsafe_chan);
|
||||
else
|
||||
#endif
|
||||
chan_0 = frskyX_scaleForPXX(startChan);
|
||||
startChan++;
|
||||
//
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if( (FS_flag & 0x10) && ((failsafe_chan & 0x07) == (startChan & 0x07)) )
|
||||
chan_1 = frskyX_scaleForPXX_FS(failsafe_chan);
|
||||
else
|
||||
#endif
|
||||
chan_1 = frskyX_scaleForPXX(startChan);
|
||||
startChan++;
|
||||
//
|
||||
packet[9+i] = lowByte(chan_0); //3 bytes*4
|
||||
packet[9+i+1]=(((chan_0>>8) & 0x0F)|(chan_1 << 4));
|
||||
packet[9+i+2]=chan_1>>4;
|
||||
}
|
||||
packet[21] = (FrX_receive_seq << 4) | FrX_send_seq ;//8 at start
|
||||
|
||||
if(sub_protocol & 0x01 ) // in X8 mode send only 8ch every 9ms
|
||||
chan_offset = 0 ;
|
||||
else
|
||||
chan_offset^=0x08;
|
||||
|
||||
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
|
||||
for (uint8_t i=22;i<limit;i++)
|
||||
packet[i]=0;
|
||||
#if defined SPORT_POLLING
|
||||
uint8_t idxs=0;
|
||||
if(ok_to_send)
|
||||
for (uint8_t i=23;i<limit;i++)
|
||||
{//
|
||||
if(sport_index==sport_idx)
|
||||
{//no new data
|
||||
ok_to_send=false;
|
||||
break;
|
||||
}
|
||||
packet[i]=SportData[sport_index];
|
||||
sport_index= (sport_index+1)& (MAX_SPORT_BUFFER-1);
|
||||
idxs++;
|
||||
}
|
||||
packet[22]= idxs;
|
||||
#ifdef DEBUG_SERIAL
|
||||
for(uint8_t i=0;i<idxs;i++)
|
||||
{
|
||||
Serial.print(packet[23+i],HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println(" ");
|
||||
#endif
|
||||
#endif // SPORT_POLLING
|
||||
|
||||
uint16_t lcrc = frskyX_crc_x(&packet[3], limit-3);
|
||||
packet[limit++]=lcrc>>8;//high byte
|
||||
packet[limit]=lcrc;//low byte
|
||||
}
|
||||
|
||||
uint16_t ReadFrSkyX()
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
default:
|
||||
frskyX_set_start(47);
|
||||
CC2500_SetPower();
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
//
|
||||
frskyX_build_bind_packet();
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
if(IS_BIND_DONE)
|
||||
state = FRSKY_BIND_DONE;
|
||||
else
|
||||
state++;
|
||||
return 9000;
|
||||
case FRSKY_BIND_DONE:
|
||||
frskyX_initialize_data(0);
|
||||
hopping_frequency_no=0;
|
||||
BIND_DONE;
|
||||
state++;
|
||||
break;
|
||||
case FRSKY_DATA1:
|
||||
if ( prev_option != option )
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
|
||||
prev_option = option ;
|
||||
}
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
frskyX_set_start(hopping_frequency_no);
|
||||
CC2500_SetPower();
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
hopping_frequency_no = (hopping_frequency_no+FrX_chanskip)%47;
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
//
|
||||
// frskyX_data_frame();
|
||||
state++;
|
||||
return 5200;
|
||||
case FRSKY_DATA2:
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
state++;
|
||||
return 200;
|
||||
case FRSKY_DATA3:
|
||||
CC2500_Strobe(CC2500_SRX);
|
||||
state++;
|
||||
return 3100;
|
||||
case FRSKY_DATA4:
|
||||
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if (len && (len<=(0x0E + 3))) //Telemetry frame is 17
|
||||
{
|
||||
packet_count=0;
|
||||
CC2500_ReadData(pkt, len);
|
||||
#if defined TELEMETRY
|
||||
frsky_check_telemetry(pkt,len); //check if valid telemetry packets
|
||||
//parse telemetry packets here
|
||||
//The same telemetry function used by FrSky(D8).
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_count++;
|
||||
// restart sequence on missed packet - might need count or timeout instead of one missed
|
||||
if(packet_count>100)
|
||||
{//~1sec
|
||||
// seq_last_sent = 0;
|
||||
// seq_last_rcvd = 8;
|
||||
FrX_send_seq = 0x08 ;
|
||||
// FrX_receive_seq = 0 ;
|
||||
packet_count=0;
|
||||
#if defined TELEMETRY
|
||||
telemetry_lost=1;
|
||||
#endif
|
||||
}
|
||||
CC2500_Strobe(CC2500_SFRX); //flush the RXFIFO
|
||||
}
|
||||
frskyX_data_frame();
|
||||
if ( FrX_send_seq != 0x08 )
|
||||
{
|
||||
FrX_send_seq = ( FrX_send_seq + 1 ) & 0x03 ;
|
||||
}
|
||||
state = FRSKY_DATA1;
|
||||
return 500;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t initFrSkyX()
|
||||
{
|
||||
set_rx_tx_addr(MProtocol_id_master);
|
||||
Frsky_init_hop();
|
||||
packet_count=0;
|
||||
while(!FrX_chanskip)
|
||||
FrX_chanskip=random(0xfefefefe)%47;
|
||||
|
||||
//for test***************
|
||||
//rx_tx_addr[3]=0xB3;
|
||||
//rx_tx_addr[2]=0xFD;
|
||||
//************************
|
||||
frskyX_init();
|
||||
#if defined SPORT_POLLING
|
||||
#ifdef INVERT_SERIAL
|
||||
start_timer4() ;
|
||||
#endif
|
||||
#endif
|
||||
//
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
state = FRSKY_BIND;
|
||||
frskyX_initialize_data(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
state = FRSKY_DATA1;
|
||||
frskyX_initialize_data(0);
|
||||
}
|
||||
// seq_last_sent = 0;
|
||||
// seq_last_rcvd = 8;
|
||||
FrX_send_seq = 0x08 ;
|
||||
FrX_receive_seq = 0 ;
|
||||
return 10000;
|
||||
}
|
||||
#endif
|
||||
@@ -1,269 +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/>.
|
||||
*/
|
||||
|
||||
#if defined(FRSKY_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
//##########Variables########
|
||||
uint32_t state;
|
||||
uint8_t len;
|
||||
|
||||
enum {
|
||||
FRSKY_BIND = 0,
|
||||
FRSKY_BIND_DONE = 1000,
|
||||
FRSKY_DATA1,
|
||||
FRSKY_DATA2,
|
||||
FRSKY_DATA3,
|
||||
FRSKY_DATA4,
|
||||
FRSKY_DATA5
|
||||
};
|
||||
|
||||
uint16_t initFrSky_2way()
|
||||
{
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
{
|
||||
frsky2way_init(1);
|
||||
state = FRSKY_BIND;//
|
||||
}
|
||||
else
|
||||
{
|
||||
frsky2way_init(0);
|
||||
state = FRSKY_DATA2;
|
||||
}
|
||||
return 10000;
|
||||
}
|
||||
|
||||
uint16_t ReadFrSky_2way()
|
||||
{
|
||||
if (state < FRSKY_BIND_DONE)
|
||||
{
|
||||
frsky2way_build_bind_packet();
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, 0x00);
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
|
||||
cc2500_strobe(CC2500_SFRX);//0x3A
|
||||
cc2500_writeFifo(packet, packet[0]+1);
|
||||
state++;
|
||||
return 9000;
|
||||
}
|
||||
if (state == FRSKY_BIND_DONE)
|
||||
{
|
||||
state = FRSKY_DATA2;
|
||||
frsky2way_init(0);
|
||||
counter = 0;
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
if (state == FRSKY_DATA5)
|
||||
{
|
||||
cc2500_strobe(CC2500_SRX);//0x34 RX enable
|
||||
state = FRSKY_DATA1;
|
||||
return 9200;
|
||||
}
|
||||
counter = (counter + 1) % 188;
|
||||
if (state == FRSKY_DATA4)
|
||||
{ //telemetry receive
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
|
||||
state++;
|
||||
return 1300;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state == FRSKY_DATA1)
|
||||
{
|
||||
len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if (len)//20 bytes
|
||||
{
|
||||
cc2500_readFifo(pkt, len); //received telemetry packets
|
||||
#if defined(TELEMETRY)
|
||||
//parse telemetry packet here
|
||||
check_telemetry(pkt,len); //check if valid telemetry packets and buffer them.
|
||||
#endif
|
||||
}
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower(); // Set tx_power
|
||||
}
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
|
||||
cc2500_strobe(CC2500_SFRX);
|
||||
frsky2way_data_frame();
|
||||
cc2500_writeFifo(packet, packet[0]+1);
|
||||
state++;
|
||||
}
|
||||
return state == FRSKY_DATA4 ? 7500 : 9000;
|
||||
}
|
||||
|
||||
#if defined(TELEMETRY)
|
||||
void check_telemetry(uint8_t *pkt,uint8_t len)
|
||||
{
|
||||
if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3)
|
||||
{//only packets with the required id and packet length
|
||||
for(uint8_t i=3;i<6;i++)
|
||||
pktt[i]=0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8_t i=3;i<len;i++)
|
||||
pktt[i]=pkt[i];
|
||||
telemetry_link=1;
|
||||
}
|
||||
}
|
||||
|
||||
void compute_RSSIdbm(){
|
||||
if(pktt[len-2] >=128){
|
||||
RSSI_dBm =(((uint16_t)(pktt[len-2])*18)>>5)- 82;
|
||||
}
|
||||
else{
|
||||
RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5)+65;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void frsky2way_init(uint8_t bind)
|
||||
{
|
||||
// Configure cc2500 for tx mode
|
||||
CC2500_Reset();
|
||||
//
|
||||
cc2500_writeReg(CC2500_02_IOCFG0, 0x06);
|
||||
cc2500_writeReg(CC2500_00_IOCFG2, 0x06);
|
||||
cc2500_writeReg(CC2500_17_MCSM1, 0x0c);
|
||||
cc2500_writeReg(CC2500_18_MCSM0, 0x18);
|
||||
cc2500_writeReg(CC2500_06_PKTLEN, 0x19);
|
||||
cc2500_writeReg(CC2500_07_PKTCTRL1, 0x04);
|
||||
cc2500_writeReg(CC2500_08_PKTCTRL0, 0x05);
|
||||
cc2500_writeReg(CC2500_3E_PATABLE, 0xff);
|
||||
cc2500_writeReg(CC2500_0B_FSCTRL1, 0x08);
|
||||
cc2500_writeReg(CC2500_0C_FSCTRL0, fine);
|
||||
//base freq FREQ = 0x5C7627 (F = 2404MHz)
|
||||
cc2500_writeReg(CC2500_0D_FREQ2, 0x5c);
|
||||
cc2500_writeReg(CC2500_0E_FREQ1, 0x76);
|
||||
cc2500_writeReg(CC2500_0F_FREQ0, 0x27);
|
||||
//
|
||||
cc2500_writeReg(CC2500_10_MDMCFG4, 0xAA);
|
||||
cc2500_writeReg(CC2500_11_MDMCFG3, 0x39);
|
||||
cc2500_writeReg(CC2500_12_MDMCFG2, 0x11);
|
||||
cc2500_writeReg(CC2500_13_MDMCFG1, 0x23);
|
||||
cc2500_writeReg(CC2500_14_MDMCFG0, 0x7a);
|
||||
cc2500_writeReg(CC2500_15_DEVIATN, 0x42);
|
||||
cc2500_writeReg(CC2500_19_FOCCFG, 0x16);
|
||||
cc2500_writeReg(CC2500_1A_BSCFG, 0x6c);
|
||||
cc2500_writeReg(CC2500_1B_AGCCTRL2, bind ? 0x43 : 0x03);
|
||||
cc2500_writeReg(CC2500_1C_AGCCTRL1,0x40);
|
||||
cc2500_writeReg(CC2500_1D_AGCCTRL0,0x91);
|
||||
cc2500_writeReg(CC2500_21_FREND1, 0x56);
|
||||
cc2500_writeReg(CC2500_22_FREND0, 0x10);
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, 0xa9);
|
||||
cc2500_writeReg(CC2500_24_FSCAL2, 0x0A);
|
||||
cc2500_writeReg(CC2500_25_FSCAL1, 0x00);
|
||||
cc2500_writeReg(CC2500_26_FSCAL0, 0x11);
|
||||
cc2500_writeReg(CC2500_29_FSTEST, 0x59);
|
||||
cc2500_writeReg(CC2500_2C_TEST2, 0x88);
|
||||
cc2500_writeReg(CC2500_2D_TEST1, 0x31);
|
||||
cc2500_writeReg(CC2500_2E_TEST0, 0x0B);
|
||||
cc2500_writeReg(CC2500_03_FIFOTHR, 0x07);
|
||||
cc2500_writeReg(CC2500_09_ADDR, 0x00);
|
||||
//
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
|
||||
cc2500_strobe(CC2500_SIDLE);
|
||||
|
||||
cc2500_writeReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]);
|
||||
cc2500_writeReg(CC2500_07_PKTCTRL1, 0x05);
|
||||
cc2500_strobe(CC2500_SIDLE); // Go to idle...
|
||||
//
|
||||
cc2500_writeReg(CC2500_0A_CHANNR, 0x00);
|
||||
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
|
||||
cc2500_strobe(CC2500_SFRX);
|
||||
//#######END INIT########
|
||||
}
|
||||
|
||||
uint8_t get_chan_num(uint16_t idx)
|
||||
{
|
||||
uint8_t ret = (idx * 0x1e) % 0xeb;
|
||||
if(idx == 3 || idx == 23 || idx == 47)
|
||||
ret++;
|
||||
if(idx > 47)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void frsky2way_build_bind_packet()
|
||||
{
|
||||
//11 03 01 d7 2d 00 00 1e 3c 5b 78 00 00 00 00 00 00 01
|
||||
//11 03 01 19 3e 00 02 8e 2f bb 5c 00 00 00 00 00 00 01
|
||||
packet[0] = 0x11;
|
||||
packet[1] = 0x03;
|
||||
packet[2] = 0x01;
|
||||
packet[3] = rx_tx_addr[3];
|
||||
packet[4] = rx_tx_addr[2];
|
||||
uint16_t idx = ((state -FRSKY_BIND) % 10) * 5;
|
||||
packet[5] = idx;
|
||||
packet[6] = get_chan_num(idx++);
|
||||
packet[7] = get_chan_num(idx++);
|
||||
packet[8] = get_chan_num(idx++);
|
||||
packet[9] = get_chan_num(idx++);
|
||||
packet[10] = get_chan_num(idx++);
|
||||
packet[11] = 0x00;
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x00;
|
||||
packet[14] = 0x00;
|
||||
packet[15] = 0x00;
|
||||
packet[16] = 0x00;
|
||||
packet[17] = 0x01;
|
||||
}
|
||||
|
||||
uint8_t telemetry_counter=0;
|
||||
|
||||
void frsky2way_data_frame()
|
||||
{//pachet[4] is telemetry user frame counter(hub)
|
||||
//11 d7 2d 22 00 01 c9 c9 ca ca 88 88 ca ca c9 ca 88 88
|
||||
//11 57 12 00 00 01 f2 f2 f2 f2 06 06 ca ca ca ca 18 18
|
||||
packet[0] = 0x11; //Length
|
||||
packet[1] = rx_tx_addr[3];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = counter;//
|
||||
packet[4] = pkt[6]?(telemetry_counter++)%32:0;
|
||||
packet[5] = 0x01;
|
||||
//
|
||||
packet[10] = 0;
|
||||
packet[11] = 0;
|
||||
packet[16] = 0;
|
||||
packet[17] = 0;
|
||||
for(uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
uint16_t value;
|
||||
value = convert_channel_frsky(i);
|
||||
if(i < 4)
|
||||
{
|
||||
packet[6+i] = value & 0xff;
|
||||
packet[10+(i>>1)] |= ((value >> 8) & 0x0f) << (4 *(i & 0x01));
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[8+i] = value & 0xff;
|
||||
packet[16+((i-4)>>1)] |= ((value >> 8) & 0x0f) << (4 * ((i-4) & 0x01));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
228
Multiprotocol/GD00X_nrf24l01.ino
Normal file
228
Multiprotocol/GD00X_nrf24l01.ino
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Compatible with GD005 C-17 and GD006 DA62 planes.
|
||||
|
||||
#if defined(GD00X_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297l.h"
|
||||
|
||||
//#define FORCE_GD00X_ORIGINAL_ID
|
||||
|
||||
#define GD00X_INITIAL_WAIT 500
|
||||
#define GD00X_PACKET_PERIOD 3500
|
||||
#define GD00X_RF_BIND_CHANNEL 2
|
||||
#define GD00X_RF_NUM_CHANNELS 4
|
||||
#define GD00X_PAYLOAD_SIZE 15
|
||||
#define GD00X_BIND_COUNT 857 //3sec
|
||||
|
||||
#define GD00X_V2_BIND_PACKET_PERIOD 5110
|
||||
#define GD00X_V2_RF_BIND_CHANNEL 0x43
|
||||
#define GD00X_V2_RF_NUM_CHANNELS 2
|
||||
#define GD00X_V2_PAYLOAD_SIZE 6
|
||||
|
||||
// flags going to packet[11]
|
||||
#define GD00X_FLAG_DR 0x08
|
||||
#define GD00X_FLAG_LIGHT 0x04
|
||||
|
||||
// flags going to packet[4]
|
||||
#define GD00X_V2_FLAG_DR 0x40
|
||||
#define GD00X_V2_FLAG_LIGHT 0x80
|
||||
|
||||
static void __attribute__((unused)) GD00X_send_packet()
|
||||
{
|
||||
static uint8_t prev_CH6=false;
|
||||
|
||||
if(sub_protocol==GD_V1)
|
||||
{
|
||||
packet[0] = IS_BIND_IN_PROGRESS?0xAA:0x55;
|
||||
memcpy(packet+1,rx_tx_addr,4);
|
||||
uint16_t channel=convert_channel_ppm(AILERON);
|
||||
packet[5 ] = channel;
|
||||
packet[6 ] = channel>>8;
|
||||
channel=convert_channel_ppm(THROTTLE);
|
||||
packet[7 ] = channel;
|
||||
packet[8 ] = channel>>8;
|
||||
channel=convert_channel_ppm(CH5); // TRIM
|
||||
packet[9 ] = channel;
|
||||
packet[10] = channel>>8;
|
||||
packet[11] = GET_FLAG(!CH7_SW, GD00X_FLAG_DR)
|
||||
| GET_FLAG(CH6_SW, GD00X_FLAG_LIGHT);
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x00;
|
||||
packet[14] = 0x00;
|
||||
}
|
||||
else
|
||||
{//GD_V2
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
for(uint8_t i=0; i<5;i++)
|
||||
packet[i]=rx_tx_addr[i];
|
||||
else
|
||||
{
|
||||
packet[0]=convert_channel_16b_limit(THROTTLE,0,100); // 0..100
|
||||
|
||||
// Deadband is needed on aileron, 40 gives +-6%
|
||||
packet[1]=convert_channel_8b_limit_deadband(AILERON,0x3F,0x20,0x00,40); // Aileron: 3F..20..00
|
||||
// Trims must be in a seperate channel for this model
|
||||
packet[2]=0x3F-(convert_channel_8b(CH5)>>2); // Trim: 0x3F..0x20..0x00
|
||||
|
||||
uint8_t seq=((packet_count*3)/7)%5;
|
||||
packet[4]=seq
|
||||
| GET_FLAG(!CH7_SW, GD00X_V2_FLAG_DR);
|
||||
|
||||
if(CH6_SW!=prev_CH6)
|
||||
{ // LED switch is temporary
|
||||
len=43;
|
||||
prev_CH6=CH6_SW;
|
||||
}
|
||||
if(len)
|
||||
{ // Send the light flag for a couple of packets
|
||||
packet[4] |= GD00X_V2_FLAG_LIGHT;
|
||||
len--;
|
||||
}
|
||||
|
||||
packet[3]=(packet[0]+packet[1]+packet[2]+packet[4])^(crc8);
|
||||
|
||||
if( (packet_count%12) == 0 )
|
||||
hopping_frequency_no ^= 1; // Toggle between the 2 frequencies
|
||||
packet_count++;
|
||||
if(packet_count>34) packet_count=0; // Full period
|
||||
if( seq == (((packet_count*3)/7)%5) )
|
||||
{
|
||||
if(packet_period==2700)
|
||||
packet_period=3000;
|
||||
else
|
||||
packet_period=2700;
|
||||
}
|
||||
else
|
||||
packet_period=4300;
|
||||
}
|
||||
packet[5]='D';
|
||||
}
|
||||
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
XN297L_Hopping(hopping_frequency_no);
|
||||
if(sub_protocol==GD_V1)
|
||||
{
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no &= GD00X_RF_NUM_CHANNELS-1; // 4 RF channels
|
||||
}
|
||||
}
|
||||
|
||||
XN297L_WritePayload(packet, packet_length);
|
||||
|
||||
XN297L_SetPower(); // Set tx_power
|
||||
XN297L_SetFreqOffset(); // Set frequency offset
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) GD00X_init()
|
||||
{
|
||||
XN297L_Init();
|
||||
if(sub_protocol==GD_V1)
|
||||
XN297L_SetTXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5);
|
||||
else
|
||||
XN297L_SetTXAddr((uint8_t*)"GDKNx", 5);
|
||||
XN297L_HoppingCalib(sub_protocol==GD_V1?GD00X_RF_NUM_CHANNELS:GD00X_V2_RF_NUM_CHANNELS); // Calibrate all channels
|
||||
XN297L_RFChannel(sub_protocol==GD_V1?GD00X_RF_BIND_CHANNEL:GD00X_V2_RF_BIND_CHANNEL); // Set bind channel
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) GD00X_initialize_txid()
|
||||
{
|
||||
if(sub_protocol==GD_V1)
|
||||
{
|
||||
uint8_t start=76+(rx_tx_addr[0]&0x03);
|
||||
for(uint8_t i=0; i<GD00X_RF_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]=start-(i<<1);
|
||||
#ifdef FORCE_GD00X_ORIGINAL_ID
|
||||
rx_tx_addr[0]=0x1F; // or 0xA5 or 0x26
|
||||
rx_tx_addr[1]=0x39; // or 0x37 or 0x35
|
||||
rx_tx_addr[2]=0x12; // Constant on 3 TXs
|
||||
rx_tx_addr[3]=0x13; // Constant on 3 TXs
|
||||
for(uint8_t i=0; i<GD00X_RF_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]=79-(i<<1); // or 77 or 78
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//Generate 64 different IDs
|
||||
rx_tx_addr[1]=0x00;
|
||||
rx_tx_addr[2]=0x00;
|
||||
rx_tx_addr[1+((rx_tx_addr[3]&0x10)>>4)]=rx_tx_addr[3]&0x8F;
|
||||
rx_tx_addr[0]=0x65;
|
||||
rx_tx_addr[3]=0x95;
|
||||
rx_tx_addr[4]=0x47; //'G'
|
||||
|
||||
crc8=rx_tx_addr[0]^rx_tx_addr[1]^rx_tx_addr[2];
|
||||
//hopping calculation
|
||||
hopping_frequency[0]=(0x15+(crc8^rx_tx_addr[3]))&0x1F;
|
||||
if( hopping_frequency[0] == 0x0F )
|
||||
hopping_frequency[0]=0x0E;
|
||||
else if( (hopping_frequency[0]&0xFE) == 0x10 )
|
||||
hopping_frequency[0]+=2;
|
||||
hopping_frequency[1]=0x20+hopping_frequency[0];
|
||||
|
||||
#ifdef FORCE_GD00X_ORIGINAL_ID
|
||||
//ID 1
|
||||
rx_tx_addr[0]=0x65;
|
||||
rx_tx_addr[1]=0x00;
|
||||
rx_tx_addr[2]=0x00;
|
||||
rx_tx_addr[3]=0x95;
|
||||
rx_tx_addr[4]=0x47; //'G'
|
||||
hopping_frequency[0]=0x05;
|
||||
hopping_frequency[1]=0x25;
|
||||
//ID 2
|
||||
rx_tx_addr[0]=0xFD;
|
||||
rx_tx_addr[1]=0x09;
|
||||
rx_tx_addr[2]=0x00;
|
||||
rx_tx_addr[3]=0x65;
|
||||
rx_tx_addr[4]=0x47; //'G'
|
||||
hopping_frequency[0]=0x06;
|
||||
hopping_frequency[1]=0x26;
|
||||
//ID 3
|
||||
rx_tx_addr[0]=0x67;
|
||||
rx_tx_addr[1]=0x0F;
|
||||
rx_tx_addr[2]=0x00;
|
||||
rx_tx_addr[3]=0x69;
|
||||
rx_tx_addr[4]=0x47; //'G'
|
||||
hopping_frequency[0]=0x16;
|
||||
hopping_frequency[1]=0x36;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t GD00X_callback()
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
if(--bind_counter==0)
|
||||
BIND_DONE;
|
||||
GD00X_send_packet();
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initGD00X()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
GD00X_initialize_txid();
|
||||
GD00X_init();
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter=GD00X_BIND_COUNT;
|
||||
packet_period=sub_protocol==GD_V1?GD00X_PACKET_PERIOD:GD00X_V2_BIND_PACKET_PERIOD;
|
||||
packet_length=sub_protocol==GD_V1?GD00X_PAYLOAD_SIZE:GD00X_V2_PAYLOAD_SIZE;
|
||||
packet_count=0;
|
||||
len=0;
|
||||
return GD00X_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
158
Multiprotocol/GW008_nrf24l01.ino
Normal file
158
Multiprotocol/GW008_nrf24l01.ino
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
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 Global Drone GW008 protocol.
|
||||
// There are 3 versions of this small quad, this protocol is for the one with a XNS104 IC in the stock Tx and PAN159CY IC in the quad (SOCs with built-in xn297 compatible RF).
|
||||
// The xn297 version is compatible with the CX10 protocol (green pcb).
|
||||
// The LT8910 version is not supported yet.
|
||||
|
||||
#if defined(GW008_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define GW008_INITIAL_WAIT 500
|
||||
#define GW008_PACKET_PERIOD 2400
|
||||
#define GW008_RF_BIND_CHANNEL 2
|
||||
#define GW008_PAYLOAD_SIZE 15
|
||||
|
||||
enum {
|
||||
GW008_BIND1,
|
||||
GW008_BIND2,
|
||||
GW008_DATA
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) GW008_send_packet(uint8_t bind)
|
||||
{
|
||||
packet[0] = rx_tx_addr[0];
|
||||
if(bind)
|
||||
{
|
||||
packet[1] = 0x55;
|
||||
packet[2] = hopping_frequency[0];
|
||||
packet[3] = hopping_frequency[1];
|
||||
packet[4] = hopping_frequency[2];
|
||||
packet[5] = hopping_frequency[3];
|
||||
memset(&packet[6], 0, 7);
|
||||
packet[13] = 0xaa;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[1] = 0x01 | GET_FLAG(CH5, 0x40); // flip
|
||||
packet[2] = convert_channel_16b_limit(AILERON , 200, 0); // aileron
|
||||
packet[3] = convert_channel_16b_limit(ELEVATOR, 0, 200); // elevator
|
||||
packet[4] = convert_channel_16b_limit(RUDDER , 200, 0); // rudder
|
||||
packet[5] = convert_channel_16b_limit(THROTTLE, 0, 200); // throttle
|
||||
packet[6] = 0xaa;
|
||||
packet[7] = 0x02; // max rate
|
||||
packet[8] = 0x00;
|
||||
packet[9] = 0x00;
|
||||
packet[10]= 0x00;
|
||||
packet[11]= 0x00;
|
||||
packet[12]= 0x00;
|
||||
packet[13]= rx_tx_addr[2];
|
||||
}
|
||||
packet[14] = rx_tx_addr[1];
|
||||
|
||||
// Power on, TX mode, CRC enabled
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? GW008_RF_BIND_CHANNEL : hopping_frequency[(hopping_frequency_no++)/2]);
|
||||
hopping_frequency_no %= 8;
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WriteEnhancedPayload(packet, GW008_PAYLOAD_SIZE, 0);
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) GW008_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 Acknowldgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01);
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, GW008_PAYLOAD_SIZE+2); // payload + 2 bytes for pcf
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
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, 0x01); // Set feature bits on
|
||||
NRF24L01_Activate(0x73);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) GW008_initialize_txid()
|
||||
{
|
||||
uint32_t lfsr = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16);
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
hopping_frequency[i] = 0x10 + ((lfsr >> (i*8)) % 0x37);
|
||||
}
|
||||
|
||||
uint16_t GW008_callback()
|
||||
{
|
||||
switch(phase)
|
||||
{
|
||||
case GW008_BIND1:
|
||||
if((NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) && // RX fifo data ready
|
||||
XN297_ReadEnhancedPayload(packet, GW008_PAYLOAD_SIZE) == GW008_PAYLOAD_SIZE && // check payload size
|
||||
packet[0] == rx_tx_addr[0] && packet[14] == rx_tx_addr[1]) // check tx id
|
||||
{
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
rx_tx_addr[2] = packet[13];
|
||||
BIND_DONE;
|
||||
phase = GW008_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
GW008_send_packet(1);
|
||||
phase = GW008_BIND2;
|
||||
return 300;
|
||||
}
|
||||
break;
|
||||
case GW008_BIND2:
|
||||
// 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));
|
||||
phase = GW008_BIND1;
|
||||
return 5000;
|
||||
break;
|
||||
case GW008_DATA:
|
||||
GW008_send_packet(0);
|
||||
break;
|
||||
}
|
||||
return GW008_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initGW008()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
GW008_initialize_txid();
|
||||
phase = GW008_BIND1;
|
||||
GW008_init();
|
||||
hopping_frequency_no = 0;
|
||||
return GW008_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
258
Multiprotocol/H8_3D_nrf24l01.ino
Normal file
258
Multiprotocol/H8_3D_nrf24l01.ino
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
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 EAchine 3D X4, CG023/CG031, Attop YD-822/YD-829/YD-829C and H8_3D/JJRC H20/H22
|
||||
// Merged CG023 and H8_3D protocols
|
||||
// Last sync with hexfet new_protocols/cg023_nrf24l01.c dated 2015-10-03
|
||||
// Last sync with hexfet new_protocols/h8_3d_nrf24l01.c dated 2015-11-18
|
||||
|
||||
#if defined(H8_3D_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define H8_3D_PACKET_PERIOD 1800
|
||||
#define H20H_PACKET_PERIOD 9340
|
||||
#define H20MINI_PACKET_PERIOD 3100
|
||||
#define H8_3D_INITIAL_WAIT 500
|
||||
#define H8_3D_PACKET_SIZE 20
|
||||
#define H8_3D_RF_NUM_CHANNELS 4
|
||||
#define H20H_BIND_RF 0x49
|
||||
#define H8_3D_BIND_COUNT 1000
|
||||
|
||||
enum H8_3D_FLAGS {
|
||||
// flags going to packet[17]
|
||||
H8_3D_FLAG_FLIP = 0x01,
|
||||
H8_3D_FLAG_RATE_MID = 0x02,
|
||||
H8_3D_FLAG_RATE_HIGH = 0x04,
|
||||
H8_3D_FLAG_LIGTH = 0x08, // Light on H22
|
||||
H8_3D_FLAG_HEADLESS = 0x10, // RTH + headless on H8, headless on JJRC H20, RTH on H22
|
||||
H8_3D_FLAG_RTH = 0x20, // 360 flip mode on H8 3D and H22, RTH on JJRC H20
|
||||
};
|
||||
|
||||
enum H8_3D_FLAGS_2 {
|
||||
// flags going to packet[18]
|
||||
H8_3D_FLAG_VIDEO = 0x80,
|
||||
H8_3D_FLAG_PICTURE = 0x40,
|
||||
H8_3D_FLAG_CALIBRATE1 = 0x20, // H8 3D acc calibration, H20,H20H headless calib
|
||||
H8_3D_FLAG_CALIBRATE2 = 0x10, // H11D, H20, H20H acc calibration
|
||||
H8_3D_FLAG_CAM_DN = 0x08,
|
||||
H8_3D_FLAG_CAM_UP = 0x04,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) H8_3D_send_packet(uint8_t bind)
|
||||
{
|
||||
if(sub_protocol==H20H)
|
||||
packet[0] = 0x14;
|
||||
else // H8_3D, H20MINI, H30MINI
|
||||
packet[0] = 0x13;
|
||||
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
packet[3] = rx_tx_addr[2];
|
||||
packet[4] = rx_tx_addr[3];
|
||||
packet[8] = rx_tx_addr[0]+rx_tx_addr[1]+rx_tx_addr[2]+rx_tx_addr[3]; // txid checksum
|
||||
memset(&packet[9], 0, 10);
|
||||
if (bind)
|
||||
{
|
||||
packet[5] = 0x00;
|
||||
packet[6] = 0x00;
|
||||
packet[7] = 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[5] = hopping_frequency_no;
|
||||
packet[7] = 0x03;
|
||||
|
||||
rudder = convert_channel_16b_limit(RUDDER,0x44,0xBC); // yaw right : 0x80 (neutral) - 0xBC (right)
|
||||
if(sub_protocol!=H20H)
|
||||
{ // H8_3D, H20MINI, H30MINI
|
||||
packet[6] = 0x08;
|
||||
packet[9] = convert_channel_8b(THROTTLE); // throttle : 0x00 - 0xFF
|
||||
packet[15] = 0x20; // trims
|
||||
packet[16] = 0x20; // trims
|
||||
if (rudder<=0x80)
|
||||
rudder=0x80-rudder; // yaw left : 0x00 (neutral) - 0x3C (left)
|
||||
if(rudder==0x01 || rudder==0x81)
|
||||
rudder=0x00; // Small deadband
|
||||
}
|
||||
else
|
||||
{ //H20H
|
||||
packet[6] = hopping_frequency_no == 0 ? 8 - packet_count : 16 - packet_count;
|
||||
packet[9] = convert_channel_16b_limit(THROTTLE, 0x43, 0xBB); // throttle : 0x43 - 0x7F - 0xBB
|
||||
packet[15]= 0x40; // trims
|
||||
packet[16]= 0x40; // trims
|
||||
rudder--; // rudder : 0x43 - 0x7F - 0xBB
|
||||
if (rudder>=0x7F-1 && rudder<=0x7F+1)
|
||||
rudder=0x7F; // Small deadband
|
||||
}
|
||||
packet[10] = rudder;
|
||||
packet[11] = convert_channel_16b_limit(ELEVATOR, 0x43, 0xBB); // elevator : 0x43 - 0x7F - 0xBB
|
||||
packet[12] = convert_channel_16b_limit(AILERON, 0x43, 0xBB); // aileron : 0x43 - 0x7F - 0xBB
|
||||
// neutral trims
|
||||
packet[13] = 0x20;
|
||||
packet[14] = 0x20;
|
||||
// flags
|
||||
packet[17] = H8_3D_FLAG_RATE_HIGH
|
||||
| GET_FLAG(CH5_SW,H8_3D_FLAG_FLIP)
|
||||
| GET_FLAG(CH6_SW,H8_3D_FLAG_LIGTH) //H22 light
|
||||
| GET_FLAG(CH9_SW,H8_3D_FLAG_HEADLESS)
|
||||
| GET_FLAG(CH10_SW,H8_3D_FLAG_RTH); // 180/360 flip mode on H8 3D
|
||||
packet[18] = GET_FLAG(CH7_SW,H8_3D_FLAG_PICTURE)
|
||||
| GET_FLAG(CH8_SW,H8_3D_FLAG_VIDEO)
|
||||
| GET_FLAG(CH11_SW,H8_3D_FLAG_CALIBRATE1)
|
||||
| GET_FLAG(CH12_SW,H8_3D_FLAG_CALIBRATE2);
|
||||
if(Channel_data[CH13]<CHANNEL_MIN_COMMAND)
|
||||
packet[18] |= H8_3D_FLAG_CAM_DN;
|
||||
if(CH13_SW)
|
||||
packet[18] |= H8_3D_FLAG_CAM_UP;
|
||||
}
|
||||
uint8_t sum = packet[9];
|
||||
for (uint8_t i=10; i < H8_3D_PACKET_SIZE-1; i++)
|
||||
sum += packet[i];
|
||||
packet[19] = sum; // data checksum
|
||||
|
||||
// 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(sub_protocol!=H20H)
|
||||
{ // H8_3D, H20MINI, H30MINI
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? hopping_frequency[0] : hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no %= H8_3D_RF_NUM_CHANNELS;
|
||||
}
|
||||
else
|
||||
{ //H20H
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? H20H_BIND_RF : hopping_frequency[packet_count>>3]);
|
||||
if(!bind)
|
||||
{
|
||||
packet_count++;
|
||||
if(packet_count>15)
|
||||
{
|
||||
packet_count = 0;
|
||||
hopping_frequency_no = 0;
|
||||
}
|
||||
else
|
||||
if(packet_count > 7)
|
||||
hopping_frequency_no = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WritePayload(packet, H8_3D_PACKET_SIZE);
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) H8_3D_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
if(sub_protocol==H20H)
|
||||
XN297_SetTXAddr((uint8_t *)"\xEE\xDD\xCC\xBB\x11", 5);
|
||||
else // H8_3D, H20MINI, H30MINI
|
||||
XN297_SetTXAddr((uint8_t *)"\xC4\x57\x09\x65\x21", 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_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
uint16_t H8_3D_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
H8_3D_send_packet(0);
|
||||
else
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
packet_count=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
H8_3D_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
// captured from H20H stock transmitters
|
||||
const uint8_t PROGMEM h20h_tx_rf_map[3][6] = {{/*ID*/0x83, 0x3c, 0x60, 0x00, /*RF*/0x47, 0x3e},
|
||||
{/*ID*/0x5c, 0x2b, 0x60, 0x00, /*RF*/0x4a, 0x3c},
|
||||
{/*ID*/0x57, 0x07, 0x00, 0x00, /*RF*/0x41, 0x48} };
|
||||
// captured from H20 Mini / H30 Mini stock transmitters
|
||||
const uint8_t PROGMEM h20mini_tx_rf_map[4][8] = {{/*ID*/0xb4, 0xbb, 0x09, 0x00, /*RF*/0x3e, 0x45, 0x47, 0x4a},
|
||||
{/*ID*/0x94, 0x9d, 0x0b, 0x00, /*RF*/0x3e, 0x43, 0x49, 0x4a},
|
||||
{/*ID*/0xd1, 0xd0, 0x00, 0x00, /*RF*/0x3f, 0x42, 0x46, 0x4a},
|
||||
{/*ID*/0xcb, 0xcd, 0x04, 0x00, /*RF*/0x41, 0x43, 0x46, 0x4a}};
|
||||
static void __attribute__((unused)) H8_3D_initialize_txid()
|
||||
{
|
||||
uint8_t id_num=rx_tx_addr[4];
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case H8_3D:
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
hopping_frequency[i] = 6 + (0x0f*i) + (((rx_tx_addr[i] >> 4) + (rx_tx_addr[i] & 0x0f)) % 0x0f);
|
||||
break;
|
||||
case H20H:
|
||||
id_num%=3; // 3 different IDs
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
{
|
||||
rx_tx_addr[i] = pgm_read_byte_near(&h20h_tx_rf_map[id_num][i]);
|
||||
if(i<2)
|
||||
hopping_frequency[i] = pgm_read_byte_near(&h20h_tx_rf_map[id_num][i+4]);
|
||||
}
|
||||
break;
|
||||
case H20MINI:
|
||||
case H30MINI:
|
||||
id_num%=4; // 4 different IDs
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
{
|
||||
rx_tx_addr[i] = pgm_read_byte_near(&h20mini_tx_rf_map[id_num][i]);
|
||||
hopping_frequency[i] = pgm_read_byte_near(&h20mini_tx_rf_map[id_num][i+4]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initH8_3D(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = H8_3D_BIND_COUNT;
|
||||
H8_3D_initialize_txid();
|
||||
H8_3D_init();
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case H8_3D:
|
||||
packet_period=H8_3D_PACKET_PERIOD;
|
||||
break;
|
||||
case H20H:
|
||||
packet_period=H20H_PACKET_PERIOD;
|
||||
break;
|
||||
case H20MINI:
|
||||
case H30MINI:
|
||||
packet_period=H20MINI_PACKET_PERIOD;
|
||||
break;
|
||||
}
|
||||
return H8_3D_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -12,26 +12,27 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with hexfet new_protocols/hisky_nrf24l01.c dated 2015-03-27
|
||||
|
||||
#if defined(HISKY_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BIND_COUNT 1000
|
||||
#define TXID_SIZE 5
|
||||
#define FREQUENCE_NUM 20
|
||||
#define HISKY_BIND_COUNT 1000
|
||||
#define HISKY_TXID_SIZE 5
|
||||
#define HISKY_FREQUENCE_NUM 20
|
||||
//
|
||||
uint8_t bind_buf_arry[4][10];
|
||||
|
||||
// HiSky protocol uses TX id as an address for nRF24L01, and uses frequency hopping sequence
|
||||
// which does not depend on this id and is passed explicitly in binding sequence. So we are free
|
||||
// to generate this sequence as we wish. It should be in the range [02..77]
|
||||
void calc_fh_channels(uint32_t seed)
|
||||
static void __attribute__((unused)) calc_fh_channels()
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint32_t rnd = seed;
|
||||
uint32_t rnd = MProtocol_id;
|
||||
|
||||
while (idx < FREQUENCE_NUM)
|
||||
while (idx < HISKY_FREQUENCE_NUM)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t count_2_26 = 0, count_27_50 = 0, count_51_74 = 0;
|
||||
@@ -40,7 +41,7 @@ void calc_fh_channels(uint32_t seed)
|
||||
// Use least-significant byte. 73 is prime, so channels 76..77 are unused
|
||||
uint8_t next_ch = ((rnd >> 8) % 73) + 2;
|
||||
// Keep the distance 2 between the channels - either odd or even
|
||||
if (((next_ch ^ (uint8_t)seed) & 0x01 )== 0)
|
||||
if (((next_ch ^ (uint8_t)rx_tx_addr[3]) & 0x01 )== 0)
|
||||
continue;
|
||||
// Check that it's not duplicated and spread uniformly
|
||||
for (i = 0; i < idx; i++) {
|
||||
@@ -60,7 +61,7 @@ void calc_fh_channels(uint32_t seed)
|
||||
}
|
||||
}
|
||||
|
||||
void build_binding_packet(void)
|
||||
static void __attribute__((unused)) build_binding_packet(void)
|
||||
{
|
||||
uint8_t i;
|
||||
uint16_t sum=0;
|
||||
@@ -94,7 +95,7 @@ void build_binding_packet(void)
|
||||
}
|
||||
}
|
||||
|
||||
void hisky_init()
|
||||
static void __attribute__((unused)) hisky_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
|
||||
@@ -115,17 +116,16 @@ void hisky_init()
|
||||
|
||||
// HiSky channel sequence: AILE ELEV THRO RUDD GEAR PITCH, channel data value is from 0 to 1000
|
||||
// Channel 7 - Gyro mode, 0 - 6 axis, 3 - 3 axis
|
||||
void build_ch_data()
|
||||
static void __attribute__((unused)) build_ch_data()
|
||||
{
|
||||
uint16_t temp;
|
||||
uint8_t i,j;
|
||||
uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4};
|
||||
for (i = 0; i< 8; i++) {
|
||||
j=ch[i];
|
||||
temp=map(limit_channel_100(j),PPM_MIN_100,PPM_MAX_100,0,1000);
|
||||
j=CH_AETR[i];
|
||||
temp=convert_channel_16b_limit(j,0,1000);
|
||||
if (j == THROTTLE) // It is clear that hisky's throttle stick is made reversely, so I adjust it here on purpose
|
||||
temp = 1000 -temp;
|
||||
if (j == AUX3)
|
||||
if (j == CH7)
|
||||
temp = temp < 400 ? 0 : 3; // Gyro mode, 0 - 6 axis, 3 - 3 axis
|
||||
packet[i] = (uint8_t)(temp&0xFF);
|
||||
packet[i<4?8:9]>>=2;
|
||||
@@ -143,15 +143,32 @@ uint16_t hisky_cb()
|
||||
NRF24L01_SetPower();
|
||||
phase=2;
|
||||
break;
|
||||
case 3:
|
||||
if (! bind_counter)
|
||||
NRF24L01_WritePayload(packet,10); // 2 packets per 5ms
|
||||
break;
|
||||
case 4:
|
||||
phase=6;
|
||||
break;
|
||||
case 7: // build packet and send failsafe every 100ms
|
||||
convert_channel_HK310(hopping_frequency_no!=0?RUDDER:AUX2,&packet[0],&packet[1]);
|
||||
convert_channel_HK310(hopping_frequency_no!=0?THROTTLE:AUX3,&packet[2],&packet[3]);
|
||||
convert_channel_HK310(hopping_frequency_no!=0?AUX1:AUX4,&packet[4],&packet[5]);
|
||||
packet[7]=hopping_frequency_no!=0?0x55:0xAA;
|
||||
packet[8]=hopping_frequency_no!=0?0x67:0x5A;
|
||||
case 7: // build packet
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(IS_FAILSAFE_VALUES_on && hopping_frequency_no==0)
|
||||
{ // send failsafe every 100ms
|
||||
convert_failsafe_HK310(RUDDER, &packet[0],&packet[1]);
|
||||
convert_failsafe_HK310(THROTTLE,&packet[2],&packet[3]);
|
||||
convert_failsafe_HK310(CH5, &packet[4],&packet[5]);
|
||||
packet[7]=0xAA;
|
||||
packet[8]=0x5A;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
convert_channel_HK310(RUDDER, &packet[0],&packet[1]);
|
||||
convert_channel_HK310(THROTTLE,&packet[2],&packet[3]);
|
||||
convert_channel_HK310(CH5, &packet[4],&packet[5]);
|
||||
packet[7]=0x55;
|
||||
packet[8]=0x67;
|
||||
}
|
||||
phase=8;
|
||||
break;
|
||||
}
|
||||
@@ -194,7 +211,7 @@ uint16_t hisky_cb()
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
hopping_frequency_no++;
|
||||
if (hopping_frequency_no >= FREQUENCE_NUM)
|
||||
if (hopping_frequency_no >= HISKY_FREQUENCE_NUM)
|
||||
hopping_frequency_no = 0;
|
||||
break;
|
||||
case 7:
|
||||
@@ -212,15 +229,19 @@ uint16_t hisky_cb()
|
||||
return 1000; // send 1 binding packet and 1 data packet per 9ms
|
||||
}
|
||||
|
||||
// Generate internal id from TX id and manufacturer id (STM32 unique id)
|
||||
void initialize_tx_id()
|
||||
static void __attribute__((unused)) initialize_tx_id()
|
||||
{
|
||||
//Generate frequency hopping table
|
||||
if(sub_protocol==HK310)
|
||||
for(uint8_t i=0;i<FREQUENCE_NUM;i++)
|
||||
hopping_frequency[i]=i; // Sequential order hop channels...
|
||||
{
|
||||
// for HiSky surface protocol, the transmitter always generates hop channels in sequential order.
|
||||
// The transmitter only generates the first hop channel between 0 and 49. So the channel range is from 0 to 69.
|
||||
hopping_frequency_no=rx_tx_addr[0]%50;
|
||||
for(uint8_t i=0;i<HISKY_FREQUENCE_NUM;i++)
|
||||
hopping_frequency[i]=hopping_frequency_no++; // Sequential order hop channels...
|
||||
}
|
||||
else
|
||||
calc_fh_channels(MProtocol_id);
|
||||
calc_fh_channels();
|
||||
}
|
||||
|
||||
uint16_t initHiSky()
|
||||
@@ -232,8 +253,8 @@ uint16_t initHiSky()
|
||||
hopping_frequency_no = 0;
|
||||
binding_idx = 0;
|
||||
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
bind_counter = BIND_COUNT;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
bind_counter = HISKY_BIND_COUNT;
|
||||
else
|
||||
bind_counter = 0;
|
||||
return 1000;
|
||||
|
||||
462
Multiprotocol/Hitec_cc2500.ino
Normal file
462
Multiprotocol/Hitec_cc2500.ino
Normal file
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
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(HITEC_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
//#define HITEC_FORCE_ID //Use the ID and hopping table from the original dump
|
||||
|
||||
#define HITEC_COARSE 0
|
||||
|
||||
#define HITEC_PACKET_LEN 13
|
||||
#define HITEC_TX_ID_LEN 2
|
||||
#define HITEC_BIND_COUNT 444 // 10sec
|
||||
#define HITEC_NUM_FREQUENCE 21
|
||||
#define HITEC_BIND_NUM_FREQUENCE 14
|
||||
|
||||
enum {
|
||||
HITEC_START = 0x00,
|
||||
HITEC_CALIB = 0x01,
|
||||
HITEC_PREP = 0x02,
|
||||
HITEC_DATA1 = 0x03,
|
||||
HITEC_DATA2 = 0x04,
|
||||
HITEC_DATA3 = 0x05,
|
||||
HITEC_DATA4 = 0x06,
|
||||
HITEC_RX1 = 0x07,
|
||||
HITEC_RX2 = 0x08,
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t HITEC_init_values[] = {
|
||||
/* 00 */ 0x2F, 0x2E, 0x2F, 0x07, 0xD3, 0x91, 0xFF, 0x04,
|
||||
/* 08 */ 0x45, 0x00, 0x00, 0x12, 0x00, 0x5C, 0x85, 0xE8 + HITEC_COARSE,
|
||||
/* 10 */ 0x3D, 0x3B, 0x73, 0x73, 0x7A, 0x01, 0x07, 0x30,
|
||||
/* 18 */ 0x08, 0x1D, 0x1C, 0xC7, 0x40, 0xB0, 0x87, 0x6B,
|
||||
/* 20 */ 0xF8, 0xB6, 0x10, 0xEA, 0x0A, 0x00, 0x11
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) HITEC_CC2500_init()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
|
||||
for (uint8_t i = 0; i < 39; ++i)
|
||||
CC2500_WriteReg(i, pgm_read_byte_near(&HITEC_init_values[i]));
|
||||
|
||||
prev_option = option;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
}
|
||||
|
||||
// Generate RF channels
|
||||
static void __attribute__((unused)) HITEC_RF_channels()
|
||||
{
|
||||
//Normal hopping
|
||||
uint8_t idx = 0;
|
||||
uint32_t rnd = MProtocol_id;
|
||||
|
||||
while (idx < HITEC_NUM_FREQUENCE)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t count_0_47 = 0, count_48_93 = 0, count_94_140 = 0;
|
||||
|
||||
rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
|
||||
// Use least-significant byte and make sure it's pair.
|
||||
uint8_t next_ch = ((rnd >> 8) % 141) & 0xFE;
|
||||
// Check that it's not duplicated and spread uniformly
|
||||
for (i = 0; i < idx; i++) {
|
||||
if(hopping_frequency[i] == next_ch)
|
||||
break;
|
||||
if(hopping_frequency[i] <= 47)
|
||||
count_0_47++;
|
||||
else if (hopping_frequency[i] <= 93)
|
||||
count_48_93++;
|
||||
else
|
||||
count_94_140++;
|
||||
}
|
||||
if (i != idx)
|
||||
continue;
|
||||
if ( (next_ch <= 47 && count_0_47 < 8) || (next_ch >= 48 && next_ch <= 93 && count_48_93 < 8) || (next_ch >= 94 && count_94_140 < 8) )
|
||||
hopping_frequency[idx++] = next_ch;//find hopping frequency
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HITEC_tune_chan()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency_no*10);
|
||||
else
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[hopping_frequency_no]);
|
||||
CC2500_Strobe(CC2500_SFTX);
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
CC2500_Strobe(CC2500_STX);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HITEC_change_chan_fast()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency_no*10);
|
||||
else
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[hopping_frequency_no]);
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[hopping_frequency_no]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HITEC_build_packet()
|
||||
{
|
||||
static boolean F5_frame=false;
|
||||
static uint8_t F5_counter=0;
|
||||
uint8_t offset;
|
||||
|
||||
packet[1] = rx_tx_addr[1];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = rx_tx_addr[3];
|
||||
packet[22] = 0xEE; // unknown always 0xEE
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[0] = 0x16; // 22 bytes to follow
|
||||
memset(packet+5,0x00,14);
|
||||
switch(bind_phase)
|
||||
{
|
||||
case 0x72: // first part of the hopping table
|
||||
for(uint8_t i=0;i<14;i++)
|
||||
packet[5+i]=hopping_frequency[i]>>1;
|
||||
break;
|
||||
case 0x73: // second part of the hopping table
|
||||
for(uint8_t i=0;i<7;i++)
|
||||
packet[5+i]=hopping_frequency[i+14]>>1;
|
||||
break;
|
||||
case 0x74:
|
||||
packet[7]=0x55; // unknown but bind does not complete if not there
|
||||
packet[8]=0x55; // unknown but bind does not complete if not there
|
||||
break;
|
||||
case 0x7B:
|
||||
packet[5]=hopping_frequency[13]>>1; // if not there the Optima link is jerky...
|
||||
break;
|
||||
}
|
||||
if(sub_protocol==MINIMA)
|
||||
packet[4] = bind_phase+0x10;
|
||||
else
|
||||
packet[4] = bind_phase; // Optima: increments based on RX answer
|
||||
packet[19] = 0x08; // packet sequence
|
||||
offset=20; // packet[20] and [21]
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0] = 0x1A; // 26 bytes to follow
|
||||
for(uint8_t i=0;i<9;i++)
|
||||
{
|
||||
uint16_t ch = convert_channel_16b_nolimit(i,0x1B87,0x3905);
|
||||
packet[4+2*i] = ch >> 8;
|
||||
packet[5+2*i] = ch & 0xFF;
|
||||
}
|
||||
packet[23] = 0x80; // packet sequence
|
||||
offset=24; // packet[24] and [25]
|
||||
packet[26] = 0x00; // unknown always 0 and the RX doesn't seem to care about the value?
|
||||
}
|
||||
|
||||
if(F5_frame)
|
||||
{// No idea what it is but Minima RXs are expecting these frames to work to work
|
||||
packet[offset] = 0xF5;
|
||||
packet[offset+1] = 0xDF;
|
||||
if((F5_counter%9)==0)
|
||||
packet[offset+1] -= 0x04; // every 8 packets send 0xDB
|
||||
F5_counter++;
|
||||
F5_counter%=59; // every 6 0xDB packets wait only 4 to resend instead of 8
|
||||
F5_frame=false; // alternate
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
packet[offset+1]++; // when binding the values are 0xE0 and 0xDC
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[offset] = 0x00;
|
||||
packet[offset+1] = 0x00;
|
||||
F5_frame=true; // alternate
|
||||
}
|
||||
/* debug("P:");
|
||||
for(uint8_t i=0;i<packet[0]+1;i++)
|
||||
debug("%02X,",packet[i]);
|
||||
debugln("");
|
||||
*/
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HITEC_send_packet()
|
||||
{
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[19] >>= 1; // packet sequence
|
||||
if( (packet[4] & 0xFE) ==0x82 )
|
||||
{ // Minima
|
||||
packet[4] ^= 1; // alternate 0x82 and 0x83
|
||||
if( packet[4] & 0x01 )
|
||||
for(uint8_t i=0;i<7;i++) // 0x83
|
||||
packet[5+i]=hopping_frequency[i+14]>>1;
|
||||
else
|
||||
for(uint8_t i=0;i<14;i++) // 0x82
|
||||
packet[5+i]=hopping_frequency[i]>>1;
|
||||
}
|
||||
}
|
||||
else
|
||||
packet[23] >>= 1; // packet sequence
|
||||
}
|
||||
|
||||
uint16_t ReadHITEC()
|
||||
{
|
||||
switch(phase)
|
||||
{
|
||||
case HITEC_START:
|
||||
HITEC_CC2500_init();
|
||||
bind_phase=0x72;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
bind_counter = HITEC_BIND_COUNT;
|
||||
rf_ch_num=HITEC_BIND_NUM_FREQUENCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
bind_counter=0;
|
||||
rf_ch_num=HITEC_NUM_FREQUENCE;
|
||||
//Set TXID
|
||||
CC2500_WriteReg(CC2500_05_SYNC0,rx_tx_addr[2]);
|
||||
CC2500_WriteReg(CC2500_04_SYNC1,rx_tx_addr[3]);
|
||||
}
|
||||
hopping_frequency_no=0;
|
||||
HITEC_tune_chan();
|
||||
phase = HITEC_CALIB;
|
||||
return 2000;
|
||||
case HITEC_CALIB:
|
||||
calData[hopping_frequency_no]=CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
hopping_frequency_no++;
|
||||
if (hopping_frequency_no < rf_ch_num)
|
||||
HITEC_tune_chan();
|
||||
else
|
||||
{
|
||||
hopping_frequency_no = 0;
|
||||
phase = HITEC_PREP;
|
||||
}
|
||||
return 2000;
|
||||
|
||||
/* Work cycle: 22.5ms */
|
||||
#define HITEC_PACKET_PERIOD 22500
|
||||
#define HITEC_PREP_TIMING 462
|
||||
#define HITEC_DATA_TIMING 2736
|
||||
#define HITEC_RX1_TIMING 4636
|
||||
case HITEC_PREP:
|
||||
if ( prev_option == option )
|
||||
{ // No user frequency change
|
||||
HITEC_change_chan_fast();
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no>=rf_ch_num)
|
||||
hopping_frequency_no=0;
|
||||
CC2500_SetPower();
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
HITEC_build_packet();
|
||||
phase++;
|
||||
}
|
||||
else
|
||||
phase = HITEC_START; // Restart the tune process if option is changed to get good tuned values
|
||||
return HITEC_PREP_TIMING;
|
||||
case HITEC_DATA1:
|
||||
case HITEC_DATA2:
|
||||
case HITEC_DATA3:
|
||||
case HITEC_DATA4:
|
||||
HITEC_send_packet();
|
||||
phase++;
|
||||
return HITEC_DATA_TIMING;
|
||||
case HITEC_RX1:
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
CC2500_Strobe(CC2500_SRX); // Turn RX ON
|
||||
phase++;
|
||||
return HITEC_RX1_TIMING;
|
||||
case HITEC_RX2:
|
||||
uint8_t len=CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if(len && len<MAX_PKT)
|
||||
{ // Something has been received
|
||||
CC2500_ReadData(pkt, len);
|
||||
if( (pkt[len-1] & 0x80) && pkt[0]==len-3 && pkt[1]==rx_tx_addr[1] && pkt[2]==rx_tx_addr[2] && pkt[3]==rx_tx_addr[3])
|
||||
{ //valid crc && length ok && tx_id ok
|
||||
debug("RX:l=%d",len);
|
||||
for(uint8_t i=0;i<len;i++)
|
||||
debug(",%02X",pkt[i]);
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
if(len==13) // Bind packets have a length of 13
|
||||
{ // bind packet: 0A,00,E5,F2,7X,05,06,07,08,09,00
|
||||
debug(",bind");
|
||||
boolean check=true;
|
||||
for(uint8_t i=5;i<=10;i++)
|
||||
if(pkt[i]!=i%10) check=false;
|
||||
if((pkt[4]&0xF0)==0x70 && check)
|
||||
{
|
||||
bind_phase=pkt[4]+1;
|
||||
if(bind_phase==0x7B)
|
||||
bind_counter=164; // in dumps the RX stops to reply at 0x7B so wait a little and exit
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if( len==15 && pkt[4]==0 && pkt[12]==0 )
|
||||
{ // Valid telemetry packets
|
||||
// no station:
|
||||
// 0C,1C,A1,2B,00,00,00,00,00,00,00,8D,00,64,8E -> 00 8D=>RX battery voltage 0x008D/28=5.03V
|
||||
// with HTS-SS:
|
||||
// 0C,1C,A1,2B,00,11,AF,00,2D,00,8D,11,00,4D,96 -> 00 8D=>RX battery voltage 0x008D/28=5.03V
|
||||
// 0C,1C,A1,2B,00,12,00,00,00,00,00,12,00,52,93
|
||||
// 0C,1C,A1,2B,00,13,00,00,00,00,46,13,00,52,8B -> 46=>temperature2 0x46-0x28=30°C
|
||||
// 0C,1C,A1,2B,00,14,00,00,00,00,41,14,00,2C,93 -> 41=>temperature1 0x41-0x28=25°C
|
||||
// 0C,1C,A1,2B,00,15,00,2A,00,0E,00,15,00,44,96 -> 2A 00=>rpm1=420, 0E 00=>rpm2=140
|
||||
// 0C,1C,A1,2B,00,16,00,00,00,00,00,16,00,2C,8E
|
||||
// 0C,1C,A1,2B,00,17,00,00,00,42,44,17,00,48,8D -> 42=>temperature3 0x42-0x28=26°C,44=>temperature4 0x44-0x28=28°C
|
||||
// 0C,1C,A1,2B,00,18,00,00,00,00,00,18,00,50,92
|
||||
debug(",telem,%02x",pkt[14]&0x7F);
|
||||
#if defined(HITEC_FW_TELEMETRY)
|
||||
if(sub_protocol==OPT_FW)
|
||||
{
|
||||
// 8 bytes telemetry packets => see at the end of this file how to fully decode it
|
||||
pkt[0]=pkt[13]; // TX RSSI
|
||||
pkt[1]=pkt[14]&0x7F; // TX LQI
|
||||
uint8_t offset=pkt[5]==0?1:0;
|
||||
for(uint8_t i=5;i < 11; i++)
|
||||
pkt[i-3]=pkt[i+offset]; // frame number followed by 5 bytes of data
|
||||
telemetry_link=2; // telemetry forward available
|
||||
}
|
||||
#endif
|
||||
#if defined(HITEC_HUB_TELEMETRY)
|
||||
if(sub_protocol==OPT_HUB)
|
||||
{
|
||||
switch(pkt[5]) // telemetry frame number
|
||||
{
|
||||
case 0x00:
|
||||
v_lipo1 = (pkt[10])<<5 | (pkt[11])>>3; // calculation in float is volt=(pkt[10]<<8+pkt[11])/28
|
||||
break;
|
||||
case 0x11:
|
||||
v_lipo1 = (pkt[9])<<5 | (pkt[10])>>3; // calculation in float is volt=(pkt[9]<<8+pkt[10])/28
|
||||
break;
|
||||
case 0x18:
|
||||
v_lipo2 = (pkt[6])<<5 | (pkt[7])>>3; // calculation in float is volt=(pkt[6]<<8+pkt[7])/10
|
||||
break;
|
||||
}
|
||||
TX_RSSI = pkt[13];
|
||||
if(TX_RSSI >=128)
|
||||
TX_RSSI -= 128;
|
||||
else
|
||||
TX_RSSI += 128;
|
||||
TX_LQI = pkt[14]&0x7F;
|
||||
telemetry_link=1; // telemetry hub available
|
||||
}
|
||||
#endif
|
||||
}
|
||||
debugln("");
|
||||
}
|
||||
}
|
||||
CC2500_Strobe(CC2500_SFRX); // Flush the RX FIFO buffer
|
||||
phase = HITEC_PREP;
|
||||
if(bind_counter)
|
||||
{
|
||||
bind_counter--;
|
||||
if(!bind_counter)
|
||||
{
|
||||
BIND_DONE;
|
||||
phase=HITEC_START;
|
||||
}
|
||||
}
|
||||
return (HITEC_PACKET_PERIOD -HITEC_PREP_TIMING -4*HITEC_DATA_TIMING -HITEC_RX1_TIMING);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t initHITEC()
|
||||
{
|
||||
HITEC_RF_channels();
|
||||
#ifdef HITEC_FORCE_ID // ID and channels taken from dump
|
||||
rx_tx_addr[1]=0x00;
|
||||
rx_tx_addr[2]=0x03;
|
||||
rx_tx_addr[3]=0x6A;
|
||||
memcpy((void *)hopping_frequency,(void *)"\x00\x3A\x4A\x32\x0C\x58\x2A\x10\x26\x20\x08\x60\x68\x70\x78\x80\x88\x56\x5E\x66\x6E",HITEC_NUM_FREQUENCE);
|
||||
#endif
|
||||
#if defined(HITEC_HUB_TELEMETRY)
|
||||
if(sub_protocol==OPT_HUB)
|
||||
init_frskyd_link_telemetry();
|
||||
#endif
|
||||
phase = HITEC_START;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
/* Full telemetry
|
||||
packet[0] = TX RSSI value
|
||||
packet[1] = TX LQI value
|
||||
packet[2] = frame number
|
||||
packet[3-7] telemetry data
|
||||
|
||||
The frame number takes the following values: 0x00, 0x11, 0x12, ..., 0x18. The frames can be present or not, they also do not have to follow each others.
|
||||
Here is a description of the telemetry data for each frame number:
|
||||
- frame 0x00
|
||||
data byte 0 -> 0x00 unknown
|
||||
data byte 1 -> 0x00 unknown
|
||||
data byte 2 -> 0x00 unknown
|
||||
data byte 3 -> RX Batt Volt_H
|
||||
data byte 4 -> RX Batt Volt_L => RX Batt=(Volt_H*256+Volt_L)/28
|
||||
- frame 0x11
|
||||
data byte 0 -> 0xAF start of frame
|
||||
data byte 1 -> 0x00 unknown
|
||||
data byte 2 -> 0x2D frame type but constant here
|
||||
data byte 3 -> Volt1_H
|
||||
data byte 4 -> Volt1_L RX Batt=(Volt1_H*256+Volt1_L)/28 V
|
||||
- frame 0x12
|
||||
data byte 0 -> Lat_sec_H GPS : latitude second
|
||||
data byte 1 -> Lat_sec_L signed int : 1/100 of second
|
||||
data byte 2 -> Lat_deg_min_H GPS : latitude degree.minute
|
||||
data byte 3 -> Lat_deg_min_L signed int : +=North, - = south
|
||||
data byte 4 -> Time_second GPS Time
|
||||
- frame 0x13
|
||||
data byte 0 -> GPS Longitude second
|
||||
data byte 1 -> signed int : 1/100 of second
|
||||
data byte 2 -> GPS Longitude degree.minute
|
||||
data byte 3 -> signed int : +=Est, - = west
|
||||
data byte 4 -> Temp2 Temperature2=Temp2-40°C
|
||||
- frame 0x14
|
||||
data byte 0 -> Speed_H
|
||||
data byte 1 -> Speed_L Speed=Speed_H*256+Speed_L km/h
|
||||
data byte 2 -> Alti_sea_H
|
||||
data byte 3 -> Alti_sea_L Altitude sea=Alti_sea_H*256+Alti_sea_L m
|
||||
data byte 4 -> Temp1 Temperature1=Temp1-40°C
|
||||
- frame 0x15
|
||||
data byte 0 -> FUEL
|
||||
data byte 1 -> RPM1_L
|
||||
data byte 2 -> RPM1_H RPM1=RPM1_H*256+RPM1_L
|
||||
data byte 3 -> RPM2_L
|
||||
data byte 4 -> RPM2_H RPM2=RPM2_H*256+RPM2_L
|
||||
- frame 0x16
|
||||
data byte 0 -> Date_year GPS Date
|
||||
data byte 1 -> Date_month
|
||||
data byte 2 -> Date_day
|
||||
data byte 3 -> Time_hour GPS Time
|
||||
data byte 4 -> Time_min
|
||||
- frame 0x17
|
||||
data byte 0 -> 0x00 COURSEH
|
||||
data byte 1 -> 0x00 COURSEL GPS Course = COURSEH*256+COURSEL
|
||||
data byte 2 -> 0x00 GPS count
|
||||
data byte 3 -> Temp3 Temperature3=Temp2-40°C
|
||||
data byte 4 -> Temp4 Temperature4=Temp3-40°C
|
||||
- frame 0x18
|
||||
data byte 1 -> Volt2_H
|
||||
data byte 2 -> Volt2_L Volt2=(Volt2_H*256+Volt2_L)/10 V
|
||||
data byte 3 -> AMP1_L
|
||||
data byte 4 -> AMP1_H Amp=(AMP1_H*256+AMP1_L -180)/14 in signed A
|
||||
*/
|
||||
#endif
|
||||
258
Multiprotocol/Hontai_nrf24l01.ino
Normal file
258
Multiprotocol/Hontai_nrf24l01.ino
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
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(HONTAI_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define HONTAI_BIND_COUNT 80
|
||||
#define HONTAI_PACKET_PERIOD 13500
|
||||
#define FQ777_951_PACKET_PERIOD 10000
|
||||
#define HONTAI_INITIAL_WAIT 500
|
||||
#define HONTAI_BIND_PACKET_SIZE 10
|
||||
#define HONTAI_PACKET_SIZE 12
|
||||
#define HONTAI_RF_BIND_CHANNEL 0
|
||||
|
||||
enum{
|
||||
HONTAI_FLAG_FLIP = 0x01,
|
||||
HONTAI_FLAG_PICTURE = 0x02,
|
||||
HONTAI_FLAG_VIDEO = 0x04,
|
||||
HONTAI_FLAG_HEADLESS = 0x08,
|
||||
HONTAI_FLAG_RTH = 0x10,
|
||||
HONTAI_FLAG_CALIBRATE = 0x20,
|
||||
};
|
||||
|
||||
// proudly swiped from http://www.drdobbs.com/implementing-the-ccitt-cyclical-redundan/199904926
|
||||
#define HONTAI_POLY 0x8408
|
||||
static void __attribute__((unused)) crc16(uint8_t *data_p, uint8_t length)
|
||||
{
|
||||
uint16_t crc = 0xffff;
|
||||
|
||||
length -= 2;
|
||||
do
|
||||
{
|
||||
for (uint8_t i = 0, data = (uint8_t)*data_p++;
|
||||
i < 8;
|
||||
i++, data >>= 1)
|
||||
{
|
||||
if ((crc & 0x01) ^ (data & 0x01))
|
||||
crc = (crc >> 1) ^ HONTAI_POLY;
|
||||
else
|
||||
crc >>= 1;
|
||||
}
|
||||
} while (--length);
|
||||
|
||||
crc = ~crc;
|
||||
*data_p++ = crc & 0xff;
|
||||
*data_p = crc >> 8;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HONTAI_send_packet(uint8_t bind)
|
||||
{
|
||||
if (bind)
|
||||
{
|
||||
memcpy(packet, rx_tx_addr, 5);
|
||||
memset(&packet[5], 0, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(packet,0,HONTAI_PACKET_SIZE);
|
||||
packet[3] = convert_channel_16b_limit(THROTTLE, 0, 127) << 1; // Throttle
|
||||
packet[4] = convert_channel_16b_limit(AILERON, 63, 0); // Aileron
|
||||
packet[5] = convert_channel_16b_limit(ELEVATOR, 0, 63); // Elevator
|
||||
packet[6] = convert_channel_16b_limit(RUDDER, 0, 63); // Rudder
|
||||
if(sub_protocol == X5C1)
|
||||
packet[7] = convert_channel_16b_limit(AILERON, 0, 63)-31; // Aileron trim
|
||||
else
|
||||
packet[7] = convert_channel_16b_limit(AILERON, 0, 32)-16; // Aileron trim
|
||||
packet[8] = convert_channel_16b_limit(RUDDER, 0, 32)-16; // Rudder trim
|
||||
if (sub_protocol == X5C1)
|
||||
packet[9] = convert_channel_16b_limit(ELEVATOR, 0, 63)-31; // Elevator trim
|
||||
else
|
||||
packet[9] = convert_channel_16b_limit(ELEVATOR, 0, 32)-16; // Elevator trim
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case HONTAI:
|
||||
packet[0] = 0x0B;
|
||||
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
|
||||
packet[4] |= GET_FLAG(CH10_SW, 0x80) // RTH
|
||||
| GET_FLAG(CH9_SW, 0x40); // Headless
|
||||
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
|
||||
| GET_FLAG(CH5_SW, 0x40); // Flip
|
||||
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
|
||||
break;
|
||||
case JJRCX1:
|
||||
packet[0] = GET_FLAG(CH6_SW, 0x02); // Arm
|
||||
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
|
||||
packet[4] |= 0x80; // unknown
|
||||
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
|
||||
| GET_FLAG(CH5_SW, 0x40); // Flip
|
||||
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
|
||||
packet[8] = 0xC0 // high rate, no rudder trim
|
||||
| GET_FLAG(CH10_SW, 0x02) // RTH
|
||||
| GET_FLAG(CH9_SW, 0x01); // Headless
|
||||
break;
|
||||
case X5C1:
|
||||
packet[0] = 0x0B;
|
||||
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
|
||||
packet[4] = 0x80 // unknown
|
||||
| GET_FLAG(CH6_SW, 0x40); // Lights
|
||||
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
|
||||
| GET_FLAG(CH5_SW, 0x40); // Flip
|
||||
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
|
||||
packet[8] = 0xC0 // high rate, no rudder trim
|
||||
| GET_FLAG(CH10_SW, 0x02) // RTH
|
||||
| GET_FLAG(CH9_SW, 0x01); // Headless
|
||||
break;
|
||||
case FQ777_951:
|
||||
packet[0] = GET_FLAG(CH7_SW, 0x01) // Picture
|
||||
| GET_FLAG(CH8_SW, 0x02); // Video
|
||||
packet[3] |= GET_FLAG(CH5_SW, 0x01); // Flip
|
||||
packet[4] |= 0xC0; // High rate (mid=0xa0, low=0x60)
|
||||
packet[5] |= GET_FLAG(CH11_SW, 0x80); // Calibrate
|
||||
packet[6] |= GET_FLAG(CH9_SW, 0x40); // Headless
|
||||
break;
|
||||
}
|
||||
}
|
||||
crc16(packet, bind ? HONTAI_BIND_PACKET_SIZE:HONTAI_PACKET_SIZE);
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
if(sub_protocol == JJRCX1)
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
else
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? HONTAI_RF_BIND_CHANNEL : hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no %= 3;
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if(sub_protocol == JJRCX1)
|
||||
NRF24L01_WritePayload(packet, bind ? HONTAI_BIND_PACKET_SIZE:HONTAI_PACKET_SIZE);
|
||||
else
|
||||
XN297_WritePayload(packet, bind ? HONTAI_BIND_PACKET_SIZE:HONTAI_PACKET_SIZE);
|
||||
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HONTAI_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
if(sub_protocol == JJRCX1)
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xd2\xb5\x99\xb3\x4a", 5);
|
||||
else
|
||||
XN297_SetTXAddr((const uint8_t*)"\xd2\xb5\x99\xb3\x4a", 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_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
if(sub_protocol == JJRCX1)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0xff); // JJRC uses dynamic payload length
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f); // match other stock settings even though AA disabled...
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00);
|
||||
}
|
||||
NRF24L01_Activate(0x73); // Deactivate feature register
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM HONTAI_hopping_frequency_nonels[][3] = {
|
||||
{0x05, 0x19, 0x28}, // Hontai
|
||||
{0x0a, 0x1e, 0x2d}}; // JJRC X1
|
||||
|
||||
const uint8_t PROGMEM HONTAI_addr_vals[4][16] = {
|
||||
{0x24, 0x26, 0x2a, 0x2c, 0x32, 0x34, 0x36, 0x4a, 0x4c, 0x4e, 0x54, 0x56, 0x5a, 0x64, 0x66, 0x6a},
|
||||
{0x92, 0x94, 0x96, 0x9a, 0xa4, 0xa6, 0xac, 0xb2, 0xb4, 0xb6, 0xca, 0xcc, 0xd2, 0xd4, 0xd6, 0xda},
|
||||
{0x93, 0x95, 0x99, 0x9b, 0xa5, 0xa9, 0xab, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, 0xcd, 0xd3, 0xd5, 0xd9},
|
||||
{0x25, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x49, 0x4b, 0x4d, 0x59, 0x5b, 0x65, 0x69, 0x6b, 0x6d, 0x6e}};
|
||||
|
||||
static void __attribute__((unused)) HONTAI_init2()
|
||||
{
|
||||
uint8_t data_tx_addr[5];
|
||||
|
||||
//TX address
|
||||
data_tx_addr[0] = pgm_read_byte_near( &HONTAI_addr_vals[0][ rx_tx_addr[3] & 0x0f]);
|
||||
data_tx_addr[1] = pgm_read_byte_near( &HONTAI_addr_vals[1][(rx_tx_addr[3] >> 4) & 0x0f]);
|
||||
data_tx_addr[2] = pgm_read_byte_near( &HONTAI_addr_vals[2][ rx_tx_addr[4] & 0x0f]);
|
||||
data_tx_addr[3] = pgm_read_byte_near( &HONTAI_addr_vals[3][(rx_tx_addr[4] >> 4) & 0x0f]);
|
||||
data_tx_addr[4] = 0x24;
|
||||
if(sub_protocol == JJRCX1)
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, data_tx_addr, sizeof(data_tx_addr));
|
||||
else
|
||||
XN297_SetTXAddr(data_tx_addr, sizeof(data_tx_addr));
|
||||
|
||||
//Hopping frequency table
|
||||
for(uint8_t i=0;i<3;i++)
|
||||
hopping_frequency[i]=pgm_read_byte_near( &HONTAI_hopping_frequency_nonels[sub_protocol == JJRCX1?1:0][i] );
|
||||
hopping_frequency_no=0;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HONTAI_initialize_txid()
|
||||
{
|
||||
rx_tx_addr[4] = rx_tx_addr[2];
|
||||
if(sub_protocol == HONTAI || sub_protocol == FQ777_951)
|
||||
{
|
||||
rx_tx_addr[0] = 0x4c; // first three bytes some kind of model id? - set same as stock tx
|
||||
rx_tx_addr[1] = 0x4b;
|
||||
rx_tx_addr[2] = 0x3a;
|
||||
}
|
||||
else
|
||||
{
|
||||
rx_tx_addr[0] = 0x4b; // JJRC X1
|
||||
rx_tx_addr[1] = 0x59;
|
||||
rx_tx_addr[2] = 0x3a;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t HONTAI_callback()
|
||||
{
|
||||
if(bind_counter!=0)
|
||||
{
|
||||
HONTAI_send_packet(1);
|
||||
bind_counter--;
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
HONTAI_init2();
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
HONTAI_send_packet(0);
|
||||
|
||||
return sub_protocol == FQ777_951 ? FQ777_951_PACKET_PERIOD : HONTAI_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initHONTAI()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = HONTAI_BIND_COUNT;
|
||||
HONTAI_initialize_txid();
|
||||
HONTAI_init();
|
||||
return HONTAI_INITIAL_WAIT;
|
||||
}
|
||||
#endif
|
||||
@@ -12,19 +12,63 @@
|
||||
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 Hubsan H102D, H107/L/C/D and H107P/C+/D+
|
||||
// Last sync with hexfet new_protocols/hubsan_a7105.c dated 2015-12-11
|
||||
|
||||
#if defined(HUBSAN_A7105_INO)
|
||||
|
||||
#include "iface_a7105.h"
|
||||
|
||||
enum{
|
||||
HUBSAN_FLAG_VIDEO = 0x01, // record video
|
||||
HUBSAN_FLAG_FLIP = 0x08,
|
||||
HUBSAN_FLAG_LIGHT = 0x04
|
||||
// flags going to packet[9] (H107)
|
||||
HUBSAN_FLAG_VIDEO= 0x01, // record video
|
||||
HUBSAN_FLAG_FLIP = 0x08, // enable flips
|
||||
HUBSAN_FLAG_LED = 0x04 // enable LEDs
|
||||
};
|
||||
|
||||
uint32_t sessionid;
|
||||
const uint32_t txid = 0xdb042679;
|
||||
enum{
|
||||
// flags going to packet[9] (H107 Plus series)
|
||||
HUBSAN_FLAG_HEADLESS = 0x08, // headless mode
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[9] (H301)
|
||||
FLAG_H301_VIDEO = 0x01,
|
||||
FLAG_H301_STAB = 0x02,
|
||||
FLAG_H301_LED = 0x10,
|
||||
FLAG_H301_RTH = 0x40,
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[13] (H107 Plus series)
|
||||
HUBSAN_FLAG_SNAPSHOT = 0x01,
|
||||
HUBSAN_FLAG_FLIP_PLUS = 0x80,
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[9] (H501S)
|
||||
FLAG_H501_VIDEO = 0x01,
|
||||
FLAG_H501_LED = 0x04,
|
||||
FLAG_H122D_FLIP = 0x08, //H122D
|
||||
FLAG_H501_RTH = 0x20,
|
||||
FLAG_H501_HEADLESS1 = 0x40,
|
||||
FLAG_H501_GPS_HOLD = 0x80,
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[11] (H122D & H123D)
|
||||
FLAG_H123D_FMODES = 0x03, //H123D 3 FMODES: Sport mode 1, Sport mode 2, Acro
|
||||
FLAG_H122D_OSD = 0x20, //H122D OSD
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[13] (H501S)
|
||||
FLAG_H501_SNAPSHOT = 0x01,
|
||||
FLAG_H501_HEADLESS2 = 0x02,
|
||||
FLAG_H501_ALT_HOLD = 0x08,
|
||||
};
|
||||
|
||||
uint32_t hubsan_id_data;
|
||||
|
||||
enum {
|
||||
BIND_1,
|
||||
@@ -41,9 +85,9 @@ enum {
|
||||
DATA_4,
|
||||
DATA_5,
|
||||
};
|
||||
#define WAIT_WRITE 0x80
|
||||
#define HUBSAN_WAIT_WRITE 0x80
|
||||
|
||||
void update_crc()
|
||||
static void __attribute__((unused)) hubsan_update_crc()
|
||||
{
|
||||
uint8_t sum = 0;
|
||||
for(uint8_t i = 0; i < 15; i++)
|
||||
@@ -51,113 +95,250 @@ void update_crc()
|
||||
packet[15] = (256 - (sum % 256)) & 0xFF;
|
||||
}
|
||||
|
||||
void hubsan_build_bind_packet(uint8_t state)
|
||||
static void __attribute__((unused)) hubsan_build_bind_packet(uint8_t bind_state)
|
||||
{
|
||||
packet[0] = state;
|
||||
static uint8_t handshake_counter;
|
||||
if(phase < BIND_7)
|
||||
handshake_counter = 0;
|
||||
memset(packet, 0, 16);
|
||||
packet[0] = bind_state;
|
||||
packet[1] = channel;
|
||||
packet[2] = (sessionid >> 24) & 0xFF;
|
||||
packet[3] = (sessionid >> 16) & 0xFF;
|
||||
packet[4] = (sessionid >> 8) & 0xFF;
|
||||
packet[5] = (sessionid >> 0) & 0xFF;
|
||||
packet[6] = 0x08;
|
||||
packet[7] = 0xe4;
|
||||
packet[8] = 0xea;
|
||||
packet[9] = 0x9e;
|
||||
packet[10] = 0x50;
|
||||
packet[11] = (txid >> 24) & 0xFF;
|
||||
packet[12] = (txid >> 16) & 0xFF;
|
||||
packet[13] = (txid >> 8) & 0xFF;
|
||||
packet[14] = (txid >> 0) & 0xFF;
|
||||
update_crc();
|
||||
packet[2] = (MProtocol_id >> 24) & 0xFF;
|
||||
packet[3] = (MProtocol_id >> 16) & 0xFF;
|
||||
packet[4] = (MProtocol_id >> 8) & 0xFF;
|
||||
packet[5] = (MProtocol_id >> 0) & 0xFF;
|
||||
if(hubsan_id_data == ID_NORMAL && sub_protocol != H501)
|
||||
{
|
||||
packet[6] = 0x08;
|
||||
packet[7] = 0xe4;
|
||||
packet[8] = 0xea;
|
||||
packet[9] = 0x9e;
|
||||
packet[10] = 0x50;
|
||||
//const uint32_t txid = 0xdb042679;
|
||||
packet[11] = 0xDB;
|
||||
packet[12] = 0x04;
|
||||
packet[13] = 0x26;
|
||||
packet[14] = 0x79;
|
||||
}
|
||||
else
|
||||
{ //ID_PLUS
|
||||
if(phase >= BIND_3)
|
||||
{
|
||||
packet[7] = 0x62;
|
||||
packet[8] = 0x16;
|
||||
}
|
||||
if(phase == BIND_7)
|
||||
packet[2] = handshake_counter++;
|
||||
}
|
||||
hubsan_update_crc();
|
||||
}
|
||||
|
||||
//cc : throttle observed range: 0x00 - 0xFF (smaller is down)
|
||||
//ee : rudder observed range: 0x34 - 0xcc (smaller is right)52-204-60%
|
||||
//gg : elevator observed range: 0x3e - 0xbc (smaller is up)62-188 -50%
|
||||
//ii : aileron observed range: 0x45 - 0xc3 (smaller is right)69-195-50%
|
||||
void hubsan_build_packet()
|
||||
static void __attribute__((unused)) hubsan_build_packet()
|
||||
{
|
||||
static uint8_t vtx_freq = 0;
|
||||
static uint8_t vtx_freq = 0, h501_packet = 0;
|
||||
memset(packet, 0, 16);
|
||||
if(vtx_freq != option || packet_count==100) // set vTX frequency (H107D)
|
||||
{
|
||||
vtx_freq = option;
|
||||
packet[0] = 0x40;
|
||||
packet[1] = (option>0xF2)?0x17:0x16;
|
||||
packet[2] = option+0x0D; // 5645 - 5900 MHz
|
||||
packet[0] = 0x40; // vtx data packet
|
||||
packet[1] = (vtx_freq>0xF2)?0x17:0x16;
|
||||
packet[2] = vtx_freq+0x0D; // 5645 - 5900 MHz
|
||||
packet[3] = 0x82;
|
||||
packet_count++;
|
||||
}
|
||||
else //20 00 00 00 80 00 7d 00 84 02 64 db 04 26 79 7b
|
||||
{
|
||||
packet[0] = 0x20;
|
||||
packet[2] = convert_channel_8b(THROTTLE);//throtle
|
||||
packet[0] = 0x20; // normal data packet
|
||||
packet[2] = convert_channel_8b(THROTTLE); //Throtle
|
||||
}
|
||||
packet[4] = 0xFF - convert_channel_8b(RUDDER);//Rudder is reversed
|
||||
packet[6] = 0xFF - convert_channel_8b(ELEVATOR); //Elevator is reversed
|
||||
packet[8] = convert_channel_8b(AILERON);//aileron
|
||||
if( packet_count < 100) {
|
||||
packet[9] = 0x02 | HUBSAN_FLAG_LIGHT | HUBSAN_FLAG_FLIP;
|
||||
packet_count++;
|
||||
packet[4] = 0xFF - convert_channel_8b(RUDDER); //Rudder is reversed
|
||||
packet[6] = 0xFF - convert_channel_8b(ELEVATOR); //Elevator is reversed
|
||||
packet[8] = convert_channel_8b(AILERON); //Aileron
|
||||
if(hubsan_id_data == ID_NORMAL && sub_protocol==H107)
|
||||
{// H107/L/C/D, H102D
|
||||
if( packet_count < 100)
|
||||
{
|
||||
packet[9] = 0x02 | HUBSAN_FLAG_LED | HUBSAN_FLAG_FLIP; // sends default value for the 100 first packets
|
||||
packet_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[9] = 0x02;
|
||||
// Channel 5
|
||||
if(CH5_SW) packet[9] |= HUBSAN_FLAG_FLIP;
|
||||
// Channel 6
|
||||
if(CH6_SW) packet[9] |= HUBSAN_FLAG_LED;
|
||||
// Channel 8
|
||||
if(CH8_SW) packet[9] |= HUBSAN_FLAG_VIDEO; // H102D
|
||||
}
|
||||
packet[10] = 0x64;
|
||||
//const uint32_t txid = 0xdb042679;
|
||||
packet[11] = 0xDB;
|
||||
packet[12] = 0x04;
|
||||
packet[13] = 0x26;
|
||||
packet[14] = 0x79;
|
||||
} else if(sub_protocol==H301)
|
||||
{// H301
|
||||
if( packet_count < 100)
|
||||
{
|
||||
packet[9] = FLAG_H301_STAB; // sends default value for the 100 first packets
|
||||
packet_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[9] = GET_FLAG(CH6_SW, FLAG_H301_LED)
|
||||
| GET_FLAG(CH7_SW, FLAG_H301_STAB)
|
||||
| GET_FLAG(CH8_SW, FLAG_H301_VIDEO)
|
||||
| GET_FLAG(CH5_SW, FLAG_H301_RTH);
|
||||
}
|
||||
packet[10] = 0x18; // ?
|
||||
packet[12] = 0x5c; // ?
|
||||
packet[14] = 0xf6; // ?
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[9] = 0x02;
|
||||
// Channel 5
|
||||
if( Servo_data[AUX1] >= PPM_SWITCH)
|
||||
packet[9] |= HUBSAN_FLAG_FLIP;
|
||||
// Channel 6
|
||||
if( Servo_data[AUX2] >= PPM_SWITCH)
|
||||
packet[9] |= HUBSAN_FLAG_LIGHT;
|
||||
// Channel 8
|
||||
if( Servo_data[AUX4] > PPM_SWITCH)
|
||||
packet[9] |= HUBSAN_FLAG_VIDEO;
|
||||
{ //ID_PLUS && H501
|
||||
packet[3] = sub_protocol==H501 ? 0x00:0x64;
|
||||
packet[5] = sub_protocol==H501 ? 0x00:0x64;
|
||||
packet[7] = sub_protocol==H501 ? 0x00:0x64;
|
||||
|
||||
if(sub_protocol==H501)
|
||||
{ // H501S
|
||||
packet[9] = 0x02
|
||||
| GET_FLAG(CH6_SW, FLAG_H501_LED)
|
||||
| GET_FLAG(CH8_SW, FLAG_H501_VIDEO)
|
||||
| GET_FLAG(CH12_SW, FLAG_H122D_FLIP) // H122D specific -> flip
|
||||
| GET_FLAG(CH5_SW, FLAG_H501_RTH)
|
||||
| GET_FLAG(CH10_SW, FLAG_H501_GPS_HOLD)
|
||||
| GET_FLAG(CH9_SW, FLAG_H501_HEADLESS1);
|
||||
//packet[10]= 0x1A;
|
||||
|
||||
//packet[11] content 0x00 is default
|
||||
//H123D specific -> Flight modes
|
||||
packet[11] = 0x41; // Sport mode 1
|
||||
if(Channel_data[CH13]>CHANNEL_MAX_COMMAND)
|
||||
packet[11]=0x43; // Acro
|
||||
else if(Channel_data[CH13]>CHANNEL_MIN_COMMAND)
|
||||
packet[11]=0x42; // Sport mode 2
|
||||
//H122D specific -> OSD but useless...
|
||||
//packet[11]|= 0x80
|
||||
// | GET_FLAG(CHXX_SW,FLAG_H122D_OSD);
|
||||
|
||||
packet[13] = GET_FLAG(CH9_SW, FLAG_H501_HEADLESS2)
|
||||
| GET_FLAG(CH11_SW, FLAG_H501_ALT_HOLD)
|
||||
| GET_FLAG(CH7_SW, FLAG_H501_SNAPSHOT);
|
||||
}
|
||||
else
|
||||
{ // H107P/C+/D+
|
||||
packet[9] = 0x06;
|
||||
//FLIP|LIGHT|PICTURE|VIDEO|HEADLESS
|
||||
if(CH8_SW) packet[9] |= HUBSAN_FLAG_VIDEO;
|
||||
if(CH9_SW) packet[9] |= HUBSAN_FLAG_HEADLESS;
|
||||
packet[10]= 0x19;
|
||||
packet[12]= 0x5C; // ghost channel ?
|
||||
packet[13] = 0;
|
||||
if(CH7_SW) packet[13] = HUBSAN_FLAG_SNAPSHOT;
|
||||
if(CH5_SW) packet[13] |= HUBSAN_FLAG_FLIP_PLUS;
|
||||
packet[14]= 0x49; // ghost channel ?
|
||||
}
|
||||
if(packet_count < 100)
|
||||
{ // set channels to neutral for first 100 packets
|
||||
packet[2] = 0x80; // throttle neutral is at mid stick on plus series
|
||||
packet[4] = 0x80;
|
||||
packet[6] = 0x80;
|
||||
packet[8] = 0x80;
|
||||
packet[9] = 0x06;
|
||||
packet[13]= 0x00;
|
||||
packet_count++;
|
||||
}
|
||||
if(sub_protocol==H501)
|
||||
{ // H501S
|
||||
h501_packet++;
|
||||
if(h501_packet == 10)
|
||||
{
|
||||
memset(packet, 0, 16);
|
||||
packet[0] = 0xe8;
|
||||
}
|
||||
else if(h501_packet == 20)
|
||||
{
|
||||
memset(packet, 0, 16);
|
||||
packet[0] = 0xe9;
|
||||
}
|
||||
if(h501_packet >= 20) h501_packet = 0;
|
||||
}
|
||||
}
|
||||
packet[10] = 0x64;
|
||||
packet[11] = (txid >> 24) & 0xFF;
|
||||
packet[12] = (txid >> 16) & 0xFF;
|
||||
packet[13] = (txid >> 8) & 0xFF;
|
||||
packet[14] = (txid >> 0) & 0xFF;
|
||||
update_crc();
|
||||
hubsan_update_crc();
|
||||
}
|
||||
|
||||
uint8_t hubsan_check_integrity()
|
||||
#ifdef HUBSAN_HUB_TELEMETRY
|
||||
static uint8_t __attribute__((unused)) hubsan_check_integrity()
|
||||
{
|
||||
uint8_t sum = 0;
|
||||
for(int i = 0; i < 15; i++)
|
||||
if( (packet[0]&0xFE) != 0xE0 )
|
||||
return 0;
|
||||
uint8_t sum = 0;
|
||||
for(uint8_t i = 0; i < 15; i++)
|
||||
sum += packet[i];
|
||||
return packet[15] == ((256 - (sum % 256)) & 0xFF);
|
||||
return ( packet[15] == (uint8_t)(-sum) );
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t ReadHubsan()
|
||||
{
|
||||
static uint8_t txState=0;
|
||||
#ifdef HUBSAN_HUB_TELEMETRY
|
||||
static uint8_t rfMode=0;
|
||||
#endif
|
||||
static uint8_t txState=0;
|
||||
uint16_t delay;
|
||||
uint8_t i;
|
||||
|
||||
switch(phase) {
|
||||
#ifndef FORCE_HUBSAN_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
switch(phase)
|
||||
{
|
||||
case BIND_1:
|
||||
bind_phase++;
|
||||
if(bind_phase >= 20 && sub_protocol != H501)
|
||||
{
|
||||
if(hubsan_id_data == ID_NORMAL)
|
||||
hubsan_id_data = ID_PLUS;
|
||||
else
|
||||
hubsan_id_data = ID_NORMAL;
|
||||
A7105_WriteID(hubsan_id_data);
|
||||
bind_phase = 0;
|
||||
}
|
||||
case BIND_3:
|
||||
case BIND_5:
|
||||
case BIND_7:
|
||||
hubsan_build_bind_packet(phase == BIND_7 ? 9 : (phase == BIND_5 ? 1 : phase + 1 - BIND_1));
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
A7105_WriteData(16, channel);
|
||||
phase |= WAIT_WRITE;
|
||||
phase |= HUBSAN_WAIT_WRITE;
|
||||
return 3000;
|
||||
case BIND_1 | WAIT_WRITE:
|
||||
case BIND_3 | WAIT_WRITE:
|
||||
case BIND_5 | WAIT_WRITE:
|
||||
case BIND_7 | WAIT_WRITE:
|
||||
case BIND_1 | HUBSAN_WAIT_WRITE:
|
||||
case BIND_3 | HUBSAN_WAIT_WRITE:
|
||||
case BIND_5 | HUBSAN_WAIT_WRITE:
|
||||
case BIND_7 | HUBSAN_WAIT_WRITE:
|
||||
//wait for completion
|
||||
for(i = 0; i< 20; i++) {
|
||||
for(i = 0; i< 20; i++)
|
||||
if(! (A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
}
|
||||
A7105_SetTxRxMode(RX_EN);
|
||||
A7105_Strobe(A7105_RX);
|
||||
phase &= ~WAIT_WRITE;
|
||||
phase &= ~HUBSAN_WAIT_WRITE;
|
||||
if(hubsan_id_data == ID_PLUS)
|
||||
{
|
||||
if(phase == BIND_7 && packet[2] == 9)
|
||||
{
|
||||
phase = DATA_1;
|
||||
A7105_WriteReg(A7105_1F_CODE_I, 0x0F);
|
||||
BIND_DONE;
|
||||
return 4500;
|
||||
}
|
||||
}
|
||||
phase++;
|
||||
return 4500; //7.5msec elapsed since last write
|
||||
case BIND_2:
|
||||
@@ -168,7 +349,7 @@ uint16_t ReadHubsan()
|
||||
phase = BIND_1;
|
||||
return 4500; //No signal, restart binding procedure. 12msec elapsed since last write
|
||||
}
|
||||
A7105_ReadData();
|
||||
A7105_ReadData(16);
|
||||
phase++;
|
||||
if (phase == BIND_5)
|
||||
A7105_WriteID(((uint32_t)packet[2] << 24) | ((uint32_t)packet[3] << 16) | ((uint32_t)packet[4] << 8) | packet[5]);
|
||||
@@ -179,8 +360,8 @@ uint16_t ReadHubsan()
|
||||
phase = BIND_7;
|
||||
return 15000; //22.5msec elapsed since last write
|
||||
}
|
||||
A7105_ReadData();
|
||||
if(packet[1] == 9) {
|
||||
A7105_ReadData(16);
|
||||
if(packet[1] == 9 && hubsan_id_data == ID_NORMAL) {
|
||||
phase = DATA_1;
|
||||
A7105_WriteReg(A7105_1F_CODE_I, 0x0F);
|
||||
BIND_DONE;
|
||||
@@ -195,12 +376,19 @@ uint16_t ReadHubsan()
|
||||
case DATA_4:
|
||||
case DATA_5:
|
||||
if( txState == 0) { // send packet
|
||||
#ifdef HUBSAN_HUB_TELEMETRY
|
||||
rfMode = A7105_TX;
|
||||
#endif
|
||||
if( phase == DATA_1)
|
||||
A7105_SetPower(); //Keep transmit power in sync
|
||||
hubsan_build_packet();
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
A7105_WriteData(16, phase == DATA_5 ? channel + 0x23 : channel);
|
||||
uint8_t ch;
|
||||
if((phase == DATA_5 && hubsan_id_data == ID_NORMAL) && sub_protocol == H107)
|
||||
ch = channel + 0x23;
|
||||
else
|
||||
ch = channel;
|
||||
A7105_WriteData(16, ch);
|
||||
if (phase == DATA_5)
|
||||
phase = DATA_1;
|
||||
else
|
||||
@@ -208,8 +396,9 @@ uint16_t ReadHubsan()
|
||||
delay=3000;
|
||||
}
|
||||
else {
|
||||
#if defined(TELEMETRY)
|
||||
if( rfMode == A7105_TX) {// switch to rx mode 3ms after packet sent
|
||||
#ifdef HUBSAN_HUB_TELEMETRY
|
||||
if( rfMode == A7105_TX)
|
||||
{// switch to rx mode 3ms after packet sent
|
||||
for( i=0; i<10; i++)
|
||||
{
|
||||
if( !(A7105_ReadReg(A7105_00_MODE) & 0x01)) {// wait for tx completion
|
||||
@@ -220,15 +409,24 @@ uint16_t ReadHubsan()
|
||||
}
|
||||
}
|
||||
}
|
||||
if( rfMode == A7105_RX) { // check for telemetry frame
|
||||
for( i=0; i<10; i++) {
|
||||
if( !(A7105_ReadReg(A7105_00_MODE) & 0x01)) { // data received
|
||||
A7105_ReadData();
|
||||
if( !(A7105_ReadReg(A7105_00_MODE) & 0x01)){ // data received
|
||||
v_lipo=packet[13];// hubsan lipo voltage 8bits the real value is h_lipo/10(0x2A=42-4.2V)
|
||||
if( rfMode == A7105_RX)
|
||||
{ // check for telemetry frame
|
||||
for( i=0; i<10; i++)
|
||||
{
|
||||
if( !(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
{ // data received
|
||||
A7105_ReadData(16);
|
||||
if( hubsan_check_integrity() )
|
||||
{
|
||||
v_lipo1=packet[13]*2;// hubsan lipo voltage 8bits the real value is h_lipo/10(0x2A=42 -> 4.2V)
|
||||
telemetry_link=1;
|
||||
}
|
||||
A7105_Strobe(A7105_RX);
|
||||
// Read TX RSSI
|
||||
int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less
|
||||
if(temp<0) temp=0;
|
||||
else if(temp>255) temp=255;
|
||||
TX_RSSI=temp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -245,17 +443,30 @@ uint16_t ReadHubsan()
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t initHubsan() {
|
||||
uint16_t initHubsan()
|
||||
{
|
||||
const uint8_t allowed_ch[] = {0x14, 0x1e, 0x28, 0x32, 0x3c, 0x46, 0x50, 0x5a, 0x64, 0x6e, 0x78, 0x82};
|
||||
A7105_Init(INIT_HUBSAN); //hubsan_init();
|
||||
A7105_Init();
|
||||
|
||||
randomSeed((uint32_t)analogRead(A0) << 10 | analogRead(A4));
|
||||
sessionid = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16);
|
||||
channel = allowed_ch[random(0xfefefefe) % sizeof(allowed_ch)];
|
||||
channel = allowed_ch[MProtocol_id % sizeof(allowed_ch)];
|
||||
hubsan_id_data=ID_NORMAL;
|
||||
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
phase = BIND_1;
|
||||
if(IS_BIND_IN_PROGRESS || sub_protocol==H107)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
phase = BIND_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
phase = DATA_1;
|
||||
A7105_WriteID(MProtocol_id);
|
||||
A7105_WriteReg(A7105_1F_CODE_I, 0x0F);
|
||||
}
|
||||
packet_count=0;
|
||||
bind_phase=0;
|
||||
#ifdef HUBSAN_HUB_TELEMETRY
|
||||
init_frskyd_link_telemetry();
|
||||
#endif
|
||||
return 10000;
|
||||
}
|
||||
|
||||
|
||||
237
Multiprotocol/J6Pro_cyrf6936.ino
Normal file
237
Multiprotocol/J6Pro_cyrf6936.ino
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
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(J6PRO_CYRF6936_INO)
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
enum PktState {
|
||||
J6PRO_BIND,
|
||||
J6PRO_BIND_01,
|
||||
J6PRO_BIND_03_START,
|
||||
J6PRO_BIND_03_CHECK,
|
||||
J6PRO_BIND_05_1,
|
||||
J6PRO_BIND_05_2,
|
||||
J6PRO_BIND_05_3,
|
||||
J6PRO_BIND_05_4,
|
||||
J6PRO_BIND_05_5,
|
||||
J6PRO_BIND_05_6,
|
||||
J6PRO_CHANSEL,
|
||||
J6PRO_CHAN_1,
|
||||
J6PRO_CHAN_2,
|
||||
J6PRO_CHAN_3,
|
||||
J6PRO_CHAN_4,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM j6pro_bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49};
|
||||
const uint8_t j6pro_data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f};
|
||||
|
||||
static void __attribute__((unused)) j6pro_build_bind_packet()
|
||||
{
|
||||
packet[0] = 0x01; //Packet type
|
||||
packet[1] = 0x01; //FIXME: What is this? Model number maybe?
|
||||
packet[2] = 0x56; //FIXME: What is this?
|
||||
packet[3] = cyrfmfg_id[0];
|
||||
packet[4] = cyrfmfg_id[1];
|
||||
packet[5] = cyrfmfg_id[2];
|
||||
packet[6] = cyrfmfg_id[3];
|
||||
packet[7] = cyrfmfg_id[4];
|
||||
packet[8] = cyrfmfg_id[5];
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) j6pro_build_data_packet()
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t upperbits = 0;
|
||||
uint16_t value;
|
||||
packet[0] = 0xaa; //FIXME what is this?
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
value = convert_channel_10b(CH_AETR[i]);
|
||||
packet[i+1] = value & 0xff;
|
||||
upperbits |= (value >> 8) << (i * 2);
|
||||
}
|
||||
packet[13] = upperbits & 0xff;
|
||||
packet[14] = (upperbits >> 8) & 0xff;
|
||||
packet[15] = (upperbits >> 16) & 0xff;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) j6pro_cyrf_init()
|
||||
{
|
||||
/* Initialise CYRF chip */
|
||||
CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
|
||||
CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3c);
|
||||
CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
|
||||
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
|
||||
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
|
||||
//CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24);
|
||||
//CYRF_SetPower(0x05);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
|
||||
CYRF_SetPower(0x28);
|
||||
CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0e);
|
||||
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xee);
|
||||
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
|
||||
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x00);
|
||||
CYRF_ConfigDataCode(j6pro_data_code, 16);
|
||||
CYRF_WritePreamble(0x333302);
|
||||
|
||||
CYRF_GetMfgData(cyrfmfg_id);
|
||||
//Model match
|
||||
cyrfmfg_id[3]+=RX_num;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) cyrf_bindinit()
|
||||
{
|
||||
/* Use when binding */
|
||||
CYRF_SetPower(0x28); //Deviation using max power, replaced by bind power...
|
||||
//CYRF_ConfigRFChannel(0x52);
|
||||
CYRF_PROGMEM_ConfigSOPCode(j6pro_bind_sop_code);
|
||||
CYRF_ConfigCRCSeed(0x0000);
|
||||
//CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
|
||||
//CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80);
|
||||
//CYRF_ConfigRFChannel(0x52);
|
||||
//CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24);
|
||||
//CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
|
||||
j6pro_build_bind_packet();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) cyrf_datainit()
|
||||
{
|
||||
/* Use when already bound */
|
||||
uint8_t sop_idx = (0xff & (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[5])) % 19;
|
||||
uint16_t crc = (0xff & (cyrfmfg_id[1] - cyrfmfg_id[4] + cyrfmfg_id[5])) |
|
||||
((0xff & (cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[4] + cyrfmfg_id[5])) << 8);
|
||||
//CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24);
|
||||
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[sop_idx]);
|
||||
CYRF_ConfigCRCSeed(crc);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) j6pro_set_radio_channels()
|
||||
{
|
||||
//FIXME: Query free channels
|
||||
//lowest channel is 0x08, upper channel is 0x4d?
|
||||
CYRF_FindBestChannels(hopping_frequency, 3, 5, 8, 77);
|
||||
hopping_frequency[3] = hopping_frequency[0];
|
||||
}
|
||||
|
||||
uint16_t ReadJ6Pro()
|
||||
{
|
||||
uint16_t start;
|
||||
|
||||
switch(phase)
|
||||
{
|
||||
case J6PRO_BIND:
|
||||
cyrf_bindinit();
|
||||
phase = J6PRO_BIND_01;
|
||||
//no break because we want to send the 1st bind packet now
|
||||
case J6PRO_BIND_01:
|
||||
CYRF_ConfigRFChannel(0x52);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
//CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24);
|
||||
CYRF_WriteDataPacketLen(packet, 0x09);
|
||||
phase = J6PRO_BIND_03_START;
|
||||
return 3000; //3msec
|
||||
case J6PRO_BIND_03_START:
|
||||
start=(uint16_t)micros();
|
||||
while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 500) // Wait max 500µs
|
||||
if((CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80) == 0x00)
|
||||
break; // Packet transmission complete
|
||||
CYRF_ConfigRFChannel(0x53);
|
||||
CYRF_SetTxRxMode(RX_EN);
|
||||
//CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80);
|
||||
phase = J6PRO_BIND_03_CHECK;
|
||||
return 30000; //30msec
|
||||
case J6PRO_BIND_03_CHECK:
|
||||
{
|
||||
uint8_t rx = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx & 0x1a) == 0x1a) {
|
||||
rx = CYRF_ReadRegister(CYRF_0A_RX_LENGTH);
|
||||
if(rx == 0x0f) {
|
||||
rx = CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
||||
if(rx == 0x0f) {
|
||||
//Expected and actual length are both 15
|
||||
CYRF_ReadDataPacketLen(packet, rx);
|
||||
if (packet[0] == 0x03 &&
|
||||
packet[3] == cyrfmfg_id[0] &&
|
||||
packet[4] == cyrfmfg_id[1] &&
|
||||
packet[5] == cyrfmfg_id[2] &&
|
||||
packet[6] == cyrfmfg_id[3] &&
|
||||
packet[7] == cyrfmfg_id[4] &&
|
||||
packet[8] == cyrfmfg_id[5])
|
||||
{
|
||||
//Send back Ack
|
||||
packet[0] = 0x05;
|
||||
CYRF_ConfigRFChannel(0x54);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
phase = J6PRO_BIND_05_1;
|
||||
return 2000; //2msec
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
phase = J6PRO_BIND_01;
|
||||
return 500;
|
||||
}
|
||||
case J6PRO_BIND_05_1:
|
||||
case J6PRO_BIND_05_2:
|
||||
case J6PRO_BIND_05_3:
|
||||
case J6PRO_BIND_05_4:
|
||||
case J6PRO_BIND_05_5:
|
||||
case J6PRO_BIND_05_6:
|
||||
//CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24);
|
||||
CYRF_WriteDataPacketLen(packet, 0x0f);
|
||||
phase = phase + 1;
|
||||
return 4600; //4.6msec
|
||||
case J6PRO_CHANSEL:
|
||||
BIND_DONE;
|
||||
j6pro_set_radio_channels();
|
||||
cyrf_datainit();
|
||||
phase = J6PRO_CHAN_1;
|
||||
case J6PRO_CHAN_1:
|
||||
//Keep transmit power updated
|
||||
CYRF_SetPower(0x28);
|
||||
j6pro_build_data_packet();
|
||||
//return 3400;
|
||||
case J6PRO_CHAN_2:
|
||||
//return 3500;
|
||||
case J6PRO_CHAN_3:
|
||||
//return 3750
|
||||
case J6PRO_CHAN_4:
|
||||
CYRF_ConfigRFChannel(hopping_frequency[phase - J6PRO_CHAN_1]);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
CYRF_WriteDataPacket(packet);
|
||||
if (phase == J6PRO_CHAN_4) {
|
||||
phase = J6PRO_CHAN_1;
|
||||
return 13900;
|
||||
}
|
||||
phase = phase + 1;
|
||||
return 3550;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t initJ6Pro()
|
||||
{
|
||||
j6pro_cyrf_init();
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
phase = J6PRO_BIND;
|
||||
else
|
||||
phase = J6PRO_CHANSEL;
|
||||
return 2400;
|
||||
}
|
||||
|
||||
#endif
|
||||
109
Multiprotocol/KF606_nrf24l01.ino
Normal file
109
Multiprotocol/KF606_nrf24l01.ino
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
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 KF606 plane.
|
||||
|
||||
#if defined(KF606_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297l.h"
|
||||
|
||||
//#define FORCE_KF606_ORIGINAL_ID
|
||||
|
||||
#define KF606_INITIAL_WAIT 500
|
||||
#define KF606_PACKET_PERIOD 3000
|
||||
#define KF606_RF_BIND_CHANNEL 7
|
||||
#define KF606_PAYLOAD_SIZE 4
|
||||
#define KF606_BIND_COUNT 857 //3sec
|
||||
#define KF606_RF_NUM_CHANNELS 2
|
||||
|
||||
static void __attribute__((unused)) KF606_send_packet()
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[0] = 0xAA;
|
||||
memcpy(&packet[1],rx_tx_addr,3);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0]= 0x55;
|
||||
packet[1]= convert_channel_8b(THROTTLE); // 0..255
|
||||
// Deadband is needed on aileron, 40 gives +-6%
|
||||
packet[2]=convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, Low rates:50..80..AF, High rates:3E..80..C1
|
||||
// Aileron trim must be on a separated channel C1..D0..DF
|
||||
packet[3]= convert_channel_16b_limit(CH5,0xC1,0xDF);
|
||||
}
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
XN297L_Hopping(hopping_frequency_no);
|
||||
hopping_frequency_no ^= 1; // 2 RF channels
|
||||
}
|
||||
|
||||
XN297L_WritePayload(packet, KF606_PAYLOAD_SIZE);
|
||||
|
||||
XN297L_SetPower(); // Set tx_power
|
||||
XN297L_SetFreqOffset(); // Set frequency offset
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) KF606_initialize_txid()
|
||||
{
|
||||
rx_tx_addr[0]=rx_tx_addr[3]; // Use RX_num;
|
||||
hopping_frequency[0]=(rx_tx_addr[0]&0x3F)+9;
|
||||
hopping_frequency[1]=hopping_frequency[0]+3;
|
||||
#ifdef FORCE_KF606_ORIGINAL_ID
|
||||
//TX1
|
||||
rx_tx_addr[0]=0x57;
|
||||
rx_tx_addr[1]=0x02;
|
||||
rx_tx_addr[2]=0x00;
|
||||
hopping_frequency[0]=0x20;
|
||||
hopping_frequency[0]=0x23;
|
||||
//TX2
|
||||
rx_tx_addr[0]=0x25;
|
||||
rx_tx_addr[1]=0x04;
|
||||
rx_tx_addr[2]=0x00;
|
||||
hopping_frequency[0]=0x2E;
|
||||
hopping_frequency[0]=0x31;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) KF606_init()
|
||||
{
|
||||
XN297L_Init();
|
||||
XN297L_SetTXAddr((uint8_t*)"\xe7\xe7\xe7\xe7\xe7", 5);
|
||||
XN297L_HoppingCalib(KF606_RF_NUM_CHANNELS); // Calibrate all channels
|
||||
XN297L_RFChannel(KF606_RF_BIND_CHANNEL); // Set bind channel
|
||||
}
|
||||
|
||||
uint16_t KF606_callback()
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
if(--bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
XN297_SetTXAddr(rx_tx_addr, 3);
|
||||
}
|
||||
KF606_send_packet();
|
||||
return KF606_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initKF606()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
KF606_initialize_txid();
|
||||
KF606_init();
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter=KF606_BIND_COUNT;
|
||||
return KF606_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -12,53 +12,241 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with hexfet new_protocols/KN_nrf24l01.c dated 2015-11-09
|
||||
|
||||
#if defined(KN_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define KN_BIND_COUNT 1000 // for KN 2sec every 2ms - 1000 packets
|
||||
// Timeout for callback in uSec, 2ms=2000us for KN
|
||||
#define KN_PACKET_PERIOD 2000
|
||||
#define KN_PACKET_CHKTIME 100 // Time to wait for packet to be sent (no ACK, so very short)
|
||||
// Wait for RX chip stable - 10ms
|
||||
#define KN_INIT_WAIT_MS 10000
|
||||
|
||||
//#define PAYLOADSIZE 16
|
||||
#define NFREQCHANNELS 4
|
||||
#define KN_TXID_SIZE 4
|
||||
//Payload(16 bytes) plus overhead(10 bytes) is 208 bits, takes about 0.4ms or 0.2ms
|
||||
//to send for the rate of 500kb/s and 1Mb/s respectively.
|
||||
|
||||
// Callback timeout period for sending bind packets, minimum 250
|
||||
#define KN_BINDING_PACKET_PERIOD 1000
|
||||
|
||||
// Timeout for sending data packets, in uSec, KN protocol requires 2ms
|
||||
#define KN_WL_SENDING_PACKET_PERIOD 2000
|
||||
// Timeout for sending data packets, in uSec, KNFX protocol requires 1.2 ms
|
||||
#define KN_FX_SENDING_PACKET_PERIOD 1200
|
||||
|
||||
// packets to be sent during binding, last 0.5 seconds in WL Toys and 0.2 seconds in Feilun
|
||||
#define KN_WL_BIND_COUNT 500
|
||||
#define KN_FX_BIND_COUNT 200
|
||||
|
||||
#define KN_PAYLOADSIZE 16
|
||||
|
||||
//24L01 has 126 RF channels, can we use all of them?
|
||||
#define KN_MAX_RF_CHANNEL 73
|
||||
|
||||
//KN protocol for WL Toys changes RF frequency every 10 ms, repeats with only 4 channels.
|
||||
//Feilun variant uses only 2 channels, so we will just repeat the hopping channels later
|
||||
#define KN_RF_CH_COUNT 4
|
||||
|
||||
//KN protocol for WL Toys sends 4 data packets every 2ms per frequency, plus a 2ms gap.
|
||||
#define KN_WL_PACKET_SEND_COUNT 5
|
||||
//KN protocol for Feilun sends 8 data packets every 1.2ms per frequency, plus a 0.3ms gap.
|
||||
#define KN_FX_PACKET_SEND_COUNT 8
|
||||
|
||||
#define KN_TX_ADDRESS_SIZE 5
|
||||
|
||||
enum {
|
||||
KN_FLAG_DR = 0x01, // Dual Rate
|
||||
KN_FLAG_TH = 0x02, // Throttle Hold
|
||||
KN_FLAG_IDLEUP = 0x04, // Idle up
|
||||
KN_PHASE_PRE_BIND,
|
||||
KN_PHASE_BINDING,
|
||||
KN_PHASE_PRE_SEND,
|
||||
KN_PHASE_SENDING,
|
||||
};
|
||||
|
||||
enum {
|
||||
KN_FLAG_DR = 0x01, // Dual Rate: 1 - full range
|
||||
KN_FLAG_TH = 0x02, // Throttle Hold: 1 - hold
|
||||
KN_FLAG_IDLEUP = 0x04, // Idle up: 1 - 3D
|
||||
KN_FLAG_RES1 = 0x08,
|
||||
KN_FLAG_RES2 = 0x10,
|
||||
KN_FLAG_RES3 = 0x20,
|
||||
KN_FLAG_GYRO3 = 0x40, // 00 - 6G mode, 01 - 3G mode
|
||||
KN_FLAG_GYRO3 = 0x40, // 0 - 6G mode, 1 - 3G mode
|
||||
KN_FLAG_GYROR = 0x80 // Always 0 so far
|
||||
};
|
||||
|
||||
//
|
||||
enum {
|
||||
KN_INIT2 = 0,
|
||||
KN_INIT2_NO_BIND,
|
||||
KN_BIND,
|
||||
KN_DATA
|
||||
};
|
||||
|
||||
/*enum {
|
||||
USE1MBPS_NO = 0,
|
||||
USE1MBPS_YES = 1,
|
||||
};*/
|
||||
|
||||
// 2-bytes CRC
|
||||
#define CRC_CONFIG (BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO))
|
||||
|
||||
void kn_init()
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// This function init 24L01 regs and packet data for binding
|
||||
// Send tx address, hopping table (for Wl Toys), and data rate to the KN receiver during binding.
|
||||
// It seems that KN can remember these parameters, no binding needed after power up.
|
||||
// Bind uses fixed TX address "KNDZK", 1 Mbps data rate and channel 83
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) kn_bind_init()
|
||||
{
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"KNDZK", 5);
|
||||
packet[0] = 'K';
|
||||
packet[1] = 'N';
|
||||
packet[2] = 'D';
|
||||
packet[3] = 'Z';
|
||||
//Use first four bytes of tx_addr
|
||||
packet[4] = rx_tx_addr[0];
|
||||
packet[5] = rx_tx_addr[1];
|
||||
packet[6] = rx_tx_addr[2];
|
||||
packet[7] = rx_tx_addr[3];
|
||||
|
||||
if(sub_protocol==WLTOYS)
|
||||
{
|
||||
packet[8] = hopping_frequency[0];
|
||||
packet[9] = hopping_frequency[1];
|
||||
packet[10] = hopping_frequency[2];
|
||||
packet[11] = hopping_frequency[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[8] = 0x00;
|
||||
packet[9] = 0x00;
|
||||
packet[10] = 0x00;
|
||||
packet[11] = 0x00;
|
||||
}
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x00;
|
||||
packet[14] = 0x00;
|
||||
packet[15] = 0x01; //(USE1MBPS_YES) ? 0x01 : 0x00;
|
||||
|
||||
//Set RF channel
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 83);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Update control data to be sent
|
||||
// Do it once per frequency, so the same values will be sent 4 times
|
||||
// KN uses 4 10-bit data channels plus a 8-bit switch channel
|
||||
//
|
||||
// The packet[0] is used for pitch/throttle, the relation is hard coded, not changeable.
|
||||
// We can change the throttle/pitch range though.
|
||||
//
|
||||
// How to use trim? V977 stock controller can trim 6-axis mode to eliminate the drift.
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) kn_update_packet_control_data()
|
||||
{
|
||||
uint16_t value;
|
||||
value = convert_channel_10b(THROTTLE);
|
||||
packet[0] = (value >> 8) & 0xFF;
|
||||
packet[1] = value & 0xFF;
|
||||
value = convert_channel_10b(AILERON);
|
||||
packet[2] = (value >> 8) & 0xFF;
|
||||
packet[3] = value & 0xFF;
|
||||
value = convert_channel_10b(ELEVATOR);
|
||||
packet[4] = (value >> 8) & 0xFF;
|
||||
packet[5] = value & 0xFF;
|
||||
value = convert_channel_10b(RUDDER);
|
||||
packet[6] = (value >> 8) & 0xFF;
|
||||
packet[7] = value & 0xFF;
|
||||
// Trims, middle is 0x64 (100) range 0-200
|
||||
packet[8] = convert_channel_16b_limit(CH9,0,200); // 0x64; // T
|
||||
packet[9] = convert_channel_16b_limit(CH10,0,200); // 0x64; // A
|
||||
packet[10] = convert_channel_16b_limit(CH11,0,200); // 0x64; // E
|
||||
packet[11] = 0x64; // R
|
||||
|
||||
flags=0;
|
||||
if (CH5_SW)
|
||||
flags = KN_FLAG_DR;
|
||||
if (CH6_SW)
|
||||
flags |= KN_FLAG_TH;
|
||||
if (CH7_SW)
|
||||
flags |= KN_FLAG_IDLEUP;
|
||||
if (CH8_SW)
|
||||
flags |= KN_FLAG_GYRO3;
|
||||
|
||||
packet[12] = flags;
|
||||
|
||||
packet[13] = 0x00;
|
||||
if(sub_protocol==WLTOYS)
|
||||
packet[13] = (packet_sent << 5) | (hopping_frequency_no << 2);
|
||||
|
||||
packet[14] = 0x00;
|
||||
packet[15] = 0x00;
|
||||
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// This function generate RF TX packet address
|
||||
// V977 can remember the binding parameters; we do not need rebind when power up.
|
||||
// This requires the address must be repeatable for a specific RF ID at power up.
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) kn_calculate_tx_addr()
|
||||
{
|
||||
if(sub_protocol==FEILUN)
|
||||
{
|
||||
uint8_t addr2;
|
||||
// Generate TXID with sum of minimum 256 and maximum 256+MAX_RF_CHANNEL-32
|
||||
rx_tx_addr[1] = 1 + rx_tx_addr[0] % (KN_MAX_RF_CHANNEL-33);
|
||||
addr2 = 1 + rx_tx_addr[2] % (KN_MAX_RF_CHANNEL-33);
|
||||
if ((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1]) < 256)
|
||||
rx_tx_addr[2] = addr2;
|
||||
else
|
||||
rx_tx_addr[2] = 0x00;
|
||||
rx_tx_addr[3] = 0x00;
|
||||
while((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]) < 257)
|
||||
rx_tx_addr[3] += addr2;
|
||||
}
|
||||
//The 5th byte is a constant, must be 'K'
|
||||
rx_tx_addr[4] = 'K';
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// This function generates "random" RF hopping frequency channel numbers.
|
||||
// These numbers must be repeatable for a specific seed
|
||||
// The generated number range is from 0 to MAX_RF_CHANNEL. No repeat or adjacent numbers
|
||||
//
|
||||
// For Feilun variant, the channels are calculated from TXID, and since only 2 channels are used
|
||||
// we copy them to fill up to MAX_RF_CHANNEL
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) kn_calculate_freqency_hopping_channels()
|
||||
{
|
||||
if(sub_protocol==WLTOYS)
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint32_t rnd = MProtocol_id;
|
||||
while (idx < KN_RF_CH_COUNT)
|
||||
{
|
||||
uint8_t i;
|
||||
rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
|
||||
|
||||
// Use least-significant byte. 73 is prime, so channels 76..77 are unused
|
||||
uint8_t next_ch = ((rnd >> 8) % KN_MAX_RF_CHANNEL) + 2;
|
||||
// Keep the distance 2 between the channels - either odd or even
|
||||
if (((next_ch ^ MProtocol_id) & 0x01 )== 0)
|
||||
continue;
|
||||
// Check that it's not duplicate and spread uniformly
|
||||
for (i = 0; i < idx; i++)
|
||||
if(hopping_frequency[i] == next_ch)
|
||||
break;
|
||||
if (i != idx)
|
||||
continue;
|
||||
hopping_frequency[idx++] = next_ch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{//FEILUN
|
||||
hopping_frequency[0] = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]; // - 256; ???
|
||||
hopping_frequency[1] = hopping_frequency[0] + 32;
|
||||
hopping_frequency[2] = hopping_frequency[0];
|
||||
hopping_frequency[3] = hopping_frequency[1];
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// This function setup 24L01
|
||||
// V977 uses one way communication, receiving only. 24L01 RX is never enabled.
|
||||
// V977 needs payload length in the packet. We should configure 24L01 to enable Packet Control Field(PCF)
|
||||
// Some RX reg settings are actually for enable PCF
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
static void __attribute__((unused)) kn_init()
|
||||
{
|
||||
kn_calculate_tx_addr();
|
||||
kn_calculate_freqency_hopping_channels();
|
||||
|
||||
NRF24L01_Initialize();
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, CRC_CONFIG);
|
||||
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, 0x03); // 5-byte RX/TX address
|
||||
@@ -68,207 +256,92 @@ void kn_init()
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x20); // bytes of data payload for pipe 0
|
||||
|
||||
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
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);
|
||||
}
|
||||
// Enable: Dynamic Payload Length to enable PCF
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, _BV(NRF2401_1D_EN_DPL));
|
||||
|
||||
NRF24L01_SetPower();
|
||||
|
||||
uint16_t kn_init2()
|
||||
{
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
packet_sent = 0;
|
||||
packet_count = 0;
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
// Turn radio power on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, CRC_CONFIG | BV(NRF24L01_00_PWR_UP));
|
||||
return 150;
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); //USE1MBPS_YES ? NRF24L01_BR_1M : NRF24L01_BR_250K;
|
||||
}
|
||||
|
||||
void set_tx_for_bind()
|
||||
|
||||
//================================================================================================
|
||||
// Private Functions
|
||||
//================================================================================================
|
||||
uint16_t initKN()
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 83);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps for binding
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *) "KNDZK", 5);
|
||||
}
|
||||
|
||||
void set_tx_for_data()
|
||||
{
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
}
|
||||
|
||||
void kn_calc_fh_channels(uint32_t seed)
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint32_t rnd = seed;
|
||||
while (idx < NFREQCHANNELS) {
|
||||
uint8_t i;
|
||||
rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
|
||||
|
||||
// Use least-significant byte. 73 is prime, so channels 76..77 are unused
|
||||
uint8_t next_ch = ((rnd >> 8) % 73) + 2;
|
||||
// Keep the distance 2 between the channels - either odd or even
|
||||
if (((next_ch ^ seed) & 0x01 )== 0)
|
||||
continue;
|
||||
// Check that it's not duplicate and spread uniformly
|
||||
for (i = 0; i < idx; i++) {
|
||||
if(hopping_frequency[i] == next_ch)
|
||||
break;
|
||||
}
|
||||
if (i != idx)
|
||||
continue;
|
||||
hopping_frequency[idx++] = next_ch;
|
||||
if(sub_protocol==WLTOYS)
|
||||
{
|
||||
packet_period = KN_WL_SENDING_PACKET_PERIOD;
|
||||
bind_counter = KN_WL_BIND_COUNT;
|
||||
packet_count = KN_WL_PACKET_SEND_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
void kn_initialize_tx_id()
|
||||
{
|
||||
rx_tx_addr[4] = 'K';
|
||||
kn_calc_fh_channels(MProtocol_id);
|
||||
}
|
||||
|
||||
#define PACKET_COUNT_SHIFT 5
|
||||
#define RF_CHANNEL_SHIFT 2
|
||||
void kn_send_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t rf_ch;
|
||||
if (bind) {
|
||||
rf_ch = 83;
|
||||
packet[0] = 'K';
|
||||
packet[1] = 'N';
|
||||
packet[2] = 'D';
|
||||
packet[3] = 'Z';
|
||||
packet[4] = rx_tx_addr[0];
|
||||
packet[5] = rx_tx_addr[1];
|
||||
packet[6] = rx_tx_addr[2];
|
||||
packet[7] = rx_tx_addr[3];
|
||||
packet[8] = hopping_frequency[0];
|
||||
packet[9] = hopping_frequency[1];
|
||||
packet[10] = hopping_frequency[2];
|
||||
packet[11] = hopping_frequency[3];
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x00;
|
||||
packet[14] = 0x00;
|
||||
packet[15] = 0x01; //mode_bitrate == USE1MBPS_YES ? 0x01 : 0x00;
|
||||
} else {
|
||||
rf_ch = hopping_frequency[hopping_frequency_no];
|
||||
|
||||
// Each packet is repeated 4 times on the same channel
|
||||
// We're not strictly repeating them, rather we
|
||||
// send new packet on the same frequency, so the
|
||||
// receiver gets the freshest command. As receiver
|
||||
// hops to a new frequency as soon as valid packet
|
||||
// received it does not matter that the packet is
|
||||
// not the same one repeated twice - nobody checks this
|
||||
|
||||
// NB! packet_count overflow is handled and used in
|
||||
// callback.
|
||||
if (++packet_count == 4)
|
||||
hopping_frequency_no = (hopping_frequency_no + 1) & 0x03;
|
||||
|
||||
uint16_t kn_throttle, kn_rudder, kn_elevator, kn_aileron;
|
||||
kn_throttle = convert_channel_10b(THROTTLE);
|
||||
kn_aileron = convert_channel_10b(AILERON);
|
||||
kn_elevator = convert_channel_10b(ELEVATOR);
|
||||
kn_rudder = convert_channel_10b(RUDDER);
|
||||
packet[0] = (kn_throttle >> 8) & 0xFF;
|
||||
packet[1] = kn_throttle & 0xFF;
|
||||
packet[2] = (kn_aileron >> 8) & 0xFF;
|
||||
packet[3] = kn_aileron & 0xFF;
|
||||
packet[4] = (kn_elevator >> 8) & 0xFF;
|
||||
packet[5] = kn_elevator & 0xFF;
|
||||
packet[6] = (kn_rudder >> 8) & 0xFF;
|
||||
packet[7] = kn_rudder & 0xFF;
|
||||
// Trims, middle is 0x64 (100) 0-200
|
||||
packet[8] = 0x64; // T
|
||||
packet[9] = 0x64; // A
|
||||
packet[10] = 0x64; // E
|
||||
packet[11] = 0x64; // R
|
||||
|
||||
if (Servo_data[AUX1] > PPM_SWITCH)
|
||||
flags |= KN_FLAG_DR;
|
||||
else
|
||||
flags=0;
|
||||
if (Servo_data[AUX2] > PPM_SWITCH)
|
||||
flags |= KN_FLAG_TH;
|
||||
if (Servo_data[AUX3] > PPM_SWITCH)
|
||||
flags |= KN_FLAG_IDLEUP;
|
||||
if (Servo_data[AUX4] > PPM_SWITCH)
|
||||
flags |= KN_FLAG_GYRO3;
|
||||
|
||||
packet[12] = flags;
|
||||
|
||||
packet[13] = (packet_count << PACKET_COUNT_SHIFT) | (hopping_frequency_no << RF_CHANNEL_SHIFT);
|
||||
|
||||
packet[14] = 0x00;
|
||||
packet[15] = 0x00;
|
||||
else
|
||||
{
|
||||
packet_period = KN_FX_SENDING_PACKET_PERIOD;
|
||||
bind_counter = KN_FX_BIND_COUNT;
|
||||
packet_count = KN_FX_PACKET_SEND_COUNT;
|
||||
}
|
||||
kn_init();
|
||||
phase = IS_BIND_IN_PROGRESS ? KN_PHASE_PRE_BIND : KN_PHASE_PRE_SEND;
|
||||
|
||||
packet_sent = 0;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, 16);
|
||||
//++total_packets;
|
||||
packet_sent = 1;
|
||||
|
||||
if (! hopping_frequency_no) {
|
||||
//Keep transmit power updated
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
return KN_INIT_WAIT_MS;
|
||||
}
|
||||
|
||||
uint16_t kn_callback()
|
||||
{
|
||||
uint16_t timeout = KN_PACKET_PERIOD;
|
||||
switch (phase)
|
||||
{
|
||||
case KN_INIT2:
|
||||
bind_counter = KN_BIND_COUNT;
|
||||
timeout = kn_init2();
|
||||
phase = KN_BIND;
|
||||
set_tx_for_bind();
|
||||
break;
|
||||
case KN_INIT2_NO_BIND:
|
||||
timeout = kn_init2();
|
||||
phase = KN_DATA;
|
||||
set_tx_for_data();
|
||||
break;
|
||||
case KN_BIND:
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
|
||||
return KN_PACKET_CHKTIME;
|
||||
kn_send_packet(1);
|
||||
if (--bind_counter == 0) {
|
||||
phase = KN_DATA;
|
||||
set_tx_for_data();
|
||||
BIND_DONE;
|
||||
case KN_PHASE_PRE_BIND:
|
||||
kn_bind_init();
|
||||
phase=KN_PHASE_BINDING;
|
||||
//Do once, no break needed
|
||||
case KN_PHASE_BINDING:
|
||||
if(bind_counter>0)
|
||||
{
|
||||
bind_counter--;
|
||||
NRF24L01_WritePayload(packet, KN_PAYLOADSIZE);
|
||||
return KN_BINDING_PACKET_PERIOD;
|
||||
}
|
||||
break;
|
||||
case KN_DATA:
|
||||
if (packet_count == 4)
|
||||
packet_count = 0;
|
||||
else {
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
|
||||
return KN_PACKET_CHKTIME;
|
||||
kn_send_packet(0);
|
||||
BIND_DONE;
|
||||
//Continue
|
||||
case KN_PHASE_PRE_SEND:
|
||||
packet_sent = 0;
|
||||
hopping_frequency_no = 0;
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, KN_TX_ADDRESS_SIZE);
|
||||
phase = KN_PHASE_SENDING;
|
||||
//Do once, no break needed
|
||||
case KN_PHASE_SENDING:
|
||||
if(packet_sent >= packet_count)
|
||||
{
|
||||
packet_sent = 0;
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no >= KN_RF_CH_COUNT) hopping_frequency_no = 0;
|
||||
kn_update_packet_control_data();
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
|
||||
uint16_t initKN(){
|
||||
//total_packets = 0;
|
||||
//mode_bitrate=USE1MBPS_YES;
|
||||
kn_init();
|
||||
phase = IS_AUTOBIND_FLAG_on ? KN_INIT2 : KN_INIT2_NO_BIND;
|
||||
kn_initialize_tx_id();
|
||||
|
||||
// Call callback in 50ms
|
||||
return 50000;
|
||||
else
|
||||
{
|
||||
// Update sending count and RF channel index.
|
||||
// The protocol sends 4 data packets every 2ms per frequency, plus a 2ms gap.
|
||||
// Each data packet need a packet number and RF channel index
|
||||
packet[13] = 0x00;
|
||||
if(sub_protocol==WLTOYS)
|
||||
packet[13] = (packet_sent << 5) | (hopping_frequency_no << 2);
|
||||
}
|
||||
NRF24L01_WritePayload(packet, KN_PAYLOADSIZE);
|
||||
packet_sent++;
|
||||
return packet_period;
|
||||
} //switch
|
||||
|
||||
//Bad things happened, reset
|
||||
packet_sent = 0;
|
||||
phase = KN_PHASE_PRE_SEND;
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
358
Multiprotocol/MJXQ_nrf24l01.ino
Normal file
358
Multiprotocol/MJXQ_nrf24l01.ino
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// compatible with MJX WLH08, X600, X800, H26D, Eachine E010
|
||||
// Last sync with hexfet new_protocols/mjxq_nrf24l01.c dated 2016-01-17
|
||||
|
||||
#if defined(MJXQ_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
#include "iface_xn297l.h"
|
||||
|
||||
#define MJXQ_BIND_COUNT 150
|
||||
#define MJXQ_PACKET_PERIOD 4000 // Timeout for callback in uSec
|
||||
#define MJXQ_INITIAL_WAIT 500
|
||||
#define MJXQ_PACKET_SIZE 16
|
||||
#define MJXQ_RF_NUM_CHANNELS 4
|
||||
#define MJXQ_ADDRESS_LENGTH 5
|
||||
|
||||
// haven't figured out txid<-->rf channel mapping for MJX models
|
||||
const uint8_t PROGMEM MJXQ_map_txid[][3] = {
|
||||
{0xF8, 0x4F, 0x1C},
|
||||
{0xC8, 0x6E, 0x02},
|
||||
{0x48, 0x6A, 0x40} };
|
||||
const uint8_t PROGMEM MJXQ_map_rfchan[][4] = {
|
||||
{0x0A, 0x46, 0x3A, 0x42},
|
||||
{0x0A, 0x3C, 0x36, 0x3F},
|
||||
{0x0A, 0x43, 0x36, 0x3F} };
|
||||
|
||||
const uint8_t PROGMEM E010_map_txid[][2] = {
|
||||
{0x4F, 0x1C},
|
||||
{0x90, 0x1C},
|
||||
{0x24, 0x36},
|
||||
{0x7A, 0x40},
|
||||
{0x61, 0x31},
|
||||
{0x5D, 0x37},
|
||||
{0xFD, 0x4F},
|
||||
{0x86, 0x3C},
|
||||
{0x41, 0x22},
|
||||
{0xEE, 0xB3},
|
||||
{0x9A, 0xB2},
|
||||
{0xC0, 0x44},
|
||||
{0x2A, 0xFE},
|
||||
{0xD7, 0x6E},
|
||||
{0x3C, 0xCD}, // for this ID rx_tx_addr[2]=0x01
|
||||
{0xF5, 0x2B} // for this ID rx_tx_addr[2]=0x02
|
||||
};
|
||||
const uint8_t PROGMEM E010_map_rfchan[][2] = {
|
||||
{0x3A, 0x35},
|
||||
{0x2E, 0x36},
|
||||
{0x32, 0x3E},
|
||||
{0x2E, 0x3C},
|
||||
{0x2F, 0x3B},
|
||||
{0x33, 0x3B},
|
||||
{0x33, 0x3B},
|
||||
{0x34, 0x3E},
|
||||
{0x34, 0x2F},
|
||||
{0x39, 0x3E},
|
||||
{0x2E, 0x38},
|
||||
{0x2E, 0x36},
|
||||
{0x2E, 0x38},
|
||||
{0x3A, 0x41},
|
||||
{0x32, 0x3E},
|
||||
{0x33, 0x3F}
|
||||
};
|
||||
|
||||
#define MJXQ_PAN_TILT_COUNT 16 // for H26D - match stock tx timing
|
||||
#define MJXQ_PAN_DOWN 0x08
|
||||
#define MJXQ_PAN_UP 0x04
|
||||
#define MJXQ_TILT_DOWN 0x20
|
||||
#define MJXQ_TILT_UP 0x10
|
||||
|
||||
static uint8_t __attribute__((unused)) MJXQ_pan_tilt_value()
|
||||
{
|
||||
// CH12_SW PAN // H26D
|
||||
// CH13_SW TILT
|
||||
uint8_t pan = 0;
|
||||
packet_count++;
|
||||
if(packet_count & MJXQ_PAN_TILT_COUNT)
|
||||
{
|
||||
if(CH12_SW)
|
||||
pan=MJXQ_PAN_UP;
|
||||
if(Channel_data[CH12]<CHANNEL_MIN_COMMAND)
|
||||
pan=MJXQ_PAN_DOWN;
|
||||
if(CH13_SW)
|
||||
pan+=MJXQ_TILT_UP;
|
||||
if(Channel_data[CH13]<CHANNEL_MIN_COMMAND)
|
||||
pan+=MJXQ_TILT_DOWN;
|
||||
}
|
||||
return pan;
|
||||
}
|
||||
|
||||
#define MJXQ_CHAN2TRIM(X) (((X) & 0x80 ? (X) : 0x7f - (X)) >> 1)
|
||||
static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
|
||||
{
|
||||
packet[0] = convert_channel_8b(THROTTLE);
|
||||
packet[1] = convert_channel_s8b(RUDDER);
|
||||
packet[4] = 0x40; // rudder does not work well with dyntrim
|
||||
packet[2] = 0x80 ^ convert_channel_s8b(ELEVATOR);
|
||||
packet[5] = (CH9_SW || CH14_SW) ? 0x40 : MJXQ_CHAN2TRIM(packet[2]); // trim elevator
|
||||
packet[3] = convert_channel_s8b(AILERON);
|
||||
packet[6] = (CH9_SW || CH14_SW) ? 0x40 : MJXQ_CHAN2TRIM(packet[3]); // trim aileron
|
||||
packet[7] = rx_tx_addr[0];
|
||||
packet[8] = rx_tx_addr[1];
|
||||
packet[9] = rx_tx_addr[2];
|
||||
|
||||
packet[10] = 0x00; // overwritten below for feature bits
|
||||
packet[11] = 0x00; // overwritten below for X600
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x00;
|
||||
|
||||
packet[14] = 0xC0; // bind value
|
||||
|
||||
// CH5_SW FLIP
|
||||
// CH6_SW LED / ARM // H26WH - TDR Phoenix mini
|
||||
// CH7_SW PICTURE
|
||||
// CH8_SW VIDEO
|
||||
// CH9_SW HEADLESS
|
||||
// CH10_SW RTH
|
||||
// CH11_SW AUTOFLIP // X800, X600
|
||||
// CH12_SW PAN
|
||||
// CH13_SW TILT
|
||||
// CH14_SW XTRM // Dyntrim, don't use if high.
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case H26WH:
|
||||
case H26D:
|
||||
packet[10]=MJXQ_pan_tilt_value();
|
||||
// fall through on purpose - no break
|
||||
case WLH08:
|
||||
case E010:
|
||||
case PHOENIX:
|
||||
packet[10] += GET_FLAG(CH10_SW, 0x02) //RTH
|
||||
| GET_FLAG(CH9_SW, 0x01); //HEADLESS
|
||||
if (!bind)
|
||||
{
|
||||
packet[14] = 0x04
|
||||
| GET_FLAG(CH5_SW, 0x01) //FLIP
|
||||
| GET_FLAG(CH7_SW, 0x08) //PICTURE
|
||||
| GET_FLAG(CH8_SW, 0x10) //VIDEO
|
||||
| GET_FLAG(!CH6_SW, 0x20); // LED or air/ground mode
|
||||
if(sub_protocol==PHOENIX)
|
||||
{
|
||||
packet[10] |=0x20 //High rate
|
||||
| GET_FLAG(CH6_SW, 0x80); // arm
|
||||
packet[14] &= ~0x24; // unset air/ground & arm flags
|
||||
}
|
||||
if(sub_protocol==H26WH)
|
||||
{
|
||||
packet[10] |=0x40; //High rate
|
||||
packet[14] &= ~0x24; // unset air/ground & arm flags
|
||||
packet[14] |= GET_FLAG(CH6_SW, 0x02); // arm
|
||||
}
|
||||
}
|
||||
break;
|
||||
case X600:
|
||||
packet[10] = GET_FLAG(!CH6_SW, 0x02); //LED
|
||||
packet[11] = GET_FLAG(CH10_SW, 0x01); //RTH
|
||||
if (!bind)
|
||||
{
|
||||
packet[14] = 0x02 // always high rates by bit2 = 1
|
||||
| GET_FLAG(CH5_SW, 0x04) //FLIP
|
||||
| GET_FLAG(CH11_SW, 0x10) //AUTOFLIP
|
||||
| GET_FLAG(CH9_SW, 0x20); //HEADLESS
|
||||
}
|
||||
break;
|
||||
case X800:
|
||||
default:
|
||||
packet[10] = 0x10
|
||||
| GET_FLAG(!CH6_SW, 0x02) //LED
|
||||
| GET_FLAG(CH11_SW, 0x01); //AUTOFLIP
|
||||
if (!bind)
|
||||
{
|
||||
packet[14] = 0x02 // always high rates by bit2 = 1
|
||||
| GET_FLAG(CH5_SW, 0x04) //FLIP
|
||||
| GET_FLAG(CH7_SW, 0x08) //PICTURE
|
||||
| GET_FLAG(CH8_SW, 0x10); //VIDEO
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t sum = packet[0];
|
||||
for (uint8_t i=1; i < MJXQ_PACKET_SIZE-1; i++) sum += packet[i];
|
||||
packet[15] = sum;
|
||||
hopping_frequency_no++;
|
||||
if (sub_protocol == E010 || sub_protocol == PHOENIX)
|
||||
{
|
||||
XN297L_Hopping(hopping_frequency_no / 2);
|
||||
XN297L_SetFreqOffset();
|
||||
XN297L_SetPower();
|
||||
XN297L_WritePayload(packet, MJXQ_PACKET_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no / 2]);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
// Power on, TX mode, 2byte CRC and send packet
|
||||
if (sub_protocol == H26D || sub_protocol == H26WH)
|
||||
{
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WritePayload(packet, MJXQ_PACKET_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
XN297_WritePayload(packet, MJXQ_PACKET_SIZE);
|
||||
}
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
hopping_frequency_no %= 2 * MJXQ_RF_NUM_CHANNELS; // channels repeated
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) MJXQ_init()
|
||||
{
|
||||
uint8_t addr[MJXQ_ADDRESS_LENGTH];
|
||||
memcpy(addr, "\x6d\x6a\x77\x77\x77", MJXQ_ADDRESS_LENGTH);
|
||||
if (sub_protocol == WLH08)
|
||||
memcpy(hopping_frequency, "\x12\x22\x32\x42", MJXQ_RF_NUM_CHANNELS);
|
||||
else
|
||||
if (sub_protocol == H26D || sub_protocol == H26WH || sub_protocol == E010 || sub_protocol == PHOENIX)
|
||||
memcpy(hopping_frequency, "\x2e\x36\x3e\x46", MJXQ_RF_NUM_CHANNELS);
|
||||
else
|
||||
{
|
||||
memcpy(hopping_frequency, "\x0a\x35\x42\x3d", MJXQ_RF_NUM_CHANNELS);
|
||||
memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_ADDRESS_LENGTH);
|
||||
}
|
||||
if (sub_protocol == E010 || sub_protocol == PHOENIX)
|
||||
{
|
||||
XN297L_Init();
|
||||
XN297L_SetTXAddr(addr, sizeof(addr));
|
||||
XN297L_HoppingCalib(MJXQ_RF_NUM_CHANNELS);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
if (sub_protocol == H26D || sub_protocol == H26WH)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, addr, MJXQ_ADDRESS_LENGTH);
|
||||
}
|
||||
else
|
||||
XN297_SetTXAddr(addr, MJXQ_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 Acknowledgment 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_WriteReg(NRF24L01_11_RX_PW_P0, MJXQ_PACKET_SIZE);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) MJXQ_init2()
|
||||
{
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case H26D:
|
||||
memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS);
|
||||
break;
|
||||
case H26WH:
|
||||
memcpy(hopping_frequency, "\x37\x32\x47\x42", MJXQ_RF_NUM_CHANNELS);
|
||||
break;
|
||||
case E010:
|
||||
case PHOENIX:
|
||||
for(uint8_t i=0;i<2;i++)
|
||||
{
|
||||
hopping_frequency[i]=pgm_read_byte_near( &E010_map_rfchan[rx_tx_addr[3]&0x0F][i] );
|
||||
hopping_frequency[i+2]=hopping_frequency[i]+0x10;
|
||||
}
|
||||
XN297L_HoppingCalib(MJXQ_RF_NUM_CHANNELS);
|
||||
break;
|
||||
case WLH08:
|
||||
// do nothing
|
||||
break;
|
||||
default:
|
||||
for(uint8_t i=0;i<MJXQ_RF_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]=pgm_read_byte_near( &MJXQ_map_rfchan[rx_tx_addr[3]%3][i] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) MJXQ_initialize_txid()
|
||||
{
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case H26WH:
|
||||
memcpy(rx_tx_addr, "\xa4\x03\x00", 3);
|
||||
break;
|
||||
case E010:
|
||||
case PHOENIX:
|
||||
for(uint8_t i=0;i<2;i++)
|
||||
rx_tx_addr[i]=pgm_read_byte_near( &E010_map_txid[rx_tx_addr[3]&0x0F][i] );
|
||||
if((rx_tx_addr[3]&0x0E) == 0x0E)
|
||||
rx_tx_addr[2]=(rx_tx_addr[3]&0x01)+1;
|
||||
else
|
||||
rx_tx_addr[2]=0;
|
||||
break;
|
||||
case WLH08:
|
||||
rx_tx_addr[0]&=0xF8;
|
||||
rx_tx_addr[2]=rx_tx_addr[3]; // Make use of RX_Num
|
||||
break;
|
||||
default:
|
||||
for(uint8_t i=0;i<3;i++)
|
||||
rx_tx_addr[i]=pgm_read_byte_near( &MJXQ_map_txid[rx_tx_addr[3]%3][i] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t MJXQ_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
MJXQ_send_packet(0);
|
||||
else
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
MJXQ_init2();
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
bind_counter--;
|
||||
MJXQ_send_packet(1);
|
||||
}
|
||||
}
|
||||
|
||||
return MJXQ_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initMJXQ(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = MJXQ_BIND_COUNT;
|
||||
MJXQ_initialize_txid();
|
||||
MJXQ_init();
|
||||
packet_count=0;
|
||||
return MJXQ_INITIAL_WAIT+MJXQ_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
#endif
|
||||
305
Multiprotocol/MT99xx_nrf24l01.ino
Normal file
305
Multiprotocol/MT99xx_nrf24l01.ino
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
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 MT99xx, Eachine H7, Yi Zhan i6S and LS114/124
|
||||
// Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29
|
||||
|
||||
#if defined(MT99XX_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define MT99XX_BIND_COUNT 928
|
||||
#define MT99XX_PACKET_PERIOD_FY805 2460
|
||||
#define MT99XX_PACKET_PERIOD_MT 2625
|
||||
#define MT99XX_PACKET_PERIOD_YZ 3125
|
||||
#define MT99XX_INITIAL_WAIT 500
|
||||
#define MT99XX_PACKET_SIZE 9
|
||||
|
||||
#define checksum_offset rf_ch_num
|
||||
#define channel_offset phase
|
||||
|
||||
enum{
|
||||
// flags going to packet[6] (MT99xx, H7)
|
||||
FLAG_MT_RATE1 = 0x01, // (H7 high rate)
|
||||
FLAG_MT_RATE2 = 0x02, // (MT9916 only)
|
||||
FLAG_MT_VIDEO = 0x10,
|
||||
FLAG_MT_SNAPSHOT= 0x20,
|
||||
FLAG_MT_FLIP = 0x80,
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[6] (LS)
|
||||
FLAG_LS_INVERT = 0x01,
|
||||
FLAG_LS_RATE = 0x02,
|
||||
FLAG_LS_HEADLESS= 0x10,
|
||||
FLAG_LS_SNAPSHOT= 0x20,
|
||||
FLAG_LS_VIDEO = 0x40,
|
||||
FLAG_LS_FLIP = 0x80,
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[7] (FY805)
|
||||
FLAG_FY805_HEADLESS= 0x10,
|
||||
};
|
||||
|
||||
enum {
|
||||
MT99XX_INIT = 0,
|
||||
MT99XX_BIND,
|
||||
MT99XX_DATA
|
||||
};
|
||||
|
||||
const uint8_t h7_mys_byte[] = {
|
||||
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
|
||||
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
|
||||
};
|
||||
|
||||
static const uint8_t ls_mys_byte[] = {
|
||||
0x05, 0x15, 0x25, 0x06, 0x16, 0x26,
|
||||
0x07, 0x17, 0x27, 0x00, 0x10, 0x20,
|
||||
0x01, 0x11, 0x21, 0x02, 0x12, 0x22,
|
||||
0x03, 0x13, 0x23, 0x04, 0x14, 0x24
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) MT99XX_send_packet()
|
||||
{
|
||||
const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60};
|
||||
static uint8_t yz_seq_num=0;
|
||||
static uint8_t ls_counter=0;
|
||||
|
||||
if(sub_protocol != YZ)
|
||||
{ // MT99XX & H7 & LS
|
||||
packet[0] = convert_channel_16b_limit(THROTTLE,0xE1,0x00); // throttle
|
||||
packet[1] = convert_channel_16b_limit(RUDDER ,0x00,0xE1); // rudder
|
||||
packet[2] = convert_channel_16b_limit(AILERON ,0xE1,0x00); // aileron
|
||||
packet[3] = convert_channel_16b_limit(ELEVATOR,0x00,0xE1); // elevator
|
||||
packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00)
|
||||
packet[5] = 0x20; // roll trim (0x00-0x20-0x3f)
|
||||
packet[6] = GET_FLAG( CH5_SW, FLAG_MT_FLIP );
|
||||
packet[7] = h7_mys_byte[hopping_frequency_no]; // next rf channel index ?
|
||||
|
||||
if(sub_protocol==H7)
|
||||
packet[6]|=FLAG_MT_RATE1; // max rate on H7
|
||||
else
|
||||
if(sub_protocol==MT99)
|
||||
packet[6] |= 0x40 | FLAG_MT_RATE2
|
||||
| GET_FLAG( CH7_SW, FLAG_MT_SNAPSHOT )
|
||||
| GET_FLAG( CH8_SW, FLAG_MT_VIDEO ); // max rate on MT99xx
|
||||
else
|
||||
if(sub_protocol==FY805)
|
||||
{
|
||||
packet[6]=0x20;
|
||||
//Rate 0x01?
|
||||
//Flip ?
|
||||
packet[7]=0x01
|
||||
|GET_FLAG( CH5_SW, FLAG_MT_FLIP )
|
||||
|GET_FLAG( CH9_SW, FLAG_FY805_HEADLESS ); //HEADLESS
|
||||
checksum_offset=0;
|
||||
}
|
||||
else //LS
|
||||
{
|
||||
packet[6] |= FLAG_LS_RATE // max rate
|
||||
| GET_FLAG( CH6_SW, FLAG_LS_INVERT ) //INVERT
|
||||
| GET_FLAG( CH7_SW, FLAG_LS_SNAPSHOT ) //SNAPSHOT
|
||||
| GET_FLAG( CH8_SW, FLAG_LS_VIDEO ) //VIDEO
|
||||
| GET_FLAG( CH9_SW, FLAG_LS_HEADLESS ); //HEADLESS
|
||||
packet[7] = ls_mys_byte[ls_counter++];
|
||||
if(ls_counter >= sizeof(ls_mys_byte))
|
||||
ls_counter=0;
|
||||
}
|
||||
|
||||
uint8_t result=checksum_offset;
|
||||
for(uint8_t i=0; i<8; i++)
|
||||
result += packet[i];
|
||||
packet[8] = result;
|
||||
}
|
||||
else
|
||||
{ // YZ
|
||||
packet[0] = convert_channel_16b_limit(THROTTLE,0x00,0x64); // throttle
|
||||
packet[1] = convert_channel_16b_limit(RUDDER ,0x64,0x00); // rudder
|
||||
packet[2] = convert_channel_16b_limit(ELEVATOR,0x00,0x64); // elevator
|
||||
packet[3] = convert_channel_16b_limit(AILERON ,0x64,0x00); // aileron
|
||||
if(packet_count++ >= 23)
|
||||
{
|
||||
yz_seq_num ++;
|
||||
if(yz_seq_num > 2)
|
||||
yz_seq_num = 0;
|
||||
packet_count=0;
|
||||
}
|
||||
packet[4] = yz_p4_seq[yz_seq_num];
|
||||
packet[5] = 0x02 // expert ? (0=unarmed, 1=normal)
|
||||
| GET_FLAG(CH8_SW, 0x10) //VIDEO
|
||||
| GET_FLAG(CH5_SW, 0x80) //FLIP
|
||||
| GET_FLAG(CH9_SW, 0x04) //HEADLESS
|
||||
| GET_FLAG(CH7_SW, 0x20); //SNAPSHOT
|
||||
packet[6] = GET_FLAG(CH6_SW, 0x80); //LED
|
||||
packet[7] = packet[0];
|
||||
for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++)
|
||||
packet[7] += packet[idx];
|
||||
packet[8] = 0xff;
|
||||
}
|
||||
|
||||
if(sub_protocol == LS)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel
|
||||
else
|
||||
if(sub_protocol==FY805)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x4B); // FY805 always transmits on the same channel
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WritePayload(packet, MT99XX_PACKET_SIZE);
|
||||
|
||||
hopping_frequency_no++;
|
||||
if(sub_protocol == YZ)
|
||||
hopping_frequency_no++; // skip every other channel
|
||||
|
||||
if(hopping_frequency_no > 15)
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) MT99XX_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
if(sub_protocol == YZ)
|
||||
XN297_SetScrambledMode(XN297_UNSCRAMBLED);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5);
|
||||
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_03_SETUP_AW, 0x03); // 5 bytes address
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no auto retransmit
|
||||
if(sub_protocol == YZ)
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps (nRF24L01+ only)
|
||||
else
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) );
|
||||
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) MT99XX_initialize_txid()
|
||||
{
|
||||
rx_tx_addr[3] = 0xCC;
|
||||
rx_tx_addr[4] = 0xCC;
|
||||
if(sub_protocol == YZ)
|
||||
{
|
||||
rx_tx_addr[0] = 0x53; // test (SB id)
|
||||
rx_tx_addr[1] = 0x00;
|
||||
rx_tx_addr[2] = 0x00;
|
||||
}
|
||||
else
|
||||
if(sub_protocol == FY805)
|
||||
{
|
||||
rx_tx_addr[0] = 0x81; // test (SB id)
|
||||
rx_tx_addr[1] = 0x0F;
|
||||
rx_tx_addr[2] = 0x00;
|
||||
}
|
||||
else
|
||||
if(sub_protocol == LS)
|
||||
rx_tx_addr[0] = 0xCC;
|
||||
else //MT99 & H7
|
||||
rx_tx_addr[2] = 0x00;
|
||||
checksum_offset = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2];
|
||||
channel_offset = (((checksum_offset & 0xf0)>>4) + (checksum_offset & 0x0f)) % 8;
|
||||
}
|
||||
|
||||
uint16_t MT99XX_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
MT99XX_send_packet();
|
||||
else
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
// set tx address for data packets
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sub_protocol == LS)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel
|
||||
else
|
||||
if(sub_protocol==FY805)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x4B); // FY805 always transmits on the same channel
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WritePayload(packet, MT99XX_PACKET_SIZE); // bind packet
|
||||
hopping_frequency_no++;
|
||||
if(sub_protocol == YZ)
|
||||
hopping_frequency_no++; // skip every other channel
|
||||
if(hopping_frequency_no > 15)
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initMT99XX(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = MT99XX_BIND_COUNT;
|
||||
|
||||
memcpy(hopping_frequency,"\x02\x48\x0C\x3e\x16\x34\x20\x2A\x2A\x20\x34\x16\x3e\x0c\x48\x02",16);
|
||||
hopping_frequency_no=0;
|
||||
|
||||
MT99XX_initialize_txid();
|
||||
MT99XX_init();
|
||||
|
||||
packet[0] = 0x20;
|
||||
packet_period = MT99XX_PACKET_PERIOD_MT;
|
||||
switch(sub_protocol)
|
||||
{ // MT99 & H7
|
||||
case MT99:
|
||||
case H7:
|
||||
packet[1] = 0x14;
|
||||
packet[2] = 0x03;
|
||||
packet[3] = 0x25;
|
||||
break;
|
||||
case YZ:
|
||||
packet_period = MT99XX_PACKET_PERIOD_YZ;
|
||||
packet[1] = 0x15;
|
||||
packet[2] = 0x05;
|
||||
packet[3] = 0x06;
|
||||
break;
|
||||
case LS:
|
||||
packet[1] = 0x14;
|
||||
packet[2] = 0x05;
|
||||
packet[3] = 0x11;
|
||||
break;
|
||||
case FY805:
|
||||
packet_period = MT99XX_PACKET_PERIOD_FY805;
|
||||
packet[1] = 0x15;
|
||||
packet[2] = 0x12;
|
||||
packet[3] = 0x17;
|
||||
break;
|
||||
}
|
||||
packet[4] = rx_tx_addr[0];
|
||||
packet[5] = rx_tx_addr[1];
|
||||
packet[6] = rx_tx_addr[2];
|
||||
packet[7] = checksum_offset; // checksum offset
|
||||
packet[8] = 0xAA; // fixed
|
||||
packet_count=0;
|
||||
return MT99XX_INITIAL_WAIT+MT99XX_PACKET_PERIOD_MT;
|
||||
}
|
||||
#endif
|
||||
52
Multiprotocol/Multi.txt
Normal file
52
Multiprotocol/Multi.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
1,Flysky,Flysky,V9x9,V6x6,V912,CX20
|
||||
2,Hubsan,H107,H301,H501
|
||||
3,FrskyD
|
||||
4,Hisky,Hisky,HK310
|
||||
5,V2x2,V2x2,JXD506
|
||||
6,DSM,DSM2-22,DSM2-11,DSMX-22,DSMX-11,AUTO
|
||||
7,Devo,8CH,10CH,12CH,6CH,7CH
|
||||
8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI
|
||||
9,KN,WLTOYS,FEILUN
|
||||
10,SymaX,SYMAX,SYMAX5C
|
||||
11,SLT,SLT_V1,SLT_V2,Q100,Q200,MR100
|
||||
12,CX10,GREEN,BLUE,DM007,---,J3015_1,J3015_2,MK33041
|
||||
13,CG023,CG023,YD829
|
||||
14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE,DHD_D4
|
||||
15,FrskyX,CH_16,CH_8,EU_16,EU_8
|
||||
16,ESky
|
||||
17,MT99xx,MT,H7,YZ,LS,FY805
|
||||
18,MJXq,WLH08,X600,X800,H26D,E010,H26WH,PHOENIX
|
||||
19,Shenqi
|
||||
20,FY326,FY326,FY319
|
||||
21,SFHSS
|
||||
22,J6PRO
|
||||
23,FQ777
|
||||
24,ASSAN
|
||||
25,FrskyV
|
||||
26,HONTAI,HONTAI,JJRCX1,X5C1,FQ777_951
|
||||
27,OpnLrs
|
||||
28,AFHDS2A,PWM_IBUS,PPM_IBUS,PWM_SBUS,PPM_SBUS
|
||||
29,Q2X2,Q222,Q242,Q282
|
||||
30,WK2x01,WK2801,WK2401,W6_5_1,W6_6_1,W6_HEL,W6_HEL_I
|
||||
31,Q303,Q303,CX35,CX10D,CX10WD
|
||||
32,GW008
|
||||
33,DM002
|
||||
34,CABELL,CAB_V3,C_TELEM,-,-,-,-,F_SAFE,UNBIND
|
||||
35,ESKY150
|
||||
36,H8_3D,H8_3D,H20H,H20Mini,H30Mini
|
||||
37,CORONA,COR_V1,COR_V2,FD_V3
|
||||
38,CFlie
|
||||
39,Hitec,OPT_FW,OPT_HUB,MINIMA
|
||||
40,WFLY
|
||||
41,BUGS
|
||||
42,BUGSMINI,BUGSMINI,BUGS3H
|
||||
43,Traxxas
|
||||
44,NCC1701
|
||||
45,E01X,E012,E015,E016H
|
||||
46,V911S
|
||||
47,GD00X,GD_V1,GD_V2
|
||||
48,V761
|
||||
49,KF606
|
||||
50,REDPINE,FAST,SLOW
|
||||
51,POTENSIC,A20
|
||||
63,XN_DUMP,250K,1M,2M
|
||||
91
Multiprotocol/MultiOrange.h
Normal file
91
Multiprotocol/MultiOrange.h
Normal file
@@ -0,0 +1,91 @@
|
||||
//#define ARDUINO_AVR_PRO 1
|
||||
|
||||
#define ORANGE_TX 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#define yield()
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
|
||||
|
||||
// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
|
||||
// the overflow handler is called every 256 ticks.
|
||||
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
|
||||
|
||||
// the whole number of milliseconds per timer0 overflow
|
||||
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
|
||||
|
||||
// the fractional number of milliseconds per timer0 overflow. we shift right
|
||||
// by three to fit these numbers into a byte. (for the clock speeds we care
|
||||
// about - 8 and 16 MHz - this doesn't lose precision.)
|
||||
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
|
||||
#define FRACT_MAX (1000 >> 3)
|
||||
|
||||
#ifndef cbi
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif
|
||||
#ifndef sbi
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif
|
||||
|
||||
|
||||
void init()
|
||||
{
|
||||
// this needs to be called before setup() or some functions won't
|
||||
// work there
|
||||
|
||||
// Enable external oscillator (16MHz)
|
||||
OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_256CLK_gc ;
|
||||
OSC.CTRL |= OSC_XOSCEN_bm ;
|
||||
while( ( OSC.STATUS & OSC_XOSCRDY_bm ) == 0 )
|
||||
/* wait */ ;
|
||||
// Enable PLL (*2 = 32MHz)
|
||||
OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2 ;
|
||||
OSC.CTRL |= OSC_PLLEN_bm ;
|
||||
while( ( OSC.STATUS & OSC_PLLRDY_bm ) == 0 )
|
||||
/* wait */ ;
|
||||
// Switch to PLL clock
|
||||
CPU_CCP = 0xD8 ;
|
||||
CLK.CTRL = CLK_SCLKSEL_RC2M_gc ;
|
||||
CPU_CCP = 0xD8 ;
|
||||
CLK.CTRL = CLK_SCLKSEL_PLL_gc ;
|
||||
|
||||
PMIC.CTRL = 7 ; // Enable all interrupt levels
|
||||
sei();
|
||||
|
||||
#if defined(ADCSRA)
|
||||
// set a2d prescale factor to 128
|
||||
// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
|
||||
// XXX: this will not work properly for other clock speeds, and
|
||||
// this code should use F_CPU to determine the prescale factor.
|
||||
sbi(ADCSRA, ADPS2);
|
||||
sbi(ADCSRA, ADPS1);
|
||||
sbi(ADCSRA, ADPS0);
|
||||
|
||||
// enable a2d conversions
|
||||
sbi(ADCSRA, ADEN);
|
||||
#endif
|
||||
|
||||
// the bootloader connects pins 0 and 1 to the USART; disconnect them
|
||||
// here so they can be used as normal digital i/o; they will be
|
||||
// reconnected in Serial.begin()
|
||||
#if defined(UCSRB)
|
||||
UCSRB = 0;
|
||||
#elif defined(UCSR0B)
|
||||
UCSR0B = 0;
|
||||
#endif
|
||||
|
||||
// Dip Switch inputs
|
||||
PORTA.DIRCLR = 0xFF ;
|
||||
PORTA.PIN0CTRL = 0x18 ;
|
||||
PORTA.PIN1CTRL = 0x18 ;
|
||||
PORTA.PIN2CTRL = 0x18 ;
|
||||
PORTA.PIN3CTRL = 0x18 ;
|
||||
PORTA.PIN4CTRL = 0x18 ;
|
||||
PORTA.PIN5CTRL = 0x18 ;
|
||||
PORTA.PIN6CTRL = 0x18 ;
|
||||
PORTA.PIN7CTRL = 0x18 ;
|
||||
}
|
||||
872
Multiprotocol/Multiprotocol.h
Normal file
872
Multiprotocol/Multiprotocol.h
Normal file
@@ -0,0 +1,872 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
//******************
|
||||
// Version
|
||||
//******************
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 2
|
||||
#define VERSION_REVISION 1
|
||||
#define VERSION_PATCH_LEVEL 67
|
||||
|
||||
//******************
|
||||
// Protocols
|
||||
//******************
|
||||
enum PROTOCOLS
|
||||
{
|
||||
MODE_SERIAL = 0, // Serial commands
|
||||
PROTO_FLYSKY = 1, // =>A7105
|
||||
PROTO_HUBSAN = 2, // =>A7105
|
||||
PROTO_FRSKYD = 3, // =>CC2500
|
||||
PROTO_HISKY = 4, // =>NRF24L01
|
||||
PROTO_V2X2 = 5, // =>NRF24L01
|
||||
PROTO_DSM = 6, // =>CYRF6936
|
||||
PROTO_DEVO = 7, // =>CYRF6936
|
||||
PROTO_YD717 = 8, // =>NRF24L01
|
||||
PROTO_KN = 9, // =>NRF24L01
|
||||
PROTO_SYMAX = 10, // =>NRF24L01
|
||||
PROTO_SLT = 11, // =>NRF24L01
|
||||
PROTO_CX10 = 12, // =>NRF24L01
|
||||
PROTO_CG023 = 13, // =>NRF24L01
|
||||
PROTO_BAYANG = 14, // =>NRF24L01
|
||||
PROTO_FRSKYX = 15, // =>CC2500
|
||||
PROTO_ESKY = 16, // =>NRF24L01
|
||||
PROTO_MT99XX = 17, // =>NRF24L01
|
||||
PROTO_MJXQ = 18, // =>NRF24L01
|
||||
PROTO_SHENQI = 19, // =>NRF24L01
|
||||
PROTO_FY326 = 20, // =>NRF24L01
|
||||
PROTO_SFHSS = 21, // =>CC2500
|
||||
PROTO_J6PRO = 22, // =>CYRF6936
|
||||
PROTO_FQ777 = 23, // =>NRF24L01
|
||||
PROTO_ASSAN = 24, // =>NRF24L01
|
||||
PROTO_FRSKYV = 25, // =>CC2500
|
||||
PROTO_HONTAI = 26, // =>NRF24L01
|
||||
PROTO_OPENLRS = 27, // =>OpenLRS hardware
|
||||
PROTO_AFHDS2A = 28, // =>A7105
|
||||
PROTO_Q2X2 = 29, // =>NRF24L01, extension of CX-10 protocol
|
||||
PROTO_WK2x01 = 30, // =>CYRF6936
|
||||
PROTO_Q303 = 31, // =>NRF24L01
|
||||
PROTO_GW008 = 32, // =>NRF24L01
|
||||
PROTO_DM002 = 33, // =>NRF24L01
|
||||
PROTO_CABELL = 34, // =>NRF24L01
|
||||
PROTO_ESKY150 = 35, // =>NRF24L01
|
||||
PROTO_H8_3D = 36, // =>NRF24L01
|
||||
PROTO_CORONA = 37, // =>CC2500
|
||||
PROTO_CFLIE = 38, // =>NRF24L01
|
||||
PROTO_HITEC = 39, // =>CC2500
|
||||
PROTO_WFLY = 40, // =>CYRF6936
|
||||
PROTO_BUGS = 41, // =>A7105
|
||||
PROTO_BUGSMINI = 42, // =>NRF24L01
|
||||
PROTO_TRAXXAS = 43, // =>CYRF6936
|
||||
PROTO_NCC1701 = 44, // =>NRF24L01
|
||||
PROTO_E01X = 45, // =>NRF24L01
|
||||
PROTO_V911S = 46, // =>NRF24L01
|
||||
PROTO_GD00X = 47, // =>NRF24L01
|
||||
PROTO_V761 = 48, // =>NRF24L01
|
||||
PROTO_KF606 = 49, // =>NRF24L01
|
||||
PROTO_REDPINE = 50, // =>CC2500
|
||||
PROTO_POTENSIC = 51, // =>NRF24L01
|
||||
PROTO_XN297DUMP = 63, // =>NRF24L01
|
||||
};
|
||||
|
||||
enum Flysky
|
||||
{
|
||||
Flysky = 0,
|
||||
V9X9 = 1,
|
||||
V6X6 = 2,
|
||||
V912 = 3,
|
||||
CX20 = 4,
|
||||
};
|
||||
enum Hubsan
|
||||
{
|
||||
H107 = 0,
|
||||
H301 = 1,
|
||||
H501 = 2,
|
||||
};
|
||||
enum AFHDS2A
|
||||
{
|
||||
PWM_IBUS = 0,
|
||||
PPM_IBUS = 1,
|
||||
PWM_SBUS = 2,
|
||||
PPM_SBUS = 3,
|
||||
};
|
||||
enum Hisky
|
||||
{
|
||||
Hisky = 0,
|
||||
HK310 = 1,
|
||||
};
|
||||
enum DSM
|
||||
{
|
||||
DSM2_22 = 0,
|
||||
DSM2_11 = 1,
|
||||
DSMX_22 = 2,
|
||||
DSMX_11 = 3,
|
||||
DSM_AUTO = 4,
|
||||
};
|
||||
enum YD717
|
||||
{
|
||||
YD717 = 0,
|
||||
SKYWLKR = 1,
|
||||
SYMAX4 = 2,
|
||||
XINXUN = 3,
|
||||
NIHUI = 4,
|
||||
};
|
||||
enum KN
|
||||
{
|
||||
WLTOYS = 0,
|
||||
FEILUN = 1,
|
||||
};
|
||||
enum SYMAX
|
||||
{
|
||||
SYMAX = 0,
|
||||
SYMAX5C = 1,
|
||||
};
|
||||
enum SLT
|
||||
{
|
||||
SLT_V1 = 0,
|
||||
SLT_V2 = 1,
|
||||
Q100 = 2,
|
||||
Q200 = 3,
|
||||
MR100 = 4,
|
||||
};
|
||||
enum CX10
|
||||
{
|
||||
CX10_GREEN = 0,
|
||||
CX10_BLUE = 1, // also compatible with CX10-A, CX12
|
||||
DM007 = 2,
|
||||
JC3015_1 = 4,
|
||||
JC3015_2 = 5,
|
||||
MK33041 = 6,
|
||||
};
|
||||
enum Q2X2
|
||||
{
|
||||
Q222 = 0,
|
||||
Q242 = 1,
|
||||
Q282 = 2,
|
||||
F_Q222 = 8,
|
||||
F_Q242 = 9,
|
||||
F_Q282 = 10,
|
||||
};
|
||||
enum CG023
|
||||
{
|
||||
CG023 = 0,
|
||||
YD829 = 1,
|
||||
};
|
||||
enum BAYANG
|
||||
{
|
||||
BAYANG = 0,
|
||||
H8S3D = 1,
|
||||
X16_AH = 2,
|
||||
IRDRONE = 3,
|
||||
DHD_D4 = 4,
|
||||
};
|
||||
enum MT99XX
|
||||
{
|
||||
MT99 = 0,
|
||||
H7 = 1,
|
||||
YZ = 2,
|
||||
LS = 3,
|
||||
FY805 = 4,
|
||||
};
|
||||
enum MJXQ
|
||||
{
|
||||
WLH08 = 0,
|
||||
X600 = 1,
|
||||
X800 = 2,
|
||||
H26D = 3,
|
||||
E010 = 4,
|
||||
H26WH = 5,
|
||||
PHOENIX = 6,
|
||||
};
|
||||
enum FRSKYX
|
||||
{
|
||||
CH_16 = 0,
|
||||
CH_8 = 1,
|
||||
EU_16 = 2,
|
||||
EU_8 = 3,
|
||||
};
|
||||
enum HONTAI
|
||||
{
|
||||
HONTAI = 0,
|
||||
JJRCX1 = 1,
|
||||
X5C1 = 2,
|
||||
FQ777_951 =3,
|
||||
};
|
||||
enum V2X2
|
||||
{
|
||||
V2X2 = 0,
|
||||
JXD506 = 1,
|
||||
};
|
||||
enum FY326
|
||||
{
|
||||
FY326 = 0,
|
||||
FY319 = 1,
|
||||
};
|
||||
enum WK2x01
|
||||
{
|
||||
WK2801 = 0,
|
||||
WK2401 = 1,
|
||||
W6_5_1 = 2,
|
||||
W6_6_1 = 3,
|
||||
W6_HEL = 4,
|
||||
W6_HEL_I= 5,
|
||||
};
|
||||
enum Q303
|
||||
{
|
||||
Q303 = 0,
|
||||
CX35 = 1,
|
||||
CX10D = 2,
|
||||
CX10WD = 3,
|
||||
};
|
||||
enum CABELL
|
||||
{
|
||||
CABELL_V3 = 0,
|
||||
CABELL_V3_TELEMETRY = 1,
|
||||
CABELL_SET_FAIL_SAFE= 6,
|
||||
CABELL_UNBIND = 7,
|
||||
};
|
||||
enum H8_3D
|
||||
{
|
||||
H8_3D = 0,
|
||||
H20H = 1,
|
||||
H20MINI = 2,
|
||||
H30MINI = 3,
|
||||
};
|
||||
enum CORONA
|
||||
{
|
||||
COR_V1 = 0,
|
||||
COR_V2 = 1,
|
||||
FD_V3 = 2,
|
||||
};
|
||||
enum HITEC
|
||||
{
|
||||
OPT_FW = 0,
|
||||
OPT_HUB = 1,
|
||||
MINIMA = 2,
|
||||
};
|
||||
enum E01X
|
||||
{
|
||||
E012 = 0,
|
||||
E015 = 1,
|
||||
E016H = 2,
|
||||
};
|
||||
enum GD00X
|
||||
{
|
||||
GD_V1 = 0,
|
||||
GD_V2 = 1,
|
||||
};
|
||||
enum BUGSMINI
|
||||
{
|
||||
BUGSMINI= 0,
|
||||
BUGS3H = 1,
|
||||
};
|
||||
enum REDPINE
|
||||
{
|
||||
RED_FAST= 0,
|
||||
RED_SLOW= 1,
|
||||
};
|
||||
#define NONE 0
|
||||
#define P_HIGH 1
|
||||
#define P_LOW 0
|
||||
#define AUTOBIND 1
|
||||
#define NO_AUTOBIND 0
|
||||
|
||||
struct PPM_Parameters
|
||||
{
|
||||
uint8_t protocol : 6;
|
||||
uint8_t sub_proto : 3;
|
||||
uint8_t rx_num : 4;
|
||||
uint8_t power : 1;
|
||||
uint8_t autobind : 1;
|
||||
uint8_t option;
|
||||
};
|
||||
|
||||
// Telemetry
|
||||
|
||||
enum MultiPacketTypes
|
||||
{
|
||||
MULTI_TELEMETRY_STATUS = 1,
|
||||
MULTI_TELEMETRY_SPORT = 2,
|
||||
MULTI_TELEMETRY_HUB = 3,
|
||||
MULTI_TELEMETRY_DSM = 4,
|
||||
MULTI_TELEMETRY_DSMBIND = 5,
|
||||
MULTI_TELEMETRY_AFHDS2A = 6,
|
||||
MULTI_TELEMETRY_CONFIG = 7,
|
||||
MULTI_TELEMETRY_SYNC = 8,
|
||||
MULTI_TELEMETRY_SPORT_POLLING = 9,
|
||||
MULTI_TELEMETRY_HITEC = 10,
|
||||
};
|
||||
|
||||
// Macros
|
||||
#define NOP() __asm__ __volatile__("nop")
|
||||
|
||||
//***************
|
||||
//*** Flags ***
|
||||
//***************
|
||||
#define RX_FLAG_on protocol_flags |= _BV(0)
|
||||
#define RX_FLAG_off protocol_flags &= ~_BV(0)
|
||||
#define IS_RX_FLAG_on ( ( protocol_flags & _BV(0) ) !=0 )
|
||||
//
|
||||
#define CHANGE_PROTOCOL_FLAG_on protocol_flags |= _BV(1)
|
||||
#define CHANGE_PROTOCOL_FLAG_off protocol_flags &= ~_BV(1)
|
||||
#define IS_CHANGE_PROTOCOL_FLAG_on ( ( protocol_flags & _BV(1) ) !=0 )
|
||||
//
|
||||
#define POWER_FLAG_on protocol_flags |= _BV(2)
|
||||
#define POWER_FLAG_off protocol_flags &= ~_BV(2)
|
||||
#define IS_POWER_FLAG_on ( ( protocol_flags & _BV(2) ) !=0 )
|
||||
//
|
||||
#define RANGE_FLAG_on protocol_flags |= _BV(3)
|
||||
#define RANGE_FLAG_off protocol_flags &= ~_BV(3)
|
||||
#define IS_RANGE_FLAG_on ( ( protocol_flags & _BV(3) ) !=0 )
|
||||
//
|
||||
#define AUTOBIND_FLAG_on protocol_flags |= _BV(4)
|
||||
#define AUTOBIND_FLAG_off protocol_flags &= ~_BV(4)
|
||||
#define IS_AUTOBIND_FLAG_on ( ( protocol_flags & _BV(4) ) !=0 )
|
||||
//
|
||||
#define BIND_BUTTON_FLAG_on protocol_flags |= _BV(5)
|
||||
#define BIND_BUTTON_FLAG_off protocol_flags &= ~_BV(5)
|
||||
#define IS_BIND_BUTTON_FLAG_on ( ( protocol_flags & _BV(5) ) !=0 )
|
||||
//PPM RX OK
|
||||
#define PPM_FLAG_off protocol_flags &= ~_BV(6)
|
||||
#define PPM_FLAG_on protocol_flags |= _BV(6)
|
||||
#define IS_PPM_FLAG_on ( ( protocol_flags & _BV(6) ) !=0 )
|
||||
//Bind flag
|
||||
#define BIND_IN_PROGRESS protocol_flags &= ~_BV(7)
|
||||
#define BIND_DONE protocol_flags |= _BV(7)
|
||||
#define IS_BIND_DONE ( ( protocol_flags & _BV(7) ) !=0 )
|
||||
#define IS_BIND_IN_PROGRESS ( ( protocol_flags & _BV(7) ) ==0 )
|
||||
//
|
||||
#define FAILSAFE_VALUES_off protocol_flags2 &= ~_BV(0)
|
||||
#define FAILSAFE_VALUES_on protocol_flags2 |= _BV(0)
|
||||
#define IS_FAILSAFE_VALUES_on ( ( protocol_flags2 & _BV(0) ) !=0 )
|
||||
//
|
||||
#define RX_DONOTUPDATE_off protocol_flags2 &= ~_BV(1)
|
||||
#define RX_DONOTUPDATE_on protocol_flags2 |= _BV(1)
|
||||
#define IS_RX_DONOTUPDATE_on ( ( protocol_flags2 & _BV(1) ) !=0 )
|
||||
//
|
||||
#define RX_MISSED_BUFF_off protocol_flags2 &= ~_BV(2)
|
||||
#define RX_MISSED_BUFF_on protocol_flags2 |= _BV(2)
|
||||
#define IS_RX_MISSED_BUFF_on ( ( protocol_flags2 & _BV(2) ) !=0 )
|
||||
//TX Pause
|
||||
#define TX_MAIN_PAUSE_off protocol_flags2 &= ~_BV(3)
|
||||
#define TX_MAIN_PAUSE_on protocol_flags2 |= _BV(3)
|
||||
#define IS_TX_MAIN_PAUSE_on ( ( protocol_flags2 & _BV(3) ) !=0 )
|
||||
#define TX_RX_PAUSE_off protocol_flags2 &= ~_BV(4)
|
||||
#define TX_RX_PAUSE_on protocol_flags2 |= _BV(4)
|
||||
#define IS_TX_RX_PAUSE_on ( ( protocol_flags2 & _BV(4) ) !=0 )
|
||||
#define IS_TX_PAUSE_on ( ( protocol_flags2 & (_BV(4)|_BV(3)) ) !=0 )
|
||||
//Signal OK
|
||||
#define INPUT_SIGNAL_off protocol_flags2 &= ~_BV(5)
|
||||
#define INPUT_SIGNAL_on protocol_flags2 |= _BV(5)
|
||||
#define IS_INPUT_SIGNAL_on ( ( protocol_flags2 & _BV(5) ) !=0 )
|
||||
#define IS_INPUT_SIGNAL_off ( ( protocol_flags2 & _BV(5) ) ==0 )
|
||||
//Bind from channel
|
||||
#define BIND_CH_PREV_off protocol_flags2 &= ~_BV(6)
|
||||
#define BIND_CH_PREV_on protocol_flags2 |= _BV(6)
|
||||
#define IS_BIND_CH_PREV_on ( ( protocol_flags2 & _BV(6) ) !=0 )
|
||||
#define IS_BIND_CH_PREV_off ( ( protocol_flags2 & _BV(6) ) ==0 )
|
||||
//Wait for bind
|
||||
#define WAIT_BIND_off protocol_flags2 &= ~_BV(7)
|
||||
#define WAIT_BIND_on protocol_flags2 |= _BV(7)
|
||||
#define IS_WAIT_BIND_on ( ( protocol_flags2 & _BV(7) ) !=0 )
|
||||
#define IS_WAIT_BIND_off ( ( protocol_flags2 & _BV(7) ) ==0 )
|
||||
|
||||
// Failsafe
|
||||
#define FAILSAFE_CHANNEL_HOLD 2047
|
||||
#define FAILSAFE_CHANNEL_NOPULSES 0
|
||||
|
||||
//********************
|
||||
//** Debug messages **
|
||||
//********************
|
||||
#if defined(STM32_BOARD) && defined (DEBUG_SERIAL)
|
||||
uint16_t debug_time=0;
|
||||
#define debug(msg, ...) {char debug_buf[64]; sprintf(debug_buf, msg, ##__VA_ARGS__); Serial.write(debug_buf);}
|
||||
#define debugln(msg, ...) {char debug_buf[64]; sprintf(debug_buf, msg "\r\n", ##__VA_ARGS__); Serial.write(debug_buf);}
|
||||
#define debug_time(msg) { uint16_t debug_time_TCNT1=TCNT1; debug_time=debug_time_TCNT1-debug_time; debug(msg "%u", debug_time>>1); debug_time=debug_time_TCNT1; }
|
||||
#else
|
||||
#define debug(...) { }
|
||||
#define debugln(...) { }
|
||||
#define debug_time(...) { }
|
||||
#undef DEBUG_SERIAL
|
||||
#endif
|
||||
|
||||
//********************
|
||||
//*** Blink timing ***
|
||||
//********************
|
||||
#define BLINK_BIND_TIME 100
|
||||
#define BLINK_SERIAL_TIME 500
|
||||
#define BLINK_PPM_TIME 1000
|
||||
#define BLINK_BAD_PROTO_TIME_HIGH 50
|
||||
#define BLINK_BAD_PROTO_TIME_LOW 1000
|
||||
#define BLINK_WAIT_BIND_TIME_HIGH 1000
|
||||
#define BLINK_WAIT_BIND_TIME_LOW 100
|
||||
#define BLINK_BANK_TIME_HIGH 50
|
||||
#define BLINK_BANK_TIME_LOW 500
|
||||
#define BLINK_BANK_REPEAT 1500
|
||||
|
||||
//*******************
|
||||
//*** AUX flags ***
|
||||
//*******************
|
||||
#define GET_FLAG(ch, mask) ( ch ? mask : 0)
|
||||
#define CH5_SW (Channel_AUX & _BV(0))
|
||||
#define CH6_SW (Channel_AUX & _BV(1))
|
||||
#define CH7_SW (Channel_AUX & _BV(2))
|
||||
#define CH8_SW (Channel_AUX & _BV(3))
|
||||
#define CH9_SW (Channel_AUX & _BV(4))
|
||||
#define CH10_SW (Channel_AUX & _BV(5))
|
||||
#define CH11_SW (Channel_AUX & _BV(6))
|
||||
#define CH12_SW (Channel_AUX & _BV(7))
|
||||
#define CH13_SW (Channel_data[CH13]>CHANNEL_SWITCH)
|
||||
#define CH14_SW (Channel_data[CH14]>CHANNEL_SWITCH)
|
||||
#define CH15_SW (Channel_data[CH15]>CHANNEL_SWITCH)
|
||||
#define CH16_SW (Channel_data[CH16]>CHANNEL_SWITCH)
|
||||
|
||||
//************************
|
||||
//*** Power settings ***
|
||||
//************************
|
||||
enum {
|
||||
TXPOWER_100uW,
|
||||
TXPOWER_300uW,
|
||||
TXPOWER_1mW,
|
||||
TXPOWER_3mW,
|
||||
TXPOWER_10mW,
|
||||
TXPOWER_30mW,
|
||||
TXPOWER_100mW,
|
||||
TXPOWER_150mW
|
||||
};
|
||||
|
||||
// A7105 power
|
||||
// Power amp is ~+16dBm so:
|
||||
enum A7105_POWER
|
||||
{
|
||||
A7105_POWER_0 = 0x00<<3 | 0x00, // TXPOWER_100uW = -23dBm == PAC=0 TBG=0
|
||||
A7105_POWER_1 = 0x00<<3 | 0x01, // TXPOWER_300uW = -20dBm == PAC=0 TBG=1
|
||||
A7105_POWER_2 = 0x00<<3 | 0x02, // TXPOWER_1mW = -16dBm == PAC=0 TBG=2
|
||||
A7105_POWER_3 = 0x00<<3 | 0x04, // TXPOWER_3mW = -11dBm == PAC=0 TBG=4
|
||||
A7105_POWER_4 = 0x01<<3 | 0x05, // TXPOWER_10mW = -6dBm == PAC=1 TBG=5
|
||||
A7105_POWER_5 = 0x02<<3 | 0x07, // TXPOWER_30mW = 0dBm == PAC=2 TBG=7
|
||||
A7105_POWER_6 = 0x03<<3 | 0x07, // TXPOWER_100mW = 1dBm == PAC=3 TBG=7
|
||||
A7105_POWER_7 = 0x03<<3 | 0x07 // TXPOWER_150mW = 1dBm == PAC=3 TBG=7
|
||||
};
|
||||
#define A7105_HIGH_POWER A7105_POWER_7
|
||||
#define A7105_LOW_POWER A7105_POWER_3
|
||||
#define A7105_RANGE_POWER A7105_POWER_0
|
||||
#define A7105_BIND_POWER A7105_POWER_0
|
||||
|
||||
// NRF Power
|
||||
// Power setting is 0..3 for nRF24L01
|
||||
// Claimed power amp for nRF24L01 from eBay is 20dBm.
|
||||
enum NRF_POWER
|
||||
{ // Raw w 20dBm PA
|
||||
NRF_POWER_0 = 0x00, // 0 : -18dBm (16uW) 2dBm (1.6mW)
|
||||
NRF_POWER_1 = 0x01, // 1 : -12dBm (60uW) 8dBm (6mW)
|
||||
NRF_POWER_2 = 0x02, // 2 : -6dBm (250uW) 14dBm (25mW)
|
||||
NRF_POWER_3 = 0x03 // 3 : 0dBm (1mW) 20dBm (100mW)
|
||||
};
|
||||
#define NRF_HIGH_POWER NRF_POWER_3
|
||||
#define NRF_LOW_POWER NRF_POWER_1
|
||||
#define NRF_RANGE_POWER NRF_POWER_0
|
||||
#define NRF_BIND_POWER NRF_POWER_0
|
||||
|
||||
// CC2500 power output from the chip itself
|
||||
// The numbers do not take into account any outside amplifier
|
||||
enum CC2500_POWER
|
||||
{
|
||||
CC2500_POWER_0 = 0x00, // -55dbm or less
|
||||
CC2500_POWER_1 = 0x50, // -30dbm
|
||||
CC2500_POWER_2 = 0x44, // -28dbm
|
||||
CC2500_POWER_3 = 0xC0, // -26dbm
|
||||
CC2500_POWER_4 = 0x84, // -24dbm
|
||||
CC2500_POWER_5 = 0x81, // -22dbm
|
||||
CC2500_POWER_6 = 0x46, // -20dbm
|
||||
CC2500_POWER_7 = 0x93, // -18dbm
|
||||
CC2500_POWER_8 = 0x55, // -16dbm
|
||||
CC2500_POWER_9 = 0x8D, // -14dbm
|
||||
CC2500_POWER_10 = 0xC6, // -12dbm
|
||||
CC2500_POWER_11 = 0x97, // -10dbm
|
||||
CC2500_POWER_12 = 0x6E, // -8dbm
|
||||
CC2500_POWER_13 = 0x7F, // -6dbm
|
||||
CC2500_POWER_14 = 0xA9, // -4dbm
|
||||
CC2500_POWER_15 = 0xBB, // -2dbm
|
||||
CC2500_POWER_16 = 0xFE, // 0dbm
|
||||
CC2500_POWER_17 = 0xFF // +1dbm
|
||||
};
|
||||
#define CC2500_HIGH_POWER CC2500_POWER_17
|
||||
#define CC2500_LOW_POWER CC2500_POWER_13
|
||||
#define CC2500_RANGE_POWER CC2500_POWER_1
|
||||
#define CC2500_BIND_POWER CC2500_POWER_1
|
||||
|
||||
// CYRF power
|
||||
enum CYRF_POWER
|
||||
{
|
||||
CYRF_POWER_0 = 0x00, // -35dbm
|
||||
CYRF_POWER_1 = 0x01, // -30dbm
|
||||
CYRF_POWER_2 = 0x02, // -24dbm
|
||||
CYRF_POWER_3 = 0x03, // -18dbm
|
||||
CYRF_POWER_4 = 0x04, // -13dbm
|
||||
CYRF_POWER_5 = 0x05, // -5dbm
|
||||
CYRF_POWER_6 = 0x06, // 0dbm
|
||||
CYRF_POWER_7 = 0x07 // +4dbm
|
||||
};
|
||||
#define CYRF_HIGH_POWER CYRF_POWER_7
|
||||
#define CYRF_LOW_POWER CYRF_POWER_3
|
||||
#define CYRF_RANGE_POWER CYRF_POWER_1 // 1/30 of the full power distance
|
||||
#define CYRF_BIND_POWER CYRF_POWER_0
|
||||
|
||||
enum TXRX_State {
|
||||
TXRX_OFF,
|
||||
TX_EN,
|
||||
RX_EN
|
||||
};
|
||||
|
||||
// Packet ack status values
|
||||
enum {
|
||||
PKT_PENDING = 0,
|
||||
PKT_ACKED,
|
||||
PKT_TIMEOUT
|
||||
};
|
||||
|
||||
// baudrate defines for serial
|
||||
#define SPEED_100K 0
|
||||
#define SPEED_9600 1
|
||||
#define SPEED_57600 2
|
||||
#define SPEED_125K 3
|
||||
|
||||
/** EEPROM Layout */
|
||||
#define EEPROM_ID_OFFSET 10 // Module ID (4 bytes)
|
||||
#define EEPROM_BANK_OFFSET 15 // Current bank number (1 byte)
|
||||
#define EEPROM_ID_VALID_OFFSET 20 // 1 byte flag that ID is valid
|
||||
#define MODELMODE_EEPROM_OFFSET 30 // Autobind mode, 1 byte per model, end is 30+16=46
|
||||
#define AFHDS2A_EEPROM_OFFSET 50 // RX ID, 4 bytes per model id, end is 50+64=114
|
||||
#define BUGS_EEPROM_OFFSET 114 // RX ID, 2 bytes per model id, end is 114+32=146
|
||||
#define BUGSMINI_EEPROM_OFFSET 146 // RX ID, 2 bytes per model id, end is 146+32=178
|
||||
//#define CONFIG_EEPROM_OFFSET 210 // Current configuration of the multimodule
|
||||
|
||||
//****************************************
|
||||
//*** MULTI protocol serial definition ***
|
||||
//****************************************
|
||||
/*
|
||||
**************************
|
||||
16 channels serial protocol
|
||||
**************************
|
||||
Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
||||
Total of 26 bytes
|
||||
Stream[0] = 0x55 sub_protocol values are 0..31 Stream contains channels
|
||||
Stream[0] = 0x54 sub_protocol values are 32..63 Stream contains channels
|
||||
Stream[0] = 0x57 sub_protocol values are 0..31 Stream contains failsafe
|
||||
Stream[0] = 0x56 sub_protocol values are 32..63 Stream contains failsafe
|
||||
header
|
||||
Stream[1] = sub_protocol|BindBit|RangeCheckBit|AutoBindBit;
|
||||
sub_protocol is 0..31 (bits 0..4), value should be added with 32 if Stream[0] = 0x54
|
||||
=> Reserved 0
|
||||
Flysky 1
|
||||
Hubsan 2
|
||||
FrskyD 3
|
||||
Hisky 4
|
||||
V2x2 5
|
||||
DSM 6
|
||||
Devo 7
|
||||
YD717 8
|
||||
KN 9
|
||||
SymaX 10
|
||||
SLT 11
|
||||
CX10 12
|
||||
CG023 13
|
||||
Bayang 14
|
||||
FrskyX 15
|
||||
ESky 16
|
||||
MT99XX 17
|
||||
MJXQ 18
|
||||
SHENQI 19
|
||||
FY326 20
|
||||
SFHSS 21
|
||||
J6PRO 22
|
||||
FQ777 23
|
||||
ASSAN 24
|
||||
FrskyV 25
|
||||
HONTAI 26
|
||||
OpenLRS 27
|
||||
AFHDS2A 28
|
||||
Q2X2 29
|
||||
WK2x01 30
|
||||
Q303 31
|
||||
GW008 32
|
||||
DM002 33
|
||||
CABELL 34
|
||||
ESKY150 35
|
||||
H8_3D 36
|
||||
CORONA 37
|
||||
CFlie 38
|
||||
Hitec 39
|
||||
WFLY 40
|
||||
BUGS 41
|
||||
BUGSMINI 42
|
||||
TRAXXAS 43
|
||||
NCC1701 44
|
||||
E01X 45
|
||||
V911S 46
|
||||
GD00X 47
|
||||
V761 48
|
||||
KF606 49
|
||||
REDPINE 50
|
||||
POTENSIC 51
|
||||
BindBit=> 0x80 1=Bind/0=No
|
||||
AutoBindBit=> 0x40 1=Yes /0=No
|
||||
RangeCheck=> 0x20 1=Yes /0=No
|
||||
Stream[2] = RxNum | Power | Type;
|
||||
RxNum value is 0..15 (bits 0..3)
|
||||
Type is 0..7 <<4 (bit 4..6)
|
||||
sub_protocol==Flysky
|
||||
Flysky 0
|
||||
V9x9 1
|
||||
V6x6 2
|
||||
V912 3
|
||||
CX20 4
|
||||
sub_protocol==Hubsan
|
||||
H107 0
|
||||
H301 1
|
||||
H501 2
|
||||
sub_protocol==Hisky
|
||||
Hisky 0
|
||||
HK310 1
|
||||
sub_protocol==DSM
|
||||
DSM2_22 0
|
||||
DSM2_11 1
|
||||
DSMX_22 2
|
||||
DSMX_11 3
|
||||
DSM_AUTO 4
|
||||
sub_protocol==YD717
|
||||
YD717 0
|
||||
SKYWLKR 1
|
||||
SYMAX4 2
|
||||
XINXUN 3
|
||||
NIHUI 4
|
||||
sub_protocol==KN
|
||||
WLTOYS 0
|
||||
FEILUN 1
|
||||
sub_protocol==SYMAX
|
||||
SYMAX 0
|
||||
SYMAX5C 1
|
||||
sub_protocol==CX10
|
||||
CX10_GREEN 0
|
||||
CX10_BLUE 1 // also compatible with CX10-A, CX12
|
||||
DM007 2
|
||||
--- 3
|
||||
JC3015_1 4
|
||||
JC3015_2 5
|
||||
MK33041 6
|
||||
sub_protocol==Q2X2
|
||||
Q222 0
|
||||
Q242 1
|
||||
Q282 2
|
||||
sub_protocol==CG023
|
||||
CG023 0
|
||||
YD829 1
|
||||
sub_protocol==BAYANG
|
||||
BAYANG 0
|
||||
H8S3D 1
|
||||
X16_AH 2
|
||||
IRDRONE 3
|
||||
DHD_D4 4
|
||||
sub_protocol==MT99XX
|
||||
MT99 0
|
||||
H7 1
|
||||
YZ 2
|
||||
LS 3
|
||||
FY805 4
|
||||
sub_protocol==MJXQ
|
||||
WLH08 0
|
||||
X600 1
|
||||
X800 2
|
||||
H26D 3
|
||||
E010 4
|
||||
H26WH 5
|
||||
PHOENIX 6
|
||||
sub_protocol==FRSKYX
|
||||
CH_16 0
|
||||
CH_8 1
|
||||
EU_16 2
|
||||
EU_8 3
|
||||
sub_protocol==HONTAI
|
||||
HONTAI 0
|
||||
JJRCX1 1
|
||||
X5C1 2
|
||||
FQ777_951 3
|
||||
sub_protocol==AFHDS2A
|
||||
PWM_IBUS 0
|
||||
PPM_IBUS 1
|
||||
PWM_SBUS 2
|
||||
PPM_SBUS 3
|
||||
sub_protocol==V2X2
|
||||
V2X2 0
|
||||
JXD506 1
|
||||
sub_protocol==FY326
|
||||
FY326 0
|
||||
FY319 1
|
||||
sub_protocol==WK2x01
|
||||
WK2801 0
|
||||
WK2401 1
|
||||
W6_5_1 2
|
||||
W6_6_1 3
|
||||
W6_HEL 4
|
||||
W6_HEL_I 5
|
||||
sub_protocol==Q303
|
||||
Q303 0
|
||||
CX35 1
|
||||
CX10D 2
|
||||
CX10WD 3
|
||||
sub_protocol==CABELL
|
||||
CABELL_V3 0
|
||||
CABELL_V3_TELEMETRY 1
|
||||
CABELL_SET_FAIL_SAFE 6
|
||||
CABELL_UNBIND 7
|
||||
sub_protocol==H8_3D
|
||||
H8_3D 0
|
||||
H20H 1
|
||||
H20MINI 2
|
||||
H30MINI 3
|
||||
sub_protocol==CORONA
|
||||
COR_V1 0
|
||||
COR_V2 1
|
||||
FD_V3 2
|
||||
sub_protocol==HITEC
|
||||
OPT_FW 0
|
||||
OPT_HUB 1
|
||||
MINIMA 2
|
||||
sub_protocol==SLT
|
||||
SLT_V1 0
|
||||
SLT_V2 1
|
||||
Q100 2
|
||||
Q200 3
|
||||
MR100 4
|
||||
sub_protocol==E01X
|
||||
E012 0
|
||||
E015 1
|
||||
E016H 2
|
||||
sub_protocol==GD00X
|
||||
GD_V1 0
|
||||
GD_V2 1
|
||||
sub_protocol==REDPINE
|
||||
RED_FAST 0
|
||||
RED_SLOW 1
|
||||
|
||||
Power value => 0x80 0=High/1=Low
|
||||
Stream[3] = option_protocol;
|
||||
option_protocol value is -128..127
|
||||
Stream[4] to [25] = Channels or failsafe depending on Steam[0]
|
||||
16 Channels on 11 bits (0..2047)
|
||||
0 -125%
|
||||
204 -100%
|
||||
1024 0%
|
||||
1843 +100%
|
||||
2047 +125%
|
||||
Values are concatenated to fit in 22 bytes like in SBUS protocol.
|
||||
Failsafe values have exactly the same range/values than normal channels except the extremes where
|
||||
0=hold, 2047=no pulse. If failsafe is not set or RX then failsafe packets should not be sent.
|
||||
*/
|
||||
/*
|
||||
Multimodule Status
|
||||
Based on #define MULTI_STATUS
|
||||
|
||||
Serial: 100000 Baud 8e2 (same as input)
|
||||
|
||||
Format: header (2 bytes) + data (variable)
|
||||
[0] = 'M' (0x4d)
|
||||
[1] Length (excluding the 2 header bytes)
|
||||
[2-xx] data
|
||||
|
||||
Type = 0x01 Multimodule Status:
|
||||
[2] Flags
|
||||
0x01 = Input signal detected
|
||||
0x02 = Serial mode enabled
|
||||
0x04 = Protocol is valid
|
||||
0x08 = Module is in binding mode
|
||||
0x10 = Module waits a bind event to load the protocol
|
||||
0x20 = Failsafe supported by currently running protocol
|
||||
[3] major
|
||||
[4] minor
|
||||
[5] revision
|
||||
[6] patchlevel,
|
||||
version of multi code, should be displayed as major.minor.revision.patchlevel
|
||||
*/
|
||||
/*
|
||||
Multiprotocol telemetry/command definition for OpenTX
|
||||
Based on #define MULTI_TELEMETRY enables OpenTX to get the multimodule status and select the correct telemetry type automatically.
|
||||
|
||||
Serial: 100000 Baud 8e2 (same as input)
|
||||
|
||||
TLV Protocol (type, length, value), allows a TX to ignore unknown messages
|
||||
|
||||
Format: header (4 byte) + data (variable)
|
||||
[0] = 'M' (0x4d)
|
||||
[1] = 'P' (0x50)
|
||||
|
||||
The first byte is deliberatly chosen to be different from other telemetry protocols
|
||||
(e.g. 0xAA for DSM/Multi, 0xAA for FlySky and 0x7e for Frsky) to allow a TX to detect
|
||||
the telemetry format of older versions
|
||||
|
||||
[2] Type (see below)
|
||||
[3] Length (excluding the 4 header bytes)
|
||||
|
||||
[4-xx] data
|
||||
|
||||
Commands from TX to multi cannot be longer than 22 bytes (RXLen -4byte header)
|
||||
|
||||
Type = 0x01 Multimodule Status:
|
||||
[4] Flags
|
||||
0x01 = Input signal detected
|
||||
0x02 = Serial mode enabled
|
||||
0x04 = protocol is valid
|
||||
0x08 = module is in binding mode
|
||||
0x10 = module waits a bind event to load the protocol
|
||||
[5] major
|
||||
[6] minor
|
||||
[7] revision
|
||||
[8] patchlevel,
|
||||
version of multi code, should be displayed as major.minor.revision.patchlevel
|
||||
|
||||
more information can be added by specifing a longer length of the type, the TX will just ignore these bytes
|
||||
|
||||
|
||||
Type 0x02 Frksy S.port telemetry
|
||||
Type 0x03 Frsky Hub telemetry
|
||||
|
||||
*No* usual frsky byte stuffing and without start/stop byte (0x7e)
|
||||
|
||||
|
||||
Type 0x04 Spektrum telemetry data
|
||||
data[0] TX RSSI
|
||||
data[1-15] telemetry data
|
||||
|
||||
Type 0x05 DSM bind data
|
||||
data[0-16] DSM bind data
|
||||
|
||||
technically DSM bind data is only 10 bytes but multi sends 16
|
||||
like with telemtery, check length field)
|
||||
|
||||
Type 0x06 Flysky AFHDS2 telemetry data
|
||||
length: 29
|
||||
data[0] = RSSI value
|
||||
data[1-28] telemetry data
|
||||
|
||||
Type 0x0A Hitec telemetry data
|
||||
length: 8
|
||||
data[0] = TX RSSI value
|
||||
data[1] = TX LQI value
|
||||
data[2] = frame number
|
||||
data[3-7] telemetry data
|
||||
Full description at the bottom of Hitec_cc2500.ino
|
||||
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
277
Multiprotocol/NCC1701_nrf24l01.ino
Normal file
277
Multiprotocol/NCC1701_nrf24l01.ino
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
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(NCC1701_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define NCC_WRITE_WAIT 2000
|
||||
#define NCC_PACKET_INTERVAL 10333
|
||||
#define NCC_TX_PACKET_LEN 16
|
||||
#define NCC_RX_PACKET_LEN 13
|
||||
|
||||
enum {
|
||||
NCC_BIND_TX1=0,
|
||||
NCC_BIND_RX1,
|
||||
NCC_BIND_TX2,
|
||||
NCC_BIND_RX2,
|
||||
NCC_TX3,
|
||||
NCC_RX3,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) NCC_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xE7\xE7\xC7\xD7\x67",5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xE7\xE7\xC7\xD7\x67",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, NCC_RX_PACKET_LEN); // Enable rx pipe 0
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // NRF24L01_BR_1M, NRF24L01_BR_2M, NRF24L01_BR_250K
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to TX mode and disable CRC
|
||||
| (1 << NRF24L01_00_CRCO)
|
||||
| (1 << NRF24L01_00_PWR_UP)
|
||||
| (0 << NRF24L01_00_PRIM_RX));
|
||||
}
|
||||
|
||||
const uint8_t NCC_xor[]={0x80, 0x44, 0x64, 0x75, 0x6C, 0x71, 0x2A, 0x36, 0x7C, 0xF1, 0x6E, 0x52, 0x09, 0x9D};
|
||||
static void __attribute__((unused)) NCC_Crypt_Packet()
|
||||
{
|
||||
uint16_t crc=0;
|
||||
for(uint8_t i=0; i< NCC_TX_PACKET_LEN-2; i++)
|
||||
{
|
||||
packet[i]^=NCC_xor[i];
|
||||
crc=crc16_update(crc, packet[i], 8);
|
||||
}
|
||||
crc^=0x60DE;
|
||||
packet[NCC_TX_PACKET_LEN-2]=crc>>8;
|
||||
packet[NCC_TX_PACKET_LEN-1]=crc;
|
||||
}
|
||||
static boolean __attribute__((unused)) NCC_Decrypt_Packet()
|
||||
{
|
||||
uint16_t crc=0;
|
||||
debug("RX: ");
|
||||
for(uint8_t i=0; i< NCC_RX_PACKET_LEN-2; i++)
|
||||
{
|
||||
crc=crc16_update(crc, packet[i], 8);
|
||||
packet[i]^=NCC_xor[i];
|
||||
debug("%02X ",packet[i]);
|
||||
}
|
||||
crc^=0xA950;
|
||||
if( (crc>>8)==packet[NCC_RX_PACKET_LEN-2] && (crc&0xFF)==packet[NCC_RX_PACKET_LEN-1] )
|
||||
{// CRC match
|
||||
debugln("OK");
|
||||
return true;
|
||||
}
|
||||
debugln("NOK");
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) NCC_Write_Packet()
|
||||
{
|
||||
packet[0]=0xAA;
|
||||
packet[1]=rx_tx_addr[0];
|
||||
packet[2]=rx_tx_addr[1];
|
||||
packet[3]=rx_id[0];
|
||||
packet[4]=rx_id[1];
|
||||
packet[5]=convert_channel_8b(THROTTLE)>>2; // 00-3D
|
||||
packet[6]=convert_channel_8b(ELEVATOR); // original: 61-80-9F but works with 00-80-FF
|
||||
packet[7]=convert_channel_8b(AILERON ); // original: 61-80-9F but works with 00-80-FF
|
||||
packet[8]=convert_channel_8b(RUDDER ); // original: 61-80-9F but works with 00-80-FF
|
||||
packet[9]=rx_id[2];
|
||||
packet[10]=rx_id[3];
|
||||
packet[11]=rx_id[4];
|
||||
packet[12]=GET_FLAG(CH5_SW, 0x02); // Warp:0x00 -> 0x02
|
||||
packet[13]=packet[5]+packet[6]+packet[7]+packet[8]+packet[12];
|
||||
if(phase==NCC_BIND_TX1)
|
||||
{
|
||||
packet[0]=0xBB;
|
||||
packet[5]=0x01;
|
||||
packet[6]=rx_tx_addr[2];
|
||||
memset((void *)(packet+7),0x55,7);
|
||||
hopping_frequency_no^=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no>2) hopping_frequency_no=0;
|
||||
}
|
||||
// change frequency
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
// switch to TX mode and disable CRC
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC)
|
||||
| (1 << NRF24L01_00_CRCO)
|
||||
| (1 << NRF24L01_00_PWR_UP)
|
||||
| (0 << NRF24L01_00_PRIM_RX));
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
// send packet
|
||||
NCC_Crypt_Packet();
|
||||
NRF24L01_WritePayload(packet,NCC_TX_PACKET_LEN);
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
uint16_t NCC_callback()
|
||||
{
|
||||
switch(phase)
|
||||
{
|
||||
case NCC_BIND_TX1:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready
|
||||
NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN);
|
||||
if(NCC_Decrypt_Packet() && packet[1]==rx_tx_addr[0] && packet[2]==rx_tx_addr[1])
|
||||
|
||||
{
|
||||
rx_id[0]=packet[3];
|
||||
rx_id[1]=packet[4];
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
phase=NCC_BIND_TX2;
|
||||
return NCC_PACKET_INTERVAL;
|
||||
}
|
||||
}
|
||||
NCC_Write_Packet();
|
||||
phase = NCC_BIND_RX1;
|
||||
return NCC_WRITE_WAIT;
|
||||
case NCC_BIND_RX1:
|
||||
// switch to RX mode and disable CRC
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC)
|
||||
| (1 << NRF24L01_00_CRCO)
|
||||
| (1 << NRF24L01_00_PWR_UP)
|
||||
| (1 << NRF24L01_00_PRIM_RX));
|
||||
NRF24L01_FlushRx();
|
||||
phase = NCC_BIND_TX1;
|
||||
return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT;
|
||||
case NCC_BIND_TX2:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready
|
||||
NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN);
|
||||
if(NCC_Decrypt_Packet() && packet[1]==rx_tx_addr[0] && packet[2]==rx_tx_addr[1] && packet[3]==rx_id[0] && packet[4]==rx_id[1])
|
||||
{
|
||||
rx_id[2]=packet[8];
|
||||
rx_id[3]=packet[9];
|
||||
rx_id[4]=packet[10];
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
BIND_DONE;
|
||||
phase=NCC_TX3;
|
||||
return NCC_PACKET_INTERVAL;
|
||||
}
|
||||
}
|
||||
NCC_Write_Packet();
|
||||
phase = NCC_BIND_RX2;
|
||||
return NCC_WRITE_WAIT;
|
||||
case NCC_BIND_RX2:
|
||||
// switch to RX mode and disable CRC
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC)
|
||||
| (1 << NRF24L01_00_CRCO)
|
||||
| (1 << NRF24L01_00_PWR_UP)
|
||||
| (1 << NRF24L01_00_PRIM_RX));
|
||||
NRF24L01_FlushRx();
|
||||
phase = NCC_BIND_TX2;
|
||||
return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT;
|
||||
case NCC_TX3:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready
|
||||
NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN);
|
||||
if(NCC_Decrypt_Packet() && packet[1]==rx_tx_addr[0] && packet[2]==rx_tx_addr[1] && packet[3]==rx_id[0] && packet[4]==rx_id[1])
|
||||
{
|
||||
//Telemetry
|
||||
//packet[5] and packet[7] roll angle
|
||||
//packet[6] crash detect: 0x00 no crash, 0x02 crash
|
||||
#ifdef NCC1701_HUB_TELEMETRY
|
||||
v_lipo1 = packet[6]?0xFF:0x00; // Crash indication
|
||||
v_lipo2 = 0x00;
|
||||
RX_RSSI = 0x7F; // Dummy RSSI
|
||||
TX_RSSI = 0x7F; // Dummy RSSI
|
||||
telemetry_link=1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
NCC_Write_Packet();
|
||||
phase = NCC_RX3;
|
||||
return NCC_WRITE_WAIT;
|
||||
case NCC_RX3:
|
||||
// switch to RX mode and disable CRC
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC)
|
||||
| (1 << NRF24L01_00_CRCO)
|
||||
| (1 << NRF24L01_00_PWR_UP)
|
||||
| (1 << NRF24L01_00_PRIM_RX));
|
||||
NRF24L01_FlushRx();
|
||||
phase = NCC_TX3;
|
||||
return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM NCC_TX_DATA[][6]= {
|
||||
{ 0x6D, 0x97, 0x04, 0x48, 0x43, 0x26 },
|
||||
{ 0x35, 0x4B, 0x80, 0x44, 0x4C, 0x0B },
|
||||
{ 0x50, 0xE2, 0x32, 0x2D, 0x4B, 0x0A },
|
||||
{ 0xBF, 0x34, 0xF3, 0x45, 0x4D, 0x0D },
|
||||
{ 0xDD, 0x7D, 0x5A, 0x46, 0x28, 0x23 },
|
||||
{ 0xED, 0x19, 0x06, 0x2C, 0x4A, 0x09 },
|
||||
{ 0xE9, 0xA8, 0x91, 0x2B, 0x49, 0x07 },
|
||||
{ 0x66, 0x17, 0x7D, 0x48, 0x43, 0x26 },
|
||||
{ 0xC2, 0x93, 0x55, 0x44, 0x4C, 0x0B },
|
||||
};
|
||||
|
||||
uint16_t initNCC(void)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
|
||||
// Load TX data
|
||||
uint8_t rand=rx_tx_addr[3]%9;
|
||||
for(uint8_t i=0; i<3; i++)
|
||||
{
|
||||
rx_tx_addr[i]=pgm_read_byte_near(&NCC_TX_DATA[rand][i]);
|
||||
hopping_frequency[i]=pgm_read_byte_near(&NCC_TX_DATA[rand][i+3]);
|
||||
}
|
||||
|
||||
// RX data is acquired during bind
|
||||
rx_id[0]=0x00;
|
||||
rx_id[1]=0x00;
|
||||
rx_id[2]=0x20;
|
||||
rx_id[3]=0x20;
|
||||
rx_id[4]=0x20;
|
||||
|
||||
hopping_frequency[4]=0x08; // bind channel 1
|
||||
hopping_frequency[5]=0x2A; // bind channel 2
|
||||
hopping_frequency_no=4; // start with bind
|
||||
NCC_init();
|
||||
phase=NCC_BIND_TX1;
|
||||
#ifdef NCC1701_HUB_TELEMETRY
|
||||
init_frskyd_link_telemetry();
|
||||
#endif
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -14,50 +14,9 @@
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------
|
||||
// AVR nrf chip bitbang SPI functions
|
||||
//---------------------------
|
||||
#ifdef NRF24L01_INSTALLED
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
void nrf_spi_write(uint8_t command)
|
||||
{
|
||||
uint8_t n=8;
|
||||
|
||||
SCK_off;//SCK start low
|
||||
SDI_off;
|
||||
while(n--) {
|
||||
if(command&0x80)
|
||||
SDI_on;
|
||||
else
|
||||
SDI_off;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
command = command << 1;
|
||||
}
|
||||
SDI_on;
|
||||
}
|
||||
|
||||
//VARIANT 2
|
||||
uint8_t nrf_spi_read(void)
|
||||
{
|
||||
uint8_t result;
|
||||
uint8_t i;
|
||||
result=0;
|
||||
for(i=0;i<8;i++) {
|
||||
result<<=1;
|
||||
if(SDO_1) ///
|
||||
result|=0x01;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
NOP();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//--------------------------------------------
|
||||
|
||||
|
||||
|
||||
//---------------------------
|
||||
// NRF24L01+ SPI Specific Functions
|
||||
@@ -68,13 +27,15 @@ uint8_t rf_setup;
|
||||
void NRF24L01_Initialize()
|
||||
{
|
||||
rf_setup = 0x09;
|
||||
prev_power = 0x00; // Make sure prev_power is inline with current power
|
||||
XN297_SetScrambledMode(XN297_SCRAMBLED);
|
||||
}
|
||||
|
||||
void NRF24L01_WriteReg(uint8_t reg, uint8_t data)
|
||||
{
|
||||
NRF_CSN_off;
|
||||
nrf_spi_write(W_REGISTER | (REGISTER_MASK & reg));
|
||||
nrf_spi_write(data);
|
||||
SPI_Write(W_REGISTER | (REGISTER_MASK & reg));
|
||||
SPI_Write(data);
|
||||
NRF_CSN_on;
|
||||
}
|
||||
|
||||
@@ -82,52 +43,53 @@ void NRF24L01_WriteRegisterMulti(uint8_t reg, uint8_t * data, uint8_t length)
|
||||
{
|
||||
NRF_CSN_off;
|
||||
|
||||
nrf_spi_write(W_REGISTER | ( REGISTER_MASK & reg));
|
||||
SPI_Write(W_REGISTER | ( REGISTER_MASK & reg));
|
||||
for (uint8_t i = 0; i < length; i++)
|
||||
nrf_spi_write(data[i]);
|
||||
SPI_Write(data[i]);
|
||||
NRF_CSN_on;
|
||||
}
|
||||
|
||||
void NRF24L01_WritePayload(uint8_t * data, uint8_t length)
|
||||
{
|
||||
NRF_CSN_off;
|
||||
nrf_spi_write(W_TX_PAYLOAD);
|
||||
SPI_Write(W_TX_PAYLOAD);
|
||||
for (uint8_t i = 0; i < length; i++)
|
||||
nrf_spi_write(data[i]);
|
||||
SPI_Write(data[i]);
|
||||
NRF_CSN_on;
|
||||
}
|
||||
|
||||
uint8_t NRF24L01_ReadReg(uint8_t reg)
|
||||
{
|
||||
NRF_CSN_off;
|
||||
nrf_spi_write(R_REGISTER | (REGISTER_MASK & reg));
|
||||
uint8_t data = nrf_spi_read();
|
||||
SPI_Write(R_REGISTER | (REGISTER_MASK & reg));
|
||||
uint8_t data = SPI_Read();
|
||||
NRF_CSN_on;
|
||||
return data;
|
||||
}
|
||||
|
||||
void NRF24L01_ReadRegisterMulti(uint8_t reg, uint8_t * data, uint8_t length)
|
||||
/*static void NRF24L01_ReadRegisterMulti(uint8_t reg, uint8_t * data, uint8_t length)
|
||||
{
|
||||
NRF_CSN_off;
|
||||
nrf_spi_write(R_REGISTER | (REGISTER_MASK & reg));
|
||||
SPI_Write(R_REGISTER | (REGISTER_MASK & reg));
|
||||
for(uint8_t i = 0; i < length; i++)
|
||||
data[i] = nrf_spi_read();
|
||||
data[i] = SPI_Read();
|
||||
NRF_CSN_on;
|
||||
}
|
||||
*/
|
||||
|
||||
void NRF24L01_ReadPayload(uint8_t * data, uint8_t length)
|
||||
static void NRF24L01_ReadPayload(uint8_t * data, uint8_t length)
|
||||
{
|
||||
NRF_CSN_off;
|
||||
nrf_spi_write(R_RX_PAYLOAD);
|
||||
SPI_Write(R_RX_PAYLOAD);
|
||||
for(uint8_t i = 0; i < length; i++)
|
||||
data[i] = nrf_spi_read();
|
||||
data[i] = SPI_Read();
|
||||
NRF_CSN_on;
|
||||
}
|
||||
|
||||
void NRF24L01_Strobe(uint8_t state)
|
||||
static void NRF24L01_Strobe(uint8_t state)
|
||||
{
|
||||
NRF_CSN_off;
|
||||
nrf_spi_write(state);
|
||||
SPI_Write(state);
|
||||
NRF_CSN_on;
|
||||
}
|
||||
|
||||
@@ -141,11 +103,25 @@ void NRF24L01_FlushRx()
|
||||
NRF24L01_Strobe(FLUSH_RX);
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) NRF24L01_GetStatus()
|
||||
{
|
||||
return SPI_Read();
|
||||
}
|
||||
|
||||
static uint8_t NRF24L01_GetDynamicPayloadSize()
|
||||
{
|
||||
NRF_CSN_off;
|
||||
SPI_Write(R_RX_PL_WID);
|
||||
uint8_t len = SPI_Read();
|
||||
NRF_CSN_on;
|
||||
return len;
|
||||
}
|
||||
|
||||
void NRF24L01_Activate(uint8_t code)
|
||||
{
|
||||
NRF_CSN_off;
|
||||
nrf_spi_write(ACTIVATE);
|
||||
nrf_spi_write(code);
|
||||
SPI_Write(ACTIVATE);
|
||||
SPI_Write(code);
|
||||
NRF_CSN_on;
|
||||
}
|
||||
|
||||
@@ -154,14 +130,16 @@ void NRF24L01_SetBitrate(uint8_t bitrate)
|
||||
// Note that bitrate 250kbps (and bit RF_DR_LOW) is valid only
|
||||
// for nRF24L01+. There is no way to programmatically tell it from
|
||||
// older version, nRF24L01, but the older is practically phased out
|
||||
// by Nordic, so we assume that we deal with with modern version.
|
||||
// by Nordic, so we assume that we deal with modern version.
|
||||
|
||||
// Bit 0 goes to RF_DR_HIGH, bit 1 - to RF_DR_LOW
|
||||
rf_setup = (rf_setup & 0xD7) | ((bitrate & 0x02) << 4) | ((bitrate & 0x01) << 3);
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup);
|
||||
prev_power=(rf_setup>>1)&0x03; // Make sure prev_power is inline with current power
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup);
|
||||
}
|
||||
|
||||
void NRF24L01_SetPower_Value(uint8_t power)
|
||||
/*
|
||||
static void NRF24L01_SetPower_Value(uint8_t power)
|
||||
{
|
||||
uint8_t nrf_power = 0;
|
||||
switch(power) {
|
||||
@@ -179,36 +157,43 @@ void NRF24L01_SetPower_Value(uint8_t power)
|
||||
rf_setup = (rf_setup & 0xF9) | ((nrf_power & 0x03) << 1);
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup);
|
||||
}
|
||||
|
||||
*/
|
||||
void NRF24L01_SetPower()
|
||||
{
|
||||
uint8_t power=NRF_BIND_POWER;
|
||||
if(IS_BIND_DONE_on)
|
||||
power=IS_POWER_FLAG_on?NRF_HIGH_POWER:NRF_LOW_POWER;
|
||||
if(IS_BIND_DONE)
|
||||
#ifdef NRF24L01_ENABLE_LOW_POWER
|
||||
power=IS_POWER_FLAG_on?NRF_HIGH_POWER:NRF_LOW_POWER;
|
||||
#else
|
||||
power=NRF_HIGH_POWER;
|
||||
#endif
|
||||
if(IS_RANGE_FLAG_on)
|
||||
power=NRF_POWER_0;
|
||||
rf_setup = (rf_setup & 0xF9) | (power << 1);
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup);
|
||||
if(prev_power != power)
|
||||
{
|
||||
rf_setup = (rf_setup & 0xF9) | (power << 1);
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup);
|
||||
prev_power=power;
|
||||
}
|
||||
}
|
||||
|
||||
void NRF24L01_SetTxRxMode(enum TXRX_State mode)
|
||||
{
|
||||
if(mode == TX_EN) {
|
||||
NRF_CSN_off;
|
||||
NRF_CE_off;
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (1 << NRF24L01_07_RX_DR) //reset the flag(s)
|
||||
| (1 << NRF24L01_07_TX_DS)
|
||||
| (1 << NRF24L01_07_MAX_RT));
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_EN_CRC) // switch to TX mode
|
||||
| (1 << NRF24L01_00_CRCO)
|
||||
| (1 << NRF24L01_00_PWR_UP));
|
||||
_delay_us(130);
|
||||
NRF_CSN_on;
|
||||
delayMicroseconds(130);
|
||||
NRF_CE_on;
|
||||
}
|
||||
else
|
||||
if (mode == RX_EN) {
|
||||
NRF_CSN_off;
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // reset the flag(s)
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); // switch to RX mode
|
||||
if (mode == RX_EN)
|
||||
{
|
||||
NRF_CE_off;
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (1 << NRF24L01_07_RX_DR) //reset the flag(s)
|
||||
| (1 << NRF24L01_07_TX_DS)
|
||||
| (1 << NRF24L01_07_MAX_RT));
|
||||
@@ -216,13 +201,13 @@ void NRF24L01_SetTxRxMode(enum TXRX_State mode)
|
||||
| (1 << NRF24L01_00_CRCO)
|
||||
| (1 << NRF24L01_00_PWR_UP)
|
||||
| (1 << NRF24L01_00_PRIM_RX));
|
||||
_delay_us(130);
|
||||
NRF_CSN_on;
|
||||
delayMicroseconds(130);
|
||||
NRF_CE_on;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_EN_CRC)); //PowerDown
|
||||
NRF_CSN_off;
|
||||
NRF_CE_off;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,80 +223,80 @@ void NRF24L01_Reset()
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_Strobe(0xff); // NOP
|
||||
NRF24L01_ReadReg(0x07);
|
||||
NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
_delay_us(100);
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
|
||||
uint8_t NRF24L01_packet_ack()
|
||||
{
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) {
|
||||
case BV(NRF24L01_07_TX_DS):
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (_BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT)))
|
||||
{
|
||||
case _BV(NRF24L01_07_TX_DS):
|
||||
return PKT_ACKED;
|
||||
case BV(NRF24L01_07_MAX_RT):
|
||||
case _BV(NRF24L01_07_MAX_RT):
|
||||
return PKT_TIMEOUT;
|
||||
}
|
||||
return PKT_PENDING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---------------------------
|
||||
/*
|
||||
void NRF24L01_spi_test(void)
|
||||
{
|
||||
unsigned long errors = 0;
|
||||
unsigned long test = 0;
|
||||
unsigned long time;
|
||||
uint8_t test_data_r[5];
|
||||
uint8_t test_data_w[5] = {0x01,0x02,0x03,0x04,0x05};
|
||||
|
||||
time = micros();
|
||||
Serial.println("Testing SPI");
|
||||
for(test=0; test < 2775600 ; test++) // should run for X mins.
|
||||
{
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, test_data_w, 5);
|
||||
NRF24L01_ReadRegisterMulti(NRF24L01_0B_RX_ADDR_P1, test_data_r, 5);
|
||||
if(0 != memcmp(test_data_r, test_data_w, sizeof(test_data_r))) errors++;
|
||||
test_data_w[0] ++;
|
||||
test_data_w[1] ++;
|
||||
test_data_w[2] ++;
|
||||
test_data_w[3] ++;
|
||||
test_data_w[4] ++;
|
||||
}
|
||||
Serial.print("test "); Serial.print(test, HEX); Serial.print("\n");
|
||||
Serial.print("errors "); Serial.print(errors, HEX); Serial.print("\n");
|
||||
Serial.print("time "); Serial.print(micros()- time, DEC); Serial.print("\n");
|
||||
|
||||
// 124211960
|
||||
// 90899216
|
||||
}
|
||||
*/
|
||||
//---------------------------
|
||||
|
||||
|
||||
///////////////
|
||||
// XN297 emulation layer
|
||||
uint8_t xn297_scramble_enabled=XN297_SCRAMBLED; //enabled by default
|
||||
uint8_t xn297_addr_len;
|
||||
uint8_t xn297_tx_addr[5];
|
||||
uint8_t xn297_rx_addr[5];
|
||||
uint8_t xn297_crc = 0;
|
||||
|
||||
static const uint8_t xn297_scramble[] = {
|
||||
0xe3, 0xb1, 0x4b, 0xea, 0x85, 0xbc, 0xe5, 0x66,
|
||||
0x0d, 0xae, 0x8c, 0x88, 0x12, 0x69, 0xee, 0x1f,
|
||||
0xc7, 0x62, 0x97, 0xd5, 0x0b, 0x79, 0xca, 0xcc,
|
||||
0x1b, 0x5d, 0x19, 0x10, 0x24, 0xd3, 0xdc, 0x3f,
|
||||
0x8e, 0xc5, 0x2f};
|
||||
// xn297 address / pcf / payload scramble table
|
||||
const uint8_t xn297_scramble[] = {
|
||||
0xE3, 0xB1, 0x4B, 0xEA, 0x85, 0xBC, 0xE5, 0x66,
|
||||
0x0D, 0xAE, 0x8C, 0x88, 0x12, 0x69, 0xEE, 0x1F,
|
||||
0xC7, 0x62, 0x97, 0xD5, 0x0B, 0x79, 0xCA, 0xCC,
|
||||
0x1B, 0x5D, 0x19, 0x10, 0x24, 0xD3, 0xDC, 0x3F,
|
||||
0x8E, 0xC5, 0x2F, 0xAA, 0x16, 0xF3, 0x95 };
|
||||
|
||||
static const uint16_t xn297_crc_xorout[] = {
|
||||
0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C, // 1st entry is missing, probably never needed
|
||||
0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x8148, // it's used for 3-byte address w/ 0 byte payload only
|
||||
0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7,
|
||||
0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401,
|
||||
0x2138, 0x129F, 0xB3A0, 0x2988};
|
||||
// scrambled, standard mode crc xorout table
|
||||
const uint16_t PROGMEM xn297_crc_xorout_scrambled[] = {
|
||||
0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C,
|
||||
0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B,
|
||||
0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7,
|
||||
0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401,
|
||||
0x2138, 0x129F, 0xB3A0, 0x2988, 0x23CA, 0xC0CB,
|
||||
0x0C6C, 0xB329, 0xA0A1, 0x0A16, 0xA9D0 };
|
||||
|
||||
uint8_t bit_reverse(uint8_t b_in)
|
||||
// unscrambled, standard mode crc xorout table
|
||||
const uint16_t PROGMEM xn297_crc_xorout[] = {
|
||||
0x0000, 0x3D5F, 0xA6F1, 0x3A23, 0xAA16, 0x1CAF,
|
||||
0x62B2, 0xE0EB, 0x0821, 0xBE07, 0x5F1A, 0xAF15,
|
||||
0x4F0A, 0xAD24, 0x5E48, 0xED34, 0x068C, 0xF2C9,
|
||||
0x1852, 0xDF36, 0x129D, 0xB17C, 0xD5F5, 0x70D7,
|
||||
0xB798, 0x5133, 0x67DB, 0xD94E, 0x0A5B, 0xE445,
|
||||
0xE6A5, 0x26E7, 0xBDAB, 0xC379, 0x8E20 };
|
||||
|
||||
// scrambled enhanced mode crc xorout table
|
||||
const uint16_t PROGMEM xn297_crc_xorout_scrambled_enhanced[] = {
|
||||
0x0000, 0x7EBF, 0x3ECE, 0x07A4, 0xCA52, 0x343B,
|
||||
0x53F8, 0x8CD0, 0x9EAC, 0xD0C0, 0x150D, 0x5186,
|
||||
0xD251, 0xA46F, 0x8435, 0xFA2E, 0x7EBD, 0x3C7D,
|
||||
0x94E0, 0x3D5F, 0xA685, 0x4E47, 0xF045, 0xB483,
|
||||
0x7A1F, 0xDEA2, 0x9642, 0xBF4B, 0x032F, 0x01D2,
|
||||
0xDC86, 0x92A5, 0x183A, 0xB760, 0xA953 };
|
||||
|
||||
// unscrambled enhanced mode crc xorout table
|
||||
// unused so far
|
||||
/*
|
||||
const uint16_t xn297_crc_xorout_enhanced[] = {
|
||||
0x0000, 0x8BE6, 0xD8EC, 0xB87A, 0x42DC, 0xAA89,
|
||||
0x83AF, 0x10E4, 0xE83E, 0x5C29, 0xAC76, 0x1C69,
|
||||
0xA4B2, 0x5961, 0xB4D3, 0x2A50, 0xCB27, 0x5128,
|
||||
0x7CDB, 0x7A14, 0xD5D2, 0x57D7, 0xE31D, 0xCE42,
|
||||
0x648D, 0xBF2D, 0x653B, 0x190C, 0x9117, 0x9A97,
|
||||
0xABFC, 0xE68E, 0x0DE7, 0x28A2, 0x1965 };
|
||||
*/
|
||||
|
||||
static uint8_t bit_reverse(uint8_t b_in)
|
||||
{
|
||||
uint8_t b_out = 0;
|
||||
for (uint8_t i = 0; i < 8; ++i)
|
||||
@@ -322,12 +307,11 @@ uint8_t bit_reverse(uint8_t b_in)
|
||||
return b_out;
|
||||
}
|
||||
|
||||
uint16_t crc16_update(uint16_t crc, uint8_t a)
|
||||
static const uint16_t polynomial = 0x1021;
|
||||
static uint16_t crc16_update(uint16_t crc, uint8_t a, uint8_t bits)
|
||||
{
|
||||
static const uint16_t polynomial = 0x1021;
|
||||
|
||||
crc ^= a << 8;
|
||||
for (uint8_t i = 0; i < 8; ++i)
|
||||
while(bits--)
|
||||
if (crc & 0x8000)
|
||||
crc = (crc << 1) ^ polynomial;
|
||||
else
|
||||
@@ -362,16 +346,25 @@ void XN297_SetRXAddr(const uint8_t* addr, uint8_t len)
|
||||
memcpy(buf, addr, len);
|
||||
memcpy(xn297_rx_addr, addr, len);
|
||||
for (uint8_t i = 0; i < xn297_addr_len; ++i)
|
||||
buf[i] = xn297_rx_addr[i] ^ xn297_scramble[xn297_addr_len-i-1];
|
||||
{
|
||||
buf[i] = xn297_rx_addr[i];
|
||||
if(xn297_scramble_enabled)
|
||||
buf[i] ^= xn297_scramble[xn297_addr_len-i-1];
|
||||
}
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, len-2);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, buf, 5);
|
||||
}
|
||||
|
||||
void XN297_Configure(uint8_t flags)
|
||||
{
|
||||
xn297_crc = !!(flags & BV(NRF24L01_00_EN_CRC));
|
||||
flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO));
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags);
|
||||
xn297_crc = !!(flags & _BV(NRF24L01_00_EN_CRC));
|
||||
flags &= ~(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xFF);
|
||||
}
|
||||
|
||||
void XN297_SetScrambledMode(const uint8_t mode)
|
||||
{
|
||||
xn297_scramble_enabled = mode;
|
||||
}
|
||||
|
||||
void XN297_WritePayload(uint8_t* msg, uint8_t len)
|
||||
@@ -387,31 +380,467 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len)
|
||||
buf[last++] = 0x55;
|
||||
}
|
||||
for (uint8_t i = 0; i < xn297_addr_len; ++i)
|
||||
buf[last++] = xn297_tx_addr[xn297_addr_len-i-1] ^ xn297_scramble[i];
|
||||
|
||||
for (uint8_t i = 0; i < len; ++i) {
|
||||
{
|
||||
buf[last] = xn297_tx_addr[xn297_addr_len-i-1];
|
||||
if(xn297_scramble_enabled)
|
||||
buf[last] ^= xn297_scramble[i];
|
||||
last++;
|
||||
}
|
||||
for (uint8_t i = 0; i < len; ++i)
|
||||
{
|
||||
// bit-reverse bytes in packet
|
||||
uint8_t b_out = bit_reverse(msg[i]);
|
||||
buf[last++] = b_out ^ xn297_scramble[xn297_addr_len+i];
|
||||
buf[last] = bit_reverse(msg[i]);
|
||||
if(xn297_scramble_enabled)
|
||||
buf[last] ^= xn297_scramble[xn297_addr_len+i];
|
||||
last++;
|
||||
}
|
||||
if (xn297_crc)
|
||||
{
|
||||
uint8_t offset = xn297_addr_len < 4 ? 1 : 0;
|
||||
uint16_t crc = 0xb5d2;
|
||||
for (uint8_t i = offset; i < last; ++i)
|
||||
crc = crc16_update(crc, buf[i]);
|
||||
crc ^= xn297_crc_xorout[xn297_addr_len - 3 + len];
|
||||
crc = crc16_update(crc, buf[i], 8);
|
||||
if(xn297_scramble_enabled)
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
|
||||
else
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout[xn297_addr_len - 3 + len]);
|
||||
buf[last++] = crc >> 8;
|
||||
buf[last++] = crc & 0xff;
|
||||
}
|
||||
NRF24L01_WritePayload(buf, last);
|
||||
}
|
||||
|
||||
void XN297_ReadPayload(uint8_t* msg, uint8_t len)
|
||||
void XN297_WriteEnhancedPayload(uint8_t* msg, uint8_t len, uint8_t noack)
|
||||
{
|
||||
NRF24L01_ReadPayload(msg, len);
|
||||
for(uint8_t i=0; i<len; i++)
|
||||
msg[i] = bit_reverse(msg[i]) ^ bit_reverse(xn297_scramble[i+xn297_addr_len]);
|
||||
uint8_t packet[32];
|
||||
uint8_t scramble_index=0;
|
||||
uint8_t last = 0;
|
||||
static uint8_t pid=0;
|
||||
|
||||
// address
|
||||
if (xn297_addr_len < 4)
|
||||
{
|
||||
// If address length (which is defined by receive address length)
|
||||
// is less than 4 the TX address can't fit the preamble, so the last
|
||||
// byte goes here
|
||||
packet[last++] = 0x55;
|
||||
}
|
||||
for (uint8_t i = 0; i < xn297_addr_len; ++i)
|
||||
{
|
||||
packet[last] = xn297_tx_addr[xn297_addr_len-i-1];
|
||||
if(xn297_scramble_enabled)
|
||||
packet[last] ^= xn297_scramble[scramble_index++];
|
||||
last++;
|
||||
}
|
||||
|
||||
// pcf
|
||||
packet[last] = (len << 1) | (pid>>1);
|
||||
if(xn297_scramble_enabled)
|
||||
packet[last] ^= xn297_scramble[scramble_index++];
|
||||
last++;
|
||||
packet[last] = (pid << 7) | (noack << 6);
|
||||
|
||||
// payload
|
||||
packet[last]|= bit_reverse(msg[0]) >> 2; // first 6 bit of payload
|
||||
if(xn297_scramble_enabled)
|
||||
packet[last] ^= xn297_scramble[scramble_index++];
|
||||
|
||||
for (uint8_t i = 0; i < len-1; ++i)
|
||||
{
|
||||
last++;
|
||||
packet[last] = (bit_reverse(msg[i]) << 6) | (bit_reverse(msg[i+1]) >> 2);
|
||||
if(xn297_scramble_enabled)
|
||||
packet[last] ^= xn297_scramble[scramble_index++];
|
||||
}
|
||||
|
||||
last++;
|
||||
packet[last] = bit_reverse(msg[len-1]) << 6; // last 2 bit of payload
|
||||
if(xn297_scramble_enabled)
|
||||
packet[last] ^= xn297_scramble[scramble_index++] & 0xc0;
|
||||
|
||||
// crc
|
||||
if (xn297_crc)
|
||||
{
|
||||
uint8_t offset = xn297_addr_len < 4 ? 1 : 0;
|
||||
uint16_t crc = 0xb5d2;
|
||||
for (uint8_t i = offset; i < last; ++i)
|
||||
crc = crc16_update(crc, packet[i], 8);
|
||||
crc = crc16_update(crc, packet[last] & 0xc0, 2);
|
||||
if (xn297_scramble_enabled)
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled_enhanced[xn297_addr_len-3+len]);
|
||||
//else
|
||||
// crc ^= pgm_read_word(&xn297_crc_xorout_enhanced[xn297_addr_len - 3 + len]);
|
||||
|
||||
packet[last++] |= (crc >> 8) >> 2;
|
||||
packet[last++] = ((crc >> 8) << 6) | ((crc & 0xff) >> 2);
|
||||
packet[last++] = (crc & 0xff) << 6;
|
||||
}
|
||||
NRF24L01_WritePayload(packet, last);
|
||||
|
||||
pid++;
|
||||
if(pid>3)
|
||||
pid=0;
|
||||
}
|
||||
|
||||
// End of XN297 emulation
|
||||
boolean XN297_ReadPayload(uint8_t* msg, uint8_t len)
|
||||
{ //!!! Don't forget if using CRC to do a +2 on any of the used NRF24L01_11_RX_PW_Px !!!
|
||||
uint8_t buf[32];
|
||||
if (xn297_crc)
|
||||
NRF24L01_ReadPayload(buf, len+2); // Read payload + CRC
|
||||
else
|
||||
NRF24L01_ReadPayload(buf, len);
|
||||
// Decode payload
|
||||
for(uint8_t i=0; i<len; i++)
|
||||
{
|
||||
uint8_t b_in=buf[i];
|
||||
if(xn297_scramble_enabled)
|
||||
b_in ^= xn297_scramble[i+xn297_addr_len];
|
||||
msg[i] = bit_reverse(b_in);
|
||||
}
|
||||
if (!xn297_crc)
|
||||
return true; // No CRC so OK by default...
|
||||
|
||||
// Calculate CRC
|
||||
uint16_t crc = 0xb5d2;
|
||||
//process address
|
||||
for (uint8_t i = 0; i < xn297_addr_len; ++i)
|
||||
{
|
||||
uint8_t b_in=xn297_tx_addr[xn297_addr_len-i-1];
|
||||
if(xn297_scramble_enabled)
|
||||
b_in ^= xn297_scramble[i];
|
||||
crc = crc16_update(crc, b_in, 8);
|
||||
}
|
||||
//process payload
|
||||
for (uint8_t i = 0; i < len; ++i)
|
||||
crc = crc16_update(crc, buf[i], 8);
|
||||
//xorout
|
||||
if(xn297_scramble_enabled)
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
|
||||
else
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout[xn297_addr_len - 3 + len]);
|
||||
//test
|
||||
if( (crc >> 8) == buf[len] && (crc & 0xff) == buf[len+1])
|
||||
return true; // CRC OK
|
||||
return false; // CRC NOK
|
||||
}
|
||||
|
||||
uint8_t XN297_ReadEnhancedPayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
uint8_t buffer[32];
|
||||
uint8_t pcf_size; // pcf payload size
|
||||
NRF24L01_ReadPayload(buffer, len+2); // pcf + payload
|
||||
pcf_size = buffer[0];
|
||||
if(xn297_scramble_enabled)
|
||||
pcf_size ^= xn297_scramble[xn297_addr_len];
|
||||
pcf_size = pcf_size >> 1;
|
||||
for(int i=0; i<len; i++)
|
||||
{
|
||||
msg[i] = bit_reverse((buffer[i+1] << 2) | (buffer[i+2] >> 6));
|
||||
if(xn297_scramble_enabled)
|
||||
msg[i] ^= bit_reverse((xn297_scramble[xn297_addr_len+i+1] << 2) |
|
||||
(xn297_scramble[xn297_addr_len+i+2] >> 6));
|
||||
}
|
||||
return pcf_size;
|
||||
}
|
||||
|
||||
// End of XN297 emulation
|
||||
|
||||
//
|
||||
// HS6200 emulation layer
|
||||
///////////////////////////
|
||||
static uint8_t hs6200_crc;
|
||||
static uint16_t hs6200_crc_init;
|
||||
static uint8_t hs6200_tx_addr[5];
|
||||
static uint8_t hs6200_address_length;
|
||||
|
||||
static const uint8_t hs6200_scramble[] = {
|
||||
0x80,0xf5,0x3b,0x0d,0x6d,0x2a,0xf9,0xbc,
|
||||
0x51,0x8e,0x4c,0xfd,0xc1,0x65,0xd0 }; // todo: find all 32 bytes ...
|
||||
|
||||
void HS6200_SetTXAddr(const uint8_t* addr, uint8_t len)
|
||||
{
|
||||
if(len < 4)
|
||||
len = 4;
|
||||
else if(len > 5)
|
||||
len = 5;
|
||||
|
||||
// use nrf24 address field as a longer preamble
|
||||
if(addr[len-1] & 0x80)
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\x55\x55\x55\x55\x55", 5);
|
||||
else
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xaa\xaa\xaa\xaa\xaa", 5);
|
||||
|
||||
// precompute address crc
|
||||
hs6200_crc_init = 0xffff;
|
||||
for(int i=0; i<len; i++)
|
||||
hs6200_crc_init = crc16_update(hs6200_crc_init, addr[len-1-i], 8);
|
||||
memcpy(hs6200_tx_addr, addr, len);
|
||||
hs6200_address_length = len;
|
||||
}
|
||||
|
||||
static uint16_t hs6200_calc_crc(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
uint8_t pos;
|
||||
uint16_t crc = hs6200_crc_init;
|
||||
|
||||
// pcf + payload
|
||||
for(pos=0; pos < len-1; pos++)
|
||||
crc = crc16_update(crc, msg[pos], 8);
|
||||
// last byte (1 bit only)
|
||||
if(len > 0)
|
||||
crc = crc16_update(crc, msg[pos+1], 1);
|
||||
return crc;
|
||||
}
|
||||
|
||||
void HS6200_Configure(uint8_t flags)
|
||||
{
|
||||
hs6200_crc = !!(flags & _BV(NRF24L01_00_EN_CRC));
|
||||
flags &= ~(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xff);
|
||||
}
|
||||
|
||||
void HS6200_WritePayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
uint8_t payload[32];
|
||||
const uint8_t no_ack = 1; // never ask for an ack
|
||||
static uint8_t pid;
|
||||
uint8_t pos = 0;
|
||||
|
||||
if(len > sizeof(hs6200_scramble))
|
||||
len = sizeof(hs6200_scramble);
|
||||
|
||||
// address
|
||||
for(int i=hs6200_address_length-1; i>=0; i--)
|
||||
payload[pos++] = hs6200_tx_addr[i];
|
||||
|
||||
// guard bytes
|
||||
payload[pos++] = hs6200_tx_addr[0];
|
||||
payload[pos++] = hs6200_tx_addr[0];
|
||||
|
||||
// packet control field
|
||||
payload[pos++] = ((len & 0x3f) << 2) | (pid & 0x03);
|
||||
payload[pos] = (no_ack & 0x01) << 7;
|
||||
pid++;
|
||||
|
||||
// scrambled payload
|
||||
if(len > 0)
|
||||
{
|
||||
payload[pos++] |= (msg[0] ^ hs6200_scramble[0]) >> 1;
|
||||
for(uint8_t i=1; i<len; i++)
|
||||
payload[pos++] = ((msg[i-1] ^ hs6200_scramble[i-1]) << 7) | ((msg[i] ^ hs6200_scramble[i]) >> 1);
|
||||
payload[pos] = (msg[len-1] ^ hs6200_scramble[len-1]) << 7;
|
||||
}
|
||||
|
||||
// crc
|
||||
if(hs6200_crc)
|
||||
{
|
||||
uint16_t crc = hs6200_calc_crc(&payload[hs6200_address_length+2], len+2);
|
||||
uint8_t hcrc = crc >> 8;
|
||||
uint8_t lcrc = crc & 0xff;
|
||||
payload[pos++] |= (hcrc >> 1);
|
||||
payload[pos++] = (hcrc << 7) | (lcrc >> 1);
|
||||
payload[pos++] = lcrc << 7;
|
||||
}
|
||||
|
||||
NRF24L01_WritePayload(payload, pos);
|
||||
delayMicroseconds(option+20);
|
||||
NRF24L01_WritePayload(payload, pos);
|
||||
}
|
||||
//
|
||||
// End of HS6200 emulation
|
||||
////////////////////////////
|
||||
|
||||
///////////////
|
||||
// LT8900 emulation layer
|
||||
uint8_t LT8900_buffer[64];
|
||||
uint8_t LT8900_buffer_start;
|
||||
uint16_t LT8900_buffer_overhead_bits;
|
||||
uint8_t LT8900_addr[8];
|
||||
uint8_t LT8900_addr_size;
|
||||
uint8_t LT8900_Preamble_Len;
|
||||
uint8_t LT8900_Tailer_Len;
|
||||
uint8_t LT8900_CRC_Initial_Data;
|
||||
uint8_t LT8900_Flags;
|
||||
#define LT8900_CRC_ON 6
|
||||
#define LT8900_SCRAMBLE_ON 5
|
||||
#define LT8900_PACKET_LENGTH_EN 4
|
||||
#define LT8900_DATA_PACKET_TYPE_1 3
|
||||
#define LT8900_DATA_PACKET_TYPE_0 2
|
||||
#define LT8900_FEC_TYPE_1 1
|
||||
#define LT8900_FEC_TYPE_0 0
|
||||
|
||||
void LT8900_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uint8_t crc_init)
|
||||
{
|
||||
//Preamble 1 to 8 bytes
|
||||
LT8900_Preamble_Len=preamble_len;
|
||||
//Trailer 4 to 18 bits
|
||||
LT8900_Tailer_Len=trailer_len;
|
||||
//Flags
|
||||
// CRC_ON: 1 on, 0 off
|
||||
// SCRAMBLE_ON: 1 on, 0 off
|
||||
// PACKET_LENGTH_EN: 1 1st byte of payload is payload size
|
||||
// DATA_PACKET_TYPE: 00 NRZ, 01 Manchester, 10 8bit/10bit line code, 11 interleave data type
|
||||
// FEC_TYPE: 00 No FEC, 01 FEC13, 10 FEC23, 11 reserved
|
||||
LT8900_Flags=flags;
|
||||
//CRC init constant
|
||||
LT8900_CRC_Initial_Data=crc_init;
|
||||
}
|
||||
|
||||
void LT8900_SetChannel(uint8_t channel)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel +2); //NRF24L01 is 2400+channel but LT8900 is 2402+channel
|
||||
}
|
||||
|
||||
void LT8900_SetTxRxMode(enum TXRX_State mode)
|
||||
{
|
||||
if(mode == TX_EN)
|
||||
{
|
||||
//Switch to TX
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
//Disable CRC
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_PWR_UP));
|
||||
}
|
||||
else
|
||||
if (mode == RX_EN)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 32);
|
||||
//Switch to RX
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
// Disable CRC
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_PWR_UP) | (1 << NRF24L01_00_PRIM_RX) );
|
||||
}
|
||||
else
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
}
|
||||
|
||||
void LT8900_BuildOverhead()
|
||||
{
|
||||
uint8_t pos;
|
||||
|
||||
//Build overhead
|
||||
//preamble
|
||||
memset(LT8900_buffer,LT8900_addr[0]&0x01?0xAA:0x55,LT8900_Preamble_Len-1);
|
||||
pos=LT8900_Preamble_Len-1;
|
||||
//address
|
||||
for(uint8_t i=0;i<LT8900_addr_size;i++)
|
||||
{
|
||||
LT8900_buffer[pos]=bit_reverse(LT8900_addr[i]);
|
||||
pos++;
|
||||
}
|
||||
//trailer
|
||||
memset(LT8900_buffer+pos,(LT8900_buffer[pos-1]&0x01)==0?0xAA:0x55,3);
|
||||
LT8900_buffer_overhead_bits=pos*8+LT8900_Tailer_Len;
|
||||
//nrf address length max is 5
|
||||
pos+=LT8900_Tailer_Len/8;
|
||||
LT8900_buffer_start=pos>5?5:pos;
|
||||
}
|
||||
|
||||
void LT8900_SetAddress(uint8_t *address,uint8_t addr_size)
|
||||
{
|
||||
uint8_t addr[5];
|
||||
|
||||
//Address size (SyncWord) 2 to 8 bytes, 16/32/48/64 bits
|
||||
LT8900_addr_size=addr_size;
|
||||
for (uint8_t i = 0; i < addr_size; i++)
|
||||
LT8900_addr[i] = address[addr_size-1-i];
|
||||
|
||||
//Build overhead
|
||||
LT8900_BuildOverhead();
|
||||
|
||||
//Set NRF RX&TX address based on overhead content
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, LT8900_buffer_start-2);
|
||||
for(uint8_t i=0;i<LT8900_buffer_start;i++) // reverse bytes order
|
||||
addr[i]=LT8900_buffer[LT8900_buffer_start-i-1];
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, addr,LT8900_buffer_start);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, addr,LT8900_buffer_start);
|
||||
}
|
||||
|
||||
uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
uint8_t i,pos=0,shift,end,buffer[32];
|
||||
unsigned int crc=LT8900_CRC_Initial_Data,a;
|
||||
pos=LT8900_buffer_overhead_bits/8-LT8900_buffer_start;
|
||||
end=pos+len+(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN)?1:0)+(LT8900_Flags&_BV(LT8900_CRC_ON)?2:0);
|
||||
//Read payload
|
||||
NRF24L01_ReadPayload(buffer,end+1);
|
||||
//Check address + trail
|
||||
for(i=0;i<pos;i++)
|
||||
if(LT8900_buffer[LT8900_buffer_start+i]!=buffer[i])
|
||||
return 0; // wrong address...
|
||||
//Shift buffer to remove trail bits
|
||||
shift=LT8900_buffer_overhead_bits&0x7;
|
||||
for(i=pos;i<end;i++)
|
||||
{
|
||||
a=(buffer[i]<<8)+buffer[i+1];
|
||||
a<<=shift;
|
||||
buffer[i]=(a>>8)&0xFF;
|
||||
}
|
||||
//Check len
|
||||
if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN))
|
||||
{
|
||||
crc=crc16_update(crc,buffer[pos],8);
|
||||
if(bit_reverse(len)!=buffer[pos++])
|
||||
return 0; // wrong len...
|
||||
}
|
||||
//Decode message
|
||||
for(i=0;i<len;i++)
|
||||
{
|
||||
crc=crc16_update(crc,buffer[pos],8);
|
||||
msg[i]=bit_reverse(buffer[pos++]);
|
||||
}
|
||||
//Check CRC
|
||||
if(LT8900_Flags&_BV(LT8900_CRC_ON))
|
||||
{
|
||||
if(buffer[pos++]!=((crc>>8)&0xFF)) return 0; // wrong CRC...
|
||||
if(buffer[pos]!=(crc&0xFF)) return 0; // wrong CRC...
|
||||
}
|
||||
//Everything ok
|
||||
return 1;
|
||||
}
|
||||
|
||||
void LT8900_WritePayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
unsigned int crc=LT8900_CRC_Initial_Data,a,mask;
|
||||
uint8_t i, pos=0,tmp, buffer[64], pos_final,shift;
|
||||
//Add packet len
|
||||
if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN))
|
||||
{
|
||||
tmp=bit_reverse(len);
|
||||
buffer[pos++]=tmp;
|
||||
crc=crc16_update(crc,tmp,8);
|
||||
}
|
||||
//Add payload
|
||||
for(i=0;i<len;i++)
|
||||
{
|
||||
tmp=bit_reverse(msg[i]);
|
||||
buffer[pos++]=tmp;
|
||||
crc=crc16_update(crc,tmp,8);
|
||||
}
|
||||
//Add CRC
|
||||
if(LT8900_Flags&_BV(LT8900_CRC_ON))
|
||||
{
|
||||
buffer[pos++]=crc>>8;
|
||||
buffer[pos++]=crc;
|
||||
}
|
||||
//Shift everything to fit behind the trailer (4 to 18 bits)
|
||||
shift=LT8900_buffer_overhead_bits&0x7;
|
||||
pos_final=LT8900_buffer_overhead_bits/8;
|
||||
mask=~(0xFF<<(8-shift));
|
||||
LT8900_buffer[pos_final+pos]=0xFF;
|
||||
for(i=pos-1;i!=0xFF;i--)
|
||||
{
|
||||
a=buffer[i]<<(8-shift);
|
||||
LT8900_buffer[pos_final+i]=(LT8900_buffer[pos_final+i]&mask>>8)|a>>8;
|
||||
LT8900_buffer[pos_final+i+1]=(LT8900_buffer[pos_final+i+1]&mask)|a;
|
||||
}
|
||||
if(shift)
|
||||
pos++;
|
||||
//Send everything
|
||||
NRF24L01_WritePayload(LT8900_buffer+LT8900_buffer_start,pos_final+pos-LT8900_buffer_start);
|
||||
}
|
||||
// End of LT8900 emulation
|
||||
#endif
|
||||
125
Multiprotocol/POTENSIC_nrf24l01.ino
Normal file
125
Multiprotocol/POTENSIC_nrf24l01.ino
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
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(POTENSIC_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
//#define FORCE_POTENSIC_ORIGINAL_ID
|
||||
|
||||
#define POTENSIC_PACKET_PERIOD 4100 // Timeout for callback in uSec
|
||||
#define POTENSIC_INITIAL_WAIT 500
|
||||
#define POTENSIC_PACKET_SIZE 10
|
||||
#define POTENSIC_BIND_COUNT 400
|
||||
#define POTENSIC_RF_NUM_CHANNELS 4
|
||||
|
||||
static void __attribute__((unused)) POTENSIC_set_checksum()
|
||||
{
|
||||
uint8_t checksum = packet[1];
|
||||
for(uint8_t i=2; i<POTENSIC_PACKET_SIZE-2; i++)
|
||||
checksum += packet[i];
|
||||
packet[8] |= checksum & 0x0f;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) POTENSIC_send_packet()
|
||||
{
|
||||
packet[8]=0;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[0] = 0x61;
|
||||
memcpy(&packet[1],rx_tx_addr,5);
|
||||
packet[6] = 0x20;
|
||||
packet[7] = 0xC0;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0] = 0x64;
|
||||
// Deadband is needed on throttle to emulate the spring to neutral otherwise the quad behaves weirdly, 160 gives +-20%
|
||||
packet[1] = convert_channel_8b_limit_deadband(THROTTLE,0x00,0x19,0x32,160)<<1; // Throttle 00..19..32 *2
|
||||
uint8_t elevator=convert_channel_8b(ELEVATOR)>>3;
|
||||
packet[2] = ((255-convert_channel_8b(RUDDER))&0xF8)|(elevator>>2);
|
||||
packet[3] = (elevator<<6)|(((255-convert_channel_8b(AILERON))>>2)&0xFE);
|
||||
packet[4] = 0x20; // Trim
|
||||
packet[5] = 0x20 // Trim
|
||||
| GET_FLAG(CH7_SW, 0x80); // High: +100%
|
||||
packet[6] = 0x20; // Trim
|
||||
packet[7] = 0x40 // Low: -100%
|
||||
| GET_FLAG((Channel_data[CH7] > CHANNEL_MIN_COMMAND && !CH7_SW), 0x80) // Medium: 0%
|
||||
| GET_FLAG((CH5_SW||CH6_SW), 0x02) // Momentary Take off/Landing + Emergency
|
||||
| GET_FLAG(CH8_SW, 0x04); // Headless: -100%=off,+100%=on
|
||||
packet[8] = GET_FLAG(CH6_SW, 0x80); // Emergency
|
||||
}
|
||||
POTENSIC_set_checksum();
|
||||
packet[9] = hopping_frequency_no;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no&0x03]);
|
||||
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();
|
||||
XN297_WritePayload(packet, POTENSIC_PACKET_SIZE);
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) POTENSIC_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
XN297_SetTXAddr((uint8_t*)"\x01\x01\x01\x01\x06", 5); // Bind address
|
||||
else
|
||||
XN297_SetTXAddr(rx_tx_addr,5); // Normal address
|
||||
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_03_SETUP_AW, 0x03); // set address length (5 bytes)
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
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);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) POTENSIC_initialize_txid()
|
||||
{
|
||||
#ifdef FORCE_POTENSIC_ORIGINAL_ID
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\xF6\xE0\x20\x00\x0E",5);
|
||||
#endif
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x32\x3E\x3A\x36",POTENSIC_RF_NUM_CHANNELS); //50, 62, 58, 54
|
||||
}
|
||||
|
||||
uint16_t POTENSIC_callback()
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
if(--bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
XN297_SetTXAddr(rx_tx_addr,5);
|
||||
}
|
||||
POTENSIC_send_packet();
|
||||
return POTENSIC_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initPOTENSIC(void)
|
||||
{
|
||||
bind_counter = POTENSIC_BIND_COUNT;
|
||||
POTENSIC_initialize_txid();
|
||||
POTENSIC_init();
|
||||
hopping_frequency_no = 0;
|
||||
return POTENSIC_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
363
Multiprotocol/Pins.h
Normal file
363
Multiprotocol/Pins.h
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
//*******************
|
||||
//*** Pinouts ***
|
||||
//*******************
|
||||
#ifndef STM32_BOARD
|
||||
// TX
|
||||
#define SERIAL_TX_pin 1 //PD1
|
||||
#define SERIAL_TX_port PORTD
|
||||
#define SERIAL_TX_ddr DDRD
|
||||
#define SERIAL_TX_output SERIAL_TX_ddr |= _BV(SERIAL_TX_pin)
|
||||
#define SERIAL_TX_on SERIAL_TX_port |= _BV(SERIAL_TX_pin)
|
||||
#define SERIAL_TX_off SERIAL_TX_port &= ~_BV(SERIAL_TX_pin)
|
||||
#ifdef DEBUG_PIN
|
||||
#define DEBUG_PIN_on SERIAL_TX_on
|
||||
#define DEBUG_PIN_off SERIAL_TX_off
|
||||
#define DEBUG_PIN_toggle SERIAL_TX_port ^= _BV(SERIAL_TX_pin)
|
||||
#else
|
||||
#define DEBUG_PIN_on
|
||||
#define DEBUG_PIN_off
|
||||
#define DEBUG_PIN_toggle
|
||||
#endif
|
||||
|
||||
// Dial
|
||||
#define PROTO_DIAL1_pin 2
|
||||
#define PROTO_DIAL1_port PORTB
|
||||
#define PROTO_DIAL1_ipr PINB
|
||||
#define PROTO_DIAL2_pin 3
|
||||
#define PROTO_DIAL2_port PORTB
|
||||
#define PROTO_DIAL2_ipr PINB
|
||||
#define PROTO_DIAL3_pin 4
|
||||
#define PROTO_DIAL3_port PORTB
|
||||
#define PROTO_DIAL3_ipr PINB
|
||||
#define PROTO_DIAL4_pin 0
|
||||
#define PROTO_DIAL4_port PORTC
|
||||
#define PROTO_DIAL4_ipr PINC
|
||||
|
||||
// PPM
|
||||
#define PPM_pin 3 //D3 = PD3
|
||||
#define PPM_port PORTD
|
||||
|
||||
// SDIO
|
||||
#define SDI_pin 5 //D5 = PD5
|
||||
#define SDI_port PORTD
|
||||
#define SDI_ipr PIND
|
||||
#define SDI_ddr DDRD
|
||||
#ifdef ORANGE_TX
|
||||
#define SDI_on SDI_port.OUTSET = _BV(SDI_pin)
|
||||
#define SDI_off SDI_port.OUTCLR = _BV(SDI_pin)
|
||||
#else
|
||||
#define SDI_on SDI_port |= _BV(SDI_pin)
|
||||
#define SDI_off SDI_port &= ~_BV(SDI_pin)
|
||||
#define SDI_1 (SDI_ipr & _BV(SDI_pin))
|
||||
#define SDI_0 (SDI_ipr & _BV(SDI_pin)) == 0x00
|
||||
#endif
|
||||
#define SDI_input SDI_ddr &= ~_BV(SDI_pin)
|
||||
#define SDI_output SDI_ddr |= _BV(SDI_pin)
|
||||
|
||||
//SDO
|
||||
#define SDO_pin 6 //D6 = PD6
|
||||
#define SDO_port PORTD
|
||||
#define SDO_ipr PIND
|
||||
#ifdef ORANGE_TX
|
||||
#define SDO_1 (SDO_port.IN & _BV(SDO_pin))
|
||||
#define SDO_0 (SDO_port.IN & _BV(SDO_pin)) == 0x00
|
||||
#else
|
||||
#define SDO_1 (SDO_ipr & _BV(SDO_pin))
|
||||
#define SDO_0 (SDO_ipr & _BV(SDO_pin)) == 0x00
|
||||
#endif
|
||||
|
||||
// SCLK
|
||||
#define SCLK_port PORTD
|
||||
#define SCLK_ddr DDRD
|
||||
#ifdef ORANGE_TX
|
||||
#define SCLK_pin 7 //PD7
|
||||
#define SCLK_on SCLK_port.OUTSET = _BV(SCLK_pin)
|
||||
#define SCLK_off SCLK_port.OUTCLR = _BV(SCLK_pin)
|
||||
#else
|
||||
#define SCLK_pin 4 //D4 = PD4
|
||||
#define SCLK_output SCLK_ddr |= _BV(SCLK_pin)
|
||||
#define SCLK_on SCLK_port |= _BV(SCLK_pin)
|
||||
#define SCLK_off SCLK_port &= ~_BV(SCLK_pin)
|
||||
#endif
|
||||
|
||||
// A7105
|
||||
#define A7105_CSN_pin 2 //D2 = PD2
|
||||
#define A7105_CSN_port PORTD
|
||||
#define A7105_CSN_ddr DDRD
|
||||
#define A7105_CSN_output A7105_CSN_ddr |= _BV(A7105_CSN_pin)
|
||||
#define A7105_CSN_on A7105_CSN_port |= _BV(A7105_CSN_pin)
|
||||
#define A7105_CSN_off A7105_CSN_port &= ~_BV(A7105_CSN_pin)
|
||||
|
||||
// CC2500
|
||||
#define CC25_CSN_pin 7 //D7 = PD7
|
||||
#define CC25_CSN_port PORTD
|
||||
#define CC25_CSN_ddr DDRD
|
||||
#define CC25_CSN_output CC25_CSN_ddr |= _BV(CC25_CSN_pin)
|
||||
#define CC25_CSN_on CC25_CSN_port |= _BV(CC25_CSN_pin)
|
||||
#define CC25_CSN_off CC25_CSN_port &= ~_BV(CC25_CSN_pin)
|
||||
|
||||
// NRF24L01
|
||||
#define NRF_CSN_pin 0 //D8 = PB0
|
||||
#define NRF_CSN_port PORTB
|
||||
#define NRF_CSN_ddr DDRB
|
||||
#define NRF_CSN_output NRF_CSN_ddr |= _BV(NRF_CSN_pin)
|
||||
#define NRF_CSN_on NRF_CSN_port |= _BV(NRF_CSN_pin)
|
||||
#define NRF_CSN_off NRF_CSN_port &= ~_BV(NRF_CSN_pin)
|
||||
#define NRF_CE_on
|
||||
#define NRF_CE_off
|
||||
|
||||
// CYRF6936
|
||||
#ifdef ORANGE_TX
|
||||
#define CYRF_CSN_pin 4 //PD4
|
||||
#define CYRF_CSN_port PORTD
|
||||
#define CYRF_CSN_ddr DDRD
|
||||
#define CYRF_CSN_on CYRF_CSN_port.OUTSET = _BV(CYRF_CSN_pin)
|
||||
#define CYRF_CSN_off CYRF_CSN_port.OUTCLR = _BV(CYRF_CSN_pin)
|
||||
|
||||
#define CYRF_RST_pin 0 //PE0
|
||||
#define CYRF_RST_port PORTE
|
||||
#define CYRF_RST_ddr DDRE
|
||||
#define CYRF_RST_HI CYRF_RST_port.OUTSET = _BV(CYRF_RST_pin)
|
||||
#define CYRF_RST_LO CYRF_RST_port.OUTCLR = _BV(CYRF_RST_pin)
|
||||
#else
|
||||
#define CYRF_CSN_pin 1 //D9 = PB1
|
||||
#define CYRF_CSN_port PORTB
|
||||
#define CYRF_CSN_ddr DDRB
|
||||
#define CYRF_CSN_output CYRF_CSN_ddr |= _BV(CYRF_CSN_pin)
|
||||
#define CYRF_CSN_on CYRF_CSN_port |= _BV(CYRF_CSN_pin)
|
||||
#define CYRF_CSN_off CYRF_CSN_port &= ~_BV(CYRF_CSN_pin)
|
||||
|
||||
#define CYRF_RST_pin 5 //A5 = PC5
|
||||
#define CYRF_RST_port PORTC
|
||||
#define CYRF_RST_ddr DDRC
|
||||
#define CYRF_RST_output CYRF_RST_ddr |= _BV(CYRF_RST_pin)
|
||||
#define CYRF_RST_HI CYRF_RST_port |= _BV(CYRF_RST_pin)
|
||||
#define CYRF_RST_LO CYRF_RST_port &= ~_BV(CYRF_RST_pin)
|
||||
#endif
|
||||
|
||||
//RF Switch
|
||||
#ifdef ORANGE_TX
|
||||
#define PE1_on
|
||||
#define PE1_off
|
||||
#define PE2_on
|
||||
#define PE2_off
|
||||
#else
|
||||
#define PE1_pin 1 //A1 = PC1
|
||||
#define PE1_port PORTC
|
||||
#define PE1_ddr DDRC
|
||||
#define PE1_output PE1_ddr |= _BV(PE1_pin)
|
||||
#define PE1_on PE1_port |= _BV(PE1_pin)
|
||||
#define PE1_off PE1_port &= ~_BV(PE1_pin)
|
||||
|
||||
#define PE2_pin 2 //A2 = PC2
|
||||
#define PE2_port PORTC
|
||||
#define PE2_ddr DDRC
|
||||
#define PE2_output PE2_ddr |= _BV(PE2_pin)
|
||||
#define PE2_on PE2_port |= _BV(PE2_pin)
|
||||
#define PE2_off PE2_port &= ~_BV(PE2_pin)
|
||||
#endif
|
||||
|
||||
// LED
|
||||
#ifdef ORANGE_TX
|
||||
#define LED_pin 1 //PD1
|
||||
#define LED_port PORTD
|
||||
#define LED_ddr DDRD
|
||||
#define LED_on LED_port.OUTCLR = _BV(LED_pin)
|
||||
#define LED_off LED_port.OUTSET = _BV(LED_pin)
|
||||
#define LED_toggle LED_port.OUTTGL = _BV(LED_pin)
|
||||
#define LED_output LED_port.DIRSET = _BV(LED_pin)
|
||||
#define IS_LED_on (LED_port.OUT & _BV(LED_pin))
|
||||
#else
|
||||
#define LED_pin 5 //D13 = PB5
|
||||
#define LED_port PORTB
|
||||
#define LED_ddr DDRB
|
||||
#define LED_on LED_port |= _BV(LED_pin)
|
||||
#define LED_off LED_port &= ~_BV(LED_pin)
|
||||
#define LED_toggle LED_port ^= _BV(LED_pin)
|
||||
#define LED_output LED_ddr |= _BV(LED_pin)
|
||||
#define IS_LED_on (LED_port & _BV(LED_pin))
|
||||
#endif
|
||||
|
||||
#define LED2_on
|
||||
#define LED2_off
|
||||
#define LED2_toggle
|
||||
#define LED2_output
|
||||
#define IS_LED2_on 0
|
||||
|
||||
//BIND
|
||||
#ifdef ORANGE_TX
|
||||
#define BIND_pin 2 //PD2
|
||||
#define BIND_port PORTD
|
||||
#define IS_BIND_BUTTON_on ( (BIND_port.IN & _BV(BIND_pin)) == 0x00 )
|
||||
#else
|
||||
#define BIND_pin 5 //D13 = PB5
|
||||
#define BIND_port PORTB
|
||||
#define BIND_ipr PINB
|
||||
#define BIND_ddr DDRB
|
||||
#define BIND_SET_INPUT BIND_ddr &= ~_BV(BIND_pin)
|
||||
#define BIND_SET_OUTPUT BIND_ddr |= _BV(BIND_pin)
|
||||
#define BIND_SET_PULLUP BIND_port |= _BV(BIND_pin)
|
||||
#define IS_BIND_BUTTON_on ( (BIND_ipr & _BV(BIND_pin)) == 0x00 )
|
||||
#endif
|
||||
#else //STM32_BOARD
|
||||
#define BIND_pin PA0
|
||||
#define LED_pin PA1
|
||||
#define LED2_pin PA2
|
||||
//
|
||||
#define PPM_pin PA8 //PPM 5V tolerant
|
||||
//
|
||||
#define S1_pin PA4 //Dial switch pins
|
||||
#define S2_pin PA5
|
||||
#define S3_pin PA6
|
||||
#define S4_pin PA7
|
||||
//
|
||||
#define PE1_pin PB4 //PE1
|
||||
#define PE2_pin PB5 //PE2
|
||||
//CS pins
|
||||
#define CC25_CSN_pin PB6 //CC2500
|
||||
#define NRF_CSN_pin PB7 //NRF24L01
|
||||
#define CYRF_RST_pin PB8 //CYRF RESET
|
||||
#define A7105_CSN_pin PB9 //A7105
|
||||
#define CYRF_CSN_pin PB12 //CYRF CSN
|
||||
#define SPI_CSN_pin PA15
|
||||
//SPI pins
|
||||
#define SCK_pin PB13 //SCK
|
||||
#define SDO_pin PB14 //MISO
|
||||
#define SDI_pin PB15 //MOSI
|
||||
//
|
||||
#define TX_INV_pin PB3
|
||||
#define RX_INV_pin PB1
|
||||
//
|
||||
#define PE1_on digitalWrite(PE1_pin,HIGH)
|
||||
#define PE1_off digitalWrite(PE1_pin,LOW)
|
||||
//
|
||||
#define PE2_on digitalWrite(PE2_pin,HIGH)
|
||||
#define PE2_off digitalWrite(PE2_pin,LOW)
|
||||
|
||||
#define A7105_CSN_on digitalWrite(A7105_CSN_pin,HIGH)
|
||||
#define A7105_CSN_off digitalWrite(A7105_CSN_pin,LOW)
|
||||
|
||||
#define NRF_CE_on
|
||||
#define NRF_CE_off
|
||||
|
||||
#define SCK_on digitalWrite(SCK_pin,HIGH)
|
||||
#define SCK_off digitalWrite(SCK_pin,LOW)
|
||||
|
||||
#define SDI_on digitalWrite(SDI_pin,HIGH)
|
||||
#define SDI_off digitalWrite(SDI_pin,LOW)
|
||||
|
||||
#define SDI_1 (digitalRead(SDI_pin)==HIGH)
|
||||
#define SDI_0 (digitalRead(SDI_pin)==LOW)
|
||||
|
||||
#define CC25_CSN_on digitalWrite(CC25_CSN_pin,HIGH)
|
||||
#define CC25_CSN_off digitalWrite(CC25_CSN_pin,LOW)
|
||||
|
||||
#define NRF_CSN_on digitalWrite(NRF_CSN_pin,HIGH)
|
||||
#define NRF_CSN_off digitalWrite(NRF_CSN_pin,LOW)
|
||||
|
||||
#define CYRF_CSN_on digitalWrite(CYRF_CSN_pin,HIGH)
|
||||
#define CYRF_CSN_off digitalWrite(CYRF_CSN_pin,LOW)
|
||||
|
||||
#define SPI_CSN_on digitalWrite(SPI_CSN_pin,HIGH)
|
||||
#define SPI_CSN_off digitalWrite(SPI_CSN_pin,LOW)
|
||||
|
||||
#define CYRF_RST_HI digitalWrite(CYRF_RST_pin,HIGH) //reset cyrf
|
||||
#define CYRF_RST_LO digitalWrite(CYRF_RST_pin,LOW) //
|
||||
|
||||
#define SDO_1 (digitalRead(SDO_pin)==HIGH)
|
||||
#define SDO_0 (digitalRead(SDO_pin)==LOW)
|
||||
|
||||
#define TX_INV_on digitalWrite(TX_INV_pin,HIGH)
|
||||
#define TX_INV_off digitalWrite(TX_INV_pin,LOW)
|
||||
|
||||
#define RX_INV_on digitalWrite(RX_INV_pin,HIGH)
|
||||
#define RX_INV_off digitalWrite(RX_INV_pin,LOW)
|
||||
|
||||
#define LED_on digitalWrite(LED_pin,HIGH)
|
||||
#define LED_off digitalWrite(LED_pin,LOW)
|
||||
#define LED_toggle digitalWrite(LED_pin ,!digitalRead(LED_pin))
|
||||
#define LED_output pinMode(LED_pin,OUTPUT)
|
||||
#define IS_LED_on ( digitalRead(LED_pin)==HIGH)
|
||||
|
||||
//iRangeX modules have a second LED
|
||||
#define LED2_on digitalWrite(LED2_pin,HIGH)
|
||||
#define LED2_off digitalWrite(LED2_pin,LOW)
|
||||
#define LED2_toggle digitalWrite(LED2_pin ,!digitalRead(LED2_pin))
|
||||
#define LED2_output pinMode(LED2_pin,OUTPUT)
|
||||
#define IS_LED2_on ( digitalRead(LED2_pin)==HIGH)
|
||||
|
||||
#define BIND_SET_INPUT pinMode(BIND_pin,INPUT)
|
||||
#define BIND_SET_PULLUP digitalWrite(BIND_pin,HIGH)
|
||||
#define BIND_SET_OUTPUT pinMode(BIND_pin,OUTPUT)
|
||||
#define IS_BIND_BUTTON_on (digitalRead(BIND_pin)==LOW)
|
||||
|
||||
#ifdef DEBUG_PIN
|
||||
#define DEBUG_PIN_on digitalWrite(SPI_CSN_pin,HIGH)
|
||||
#define DEBUG_PIN_off digitalWrite(SPI_CSN_pin,LOW)
|
||||
#define DEBUG_PIN_toggle digitalWrite(SPI_CSN_pin,!digitalRead(SPI_CSN_pin))
|
||||
#else
|
||||
#define DEBUG_PIN_on
|
||||
#define DEBUG_PIN_off
|
||||
#define DEBUG_PIN_toggle
|
||||
#endif
|
||||
|
||||
#define cli() noInterrupts()
|
||||
#define sei() interrupts()
|
||||
#define delayMilliseconds(x) delay(x)
|
||||
#endif
|
||||
|
||||
//*******************
|
||||
//*** Timer ***
|
||||
//*******************
|
||||
#ifdef ORANGE_TX
|
||||
#define TIFR1 TCC1.INTFLAGS
|
||||
#define OCF1A_bm TC1_CCAIF_bm
|
||||
#define OCR1A TCC1.CCA
|
||||
#define TCNT1 TCC1.CNT
|
||||
#define UDR0 USARTC0.DATA
|
||||
#define OCF1B_bm TC1_CCBIF_bm
|
||||
#define OCR1B TCC1.CCB
|
||||
#define TIMSK1 TCC1.INTCTRLB
|
||||
#define SET_TIMSK1_OCIE1B TIMSK1 = (TIMSK1 & 0xF3) | 0x04
|
||||
#define CLR_TIMSK1_OCIE1B TIMSK1 &= 0xF3
|
||||
#else
|
||||
#ifdef STM32_BOARD
|
||||
#define OCR1A TIMER2_BASE->CCR1
|
||||
#define TCNT1 TIMER2_BASE->CNT
|
||||
#define TIFR1 TIMER2_BASE->SR
|
||||
#define OCF1A_bm TIMER_SR_CC1IF
|
||||
#define UDR0 USART2_BASE->DR
|
||||
#define UCSR0B USART2_BASE->CR1
|
||||
#define RXCIE0 USART_CR1_RXNEIE_BIT
|
||||
#define TXCIE0 USART_CR1_TXEIE_BIT
|
||||
//#define TIFR1 TIMER2_BASE->SR
|
||||
#else
|
||||
#define OCF1A_bm _BV(OCF1A)
|
||||
#define OCF1B_bm _BV(OCF1B)
|
||||
#define SET_TIMSK1_OCIE1B TIMSK1 |= _BV(OCIE1B)
|
||||
#define CLR_TIMSK1_OCIE1B TIMSK1 &=~_BV(OCIE1B)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//*******************
|
||||
//*** EEPROM ***
|
||||
//*******************
|
||||
#ifdef STM32_BOARD
|
||||
#define EE_ADDR uint16
|
||||
#define eeprom_write_byte EEPROM.write
|
||||
#define eeprom_read_byte EEPROM.read
|
||||
#else
|
||||
#define EE_ADDR uint8_t*
|
||||
#endif
|
||||
408
Multiprotocol/Q303_nrf24l01.ino
Normal file
408
Multiprotocol/Q303_nrf24l01.ino
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
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(Q303_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define Q303_BIND_COUNT 1500
|
||||
#define Q303_INITIAL_WAIT 500
|
||||
#define Q303_RF_BIND_CHANNEL 0x02
|
||||
|
||||
#define Q303_BTN_TAKEOFF 1
|
||||
#define Q303_BTN_DESCEND 2
|
||||
#define Q303_BTN_SNAPSHOT 4
|
||||
#define Q303_BTN_VIDEO 8
|
||||
#define Q303_BTN_RTH 16
|
||||
#define Q303_BTN_VTX 32
|
||||
|
||||
static uint8_t __attribute__((unused)) cx10wd_getButtons()
|
||||
{
|
||||
#define CX10WD_FLAG_LAND 0x20
|
||||
#define CX10D_FLAG_LAND 0x80
|
||||
#define CX10WD_FLAG_TAKEOFF 0x40
|
||||
|
||||
static uint8_t BTN_state;
|
||||
static uint8_t command;
|
||||
|
||||
// startup
|
||||
if(packet_count < 50)
|
||||
{
|
||||
BTN_state = 0;
|
||||
command = 0;
|
||||
packet_count++;
|
||||
}
|
||||
// auto land
|
||||
else if((Channel_data[CH5]<CHANNEL_MIN_COMMAND) && !(BTN_state & Q303_BTN_DESCEND))
|
||||
{
|
||||
BTN_state |= Q303_BTN_DESCEND;
|
||||
BTN_state &= ~Q303_BTN_TAKEOFF;
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case CX10WD:
|
||||
command ^= CX10WD_FLAG_LAND;
|
||||
break;
|
||||
case CX10D:
|
||||
command ^= CX10D_FLAG_LAND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// auto take off
|
||||
else if(CH5_SW && !(BTN_state & Q303_BTN_TAKEOFF))
|
||||
{
|
||||
BTN_state |= Q303_BTN_TAKEOFF;
|
||||
BTN_state &= ~Q303_BTN_DESCEND;
|
||||
command ^= CX10WD_FLAG_TAKEOFF;
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) cx35_lastButton()
|
||||
{
|
||||
#define CX35_CMD_RATE 0x09
|
||||
#define CX35_CMD_TAKEOFF 0x0e
|
||||
#define CX35_CMD_DESCEND 0x0f
|
||||
#define CX35_CMD_SNAPSHOT 0x0b
|
||||
#define CX35_CMD_VIDEO 0x0c
|
||||
#define CX35_CMD_RTH 0x11
|
||||
#define CX35_CMD_VTX 0x10
|
||||
|
||||
static uint8_t BTN_state;
|
||||
static uint8_t command;
|
||||
// simulate 2 keypress on rate button just after bind
|
||||
if(packet_count < 50)
|
||||
{
|
||||
BTN_state = 0;
|
||||
packet_count++;
|
||||
command = 0x00; // startup
|
||||
}
|
||||
else if(packet_count < 150)
|
||||
{
|
||||
packet_count++;
|
||||
command = CX35_CMD_RATE; // 1st keypress
|
||||
}
|
||||
else if(packet_count < 250)
|
||||
{
|
||||
packet_count++;
|
||||
command |= 0x20; // 2nd keypress
|
||||
}
|
||||
// descend
|
||||
else if(!(GET_FLAG(CH5_SW, 1)) && !(BTN_state & Q303_BTN_DESCEND))
|
||||
{
|
||||
BTN_state |= Q303_BTN_DESCEND;
|
||||
BTN_state &= ~Q303_BTN_TAKEOFF;
|
||||
command = CX35_CMD_DESCEND;
|
||||
}
|
||||
// take off
|
||||
else if(GET_FLAG(CH5_SW,1) && !(BTN_state & Q303_BTN_TAKEOFF))
|
||||
{
|
||||
BTN_state |= Q303_BTN_TAKEOFF;
|
||||
BTN_state &= ~Q303_BTN_DESCEND;
|
||||
command = CX35_CMD_TAKEOFF;
|
||||
}
|
||||
// RTH
|
||||
else if(GET_FLAG(CH10_SW,1) && !(BTN_state & Q303_BTN_RTH))
|
||||
{
|
||||
BTN_state |= Q303_BTN_RTH;
|
||||
if(command == CX35_CMD_RTH)
|
||||
command |= 0x20;
|
||||
else
|
||||
command = CX35_CMD_RTH;
|
||||
}
|
||||
else if(!(GET_FLAG(CH10_SW,1)) && (BTN_state & Q303_BTN_RTH))
|
||||
{
|
||||
BTN_state &= ~Q303_BTN_RTH;
|
||||
if(command == CX35_CMD_RTH)
|
||||
command |= 0x20;
|
||||
else
|
||||
command = CX35_CMD_RTH;
|
||||
}
|
||||
// video
|
||||
else if(GET_FLAG(CH8_SW,1) && !(BTN_state & Q303_BTN_VIDEO))
|
||||
{
|
||||
BTN_state |= Q303_BTN_VIDEO;
|
||||
if(command == CX35_CMD_VIDEO)
|
||||
command |= 0x20;
|
||||
else
|
||||
command = CX35_CMD_VIDEO;
|
||||
}
|
||||
else if(!(GET_FLAG(CH8_SW,1)) && (BTN_state & Q303_BTN_VIDEO))
|
||||
{
|
||||
BTN_state &= ~Q303_BTN_VIDEO;
|
||||
if(command == CX35_CMD_VIDEO)
|
||||
command |= 0x20;
|
||||
else
|
||||
command = CX35_CMD_VIDEO;
|
||||
}
|
||||
// snapshot
|
||||
else if(GET_FLAG(CH7_SW,1) && !(BTN_state & Q303_BTN_SNAPSHOT))
|
||||
{
|
||||
BTN_state |= Q303_BTN_SNAPSHOT;
|
||||
if(command == CX35_CMD_SNAPSHOT)
|
||||
command |= 0x20;
|
||||
else
|
||||
command = CX35_CMD_SNAPSHOT;
|
||||
}
|
||||
// vtx channel
|
||||
else if(GET_FLAG(CH6_SW,1) && !(BTN_state & Q303_BTN_VTX))
|
||||
{
|
||||
BTN_state |= Q303_BTN_VTX;
|
||||
if(command == CX35_CMD_VTX)
|
||||
command |= 0x20;
|
||||
else
|
||||
command = CX35_CMD_VTX;
|
||||
}
|
||||
|
||||
if(!(GET_FLAG(CH7_SW,1)))
|
||||
BTN_state &= ~Q303_BTN_SNAPSHOT;
|
||||
if(!(GET_FLAG(CH6_SW,1)))
|
||||
BTN_state &= ~Q303_BTN_VTX;
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) Q303_send_packet(uint8_t bind)
|
||||
{
|
||||
uint16_t aileron, elevator, throttle, rudder, slider;
|
||||
if(bind)
|
||||
{
|
||||
packet[0] = 0xaa;
|
||||
memcpy(&packet[1], rx_tx_addr + 1, 4);
|
||||
memset(&packet[5], 0, packet_length-5);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0] = 0x55;
|
||||
// sticks
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case Q303:
|
||||
case CX35:
|
||||
aileron = convert_channel_16b_limit(AILERON, 0, 1000);
|
||||
elevator = convert_channel_16b_limit(ELEVATOR, 1000, 0);
|
||||
throttle = convert_channel_16b_limit(THROTTLE, 0, 1000);
|
||||
rudder = convert_channel_16b_limit(RUDDER, 1000, 0);
|
||||
if(sub_protocol == CX35)
|
||||
aileron = 1000 - aileron;
|
||||
packet[1] = aileron >> 2; // 8 bits
|
||||
packet[2] = (aileron & 0x03) << 6 // 2 bits
|
||||
| (elevator >> 4); // 6 bits
|
||||
packet[3] = (elevator & 0x0f) << 4 // 4 bits
|
||||
| (throttle >> 6); // 4 bits
|
||||
packet[4] = (throttle & 0x3f) << 2 // 6 bits
|
||||
| (rudder >> 8); // 2 bits
|
||||
packet[5] = rudder & 0xff; // 8 bits
|
||||
break;
|
||||
case CX10D:
|
||||
case CX10WD:
|
||||
aileron = convert_channel_16b_limit(AILERON, 2000, 1000);
|
||||
elevator = convert_channel_16b_limit(ELEVATOR, 2000, 1000);
|
||||
throttle = convert_channel_16b_limit(THROTTLE, 1000, 2000);
|
||||
rudder = convert_channel_16b_limit(RUDDER, 1000, 2000);
|
||||
packet[1] = aileron & 0xff;
|
||||
packet[2] = aileron >> 8;
|
||||
packet[3] = elevator & 0xff;
|
||||
packet[4] = elevator >> 8;
|
||||
packet[5] = throttle & 0xff;
|
||||
packet[6] = throttle >> 8;
|
||||
packet[7] = rudder & 0xff;
|
||||
packet[8] = rudder >> 8;
|
||||
break;
|
||||
}
|
||||
|
||||
// buttons
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case Q303:
|
||||
packet[6] = 0x10; // trim(s) ?
|
||||
packet[7] = 0x10; // trim(s) ?
|
||||
packet[8] = 0x03 // high rate (0-3)
|
||||
| GET_FLAG(CH5_SW, 0x40)
|
||||
| GET_FLAG(CH10_SW, 0x80);
|
||||
packet[9] = 0x40 // always set
|
||||
| GET_FLAG(CH9_SW,0x08)
|
||||
| GET_FLAG(CH6_SW, 0x80)
|
||||
| GET_FLAG(CH7_SW,0x10)
|
||||
| GET_FLAG(CH8_SW, 0x01);
|
||||
if(Channel_data[CH11] < CHANNEL_MIN_COMMAND)
|
||||
packet[9] |= 0x04; // gimbal down
|
||||
else if(CH11_SW)
|
||||
packet[9] |= 0x20; // gimbal up
|
||||
break;
|
||||
|
||||
case CX35:
|
||||
slider = convert_channel_16b_limit(CH11, 731, 342);
|
||||
packet[6] = slider >> 2;
|
||||
packet[7] = ((slider & 3) << 6)
|
||||
| 0x3e; // ?? 6 bit left (always 111110 ?)
|
||||
packet[8] = 0x80; // always set
|
||||
packet[9] = cx35_lastButton();
|
||||
break;
|
||||
|
||||
case CX10D:
|
||||
packet[8] |= GET_FLAG(CH6_SW, 0x10);
|
||||
packet[9] = 0x02; // rate (0-2)
|
||||
packet[10]= cx10wd_getButtons(); // auto land / take off management
|
||||
break;
|
||||
|
||||
case CX10WD:
|
||||
packet[8] |= GET_FLAG(CH6_SW, 0x10);
|
||||
packet[9] = 0x02 // rate (0-2)
|
||||
| cx10wd_getButtons(); // auto land / take off management
|
||||
packet[10] = 0x00;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Power on, TX mode, CRC enabled
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? Q303_RF_BIND_CHANNEL : hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no %= rf_ch_num;
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
XN297_WritePayload(packet, packet_length);
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) Q303_init()
|
||||
{
|
||||
const uint8_t bind_address[] = {0xcc,0xcc,0xcc,0xcc,0xcc};
|
||||
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case CX35:
|
||||
case CX10D:
|
||||
case CX10WD:
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M);
|
||||
break;
|
||||
case Q303:
|
||||
XN297_SetScrambledMode(XN297_UNSCRAMBLED);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K);
|
||||
break;
|
||||
}
|
||||
XN297_SetTXAddr(bind_address, 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);
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
|
||||
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); // Set feature bits on
|
||||
NRF24L01_Activate(0x73);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) Q303_initialize_txid()
|
||||
{
|
||||
uint8_t i,offset;
|
||||
|
||||
rx_tx_addr[0] = 0x55;
|
||||
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case Q303:
|
||||
case CX10WD:
|
||||
offset = rx_tx_addr[1] & 3;
|
||||
for(i=0; i<4; i++)
|
||||
hopping_frequency[i] = 0x46 + i*2 + offset;
|
||||
break;
|
||||
case CX35:
|
||||
case CX10D:
|
||||
// not thoroughly figured out rx_tx_addr/channels mapping yet
|
||||
// for now 5 msb of rx_tx_addr[1] must be cleared
|
||||
rx_tx_addr[1] &= 7;
|
||||
offset = 6+(rx_tx_addr[1]*3);
|
||||
hopping_frequency[0] = 0x14; // works only if rx_tx_addr[1] < 8
|
||||
for(i=1; i<16; i++)
|
||||
{
|
||||
hopping_frequency[i] = hopping_frequency[i-1] + offset;
|
||||
if(hopping_frequency[i] > 0x41)
|
||||
hopping_frequency[i] -= 0x33;
|
||||
if(hopping_frequency[i] < 0x14)
|
||||
hopping_frequency[i] += offset;
|
||||
}
|
||||
// CX35 tx uses only 4 of those channels (#0,3,6,9)
|
||||
if(sub_protocol == CX35)
|
||||
for(i=0; i<4; i++)
|
||||
hopping_frequency[i] = hopping_frequency[i*3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t Q303_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
Q303_send_packet(0);
|
||||
else
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
packet_count = 0;
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Q303_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initQ303()
|
||||
{
|
||||
Q303_initialize_txid();
|
||||
Q303_init();
|
||||
bind_counter = Q303_BIND_COUNT;
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case Q303:
|
||||
packet_period = 1500;
|
||||
packet_length = 10;
|
||||
rf_ch_num = 4;
|
||||
break;
|
||||
case CX35:
|
||||
packet_period = 3000;
|
||||
packet_length = 10;
|
||||
rf_ch_num = 4;
|
||||
break;
|
||||
case CX10D:
|
||||
packet_period = 3000;
|
||||
packet_length = 11;
|
||||
rf_ch_num = 16;
|
||||
break;
|
||||
case CX10WD:
|
||||
packet_period = 3000;
|
||||
packet_length = 11;
|
||||
rf_ch_num = 4;
|
||||
break;
|
||||
}
|
||||
hopping_frequency_no = 0;
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
return Q303_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
243
Multiprotocol/Redpine_cc2500.ino
Normal file
243
Multiprotocol/Redpine_cc2500.ino
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
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(REDPINE_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
#define REDPINE_LOOPTIME_FAST 25 //2.5ms
|
||||
#define REDPINE_LOOPTIME_SLOW 6 //6ms
|
||||
|
||||
#define REDPINE_BIND 1000
|
||||
#define REDPINE_PACKET_SIZE 11
|
||||
#define REDPINE_FEC false // from cc2500 datasheet: The convolutional coder is a rate 1/2 code with a constraint length of m=4
|
||||
#define REDPINE_NUM_HOPS 50
|
||||
|
||||
static void REDPINE_set_channel(uint8_t ch)
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[ch]);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[ch]);
|
||||
}
|
||||
|
||||
static void REDPINE_build_bind_packet()
|
||||
{
|
||||
memset(&packet[0], 0, REDPINE_PACKET_SIZE);
|
||||
|
||||
packet[0] = REDPINE_PACKET_SIZE - 1;
|
||||
packet[1] = 0x03;
|
||||
packet[2] = 0x01;
|
||||
packet[3] = rx_tx_addr[2];
|
||||
packet[4] = rx_tx_addr[3]; // Use RX_Num
|
||||
uint16_t idx = ((REDPINE_BIND - bind_counter) % 10) * 5;
|
||||
packet[5] = idx;
|
||||
packet[6] = hopping_frequency[idx++];
|
||||
packet[7] = hopping_frequency[idx++];
|
||||
packet[8] = hopping_frequency[idx++];
|
||||
packet[9] = hopping_frequency[idx++];
|
||||
packet[10] = hopping_frequency[idx++];
|
||||
// packet[11] = 0x02;
|
||||
// packet[12] = RXNUM;
|
||||
}
|
||||
|
||||
static uint16_t Redpine_Scale(uint8_t chan)
|
||||
{
|
||||
uint16_t chan_val=Channel_data[chan]; // -125%..+125% <=> 0..2047
|
||||
if (chan_val > 2046) chan_val = 2046;
|
||||
else if (chan_val < 10) chan_val = 10;
|
||||
return chan_val;
|
||||
}
|
||||
|
||||
|
||||
static void REDPINE_data_frame() {
|
||||
uint16_t chan[4];
|
||||
|
||||
memset(&packet[0], 0, REDPINE_PACKET_SIZE);
|
||||
|
||||
packet[0] = REDPINE_PACKET_SIZE - 1;
|
||||
packet[1] = rx_tx_addr[2];
|
||||
packet[2] = rx_tx_addr[3]; // Use RX_Num
|
||||
|
||||
chan[0] = Redpine_Scale(0);
|
||||
chan[1] = Redpine_Scale(1);
|
||||
chan[2] = Redpine_Scale(2);
|
||||
chan[3] = Redpine_Scale(3);
|
||||
|
||||
packet[3] = chan[0];
|
||||
packet[4] = (((chan[0] >> 8) & 0x07) | (chan[1] << 4)) | GET_FLAG(CH5_SW, 0x08);
|
||||
packet[5] = ((chan[1] >> 4) & 0x7F) | GET_FLAG(CH6_SW, 0x80);
|
||||
packet[6] = chan[2];
|
||||
packet[7] = (((chan[2] >> 8) & 0x07) | (chan[3] << 4)) | GET_FLAG(CH7_SW, 0x08);
|
||||
packet[8] = ((chan[3] >> 4) & 0x7F) | GET_FLAG(CH8_SW, 0x80);
|
||||
packet[9] = GET_FLAG(CH9_SW, 0x01)
|
||||
| GET_FLAG(CH10_SW, 0x02)
|
||||
| GET_FLAG(CH11_SW, 0x04)
|
||||
| GET_FLAG(CH12_SW, 0x08)
|
||||
| GET_FLAG(CH13_SW, 0x10)
|
||||
| GET_FLAG(CH14_SW, 0x20)
|
||||
| GET_FLAG(CH15_SW, 0x40)
|
||||
| GET_FLAG(CH16_SW, 0x80);
|
||||
|
||||
if (sub_protocol==0)
|
||||
packet[10] = REDPINE_LOOPTIME_FAST;
|
||||
else
|
||||
packet[10] = REDPINE_LOOPTIME_SLOW;
|
||||
}
|
||||
|
||||
static uint16_t ReadREDPINE()
|
||||
{
|
||||
if ( prev_option != option )
|
||||
{ // Frequency adjust
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
prev_option = option ;
|
||||
}
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
if(bind_counter == REDPINE_BIND)
|
||||
REDPINE_init(0);
|
||||
if(bind_counter == REDPINE_BIND/2)
|
||||
REDPINE_init(1);
|
||||
REDPINE_set_channel(49);
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
REDPINE_build_bind_packet();
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteData(packet, REDPINE_PACKET_SIZE);
|
||||
if(--bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
REDPINE_init(sub_protocol);
|
||||
}
|
||||
return 9000;
|
||||
}
|
||||
else
|
||||
{
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
REDPINE_set_channel(hopping_frequency_no);
|
||||
CC2500_SetPower();
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
REDPINE_data_frame();
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
hopping_frequency_no = (hopping_frequency_no + 1) % 49;
|
||||
CC2500_WriteData(packet, REDPINE_PACKET_SIZE);
|
||||
if (sub_protocol==0)
|
||||
return REDPINE_LOOPTIME_FAST*100;
|
||||
else
|
||||
return REDPINE_LOOPTIME_SLOW*1000;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// register, fast 250k, slow
|
||||
static const uint8_t REDPINE_init_data[][3] = {
|
||||
{CC2500_00_IOCFG2, 0x06, 0x06},
|
||||
{CC2500_02_IOCFG0, 0x06, 0x06},
|
||||
{CC2500_03_FIFOTHR, 0x07, 0x07},
|
||||
{CC2500_07_PKTCTRL1, 0x04, 0x04},
|
||||
{CC2500_08_PKTCTRL0, 0x05, 0x05},
|
||||
{CC2500_09_ADDR, 0x00, 0x00},
|
||||
{CC2500_0B_FSCTRL1, 0x0A, 0x0A},
|
||||
{CC2500_0C_FSCTRL0, 0x00, 0x00},
|
||||
{CC2500_0D_FREQ2, 0x5D, 0x5c},
|
||||
{CC2500_0E_FREQ1, 0x93, 0x76},
|
||||
{CC2500_0F_FREQ0, 0xB1, 0x27},
|
||||
{CC2500_10_MDMCFG4, 0x2D, 0x7B},
|
||||
{CC2500_11_MDMCFG3, 0x3B, 0x61},
|
||||
{CC2500_12_MDMCFG2, 0x73, 0x13},
|
||||
#ifdef REDPINE_FEC
|
||||
{CC2500_13_MDMCFG1, 0xA3, 0xA3},
|
||||
#else
|
||||
{CC2500_13_MDMCFG1, 0x23, 0x23},
|
||||
#endif
|
||||
{CC2500_14_MDMCFG0, 0x56, 0x7a}, // Chan space
|
||||
{CC2500_15_DEVIATN, 0x00, 0x51},
|
||||
{CC2500_17_MCSM1, 0x0c, 0x0c},
|
||||
{CC2500_18_MCSM0, 0x08, 0x08}, //??? 0x18, 0x18},
|
||||
{CC2500_19_FOCCFG, 0x1D, 0x16},
|
||||
{CC2500_1A_BSCFG, 0x1C, 0x6c},
|
||||
{CC2500_1B_AGCCTRL2, 0xC7, 0x43},
|
||||
{CC2500_1C_AGCCTRL1, 0x00, 0x40},
|
||||
{CC2500_1D_AGCCTRL0, 0xB0, 0x91},
|
||||
{CC2500_21_FREND1, 0xB6, 0x56},
|
||||
{CC2500_22_FREND0, 0x10, 0x10},
|
||||
{CC2500_23_FSCAL3, 0xEA, 0xA9},
|
||||
{CC2500_24_FSCAL2, 0x0A, 0x0A},
|
||||
{CC2500_25_FSCAL1, 0x00, 0x00},
|
||||
{CC2500_26_FSCAL0, 0x11, 0x11},
|
||||
{CC2500_29_FSTEST, 0x59, 0x59},
|
||||
{CC2500_2C_TEST2, 0x88, 0x88},
|
||||
{CC2500_2D_TEST1, 0x31, 0x31},
|
||||
{CC2500_2E_TEST0, 0x0B, 0x0B},
|
||||
{CC2500_3E_PATABLE, 0xff, 0xff}
|
||||
};
|
||||
|
||||
static void REDPINE_init(uint8_t format)
|
||||
{
|
||||
CC2500_Reset();
|
||||
|
||||
CC2500_WriteReg(CC2500_06_PKTLEN, REDPINE_PACKET_SIZE);
|
||||
|
||||
for (uint8_t i=0; i < ((sizeof REDPINE_init_data) / (sizeof REDPINE_init_data[0])); i++)
|
||||
CC2500_WriteReg(REDPINE_init_data[i][0], REDPINE_init_data[i][format+1]);
|
||||
|
||||
prev_option = option;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
|
||||
// calibrate hop channels
|
||||
for (uint8_t c = 0; c < REDPINE_NUM_HOPS; c++)
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[c]);
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);
|
||||
calData[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t initREDPINE()
|
||||
{
|
||||
hopping_frequency_no = 0;
|
||||
// Used from kn_nrf24l01.c : kn_calculate_freqency_hopping_channels
|
||||
uint32_t idx = 0;
|
||||
uint32_t rnd = MProtocol_id;
|
||||
#define REDPINE_MAX_RF_CHANNEL 255
|
||||
hopping_frequency[idx++] = 1;
|
||||
while (idx < REDPINE_NUM_HOPS-1)
|
||||
{
|
||||
uint32_t i;
|
||||
rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
|
||||
// Drop least-significant byte for better randomization. Start from 1
|
||||
uint8_t next_ch = (rnd >> 8) % REDPINE_MAX_RF_CHANNEL + 1;
|
||||
// Check that it's not duplicate nor adjacent nor channel 0 or 1
|
||||
for (i = 0; i < idx; i++)
|
||||
{
|
||||
uint8_t ch = hopping_frequency[i];
|
||||
if ((ch <= next_ch + 1) && (ch >= next_ch - 1) && (ch > 1))
|
||||
break;
|
||||
}
|
||||
if (i != idx)
|
||||
continue;
|
||||
hopping_frequency[idx++] = next_ch;
|
||||
}
|
||||
hopping_frequency[49] = 0; // Last channel is the bind channel at hop 0
|
||||
|
||||
bind_counter=REDPINE_BIND;
|
||||
REDPINE_init(sub_protocol);
|
||||
CC2500_SetTxRxMode(TX_EN); // enable PA
|
||||
return 10000;
|
||||
}
|
||||
#endif
|
||||
300
Multiprotocol/SFHSS_cc2500.ino
Normal file
300
Multiprotocol/SFHSS_cc2500.ino
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with main deviation/sfhss_cc2500.c dated 2016-03-23
|
||||
|
||||
#if defined(SFHSS_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
#define SFHSS_COARSE 0
|
||||
|
||||
#define SFHSS_PACKET_LEN 13
|
||||
#define SFHSS_TX_ID_LEN 2
|
||||
|
||||
uint8_t fhss_code=0; // 0-27
|
||||
|
||||
enum {
|
||||
SFHSS_START = 0x00,
|
||||
SFHSS_CAL = 0x01,
|
||||
SFHSS_DATA1 = 0x02,
|
||||
SFHSS_DATA2 = 0x03,
|
||||
SFHSS_TUNE = 0x04
|
||||
};
|
||||
|
||||
#define SFHSS_FREQ0_VAL 0xC4
|
||||
|
||||
// Some important initialization parameters, all others are either default,
|
||||
// or not important in the context of transmitter
|
||||
// IOCFG2 2F - GDO2_INV=0 GDO2_CFG=2F - HW0
|
||||
// IOCFG1 2E - GDO1_INV=0 GDO1_CFG=2E - High Impedance
|
||||
// IOCFG0 2F - GDO0 same as GDO2, TEMP_SENSOR_ENABLE=off
|
||||
// FIFOTHR 07 - 33 decimal TX threshold
|
||||
// SYNC1 D3
|
||||
// SYNC0 91
|
||||
// PKTLEN 0D - Packet length, 0D bytes
|
||||
// PKTCTRL1 04 - APPEND_STATUS on, all other are receive parameters - irrelevant
|
||||
// PKTCTRL0 0C - No whitening, use FIFO, CC2400 compatibility on, use CRC, fixed packet length
|
||||
// ADDR 29
|
||||
// CHANNR 10
|
||||
// FSCTRL1 06 - IF 152343.75Hz, see page 65
|
||||
// FSCTRL0 00 - zero freq offset
|
||||
// FREQ2 5C - synthesizer frequency 2399999633Hz for 26MHz crystal, ibid
|
||||
// FREQ1 4E
|
||||
// FREQ0 C4
|
||||
// MDMCFG4 7C - CHANBW_E - 01, CHANBW_M - 03, DRATE_E - 0C. Filter bandwidth = 232142Hz
|
||||
// MDMCFG3 43 - DRATE_M - 43. Data rate = 128143bps
|
||||
// MDMCFG2 83 - disable DC blocking, 2-FSK, no Manchester code, 15/16 sync bits detected (irrelevant for TX)
|
||||
// MDMCFG1 23 - no FEC, 4 preamble bytes, CHANSPC_E - 03
|
||||
// MDMCFG0 3B - CHANSPC_M - 3B. Channel spacing = 249938Hz (each 6th channel used, resulting in spacing of 1499628Hz)
|
||||
// DEVIATN 44 - DEVIATION_E - 04, DEVIATION_M - 04. Deviation = 38085.9Hz
|
||||
// MCSM2 07 - receive parameters, default, irrelevant
|
||||
// MCSM1 0C - no CCA (transmit always), when packet received stay in RX, when sent go to IDLE
|
||||
// MCSM0 08 - no autocalibration, PO_TIMEOUT - 64, no pin radio control, no forcing XTAL to stay in SLEEP
|
||||
// FOCCFG 1D - not interesting, Frequency Offset Compensation
|
||||
// FREND0 10 - PA_POWER = 0
|
||||
const PROGMEM uint8_t SFHSS_init_values[] = {
|
||||
/* 00 */ 0x2F, 0x2E, 0x2F, 0x07, 0xD3, 0x91, 0x0D, 0x04,
|
||||
/* 08 */ 0x0C, 0x29, 0x10, 0x06, 0x00, 0x5C, 0x4E, SFHSS_FREQ0_VAL + SFHSS_COARSE,
|
||||
/* 10 */ 0x7C, 0x43, 0x83, 0x23, 0x3B, 0x44, 0x07, 0x0C,
|
||||
/* 18 */ 0x08, 0x1D, 0x1C, 0x43, 0x40, 0x91, 0x57, 0x6B,
|
||||
/* 20 */ 0xF8, 0xB6, 0x10, 0xEA, 0x0A, 0x11, 0x11
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) SFHSS_rf_init()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
|
||||
for (uint8_t i = 0; i < 39; ++i)
|
||||
CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i]));
|
||||
|
||||
prev_option = option;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SFHSS_tune_chan()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num*6+16);
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SFHSS_tune_chan_fast()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num*6+16);
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[rf_ch_num]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SFHSS_tune_freq()
|
||||
{
|
||||
if ( prev_option != option )
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
CC2500_WriteReg(CC2500_0F_FREQ0, SFHSS_FREQ0_VAL + SFHSS_COARSE);
|
||||
prev_option = option ;
|
||||
phase = SFHSS_START; // Restart the tune process if option is changed to get good tuned values
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SFHSS_calc_next_chan()
|
||||
{
|
||||
rf_ch_num += fhss_code + 2;
|
||||
if (rf_ch_num > 29)
|
||||
{
|
||||
if (rf_ch_num < 31)
|
||||
rf_ch_num += fhss_code + 2;
|
||||
rf_ch_num -= 31;
|
||||
}
|
||||
}
|
||||
|
||||
// Channel values are 12-bit values between 1020 and 2020, 1520 is the middle.
|
||||
// Futaba @140% is 2070...1520...970
|
||||
// Values grow down and to the right.
|
||||
static void __attribute__((unused)) SFHSS_build_data_packet()
|
||||
{
|
||||
uint16_t ch[4];
|
||||
// command.bit0 is the packet number indicator: =0 -> SFHSS_DATA1, =1 -> SFHSS_DATA2
|
||||
// command.bit1 is unknown but seems to be linked to the payload[0].bit0 but more dumps are needed: payload[0]=0x82 -> =0, payload[0]=0x81 -> =1
|
||||
// command.bit2 is the failsafe transmission indicator: =0 -> normal data, =1->failsafe data
|
||||
// command.bit3 is the channels indicator: =0 -> CH1-4, =1 -> CH5-8
|
||||
|
||||
//Coding below matches the Futaba T8J transmission scheme DATA1->CH1-4, DATA2->CH5-8, DATA1->CH5-8, DATA2->CH1-4,...
|
||||
// XK, T10J and TM-FH are different with a classic DATA1->CH1-4, DATA2->CH5-8,...
|
||||
//Failsafe is sent twice every couple of seconds (unknown but >5s)
|
||||
|
||||
uint8_t command= (phase == SFHSS_DATA1) ? 0 : 1; // Building packet for Data1 or Data2
|
||||
counter+=command;
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if( (counter&0x3FC) == 0x3FC && IS_FAILSAFE_VALUES_on)
|
||||
{ // Transmit failsafe data twice every 7s
|
||||
if( ((counter&1)^(command&1)) == 0 )
|
||||
command|=0x04; // Failsafe
|
||||
}
|
||||
else
|
||||
#endif
|
||||
command|=0x02; // Assuming packet[0] == 0x81
|
||||
counter&=0x3FF; // Reset failsafe counter
|
||||
if(counter&1) command|=0x08; // Transmit lower and upper channels twice in a row
|
||||
|
||||
uint8_t ch_offset = (command&0x08) >> 1; // CH1..CH4 or CH5..CH8
|
||||
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(command&0x04)
|
||||
{ //Failsafe data are:
|
||||
// 0 to 1023 -> no output on channel
|
||||
// 1024-2047 -> hold output on channel
|
||||
// 2048-4095 -> channel_output=(data&0x3FF)*5/4+880 in µs
|
||||
// Notes:
|
||||
// 2048-2559 -> does not look valid since it only covers the range from 1520µs to 2160µs
|
||||
// 2560-3583 -> valid for any channel values from 880µs to 2160µs
|
||||
// 3584-4095 -> looks to be used for the throttle channel with values ranging from 880µs to 1520µs
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
{
|
||||
ch[i]=Failsafe_data[CH_AETR[ch_offset+i]];
|
||||
if(ch[i]==FAILSAFE_CHANNEL_HOLD)
|
||||
ch[i]=1024;
|
||||
else if(ch[i]==FAILSAFE_CHANNEL_NOPULSES)
|
||||
ch[i]=0;
|
||||
else
|
||||
{ //Use channel value
|
||||
ch[i]=(ch[i]>>1)+2560;
|
||||
if(CH_AETR[ch_offset+i]==THROTTLE && ch[i]<3072) // Throttle
|
||||
ch[i]+=1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{ //Normal data
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
ch[i] = convert_channel_16b_nolimit(CH_AETR[ch_offset+i],2020,1020);
|
||||
}
|
||||
|
||||
|
||||
// XK [0]=0x81 [3]=0x00 [4]=0x00
|
||||
// T8J [0]=0x81 [3]=0x42 [4]=0x07
|
||||
// T10J [0]=0x81 [3]=0x0F [4]=0x09
|
||||
// TM-FH [0]=0x82 [3]=0x9A [4]=0x06
|
||||
packet[0] = 0x81; // can be 80 or 81 for Orange, only 81 for XK
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
packet[3] = 0x00; // unknown but prevents some receivers to bind if not 0
|
||||
packet[4] = 0x00; // unknown but prevents some receivers to bind if not 0
|
||||
packet[5] = (rf_ch_num << 3) | ((ch[0] >> 9) & 0x07);
|
||||
packet[6] = (ch[0] >> 1);
|
||||
packet[7] = (ch[0] << 7) | ((ch[1] >> 5) & 0x7F );
|
||||
packet[8] = (ch[1] << 3) | ((ch[2] >> 9) & 0x07 );
|
||||
packet[9] = (ch[2] >> 1);
|
||||
packet[10] = (ch[2] << 7) | ((ch[3] >> 5) & 0x7F );
|
||||
packet[11] = (ch[3] << 3) | ((fhss_code >> 2) & 0x07 );
|
||||
packet[12] = (fhss_code << 6) | command;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SFHSS_send_packet()
|
||||
{
|
||||
CC2500_WriteData(packet, SFHSS_PACKET_LEN);
|
||||
}
|
||||
|
||||
uint16_t ReadSFHSS()
|
||||
{
|
||||
switch(phase)
|
||||
{
|
||||
case SFHSS_START:
|
||||
rf_ch_num = 0;
|
||||
SFHSS_tune_chan();
|
||||
phase = SFHSS_CAL;
|
||||
return 2000;
|
||||
case SFHSS_CAL:
|
||||
calData[rf_ch_num]=CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
if (++rf_ch_num < 30)
|
||||
SFHSS_tune_chan();
|
||||
else
|
||||
{
|
||||
rf_ch_num = 0;
|
||||
counter = 0;
|
||||
phase = SFHSS_DATA1;
|
||||
}
|
||||
return 2000;
|
||||
|
||||
/* Work cycle: 6.8ms */
|
||||
#define SFHSS_PACKET_PERIOD 6800
|
||||
#define SFHSS_DATA2_TIMING 1625 // Adjust this value between 1600 and 1650 if your RX(s) are not operating properly
|
||||
case SFHSS_DATA1:
|
||||
SFHSS_build_data_packet();
|
||||
SFHSS_send_packet();
|
||||
phase = SFHSS_DATA2;
|
||||
return SFHSS_DATA2_TIMING; // original 1650
|
||||
case SFHSS_DATA2:
|
||||
SFHSS_build_data_packet();
|
||||
SFHSS_send_packet();
|
||||
SFHSS_calc_next_chan();
|
||||
phase = SFHSS_TUNE;
|
||||
return (SFHSS_PACKET_PERIOD -2000 -SFHSS_DATA2_TIMING); // original 2000
|
||||
case SFHSS_TUNE:
|
||||
phase = SFHSS_DATA1;
|
||||
SFHSS_tune_freq();
|
||||
SFHSS_tune_chan_fast();
|
||||
CC2500_SetPower();
|
||||
return 2000; // original 3150
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate internal id
|
||||
static void __attribute__((unused)) SFHSS_get_tx_id()
|
||||
{
|
||||
// Some receivers (Orange) behaves better if they tuned to id that has
|
||||
// no more than 6 consecutive zeros and ones
|
||||
uint32_t fixed_id;
|
||||
uint8_t run_count = 0;
|
||||
// add guard for bit count
|
||||
fixed_id = 1 ^ (MProtocol_id & 1);
|
||||
for (uint8_t i = 0; i < 16; ++i)
|
||||
{
|
||||
fixed_id = (fixed_id << 1) | (MProtocol_id & 1);
|
||||
MProtocol_id >>= 1;
|
||||
// If two LS bits are the same
|
||||
if ((fixed_id & 3) == 0 || (fixed_id & 3) == 3)
|
||||
{
|
||||
if (++run_count > 6)
|
||||
{
|
||||
fixed_id ^= 1;
|
||||
run_count = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
run_count = 0;
|
||||
}
|
||||
// fixed_id = 0xBC11;
|
||||
rx_tx_addr[0] = fixed_id >> 8;
|
||||
rx_tx_addr[1] = fixed_id >> 0;
|
||||
}
|
||||
|
||||
uint16_t initSFHSS()
|
||||
{
|
||||
BIND_DONE; // Not a TX bind protocol
|
||||
SFHSS_get_tx_id();
|
||||
|
||||
fhss_code=random(0xfefefefe)%28; // Initialize it to random 0-27 inclusive
|
||||
|
||||
SFHSS_rf_init();
|
||||
phase = SFHSS_START;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
123
Multiprotocol/SHENQI_nrf24l01.ino
Normal file
123
Multiprotocol/SHENQI_nrf24l01.ino
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
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(SHENQI_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
const uint8_t PROGMEM SHENQI_Freq[] = {
|
||||
50,50,20,60,30,40,
|
||||
10,30,40,20,60,10,
|
||||
50,20,50,40,10,60,
|
||||
30,30,60,10,40,50,
|
||||
20,10,60,20,50,30,
|
||||
40,40,30,50,20,60,
|
||||
10,10,20,30,40,50,
|
||||
60,60,50,40,30,20,
|
||||
10,60,10,50,30,40,
|
||||
20,10,40,30,60,20 };
|
||||
|
||||
void SHENQI_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
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_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes rx/tx address
|
||||
|
||||
LT8900_Config(4, 8, _BV(LT8900_CRC_ON)|_BV(LT8900_PACKET_LENGTH_EN), 0xAA);
|
||||
LT8900_SetChannel(2);
|
||||
LT8900_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4);
|
||||
LT8900_SetTxRxMode(RX_EN);
|
||||
}
|
||||
|
||||
void SHENQI_send_packet()
|
||||
{
|
||||
packet[0]=0x00;
|
||||
if(packet_count==0)
|
||||
{
|
||||
uint8_t bind_addr[4];
|
||||
bind_addr[0]=rx_tx_addr[0];
|
||||
bind_addr[1]=rx_tx_addr[1];
|
||||
bind_addr[2]=0x9A;
|
||||
bind_addr[3]=0x9A;
|
||||
LT8900_SetAddress(bind_addr,4);
|
||||
LT8900_SetChannel(2);
|
||||
packet[1]=rx_tx_addr[2];
|
||||
packet[2]=rx_tx_addr[3];
|
||||
packet_period=2508;
|
||||
}
|
||||
else
|
||||
{
|
||||
LT8900_SetAddress(rx_tx_addr,4);
|
||||
packet[1]=255-convert_channel_8b(RUDDER);
|
||||
packet[2]=255-convert_channel_16b_limit(THROTTLE,0x60,0xA0);
|
||||
uint8_t freq=pgm_read_byte_near(&SHENQI_Freq[hopping_frequency_no])+(rx_tx_addr[2]&0x0F);
|
||||
LT8900_SetChannel(freq);
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no==60)
|
||||
hopping_frequency_no=0;
|
||||
packet_period=1750;
|
||||
}
|
||||
// Send packet + 1 retransmit - not sure why but needed (not present on original TX...)
|
||||
LT8900_WritePayload(packet,3);
|
||||
while(NRF24L01_packet_ack()!=PKT_ACKED);
|
||||
LT8900_WritePayload(packet,3);
|
||||
|
||||
packet_count++;
|
||||
if(packet_count==7)
|
||||
{
|
||||
packet_count=0;
|
||||
packet_period=3000;
|
||||
}
|
||||
// Set power
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
uint16_t SHENQI_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
SHENQI_send_packet();
|
||||
else
|
||||
{
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{
|
||||
if(LT8900_ReadPayload(packet, 3))
|
||||
{
|
||||
BIND_DONE;
|
||||
rx_tx_addr[0]=packet[1];
|
||||
rx_tx_addr[1]=packet[2];
|
||||
LT8900_SetTxRxMode(TX_EN);
|
||||
packet_period=14000;
|
||||
}
|
||||
NRF24L01_FlushRx();
|
||||
}
|
||||
}
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initSHENQI()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
SHENQI_init();
|
||||
hopping_frequency_no = 0;
|
||||
packet_count=0;
|
||||
packet_period=500;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,203 +1,295 @@
|
||||
/*
|
||||
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(SLT_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
// For code readability
|
||||
#define SLT_PAYLOADSIZE 7
|
||||
#define SLT_NFREQCHANNELS 15
|
||||
#define SLT_TXID_SIZE 4
|
||||
|
||||
enum {
|
||||
SLT_INIT2 = 0,
|
||||
SLT_BIND,
|
||||
SLT_DATA1,
|
||||
SLT_DATA2,
|
||||
SLT_DATA3
|
||||
};
|
||||
|
||||
void SLT_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); // 2-bytes CRC, radio off
|
||||
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, 0x00); // Disable auto retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 4); // bytes of data payload for pipe 1
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 256kbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xC3\xC3\xAA\x55", 4);
|
||||
NRF24L01_FlushRx();
|
||||
}
|
||||
|
||||
static void SLT_init2()
|
||||
{
|
||||
NRF24L01_FlushTx();
|
||||
packet_sent = 0;
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
// Turn radio power on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
}
|
||||
|
||||
void SLT_set_tx_id(void)
|
||||
{
|
||||
// Frequency hopping sequence generation
|
||||
for (uint8_t i = 0; i < 4; ++i)
|
||||
{
|
||||
uint8_t next_i = (i+1) % 4; // is & 3 better than % 4 ?
|
||||
uint8_t base = i < 2 ? 0x03 : 0x10;
|
||||
hopping_frequency[i*4 + 0] = (rx_tx_addr[i] & 0x3f) + base;
|
||||
hopping_frequency[i*4 + 1] = (rx_tx_addr[i] >> 2) + base;
|
||||
hopping_frequency[i*4 + 2] = (rx_tx_addr[i] >> 4) + (rx_tx_addr[next_i] & 0x03)*0x10 + base;
|
||||
if (i*4 + 3 < SLT_NFREQCHANNELS) // guard for 16 channel
|
||||
hopping_frequency[i*4 + 3] = (rx_tx_addr[i] >> 6) + (rx_tx_addr[next_i] & 0x0f)*0x04 + base;
|
||||
}
|
||||
|
||||
// unique
|
||||
uint8_t done = 0;
|
||||
for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i)
|
||||
while (!done)
|
||||
{
|
||||
done = 1;
|
||||
for (uint8_t j = 0; j < i; ++j)
|
||||
if (hopping_frequency[i] == hopping_frequency[j])
|
||||
{
|
||||
done = 0;
|
||||
hopping_frequency[i] += 7;
|
||||
if (hopping_frequency[i] >= 0x50)
|
||||
hopping_frequency[i] = hopping_frequency[i] - 0x50 + 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4);
|
||||
}
|
||||
|
||||
void wait_radio()
|
||||
{
|
||||
if (packet_sent)
|
||||
while (!(NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_TX_DS))) ;
|
||||
packet_sent = 0;
|
||||
}
|
||||
|
||||
void send_data(uint8_t *data, uint8_t len)
|
||||
{
|
||||
wait_radio();
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_RX_DR) | BV(NRF24L01_07_MAX_RT));
|
||||
NRF24L01_WritePayload(data, len);
|
||||
//NRF24L01_PulseCE();
|
||||
packet_sent = 1;
|
||||
}
|
||||
|
||||
void SLT_build_packet()
|
||||
{
|
||||
// aileron, elevator, throttle, rudder, gear, pitch
|
||||
uint8_t e = 0; // byte where extension 2 bits for every 10-bit channel are packed
|
||||
uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER};
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
uint16_t v = convert_channel_10b(ch[i]);
|
||||
packet[i] = v;
|
||||
e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0);
|
||||
}
|
||||
// Extra bits for AETR
|
||||
packet[4] = e;
|
||||
// 8-bit channels
|
||||
packet[5] = convert_channel_8b(AUX1);
|
||||
packet[6] = convert_channel_8b(AUX2);
|
||||
|
||||
// Set radio channel - once per packet batch
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
if (++hopping_frequency_no >= SLT_NFREQCHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
}
|
||||
|
||||
static void send_bind_packet()
|
||||
{
|
||||
wait_radio();
|
||||
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x7E\xB8\x63\xA9", 4);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x50);
|
||||
send_data(rx_tx_addr, 4);
|
||||
|
||||
// NB: we should wait until the packet's sent before changing TX address!
|
||||
wait_radio();
|
||||
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4);
|
||||
}
|
||||
|
||||
uint16_t SLT_callback()
|
||||
{
|
||||
uint16_t delay_us = 20000; // 3 packets with 1ms intervals every 22ms
|
||||
switch (phase)
|
||||
{
|
||||
case SLT_INIT2:
|
||||
SLT_init2();
|
||||
phase = SLT_BIND;
|
||||
delay_us = 150;
|
||||
break;
|
||||
case SLT_BIND:
|
||||
send_bind_packet();
|
||||
phase = SLT_DATA1;
|
||||
delay_us = 19000;
|
||||
BIND_DONE;
|
||||
break;
|
||||
case SLT_DATA1:
|
||||
SLT_build_packet();
|
||||
send_data(packet, 7);
|
||||
phase = SLT_DATA2;
|
||||
delay_us = 1000;
|
||||
break;
|
||||
case SLT_DATA2:
|
||||
send_data(packet, 7);
|
||||
phase = SLT_DATA3;
|
||||
delay_us = 1000;
|
||||
break;
|
||||
case SLT_DATA3:
|
||||
send_data(packet, 7);
|
||||
if (++counter >= 100)
|
||||
{
|
||||
counter = 0;
|
||||
phase = SLT_BIND;
|
||||
delay_us = 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
phase = SLT_DATA1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return delay_us;
|
||||
}
|
||||
|
||||
uint16_t initSLT()
|
||||
{
|
||||
counter = 0;
|
||||
SLT_init();
|
||||
phase = SLT_INIT2;
|
||||
SLT_set_tx_id();
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
return 50000;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with deviation main github branch
|
||||
|
||||
#if defined(SLT_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
//#define SLT_Q200_FORCE_ID
|
||||
|
||||
// For code readability
|
||||
#define SLT_PAYLOADSIZE_V1 7
|
||||
#define SLT_PAYLOADSIZE_V2 11
|
||||
#define SLT_NFREQCHANNELS 15
|
||||
#define SLT_TXID_SIZE 4
|
||||
|
||||
enum{
|
||||
// flags going to packet[6] (Q200)
|
||||
FLAG_Q200_FMODE = 0x20,
|
||||
FLAG_Q200_VIDON = 0x10,
|
||||
FLAG_Q200_FLIP = 0x08,
|
||||
FLAG_Q200_VIDOFF= 0x04,
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[6] (MR100 & Q100)
|
||||
FLAG_MR100_FMODE = 0x20,
|
||||
FLAG_MR100_FLIP = 0x04,
|
||||
FLAG_MR100_VIDEO = 0x02,
|
||||
FLAG_MR100_PICTURE = 0x01,
|
||||
};
|
||||
|
||||
enum {
|
||||
SLT_BUILD=0,
|
||||
SLT_DATA1,
|
||||
SLT_DATA2,
|
||||
SLT_DATA3,
|
||||
SLT_BIND1,
|
||||
SLT_BIND2
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) SLT_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)); // 2-bytes CRC, radio off
|
||||
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, 0x00); // Disable auto retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 4); // bytes of data payload for pipe 1
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 256kbps
|
||||
NRF24L01_SetPower();
|
||||
if(sub_protocol==SLT_V1)
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xC3\xC3\xAA\x55", SLT_TXID_SIZE);
|
||||
else // V2
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x7E\xB8\x63\xA9", SLT_TXID_SIZE);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, SLT_TXID_SIZE);
|
||||
NRF24L01_FlushTx();
|
||||
// Turn radio power on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SLT_set_freq(void)
|
||||
{
|
||||
// Frequency hopping sequence generation
|
||||
for (uint8_t i = 0; i < SLT_TXID_SIZE; ++i)
|
||||
{
|
||||
uint8_t next_i = (i+1) % SLT_TXID_SIZE; // is & 3 better than % 4 ?
|
||||
uint8_t base = i < 2 ? 0x03 : 0x10;
|
||||
hopping_frequency[i*4 + 0] = (rx_tx_addr[i] & 0x3f) + base;
|
||||
hopping_frequency[i*4 + 1] = (rx_tx_addr[i] >> 2) + base;
|
||||
hopping_frequency[i*4 + 2] = (rx_tx_addr[i] >> 4) + (rx_tx_addr[next_i] & 0x03)*0x10 + base;
|
||||
hopping_frequency[i*4 + 3] = (rx_tx_addr[i] >> 6) + (rx_tx_addr[next_i] & 0x0f)*0x04 + base;
|
||||
}
|
||||
|
||||
// Unique freq
|
||||
uint8_t max_freq=0x50; //V1 and V2
|
||||
if(sub_protocol==Q200)
|
||||
max_freq=45;
|
||||
for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i)
|
||||
{
|
||||
if(sub_protocol==Q200 && hopping_frequency[i] >= max_freq)
|
||||
hopping_frequency[i] = hopping_frequency[i] - max_freq + 0x03;
|
||||
uint8_t done = 0;
|
||||
while (!done)
|
||||
{
|
||||
done = 1;
|
||||
for (uint8_t j = 0; j < i; ++j)
|
||||
if (hopping_frequency[i] == hopping_frequency[j])
|
||||
{
|
||||
done = 0;
|
||||
hopping_frequency[i] += 7;
|
||||
if (hopping_frequency[i] >= max_freq)
|
||||
hopping_frequency[i] = hopping_frequency[i] - max_freq + 0x03;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SLT_wait_radio()
|
||||
{
|
||||
if (packet_sent)
|
||||
while (!(NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS)));
|
||||
packet_sent = 0;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SLT_send_packet(uint8_t len)
|
||||
{
|
||||
SLT_wait_radio();
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_MAX_RT));
|
||||
NRF24L01_WritePayload(packet, len);
|
||||
packet_sent = 1;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SLT_build_packet()
|
||||
{
|
||||
static uint8_t calib_counter=0;
|
||||
|
||||
// Set radio channel - once per packet batch
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
if (++hopping_frequency_no >= SLT_NFREQCHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
// aileron, elevator, throttle, rudder, gear, pitch
|
||||
uint8_t e = 0; // byte where extension 2 bits for every 10-bit channel are packed
|
||||
for (uint8_t i = 0; i < 4; ++i)
|
||||
{
|
||||
uint16_t v = convert_channel_10b(CH_AETR[i]);
|
||||
if(sub_protocol>SLT_V2 && (CH_AETR[i]==THROTTLE || CH_AETR[i]==ELEVATOR) )
|
||||
v=1023-v; // reverse throttle and elevator channels for Q100/Q200/MR100 protocols
|
||||
packet[i] = v;
|
||||
e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0);
|
||||
}
|
||||
// Extra bits for AETR
|
||||
packet[4] = e;
|
||||
// 8-bit channels
|
||||
packet[5] = convert_channel_8b(CH5);
|
||||
packet[6] = convert_channel_8b(CH6);
|
||||
if(sub_protocol!=SLT_V1)
|
||||
{
|
||||
if(sub_protocol==Q200)
|
||||
packet[6] = GET_FLAG(CH9_SW , FLAG_Q200_FMODE)
|
||||
|GET_FLAG(CH10_SW, FLAG_Q200_FLIP)
|
||||
|GET_FLAG(CH11_SW, FLAG_Q200_VIDON)
|
||||
|GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF);
|
||||
else if(sub_protocol==MR100 || sub_protocol==Q100)
|
||||
packet[6] = GET_FLAG(CH9_SW , FLAG_MR100_FMODE)
|
||||
|GET_FLAG(CH10_SW, FLAG_MR100_FLIP)
|
||||
|GET_FLAG(CH11_SW, FLAG_MR100_VIDEO) // Does not exist on the Q100 but...
|
||||
|GET_FLAG(CH12_SW, FLAG_MR100_PICTURE); // Does not exist on the Q100 but...
|
||||
packet[7]=convert_channel_8b(CH7);
|
||||
packet[8]=convert_channel_8b(CH8);
|
||||
packet[9]=0xAA; //normal mode for Q100/Q200, unknown for V2/MR100
|
||||
packet[10]=0x00; //normal mode for Q100/Q200, unknown for V2/MR100
|
||||
if((sub_protocol==Q100 || sub_protocol==Q200) && CH13_SW)
|
||||
{//Calibrate
|
||||
packet[9]=0x77; //enter calibration
|
||||
if(calib_counter>=20 && calib_counter<=25) // 7 packets for Q100 / 3 packets for Q200
|
||||
packet[10]=0x20; //launch calibration
|
||||
calib_counter++;
|
||||
if(calib_counter>250) calib_counter=250;
|
||||
}
|
||||
else
|
||||
calib_counter=0;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SLT_send_bind_packet()
|
||||
{
|
||||
SLT_wait_radio();
|
||||
BIND_IN_PROGRESS; //Limit TX power to bind level
|
||||
NRF24L01_SetPower();
|
||||
BIND_DONE;
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x7E\xB8\x63\xA9", SLT_TXID_SIZE);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x50);
|
||||
memcpy((void*)packet,(void*)rx_tx_addr,SLT_TXID_SIZE);
|
||||
if(phase==SLT_BIND2)
|
||||
SLT_send_packet(SLT_TXID_SIZE);
|
||||
else // SLT_BIND1
|
||||
SLT_send_packet(SLT_PAYLOADSIZE_V2);
|
||||
|
||||
SLT_wait_radio(); //Wait until the packet's sent before changing TX address!
|
||||
|
||||
NRF24L01_SetPower(); //Change power back to normal level
|
||||
if(phase==SLT_BIND2) // after V1 bind and V2 second bind packet
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, SLT_TXID_SIZE);
|
||||
}
|
||||
|
||||
#define SLT_TIMING_BUILD 1000
|
||||
#define SLT_V1_TIMING_PACKET 1000
|
||||
#define SLT_V2_TIMING_PACKET 2042
|
||||
#define SLT_V1_TIMING_BIND2 1000
|
||||
#define SLT_V2_TIMING_BIND1 6507
|
||||
#define SLT_V2_TIMING_BIND2 2112
|
||||
uint16_t SLT_callback()
|
||||
{
|
||||
switch (phase)
|
||||
{
|
||||
case SLT_BUILD:
|
||||
SLT_build_packet();
|
||||
phase++;
|
||||
return SLT_TIMING_BUILD;
|
||||
case SLT_DATA1:
|
||||
case SLT_DATA2:
|
||||
phase++;
|
||||
if(sub_protocol==SLT_V1)
|
||||
{
|
||||
SLT_send_packet(SLT_PAYLOADSIZE_V1);
|
||||
return SLT_V1_TIMING_PACKET;
|
||||
}
|
||||
else //V2
|
||||
{
|
||||
SLT_send_packet(SLT_PAYLOADSIZE_V2);
|
||||
return SLT_V2_TIMING_PACKET;
|
||||
}
|
||||
case SLT_DATA3:
|
||||
if(sub_protocol==SLT_V1)
|
||||
SLT_send_packet(SLT_PAYLOADSIZE_V1);
|
||||
else //V2
|
||||
SLT_send_packet(SLT_PAYLOADSIZE_V2);
|
||||
if (++packet_count >= 100)
|
||||
{// Send bind packet
|
||||
packet_count = 0;
|
||||
if(sub_protocol==SLT_V1)
|
||||
{
|
||||
phase=SLT_BIND2;
|
||||
return SLT_V1_TIMING_BIND2;
|
||||
}
|
||||
else //V2
|
||||
{
|
||||
phase=SLT_BIND1;
|
||||
return SLT_V2_TIMING_BIND1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{// Continue to send normal packets
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
phase = SLT_BUILD;
|
||||
if(sub_protocol==SLT_V1)
|
||||
return 20000-SLT_TIMING_BUILD;
|
||||
else //V2
|
||||
return 13730-SLT_TIMING_BUILD;
|
||||
}
|
||||
case SLT_BIND1:
|
||||
SLT_send_bind_packet();
|
||||
phase++;
|
||||
return SLT_V2_TIMING_BIND2;
|
||||
case SLT_BIND2:
|
||||
SLT_send_bind_packet();
|
||||
phase = SLT_BUILD;
|
||||
if(sub_protocol==SLT_V1)
|
||||
return 20000-SLT_TIMING_BUILD-SLT_V1_TIMING_BIND2;
|
||||
else //V2
|
||||
return 13730-SLT_TIMING_BUILD-SLT_V2_TIMING_BIND1-SLT_V2_TIMING_BIND2;
|
||||
}
|
||||
return 19000;
|
||||
}
|
||||
|
||||
uint16_t initSLT()
|
||||
{
|
||||
packet_count = 0;
|
||||
packet_sent = 0;
|
||||
hopping_frequency_no = 0;
|
||||
if(sub_protocol==Q200)
|
||||
{ //Q200: Force high part of the ID otherwise it won't bind
|
||||
rx_tx_addr[0]=0x01;
|
||||
rx_tx_addr[1]=0x02;
|
||||
#ifdef SLT_Q200_FORCE_ID // ID taken from TX dumps
|
||||
rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x6A;rx_tx_addr[3]=0x31;
|
||||
/* rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x0B;rx_tx_addr[3]=0x57;*/
|
||||
#endif
|
||||
}
|
||||
SLT_set_freq();
|
||||
SLT_init();
|
||||
phase = SLT_BUILD;
|
||||
return 50000;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
170
Multiprotocol/SPI.ino
Normal file
170
Multiprotocol/SPI.ino
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/********************/
|
||||
/** SPI routines **/
|
||||
/********************/
|
||||
#ifdef STM32_BOARD
|
||||
|
||||
#ifdef DEBUG_SERIAL
|
||||
// #define DEBUG_SPI
|
||||
#endif
|
||||
|
||||
SPIClass SPI_2(2); //Create an instance of the SPI Class called SPI_2 that uses the 2nd SPI Port
|
||||
|
||||
void initSPI2()
|
||||
{
|
||||
//SPI_DISABLE();
|
||||
SPI_2.end();
|
||||
SPI2_BASE->CR1 &= ~SPI_CR1_DFF_8_BIT; //8 bits format, this bit should be written only when SPI is disabled (SPE = ?0?) for correct operation.
|
||||
SPI_2.begin(); //Initialize the SPI_2 port.
|
||||
|
||||
SPI2_BASE->CR1 &= ~SPI_CR1_LSBFIRST; // Set the SPI_2 bit order MSB first
|
||||
SPI2_BASE->CR1 &= ~(SPI_CR1_CPOL|SPI_CR1_CPHA); // Set the SPI_2 data mode 0: Clock idles low, data captured on rising edge (first transition)
|
||||
SPI2_BASE->CR1 &= ~(SPI_CR1_BR);
|
||||
SPI2_BASE->CR1 |= SPI_CR1_BR_PCLK_DIV_8; // Set the speed (36 / 8 = 4.5 MHz SPI_2 speed) SPI_CR1_BR_PCLK_DIV_8
|
||||
}
|
||||
|
||||
void SPI_Write(uint8_t command)
|
||||
{//working OK
|
||||
SPI2_BASE->DR = command; //Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag).
|
||||
#ifdef DEBUG_SPI
|
||||
debug("%02X ",command);
|
||||
#endif
|
||||
while (!(SPI2_BASE->SR & SPI_SR_RXNE));
|
||||
command = SPI2_BASE->DR; // ... and read the last received data.
|
||||
}
|
||||
|
||||
uint8_t SPI_Read(void)
|
||||
{
|
||||
SPI_Write(0x00);
|
||||
return SPI2_BASE->DR;
|
||||
}
|
||||
|
||||
uint8_t SPI_SDI_Read()
|
||||
{
|
||||
uint8_t rx=0;
|
||||
cli(); //Fix Hubsan droputs??
|
||||
while(!(SPI2_BASE->SR & SPI_SR_TXE));
|
||||
while((SPI2_BASE->SR & SPI_SR_BSY));
|
||||
//
|
||||
SPI_DISABLE();
|
||||
SPI_SET_BIDIRECTIONAL();
|
||||
volatile uint8_t x = SPI2_BASE->DR;
|
||||
(void)x;
|
||||
SPI_ENABLE();
|
||||
//
|
||||
SPI_DISABLE();
|
||||
while(!(SPI2_BASE->SR& SPI_SR_RXNE));
|
||||
rx=SPI2_BASE->DR;
|
||||
SPI_SET_UNIDIRECTIONAL();
|
||||
SPI_ENABLE();
|
||||
sei();//fix Hubsan dropouts??
|
||||
return rx;
|
||||
}
|
||||
|
||||
void SPI_ENABLE()
|
||||
{
|
||||
SPI2_BASE->CR1 |= SPI_CR1_SPE;
|
||||
}
|
||||
|
||||
void SPI_DISABLE()
|
||||
{
|
||||
SPI2_BASE->CR1 &= ~SPI_CR1_SPE;
|
||||
}
|
||||
|
||||
void SPI_SET_BIDIRECTIONAL()
|
||||
{
|
||||
SPI2_BASE->CR1 |= SPI_CR1_BIDIMODE;
|
||||
SPI2_BASE->CR1 &= ~ SPI_CR1_BIDIOE;//receive only
|
||||
}
|
||||
|
||||
void SPI_SET_UNIDIRECTIONAL()
|
||||
{
|
||||
SPI2_BASE->CR1 &= ~SPI_CR1_BIDIMODE;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef ORANGE_TX
|
||||
#define XNOP() NOP()
|
||||
#else
|
||||
#define XNOP()
|
||||
#endif
|
||||
|
||||
void SPI_Write(uint8_t command)
|
||||
{
|
||||
uint8_t n=8;
|
||||
|
||||
SCLK_off;//SCK start low
|
||||
XNOP();
|
||||
SDI_off;
|
||||
XNOP();
|
||||
do
|
||||
{
|
||||
if(command&0x80)
|
||||
SDI_on;
|
||||
else
|
||||
SDI_off;
|
||||
XNOP();
|
||||
SCLK_on;
|
||||
XNOP();
|
||||
XNOP();
|
||||
command = command << 1;
|
||||
SCLK_off;
|
||||
XNOP();
|
||||
}
|
||||
while(--n) ;
|
||||
SDI_on;
|
||||
}
|
||||
|
||||
uint8_t SPI_Read(void)
|
||||
{
|
||||
uint8_t result=0,i;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
result=result<<1;
|
||||
if(SDO_1)
|
||||
result |= 0x01;
|
||||
SCLK_on;
|
||||
XNOP();
|
||||
XNOP();
|
||||
NOP();
|
||||
SCLK_off;
|
||||
XNOP();
|
||||
XNOP();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef A7105_INSTALLED
|
||||
uint8_t SPI_SDI_Read(void)
|
||||
{
|
||||
uint8_t result=0;
|
||||
SDI_input;
|
||||
for(uint8_t i=0;i<8;i++)
|
||||
{
|
||||
result=result<<1;
|
||||
if(SDI_1) ///if SDIO =1
|
||||
result |= 0x01;
|
||||
SCLK_on;
|
||||
NOP();
|
||||
SCLK_off;
|
||||
}
|
||||
SDI_output;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif//STM32_BOARD
|
||||
@@ -12,16 +12,12 @@
|
||||
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 Syma X5C-1, X11, X11C, X12 and for sub protocol X5C Syma X5C (original), X2
|
||||
|
||||
#if defined(SYMAX_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
/***
|
||||
Main protocol compatible with Syma X5C-1, X11, X11C, X12.
|
||||
SymaX5C protocol option compatible with Syma X5C (original) and X2.
|
||||
***/
|
||||
|
||||
#define SYMAX_BIND_COUNT 345 // 1.5 seconds
|
||||
#define SYMAX_FIRST_PACKET_DELAY 12000
|
||||
#define SYMAX_PACKET_PERIOD 4000 // Timeout for callback in uSec
|
||||
@@ -33,6 +29,7 @@
|
||||
#define SYMAX_FLAG_VIDEO 0x02
|
||||
#define SYMAX_FLAG_PICTURE 0x04
|
||||
#define SYMAX_FLAG_HEADLESS 0x08
|
||||
#define SYMAX_XTRM_RATES 0x10
|
||||
|
||||
#define SYMAX_PAYLOADSIZE 10 // receive data pipes set to this size, but unused
|
||||
#define SYMAX_MAX_PACKET_LENGTH 16 // X11,X12,X5C-1 10-byte, X5C 16-byte
|
||||
@@ -44,16 +41,7 @@ enum {
|
||||
SYMAX_DATA
|
||||
};
|
||||
|
||||
/*
|
||||
http://www.deviationtx.com/forum/protocol-development/3768-syma-x5c-1-x11-x12?start=140
|
||||
TX address Channel Sequence
|
||||
S1 3B B6 00 00 A2 15 35 1D 3D
|
||||
D1 9A E9 02 00 A2 14 34 1C 3C
|
||||
|
||||
D2 46 18 00 00 A2 11 21 31 41
|
||||
*/
|
||||
|
||||
uint8_t SYMAX_checksum(uint8_t *data)
|
||||
static uint8_t __attribute__((unused)) SYMAX_checksum(uint8_t *data)
|
||||
{
|
||||
uint8_t sum = data[0];
|
||||
|
||||
@@ -66,34 +54,40 @@ uint8_t SYMAX_checksum(uint8_t *data)
|
||||
return sum + ( sub_protocol==SYMAX5C ? 0 : 0x55 );
|
||||
}
|
||||
|
||||
void SYMAX_read_controls()
|
||||
static void __attribute__((unused)) SYMAX_read_controls()
|
||||
{
|
||||
// Protocol is registered AETRF, that is
|
||||
// Aileron is channel 1, Elevator - 2, Throttle - 3, Rudder - 4, Flip control - 5
|
||||
// Extended (trim-added) Rates - 6, Photo - 7, Video - 8, Headless - 9
|
||||
aileron = convert_channel_s8b(AILERON);
|
||||
elevator = convert_channel_s8b(ELEVATOR);
|
||||
throttle = convert_channel_8b(THROTTLE);
|
||||
rudder = convert_channel_s8b(RUDDER);
|
||||
|
||||
flags=0;
|
||||
// Channel 5
|
||||
if (Servo_data[AUX1] > PPM_SWITCH)
|
||||
if (CH5_SW)
|
||||
flags = SYMAX_FLAG_FLIP;
|
||||
else
|
||||
flags=0;
|
||||
// Channel 6
|
||||
if (CH6_SW)
|
||||
flags |= SYMAX_XTRM_RATES;
|
||||
// Channel 7
|
||||
if (Servo_data[AUX3] > PPM_SWITCH)
|
||||
if (CH7_SW)
|
||||
flags |= SYMAX_FLAG_PICTURE;
|
||||
// Channel 8
|
||||
if (Servo_data[AUX4] > PPM_SWITCH)
|
||||
if (CH8_SW)
|
||||
flags |= SYMAX_FLAG_VIDEO;
|
||||
// Channel 9
|
||||
if (Servo_data[AUX5] > PPM_SWITCH)
|
||||
if (CH9_SW)
|
||||
{
|
||||
flags |= SYMAX_FLAG_HEADLESS;
|
||||
flags &= ~SYMAX_XTRM_RATES; // Extended rates & headless incompatible
|
||||
}
|
||||
}
|
||||
|
||||
#define X5C_CHAN2TRIM(X) ((((X) & 0x80 ? 0xff - (X) : 0x80 + (X)) >> 2) + 0x20)
|
||||
|
||||
void SYMAX_build_packet_x5c(uint8_t bind)
|
||||
static void __attribute__((unused)) SYMAX_build_packet_x5c(uint8_t bind)
|
||||
{
|
||||
if (bind)
|
||||
{
|
||||
@@ -111,9 +105,18 @@ void SYMAX_build_packet_x5c(uint8_t bind)
|
||||
packet[1] = rudder;
|
||||
packet[2] = elevator ^ 0x80; // reversed from default
|
||||
packet[3] = aileron;
|
||||
packet[4] = X5C_CHAN2TRIM(rudder ^ 0x80);// drive trims for extra control range
|
||||
packet[5] = X5C_CHAN2TRIM(elevator);
|
||||
packet[6] = X5C_CHAN2TRIM(aileron ^ 0x80);
|
||||
if (flags & SYMAX_XTRM_RATES)
|
||||
{ // drive trims for extra control range
|
||||
packet[4] = X5C_CHAN2TRIM(rudder ^ 0x80);
|
||||
packet[5] = X5C_CHAN2TRIM(elevator);
|
||||
packet[6] = X5C_CHAN2TRIM(aileron ^ 0x80);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[4] = 0x00;
|
||||
packet[5] = 0x00;
|
||||
packet[6] = 0x00;
|
||||
}
|
||||
packet[7] = 0xae;
|
||||
packet[8] = 0xa9;
|
||||
packet[9] = 0x00;
|
||||
@@ -124,12 +127,12 @@ void SYMAX_build_packet_x5c(uint8_t bind)
|
||||
packet[14] = (flags & SYMAX_FLAG_VIDEO ? 0x10 : 0x00)
|
||||
| (flags & SYMAX_FLAG_PICTURE ? 0x08 : 0x00)
|
||||
| (flags & SYMAX_FLAG_FLIP ? 0x01 : 0x00)
|
||||
| 0x04;// (flags & SYMAX_FLAG_RATES ? 0x04 : 0x00);
|
||||
| 0x04;// always high rates (bit 3 is rate control)
|
||||
packet[15] = SYMAX_checksum(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void SYMAX_build_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) SYMAX_build_packet(uint8_t bind)
|
||||
{
|
||||
if (bind)
|
||||
{
|
||||
@@ -151,15 +154,21 @@ void SYMAX_build_packet(uint8_t bind)
|
||||
packet[2] = rudder;
|
||||
packet[3] = aileron;
|
||||
packet[4] = (flags & SYMAX_FLAG_VIDEO ? 0x80 : 0x00) | (flags & SYMAX_FLAG_PICTURE ? 0x40 : 0x00);
|
||||
packet[5] = (elevator >> 2) | 0xc0; //always high rates (bit 7 is rate control) (flags & SYMAX_FLAG_RATES ? 0x80 : 0x00) | 0x40; // use trims to extend controls
|
||||
packet[6] = (rudder >> 2) | (flags & SYMAX_FLAG_FLIP ? 0x40 : 0x00);
|
||||
packet[7] = (aileron >> 2) | (flags & SYMAX_FLAG_HEADLESS ? 0x80 : 0x00);
|
||||
packet[5] = 0xc0; //always high rates (bit 7 is rate control)
|
||||
packet[6] = flags & SYMAX_FLAG_FLIP ? 0x40 : 0x00;
|
||||
packet[7] = flags & SYMAX_FLAG_HEADLESS ? 0x80 : 0x00;
|
||||
if (flags & SYMAX_XTRM_RATES)
|
||||
{ // use trims to extend controls
|
||||
packet[5] |= elevator >> 2;
|
||||
packet[6] |= rudder >> 2;
|
||||
packet[7] |= aileron >> 2;
|
||||
}
|
||||
packet[8] = 0x00;
|
||||
}
|
||||
packet[9] = SYMAX_checksum(packet);
|
||||
}
|
||||
|
||||
void SYMAX_send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) SYMAX_send_packet(uint8_t bind)
|
||||
{
|
||||
if (sub_protocol==SYMAX5C)
|
||||
SYMAX_build_packet_x5c(bind);
|
||||
@@ -174,20 +183,20 @@ void SYMAX_send_packet(uint8_t bind)
|
||||
|
||||
NRF24L01_WritePayload(packet, packet_length);
|
||||
|
||||
if (packet_counter++ % 2) // use each channel twice
|
||||
if (packet_count++ % 2) // use each channel twice
|
||||
hopping_frequency_no = (hopping_frequency_no + 1) % rf_ch_num;
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void symax_init()
|
||||
static void __attribute__((unused)) symax_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
//
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
//
|
||||
NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO));
|
||||
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, 0x3F); // Enable all data pipes (even though not used?)
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
|
||||
@@ -232,7 +241,7 @@ static void symax_init()
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0e); // power on
|
||||
}
|
||||
|
||||
void symax_init1()
|
||||
static void __attribute__((unused)) symax_init1()
|
||||
{
|
||||
// duplicate stock tx sending strange packet (effect unknown)
|
||||
uint8_t first_packet[] = {0xf9, 0x96, 0x82, 0x1b, 0x20, 0x08, 0x08, 0xf2, 0x7d, 0xef, 0xff, 0x00, 0x00, 0x00, 0x00};
|
||||
@@ -240,13 +249,6 @@ void symax_init1()
|
||||
uint8_t chans_bind_x5c[] = {0x27, 0x1b, 0x39, 0x28, 0x24, 0x22, 0x2e, 0x36,
|
||||
0x19, 0x21, 0x29, 0x14, 0x1e, 0x12, 0x2d, 0x18};
|
||||
|
||||
//uint8_t data_rx_tx_addr[] = {0x3b,0xb6,0x00,0x00,0xa2};
|
||||
//uint8_t data_rx_tx_addr[] = {0x9A,0xe9,0x03,0x00,0xa2};//<<---- is ok
|
||||
//uint8_t data_rx_tx_addr[] = {0x3b,0xb6,0x00,0x00,0xa2};//<<--- is ok
|
||||
//uint8_t data_rx_tx_addr[] = {0x9A,0xe9,0x00,0x00,0xa2};
|
||||
//uint8_t data_rx_tx_addr[] = {0x9A,0xe9,0x03,0x00,0xa2};//<<---- is ok
|
||||
//uint8_t data_rx_tx_addr[] = {0x46,0x18,0x00,0x00,0xa2};
|
||||
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x08);
|
||||
NRF24L01_WritePayload(first_packet, 15);
|
||||
@@ -263,18 +265,16 @@ void symax_init1()
|
||||
memcpy(hopping_frequency, chans_bind, rf_ch_num);
|
||||
}
|
||||
hopping_frequency_no = 0;
|
||||
packet_counter = 0;
|
||||
packet_count = 0;
|
||||
}
|
||||
|
||||
// channels determined by last byte of tx address
|
||||
void symax_set_channels(uint8_t address)
|
||||
static void __attribute__((unused)) symax_set_channels(uint8_t address)
|
||||
{
|
||||
static const uint8_t start_chans_1[] = {0x0a, 0x1a, 0x2a, 0x3a};
|
||||
static const uint8_t start_chans_2[] = {0x2a, 0x0a, 0x42, 0x22};
|
||||
static const uint8_t start_chans_3[] = {0x1a, 0x3a, 0x12, 0x32};
|
||||
//static const uint8_t start_chans_4[] = {0x15, 0x35, 0x1d, 0x3d};
|
||||
//static const uint8_t start_chans_5[] = {0x14, 0x34, 0x1c, 0x3c};
|
||||
//static const uint8_t start_chans_6[] = {0x11, 0x21, 0x31, 0x41};
|
||||
|
||||
uint8_t laddress = address & 0x1f;
|
||||
uint8_t i;
|
||||
uint32_t *pchans = (uint32_t *)hopping_frequency; // avoid compiler warning
|
||||
@@ -312,9 +312,9 @@ void symax_set_channels(uint8_t address)
|
||||
*pchans = 0x39194121;
|
||||
}
|
||||
|
||||
void symax_init2()
|
||||
static void __attribute__((unused)) symax_init2()
|
||||
{
|
||||
uint8_t chans_data_x5c[] = {0x1d, 0x2f, 0x26, 0x3d, 0x15, 0x2b, 0x25, 0x24,
|
||||
static uint8_t chans_data_x5c[] = {0x1d, 0x2f, 0x26, 0x3d, 0x15, 0x2b, 0x25, 0x24,
|
||||
0x27, 0x2c, 0x1c, 0x3e, 0x39, 0x2d, 0x22};
|
||||
|
||||
if (sub_protocol==SYMAX5C)
|
||||
@@ -328,7 +328,7 @@ void symax_init2()
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
}
|
||||
hopping_frequency_no = 0;
|
||||
packet_counter = 0;
|
||||
packet_count = 0;
|
||||
}
|
||||
|
||||
uint16_t symax_callback()
|
||||
@@ -341,12 +341,12 @@ uint16_t symax_callback()
|
||||
return SYMAX_FIRST_PACKET_DELAY;
|
||||
break;
|
||||
case SYMAX_BIND2:
|
||||
counter = SYMAX_BIND_COUNT;
|
||||
bind_counter = SYMAX_BIND_COUNT;
|
||||
phase = SYMAX_BIND3;
|
||||
SYMAX_send_packet(1);
|
||||
break;
|
||||
case SYMAX_BIND3:
|
||||
if (counter == 0)
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
symax_init2();
|
||||
phase = SYMAX_DATA;
|
||||
@@ -355,7 +355,7 @@ uint16_t symax_callback()
|
||||
else
|
||||
{
|
||||
SYMAX_send_packet(1);
|
||||
counter--;
|
||||
bind_counter--;
|
||||
}
|
||||
break;
|
||||
case SYMAX_DATA:
|
||||
@@ -367,7 +367,7 @@ uint16_t symax_callback()
|
||||
|
||||
uint16_t initSymax()
|
||||
{
|
||||
packet_counter = 0;
|
||||
packet_count = 0;
|
||||
flags = 0;
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
symax_init();
|
||||
|
||||
213
Multiprotocol/TX_Def.h
Normal file
213
Multiprotocol/TX_Def.h
Normal file
@@ -0,0 +1,213 @@
|
||||
// Turnigy PPM and channels
|
||||
#if defined(TX_ER9X)
|
||||
#define PPM_MAX_100 2012 // 100%
|
||||
#define PPM_MIN_100 988 // 100%
|
||||
#endif
|
||||
|
||||
// Devo PPM and channels
|
||||
#if defined(TX_DEVO7)
|
||||
#define PPM_MAX_100 1920 // 100%
|
||||
#define PPM_MIN_100 1120 // 100%
|
||||
#endif
|
||||
|
||||
// SPEKTRUM PPM and channels
|
||||
#if defined(TX_SPEKTRUM)
|
||||
#define PPM_MAX_100 1900 // 100%
|
||||
#define PPM_MIN_100 1100 // 100%
|
||||
#endif
|
||||
|
||||
// HISKY
|
||||
#if defined(TX_HISKY)
|
||||
#define PPM_MAX_100 1920 // 100%
|
||||
#define PPM_MIN_100 1120 // 100%
|
||||
#endif
|
||||
|
||||
// Multiplex MC2020
|
||||
#if defined(TX_MPX)
|
||||
#define PPM_MAX_100 1950 // 100%
|
||||
#define PPM_MIN_100 1250 // 100%
|
||||
#endif
|
||||
|
||||
// Walkera PL0811-01H
|
||||
#if defined(TX_WALKERA)
|
||||
#define PPM_MAX_100 1800 // 100%
|
||||
#define PPM_MIN_100 1000 // 100%
|
||||
#endif
|
||||
|
||||
//Channel MIN MAX values
|
||||
#define CHANNEL_MAX_100 1844 // 100%
|
||||
#define CHANNEL_MIN_100 204 // 100%
|
||||
#define CHANNEL_MAX_125 2047 // 125%
|
||||
#define CHANNEL_MIN_125 0 // 125%
|
||||
|
||||
#define CHANNEL_MID 1024
|
||||
|
||||
#define CHANNEL_MIN_COMMAND 784 // 1350us
|
||||
#define CHANNEL_SWITCH 1104 // 1550us
|
||||
#define CHANNEL_MAX_COMMAND 1424 // 1750us
|
||||
|
||||
//Channel definitions
|
||||
#ifdef AETR
|
||||
#define AILERON 0
|
||||
#define ELEVATOR 1
|
||||
#define THROTTLE 2
|
||||
#define RUDDER 3
|
||||
#endif
|
||||
#ifdef AERT
|
||||
#define AILERON 0
|
||||
#define ELEVATOR 1
|
||||
#define THROTTLE 3
|
||||
#define RUDDER 2
|
||||
#endif
|
||||
#ifdef ARET
|
||||
#define AILERON 0
|
||||
#define ELEVATOR 2
|
||||
#define THROTTLE 3
|
||||
#define RUDDER 1
|
||||
#endif
|
||||
#ifdef ARTE
|
||||
#define AILERON 0
|
||||
#define ELEVATOR 3
|
||||
#define THROTTLE 2
|
||||
#define RUDDER 1
|
||||
#endif
|
||||
#ifdef ATRE
|
||||
#define AILERON 0
|
||||
#define ELEVATOR 3
|
||||
#define THROTTLE 1
|
||||
#define RUDDER 2
|
||||
#endif
|
||||
#ifdef ATER
|
||||
#define AILERON 0
|
||||
#define ELEVATOR 2
|
||||
#define THROTTLE 1
|
||||
#define RUDDER 3
|
||||
#endif
|
||||
|
||||
#ifdef EATR
|
||||
#define AILERON 1
|
||||
#define ELEVATOR 0
|
||||
#define THROTTLE 2
|
||||
#define RUDDER 3
|
||||
#endif
|
||||
#ifdef EART
|
||||
#define AILERON 1
|
||||
#define ELEVATOR 0
|
||||
#define THROTTLE 3
|
||||
#define RUDDER 2
|
||||
#endif
|
||||
#ifdef ERAT
|
||||
#define AILERON 2
|
||||
#define ELEVATOR 0
|
||||
#define THROTTLE 3
|
||||
#define RUDDER 1
|
||||
#endif
|
||||
#ifdef ERTA
|
||||
#define AILERON 3
|
||||
#define ELEVATOR 0
|
||||
#define THROTTLE 2
|
||||
#define RUDDER 1
|
||||
#endif
|
||||
#ifdef ETRA
|
||||
#define AILERON 3
|
||||
#define ELEVATOR 0
|
||||
#define THROTTLE 1
|
||||
#define RUDDER 2
|
||||
#endif
|
||||
#ifdef ETAR
|
||||
#define AILERON 2
|
||||
#define ELEVATOR 0
|
||||
#define THROTTLE 1
|
||||
#define RUDDER 3
|
||||
#endif
|
||||
|
||||
#ifdef TEAR
|
||||
#define AILERON 2
|
||||
#define ELEVATOR 1
|
||||
#define THROTTLE 0
|
||||
#define RUDDER 3
|
||||
#endif
|
||||
#ifdef TERA
|
||||
#define AILERON 3
|
||||
#define ELEVATOR 1
|
||||
#define THROTTLE 0
|
||||
#define RUDDER 2
|
||||
#endif
|
||||
#ifdef TREA
|
||||
#define AILERON 3
|
||||
#define ELEVATOR 2
|
||||
#define THROTTLE 0
|
||||
#define RUDDER 1
|
||||
#endif
|
||||
#ifdef TRAE
|
||||
#define AILERON 2
|
||||
#define ELEVATOR 3
|
||||
#define THROTTLE 0
|
||||
#define RUDDER 1
|
||||
#endif
|
||||
#ifdef TARE
|
||||
#define AILERON 1
|
||||
#define ELEVATOR 3
|
||||
#define THROTTLE 0
|
||||
#define RUDDER 2
|
||||
#endif
|
||||
#ifdef TAER
|
||||
#define AILERON 1
|
||||
#define ELEVATOR 2
|
||||
#define THROTTLE 0
|
||||
#define RUDDER 3
|
||||
#endif
|
||||
|
||||
#ifdef RETA
|
||||
#define AILERON 3
|
||||
#define ELEVATOR 1
|
||||
#define THROTTLE 2
|
||||
#define RUDDER 0
|
||||
#endif
|
||||
#ifdef REAT
|
||||
#define AILERON 2
|
||||
#define ELEVATOR 1
|
||||
#define THROTTLE 3
|
||||
#define RUDDER 0
|
||||
#endif
|
||||
#ifdef RAET
|
||||
#define AILERON 1
|
||||
#define ELEVATOR 2
|
||||
#define THROTTLE 3
|
||||
#define RUDDER 0
|
||||
#endif
|
||||
#ifdef RATE
|
||||
#define AILERON 1
|
||||
#define ELEVATOR 3
|
||||
#define THROTTLE 2
|
||||
#define RUDDER 0
|
||||
#endif
|
||||
#ifdef RTAE
|
||||
#define AILERON 2
|
||||
#define ELEVATOR 3
|
||||
#define THROTTLE 1
|
||||
#define RUDDER 0
|
||||
#endif
|
||||
#ifdef RTEA
|
||||
#define AILERON 3
|
||||
#define ELEVATOR 2
|
||||
#define THROTTLE 1
|
||||
#define RUDDER 0
|
||||
#endif
|
||||
|
||||
#define CH1 0
|
||||
#define CH2 1
|
||||
#define CH3 2
|
||||
#define CH4 3
|
||||
#define CH5 4
|
||||
#define CH6 5
|
||||
#define CH7 6
|
||||
#define CH8 7
|
||||
#define CH9 8
|
||||
#define CH10 9
|
||||
#define CH11 10
|
||||
#define CH12 11
|
||||
#define CH13 12
|
||||
#define CH14 13
|
||||
#define CH15 14
|
||||
#define CH16 15
|
||||
1392
Multiprotocol/Telemetry.ino
Normal file
1392
Multiprotocol/Telemetry.ino
Normal file
File diff suppressed because it is too large
Load Diff
@@ -12,20 +12,22 @@
|
||||
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 WLToys V2x2, JXD JD38x, JD39x, JJRC H6C, Yizhan Tarantula X6 ...
|
||||
// Last sync with hexfet new_protocols/v202_nrf24l01.c dated 2015-03-15
|
||||
|
||||
#if defined(V2X2_NRF24L01_INO)
|
||||
|
||||
// compatible with WLToys V2x2, JXD JD38x, JD39x, JJRC H6C, Yizhan Tarantula X6 ...
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
|
||||
#define BIND_COUNT 1000
|
||||
#define V2X2_BIND_COUNT 1000
|
||||
// Timeout for callback in uSec, 4ms=4000us for V202
|
||||
#define PACKET_PERIOD 4000
|
||||
#define V2X2_PACKET_PERIOD 4000
|
||||
//
|
||||
// Time to wait for packet to be sent (no ACK, so very short)
|
||||
#define PACKET_CHKTIME 100
|
||||
#define V2X2_PACKET_CHKTIME 100
|
||||
#define V2X2_PAYLOADSIZE 16
|
||||
|
||||
//
|
||||
enum {
|
||||
@@ -39,11 +41,15 @@ enum {
|
||||
// flags going to byte 10
|
||||
V2X2_FLAG_HEADLESS = 0x02,
|
||||
V2X2_FLAG_MAG_CAL_X = 0x08,
|
||||
V2X2_FLAG_MAG_CAL_Y = 0x20
|
||||
V2X2_FLAG_MAG_CAL_Y = 0x20,
|
||||
V2X2_FLAG_EMERGENCY = 0x80, // JXD-506
|
||||
// flags going to byte 11 (JXD-506)
|
||||
V2X2_FLAG_START_STOP = 0x40,
|
||||
V2X2_FLAG_CAMERA_UP = 0x01,
|
||||
V2X2_FLAG_CAMERA_DN = 0x02,
|
||||
};
|
||||
|
||||
//
|
||||
#define V2X2_PAYLOADSIZE 16
|
||||
|
||||
enum {
|
||||
V202_INIT2 = 0,
|
||||
@@ -53,8 +59,6 @@ enum {
|
||||
V202_DATA//4
|
||||
};
|
||||
|
||||
// static u32 bind_count;
|
||||
|
||||
// This is frequency hopping table for V202 protocol
|
||||
// The table is the first 4 rows of 32 frequency hopping
|
||||
// patterns, all other rows are derived from the first 4.
|
||||
@@ -63,7 +67,7 @@ enum {
|
||||
// number in this case.
|
||||
// The pattern is defined by 5 least significant bits of
|
||||
// sum of 3 bytes comprising TX id
|
||||
static const uint8_t freq_hopping[][16] = {
|
||||
const uint8_t PROGMEM freq_hopping[][16] = {
|
||||
{ 0x27, 0x1B, 0x39, 0x28, 0x24, 0x22, 0x2E, 0x36,
|
||||
0x19, 0x21, 0x29, 0x14, 0x1E, 0x12, 0x2D, 0x18 }, // 00
|
||||
{ 0x2E, 0x33, 0x25, 0x38, 0x19, 0x12, 0x18, 0x16,
|
||||
@@ -73,14 +77,13 @@ static const uint8_t freq_hopping[][16] = {
|
||||
{ 0x22, 0x27, 0x17, 0x39, 0x34, 0x28, 0x2B, 0x1D,
|
||||
0x18, 0x2A, 0x21, 0x38, 0x10, 0x26, 0x20, 0x1F } // 03
|
||||
};
|
||||
//static uint8_t hopping_frequency[16];
|
||||
|
||||
void v202_init()
|
||||
static void __attribute__((unused)) v202_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_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, 0x3F); // Enable all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
|
||||
@@ -103,14 +106,12 @@ void v202_init()
|
||||
NRF24L01_WriteReg(NRF24L01_15_RX_PW_P4, V2X2_PAYLOADSIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_16_RX_PW_P5, V2X2_PAYLOADSIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
|
||||
uint8_t v2x2_rx_tx_addr[] = {0x66, 0x88, 0x68, 0x68, 0x68};
|
||||
uint8_t rx_p1_addr[] = {0x88, 0x66, 0x86, 0x86, 0x86};
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, v2x2_rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, rx_p1_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, v2x2_rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x66\x88\x68\x68\x68", 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, (uint8_t *)"\x88\x66\x86\x86\x86", 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x66\x88\x68\x68\x68", 5);
|
||||
}
|
||||
|
||||
void V202_init2()
|
||||
static void __attribute__((unused)) V202_init2()
|
||||
{
|
||||
NRF24L01_FlushTx();
|
||||
packet_sent = 0;
|
||||
@@ -118,25 +119,25 @@ void V202_init2()
|
||||
|
||||
// Turn radio power on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
//Done by TX_EN??? => NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
//Done by TX_EN??? => NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
}
|
||||
|
||||
void set_tx_id(void)
|
||||
static void __attribute__((unused)) V2X2_set_tx_id(void)
|
||||
{
|
||||
uint8_t sum;
|
||||
sum = rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3];
|
||||
// Base row is defined by lowest 2 bits
|
||||
const uint8_t *fh_row = freq_hopping[sum & 0x03];
|
||||
// Higher 3 bits define increment to corresponding row
|
||||
uint8_t increment = (sum & 0x1e) >> 2;
|
||||
// Base row is defined by lowest 2 bits
|
||||
sum &=0x03;
|
||||
for (uint8_t i = 0; i < 16; ++i) {
|
||||
uint8_t val = fh_row[i] + increment;
|
||||
uint8_t val = pgm_read_byte_near(&freq_hopping[sum][i]) + increment;
|
||||
// Strange avoidance of channels divisible by 16
|
||||
hopping_frequency[i] = (val & 0x0f) ? val : val - 3;
|
||||
}
|
||||
}
|
||||
|
||||
void add_pkt_checksum()
|
||||
static void __attribute__((unused)) V2X2_add_pkt_checksum()
|
||||
{
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 0; i < 15; ++i)
|
||||
@@ -144,7 +145,7 @@ void add_pkt_checksum()
|
||||
packet[15] = sum;
|
||||
}
|
||||
|
||||
void send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) V2X2_send_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t flags2=0;
|
||||
if (bind)
|
||||
@@ -170,42 +171,60 @@ void send_packet(uint8_t bind)
|
||||
packet[6] = 0x40; // roll
|
||||
|
||||
//Flags
|
||||
flags=0;
|
||||
// Channel 5
|
||||
if (Servo_data[AUX1] > PPM_SWITCH)
|
||||
flags |= V2X2_FLAG_FLIP;
|
||||
if (CH5_SW) flags = V2X2_FLAG_FLIP;
|
||||
// Channel 6
|
||||
if (Servo_data[AUX2] > PPM_SWITCH)
|
||||
flags |= V2X2_FLAG_LIGHT;
|
||||
if (CH6_SW) flags |= V2X2_FLAG_LIGHT;
|
||||
// Channel 7
|
||||
if (Servo_data[AUX3] > PPM_SWITCH)
|
||||
flags |= V2X2_FLAG_CAMERA;
|
||||
if (CH7_SW) flags |= V2X2_FLAG_CAMERA;
|
||||
// Channel 8
|
||||
if (Servo_data[AUX4] > PPM_SWITCH)
|
||||
flags |= V2X2_FLAG_VIDEO;
|
||||
if (CH8_SW) flags |= V2X2_FLAG_VIDEO;
|
||||
|
||||
//Flags2
|
||||
// Channel 9
|
||||
if (Servo_data[AUX5] > PPM_SWITCH)
|
||||
if (CH9_SW)
|
||||
flags2 = V2X2_FLAG_HEADLESS;
|
||||
// Channel 10
|
||||
if (Servo_data[AUX6] > PPM_SWITCH)
|
||||
flags2 |= V2X2_FLAG_MAG_CAL_X;
|
||||
// Channel 11
|
||||
if (Servo_data[AUX7] > PPM_SWITCH)
|
||||
flags2 |= V2X2_FLAG_MAG_CAL_Y;
|
||||
if(sub_protocol==JXD506)
|
||||
{
|
||||
// Channel 11
|
||||
if (CH11_SW)
|
||||
flags2 |= V2X2_FLAG_EMERGENCY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Channel 10
|
||||
if (CH10_SW)
|
||||
flags2 |= V2X2_FLAG_MAG_CAL_X;
|
||||
// Channel 11
|
||||
if (CH11_SW)
|
||||
flags2 |= V2X2_FLAG_MAG_CAL_Y;
|
||||
}
|
||||
}
|
||||
// TX id
|
||||
packet[7] = rx_tx_addr[1];
|
||||
packet[8] = rx_tx_addr[2];
|
||||
packet[9] = rx_tx_addr[3];
|
||||
// empty
|
||||
// flags
|
||||
packet[10] = flags2;
|
||||
packet[11] = 0x00;
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x00;
|
||||
//
|
||||
if(sub_protocol==JXD506)
|
||||
{
|
||||
// Channel 10
|
||||
if (CH10_SW)
|
||||
packet[11] = V2X2_FLAG_START_STOP;
|
||||
// Channel 12
|
||||
if(CH12_SW)
|
||||
packet[11] |= V2X2_FLAG_CAMERA_UP;
|
||||
else if(Channel_data[CH12] < CHANNEL_MIN_COMMAND)
|
||||
packet[11] |= V2X2_FLAG_CAMERA_DN;
|
||||
packet[12] = 0x40;
|
||||
packet[13] = 0x40;
|
||||
}
|
||||
packet[14] = flags;
|
||||
add_pkt_checksum();
|
||||
V2X2_add_pkt_checksum();
|
||||
|
||||
packet_sent = 0;
|
||||
uint8_t rf_ch = hopping_frequency[hopping_frequency_no >> 1];
|
||||
@@ -213,7 +232,6 @@ void send_packet(uint8_t bind)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, V2X2_PAYLOADSIZE);
|
||||
++packet_counter;
|
||||
packet_sent = 1;
|
||||
|
||||
if (! hopping_frequency_no)
|
||||
@@ -234,40 +252,37 @@ uint16_t ReadV2x2()
|
||||
return 150;
|
||||
break;
|
||||
case V202_BIND2:
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED) {
|
||||
return PACKET_CHKTIME;
|
||||
}
|
||||
send_packet(1);
|
||||
if (--counter == 0) {
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
|
||||
return V2X2_PACKET_CHKTIME;
|
||||
V2X2_send_packet(1);
|
||||
if (--bind_counter == 0)
|
||||
{
|
||||
phase = V202_DATA;
|
||||
BIND_DONE;
|
||||
}
|
||||
break;
|
||||
case V202_DATA:
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED) {
|
||||
return PACKET_CHKTIME;
|
||||
}
|
||||
send_packet(0);
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
|
||||
return V2X2_PACKET_CHKTIME;
|
||||
V2X2_send_packet(0);
|
||||
break;
|
||||
}
|
||||
// Packet every 4ms
|
||||
return PACKET_PERIOD;
|
||||
return V2X2_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initV2x2()
|
||||
{
|
||||
flags=0;
|
||||
packet_counter = 0;
|
||||
v202_init();
|
||||
//
|
||||
if (IS_AUTOBIND_FLAG_on)
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
counter = BIND_COUNT;
|
||||
bind_counter = V2X2_BIND_COUNT;
|
||||
phase = V202_INIT2;
|
||||
}
|
||||
else
|
||||
phase = V202_INIT2_NO_BIND;
|
||||
set_tx_id();
|
||||
V2X2_set_tx_id();
|
||||
return 50000;
|
||||
}
|
||||
|
||||
|
||||
195
Multiprotocol/V761_nrf24l01.ino
Normal file
195
Multiprotocol/V761_nrf24l01.ino
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
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/>.
|
||||
|
||||
Thanks to Goebish ,Ported from his deviation firmware
|
||||
*/
|
||||
|
||||
#if defined(V761_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define V761_PACKET_PERIOD 7060 // Timeout for callback in uSec
|
||||
#define V761_INITIAL_WAIT 500
|
||||
#define V761_PACKET_SIZE 8
|
||||
#define V761_BIND_COUNT 200
|
||||
|
||||
//Fx chan management
|
||||
#define V761_BIND_FREQ 0x28
|
||||
#define V761_RF_NUM_CHANNELS 3
|
||||
|
||||
enum
|
||||
{
|
||||
V761_BIND1 = 0,
|
||||
V761_BIND2,
|
||||
V761_DATA
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) V761_set_checksum()
|
||||
{
|
||||
uint8_t checksum = packet[0];
|
||||
for(uint8_t i=1; i<V761_PACKET_SIZE-2; i++)
|
||||
checksum += packet[i];
|
||||
if(phase == V761_BIND1)
|
||||
{
|
||||
packet[6] = checksum ^ 0xff;
|
||||
packet[7] = packet[6];
|
||||
}
|
||||
else
|
||||
{
|
||||
checksum += packet[6];
|
||||
packet[7] = checksum ^ 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((unused)) V761_send_packet()
|
||||
{
|
||||
if(phase != V761_DATA)
|
||||
{
|
||||
packet[0] = rx_tx_addr[0];
|
||||
packet[1] = rx_tx_addr[1];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = rx_tx_addr[3];
|
||||
packet[4] = hopping_frequency[1];
|
||||
packet[5] = hopping_frequency[2];
|
||||
if(phase == V761_BIND2)
|
||||
packet[6] = 0xf0; // ?
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0] = convert_channel_8b(THROTTLE); // throttle
|
||||
packet[1] = convert_channel_8b(RUDDER)>>1; // rudder
|
||||
packet[2] = convert_channel_8b(ELEVATOR)>>1; // elevator
|
||||
packet[3] = convert_channel_8b(AILERON)>>1; // aileron
|
||||
packet[5] = (packet_count++ / 3)<<6;
|
||||
packet[4] = (packet[5] == 0x40) ? 0x1a : 0x20;
|
||||
|
||||
// Channel 5 - Gyro mode is packet 5
|
||||
if(CH5_SW) // Mode Expert Gyro off
|
||||
flags = 0x0c;
|
||||
else
|
||||
if(Channel_data[CH5] < CHANNEL_MIN_COMMAND)
|
||||
flags = 0x08; // Beginer mode (Gyro on, yaw and pitch rate limited)
|
||||
else
|
||||
flags = 0x0a; // Mid Mode ( Gyro on no rate limits)
|
||||
packet[5] |= flags;
|
||||
packet[6] = 0x80; // unknown
|
||||
|
||||
//packet counter
|
||||
if(packet_count >= 12)
|
||||
packet_count = 0;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
if(hopping_frequency_no >= V761_RF_NUM_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
}
|
||||
V761_set_checksum();
|
||||
// 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();
|
||||
XN297_WritePayload(packet, V761_PACKET_SIZE);
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) V761_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
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_03_SETUP_AW, 0x02); // set address length (4 bytes)
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
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);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) V761_initialize_txid()
|
||||
{
|
||||
// TODO: try arbitrary rx_tx_addr & frequencies (except hopping_frequency[0])
|
||||
switch(RX_num%3)
|
||||
{
|
||||
case 1: //Dump from air on Protonus TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\xE8\xE4\x45\x09",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x0D\x21\x44",3);
|
||||
break;
|
||||
case 2: //Dump from air on mshagg2 TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\xAE\xD1\x45\x09",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x13\x1D\x4A",3);
|
||||
break;
|
||||
default: //Dump from SPI
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\x6f\x2c\xb1\x93",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x14\x1e\x4b",3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t V761_callback()
|
||||
{
|
||||
switch(phase)
|
||||
{
|
||||
case V761_BIND1:
|
||||
if(bind_counter)
|
||||
bind_counter--;
|
||||
packet_count ++;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, V761_BIND_FREQ);
|
||||
XN297_SetTXAddr((uint8_t*)"\x34\x43\x10\x10", 4);
|
||||
V761_send_packet();
|
||||
if(packet_count >= 20)
|
||||
{
|
||||
packet_count = 0;
|
||||
phase = V761_BIND2;
|
||||
}
|
||||
return 15730;
|
||||
case V761_BIND2:
|
||||
if(bind_counter)
|
||||
bind_counter--;
|
||||
packet_count ++;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[0]);
|
||||
XN297_SetTXAddr(rx_tx_addr, 4);
|
||||
V761_send_packet();
|
||||
if(bind_counter == 0)
|
||||
{
|
||||
phase = V761_DATA;
|
||||
BIND_DONE;
|
||||
}
|
||||
else if(packet_count >= 20)
|
||||
{
|
||||
packet_count = 0;
|
||||
phase = V761_BIND1;
|
||||
}
|
||||
return 15730;
|
||||
case V761_DATA:
|
||||
V761_send_packet();
|
||||
break;
|
||||
}
|
||||
return V761_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initV761(void)
|
||||
{
|
||||
BIND_IN_PROGRESS;
|
||||
bind_counter = V761_BIND_COUNT;
|
||||
V761_initialize_txid();
|
||||
phase = V761_BIND1;
|
||||
V761_init();
|
||||
hopping_frequency_no = 0;
|
||||
packet_count = 0;
|
||||
return V761_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
165
Multiprotocol/V911S_nrf24l01.ino
Normal file
165
Multiprotocol/V911S_nrf24l01.ino
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
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 V911S
|
||||
|
||||
#if defined(V911S_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297l.h"
|
||||
|
||||
//#define V911S_ORIGINAL_ID
|
||||
|
||||
#define V911S_PACKET_PERIOD 5000
|
||||
#define V911S_BIND_PACKET_PERIOD 3300
|
||||
#define V911S_INITIAL_WAIT 500
|
||||
#define V911S_PACKET_SIZE 16
|
||||
#define V911S_RF_BIND_CHANNEL 35
|
||||
#define V911S_NUM_RF_CHANNELS 8
|
||||
#define V911S_BIND_COUNT 200
|
||||
|
||||
// flags going to packet[1]
|
||||
#define V911S_FLAG_EXPERT 0x04
|
||||
// flags going to packet[2]
|
||||
#define V911S_FLAG_CALIB 0x01
|
||||
|
||||
static void __attribute__((unused)) V911S_send_packet(uint8_t bind)
|
||||
{
|
||||
if(bind)
|
||||
{
|
||||
packet[0] = 0x42;
|
||||
packet[1] = 0x4E;
|
||||
packet[2] = 0x44;
|
||||
for(uint8_t i=0;i<5;i++)
|
||||
packet[i+3] = rx_tx_addr[i];
|
||||
for(uint8_t i=0;i<8;i++)
|
||||
packet[i+8] = hopping_frequency[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t channel=hopping_frequency_no;
|
||||
if(rf_ch_num&1)
|
||||
{
|
||||
if((hopping_frequency_no&1)==0)
|
||||
channel+=8;
|
||||
channel>>=1;
|
||||
}
|
||||
if(rf_ch_num&2)
|
||||
channel=7-channel;
|
||||
packet[ 0]=(rf_ch_num<<3)|channel;
|
||||
packet[ 1]=V911S_FLAG_EXPERT; // short press on left button
|
||||
packet[ 2]=GET_FLAG(CH5_SW,V911S_FLAG_CALIB); // long press on right button
|
||||
memset(packet+3, 0x00, V911S_PACKET_SIZE - 3);
|
||||
//packet[3..6]=trims TAER signed
|
||||
uint16_t ch=convert_channel_16b_limit(THROTTLE ,0,0x7FF);
|
||||
packet[ 7] = ch;
|
||||
packet[ 8] = ch>>8;
|
||||
ch=convert_channel_16b_limit(AILERON ,0x7FF,0);
|
||||
packet[ 8]|= ch<<3;
|
||||
packet[ 9] = ch>>5;
|
||||
ch=convert_channel_16b_limit(ELEVATOR,0,0x7FF);
|
||||
packet[10] = ch;
|
||||
packet[11] = ch>>8;
|
||||
ch=convert_channel_16b_limit(RUDDER ,0x7FF,0);
|
||||
packet[11]|= ch<<3;
|
||||
packet[12] = ch>>5;
|
||||
}
|
||||
|
||||
if (!bind)
|
||||
{
|
||||
XN297L_Hopping(channel);
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no&=7; // 8 RF channels
|
||||
}
|
||||
|
||||
XN297L_WritePayload(packet, V911S_PACKET_SIZE);
|
||||
|
||||
XN297L_SetPower(); // Set tx_power
|
||||
XN297L_SetFreqOffset(); // Set frequency offset
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) V911S_init()
|
||||
{
|
||||
XN297L_Init();
|
||||
XN297L_SetTXAddr((uint8_t *)"KNBND",5); // Bind address
|
||||
XN297L_HoppingCalib(V911S_NUM_RF_CHANNELS); // Calibrate all channels
|
||||
XN297L_RFChannel(V911S_RF_BIND_CHANNEL); // Set bind channel
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) V911S_initialize_txid()
|
||||
{
|
||||
//channels
|
||||
uint8_t offset=rx_tx_addr[3]%5; // 0-4
|
||||
for(uint8_t i=0;i<V911S_NUM_RF_CHANNELS;i++)
|
||||
hopping_frequency[i]=0x10+i*5+offset;
|
||||
if(!offset) hopping_frequency[0]++;
|
||||
|
||||
// channels order
|
||||
rf_ch_num=random(0xfefefefe)&0x03; // 0-3
|
||||
}
|
||||
|
||||
uint16_t V911S_callback()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
V911S_send_packet(0);
|
||||
else
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
packet_period=V911S_PACKET_PERIOD;
|
||||
}
|
||||
else
|
||||
{
|
||||
V911S_send_packet(1);
|
||||
bind_counter--;
|
||||
if(bind_counter==100) // same as original TX...
|
||||
packet_period=V911S_BIND_PACKET_PERIOD*3;
|
||||
}
|
||||
}
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initV911S(void)
|
||||
{
|
||||
V911S_initialize_txid();
|
||||
#ifdef V911S_ORIGINAL_ID
|
||||
rx_tx_addr[0]=0xA5;
|
||||
rx_tx_addr[1]=0xFF;
|
||||
rx_tx_addr[2]=0x70;
|
||||
rx_tx_addr[3]=0x8D;
|
||||
rx_tx_addr[4]=0x76;
|
||||
for(uint8_t i=0;i<V911S_NUM_RF_CHANNELS;i++)
|
||||
hopping_frequency[i]=0x10+i*5;
|
||||
hopping_frequency[0]++;
|
||||
rf_ch_num=0;
|
||||
#endif
|
||||
|
||||
V911S_init();
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
bind_counter = V911S_BIND_COUNT;
|
||||
packet_period= V911S_BIND_PACKET_PERIOD;
|
||||
}
|
||||
else
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
packet_period= V911S_PACKET_PERIOD;
|
||||
}
|
||||
hopping_frequency_no=0;
|
||||
return V911S_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
320
Multiprotocol/Validate.h
Normal file
320
Multiprotocol/Validate.h
Normal file
@@ -0,0 +1,320 @@
|
||||
// Check selected board type
|
||||
#if defined (STM32_BOARD) && defined (ORANGE_TX)
|
||||
#error You must comment the board type STM32_BOARD in _Config.h to compile ORANGE_TX
|
||||
#endif
|
||||
#if not defined (ORANGE_TX) && not defined (STM32_BOARD)
|
||||
//Atmega328p
|
||||
#if not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_MULTI_NO_BOOT) && not defined(ARDUINO_MULTI_FLASH_FROM_TX) && not defined(ARDUINO_AVR_MINI) && not defined(ARDUINO_AVR_NANO)
|
||||
#error You must select one of these boards: "Multi 4-in-1", "Arduino Pro or Pro Mini" or "Arduino Mini"
|
||||
#endif
|
||||
#if F_CPU != 16000000L || not defined(__AVR_ATmega328P__)
|
||||
#error You must select the processor type "ATmega328(5V, 16MHz)"
|
||||
#endif
|
||||
#endif
|
||||
#if defined (STM32_BOARD) && not defined (ORANGE_TX)
|
||||
//STM32
|
||||
#if not defined(ARDUINO_GENERIC_STM32F103C) && not defined(ARDUINO_MULTI_STM32_FLASH_FROM_TX) && not defined(ARDUINO_MULTI_STM32_NO_BOOT) && not defined(ARDUINO_MULTI_STM32_WITH_BOOT)
|
||||
#error You must select one of these boards: "Multi 4-in-1 (STM32F103CB)" or "Generic STM32F103C series"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Check for minimum version of multi-module boards
|
||||
#define MIN_AVR_BOARD 107
|
||||
#define MIN_ORX_BOARD 107
|
||||
#define MIN_STM32_BOARD 114
|
||||
//AVR
|
||||
#if (defined(ARDUINO_MULTI_NO_BOOT) && ARDUINO_MULTI_NO_BOOT < MIN_AVR_BOARD) || (defined(ARDUINO_MULTI_FLASH_FROM_TX) && ARDUINO_MULTI_FLASH_FROM_TX < MIN_AVR_BOARD)
|
||||
#error You need to update your Multi 4-in-1 board definition. Open Boards Manager and update to the latest version of the Multi 4-in-1 AVR Boards.
|
||||
#endif
|
||||
//OrangeRX
|
||||
#if (defined(ARDUINO_MULTI_ORANGERX) && ARDUINO_MULTI_ORANGERX < MIN_ORX_BOARD)
|
||||
#error You need to update your Multi 4-in-1 board definition. Open Boards Manager and update to the latest version of the Multi 4-in-1 AVR Boards.
|
||||
#endif
|
||||
//STM32
|
||||
#if (defined(ARDUINO_MULTI_STM32_NO_BOOT) && ARDUINO_MULTI_STM32_NO_BOOT < MIN_STM32_BOARD) || (defined(ARDUINO_MULTI_STM32_FLASH_FROM_TX) && ARDUINO_MULTI_STM32_FLASH_FROM_TX < MIN_STM32_BOARD) || (defined(ARDUINO_MULTI_STM32_WITH_BOOT) && ARDUINO_MULTI_STM32_WITH_BOOT < MIN_STM32_BOARD)
|
||||
#error You need to update your Multi 4-in-1 board definition. Open Boards Manager and update to the latest version of the Multi 4-in-1 STM32 Board.
|
||||
#endif
|
||||
|
||||
// Error if CHECK_FOR_BOOTLOADER is not enabled but a FLASH_FROM_TX board is selected
|
||||
#if (defined(ARDUINO_MULTI_FLASH_FROM_TX) || defined(ARDUINO_MULTI_STM32_FLASH_FROM_TX)) &! defined(CHECK_FOR_BOOTLOADER)
|
||||
#if defined(STM32_BOARD)
|
||||
#error "You have selected the 'Flash from TX' upload method but not enabled CHECK_FOR_BOOTLOADER."
|
||||
#else
|
||||
#error "You have selected the 'Flash from TX' bootloader but not enabled CHECK_FOR_BOOTLOADER."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Error if CHECK_FOR_BOOTLOADER is enabled but the 'Flash from TX' bootloader
|
||||
#if defined(ARDUINO_MULTI_NO_BOOT) && defined(CHECK_FOR_BOOTLOADER)
|
||||
#error "You have enabled CHECK_FOR_BOOTLOADER but not selected the 'Flash from TX' bootloader."
|
||||
#endif
|
||||
|
||||
//Check number of banks
|
||||
#if NBR_BANKS < 1 || NBR_BANKS > 5
|
||||
#error "You need to select a number of banks between 1 and 5."
|
||||
#endif
|
||||
|
||||
//Check failsafe throttle value
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
#if ( FAILSAFE_THROTTLE_LOW < -125 ) || ( FAILSAFE_THROTTLE_LOW > 125 )
|
||||
#error "The failsafe value for throttle is outside of the range -125..125."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Check forced tuning values are valid
|
||||
#ifdef FORCE_FRSKYD_TUNING
|
||||
#if ( FORCE_FRSKYD_TUNING < -127 ) || ( FORCE_FRSKYD_TUNING > 127 )
|
||||
#error "The FrSkyD forced frequency tuning value is outside of the range -127..127."
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FORCE_FRSKYV_TUNING
|
||||
#if ( FORCE_FRSKYV_TUNING < -127 ) || ( FORCE_FRSKYV_TUNING > 127 )
|
||||
#error "The FrSkyV forced frequency tuning value is outside of the range -127..127."
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FORCE_FRSKYX_TUNING
|
||||
#if ( FORCE_FRSKYX_TUNING < -127 ) || ( FORCE_FRSKYX_TUNING > 127 )
|
||||
#error "The FrSkyX forced frequency tuning value is outside of the range -127..127."
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FORCE_SFHSS_TUNING
|
||||
#if ( FORCE_SFHSS_TUNING < -127 ) || ( FORCE_SFHSS_TUNING > 127 )
|
||||
#error "The SFHSS forced frequency tuning value is outside of the range -127..127."
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FORCE_CORONA_TUNING
|
||||
#if ( FORCE_CORONA_TUNING < -127 ) || ( FORCE_CORONA_TUNING > 127 )
|
||||
#error "The CORONA forced frequency tuning value is outside of the range -127..127."
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FORCE_REDPINE_TUNING
|
||||
#if ( FORCE_REDPINE_TUNING < -127 ) || ( FORCE_REDPINE_TUNING > 127 )
|
||||
#error "The REDPINE forced frequency tuning value is outside of the range -127..127."
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FORCE_HITEC_TUNING
|
||||
#if ( FORCE_HITEC_TUNING < -127 ) || ( FORCE_HITEC_TUNING > 127 )
|
||||
#error "The HITEC forced frequency tuning value is outside of the range -127..127."
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FORCE_FLYSKY_TUNING
|
||||
#if ( FORCE_FLYSKY_TUNING < -300 ) || ( FORCE_FLYSKY_TUNING > 300 )
|
||||
#error "The Flysky forced frequency tuning value is outside of the range -300..300."
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FORCE_HUBSAN_TUNING
|
||||
#if ( FORCE_HUBSAN_TUNING < -300 ) || ( FORCE_HUBSAN_TUNING > 300 )
|
||||
#error "The Hubsan forced frequency tuning value is outside of the range -300..300."
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FORCE_AFHDS2A_TUNING
|
||||
#if ( FORCE_AFHDS2A_TUNING < -300 ) || ( FORCE_AFHDS2A_TUNING > 300 )
|
||||
#error "The AFHDS2A forced frequency tuning value is outside of the range -300..300."
|
||||
#endif
|
||||
#endif
|
||||
#ifndef USE_A7105_CH15_TUNING
|
||||
#ifndef FORCE_FLYSKY_TUNING
|
||||
#define FORCE_FLYSKY_TUNING 0
|
||||
#endif
|
||||
#ifndef FORCE_HUBSAN_TUNING
|
||||
#define FORCE_HUBSAN_TUNING 0
|
||||
#endif
|
||||
#ifndef FORCE_AFHDS2A_TUNING
|
||||
#define FORCE_AFHDS2A_TUNING 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//Change/Force configuration if OrangeTX
|
||||
#ifdef ORANGE_TX
|
||||
#undef ENABLE_PPM // Disable PPM for OrangeTX module
|
||||
#undef A7105_INSTALLED // Disable A7105 for OrangeTX module
|
||||
#undef A7105_CSN_pin
|
||||
#undef CC2500_INSTALLED // Disable CC2500 for OrangeTX module
|
||||
#undef CC25_CSN_pin
|
||||
#undef NRF24L01_INSTALLED // Disable NRF for OrangeTX module
|
||||
#undef NRF_CSN_pin
|
||||
#define TELEMETRY // Enable telemetry
|
||||
#define INVERT_TELEMETRY // Enable invert telemetry
|
||||
#define DSM_TELEMETRY // Enable DSM telemetry
|
||||
#endif
|
||||
|
||||
//Make sure protocols are selected correctly
|
||||
#ifndef A7105_INSTALLED
|
||||
#undef FLYSKY_A7105_INO
|
||||
#undef HUBSAN_A7105_INO
|
||||
#undef AFHDS2A_A7105_INO
|
||||
#undef BUGS_A7105_INO
|
||||
#endif
|
||||
#ifndef CYRF6936_INSTALLED
|
||||
#undef DEVO_CYRF6936_INO
|
||||
#undef DSM_CYRF6936_INO
|
||||
#undef J6PRO_CYRF6936_INO
|
||||
#undef WFLY_CYRF6936_INO
|
||||
#undef WK2x01_CYRF6936_INO
|
||||
#undef TRAXXAS_CYRF6936_INO
|
||||
#endif
|
||||
#ifndef CC2500_INSTALLED
|
||||
#undef FRSKYD_CC2500_INO
|
||||
#undef FRSKYV_CC2500_INO
|
||||
#undef FRSKYX_CC2500_INO
|
||||
#undef SFHSS_CC2500_INO
|
||||
#undef CORONA_CC2500_INO
|
||||
#undef REDPINE_CC2500_INO
|
||||
#undef HITEC_CC2500_INO
|
||||
#undef XN297L_CC2500_EMU
|
||||
#endif
|
||||
#ifndef NRF24L01_INSTALLED
|
||||
#undef BAYANG_NRF24L01_INO
|
||||
#undef CG023_NRF24L01_INO
|
||||
#undef CX10_NRF24L01_INO
|
||||
#undef ESKY_NRF24L01_INO
|
||||
#undef HISKY_NRF24L01_INO
|
||||
#undef KF606_NRF24L01_INO
|
||||
#undef KN_NRF24L01_INO
|
||||
#undef SLT_NRF24L01_INO
|
||||
#undef SYMAX_NRF24L01_INO
|
||||
#undef V2X2_NRF24L01_INO
|
||||
#undef YD717_NRF24L01_INO
|
||||
#undef MT99XX_NRF24L01_INO
|
||||
#undef MJXQ_NRF24L01_INO
|
||||
#undef SHENQI_NRF24L01_INO
|
||||
#undef FY326_NRF24L01_INO
|
||||
#undef FQ777_NRF24L01_INO
|
||||
#undef ASSAN_NRF24L01_INO
|
||||
#undef HONTAI_NRF24L01_INO
|
||||
#undef Q303_NRF24L01_INO
|
||||
#undef GW008_NRF24L01_INO
|
||||
#undef GD00X_NRF24L01_INO
|
||||
#undef DM002_NRF24L01_INO
|
||||
#undef CABELL_NRF24L01_INO
|
||||
#undef ESKY150_NRF24L01_INO
|
||||
#undef H8_3D_NRF24L01_INO
|
||||
#undef CFLIE_NRF24L01_INO
|
||||
#undef BUGSMINI_NRF24L01_INO
|
||||
#undef NCC1701_NRF24L01_INO
|
||||
#undef E01X_NRF24L01_INO
|
||||
#undef V761_NRF24L01_INO
|
||||
#undef V911S_NRF24L01_INO
|
||||
#undef XN297L_CC2500_EMU
|
||||
#undef POTENSIC_NRF24L01_INO
|
||||
#endif
|
||||
|
||||
//Make sure telemetry is selected correctly
|
||||
#ifndef TELEMETRY
|
||||
#undef INVERT_TELEMETRY
|
||||
#undef AFHDS2A_FW_TELEMETRY
|
||||
#undef AFHDS2A_HUB_TELEMETRY
|
||||
#undef HITEC_FW_TELEMETRY
|
||||
#undef HITEC_HUB_TELEMETRY
|
||||
#undef BAYANG_HUB_TELEMETRY
|
||||
#undef CABELL_HUB_TELEMETRY
|
||||
#undef HUBSAN_HUB_TELEMETRY
|
||||
#undef BUGS_HUB_TELEMETRY
|
||||
#undef NCC1701_HUB_TELEMETRY
|
||||
#undef HUB_TELEMETRY
|
||||
#undef SPORT_TELEMETRY
|
||||
#undef SPORT_POLLING
|
||||
#undef DSM_TELEMETRY
|
||||
#undef MULTI_STATUS
|
||||
#undef MULTI_TELEMETRY
|
||||
#else
|
||||
#if defined MULTI_TELEMETRY && not defined INVERT_TELEMETRY
|
||||
#warning MULTI_TELEMETRY has been defined but not INVERT_TELEMETRY. They should be both enabled for OpenTX telemetry and status to work.
|
||||
#endif
|
||||
#if not defined(BAYANG_NRF24L01_INO)
|
||||
#undef BAYANG_HUB_TELEMETRY
|
||||
#endif
|
||||
#if not defined(NCC1701_NRF24L01_INO)
|
||||
#undef NCC1701_HUB_TELEMETRY
|
||||
#endif
|
||||
#if not ( defined(BUGS_A7105_INO) || defined(BUGSMINI_NRF24L01_INO) )
|
||||
#undef BUGS_HUB_TELEMETRY
|
||||
#endif
|
||||
#if not defined(CABELL_NRF24L01_INO)
|
||||
#undef CABELL_HUB_TELEMETRY
|
||||
#endif
|
||||
#if not defined(HUBSAN_A7105_INO)
|
||||
#undef HUBSAN_HUB_TELEMETRY
|
||||
#endif
|
||||
#if not defined(AFHDS2A_A7105_INO)
|
||||
#undef AFHDS2A_HUB_TELEMETRY
|
||||
#undef AFHDS2A_FW_TELEMETRY
|
||||
#endif
|
||||
#if not defined(HITEC_CC2500_INO)
|
||||
#undef HITEC_HUB_TELEMETRY
|
||||
#undef HITEC_FW_TELEMETRY
|
||||
#endif
|
||||
#if not defined(FRSKYD_CC2500_INO)
|
||||
#undef HUB_TELEMETRY
|
||||
#endif
|
||||
#if not defined(FRSKYX_CC2500_INO)
|
||||
#undef SPORT_TELEMETRY
|
||||
#undef SPORT_POLLING
|
||||
#endif
|
||||
#if not defined (SPORT_TELEMETRY) || not defined (STM32_BOARD)
|
||||
#undef SPORT_POLLING
|
||||
#endif
|
||||
#if defined SPORT_POLLING && not defined INVERT_TELEMETRY
|
||||
#error SPORT_POLLING has been defined but not INVERT_TELEMETRY. They should be both enabled to work.
|
||||
#endif
|
||||
#if not defined(DSM_CYRF6936_INO)
|
||||
#undef DSM_TELEMETRY
|
||||
#endif
|
||||
#if not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BUGS_HUB_TELEMETRY) && not defined(NCC1701_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY)
|
||||
#undef TELEMETRY
|
||||
#undef INVERT_TELEMETRY
|
||||
#undef SPORT_POLLING
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//Make sure TX is defined correctly
|
||||
#ifndef AILERON
|
||||
#error You must select a correct channel order.
|
||||
#endif
|
||||
#if not defined(PPM_MAX_100) || not defined(PPM_MIN_100)
|
||||
#error You must set correct PPM end points for your TX.
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_BIND_CH)
|
||||
#if BIND_CH<4
|
||||
#error BIND_CH must be above 4.
|
||||
#endif
|
||||
#if BIND_CH>16
|
||||
#error BIND_CH must be below or equal to 16.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(DSM_THROTTLE_KILL_CH)
|
||||
#if DSM_THROTTLE_KILL_CH<4
|
||||
#error DSM_THROTTLE_KILL_CH must be above 4.
|
||||
#endif
|
||||
#if DSM_THROTTLE_KILL_CH>16
|
||||
#error DSM_THROTTLE_KILL_CH must be below or equal to 16.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(AFHDS2A_LQI_CH)
|
||||
#if AFHDS2A_LQI_CH<4
|
||||
#error AFHDS2A_LQI_CH must be above 4.
|
||||
#endif
|
||||
#if AFHDS2A_LQI_CH>14
|
||||
#error AFHDS2A_LQI_CH must be below or equal to 14.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MIN_PPM_CHANNELS>16
|
||||
#error MIN_PPM_CHANNELS must be below or equal to 16. The default for this value is 4.
|
||||
#endif
|
||||
#if MIN_PPM_CHANNELS<2
|
||||
#error MIN_PPM_CHANNELS must be larger than 1. The default for this value is 4.
|
||||
#endif
|
||||
#if MAX_PPM_CHANNELS<MIN_PPM_CHANNELS
|
||||
#error MAX_PPM_CHANNELS must be higher than MIN_PPM_CHANNELS. The default for this value is 16.
|
||||
#endif
|
||||
#if MAX_PPM_CHANNELS>16
|
||||
#error MAX_PPM_CHANNELS must be below or equal to 16. The default for this value is 16.
|
||||
#endif
|
||||
|
||||
#if defined (STM32_BOARD) && defined (DEBUG_SERIAL) && defined (NRF24L01_INSTALLED)
|
||||
#define XN297DUMP_NRF24L01_INO
|
||||
#endif
|
||||
307
Multiprotocol/WFLY_cyrf6936.ino
Normal file
307
Multiprotocol/WFLY_cyrf6936.ino
Normal file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
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(WFLY_CYRF6936_INO)
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
//#define WFLY_FORCE_ID
|
||||
#define WFLY_BIND_COUNT 1500 // around 15s
|
||||
#define WFLY_NUM_FREQUENCE 4
|
||||
#define WFLY_BIND_CHANNEL 0x09
|
||||
|
||||
enum {
|
||||
WFLY_BIND_TX=0,
|
||||
WFLY_BIND_PREP_RX,
|
||||
WFLY_BIND_RX,
|
||||
WFLY_PREP_DATA,
|
||||
WFLY_DATA,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM WFLY_sop_bind[]={ 0x5A, 0xCC, 0xAE, 0x46, 0xB6, 0x31, 0xAE, 0x46 };
|
||||
const uint8_t PROGMEM WFLY_sop_data[]={ 0xEF, 0x64, 0xB0, 0x2A, 0xD2, 0x8F, 0xB1, 0x2A };
|
||||
|
||||
//Most of the bytes are unknown... 1C A7 looks to be the bind ID, BF 13 is the TX ID, 15 is the channel used to send the hopping frequencies.
|
||||
const uint8_t PROGMEM WFLY_bind_packet[]={ 0x1C, 0xA7, 0x60, 0x04, 0x04, 0xBF, 0x13, 0x15, 0xC5, 0x40, 0x8A, 0x37, 0xE0, 0xE8, 0x03, 0xA3 };
|
||||
|
||||
|
||||
const uint8_t PROGMEM WFLY_init_vals[][2] = {
|
||||
//Init from dump
|
||||
{CYRF_1D_MODE_OVERRIDE, 0x19}, // Reset
|
||||
{CYRF_32_AUTO_CAL_TIME, 0x3C}, // Default init value
|
||||
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
|
||||
{CYRF_1B_TX_OFFSET_LSB, 0x55}, // Default init value
|
||||
{CYRF_1C_TX_OFFSET_MSB, 0x05}, // Default init value
|
||||
{CYRF_06_RX_CFG, 0x48 | 0x02}, // LNA enabled, Fast Turn Mode enabled, adding overwrite enable to not lockup RX
|
||||
{CYRF_10_FRAMING_CFG, 0xE8}, // SOP enable
|
||||
{CYRF_03_TX_CFG, 0x08 | CYRF_BIND_POWER}, // Original=0x0F, 8DR Mode, 32 chip codes
|
||||
{CYRF_0C_XTAL_CTRL, 0xC4}, // Enable XOUT as GPIO
|
||||
{CYRF_0D_IO_CFG, 0x04}, // Enable PACTL as GPIO
|
||||
{CYRF_0F_XACT_CFG, 0x21}, // Abort current operation
|
||||
{CYRF_1E_RX_OVERRIDE, 0x00}, // Accept packets with 0 seed for bind
|
||||
{CYRF_15_CRC_SEED_LSB, 0x00}, // CRC seed for bind
|
||||
{CYRF_16_CRC_SEED_MSB, 0x00}, // CRC seed for bind
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) WFLY_cyrf_bind_config()
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(WFLY_init_vals) / 2; i++)
|
||||
CYRF_WriteRegister(pgm_read_byte_near(&WFLY_init_vals[i][0]), pgm_read_byte_near(&WFLY_init_vals[i][1]));
|
||||
|
||||
CYRF_PROGMEM_ConfigSOPCode(WFLY_sop_bind);
|
||||
CYRF_ConfigRFChannel(WFLY_BIND_CHANNEL);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) WFLY_cyrf_data_config()
|
||||
{
|
||||
for(uint8_t i = 0; i < (sizeof(WFLY_init_vals) / 2)-3; i++)
|
||||
CYRF_WriteRegister(pgm_read_byte_near(&WFLY_init_vals[i][0]), pgm_read_byte_near(&WFLY_init_vals[i][1]));
|
||||
|
||||
//CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x08); // Do not accept CRC with 0 seed but not needed since the RX is not sending any data...
|
||||
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB, rx_tx_addr[2]);
|
||||
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB, rx_tx_addr[3]);
|
||||
|
||||
CYRF_PROGMEM_ConfigSOPCode(WFLY_sop_data);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
}
|
||||
|
||||
static uint16_t __attribute__((unused)) WFLY_send_data_packet()
|
||||
{
|
||||
#ifdef USE_CYRF6936_CH15_TUNING
|
||||
static uint16_t Channel15=1024;
|
||||
#endif
|
||||
packet_count++;
|
||||
packet[0] = rx_tx_addr[2];
|
||||
packet[1] = rx_tx_addr[3];
|
||||
if(packet_count%4==3)
|
||||
{ // Send the hopping frequencies
|
||||
packet[2]=0x70; // packet type
|
||||
packet[3]=0x04; // unknown
|
||||
packet[4]=0x00; // unknown
|
||||
packet[5]=0x04; // unknown
|
||||
packet[6]=hopping_frequency[0];
|
||||
packet[7]=hopping_frequency[0];
|
||||
packet[8]=hopping_frequency[1];
|
||||
packet[9]=hopping_frequency[2];
|
||||
len=10; // packet[10] contains the checksum
|
||||
}
|
||||
else
|
||||
{ // Send sticks packet
|
||||
uint8_t nbr_ch=option;
|
||||
if(nbr_ch<4) nbr_ch=9; // 4 channels min can be sent, default to 9
|
||||
if(nbr_ch>9) nbr_ch=9; // 9 channels max can be sent
|
||||
packet[2]=nbr_ch-3; // nbr of channels to follow
|
||||
packet[3]=packet_count>>2; // packet counter 0x00..0x3F
|
||||
len=4;
|
||||
for(uint8_t i=0;i<3;i++)
|
||||
{ // Channels
|
||||
uint16_t ch = convert_channel_16b_nolimit(i*4+0,151,847);
|
||||
uint8_t offset=i*5;
|
||||
packet[3+offset]|=ch<<6;
|
||||
packet[4+offset]=ch>>2;
|
||||
len++;
|
||||
if(--nbr_ch==0) break;
|
||||
ch = convert_channel_16b_nolimit(i*4+1,151,847);
|
||||
packet[5+offset]=ch;
|
||||
packet[6+offset]=ch>>8;
|
||||
len+=2;
|
||||
if(--nbr_ch==0) break;
|
||||
ch = convert_channel_16b_nolimit(i*4+2,151,847);
|
||||
packet[6+offset]|=ch<<2;
|
||||
packet[7+offset]=ch>>6;
|
||||
len++;
|
||||
if(--nbr_ch==0) break;
|
||||
ch = convert_channel_16b_nolimit(i*4+3,151,847);
|
||||
packet[7+offset]|=ch<<4;
|
||||
packet[8+offset]=ch>>4;
|
||||
len++;
|
||||
if(--nbr_ch==0) break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t sum=0;
|
||||
for(uint8_t i = 0; i < len; i++)
|
||||
sum += packet[i];
|
||||
packet[len] = sum;
|
||||
|
||||
#ifdef USE_CYRF6936_CH15_TUNING
|
||||
if(Channel15!=Channel_data[CH15])
|
||||
{ // adjust frequency
|
||||
Channel15=Channel_data[CH15]+0x155; // default value is 0x555 = 0x400 + 0x155
|
||||
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, Channel15&0xFF);
|
||||
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, Channel15>>8);
|
||||
Channel15-=0x155;
|
||||
}
|
||||
#endif
|
||||
|
||||
CYRF_ConfigRFChannel(hopping_frequency[(packet_count)%4]);
|
||||
CYRF_SetPower(0x08);
|
||||
CYRF_WriteDataPacketLen(packet, len+1);
|
||||
|
||||
switch(packet_count%4)
|
||||
{
|
||||
case 0:
|
||||
return 1393;
|
||||
case 1:
|
||||
return 1330;
|
||||
case 2:
|
||||
return 1555;
|
||||
}
|
||||
return 1093; // case 3
|
||||
}
|
||||
|
||||
uint16_t ReadWFLY()
|
||||
{
|
||||
uint8_t status,len,sum=0,check=0;
|
||||
uint8_t start;
|
||||
static uint8_t retry;
|
||||
|
||||
switch(phase)
|
||||
{
|
||||
case WFLY_BIND_TX:
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
CYRF_WriteDataPacketLen(packet, sizeof(WFLY_bind_packet));
|
||||
debug("P=");
|
||||
for(uint8_t i=0;i<sizeof(WFLY_bind_packet);i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln(" , L=%02X", sizeof(WFLY_bind_packet));
|
||||
phase++;
|
||||
if(--bind_counter==0)
|
||||
{ // Switch to normal mode
|
||||
BIND_DONE;
|
||||
phase=WFLY_PREP_DATA;
|
||||
}
|
||||
return 2500;
|
||||
case WFLY_BIND_PREP_RX:
|
||||
start=micros();
|
||||
while ((uint8_t)((uint8_t)micros()-(uint8_t)start) < 200) // Wait max 200µs for TX to finish
|
||||
if((CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80) == 0x00)
|
||||
break; // Packet transmission complete
|
||||
CYRF_SetTxRxMode(RX_EN); //Receive mode
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive
|
||||
retry=10; //Timeout for RX
|
||||
phase=WFLY_BIND_RX;
|
||||
return 700;
|
||||
case WFLY_BIND_RX:
|
||||
//Read data from RX
|
||||
status = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((status & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
|
||||
status |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
|
||||
if((status & 0x07) == 0x02)
|
||||
{ // Data received with no errors
|
||||
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
||||
debugln("L=%02X",len)
|
||||
if(len==0x10)
|
||||
{
|
||||
CYRF_ReadDataPacketLen(pkt, len);
|
||||
debug("RX=");
|
||||
for(uint8_t i=0;i<0x0F;i++)
|
||||
{
|
||||
debug(" %02X",pkt[i]);
|
||||
if(pkt[i]==packet[i])
|
||||
check++; // Verify quickly the content
|
||||
sum+=pkt[i];
|
||||
}
|
||||
debugln(" %02X",pkt[15]);
|
||||
if(sum==pkt[15] && check>=10)
|
||||
{ // Good packet received
|
||||
if(pkt[2]==0x64)
|
||||
{ // Switch to normal mode
|
||||
BIND_DONE;
|
||||
phase=WFLY_PREP_DATA;
|
||||
return 10000;
|
||||
}
|
||||
memcpy((void *)packet,(void *)pkt,0x10); // Send back to the RX what we've just received with no modifications
|
||||
}
|
||||
phase=WFLY_BIND_TX;
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
if(status & 0x85 || --retry == 0)
|
||||
{ // RX error or no answer
|
||||
debugln("Abort");
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x21); // Force end state
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort
|
||||
phase=WFLY_BIND_TX; // Retry sending bind packet
|
||||
}
|
||||
return 700;
|
||||
case WFLY_PREP_DATA:
|
||||
WFLY_cyrf_data_config();
|
||||
packet_count=0;
|
||||
phase++;
|
||||
case WFLY_DATA:
|
||||
start=micros();
|
||||
while ((uint8_t)((uint8_t)micros()-(uint8_t)start) < 200)
|
||||
if((CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80) == 0x00)
|
||||
break; // Packet transmission complete
|
||||
return WFLY_send_data_packet();
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
uint16_t initWFLY()
|
||||
{
|
||||
//Random start channel
|
||||
uint8_t ch=0x0A+random(0xfefefefe)%0x0E;
|
||||
if(ch%3==0)
|
||||
ch++; // remove these channels as they seem to not be working...
|
||||
rf_ch_num=0x0C+(rx_tx_addr[1]%4)*3; // use the start channels which do not seem to work to send the hopping table instead
|
||||
|
||||
#ifdef WFLY_FORCE_ID // data taken from TX dump
|
||||
rx_tx_addr[2]=0xBF; // ID
|
||||
rx_tx_addr[3]=0x13; // ID
|
||||
ch=0x16; // value seen between 0x0A and 0x17
|
||||
rf_ch_num=0x15 // RF channel to send the current hopping table
|
||||
#endif
|
||||
|
||||
debug("ID:")
|
||||
for(uint8_t i=0;i<2;i++)
|
||||
debug(" %02X", rx_tx_addr[2+i]);
|
||||
debugln("");
|
||||
|
||||
hopping_frequency[0]=ch;
|
||||
hopping_frequency[1]=ch+0x1E;
|
||||
hopping_frequency[2]=ch+0x2D;
|
||||
hopping_frequency[3]=rf_ch_num; // RF channel used to send the current hopping table
|
||||
|
||||
debug("RF Channels:")
|
||||
for(uint8_t i=0;i<WFLY_NUM_FREQUENCE;i++)
|
||||
debug(" %02X", hopping_frequency[i]);
|
||||
debugln("");
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
bind_counter=WFLY_BIND_COUNT;
|
||||
WFLY_cyrf_bind_config();
|
||||
for(uint8_t i=0;i<sizeof(WFLY_bind_packet);i++)
|
||||
packet[i]=pgm_read_byte_near(&WFLY_bind_packet[i]);
|
||||
packet[5]=rx_tx_addr[2];
|
||||
packet[6]=rx_tx_addr[3];
|
||||
packet[7]=rf_ch_num;
|
||||
uint8_t sum=0;
|
||||
for(uint8_t i = 0; i < 15; i++)
|
||||
sum += packet[i];
|
||||
packet[15] = sum;
|
||||
phase=WFLY_BIND_TX;
|
||||
}
|
||||
else
|
||||
phase = WFLY_PREP_DATA;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
501
Multiprotocol/WK2x01_cyrf6936.ino
Normal file
501
Multiprotocol/WK2x01_cyrf6936.ino
Normal file
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
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(WK2x01_CYRF6936_INO)
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
#define WK_BIND_COUNT 2980
|
||||
#define WK_NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
|
||||
|
||||
enum {
|
||||
WK_BIND=0,
|
||||
WK_BOUND_1,
|
||||
WK_BOUND_2,
|
||||
WK_BOUND_3,
|
||||
WK_BOUND_4,
|
||||
WK_BOUND_5,
|
||||
WK_BOUND_6,
|
||||
WK_BOUND_7,
|
||||
WK_BOUND_8,
|
||||
};
|
||||
|
||||
static const uint8_t WK_sopcodes[8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
0xDF,0xB1,0xC0,0x49,0x62,0xDF,0xC1,0x49 //0x49C1DF6249C0B1DF
|
||||
};
|
||||
static const uint8_t init_2801[] = {0xc5, 0x34, 0x60, 0x00, 0x25};
|
||||
static const uint8_t init_2601[] = {0xb9, 0x45, 0xb0, 0xf1, 0x3a};
|
||||
static const uint8_t init_2401[] = {0xa5, 0x23, 0xd0, 0xf0, 0x00};
|
||||
|
||||
uint8_t WK_last_beacon;
|
||||
|
||||
static void __attribute__((unused)) WK_add_pkt_crc(uint8_t init)
|
||||
{
|
||||
uint8_t add = init;
|
||||
uint8_t xou = init;
|
||||
for (uint8_t i = 0; i < 14; i++)
|
||||
{
|
||||
add += packet[i];
|
||||
xou ^= packet[i];
|
||||
}
|
||||
packet[14] = xou;
|
||||
packet[15] = add;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) WK_build_bind_pkt(const uint8_t *init)
|
||||
{
|
||||
packet[0] = init[0];
|
||||
packet[1] = init[1];
|
||||
packet[2] = hopping_frequency[0];
|
||||
packet[3] = hopping_frequency[1];
|
||||
packet[4] = init[2];
|
||||
packet[5] = hopping_frequency[2];
|
||||
packet[6] = 0xff;
|
||||
packet[7] = 0x00;
|
||||
packet[8] = 0x00;
|
||||
packet[9] = 0x32;
|
||||
if (sub_protocol == WK2401)
|
||||
packet[10] = 0x10 | (rx_tx_addr[0] & 0x0e);
|
||||
else
|
||||
packet[10] = rx_tx_addr[0];
|
||||
packet[11] = rx_tx_addr[1];
|
||||
packet[12] = rx_tx_addr[2] | packet_count;
|
||||
packet[13] = init[3];
|
||||
WK_add_pkt_crc(init[4]);
|
||||
}
|
||||
|
||||
static int16_t __attribute__((unused)) WK_get_channel(uint8_t ch, int32_t scale, int16_t center, int16_t range)
|
||||
{
|
||||
int16_t value = convert_channel_16b_nolimit(CH_AETR[ch],-scale,scale)+center;
|
||||
if (value < center - range) value = center - range;
|
||||
if (value > center + range) value = center + range;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) WK_build_data_pkt_2401()
|
||||
{
|
||||
uint16_t msb = 0;
|
||||
uint8_t offset = 0;
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
if (i == 2)
|
||||
offset = 1;
|
||||
int16_t value = WK_get_channel(i, 0x800, 0, 0xA00); //12 bits, allow value to go to 125%
|
||||
uint16_t base = abs(value) >> 2; //10 bits is the base value
|
||||
uint16_t trim = abs(value) & 0x03; //lowest 2 bits represent trim
|
||||
if (base >= 0x200)
|
||||
{ //if value is > 100%, remainder goes to trim
|
||||
trim = 4 *(base - 0x200);
|
||||
base = 0x1ff;
|
||||
}
|
||||
base = (value >= 0) ? 0x200 + base : 0x200 - base;
|
||||
trim = (value >= 0) ? 0x200 + trim : 0x200 - trim;
|
||||
|
||||
packet[2*i+offset] = base & 0xff;
|
||||
packet[2*i+offset+1] = trim & 0xff;
|
||||
msb = (msb << 4) | ((base >> 6) & 0x0c) | ((trim >> 8) & 0x03);
|
||||
}
|
||||
packet[4] = msb >> 8; //Ele/Ail MSB
|
||||
packet[9] = msb & 0xff; //Thr/Rud MSB
|
||||
packet[10] = 0xe0 | (rx_tx_addr[0] & 0x0e);
|
||||
packet[11] = rx_tx_addr[1];
|
||||
packet[12] = rx_tx_addr[2] | packet_count;
|
||||
packet[13] = 0xf0; //FIXME - What is this?
|
||||
WK_add_pkt_crc(0x00);
|
||||
}
|
||||
|
||||
#define PCT(pct, max) (((int32_t)(max) * (int32_t)(pct) + 1L) / 1000L)
|
||||
#define MAXTHR 426 //Measured to provide equal value at +/-0
|
||||
static void __attribute__((unused)) WK_channels_6plus1_2601(uint8_t frame, int16_t *_v1, int16_t *_v2)
|
||||
{
|
||||
int16_t thr = WK_get_channel(2, 1000, 0, 1000);
|
||||
int16_t v1;
|
||||
uint8_t thr_rev = 0, pitch_rev = 0;
|
||||
if(thr > 0)
|
||||
{
|
||||
if(thr >= 780)
|
||||
{ //78%
|
||||
v1 = 0; //thr = 60% * (x - 78%) / 22% + 40%
|
||||
thr = PCT(1000-MAXTHR,512) * (thr-PCT(780,1000)) / PCT(220,1000) + PCT(MAXTHR,512);
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = 1023 - 1023 * thr / 780;
|
||||
thr = PCT(MAXTHR, 512); //40%
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
thr = -thr;
|
||||
thr_rev = 1;
|
||||
if(thr >= 780)
|
||||
{ //78%
|
||||
v1 = 1023; //thr = 60% * (x - 78%) / 22% + 40%
|
||||
thr = PCT(1000-MAXTHR,512) * (thr-PCT(780,1000)) / PCT(220,1000) + PCT(MAXTHR,512);
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = 1023 * thr / 780;
|
||||
thr = PCT(MAXTHR, 512); //40%
|
||||
}
|
||||
}
|
||||
if (thr >= 512)
|
||||
thr = 511;
|
||||
packet[2] = thr & 0xff;
|
||||
packet[4] = (packet[4] & 0xF3) | ((thr >> 6) & 0x04);
|
||||
|
||||
int16_t pitch= WK_get_channel(5, 0x400, 0, 0x400);
|
||||
if (pitch < 0)
|
||||
{
|
||||
pitch_rev = 1;
|
||||
pitch = -pitch;
|
||||
}
|
||||
if (frame == 1)
|
||||
{
|
||||
//Pitch curve and range
|
||||
if (thr > PCT(MAXTHR, 512))
|
||||
*_v2 = pitch - pitch * 16 * (thr - PCT(MAXTHR, 512)) / PCT(1000 - MAXTHR, 512) / 100;
|
||||
else
|
||||
*_v2 = pitch;
|
||||
*_v1 = 0;
|
||||
}
|
||||
else
|
||||
if (frame == 2)
|
||||
{
|
||||
//Throttle curve & Expo
|
||||
*_v1 = v1;
|
||||
*_v2 = 512;
|
||||
}
|
||||
packet[7] = (thr_rev << 5) | (pitch_rev << 2); //reverse bits
|
||||
packet[8] = 0;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) WK_channels_5plus1_2601(uint8_t frame, int16_t *v1, int16_t *v2)
|
||||
{
|
||||
(void)v1;
|
||||
//Zero out pitch, provide ail, ele, thr, rud, gyr + gear
|
||||
if (frame == 1)
|
||||
*v2 = 0; //Pitch curve and range
|
||||
packet[7] = 0;
|
||||
packet[8] = 0;
|
||||
}
|
||||
static void __attribute__((unused)) WK_channels_heli_2601(uint8_t frame, int16_t *v1, int16_t *v2)
|
||||
{
|
||||
//pitch is controlled by rx
|
||||
//we can only control fmode, pit-reverse and pit/thr rate
|
||||
uint8_t pit_rev = 0;
|
||||
if (sub_protocol==W6_HEL_I)
|
||||
pit_rev = 1;
|
||||
int16_t pit_rate = WK_get_channel(5, 0x400, 0, 0x400);
|
||||
uint8_t fmode = 1;
|
||||
if (pit_rate < 0)
|
||||
{
|
||||
pit_rate = -pit_rate;
|
||||
fmode = 0;
|
||||
}
|
||||
if (frame == 1)
|
||||
{
|
||||
//Pitch curve and range
|
||||
*v1 = pit_rate;
|
||||
*v2 = (int16_t)(option) * 0x400 / 100 + 0x400;
|
||||
}
|
||||
packet[7] = (pit_rev << 2); //reverse bits
|
||||
packet[8] = fmode ? 0x02 : 0x00;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) WK_build_data_pkt_2601()
|
||||
{
|
||||
uint8_t msb = 0;
|
||||
uint8_t frame = (packet_count % 3);
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
int16_t value = WK_get_channel(i, 0x190, 0, 0x1FF);
|
||||
uint16_t mag = value < 0 ? -value : value;
|
||||
packet[i] = mag & 0xff;
|
||||
msb = (msb << 2) | ((mag >> 8) & 0x01) | (value < 0 ? 0x02 : 0x00);
|
||||
}
|
||||
packet[4] = msb;
|
||||
int16_t v1 = 0x200, v2 = 0x200;
|
||||
if (frame == 0)
|
||||
{
|
||||
//Gyro & Rudder mix
|
||||
v1 = WK_get_channel(6, 0x200, 0x200, 0x200);
|
||||
v2 = 0;
|
||||
}
|
||||
if (sub_protocol == W6_5_1)
|
||||
WK_channels_5plus1_2601(frame, &v1, &v2);
|
||||
else if (sub_protocol == W6_6_1)
|
||||
WK_channels_6plus1_2601(frame, &v1, &v2);
|
||||
else
|
||||
WK_channels_heli_2601(frame, &v1, &v2);
|
||||
if (v1 > 1023)
|
||||
v1 = 1023;
|
||||
if (v2 > 1023)
|
||||
v2 = 1023;
|
||||
packet[5] = v2 & 0xff;
|
||||
packet[6] = v1 & 0xff;
|
||||
//packet[7] handled by channel code
|
||||
packet[8] |= (WK_get_channel(4, 0x190, 0, 0x1FF) > 0 ? 1 : 0);
|
||||
packet[9] = ((v1 >> 4) & 0x30) | ((v2 >> 2) & 0xc0) | 0x04 | frame;
|
||||
packet[10] = rx_tx_addr[0];
|
||||
packet[11] = rx_tx_addr[1];
|
||||
packet[12] = rx_tx_addr[2] | packet_count;
|
||||
packet[13] = 0xff;
|
||||
|
||||
WK_add_pkt_crc(0x3A);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) WK_build_data_pkt_2801()
|
||||
{
|
||||
uint16_t msb = 0;
|
||||
uint8_t offset = 0;
|
||||
uint8_t sign = 0;
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (i == 4) { offset = 1; }
|
||||
int16_t value = WK_get_channel(i, 0x1C2, 0, 0x3FF);
|
||||
uint16_t mag = value < 0 ? -value : value;
|
||||
packet[i+offset] = mag & 0xff;
|
||||
msb = (msb << 2) | ((mag >> 8) & 0x03);
|
||||
if (value < 0) { sign |= 1 << i; }
|
||||
}
|
||||
packet[4] = msb >> 8;
|
||||
packet[9] = msb & 0xff;
|
||||
packet[10] = rx_tx_addr[0];
|
||||
packet[11] = rx_tx_addr[1];
|
||||
packet[12] = rx_tx_addr[2] | packet_count;
|
||||
packet[13] = sign;
|
||||
WK_add_pkt_crc(0x25);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) WK_build_beacon_pkt_2801()
|
||||
{
|
||||
WK_last_beacon ^= 1;
|
||||
uint8_t en = 0;
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
BIND_SET_OUTPUT;
|
||||
}
|
||||
#endif //ENABLE_PPM
|
||||
if(prev_option!=option && IS_BIND_DONE)
|
||||
{
|
||||
set_rx_tx_addr(MProtocol_id);
|
||||
rx_tx_addr[2]=rx_tx_addr[3]<<4; // Make use of RX_num
|
||||
bind_counter = WK_BIND_COUNT / 8 + 1;
|
||||
}
|
||||
if (option)
|
||||
{
|
||||
if (bind_counter)
|
||||
bind_state = 0xe4;
|
||||
else
|
||||
bind_state = 0x1b;
|
||||
}
|
||||
else
|
||||
bind_state = 0x99;
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
uint16_t failsafe=Failsafe_data[CH_AETR[i + WK_last_beacon * 4]];
|
||||
if(failsafe!=FAILSAFE_CHANNEL_HOLD && IS_FAILSAFE_VALUES_on)
|
||||
{
|
||||
packet[i+1] = failsafe>>3; //0..255
|
||||
en |= 1 << i;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
packet[i+1] = 0;
|
||||
}
|
||||
packet[0] = en;
|
||||
packet[5] = packet[4];
|
||||
packet[4] = WK_last_beacon << 6;
|
||||
packet[6] = hopping_frequency[0];
|
||||
packet[7] = hopping_frequency[1];
|
||||
packet[8] = hopping_frequency[2];
|
||||
packet[9] = bind_state;
|
||||
packet[10] = rx_tx_addr[0];
|
||||
packet[11] = rx_tx_addr[1];
|
||||
packet[12] = rx_tx_addr[2] | packet_count;
|
||||
packet[13] = 0x00; //Does this matter? in the docs it is the same as the data packet
|
||||
WK_add_pkt_crc(0x1C);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) wk2x01_cyrf_init() {
|
||||
/* Initialize CYRF chip */
|
||||
CYRF_SetPower(0x28);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A);
|
||||
CYRF_WriteRegister(CYRF_0B_PWR_CTRL, 0x00);
|
||||
CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0);
|
||||
CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C);
|
||||
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xEE);
|
||||
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
|
||||
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
|
||||
CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x18);
|
||||
CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C);
|
||||
CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
|
||||
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x90);
|
||||
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
|
||||
CYRF_WriteRegister(CYRF_01_TX_LENGTH, 0x10);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C);
|
||||
CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
|
||||
CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x02);
|
||||
CYRF_ConfigSOPCode(WK_sopcodes);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28);
|
||||
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x10);
|
||||
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL, 0x20);
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) WK_BuildPacket_2801()
|
||||
{
|
||||
switch(phase) {
|
||||
case WK_BIND:
|
||||
bind_counter--;
|
||||
WK_build_bind_pkt(init_2801);
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
BIND_DONE;
|
||||
phase++;
|
||||
}
|
||||
break;
|
||||
case WK_BOUND_1:
|
||||
case WK_BOUND_2:
|
||||
case WK_BOUND_3:
|
||||
case WK_BOUND_4:
|
||||
case WK_BOUND_5:
|
||||
case WK_BOUND_6:
|
||||
case WK_BOUND_7:
|
||||
WK_build_data_pkt_2801();
|
||||
phase++;
|
||||
break;
|
||||
case WK_BOUND_8:
|
||||
WK_build_beacon_pkt_2801();
|
||||
phase = WK_BOUND_1;
|
||||
if (bind_counter)
|
||||
{
|
||||
bind_counter--;
|
||||
if (bind_counter == 0)
|
||||
BIND_DONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) WK_BuildPacket_2601()
|
||||
{
|
||||
if (bind_counter)
|
||||
{
|
||||
bind_counter--;
|
||||
WK_build_bind_pkt(init_2601);
|
||||
if (bind_counter == 0)
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
WK_build_data_pkt_2601();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) WK_BuildPacket_2401()
|
||||
{
|
||||
if (bind_counter)
|
||||
{
|
||||
bind_counter--;
|
||||
WK_build_bind_pkt(init_2401);
|
||||
if(bind_counter == 0)
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
WK_build_data_pkt_2401();
|
||||
}
|
||||
|
||||
uint16_t WK_cb()
|
||||
{
|
||||
if (packet_sent == 0)
|
||||
{
|
||||
packet_sent = 1;
|
||||
if(sub_protocol == WK2801)
|
||||
WK_BuildPacket_2801();
|
||||
else if(sub_protocol == WK2401)
|
||||
WK_BuildPacket_2401();
|
||||
else
|
||||
WK_BuildPacket_2601();
|
||||
packet_count = (packet_count + 1) % 12;
|
||||
CYRF_WriteDataPacket(packet);
|
||||
return 1600;
|
||||
}
|
||||
packet_sent = 0;
|
||||
uint8_t start=micros();
|
||||
while ((uint8_t)micros()-start < 100) // Wait max 100µs
|
||||
if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02)
|
||||
break;
|
||||
if((packet_count & 0x03) == 0)
|
||||
{
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no%=3;
|
||||
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
|
||||
//Keep transmit power updated
|
||||
CYRF_SetPower(0x28);
|
||||
}
|
||||
return 1200;
|
||||
}
|
||||
|
||||
uint16_t WK_setup()
|
||||
{
|
||||
wk2x01_cyrf_init();
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
|
||||
hopping_frequency_no=0;
|
||||
CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80);
|
||||
CYRF_ConfigRFChannel(hopping_frequency[0]);
|
||||
|
||||
packet_count = 0;
|
||||
packet_sent = 0;
|
||||
WK_last_beacon = 0;
|
||||
prev_option=option;
|
||||
if(sub_protocol!=WK2801 || option==0)
|
||||
{
|
||||
CYRF_GetMfgData(cyrfmfg_id);
|
||||
rx_tx_addr[2]=(hopping_frequency[0] ^ cyrfmfg_id[0] ^ cyrfmfg_id[3])<<4;
|
||||
rx_tx_addr[1]=hopping_frequency[1] ^ cyrfmfg_id[1] ^ cyrfmfg_id[4];
|
||||
rx_tx_addr[0]=hopping_frequency[2] ^ cyrfmfg_id[2] ^ cyrfmfg_id[5];
|
||||
if(sub_protocol == WK2401)
|
||||
rx_tx_addr[0] |= 0x01; //ID must be odd for 2401
|
||||
|
||||
bind_counter = WK_BIND_COUNT;
|
||||
phase = WK_BIND;
|
||||
BIND_IN_PROGRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
rx_tx_addr[2]=rx_tx_addr[3]<<4; // Make use of RX_num
|
||||
bind_counter = 0;
|
||||
phase = WK_BOUND_1;
|
||||
BIND_DONE;
|
||||
}
|
||||
return 2800;
|
||||
}
|
||||
|
||||
#endif
|
||||
238
Multiprotocol/XN297Dump_nrf24l01.ino
Normal file
238
Multiprotocol/XN297Dump_nrf24l01.ino
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
// sub_protocol: 0=250Kbps, 1=1Mbps, 2=2Mbps. Other values default to 1Mbps.
|
||||
// RX_num = address length 3 or 4 or 5. Other values default to 5.
|
||||
// option = RF channel number 0..84 and -1 = scan all channels. Other values default to RF channel 0.
|
||||
|
||||
#ifdef XN297DUMP_NRF24L01_INO
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
// Parameters which can be modified
|
||||
#define XN297DUMP_PERIOD_SCAN 50000 // 25000
|
||||
#define XN297DUMP_MAX_RF_CHANNEL 84 // Default 84
|
||||
|
||||
// Do not touch from there
|
||||
#define XN297DUMP_INITIAL_WAIT 500
|
||||
#define XN297DUMP_MAX_PACKET_LEN 32
|
||||
#define XN297DUMP_CRC_LENGTH 2
|
||||
|
||||
uint8_t address_length;
|
||||
uint16_t timeH=0;
|
||||
boolean scramble;
|
||||
|
||||
static void __attribute__((unused)) XN297Dump_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(RX_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 Acknowledgment on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3 bytes RX/TX address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x55\x0F\x71", 3); // set up RX address to xn297 preamble
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, XN297DUMP_MAX_PACKET_LEN); // Enable rx pipe 0
|
||||
|
||||
debug("XN297 dump, address length=%d, speed=",address_length);
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case 0:
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_250K);
|
||||
debugln("250K");
|
||||
break;
|
||||
case 2:
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_2M);
|
||||
debugln("2M");
|
||||
break;
|
||||
default:
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M);
|
||||
debugln("1M");
|
||||
break;
|
||||
|
||||
}
|
||||
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_SetPower();
|
||||
}
|
||||
|
||||
static boolean __attribute__((unused)) XN297Dump_process_packet(void)
|
||||
{
|
||||
uint16_t crcxored;
|
||||
uint8_t packet_sc[XN297DUMP_MAX_PACKET_LEN], packet_un[XN297DUMP_MAX_PACKET_LEN];
|
||||
|
||||
// init crc
|
||||
crc = 0xb5d2;
|
||||
|
||||
// address
|
||||
for (uint8_t i = 0; i < address_length; i++)
|
||||
{
|
||||
crc = crc16_update(crc, packet[i], 8);
|
||||
packet_un[address_length-1-i]=packet[i];
|
||||
packet_sc[address_length-1-i]=packet[i] ^ xn297_scramble[i];
|
||||
}
|
||||
|
||||
// payload
|
||||
for (uint8_t i = address_length; i < XN297DUMP_MAX_PACKET_LEN-XN297DUMP_CRC_LENGTH; i++)
|
||||
{
|
||||
crc = crc16_update(crc, packet[i], 8);
|
||||
packet_sc[i] = bit_reverse(packet[i]^xn297_scramble[i]);
|
||||
packet_un[i] = bit_reverse(packet[i]);
|
||||
// check crc
|
||||
crcxored = crc ^ pgm_read_word(&xn297_crc_xorout[i+1 - 3]);
|
||||
if( (crcxored >> 8) == packet[i + 1] && (crcxored & 0xff) == packet[i + 2])
|
||||
{
|
||||
packet_length=i+1;
|
||||
memcpy(packet,packet_un,packet_length);
|
||||
scramble=false;
|
||||
return true;
|
||||
}
|
||||
crcxored = crc ^ pgm_read_word(&xn297_crc_xorout_scrambled[i+1 - 3]);
|
||||
if( (crcxored >> 8) == packet[i + 1] && (crcxored & 0xff) == packet[i + 2])
|
||||
{
|
||||
packet_length=i+1;
|
||||
memcpy(packet,packet_sc,packet_length);
|
||||
scramble=true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297Dump_overflow()
|
||||
{
|
||||
if(TIMER2_BASE->SR & TIMER_SR_UIF)
|
||||
{ // timer overflow
|
||||
timeH++;
|
||||
TIMER2_BASE->SR = 0x1E5F & ~TIMER_SR_UIF; // Clear Timer2 overflow flag
|
||||
}
|
||||
}
|
||||
static uint16_t XN297Dump_callback()
|
||||
{
|
||||
static uint32_t time=0;
|
||||
while(1)
|
||||
{
|
||||
if(option==0xFF && bind_counter>XN297DUMP_PERIOD_SCAN)
|
||||
{ // Scan frequencies
|
||||
hopping_frequency_no++;
|
||||
bind_counter=0;
|
||||
}
|
||||
if(hopping_frequency_no!=rf_ch_num)
|
||||
{ // Channel has changed
|
||||
if(hopping_frequency_no>XN297DUMP_MAX_RF_CHANNEL)
|
||||
hopping_frequency_no=0; // Invalid channel 0 by default
|
||||
rf_ch_num=hopping_frequency_no;
|
||||
debugln("Channel=%d,0x%02X",hopping_frequency_no,hopping_frequency_no)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency_no);
|
||||
// switch to RX mode
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
|
||||
| (1 << NRF24L01_00_CRCO)
|
||||
| (1 << NRF24L01_00_PWR_UP)
|
||||
| (1 << NRF24L01_00_PRIM_RX));
|
||||
phase=0; // init timer
|
||||
}
|
||||
XN297Dump_overflow();
|
||||
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready
|
||||
if(NRF24L01_ReadReg(NRF24L01_09_CD) || option != 0xFF)
|
||||
{
|
||||
NRF24L01_ReadPayload(packet,XN297DUMP_MAX_PACKET_LEN);
|
||||
XN297Dump_overflow();
|
||||
uint16_t timeL=TCNT1;
|
||||
if(TIMER2_BASE->SR & TIMER_SR_UIF)
|
||||
{//timer just rolled over...
|
||||
XN297Dump_overflow();
|
||||
timeL=0;
|
||||
}
|
||||
if(phase==0)
|
||||
{
|
||||
phase=1;
|
||||
time=0;
|
||||
}
|
||||
else
|
||||
time=(timeH<<16)+timeL-time;
|
||||
debug("RX: %5luus C=%d ", time>>1 , hopping_frequency_no);
|
||||
time=(timeH<<16)+timeL;
|
||||
if(XN297Dump_process_packet())
|
||||
{ // valid crc found
|
||||
debug("S=%c A=",scramble?'Y':'N');
|
||||
for(uint8_t i=0; i<address_length; i++)
|
||||
{
|
||||
debug(" %02X",packet[i]);
|
||||
}
|
||||
debug(" P(%d)=",packet_length-address_length);
|
||||
for(uint8_t i=address_length; i<packet_length; i++)
|
||||
{
|
||||
debug(" %02X",packet[i]);
|
||||
}
|
||||
debugln("");
|
||||
}
|
||||
else
|
||||
{
|
||||
debugln("Bad CRC");
|
||||
}
|
||||
}
|
||||
|
||||
XN297Dump_overflow();
|
||||
// restart RX mode
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
|
||||
| (1 << NRF24L01_00_CRCO)
|
||||
| (1 << NRF24L01_00_PWR_UP)
|
||||
| (1 << NRF24L01_00_PRIM_RX));
|
||||
XN297Dump_overflow();
|
||||
}
|
||||
bind_counter++;
|
||||
if(IS_RX_FLAG_on) // Let the radio update the protocol
|
||||
{
|
||||
if(Update_All()) return 10000; // New protocol selected
|
||||
if(prev_option!=option)
|
||||
{ // option has changed
|
||||
hopping_frequency_no=option;
|
||||
prev_option=option;
|
||||
}
|
||||
}
|
||||
XN297Dump_overflow();
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
uint16_t initXN297Dump(void)
|
||||
{
|
||||
BIND_DONE;
|
||||
address_length=RX_num;
|
||||
if(address_length<3||address_length>5)
|
||||
address_length=5; //default
|
||||
XN297Dump_init();
|
||||
bind_counter=0;
|
||||
rf_ch_num=0xFF;
|
||||
prev_option=option^0x55;
|
||||
phase=0; // init timer
|
||||
return XN297DUMP_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
223
Multiprotocol/XN297L_EMU.ino
Normal file
223
Multiprotocol/XN297L_EMU.ino
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
#include "iface_xn297l.h"
|
||||
|
||||
#if defined (XN297L_CC2500_EMU)
|
||||
static void __attribute__((unused)) XN297L_Init()
|
||||
{
|
||||
PE1_off; // antenna RF2
|
||||
PE2_on;
|
||||
CC2500_Reset();
|
||||
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
|
||||
|
||||
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_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
xn297_scramble_enabled=XN297_SCRAMBLED; //enabled by default
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_SetTXAddr(const uint8_t* addr, uint8_t len)
|
||||
{
|
||||
if (len > 5) len = 5;
|
||||
if (len < 3) len = 3;
|
||||
xn297_addr_len = len;
|
||||
memcpy(xn297_tx_addr, addr, len);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_WritePayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
uint8_t buf[32];
|
||||
uint8_t last = 0;
|
||||
uint8_t i;
|
||||
static const uint16_t initial = 0xb5d2;
|
||||
|
||||
// address
|
||||
for (i = 0; i < xn297_addr_len; ++i)
|
||||
{
|
||||
buf[last] = xn297_tx_addr[xn297_addr_len - i - 1];
|
||||
if(xn297_scramble_enabled)
|
||||
buf[last] ^= xn297_scramble[i];
|
||||
last++;
|
||||
}
|
||||
|
||||
// payload
|
||||
for (i = 0; i < len; ++i) {
|
||||
// bit-reverse bytes in packet
|
||||
buf[last] = bit_reverse(msg[i]);
|
||||
if(xn297_scramble_enabled)
|
||||
buf[last] ^= xn297_scramble[xn297_addr_len+i];
|
||||
last++;
|
||||
}
|
||||
|
||||
// crc
|
||||
uint16_t crc = initial;
|
||||
for (uint8_t i = 0; i < last; ++i)
|
||||
crc = crc16_update(crc, buf[i], 8);
|
||||
if(xn297_scramble_enabled)
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
|
||||
else
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout[xn297_addr_len - 3 + len]);
|
||||
buf[last++] = crc >> 8;
|
||||
buf[last++] = crc & 0xff;
|
||||
|
||||
// stop TX/RX
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
// flush tx FIFO
|
||||
CC2500_Strobe(CC2500_SFTX);
|
||||
// packet length
|
||||
CC2500_WriteReg(CC2500_3F_TXFIFO, last + 3);
|
||||
// xn297L preamble
|
||||
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, (uint8_t*)"\x71\x0f\x55", 3);
|
||||
// xn297 packet
|
||||
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buf, last);
|
||||
// transmit
|
||||
CC2500_Strobe(CC2500_STX);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_HoppingCalib(uint8_t num_freq)
|
||||
{ //calibrate hopping frequencies
|
||||
for (uint8_t i = 0; i < num_freq; i++)
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[i]*3);
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);
|
||||
calData[i]=CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_Hopping(uint8_t index)
|
||||
{
|
||||
// spacing is 333.25 kHz, must multiply xn297 channel by 3
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[index] * 3);
|
||||
// set PLL calibration
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[index]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_RFChannel(uint8_t number)
|
||||
{ //change channel
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, number*3);
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_SetPower()
|
||||
{
|
||||
CC2500_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_SetFreqOffset()
|
||||
{ // Frequency offset
|
||||
if (prev_option != option)
|
||||
{
|
||||
prev_option = option;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined (NRF24L01_INSTALLED)
|
||||
|
||||
static void __attribute__((unused)) XN297L_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_SetBitrate(NRF24L01_BR_250K); // 250Kbps
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_SetTXAddr(const uint8_t* addr, uint8_t len)
|
||||
{
|
||||
XN297_SetTXAddr(addr,len);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_WritePayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WritePayload(msg, len);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_HoppingCalib(__attribute__((unused)) uint8_t num_freq)
|
||||
{ //calibrate hopping frequencies
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_Hopping(uint8_t index)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[index]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_RFChannel(uint8_t number)
|
||||
{ //change channel
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, number);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_SetPower()
|
||||
{
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XN297L_SetFreqOffset()
|
||||
{ // Frequency offset
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -12,18 +12,18 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Last sync with hexfet new_protocols/yd717_nrf24l01.c dated 2015-09-28
|
||||
|
||||
#if defined(YD717_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define YD717_BIND_COUNT 60
|
||||
#define YD717_BIND_COUNT 120
|
||||
#define YD717_PACKET_PERIOD 8000 // Timeout for callback in uSec, 8ms=8000us for YD717
|
||||
#define YD717_INITIAL_WAIT 50000 // Initial wait before starting callbacks
|
||||
#define YD717_PACKET_CHKTIME 500 // Time to wait if packet not yet acknowledged or timed out
|
||||
|
||||
// Stock tx fixed frequency is 0x3C. Receiver only binds on this freq.
|
||||
#define RF_CHANNEL 0x3C
|
||||
#define YD717_RF_CHANNEL 0x3C
|
||||
|
||||
#define YD717_FLAG_FLIP 0x0F
|
||||
#define YD717_FLAG_LIGHT 0x80
|
||||
@@ -32,16 +32,8 @@
|
||||
#define YD717_FLAG_HEADLESS 0x10
|
||||
|
||||
#define YD717_PAYLOADSIZE 8 // receive data pipes set to this size, but unused
|
||||
//#define YD717_MAX_PACKET_SIZE 9 // YD717 packets have 8-byte payload, Syma X4 is 9
|
||||
|
||||
enum {
|
||||
YD717_INIT1 = 0,
|
||||
YD717_BIND2,
|
||||
YD717_BIND3,
|
||||
YD717_DATA
|
||||
};
|
||||
|
||||
void yd717_send_packet(uint8_t bind)
|
||||
static void __attribute__((unused)) yd717_send_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t rudder_trim, elevator_trim, aileron_trim;
|
||||
if (bind)
|
||||
@@ -93,28 +85,22 @@ void yd717_send_packet(uint8_t bind)
|
||||
packet[6] = aileron_trim;
|
||||
}
|
||||
// Flags
|
||||
flags=0;
|
||||
// Channel 5
|
||||
if (Servo_data[AUX1] > PPM_SWITCH)
|
||||
flags = YD717_FLAG_FLIP;
|
||||
else
|
||||
flags=0;
|
||||
if (CH5_SW) flags = YD717_FLAG_FLIP;
|
||||
// Channel 6
|
||||
if (Servo_data[AUX2] > PPM_SWITCH)
|
||||
flags |= YD717_FLAG_LIGHT;
|
||||
if (CH6_SW) flags |= YD717_FLAG_LIGHT;
|
||||
// Channel 7
|
||||
if (Servo_data[AUX3] > PPM_SWITCH)
|
||||
flags |= YD717_FLAG_PICTURE;
|
||||
if (CH7_SW) flags |= YD717_FLAG_PICTURE;
|
||||
// Channel 8
|
||||
if (Servo_data[AUX4] > PPM_SWITCH)
|
||||
flags |= YD717_FLAG_VIDEO;
|
||||
if (CH8_SW) flags |= YD717_FLAG_VIDEO;
|
||||
// Channel 9
|
||||
if (Servo_data[AUX5] > PPM_SWITCH)
|
||||
flags |= YD717_FLAG_HEADLESS;
|
||||
if (CH9_SW) flags |= YD717_FLAG_HEADLESS;
|
||||
packet[7] = flags;
|
||||
}
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (_BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if( sub_protocol == YD717 )
|
||||
@@ -123,7 +109,7 @@ void yd717_send_packet(uint8_t bind)
|
||||
{
|
||||
packet[8] = packet[0]; // checksum
|
||||
for(uint8_t i=1; i < 8; i++)
|
||||
packet[8] += packet[i];
|
||||
packet[8] += packet[i];
|
||||
packet[8] = ~packet[8];
|
||||
NRF24L01_WritePayload(packet, 9);
|
||||
}
|
||||
@@ -131,126 +117,72 @@ void yd717_send_packet(uint8_t bind)
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
void yd717_init()
|
||||
static void __attribute__((unused)) yd717_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
|
||||
// CRC, radio on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3F); // Auto Acknoledgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x3F); // Enable all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x1A); // 500uS retransmit t/o, 10 tries
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_CHANNEL); // Channel 3C
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3F); // Enable Acknowledgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x3F); // Enable all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x1A); // 500uS retransmit t/o, 10 tries
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, YD717_RF_CHANNEL); // Channel 3C
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_0C_RX_ADDR_P2, 0xC3); // LSB byte of pipe 2 receive address
|
||||
NRF24L01_WriteReg(NRF24L01_0D_RX_ADDR_P3, 0xC4);
|
||||
NRF24L01_WriteReg(NRF24L01_0E_RX_ADDR_P4, 0xC5);
|
||||
NRF24L01_WriteReg(NRF24L01_0F_RX_ADDR_P5, 0xC6);
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, YD717_PAYLOADSIZE); // bytes of data payload for pipe 1
|
||||
NRF24L01_WriteReg(NRF24L01_12_RX_PW_P1, YD717_PAYLOADSIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_13_RX_PW_P2, YD717_PAYLOADSIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_14_RX_PW_P3, YD717_PAYLOADSIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_15_RX_PW_P4, YD717_PAYLOADSIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_16_RX_PW_P5, YD717_PAYLOADSIZE);
|
||||
NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent and retransmit
|
||||
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F); // Enable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); // Set feature bits on
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F); // Enable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); // Set feature bits on
|
||||
NRF24L01_Activate(0x73);
|
||||
|
||||
// set tx id
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
}
|
||||
|
||||
void YD717_init1()
|
||||
{
|
||||
// for bind packets set address to prearranged value known to receiver
|
||||
uint8_t bind_rx_tx_addr[] = {0x65, 0x65, 0x65, 0x65, 0x65};
|
||||
if( sub_protocol==SYMAX2 )
|
||||
for(uint8_t i=0; i < 5; i++)
|
||||
bind_rx_tx_addr[i] = 0x60;
|
||||
uint8_t bind_rx_tx_addr[5];
|
||||
uint8_t offset=5;
|
||||
if( sub_protocol==SYMAX4 )
|
||||
offset=0;
|
||||
else
|
||||
if( sub_protocol==NIHUI )
|
||||
for(uint8_t i=0; i < 5; i++)
|
||||
bind_rx_tx_addr[i] = 0x64;
|
||||
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_rx_tx_addr, 5);
|
||||
offset=4;
|
||||
for(uint8_t i=0; i < 5; i++)
|
||||
bind_rx_tx_addr[i] = 0x60 + offset;
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_rx_tx_addr, 5);
|
||||
}
|
||||
|
||||
void YD717_init2()
|
||||
{
|
||||
// set rx/tx address for data phase
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_rx_tx_addr, 5);
|
||||
}
|
||||
|
||||
uint16_t yd717_callback()
|
||||
{
|
||||
switch (phase)
|
||||
if(IS_BIND_DONE)
|
||||
yd717_send_packet(0);
|
||||
else
|
||||
{
|
||||
case YD717_INIT1:
|
||||
yd717_send_packet(0); // receiver doesn't re-enter bind mode if connection lost...check if already bound
|
||||
phase = YD717_BIND3;
|
||||
break;
|
||||
case YD717_BIND2:
|
||||
if (counter == 0)
|
||||
{
|
||||
if (NRF24L01_packet_ack() == PKT_PENDING)
|
||||
return YD717_PACKET_CHKTIME; // packet send not yet complete
|
||||
YD717_init2(); // change to data phase rx/tx address
|
||||
yd717_send_packet(0);
|
||||
phase = YD717_BIND3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NRF24L01_packet_ack() == PKT_PENDING)
|
||||
return YD717_PACKET_CHKTIME; // packet send not yet complete;
|
||||
yd717_send_packet(1);
|
||||
counter--;
|
||||
}
|
||||
break;
|
||||
case YD717_BIND3:
|
||||
switch (NRF24L01_packet_ack())
|
||||
{
|
||||
case PKT_PENDING:
|
||||
return YD717_PACKET_CHKTIME; // packet send not yet complete
|
||||
case PKT_ACKED:
|
||||
phase = YD717_DATA;
|
||||
BIND_DONE; // bind complete
|
||||
break;
|
||||
case PKT_TIMEOUT:
|
||||
YD717_init1(); // change to bind rx/tx address
|
||||
counter = YD717_BIND_COUNT;
|
||||
phase = YD717_BIND2;
|
||||
yd717_send_packet(1);
|
||||
}
|
||||
break;
|
||||
case YD717_DATA:
|
||||
if (NRF24L01_packet_ack() == PKT_PENDING)
|
||||
return YD717_PACKET_CHKTIME; // packet send not yet complete
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); // set address
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
|
||||
yd717_send_packet(0);
|
||||
break;
|
||||
}
|
||||
BIND_DONE; // bind complete
|
||||
}
|
||||
else
|
||||
{
|
||||
yd717_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
return YD717_PACKET_PERIOD; // Packet every 8ms
|
||||
}
|
||||
|
||||
uint16_t initYD717()
|
||||
{
|
||||
rx_tx_addr[4] = 0xC1; // always uses first data port
|
||||
flags = 0;
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
rx_tx_addr[4] = 0xC1; // always uses first data port
|
||||
yd717_init();
|
||||
phase = YD717_INIT1;
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = YD717_BIND_COUNT;
|
||||
|
||||
// Call callback in 50ms
|
||||
return YD717_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
647
Multiprotocol/_Config.h
Normal file
647
Multiprotocol/_Config.h
Normal file
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/**********************************************/
|
||||
/** Multiprotocol module configuration file ***/
|
||||
/**********************************************/
|
||||
|
||||
/********************/
|
||||
/*** LOCAL CONFIG ***/
|
||||
/********************/
|
||||
//If you know parameters you want for sure to be enabled or disabled which survives in future, you can use a file named "_MyConfig.h".
|
||||
//An example is given within the file named "_MyConfig.h.example" which needs to be renamed if you want to use it.
|
||||
//To enable this config file remove the // from the line below.
|
||||
//#define USE_MY_CONFIG
|
||||
|
||||
|
||||
/*************************/
|
||||
/*** BOOTLOADER USE ***/
|
||||
/*************************/
|
||||
//Allow flashing multimodule directly with TX(erky9x or opentx maintenance mode)
|
||||
//Instructions:https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/docs/Flash_from_Tx.md
|
||||
//To enable this feature remove the "//" on the next line. Requires a compatible bootloader or upload method to be selected when you use the Multi 4-in-1 Boards Manager definitions.
|
||||
//#define CHECK_FOR_BOOTLOADER
|
||||
|
||||
|
||||
/*******************/
|
||||
/*** TX SETTINGS ***/
|
||||
/*******************/
|
||||
//Modify the channel order based on your TX: AETR, TAER, RETA...
|
||||
//Examples: Flysky & DEVO is AETR, JR/Spektrum radio is TAER, Multiplex is AERT...
|
||||
//Default is AETR.
|
||||
#define AETR
|
||||
|
||||
//Uncomment to reverse the direction of the specified channel for all protocols
|
||||
//#define REVERSE_AILERON
|
||||
//#define REVERSE_ELEVATOR
|
||||
//#define REVERSE_THROTTLE
|
||||
//#define REVERSE_RUDDER
|
||||
|
||||
|
||||
/*****************/
|
||||
/*** AUTO BIND ***/ // Also referred as "Bind on powerup"
|
||||
/*****************/
|
||||
//Bind from channel enables you to bind when a specified channel is going from low to high. This feature is only active
|
||||
// if you specify AUTOBIND in PPM mode or set AutoBind to YES for serial mode. It also requires that the throttle channel is low.
|
||||
//Comment to globaly disable the bind feature from a channel.
|
||||
#define ENABLE_BIND_CH
|
||||
//Set the channel number used for bind. Default is 16.
|
||||
#define BIND_CH 16
|
||||
|
||||
//Comment to disable the wait for bind feature. If Autobind is enabled in the model config, this feature will not activate
|
||||
// the selected protocol unless a bind is requested using bind from channel or the GUI "Bind" button.
|
||||
//The goal is to prevent binding other people's model when powering up the TX, changing model or scanning through protocols.
|
||||
#define WAIT_FOR_BIND
|
||||
|
||||
|
||||
/****************/
|
||||
/*** RF CHIPS ***/
|
||||
/****************/
|
||||
//There are 4 RF components supported. If one of them is not installed you must comment it using "//".
|
||||
//If a chip is not installed all associated protocols are automatically disabled.
|
||||
//4-in-1 modules have all RF chips installed
|
||||
//!!!If a RF chip is present it MUST be marked as installed!!! or weird things will happen you have been warned.
|
||||
#define A7105_INSTALLED
|
||||
#define CYRF6936_INSTALLED
|
||||
#define CC2500_INSTALLED
|
||||
#define NRF24L01_INSTALLED
|
||||
|
||||
//If available use the CC2500 to emulate the XN297L @250Kbps instead of the NRF24L01. Comment to disable.
|
||||
#define XN297L_CC2500_EMU
|
||||
|
||||
/** OrangeRX TX **/
|
||||
//If you compile for the OrangeRX TX module you need to select the correct board type.
|
||||
//By default the compilation is done for the GREEN board, to switch to a BLUE board uncomment the line below by removing the "//"
|
||||
//#define ORANGE_TX_BLUE
|
||||
|
||||
/** CC2500 Fine Frequency Tuning **/
|
||||
//For optimal performance the CC2500 RF module used by the FrSkyD, FrSkyV, FrSkyX, SFHSS, CORONA, Redpine and Hitec protocols needs to be tuned for each protocol.
|
||||
//Initial tuning should be done via the radio menu with a genuine FrSky/Futaba/CORONA/Hitec/Redpine receiver.
|
||||
//Once a good tuning value is found it can be set here and will override the radio's 'option' setting for all existing and new models which use that protocol.
|
||||
//For more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/tree/master/docs/Frequency_Tuning.md
|
||||
//Uncomment the lines below (remove the "//") and set an appropriate value (replace the "0") to enable. Valid range is -127 to +127.
|
||||
//#define FORCE_FRSKYD_TUNING 0
|
||||
//#define FORCE_FRSKYV_TUNING 0
|
||||
//#define FORCE_FRSKYX_TUNING 0
|
||||
//#define FORCE_SFHSS_TUNING 0
|
||||
//#define FORCE_CORONA_TUNING 0
|
||||
//#define FORCE_HITEC_TUNING 0
|
||||
//#define FORCE_REDPINE_TUNING 0
|
||||
|
||||
/** A7105 Fine Frequency Tuning **/
|
||||
//This is required in rare cases where some A7105 modules and/or RXs have an inaccurate crystal oscillator.
|
||||
//If using Serial mode only (for now), you can use CH15 to find the right tuning value. -100%=-300, 0%=default 0, +100%=+300.
|
||||
//Uncomment the line below (remove the "//") to enable this feature.
|
||||
//#define USE_A7105_CH15_TUNING
|
||||
|
||||
//Once a good tuning value is found it can be set here and will override the frequency tuning for a specific protocol.
|
||||
//Uncomment the lines below (remove the "//") and set an appropriate value (replace the "0") to enable. Valid range is -300 to +300 and default is 0.
|
||||
//#define FORCE_FLYSKY_TUNING 0
|
||||
//#define FORCE_HUBSAN_TUNING 0
|
||||
//#define FORCE_AFHDS2A_TUNING 0
|
||||
//#define FORCE_BUGS_TUNING 0
|
||||
|
||||
/** CYRF6936 Fine Frequency Tuning **/
|
||||
//This is required in rare cases where some CYRF6936 modules and/or RXs have an inaccurate crystal oscillator.
|
||||
//If using Serial mode only (for now), you can use CH15 to find the right tuning value. -100%=-300, 0%=default 0, +100%=+300.
|
||||
//Uncomment the line below (remove the "//") to enable this feature.
|
||||
//#define USE_CYRF6936_CH15_TUNING
|
||||
|
||||
/** Low Power **/
|
||||
//Low power is reducing the transmit power of the multi module. This setting is configurable per model in PPM (table below) or Serial mode (radio GUI).
|
||||
//It can be activated when flying indoor or small models since the distance is short or if a model is causing issues when flying closed to the TX.
|
||||
//By default low power is completly disabled on all rf chips to prevent mistakes, but you can enable it by uncommenting the lines below:
|
||||
//#define A7105_ENABLE_LOW_POWER
|
||||
//#define CYRF6936_ENABLE_LOW_POWER
|
||||
//#define CC2500_ENABLE_LOW_POWER
|
||||
//#define NRF24L01_ENABLE_LOW_POWER
|
||||
|
||||
|
||||
/*****************/
|
||||
/*** GLOBAL ID ***/
|
||||
/*****************/
|
||||
//A global ID is used by most protocols to bind and retain the bind to models. To prevent duplicate IDs, it is automatically
|
||||
// generated using a random 32 bits number the first time the eeprom is initialized.
|
||||
//If you have 2 Multi modules which you want to share the same ID so you can use either to control the same RC model
|
||||
// then you can force the ID to a certain known value using the lines below.
|
||||
//Default is commented, you should uncoment only for test purpose or if you know exactly what you are doing!!!
|
||||
//#define FORCE_GLOBAL_ID 0x12345678
|
||||
|
||||
//Protocols using the CYRF6936 (DSM, Devo, Walkera...) are using the CYRF ID instead which should prevent duplicated IDs.
|
||||
//If you have 2 Multi modules which you want to share the same ID so you can use either to control the same RC model
|
||||
// then you can force the ID to a certain known value using the lines below.
|
||||
//Default is commented, you should uncoment only for test purpose or if you know exactly what you are doing!!!
|
||||
//#define FORCE_CYRF_ID "\x12\x34\x56\x78\x9A\xBC"
|
||||
|
||||
|
||||
/****************************/
|
||||
/*** PROTOCOLS TO INCLUDE ***/
|
||||
/****************************/
|
||||
//In this section select the protocols you want to be accessible when using the module.
|
||||
//All the protocols will not fit in the Atmega328p module so you need to pick and choose.
|
||||
//Comment the protocols you are not using with "//" to save Flash space.
|
||||
|
||||
//The protocols below need an A7105 to be installed
|
||||
#define AFHDS2A_A7105_INO
|
||||
#define FLYSKY_A7105_INO
|
||||
#define HUBSAN_A7105_INO
|
||||
#define BUGS_A7105_INO
|
||||
|
||||
//The protocols below need a CYRF6936 to be installed
|
||||
#define DEVO_CYRF6936_INO
|
||||
#define DSM_CYRF6936_INO
|
||||
#define J6PRO_CYRF6936_INO
|
||||
#define WFLY_CYRF6936_INO
|
||||
#define WK2x01_CYRF6936_INO
|
||||
|
||||
//#define TRAXXAS_CYRF6936_INO
|
||||
|
||||
//The protocols below need a CC2500 to be installed
|
||||
#define CORONA_CC2500_INO
|
||||
#define FRSKYD_CC2500_INO
|
||||
#define FRSKYV_CC2500_INO
|
||||
#define FRSKYX_CC2500_INO
|
||||
#define HITEC_CC2500_INO
|
||||
#define SFHSS_CC2500_INO
|
||||
#define REDPINE_CC2500_INO
|
||||
|
||||
//The protocols below need a NRF24L01 to be installed
|
||||
#define ASSAN_NRF24L01_INO
|
||||
#define BAYANG_NRF24L01_INO
|
||||
#define BUGSMINI_NRF24L01_INO
|
||||
#define CABELL_NRF24L01_INO
|
||||
#define CFLIE_NRF24L01_INO
|
||||
#define CG023_NRF24L01_INO
|
||||
#define CX10_NRF24L01_INO //Include Q2X2 protocol
|
||||
#define DM002_NRF24L01_INO
|
||||
#define E01X_NRF24L01_INO
|
||||
#define ESKY_NRF24L01_INO
|
||||
#define ESKY150_NRF24L01_INO
|
||||
#define FQ777_NRF24L01_INO
|
||||
#define FY326_NRF24L01_INO
|
||||
#define GD00X_NRF24L01_INO
|
||||
#define GW008_NRF24L01_INO
|
||||
#define HISKY_NRF24L01_INO
|
||||
#define HONTAI_NRF24L01_INO
|
||||
#define H8_3D_NRF24L01_INO
|
||||
#define KF606_NRF24L01_INO
|
||||
#define KN_NRF24L01_INO
|
||||
#define MJXQ_NRF24L01_INO
|
||||
#define MT99XX_NRF24L01_INO
|
||||
#define NCC1701_NRF24L01_INO
|
||||
#define POTENSIC_NRF24L01_INO
|
||||
#define Q303_NRF24L01_INO
|
||||
#define SHENQI_NRF24L01_INO
|
||||
#define SLT_NRF24L01_INO
|
||||
#define SYMAX_NRF24L01_INO
|
||||
#define V2X2_NRF24L01_INO
|
||||
#define V761_NRF24L01_INO
|
||||
#define V911S_NRF24L01_INO
|
||||
#define YD717_NRF24L01_INO
|
||||
|
||||
|
||||
/***************************/
|
||||
/*** PROTOCOLS SETTINGS ***/
|
||||
/***************************/
|
||||
|
||||
//DSM specific settings
|
||||
//---------------------
|
||||
//The DSM protocol is using by default the Spektrum throw of 1100..1900us @100% and 1000..2000us @125%.
|
||||
// For more throw, 1024..1976us @100% and 904..2096us @125%, remove the "//" on the line below. Be aware that too much throw can damage some UMX servos. To achieve standard throw in this mode use a channel weight of 84%.
|
||||
//#define DSM_MAX_THROW
|
||||
//Some models (X-Vert, Blade 230S...) require a special value to instant stop the motor(s).
|
||||
// You can disable this feature by adding "//" on the line below. You have to specify which channel (15 by default) will be used to kill the throttle channel.
|
||||
// If the channel 15 is above -50% the throttle is untouched but if it is between -50% and -100%, the throttle output will be forced between -100% and -150%.
|
||||
// For example, a value of -80% applied on channel 15 will instantly kill the motors on the X-Vert.
|
||||
#define DSM_THROTTLE_KILL_CH 15
|
||||
|
||||
//AFHDS2A specific settings
|
||||
//-------------------------
|
||||
//When enabled (remove the "//"), the below setting makes LQI (Link Quality Indicator) available on one of the RX ouput channel (5-14).
|
||||
//#define AFHDS2A_LQI_CH 14
|
||||
|
||||
|
||||
/**************************/
|
||||
/*** FAILSAFE SETTINGS ***/
|
||||
/**************************/
|
||||
//The module is using the same default failsafe values for all protocols which currently supports it:
|
||||
// Devo, WK2x01, SFHSS, HISKY/HK310 and AFHDS2A
|
||||
//All channels are centered except throttle which is forced low.
|
||||
//If you want to diasble failsafe globally comment the line below using "//".
|
||||
#define FAILSAFE_ENABLE
|
||||
|
||||
//Failsafe throttle low value in percentage.
|
||||
//Value between -125% and +125%. Default -100.
|
||||
#define FAILSAFE_THROTTLE_LOW -100
|
||||
|
||||
//The radio using serial protocol can set failsafe data.
|
||||
// Two options are available:
|
||||
// a. replace the default failsafe data with serial failsafe data when they are received.
|
||||
// b. wait for the radio to provide failsafe before sending it. Enable advanced settings like "FAILSAFE NOT SET" or "FAILSAFE RX".
|
||||
// Option a. is the default since you have a protection even if no failsafe has been set on the radio.
|
||||
// You can force option b. by uncommenting the line below (remove the "//").
|
||||
//#define FAILSAFE_SERIAL_ONLY
|
||||
|
||||
|
||||
/**************************/
|
||||
/*** TELEMETRY SETTINGS ***/
|
||||
/**************************/
|
||||
//In this section you can configure the telemetry.
|
||||
|
||||
//If you do not plan using the telemetry comment this global setting using "//" and skip to the next section.
|
||||
#define TELEMETRY
|
||||
|
||||
//Comment to invert the polarity of the output telemetry serial signal.
|
||||
//This function takes quite some flash space and processor power on an atmega.
|
||||
//For OpenTX it must be uncommented.
|
||||
//On a 9XR_PRO running ersky9x both commented and uncommented will work depending on the radio setting Invert COM1 under the Telemetry menu.
|
||||
//On other addon/replacement boards like the 9xtreme board or the Ar9x board running ersky9x, you need to uncomment the line below.
|
||||
//For er9x it depends if you have an inveter mod or not on the telemetry pin. If you don't have an inverter comment this line.
|
||||
#define INVERT_TELEMETRY
|
||||
|
||||
//Comment if you don't want to send Multi status telemetry frames (Protocol available, Bind in progress, version...)
|
||||
//Use with er9x/erksy9x, for OpenTX MULTI_TELEMETRY below is preferred instead
|
||||
#define MULTI_STATUS
|
||||
|
||||
//Uncomment to send Multi status and allow OpenTX to autodetect the telemetry format
|
||||
//Supported by OpenTX version 2.2 RC9 and newer. NOT supported by er9x/ersky9x use MULTI_STATUS instead.
|
||||
//#define MULTI_TELEMETRY
|
||||
|
||||
//Comment a line to disable a specific protocol telemetry
|
||||
#define DSM_TELEMETRY // Forward received telemetry packet directly to TX to be decoded by er9x, ersky9x and OpenTX
|
||||
#define SPORT_TELEMETRY // Use FrSkyX SPORT format to send telemetry to TX
|
||||
#define AFHDS2A_FW_TELEMETRY // Forward received telemetry packet directly to TX to be decoded by ersky9x and OpenTX
|
||||
#define AFHDS2A_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to TX like er9x
|
||||
#define HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
|
||||
#define BAYANG_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
|
||||
#define BUGS_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
|
||||
#define HUBSAN_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
|
||||
#define NCC1701_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
|
||||
#define CABELL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
|
||||
#define HITEC_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to the radios which can decode it like er9x, ersky9x and OpenTX
|
||||
#define HITEC_FW_TELEMETRY // Under development: Forward received telemetry packets to be decoded by ersky9x and OpenTX
|
||||
|
||||
//SPORT_POLLING is an implementation of the same polling routine as XJT module for sport telemetry bidirectional communication.
|
||||
//This is useful for passing sport control frames from TX to RX(ex: changing Betaflight PID or VTX channels on the fly using LUA scripts with OpentX).
|
||||
//Using this feature requires to uncomment INVERT_TELEMETRY as this TX output on telemetry pin only inverted signal.
|
||||
//!!!! This is a work in progress!!! Do not enable unless you want to test and report
|
||||
//#define SPORT_POLLING
|
||||
|
||||
|
||||
/****************************/
|
||||
/*** SERIAL MODE SETTINGS ***/
|
||||
/****************************/
|
||||
//In this section you can configure the serial mode.
|
||||
//The serial mode enables full editing of all the parameters in the GUI of the radio. It is enabled by placing the rotary switch on position 0.
|
||||
//This is available natively for ER9X, ERSKY9X and OpenTX.
|
||||
|
||||
//If you do not plan to use the Serial mode comment this line using "//" to save Flash space
|
||||
#define ENABLE_SERIAL
|
||||
|
||||
|
||||
/*************************/
|
||||
/*** PPM MODE SETTINGS ***/
|
||||
/*************************/
|
||||
//In this section you can configure all details about PPM.
|
||||
//If you do not plan to use the PPM mode comment this line using "//" to save Flash space, you don't need to configure anything below in this case
|
||||
#define ENABLE_PPM
|
||||
|
||||
/** TX END POINTS **/
|
||||
//It is important for the module to know the endpoints of your radio.
|
||||
//Below are some standard transmitters already preconfigured.
|
||||
//Uncomment only the one which matches your transmitter.
|
||||
#define TX_ER9X //ER9X/ERSKY9X/OpenTX ( 988<->2012 microseconds)
|
||||
//#define TX_DEVO7 //DEVO (1120<->1920 microseconds)
|
||||
//#define TX_SPEKTRUM //Spektrum (1100<->1900 microseconds)
|
||||
//#define TX_HISKY //HISKY (1120<->1920 microseconds)
|
||||
//#define TX_MPX //Multiplex MC2020 (1250<->1950 microseconds)
|
||||
//#define TX_WALKERA //Walkera PL0811-01H (1000<->1800 microseconds)
|
||||
//#define TX_CUSTOM //Custom
|
||||
|
||||
// The lines below are used to set the end points in microseconds if you have selected TX_CUSTOM.
|
||||
// A few things to consider:
|
||||
// - If you put too big values compared to your TX you won't be able to reach the extremes which is bad for throttle as an example
|
||||
// - If you put too low values you won't be able to use your full stick range, it will be maxed out before reaching the ends
|
||||
// - Centered stick value is usually 1500. It should match the middle between MIN and MAX, ie Center=(MAX+MIN)/2. If your TX is not centered you can adjust the value MIN or MAX.
|
||||
// - 100% is referred as the value when the TX is set to default with no trims
|
||||
#if defined(TX_CUSTOM)
|
||||
#define PPM_MAX_100 1900 // 100%
|
||||
#define PPM_MIN_100 1100 // 100%
|
||||
#endif
|
||||
|
||||
/** Number of PPM Channels **/
|
||||
// The line below is used to set the minimum number of channels which the module should receive to consider a PPM frame valid.
|
||||
// The default value is 4 to receive at least AETR for flying models but you could also connect the PPM from a car radio which has only 3 channels by changing this number to 3.
|
||||
#define MIN_PPM_CHANNELS 4
|
||||
// The line below is used to set the maximum number of channels which the module should work with. Any channels received above this number are discarded.
|
||||
// The default value is 16 to receive all possible channels but you might want to filter some "bad" channels from the PPM frame like the ones above 6 on the Walkera PL0811.
|
||||
#define MAX_PPM_CHANNELS 16
|
||||
|
||||
/** Rotary Switch Protocol Selector Settings **/
|
||||
//The table below indicates which protocol to run when a specific position on the rotary switch has been selected.
|
||||
//All fields and values are explained below. Everything is configurable from here like in the Serial mode.
|
||||
//Tip: You can associate multiple times the same protocol to different rotary switch positions to take advantage of the model match based on RX_Num
|
||||
|
||||
//A system of banks enable the access to more protocols than positions on the rotary switch. Banks can be selected by placing the rotary switch on position 15, power up the module and
|
||||
// short press the bind button multiple times until you reach the desired one. The bank number currently selected is indicated by the number of LED flash.
|
||||
// Full procedure is located here: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md#protocol-selection-in-ppm-mode
|
||||
|
||||
//The parameter below indicates the number of desired banks between 1 and 5. Default is 5.
|
||||
#define NBR_BANKS 5
|
||||
|
||||
const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
#if NBR_BANKS > 0
|
||||
//****************************** BANK 1 ******************************
|
||||
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option
|
||||
/* 1 */ {PROTO_FLYSKY, Flysky , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 2 */ {PROTO_AFHDS2A, PWM_IBUS , 0 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 0
|
||||
/* 3 */ {PROTO_AFHDS2A, PWM_IBUS , 1 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 1
|
||||
/* 4 */ {PROTO_AFHDS2A, PWM_IBUS , 2 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 2
|
||||
/* 5 */ {PROTO_AFHDS2A, PWM_IBUS , 3 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 3
|
||||
/* 6 */ {PROTO_AFHDS2A, PWM_IBUS , 2 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 4
|
||||
/* 7 */ {PROTO_AFHDS2A, PWM_IBUS , 3 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 5
|
||||
/* 8 */ {PROTO_SFHSS, H107 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 9 */ {PROTO_FRSKYV, NONE , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
|
||||
/* 10 */ {PROTO_FRSKYD, NONE , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
|
||||
/* 11 */ {PROTO_FRSKYX, CH_16 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
|
||||
/* 12 */ {PROTO_FRSKYX, EU_16 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
|
||||
/* 13 */ {PROTO_DEVO , NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 14 */ {PROTO_WK2x01, WK2801 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
#endif
|
||||
#if NBR_BANKS > 1
|
||||
//****************************** BANK 2 ******************************
|
||||
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option
|
||||
/* 1 */ {PROTO_DSM , DSM2_11 , 0 , P_HIGH , NO_AUTOBIND , 6 }, // option=number of channels
|
||||
/* 2 */ {PROTO_DSM , DSM2_22 , 0 , P_HIGH , NO_AUTOBIND , 6 }, // option=number of channels
|
||||
/* 3 */ {PROTO_DSM , DSMX_11 , 0 , P_HIGH , NO_AUTOBIND , 6 }, // option=number of channels
|
||||
/* 4 */ {PROTO_DSM , DSMX_22 , 0 , P_HIGH , NO_AUTOBIND , 6 }, // option=number of channels
|
||||
/* 5 */ {PROTO_DSM , DSM2_11 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels
|
||||
/* 6 */ {PROTO_DSM , DSM2_22 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels
|
||||
/* 7 */ {PROTO_DSM , DSMX_11 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels
|
||||
/* 8 */ {PROTO_DSM , DSMX_22 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels
|
||||
/* 9 */ {PROTO_SLT , SLT_V1 , 0 , P_HIGH , NO_AUTOBIND , 6 },
|
||||
/* 10 */ {PROTO_HUBSAN, H107 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 11 */ {PROTO_HUBSAN, H301 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 12 */ {PROTO_HUBSAN, H501 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 13 */ {PROTO_HISKY, Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 14 */ {PROTO_V2X2 , NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
#endif
|
||||
#if NBR_BANKS > 2
|
||||
//****************************** BANK 3 ******************************
|
||||
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option
|
||||
/* 1 */ {PROTO_ESKY , NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 2 */ {PROTO_ESKY150, NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 3 */ {PROTO_ASSAN, NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 4 */ {PROTO_CORONA, COR_V2 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 5 */ {PROTO_SYMAX, SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 6 */ {PROTO_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 7 */ {PROTO_BAYANG, BAYANG , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 8 */ {PROTO_BAYANG, H8S3D , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 9 */ {PROTO_BAYANG, X16_AH , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 10 */ {PROTO_BAYANG, IRDRONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 11 */ {PROTO_H8_3D, H8_3D , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 12 */ {PROTO_H8_3D, H20H , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 13 */ {PROTO_H8_3D, H20MINI , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 14 */ {PROTO_H8_3D, H30MINI , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
#endif
|
||||
#if NBR_BANKS > 3
|
||||
//****************************** BANK 4 ******************************
|
||||
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option
|
||||
/* 1 */ {PROTO_MJXQ , WLH08 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 2 */ {PROTO_MJXQ , X600 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 3 */ {PROTO_MJXQ , X800 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 4 */ {PROTO_MJXQ , H26D , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 5 */ {PROTO_MJXQ , E010 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 6 */ {PROTO_MJXQ , H26WH , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 7 */ {PROTO_HONTAI, HONTAI , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 8 */ {PROTO_HONTAI, JJRCX1 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 9 */ {PROTO_HONTAI, X5C1 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 10 */ {PROTO_HONTAI, FQ777_951 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 11 */ {PROTO_Q303 , Q303 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 12 */ {PROTO_Q303 , CX35 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 13 */ {PROTO_Q303 , CX10D , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 14 */ {PROTO_Q303 , CX10WD , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
#endif
|
||||
#if NBR_BANKS > 4
|
||||
//****************************** BANK 5 ******************************
|
||||
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option
|
||||
/* 1 */ {PROTO_CX10 , CX10_GREEN , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 2 */ {PROTO_CX10 , CX10_BLUE , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 3 */ {PROTO_CX10 , DM007 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 4 */ {PROTO_CX10 , JC3015_1 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 5 */ {PROTO_CX10 , JC3015_2 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 6 */ {PROTO_CX10 , MK33041 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 7 */ {PROTO_Q2X2 , Q222 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 8 */ {PROTO_Q2X2 , Q242 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 9 */ {PROTO_Q2X2 , Q282 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 10 */ {PROTO_CG023, CG023 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 11 */ {PROTO_CG023, YD829 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 12 */ {PROTO_FQ777, NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 13 */ {PROTO_YD717, YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 14 */ {PROTO_MT99XX, MT99 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
#endif
|
||||
};
|
||||
// RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded...
|
||||
// RX_Num value is between 0 and 15.
|
||||
|
||||
// Power P_HIGH or P_LOW: High or low power setting for the transmission.
|
||||
// For indoor P_LOW is more than enough.
|
||||
|
||||
// Auto Bind AUTOBIND or NO_AUTOBIND
|
||||
// For protocols which does not require binding at each power up (like Flysky, FrSky...), you might still want a bind to be initiated each time you power up the TX.
|
||||
// As an example, it's usefull for the WLTOYS F929/F939/F949/F959 (all using the Flysky protocol) which requires a bind at each power up.
|
||||
// It also enables the Bind from channel feature, allowing to execute a bind by toggling a designated channel.
|
||||
|
||||
// Option: the value is between -128 and +127.
|
||||
// The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md
|
||||
|
||||
/* Available protocols and associated sub protocols to pick and choose from (Listed in alphabetical order)
|
||||
PROTO_AFHDS2A
|
||||
PWM_IBUS
|
||||
PPM_IBUS
|
||||
PWM_SBUS
|
||||
PPM_SBUS
|
||||
PROTO_ASSAN
|
||||
NONE
|
||||
PROTO_BAYANG
|
||||
BAYANG
|
||||
H8S3D
|
||||
X16_AH
|
||||
IRDRONE
|
||||
DHD_D4
|
||||
PROTO_BUGS
|
||||
NONE
|
||||
PROTO_BUGSMINI
|
||||
BUGSMINI
|
||||
BUGS3H
|
||||
PROTO_CABELL
|
||||
CABELL_V3
|
||||
CABELL_V3_TELEMETRY
|
||||
CABELL_SET_FAIL_SAFE
|
||||
CABELL_UNBIND
|
||||
PROTO_CFLIE
|
||||
NONE
|
||||
PROTO_CG023
|
||||
CG023
|
||||
YD829
|
||||
PROTO_CORONA
|
||||
COR_V1
|
||||
COR_V2
|
||||
FD_V3
|
||||
PROTO_CX10
|
||||
CX10_GREEN
|
||||
CX10_BLUE
|
||||
DM007
|
||||
JC3015_1
|
||||
JC3015_2
|
||||
MK33041
|
||||
PROTO_DEVO
|
||||
NONE
|
||||
PROTO_DM002
|
||||
NONE
|
||||
PROTO_DSM
|
||||
DSM2_22
|
||||
DSM2_11
|
||||
DSMX_22
|
||||
DSMX_11
|
||||
PROTO_E01X
|
||||
E012
|
||||
E015
|
||||
E016H
|
||||
PROTO_ESKY
|
||||
NONE
|
||||
PROTO_ESKY150
|
||||
NONE
|
||||
PROTO_FLYSKY
|
||||
Flysky
|
||||
V9X9
|
||||
V6X6
|
||||
V912
|
||||
CX20
|
||||
PROTO_FQ777
|
||||
NONE
|
||||
PROTO_FRSKYD
|
||||
NONE
|
||||
PROTO_FRSKYV
|
||||
NONE
|
||||
PROTO_FRSKYX
|
||||
CH_16
|
||||
CH_8
|
||||
EU_16
|
||||
EU_8
|
||||
PROTO_FY326
|
||||
FY326
|
||||
FY319
|
||||
PROTO_GD00X
|
||||
GD_V1
|
||||
GD_V2
|
||||
PROTO_GW008
|
||||
NONE
|
||||
PROTO_H8_3D
|
||||
H8_3D
|
||||
H20H
|
||||
H20MINI
|
||||
H30MINI
|
||||
PROTO_HISKY
|
||||
Hisky
|
||||
HK310
|
||||
PROTO_HITEC
|
||||
OPT_FW
|
||||
OPT_HUB
|
||||
MINIMA
|
||||
PROTO_HONTAI
|
||||
HONTAI
|
||||
JJRCX1
|
||||
X5C1
|
||||
FQ777_951
|
||||
PROTO_HUBSAN
|
||||
H107
|
||||
H301
|
||||
H501
|
||||
PROTO_J6PRO
|
||||
NONE
|
||||
PROTO_KF606
|
||||
NONE
|
||||
PROTO_KN
|
||||
WLTOYS
|
||||
FEILUN
|
||||
PROTO_MJXQ
|
||||
WLH08
|
||||
X600
|
||||
X800
|
||||
H26D
|
||||
E010
|
||||
H26WH
|
||||
PHOENIX
|
||||
PROTO_MT99XX
|
||||
MT99
|
||||
H7
|
||||
YZ
|
||||
LS
|
||||
FY805
|
||||
PROTO_NCC1701
|
||||
NONE
|
||||
PROTO_POTENSIC
|
||||
NONE
|
||||
PROTO_Q2X2
|
||||
Q222
|
||||
Q242
|
||||
Q282
|
||||
PROTO_Q303
|
||||
Q303
|
||||
CX35
|
||||
CX10D
|
||||
CX10WD
|
||||
PROTO_REDPINE
|
||||
RED_FAST
|
||||
RED_SLOW
|
||||
PROTO_SFHSS
|
||||
NONE
|
||||
PROTO_SHENQI
|
||||
NONE
|
||||
PROTO_SLT
|
||||
SLT_V1
|
||||
SLT_V2
|
||||
Q100
|
||||
Q200
|
||||
MR100
|
||||
PROTO_SYMAX
|
||||
SYMAX
|
||||
SYMAX5C
|
||||
PROTO_TRAXXAS
|
||||
NONE
|
||||
PROTO_V2X2
|
||||
V2X2
|
||||
JXD506
|
||||
PROTO_V761
|
||||
NONE
|
||||
PROTO_V911S
|
||||
NONE
|
||||
PROTO_WFLY
|
||||
NONE
|
||||
PROTO_WK2x01
|
||||
WK2801
|
||||
WK2401
|
||||
W6_5_1
|
||||
W6_6_1
|
||||
W6_HEL
|
||||
W6_HEL_I
|
||||
PROTO_YD717
|
||||
YD717
|
||||
SKYWLKR
|
||||
SYMAX4
|
||||
XINXUN
|
||||
NIHUI
|
||||
*/
|
||||
79
Multiprotocol/_MyConfig.h.example
Normal file
79
Multiprotocol/_MyConfig.h.example
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
This file is meant to keep your settings after an upgrade of the multi source.
|
||||
If you know parameters you want for sure to be enabled or disabled in future
|
||||
then just force their values here.
|
||||
To enable a setting use #define <setting name>
|
||||
To disable a setting use #undef <setting name>
|
||||
*/
|
||||
|
||||
// For example you can also define multiple module configurations, uncomment the one you want to compile for:
|
||||
#define Module_1
|
||||
//#define Module_2
|
||||
//#define Module_3
|
||||
//#define Module_4
|
||||
|
||||
//Example on how to force the "Flash from TX" feature for all modules
|
||||
#define CHECK_FOR_BOOTLOADER
|
||||
|
||||
//Example on how to force the same ID for all modules: be carefull this is really if you want to be able to use one or another radio but not both!
|
||||
//#define FORCE_GLOBAL_ID 0x12345678
|
||||
|
||||
#if defined Module_1
|
||||
//Example on how to remove unwanted protocols to fit in flash for Atmega 328 modules
|
||||
#undef AFHDS2A_A7105_INO
|
||||
|
||||
#undef DEVO_CYRF6936_INO
|
||||
#undef J6PRO_CYRF6936_INO
|
||||
#undef WK2x01_CYRF6936_INO
|
||||
|
||||
#undef FRSKYV_CC2500_INO
|
||||
#undef FRSKYX_CC2500_INO
|
||||
|
||||
#undef KN_NRF24L01_INO
|
||||
#undef SLT_NRF24L01_INO
|
||||
|
||||
#undef FY326_NRF24L01_INO
|
||||
#undef FQ777_NRF24L01_INO
|
||||
#undef ASSAN_NRF24L01_INO
|
||||
#undef HONTAI_NRF24L01_INO
|
||||
#undef Q303_NRF24L01_INO
|
||||
#undef GW008_NRF24L01_INO
|
||||
#undef DM002_NRF24L01_INO
|
||||
#undef CABELL_NRF24L01_INO
|
||||
#undef ESKY150_NRF24L01_INO
|
||||
#undef H8_3D_NRF24L01_INO
|
||||
|
||||
#elif defined Module_2
|
||||
//Example of a module which doesn't need the telemetry signal to be inverted
|
||||
#undef INVERT_TELEMETRY
|
||||
|
||||
#elif defined Module_3
|
||||
//Example of a module which will be used with OpenTX
|
||||
#undef MULTI_STATUS
|
||||
#define MULTI_TELEMETRY
|
||||
|
||||
#elif defined Module_4
|
||||
//Example of a module which will be PPM only with a different protocol table
|
||||
#undef ENABLE_SERIAL
|
||||
#undef NBR_BANKS
|
||||
#define NBR_BANKS 1 // redefine the number of banks
|
||||
#define MY_PPM_PROT // Use the bellow protocol list
|
||||
const PPM_Parameters My_PPM_prot[14*NBR_BANKS]={
|
||||
//****************************** BANK 1 ******************************
|
||||
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option
|
||||
/* 1 */ {PROTO_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 2 */ {PROTO_FLYSKY, Flysky , 0 , P_HIGH , AUTOBIND , 0 },
|
||||
/* 3 */ {PROTO_AFHDS2A, PWM_IBUS , 1 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 1
|
||||
/* 4 */ {PROTO_AFHDS2A, PWM_IBUS , 2 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 2
|
||||
/* 5 */ {PROTO_AFHDS2A, PWM_IBUS , 3 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 3
|
||||
/* 6 */ {PROTO_AFHDS2A, PWM_IBUS , 2 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 4
|
||||
/* 7 */ {PROTO_AFHDS2A, PWM_IBUS , 3 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 5
|
||||
/* 8 */ {PROTO_SFHSS, H107 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 9 */ {PROTO_FRSKYV, NONE , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
|
||||
/* 10 */ {PROTO_FRSKYD, NONE , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
|
||||
/* 11 */ {PROTO_FRSKYX, CH_16 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
|
||||
/* 12 */ {PROTO_FRSKYX, EU_16 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
|
||||
/* 13 */ {PROTO_DEVO , NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
/* 14 */ {PROTO_WK2x01, WK2801 , 0 , P_HIGH , NO_AUTOBIND , 0 },
|
||||
};
|
||||
#endif
|
||||
@@ -87,9 +87,4 @@ enum A7105_MASK {
|
||||
A7105_MASK_VBCF = 1 << 3,
|
||||
};
|
||||
|
||||
enum {
|
||||
INIT_FLYSKY,
|
||||
INIT_HUBSAN
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -146,4 +146,5 @@ enum {
|
||||
//void CC2500_WriteData(u8 *packet, u8 length);
|
||||
//void CC2500_ReadData(u8 *dpbuffer, int len);
|
||||
//void CC2500_SetTxRxMode(enum TXRX_State);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -83,13 +83,13 @@ void CYRF_SetTxRxMode(enum TXRX_State);
|
||||
void CYRF_ConfigRFChannel(u8 ch);
|
||||
void CYRF_SetPower(u8 power);
|
||||
void CYRF_ConfigCRCSeed(u16 crc);
|
||||
void CYRF_StartReceive();
|
||||
static void CYRF_StartReceive();
|
||||
void CYRF_ConfigSOPCode(const u8 *sopcodes);
|
||||
void CYRF_ConfigDataCode(const u8 *datacodes, u8 len);
|
||||
u8 CYRF_ReadRSSI(u32 dodummyread);
|
||||
void CYRF_ReadDataPacket(u8 dpbuffer[]);
|
||||
static u8 CYRF_ReadRSSI(u32 dodummyread);
|
||||
static void CYRF_ReadDataPacket(u8 dpbuffer[]);
|
||||
void CYRF_WriteDataPacket(const u8 dpbuffer[]);
|
||||
void CYRF_WriteDataPacketLen(const u8 dpbuffer[], u8 len);
|
||||
static void CYRF_WriteDataPacketLen(const u8 dpbuffer[], u8 len);
|
||||
void CYRF_WriteRegister(u8 address, u8 data);
|
||||
u8 CYRF_ReadRegister(u8 address);
|
||||
void CYRF_WritePreamble(u32 preamble);
|
||||
|
||||
@@ -102,18 +102,9 @@ enum {
|
||||
#define REUSE_TX_PL 0xE3
|
||||
//#define NOP 0xFF
|
||||
|
||||
/*
|
||||
void NRF24L01_Initialize();
|
||||
byte NRF24L01_WriteReg(byte reg, byte data);
|
||||
byte NRF24L01_WriteRegisterMulti(byte reg, byte data[], byte length);
|
||||
byte NRF24L01_WritePayload(byte *data, byte len);
|
||||
byte NRF24L01_ReadReg(byte reg);
|
||||
byte NRF24L01_ReadRegisterMulti(byte reg, byte data[], byte length);
|
||||
byte NRF24L01_ReadPayload(byte *data, byte len);
|
||||
|
||||
byte NRF24L01_FlushTx();
|
||||
byte NRF24L01_FlushRx();
|
||||
byte NRF24L01_Activate(byte code);
|
||||
|
||||
*/
|
||||
// XN297 emulation layer
|
||||
enum {
|
||||
XN297_UNSCRAMBLED = 0,
|
||||
XN297_SCRAMBLED
|
||||
};
|
||||
#endif
|
||||
20
Multiprotocol/iface_xn297l.h
Normal file
20
Multiprotocol/iface_xn297l.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef _IFACE_XN297L_H_
|
||||
|
||||
#define _IFACE_XN297L_H_
|
||||
|
||||
#if defined (XN297L_CC2500_EMU)
|
||||
#include "iface_cc2500.h"
|
||||
#elif defined (NRF24L01_INSTALLED)
|
||||
#include "iface_nrf24l01.h"
|
||||
#endif
|
||||
|
||||
static void __attribute__((unused)) XN297L_Init();
|
||||
static void __attribute__((unused)) XN297L_SetTXAddr(const uint8_t*, uint8_t);
|
||||
static void __attribute__((unused)) XN297L_WritePayload(uint8_t*, uint8_t);
|
||||
static void __attribute__((unused)) XN297L_HoppingCalib(__attribute__((unused)) uint8_t);
|
||||
static void __attribute__((unused)) XN297L_Hopping(uint8_t);
|
||||
static void __attribute__((unused)) XN297L_RFChannel(uint8_t);
|
||||
static void __attribute__((unused)) XN297L_SetPower();
|
||||
static void __attribute__((unused)) XN297L_SetFreqOffset();
|
||||
|
||||
#endif
|
||||
@@ -1,471 +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/>.
|
||||
*/
|
||||
|
||||
//******************
|
||||
enum PROTOCOLS
|
||||
{
|
||||
MODE_SERIAL = 0, // Serial commands
|
||||
MODE_FLYSKY = 1, // =>A7105 / FLYSKY protocol
|
||||
MODE_HUBSAN = 2, // =>A7105 / HUBSAN protocol
|
||||
MODE_FRSKY = 3, // =>CC2500 / FRSKY protocol
|
||||
MODE_HISKY = 4, // =>NRF24L01 / HISKY protocol
|
||||
MODE_V2X2 = 5, // =>NRF24L01 / V2x2 protocol
|
||||
MODE_DSM2 = 6, // =>CYRF6936 / DSM2 protocol
|
||||
MODE_DEVO =7, // =>CYRF6936 / DEVO protocol
|
||||
MODE_YD717 = 8, // =>NRF24L01 / YD717 protocol (CX10 red pcb)
|
||||
MODE_KN = 9, // =>NRF24L01 / KN protocol
|
||||
MODE_SYMAX = 10, // =>NRF24L01 / SYMAX protocol (SYMAX4 working)
|
||||
MODE_SLT = 11, // =>NRF24L01 / SLT protocol
|
||||
MODE_CX10 = 12, // =>NRF24L01 / CX-10 protocol
|
||||
MODE_CG023 = 13, // =>NRF24L01 / CG023 protocol
|
||||
MODE_BAYANG = 14, // =>NRF24L01 / BAYANG protocol
|
||||
MODE_FRSKYX = 15, // =>CC2500 / FRSKYX protocol
|
||||
};
|
||||
enum Flysky
|
||||
{
|
||||
Flysky=0,
|
||||
V9X9=1,
|
||||
V6X6=2,
|
||||
V912=3
|
||||
};
|
||||
enum Hisky
|
||||
{
|
||||
Hisky=0,
|
||||
HK310=1
|
||||
};
|
||||
enum DSM2{
|
||||
DSM2=0,
|
||||
DSMX=1
|
||||
};
|
||||
enum YD717
|
||||
{
|
||||
YD717=0,
|
||||
SKYWLKR=1,
|
||||
SYMAX2=2,
|
||||
XINXUN=3,
|
||||
NIHUI=4
|
||||
};
|
||||
enum SYMAX
|
||||
{
|
||||
SYMAX=0,
|
||||
SYMAX5C=1,
|
||||
};
|
||||
|
||||
enum CX10 {
|
||||
CX10_GREEN = 0,
|
||||
CX10_BLUE, // also compatible with CX10-A, CX12
|
||||
DM007
|
||||
};
|
||||
|
||||
enum CG023 {
|
||||
CG023 = 0,
|
||||
YD829 = 1,
|
||||
H8_3D = 2
|
||||
};
|
||||
|
||||
#define PPM_MIN_COMMAND 1250
|
||||
#define PPM_SWITCH 1550
|
||||
#define PPM_MAX_COMMAND 1750
|
||||
|
||||
//*******************
|
||||
//*** Pinouts ***
|
||||
//*******************
|
||||
//#define BIND_pin 13
|
||||
#define LED_pin 13 //Promini original led on B5
|
||||
//
|
||||
#define PPM_pin 3 //PPM -D3
|
||||
#define SDI_pin 5 //SDIO-D5
|
||||
#define SCLK_pin 4 //SCK-D4
|
||||
#define CS_pin 2 //CS-D2
|
||||
#define SDO_pin 6 //D6
|
||||
//
|
||||
#define CTRL1 1 //C1 (A1)
|
||||
#define CTRL2 2 //C2 (A2)
|
||||
//
|
||||
#define CTRL1_on PORTC |= _BV(1)
|
||||
#define CTRL1_off PORTC &= ~_BV(1)
|
||||
//
|
||||
#define CTRL2_on PORTC |= _BV(2)
|
||||
#define CTRL2_off PORTC &= ~_BV(2)
|
||||
//
|
||||
#define CS_on PORTD |= _BV(2) //D2
|
||||
#define CS_off PORTD &= ~_BV(2) //D2
|
||||
//
|
||||
#define SCK_on PORTD |= _BV(4) //D4
|
||||
#define SCK_off PORTD &= ~_BV(4) //D4
|
||||
//
|
||||
#define SDI_on PORTD |= _BV(5) //D5
|
||||
#define SDI_off PORTD &= ~_BV(5) //D5
|
||||
|
||||
#define SDI_1 (PIND & (1<<SDI_pin)) == (1<<SDI_pin) //D5
|
||||
#define SDI_0 (PIND & (1<<SDI_pin)) == 0x00 //D5
|
||||
//
|
||||
#define SDI_SET_INPUT DDRD &= ~_BV(5) //D5
|
||||
#define SDI_SET_OUTPUT DDRD |= _BV(5) //D5
|
||||
//Hisky /CC2500/CYRF aditional pinout
|
||||
#define CC25_CSN_pin 7
|
||||
#define NRF_CSN_pin 8
|
||||
#define CYRF_CSN_pin 9
|
||||
//
|
||||
#define CYRF_RST_pin A5 //reset pin
|
||||
//
|
||||
#define CC25_CSN_on PORTD |= _BV(7) //D7
|
||||
#define CC25_CSN_off PORTD &= ~_BV(7) //D7
|
||||
//
|
||||
#define NRF_CSN_on PORTB |= _BV(0) //D8
|
||||
#define NRF_CSN_off PORTB &= ~_BV(0) //D8
|
||||
//
|
||||
#define CYRF_CSN_on PORTB |= _BV(1) //D9
|
||||
#define CYRF_CSN_off PORTB &= ~_BV(1) //D9
|
||||
//
|
||||
#define SDO_1 (PIND & (1<<SDO_pin)) == (1<<SDO_pin) //D6
|
||||
#define SDO_0 (PIND & (1<<SDO_pin)) == 0x00 //D6
|
||||
//
|
||||
#define RS_HI PORTC|=_BV(5) //reset pin cyrf
|
||||
#define RX_LO PORTB &= ~_BV(5)//
|
||||
//
|
||||
//
|
||||
|
||||
// LED
|
||||
#define LED_ON PORTB |= _BV(5)
|
||||
#define LED_OFF PORTB &= ~_BV(5)
|
||||
#define LED_TOGGLE PORTB ^= _BV(5)
|
||||
#define LED_SET_OUTPUT DDRB |= _BV(5)
|
||||
|
||||
// Macros
|
||||
#define NOP() __asm__ __volatile__("nop")
|
||||
#define BV(bit) (1 << bit)
|
||||
|
||||
//Serial flags definition
|
||||
#define RX_FLAG_on protocol_flags |= _BV(0)
|
||||
#define RX_FLAG_off protocol_flags &= ~_BV(0)
|
||||
#define IS_RX_FLAG_on ( ( protocol_flags & _BV(0) ) !=0 )
|
||||
//
|
||||
#define CHANGE_PROTOCOL_FLAG_on protocol_flags |= _BV(1)
|
||||
#define CHANGE_PROTOCOL_FLAG_off protocol_flags &= ~_BV(1)
|
||||
#define IS_CHANGE_PROTOCOL_FLAG_on ( ( protocol_flags & _BV(1) ) !=0 )
|
||||
//
|
||||
#define POWER_FLAG_on protocol_flags |= _BV(2)
|
||||
#define POWER_FLAG_off protocol_flags &= ~_BV(2)
|
||||
#define IS_POWER_FLAG_on ( ( protocol_flags & _BV(2) ) !=0 )
|
||||
//
|
||||
#define RANGE_FLAG_on protocol_flags |= _BV(3)
|
||||
#define RANGE_FLAG_off protocol_flags &= ~_BV(3)
|
||||
#define IS_RANGE_FLAG_on ( ( protocol_flags & _BV(3) ) !=0 )
|
||||
//
|
||||
#define AUTOBIND_FLAG_on protocol_flags |= _BV(4)
|
||||
#define AUTOBIND_FLAG_off protocol_flags &= ~_BV(4)
|
||||
#define IS_AUTOBIND_FLAG_on ( ( protocol_flags & _BV(4) ) !=0 )
|
||||
//
|
||||
#define BIND_BUTTON_FLAG_on protocol_flags |= _BV(5)
|
||||
#define BIND_BUTTON_FLAG_off protocol_flags &= ~_BV(5)
|
||||
#define IS_BIND_BUTTON_FLAG_on ( ( protocol_flags & _BV(5) ) !=0 )
|
||||
|
||||
//PPM RX OK
|
||||
#define PPM_FLAG_off protocol_flags &= ~_BV(6)
|
||||
#define PPM_FLAG_on protocol_flags |= _BV(6)
|
||||
#define IS_PPM_FLAG_on ( ( protocol_flags & _BV(6) ) !=0 )
|
||||
|
||||
//Bind flag for blinking
|
||||
#define BIND_IN_PROGRESS protocol_flags &= ~_BV(7)
|
||||
#define BIND_DONE protocol_flags |= _BV(7)
|
||||
#define IS_BIND_DONE_on ( ( protocol_flags & _BV(7) ) !=0 )
|
||||
|
||||
#define BLINK_BIND_TIME 100
|
||||
#define BLINK_SERIAL_TIME 500
|
||||
|
||||
//************************
|
||||
//*** Power settings ***
|
||||
//************************
|
||||
enum {
|
||||
TXPOWER_100uW,
|
||||
TXPOWER_300uW,
|
||||
TXPOWER_1mW,
|
||||
TXPOWER_3mW,
|
||||
TXPOWER_10mW,
|
||||
TXPOWER_30mW,
|
||||
TXPOWER_100mW,
|
||||
TXPOWER_150mW
|
||||
};
|
||||
|
||||
// A7105 power
|
||||
// Power amp is ~+16dBm so:
|
||||
enum A7105_POWER
|
||||
{
|
||||
A7105_POWER_0 = 0x00<<3 | 0x00, // TXPOWER_100uW = -23dBm == PAC=0 TBG=0
|
||||
A7105_POWER_1 = 0x00<<3 | 0x01, // TXPOWER_300uW = -20dBm == PAC=0 TBG=1
|
||||
A7105_POWER_2 = 0x00<<3 | 0x02, // TXPOWER_1mW = -16dBm == PAC=0 TBG=2
|
||||
A7105_POWER_3 = 0x00<<3 | 0x04, // TXPOWER_3mW = -11dBm == PAC=0 TBG=4
|
||||
A7105_POWER_4 = 0x01<<3 | 0x05, // TXPOWER_10mW = -6dBm == PAC=1 TBG=5
|
||||
A7105_POWER_5 = 0x02<<3 | 0x07, // TXPOWER_30mW = 0dBm == PAC=2 TBG=7
|
||||
A7105_POWER_6 = 0x03<<3 | 0x07, // TXPOWER_100mW = 1dBm == PAC=3 TBG=7
|
||||
A7105_POWER_7 = 0x03<<3 | 0x07 // TXPOWER_150mW = 1dBm == PAC=3 TBG=7
|
||||
};
|
||||
#define A7105_HIGH_POWER A7105_POWER_5
|
||||
#define A7105_LOW_POWER A7105_POWER_3
|
||||
#define A7105_BIND_POWER A7105_POWER_0
|
||||
#define A7105_RANGE_POWER A7105_POWER_0
|
||||
|
||||
// NRF Power
|
||||
// Power setting is 0..3 for nRF24L01
|
||||
// Claimed power amp for nRF24L01 from eBay is 20dBm.
|
||||
enum NRF_POWER
|
||||
{ // Raw w 20dBm PA
|
||||
NRF_POWER_0 = 0x00, // 0 : -18dBm (16uW) 2dBm (1.6mW)
|
||||
NRF_POWER_1 = 0x01, // 1 : -12dBm (60uW) 8dBm (6mW)
|
||||
NRF_POWER_2 = 0x02, // 2 : -6dBm (250uW) 14dBm (25mW)
|
||||
NRF_POWER_3 = 0x03 // 3 : 0dBm (1mW) 20dBm (100mW)
|
||||
};
|
||||
#define NRF_HIGH_POWER NRF_POWER_2
|
||||
#define NRF_LOW_POWER NRF_POWER_1
|
||||
#define NRF_BIND_POWER NRF_POWER_0
|
||||
#define NRF_RANGE_POWER NRF_POWER_0
|
||||
|
||||
// CC2500 power
|
||||
enum CC2500_POWER
|
||||
{
|
||||
CC2500_POWER_0 = 0xC5, // -12dbm
|
||||
CC2500_POWER_1 = 0x97, // -10dbm
|
||||
CC2500_POWER_2 = 0x6E, // -8dbm
|
||||
CC2500_POWER_3 = 0x7F, // -6dbm
|
||||
CC2500_POWER_4 = 0xA9, // -4dbm
|
||||
CC2500_POWER_5 = 0xBB, // -2dbm
|
||||
CC2500_POWER_6 = 0xFE, // 0dbm
|
||||
CC2500_POWER_7 = 0xFF // 1.5dbm
|
||||
};
|
||||
#define CC2500_HIGH_POWER CC2500_POWER_6
|
||||
#define CC2500_LOW_POWER CC2500_POWER_3
|
||||
#define CC2500_BIND_POWER CC2500_POWER_0
|
||||
#define CC2500_RANGE_POWER CC2500_POWER_0
|
||||
|
||||
// CYRF power
|
||||
enum CYRF_POWER
|
||||
{
|
||||
CYRF_POWER_0 = 0x00, // -35dbm
|
||||
CYRF_POWER_1 = 0x01, // -30dbm
|
||||
CYRF_POWER_2 = 0x02, // -24dbm
|
||||
CYRF_POWER_3 = 0x03, // -18dbm
|
||||
CYRF_POWER_4 = 0x04, // -13dbm
|
||||
CYRF_POWER_5 = 0x05, // -5dbm
|
||||
CYRF_POWER_6 = 0x06, // 0dbm
|
||||
CYRF_POWER_7 = 0x07 // +4dbm
|
||||
};
|
||||
#define CYRF_HIGH_POWER CYRF_POWER_7
|
||||
#define CYRF_LOW_POWER CYRF_POWER_3
|
||||
#define CYRF_BIND_POWER CYRF_POWER_0
|
||||
#define CYRF_RANGE_POWER CYRF_POWER_0
|
||||
|
||||
enum TXRX_State {
|
||||
TXRX_OFF,
|
||||
TX_EN,
|
||||
RX_EN
|
||||
};
|
||||
|
||||
// Packet ack status values
|
||||
enum {
|
||||
PKT_PENDING = 0,
|
||||
PKT_ACKED,
|
||||
PKT_TIMEOUT
|
||||
};
|
||||
|
||||
//*******************
|
||||
//*** CRC Table ***
|
||||
//*******************
|
||||
const uint16_t PROGMEM CRCTable[]=
|
||||
{
|
||||
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
|
||||
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
|
||||
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
|
||||
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
|
||||
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
|
||||
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
|
||||
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
|
||||
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
|
||||
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
|
||||
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
|
||||
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
|
||||
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
|
||||
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
|
||||
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
|
||||
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
|
||||
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
|
||||
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
|
||||
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
|
||||
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
|
||||
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
|
||||
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
|
||||
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
|
||||
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
|
||||
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
|
||||
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
|
||||
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
|
||||
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
|
||||
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
|
||||
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
|
||||
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
|
||||
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
|
||||
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
|
||||
};
|
||||
|
||||
|
||||
//****************************************
|
||||
//*** MULTI protocol serial definition ***
|
||||
//****************************************
|
||||
/*
|
||||
**************************
|
||||
16 channels serial protocol
|
||||
**************************
|
||||
Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
||||
Total of 26 bytes
|
||||
Stream[0] = 0x55
|
||||
header
|
||||
Stream[1] = sub_protocol|BindBit|RangeCheckBit|AutoBindBit;
|
||||
sub_protocol is 0..31 (bits 0..4)
|
||||
=> Reserved 0
|
||||
Flysky 1
|
||||
Hubsan 2
|
||||
Frsky 3
|
||||
Hisky 4
|
||||
V2x2 5
|
||||
DSM2 6
|
||||
Devo 7
|
||||
YD717 8
|
||||
KN 9
|
||||
SymaX 10
|
||||
SLT 11
|
||||
CX10 12
|
||||
CG023 13
|
||||
Bayang 14
|
||||
FrskyX 15
|
||||
BindBit=> 0x80 1=Bind/0=No
|
||||
AutoBindBit=> 0x40 1=Yes /0=No
|
||||
RangeCheck=> 0x20 1=Yes /0=No
|
||||
Stream[2] = RxNum | Power | Type;
|
||||
RxNum value is 0..15 (bits 0..3)
|
||||
Type is 0..7 <<4 (bit 4..6)
|
||||
sub_protocol==Flysky
|
||||
Flysky 0
|
||||
V9x9 1
|
||||
V6x6 2
|
||||
V912 3
|
||||
sub_protocol==Hisky
|
||||
Hisky 0
|
||||
HK310 1
|
||||
sub_protocol==DSM2
|
||||
DSM2 0
|
||||
DSMX 1
|
||||
sub_protocol==YD717
|
||||
YD717 0
|
||||
SKYWLKR 1
|
||||
SYMAX2 2
|
||||
XINXUN 3
|
||||
NIHUI 4
|
||||
sub_protocol==SYMAX
|
||||
SYMAX 0
|
||||
SYMAX5C 1
|
||||
sub_protocol==CX10
|
||||
CX10_GREEN 0
|
||||
CX10_BLUE 1 // also compatible with CX10-A, CX12
|
||||
DM007 2
|
||||
sub_protocol==CG023
|
||||
CG023 0
|
||||
YD829 1
|
||||
H8_3D 2
|
||||
Power value => 0x80 0=High/1=Low
|
||||
Stream[3] = option_protocol;
|
||||
option_protocol value is -127..127
|
||||
Stream[4] to [25] = Channels
|
||||
16 Channels on 11 bits (0..2047)
|
||||
0 -125%
|
||||
204 -100%
|
||||
1024 0%
|
||||
1843 +100%
|
||||
2047 +125%
|
||||
Channels bits are concatenated to fit in 22 bytes like in SBUS protocol
|
||||
|
||||
|
||||
**************************
|
||||
8 channels serial protocol
|
||||
**************************
|
||||
Serial: 125000 Baud 8n1 _ xxxx xxxx - ---
|
||||
Channels:
|
||||
Nbr=8
|
||||
10bits=0..1023
|
||||
0 -125%
|
||||
96 -100%
|
||||
512 0%
|
||||
928 +100%
|
||||
1023 +125%
|
||||
Stream[0] = sub_protocol|BindBit|RangeCheckBit|AutoBindBit;
|
||||
sub_protocol is 0..31 (bits 0..4)
|
||||
=> Reserved 0
|
||||
Flysky 1
|
||||
Hubsan 2
|
||||
Frsky 3
|
||||
Hisky 4
|
||||
V2x2 5
|
||||
DSM2 6
|
||||
Devo 7
|
||||
YD717 8
|
||||
KN 9
|
||||
SymaX 10
|
||||
SLT 11
|
||||
CX10 12
|
||||
CG023 13
|
||||
Bayang 14
|
||||
FrskyX 15
|
||||
BindBit=> 0x80 1=Bind/0=No
|
||||
AutoBindBit=> 0x40 1=Yes /0=No
|
||||
RangeCheck=> 0x20 1=Yes /0=No
|
||||
Stream[1] = RxNum | Power | Type;
|
||||
RxNum value is 0..15 (bits 0..3)
|
||||
Type is 0..7 <<4 (bit 4..6)
|
||||
sub_protocol==Flysky
|
||||
Flysky 0
|
||||
V9x9 1
|
||||
V6x6 2
|
||||
V912 3
|
||||
sub_protocol==Hisky
|
||||
Hisky 0
|
||||
HK310 1
|
||||
sub_protocol==DSM2
|
||||
DSM2 0
|
||||
DSMX 1
|
||||
sub_protocol==YD717
|
||||
YD717 0
|
||||
SKYWLKR 1
|
||||
SYMAX2 2
|
||||
XINXUN 3
|
||||
NIHUI 4
|
||||
sub_protocol==SYMAX
|
||||
SYMAX 0
|
||||
SYMAX5C 1
|
||||
sub_protocol==CX10
|
||||
CX10_GREEN 0
|
||||
CX10_BLUE 1 // also compatible with CX10-A, CX12
|
||||
DM007 2
|
||||
sub_protocol==CG023
|
||||
CG023 0
|
||||
YD829 1
|
||||
H8_3D 2
|
||||
Power value => 0x80 0=High/1=Low
|
||||
Stream[2] = option_protocol;
|
||||
option_protocol value is -127..127
|
||||
Stream[i+3] = lowByte(channel[i]) // with i[0..7]
|
||||
Stream[11] = highByte(channel[0])<<6 | highByte(channel[1])<<4 | highByte(channel[2])<<2 | highByte(channel[3])
|
||||
Stream[12] = highByte(channel[4])<<6 | highByte(channel[5])<<4 | highByte(channel[6])<<2 | highByte(channel[7])
|
||||
Stream[13] = lowByte(CRC16(Stream[0..12])
|
||||
*/
|
||||
|
||||
@@ -1,69 +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/>.
|
||||
*/
|
||||
|
||||
|
||||
void frskySendStuffed(uint8_t frame[])
|
||||
{
|
||||
|
||||
Serial_write(0x7E);
|
||||
for (uint8_t i = 0; i < 9; i++) {
|
||||
if ((frame[i] == 0x7e) || (frame[i] == 0x7d)) {
|
||||
Serial_write(0x7D);
|
||||
frame[i] ^= 0x20;
|
||||
}
|
||||
Serial_write(frame[i]);
|
||||
}
|
||||
Serial_write(0x7E);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void frskySendFrame()
|
||||
{
|
||||
uint8_t frame[9];
|
||||
|
||||
frame[0] = 0xfe;
|
||||
if ((cur_protocol[0]&0x1F)==MODE_FRSKY)
|
||||
{
|
||||
compute_RSSIdbm();
|
||||
frame[1] = pktt[3];
|
||||
frame[2] = pktt[4];
|
||||
frame[3] = (uint8_t)RSSI_dBm;
|
||||
frame[4] = pktt[5]*2;//txrssi
|
||||
frame[5] = frame[6] = frame[7] = frame[8] = 0;
|
||||
}
|
||||
else
|
||||
if ((cur_protocol[0]&0x1F)==MODE_HUBSAN)
|
||||
{
|
||||
frame[1] = v_lipo*2;
|
||||
frame[2] = 0;
|
||||
frame[3] = 0x5A;//dummy value
|
||||
frame[4] = 2 * 0x5A;//dummy value
|
||||
frame[5] = frame[6] = frame[7] = frame[8] = 0;
|
||||
}
|
||||
frskySendStuffed(frame);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void frskyUpdate()
|
||||
{
|
||||
if(telemetry_link){
|
||||
frskySendFrame();
|
||||
telemetry_link=0;
|
||||
|
||||
}
|
||||
}
|
||||
412
PCB v2.3d/Multipro-txV2-3d-cache.lib
Normal file
412
PCB v2.3d/Multipro-txV2-3d-cache.lib
Normal file
@@ -0,0 +1,412 @@
|
||||
EESchema-LIBRARY Version 2.3 Date: 05/02/2016 16:56:43
|
||||
#encoding utf-8
|
||||
#
|
||||
# +5V
|
||||
#
|
||||
DEF +5V #PWR 0 40 Y Y 1 F P
|
||||
F0 "#PWR" 0 90 20 H I C CNN
|
||||
F1 "+5V" 0 90 30 H V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
X +5V 1 0 0 0 U 20 20 0 0 W N
|
||||
C 0 50 20 0 1 0 N
|
||||
P 4 0 1 0 0 0 0 30 0 30 0 30 N
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# +BATT
|
||||
#
|
||||
DEF +BATT #PWR 0 0 Y Y 1 F P
|
||||
F0 "#PWR" 0 -50 20 H I C CNN
|
||||
F1 "+BATT" 0 100 30 H V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
X +BATT 1 0 0 0 U 20 20 0 0 w N
|
||||
C 0 60 20 0 1 0 N
|
||||
P 3 0 1 0 0 0 0 40 0 40 N
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# 3V3
|
||||
#
|
||||
DEF 3V3 #PWR 0 0 Y Y 1 F P
|
||||
F0 "#PWR" 0 100 40 H I C CNN
|
||||
F1 "3V3" 0 125 40 H V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
X 3V3 1 0 0 0 U 30 30 0 0 W N
|
||||
P 2 0 1 0 0 60 0 0 N
|
||||
P 6 0 1 0 0 60 20 40 0 90 -20 40 0 60 0 60 N
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# A7105
|
||||
#
|
||||
DEF A7105 U 0 40 Y Y 1 F N
|
||||
F0 "U" 500 650 60 H V C CNN
|
||||
F1 "A7105" 0 800 60 H V C CNN
|
||||
F2 "~" 0 -400 60 H V C CNN
|
||||
F3 "~" 0 -400 60 H V C CNN
|
||||
DRAW
|
||||
S 400 -800 -350 700 0 1 0 N
|
||||
X 3V3 1 -650 550 300 R 70 70 1 1 I
|
||||
X SCS 2 -650 400 300 R 70 70 1 1 I
|
||||
X GND 3 -650 250 300 R 70 70 1 1 I
|
||||
X SCK 4 -650 100 300 R 70 70 1 1 I
|
||||
X SDIO 5 -650 -50 300 R 70 70 1 1 I
|
||||
X GIO1 6 -650 -200 300 R 70 70 1 1 I
|
||||
X GIO2 7 -650 -350 300 R 70 70 1 1 O
|
||||
X RXEN 8 -650 -500 300 R 70 70 1 1 I
|
||||
X TXEN 9 -650 -650 300 R 70 70 1 1 O
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# ATMEGA168A-A
|
||||
#
|
||||
DEF ATMEGA168A-A IC 0 40 Y Y 1 F N
|
||||
F0 "IC" -750 1250 40 H V L BNN
|
||||
F1 "ATMEGA168A-A" 400 -1400 40 H V L BNN
|
||||
F2 "TQFP32" 0 0 30 H V C CIN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
ALIAS ATMEGA48A-A ATMEGA48PA-A ATMEGA88A-A ATMEGA88PA-A ATMEGA168PA-A ATMEGA328-A ATMEGA328P-A
|
||||
DRAW
|
||||
S -750 1200 850 -1300 0 1 10 f
|
||||
X (PCINT19/OC2B/INT1)PD3 1 1000 -800 150 L 40 40 1 1 B
|
||||
X (PCINT20/XCK/T0)PD4 2 1000 -900 150 L 40 40 1 1 B
|
||||
X GND 3 -900 -1200 150 R 40 40 1 1 W
|
||||
X VCC 4 -900 1100 150 R 40 40 1 1 W
|
||||
X GND 5 -900 -1100 150 R 40 40 1 1 W
|
||||
X VCC 6 -900 1000 150 R 40 40 1 1 W
|
||||
X (PCINT6/XTAL1/TOSC1)PB6 7 1000 500 150 L 40 40 1 1 B
|
||||
X (PCINT7/XTAL2/TOSC2)PB7 8 1000 400 150 L 40 40 1 1 B
|
||||
X (PCINT21/OC0B/T1)PD5 9 1000 -1000 150 L 40 40 1 1 B
|
||||
X (PCINT22/OC0A/AIN0)PD6 10 1000 -1100 150 L 40 40 1 1 B
|
||||
X AREF 20 -900 500 150 R 40 40 1 1 B
|
||||
X (PCINT16/RXD)PD0 30 1000 -500 150 L 40 40 1 1 B
|
||||
X (PCINT23/AIN1)PD7 11 1000 -1200 150 L 40 40 1 1 B
|
||||
X GND 21 -900 -1000 150 R 40 40 1 1 W
|
||||
X (PCINT17/TXD)PD1 31 1000 -600 150 L 40 40 1 1 B
|
||||
X (PCINT0/CLKO/ICP1)PB0 12 1000 1100 150 L 40 40 1 1 B
|
||||
X ADC7 22 -900 -350 150 R 40 40 1 1 N
|
||||
X (PCINT18/INT0)PD2 32 1000 -700 150 L 40 40 1 1 B
|
||||
X (PCINT1/OC1A)PB1 13 1000 1000 150 L 40 40 1 1 B
|
||||
X (PCINT8/ADC0)PC0 23 1000 250 150 L 40 40 1 1 B
|
||||
X (PCINT2/OC1B/~SS~)PB2 14 1000 900 150 L 40 40 1 1 B
|
||||
X (PCINT9/ADC1)PC1 24 1000 150 150 L 40 40 1 1 B
|
||||
X (PCINT3/OC2A/MOSI)PB3 15 1000 800 150 L 40 40 1 1 B
|
||||
X (PCINT10/ADC2)PC2 25 1000 50 150 L 40 40 1 1 B
|
||||
X (PCINT4/MISO)PB4 16 1000 700 150 L 40 40 1 1 B
|
||||
X (PCINT11/ADC3)PC3 26 1000 -50 150 L 40 40 1 1 B
|
||||
X (PCINT5/SCK)PB5 17 1000 600 150 L 40 40 1 1 B
|
||||
X (PCINT12/SDA/ADC4)PC4 27 1000 -150 150 L 40 40 1 1 B
|
||||
X AVCC 18 -900 800 150 R 40 40 1 1 W
|
||||
X (PCINT14/SCL/ADC5)PC5 28 1000 -250 150 L 40 40 1 1 B
|
||||
X ADC6 19 -900 -250 150 R 40 40 1 1 N
|
||||
X (PCINT14/~RESET~)PC6 29 1000 -350 150 L 40 40 1 1 B
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# C
|
||||
#
|
||||
DEF C C 0 10 N Y 1 F N
|
||||
F0 "C" 0 100 40 H V L CNN
|
||||
F1 "C" 6 -85 40 H V L CNN
|
||||
F2 "~" 38 -150 30 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
$FPLIST
|
||||
SM*
|
||||
C?
|
||||
C1-1
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 2 0 1 20 -80 -30 80 -30 N
|
||||
P 2 0 1 20 -80 30 80 30 N
|
||||
X ~ 1 0 200 170 D 40 40 1 1 P
|
||||
X ~ 2 0 -200 170 U 40 40 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# CC2500
|
||||
#
|
||||
DEF CC2500 U 0 40 Y Y 1 F N
|
||||
F0 "U" 500 600 60 H V C CNN
|
||||
F1 "CC2500" 0 700 60 H V C CNN
|
||||
F2 "~" 0 -400 60 H V C CNN
|
||||
F3 "~" 0 -400 60 H V C CNN
|
||||
DRAW
|
||||
S 400 -900 -350 650 0 1 0 N
|
||||
X 3V3 1 -650 550 300 R 70 70 1 1 I
|
||||
X SI 2 -650 400 300 R 70 70 1 1 I
|
||||
X SCLK 3 -650 250 300 R 70 70 1 1 I
|
||||
X SO 4 -650 100 300 R 70 70 1 1 I
|
||||
X GDO2 5 -650 -50 300 R 70 70 1 1 I
|
||||
X GND 6 -650 -200 300 R 70 70 1 1 I
|
||||
X GDOo 7 -650 -350 300 R 70 70 1 1 I
|
||||
X CSn 8 -650 -500 300 R 70 70 1 1 I
|
||||
X PA_EN 9 -650 -650 300 R 70 70 1 1 I
|
||||
X LNA_EN 10 -650 -800 300 R 70 70 1 1 I
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# CONN_2
|
||||
#
|
||||
DEF CONN_2 P 0 40 Y N 1 F N
|
||||
F0 "P" -50 0 40 V V C CNN
|
||||
F1 "CONN_2" 50 0 40 V V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
S -100 150 100 -150 0 1 0 N
|
||||
X P1 1 -350 100 250 R 60 60 1 1 P I
|
||||
X PM 2 -350 -100 250 R 60 60 1 1 P I
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# CONN_3X2
|
||||
#
|
||||
DEF CONN_3X2 P 0 40 Y N 1 F N
|
||||
F0 "P" 0 250 50 H V C CNN
|
||||
F1 "CONN_3X2" 0 50 40 V V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
S -100 200 100 -100 0 1 0 N
|
||||
X 1 1 -400 150 300 R 60 60 1 1 P I
|
||||
X 2 2 400 150 300 L 60 60 1 1 P I
|
||||
X 3 3 -400 50 300 R 60 60 1 1 P I
|
||||
X 4 4 400 50 300 L 60 60 1 1 P I
|
||||
X 5 5 -400 -50 300 R 60 60 1 1 P I
|
||||
X 6 6 400 -50 300 L 60 60 1 1 P I
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# CONN_5
|
||||
#
|
||||
DEF CONN_5 P 0 40 Y Y 1 F N
|
||||
F0 "P" -50 0 50 V V C CNN
|
||||
F1 "CONN_5" 50 0 50 V V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
S -100 250 100 -250 0 1 0 f
|
||||
X ~ 1 -400 200 300 R 60 60 1 1 P I
|
||||
X ~ 2 -400 100 300 R 60 60 1 1 P I
|
||||
X ~ 3 -400 0 300 R 60 60 1 1 P I
|
||||
X ~ 4 -400 -100 300 R 60 60 1 1 P I
|
||||
X ~ 5 -400 -200 300 R 60 60 1 1 P I
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# CP1
|
||||
#
|
||||
DEF CP1 C 0 10 N N 1 F N
|
||||
F0 "C" 50 100 50 H V L CNN
|
||||
F1 "CP1" 50 -100 50 H V L CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
$FPLIST
|
||||
CP*
|
||||
SM*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
T 0 -50 100 80 0 0 0 + Normal 0 C C
|
||||
A 0 -200 180 563 1236 0 1 15 N 100 -50 -100 -50
|
||||
P 4 0 1 15 -100 50 100 50 50 50 50 50 N
|
||||
X ~ 1 0 200 150 D 40 40 1 1 P
|
||||
X ~ 2 0 -200 180 U 40 40 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# CRYSTAL
|
||||
#
|
||||
DEF CRYSTAL X 0 40 N N 1 F N
|
||||
F0 "X" 0 150 60 H V C CNN
|
||||
F1 "CRYSTAL" 0 -150 60 H V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
P 2 0 1 16 -100 100 -100 -100 N
|
||||
P 2 0 1 16 100 100 100 -100 N
|
||||
P 5 0 1 12 -50 50 50 50 50 -50 -50 -50 -50 50 f
|
||||
X 1 1 -300 -50 200 R 40 40 1 1 P
|
||||
X 2 2 -300 50 200 R 40 40 1 1 P
|
||||
X 3 3 300 50 200 L 40 40 1 1 P
|
||||
X 4 4 300 -50 200 L 40 40 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# CYRF6936
|
||||
#
|
||||
DEF CYRF6936 U 0 40 Y Y 1 F N
|
||||
F0 "U" 0 1000 60 H V C CNN
|
||||
F1 "CYRF6936" 0 800 60 H V C CNN
|
||||
F2 "~" 0 -400 60 H V C CNN
|
||||
F3 "~" 0 -400 60 H V C CNN
|
||||
DRAW
|
||||
S 400 -800 -350 700 0 1 0 N
|
||||
X 5.0V 1 -650 500 300 R 70 70 1 1 I
|
||||
X NCS 2 -650 350 300 R 70 70 1 1 I
|
||||
X SCK 4 -650 200 300 R 70 70 1 1 I
|
||||
X GND 5 -650 50 300 R 70 70 1 1 I
|
||||
X GND 6 -650 -100 300 R 70 70 1 1 I
|
||||
X MOSI 8 -650 -250 300 R 70 70 1 1 I
|
||||
X RST 9 -650 -400 300 R 70 70 1 1 I
|
||||
X MISO 10 -650 -600 300 R 70 70 1 1 I
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# GND
|
||||
#
|
||||
DEF ~GND #PWR 0 0 Y Y 1 F P
|
||||
F0 "#PWR" 0 0 30 H I C CNN
|
||||
F1 "GND" 0 -70 30 H I C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
P 4 0 1 0 -50 0 0 -50 50 0 -50 0 N
|
||||
X GND 1 0 0 0 U 30 30 1 1 W N
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# HEX_DIP
|
||||
#
|
||||
DEF HEX_DIP SW 0 40 Y Y 1 F N
|
||||
F0 "SW" 0 -350 60 H V C CNN
|
||||
F1 "HEX_DIP" 0 350 60 H V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
S -200 250 200 -250 0 1 0 N
|
||||
P 4 0 1 0 50 50 -50 0 50 -100 50 50 F
|
||||
X 1 1 500 -150 300 L 50 50 1 1 O
|
||||
X C 2 500 0 300 L 50 50 1 1 P
|
||||
X 4 3 500 150 300 L 50 50 1 1 O
|
||||
X 2 4 -500 150 300 R 50 50 1 1 O
|
||||
X C 5 -500 0 300 R 50 50 1 1 P
|
||||
X 8 6 -500 -150 300 R 50 50 1 1 O
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# JUMPER
|
||||
#
|
||||
DEF JUMPER JP 0 30 Y N 1 F N
|
||||
F0 "JP" 0 150 60 H V C CNN
|
||||
F1 "JUMPER" 0 -80 40 H V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
A 0 -26 125 1426 373 0 1 0 N -98 50 99 50
|
||||
C -100 0 35 0 1 0 N
|
||||
C 100 0 35 0 1 0 N
|
||||
X 1 1 -300 0 165 R 60 60 0 1 P
|
||||
X 2 2 300 0 165 L 60 60 0 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# LED
|
||||
#
|
||||
DEF LED D 0 40 Y N 1 F N
|
||||
F0 "D" 0 100 50 H V C CNN
|
||||
F1 "LED" 0 -100 50 H V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
$FPLIST
|
||||
LED-3MM
|
||||
LED-5MM
|
||||
LED-10MM
|
||||
LED-0603
|
||||
LED-0805
|
||||
LED-1206
|
||||
LEDV
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 2 0 1 0 50 50 50 -50 N
|
||||
P 3 0 1 0 -50 50 50 0 -50 -50 F
|
||||
P 3 0 1 0 65 -40 110 -80 105 -55 N
|
||||
P 3 0 1 0 80 -25 125 -65 120 -40 N
|
||||
X A 1 -200 0 150 R 40 40 1 1 P
|
||||
X K 2 200 0 150 L 40 40 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# NCP1117ST50T3G
|
||||
#
|
||||
DEF NCP1117ST50T3G U 0 30 Y Y 1 F N
|
||||
F0 "U" 150 -196 40 H V C CNN
|
||||
F1 "NCP1117ST50T3G" 0 200 40 H V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
ALIAS NCP1117ST12T3G NCP1117ST15T3G NCP1117ST18T3G NCP1117ST20T3G NCP1117ST25T3G NCP1117ST285T3G NCP1117ST33T3G
|
||||
$FPLIST
|
||||
SOT223
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
S -250 -150 250 150 0 1 10 f
|
||||
X GND 1 0 -250 100 U 40 40 1 1 W
|
||||
X VO 2 400 50 150 L 40 40 1 1 w
|
||||
X VI 3 -400 50 150 R 40 40 1 1 W
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# NRF24L01
|
||||
#
|
||||
DEF NRF24L01 U 0 40 Y Y 1 F N
|
||||
F0 "U" 500 650 60 H V C CNN
|
||||
F1 "NRF24L01" 0 800 60 H V C CNN
|
||||
F2 "~" 0 -400 60 H V C CNN
|
||||
F3 "~" 0 -400 60 H V C CNN
|
||||
DRAW
|
||||
S 400 -650 -350 700 0 1 0 N
|
||||
X GND 1 -650 550 300 R 70 70 1 1 I
|
||||
X 3V3 2 -650 400 300 R 70 70 1 1 I
|
||||
X CE 3 -650 250 300 R 70 70 1 1 I
|
||||
X CSN 4 -650 100 300 R 70 70 1 1 I
|
||||
X SCK 5 -650 -50 300 R 70 70 1 1 I
|
||||
X MOSI 6 -650 -200 300 R 70 70 1 1 I
|
||||
X MISO 7 -650 -350 300 R 70 70 1 1 I
|
||||
X IRQ 8 -650 -500 300 R 70 70 1 1 N
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# R
|
||||
#
|
||||
DEF R R 0 0 N Y 1 F N
|
||||
F0 "R" 80 0 40 V V C CNN
|
||||
F1 "R" 7 1 40 V V C CNN
|
||||
F2 "~" -70 0 30 V V C CNN
|
||||
F3 "~" 0 0 30 H V C CNN
|
||||
$FPLIST
|
||||
R?
|
||||
SM0603
|
||||
SM0805
|
||||
R?-*
|
||||
SM1206
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
S -40 150 40 -150 0 1 12 N
|
||||
X ~ 1 0 250 100 D 60 60 1 1 P
|
||||
X ~ 2 0 -250 100 U 60 60 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# SW_PUSH_4_Pin
|
||||
#
|
||||
DEF SW_PUSH_4_Pin SW 0 40 N N 1 F N
|
||||
F0 "SW" 150 110 50 H V C CNN
|
||||
F1 "SW_PUSH_4_Pin" 0 -200 50 H V C CNN
|
||||
F2 "~" 0 0 60 H V C CNN
|
||||
F3 "~" 0 0 60 H V C CNN
|
||||
DRAW
|
||||
S -170 50 170 60 0 1 0 N
|
||||
P 4 0 1 0 -40 60 -30 90 30 90 40 60 N
|
||||
X 1 1 -300 0 200 R 60 60 0 1 P I
|
||||
X 3 3 300 0 200 L 60 60 0 1 P I
|
||||
X 2 2 -300 -100 200 R 50 50 1 1 I I
|
||||
X 4 4 300 -100 200 L 50 50 1 1 I I
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
#End Library
|
||||
248
PCB v2.3d/Multipro-txV2-3d.cmp
Normal file
248
PCB v2.3d/Multipro-txV2-3d.cmp
Normal file
@@ -0,0 +1,248 @@
|
||||
Cmp-Mod V01 Created by CvPcb (2013-07-07 BZR 4022)-stable date = 05/02/2016 14:40:56
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2AE5B;
|
||||
Reference = C1;
|
||||
ValeurCmp = 22uF;
|
||||
IdModule = c_tant_B;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53BC5DA8;
|
||||
Reference = C2;
|
||||
ValeurCmp = 0.1uF;
|
||||
IdModule = SM0603_Capa;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2AE76;
|
||||
Reference = C3;
|
||||
ValeurCmp = 22uF;
|
||||
IdModule = c_tant_B;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53BC62F4;
|
||||
Reference = C4;
|
||||
ValeurCmp = 18pF;
|
||||
IdModule = SM0603_Capa;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53BC631E;
|
||||
Reference = C5;
|
||||
ValeurCmp = 18pF;
|
||||
IdModule = SM0603_Capa;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2B150;
|
||||
Reference = C6;
|
||||
ValeurCmp = 22uF;
|
||||
IdModule = c_tant_B;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /54845FE2;
|
||||
Reference = C7;
|
||||
ValeurCmp = 0.1uF;
|
||||
IdModule = SM0603_Capa;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53BC617C;
|
||||
Reference = D1;
|
||||
ValeurCmp = LED;
|
||||
IdModule = LED-0603;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2D9F8;
|
||||
Reference = D2;
|
||||
ValeurCmp = LED;
|
||||
IdModule = LED-0603;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53BC5C99;
|
||||
Reference = IC1;
|
||||
ValeurCmp = ATMEGA328-A;
|
||||
IdModule = TQFP32;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53FE5887;
|
||||
Reference = JP1;
|
||||
ValeurCmp = JUMPER;
|
||||
IdModule = c_0603;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53FE5896;
|
||||
Reference = JP2;
|
||||
ValeurCmp = JUMPER;
|
||||
IdModule = c_0603;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /56B4E4E1;
|
||||
Reference = JP3;
|
||||
ValeurCmp = JUMPER;
|
||||
IdModule = c_0603;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /56B4EFD5;
|
||||
Reference = JP4;
|
||||
ValeurCmp = JUMPER;
|
||||
IdModule = c_0603;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2DBCC;
|
||||
Reference = P1;
|
||||
ValeurCmp = ISP;
|
||||
IdModule = pin_array_3x2;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53FE5423;
|
||||
Reference = P2;
|
||||
ValeurCmp = CONN_5;
|
||||
IdModule = MOLEX_4455_N2X5;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /56B4E4CA;
|
||||
Reference = P3;
|
||||
ValeurCmp = CONN_2;
|
||||
IdModule = PIN_ARRAY_2X1;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53BC5FEA;
|
||||
Reference = R1;
|
||||
ValeurCmp = 10K;
|
||||
IdModule = SM0603_Resistor;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2B990;
|
||||
Reference = R2;
|
||||
ValeurCmp = 2K2;
|
||||
IdModule = SM0603_Resistor;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2B99F;
|
||||
Reference = R3;
|
||||
ValeurCmp = 1K;
|
||||
IdModule = SM0603_Resistor;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53BC6125;
|
||||
Reference = R4;
|
||||
ValeurCmp = 1K;
|
||||
IdModule = SM0603_Resistor;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2B787;
|
||||
Reference = R5;
|
||||
ValeurCmp = 2K2;
|
||||
IdModule = SM0603_Resistor;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2D8C4;
|
||||
Reference = R6;
|
||||
ValeurCmp = 1K;
|
||||
IdModule = SM0603_Resistor;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /54DCE006;
|
||||
Reference = R7;
|
||||
ValeurCmp = 2K2;
|
||||
IdModule = SM0603_Resistor;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /56B4E6D8;
|
||||
Reference = R8;
|
||||
ValeurCmp = 470;
|
||||
IdModule = SM0603_Resistor;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /54394777;
|
||||
Reference = SW1;
|
||||
ValeurCmp = HEX_DIP;
|
||||
IdModule = DIP-6__300;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /56B4EC6E;
|
||||
Reference = SW2;
|
||||
ValeurCmp = BIND;
|
||||
IdModule = SW_PUSH_6x4.5MM;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /56B4EC7B;
|
||||
Reference = SW3;
|
||||
ValeurCmp = RESET;
|
||||
IdModule = Switch_SMT5mm;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2ACE9;
|
||||
Reference = U1;
|
||||
ValeurCmp = NCP1117ST50T3G;
|
||||
IdModule = SOT223;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2AD08;
|
||||
Reference = U2;
|
||||
ValeurCmp = NCP1117ST33T3G;
|
||||
IdModule = SOT223;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2BF57;
|
||||
Reference = U3;
|
||||
ValeurCmp = CYRF6936;
|
||||
IdModule = CYRF6936;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2C184;
|
||||
Reference = U4;
|
||||
ValeurCmp = A7105;
|
||||
IdModule = XL7105-D03B;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2C24E;
|
||||
Reference = U5;
|
||||
ValeurCmp = NRF24L01;
|
||||
IdModule = NRF24L01;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53C2C3F4;
|
||||
Reference = U6;
|
||||
ValeurCmp = CC2500;
|
||||
IdModule = header_10_2mm;
|
||||
EndCmp
|
||||
|
||||
BeginCmp
|
||||
TimeStamp = /53BC62D3;
|
||||
Reference = X1;
|
||||
ValeurCmp = 16MHz;
|
||||
IdModule = crystal_FA238-TSX3225;
|
||||
EndCmp
|
||||
|
||||
EndListe
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user