mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-11-26 05:51:09 +00:00
Compare commits
1501 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a9b6ed4be | ||
|
|
953a97dae4 | ||
|
|
86778c5997 | ||
|
|
8c32cdf5fd | ||
|
|
d092593e5c | ||
|
|
edbf4b6908 | ||
|
|
43f688d011 | ||
|
|
054c3088c3 | ||
|
|
0cedd5bb66 | ||
|
|
1961579fe4 | ||
|
|
6906f1652e | ||
|
|
e2bbe8a422 | ||
|
|
8ea4e00d31 | ||
|
|
917e27280f | ||
|
|
ec92edfc85 | ||
|
|
afd2be6c59 | ||
|
|
a23d50bf0d | ||
|
|
cace1144db | ||
|
|
0d646ed1a6 | ||
|
|
e9b09ffecd | ||
|
|
0008633d6e | ||
|
|
396c005b0a | ||
|
|
d3c3fac4f7 | ||
|
|
cf4acc1d4c | ||
|
|
5bd95f8414 | ||
|
|
a31d9a83a3 | ||
|
|
9b24589897 | ||
|
|
8f3d634132 | ||
|
|
5ef1ccb99b | ||
|
|
e7d91bc76a | ||
|
|
e4309824c2 | ||
|
|
cc6a35ac8a | ||
|
|
1f13a6c281 | ||
|
|
69519bdf14 | ||
|
|
2e5a8f384a | ||
|
|
c803eeb26a | ||
|
|
6a7497cdf8 | ||
|
|
3067ea3a5c | ||
|
|
9a5309d84b | ||
|
|
fff18f825a | ||
|
|
e70bdd4152 | ||
|
|
cf77a1981f | ||
|
|
10e33f5d5c | ||
|
|
db442d81dd | ||
|
|
f800b4f90b | ||
|
|
712f297d86 | ||
|
|
0afed7d3a4 | ||
|
|
6a03972ff3 | ||
|
|
0e40f64c6b | ||
|
|
c83b769f28 | ||
|
|
dad3282bbb | ||
|
|
1621263fb0 | ||
|
|
2686cd0c48 | ||
|
|
b07b081a15 | ||
|
|
c5d4e8c191 | ||
|
|
928641f535 | ||
|
|
c4c5ffec4f | ||
|
|
c048e97d3a | ||
|
|
00f0719659 | ||
|
|
0482627512 | ||
|
|
5856442e0f | ||
|
|
7b281e47d6 | ||
|
|
6ef2934c18 | ||
|
|
19b931223b | ||
|
|
ca15d7108f | ||
|
|
e6e4d33847 | ||
|
|
815cf4fd99 | ||
|
|
5cf2bf2cf5 | ||
|
|
6632da0276 | ||
|
|
9b499ab7d1 | ||
|
|
d29461607b | ||
|
|
243bdf2240 | ||
|
|
cde185901a | ||
|
|
a9f35f8095 | ||
|
|
63d7e32e06 | ||
|
|
400fdb3cc6 | ||
|
|
9f1bdc901c | ||
|
|
61970b028e | ||
|
|
aee92737ca | ||
|
|
0fddd9c119 | ||
|
|
b156f66146 | ||
|
|
63e6590b65 | ||
|
|
103be7f6e0 | ||
|
|
2154b75499 | ||
|
|
6a83cb5577 | ||
|
|
70ce8e9a1f | ||
|
|
fdd0a00d5a | ||
|
|
a8cad1e70a | ||
|
|
40afd67fc6 | ||
|
|
f3b9206d67 | ||
|
|
b76dd4c8ac | ||
|
|
3eb507ebe6 | ||
|
|
fe0a1f0f94 | ||
|
|
fab3339b8d | ||
|
|
10604cf820 | ||
|
|
e297310a25 | ||
|
|
d71006f2ae | ||
|
|
7a8e099a79 | ||
|
|
822aa84fa2 | ||
|
|
948ce9e8b8 | ||
|
|
caf145c38a | ||
|
|
f964cdec98 | ||
|
|
6848fab873 | ||
|
|
72d57cae71 | ||
|
|
a23178e20e | ||
|
|
5ae4f0288b | ||
|
|
e0e51eb187 | ||
|
|
840944ea94 | ||
|
|
31ff27b1d3 | ||
|
|
a234ccbd05 | ||
|
|
6dfd54b8be | ||
|
|
edb7729b35 | ||
|
|
d434e63c22 | ||
|
|
cd7ede006c | ||
|
|
d4d0dc3dbc | ||
|
|
5c7f997e7a | ||
|
|
1623a007a4 | ||
|
|
0b19fa0bdf | ||
|
|
897c8b6ec5 | ||
|
|
d427a7fec1 | ||
|
|
b0749a1bee | ||
|
|
2406080515 | ||
|
|
ff96146b04 | ||
|
|
e3a5b2825d | ||
|
|
9fd72b5ad5 | ||
|
|
c2bf63991f | ||
|
|
a75ae7b65a | ||
|
|
507e4cb07b | ||
|
|
0f250bb04b | ||
|
|
4a315057a2 | ||
|
|
c8f44a0c4b | ||
|
|
382d853fe2 | ||
|
|
a5996c488e | ||
|
|
760642ecb3 | ||
|
|
c7a3548df0 | ||
|
|
d8acc6a5e8 | ||
|
|
431808286b | ||
|
|
747fa19259 | ||
|
|
bf61295b76 | ||
|
|
49a1ecea00 | ||
|
|
11f0e55bb1 | ||
|
|
331da37840 | ||
|
|
032e0641a5 | ||
|
|
f3d2ab61e4 | ||
|
|
e8b5f071fe | ||
|
|
ada72d6113 | ||
|
|
c2404d4f0d | ||
|
|
821732bba9 | ||
|
|
b6df650f50 | ||
|
|
e783ce5788 | ||
|
|
18af4a0724 | ||
|
|
7e6ec1dc8d | ||
|
|
4fbe0859e0 | ||
|
|
b89c23fe7c | ||
|
|
e038c49ae9 | ||
|
|
bed02c9384 | ||
|
|
96bc4f7cdf | ||
|
|
6503469ddd | ||
|
|
61a1c3742c | ||
|
|
1fb2a38bc1 | ||
|
|
22a0d79315 | ||
|
|
0cc72772a3 | ||
|
|
11f4e636e3 | ||
|
|
fef1a2e041 | ||
|
|
41a9c8e013 | ||
|
|
c1ad02b792 | ||
|
|
ab2315c951 | ||
|
|
7948e33cbc | ||
|
|
2be2dce584 | ||
|
|
69bdfe3dba | ||
|
|
d73d163a58 | ||
|
|
48a52ae5b2 | ||
|
|
078dc2ab17 | ||
|
|
6f4522caa6 | ||
|
|
3c76ce9f39 | ||
|
|
8601149051 | ||
|
|
d7ef15d435 | ||
|
|
27e3645b56 | ||
|
|
95eb4e1a22 | ||
|
|
32ea07bf5a | ||
|
|
06272575c5 | ||
|
|
edd6432d4c | ||
|
|
303c4615e9 | ||
|
|
7d327c1622 | ||
|
|
6a74b83f98 | ||
|
|
c601c2dd98 | ||
|
|
c27b60749f | ||
|
|
b3cb286088 | ||
|
|
361903e8ec | ||
|
|
d72c69242d | ||
|
|
539819fa0c | ||
|
|
d80c218744 | ||
|
|
0603d220a9 | ||
|
|
e13fe56f47 | ||
|
|
acd7694485 | ||
|
|
7f50edacc8 | ||
|
|
5a4906c5b5 | ||
|
|
4e906757b9 | ||
|
|
1f0b21e351 | ||
|
|
2f3ea323c7 | ||
|
|
d4e77c6499 | ||
|
|
ffc56b049d | ||
|
|
ddac89d732 | ||
|
|
fecf2805c7 | ||
|
|
4dcc88ba32 | ||
|
|
084308d8a4 | ||
|
|
1ffb5c405b | ||
|
|
ad29409407 | ||
|
|
6f33abb25e | ||
|
|
2c9693389e | ||
|
|
d3c82c4da4 | ||
|
|
541a96e7b4 | ||
|
|
5b234a9cbc | ||
|
|
24c3a62f3a | ||
|
|
23756a387a | ||
|
|
efbd350dfd | ||
|
|
072e95c84e | ||
|
|
4be26e7202 | ||
|
|
a616cbb95c | ||
|
|
8aea9aa3dd | ||
|
|
e4992bc917 | ||
|
|
000b3e97c7 | ||
|
|
cb91e19413 | ||
|
|
c72e690085 | ||
|
|
f1a4e659e7 | ||
|
|
0d56d17d52 | ||
|
|
96c89c8c97 | ||
|
|
7df5a1f211 | ||
|
|
8ae8e028c7 | ||
|
|
581ad5f8f4 | ||
|
|
977bae3750 | ||
|
|
8a0161607e | ||
|
|
cd6a7bfc3a | ||
|
|
4671700b7d | ||
|
|
840ca74407 | ||
|
|
0d8a7e46de | ||
|
|
8b9940b0f0 | ||
|
|
521b819b8a | ||
|
|
208e9ef64b | ||
|
|
a7ea8e012e | ||
|
|
d940a7e49a | ||
|
|
9d50171034 | ||
|
|
701a5b9e28 | ||
|
|
d11785ef2d | ||
|
|
f4a4d91ef8 | ||
|
|
9514e47ed3 | ||
|
|
9461f2d632 | ||
|
|
f6064d03e1 | ||
|
|
0d917e0dc5 | ||
|
|
9408af8d08 | ||
|
|
862ab48bbc | ||
|
|
f498347c53 | ||
|
|
3f77f59c8a | ||
|
|
e96186015d | ||
|
|
1fa6e4526b | ||
|
|
3853d585a0 | ||
|
|
e8c6225ef0 | ||
|
|
17c67cc780 | ||
|
|
dcc4236833 | ||
|
|
6a7c735924 | ||
|
|
3c40cd853e | ||
|
|
5357660b68 | ||
|
|
a15a911f8e | ||
|
|
ded0487ce6 | ||
|
|
e7b079ece7 | ||
|
|
0cbe4de920 | ||
|
|
5c3bf30fe7 | ||
|
|
56b8694fd5 | ||
|
|
c9fecafada | ||
|
|
f3ca7ad644 | ||
|
|
c3b48c78af | ||
|
|
18dcc29a0d | ||
|
|
c3a5c263d3 | ||
|
|
ccdf60d525 | ||
|
|
443e1cec75 | ||
|
|
aa540514b8 | ||
|
|
fda7e2e5b6 | ||
|
|
fb4d5cf437 | ||
|
|
9fc2898a56 | ||
|
|
2e24323adf | ||
|
|
77abc1ed7c | ||
|
|
259d550d04 | ||
|
|
1a8f9c5a12 | ||
|
|
1916eb3095 | ||
|
|
fc3eec7ae1 | ||
|
|
8d10c9b004 | ||
|
|
511f77f5e7 | ||
|
|
a58d7a4d79 | ||
|
|
6748f6ce78 | ||
|
|
2dcb6b1987 | ||
|
|
2b4ac41142 | ||
|
|
2b47958207 | ||
|
|
5538d4d1c4 | ||
|
|
467756df48 | ||
|
|
534ebb26c0 | ||
|
|
21790a9725 | ||
|
|
6bc22c8ac4 | ||
|
|
ac1c422f14 | ||
|
|
efa1860104 | ||
|
|
c673b4254f | ||
|
|
96db173694 | ||
|
|
1d5be624fe | ||
|
|
56f9672896 | ||
|
|
303b3f08b8 | ||
|
|
150e3fd92e | ||
|
|
840b01273c | ||
|
|
8a7beda339 | ||
|
|
65606f7083 | ||
|
|
0095071ebf | ||
|
|
ae4ee9061d | ||
|
|
6ba06bc006 | ||
|
|
00f247eae1 | ||
|
|
c250c91ab4 | ||
|
|
b1ac10a4c4 | ||
|
|
af4185fbea | ||
|
|
aa85d4d797 | ||
|
|
74cc63e6dd | ||
|
|
04ed613ca3 | ||
|
|
9ea157b9b6 | ||
|
|
536d7f6124 | ||
|
|
869a01b57f | ||
|
|
ea982b23c2 | ||
|
|
15dfe8cead | ||
|
|
b50027150e | ||
|
|
103acb8294 | ||
|
|
aca23b8bca | ||
|
|
aaffbbc5be | ||
|
|
e0002c9488 | ||
|
|
687d6d914c | ||
|
|
9a61b2701e | ||
|
|
d8224ebefe | ||
|
|
cc2af73a05 | ||
|
|
aecd44ada6 | ||
|
|
72593c4d99 | ||
|
|
52ca258616 | ||
|
|
04412667ff | ||
|
|
4124ec80ec | ||
|
|
693ea75e95 | ||
|
|
9e3c1ab059 | ||
|
|
5fc860702f | ||
|
|
6ad2ee5a47 | ||
|
|
b0f64297cb | ||
|
|
f99a63dbc0 | ||
|
|
9261e8fe94 | ||
|
|
52bb116e24 | ||
|
|
7006c36101 | ||
|
|
f7d452e3f1 | ||
|
|
598e50a40f | ||
|
|
eadfa26c3b | ||
|
|
b03491fdf7 | ||
|
|
42911c63b3 | ||
|
|
43462757ed | ||
|
|
0eee1c5d15 | ||
|
|
3a21bf69f1 | ||
|
|
7d4c8f7f07 | ||
|
|
866d19d649 | ||
|
|
c27ec2475c | ||
|
|
1d64cbfaa0 | ||
|
|
5d1baa89e4 | ||
|
|
e846ce7e98 | ||
|
|
300b3582a6 | ||
|
|
3a7ffe62b0 | ||
|
|
d990ebe49e | ||
|
|
bd78739217 | ||
|
|
6c7312a09c | ||
|
|
1525e564cb | ||
|
|
7fb4bbbf3c | ||
|
|
2553d44d32 | ||
|
|
dc902b7a61 | ||
|
|
b992cbd92e | ||
|
|
22711fad28 | ||
|
|
a9df0abed3 | ||
|
|
fd65550f8d | ||
|
|
b910ad3386 | ||
|
|
fb9f094365 | ||
|
|
05470446a0 | ||
|
|
903982afb7 | ||
|
|
8bea5b125b | ||
|
|
c658a892f2 | ||
|
|
3f0d6cfcf1 | ||
|
|
c6657c199c | ||
|
|
cf6d980b8b | ||
|
|
c3ff49e86e | ||
|
|
e51f91f041 | ||
|
|
2589c67f6c | ||
|
|
2f4f19b52b | ||
|
|
b3ed7563dc | ||
|
|
ea96c328fc | ||
|
|
f42da14413 | ||
|
|
2149149723 | ||
|
|
f1916b3d0b | ||
|
|
10788976b6 | ||
|
|
567d26a385 | ||
|
|
220eb8f6f4 | ||
|
|
b40e7d6e97 | ||
|
|
97dd90a718 | ||
|
|
75ba6401a4 | ||
|
|
5cf8d8d263 | ||
|
|
058e09c413 | ||
|
|
63fb1b1f36 | ||
|
|
7c0b9ce3c6 | ||
|
|
c153d236f2 | ||
|
|
3b3a3c275c | ||
|
|
f4691d08cc | ||
|
|
e5d9471b33 | ||
|
|
ab9525c507 | ||
|
|
b1fb3a5470 | ||
|
|
b2194790eb | ||
|
|
8901310ed4 | ||
|
|
09c6adaa95 | ||
|
|
5fe1e9674e | ||
|
|
601116bd59 | ||
|
|
27dc02fdec | ||
|
|
03f417546e | ||
|
|
3b9aa79201 | ||
|
|
5aa4936c0e | ||
|
|
1e65d58113 | ||
|
|
e2a66bdd1f | ||
|
|
4f9c30505a | ||
|
|
1ec817c96c | ||
|
|
41528ae7b6 | ||
|
|
77d248df0b | ||
|
|
c6cb13b332 | ||
|
|
d67108fa8b | ||
|
|
b7447f055a | ||
|
|
3902ed19b7 | ||
|
|
51ba7cf75c | ||
|
|
82fb5dd0da | ||
|
|
2ac20cb575 | ||
|
|
3f33e5b2a8 | ||
|
|
655ea98bf1 | ||
|
|
238260612c | ||
|
|
cd26c2d8e6 | ||
|
|
814e28b86a | ||
|
|
f515ba79af | ||
|
|
e6f16700e4 | ||
|
|
f38e7c35da | ||
|
|
b3576b7162 | ||
|
|
d9914e95d9 | ||
|
|
64c79626b4 | ||
|
|
e047a76855 | ||
|
|
e7449897f9 | ||
|
|
db093cf25b | ||
|
|
4bb4bd9792 | ||
|
|
c16654c8cf | ||
|
|
817ff7e239 | ||
|
|
685de52538 | ||
|
|
1dc52773f4 | ||
|
|
fbb04ea88a | ||
|
|
23da318645 | ||
|
|
30b77931d7 | ||
|
|
39327b2b27 | ||
|
|
13c3af96a6 | ||
|
|
4411732022 | ||
|
|
0c08b8b93b | ||
|
|
838755aabf | ||
|
|
2bca104e33 | ||
|
|
cf857f3256 | ||
|
|
1647d3d841 | ||
|
|
2f5252ab88 | ||
|
|
eb89b5be1b | ||
|
|
e80fe29dba | ||
|
|
74ab2a4bd7 | ||
|
|
edd4f740e0 | ||
|
|
d0c9bc801b | ||
|
|
73dd63caa1 | ||
|
|
cc4703ea40 | ||
|
|
f105d7c7eb | ||
|
|
e85ad00a46 | ||
|
|
658dfa4290 | ||
|
|
df75036501 | ||
|
|
9ab5353122 | ||
|
|
5345ece322 | ||
|
|
9f09c81ef4 | ||
|
|
c8dea20865 | ||
|
|
bf09177916 | ||
|
|
d71640ad7e | ||
|
|
68afcc0c44 | ||
|
|
9b30a3d72a | ||
|
|
789cd21618 | ||
|
|
d9f343e20b | ||
|
|
0b8ff15133 | ||
|
|
27a4748111 | ||
|
|
18efaef38c | ||
|
|
35137b87ed | ||
|
|
9019c46102 | ||
|
|
52d0869c50 | ||
|
|
236b375669 | ||
|
|
9502b5a12a | ||
|
|
ad18856f7a | ||
|
|
9015b78aaf | ||
|
|
8cc7a4f693 | ||
|
|
ac298fee61 | ||
|
|
457fc5296e | ||
|
|
b8f3cd1ad8 | ||
|
|
f9f265271a | ||
|
|
dde5f6e119 | ||
|
|
add3fb13ef | ||
|
|
51c1936c24 | ||
|
|
07adeaf60d | ||
|
|
811913bf89 | ||
|
|
8906c85d06 | ||
|
|
7df5894ca4 | ||
|
|
fa9e559195 | ||
|
|
81f408ee77 | ||
|
|
aa8a059553 | ||
|
|
8c7918577d | ||
|
|
7219885196 | ||
|
|
9f8915239f | ||
|
|
83401f6e1a | ||
|
|
dd686ad9d1 | ||
|
|
7d04005c72 | ||
|
|
cdbaeb1c6c | ||
|
|
6bf432a112 | ||
|
|
f6ef136502 | ||
|
|
4a9d295f1a | ||
|
|
105e0bb7a4 | ||
|
|
ab27ee50b0 | ||
|
|
f4a4f67453 | ||
|
|
fb88eebc2f | ||
|
|
6fea0c2a93 | ||
|
|
301c8da9eb | ||
|
|
4facdf0932 | ||
|
|
ce489887db | ||
|
|
55e30bd4aa | ||
|
|
eb0d03d420 | ||
|
|
db1da2d9cf | ||
|
|
6fa3b8597f | ||
|
|
c8da89f0d3 | ||
|
|
c3c89801e9 | ||
|
|
eb3f8b0d91 | ||
|
|
d3285f002e | ||
|
|
e81ee38fa5 | ||
|
|
499e854275 | ||
|
|
cd235bbcde | ||
|
|
984aa3f413 | ||
|
|
11287cb9c0 | ||
|
|
5cc49a8862 | ||
|
|
fabda76e98 | ||
|
|
70db505dd9 | ||
|
|
29fd1c800b | ||
|
|
d70d8f62a4 | ||
|
|
bef562964d | ||
|
|
fc5495b6d1 | ||
|
|
f3838ae4b0 | ||
|
|
b3eccf55ba | ||
|
|
835cc3d0a2 | ||
|
|
b49584ec16 | ||
|
|
334e49c4ca | ||
|
|
3fc5be111b | ||
|
|
1bc2dd2964 | ||
|
|
68dcc75949 | ||
|
|
dc9f738f30 | ||
|
|
4171d2f93b | ||
|
|
64fb90960b | ||
|
|
93e277bb0f | ||
|
|
337216efac | ||
|
|
f1f5b68821 | ||
|
|
8f941e6d12 | ||
|
|
6a4dcbd6e1 | ||
|
|
7e773dfe1b | ||
|
|
465ae75ffc | ||
|
|
8da03940e8 | ||
|
|
f280779528 | ||
|
|
5c568da125 | ||
|
|
f46b8366b0 | ||
|
|
1d9c052c01 | ||
|
|
544927b9b7 | ||
|
|
8b5bb0d358 | ||
|
|
6031f1e3b8 | ||
|
|
c297df76ef | ||
|
|
122e9f4fca | ||
|
|
748ed01252 | ||
|
|
56188328fb | ||
|
|
880e463b01 | ||
|
|
a53046bf12 | ||
|
|
a8050fd8a1 | ||
|
|
6ae819e8d5 | ||
|
|
79c73444ab | ||
|
|
8cc1b07456 | ||
|
|
0d43614ac3 | ||
|
|
19f879da7f | ||
|
|
ed42bf311f | ||
|
|
fd4346cb64 | ||
|
|
6e458ebd4a | ||
|
|
0f0be60245 | ||
|
|
27783677c2 | ||
|
|
4418cab3a5 | ||
|
|
b3cddfe2d4 | ||
|
|
a19ac87a04 | ||
|
|
3ba951fd91 | ||
|
|
824f23c3d6 | ||
|
|
fc49a32008 | ||
|
|
5ca0d31606 | ||
|
|
ebd44d9628 | ||
|
|
329fa1c2a5 | ||
|
|
9a5bf7999b | ||
|
|
7debad6c67 | ||
|
|
dc9b84ea8b | ||
|
|
199c254838 | ||
|
|
7ff482dafe | ||
|
|
9376019198 | ||
|
|
cec654a75b | ||
|
|
3e004d01ec | ||
|
|
21266d0a17 | ||
|
|
2b62b8dab3 | ||
|
|
b24564ffe9 | ||
|
|
f57d436640 | ||
|
|
762613bd7f | ||
|
|
e2ed752b51 | ||
|
|
2610926f47 | ||
|
|
cf1a74e532 | ||
|
|
f55b451d9b | ||
|
|
ae51e389ca | ||
|
|
6f71ef1d03 | ||
|
|
94a9e4db05 | ||
|
|
82dc0c4f32 | ||
|
|
bb5827629e | ||
|
|
76f7cb7126 | ||
|
|
d5005323d4 | ||
|
|
9bc1a9963f | ||
|
|
cefbf2ee70 | ||
|
|
e10dc6dcec | ||
|
|
e4f4d278a8 | ||
|
|
3dd9df558e | ||
|
|
87c2216d0f | ||
|
|
8cd5ff6bd6 | ||
|
|
28868e4c78 | ||
|
|
01bef23ac9 | ||
|
|
9379bd1792 | ||
|
|
63a479b6b6 | ||
|
|
49b0d92c75 | ||
|
|
277402a25d | ||
|
|
cc83177542 | ||
|
|
5a342cf8e6 | ||
|
|
7d5dabde82 | ||
|
|
e3917226cc | ||
|
|
4e3c1edd52 | ||
|
|
e52b7ea7ff | ||
|
|
6f60d87f85 | ||
|
|
049db615e3 | ||
|
|
e557155b17 | ||
|
|
9bf5b0c9a7 | ||
|
|
ea860f24a1 | ||
|
|
5e89d49bd9 | ||
|
|
cb1ba0e00c | ||
|
|
0f965b6800 | ||
|
|
486c2170cd | ||
|
|
83641a4f54 | ||
|
|
5cb2326ea7 | ||
|
|
84d7986353 | ||
|
|
a3c2628359 | ||
|
|
8ae34bdd9d | ||
|
|
4a9374936d | ||
|
|
110378e3b4 | ||
|
|
bd60feff60 | ||
|
|
2181d0b33c | ||
|
|
2afa7ea691 | ||
|
|
d0f76117cd | ||
|
|
e25060a16e | ||
|
|
5e6da326f6 | ||
|
|
981a8f8d2c | ||
|
|
5c7e592e1e | ||
|
|
2a25f76b56 | ||
|
|
41d579dc23 | ||
|
|
7d41017850 | ||
|
|
daeba0d43a | ||
|
|
24fd5ba361 | ||
|
|
3353637c8f | ||
|
|
9601e6942d | ||
|
|
4b32a93f27 | ||
|
|
9e8978166e | ||
|
|
6bf873f4db | ||
|
|
1318f1a29b | ||
|
|
d9282ac750 | ||
|
|
205d728798 | ||
|
|
bd9c772a52 | ||
|
|
76e9002995 | ||
|
|
e990d44bb6 | ||
|
|
2ffa2d7b73 | ||
|
|
0e4583f8e2 | ||
|
|
3802722bb1 | ||
|
|
41f0a712fd | ||
|
|
4633c37380 | ||
|
|
b779becf8c | ||
|
|
35089febab | ||
|
|
a95fd1e1d8 | ||
|
|
6535f64699 | ||
|
|
b15a5d4a45 | ||
|
|
65a5c37ffb | ||
|
|
6cf58c032c | ||
|
|
e0365df6dd | ||
|
|
40ae0c7257 | ||
|
|
aecd4c5266 | ||
|
|
113caf4970 | ||
|
|
da2d57c8e9 | ||
|
|
3aed8b8479 | ||
|
|
ff58a826b1 | ||
|
|
9a0873e404 | ||
|
|
7d9133793c | ||
|
|
f43d9883cf | ||
|
|
067842818e | ||
|
|
8ea70a1b77 | ||
|
|
47207dcead | ||
|
|
235876a4d8 | ||
|
|
af88abb13f | ||
|
|
f13701b120 | ||
|
|
5f7c598a34 | ||
|
|
defd354286 | ||
|
|
f9e6b30550 | ||
|
|
d451af365a | ||
|
|
57a78535f2 | ||
|
|
f824ecb7f9 | ||
|
|
98f848138d | ||
|
|
200a1dc3da | ||
|
|
507e1d2b50 | ||
|
|
0f752e2571 | ||
|
|
ca6cd65d46 | ||
|
|
ddc287a84e | ||
|
|
c92ec031ae | ||
|
|
ef2d4d6b12 | ||
|
|
2753f6c4e5 | ||
|
|
021577d638 | ||
|
|
dd3f8b4717 | ||
|
|
a1fb4a0ac5 | ||
|
|
ebf0c4fae6 | ||
|
|
44a086a27b | ||
|
|
4624075112 | ||
|
|
97a3c8dca1 | ||
|
|
c50b5d93d7 | ||
|
|
08f9176f3f | ||
|
|
f95ca6eac6 | ||
|
|
34165c0d90 | ||
|
|
1f87cf09d7 | ||
|
|
005c7b9cb0 | ||
|
|
2b265bd1de | ||
|
|
3e83216384 | ||
|
|
a9889b5b79 | ||
|
|
2aa5b7917f | ||
|
|
040354501c | ||
|
|
bd46f6d25f | ||
|
|
7e801269af | ||
|
|
2586e2e661 | ||
|
|
fb2a5c2378 | ||
|
|
f490fa6e7d | ||
|
|
df347be672 | ||
|
|
4e518bf70c | ||
|
|
29e90246d2 | ||
|
|
1e62c0d836 | ||
|
|
278ebf4ff2 | ||
|
|
edc58a3496 | ||
|
|
7c96862b19 | ||
|
|
11b18f7468 | ||
|
|
86787b6099 | ||
|
|
12645c19aa | ||
|
|
7e06a57fd9 | ||
|
|
4d7c31cfa1 | ||
|
|
f5e4fc5a3d | ||
|
|
1c4174431e | ||
|
|
60d4f2d6c7 | ||
|
|
5a30a96c0c | ||
|
|
09b454ba6a | ||
|
|
8ea06e84a6 | ||
|
|
ebaf56d964 | ||
|
|
517d2bb1ec | ||
|
|
706d43ee41 | ||
|
|
e537d27e28 | ||
|
|
948f28b0af | ||
|
|
70f7c6a25e | ||
|
|
a0a0cd4f57 | ||
|
|
dfa120339c | ||
|
|
36f194b9bd | ||
|
|
12dd851fc3 | ||
|
|
cc9a5893de | ||
|
|
9d2ac3f2c4 | ||
|
|
9cda61de3d | ||
|
|
060d93d68b | ||
|
|
8d1e8c6699 | ||
|
|
f4865c5206 | ||
|
|
2d44c89149 | ||
|
|
c2050d4314 | ||
|
|
7991605106 | ||
|
|
adeea85c9a | ||
|
|
c32e390184 | ||
|
|
154f61fb11 | ||
|
|
b08bcf041b | ||
|
|
e51f6e1e86 | ||
|
|
62e2a0211f | ||
|
|
5286e7f89c | ||
|
|
e81ba55967 | ||
|
|
25a2689bd0 | ||
|
|
c949eb5491 | ||
|
|
709c5cbd71 | ||
|
|
3ac59a5bc0 | ||
|
|
6894228a63 | ||
|
|
a7b914b84e | ||
|
|
84922e84a3 | ||
|
|
7ee0b2b0a3 | ||
|
|
5c06a241ac | ||
|
|
0cb0128caf | ||
|
|
8661b8074c | ||
|
|
fa52a1a81e | ||
|
|
680fa7a350 | ||
|
|
3850ce88d3 | ||
|
|
a800f1efc7 | ||
|
|
514bbbe8a3 | ||
|
|
700b922350 | ||
|
|
bdfeeb9a41 | ||
|
|
2b80d1a6d8 | ||
|
|
fa6f2061e7 | ||
|
|
ff5f12e4d2 | ||
|
|
9ad6e8142d | ||
|
|
49e3534738 | ||
|
|
4cb7ba83e9 | ||
|
|
9282828ffc | ||
|
|
2f2a2d4bee | ||
|
|
b904e6a889 | ||
|
|
804d5723c2 | ||
|
|
681e3a6865 | ||
|
|
dd75c56404 | ||
|
|
86cee1e339 | ||
|
|
063edc032a | ||
|
|
32c59cb583 | ||
|
|
0242f88d26 | ||
|
|
940a89fa38 | ||
|
|
364a66ad0b | ||
|
|
f714315b0d | ||
|
|
ed83471a13 | ||
|
|
1263aa7884 | ||
|
|
c21afc3f8a | ||
|
|
59af0594dc | ||
|
|
8cf6d4f7d8 | ||
|
|
61ceeb44fb | ||
|
|
995bb921c1 | ||
|
|
e7cab78aad | ||
|
|
1c06bd45ef | ||
|
|
85a3e112e0 | ||
|
|
9c5e054dda | ||
|
|
86932e6da4 | ||
|
|
5f94fdfc93 | ||
|
|
74584dd39e | ||
|
|
18ed5d51a9 | ||
|
|
d7076f5295 | ||
|
|
29a5397491 | ||
|
|
47a4261631 | ||
|
|
a3927218a6 | ||
|
|
7d846a3d0d | ||
|
|
8db1f6d1e2 | ||
|
|
9cb679d545 | ||
|
|
006d705cbd | ||
|
|
a19a14665f | ||
|
|
55bc6f9a00 | ||
|
|
997d31addd | ||
|
|
548390b0d7 | ||
|
|
bd64bdedc3 | ||
|
|
846e09c7cb | ||
|
|
2ba3552578 | ||
|
|
943bb6d15b | ||
|
|
af53e75ae4 | ||
|
|
14ca63571d | ||
|
|
10c5ce68f5 | ||
|
|
d9fb856eb8 | ||
|
|
f5c08158cb | ||
|
|
9ee0311ea9 | ||
|
|
69ed2d2428 | ||
|
|
0c5fae01b5 | ||
|
|
72052925a6 | ||
|
|
dc2d02bf32 | ||
|
|
ee267ea086 | ||
|
|
1e730f3376 | ||
|
|
c230c52af6 | ||
|
|
219beb4a0e | ||
|
|
c4807c44f3 | ||
|
|
7dafd14644 | ||
|
|
57c3e8c51d | ||
|
|
da71eca978 | ||
|
|
7a47af14be | ||
|
|
f67adc53ab | ||
|
|
68e9948493 | ||
|
|
894416c719 | ||
|
|
11650450c8 | ||
|
|
6973d85b10 | ||
|
|
bf5598515e | ||
|
|
cc03c27d17 | ||
|
|
9cd729df71 | ||
|
|
d6ee9fbfac | ||
|
|
b6999f5c67 | ||
|
|
c02f273d57 | ||
|
|
8d87bfb4a3 | ||
|
|
0a7cd3d6e9 | ||
|
|
235699b3b9 | ||
|
|
1aebfbecc1 | ||
|
|
00e47b9afb | ||
|
|
68b94cfcaa | ||
|
|
0068f21a2d | ||
|
|
7a7e639490 | ||
|
|
81bae1441e | ||
|
|
3516e5ae8a | ||
|
|
04bbe3187f | ||
|
|
877cdec4ea | ||
|
|
21ab94c512 | ||
|
|
70f52afb3d | ||
|
|
85f4dbd670 | ||
|
|
bee70e67bc | ||
|
|
7e137f17a5 | ||
|
|
c576f62ca3 | ||
|
|
9c8499e6cd | ||
|
|
f81e7cb78a | ||
|
|
773f3048f7 | ||
|
|
40faaea7f8 | ||
|
|
47b4409f3e | ||
|
|
9ce23c3d61 | ||
|
|
f40ffed069 | ||
|
|
0b223170d9 | ||
|
|
e61f8a512c | ||
|
|
65b43c39ed | ||
|
|
131645f31e | ||
|
|
ca8fc14d36 | ||
|
|
efe693c0c0 | ||
|
|
4eb2d073ac | ||
|
|
fd49c02e18 | ||
|
|
f0e3d492d3 | ||
|
|
3f8ba6be9d | ||
|
|
df4563379d | ||
|
|
f0f9d8faa7 | ||
|
|
031b4b637a | ||
|
|
e206ae3403 | ||
|
|
021c463d80 | ||
|
|
41d75da33f | ||
|
|
c7e7a559a6 | ||
|
|
4f5dfcc65b | ||
|
|
e85208110f | ||
|
|
17bb2f11e4 | ||
|
|
124db5f11f | ||
|
|
6b099d7298 | ||
|
|
7ac2e227b1 | ||
|
|
868c1aa251 | ||
|
|
7283fc89a5 | ||
|
|
f933560934 | ||
|
|
7ee918ad49 | ||
|
|
e30ebd39fd | ||
|
|
7ac6ff828c | ||
|
|
017f5f8e74 | ||
|
|
2c46feb8f8 | ||
|
|
f5171f3f47 | ||
|
|
1a2c28435a | ||
|
|
7221fc2060 | ||
|
|
e17e7ab4ec | ||
|
|
46eb0bc474 | ||
|
|
b03227ea9f | ||
|
|
a1de5e15c5 | ||
|
|
7f2322ba60 | ||
|
|
5c04844461 | ||
|
|
591a185fc2 | ||
|
|
fbc0b60b68 | ||
|
|
325ce8824e | ||
|
|
d54e25bb44 | ||
|
|
740943aee2 | ||
|
|
73ee93335b | ||
|
|
c69c3361ac | ||
|
|
a91d019738 | ||
|
|
dc272a472d | ||
|
|
b265108322 | ||
|
|
6cab6a9646 | ||
|
|
3baf237fa8 | ||
|
|
fa8503546e | ||
|
|
b9d988c712 | ||
|
|
2bbf672094 | ||
|
|
a6f8fe4c95 | ||
|
|
6d7415880a | ||
|
|
479e4588f3 | ||
|
|
821f1bdc2b | ||
|
|
5cdd672e84 | ||
|
|
48fb8d0b92 | ||
|
|
52fae655ba | ||
|
|
3ab6e84275 | ||
|
|
2b5ab6db11 | ||
|
|
a0f6d47153 | ||
|
|
787901ba73 | ||
|
|
37c7167128 | ||
|
|
35e1ddc578 | ||
|
|
d61e7b8729 | ||
|
|
8ef73f9dd2 | ||
|
|
f7448cc2e4 | ||
|
|
6af35b5ec5 | ||
|
|
8f4e5c6064 | ||
|
|
2d76775e40 | ||
|
|
8eb71cbe74 | ||
|
|
9146a8bb21 | ||
|
|
445bca7333 | ||
|
|
6286551ef5 | ||
|
|
1ae6a69c7a | ||
|
|
34851b772f | ||
|
|
4823aa378e | ||
|
|
40a42e86ee | ||
|
|
c518b52243 | ||
|
|
abccc3c3cd | ||
|
|
9786b7139e | ||
|
|
28e8e3434e | ||
|
|
cdf59fba10 | ||
|
|
be8571cb56 | ||
|
|
857715e55c | ||
|
|
5ccc815a47 | ||
|
|
d77c04109b | ||
|
|
1ba8b8b1b1 | ||
|
|
caa349b59b | ||
|
|
9a7350149d | ||
|
|
7f435363f7 | ||
|
|
832cb79f88 | ||
|
|
ba7290fdda | ||
|
|
85ee4a95ec | ||
|
|
eb164c511f | ||
|
|
26e3119ef3 | ||
|
|
6c38b54f7d | ||
|
|
7e6badaf5d | ||
|
|
c104e8e1f0 | ||
|
|
c8d04f3373 | ||
|
|
f64f417711 | ||
|
|
92fe975e3d | ||
|
|
e00731ef8f | ||
|
|
0d7d0664f6 | ||
|
|
b59b0ef041 | ||
|
|
964aa0ecce | ||
|
|
a9ecf06cd4 | ||
|
|
76da6857e7 | ||
|
|
9eef60c93d | ||
|
|
df412bbef7 | ||
|
|
b4c6632162 | ||
|
|
5f2eb6bd32 | ||
|
|
ea532b15fc | ||
|
|
01bd1fde39 | ||
|
|
c6c1c61ff6 | ||
|
|
bbd33c70c1 | ||
|
|
a2592342fe | ||
|
|
db06e12337 | ||
|
|
22139c9650 | ||
|
|
3b1e2e38fb | ||
|
|
6f6da47ebe | ||
|
|
f3237172f3 | ||
|
|
45dc64af5a | ||
|
|
4df71bff7f | ||
|
|
f5003d3505 | ||
|
|
f2f3fab3e2 | ||
|
|
2357e139f0 | ||
|
|
c74eaa47a3 | ||
|
|
591f9fa4c2 | ||
|
|
766ffa3e65 | ||
|
|
78d2c7beaa | ||
|
|
f11c38238a | ||
|
|
6d388d50ee | ||
|
|
9479254562 | ||
|
|
9c9fdaf35d | ||
|
|
a4767591ae | ||
|
|
ecbc50b990 | ||
|
|
dde9cc27d0 | ||
|
|
703c03e84b | ||
|
|
2f831b3e6f | ||
|
|
d54eec0b87 | ||
|
|
bc80554cd3 | ||
|
|
a696d330e5 | ||
|
|
b1479ab3c5 | ||
|
|
e51fb06ceb | ||
|
|
dc0f2bde6b | ||
|
|
eb13f267fe | ||
|
|
8677e73d75 | ||
|
|
fbb919d767 | ||
|
|
1f0f9a2eae | ||
|
|
282b2a0a43 | ||
|
|
6d0e4d5a38 | ||
|
|
43956bbf2c | ||
|
|
18e31b3821 | ||
|
|
0d0acb9d10 | ||
|
|
6a792ce6a0 | ||
|
|
917cea5052 | ||
|
|
c98f0d3c81 | ||
|
|
88d650e638 | ||
|
|
72ebe937fb | ||
|
|
8efa5bc1dc | ||
|
|
9b6d2bce58 | ||
|
|
7bb26a7f07 | ||
|
|
9585b3919a | ||
|
|
f56c9deb00 | ||
|
|
c6221fc60f | ||
|
|
acfe3e912e | ||
|
|
50be0ebe3c | ||
|
|
704dc803b8 | ||
|
|
e2d64e9140 | ||
|
|
bdef0612f7 | ||
|
|
a196b71d36 | ||
|
|
fff8116430 | ||
|
|
2be6fb13d2 | ||
|
|
faa6d7f148 | ||
|
|
982fc2838d | ||
|
|
a8351319f8 | ||
|
|
5b1901708c | ||
|
|
fa8d4f511f | ||
|
|
b4215afe82 | ||
|
|
2ad25e8fbc | ||
|
|
67d0e9d2c2 | ||
|
|
f69aae550f | ||
|
|
2d26acd991 | ||
|
|
8dec1453c4 | ||
|
|
241d1e181f | ||
|
|
f267c597e0 | ||
|
|
192437896d | ||
|
|
d59ae7fce1 | ||
|
|
18b21005f1 | ||
|
|
94ac91cce3 | ||
|
|
46e255bccc | ||
|
|
87de5b5305 | ||
|
|
1ddc923631 | ||
|
|
03f65606fd | ||
|
|
148cf9552b | ||
|
|
bf230322d0 | ||
|
|
758779a8f5 | ||
|
|
55eb39c51d | ||
|
|
13b8475c54 | ||
|
|
d3d52b44ee | ||
|
|
d2886432b7 | ||
|
|
7bb8737ff9 | ||
|
|
3904c36a6e | ||
|
|
c2577df6f7 | ||
|
|
36cb0fb4cd | ||
|
|
ec79793f3d | ||
|
|
188bf76ed1 | ||
|
|
e4e909737c | ||
|
|
d32421c583 | ||
|
|
63cbcdc3ea | ||
|
|
dfd8d0fa3d | ||
|
|
7d7ca11c81 | ||
|
|
ee50a31bba | ||
|
|
179930ad80 | ||
|
|
fdb02da5ed | ||
|
|
5499beb510 | ||
|
|
96046d2ee2 | ||
|
|
a35a209066 | ||
|
|
8139c33b86 | ||
|
|
da40562ee3 | ||
|
|
ce478583ab | ||
|
|
6215af0e5a | ||
|
|
8f0ecac842 | ||
|
|
54dd562d88 | ||
|
|
c24f7a86d4 | ||
|
|
d6b4437664 | ||
|
|
68e74b9830 | ||
|
|
3fa40b2303 | ||
|
|
5feb73c65b | ||
|
|
33d676e1fe | ||
|
|
afb7af287b | ||
|
|
d6291a4c47 | ||
|
|
7228b84bf8 | ||
|
|
2dbf8ebb65 | ||
|
|
2d90844239 | ||
|
|
bf6e66ea47 | ||
|
|
5edaa6ec29 | ||
|
|
881ca67f80 | ||
|
|
1c0ed2a2c1 | ||
|
|
245d27ea71 | ||
|
|
f14d4b8ac3 | ||
|
|
fdc867b9d5 | ||
|
|
8e876d6a99 | ||
|
|
c9de0b4cf2 | ||
|
|
27b3a86155 | ||
|
|
683bdc838d | ||
|
|
4f9f10ddf2 | ||
|
|
6fe3f90a26 | ||
|
|
5bdb7eee85 | ||
|
|
34262a45ca | ||
|
|
7c22110c96 | ||
|
|
6ad9fb8f27 | ||
|
|
4348f4b0d4 | ||
|
|
22529e28d8 | ||
|
|
aa52bcee8c | ||
|
|
d731ab3682 | ||
|
|
7840438bfc | ||
|
|
455a2dba8a | ||
|
|
01c310c913 | ||
|
|
a679d6f2e1 | ||
|
|
e8af56bdbe | ||
|
|
efa099ac5b | ||
|
|
81181aa7e6 | ||
|
|
1ab6640983 | ||
|
|
e5636cde05 | ||
|
|
0a0d00b26e | ||
|
|
6c9afcff81 | ||
|
|
b7933b282b | ||
|
|
653c34758b | ||
|
|
9d18ab795e | ||
|
|
a5c06c67bc | ||
|
|
db2f790bf7 | ||
|
|
5cbc6b5f6a | ||
|
|
f7ecf40633 | ||
|
|
6cd83c60ef | ||
|
|
90ffce63e5 | ||
|
|
2910ebc0fd | ||
|
|
02fab95637 | ||
|
|
22d2209a1b | ||
|
|
e2bea81c64 | ||
|
|
466b8bd1cc | ||
|
|
c5287d2869 | ||
|
|
010502ed9d | ||
|
|
be06e74d94 | ||
|
|
199d2cf851 | ||
|
|
deab1b4962 | ||
|
|
d04411e4a8 | ||
|
|
ce52b57a52 | ||
|
|
c760c19056 | ||
|
|
6b5e469b19 | ||
|
|
8663489ae4 | ||
|
|
877ef1d7ed | ||
|
|
6a81035f10 | ||
|
|
1f7276bbfd | ||
|
|
90e8490a85 | ||
|
|
38d51988d9 | ||
|
|
b8fccd1bac | ||
|
|
ded8e7b916 | ||
|
|
f56ca6318a | ||
|
|
5bd6ba4f36 | ||
|
|
909fb2eb2b | ||
|
|
b2209eaad0 | ||
|
|
dcae3c4acb | ||
|
|
3a3a2ec76d | ||
|
|
5e2ba192c1 | ||
|
|
6d4452bf94 | ||
|
|
998f9491f6 | ||
|
|
fa7efeb283 | ||
|
|
22206b6a99 | ||
|
|
34036ee355 | ||
|
|
2eb2d555ad | ||
|
|
722abf9cab | ||
|
|
357d3b8140 | ||
|
|
01ef79ac33 | ||
|
|
8d2456f238 | ||
|
|
bb164edb55 | ||
|
|
21117eaa17 | ||
|
|
573f823f48 | ||
|
|
47ca3b5d33 | ||
|
|
7334134b45 | ||
|
|
e6be594395 | ||
|
|
e2b6697362 | ||
|
|
f78e11057d | ||
|
|
314ee96525 | ||
|
|
efc1223d45 | ||
|
|
38d9aa4997 | ||
|
|
42c7431416 | ||
|
|
d1e40ee71c | ||
|
|
43169d8bab | ||
|
|
8cbbb52b95 | ||
|
|
807a55fcdc | ||
|
|
8c5351445b | ||
|
|
999c630c5a | ||
|
|
a0186ce8e4 | ||
|
|
9fe336d564 | ||
|
|
34a1d4e6b9 | ||
|
|
bafa548f2f | ||
|
|
fa709a9bdc | ||
|
|
2a1cc7e3ea | ||
|
|
68648b9920 | ||
|
|
b9f297935b | ||
|
|
eb6fc4f8cf | ||
|
|
8a177c34fa | ||
|
|
22a5f411d0 | ||
|
|
f557609e9e | ||
|
|
cde8deaf4b | ||
|
|
48eb1c6d67 | ||
|
|
4db741a87c | ||
|
|
3188ca6884 | ||
|
|
bb9cd171bf | ||
|
|
7a81638258 | ||
|
|
6519db1fe8 | ||
|
|
f313d319d4 | ||
|
|
a8c4e6fedc | ||
|
|
db16458cf5 | ||
|
|
38a9562eaf | ||
|
|
b2327e8bf7 | ||
|
|
aafef107ec | ||
|
|
4b442e75f7 | ||
|
|
e8f103799b | ||
|
|
618685dc05 | ||
|
|
f0d50e53fa | ||
|
|
1b4828f4fa | ||
|
|
56730d67a2 | ||
|
|
b02516b0b3 | ||
|
|
1eb32f86bd | ||
|
|
3b669e64e2 | ||
|
|
fbccd70f7d | ||
|
|
61e5231d99 | ||
|
|
5c101c5a85 | ||
|
|
a6e991923e | ||
|
|
f0c494ecea | ||
|
|
40dfdf9bb1 | ||
|
|
770e0f01f1 | ||
|
|
8448d3e516 | ||
|
|
292a11f942 | ||
|
|
6099986f5b | ||
|
|
53d18d8947 | ||
|
|
f77bdd233b | ||
|
|
dc25a1294c | ||
|
|
8f4bffa950 | ||
|
|
96195fa16a | ||
|
|
4e8a59ad4e | ||
|
|
e42ee6d6be | ||
|
|
f6a04a8b36 | ||
|
|
36b94b81ce | ||
|
|
d66e782152 | ||
|
|
d122d39d3a | ||
|
|
7c3053e8cd | ||
|
|
ecdfa61755 | ||
|
|
7321117c99 | ||
|
|
b50560eadf | ||
|
|
60841e6312 | ||
|
|
66cc61f967 | ||
|
|
1933f4bcc8 | ||
|
|
977f5ca9ce | ||
|
|
e5e529d3d2 | ||
|
|
e1f9d6091c | ||
|
|
a83d8064f2 | ||
|
|
9afb5e7272 | ||
|
|
4c7c2ccc74 | ||
|
|
a6d5686c1c | ||
|
|
8fa1b92deb | ||
|
|
f06e3643b6 | ||
|
|
cd8e59bc9c | ||
|
|
b6eeeea1ea | ||
|
|
aea642fcde | ||
|
|
27bec7ad05 | ||
|
|
80cb3458de | ||
|
|
615048df04 | ||
|
|
4e07b56f3e | ||
|
|
7d18da13a1 | ||
|
|
a49e9e346f | ||
|
|
87fd267183 | ||
|
|
c61fefb55f | ||
|
|
c644031041 | ||
|
|
79f0f52825 | ||
|
|
03ac62044b | ||
|
|
531bc0f887 | ||
|
|
af8b60ca29 | ||
|
|
80c14e9ebd | ||
|
|
3d658eff29 | ||
|
|
8a8a75aa79 | ||
|
|
ea3fe06613 | ||
|
|
92e7f6bd68 | ||
|
|
96b22a00ff | ||
|
|
cfddbc5b3f | ||
|
|
725009d719 | ||
|
|
7f7370f6db | ||
|
|
0fcc1316b2 | ||
|
|
e9933bebe7 | ||
|
|
9810081b11 | ||
|
|
6522d252cb | ||
|
|
a2867cffb7 | ||
|
|
e92c1b53a1 | ||
|
|
52aecb47e7 | ||
|
|
c4652d39fa | ||
|
|
c7b155ccac | ||
|
|
96d18535f8 | ||
|
|
98471e39e1 | ||
|
|
f55fc5776e | ||
|
|
f9a8d1cc40 | ||
|
|
e55a210cf9 | ||
|
|
d19d4406f6 | ||
|
|
9697331abb | ||
|
|
91db02f2da | ||
|
|
b933b30e0a | ||
|
|
2cb9a7c199 | ||
|
|
06ff17ebb2 | ||
|
|
44a573ecd5 | ||
|
|
ffa7952fc1 | ||
|
|
701514a168 | ||
|
|
1565bc9e1a | ||
|
|
0681bad8e6 | ||
|
|
23a21bb39f | ||
|
|
9aabb575c1 | ||
|
|
cf607e892b | ||
|
|
6bf906f2a7 | ||
|
|
7e897d604c | ||
|
|
39887df3ec | ||
|
|
fbb7a684bf | ||
|
|
449ad6cd0d | ||
|
|
cfcd6e5f93 | ||
|
|
73aab88109 | ||
|
|
beb692a3c4 | ||
|
|
fe8385e759 | ||
|
|
58fb331019 | ||
|
|
e4986a6a47 | ||
|
|
fcd47ecec6 | ||
|
|
174e6ad637 | ||
|
|
2ac4097e32 | ||
|
|
dd13ac5cbb | ||
|
|
9c55a898f7 | ||
|
|
bb9018c094 | ||
|
|
b09b4183bb | ||
|
|
3d7bc6583d | ||
|
|
99e8be227e | ||
|
|
b1c38cc793 | ||
|
|
26e4e70fc8 | ||
|
|
04bdf3f26a | ||
|
|
cafeacf69f | ||
|
|
4c2d6d78ea | ||
|
|
ea7d0cdef5 | ||
|
|
47bae63548 | ||
|
|
8470f4f7fb | ||
|
|
242f9d55ed | ||
|
|
236ac52925 | ||
|
|
baab9a9c89 | ||
|
|
3d26e6e340 | ||
|
|
c34ab48972 | ||
|
|
cf0abf21db | ||
|
|
7918b392e8 | ||
|
|
f0ced15e6a | ||
|
|
c0204cb725 | ||
|
|
eb3905447f | ||
|
|
16c7459906 | ||
|
|
eae5f87eed | ||
|
|
d4b85e3b1c | ||
|
|
a989c3b7d0 | ||
|
|
d96ba9fa46 | ||
|
|
2261d655ea | ||
|
|
8b67049863 | ||
|
|
48258dd9dd | ||
|
|
e04c573726 | ||
|
|
4daec3794e | ||
|
|
f0646dde32 | ||
|
|
ec2086e0f7 | ||
|
|
2ac704178c | ||
|
|
7c43c38e28 | ||
|
|
043a8336e5 | ||
|
|
ee27535b82 | ||
|
|
89e6ae2475 | ||
|
|
e51615f520 | ||
|
|
6e59897587 | ||
|
|
bd0644a261 | ||
|
|
d7825e1bf8 | ||
|
|
97956b6c5e | ||
|
|
8150504ea0 | ||
|
|
942dec81c7 | ||
|
|
dcbc377c62 | ||
|
|
7b65233699 | ||
|
|
eabfd8b5c4 | ||
|
|
b7b2799611 | ||
|
|
ece59ac374 | ||
|
|
83cc8b772c | ||
|
|
8b5bc18142 | ||
|
|
e1413baa9a | ||
|
|
03640e6d37 | ||
|
|
2588011524 | ||
|
|
0c16a6804a | ||
|
|
e2021fdf5d | ||
|
|
33b5694d35 | ||
|
|
af7d04fef6 | ||
|
|
14e3419e4c | ||
|
|
f6c5252376 | ||
|
|
78ee77444f | ||
|
|
fb022970b5 | ||
|
|
e5d378dc93 | ||
|
|
5969902263 | ||
|
|
d5894de142 | ||
|
|
059c6baa4e | ||
|
|
bbf9331baf | ||
|
|
a5b084f506 | ||
|
|
3b5471b97c | ||
|
|
fae37fe67d | ||
|
|
1f975efda1 | ||
|
|
3b3b61f52c | ||
|
|
1c1f6e21c5 | ||
|
|
8b60c7cc09 | ||
|
|
d4f9752cd4 | ||
|
|
6332a37f5b | ||
|
|
840a583a0b | ||
|
|
e7ed80d3e0 | ||
|
|
c2b9376313 | ||
|
|
7a8b291189 | ||
|
|
e63f71d3a7 | ||
|
|
061c97caca | ||
|
|
988d28f2fd | ||
|
|
af8a0ea9c0 | ||
|
|
c78e8d8358 | ||
|
|
392f7098bc | ||
|
|
195f918543 | ||
|
|
b2579538fa | ||
|
|
35b97c4f45 | ||
|
|
adaa89a963 | ||
|
|
fc1429fae5 | ||
|
|
4090f95098 | ||
|
|
3189d8d43e | ||
|
|
cd6d10e428 | ||
|
|
7d37236d78 | ||
|
|
7c127acf17 | ||
|
|
0a4ce2350a | ||
|
|
181a70cb1f | ||
|
|
7438545a16 | ||
|
|
9e902a5dd4 | ||
|
|
91e395884f | ||
|
|
7107c68a41 | ||
|
|
86728b79e3 | ||
|
|
e04f901590 | ||
|
|
47ad2b5cfa | ||
|
|
cea0f1766f | ||
|
|
407e57d334 | ||
|
|
c4e66d0c9c |
334
.travis.yml
Normal file
334
.travis.yml
Normal file
@@ -0,0 +1,334 @@
|
||||
dist: bionic
|
||||
sudo: true
|
||||
language: c
|
||||
|
||||
env:
|
||||
global:
|
||||
- IDE_VERSION=1.8.9
|
||||
matrix:
|
||||
- BOARD="multi4in1:avr:multiatmega328p:bootloader=none"
|
||||
- BOARD="multi4in1:avr:multiatmega328p:bootloader=optiboot"
|
||||
- BOARD="multi4in1:avr:multixmega32d4"
|
||||
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=none"
|
||||
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=native"
|
||||
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=ftdi"
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
before_install:
|
||||
# Fetch the tag information for the current branch
|
||||
- git fetch origin --tags
|
||||
|
||||
# Publish the buildroot script folder
|
||||
- chmod +x ${TRAVIS_BUILD_DIR}/buildroot/bin/*
|
||||
- export PATH=${TRAVIS_BUILD_DIR}/buildroot/bin/:${PATH}
|
||||
|
||||
# Arduino IDE adds a lot of noise caused by network traffic; firewall it
|
||||
- sudo iptables -P INPUT DROP
|
||||
- sudo iptables -P FORWARD DROP
|
||||
- sudo iptables -P OUTPUT ACCEPT
|
||||
- sudo iptables -A INPUT -i lo -j ACCEPT
|
||||
- sudo iptables -A OUTPUT -o lo -j ACCEPT
|
||||
- sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
# Helper functions for the builds
|
||||
- buildMulti() { start_fold config_diff; travis_time_start; git diff Multiprotocol/_Config.h; end_fold config_diff; exitcode=0; BUILDCMD="arduino --verify --board $BOARD Multiprotocol/Multiprotocol.ino --pref build.path=./build/"; echo $BUILDCMD; $BUILDCMD; if [ $? -ne 0 ]; then exitcode=1; fi; echo; return $exitcode; }
|
||||
- buildProtocol() { exitcode=0; opt_disable $ALL_PROTOCOLS; opt_enable $1; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
|
||||
- buildEachProtocol() { exitcodesum=0; for PROTOCOL in $ALL_PROTOCOLS ; do printf "\e[33;1mBuilding $PROTOCOL\e[0m"; buildProtocol $PROTOCOL; if [ $? -ne 0 ]; then exitcodesum=$((exitcodesum + 1)); fi; done; return $exitcodesum; }
|
||||
- buildRFModule() { exitcode=0; opt_disable $ALL_RFMODULES; opt_enable $1; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
|
||||
- buildEachRFModule() { exitcodesum=0; for RFMODULE in $ALL_RFMODULES; do printf "\e[33;1mBuilding $RFMODULE\e[0m"; buildRFModule $RFMODULE; if [ $? -ne 0 ]; then exitcodesum=$((exitcodesum + 1)); fi; done; return $exitcodesum; }
|
||||
- buildDefault() { exitcode=0; printf "\n\e[33;1mBuilding default configuration\e[0m\n"; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
|
||||
- buildSerialOnly() { exitcode=0; printf "\n\e[33;1mBuilding serial mode only\e[0m\n"; opt_disable ENABLE_PPM; opt_enable ENABLE_SERIAL; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
|
||||
- buildPPMOnly() { exitcode=0; printf "\n\e[33;1mBuilding PPM mode only\e[0m\n"; opt_enable ENABLE_PPM; opt_disable ENABLE_SERIAL; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
|
||||
|
||||
# Function to build the release files - dependent on board type
|
||||
- if [[ "$BOARD" == "multi4in1:avr:multixmega32d4" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-orangerx-aetr-green-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
opt_disable ORANGE_TX_BLUE;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-orangerx-aetr-green-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-orangerx-aetr-blue-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable ORANGE_TX_BLUE;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-orangerx-aetr-blue-inv-v$MULTI_VERSION.bin;
|
||||
cp Multiprotocol/Multi.txt ./binaries/Multi.txt; };
|
||||
elif [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=none" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-avr-usbasp-aetr-A7105-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $A7105_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-usbasp-aetr-A7105-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-avr-usbasp-aetr-CC2500-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CC2500_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-usbasp-aetr-CC2500-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CYRF6936_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin; };
|
||||
elif [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=optiboot" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-avr-txflash-aetr-A7105-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $A7105_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-txflash-aetr-A7105-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-avr-txflash-aetr-CC2500-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CC2500_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-txflash-aetr-CC2500-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CYRF6936_PROTOCOLS;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin; };
|
||||
elif [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103c:debug_option=none" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-aetr-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
opt_enable MULTI_STATUS;
|
||||
opt_disable MULTI_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-aetr-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-taer-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-taer-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-reta-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-reta-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-aetr-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace RETA AETR;
|
||||
opt_disable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-aetr-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-taer-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-taer-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-reta-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-reta-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-aetr-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace RETA AETR;
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_enable MULTI_TELEMETRY;
|
||||
opt_enable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-aetr-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-taer-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-taer-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-reta-inv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-reta-inv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-aetr-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace RETA AETR;
|
||||
opt_disable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-aetr-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-taer-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-taer-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-reta-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-reta-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-ppm-aetr-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace RETA AETR;
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_disable MULTI_TELEMETRY;
|
||||
opt_set NBR_BANKS 5;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-ppm-aetr-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-ppm-taer-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-ppm-taer-noinv-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-ppm-reta-noinv-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-ppm-reta-noinv-v$MULTI_VERSION.bin; };
|
||||
elif [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103c:debug_option=native" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-xn297dump-inv-usbdebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_add XN297DUMP_NRF24L01_INO;
|
||||
opt_enable MULTI_STATUS;
|
||||
opt_disable MULTI_TELEMETRY;
|
||||
opt_enable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-xn297dump-inv-usbdebug-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-xn297dump-inv-usbdebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_enable MULTI_TELEMETRY;
|
||||
opt_enable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-xn297dump-inv-usbdebug-v$MULTI_VERSION.bin; };
|
||||
elif [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103c:debug_option=ftdi" ]]; then
|
||||
buildReleaseFiles(){
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-xn297dump-inv-ftdidebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_add XN297DUMP_NRF24L01_INO;
|
||||
opt_enable MULTI_STATUS;
|
||||
opt_disable MULTI_TELEMETRY;
|
||||
opt_enable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-xn297dump-inv-ftdidebug-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-xn297dump-inv-ftdidebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_enable MULTI_TELEMETRY;
|
||||
opt_enable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-xn297dump-inv-ftdidebug-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-erskytx-aetr-inv-ftdidebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
opt_enable MULTI_STATUS;
|
||||
opt_disable MULTI_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-erskytx-aetr-inv-ftdidebug-v$MULTI_VERSION.bin;
|
||||
printf "\n\e[33;1mBuilding multi-stm-opentx-aetr-inv-ftdidebug-v$MULTI_VERSION.bin\e[0m";
|
||||
opt_disable MULTI_STATUS;
|
||||
opt_enable MULTI_TELEMETRY;
|
||||
buildMulti;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-aetr-inv-ftdidebug-v$MULTI_VERSION.bin; };
|
||||
else
|
||||
buildReleaseFiles() { echo "No release files for this board."; };
|
||||
fi
|
||||
|
||||
install:
|
||||
# Install Arduino IDE
|
||||
- wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz
|
||||
- tar xf arduino-$IDE_VERSION-linux64.tar.xz
|
||||
- mv arduino-$IDE_VERSION $HOME/arduino-ide
|
||||
- export PATH=$PATH:$HOME/arduino-ide
|
||||
|
||||
# Set the Multi boards package URL
|
||||
- arduino --pref "boardsmanager.additional.urls=https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json" --save-prefs
|
||||
|
||||
# Install the STM32 board if needed
|
||||
- if [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
arduino --install-boards multi4in1:STM32F1;
|
||||
fi
|
||||
|
||||
# Install the AVR board if needed
|
||||
- if [[ "$BOARD" =~ "multi4in1:avr:" ]]; then
|
||||
arduino --install-boards multi4in1:avr;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
# Change current working directory to the build dir
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
|
||||
# Create somwhere to put the exported binaries
|
||||
- mkdir ./binaries
|
||||
|
||||
# Log the initial Multi config
|
||||
- cat Multiprotocol/_Config.h
|
||||
|
||||
# Back up the configuration
|
||||
- cp Multiprotocol/_Config.h ./_Config.h.bak
|
||||
|
||||
# Get the firmware version number from the source
|
||||
- MAJOR_VERSION=$(grep "VERSION_MAJOR" "Multiprotocol/Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
|
||||
- MINOR_VERSION=$(grep "VERSION_MINOR" "Multiprotocol/Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
|
||||
- REVISION_VERSION=$(grep "VERSION_REVISION" "Multiprotocol//Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
|
||||
- PATCH_VERSION=$(grep "VERSION_PATCH" "Multiprotocol//Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
|
||||
- MULTI_VERSION=$MAJOR_VERSION.$MINOR_VERSION.$REVISION_VERSION.$PATCH_VERSION
|
||||
|
||||
# Derive the Multi protocols from the Multi source
|
||||
- A7105_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_A7105_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
|
||||
- CC2500_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CC2500_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
|
||||
- CYRF6936_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CYRF6936_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
|
||||
- NRF24L01_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_NRF24L01_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
|
||||
- if [[ "$BOARD" =~ "multi4in1:avr:multixmega32d4" ]]; then
|
||||
ALL_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS);
|
||||
else
|
||||
ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS);
|
||||
fi
|
||||
- echo $ALL_PROTOCOLS
|
||||
|
||||
# Declare all the installed modules
|
||||
- ALL_RFMODULES=$(echo A7105_INSTALLED CYRF6936_INSTALLED CC2500_INSTALLED NRF24L01_INSTALLED);
|
||||
|
||||
# Disable CHECK_FOR_BOOTLOADER when not needed
|
||||
- if [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=none" ]]; then
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
fi
|
||||
|
||||
# Trim the enabled protocols down for the STM32 board with USB debugging
|
||||
- if [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103c:debug_option=native" ]]; then
|
||||
opt_disable AFHDS2A_RX_A7105_INO FRSKY_RX_CC2500_INO SCANNER_CC2500_INO WK2x01_CYRF6936_INO HUBSAN_A7105_INO;
|
||||
fi
|
||||
|
||||
# Trim the enabled protocols down for the Atmega328p board
|
||||
- if [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
|
||||
fi
|
||||
|
||||
# Useful Travis functions
|
||||
- export -f travis_fold
|
||||
- export -f travis_nanoseconds
|
||||
- export -f travis_time_start
|
||||
- export -f travis_time_finish
|
||||
- start_fold() { echo -e "travis_fold:start:$1"; }
|
||||
- end_fold() { echo -e "\ntravis_fold:end:$1\r"; }
|
||||
|
||||
script:
|
||||
# Build with default configuration - all protocols are enabled for STM32; a subset of protocols for Atmega
|
||||
- buildDefault
|
||||
|
||||
# Serial only
|
||||
- buildSerialOnly
|
||||
|
||||
# PPM only
|
||||
- buildPPMOnly
|
||||
|
||||
# Re-enable PPM and serial
|
||||
- opt_enable ENABLE_SERIAL
|
||||
- opt_enable ENABLE_PPM
|
||||
|
||||
# Build for each RF module individually
|
||||
- buildEachRFModule
|
||||
|
||||
# Restore the default configuration
|
||||
- cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
|
||||
# Build each protocol individually
|
||||
- buildEachProtocol
|
||||
|
||||
# Restore the default configuration
|
||||
- cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
|
||||
# Builds the files for a release - always built, but only copied to Github if the test is tagged as a release
|
||||
- buildReleaseFiles
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: KGXaoqvd8rbZ3AZtL9Rrn1JYiocGsPaihRUyR8gM8vTfvH9WYAE1+h6SzROQOuJSwr89MvTo3SBOTlM/0PDBnEGLec9Irt7cwO0xf9xM2vPuUG8DYcUzmJJzME9dkn/7qHof1JGgRpp1duUAN1triE9NxhKxL1hbs+tUUbDPAejxwoFNfnta/T4PfD6xmkZNJbneIfYFuFgyLpwwFhuUy9JP7s1AFOiT+fCHxPaZrPn5GsXqAi95Cb7Q3w1iVSt3BmrGxL2j3CeNpWzFY1RrMdc8ay+ppOhSPEIl2vyM7VeLRRBL3EVeFWkiS4ywevqw70wOivTczluv3OeuIJAe5o2UU+w5+59c7+i44Nih23PDAZBhAG5JkLUYUN0XUJpXJ5ZlZsb8IS8sI1txlZa5tNVoXO9+soGEY4rKSpZaPptuENm792CzzAjcaUI9pOFJ/0CBoSCbu5MpM/plkJCMd8fY27EE8cNYvolMuRATNlXs7h9mURGR69pmcR1jFShH+A7Kyp1S1sH19sGCEU16rt2aAtf2FadFg/gKACC2y9rB3wBb4Qnapu2AwNRlTYNuU1+G+kb2FXRwMl04q+38S+cIBHH9NHfdftp9MRPf8Ekatojs92be/Ux21S+hcA7sx/DV22Dl45V6l4mXzR7U4x1nQcdn1SGuy5I4lL6IYCk=
|
||||
skip_cleanup: true
|
||||
file_glob: true
|
||||
file: binaries/*
|
||||
on:
|
||||
tags: true
|
||||
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.
550
BootLoaders/package_multi_4in1_board_index.json
Normal file
550
BootLoaders/package_multi_4in1_board_index.json
Normal file
@@ -0,0 +1,550 @@
|
||||
{
|
||||
"packages": [{
|
||||
"name": "multi4in1",
|
||||
"maintainer": "Pascal Langer",
|
||||
"websiteURL": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module",
|
||||
"email": "pascal_langer@yahoo.fr",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"platforms": [
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.2.tar.gz",
|
||||
"checksum": "SHA-256:b7e2fda37186bf696b7a769b12317737d513181096b33d9ad321ec2fd47f3f80",
|
||||
"size": "164467",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.3.tar.gz",
|
||||
"checksum": "SHA-256:7d4561eebe0d7f6422f06d5719a417e15fcc0aa9cdbfc1c48a57066ce768e33c",
|
||||
"size": "164483",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.4.tar.gz",
|
||||
"checksum": "SHA-256:6c51a4eb09bcd074cc651dab3f2356ea3afd358f6330aba0d8bdfaa75f718dbb",
|
||||
"size": "167975",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.5.tar.gz",
|
||||
"checksum": "SHA-256:0a4754d47cdbb49ca194b15835686331530ed9d36c0db093a29ae5f865e75421",
|
||||
"size": "169830",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.6.tar.gz",
|
||||
"checksum": "SHA-256:4f4cf8820e30bf6c88f280514c67ee67b9dc6649f439597cfb8d0be3a5b13bf5",
|
||||
"size": "169819",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.7.tar.gz",
|
||||
"checksum": "SHA-256:453c9999e433ed1bdda2ba2b12cb7cbba7b547591db969dc6b7efb941b61cf76",
|
||||
"size": "169825",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.8",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.8.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.8.tar.gz",
|
||||
"checksum": "SHA-256:8e58b8733220d56155e10bf5bec0bfe6bf96f8460b3fd49a4b45c7f9fad776cb",
|
||||
"size": "293388",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.0.9",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.9.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.0.9.tar.gz",
|
||||
"checksum": "SHA-256:269c4ddcb8018be2b31f5c9e9f0814d120af492e894b8d5098a814486d56faa5",
|
||||
"size": "318437",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 AVR Boards",
|
||||
"architecture": "avr",
|
||||
"version": "1.1.0",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.1.0.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_avr_board_v1.1.0.tar.gz",
|
||||
"checksum": "SHA-256:7bacf2db754ceb890a203de5ce89d97aa787a9e6462debeb44cf04830859687a",
|
||||
"size": "326431",
|
||||
"boards": [
|
||||
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
|
||||
{"name": "Multi 4-in-1 (OrangeRX)"}
|
||||
],
|
||||
"toolsDependencies": []
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.1.tar.gz",
|
||||
"checksum": "SHA-256:b522b5d3474308768c197a6897cad037fb54d6fac26c75678415a0908793bae3",
|
||||
"size": "10332875",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.2.tar.gz",
|
||||
"checksum": "SHA-256:26d21dbd2fe80680ac523b8bca24b3ecf2c2016bac626826d20b651e11278287",
|
||||
"size": "10318646",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.3.tar.gz",
|
||||
"checksum": "SHA-256:e48f1f30948b3f7be83e8b1fe2bb5c6b41be7c4d5da02503a0b4827c60926541",
|
||||
"size": "10309833",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.4.tar.gz",
|
||||
"checksum": "SHA-256:388a4dbcd567f9d41b82955e12e8a640d9696217081c0ee6ab8c58a25aedf70f",
|
||||
"size": "10307581",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.5.tar.gz",
|
||||
"checksum": "SHA-256:46d3b4e62fc46e6b8ca4f429974ffd2ee8cde9e29a6e0cda58f85044991a9c2b",
|
||||
"size": "10313436",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.6.tar.gz",
|
||||
"checksum": "SHA-256:ad7a330326069a5ffb2908495b288933f68517b1247cc6636b160eb483a58284",
|
||||
"size": "10319669",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.7.tar.gz",
|
||||
"checksum": "SHA-256:f73fded48beaee55e646a3cf36d24beeedc336873c7824683a4912f2aee9e350",
|
||||
"size": "10322111",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.8",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.8.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.8.tar.gz",
|
||||
"checksum": "SHA-256:f8100272ec615074cf7962c2c8331014ebda78f3e4c17172b88b6dd3d83c4331",
|
||||
"size": "10319134",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.0.9",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.9.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.9.tar.gz",
|
||||
"checksum": "SHA-256:c3621d1cf6580ca5c943a67dc14dc15a60e2797a4b985548abe1919486bf4a8b",
|
||||
"size": "10324251",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.0",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.0.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.0.tar.gz",
|
||||
"checksum": "SHA-256:919ece2021757686e6892679956dcb8a01c9308a152167d61d9204656b4ed7ee",
|
||||
"size": "10333612",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.1",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.1.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.1.tar.gz",
|
||||
"checksum": "SHA-256:549dbfa0f48f3e519a9efa96d03e8933cc72989c618826b2b570980d9c382979",
|
||||
"size": "10331547",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.2",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.2.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.2.tar.gz",
|
||||
"checksum": "SHA-256:debfdc14df3023045a2297bc99daf7104be75f21572fc5a4f57192ffae4028f0",
|
||||
"size": "10322776",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.3",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.3.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.3.tar.gz",
|
||||
"checksum": "SHA-256:6b9dceb033ccc31f37cebc4f025ddb862cd24a733e7c356ca2fa5719d595af89",
|
||||
"size": "10322145",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.4",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.4.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.4.tar.gz",
|
||||
"checksum": "SHA-256:16a83a3b4409cb55aead6593396979483996080634d214ae07c8a956db2480fb",
|
||||
"size": "10322152",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.5",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.5.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.5.tar.gz",
|
||||
"checksum": "SHA-256:2d45c95f59b4fb9fc7f7bf8caca2dd8c13b4258141c20db6169e0c7faf72e5e4",
|
||||
"size": "7930904",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.6",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.6.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.6.tar.gz",
|
||||
"checksum": "SHA-256:d2d1ef721bbcdc3c680c6f98b4b8ab394478ac0f82d67af2f6c389a4a30789f4",
|
||||
"size": "7962942",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 4-in-1 STM32 Board",
|
||||
"architecture": "STM32F1",
|
||||
"version": "1.1.7",
|
||||
"category": "Contributed",
|
||||
"help": {
|
||||
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
|
||||
},
|
||||
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.7.tar.gz",
|
||||
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.7.tar.gz",
|
||||
"checksum": "SHA-256:37cccde7eafad3d0587d28d13d5f8b2b3244bf7c83e6819b6cb08f4f468815e2",
|
||||
"size": "7966348",
|
||||
"boards": [{
|
||||
"name": "Multi 4-in-1 (STM32F103C)"
|
||||
}],
|
||||
"toolsDependencies": [{
|
||||
"packager": "arduino",
|
||||
"name": "arm-none-eabi-gcc",
|
||||
"version": "4.8.3-2014q1"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "Multi 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,89 +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_CSN_off;
|
||||
SPI_Write(A7105_RST_WRPTR);
|
||||
SPI_Write(0x05);
|
||||
SPI_Write(A7105_05_FIFO_DATA);
|
||||
for (i = 0; i < len; i++)
|
||||
SPI_Write(packet[i]);
|
||||
CS_on;
|
||||
A7105_WriteReg(0x0F, channel);
|
||||
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;
|
||||
SPI_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_CSN_off;
|
||||
SPI_Write(address);
|
||||
NOP();
|
||||
SPI_Write(data);
|
||||
CS_on;
|
||||
A7105_CSN_on;
|
||||
}
|
||||
|
||||
uint8_t A7105_ReadReg(uint8_t address) {
|
||||
uint8_t A7105_ReadReg(uint8_t address)
|
||||
{
|
||||
uint8_t result;
|
||||
CS_off;
|
||||
SPI_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);
|
||||
}
|
||||
|
||||
uint8_t A7105_Read(void)
|
||||
{
|
||||
uint8_t result;
|
||||
uint8_t i;
|
||||
SDI_SET_INPUT;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
result=result<<1;
|
||||
if(SDI_1) ///if SDIO =1
|
||||
result |= 0x01;
|
||||
SCK_on;
|
||||
NOP();
|
||||
SCK_off;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------
|
||||
@@ -102,22 +95,23 @@ uint8_t A7105_Reset()
|
||||
{
|
||||
uint8_t result;
|
||||
|
||||
A7105_WriteReg(0x00, 0x00);
|
||||
delayMicroseconds(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;
|
||||
SPI_Write(0x06);//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
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -151,85 +145,289 @@ static void A7105_SetPower_Value(int power)
|
||||
void A7105_SetPower()
|
||||
{
|
||||
uint8_t power=A7105_BIND_POWER;
|
||||
if(IS_BIND_DONE_on)
|
||||
power=IS_POWER_FLAG_on?A7105_HIGH_POWER:A7105_LOW_POWER;
|
||||
if(IS_BIND_DONE)
|
||||
#ifdef A7105_ENABLE_LOW_POWER
|
||||
power=IS_POWER_FLAG_on?A7105_HIGH_POWER:A7105_LOW_POWER;
|
||||
#else
|
||||
power=A7105_HIGH_POWER;
|
||||
#endif
|
||||
if(IS_RANGE_FLAG_on)
|
||||
power=A7105_RANGE_POWER;
|
||||
A7105_WriteReg(0x28, power);
|
||||
if(prev_power != power)
|
||||
{
|
||||
A7105_WriteReg(A7105_28_TX_TEST, power);
|
||||
prev_power=power;
|
||||
}
|
||||
}
|
||||
|
||||
void A7105_Strobe(uint8_t address) {
|
||||
CS_off;
|
||||
A7105_CSN_off;
|
||||
SPI_Write(address);
|
||||
CS_on;
|
||||
A7105_CSN_on;
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM HUBSAN_A7105_regs[] = {
|
||||
0xFF, 0x63, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x04, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0x62, 0x80, 0xFF, 0xFF, 0x0A, 0xFF, 0xFF, 0x07,
|
||||
0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF
|
||||
};
|
||||
const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x14, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50,
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f,
|
||||
0x13, 0xc3, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00,
|
||||
0x01, 0x0f, 0xff
|
||||
};
|
||||
#define ID_NORMAL 0x55201041
|
||||
#define ID_PLUS 0xAA201041
|
||||
void A7105_Init(uint8_t protocol)
|
||||
// Fine tune A7105 LO base frequency
|
||||
// this is required for some A7105 modules and/or RXs with inaccurate crystal oscillator
|
||||
void A7105_AdjustLOBaseFreq(uint8_t cmd)
|
||||
{
|
||||
void *A7105_Regs;
|
||||
|
||||
if(protocol==INIT_FLYSKY)
|
||||
static int16_t old_offset=2048;
|
||||
int16_t offset=1024;
|
||||
if(cmd==0)
|
||||
{ // Called at init of the A7105
|
||||
old_offset=2048;
|
||||
switch(protocol)
|
||||
{
|
||||
case PROTO_HUBSAN:
|
||||
#ifdef FORCE_HUBSAN_TUNING
|
||||
offset=(int16_t)FORCE_HUBSAN_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_BUGS:
|
||||
#ifdef FORCE_BUGS_TUNING
|
||||
offset=(int16_t)FORCE_BUGS_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_FLYSKY:
|
||||
#ifdef FORCE_FLYSKY_TUNING
|
||||
offset=(int16_t)FORCE_FLYSKY_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_FLYZONE:
|
||||
#ifdef FORCE_FLYZONE_TUNING
|
||||
offset=(int16_t)FORCE_FLYZONE_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_PELIKAN:
|
||||
#ifdef FORCE_PELIKAN_TUNING
|
||||
offset=(int16_t)FORCE_PELIKAN_TUNING;
|
||||
#endif
|
||||
break;
|
||||
case PROTO_AFHDS2A:
|
||||
case PROTO_AFHDS2A_RX:
|
||||
#ifdef FORCE_AFHDS2A_TUNING
|
||||
offset=(int16_t)FORCE_AFHDS2A_TUNING;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(offset==1024) // Use channel 15 as an input
|
||||
offset=convert_channel_16b_nolimit(CH15,-300,300);
|
||||
|
||||
if(old_offset==offset) // offset is the same as before...
|
||||
return;
|
||||
old_offset=offset;
|
||||
|
||||
// LO base frequency = 32e6*(bip+(bfp/(2^16)))
|
||||
uint8_t bip; // LO base frequency integer part
|
||||
uint16_t bfp; // LO base frequency fractional part
|
||||
offset++; // as per datasheet, not sure why recommended, but that's a +1kHz drift only ...
|
||||
offset<<=1;
|
||||
if(offset < 0)
|
||||
{
|
||||
A7105_WriteID(0x5475c52A);//0x2Ac57554
|
||||
A7105_Regs=(void *)FLYSKY_A7105_regs;
|
||||
bip = 0x4a; // 2368 MHz
|
||||
bfp = 0xffff + offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
A7105_WriteID(ID_NORMAL);
|
||||
A7105_Regs=(void *)HUBSAN_A7105_regs;
|
||||
bip = 0x4b; // 2400 MHz (default)
|
||||
bfp = offset;
|
||||
}
|
||||
for (uint8_t i = 0; i < 0x33; i++){
|
||||
if( pgm_read_byte_near((uint16_t)(A7105_Regs)+i) != 0xFF)
|
||||
A7105_WriteReg(i, pgm_read_byte_near((uint16_t)(A7105_Regs)+i));
|
||||
A7105_WriteReg( A7105_11_PLL_III, bip);
|
||||
A7105_WriteReg( A7105_12_PLL_IV, (bfp >> 8) & 0xff);
|
||||
A7105_WriteReg( A7105_13_PLL_V, bfp & 0xff);
|
||||
//debugln("Channel: %d, offset: %d, bip: %2x, bfp: %4x", Channel_data[14], offset, bip, bfp);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) A7105_SetVCOBand(uint8_t vb1, uint8_t vb2)
|
||||
{ // Set calibration band value to best match
|
||||
uint8_t diff1, diff2;
|
||||
|
||||
if (vb1 >= 4)
|
||||
diff1 = vb1 - 4;
|
||||
else
|
||||
diff1 = 4 - vb1;
|
||||
|
||||
if (vb2 >= 4)
|
||||
diff2 = vb2 - 4;
|
||||
else
|
||||
diff2 = 4 - vb2;
|
||||
|
||||
if (diff1 == diff2 || diff1 > diff2)
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I, vb1 | 0x08);
|
||||
else
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I, vb2 | 0x08);
|
||||
}
|
||||
|
||||
#if defined(AFHDS2A_A7105_INO) || defined(AFHDS2A_RX_A7105_INO)
|
||||
const uint8_t PROGMEM AFHDS2A_A7105_regs[] = {
|
||||
0xFF, 0x42 | (1<<5), 0x00, 0x25, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3c, 0x05, 0x00, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x4f, 0x62, 0x80, 0xFF, 0xFF, 0x2a, 0x32, 0xc3, 0x1f, // 10 - 1f
|
||||
0x1e, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef BUGS_A7105_INO
|
||||
const uint8_t PROGMEM BUGS_A7105_regs[] = {
|
||||
0xFF, 0x42, 0x00, 0x15, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0x01, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x40, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, // 10 - 1f
|
||||
0x16, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3b, 0x00, 0x0b, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef FLYSKY_A7105_INO
|
||||
const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x14, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, // 10 - 1f
|
||||
0x13, 0xc3, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef FLYZONE_A7105_INO
|
||||
const uint8_t PROGMEM FLYZONE_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x07, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x01, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x1f, // 10 - 1f
|
||||
0x12, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3a, 0x00, 0x3f, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef HUBSAN_A7105_INO
|
||||
const uint8_t PROGMEM HUBSAN_A7105_regs[] = {
|
||||
0xFF, 0x63, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x04, 0xFF, // 00 - 0f
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0x62, 0x80, 0xFF, 0xFF, 0x0A, 0xFF, 0xFF, 0x07, // 10 - 1f
|
||||
0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 20 - 2f
|
||||
0xFF, 0xFF // 30 - 31
|
||||
};
|
||||
#endif
|
||||
#ifdef PELIKAN_A7105_INO
|
||||
const uint8_t PROGMEM PELIKAN_A7105_regs[] = {
|
||||
0xff, 0x42, 0x00, 0x0F, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x01, 0x50, // 00 - 0f
|
||||
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x07, // 10 - 1f
|
||||
0x16, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x1f, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
|
||||
0x01, 0x0f // 30 - 31
|
||||
};
|
||||
#endif
|
||||
|
||||
#define ID_NORMAL 0x55201041
|
||||
#define ID_PLUS 0xAA201041
|
||||
void A7105_Init(void)
|
||||
{
|
||||
uint8_t *A7105_Regs=0;
|
||||
uint8_t vco_calibration0, vco_calibration1;
|
||||
|
||||
#ifdef FLYZONE_A7105_INO
|
||||
if(protocol==PROTO_FLYZONE)
|
||||
{
|
||||
A7105_Regs=(uint8_t*)FLYZONE_A7105_regs;
|
||||
A7105_WriteID(0x25A53C45);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef PELIKAN_A7105_INO
|
||||
if(protocol==PROTO_PELIKAN)
|
||||
{
|
||||
A7105_Regs=(uint8_t*)PELIKAN_A7105_regs;
|
||||
A7105_WriteID(0x06230623);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef BUGS_A7105_INO
|
||||
if(protocol==PROTO_BUGS)
|
||||
A7105_Regs=(uint8_t*)BUGS_A7105_regs;
|
||||
else
|
||||
#endif
|
||||
#ifdef HUBSAN_A7105_INO
|
||||
if(protocol==PROTO_HUBSAN)
|
||||
{
|
||||
A7105_WriteID(ID_NORMAL);
|
||||
A7105_Regs=(uint8_t*)HUBSAN_A7105_regs;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
A7105_WriteID(0x5475c52A);//0x2Ac57554
|
||||
#ifdef FLYSKY_A7105_INO
|
||||
if(protocol==PROTO_FLYSKY)
|
||||
A7105_Regs=(uint8_t*)FLYSKY_A7105_regs;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if defined(AFHDS2A_A7105_INO) || defined(AFHDS2A_RX_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);
|
||||
|
||||
//Reset VCO Band calibration
|
||||
if(protocol==INIT_FLYSKY)
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I,0x08);
|
||||
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
|
||||
vco_calibration1 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
|
||||
|
||||
if(protocol==PROTO_BUGS)
|
||||
A7105_SetVCOBand(vco_calibration0 & 0x07, vco_calibration1 & 0x07); // Set calibration band value to best match
|
||||
else
|
||||
if(protocol!=PROTO_HUBSAN)
|
||||
{
|
||||
switch(protocol)
|
||||
{
|
||||
case PROTO_FLYSKY:
|
||||
vco_calibration1=0x08;
|
||||
break;
|
||||
case PROTO_FLYZONE:
|
||||
vco_calibration1=0x02;
|
||||
break;
|
||||
case PROTO_PELIKAN:
|
||||
vco_calibration1=0x0C;
|
||||
break;
|
||||
default:
|
||||
vco_calibration1=0x0A;
|
||||
break;
|
||||
}
|
||||
A7105_WriteReg(A7105_25_VCO_SBCAL_I,vco_calibration1); //Reset VCO Band calibration
|
||||
}
|
||||
A7105_SetTxRxMode(TX_EN);
|
||||
A7105_SetPower();
|
||||
|
||||
#ifdef USE_A7105_CH15_TUNING
|
||||
A7105_AdjustLOBaseFreq(0);
|
||||
#endif
|
||||
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
}
|
||||
#endif
|
||||
203
Multiprotocol/AFHDS2A_Rx_a7105.ino
Normal file
203
Multiprotocol/AFHDS2A_Rx_a7105.ino
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(AFHDS2A_RX_A7105_INO)
|
||||
|
||||
#include "iface_a7105.h"
|
||||
|
||||
#define AFHDS2A_RX_TXPACKET_SIZE 38
|
||||
#define AFHDS2A_RX_RXPACKET_SIZE 37
|
||||
#define AFHDS2A_RX_NUMFREQ 16
|
||||
|
||||
enum {
|
||||
AFHDS2A_RX_BIND1,
|
||||
AFHDS2A_RX_BIND2,
|
||||
AFHDS2A_RX_DATA
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) AFHDS2A_Rx_build_telemetry_packet()
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
uint8_t bitsavailable = 0;
|
||||
uint8_t idx = 0;
|
||||
|
||||
packet_in[idx++] = RX_LQI; // 0 - 130
|
||||
packet_in[idx++] = RX_RSSI;
|
||||
packet_in[idx++] = 0; // start channel
|
||||
packet_in[idx++] = 14; // number of channels in packet
|
||||
// pack channels
|
||||
for (uint8_t i = 0; i < 14; i++) {
|
||||
uint32_t val = packet[9+i*2] | (packet[10+i*2] << 8);
|
||||
if (val < 860)
|
||||
val = 860;
|
||||
// convert ppm (860-2140) to Multi (0-2047)
|
||||
val = min(((val-860)<<3)/5, 2047);
|
||||
|
||||
bits |= val << bitsavailable;
|
||||
bitsavailable += 11;
|
||||
while (bitsavailable >= 8) {
|
||||
packet_in[idx++] = bits & 0xff;
|
||||
bits >>= 8;
|
||||
bitsavailable -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) AFHDS2A_Rx_data_ready()
|
||||
{
|
||||
// check if FECF+CRCF Ok
|
||||
return !(A7105_ReadReg(A7105_00_MODE) & (1 << 5 | 1 << 6 | 1 << 0));
|
||||
}
|
||||
|
||||
uint16_t initAFHDS2A_Rx()
|
||||
{
|
||||
uint8_t i;
|
||||
A7105_Init();
|
||||
hopping_frequency_no = 0;
|
||||
packet_count = 0;
|
||||
rx_data_started = false;
|
||||
rx_disable_lna = IS_POWER_FLAG_on;
|
||||
A7105_SetTxRxMode(rx_disable_lna ? TXRX_OFF : RX_EN);
|
||||
A7105_Strobe(A7105_RX);
|
||||
|
||||
if (IS_BIND_IN_PROGRESS) {
|
||||
phase = AFHDS2A_RX_BIND1;
|
||||
}
|
||||
else {
|
||||
uint16_t temp = AFHDS2A_RX_EEPROM_OFFSET;
|
||||
for (i = 0; i < 4; i++)
|
||||
rx_id[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
for (i = 0; i < AFHDS2A_RX_NUMFREQ; i++)
|
||||
hopping_frequency[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
phase = AFHDS2A_RX_DATA;
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
#define AFHDS2A_RX_WAIT_WRITE 0x80
|
||||
|
||||
uint16_t AFHDS2A_Rx_callback()
|
||||
{
|
||||
static uint32_t pps_timer = 0;
|
||||
static uint16_t pps_counter = 0;
|
||||
static int8_t read_retry;
|
||||
int16_t temp;
|
||||
uint8_t i;
|
||||
|
||||
#ifndef FORCE_AFHDS2A_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
if (rx_disable_lna != IS_POWER_FLAG_on) {
|
||||
rx_disable_lna = IS_POWER_FLAG_on;
|
||||
A7105_SetTxRxMode(rx_disable_lna ? TXRX_OFF : RX_EN);
|
||||
}
|
||||
|
||||
switch(phase) {
|
||||
case AFHDS2A_RX_BIND1:
|
||||
if (AFHDS2A_Rx_data_ready()) {
|
||||
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
|
||||
if ((packet[0] == 0xbb && packet[9] == 0x01) || (packet[0] == 0xbc && packet[9] <= 0x02)) {
|
||||
memcpy(rx_id, &packet[1], 4); // TX id actually
|
||||
memcpy(hopping_frequency, &packet[11], AFHDS2A_RX_NUMFREQ);
|
||||
phase = AFHDS2A_RX_BIND2;
|
||||
}
|
||||
}
|
||||
A7105_WriteReg(A7105_0F_PLL_I, (packet_count++ & 1) ? 0x0D : 0x8C); // bind channels
|
||||
A7105_SetTxRxMode(RX_EN);
|
||||
A7105_Strobe(A7105_RX);
|
||||
return 10000;
|
||||
|
||||
case AFHDS2A_RX_BIND2:
|
||||
// got 2nd bind packet from tx ?
|
||||
if (AFHDS2A_Rx_data_ready()) {
|
||||
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
|
||||
if ((packet[0] == 0xBC && packet[9] == 0x02 && packet[10] == 0x00) &&
|
||||
(memcmp(rx_id, &packet[1], 4) == 0) &&
|
||||
(memcmp(rx_tx_addr, &packet[5], 4) == 0)) {
|
||||
// save tx info to eeprom
|
||||
temp = AFHDS2A_RX_EEPROM_OFFSET;
|
||||
for (i = 0; i < 4; i++)
|
||||
eeprom_write_byte((EE_ADDR)temp++, rx_id[i]);
|
||||
for (i = 0; i < AFHDS2A_RX_NUMFREQ; i++)
|
||||
eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[i]);
|
||||
BIND_DONE;
|
||||
phase = AFHDS2A_RX_DATA;
|
||||
return 3850;
|
||||
}
|
||||
}
|
||||
|
||||
// transmit response packet
|
||||
packet[0] = 0xBC;
|
||||
memcpy(&packet[1], rx_id, 4);
|
||||
memcpy(&packet[5], rx_tx_addr, 4);
|
||||
packet[9] = 0x01;
|
||||
packet[10] = 0x00;
|
||||
memset(&packet[11], 0xFF, 26);
|
||||
A7105_WriteData(AFHDS2A_RX_RXPACKET_SIZE, packet_count++ & 1 ? 0x0D : 0x8C);
|
||||
phase |= AFHDS2A_RX_WAIT_WRITE;
|
||||
return 1700;
|
||||
|
||||
case AFHDS2A_RX_BIND2 | AFHDS2A_RX_WAIT_WRITE:
|
||||
//Wait for TX completion
|
||||
pps_timer = micros();
|
||||
while (micros() - pps_timer < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
|
||||
if (!(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_Strobe(A7105_RX);
|
||||
phase &= ~AFHDS2A_RX_WAIT_WRITE;
|
||||
return 10000;
|
||||
|
||||
case AFHDS2A_RX_DATA:
|
||||
if (AFHDS2A_Rx_data_ready()) {
|
||||
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
|
||||
if (memcmp(&packet[1], rx_id, 4) == 0 && memcmp(&packet[5], rx_tx_addr, 4) == 0) {
|
||||
if (packet[0] == 0x58 && packet[37] == 0x00 && telemetry_link == 0) { // standard packet, send channels to TX
|
||||
int rssi = min(A7105_ReadReg(A7105_1D_RSSI_THOLD),160);
|
||||
RX_RSSI = map16b(rssi, 160, 8, 0, 128);
|
||||
AFHDS2A_Rx_build_telemetry_packet();
|
||||
telemetry_link = 1;
|
||||
}
|
||||
rx_data_started = true;
|
||||
read_retry = 10; // hop to next channel
|
||||
pps_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
// packets per second
|
||||
if (millis() - pps_timer >= 1000) {
|
||||
pps_timer = millis();
|
||||
debugln("%d pps", pps_counter);
|
||||
RX_LQI = pps_counter / 2;
|
||||
pps_counter = 0;
|
||||
}
|
||||
|
||||
// frequency hopping
|
||||
if (read_retry++ >= 10) {
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no >= AFHDS2A_RX_NUMFREQ)
|
||||
hopping_frequency_no = 0;
|
||||
A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no]);
|
||||
A7105_Strobe(A7105_RX);
|
||||
if (rx_data_started)
|
||||
read_retry = 0;
|
||||
else
|
||||
read_retry = -127; // retry longer until first packet is catched
|
||||
}
|
||||
return 385;
|
||||
}
|
||||
return 3850; // never reached
|
||||
}
|
||||
|
||||
#endif
|
||||
421
Multiprotocol/AFHDS2A_a7105.ino
Normal file
421
Multiprotocol/AFHDS2A_a7105.ino
Normal file
@@ -0,0 +1,421 @@
|
||||
/*
|
||||
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()
|
||||
{
|
||||
if(packet[0]==0xAA && packet[9]==0xFD)
|
||||
return; // ignore packets which contain the RX configuration: FD FF 32 00 01 00 FF FF FF 05 DC 05 DE FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
// Read TX RSSI
|
||||
int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less
|
||||
if(temp<0) temp=0;
|
||||
else if(temp>255) temp=255;
|
||||
TX_RSSI=temp;
|
||||
// AA | TXID | rx_id | sensor id | sensor # | value 16 bit big endian | sensor id ......
|
||||
// AC | TXID | rx_id | sensor id | sensor # | length | bytes | sensor id ......
|
||||
#ifdef AFHDS2A_FW_TELEMETRY
|
||||
if (option & 0x80)
|
||||
{// forward 0xAA and 0xAC telemetry to TX, skip rx and tx id to save space
|
||||
packet_in[0]= TX_RSSI;
|
||||
debug("T(%02X)=",packet[0]);
|
||||
for(uint8_t i=9;i < AFHDS2A_RXPACKET_SIZE; i++)
|
||||
{
|
||||
packet_in[i-8]=packet[i];
|
||||
debug(" %02X",packet[i]);
|
||||
}
|
||||
packet_in[29]=packet[0]; // 0xAA Normal telemetry, 0xAC Extended telemetry
|
||||
telemetry_link=2;
|
||||
debugln("");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef AFHDS2A_HUB_TELEMETRY
|
||||
if(packet[0]==0xAA)
|
||||
{ // 0xAA Normal telemetry, 0xAC Extended telemetry not decoded here
|
||||
for(uint8_t sensor=0; sensor<7; sensor++)
|
||||
{
|
||||
// Send FrSkyD telemetry to TX
|
||||
uint8_t index = 9+(4*sensor);
|
||||
switch(packet[index])
|
||||
{
|
||||
case AFHDS2A_SENSOR_RX_VOLTAGE:
|
||||
//v_lipo1 = packet[index+3]<<8 | packet[index+2];
|
||||
v_lipo1 = packet[index+2];
|
||||
telemetry_link=1;
|
||||
break;
|
||||
case AFHDS2A_SENSOR_A3_VOLTAGE:
|
||||
v_lipo2 = (packet[index+3]<<5) | (packet[index+2]>>3); // allows to read voltage up to 4S
|
||||
telemetry_link=1;
|
||||
break;
|
||||
case AFHDS2A_SENSOR_RX_ERR_RATE:
|
||||
if(packet[index+2]<=100)
|
||||
RX_LQI=packet[index+2];
|
||||
break;
|
||||
case AFHDS2A_SENSOR_RX_RSSI:
|
||||
RX_RSSI = -packet[index+2];
|
||||
break;
|
||||
case 0xff: // end of data
|
||||
return;
|
||||
/*default:
|
||||
// unknown sensor ID
|
||||
break;*/
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void AFHDS2A_build_bind_packet()
|
||||
{
|
||||
uint8_t ch;
|
||||
memcpy( &packet[1], rx_tx_addr, 4);
|
||||
memset( &packet[5], 0xff, 4);
|
||||
packet[10]= 0x00;
|
||||
for(ch=0; ch<AFHDS2A_NUMFREQ; ch++)
|
||||
packet[11+ch] = hopping_frequency[ch];
|
||||
memset( &packet[27], 0xff, 10);
|
||||
packet[37] = 0x00;
|
||||
switch(phase)
|
||||
{
|
||||
case AFHDS2A_BIND1:
|
||||
packet[0] = 0xbb;
|
||||
packet[9] = 0x01;
|
||||
break;
|
||||
case AFHDS2A_BIND2:
|
||||
case AFHDS2A_BIND3:
|
||||
case AFHDS2A_BIND4:
|
||||
packet[0] = 0xbc;
|
||||
if(phase == AFHDS2A_BIND4)
|
||||
{
|
||||
memcpy( &packet[5], &rx_id, 4);
|
||||
memset( &packet[11], 0xff, 16);
|
||||
}
|
||||
packet[9] = phase-1;
|
||||
if(packet[9] > 0x02)
|
||||
packet[9] = 0x02;
|
||||
packet[27]= 0x01;
|
||||
packet[28]= 0x80;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void AFHDS2A_build_packet(uint8_t type)
|
||||
{
|
||||
uint16_t val;
|
||||
memcpy( &packet[1], rx_tx_addr, 4);
|
||||
memcpy( &packet[5], rx_id, 4);
|
||||
switch(type)
|
||||
{
|
||||
case AFHDS2A_PACKET_STICKS:
|
||||
packet[0] = 0x58;
|
||||
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 addr;
|
||||
if(RX_num<16)
|
||||
addr=AFHDS2A_EEPROM_OFFSET+RX_num*4;
|
||||
else
|
||||
addr=AFHDS2A_EEPROM_OFFSET2+(RX_num-16)*4;
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
{
|
||||
rx_id[i] = packet[5+i];
|
||||
eeprom_write_byte((EE_ADDR)(addr+i),rx_id[i]);
|
||||
}
|
||||
phase = AFHDS2A_BIND4;
|
||||
packet_count++;
|
||||
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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(3850);
|
||||
#endif
|
||||
AFHDS2A_build_packet(packet_type);
|
||||
if((A7105_ReadReg(A7105_00_MODE) & 0x01)) // Check if something has been received...
|
||||
data_rx=0;
|
||||
else
|
||||
data_rx=1; // Yes
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, hopping_frequency[hopping_frequency_no++]);
|
||||
if(hopping_frequency_no >= AFHDS2A_NUMFREQ)
|
||||
hopping_frequency_no = 0;
|
||||
if(!(packet_counter % 1313))
|
||||
packet_type = AFHDS2A_PACKET_SETTINGS;
|
||||
else
|
||||
{
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(!(packet_counter % 1569) && IS_FAILSAFE_VALUES_on)
|
||||
{
|
||||
packet_type = AFHDS2A_PACKET_FAILSAFE;
|
||||
FAILSAFE_VALUES_off;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
packet_type = AFHDS2A_PACKET_STICKS; // todo : check for settings changes
|
||||
}
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5 | 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))
|
||||
{ // TX address validated
|
||||
#ifdef AFHDS2A_LQI_CH
|
||||
if(packet[0]==0xAA && packet[9]!=0xFD)
|
||||
{// Normal telemetry packet
|
||||
for(uint8_t sensor=0; sensor<7; sensor++)
|
||||
{//read LQI value for RX output
|
||||
uint8_t index = 9+(4*sensor);
|
||||
if(packet[index]==AFHDS2A_SENSOR_RX_ERR_RATE && packet[index+2]<=100)
|
||||
{
|
||||
RX_LQI=packet[index+2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#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 addr;
|
||||
if(RX_num<16)
|
||||
addr=AFHDS2A_EEPROM_OFFSET+RX_num*4;
|
||||
else
|
||||
addr=AFHDS2A_EEPROM_OFFSET2+(RX_num-16)*4;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
rx_id[i]=eeprom_read_byte((EE_ADDR)(addr+i));
|
||||
}
|
||||
hopping_frequency_no = 0;
|
||||
return 50000;
|
||||
}
|
||||
#endif
|
||||
185
Multiprotocol/ASSAN_nrf24l01.ino
Normal file
185
Multiprotocol/ASSAN_nrf24l01.ino
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(12000);
|
||||
#endif
|
||||
case ASSAN_DATA3:
|
||||
ASSAN_send_packet();
|
||||
phase++; // DATA 3 or 4
|
||||
return 5000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ASSAN_initialize_txid()
|
||||
{
|
||||
/* //Renaud TXID with Freq=36 and alternate Freq 67 or 68 or 69 or 70 or 71 or 73 or 74 or 75 or 78 and may be more...
|
||||
packet[23]=0x22;
|
||||
packet[22]=0x37;
|
||||
packet[21]=0xFA;
|
||||
packet[20]=0x53; */
|
||||
// Using packet[20..23] to store the ID1 and packet[24..27] to store the ID2
|
||||
uint8_t freq=0,freq2;
|
||||
for(uint8_t i=0;i<ASSAN_ADDRESS_LENGTH;i++)
|
||||
{
|
||||
uint8_t temp=rx_tx_addr[i];
|
||||
packet[i+20]=temp;
|
||||
packet[i+24]=temp+1;
|
||||
freq+=temp;
|
||||
}
|
||||
|
||||
// Main frequency
|
||||
freq=((freq%25)+2)<<1;
|
||||
if(freq&0x02) freq|=0x01;
|
||||
hopping_frequency[0]=freq;
|
||||
// Alternate frequency has some random
|
||||
do
|
||||
{
|
||||
freq2=random(0xfefefefe)%9;
|
||||
freq2+=freq*2-5;
|
||||
}
|
||||
while( (freq2>118) || (freq2<freq+1) || (freq2==2*freq) );
|
||||
hopping_frequency[1]=freq2;
|
||||
}
|
||||
|
||||
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&0x0F)*2;
|
||||
uint8_t rxid_high = eeprom_read_byte((EE_ADDR)(base_adr+0));
|
||||
uint8_t rxid_low = eeprom_read_byte((EE_ADDR)(base_adr+1));
|
||||
|
||||
if(rxid_high==0x00 || rxid_high==0xFF)
|
||||
rx_tx_addr[0]=0x52;
|
||||
else
|
||||
rx_tx_addr[0]=rxid_high;
|
||||
|
||||
rx_tx_addr[1]=BUGSMINI_txhash;
|
||||
|
||||
if(rxid_low==0x00 || rxid_low==0xFF)
|
||||
rx_tx_addr[2]=0x66;
|
||||
else
|
||||
rx_tx_addr[2]=rxid_low;
|
||||
|
||||
for(uint8_t end_idx=0;end_idx<23;end_idx++)
|
||||
{
|
||||
//calculate sequence start
|
||||
if(end_idx<=7)
|
||||
start=end_idx;
|
||||
else
|
||||
start=(end_idx-7)*16+7;
|
||||
//calculate sequence length
|
||||
if(end_idx>6)
|
||||
{
|
||||
if(end_idx>15)
|
||||
length=(23-end_idx)<<1;
|
||||
else
|
||||
length=16;
|
||||
}
|
||||
else
|
||||
length=(end_idx+1)<<1;
|
||||
//calculate first index
|
||||
index=start-rxid_high;
|
||||
//scan for a possible match using the current end
|
||||
for(uint8_t i=0;i<length;i++)
|
||||
{
|
||||
if(index==rxid_low)
|
||||
{ //match found
|
||||
rx_tx_addr[3]=pgm_read_byte_near( &BUGSMINI_end[end_idx<<1] );
|
||||
rx_tx_addr[4]=pgm_read_byte_near( &BUGSMINI_end[(end_idx<<1)+1] );
|
||||
return;
|
||||
}
|
||||
index+=i&1?7:8; //increment index
|
||||
}
|
||||
}
|
||||
// Something wrong happened if we arrive here....
|
||||
}
|
||||
|
||||
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&0x0F)*2;
|
||||
eeprom_write_byte((EE_ADDR)(base_adr+0),packet[1]); // Save rxid in EEPROM
|
||||
eeprom_write_byte((EE_ADDR)(base_adr+1),packet[2]); // Save rxid in EEPROM
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(BUGSMINI_PACKET_INTERVAL);
|
||||
#endif
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready => read only 12 bytes to not overwrite channel change flag
|
||||
XN297_ReadPayload(packet, 12);
|
||||
BUGSMINI_update_telemetry();
|
||||
}
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
BUGSMINI_send_packet(0);
|
||||
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;
|
||||
return BUGSMINI_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
207
Multiprotocol/Bayang_Rx_nrf24l01.ino
Normal file
207
Multiprotocol/Bayang_Rx_nrf24l01.ino
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(BAYANG_RX_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define BAYANG_RX_PACKET_SIZE 15
|
||||
#define BAYANG_RX_RF_NUM_CHANNELS 4
|
||||
#define BAYANG_RX_RF_BIND_CHANNEL 0
|
||||
#define BAYANG_RX_ADDRESS_LENGTH 5
|
||||
|
||||
enum {
|
||||
BAYANG_RX_BIND = 0,
|
||||
BAYANG_RX_DATA
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) Bayang_Rx_init_nrf24l01()
|
||||
{
|
||||
const uint8_t bind_address[BAYANG_RX_ADDRESS_LENGTH] = { 0,0,0,0,0 };
|
||||
NRF24L01_Initialize();
|
||||
XN297_SetTXAddr(bind_address, BAYANG_RX_ADDRESS_LENGTH);
|
||||
XN297_SetRXAddr(bind_address, BAYANG_RX_ADDRESS_LENGTH);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, BAYANG_RX_PACKET_SIZE + 2); // 2 extra bytes for xn297 crc
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, BAYANG_RX_RF_BIND_CHANNEL);
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
|
||||
NRF24L01_Activate(0x73);
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_SetTxRxMode(RX_EN);
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) Bayang_Rx_check_validity() {
|
||||
uint8_t sum = packet[0];
|
||||
for (uint8_t i = 1; i < BAYANG_RX_PACKET_SIZE - 1; i++)
|
||||
sum += packet[i];
|
||||
return sum == packet[14];
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) Bayang_Rx_build_telemetry_packet()
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
uint8_t bitsavailable = 0;
|
||||
uint8_t idx = 0;
|
||||
|
||||
packet_in[idx++] = RX_LQI;
|
||||
packet_in[idx++] = RX_LQI>>1; // no RSSI: 125..0
|
||||
packet_in[idx++] = 0; // start channel
|
||||
packet_in[idx++] = 10; // number of channels in packet
|
||||
|
||||
// convert & pack channels
|
||||
for (uint8_t i = 0; i < packet_in[3]; i++) {
|
||||
uint32_t val = CHANNEL_MIN_100;
|
||||
if (i < 4) {
|
||||
// AETR
|
||||
//val = (((packet[4 + i * 2] & ~0x7C) << 8) | packet[5 + i * 2]) << 1;
|
||||
val=packet[4 + i * 2]&0x03;
|
||||
val=(val<<8)+packet[5 + i * 2];
|
||||
val=((val+128)<<3)/5;
|
||||
} else if (i == 4 || i == 5) {
|
||||
val=packet[i==4?1:13];
|
||||
val=((val+32)<<5)/5; // extra analog channel
|
||||
} else if (((i == 6) && (packet[2] & 0x08)) || // flip
|
||||
((i == 7) && (packet[2] & 0x01)) || // rth
|
||||
((i == 8) && (packet[2] & 0x20)) || // picture
|
||||
((i == 9) && (packet[2] & 0x10))) { // video
|
||||
// set channel to 100% if feature is enabled
|
||||
val = CHANNEL_MAX_100;
|
||||
}
|
||||
bits |= val << bitsavailable;
|
||||
bitsavailable += 11;
|
||||
while (bitsavailable >= 8) {
|
||||
packet_in[idx++] = bits & 0xff;
|
||||
bits >>= 8;
|
||||
bitsavailable -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initBayang_Rx()
|
||||
{
|
||||
uint8_t i;
|
||||
Bayang_Rx_init_nrf24l01();
|
||||
hopping_frequency_no = 0;
|
||||
rx_data_started = false;
|
||||
rx_data_received = false;
|
||||
|
||||
if (IS_BIND_IN_PROGRESS) {
|
||||
phase = BAYANG_RX_BIND;
|
||||
}
|
||||
else {
|
||||
uint16_t temp = BAYANG_RX_EEPROM_OFFSET;
|
||||
for (i = 0; i < 5; i++)
|
||||
rx_tx_addr[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
for (i = 0; i < BAYANG_RX_RF_NUM_CHANNELS; i++)
|
||||
hopping_frequency[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
XN297_SetTXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
|
||||
XN297_SetRXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
|
||||
phase = BAYANG_RX_DATA;
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
uint16_t Bayang_Rx_callback()
|
||||
{
|
||||
uint8_t i;
|
||||
static int8_t read_retry;
|
||||
static uint16_t pps_counter;
|
||||
static uint32_t pps_timer = 0;
|
||||
|
||||
switch (phase) {
|
||||
case BAYANG_RX_BIND:
|
||||
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) {
|
||||
// data received from TX
|
||||
if (XN297_ReadPayload(packet, BAYANG_RX_PACKET_SIZE) && ( packet[0] == 0xA4 || packet[0] == 0xA2 ) && Bayang_Rx_check_validity()) {
|
||||
// store tx info into eeprom
|
||||
uint16_t temp = BAYANG_RX_EEPROM_OFFSET;
|
||||
for (i = 0; i < 5; i++) {
|
||||
rx_tx_addr[i] = packet[i + 1];
|
||||
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[i]);
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
hopping_frequency[i] = packet[i + 6];
|
||||
eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[i]);
|
||||
}
|
||||
XN297_SetTXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
|
||||
XN297_SetRXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
|
||||
BIND_DONE;
|
||||
phase = BAYANG_RX_DATA;
|
||||
}
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
}
|
||||
break;
|
||||
case BAYANG_RX_DATA:
|
||||
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) {
|
||||
if (XN297_ReadPayload(packet, BAYANG_RX_PACKET_SIZE) && packet[0] == 0xA5 && Bayang_Rx_check_validity()) {
|
||||
if (telemetry_link == 0) {
|
||||
Bayang_Rx_build_telemetry_packet();
|
||||
telemetry_link = 1;
|
||||
}
|
||||
rx_data_started = true;
|
||||
rx_data_received = true;
|
||||
read_retry = 8;
|
||||
pps_counter++;
|
||||
}
|
||||
}
|
||||
// packets per second
|
||||
if (millis() - pps_timer >= 1000) {
|
||||
pps_timer = millis();
|
||||
debugln("%d pps", pps_counter);
|
||||
RX_LQI = pps_counter >> 1;
|
||||
pps_counter = 0;
|
||||
}
|
||||
// frequency hopping
|
||||
if (read_retry++ >= 8) {
|
||||
hopping_frequency_no++;
|
||||
if (hopping_frequency_no >= BAYANG_RX_RF_NUM_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
if (rx_data_started)
|
||||
{
|
||||
if(rx_data_received)
|
||||
{ // In sync
|
||||
rx_data_received = false;
|
||||
read_retry = 5;
|
||||
return 1500;
|
||||
}
|
||||
else
|
||||
{ // packet lost
|
||||
read_retry = 0;
|
||||
if(RX_LQI==0) // communication lost
|
||||
rx_data_started=false;
|
||||
}
|
||||
}
|
||||
else
|
||||
read_retry = -16; // retry longer until first packet is caught
|
||||
}
|
||||
return 250;
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -20,22 +20,30 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
#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,
|
||||
BAYANG_FLAG_VIDEO = 0x10,
|
||||
BAYANG_FLAG_PICTURE = 0x20,
|
||||
// flags going to packet[3]
|
||||
BAYANG_FLAG_INVERTED = 0x80 // inverted flight on Floureon H101
|
||||
// flags going to packet[2]
|
||||
BAYANG_FLAG_RTH = 0x01,
|
||||
BAYANG_FLAG_HEADLESS = 0x02,
|
||||
BAYANG_FLAG_FLIP = 0x08,
|
||||
BAYANG_FLAG_VIDEO = 0x10,
|
||||
BAYANG_FLAG_PICTURE = 0x20,
|
||||
// flags going to packet[3]
|
||||
BAYANG_FLAG_INVERTED = 0x80, // inverted flight on Floureon H101
|
||||
BAYANG_FLAG_TAKE_OFF = 0x20, // take off / landing on X16 AH
|
||||
BAYANG_FLAG_EMG_STOP = 0x04|0x08, // 0x08 for VISUO XS809H-W-HD-G
|
||||
};
|
||||
|
||||
enum BAYANG_OPTION_FLAGS {
|
||||
BAYANG_OPTION_FLAG_TELEMETRY = 0x01,
|
||||
BAYANG_OPTION_FLAG_ANALOGAUX = 0x02,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
|
||||
@@ -43,44 +51,99 @@ 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]; // txid[0]
|
||||
packet[11] = rx_tx_addr[1]; // txid[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]
|
||||
packet[2] = 0x00;
|
||||
if(Servo_AUX1)
|
||||
if(CH5_SW)
|
||||
packet[2] = BAYANG_FLAG_FLIP;
|
||||
if(Servo_AUX2)
|
||||
if(CH6_SW)
|
||||
packet[2] |= BAYANG_FLAG_RTH;
|
||||
if(Servo_AUX3)
|
||||
if(CH7_SW)
|
||||
packet[2] |= BAYANG_FLAG_PICTURE;
|
||||
if(Servo_AUX4)
|
||||
if(CH8_SW)
|
||||
packet[2] |= BAYANG_FLAG_VIDEO;
|
||||
if(Servo_AUX5)
|
||||
if(CH9_SW)
|
||||
{
|
||||
packet[2] |= BAYANG_FLAG_HEADLESS;
|
||||
dyntrim = 0;
|
||||
}
|
||||
//Flags packet[3]
|
||||
packet[3] = 0x00;
|
||||
if(Servo_AUX6)
|
||||
if(CH10_SW)
|
||||
packet[3] = BAYANG_FLAG_INVERTED;
|
||||
|
||||
if(CH11_SW)
|
||||
dyntrim = 0;
|
||||
if(CH12_SW)
|
||||
packet[3] |= BAYANG_FLAG_TAKE_OFF;
|
||||
if(CH13_SW)
|
||||
packet[3] |= BAYANG_FLAG_EMG_STOP;
|
||||
//Aileron
|
||||
val = convert_channel_10b(AILERON);
|
||||
packet[4] = (val>>8) + ((val>>2) & 0xFC);
|
||||
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);
|
||||
@@ -88,30 +151,100 @@ static void __attribute__((unused)) 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]; // txid[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));
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? BAYANG_RF_BIND_CHANNEL: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
|
||||
}
|
||||
|
||||
#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();
|
||||
@@ -121,27 +254,80 @@ static void __attribute__((unused)) BAYANG_init()
|
||||
|
||||
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();
|
||||
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);
|
||||
|
||||
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()
|
||||
{
|
||||
if(IS_BIND_DONE_on)
|
||||
BAYANG_send_packet(0);
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
if(packet_count==0)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync((option & BAYANG_OPTION_FLAG_TELEMETRY)?5*BAYANG_PACKET_PERIOD:2*BAYANG_PACKET_PERIOD);
|
||||
#endif
|
||||
BAYANG_send_packet(0);
|
||||
}
|
||||
packet_count++;
|
||||
#ifdef BAYANG_HUB_TELEMETRY
|
||||
if (option & BAYANG_OPTION_FLAG_TELEMETRY)
|
||||
{ // telemetry is enabled
|
||||
state++;
|
||||
if (state > 1000)
|
||||
{
|
||||
//calculate telemetry reception packet rate - packets per 1000ms
|
||||
TX_RSSI = telemetry_counter;
|
||||
telemetry_counter = 0;
|
||||
state = 0;
|
||||
telemetry_lost=0;
|
||||
}
|
||||
|
||||
if (packet_count > 1)
|
||||
BAYANG_check_rx();
|
||||
|
||||
packet_count %= 5;
|
||||
}
|
||||
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
|
||||
{
|
||||
BAYANG_send_packet(1);
|
||||
if(packet_count==0)
|
||||
BAYANG_send_packet(1);
|
||||
packet_count++;
|
||||
packet_count%=4;
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
@@ -151,8 +337,11 @@ uint16_t BAYANG_callback()
|
||||
static void __attribute__((unused)) BAYANG_initialize_txid()
|
||||
{
|
||||
//Could be using txid[0..2] but using rx_tx_addr everywhere instead...
|
||||
hopping_frequency[0]=0;
|
||||
hopping_frequency[1]=(rx_tx_addr[0]&0x1F)+0x10;
|
||||
if(sub_protocol==DHD_D4)
|
||||
hopping_frequency[0]=(rx_tx_addr[2]&0x07)|0x01;
|
||||
else
|
||||
hopping_frequency[0]=0;
|
||||
hopping_frequency[1]=(rx_tx_addr[3]&0x1F)+0x10;
|
||||
hopping_frequency[2]=hopping_frequency[1]+0x20;
|
||||
hopping_frequency[3]=hopping_frequency[2]+0x20;
|
||||
hopping_frequency_no=0;
|
||||
@@ -164,7 +353,8 @@ uint16_t initBAYANG(void)
|
||||
bind_counter = BAYANG_BIND_COUNT;
|
||||
BAYANG_initialize_txid();
|
||||
BAYANG_init();
|
||||
packet_count=0;
|
||||
return BAYANG_INITIAL_WAIT+BAYANG_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
184
Multiprotocol/Binary_Signature.ino
Normal file
184
Multiprotocol/Binary_Signature.ino
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/************************/
|
||||
/** Firmware Signature **/
|
||||
/************************/
|
||||
|
||||
/*
|
||||
The firmware signature is appended to the compiled binary image in order to provide information
|
||||
about the options used to compile the firmware file. This information is then used by Multi-module
|
||||
flashing tools to verify that the image is correct / valid.
|
||||
|
||||
In order for the build process to determine the options used to build the firmware this file conditionally
|
||||
declares 'flag' variables for the options we are interested in.
|
||||
|
||||
When the pre-compiler parses the source code these variables are either present or not in the parsed cpp file,
|
||||
typically '$build_dir$/preproc/ctags_target_for_gcc_minus_e.cpp'.
|
||||
|
||||
Once the .bin file is created an additional command-line build tool scans the parsed cpp file, detects the
|
||||
flags, assembles the signature, and finally appends the signature to the end of the binary file.
|
||||
|
||||
The signature is 24 bytes long:
|
||||
multi-x[8-byte hex code]-[8-byte version number]
|
||||
|
||||
For example:
|
||||
multi-x1234abcd-01020199
|
||||
|
||||
The 8-byte hex code is a 32-bit bitmask value indicating the configuration options, currently:
|
||||
|
||||
Bit(s) Bitmask Option Comment
|
||||
1-2 0x3 Module type Read as a two-bit value indicating a number from 0-3 which maps to a module type (AVR, STM32, OrangeRX)
|
||||
3-7 0x7C Channel order Read as a five-bit value indicating a number from 0-23 which maps to as channel order (AETR, TAER, RETA, etc) (right-shift two bits to read)
|
||||
8 0x80 Bootloader support Indicates whether or not the firmware was built with support for the bootloader
|
||||
9 0x100 CHECK_FOR_BOOTLOADER Indicates if CHECK_FOR_BOOTLOADER is defined
|
||||
10 0x200 INVERT_TELEMETRY Indicates if INVERT_TELEMETRY is defined
|
||||
11 0x400 MULTI_STATUS Indicates if MULTI_STATUS is defined
|
||||
12 0x800 MULTI_TELEMETRY Indicates if MULTI_TELEMETRY is defined
|
||||
13 0x1000 DEBUG_SERIAL Indicates if DEBUG_SERIAL is defined
|
||||
|
||||
The 8-byte version number is the version number zero-padded to a fixed width of two-bytes per segment and no separator.
|
||||
E.g. 1.2.3.45 becomes 01020345.
|
||||
|
||||
Multi Telemetery Type can be read from bits 11 and 12 using the bitmask 0xC00 and right-shifting ten bits:
|
||||
Telemetry Type Decimal Value Binary Value
|
||||
Undefined 0 00
|
||||
erSkyTX 1 01
|
||||
OpenTX 2 10
|
||||
|
||||
Module types are mapped to the following decimal / binary values:
|
||||
Module Type Decimal Value Binary Valsue
|
||||
AVR 0 00
|
||||
STM32 1 01
|
||||
OrangeRX 2 10
|
||||
|
||||
Channel orders are mapped to the following decimal / binary values:
|
||||
Channel Order Decimal Value Binary Value
|
||||
AETR 0 00000
|
||||
AERT 1 00001
|
||||
ARET 2 00010
|
||||
ARTE 3 00011
|
||||
ATRE 4 00100
|
||||
ATER 5 00101
|
||||
EATR 6 00110
|
||||
EART 7 00111
|
||||
ERAT 8 01000
|
||||
ERTA 9 01001
|
||||
ETRA 10 01010
|
||||
ETAR 11 01011
|
||||
TEAR 12 01100
|
||||
TERA 13 01101
|
||||
TREA 14 01110
|
||||
TRAE 15 01111
|
||||
TARE 16 10000
|
||||
TAER 17 10001
|
||||
RETA 18 10010
|
||||
REAT 19 10011
|
||||
RAET 20 10100
|
||||
RATE 21 10101
|
||||
RTAE 22 10110
|
||||
RTEA 23 10111
|
||||
*/
|
||||
|
||||
// Set the flags for detecting and writing the firmware signature
|
||||
#if defined (CHECK_FOR_BOOTLOADER)
|
||||
bool firmwareFlag_CHECK_FOR_BOOTLOADER = true;
|
||||
#endif
|
||||
#if defined (INVERT_TELEMETRY)
|
||||
bool firmwareFlag_INVERT_TELEMETRY = true;
|
||||
#endif
|
||||
#if defined (MULTI_STATUS)
|
||||
bool firmwareFlag_MULTI_STATUS = true;
|
||||
#endif
|
||||
#if defined (MULTI_TELEMETRY)
|
||||
bool firmwareFlag_MULTI_TELEMETRY = true;
|
||||
#endif
|
||||
#if defined (DEBUG_SERIAL)
|
||||
bool firmwareFlag_DEBUG_SERIAL = true;
|
||||
#endif
|
||||
|
||||
// Channel order flags
|
||||
#if defined (AETR)
|
||||
bool firmwareFlag_ChannelOrder_AETR = true;
|
||||
#endif
|
||||
#if defined (AERT)
|
||||
bool firmwareFlag_ChannelOrder_AERT = true;
|
||||
#endif
|
||||
#if defined (ARET)
|
||||
bool firmwareFlag_ChannelOrder_ARET = true;
|
||||
#endif
|
||||
#if defined (ARTE)
|
||||
bool firmwareFlag_ChannelOrder_ARTE = true;
|
||||
#endif
|
||||
#if defined (ATRE)
|
||||
bool firmwareFlag_ChannelOrder_ATRE = true;
|
||||
#endif
|
||||
#if defined (ATER)
|
||||
bool firmwareFlag_ChannelOrder_ATER = true;
|
||||
#endif
|
||||
#if defined (EATR)
|
||||
bool firmwareFlag_ChannelOrder_EATR = true;
|
||||
#endif
|
||||
#if defined (EART)
|
||||
bool firmwareFlag_ChannelOrder_EART = true;
|
||||
#endif
|
||||
#if defined (ERAT)
|
||||
bool firmwareFlag_ChannelOrder_ERAT = true;
|
||||
#endif
|
||||
#if defined (ERTA)
|
||||
bool firmwareFlag_ChannelOrder_ERTA = true;
|
||||
#endif
|
||||
#if defined (ETRA)
|
||||
bool firmwareFlag_ChannelOrder_ETRA = true;
|
||||
#endif
|
||||
#if defined (ETAR)
|
||||
bool firmwareFlag_ChannelOrder_ETAR = true;
|
||||
#endif
|
||||
#if defined (TEAR)
|
||||
bool firmwareFlag_ChannelOrder_TEAR = true;
|
||||
#endif
|
||||
#if defined (TERA)
|
||||
bool firmwareFlag_ChannelOrder_TERA = true;
|
||||
#endif
|
||||
#if defined (TREA)
|
||||
bool firmwareFlag_ChannelOrder_TREA = true;
|
||||
#endif
|
||||
#if defined (TRAE)
|
||||
bool firmwareFlag_ChannelOrder_TRAE = true;
|
||||
#endif
|
||||
#if defined (TARE)
|
||||
bool firmwareFlag_ChannelOrder_TARE = true;
|
||||
#endif
|
||||
#if defined (TAER)
|
||||
bool firmwareFlag_ChannelOrder_TAER = true;
|
||||
#endif
|
||||
#if defined (RETA)
|
||||
bool firmwareFlag_ChannelOrder_RETA = true;
|
||||
#endif
|
||||
#if defined (REAT)
|
||||
bool firmwareFlag_ChannelOrder_REAT = true;
|
||||
#endif
|
||||
#if defined (RAET)
|
||||
bool firmwareFlag_ChannelOrder_RAET = true;
|
||||
#endif
|
||||
#if defined (RATE)
|
||||
bool firmwareFlag_ChannelOrder_RATE = true;
|
||||
#endif
|
||||
#if defined (RTAE)
|
||||
bool firmwareFlag_ChannelOrder_RTAE = true;
|
||||
#endif
|
||||
#if defined (RTEA)
|
||||
bool firmwareFlag_ChannelOrder_RTEA = true;
|
||||
#endif
|
||||
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&0x0F)*2;
|
||||
uint16_t rxid=0;
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
rxid|=eeprom_read_byte((EE_ADDR)(base_adr+i))<<(i*8);
|
||||
radio_id = BUGS_rxid_to_radioid(rxid);
|
||||
}
|
||||
A7105_WriteID(radio_id);
|
||||
|
||||
for(uint8_t i=0; i<BUGS_NUM_RFCHAN;i++)
|
||||
hopping_frequency[i]=pgm_read_byte_near( &BUGS_hop[i+offset] );
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) BUGS_increment_counts()
|
||||
{ // this logic works with the use of packet_count in BUGS_build_packet
|
||||
// to properly indicate channel changes to rx
|
||||
packet_count += 1;
|
||||
if ((packet_count & 1) == 0)
|
||||
{
|
||||
hopping_frequency_no += 1;
|
||||
hopping_frequency_no %= BUGS_NUM_RFCHAN;
|
||||
}
|
||||
}
|
||||
|
||||
#define BUGS_PACKET_PERIOD 6100
|
||||
#define BUGS_DELAY_TX 2000
|
||||
#define BUGS_DELAY_POST_RX 1500
|
||||
#define BUGS_DELAY_BIND_RST 200
|
||||
|
||||
// FIFO config is one less than desired value
|
||||
#define BUGS_FIFO_SIZE_RX 15
|
||||
#define BUGS_FIFO_SIZE_TX 21
|
||||
uint16_t 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&0x0F)*2;
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
eeprom_write_byte((EE_ADDR)(base_adr+i),rxid>>(i*8)); // Save rxid in EEPROM
|
||||
BUGS_set_radio_data();
|
||||
phase = BUGS_DATA_1;
|
||||
packet_count = 0;
|
||||
hopping_frequency_no = 0;
|
||||
packet_period = BUGS_DELAY_POST_RX;
|
||||
break;
|
||||
|
||||
case BUGS_DATA_1:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(BUGS_PACKET_PERIOD);
|
||||
#endif
|
||||
A7105_SetPower();
|
||||
BUGS_build_packet(0);
|
||||
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_TX);
|
||||
A7105_WriteData(BUGS_PACKET_SIZE, hopping_frequency[hopping_frequency_no]);
|
||||
phase = BUGS_DATA_2;
|
||||
packet_period = BUGS_DELAY_TX;
|
||||
break;
|
||||
|
||||
case BUGS_DATA_2:
|
||||
//Wait for TX completion
|
||||
start=micros();
|
||||
while ((uint16_t)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&0x0F)*2;
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
rxid|=eeprom_read_byte((EE_ADDR)(base_adr+i))<<(i*8);
|
||||
if(rxid==0xffff)
|
||||
BIND_IN_PROGRESS;
|
||||
|
||||
BUGS_set_radio_data();
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
phase = BUGS_BIND_1;
|
||||
else
|
||||
phase = BUGS_DATA_1;
|
||||
|
||||
A7105_Init();
|
||||
|
||||
hopping_frequency_no = 0;
|
||||
packet_count = 0;
|
||||
armed = 0;
|
||||
arm_flags = BUGS_FLAG_DISARM; // initial value from captures
|
||||
arm_channel_previous = BUGS_CH_SW_ARM;
|
||||
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
441
Multiprotocol/CABELL_nrf224l01.ino
Normal file
441
Multiprotocol/CABELL_nrf224l01.ino
Normal file
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
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
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
return packet_period;
|
||||
}
|
||||
else 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();
|
||||
|
||||
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,24 +18,53 @@
|
||||
//CC2500 SPI routines
|
||||
//-------------------------------
|
||||
//-------------------------------
|
||||
#ifdef CC2500_INSTALLED
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
void CC2500_ReadData(uint8_t *dpbuffer, uint8_t len)
|
||||
//----------------------------
|
||||
void CC2500_WriteReg(uint8_t address, uint8_t data)
|
||||
{
|
||||
CC2500_ReadRegisterMulti(CC2500_3F_RXFIFO | CC2500_READ_BURST, dpbuffer, len);
|
||||
}
|
||||
CC25_CSN_off;
|
||||
SPI_Write(address);
|
||||
NOP();
|
||||
SPI_Write(data);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
//----------------------
|
||||
static void CC2500_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
SPI_Write(address);
|
||||
SPI_Write(CC2500_READ_BURST | address);
|
||||
for(uint8_t i = 0; i < length; i++)
|
||||
data[i] = SPI_Read();
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
//--------------------------------------------
|
||||
static uint8_t CC2500_ReadReg(uint8_t address)
|
||||
{
|
||||
uint8_t result;
|
||||
CC25_CSN_off;
|
||||
SPI_Write(CC2500_READ_SINGLE | address);
|
||||
result = SPI_Read();
|
||||
CC25_CSN_on;
|
||||
return(result);
|
||||
}
|
||||
|
||||
//------------------------
|
||||
void CC2500_ReadData(uint8_t *dpbuffer, uint8_t len)
|
||||
{
|
||||
CC2500_ReadRegisterMulti(CC2500_3F_RXFIFO, dpbuffer, len);
|
||||
}
|
||||
|
||||
//*********************************************
|
||||
void CC2500_Strobe(uint8_t state)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
SPI_Write(state);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
static void CC2500_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8_t length)
|
||||
{
|
||||
@@ -47,38 +77,31 @@ static void CC2500_WriteRegisterMulti(uint8_t address, const uint8_t data[], uin
|
||||
|
||||
void CC2500_WriteData(uint8_t *dpbuffer, uint8_t len)
|
||||
{
|
||||
CC2500_Strobe(CC2500_SFTX);//0x3B
|
||||
CC2500_Strobe(CC2500_SFTX);
|
||||
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, dpbuffer, len);
|
||||
CC2500_Strobe(CC2500_STX);//0x35
|
||||
CC2500_Strobe(CC2500_STX);
|
||||
}
|
||||
|
||||
//----------------------------
|
||||
void CC2500_WriteReg(uint8_t address, uint8_t data) {//same as 7105
|
||||
CC25_CSN_off;
|
||||
SPI_Write(address);
|
||||
NOP();
|
||||
SPI_Write(data);
|
||||
CC25_CSN_on;
|
||||
}
|
||||
|
||||
//--------------------------------------------
|
||||
static uint8_t CC2500_ReadReg(uint8_t address)
|
||||
{
|
||||
uint8_t result;
|
||||
CC25_CSN_off;
|
||||
address |=0x80; //bit 7 =1 for reading
|
||||
SPI_Write(address);
|
||||
result = SPI_Read();
|
||||
CC25_CSN_on;
|
||||
return(result);
|
||||
}
|
||||
//------------------------
|
||||
void CC2500_Strobe(uint8_t address)
|
||||
void CC2500_SetTxRxMode(uint8_t mode)
|
||||
{
|
||||
CC25_CSN_off;
|
||||
SPI_Write(address);
|
||||
CC25_CSN_on;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------
|
||||
/*static void cc2500_resetChip(void)
|
||||
{
|
||||
@@ -96,7 +119,7 @@ void CC2500_Strobe(uint8_t address)
|
||||
uint8_t CC2500_Reset()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SRES);
|
||||
delayMicroseconds(1000);
|
||||
delayMilliseconds(1);
|
||||
CC2500_SetTxRxMode(TXRX_OFF);
|
||||
return CC2500_ReadReg(CC2500_0E_FREQ1) == 0xC4;//check if reset
|
||||
}
|
||||
@@ -121,29 +144,18 @@ static void CC2500_SetPower_Value(uint8_t 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
|
||||
862
Multiprotocol/CFlie_nrf24l01.ino
Normal file
862
Multiprotocol/CFlie_nrf24l01.ino
Normal file
@@ -0,0 +1,862 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Most of this code was ported from theseankelly's related DeviationTX work.
|
||||
|
||||
#if defined(CFLIE_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define CFLIE_BIND_COUNT 60
|
||||
|
||||
//=============================================================================
|
||||
// CRTP (Crazy RealTime Protocol) Implementation
|
||||
//=============================================================================
|
||||
|
||||
// Port IDs
|
||||
enum {
|
||||
CRTP_PORT_CONSOLE = 0x00,
|
||||
CRTP_PORT_PARAM = 0x02,
|
||||
CRTP_PORT_SETPOINT = 0x03,
|
||||
CRTP_PORT_MEM = 0x04,
|
||||
CRTP_PORT_LOG = 0x05,
|
||||
CRTP_PORT_POSITION = 0x06,
|
||||
CRTP_PORT_SETPOINT_GENERIC = 0x07,
|
||||
CRTP_PORT_PLATFORM = 0x0D,
|
||||
CRTP_PORT_LINK = 0x0F,
|
||||
};
|
||||
|
||||
// Channel definitions for the LOG port
|
||||
enum {
|
||||
CRTP_LOG_CHAN_TOC = 0x00,
|
||||
CRTP_LOG_CHAN_SETTINGS = 0x01,
|
||||
CRTP_LOG_CHAN_LOGDATA = 0x02,
|
||||
};
|
||||
|
||||
// Command definitions for the LOG port's TOC channel
|
||||
enum {
|
||||
CRTP_LOG_TOC_CMD_ELEMENT = 0x00,
|
||||
CRTP_LOG_TOC_CMD_INFO = 0x01,
|
||||
};
|
||||
|
||||
// Command definitions for the LOG port's CMD channel
|
||||
enum {
|
||||
CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK = 0x00,
|
||||
CRTP_LOG_SETTINGS_CMD_APPEND_BLOCK = 0x01,
|
||||
CRTP_LOG_SETTINGS_CMD_DELETE_BLOCK = 0x02,
|
||||
CRTP_LOG_SETTINGS_CMD_START_LOGGING = 0x03,
|
||||
CRTP_LOG_SETTINGS_CMD_STOP_LOGGING = 0x04,
|
||||
CRTP_LOG_SETTINGS_CMD_RESET_LOGGING = 0x05,
|
||||
};
|
||||
|
||||
// Log variables types
|
||||
enum {
|
||||
LOG_UINT8 = 0x01,
|
||||
LOG_UINT16 = 0x02,
|
||||
LOG_UINT32 = 0x03,
|
||||
LOG_INT8 = 0x04,
|
||||
LOG_INT16 = 0x05,
|
||||
LOG_INT32 = 0x06,
|
||||
LOG_FLOAT = 0x07,
|
||||
LOG_FP16 = 0x08,
|
||||
};
|
||||
|
||||
#define CFLIE_TELEM_LOG_BLOCK_ID 0x01
|
||||
#define CFLIE_TELEM_LOG_BLOCK_PERIOD_10MS 50 // 50*10 = 500ms
|
||||
|
||||
// Setpoint type definitions for the generic setpoint channel
|
||||
enum {
|
||||
CRTP_SETPOINT_GENERIC_STOP_TYPE = 0x00,
|
||||
CRTP_SETPOINT_GENERIC_VELOCITY_WORLD_TYPE = 0x01,
|
||||
CRTP_SETPOINT_GENERIC_Z_DISTANCE_TYPE = 0x02,
|
||||
CRTP_SETPOINT_GENERIC_CPPM_EMU_TYPE = 0x03,
|
||||
};
|
||||
|
||||
static inline uint8_t crtp_create_header(uint8_t port, uint8_t channel)
|
||||
{
|
||||
return ((port)&0x0F)<<4 | (channel & 0x03);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// End CRTP implementation
|
||||
//=============================================================================
|
||||
|
||||
// Address size
|
||||
#define TX_ADDR_SIZE 5
|
||||
|
||||
// Timeout for callback in uSec, 10ms=10000us for Crazyflie
|
||||
#define CFLIE_PACKET_PERIOD 10000
|
||||
|
||||
#define MAX_PACKET_SIZE 32 // CRTP is 32 bytes
|
||||
|
||||
// CPPM CRTP supports up to 10 aux channels but deviation only
|
||||
// supports a total of 12 channels. R,P,Y,T leaves 8 aux channels left
|
||||
#define MAX_CPPM_AUX_CHANNELS 8
|
||||
|
||||
static uint8_t tx_payload_len = 0; // Length of the packet stored in packet
|
||||
static uint8_t rx_payload_len = 0; // Length of the packet stored in rx_packet
|
||||
static uint8_t rx_packet[MAX_PACKET_SIZE]; // For reading in ACK payloads
|
||||
|
||||
static uint8_t data_rate;
|
||||
|
||||
enum {
|
||||
CFLIE_INIT_SEARCH = 0,
|
||||
CFLIE_INIT_CRTP_LOG,
|
||||
CFLIE_INIT_DATA,
|
||||
CFLIE_SEARCH,
|
||||
CFLIE_DATA
|
||||
};
|
||||
|
||||
static uint8_t crtp_log_setup_state;
|
||||
enum {
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_INIT = 0,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_INFO,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_ITEM,
|
||||
// It might be a good idea to add a state here
|
||||
// to send the command to reset the logging engine
|
||||
// to avoid log block ID conflicts. However, there
|
||||
// is not a conflict with the current defaults in
|
||||
// cfclient and I'd rather be able to log from the Tx
|
||||
// and cfclient simultaneously
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_START_BLOCK,
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_COMPLETE,
|
||||
};
|
||||
|
||||
// State variables for the crtp_log_setup_state_machine
|
||||
static uint8_t toc_size; // Size of the TOC read from the crazyflie
|
||||
static uint8_t next_toc_variable; // State variable keeping track of the next var to read
|
||||
static uint8_t vbat_var_id; // ID of the vbatMV variable
|
||||
static uint8_t extvbat_var_id; // ID of the extVbatMV variable
|
||||
static uint8_t rssi_var_id; // ID of the RSSI variable
|
||||
|
||||
// Constants used for finding var IDs from the toc
|
||||
static const char* pm_group_name = "pm";
|
||||
static const char* vbat_var_name = "vbatMV";
|
||||
static const uint8_t vbat_var_type = LOG_UINT16;
|
||||
static const char* extvbat_var_name = "extVbatMV";
|
||||
static const uint8_t extvbat_var_type = LOG_UINT16;
|
||||
static const char* radio_group_name = "radio";
|
||||
static const char* rssi_var_name = "rssi";
|
||||
static const uint8_t rssi_var_type = LOG_UINT8;
|
||||
|
||||
// Repurposing DSM Telemetry fields
|
||||
#define TELEM_CFLIE_INTERNAL_VBAT TELEM_DSM_FLOG_VOLT2 // Onboard voltage
|
||||
#define TELEM_CFLIE_EXTERNAL_VBAT TELEM_DSM_FLOG_VOLT1 // Voltage from external pin (BigQuad)
|
||||
#define TELEM_CFLIE_RSSI TELEM_DSM_FLOG_FADESA // Repurpose FADESA for RSSI
|
||||
|
||||
enum {
|
||||
PROTOOPTS_TELEMETRY = 0,
|
||||
PROTOOPTS_CRTP_MODE = 1,
|
||||
LAST_PROTO_OPT,
|
||||
};
|
||||
|
||||
#define TELEM_OFF 0
|
||||
#define TELEM_ON_ACKPKT 1
|
||||
#define TELEM_ON_CRTPLOG 2
|
||||
|
||||
#define CRTP_MODE_RPYT 0
|
||||
#define CRTP_MODE_CPPM 1
|
||||
|
||||
// Bit vector from bit position
|
||||
#define BV(bit) (1 << bit)
|
||||
|
||||
#define PACKET_CHKTIME 500 // time to wait if packet not yet acknowledged or timed out
|
||||
|
||||
// Helper for sending a packet
|
||||
// Assumes packet data has been put in packet
|
||||
// and tx_payload_len has been set correctly
|
||||
static void send_packet()
|
||||
{
|
||||
// clear packet status bits and Tx/Rx FIFOs
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (_BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
|
||||
// Transmit the payload
|
||||
NRF24L01_WritePayload(packet, tx_payload_len);
|
||||
|
||||
// // Check and adjust transmission power.
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static uint16_t dbg_cnt = 0;
|
||||
static uint8_t packet_ack()
|
||||
{
|
||||
if (++dbg_cnt > 50)
|
||||
{
|
||||
// debugln("S: %02x\n", NRF24L01_ReadReg(NRF24L01_07_STATUS));
|
||||
dbg_cnt = 0;
|
||||
}
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)))
|
||||
{
|
||||
case BV(NRF24L01_07_TX_DS):
|
||||
rx_payload_len = NRF24L01_GetDynamicPayloadSize();
|
||||
if (rx_payload_len > MAX_PACKET_SIZE)
|
||||
rx_payload_len = MAX_PACKET_SIZE;
|
||||
NRF24L01_ReadPayload(rx_packet, rx_payload_len);
|
||||
return PKT_ACKED;
|
||||
case BV(NRF24L01_07_MAX_RT):
|
||||
return PKT_TIMEOUT;
|
||||
}
|
||||
return PKT_PENDING;
|
||||
}
|
||||
|
||||
static void set_rate_channel(uint8_t rate, uint8_t channel)
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel); // Defined by model id
|
||||
NRF24L01_SetBitrate(rate); // Defined by model id
|
||||
}
|
||||
|
||||
static void send_search_packet()
|
||||
{
|
||||
uint8_t buf[1];
|
||||
buf[0] = 0xff;
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)));
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if (rf_ch_num++ > 125)
|
||||
{
|
||||
rf_ch_num = 0;
|
||||
switch(data_rate)
|
||||
{
|
||||
case NRF24L01_BR_250K:
|
||||
data_rate = NRF24L01_BR_1M;
|
||||
break;
|
||||
case NRF24L01_BR_1M:
|
||||
data_rate = NRF24L01_BR_2M;
|
||||
break;
|
||||
case NRF24L01_BR_2M:
|
||||
data_rate = NRF24L01_BR_250K;
|
||||
break;
|
||||
}
|
||||
}
|
||||
set_rate_channel(data_rate, rf_ch_num);
|
||||
|
||||
NRF24L01_WritePayload(buf, sizeof(buf));
|
||||
|
||||
}
|
||||
|
||||
// Frac 16.16
|
||||
#define FRAC_MANTISSA 16 // This means, not IEEE 754...
|
||||
#define FRAC_SCALE (1 << FRAC_MANTISSA)
|
||||
|
||||
// Convert fractional 16.16 to float32
|
||||
static void frac2float(int32_t n, float* res)
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
*res = 0.0;
|
||||
return;
|
||||
}
|
||||
uint32_t m = n < 0 ? -n : n; // Figure out mantissa?
|
||||
int i;
|
||||
for (i = (31-FRAC_MANTISSA); (m & 0x80000000) == 0; i--, m <<= 1);
|
||||
m <<= 1; // Clear implicit leftmost 1
|
||||
m >>= 9;
|
||||
uint32_t e = 127 + i;
|
||||
if (n < 0) m |= 0x80000000;
|
||||
m |= e << 23;
|
||||
*((uint32_t *) res) = m;
|
||||
}
|
||||
|
||||
static void send_crtp_rpyt_packet()
|
||||
{
|
||||
int32_t f_roll;
|
||||
int32_t f_pitch;
|
||||
int32_t f_yaw;
|
||||
uint16_t thrust;
|
||||
|
||||
uint16_t val;
|
||||
|
||||
struct CommanderPacketRPYT
|
||||
{
|
||||
float roll;
|
||||
float pitch;
|
||||
float yaw;
|
||||
uint16_t thrust;
|
||||
}__attribute__((packed)) cpkt;
|
||||
|
||||
// Channels in AETR order
|
||||
// Roll, aka aileron, float +- 50.0 in degrees
|
||||
// float roll = -(float) Channels[0]*50.0/10000;
|
||||
val = convert_channel_16b_limit(AILERON, -10000, 10000);
|
||||
// f_roll = -Channels[0] * FRAC_SCALE / (10000 / 50);
|
||||
f_roll = val * FRAC_SCALE / (10000 / 50);
|
||||
|
||||
frac2float(f_roll, &cpkt.roll); // TODO: Remove this and use the correct Mode switch below...
|
||||
// debugln("Roll: raw, converted: %d, %d, %d, %0.2f", Channel_data[AILERON], val, f_roll, cpkt.roll);
|
||||
|
||||
// Pitch, aka elevator, float +- 50.0 degrees
|
||||
//float pitch = -(float) Channels[1]*50.0/10000;
|
||||
val = convert_channel_16b_limit(ELEVATOR, -10000, 10000);
|
||||
// f_pitch = -Channels[1] * FRAC_SCALE / (10000 / 50);
|
||||
f_pitch = -val * FRAC_SCALE / (10000 / 50);
|
||||
|
||||
frac2float(f_pitch, &cpkt.pitch); // TODO: Remove this and use the correct Mode switch below...
|
||||
// debugln("Pitch: raw, converted: %d, %d, %d, %0.2f", Channel_data[ELEVATOR], val, f_pitch, cpkt.pitch);
|
||||
|
||||
// Thrust, aka throttle 0..65535, working range 5535..65535
|
||||
// Android Crazyflie app puts out a throttle range of 0-80%: 0..52000
|
||||
thrust = convert_channel_16b_limit(THROTTLE, 0, 32767) * 2;
|
||||
|
||||
// Crazyflie needs zero thrust to unlock
|
||||
if (thrust < 900)
|
||||
cpkt.thrust = 0;
|
||||
else
|
||||
cpkt.thrust = thrust;
|
||||
|
||||
// debugln("Thrust: raw, converted: %d, %u, %u", Channel_data[THROTTLE], thrust, cpkt.thrust);
|
||||
|
||||
// Yaw, aka rudder, float +- 400.0 deg/s
|
||||
// float yaw = -(float) Channels[3]*400.0/10000;
|
||||
val = convert_channel_16b_limit(RUDDER, -10000, 10000);
|
||||
// f_yaw = - Channels[3] * FRAC_SCALE / (10000 / 400);
|
||||
f_yaw = val * FRAC_SCALE / (10000 / 400);
|
||||
frac2float(f_yaw, &cpkt.yaw);
|
||||
|
||||
// debugln("Yaw: raw, converted: %d, %d, %d, %0.2f", Channel_data[RUDDER], val, f_yaw, cpkt.yaw);
|
||||
|
||||
// Switch on/off?
|
||||
// TODO: Get X or + mode working again:
|
||||
// if (Channels[4] >= 0) {
|
||||
// frac2float(f_roll, &cpkt.roll);
|
||||
// frac2float(f_pitch, &cpkt.pitch);
|
||||
// } else {
|
||||
// // Rotate 45 degrees going from X to + mode or opposite.
|
||||
// // 181 / 256 = 0.70703125 ~= sqrt(2) / 2
|
||||
// int32_t f_x_roll = (f_roll + f_pitch) * 181 / 256;
|
||||
// frac2float(f_x_roll, &cpkt.roll);
|
||||
// int32_t f_x_pitch = (f_pitch - f_roll) * 181 / 256;
|
||||
// frac2float(f_x_pitch, &cpkt.pitch);
|
||||
// }
|
||||
|
||||
// Construct and send packet
|
||||
packet[0] = crtp_create_header(CRTP_PORT_SETPOINT, 0); // Commander packet to channel 0
|
||||
memcpy(&packet[1], (char*) &cpkt, sizeof(cpkt));
|
||||
tx_payload_len = 1 + sizeof(cpkt);
|
||||
send_packet();
|
||||
}
|
||||
|
||||
/*static void send_crtp_cppm_emu_packet()
|
||||
{
|
||||
struct CommanderPacketCppmEmu {
|
||||
struct {
|
||||
uint8_t numAuxChannels : 4; // Set to 0 through MAX_AUX_RC_CHANNELS
|
||||
uint8_t reserved : 4;
|
||||
} hdr;
|
||||
uint16_t channelRoll;
|
||||
uint16_t channelPitch;
|
||||
uint16_t channelYaw;
|
||||
uint16_t channelThrust;
|
||||
uint16_t channelAux[10];
|
||||
} __attribute__((packed)) cpkt;
|
||||
|
||||
// To emulate PWM RC signals, rescale channels from (-10000,10000) to (1000,2000)
|
||||
// This is done by dividing by 20 to get a total range of 1000 (-500,500)
|
||||
// and then adding 1500 to to rebase the offset
|
||||
#define RESCALE_RC_CHANNEL_TO_PWM(chan) ((chan / 20) + 1500)
|
||||
|
||||
// Make sure the number of aux channels in use is capped to MAX_CPPM_AUX_CHANNELS
|
||||
// uint8_t numAuxChannels = Model.num_channels - 4;
|
||||
uint8_t numAuxChannels = 2; // TODO: Figure this out correctly
|
||||
if(numAuxChannels > MAX_CPPM_AUX_CHANNELS)
|
||||
{
|
||||
numAuxChannels = MAX_CPPM_AUX_CHANNELS;
|
||||
}
|
||||
|
||||
cpkt.hdr.numAuxChannels = numAuxChannels;
|
||||
|
||||
// Remap AETR to AERT (RPYT)
|
||||
cpkt.channelRoll = convert_channel_16b_limit(AILERON,1000,2000);
|
||||
cpkt.channelPitch = convert_channel_16b_limit(ELEVATOR,1000,2000);
|
||||
// Note: T & R Swapped:
|
||||
cpkt.channelYaw = convert_channel_16b_limit(RUDDER, 1000, 2000);
|
||||
cpkt.channelThrust = convert_channel_16b_limit(THROTTLE, 1000, 2000);
|
||||
|
||||
// Rescale the rest of the aux channels - RC channel 4 and up
|
||||
for (uint8_t i = 4; i < 14; i++)
|
||||
{
|
||||
cpkt.channelAux[i] = convert_channel_16b_limit(i, 1000, 2000);
|
||||
}
|
||||
|
||||
// Total size of the commander packet is a 1-byte header, 4 2-byte channels and
|
||||
// a variable number of 2-byte auxiliary channels
|
||||
uint8_t commanderPacketSize = 1 + 8 + (2*numAuxChannels);
|
||||
|
||||
// Construct and send packet
|
||||
packet[0] = crtp_create_header(CRTP_PORT_SETPOINT_GENERIC, 0); // Generic setpoint packet to channel 0
|
||||
packet[1] = CRTP_SETPOINT_GENERIC_CPPM_EMU_TYPE;
|
||||
|
||||
// Copy the header (1) plus 4 2-byte channels (8) plus whatever number of 2-byte aux channels are in use
|
||||
memcpy(&packet[2], (char*)&cpkt, commanderPacketSize); // Why not use sizeof(cpkt) here??
|
||||
tx_payload_len = 2 + commanderPacketSize; // CRTP header, commander type, and packet
|
||||
send_packet();
|
||||
}*/
|
||||
|
||||
static void send_cmd_packet()
|
||||
{
|
||||
// TODO: Fix this so we can actually configure the packet type
|
||||
// switch(Model.proto_opts[PROTOOPTS_CRTP_MODE])
|
||||
// {
|
||||
// case CRTP_MODE_CPPM:
|
||||
// send_crtp_cppm_emu_packet();
|
||||
// break;
|
||||
// case CRTP_MODE_RPYT:
|
||||
// send_crtp_rpyt_packet();
|
||||
// break;
|
||||
// default:
|
||||
// send_crtp_rpyt_packet();
|
||||
// }
|
||||
|
||||
// send_crtp_cppm_emu_packet(); // oh maAAAn
|
||||
send_crtp_rpyt_packet();
|
||||
}
|
||||
|
||||
// State machine for setting up CRTP logging
|
||||
// returns 1 when the state machine has completed, 0 otherwise
|
||||
static uint8_t crtp_log_setup_state_machine()
|
||||
{
|
||||
uint8_t state_machine_completed = 0;
|
||||
// A note on the design of this state machine:
|
||||
//
|
||||
// Responses from the crazyflie come in the form of ACK payloads.
|
||||
// There is no retry logic associated with ACK payloads, so it is possible
|
||||
// to miss a response from the crazyflie. To avoid this, the request
|
||||
// packet must be re-sent until the expected response is received. However,
|
||||
// re-sending the same request generates another response in the crazyflie
|
||||
// Rx queue, which can produce large backlogs of duplicate responses.
|
||||
//
|
||||
// To avoid this backlog but still guard against dropped ACK payloads,
|
||||
// transmit cmd packets (which don't generate responses themselves)
|
||||
// until an empty ACK payload is received (the crazyflie alternates between
|
||||
// 0xF3 and 0xF7 for empty ACK payloads) which indicates the Rx queue on the
|
||||
// crazyflie has been drained. If the queue has been drained and the
|
||||
// desired ACK has still not been received, it was likely dropped and the
|
||||
// request should be re-transmit.
|
||||
|
||||
switch (crtp_log_setup_state) {
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_INIT:
|
||||
toc_size = 0;
|
||||
next_toc_variable = 0;
|
||||
vbat_var_id = 0;
|
||||
extvbat_var_id = 0;
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO;
|
||||
// fallthrough
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_INFO;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC);
|
||||
packet[1] = CRTP_LOG_TOC_CMD_INFO;
|
||||
tx_payload_len = 2;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_INFO:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 3
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC)
|
||||
&& rx_packet[1] == CRTP_LOG_TOC_CMD_INFO) {
|
||||
// Received the ACK payload. Save the toc_size
|
||||
// and advance to the next state
|
||||
toc_size = rx_packet[2];
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM;
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_ITEM;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC);
|
||||
packet[1] = CRTP_LOG_TOC_CMD_ELEMENT;
|
||||
packet[2] = next_toc_variable;
|
||||
tx_payload_len = 3;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CMD_GET_ITEM:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 3
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC)
|
||||
&& rx_packet[1] == CRTP_LOG_TOC_CMD_ELEMENT
|
||||
&& rx_packet[2] == next_toc_variable) {
|
||||
// For every element in the TOC we must compare its
|
||||
// type (rx_packet[3]), group and name (back to back
|
||||
// null terminated strings starting with the fifth byte)
|
||||
// and see if it matches any of the variables we need
|
||||
// for logging
|
||||
//
|
||||
// Currently enabled for logging:
|
||||
// - vbatMV (LOG_UINT16)
|
||||
// - extVbatMV (LOG_UINT16)
|
||||
// - rssi (LOG_UINT8)
|
||||
if(rx_packet[3] == vbat_var_type
|
||||
&& (0 == strcmp((char*)&rx_packet[4], pm_group_name))
|
||||
&& (0 == strcmp((char*)&rx_packet[4 + strlen(pm_group_name) + 1], vbat_var_name))) {
|
||||
// Found the vbat element - save it for later
|
||||
vbat_var_id = next_toc_variable;
|
||||
}
|
||||
|
||||
if(rx_packet[3] == extvbat_var_type
|
||||
&& (0 == strcmp((char*)&rx_packet[4], pm_group_name))
|
||||
&& (0 == strcmp((char*)&rx_packet[4 + strlen(pm_group_name) + 1], extvbat_var_name))) {
|
||||
// Found the extvbat element - save it for later
|
||||
extvbat_var_id = next_toc_variable;
|
||||
}
|
||||
|
||||
if(rx_packet[3] == rssi_var_type
|
||||
&& (0 == strcmp((char*)&rx_packet[4], radio_group_name))
|
||||
&& (0 == strcmp((char*)&rx_packet[4 + strlen(radio_group_name) + 1], rssi_var_name))) {
|
||||
// Found the rssi element - save it for later
|
||||
rssi_var_id = next_toc_variable;
|
||||
}
|
||||
|
||||
// Advance the toc variable counter
|
||||
// If there are more variables, read them
|
||||
// If not, move on to the next state
|
||||
next_toc_variable += 1;
|
||||
if(next_toc_variable >= toc_size) {
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK;
|
||||
} else {
|
||||
// There are more TOC elements to get
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_ITEM;
|
||||
}
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CMD_GET_INFO;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS);
|
||||
packet[1] = CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK;
|
||||
packet[2] = CFLIE_TELEM_LOG_BLOCK_ID; // Log block ID
|
||||
packet[3] = vbat_var_type; // Variable type
|
||||
packet[4] = vbat_var_id; // ID of the VBAT variable
|
||||
packet[5] = extvbat_var_type; // Variable type
|
||||
packet[6] = extvbat_var_id; // ID of the ExtVBat variable
|
||||
packet[7] = rssi_var_type; // Variable type
|
||||
packet[8] = rssi_var_id; // ID of the RSSI variable
|
||||
tx_payload_len = 9;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 2
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS)
|
||||
&& rx_packet[1] == CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK) {
|
||||
// Received the ACK payload. Advance to the next state
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK;
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK:
|
||||
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_START_BLOCK;
|
||||
packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS);
|
||||
packet[1] = CRTP_LOG_SETTINGS_CMD_START_LOGGING;
|
||||
packet[2] = CFLIE_TELEM_LOG_BLOCK_ID; // Log block ID 1
|
||||
packet[3] = CFLIE_TELEM_LOG_BLOCK_PERIOD_10MS; // Log frequency in 10ms units
|
||||
tx_payload_len = 4;
|
||||
send_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_ACK_CONTROL_START_BLOCK:
|
||||
if (packet_ack() == PKT_ACKED) {
|
||||
if (rx_payload_len >= 2
|
||||
&& rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS)
|
||||
&& rx_packet[1] == CRTP_LOG_SETTINGS_CMD_START_LOGGING) {
|
||||
// Received the ACK payload. Advance to the next state
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_COMPLETE;
|
||||
return state_machine_completed;
|
||||
} else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) {
|
||||
// "empty" ACK packet received - likely missed the ACK
|
||||
// payload we are waiting for.
|
||||
// return to the send state and retransmit the request
|
||||
crtp_log_setup_state =
|
||||
CFLIE_CRTP_LOG_SETUP_STATE_SEND_CONTROL_START_BLOCK;
|
||||
return state_machine_completed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, send a cmd packet to get the next ACK in the Rx queue
|
||||
send_cmd_packet();
|
||||
break;
|
||||
|
||||
case CFLIE_CRTP_LOG_SETUP_STATE_COMPLETE:
|
||||
state_machine_completed = 1;
|
||||
return state_machine_completed;
|
||||
break;
|
||||
}
|
||||
|
||||
return state_machine_completed;
|
||||
}
|
||||
|
||||
static 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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(CFLIE_PACKET_PERIOD);
|
||||
#endif
|
||||
// if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_CRTPLOG) {
|
||||
// update_telemetry_crtplog();
|
||||
// } else if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_ACKPKT) {
|
||||
// update_telemetry_ackpkt();
|
||||
// }
|
||||
|
||||
if (packet_ack() == PKT_PENDING)
|
||||
return PACKET_CHKTIME; // packet send not yet complete
|
||||
send_cmd_packet();
|
||||
break;
|
||||
}
|
||||
return CFLIE_PACKET_PERIOD; // Packet at standard protocol interval
|
||||
}
|
||||
|
||||
// Generate address to use from TX id and manufacturer id (STM32 unique id)
|
||||
static uint8_t 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
|
||||
@@ -13,9 +13,6 @@
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// compatible with EAchine 3D X4, CG023/CG031, Attop YD-822/YD-829/YD-829C and H8_3D/JJRC H20/H22
|
||||
// Merged CG023 and H8_3D protocols
|
||||
// Last sync with hexfet new_protocols/cg023_nrf24l01.c dated 2015-10-03
|
||||
// Last sync with hexfet new_protocols/h8_3d_nrf24l01.c dated 2015-11-18
|
||||
|
||||
#if defined(CG023_NRF24L01_INO)
|
||||
|
||||
@@ -27,9 +24,6 @@
|
||||
#define CG023_RF_BIND_CHANNEL 0x2D
|
||||
#define CG023_BIND_COUNT 500 // 4 seconds
|
||||
#define YD829_PACKET_PERIOD 4100 // Timeout for callback in uSec
|
||||
#define H8_3D_PACKET_PERIOD 1800 // Timeout for callback in uSec
|
||||
#define H8_3D_PACKET_SIZE 20
|
||||
#define H8_3D_RF_NUM_CHANNELS 4
|
||||
|
||||
|
||||
enum CG023_FLAGS {
|
||||
@@ -55,139 +49,72 @@ enum YD829_FLAGS {
|
||||
YD829_FLAG_STILL = 0x80,
|
||||
};
|
||||
|
||||
enum H8_3D_FLAGS {
|
||||
// flags going to packet[17]
|
||||
H8_3D_FLAG_FLIP = 0x01,
|
||||
H8_3D_FLAG_RATE_MID = 0x02,
|
||||
H8_3D_FLAG_RATE_HIGH = 0x04,
|
||||
H8_3D_FLAG_LIGTH = 0x08, // Light on H22
|
||||
H8_3D_FLAG_HEADLESS = 0x10, // RTH + headless on H8, headless on JJRC H20, RTH on H22
|
||||
H8_3D_FLAG_RTH = 0x20, // 360 flip mode on H8 3D and H22, RTH on JJRC H20
|
||||
};
|
||||
|
||||
enum H8_3D_FLAGS_2 {
|
||||
// flags going to packet[18]
|
||||
H8_3D_FLAG_CALIBRATE = 0x20, // accelerometer calibration
|
||||
};
|
||||
|
||||
static void __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]; // 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;
|
||||
if(rudder==0x01) rudder=0; // Small deadband
|
||||
if(rudder==0x81) rudder=0; // Small deadband
|
||||
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
|
||||
| GET_FLAG(Servo_AUX1,H8_3D_FLAG_FLIP)
|
||||
| GET_FLAG(Servo_AUX2,H8_3D_FLAG_LIGTH) //H22 light
|
||||
| GET_FLAG(Servo_AUX3,H8_3D_FLAG_HEADLESS)
|
||||
| GET_FLAG(Servo_AUX4,H8_3D_FLAG_RTH); // 180/360 flip mode on H8 3D
|
||||
if(Servo_AUX5)
|
||||
packet[18] = H8_3D_FLAG_CALIBRATE;
|
||||
}
|
||||
uint8_t sum = packet[9];
|
||||
for (uint8_t i=10; i < H8_3D_PACKET_SIZE-1; i++)
|
||||
sum += packet[i];
|
||||
packet[19] = sum; // data checksum
|
||||
// rate
|
||||
packet[13] = CG023_FLAG_RATE_HIGH
|
||||
| GET_FLAG(CH5_SW,CG023_FLAG_FLIP)
|
||||
| GET_FLAG(CH6_SW,CG023_FLAG_LED_OFF)
|
||||
| GET_FLAG(CH7_SW,CG023_FLAG_STILL)
|
||||
| GET_FLAG(CH8_SW,CG023_FLAG_VIDEO)
|
||||
| GET_FLAG(CH9_SW,CG023_FLAG_EASY);
|
||||
}
|
||||
else
|
||||
{ // CG023 and YD829
|
||||
if (bind)
|
||||
packet[0]= 0xaa;
|
||||
else
|
||||
packet[0]= 0x55;
|
||||
// transmitter id
|
||||
// unknown
|
||||
packet[3] = 0x00;
|
||||
packet[4] = 0x00;
|
||||
packet[5] = throttle;
|
||||
packet[6] = rudder;
|
||||
packet[7] = elevator;
|
||||
packet[8] = aileron;
|
||||
// throttle trim : 0x30 - 0x20 - 0x10
|
||||
packet[9] = 0x20; // neutral
|
||||
// neutral trims
|
||||
packet[10] = 0x20;
|
||||
packet[11] = 0x40;
|
||||
packet[12] = 0x40;
|
||||
if(sub_protocol==CG023)
|
||||
{
|
||||
// rate
|
||||
packet[13] = CG023_FLAG_RATE_HIGH
|
||||
| GET_FLAG(Servo_AUX1,CG023_FLAG_FLIP)
|
||||
| GET_FLAG(Servo_AUX2,CG023_FLAG_LED_OFF)
|
||||
| GET_FLAG(Servo_AUX3,CG023_FLAG_STILL)
|
||||
| GET_FLAG(Servo_AUX4,CG023_FLAG_VIDEO)
|
||||
| GET_FLAG(Servo_AUX5,CG023_FLAG_EASY);
|
||||
}
|
||||
else
|
||||
{// YD829
|
||||
// rate
|
||||
packet[13] = YD829_FLAG_RATE_HIGH
|
||||
| GET_FLAG(Servo_AUX1,YD829_FLAG_FLIP)
|
||||
| GET_FLAG(Servo_AUX3,YD829_FLAG_STILL)
|
||||
| GET_FLAG(Servo_AUX4,YD829_FLAG_VIDEO)
|
||||
| GET_FLAG(Servo_AUX5,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
|
||||
}
|
||||
@@ -196,24 +123,27 @@ 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()
|
||||
{
|
||||
if(IS_BIND_DONE_on)
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
CG023_send_packet(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
@@ -229,25 +159,10 @@ uint16_t CG023_callback()
|
||||
|
||||
static void __attribute__((unused)) CG023_initialize_txid()
|
||||
{
|
||||
if(sub_protocol==H8_3D)
|
||||
{
|
||||
rx_tx_addr[0] = 0xa0 + (rx_tx_addr[0] % 0x10);
|
||||
rx_tx_addr[1] = 0xb0 + (rx_tx_addr[1] % 0x20);
|
||||
rx_tx_addr[2] = rx_tx_addr[2] % 0x20;
|
||||
rx_tx_addr[3] = rx_tx_addr[3] % 0x11;
|
||||
|
||||
hopping_frequency[0] = 0x06 + ((rx_tx_addr[0]&0x0f) % 0x0f);
|
||||
hopping_frequency[1] = 0x15 + ((rx_tx_addr[1]&0x0f) % 0x0f);
|
||||
hopping_frequency[2] = 0x24 + ((rx_tx_addr[2]&0x0f) % 0x0f);
|
||||
hopping_frequency[3] = 0x33 + ((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)
|
||||
@@ -258,11 +173,8 @@ uint16_t initCG023(void)
|
||||
CG023_init();
|
||||
if(sub_protocol==CG023)
|
||||
packet_period=CG023_PACKET_PERIOD;
|
||||
else
|
||||
if(sub_protocol==YD829)
|
||||
packet_period=YD829_PACKET_PERIOD;
|
||||
else
|
||||
packet_period=H8_3D_PACKET_PERIOD;
|
||||
else // YD829
|
||||
packet_period=YD829_PACKET_PERIOD;
|
||||
return CG023_INITIAL_WAIT+YD829_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +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/>.
|
||||
*/
|
||||
// compatible with Cheerson CX-10 blue & newer red pcb, CX-10A, CX11, CX-10 green pcb, DM007, Floureon FX-10, JXD 509 (Q282)
|
||||
// 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)
|
||||
@@ -22,7 +22,7 @@
|
||||
#define CX10_BIND_COUNT 4360 // 6 seconds
|
||||
#define CX10_PACKET_SIZE 15
|
||||
#define CX10A_PACKET_SIZE 19 // CX10 blue board packets have 19-byte payload
|
||||
#define Q282_PACKET_SIZE 21
|
||||
#define Q2X2_PACKET_SIZE 21
|
||||
#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
|
||||
#define CX10A_PACKET_PERIOD 6000
|
||||
|
||||
@@ -57,98 +57,103 @@ static void __attribute__((unused)) 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_AUX1)
|
||||
packet[12+offset] |= CX10_FLAG_FLIP; // flip flag
|
||||
|
||||
//flags=0; // packet 13
|
||||
uint8_t flags2=0; // packet 14
|
||||
packet[12+offset] = GET_FLAG(CH5_SW,CX10_FLAG_FLIP); // flip flag applied on rudder
|
||||
|
||||
// Channel 6 - rate mode is 2 lsb of packet 13
|
||||
if(Servo_data[AUX2] > PPM_MAX_COMMAND) // rate 3 / headless on CX-10A
|
||||
if(CH6_SW) // rate 3 / headless on CX-10A
|
||||
flags = 0x02;
|
||||
else
|
||||
if(Servo_data[AUX2] < PPM_MIN_COMMAND)
|
||||
if(Channel_data[CH6] < CHANNEL_MIN_COMMAND)
|
||||
flags = 0x00; // rate 1
|
||||
else
|
||||
flags = 0x01; // rate 2
|
||||
uint8_t flags2=0; // packet 14
|
||||
|
||||
uint8_t video_state=packet[14] & 0x21;
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case CX10_BLUE:
|
||||
flags |= GET_FLAG(!Servo_AUX3, 0x10) // Channel 7 - picture
|
||||
|GET_FLAG( Servo_AUX4, 0x08); // Channel 8 - video
|
||||
flags |= GET_FLAG(!CH7_SW, 0x10) // Channel 7 - picture
|
||||
|GET_FLAG( CH8_SW, 0x08); // Channel 8 - video
|
||||
break;
|
||||
case Q282:
|
||||
case Q242:
|
||||
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(Servo_AUX1, 0x80) // Channel 5 - FLIP
|
||||
|GET_FLAG(Servo_AUX2, 0x40) // Channel 6 - LED
|
||||
|GET_FLAG(Servo_AUX5, 0x08) // Channel 9 - HEADLESS
|
||||
|GET_FLAG(Servo_AUX7, 0x04) // Channel 11 - XCAL
|
||||
|GET_FLAG(Servo_AUX8, 0x02); // Channel 12 - YCAL or Start/Stop motors on JXD 509
|
||||
flags2 = GET_FLAG(CH5_SW, 0x80) // Channel 5 - FLIP
|
||||
|GET_FLAG(!CH6_SW, 0x40) // Channel 6 - LED
|
||||
|GET_FLAG(CH9_SW, 0x08) // Channel 9 - HEADLESS
|
||||
|GET_FLAG(CH11_SW, 0x04) // Channel 11 - XCAL
|
||||
|GET_FLAG(CH12_SW, 0x02); // Channel 12 - YCAL or Start/Stop motors on JXD 509
|
||||
|
||||
if(sub_protocol==Q282)
|
||||
if(sub_protocol==F_Q242)
|
||||
{
|
||||
flags=3;
|
||||
if(Servo_AUX4) // Channel 8 - video
|
||||
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(Servo_AUX3,0x10); // Channel 7 - picture
|
||||
|GET_FLAG(CH7_SW,0x10); // Channel 7 - F_Q282 picture / F_Q222 Module 2
|
||||
}
|
||||
else
|
||||
{
|
||||
flags=2;
|
||||
flags2|= GET_FLAG(Servo_AUX3,0x01) // Channel 7 - picture
|
||||
|GET_FLAG(Servo_AUX4,0x10); // Channel 8 - video
|
||||
packet[17]=0x00;
|
||||
packet[18]=0x00;
|
||||
}
|
||||
if(Servo_AUX6) flags |=0x80; // Channel 10 - RTH
|
||||
if(CH10_SW) flags |=0x80; // Channel 10 - RTH
|
||||
break;
|
||||
case DM007:
|
||||
aileron = 3000 - aileron;
|
||||
//FLIP|MODE|PICTURE|VIDEO|HEADLESS
|
||||
flags2= GET_FLAG(Servo_AUX3,CX10_FLAG_SNAPSHOT) // Channel 7 - picture
|
||||
|GET_FLAG(Servo_AUX4,CX10_FLAG_VIDEO); // Channel 8 - video
|
||||
if(Servo_AUX5) flags |= CX10_FLAG_HEADLESS; // Channel 9 - 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(Servo_AUX4) packet[12] &= ~CX10_FLAG_FLIP;
|
||||
if(CH8_SW) packet[12] &= ~CX10_FLAG_FLIP;
|
||||
case JC3015_1:
|
||||
//FLIP|MODE|PICTURE|VIDEO
|
||||
flags2= GET_FLAG(Servo_AUX3,_BV(3)) // Channel 7
|
||||
|GET_FLAG(Servo_AUX4,_BV(4)); // Channel 8
|
||||
flags2= GET_FLAG(CH7_SW,_BV(3)) // Channel 7
|
||||
|GET_FLAG(CH8_SW,_BV(4)); // Channel 8
|
||||
break;
|
||||
case MK33041:
|
||||
elevator = 3000 - elevator;
|
||||
//FLIP|MODE|PICTURE|VIDEO|HEADLESS|RTH
|
||||
flags|=GET_FLAG(Servo_AUX3,_BV(7)) // Channel 7 - picture
|
||||
|GET_FLAG(Servo_AUX6,_BV(2)); // Channel 10 - rth
|
||||
flags2=GET_FLAG(Servo_AUX4,_BV(0)) // Channel 8 - video
|
||||
|GET_FLAG(Servo_AUX5,_BV(5)); // Channel 9 - headless
|
||||
flags|=GET_FLAG(CH7_SW,_BV(7)) // Channel 7 - picture
|
||||
|GET_FLAG(CH10_SW,_BV(2)); // Channel 10 - rth
|
||||
flags2=GET_FLAG(CH8_SW,_BV(0)) // Channel 8 - video
|
||||
|GET_FLAG(CH9_SW,_BV(5)); // Channel 9 - headless
|
||||
break;
|
||||
}
|
||||
packet[5+offset] = lowByte(aileron);
|
||||
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, CX10_RF_BIND_CHANNEL);
|
||||
else
|
||||
@@ -197,7 +202,7 @@ 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);
|
||||
@@ -220,10 +225,13 @@ uint16_t CX10_callback()
|
||||
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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
CX10_Write_Packet(0);
|
||||
break;
|
||||
}
|
||||
@@ -233,32 +241,28 @@ uint16_t CX10_callback()
|
||||
static void __attribute__((unused)) CX10_initialize_txid()
|
||||
{
|
||||
rx_tx_addr[1]%= 0x30;
|
||||
if(sub_protocol==Q282)
|
||||
if(sub_protocol&0x08) //F_Q2X2 protocols
|
||||
{
|
||||
hopping_frequency[0] = 0x46;
|
||||
hopping_frequency[1] = 0x48;
|
||||
hopping_frequency[2] = 0x4a;
|
||||
hopping_frequency[3] = 0x4c;
|
||||
uint8_t offset=0; //F_Q282
|
||||
if(sub_protocol==F_Q242)
|
||||
offset=2;
|
||||
if(sub_protocol==F_Q222)
|
||||
offset=3;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
hopping_frequency[i]=0x46+2*i+offset;
|
||||
}
|
||||
else
|
||||
if(sub_protocol==Q242)
|
||||
{
|
||||
hopping_frequency[0] = 0x48;
|
||||
hopping_frequency[1] = 0x4a;
|
||||
hopping_frequency[2] = 0x4c;
|
||||
hopping_frequency[3] = 0x4e;
|
||||
}
|
||||
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);
|
||||
}
|
||||
{
|
||||
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)
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
if(sub_protocol==CX10_BLUE)
|
||||
{
|
||||
packet_length = CX10A_PACKET_SIZE;
|
||||
@@ -272,8 +276,8 @@ uint16_t initCX10(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sub_protocol==Q282||sub_protocol==Q242)
|
||||
packet_length = Q282_PACKET_SIZE;
|
||||
if(sub_protocol&0x08) //F_Q2X2 protocols
|
||||
packet_length = Q2X2_PACKET_SIZE;
|
||||
else
|
||||
packet_length = CX10_PACKET_SIZE;
|
||||
packet_period = CX10_PACKET_PERIOD;
|
||||
@@ -282,7 +286,6 @@ uint16_t initCX10(void)
|
||||
}
|
||||
CX10_initialize_txid();
|
||||
CX10_init();
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
return CX10_INITIAL_WAIT+packet_period;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
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_WriteRegister(uint8_t address, uint8_t data)
|
||||
{
|
||||
CYRF_CSN_off;
|
||||
@@ -58,17 +58,19 @@ uint8_t CYRF_ReadRegister(uint8_t address)
|
||||
|
||||
uint8_t CYRF_Reset()
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x01);//software reset
|
||||
delayMicroseconds(200);//
|
||||
// RS_HI;
|
||||
// delayMicroseconds(100);
|
||||
// RS_LO;
|
||||
// delayMicroseconds(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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -76,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);
|
||||
|
||||
@@ -83,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
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -92,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
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -124,11 +138,31 @@ static void CYRF_SetPower_Value(uint8_t power)
|
||||
void CYRF_SetPower(uint8_t val)
|
||||
{
|
||||
uint8_t power=CYRF_BIND_POWER;
|
||||
if(IS_BIND_DONE_on)
|
||||
power=IS_POWER_FLAG_on?CYRF_HIGH_POWER:CYRF_LOW_POWER;
|
||||
if(IS_BIND_DONE)
|
||||
#ifdef CYRF6936_ENABLE_LOW_POWER
|
||||
power=IS_POWER_FLAG_on?CYRF_HIGH_POWER:CYRF_LOW_POWER;
|
||||
#else
|
||||
power=CYRF_HIGH_POWER;
|
||||
#endif
|
||||
if(IS_RANGE_FLAG_on)
|
||||
power=CYRF_RANGE_POWER;
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG, val | power);
|
||||
power|=val;
|
||||
if(prev_power != power)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_03_TX_CFG,power);
|
||||
prev_power=power;
|
||||
}
|
||||
|
||||
#ifdef USE_CYRF6936_CH15_TUNING
|
||||
static uint16_t Channel15=1024;
|
||||
if(Channel15!=Channel_data[CH15])
|
||||
{ // adjust frequency
|
||||
Channel15=Channel_data[CH15]+0x155; // default value is 0x555 = 0x400 + 0x155
|
||||
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, Channel15&0xFF);
|
||||
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, Channel15>>8);
|
||||
Channel15-=0x155;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -169,11 +203,6 @@ void CYRF_WritePreamble(uint32_t preamble)
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void CYRF_StartReceive()
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL,0x87);
|
||||
}
|
||||
|
||||
/*static void CYRF_ReadDataPacket(uint8_t dpbuffer[])
|
||||
{
|
||||
CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, 0x10);
|
||||
@@ -187,9 +216,9 @@ void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length)
|
||||
static void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len)
|
||||
{
|
||||
CYRF_WriteRegister(CYRF_01_TX_LENGTH, len);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x43); // 0x40
|
||||
CYRF_WriteRegisterMulti(CYRF_20_TX_BUFFER, dpbuffer, len);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0xBF);
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x83); // 0xBF
|
||||
}
|
||||
|
||||
void CYRF_WriteDataPacket(const uint8_t dpbuffer[])
|
||||
@@ -226,14 +255,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
|
||||
delayMicroseconds(1000);
|
||||
delayMilliseconds(1);
|
||||
for(i = 0; i < NUM_FREQ; i++)
|
||||
{
|
||||
CYRF_ConfigRFChannel(i);
|
||||
CYRF_ReadRegister(CYRF_13_RSSI);
|
||||
CYRF_StartReceive();
|
||||
delayMicroseconds(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++)
|
||||
@@ -249,5 +282,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
|
||||
142
Multiprotocol/Convert.ino
Normal file
142
Multiprotocol/Convert.ino
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/************************/
|
||||
/** Convert routines **/
|
||||
/************************/
|
||||
// Reverse a channel and store it
|
||||
void reverse_channel(uint8_t num)
|
||||
{
|
||||
uint16_t val=2048-Channel_data[num];
|
||||
if(val>=2048) val=2047;
|
||||
Channel_data[num]=val;
|
||||
}
|
||||
|
||||
// Channel value is converted to ppm 860<->2140 -125%<->+125% and 988<->2012 -100%<->+100%
|
||||
uint16_t convert_channel_ppm(uint8_t num)
|
||||
{
|
||||
uint16_t val=Channel_data[num];
|
||||
return (((val<<2)+val)>>3)+860; //value range 860<->2140 -125%<->+125%
|
||||
}
|
||||
|
||||
// Channel value 100% is converted to 10bit values 0<->1023
|
||||
uint16_t convert_channel_10b(uint8_t num)
|
||||
{
|
||||
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 8b with deadband
|
||||
uint8_t convert_channel_8b_limit_deadband(uint8_t num,uint8_t min,uint8_t mid, uint8_t max, uint8_t deadband)
|
||||
{
|
||||
uint16_t val=limit_channel_100(num); // 204<->1844
|
||||
uint16_t db_low=CHANNEL_MID-deadband, db_high=CHANNEL_MID+deadband; // 1024+-deadband
|
||||
int32_t calc;
|
||||
uint8_t out;
|
||||
if(val>=db_low && val<=db_high)
|
||||
return mid;
|
||||
else if(val<db_low)
|
||||
{
|
||||
val-=CHANNEL_MIN_100;
|
||||
calc=mid-min;
|
||||
calc*=val;
|
||||
calc/=(db_low-CHANNEL_MIN_100);
|
||||
out=calc;
|
||||
out+=min;
|
||||
}
|
||||
else
|
||||
{
|
||||
val-=db_high;
|
||||
calc=max-mid;
|
||||
calc*=val;
|
||||
calc/=(CHANNEL_MAX_100-db_high+1);
|
||||
out=calc;
|
||||
out+=mid;
|
||||
if(max>min) out++; else out--;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Channel value 100% is converted to value scaled
|
||||
int16_t convert_channel_16b_limit(uint8_t num,int16_t min,int16_t max)
|
||||
{
|
||||
int32_t val=limit_channel_100(num); // 204<->1844
|
||||
val=(val-CHANNEL_MIN_100)*(max-min)/(CHANNEL_MAX_100-CHANNEL_MIN_100)+min;
|
||||
return (uint16_t)val;
|
||||
}
|
||||
|
||||
// Channel value -125%<->125% is scaled to 16bit value with no limit
|
||||
int16_t convert_channel_16b_nolimit(uint8_t num, int16_t min, int16_t max)
|
||||
{
|
||||
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;
|
||||
}
|
||||
306
Multiprotocol/Corona_cc2500.ino
Normal file
306
Multiprotocol/Corona_cc2500.ino
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
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()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(22000);
|
||||
#endif
|
||||
// Tune frequency if it has been changed
|
||||
if ( prev_option != option )
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
prev_option = option ;
|
||||
}
|
||||
|
||||
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
|
||||
167
Multiprotocol/DM002_nrf24l01.ino
Normal file
167
Multiprotocol/DM002_nrf24l01.ino
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
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)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(DM002_PACKET_PERIOD);
|
||||
#endif
|
||||
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,599 +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 RANDOM_CHANNELS 0 // disabled
|
||||
//#define RANDOM_CHANNELS 1 // enabled
|
||||
#define BIND_CHANNEL 0x0d //13 This can be any odd channel
|
||||
|
||||
//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 PROGMEM pncodes[5][9][8] = {
|
||||
/* Note these are in order transmitted (LSB 1st) */
|
||||
{ /* Row 0 */
|
||||
/* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8},
|
||||
/* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6},
|
||||
/* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9},
|
||||
/* Col 3 */ {0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4},
|
||||
/* Col 4 */ {0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0},
|
||||
/* Col 5 */ {0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8},
|
||||
/* Col 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D},
|
||||
/* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1},
|
||||
/* Col 8 */ {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86}
|
||||
},
|
||||
{ /* Row 1 */
|
||||
/* Col 0 */ {0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3},
|
||||
/* Col 1 */ {0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9},
|
||||
/* Col 2 */ {0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82},
|
||||
/* Col 3 */ {0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB},
|
||||
/* Col 4 */ {0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7},
|
||||
/* Col 5 */ {0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95},
|
||||
/* Col 6 */ {0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4},
|
||||
/* Col 7 */ {0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF},
|
||||
/* Col 8 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97}
|
||||
},
|
||||
{ /* Row 2 */
|
||||
/* Col 0 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97},
|
||||
/* Col 1 */ {0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA},
|
||||
/* Col 2 */ {0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE},
|
||||
/* Col 3 */ {0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD},
|
||||
/* Col 4 */ {0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD},
|
||||
/* Col 5 */ {0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9},
|
||||
/* Col 6 */ {0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3},
|
||||
/* Col 7 */ {0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0},
|
||||
/* Col 8 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E}
|
||||
},
|
||||
{ /* Row 3 */
|
||||
/* Col 0 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E},
|
||||
/* Col 1 */ {0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7},
|
||||
/* Col 2 */ {0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1},
|
||||
/* Col 3 */ {0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4},
|
||||
/* Col 4 */ {0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6},
|
||||
/* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80},
|
||||
/* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88},
|
||||
/* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88},
|
||||
/* Col 8 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}
|
||||
},
|
||||
{ /* 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)) 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( &pncodes[row][col][i] );
|
||||
}
|
||||
|
||||
//
|
||||
uint8_t sop_col;
|
||||
uint8_t data_col;
|
||||
uint16_t cyrf_state;
|
||||
uint8_t binding;
|
||||
|
||||
static void __attribute__((unused)) 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] = option>3?option:option+4;
|
||||
if(sub_protocol==DSMX) //DSMX type
|
||||
#if defined DSM_TELEMETRY
|
||||
packet[12] = 0xb2; // Telemetry on
|
||||
#else
|
||||
packet[12] = option<8? 0xa2 : 0xb2; // Telemetry off
|
||||
#endif
|
||||
else
|
||||
packet[12] = option<8?0x01:0x02;
|
||||
packet[13] = 0x00; //???
|
||||
for(i = 8; i < 14; i++)
|
||||
sum += packet[i];
|
||||
packet[14] = sum >> 8;
|
||||
packet[15] = sum & 0xff;
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) 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);//
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) build_data_packet(uint8_t upper)//
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t bits;
|
||||
|
||||
uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //9 Channels - DM9 TX
|
||||
switch(option>3?option:option+4) // Create channel map based on number of channels
|
||||
{
|
||||
case 12:
|
||||
ch_map[11]=11; // 12 channels
|
||||
case 11:
|
||||
ch_map[10]=10; // 11 channels
|
||||
case 10:
|
||||
ch_map[9]=9; // 10 channels
|
||||
break;
|
||||
case 8:
|
||||
memcpy(ch_map,"\x01\x05\x02\x03\x06\xFF\xFF\x04\x00\x07",10); // 8 channels - DX8 TX
|
||||
break;
|
||||
case 7:
|
||||
memcpy(ch_map,"\x01\x05\x02\x04\x03\x06\x00",7); // 7 channels - DX6i TX
|
||||
break;
|
||||
case 6:
|
||||
memcpy(ch_map,"\x01\x05\x02\x03\x00\x04\xFF",7); // 6 channels - HP6DSM TX
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
memcpy(ch_map,"\x00\x01\x02\x03\xFF\xFF\xFF",7); // 4 channels - Guess
|
||||
if(option&0x01)
|
||||
ch_map[4]=4; // 5 channels - Guess
|
||||
break;
|
||||
}
|
||||
//
|
||||
if( binding && PROTOCOL_SticksMoved(0) )
|
||||
binding = 0;
|
||||
if (sub_protocol==DSMX)
|
||||
{
|
||||
packet[0] = cyrfmfg_id[2];
|
||||
packet[1] = cyrfmfg_id[3];
|
||||
bits=11;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0] = (0xff ^ cyrfmfg_id[2]);
|
||||
packet[1] = (0xff ^ cyrfmfg_id[3]);
|
||||
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;
|
||||
case 8:
|
||||
value=Servo_data[AUX5];
|
||||
break;
|
||||
case 9:
|
||||
value=Servo_data[AUX6];
|
||||
break;
|
||||
case 10:
|
||||
value=Servo_data[AUX7];
|
||||
break;
|
||||
case 11:
|
||||
value=Servo_data[AUX8];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) 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, 0x02}, //0x00 in deviation but needed to know when transmit is over
|
||||
{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
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) 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);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) initialize_bind_state()
|
||||
{
|
||||
uint8_t 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);
|
||||
|
||||
read_code(code,pn_row,sop_col,8);
|
||||
CYRF_ConfigSOPCode(code);
|
||||
read_code(code,pn_row,data_col,16);
|
||||
read_code(code+16,0,8,8);
|
||||
memcpy(code + 24, (void *)"\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 8);
|
||||
CYRF_ConfigDataCode(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},
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) cyrf_configdata()
|
||||
{
|
||||
for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++)
|
||||
CYRF_WriteRegister(data_vals[i][0], data_vals[i][1]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) set_sop_data_crc()
|
||||
{
|
||||
uint8_t code[16];
|
||||
uint8_t pn_row = get_pn_row(hopping_frequency[hopping_frequency_no]);
|
||||
//printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[hopping_frequency_no], pn_row, sop_col, data_col);
|
||||
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
|
||||
CYRF_ConfigCRCSeed(crc);
|
||||
crc=~crc;
|
||||
|
||||
read_code(code,pn_row,sop_col,8);
|
||||
CYRF_ConfigSOPCode(code);
|
||||
read_code(code,pn_row,data_col,16);
|
||||
CYRF_ConfigDataCode(code, 16);
|
||||
|
||||
if(sub_protocol == DSMX)
|
||||
hopping_frequency_no = (hopping_frequency_no + 1) % 23;
|
||||
else
|
||||
hopping_frequency_no = (hopping_frequency_no + 1) % 2;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t ReadDsm2()
|
||||
{
|
||||
#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
|
||||
#define DSM_WRITE_DELAY 1550 // Time after write to verify write complete
|
||||
#define DSM_READ_DELAY 600 // Time before write to check read state, and switch channels. Was 400 but 500 seems what the 328p needs to read a packet
|
||||
uint32_t start;
|
||||
|
||||
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);
|
||||
hopping_frequency_no = 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:
|
||||
case DSM2_CH2_WRITE_A:
|
||||
case DSM2_CH2_WRITE_B:
|
||||
build_data_packet(cyrf_state == DSM2_CH1_WRITE_B);// build lower or upper channels
|
||||
CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags
|
||||
CYRF_WriteDataPacket(packet);
|
||||
cyrf_state++; // change from WRITE to CHECK mode
|
||||
return DSM_WRITE_DELAY;
|
||||
case DSM2_CH1_CHECK_A:
|
||||
case DSM2_CH1_CHECK_B:
|
||||
start=micros();
|
||||
while (micros()-start < 500) // Wait max 500µs
|
||||
if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02)
|
||||
break;
|
||||
set_sop_data_crc();
|
||||
cyrf_state++; // change from CH1_CHECK to CH2_WRITE
|
||||
return DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY;
|
||||
case DSM2_CH2_CHECK_A:
|
||||
case DSM2_CH2_CHECK_B:
|
||||
start=micros();
|
||||
while (micros()-start < 500) // Wait max 500µs
|
||||
if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02)
|
||||
break;
|
||||
if (cyrf_state == DSM2_CH2_CHECK_A)
|
||||
CYRF_SetPower(0x28); //Keep transmit power in sync
|
||||
#if defined DSM_TELEMETRY
|
||||
cyrf_state++; // change from CH2_CHECK to CH2_READ
|
||||
if(option<=3 || option>7)
|
||||
{ // disable telemetry for option between 4 and 7 ie 4,5,6,7 channels @11ms since it does not work...
|
||||
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 DSM2_CH2_READ_A:
|
||||
case DSM2_CH2_READ_B:
|
||||
//Read telemetry
|
||||
uint8_t rx_state = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx_state & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
|
||||
rx_state |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
if((rx_state & 0x07) == 0x02)
|
||||
{ // good data (complete with no errors)
|
||||
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
|
||||
uint8_t 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;
|
||||
}
|
||||
if (cyrf_state == DSM2_CH2_READ_A && option <= 3) // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms
|
||||
{
|
||||
//Force end read state
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, (CYRF_ReadRegister(CYRF_0F_XACT_CFG) | 0x20)); // Force end state
|
||||
start=micros();
|
||||
while (micros()-start < 100) // Wait max 100 µs
|
||||
if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0)
|
||||
break;
|
||||
cyrf_state = DSM2_CH2_READ_B;
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
|
||||
return 11000;
|
||||
}
|
||||
if (cyrf_state == DSM2_CH2_READ_A && option>7)
|
||||
cyrf_state = DSM2_CH1_WRITE_B; //Transmit upper
|
||||
else
|
||||
cyrf_state = DSM2_CH1_WRITE_A; //Force 11ms if option>3 ie 4,5,6,7 channels @11ms
|
||||
CYRF_SetTxRxMode(TX_EN); //Write mode
|
||||
set_sop_data_crc();
|
||||
return DSM_READ_DELAY;
|
||||
#else
|
||||
// No telemetry
|
||||
set_sop_data_crc();
|
||||
if (cyrf_state == DSM2_CH2_CHECK_A)
|
||||
{
|
||||
if(option < 8)
|
||||
{
|
||||
cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
|
||||
if(option>3)
|
||||
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms
|
||||
else
|
||||
return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms
|
||||
}
|
||||
else
|
||||
cyrf_state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper)
|
||||
}
|
||||
else
|
||||
cyrf_state = DSM2_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 initDsm2()
|
||||
{
|
||||
CYRF_Reset();
|
||||
CYRF_GetMfgData(cyrfmfg_id);//
|
||||
//Model match
|
||||
cyrfmfg_id[3]+=RX_num;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
//The crc for channel '1' is NOT(mfgid[0] << 8 + mfgid[1])
|
||||
//The crc for channel '2' is (mfgid[0] << 8 + mfgid[1])
|
||||
crc = ~((cyrfmfg_id[0] << 8) + cyrfmfg_id[1]);
|
||||
//
|
||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
|
||||
data_col = 7 - sop_col;
|
||||
|
||||
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
|
||||
603
Multiprotocol/DSM_cyrf6936.ino
Normal file
603
Multiprotocol/DSM_cyrf6936.ino
Normal file
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
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 & 0x7F; // Remove the Max Throw flag
|
||||
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(idx==CH1 && kill_ch<=604)
|
||||
{//Activate throttle kill only if channel is throttle and DSM_THROTTLE_KILL_CH below -50%
|
||||
if(kill_ch<CHANNEL_MIN_100) // restrict val to 0...400
|
||||
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
|
||||
if(option & 0x80)
|
||||
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
|
||||
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 += packet_in[i];
|
||||
if(i<5)
|
||||
if(packet_in[i] != (0xff ^ cyrfmfg_id[i-1]))
|
||||
result=0; // bad packet
|
||||
}
|
||||
if( packet_in[9] != (sum>>8) && packet_in[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
|
||||
#ifdef STM32_BOARD
|
||||
#define DSM_WRITE_DELAY 1600 // Time after write to verify write complete
|
||||
#else
|
||||
#define DSM_WRITE_DELAY 1950 // Time after write to verify write complete
|
||||
#endif
|
||||
#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>TELEMETRY_BUFFER_SIZE-2)
|
||||
len=TELEMETRY_BUFFER_SIZE-2;
|
||||
CYRF_ReadDataPacketLen(packet_in+1, len);
|
||||
if(len==10 && DSM_Check_RX_packet())
|
||||
{
|
||||
packet_in[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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(11000); // Always request 11ms spacing even if we don't use half of it in 22ms mode
|
||||
#endif
|
||||
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>TELEMETRY_BUFFER_SIZE-2)
|
||||
len=TELEMETRY_BUFFER_SIZE-2;
|
||||
CYRF_ReadDataPacketLen(packet_in+1, len);
|
||||
packet_in[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;// store RSSI of the received telemetry signal
|
||||
telemetry_link=1;
|
||||
}
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||
if (phase == DSM_CH2_READ_A && (sub_protocol==DSM2_22 || sub_protocol==DSMX_22) && num_ch < 8) // 22ms mode
|
||||
{
|
||||
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;
|
||||
|
||||
static void __attribute__((unused)) 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
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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 @@ static void __attribute__((unused)) 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 @@ static void __attribute__((unused)) build_bind_pkt()
|
||||
packet[15] ^= cyrfmfg_id[2];
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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 @@ static void __attribute__((unused)) 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();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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 @@ static void __attribute__((unused)) 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);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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]) );
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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];
|
||||
}
|
||||
|
||||
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 @@ static void __attribute__((unused)) 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,21 +256,25 @@ static void __attribute__((unused)) 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)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(2400);
|
||||
#endif
|
||||
txState = 1;
|
||||
DEVO_BuildPacket();
|
||||
CYRF_WriteDataPacket(packet);
|
||||
@@ -284,107 +283,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;
|
||||
}
|
||||
|
||||
/*static void __attribute__((unused)) devo_bind()
|
||||
{
|
||||
fixed_id = Model_fixed_id;
|
||||
bind_counter = DEVO_BIND_COUNT;
|
||||
use_fixed_id = 1;
|
||||
//PROTOCOL_SetBindState(0x1388 * 2400 / 1000); //msecs 12000ms
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((unused)) 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;
|
||||
}
|
||||
|
||||
|
||||
352
Multiprotocol/E01X_nrf24l01.ino
Normal file
352
Multiprotocol/E01X_nrf24l01.ino
Normal file
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// compatible with E012 and E015
|
||||
|
||||
#if defined(E01X_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
//Protocols constants
|
||||
#define E01X_BIND_COUNT 500
|
||||
#define E01X_INITIAL_WAIT 500
|
||||
#define E01X_ADDRESS_LENGTH 5
|
||||
|
||||
#define E012_PACKET_PERIOD 4525
|
||||
#define E012_RF_BIND_CHANNEL 0x3c
|
||||
#define E012_NUM_RF_CHANNELS 4
|
||||
#define E012_PACKET_SIZE 15
|
||||
|
||||
#define E015_PACKET_PERIOD 4500 // stock Tx=9000, but let's send more packets ...
|
||||
#define E015_RF_CHANNEL 0x2d // 2445 MHz
|
||||
#define E015_PACKET_SIZE 10
|
||||
#define E015_BIND_PACKET_SIZE 9
|
||||
|
||||
#define E016H_PACKET_PERIOD 4080
|
||||
#define E016H_PACKET_SIZE 10
|
||||
#define E016H_BIND_CHANNEL 80
|
||||
#define E016H_NUM_CHANNELS 4
|
||||
|
||||
//Channels
|
||||
#define E01X_ARM_SW CH5_SW
|
||||
#define E016H_STOP_SW CH5_SW
|
||||
#define E01X_FLIP_SW CH6_SW
|
||||
#define E01X_LED_SW CH7_SW
|
||||
#define E01X_HEADLESS_SW CH8_SW
|
||||
#define E01X_RTH_SW CH9_SW
|
||||
|
||||
// E012 flags packet[1]
|
||||
#define E012_FLAG_FLIP 0x40
|
||||
#define E012_FLAG_HEADLESS 0x10
|
||||
#define E012_FLAG_RTH 0x04
|
||||
// E012 flags packet[7]
|
||||
#define E012_FLAG_EXPERT 0x02
|
||||
|
||||
// E015 flags packet[6]
|
||||
#define E015_FLAG_DISARM 0x80
|
||||
#define E015_FLAG_ARM 0x40
|
||||
// E015 flags packet[7]
|
||||
#define E015_FLAG_FLIP 0x80
|
||||
#define E015_FLAG_HEADLESS 0x10
|
||||
#define E015_FLAG_RTH 0x08
|
||||
#define E015_FLAG_LED 0x04
|
||||
#define E015_FLAG_EXPERT 0x02
|
||||
#define E015_FLAG_INTERMEDIATE 0x01
|
||||
|
||||
// E016H flags packet[1]
|
||||
#define E016H_FLAG_CALIBRATE 0x80
|
||||
#define E016H_FLAG_STOP 0x20
|
||||
#define E016H_FLAG_FLIP 0x04
|
||||
// E016H flags packet[3]
|
||||
#define E016H_FLAG_HEADLESS 0x10
|
||||
#define E016H_FLAG_RTH 0x04
|
||||
// E016H flags packet[7]
|
||||
#define E016H_FLAG_TAKEOFF 0x80
|
||||
#define E016H_FLAG_HIGHRATE 0x08
|
||||
|
||||
static void __attribute__((unused)) E015_check_arming()
|
||||
{
|
||||
uint8_t arm_channel = E01X_ARM_SW;
|
||||
|
||||
if (arm_channel != arm_channel_previous)
|
||||
{
|
||||
arm_channel_previous = arm_channel;
|
||||
if (arm_channel)
|
||||
{
|
||||
armed = 1;
|
||||
arm_flags ^= E015_FLAG_ARM;
|
||||
}
|
||||
else
|
||||
{
|
||||
armed = 0;
|
||||
arm_flags ^= E015_FLAG_DISARM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E01X_send_packet(uint8_t bind)
|
||||
{
|
||||
uint8_t can_flip = 0, calibrate = 1;
|
||||
if(sub_protocol==E012)
|
||||
{
|
||||
packet_length=E012_PACKET_SIZE;
|
||||
packet[0] = rx_tx_addr[1];
|
||||
if(bind)
|
||||
{
|
||||
packet[1] = 0xaa;
|
||||
memcpy(&packet[2], hopping_frequency, E012_NUM_RF_CHANNELS);
|
||||
memcpy(&packet[6], rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
rf_ch_num=E012_RF_BIND_CHANNEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[1] = 0x01
|
||||
| GET_FLAG(E01X_RTH_SW, E012_FLAG_RTH)
|
||||
| GET_FLAG(E01X_HEADLESS_SW, E012_FLAG_HEADLESS)
|
||||
| GET_FLAG(E01X_FLIP_SW, E012_FLAG_FLIP);
|
||||
packet[2] = convert_channel_16b_limit(AILERON, 0xc8, 0x00); // aileron
|
||||
packet[3] = convert_channel_16b_limit(ELEVATOR, 0x00, 0xc8); // elevator
|
||||
packet[4] = convert_channel_16b_limit(RUDDER, 0xc8, 0x00); // rudder
|
||||
packet[5] = convert_channel_16b_limit(THROTTLE, 0x00, 0xc8); // throttle
|
||||
packet[6] = 0xaa;
|
||||
packet[7] = E012_FLAG_EXPERT; // rate (0-2)
|
||||
packet[8] = 0x00;
|
||||
packet[9] = 0x00;
|
||||
packet[10]= 0x00;
|
||||
rf_ch_num=hopping_frequency[hopping_frequency_no++];
|
||||
hopping_frequency_no %= E012_NUM_RF_CHANNELS;
|
||||
}
|
||||
packet[11] = 0x00;
|
||||
packet[12] = 0x00;
|
||||
packet[13] = 0x56;
|
||||
packet[14] = rx_tx_addr[2];
|
||||
}
|
||||
else if(sub_protocol==E015)
|
||||
{ // E015
|
||||
if(bind)
|
||||
{
|
||||
packet[0] = 0x18;
|
||||
packet[1] = 0x04;
|
||||
packet[2] = 0x06;
|
||||
// data phase address
|
||||
memcpy(&packet[3], rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
// checksum
|
||||
packet[8] = packet[3];
|
||||
for(uint8_t i=4; i<8; i++)
|
||||
packet[8] += packet[i];
|
||||
packet_length=E015_BIND_PACKET_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
E015_check_arming();
|
||||
packet[0] = convert_channel_16b_limit(THROTTLE, 0, 225); // throttle
|
||||
packet[1] = convert_channel_16b_limit(RUDDER, 225, 0); // rudder
|
||||
packet[2] = convert_channel_16b_limit(AILERON, 0, 225); // aileron
|
||||
packet[3] = convert_channel_16b_limit(ELEVATOR, 225, 0); // elevator
|
||||
packet[4] = 0x20; // elevator trim
|
||||
packet[5] = 0x20; // aileron trim
|
||||
packet[6] = arm_flags;
|
||||
packet[7] = E015_FLAG_EXPERT
|
||||
| GET_FLAG(E01X_FLIP_SW, E015_FLAG_FLIP)
|
||||
| GET_FLAG(E01X_LED_SW, E015_FLAG_LED)
|
||||
| GET_FLAG(E01X_HEADLESS_SW,E015_FLAG_HEADLESS)
|
||||
| GET_FLAG(E01X_RTH_SW, E015_FLAG_RTH);
|
||||
packet[8] = 0;
|
||||
// checksum
|
||||
packet[9] = packet[0];
|
||||
for(uint8_t i=1; i<9; i++)
|
||||
packet[9] += packet[i];
|
||||
packet_length=E015_PACKET_SIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // E016H
|
||||
packet_length=E016H_PACKET_SIZE;
|
||||
if(bind)
|
||||
{
|
||||
rf_ch_num=E016H_BIND_CHANNEL;
|
||||
memcpy(packet, &rx_tx_addr[1], 4);
|
||||
memcpy(&packet[4], hopping_frequency, 4);
|
||||
packet[8] = 0x23;
|
||||
}
|
||||
else
|
||||
{
|
||||
// trim commands
|
||||
packet[0] = 0;
|
||||
// aileron
|
||||
uint16_t val = convert_channel_16b_limit(AILERON, 0, 0x3ff);
|
||||
can_flip |= (val < 0x100) || (val > 0x300);
|
||||
packet[1] = val >> 8;
|
||||
packet[2] = val & 0xff;
|
||||
if(val < 0x300) calibrate = 0;
|
||||
// elevator
|
||||
val = convert_channel_16b_limit(ELEVATOR, 0x3ff, 0);
|
||||
can_flip |= (val < 0x100) || (val > 0x300);
|
||||
packet[3] = val >> 8;
|
||||
packet[4] = val & 0xff;
|
||||
if(val < 0x300) calibrate = 0;
|
||||
// throttle
|
||||
val = convert_channel_16b_limit(THROTTLE, 0, 0x3ff);
|
||||
packet[5] = val >> 8;
|
||||
packet[6] = val & 0xff;
|
||||
if(val > 0x100) calibrate = 0;
|
||||
// rudder
|
||||
val = convert_channel_16b_limit(RUDDER, 0, 0x3ff);
|
||||
packet[7] = val >> 8;
|
||||
packet[8] = val & 0xff;
|
||||
if(val > 0x100) calibrate = 0;
|
||||
// flags
|
||||
packet[1] |= GET_FLAG(E016H_STOP_SW, E016H_FLAG_STOP)
|
||||
| (can_flip ? GET_FLAG(E01X_FLIP_SW, E016H_FLAG_FLIP) : 0)
|
||||
| (calibrate ? E016H_FLAG_CALIBRATE : 0);
|
||||
packet[3] |= GET_FLAG(E01X_HEADLESS_SW, E016H_FLAG_HEADLESS)
|
||||
| GET_FLAG(E01X_RTH_SW, E016H_FLAG_RTH);
|
||||
packet[7] |= E016H_FLAG_HIGHRATE;
|
||||
// frequency hopping
|
||||
rf_ch_num=hopping_frequency[hopping_frequency_no++ & 0x03];
|
||||
}
|
||||
// checksum
|
||||
packet[9] = packet[0];
|
||||
for (uint8_t i=1; i < E016H_PACKET_SIZE-1; i++)
|
||||
packet[9] += packet[i];
|
||||
}
|
||||
|
||||
// Power on, TX mode, CRC enabled
|
||||
if(sub_protocol==E016H)
|
||||
XN297_Configure( _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
else //E012 & E015
|
||||
HS6200_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if(sub_protocol==E016H)
|
||||
XN297_WritePayload(packet, packet_length);
|
||||
else
|
||||
HS6200_WritePayload(packet, packet_length);
|
||||
|
||||
// Check and adjust transmission power. We do this after
|
||||
// transmission to not bother with timeout after power
|
||||
// settings change - we have plenty of time until next
|
||||
// packet.
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E01X_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
if(sub_protocol==E012)
|
||||
HS6200_SetTXAddr((uint8_t *)"\x55\x42\x9C\x8F\xC9", E01X_ADDRESS_LENGTH);
|
||||
else if(sub_protocol==E015)
|
||||
HS6200_SetTXAddr((uint8_t *)"\x62\x54\x79\x38\x53", E01X_ADDRESS_LENGTH);
|
||||
else //E016H
|
||||
XN297_SetTXAddr((uint8_t *)"\x5a\x53\x46\x30\x31", 5); // bind address
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1 Mbps
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01); // Set feature bits on
|
||||
NRF24L01_Activate(0x73);
|
||||
}
|
||||
|
||||
uint16_t E01X_callback()
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
if(sub_protocol==E016H)
|
||||
XN297_SetTXAddr(rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
else
|
||||
HS6200_SetTXAddr(rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
E01X_send_packet(1);
|
||||
bind_counter--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
E01X_send_packet(0);
|
||||
}
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E012_initialize_txid()
|
||||
{
|
||||
// rf channels
|
||||
uint32_t lfsr=random(0xfefefefe);
|
||||
for(uint8_t i=0; i<E012_NUM_RF_CHANNELS; i++)
|
||||
{
|
||||
hopping_frequency[i] = 0x10 + ((lfsr & 0xff) % 0x32);
|
||||
lfsr>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E016H_initialize_txid()
|
||||
{
|
||||
// tx id
|
||||
rx_tx_addr[0] = 0xa5;
|
||||
rx_tx_addr[1] = 0x00;
|
||||
|
||||
// rf channels
|
||||
uint32_t lfsr=random(0xfefefefe);
|
||||
for(uint8_t i=0; i<E016H_NUM_CHANNELS; i++)
|
||||
{
|
||||
hopping_frequency[i] = (lfsr & 0xFF) % 80;
|
||||
lfsr>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initE01X()
|
||||
{
|
||||
BIND_IN_PROGRESS;
|
||||
if(sub_protocol==E012)
|
||||
{
|
||||
E012_initialize_txid();
|
||||
packet_period=E012_PACKET_PERIOD;
|
||||
}
|
||||
else if(sub_protocol==E015)
|
||||
{
|
||||
packet_period=E015_PACKET_PERIOD;
|
||||
rf_ch_num=E015_RF_CHANNEL;
|
||||
armed = 0;
|
||||
arm_flags = 0;
|
||||
arm_channel_previous = E01X_ARM_SW;
|
||||
}
|
||||
else
|
||||
{ // E016H
|
||||
E016H_initialize_txid();
|
||||
packet_period=E016H_PACKET_PERIOD;
|
||||
}
|
||||
E01X_init();
|
||||
bind_counter = E01X_BIND_COUNT;
|
||||
hopping_frequency_no = 0;
|
||||
return E01X_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
186
Multiprotocol/ESky150_nrf24l01.ino
Normal file
186
Multiprotocol/ESky150_nrf24l01.ino
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
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(sub_protocol)
|
||||
{ // 7 channels
|
||||
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)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(ESKY150_SENDING_PACKET_PERIOD);
|
||||
#endif
|
||||
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
|
||||
@@ -30,15 +30,15 @@ static void __attribute__((unused)) ESKY_set_data_address()
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) ESKY_init(uint8_t bind)
|
||||
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_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 (bind)
|
||||
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);
|
||||
@@ -63,7 +63,6 @@ static void __attribute__((unused)) ESKY_init(uint8_t bind)
|
||||
static void __attribute__((unused)) ESKY_init2()
|
||||
{
|
||||
NRF24L01_FlushTx();
|
||||
packet_sent = 0;
|
||||
hopping_frequency_no = 0;
|
||||
uint16_t channel_ord = rx_tx_addr[0] % 74;
|
||||
hopping_frequency[12] = 10 + (uint8_t)channel_ord; //channel_code
|
||||
@@ -116,13 +115,12 @@ static void __attribute__((unused)) ESKY_send_packet(uint8_t bind)
|
||||
// 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++)
|
||||
{
|
||||
packet[i*2] = Servo_data[CH_AETR[i]]>>8; //high byte of servo timing(1000-2000us)
|
||||
packet[i*2+1] = Servo_data[CH_AETR[i]]&0xFF; //low byte of servo timing(1000-2000us)
|
||||
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++;
|
||||
@@ -131,23 +129,20 @@ static void __attribute__((unused)) ESKY_send_packet(uint8_t bind)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet, ESKY_PAYLOAD_SIZE);
|
||||
packet_sent = 1;
|
||||
if (! rf_ch_num)
|
||||
NRF24L01_SetPower(); //Keep transmit power updated
|
||||
NRF24L01_SetPower(); //Keep transmit power updated
|
||||
}
|
||||
|
||||
uint16_t ESKY_callback()
|
||||
{
|
||||
if(IS_BIND_DONE_on)
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
|
||||
return ESKY_PACKET_CHKTIME;
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(ESKY_PACKET_PERIOD);
|
||||
#endif
|
||||
ESKY_send_packet(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
|
||||
return ESKY_PACKET_CHKTIME;
|
||||
ESKY_send_packet(1);
|
||||
if (--bind_counter == 0)
|
||||
{
|
||||
@@ -161,8 +156,9 @@ uint16_t ESKY_callback()
|
||||
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(IS_AUTOBIND_FLAG_on);
|
||||
ESKY_init();
|
||||
ESKY_init2();
|
||||
return 50000;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define FQ777_INITIAL_WAIT 500
|
||||
#define FQ777_PACKET_PERIOD 1500
|
||||
#define FQ777_PACKET_PERIOD 2000
|
||||
#define FQ777_PACKET_SIZE 8
|
||||
#define FQ777_BIND_COUNT 1000
|
||||
#define FQ777_NUM_RF_CHANNELS 4
|
||||
@@ -58,10 +58,11 @@ static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, ui
|
||||
uint16_t val;
|
||||
} crc;
|
||||
|
||||
crc.val=0x3c18;
|
||||
for (i = 0; i < 7; ++i)
|
||||
crc.val=crc16_update(0x3c18,header[i]);
|
||||
crc.val=crc16_update(crc.val,header[i],8);
|
||||
for (i = 0; i < *len; ++i)
|
||||
crc.val=crc16_update(crc.val,payload[i]);
|
||||
crc.val=crc16_update(crc.val,payload[i],8);
|
||||
|
||||
// encode payload and crc
|
||||
// xor with this:
|
||||
@@ -101,7 +102,7 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
|
||||
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[4] + packet[5] + packet[6];
|
||||
packet_ori[7] = packet_ori[4] + packet_ori[5] + packet_ori[6];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -112,7 +113,7 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
|
||||
//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;
|
||||
@@ -120,20 +121,19 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
|
||||
trim_val = 0x20; // don't modify yaw trim
|
||||
else
|
||||
if (108 < trim_mod && trim_mod) // pitch
|
||||
trim_val = map(ppm[FQ777124_TRIM_CHAN_PITCH], PPM_MIN, PPM_MAX, 0x01, 0x3E) + 0xA0 - 0x1F;
|
||||
trim_val = 0xA0;
|
||||
else // roll
|
||||
trim_val = map(ppm[FQ777124_TRIM_CHAN_ROLL], PPM_MIN, PPM_MAX, 0x01, 0x3E) + 0x60 - 0x1F;*/
|
||||
trim_val = 0x60;
|
||||
|
||||
packet_ori[0] = convert_channel_8b_scale(THROTTLE,0,0x64);
|
||||
packet_ori[1] = convert_channel_8b_scale(RUDDER,0,0x64);
|
||||
packet_ori[2] = convert_channel_8b_scale(ELEVATOR,0,0x64);
|
||||
packet_ori[3] = convert_channel_8b_scale(AILERON,0,0x64);
|
||||
packet_ori[4] = 0x20; //trim_val; // calculated above
|
||||
packet_ori[5] = GET_FLAG(Servo_AUX1, FQ777_FLAG_FLIP)
|
||||
| GET_FLAG(Servo_AUX3, FQ777_FLAG_HEADLESS)
|
||||
| GET_FLAG(!Servo_AUX2, FQ777_FLAG_RETURN)
|
||||
| GET_FLAG(Servo_AUX4,FQ777_FLAG_EXPERT);
|
||||
|
||||
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;
|
||||
@@ -141,7 +141,7 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
|
||||
checksum += packet_ori[i];
|
||||
packet_ori[7] = checksum;
|
||||
|
||||
//packet_count++;
|
||||
packet_count++;
|
||||
}
|
||||
|
||||
ssv_pack_dpl( (0 == bind) ? rx_tx_addr : FQ777_bind_addr, hopping_frequency_no, &packet_len, packet_ori, packet);
|
||||
@@ -166,8 +166,13 @@ static void __attribute__((unused)) FQ777_init()
|
||||
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()
|
||||
@@ -175,14 +180,20 @@ uint16_t FQ777_callback()
|
||||
if(bind_counter!=0)
|
||||
{
|
||||
FQ777_send_packet(1);
|
||||
if (bind_counter-- == 0)
|
||||
bind_counter--;
|
||||
if (bind_counter == 0)
|
||||
{
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(FQ777_PACKET_PERIOD);
|
||||
#endif
|
||||
FQ777_send_packet(0);
|
||||
}
|
||||
return FQ777_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
@@ -190,6 +201,7 @@ 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;
|
||||
|
||||
113
Multiprotocol/FX816_nrf24l01.ino
Normal file
113
Multiprotocol/FX816_nrf24l01.ino
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Compatible with FEI XIONG P38 plane.
|
||||
|
||||
#if defined(FX816_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define FX816_INITIAL_WAIT 500
|
||||
#define FX816_PACKET_PERIOD 10000
|
||||
#define FX816_RF_BIND_CHANNEL 0x28 //40
|
||||
#define FX816_RF_NUM_CHANNELS 4
|
||||
#define FX816_PAYLOAD_SIZE 6
|
||||
#define FX816_BIND_COUNT 300 //3sec
|
||||
|
||||
static void __attribute__((unused)) FX816_send_packet()
|
||||
{
|
||||
packet[0] = IS_BIND_IN_PROGRESS?0x55:0xAA;
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
uint8_t val=convert_channel_8b(AILERON);
|
||||
#define FX816_SWITCH 20
|
||||
if(val>127+FX816_SWITCH)
|
||||
packet[3] = 1;
|
||||
else if(val<127-FX816_SWITCH)
|
||||
packet[3] = 2;
|
||||
else
|
||||
packet[3] = 0;
|
||||
packet[4] = convert_channel_16b_limit(THROTTLE,0,100);
|
||||
val=0;
|
||||
for(uint8_t i=0;i<FX816_PAYLOAD_SIZE-1;i++)
|
||||
val+=packet[i];
|
||||
packet[5]=val;
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, IS_BIND_IN_PROGRESS ? FX816_RF_BIND_CHANNEL:hopping_frequency[hopping_frequency_no++]);
|
||||
hopping_frequency_no%=FX816_RF_NUM_CHANNELS;
|
||||
|
||||
// clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
XN297_WritePayload(packet, FX816_PAYLOAD_SIZE);
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
|
||||
NRF24L01_SetPower(); // Set tx_power
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX816_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // No retransmits
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
|
||||
NRF24L01_Activate(0x73);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX816_initialize_txid()
|
||||
{
|
||||
//Only 8 IDs: the RX led does not indicate frame loss.
|
||||
//I didn't open the plane to find out if I could connect there so this is the best I came up with with few trial and errors...
|
||||
rx_tx_addr[0]=0x35+(rx_tx_addr[3]&0x07); //Original dump=0x35
|
||||
rx_tx_addr[1]=0x09; //Original dump=0x09
|
||||
memcpy(hopping_frequency,"\x09\x1B\x30\x42",FX816_RF_NUM_CHANNELS); //Original dump=9=0x09,27=0x1B,48=0x30,66=0x42
|
||||
for(uint8_t i=0;i<FX816_RF_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
|
||||
}
|
||||
|
||||
uint16_t FX816_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(FX816_PACKET_PERIOD);
|
||||
#endif
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
if(--bind_counter==0)
|
||||
BIND_DONE;
|
||||
FX816_send_packet();
|
||||
return FX816_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initFX816()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
FX816_initialize_txid();
|
||||
FX816_init();
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter=FX816_BIND_COUNT;
|
||||
return FX816_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -29,7 +29,9 @@
|
||||
enum {
|
||||
FY326_BIND1=0,
|
||||
FY326_BIND2,
|
||||
FY326_DATA
|
||||
FY326_DATA,
|
||||
FY319_BIND1,
|
||||
FY319_BIND2,
|
||||
};
|
||||
|
||||
#define rxid channel
|
||||
@@ -41,18 +43,27 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
|
||||
if(bind)
|
||||
packet[1] = 0x55;
|
||||
else
|
||||
packet[1] = GET_FLAG(Servo_AUX3, 0x80) // Headless
|
||||
| GET_FLAG(Servo_AUX2, 0x40) // RTH
|
||||
| GET_FLAG(Servo_AUX1, 0x02) // Flip
|
||||
| GET_FLAG(Servo_AUX5, 0x01) // Calibrate
|
||||
| GET_FLAG(Servo_AUX4, 0x04); // Expert
|
||||
packet[2] = 200 - convert_channel_8b_scale(AILERON, 0, 200); // aileron
|
||||
packet[3] = convert_channel_8b_scale(ELEVATOR, 0, 200); // elevator
|
||||
packet[4] = 200 - convert_channel_8b_scale(RUDDER, 0, 200); // rudder
|
||||
packet[5] = convert_channel_8b_scale(THROTTLE, 0, 200); // throttle
|
||||
packet[6] = rx_tx_addr[0];
|
||||
packet[7] = rx_tx_addr[1];
|
||||
packet[8] = rx_tx_addr[2];
|
||||
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;
|
||||
@@ -81,7 +92,10 @@ static void __attribute__((unused)) FY326_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address
|
||||
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();
|
||||
@@ -98,14 +112,50 @@ static void __attribute__((unused)) FY326_init()
|
||||
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))
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{ // RX fifo data ready
|
||||
NRF24L01_ReadPayload(packet, FY326_PACKET_SIZE);
|
||||
rxid = packet[13];
|
||||
@@ -127,7 +177,7 @@ uint16_t FY326_callback()
|
||||
}
|
||||
break;
|
||||
case FY326_BIND2:
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_TX_DS))
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS))
|
||||
{ // TX data sent -> switch to RX mode
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
NRF24L01_FlushRx();
|
||||
@@ -138,6 +188,9 @@ uint16_t FY326_callback()
|
||||
return FY326_PACKET_CHKTIME;
|
||||
break;
|
||||
case FY326_DATA:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(FY326_PACKET_PERIOD);
|
||||
#endif
|
||||
FY326_send_packet(0);
|
||||
break;
|
||||
}
|
||||
@@ -151,16 +204,24 @@ static void __attribute__((unused)) FY326_initialize_txid()
|
||||
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 = 0;
|
||||
bind_counter = FY326_BIND_COUNT;
|
||||
FY326_initialize_txid();
|
||||
FY326_init();
|
||||
phase=FY326_BIND1;
|
||||
if(sub_protocol==FY319)
|
||||
{
|
||||
phase=FY319_BIND1;
|
||||
}
|
||||
else
|
||||
phase=FY326_BIND1;
|
||||
return FY326_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,49 +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, };
|
||||
|
||||
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)
|
||||
{
|
||||
case V9X9:
|
||||
if(Servo_AUX1)
|
||||
if(CH5_SW)
|
||||
packet[12] |= FLAG_V9X9_FLIP;
|
||||
if(Servo_AUX2)
|
||||
if(CH6_SW)
|
||||
packet[12] |= FLAG_V9X9_LED;
|
||||
if(Servo_AUX3)
|
||||
if(CH7_SW)
|
||||
packet[10] |= FLAG_V9X9_CAMERA;
|
||||
if(Servo_AUX4)
|
||||
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_AUX1)
|
||||
if(CH5_SW)
|
||||
packet[14] |= FLAG_V6X6_FLIP;
|
||||
if(Servo_AUX2)
|
||||
if(CH6_SW)
|
||||
packet[14] |= FLAG_V6X6_LED;
|
||||
if(Servo_AUX3)
|
||||
if(CH7_SW)
|
||||
packet[14] |= FLAG_V6X6_CAMERA;
|
||||
if(Servo_AUX4)
|
||||
if(CH8_SW)
|
||||
packet[14] |= FLAG_V6X6_VIDEO;
|
||||
if(Servo_AUX5)
|
||||
if(CH9_SW)
|
||||
{
|
||||
packet[13] |= FLAG_V6X6_HLESS1;
|
||||
packet[14] |= FLAG_V6X6_HLESS2;
|
||||
}
|
||||
if(Servo_AUX6) //use option to manipulate these bytes
|
||||
if(CH10_SW)
|
||||
packet[14] |= FLAG_V6X6_RTH;
|
||||
if(Servo_AUX7)
|
||||
if(CH11_SW)
|
||||
packet[14] |= FLAG_V6X6_XCAL;
|
||||
if(Servo_AUX8)
|
||||
if(CH12_SW)
|
||||
packet[14] |= FLAG_V6X6_YCAL;
|
||||
packet[15] = 0x10; // unknown
|
||||
packet[16] = 0x10; // unknown
|
||||
@@ -103,20 +99,20 @@ static void __attribute__((unused)) 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_AUX1)
|
||||
if(CH5_SW)
|
||||
packet[14] = FLAG_V912_BTMBTN;
|
||||
if(Servo_AUX2)
|
||||
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;
|
||||
@@ -124,6 +120,10 @@ static void __attribute__((unused)) 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;
|
||||
}
|
||||
@@ -133,10 +133,10 @@ 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];
|
||||
@@ -144,66 +144,104 @@ static void __attribute__((unused)) flysky_build_packet(uint8_t init)
|
||||
packet[4] = rx_tx_addr[0];
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
packet[5 + i*2]=Servo_data[CH_AETR[i]]&0xFF; //low byte of servo timing(1000-2000us)
|
||||
packet[6 + i*2]=(Servo_data[CH_AETR[i]]>>8)&0xFF; //high byte of servo timing(1000-2000us)
|
||||
uint16_t temp=convert_channel_ppm(CH_AETR[i]);
|
||||
if(sub_protocol == CX20 && i==CH2) //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();
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM tx_channels[16][16] = {
|
||||
{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},
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
flysky_build_packet(0);
|
||||
A7105_WriteData(21, pgm_read_byte_near(&tx_channels[chanrow][chancol])-chanoffset);
|
||||
chancol = (chancol + 1) % 16;
|
||||
if (! chancol) //Keep transmit power updated
|
||||
A7105_SetPower();
|
||||
}
|
||||
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.
|
||||
A7105_WriteData(21, hopping_frequency[hopping_frequency_no & 0x0F]);
|
||||
A7105_SetPower();
|
||||
}
|
||||
hopping_frequency_no++;
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initFlySky() {
|
||||
A7105_Init(INIT_FLYSKY); //flysky_init();
|
||||
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}
|
||||
};
|
||||
|
||||
uint16_t initFlySky()
|
||||
{
|
||||
uint8_t chanrow;
|
||||
uint8_t chanoffset;
|
||||
uint8_t temp;
|
||||
|
||||
A7105_Init();
|
||||
|
||||
if ((rx_tx_addr[3]&0xF0) > 0x90) // limit offset to 9 as higher values don't work with some RX (ie V912)
|
||||
// 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;
|
||||
chancol=0;
|
||||
chanoffset=rx_tx_addr[3]/16;
|
||||
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
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(sub_protocol==CX20)
|
||||
packet_period=3984;
|
||||
else
|
||||
packet_period=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.
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
bind_counter = FLYSKY_BIND_COUNT;
|
||||
else
|
||||
bind_counter = 0;
|
||||
return 2400;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
106
Multiprotocol/Flyzone_a7105.ino
Normal file
106
Multiprotocol/Flyzone_a7105.ino
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
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 FZ-410 TX
|
||||
|
||||
#if defined(FLYZONE_A7105_INO)
|
||||
|
||||
#include "iface_a7105.h"
|
||||
|
||||
//#define FLYZONE_FORCEID
|
||||
|
||||
#define FLYZONE_BIND_COUNT 220 // 5 sec
|
||||
#define FLYZONE_BIND_CH 0x18 // TX, RX for bind end is 0x17
|
||||
|
||||
static void __attribute__((unused)) flyzone_build_packet()
|
||||
{
|
||||
packet[0] = 0xA5;
|
||||
packet[1] = rx_tx_addr[2];
|
||||
packet[2] = rx_tx_addr[3];
|
||||
packet[3] = convert_channel_8b(AILERON); //00..80..FF
|
||||
packet[4] = convert_channel_8b(ELEVATOR); //00..80..FF
|
||||
packet[5] = convert_channel_8b(THROTTLE); //00..FF
|
||||
packet[6] = convert_channel_8b(RUDDER); //00..80..FF
|
||||
packet[7] = convert_channel_8b(CH5); //00..80..FF
|
||||
}
|
||||
|
||||
uint16_t ReadFlyzone()
|
||||
{
|
||||
#ifndef FORCE_FLYZONE_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[0] = 0x1B;
|
||||
packet[1] = rx_tx_addr[2];
|
||||
packet[2] = rx_tx_addr[3];
|
||||
A7105_WriteData(3, FLYZONE_BIND_CH);
|
||||
if (bind_counter--==0)
|
||||
BIND_DONE;
|
||||
return 22700;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(phase>19)
|
||||
{
|
||||
phase=0;
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(20*1500);
|
||||
#endif
|
||||
flyzone_build_packet();
|
||||
A7105_WriteData(8, hopping_frequency[0]);
|
||||
A7105_SetPower();
|
||||
}
|
||||
else
|
||||
{
|
||||
A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[(phase&0x02)>>1]);
|
||||
A7105_Strobe(A7105_TX);
|
||||
}
|
||||
phase++;
|
||||
}
|
||||
return 1500;
|
||||
}
|
||||
|
||||
uint16_t initFlyzone()
|
||||
{
|
||||
A7105_Init();
|
||||
|
||||
hopping_frequency[0]=((random(0xfefefefe) & 0x0F)+2)<<2;
|
||||
hopping_frequency[1]=hopping_frequency[0]+0x50;
|
||||
|
||||
#ifdef FLYZONE_FORCEID
|
||||
rx_tx_addr[2]=0x35;
|
||||
rx_tx_addr[3]=0xD0;
|
||||
hopping_frequency[0]=0x18;
|
||||
hopping_frequency[1]=0x68;
|
||||
#endif
|
||||
|
||||
phase=255;
|
||||
bind_counter = FLYZONE_BIND_COUNT;
|
||||
return 2400;
|
||||
}
|
||||
#endif
|
||||
// Normal packet is 8 bytes: 0xA5 0xAF 0x59 0x84 0x7A 0x00 0x80 0xFF
|
||||
// Protocol is using AETR channel order, 1 byte per channel 00..80..FF including trim. Channels are in packet [3,4,5,6].
|
||||
// packet[0,1,2,7] values are constant in normal mode.
|
||||
// packet[0]=0xA5 -> normal mode
|
||||
// packet[1,2] ->ID
|
||||
// packet[7]=0xFF -> ???
|
||||
// Channel values are updated every 30ms which is quite slow, slower than PPM...
|
||||
// Packets are sent every 1500µs on 2 different channels. 2 times on first channel, 2 times on second channel and restart. The channels are changing between the files 0x08, 0x58 and 0x18, 0x68.
|
||||
//
|
||||
// Bind is sending 3 bytes on channel 0x18: 0x1B 0x35 0xD0 every 22.7ms
|
||||
// packet[0]=0x1B -> bind mode
|
||||
// packet[1,2] ->ID
|
||||
// It listens for the model on channel 0x17 and recieves 0x1B 0x35 0xD0 when the plane accepts bind.
|
||||
229
Multiprotocol/FrSkyDVX_common.ino
Normal file
229
Multiprotocol/FrSkyDVX_common.ino
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/******************************/
|
||||
/** FrSky D and X routines **/
|
||||
/******************************/
|
||||
|
||||
#if defined(FRSKYX_CC2500_INO) || defined(FRSKY_RX_CC2500_INO)
|
||||
//**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) ;
|
||||
}
|
||||
uint16_t FrSkyX_crc(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;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#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
|
||||
@@ -13,48 +13,13 @@
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(FRSKY_CC2500_INO)
|
||||
#if defined(FRSKYD_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
|
||||
};
|
||||
*/
|
||||
|
||||
static void __attribute__((unused)) frsky2way_init(uint8_t bind)
|
||||
{
|
||||
// Configure cc2500 for tx mode
|
||||
CC2500_Reset();
|
||||
//
|
||||
for(uint8_t i=0;i<36;i++)
|
||||
{
|
||||
uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]);
|
||||
uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]);
|
||||
|
||||
if(reg==CC2500_0C_FSCTRL0)
|
||||
val=option;
|
||||
else
|
||||
if(reg==CC2500_1B_AGCCTRL2)
|
||||
val=bind ? 0x43 : 0x03;
|
||||
CC2500_WriteReg(reg,val);
|
||||
}
|
||||
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
FRSKY_init_cc2500(FRSKYD_cc2500_conf);
|
||||
|
||||
CC2500_WriteReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]);
|
||||
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05);
|
||||
@@ -66,16 +31,6 @@ static void __attribute__((unused)) frsky2way_init(uint8_t bind)
|
||||
//#######END INIT########
|
||||
}
|
||||
|
||||
static uint8_t __attribute__((unused)) 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;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -87,11 +42,11 @@ static void __attribute__((unused)) frsky2way_build_bind_packet()
|
||||
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[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;
|
||||
@@ -140,15 +95,16 @@ static void __attribute__((unused)) frsky2way_data_frame()
|
||||
|
||||
uint16_t initFrSky_2way()
|
||||
{
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
{
|
||||
Frsky_init_hop();
|
||||
packet_count=0;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
frsky2way_init(1);
|
||||
state = FRSKY_BIND;//
|
||||
state = FRSKY_BIND;
|
||||
}
|
||||
else
|
||||
{
|
||||
frsky2way_init(0);
|
||||
state = FRSKY_DATA2;
|
||||
state = FRSKY_BIND_DONE;
|
||||
}
|
||||
return 10000;
|
||||
}
|
||||
@@ -163,7 +119,10 @@ uint16_t ReadFrSky_2way()
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
|
||||
CC2500_Strobe(CC2500_SFRX);//0x3A
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
state++;
|
||||
if(IS_BIND_DONE)
|
||||
state = FRSKY_BIND_DONE;
|
||||
else
|
||||
state++;
|
||||
return 9000;
|
||||
}
|
||||
if (state == FRSKY_BIND_DONE)
|
||||
@@ -185,7 +144,7 @@ uint16_t ReadFrSky_2way()
|
||||
{ //telemetry receive
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[counter % 47]);
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
|
||||
state++;
|
||||
return 1300;
|
||||
@@ -194,20 +153,44 @@ uint16_t ReadFrSky_2way()
|
||||
{
|
||||
if (state == FRSKY_DATA1)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(9000);
|
||||
#endif
|
||||
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if (len && len<=MAX_PKT)//27 bytes
|
||||
{
|
||||
CC2500_ReadData(pkt, len); //received telemetry packets
|
||||
if (len && len<=(0x11+3))// 20bytes
|
||||
{
|
||||
CC2500_ReadData(packet_in, len); //received telemetry packets
|
||||
#if defined(TELEMETRY)
|
||||
//parse telemetry packet here
|
||||
frsky_check_telemetry(pkt,len); //check if valid telemetry packets and buffer them.
|
||||
#endif
|
||||
}
|
||||
if(packet_in[len-1] & 0x80)
|
||||
{//with valid crc
|
||||
packet_count=0;
|
||||
frsky_check_telemetry(packet_in,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
|
||||
packet_in[6]=0;//no user frames.
|
||||
#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_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();
|
||||
168
Multiprotocol/FrSkyV_cc2500.ino
Normal file
168
Multiprotocol/FrSkyV_cc2500.ino
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
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
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(9006);
|
||||
#endif
|
||||
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,4 +1,3 @@
|
||||
|
||||
/* **************************
|
||||
* By Midelic on RCGroups *
|
||||
**************************
|
||||
@@ -20,316 +19,424 @@
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
uint8_t chanskip;
|
||||
uint8_t channr;
|
||||
uint8_t counter_rst;
|
||||
uint8_t ctr;
|
||||
uint8_t FS_flag=0;
|
||||
uint8_t seq_last_sent;
|
||||
uint8_t seq_last_rcvd;
|
||||
uint8_t FrSkyX_chanskip;
|
||||
uint8_t FrSkyX_TX_Seq, FrSkyX_TX_IN_Seq;
|
||||
uint8_t FrSkyX_RX_Seq ;
|
||||
|
||||
const PROGMEM uint8_t hop_data[]={
|
||||
0x02, 0xD4, 0xBB, 0xA2, 0x89,
|
||||
0x70, 0x57, 0x3E, 0x25, 0x0C,
|
||||
0xDE, 0xC5, 0xAC, 0x93, 0x7A,
|
||||
0x61, 0x48, 0x2F, 0x16, 0xE8,
|
||||
0xCF, 0xB6, 0x9D, 0x84, 0x6B,
|
||||
0x52, 0x39, 0x20, 0x07, 0xD9,
|
||||
0xC0, 0xA7, 0x8E, 0x75, 0x5C,
|
||||
0x43, 0x2A, 0x11, 0xE3, 0xCA,
|
||||
0xB1, 0x98, 0x7F, 0x66, 0x4D,
|
||||
0x34, 0x1B, 0x00, 0x1D, 0x03
|
||||
};
|
||||
#ifdef SPORT_SEND
|
||||
struct t_FrSkyX_TX_Frame
|
||||
{
|
||||
uint8_t count;
|
||||
uint8_t payload[8];
|
||||
} ;
|
||||
// Store FrskyX telemetry
|
||||
struct t_FrSkyX_TX_Frame FrSkyX_TX_Frames[4] ;
|
||||
#endif
|
||||
|
||||
static uint8_t __attribute__((unused)) hop(uint8_t byte)
|
||||
{
|
||||
return pgm_read_byte_near(&hop_data[byte]);
|
||||
}
|
||||
#define FrSkyX_FAILSAFE_TIMEOUT 1032
|
||||
|
||||
static void __attribute__((unused)) set_start(uint8_t ch )
|
||||
static void __attribute__((unused)) FrSkyX_set_start(uint8_t ch )
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, calData[ch][0]);
|
||||
CC2500_WriteReg(CC2500_24_FSCAL2, calData[ch][1]);
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[ch][2]);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, ch==47? 0:pgm_read_word(&hop_data[ch]));
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[ch]);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[ch]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frskyX_init()
|
||||
static void __attribute__((unused)) FrSkyX_init()
|
||||
{
|
||||
CC2500_Reset();
|
||||
|
||||
for(uint8_t i=0;i<36;i++)
|
||||
{
|
||||
uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]);
|
||||
uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]);
|
||||
|
||||
if(reg==CC2500_06_PKTLEN)
|
||||
val=0x1E;
|
||||
else
|
||||
if(reg==CC2500_08_PKTCTRL0)
|
||||
val=0x01;
|
||||
else
|
||||
if(reg==CC2500_0B_FSCTRL1)
|
||||
val=0x0A;
|
||||
else
|
||||
if(reg==CC2500_10_MDMCFG4)
|
||||
val=0x7B;
|
||||
else
|
||||
if(reg==CC2500_11_MDMCFG3)
|
||||
val=0x61;
|
||||
else
|
||||
if(reg==CC2500_12_MDMCFG2)
|
||||
val=0x13;
|
||||
else
|
||||
if(reg==CC2500_15_DEVIATN)
|
||||
val=0x51;
|
||||
|
||||
CC2500_WriteReg(reg,val);
|
||||
}
|
||||
|
||||
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x04);
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
FRSKY_init_cc2500((sub_protocol&2)?FRSKYXEU_cc2500_conf:FRSKYX_cc2500_conf); // LBT or FCC
|
||||
//
|
||||
for(uint8_t c=0;c < 47;c++)
|
||||
for(uint8_t c=0;c < 48;c++)
|
||||
{//calibrate hop channels
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR,pgm_read_word(&hop_data[c]));
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR,hopping_frequency[c]);
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);//
|
||||
calData[c][0] = CC2500_ReadReg(CC2500_23_FSCAL3);
|
||||
calData[c][1] = CC2500_ReadReg(CC2500_24_FSCAL2);
|
||||
calData[c][2] = CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
calData[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
}
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR,0x00);
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);
|
||||
calData[47][0] = CC2500_ReadReg(CC2500_23_FSCAL3);
|
||||
calData[47][1] = CC2500_ReadReg(CC2500_24_FSCAL2);
|
||||
calData[47][2] = CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
//#######END INIT########
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) initialize_data(uint8_t adr)
|
||||
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);
|
||||
}
|
||||
/*
|
||||
static uint8_t __attribute__((unused)) crc_Byte( uint8_t byte )
|
||||
{
|
||||
crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ byte) & 0xFF]);
|
||||
return byte;
|
||||
}
|
||||
*/
|
||||
static uint16_t __attribute__((unused)) crc_x(uint8_t *data, uint8_t len)
|
||||
|
||||
static void __attribute__((unused)) FrSkyX_build_bind_packet()
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
for(uint8_t i=0; i < len; i++)
|
||||
crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ *data++) & 0xFF]);
|
||||
return crc;
|
||||
}
|
||||
|
||||
// 0-2047, 0 = 817, 1024 = 1500, 2047 = 2182
|
||||
//64=860,1024=1500,1984=2140//Taranis 125%
|
||||
|
||||
static uint16_t __attribute__((unused)) scaleForPXX( uint8_t i )
|
||||
{ //mapped 860,2140(125%) range to 64,1984(PXX values);
|
||||
return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frskyX_build_bind_packet()
|
||||
{
|
||||
packet[0] = 0x1D;
|
||||
packet[1] = 0x03;
|
||||
packet[2] = 0x01;
|
||||
//
|
||||
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] = pgm_read_word(&hop_data[idx++]);
|
||||
packet[7] = pgm_read_word(&hop_data[idx++]);
|
||||
packet[8] = pgm_read_word(&hop_data[idx++]);
|
||||
packet[9] = pgm_read_word(&hop_data[idx++]);
|
||||
packet[10] = pgm_read_word(&hop_data[idx++]);
|
||||
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;
|
||||
//
|
||||
memset(&packet[13], 0, 15);
|
||||
uint16_t lcrc = crc_x(&packet[3], 25);
|
||||
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
|
||||
memset(&packet[13], 0, limit - 13);
|
||||
if(binding_idx&0x01)
|
||||
memcpy(&packet[13],(void *)"\x55\xAA\x5A\xA5",4); // Telem off
|
||||
if(binding_idx&0x02)
|
||||
memcpy(&packet[17],(void *)"\x55\xAA\x5A\xA5",4); // CH9-16
|
||||
//
|
||||
packet[28] = lcrc >> 8;
|
||||
packet[29] = lcrc;
|
||||
uint16_t lcrc = FrSkyX_crc(&packet[3], limit-3);
|
||||
//
|
||||
packet[limit++] = lcrc >> 8;
|
||||
packet[limit] = lcrc;
|
||||
//
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frskyX_data_frame()
|
||||
// 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 FrSkyX_FAILSAFE_TIME 1032
|
||||
static void __attribute__((unused)) FrSkyX_build_packet()
|
||||
{
|
||||
//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 lpass;
|
||||
static uint8_t chan_offset=0;
|
||||
uint16_t chan_0 ;
|
||||
uint16_t chan_1 ;
|
||||
uint8_t startChan = 0;
|
||||
//
|
||||
packet[0] = 0x1D;
|
||||
// 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 > FrSkyX_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_VALUES_off;
|
||||
}
|
||||
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] = (ctr<<6)+channr;
|
||||
packet[5] = counter_rst;
|
||||
packet[4] = (FrSkyX_chanskip<<6)|hopping_frequency_no;
|
||||
packet[5] = FrSkyX_chanskip>>2;
|
||||
packet[6] = RX_num;
|
||||
//FLAGS 00 - standard packet
|
||||
//packet[7] = FLAGS 00 - standard packet
|
||||
//10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
|
||||
//20 - range check packet
|
||||
packet[7] = FS_flag;
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
packet[7] = FS_flag;
|
||||
#else
|
||||
packet[7] = 0;
|
||||
#endif
|
||||
packet[8] = 0;
|
||||
//
|
||||
if ( lpass & 1 )
|
||||
startChan += 8 ;
|
||||
|
||||
uint8_t startChan = chan_offset;
|
||||
for(uint8_t i = 0; i <12 ; i+=3)
|
||||
{//12 bytes
|
||||
chan_0 = scaleForPXX(startChan);
|
||||
if(lpass & 1 )
|
||||
chan_0+=2048;
|
||||
startChan+=1;
|
||||
{//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++;
|
||||
//
|
||||
chan_1 = scaleForPXX(startChan);
|
||||
if(lpass & 1 )
|
||||
chan_1+= 2048;
|
||||
startChan+=1;
|
||||
#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] = 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] = seq_last_sent << 4 | seq_last_rcvd;//8 at start
|
||||
if (seq_last_sent < 0x08 && seq_last_rcvd < 8)
|
||||
seq_last_sent = (seq_last_sent + 1) % 4;
|
||||
else if (seq_last_rcvd == 0x00)
|
||||
seq_last_sent = 1;
|
||||
|
||||
if(sub_protocol== CH_8 )// in X8 mode send only 8ch every 9ms
|
||||
lpass = 0 ;
|
||||
if(sub_protocol & 0x01 ) //In X8 mode send only 8ch every 9ms
|
||||
chan_offset = 0 ;
|
||||
else
|
||||
lpass += 1 ;
|
||||
chan_offset^=0x08;
|
||||
|
||||
for (uint8_t i=22;i<28;i++)
|
||||
//sequence and send SPort
|
||||
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
|
||||
for (uint8_t i=22;i<limit;i++)
|
||||
packet[i]=0;
|
||||
uint16_t lcrc = crc_x(&packet[3], 25);
|
||||
|
||||
packet[28]=lcrc>>8;//high byte
|
||||
packet[29]=lcrc;//low byte
|
||||
packet[21] = FrSkyX_RX_Seq << 4; //TX=8 at startup
|
||||
#ifdef SPORT_SEND
|
||||
if (FrSkyX_TX_IN_Seq!=0xFF)
|
||||
{//RX has replied at least once
|
||||
if (FrSkyX_TX_IN_Seq & 0x08)
|
||||
{//Request init
|
||||
//debugln("Init");
|
||||
FrSkyX_TX_Seq = 0 ;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
FrSkyX_TX_Frames[i].count=0; //Discard frames in current output buffer
|
||||
}
|
||||
else if (FrSkyX_TX_IN_Seq & 0x04)
|
||||
{//Retransmit the requested packet
|
||||
debugln("Retry:%d",FrSkyX_TX_IN_Seq&0x03);
|
||||
packet[21] |= FrSkyX_TX_IN_Seq&0x03;
|
||||
packet[22] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq&0x03].count;
|
||||
for (uint8_t i=23;i<23+FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq&0x03].count;i++)
|
||||
packet[i] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq&0x03].payload[i];
|
||||
}
|
||||
else if ( FrSkyX_TX_Seq != 0x08 )
|
||||
{
|
||||
if(FrSkyX_TX_Seq==FrSkyX_TX_IN_Seq)
|
||||
{//Send packet from the incoming radio buffer
|
||||
//debugln("Send:%d",FrSkyX_TX_Seq);
|
||||
packet[21] |= FrSkyX_TX_Seq;
|
||||
uint8_t nbr_bytes=0;
|
||||
for (uint8_t i=23;i<limit;i++)
|
||||
{
|
||||
if(SportHead==SportTail)
|
||||
break; //buffer empty
|
||||
packet[i]=SportData[SportHead];
|
||||
FrSkyX_TX_Frames[FrSkyX_TX_Seq].payload[i-23]=SportData[SportHead];
|
||||
SportHead=(SportHead+1) & (MAX_SPORT_BUFFER-1);
|
||||
nbr_bytes++;
|
||||
}
|
||||
packet[22]=nbr_bytes;
|
||||
FrSkyX_TX_Frames[FrSkyX_TX_Seq].count=nbr_bytes;
|
||||
if(nbr_bytes)
|
||||
{//Check the buffer status
|
||||
uint8_t used = SportTail;
|
||||
if ( SportHead > SportTail )
|
||||
used += MAX_SPORT_BUFFER - SportHead ;
|
||||
else
|
||||
used -= SportHead ;
|
||||
if ( used < (MAX_SPORT_BUFFER>>1) )
|
||||
{
|
||||
DATA_BUFFER_LOW_off;
|
||||
debugln("Ok buf:%d",used);
|
||||
}
|
||||
}
|
||||
FrSkyX_TX_Seq = ( FrSkyX_TX_Seq + 1 ) & 0x03 ; //Next iteration send next packet
|
||||
}
|
||||
else
|
||||
{//Not in sequence somehow, transmit what the receiver wants but why not asking for retransmit...
|
||||
//debugln("RX_Seq:%d,TX:%d",FrSkyX_TX_IN_Seq,FrSkyX_TX_Seq);
|
||||
packet[21] |= FrSkyX_TX_IN_Seq;
|
||||
packet[22] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq].count;
|
||||
for (uint8_t i=23;i<23+FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq].count;i++)
|
||||
packet[i] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq].payload[i-23];
|
||||
}
|
||||
}
|
||||
else
|
||||
packet[21] |= 0x08 ; //FrSkyX_TX_Seq=8 at startup
|
||||
}
|
||||
if(packet[22])
|
||||
{//Debug
|
||||
debug("SP: ");
|
||||
for(uint8_t i=0;i<packet[22];i++)
|
||||
debug("%02X ",packet[23+i]);
|
||||
debugln("");
|
||||
}
|
||||
#else
|
||||
packet[21] |= FrSkyX_TX_Seq ;//TX=8 at startup
|
||||
if ( !(FrSkyX_TX_IN_Seq & 0xF8) )
|
||||
FrSkyX_TX_Seq = ( FrSkyX_TX_Seq + 1 ) & 0x03 ; // Next iteration send next packet
|
||||
#endif // SPORT_SEND
|
||||
|
||||
uint16_t lcrc = FrSkyX_crc(&packet[3], limit-3);
|
||||
packet[limit++]=lcrc>>8;//high byte
|
||||
packet[limit]=lcrc;//low byte
|
||||
}
|
||||
|
||||
uint16_t ReadFrSkyX()
|
||||
{
|
||||
static bool transmit=true;
|
||||
#ifdef DEBUG_SERIAL
|
||||
static uint16_t fr_time=0;
|
||||
#endif
|
||||
|
||||
switch(state)
|
||||
{
|
||||
default:
|
||||
set_start(47);
|
||||
FrSkyX_set_start(47);
|
||||
CC2500_SetPower();
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
//
|
||||
frskyX_build_bind_packet();
|
||||
FrSkyX_build_bind_packet();
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
state++;
|
||||
if(IS_BIND_DONE)
|
||||
state = FRSKY_BIND_DONE;
|
||||
else
|
||||
state++;
|
||||
return 9000;
|
||||
case FRSKY_BIND_DONE:
|
||||
initialize_data(0);
|
||||
channr=0;
|
||||
FrSkyX_initialize_data(0);
|
||||
hopping_frequency_no=0;
|
||||
BIND_DONE;
|
||||
state++;
|
||||
break;
|
||||
state++; //FRSKY_DATA1
|
||||
break;
|
||||
case FRSKY_DATA5:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(9000);
|
||||
#endif
|
||||
#if defined TELEMETRY
|
||||
telemetry_link=1; //Send telemetry out anyway
|
||||
#endif
|
||||
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if (len && (len<=(0x0E + 3))) //Telemetry frame is 17
|
||||
{
|
||||
packet_count=0;
|
||||
CC2500_ReadData(packet_in, len);
|
||||
#if defined TELEMETRY
|
||||
frsky_check_telemetry(packet_in,len); //Check and parse telemetry packets
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_count++;
|
||||
//debugln("M %d",packet_count);
|
||||
// restart sequence on missed packet - might need count or timeout instead of one missed
|
||||
if(packet_count>100)
|
||||
{//~1sec
|
||||
FrSkyX_TX_Seq = 0x08 ; //Request init
|
||||
FrSkyX_TX_IN_Seq = 0xFF ; //No sequence received yet
|
||||
#ifdef SPORT_SEND
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
FrSkyX_TX_Frames[i].count=0; //Discard frames in current output buffer
|
||||
#endif
|
||||
packet_count=0;
|
||||
#if defined TELEMETRY
|
||||
telemetry_lost=1;
|
||||
telemetry_link=0; //Stop sending telemetry
|
||||
#endif
|
||||
}
|
||||
CC2500_Strobe(CC2500_SFRX); //Flush the RXFIFO
|
||||
}
|
||||
FrSkyX_build_packet();
|
||||
state = FRSKY_DATA1;
|
||||
#if not defined(FRSKYX_LBT)
|
||||
return 500;
|
||||
#endif // for LBT just continue to DATA1 right away
|
||||
case FRSKY_DATA1:
|
||||
LED_ON;
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
set_start(channr);
|
||||
CC2500_SetPower();
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
channr = (channr+chanskip)%47;
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
//
|
||||
frskyX_data_frame();
|
||||
if ( prev_option != option )
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); //Frequency offset hack
|
||||
prev_option = option ;
|
||||
}
|
||||
FrSkyX_set_start(hopping_frequency_no);
|
||||
transmit=true;
|
||||
#ifdef FRSKYX_LBT
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
delayMicroseconds(90); //Wait for the freq to stabilize
|
||||
CC2500_Strobe(CC2500_SRX); //Acquire RSSI
|
||||
state++;
|
||||
return 5500;
|
||||
return 500;
|
||||
case FRSKY_DATA2:
|
||||
uint8_t rssi;
|
||||
rssi = CC2500_ReadReg(CC2500_34_RSSI | CC2500_READ_BURST); // 0.5 db/count, RSSI value read from the RSSI status register is a 2's complement number
|
||||
if ((sub_protocol & 2) && rssi > 72 && rssi < 128) //LBT and RSSI between -36 and -8.5 dBm
|
||||
{
|
||||
transmit=false;
|
||||
debugln("Busy %d %d",hopping_frequency_no,rssi);
|
||||
}
|
||||
#endif
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
hopping_frequency_no = (hopping_frequency_no+FrSkyX_chanskip)%47;
|
||||
if(transmit)
|
||||
{
|
||||
#ifdef DEBUG_SERIAL
|
||||
uint16_t fr_cur=millis();
|
||||
fr_time=fr_cur-fr_time;
|
||||
if(fr_time!=9)
|
||||
debugln("Bad timing: %d",fr_time);
|
||||
fr_time=fr_cur;
|
||||
#endif
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
}
|
||||
state=FRSKY_DATA3;
|
||||
return 5200;
|
||||
case FRSKY_DATA3:
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
state++;
|
||||
return 200;
|
||||
case FRSKY_DATA3:
|
||||
case FRSKY_DATA4:
|
||||
CC2500_Strobe(CC2500_SRX);
|
||||
state++;
|
||||
return 3000;
|
||||
case FRSKY_DATA4:
|
||||
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if (len && (len<MAX_PKT))
|
||||
{
|
||||
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
|
||||
{
|
||||
counter++;
|
||||
// restart sequence on missed packet - might need count or timeout instead of one missed
|
||||
if(counter>100)
|
||||
{//~1sec
|
||||
seq_last_sent = 0;
|
||||
seq_last_rcvd = 8;
|
||||
counter=0;
|
||||
}
|
||||
}
|
||||
state = FRSKY_DATA1;
|
||||
return 300;
|
||||
return 3100;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t initFrSkyX()
|
||||
{
|
||||
while(!chanskip)
|
||||
{
|
||||
randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7));
|
||||
chanskip=random(0xfefefefe)%47;
|
||||
}
|
||||
while((chanskip-ctr)%4)
|
||||
ctr=(ctr+1)%4;
|
||||
|
||||
counter_rst=(chanskip-ctr)>>2;
|
||||
set_rx_tx_addr(MProtocol_id_master);
|
||||
Frsky_init_hop();
|
||||
packet_count=0;
|
||||
while(!FrSkyX_chanskip)
|
||||
FrSkyX_chanskip=random(0xfefefefe)%47;
|
||||
|
||||
//for test***************
|
||||
//rx_tx_addr[3]=0xB3;
|
||||
//rx_tx_addr[2]=0xFD;
|
||||
//************************
|
||||
frskyX_init();
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
//
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
FrSkyX_init();
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
state = FRSKY_BIND;
|
||||
initialize_data(1);
|
||||
FrSkyX_initialize_data(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
state = FRSKY_DATA1;
|
||||
initialize_data(0);
|
||||
FrSkyX_initialize_data(0);
|
||||
}
|
||||
seq_last_sent = 0;
|
||||
seq_last_rcvd = 8;
|
||||
FrSkyX_TX_Seq = 0x08 ; // Request init
|
||||
FrSkyX_TX_IN_Seq = 0xFF ; // No sequence received yet
|
||||
#ifdef SPORT_SEND
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
FrSkyX_TX_Frames[i].count=0; // discard frames in current output buffer
|
||||
SportHead=SportTail=0; // empty data buffer
|
||||
#endif
|
||||
FrSkyX_RX_Seq = 0 ; // Seq 0 to start with
|
||||
binding_idx=0; // CH1-8 and Telem on
|
||||
return 10000;
|
||||
}
|
||||
#endif
|
||||
454
Multiprotocol/FrSky_Rx_cc2500.ino
Normal file
454
Multiprotocol/FrSky_Rx_cc2500.ino
Normal file
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
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_RX_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
#define FRSKY_RX_D16FCC_LENGTH 32
|
||||
#define FRSKY_RX_D16LBT_LENGTH 35
|
||||
#define FRSKY_RX_D8_LENGTH 20
|
||||
#define FRSKY_RX_FORMATS 3
|
||||
|
||||
enum
|
||||
{
|
||||
FRSKY_RX_D16FCC = 0,
|
||||
FRSKY_RX_D16LBT,
|
||||
FRSKY_RX_D8
|
||||
};
|
||||
|
||||
enum {
|
||||
FRSKY_RX_TUNE_START,
|
||||
FRSKY_RX_TUNE_LOW,
|
||||
FRSKY_RX_TUNE_HIGH,
|
||||
FRSKY_RX_BIND,
|
||||
FRSKY_RX_DATA,
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t frsky_rx_common_reg[][2] = {
|
||||
{CC2500_02_IOCFG0, 0x01},
|
||||
{CC2500_18_MCSM0, 0x18},
|
||||
{CC2500_07_PKTCTRL1, 0x04},
|
||||
{CC2500_3E_PATABLE, 0xFF},
|
||||
{CC2500_0C_FSCTRL0, 0},
|
||||
{CC2500_0D_FREQ2, 0x5C},
|
||||
{CC2500_13_MDMCFG1, 0x23},
|
||||
{CC2500_14_MDMCFG0, 0x7A},
|
||||
{CC2500_19_FOCCFG, 0x16},
|
||||
{CC2500_1A_BSCFG, 0x6C},
|
||||
{CC2500_1B_AGCCTRL2, 0x03},
|
||||
{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},
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t frsky_rx_d16fcc_reg[][2] = {
|
||||
{CC2500_17_MCSM1, 0x0C},
|
||||
{CC2500_0E_FREQ1, 0x76},
|
||||
{CC2500_0F_FREQ0, 0x27},
|
||||
{CC2500_06_PKTLEN, 0x1E},
|
||||
{CC2500_08_PKTCTRL0, 0x01},
|
||||
{CC2500_0B_FSCTRL1, 0x0A},
|
||||
{CC2500_10_MDMCFG4, 0x7B},
|
||||
{CC2500_11_MDMCFG3, 0x61},
|
||||
{CC2500_12_MDMCFG2, 0x13},
|
||||
{CC2500_15_DEVIATN, 0x51},
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t frsky_rx_d16lbt_reg[][2] = {
|
||||
{CC2500_17_MCSM1, 0x0E},
|
||||
{CC2500_0E_FREQ1, 0x80},
|
||||
{CC2500_0F_FREQ0, 0x00},
|
||||
{CC2500_06_PKTLEN, 0x23},
|
||||
{CC2500_08_PKTCTRL0, 0x01},
|
||||
{CC2500_0B_FSCTRL1, 0x08},
|
||||
{CC2500_10_MDMCFG4, 0x7B},
|
||||
{CC2500_11_MDMCFG3, 0xF8},
|
||||
{CC2500_12_MDMCFG2, 0x03},
|
||||
{CC2500_15_DEVIATN, 0x53},
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t frsky_rx_d8_reg[][2] = {
|
||||
{CC2500_17_MCSM1, 0x0C},
|
||||
{CC2500_0E_FREQ1, 0x76},
|
||||
{CC2500_0F_FREQ0, 0x27},
|
||||
{CC2500_06_PKTLEN, 0x19},
|
||||
{CC2500_08_PKTCTRL0, 0x05},
|
||||
{CC2500_0B_FSCTRL1, 0x08},
|
||||
{CC2500_10_MDMCFG4, 0xAA},
|
||||
{CC2500_11_MDMCFG3, 0x39},
|
||||
{CC2500_12_MDMCFG2, 0x11},
|
||||
{CC2500_15_DEVIATN, 0x42},
|
||||
};
|
||||
|
||||
static uint8_t frsky_rx_chanskip;
|
||||
static int8_t frsky_rx_finetune;
|
||||
static uint8_t frsky_rx_format;
|
||||
|
||||
static void __attribute__((unused)) frsky_rx_strobe_rx()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
CC2500_Strobe(CC2500_SRX);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frsky_rx_initialise_cc2500() {
|
||||
const uint8_t frsky_rx_length[] = { FRSKY_RX_D16FCC_LENGTH, FRSKY_RX_D16LBT_LENGTH, FRSKY_RX_D8_LENGTH };
|
||||
packet_length = frsky_rx_length[frsky_rx_format];
|
||||
CC2500_Reset();
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
for (uint8_t i = 0; i < sizeof(frsky_rx_common_reg) / 2; i++)
|
||||
CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_common_reg[i][0]), pgm_read_byte_near(&frsky_rx_common_reg[i][1]));
|
||||
|
||||
switch (frsky_rx_format) {
|
||||
case FRSKY_RX_D16FCC:
|
||||
for (uint8_t i = 0; i < sizeof(frsky_rx_d16fcc_reg) / 2; i++)
|
||||
CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_d16fcc_reg[i][0]), pgm_read_byte_near(&frsky_rx_d16fcc_reg[i][1]));
|
||||
break;
|
||||
case FRSKY_RX_D16LBT:
|
||||
for (uint8_t i = 0; i < sizeof(frsky_rx_d16lbt_reg) / 2; i++)
|
||||
CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_d16lbt_reg[i][0]), pgm_read_byte_near(&frsky_rx_d16lbt_reg[i][1]));
|
||||
break;
|
||||
case FRSKY_RX_D8:
|
||||
for (uint8_t i = 0; i < sizeof(frsky_rx_d8_reg) / 2; i++)
|
||||
CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_d8_reg[i][0]), pgm_read_byte_near(&frsky_rx_d8_reg[i][1]));
|
||||
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // always check address
|
||||
CC2500_WriteReg(CC2500_09_ADDR, 0x03); // bind address
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
|
||||
break;
|
||||
}
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, 0); // bind channel
|
||||
rx_disable_lna = IS_POWER_FLAG_on;
|
||||
CC2500_SetTxRxMode(rx_disable_lna ? TXRX_OFF : RX_EN); // lna disable / enable
|
||||
frsky_rx_strobe_rx();
|
||||
delayMicroseconds(1000); // wait for RX to activate
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frsky_rx_set_channel(uint8_t channel)
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[channel]);
|
||||
if(frsky_rx_format == FRSKY_RX_D8)
|
||||
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[channel]);
|
||||
frsky_rx_strobe_rx();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frsky_rx_calibrate()
|
||||
{
|
||||
frsky_rx_strobe_rx();
|
||||
for (unsigned c = 0; c < 47; 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 uint8_t __attribute__((unused)) frskyx_rx_check_crc()
|
||||
{
|
||||
// check D8 checksum
|
||||
if (frsky_rx_format == FRSKY_RX_D8)
|
||||
return (packet[packet_length-1] & 0x80) == 0x80; // check CRC_OK flag in status byte 2
|
||||
// check D16 checksum
|
||||
uint8_t limit = packet_length - 4;
|
||||
uint16_t lcrc = FrSkyX_crc(&packet[3], limit - 3); // computed crc
|
||||
uint16_t rcrc = (packet[limit] << 8) | (packet[limit + 1] & 0xff); // received crc
|
||||
return lcrc == rcrc;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) frsky_rx_build_telemetry_packet()
|
||||
{
|
||||
uint16_t raw_channel[8];
|
||||
uint32_t bits = 0;
|
||||
uint8_t bitsavailable = 0;
|
||||
uint8_t idx = 0;
|
||||
uint8_t i;
|
||||
|
||||
if (frsky_rx_format == FRSKY_RX_D16FCC || frsky_rx_format == FRSKY_RX_D16LBT) {
|
||||
// decode D16 channels
|
||||
raw_channel[0] = ((packet[10] << 8) & 0xF00) | packet[9];
|
||||
raw_channel[1] = ((packet[11] << 4) & 0xFF0) | (packet[10] >> 4);
|
||||
raw_channel[2] = ((packet[13] << 8) & 0xF00) | packet[12];
|
||||
raw_channel[3] = ((packet[14] << 4) & 0xFF0) | (packet[13] >> 4);
|
||||
raw_channel[4] = ((packet[16] << 8) & 0xF00) | packet[15];
|
||||
raw_channel[5] = ((packet[17] << 4) & 0xFF0) | (packet[16] >> 4);
|
||||
raw_channel[6] = ((packet[19] << 8) & 0xF00) | packet[18];
|
||||
raw_channel[7] = ((packet[20] << 4) & 0xFF0) | (packet[19] >> 4);
|
||||
for (i = 0; i < 8; i++) {
|
||||
// ignore failsafe channels
|
||||
if(packet[7] != 0x10+(i<<1)) {
|
||||
uint8_t shifted = (raw_channel[i] & 0x800)>0;
|
||||
uint16_t channel_value = raw_channel[i] & 0x7FF;
|
||||
if (channel_value < 64)
|
||||
rx_rc_chan[shifted ? i + 8 : i] = 0;
|
||||
else
|
||||
rx_rc_chan[shifted ? i + 8 : i] = min(((channel_value - 64) << 4) / 15, 2047);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// decode D8 channels
|
||||
raw_channel[0] = ((packet[10] & 0x0F) << 8 | packet[6]);
|
||||
raw_channel[1] = ((packet[10] & 0xF0) << 4 | packet[7]);
|
||||
raw_channel[2] = ((packet[11] & 0x0F) << 8 | packet[8]);
|
||||
raw_channel[3] = ((packet[11] & 0xF0) << 4 | packet[9]);
|
||||
raw_channel[4] = ((packet[16] & 0x0F) << 8 | packet[12]);
|
||||
raw_channel[5] = ((packet[16] & 0xF0) << 4 | packet[13]);
|
||||
raw_channel[6] = ((packet[17] & 0x0F) << 8 | packet[14]);
|
||||
raw_channel[7] = ((packet[17] & 0xF0) << 4 | packet[15]);
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (raw_channel[i] < 1290)
|
||||
raw_channel[i] = 1290;
|
||||
rx_rc_chan[i] = min(((raw_channel[i] - 1290) << 4) / 15, 2047);
|
||||
}
|
||||
}
|
||||
|
||||
// buid telemetry packet
|
||||
packet_in[idx++] = RX_LQI;
|
||||
packet_in[idx++] = RX_RSSI;
|
||||
packet_in[idx++] = 0; // start channel
|
||||
packet_in[idx++] = frsky_rx_format == FRSKY_RX_D8 ? 8 : 16; // number of channels in packet
|
||||
|
||||
// pack channels
|
||||
for (i = 0; i < packet_in[3]; i++) {
|
||||
bits |= ((uint32_t)rx_rc_chan[i]) << bitsavailable;
|
||||
bitsavailable += 11;
|
||||
while (bitsavailable >= 8) {
|
||||
packet_in[idx++] = bits & 0xff;
|
||||
bits >>= 8;
|
||||
bitsavailable -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t initFrSky_Rx()
|
||||
{
|
||||
state = 0;
|
||||
frsky_rx_chanskip = 1;
|
||||
hopping_frequency_no = 0;
|
||||
rx_data_started = false;
|
||||
frsky_rx_finetune = 0;
|
||||
telemetry_link = 0;
|
||||
if (IS_BIND_IN_PROGRESS) {
|
||||
frsky_rx_format = FRSKY_RX_D8;
|
||||
frsky_rx_initialise_cc2500();
|
||||
phase = FRSKY_RX_TUNE_START;
|
||||
}
|
||||
else {
|
||||
uint16_t temp = FRSKY_RX_EEPROM_OFFSET;
|
||||
frsky_rx_format = eeprom_read_byte((EE_ADDR)temp++) % FRSKY_RX_FORMATS;
|
||||
rx_tx_addr[0] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
rx_tx_addr[1] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
rx_tx_addr[2] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
frsky_rx_finetune = eeprom_read_byte((EE_ADDR)temp++);
|
||||
for (uint8_t ch = 0; ch < 47; ch++)
|
||||
hopping_frequency[ch] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
frsky_rx_initialise_cc2500();
|
||||
frsky_rx_calibrate();
|
||||
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // FS_AUTOCAL = manual
|
||||
CC2500_WriteReg(CC2500_09_ADDR, rx_tx_addr[0]); // set address
|
||||
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // check address
|
||||
if (option == 0)
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
|
||||
else
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
frsky_rx_set_channel(hopping_frequency_no);
|
||||
phase = FRSKY_RX_DATA;
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
uint16_t FrSky_Rx_callback()
|
||||
{
|
||||
static uint32_t pps_timer=0;
|
||||
static uint8_t pps_counter=0;
|
||||
static int8_t read_retry = 0;
|
||||
static int8_t tune_low, tune_high;
|
||||
uint8_t len, ch;
|
||||
|
||||
if ((prev_option != option) && (phase >= FRSKY_RX_DATA)) {
|
||||
if (option == 0)
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
|
||||
else
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
prev_option = option;
|
||||
}
|
||||
|
||||
if (rx_disable_lna != IS_POWER_FLAG_on) {
|
||||
rx_disable_lna = IS_POWER_FLAG_on;
|
||||
CC2500_SetTxRxMode(rx_disable_lna ? TXRX_OFF : RX_EN);
|
||||
}
|
||||
|
||||
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
|
||||
switch(phase) {
|
||||
case FRSKY_RX_TUNE_START:
|
||||
if (len >= packet_length) {
|
||||
CC2500_ReadData(packet, packet_length);
|
||||
if(packet[1] == 0x03 && packet[2] == 0x01 && frskyx_rx_check_crc()) {
|
||||
rx_tx_addr[0] = packet[3]; // TXID
|
||||
rx_tx_addr[1] = packet[4]; // TXID
|
||||
frsky_rx_finetune = -127;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
|
||||
phase = FRSKY_RX_TUNE_LOW;
|
||||
frsky_rx_strobe_rx();
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
frsky_rx_format = (frsky_rx_format + 1) % FRSKY_RX_FORMATS; // switch to next format (D16FCC, D16LBT, D8)
|
||||
frsky_rx_initialise_cc2500();
|
||||
frsky_rx_finetune += 10;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
|
||||
frsky_rx_strobe_rx();
|
||||
return 18000;
|
||||
|
||||
case FRSKY_RX_TUNE_LOW:
|
||||
if (len >= packet_length) {
|
||||
CC2500_ReadData(packet, packet_length);
|
||||
if(packet[1] == 0x03 && packet[2] == 0x01 && frskyx_rx_check_crc() && packet[3] == rx_tx_addr[0] && packet[4] == rx_tx_addr[1]) {
|
||||
tune_low = frsky_rx_finetune;
|
||||
frsky_rx_finetune = 127;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
|
||||
phase = FRSKY_RX_TUNE_HIGH;
|
||||
frsky_rx_strobe_rx();
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
frsky_rx_finetune += 1;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
|
||||
frsky_rx_strobe_rx();
|
||||
return 18000;
|
||||
|
||||
case FRSKY_RX_TUNE_HIGH:
|
||||
if (len >= packet_length) {
|
||||
CC2500_ReadData(packet, packet_length);
|
||||
if(packet[1] == 0x03 && packet[2] == 0x01 && frskyx_rx_check_crc() && packet[3] == rx_tx_addr[0] && packet[4] == rx_tx_addr[1]) {
|
||||
tune_high = frsky_rx_finetune;
|
||||
frsky_rx_finetune = (tune_low + tune_high) / 2;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, (int8_t)frsky_rx_finetune);
|
||||
if(tune_low < tune_high)
|
||||
phase = FRSKY_RX_BIND;
|
||||
else
|
||||
phase = FRSKY_RX_TUNE_START;
|
||||
frsky_rx_strobe_rx();
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
frsky_rx_finetune -= 1;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
|
||||
frsky_rx_strobe_rx();
|
||||
return 18000;
|
||||
|
||||
case FRSKY_RX_BIND:
|
||||
if(len >= packet_length) {
|
||||
CC2500_ReadData(packet, packet_length);
|
||||
if(packet[1] == 0x03 && packet[2] == 0x01 && frskyx_rx_check_crc() && packet[3] == rx_tx_addr[0] && packet[4] == rx_tx_addr[1] && packet[5] <= 0x2D) {
|
||||
for (ch = 0; ch < 5; ch++)
|
||||
hopping_frequency[packet[5]+ch] = packet[6+ch];
|
||||
state |= 1 << (packet[5] / 5);
|
||||
if (state == 0x3ff) {
|
||||
debug("Bind complete: ");
|
||||
frsky_rx_calibrate();
|
||||
rx_tx_addr[2] = packet[12]; // RX # (D16)
|
||||
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // FS_AUTOCAL = manual
|
||||
CC2500_WriteReg(CC2500_09_ADDR, rx_tx_addr[0]); // set address
|
||||
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // check address
|
||||
phase = FRSKY_RX_DATA;
|
||||
frsky_rx_set_channel(hopping_frequency_no);
|
||||
// store format, finetune setting, txid, channel list
|
||||
uint16_t temp = FRSKY_RX_EEPROM_OFFSET;
|
||||
eeprom_write_byte((EE_ADDR)temp++, frsky_rx_format);
|
||||
debug("format=%d, ", frsky_rx_format);
|
||||
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[0]);
|
||||
debug("addr[0]=%02X, ", rx_tx_addr[0]);
|
||||
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[1]);
|
||||
debug("addr[1]=%02X, ", rx_tx_addr[1]);
|
||||
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[2]);
|
||||
debug("rx_num=%02X, ", rx_tx_addr[2]);
|
||||
eeprom_write_byte((EE_ADDR)temp++, frsky_rx_finetune);
|
||||
debugln("tune=%d", (int8_t)frsky_rx_finetune);
|
||||
for (ch = 0; ch < 47; ch++)
|
||||
{
|
||||
eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[ch]);
|
||||
debug("%02X ", hopping_frequency[ch]);
|
||||
}
|
||||
debugln("");
|
||||
BIND_DONE;
|
||||
}
|
||||
}
|
||||
frsky_rx_strobe_rx();
|
||||
}
|
||||
return 1000;
|
||||
|
||||
case FRSKY_RX_DATA:
|
||||
if (len >= packet_length) {
|
||||
CC2500_ReadData(packet, packet_length);
|
||||
if (packet[1] == rx_tx_addr[0] && packet[2] == rx_tx_addr[1] && frskyx_rx_check_crc() && (frsky_rx_format == FRSKY_RX_D8 || packet[6] == rx_tx_addr[2])) {
|
||||
RX_RSSI = packet[packet_length-2];
|
||||
if(RX_RSSI >= 128)
|
||||
RX_RSSI -= 128;
|
||||
else
|
||||
RX_RSSI += 128;
|
||||
// hop to next channel
|
||||
if (frsky_rx_format == FRSKY_RX_D16FCC || frsky_rx_format == FRSKY_RX_D16LBT)
|
||||
frsky_rx_chanskip = ((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2);
|
||||
hopping_frequency_no = (hopping_frequency_no + frsky_rx_chanskip) % 47;
|
||||
frsky_rx_set_channel(hopping_frequency_no);
|
||||
if (telemetry_link == 0) { // send channels to TX
|
||||
frsky_rx_build_telemetry_packet();
|
||||
telemetry_link = 1;
|
||||
}
|
||||
rx_data_started = true;
|
||||
read_retry = 0;
|
||||
pps_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
// packets per second
|
||||
if (millis() - pps_timer >= 1000) {
|
||||
pps_timer = millis();
|
||||
debugln("%d pps", pps_counter);
|
||||
RX_LQI = pps_counter;
|
||||
pps_counter = 0;
|
||||
}
|
||||
|
||||
// skip channel if no packet received in time
|
||||
if (read_retry++ >= 9) {
|
||||
hopping_frequency_no = (hopping_frequency_no + frsky_rx_chanskip) % 47;
|
||||
frsky_rx_set_channel(hopping_frequency_no);
|
||||
if(rx_data_started)
|
||||
read_retry = 0;
|
||||
else
|
||||
read_retry = -50; // retry longer until first packet is catched
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
#endif
|
||||
231
Multiprotocol/GD00X_nrf24l01.ino
Normal file
231
Multiprotocol/GD00X_nrf24l01.ino
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
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();
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
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
|
||||
161
Multiprotocol/GW008_nrf24l01.ino
Normal file
161
Multiprotocol/GW008_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/>.
|
||||
*/
|
||||
// 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_SW, 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 850; // minimum value 750 for STM32
|
||||
}
|
||||
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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(GW008_PACKET_PERIOD);
|
||||
#endif
|
||||
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
|
||||
263
Multiprotocol/H8_3D_nrf24l01.ino
Normal file
263
Multiprotocol/H8_3D_nrf24l01.ino
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
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)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
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
|
||||
387
Multiprotocol/HOTT_cc2500.ino
Normal file
387
Multiprotocol/HOTT_cc2500.ino
Normal file
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
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(HOTT_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
//#define HOTT_FORCE_ID // Force ID of original dump
|
||||
|
||||
#define HOTT_TX_PACKET_LEN 50
|
||||
#define HOTT_RX_PACKET_LEN 22
|
||||
#define HOTT_PACKET_PERIOD 10000
|
||||
#define HOTT_NUM_RF_CHANNELS 75
|
||||
#define HOTT_COARSE 0
|
||||
|
||||
enum {
|
||||
HOTT_START = 0x00,
|
||||
HOTT_CAL = 0x01,
|
||||
HOTT_DATA1 = 0x02,
|
||||
HOTT_RX1 = 0x03,
|
||||
HOTT_RX2 = 0x04,
|
||||
};
|
||||
|
||||
#define HOTT_FREQ0_VAL 0x6E
|
||||
|
||||
// Some important initialization parameters, all others are either default,
|
||||
// or not important in the context of transmitter
|
||||
// FIFOTHR 00
|
||||
// SYNC1 D3
|
||||
// SYNC0 91
|
||||
// PKTLEN 32 - Packet length, 50 bytes
|
||||
// PKTCTRL1 04 - APPEND_STATUS on=RSSI+LQI, all other are receive parameters - irrelevant
|
||||
// PKTCTRL0 44 - whitening, use FIFO, use CRC, fixed packet length
|
||||
// ADDR 00
|
||||
// CHANNR 10
|
||||
// FSCTRL1 09 - IF
|
||||
// FSCTRL0 00 - zero freq offset
|
||||
// FREQ2 5C - synthesizer frequencyfor 26MHz crystal
|
||||
// FREQ1 6C
|
||||
// FREQ0 B9
|
||||
// MDMCFG4 2D -
|
||||
// MDMCFG3 3B -
|
||||
// MDMCFG2 73 - disable DC blocking, MSK, no Manchester code, 32 bits sync word
|
||||
// MDMCFG1 A3 - FEC enable, 4 preamble bytes, CHANSPC_E - 03
|
||||
// MDMCFG0 AA - CHANSPC_M - AA
|
||||
// DEVIATN 47 -
|
||||
// MCSM2 07 -
|
||||
// MCSM1 00 - always use CCA, go to IDLE when done
|
||||
// MCSM0 08 - disable autocalibration, PO_TIMEOUT - 64, no pin radio control, no forcing XTAL to stay in SLEEP
|
||||
// FOCCFG 1D
|
||||
const PROGMEM uint8_t HOTT_init_values[] = {
|
||||
/* 00 */ 0x2F, 0x2E, 0x2F, 0x00, 0xD3, 0x91, 0x32, 0x04,
|
||||
/* 08 */ 0x44, 0x00, 0x00, 0x09, 0x00, 0x5C, 0x6C, HOTT_FREQ0_VAL + HOTT_COARSE,
|
||||
/* 10 */ 0x2D, 0x3B, 0x73, 0xA3, 0xAA, 0x47, 0x07, 0x00,
|
||||
/* 18 */ 0x08, 0x1D, 0x1C, 0xC7, 0x09, 0xF0, 0x87, 0x6B,
|
||||
/* 20 */ 0xF0, 0xB6, 0x10, 0xEA, 0x0A, 0x00, 0x11
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) HOTT_rf_init()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
|
||||
for (uint8_t i = 0; i < 39; ++i)
|
||||
CC2500_WriteReg(i, pgm_read_byte_near(&HOTT_init_values[i]));
|
||||
|
||||
prev_option = option;
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HOTT_tune_chan()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, (rf_ch_num+1)*3);
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HOTT_tune_chan_fast()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, (rf_ch_num+1)*3);
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[rf_ch_num]);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HOTT_tune_freq()
|
||||
{
|
||||
if ( prev_option != option )
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
CC2500_WriteReg(CC2500_0F_FREQ0, HOTT_FREQ0_VAL + HOTT_COARSE);
|
||||
prev_option = option ;
|
||||
phase = HOTT_START; // Restart the tune process if option is changed to get good tuned values
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM HOTT_hop[][HOTT_NUM_RF_CHANNELS]=
|
||||
{ { 48, 37, 16, 62, 9, 50, 42, 22, 68, 0, 55, 35, 21, 74, 1, 56, 31, 20, 70, 11, 45, 32, 24, 71, 8, 54, 38, 26, 61, 13, 53, 30, 15, 65, 7, 52, 34, 28, 60, 3, 47, 39, 18, 69, 2, 49, 44, 23, 72, 5, 51, 43, 19, 64, 12, 46, 33, 17, 67, 6, 58, 36, 29, 73, 14, 57, 41, 25, 63, 4, 59, 40, 27, 66, 10 },
|
||||
{ 50, 23, 5, 34, 67, 53, 22, 12, 39, 62, 51, 21, 10, 33, 63, 59, 16, 1, 43, 66, 49, 19, 8, 30, 71, 47, 24, 2, 35, 68, 45, 25, 14, 41, 74, 55, 18, 4, 32, 61, 54, 17, 11, 31, 72, 52, 28, 6, 38, 65, 46, 15, 9, 40, 60, 48, 26, 3, 37, 70, 58, 29, 0, 36, 64, 56, 20, 7, 42, 69, 57, 27, 13, 44, 73 },
|
||||
{ 73, 51, 39, 18, 9, 64, 56, 34, 16, 12, 66, 58, 36, 25, 11, 61, 47, 40, 15, 8, 71, 50, 43, 20, 6, 62, 54, 42, 19, 3, 63, 46, 44, 29, 14, 72, 49, 33, 22, 5, 69, 57, 30, 21, 10, 70, 45, 35, 26, 7, 65, 59, 31, 28, 1, 67, 48, 32, 24, 0, 60, 55, 41, 17, 2, 74, 52, 38, 27, 4, 68, 53, 37, 23, 13 },
|
||||
{ 52, 60, 40, 21, 14, 50, 72, 41, 23, 13, 59, 61, 39, 16, 6, 58, 66, 33, 17, 5, 55, 64, 43, 20, 12, 54, 74, 35, 29, 3, 46, 63, 37, 22, 10, 48, 65, 31, 27, 9, 49, 73, 38, 24, 11, 56, 70, 32, 15, 1, 51, 71, 44, 18, 8, 45, 67, 36, 25, 7, 57, 62, 34, 28, 2, 53, 69, 42, 19, 4, 47, 68, 30, 26, 0 },
|
||||
{ 50, 16, 34, 6, 71, 51, 24, 40, 7, 68, 57, 27, 33, 14, 70, 55, 26, 30, 5, 74, 47, 28, 44, 11, 67, 49, 15, 32, 9, 61, 52, 22, 37, 13, 66, 59, 18, 42, 3, 62, 46, 29, 31, 12, 60, 48, 19, 38, 1, 72, 58, 17, 36, 4, 64, 53, 21, 39, 0, 63, 56, 20, 41, 2, 65, 45, 25, 35, 10, 69, 54, 23, 43, 8, 73 },
|
||||
{ 55, 38, 12, 62, 23, 52, 44, 3, 66, 18, 54, 36, 10, 74, 16, 56, 42, 9, 70, 17, 58, 33, 5, 69, 20, 50, 40, 1, 63, 24, 53, 37, 13, 65, 15, 48, 34, 4, 61, 22, 57, 31, 6, 64, 26, 46, 35, 11, 72, 21, 47, 30, 7, 68, 29, 45, 32, 8, 60, 19, 49, 43, 2, 67, 27, 51, 39, 0, 71, 28, 59, 41, 14, 73, 25 },
|
||||
{ 70, 32, 18, 10, 58, 69, 38, 22, 2, 54, 67, 36, 19, 12, 57, 62, 34, 20, 14, 52, 63, 41, 15, 3, 51, 73, 42, 28, 6, 48, 60, 43, 29, 5, 45, 64, 31, 17, 4, 56, 65, 35, 26, 13, 53, 61, 37, 23, 1, 49, 68, 40, 16, 9, 47, 71, 39, 25, 7, 50, 66, 33, 24, 8, 59, 72, 44, 27, 11, 46, 74, 30, 21, 0, 55 },
|
||||
{ 6, 45, 71, 27, 44, 10, 46, 74, 22, 32, 0, 55, 69, 21, 33, 4, 50, 66, 18, 38, 7, 57, 62, 19, 36, 1, 48, 70, 20, 40, 8, 47, 68, 15, 43, 2, 58, 61, 26, 42, 3, 56, 72, 23, 34, 14, 54, 67, 16, 37, 5, 59, 64, 24, 30, 12, 52, 65, 25, 39, 13, 49, 73, 17, 31, 9, 53, 60, 28, 35, 11, 51, 63, 29, 41 },
|
||||
{ 31, 65, 50, 20, 13, 37, 66, 45, 23, 5, 32, 69, 54, 19, 7, 39, 74, 52, 27, 1, 42, 64, 53, 22, 4, 43, 70, 58, 16, 3, 40, 71, 57, 17, 0, 35, 63, 56, 18, 9, 44, 72, 51, 21, 6, 33, 67, 46, 25, 11, 30, 73, 55, 15, 8, 36, 62, 48, 24, 10, 41, 60, 49, 29, 14, 34, 61, 47, 26, 2, 38, 68, 59, 28, 12 },
|
||||
{ 67, 22, 49, 36, 13, 64, 28, 57, 37, 6, 65, 29, 46, 39, 3, 70, 26, 45, 35, 1, 62, 24, 58, 34, 10, 68, 19, 53, 33, 4, 66, 21, 52, 31, 7, 74, 18, 47, 32, 5, 61, 16, 51, 38, 8, 72, 23, 55, 30, 12, 73, 17, 59, 44, 0, 60, 15, 50, 43, 14, 63, 27, 48, 42, 11, 71, 20, 54, 41, 9, 69, 25, 56, 40, 2 },
|
||||
{ 19, 38, 14, 66, 57, 18, 44, 7, 74, 48, 23, 30, 6, 71, 58, 26, 32, 5, 61, 46, 20, 34, 0, 68, 45, 24, 36, 1, 70, 50, 27, 33, 10, 63, 52, 16, 42, 9, 65, 51, 15, 41, 11, 64, 53, 22, 37, 3, 60, 56, 28, 35, 4, 67, 49, 17, 39, 13, 69, 54, 25, 43, 2, 73, 55, 21, 31, 8, 62, 47, 29, 40, 12, 72, 59 },
|
||||
{ 4, 52, 64, 28, 44, 14, 46, 74, 16, 32, 11, 50, 68, 27, 36, 0, 47, 70, 26, 34, 13, 57, 61, 18, 38, 6, 56, 62, 19, 40, 5, 58, 67, 17, 31, 12, 54, 63, 22, 33, 3, 53, 72, 21, 41, 10, 48, 66, 15, 35, 7, 45, 60, 20, 37, 9, 51, 69, 25, 42, 2, 59, 71, 24, 39, 1, 55, 65, 23, 30, 8, 49, 73, 29, 43 },
|
||||
{ 44, 66, 19, 1, 56, 35, 62, 20, 4, 54, 39, 70, 24, 5, 55, 31, 74, 26, 12, 58, 32, 60, 17, 10, 45, 37, 63, 22, 3, 50, 33, 64, 16, 7, 51, 34, 61, 21, 8, 48, 38, 68, 29, 0, 46, 36, 72, 28, 14, 49, 42, 69, 25, 6, 57, 43, 65, 18, 2, 52, 30, 71, 23, 13, 47, 41, 67, 15, 9, 53, 40, 73, 27, 11, 59 },
|
||||
{ 12, 16, 36, 46, 69, 6, 20, 44, 58, 62, 11, 19, 34, 48, 71, 1, 18, 42, 50, 74, 3, 25, 31, 47, 65, 0, 24, 33, 45, 72, 2, 23, 35, 56, 64, 10, 22, 38, 49, 63, 7, 26, 37, 51, 70, 14, 21, 30, 53, 67, 5, 15, 40, 52, 66, 9, 17, 39, 55, 60, 13, 27, 41, 54, 73, 4, 28, 32, 57, 61, 8, 29, 43, 59, 68 },
|
||||
{ 63, 42, 18, 2, 57, 71, 34, 22, 10, 48, 67, 36, 25, 4, 46, 60, 31, 28, 6, 47, 74, 37, 15, 0, 55, 65, 32, 24, 12, 56, 66, 40, 27, 14, 52, 62, 38, 19, 3, 50, 73, 33, 29, 11, 53, 61, 35, 16, 7, 58, 72, 41, 26, 5, 59, 69, 30, 20, 9, 51, 68, 44, 23, 1, 49, 70, 39, 17, 8, 54, 64, 43, 21, 13, 45 },
|
||||
{ 52, 1, 71, 17, 36, 47, 7, 64, 26, 32, 53, 5, 60, 20, 42, 57, 2, 66, 18, 34, 56, 4, 63, 24, 35, 46, 13, 72, 22, 30, 48, 0, 67, 21, 39, 50, 3, 74, 16, 31, 59, 14, 61, 23, 37, 45, 6, 65, 19, 44, 51, 11, 62, 27, 41, 55, 9, 68, 15, 38, 58, 8, 70, 29, 40, 54, 10, 69, 28, 33, 49, 12, 73, 25, 43 }
|
||||
};
|
||||
const uint16_t PROGMEM HOTT_hop_val[] = { 0xC06B, 0xC34A, 0xDB24, 0x8E09, 0x272E, 0x217F, 0x155B, 0xEDE8, 0x1D31, 0x0986, 0x56F7, 0x6454, 0xC42D, 0x01D2, 0xC253, 0x1180 };
|
||||
|
||||
static void __attribute__((unused)) HOTT_init()
|
||||
{
|
||||
packet[0] = pgm_read_word_near( &HOTT_hop_val[num_ch] );
|
||||
packet[1] = pgm_read_word_near( &HOTT_hop_val[num_ch] )>>8;
|
||||
|
||||
for(uint8_t i=0; i<HOTT_NUM_RF_CHANNELS; i++)
|
||||
hopping_frequency[i]=pgm_read_byte_near( &HOTT_hop[num_ch][i] );
|
||||
|
||||
#ifdef HOTT_FORCE_ID
|
||||
memcpy(rx_tx_addr,"\x7C\x94\x00\x0D\x50",5);
|
||||
#endif
|
||||
memset(&packet[30],0xFF,9);
|
||||
packet[39]=0x07; // unknown and constant
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[28] = 0x80; // unknown 0x80 when bind starts then when RX replies start normal, 0x89/8A/8B/8C/8D/8E during normal packets
|
||||
packet[29] = 0x02; // unknown 0x02 when bind starts then when RX replies cycle in sequence 0x1A/22/2A/0A/12, 0x02 during normal packets
|
||||
memset(&packet[40],0xFA,5);
|
||||
memcpy(&packet[45],rx_tx_addr,5);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[28] = 0x8C; // unknown 0x80 when bind starts then when RX replies start normal, 0x89/8A/8B/8C/8D/8E during normal packets, 0x0F->config menu
|
||||
packet[29] = 0x02; // unknown 0x02 when bind starts then when RX replies cycle in sequence 0x1A/22/2A/0A/12, 0x02 during normal packets, 0x01->config menu, 0x0A->no more RX telemetry
|
||||
memcpy(&packet[40],rx_tx_addr,5);
|
||||
|
||||
uint8_t addr=HOTT_EEPROM_OFFSET+RX_num*5;
|
||||
for(uint8_t i=0;i<5;i++)
|
||||
packet[45+i]=eeprom_read_byte((EE_ADDR)(addr+i));
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HOTT_data_packet()
|
||||
{
|
||||
packet[2] = hopping_frequency_no;
|
||||
|
||||
packet[3] = 0x00; // used for failsafe but may also be used for additional channels
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
static uint8_t failsafe_count=0;
|
||||
if(IS_FAILSAFE_VALUES_on && IS_BIND_DONE)
|
||||
{
|
||||
failsafe_count++;
|
||||
if(failsafe_count>=3)
|
||||
{
|
||||
FAILSAFE_VALUES_off;
|
||||
failsafe_count=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
failsafe_count=0;
|
||||
#endif
|
||||
|
||||
// Channels value are PPM*2, -100%=1100µs, +100%=1900µs, order TAER
|
||||
uint16_t val;
|
||||
for(uint8_t i=4;i<28;i+=2)
|
||||
{
|
||||
val=Channel_data[(i-4)>>1];
|
||||
val=(((val<<2)+val)>>2)+860*2; // value range 860<->2140 *2 <-> -125%<->+125%
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(failsafe_count==1)
|
||||
{ // first failsafe packet
|
||||
packet[3]=0x40;
|
||||
uint16_t fs=Failsafe_data[(i-4)>>1];
|
||||
if( fs == FAILSAFE_CHANNEL_HOLD || fs == FAILSAFE_CHANNEL_NOPULSES)
|
||||
val|=0x8000; // channel hold flag
|
||||
else
|
||||
{
|
||||
val=(((fs<<2)+fs)>>2)+860*2; // value range 860<->2140 *2 <-> -125%<->+125%
|
||||
val|=0x4000; // channel specific position flag
|
||||
}
|
||||
}
|
||||
else if(failsafe_count==2)
|
||||
{ // second failsafe packet=timing?
|
||||
packet[3]=0x50;
|
||||
if(i==4)
|
||||
val=2;
|
||||
else
|
||||
val=0;
|
||||
}
|
||||
#endif
|
||||
packet[i] = val;
|
||||
packet[i+1] = val>>8;
|
||||
}
|
||||
|
||||
#ifdef HOTT_FW_TELEMETRY
|
||||
static uint8_t prev_SerialRX_val=0;
|
||||
if(HoTT_SerialRX && HoTT_SerialRX_val >= 0xD7 && HoTT_SerialRX_val <= 0xDF)
|
||||
{
|
||||
if(prev_SerialRX_val!=HoTT_SerialRX_val)
|
||||
{
|
||||
prev_SerialRX_val=HoTT_SerialRX_val;
|
||||
packet[28] = HoTT_SerialRX_val; // send the touch being pressed only once
|
||||
}
|
||||
else
|
||||
packet[28] = 0xDF; // no touch pressed
|
||||
packet[29] = 0x01; // 0x01->config menu
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[28] = 0x8C; // unknown 0x80 when bind starts then when RX replies start normal, 0x89/8A/8B/8C/8D/8E during normal packets, 0x0F->config menu
|
||||
packet[29] = 0x02; // unknown 0x02 when bind starts then when RX replies cycle in sequence 0x1A/22/2A/0A/12, 0x02 during normal packets, 0x01->config menu, 0x0A->no more RX telemetry
|
||||
}
|
||||
#endif
|
||||
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
CC2500_WriteReg(CC2500_06_PKTLEN, 0x32);
|
||||
CC2500_WriteData(packet, HOTT_TX_PACKET_LEN);
|
||||
#if 0
|
||||
debug("RF:%02X P:",rf_ch_num);
|
||||
for(uint8_t i=0;i<HOTT_TX_PACKET_LEN;i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no %= HOTT_NUM_RF_CHANNELS;
|
||||
rf_ch_num=hopping_frequency[hopping_frequency_no];
|
||||
}
|
||||
|
||||
uint16_t ReadHOTT()
|
||||
{
|
||||
#ifdef HOTT_FW_TELEMETRY
|
||||
static uint8_t pps_counter=0;
|
||||
#endif
|
||||
|
||||
switch(phase)
|
||||
{
|
||||
case HOTT_START:
|
||||
rf_ch_num = 0;
|
||||
HOTT_tune_chan();
|
||||
phase = HOTT_CAL;
|
||||
return 2000;
|
||||
case HOTT_CAL:
|
||||
calData[rf_ch_num]=CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
if (++rf_ch_num < HOTT_NUM_RF_CHANNELS)
|
||||
HOTT_tune_chan();
|
||||
else
|
||||
{
|
||||
hopping_frequency_no = 0;
|
||||
rf_ch_num=hopping_frequency[hopping_frequency_no];
|
||||
counter = 0;
|
||||
phase = HOTT_DATA1;
|
||||
}
|
||||
return 2000;
|
||||
|
||||
/* Work cycle: 10ms */
|
||||
case HOTT_DATA1:
|
||||
//TX
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(HOTT_PACKET_PERIOD);
|
||||
#endif
|
||||
HOTT_tune_freq();
|
||||
HOTT_tune_chan_fast();
|
||||
HOTT_data_packet();
|
||||
phase = HOTT_RX1;
|
||||
return 4500;
|
||||
case HOTT_RX1:
|
||||
//RX
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
CC2500_WriteReg(CC2500_06_PKTLEN, HOTT_RX_PACKET_LEN);
|
||||
CC2500_Strobe(CC2500_SRX);
|
||||
phase = HOTT_RX2;
|
||||
return 4500;
|
||||
case HOTT_RX2:
|
||||
//Telemetry
|
||||
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if (len==HOTT_RX_PACKET_LEN+2)
|
||||
{
|
||||
CC2500_ReadData(packet_in, len);
|
||||
if(memcmp(rx_tx_addr,packet_in,5)==0)
|
||||
{ // TX ID matches
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
debug("B:");
|
||||
for(uint8_t i=0;i<HOTT_RX_PACKET_LEN;i++)
|
||||
debug(" %02X", packet_in[i]);
|
||||
debugln("");
|
||||
uint8_t addr=HOTT_EEPROM_OFFSET+RX_num*5;
|
||||
for(uint8_t i=0; i<5; i++)
|
||||
eeprom_write_byte((EE_ADDR)(addr+i),packet_in[5+i]);
|
||||
BIND_DONE;
|
||||
HOTT_init();
|
||||
}
|
||||
#ifdef HOTT_FW_TELEMETRY
|
||||
else
|
||||
{ //Telemetry
|
||||
// [0..4] = TXID
|
||||
// [5..9] = RXID
|
||||
// [10] = 0x40 bind, 0x00 normal, 0x80 config menu
|
||||
// [11] = telmetry pages. For sensors 0x00 to 0x04, for config mennu 0x00 to 0x12.
|
||||
// Normal telem page 0 = 0x00, 0x33, 0x34, 0x46, 0x64, 0x33, 0x0A, 0x00, 0x00, 0x00
|
||||
// = 0x55, 0x32, 0x38, 0x55, 0x64, 0x32, 0xD0, 0x07, 0x00, 0x55
|
||||
// Page 0 [12] = [21] = ??
|
||||
// Page 0 [13] = RX_Voltage*10 in V
|
||||
// Page 0 [14] = Temperature-20 in °C
|
||||
// Page 0 [15] = RX_RSSI
|
||||
// Page 0 [16] = RX_LQI ??
|
||||
// Page 0 [17] = RX_STR ??
|
||||
// Page 0 [18,19] = [19]*256+[18]=max lost packet time in ms, max value seems 2s=0x7D0
|
||||
// Page 0 [20] = 0x00 ??
|
||||
// Config menu consists of the different telem pages put all together
|
||||
// Page X [12] = seems like all the telem pages with the same value are going together to make the full config menu text. Seen so far 'a', 'b', 'c', 'd'
|
||||
// Page X [13..21] = 9 ascii chars to be displayed, char is highlighted when ascii|0x80
|
||||
// Screen display is 21 characters large which means that once the first 21 chars are filled go to the begining of the next line
|
||||
// Menu commands are sent through TX packets:
|
||||
// packet[28]= 0xXF=>no key press, 0xXD=>down, 0xXB=>up, 0xX9=>enter, 0xXE=>right, 0xX7=>left with X=0 or D
|
||||
// packet[29]= 0xX1/0xX9 with X=0 or X counting 0,1,1,2,2,..,9,9
|
||||
TX_RSSI = packet_in[22];
|
||||
if(TX_RSSI >=128)
|
||||
TX_RSSI -= 128;
|
||||
else
|
||||
TX_RSSI += 128;
|
||||
// Reduce telemetry to 14 bytes
|
||||
packet_in[0]= TX_RSSI;
|
||||
packet_in[1]= TX_LQI;
|
||||
debug("T=");
|
||||
for(uint8_t i=10;i < HOTT_RX_PACKET_LEN; i++)
|
||||
{
|
||||
packet_in[i-8]=packet_in[i];
|
||||
debug(" %02X",packet_in[i]);
|
||||
}
|
||||
debugln("");
|
||||
telemetry_link=2;
|
||||
}
|
||||
pps_counter++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HOTT_FW_TELEMETRY
|
||||
packet_count++;
|
||||
if(packet_count>=100)
|
||||
{
|
||||
TX_LQI=pps_counter;
|
||||
pps_counter=packet_count=0;
|
||||
}
|
||||
#endif
|
||||
CC2500_Strobe(CC2500_SFRX); //Flush the RXFIFO
|
||||
phase=HOTT_DATA1;
|
||||
return 1000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t initHOTT()
|
||||
{
|
||||
num_ch=random(0xfefefefe)%16;
|
||||
HOTT_init();
|
||||
HOTT_rf_init();
|
||||
packet_count=0;
|
||||
#ifdef HOTT_FW_TELEMETRY
|
||||
HoTT_SerialRX_val=0;
|
||||
HoTT_SerialRX=false;
|
||||
#endif
|
||||
phase = HOTT_START;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -122,10 +122,10 @@ static void __attribute__((unused)) build_ch_data()
|
||||
uint8_t i,j;
|
||||
for (i = 0; i< 8; i++) {
|
||||
j=CH_AETR[i];
|
||||
temp=map(limit_channel_100(j),PPM_MIN_100,PPM_MAX_100,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)
|
||||
temp=convert_channel_16b_limit(j,0,1000);
|
||||
if (j == CH3) // It is clear that hisky's throttle stick is made reversely, so I adjust it here on purpose
|
||||
temp = 1000 - temp;
|
||||
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;
|
||||
@@ -150,12 +150,29 @@ uint16_t hisky_cb()
|
||||
case 4:
|
||||
phase=6;
|
||||
break;
|
||||
case 7: // build packet with 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 MULTI_SYNC
|
||||
telemetry_set_input_sync(5000);
|
||||
#endif
|
||||
#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;
|
||||
FAILSAFE_VALUES_off;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -203,6 +220,9 @@ uint16_t hisky_cb()
|
||||
break;
|
||||
case 7:
|
||||
//Build normal packet
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(9000);
|
||||
#endif
|
||||
build_ch_data();
|
||||
break;
|
||||
case 8:
|
||||
@@ -240,7 +260,7 @@ uint16_t initHiSky()
|
||||
hopping_frequency_no = 0;
|
||||
binding_idx = 0;
|
||||
|
||||
if(IS_AUTOBIND_FLAG_on)
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
bind_counter = HISKY_BIND_COUNT;
|
||||
else
|
||||
bind_counter = 0;
|
||||
|
||||
478
Multiprotocol/Hitec_cc2500.ino
Normal file
478
Multiprotocol/Hitec_cc2500.ino
Normal file
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
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
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(HITEC_PACKET_PERIOD);
|
||||
#endif
|
||||
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<TELEMETRY_BUFFER_SIZE)
|
||||
{ // Something has been received
|
||||
CC2500_ReadData(packet_in, len);
|
||||
if( (packet_in[len-1] & 0x80) && packet_in[0]==len-3 && packet_in[1]==rx_tx_addr[1] && packet_in[2]==rx_tx_addr[2] && packet_in[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",packet_in[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(packet_in[i]!=i%10) check=false;
|
||||
if((packet_in[4]&0xF0)==0x70 && check)
|
||||
{
|
||||
bind_phase=packet_in[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 && packet_in[4]==0 && packet_in[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",packet_in[14]&0x7F);
|
||||
#if defined(HITEC_FW_TELEMETRY) || defined(HITEC_HUB_TELEMETRY)
|
||||
TX_RSSI = packet_in[13];
|
||||
if(TX_RSSI >=128)
|
||||
TX_RSSI -= 128;
|
||||
else
|
||||
TX_RSSI += 128;
|
||||
TX_LQI = packet_in[14]&0x7F;
|
||||
#endif
|
||||
#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
|
||||
packet_in[0]=TX_RSSI; // TX RSSI
|
||||
packet_in[1]=TX_LQI; // TX LQI
|
||||
uint8_t offset=packet_in[5]==0?1:0;
|
||||
for(uint8_t i=5;i < 11; i++)
|
||||
packet_in[i-3]=packet_in[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(packet_in[5]) // telemetry frame number
|
||||
{
|
||||
case 0x00:
|
||||
v_lipo1 = (packet_in[10])<<5 | (packet_in[11])>>3; // calculation in float is volt=(packet_in[10]<<8+packet_in[11])/28
|
||||
break;
|
||||
case 0x11:
|
||||
v_lipo1 = (packet_in[9])<<5 | (packet_in[10])>>3; // calculation in float is volt=(packet_in[9]<<8+packet_in[10])/28
|
||||
break;
|
||||
case 0x18:
|
||||
v_lipo2 = (packet_in[6])<<5 | (packet_in[7])>>3; // calculation in float is volt=(packet_in[6]<<8+packet_in[7])/10
|
||||
break;
|
||||
}
|
||||
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
|
||||
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, ..., 0x1C. 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 station type 0x2D=standard station nitro or electric, 0xAC=advanced station
|
||||
data byte 3 -> RX Batt Volt_H
|
||||
data byte 4 -> RX Batt Volt_L => RX Batt=(Volt_H*256+Volt_L)/28
|
||||
- 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 GPS Speed=Speed_H*256+Speed_L km/h
|
||||
data byte 2 -> Alti_sea_H
|
||||
data byte 3 -> Alti_sea_L GPS Altitude=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 -> COURSEH
|
||||
data byte 1 -> COURSEL GPS heading = COURSEH*256+COURSEL in degrees
|
||||
data byte 2 -> Count GPS satellites
|
||||
data byte 3 -> Temp3 Temperature3=Temp2-40°C
|
||||
data byte 4 -> Temp4 Temperature4=Temp3-40°C
|
||||
- frame 0x18
|
||||
data byte 0 -> Volt_L Volt=(Volt_H*256+Volt_L)/10 V
|
||||
data byte 1 -> Volt_H
|
||||
data byte 2 -> AMP_L
|
||||
data byte 3 -> AMP_H Amp=(AMP1_*256+AMP_L -180)/14 in signed A
|
||||
- frame 0x19 Servo sensor
|
||||
data byte 0 -> AMP_Servo1 Amp=AMP_Servo1/10 in A
|
||||
data byte 1 -> AMP_Servo2 Amp=AMP_Servo2/10 in A
|
||||
data byte 2 -> AMP_Servo3 Amp=AMP_Servo3/10 in A
|
||||
data byte 3 -> AMP_Servo4 Amp=AMP_Servo4/10 in A
|
||||
- frame 0x1A
|
||||
data byte 2 -> ASpeed_H Air speed=ASpeed_H*256+ASpeed_L km/h
|
||||
data byte 3 -> ASpeed_L
|
||||
- frame 0x1B Variometer sensor
|
||||
data byte 0 -> Alti1H
|
||||
data byte 1 -> Alti1L Altitude unfiltered
|
||||
data byte 2 -> Alti2H
|
||||
data byte 3 -> Alti2L Altitude filtered
|
||||
- frame 0x1C Unknown
|
||||
- frame 0x22 Unknown
|
||||
*/
|
||||
#endif
|
||||
264
Multiprotocol/Hontai_nrf24l01.ino
Normal file
264
Multiprotocol/Hontai_nrf24l01.ino
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
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
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
HONTAI_send_packet(0);
|
||||
}
|
||||
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
uint16_t initHONTAI()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
bind_counter = HONTAI_BIND_COUNT;
|
||||
HONTAI_initialize_txid();
|
||||
HONTAI_init();
|
||||
packet_period = sub_protocol == FQ777_951 ? FQ777_951_PACKET_PERIOD : HONTAI_PACKET_PERIOD;
|
||||
return HONTAI_INITIAL_WAIT;
|
||||
}
|
||||
#endif
|
||||
@@ -20,24 +20,55 @@
|
||||
#include "iface_a7105.h"
|
||||
|
||||
enum{
|
||||
// flags going to packet[9] (Normal)
|
||||
HUBSAN_FLAG_VIDEO= 0x01, // record video
|
||||
HUBSAN_FLAG_FLIP = 0x08, // enable flips
|
||||
HUBSAN_FLAG_LED = 0x04 // enable LEDs
|
||||
// flags going to packet[9] (H107)
|
||||
HUBSAN_FLAG_VIDEO= 0x01, // record video
|
||||
HUBSAN_FLAG_FLIP = 0x08, // enable flips
|
||||
HUBSAN_FLAG_LED = 0x04 // enable LEDs
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[9] (Plus series)
|
||||
HUBSAN_FLAG_HEADLESS = 0x08, // headless mode
|
||||
// flags going to packet[9] (H107 Plus series)
|
||||
HUBSAN_FLAG_HEADLESS = 0x08, // headless mode
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[13] (Plus series)
|
||||
HUBSAN_FLAG_SNAPSHOT = 0x01,
|
||||
HUBSAN_FLAG_FLIP_PLUS = 0x80,
|
||||
// flags going to packet[9] (H301)
|
||||
FLAG_H301_VIDEO = 0x01,
|
||||
FLAG_H301_STAB = 0x02,
|
||||
FLAG_H301_LED = 0x10,
|
||||
FLAG_H301_RTH = 0x40,
|
||||
};
|
||||
|
||||
uint32_t sessionid,id_data;
|
||||
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,
|
||||
@@ -54,7 +85,7 @@ enum {
|
||||
DATA_4,
|
||||
DATA_5,
|
||||
};
|
||||
#define WAIT_WRITE 0x80
|
||||
#define HUBSAN_WAIT_WRITE 0x80
|
||||
|
||||
static void __attribute__((unused)) hubsan_update_crc()
|
||||
{
|
||||
@@ -72,11 +103,11 @@ static void __attribute__((unused)) hubsan_build_bind_packet(uint8_t bind_state)
|
||||
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;
|
||||
if(id_data == ID_NORMAL)
|
||||
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;
|
||||
@@ -108,7 +139,7 @@ static void __attribute__((unused)) hubsan_build_bind_packet(uint8_t bind_state)
|
||||
//ii : aileron observed range: 0x45 - 0xc3 (smaller is right)69-195-50%
|
||||
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)
|
||||
{
|
||||
@@ -127,8 +158,8 @@ static void __attribute__((unused)) hubsan_build_packet()
|
||||
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(id_data == ID_NORMAL)
|
||||
{
|
||||
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
|
||||
@@ -138,11 +169,11 @@ static void __attribute__((unused)) hubsan_build_packet()
|
||||
{
|
||||
packet[9] = 0x02;
|
||||
// Channel 5
|
||||
if(Servo_AUX1) packet[9] |= HUBSAN_FLAG_FLIP;
|
||||
if(CH5_SW) packet[9] |= HUBSAN_FLAG_FLIP;
|
||||
// Channel 6
|
||||
if(Servo_AUX2) packet[9] |= HUBSAN_FLAG_LED;
|
||||
if(CH6_SW) packet[9] |= HUBSAN_FLAG_LED;
|
||||
// Channel 8
|
||||
if(Servo_AUX4) packet[9] |= HUBSAN_FLAG_VIDEO; // H102D
|
||||
if(CH8_SW) packet[9] |= HUBSAN_FLAG_VIDEO; // H102D
|
||||
}
|
||||
packet[10] = 0x64;
|
||||
//const uint32_t txid = 0xdb042679;
|
||||
@@ -150,22 +181,69 @@ static void __attribute__((unused)) hubsan_build_packet()
|
||||
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
|
||||
{ //ID_PLUS
|
||||
packet[3] = 0x64;
|
||||
packet[5] = 0x64;
|
||||
packet[7] = 0x64;
|
||||
packet[9] = 0x06;
|
||||
//FLIP|LIGHT|PICTURE|VIDEO|HEADLESS
|
||||
if(Servo_AUX4) packet[9] |= HUBSAN_FLAG_VIDEO;
|
||||
if(Servo_AUX5) packet[9] |= HUBSAN_FLAG_HEADLESS;
|
||||
packet[10]= 0x19;
|
||||
packet[12]= 0x5C; // ghost channel ?
|
||||
packet[13] = 0;
|
||||
if(Servo_AUX3) packet[13] = HUBSAN_FLAG_SNAPSHOT;
|
||||
if(Servo_AUX1) packet[13] |= HUBSAN_FLAG_FLIP_PLUS;
|
||||
packet[14]= 0x49; // ghost channel ?
|
||||
{ //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
|
||||
@@ -176,11 +254,26 @@ static void __attribute__((unused)) hubsan_build_packet()
|
||||
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;
|
||||
}
|
||||
}
|
||||
hubsan_update_crc();
|
||||
}
|
||||
|
||||
#if defined(TELEMETRY)
|
||||
#ifdef HUBSAN_HUB_TELEMETRY
|
||||
static uint8_t __attribute__((unused)) hubsan_check_integrity()
|
||||
{
|
||||
if( (packet[0]&0xFE) != 0xE0 )
|
||||
@@ -194,25 +287,28 @@ static uint8_t __attribute__((unused)) hubsan_check_integrity()
|
||||
|
||||
uint16_t ReadHubsan()
|
||||
{
|
||||
#if defined(TELEMETRY)
|
||||
#ifdef HUBSAN_HUB_TELEMETRY
|
||||
static uint8_t rfMode=0;
|
||||
#endif
|
||||
static uint8_t txState=0;
|
||||
static uint8_t bind_count=0;
|
||||
uint16_t delay;
|
||||
uint8_t i;
|
||||
|
||||
switch(phase) {
|
||||
#ifndef FORCE_HUBSAN_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
switch(phase)
|
||||
{
|
||||
case BIND_1:
|
||||
bind_count++;
|
||||
if(bind_count >= 20)
|
||||
bind_phase++;
|
||||
if(bind_phase >= 20 && sub_protocol != H501)
|
||||
{
|
||||
if(id_data == ID_NORMAL)
|
||||
id_data = ID_PLUS;
|
||||
if(hubsan_id_data == ID_NORMAL)
|
||||
hubsan_id_data = ID_PLUS;
|
||||
else
|
||||
id_data = ID_NORMAL;
|
||||
A7105_WriteID(id_data);
|
||||
bind_count = 0;
|
||||
hubsan_id_data = ID_NORMAL;
|
||||
A7105_WriteID(hubsan_id_data);
|
||||
bind_phase = 0;
|
||||
}
|
||||
case BIND_3:
|
||||
case BIND_5:
|
||||
@@ -220,20 +316,20 @@ uint16_t ReadHubsan()
|
||||
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++)
|
||||
if(! (A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_SetTxRxMode(RX_EN);
|
||||
A7105_Strobe(A7105_RX);
|
||||
phase &= ~WAIT_WRITE;
|
||||
if(id_data == ID_PLUS)
|
||||
phase &= ~HUBSAN_WAIT_WRITE;
|
||||
if(hubsan_id_data == ID_PLUS)
|
||||
{
|
||||
if(phase == BIND_7 && packet[2] == 9)
|
||||
{
|
||||
@@ -253,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]);
|
||||
@@ -264,8 +360,8 @@ uint16_t ReadHubsan()
|
||||
phase = BIND_7;
|
||||
return 15000; //22.5msec elapsed since last write
|
||||
}
|
||||
A7105_ReadData();
|
||||
if(packet[1] == 9 && id_data == ID_NORMAL) {
|
||||
A7105_ReadData(16);
|
||||
if(packet[1] == 9 && hubsan_id_data == ID_NORMAL) {
|
||||
phase = DATA_1;
|
||||
A7105_WriteReg(A7105_1F_CODE_I, 0x0F);
|
||||
BIND_DONE;
|
||||
@@ -280,14 +376,22 @@ uint16_t ReadHubsan()
|
||||
case DATA_4:
|
||||
case DATA_5:
|
||||
if( txState == 0) { // send packet
|
||||
#if defined(TELEMETRY)
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(10000);
|
||||
#endif
|
||||
#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 && id_data == ID_NORMAL ? 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
|
||||
@@ -295,7 +399,7 @@ uint16_t ReadHubsan()
|
||||
delay=3000;
|
||||
}
|
||||
else {
|
||||
#if defined(TELEMETRY)
|
||||
#ifdef HUBSAN_HUB_TELEMETRY
|
||||
if( rfMode == A7105_TX)
|
||||
{// switch to rx mode 3ms after packet sent
|
||||
for( i=0; i<10; i++)
|
||||
@@ -314,17 +418,18 @@ uint16_t ReadHubsan()
|
||||
{
|
||||
if( !(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
{ // data received
|
||||
A7105_ReadData();
|
||||
A7105_ReadData(16);
|
||||
if( hubsan_check_integrity() )
|
||||
{
|
||||
v_lipo=packet[13];// hubsan lipo voltage 8bits the real value is h_lipo/10(0x2A=42 -> 4.2V)
|
||||
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
|
||||
RSSI_dBm=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less
|
||||
if(RSSI_dBm<0) RSSI_dBm=0;
|
||||
else if(RSSI_dBm>255) RSSI_dBm=255;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -341,21 +446,27 @@ 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(A6) << 10 | analogRead(A7));
|
||||
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;
|
||||
id_data=ID_NORMAL;
|
||||
#if defined(TELEMETRY)
|
||||
telemetry_link=0;
|
||||
#endif
|
||||
bind_phase=0;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,30 +35,8 @@ enum PktState {
|
||||
J6PRO_CHAN_4,
|
||||
};
|
||||
|
||||
const uint8_t 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},
|
||||
{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},
|
||||
};
|
||||
const uint8_t bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49};
|
||||
const uint8_t data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f};
|
||||
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()
|
||||
{
|
||||
@@ -77,10 +55,10 @@ static void __attribute__((unused)) j6pro_build_data_packet()
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t upperbits = 0;
|
||||
uint16_t value;
|
||||
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);
|
||||
@@ -98,16 +76,16 @@ static void __attribute__((unused)) j6pro_cyrf_init()
|
||||
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, 0x25);
|
||||
CYRF_SetPower(0x05);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x8a);
|
||||
//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(data_code, 16);
|
||||
CYRF_WritePreamble(0x023333);
|
||||
CYRF_ConfigDataCode(j6pro_data_code, 16);
|
||||
CYRF_WritePreamble(0x333302);
|
||||
|
||||
CYRF_GetMfgData(cyrfmfg_id);
|
||||
//Model match
|
||||
@@ -116,36 +94,28 @@ static void __attribute__((unused)) j6pro_cyrf_init()
|
||||
|
||||
static void __attribute__((unused)) cyrf_bindinit()
|
||||
{
|
||||
/* Use when binding */
|
||||
//0.060470# 03 2f
|
||||
CYRF_SetPower(0x28); //Deviation using max power, replaced by bind power...
|
||||
|
||||
CYRF_ConfigRFChannel(0x52);
|
||||
CYRF_ConfigSOPCode(bind_sop_code);
|
||||
CYRF_ConfigCRCSeed(0x0000);
|
||||
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83);
|
||||
//0.061511# 13 20
|
||||
|
||||
CYRF_ConfigRFChannel(0x52);
|
||||
//0.062684# 0f 05
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
//0.062792# 0f 05
|
||||
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
|
||||
j6pro_build_bind_packet(); //01 01 e9 49 ec a9 c4 c1 ff
|
||||
//CYRF_WriteDataPacketLen(packet, 0x09);
|
||||
/* 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 */
|
||||
//0.094007# 0f 05
|
||||
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, 0x25);
|
||||
CYRF_ConfigSOPCode(j6pro_sopcodes[sop_idx]);
|
||||
CYRF_ConfigCRCSeed(crc);
|
||||
/* 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()
|
||||
@@ -158,10 +128,10 @@ static void __attribute__((unused)) j6pro_set_radio_channels()
|
||||
|
||||
uint16_t ReadJ6Pro()
|
||||
{
|
||||
uint32_t start;
|
||||
uint16_t start;
|
||||
|
||||
switch(phase)
|
||||
{
|
||||
{
|
||||
case J6PRO_BIND:
|
||||
cyrf_bindinit();
|
||||
phase = J6PRO_BIND_01;
|
||||
@@ -169,21 +139,19 @@ uint16_t ReadJ6Pro()
|
||||
case J6PRO_BIND_01:
|
||||
CYRF_ConfigRFChannel(0x52);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
//0.062684# 0f 05
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
//0.062684# 0f 05
|
||||
//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=micros();
|
||||
while (micros()-start < 500) // Wait max 500µs
|
||||
if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x06)
|
||||
break;
|
||||
CYRF_ConfigRFChannel(0x53);
|
||||
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, 0x83);
|
||||
//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:
|
||||
@@ -223,7 +191,7 @@ uint16_t ReadJ6Pro()
|
||||
case J6PRO_BIND_05_4:
|
||||
case J6PRO_BIND_05_5:
|
||||
case J6PRO_BIND_05_6:
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
|
||||
//CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24);
|
||||
CYRF_WriteDataPacketLen(packet, 0x0f);
|
||||
phase = phase + 1;
|
||||
return 4600; //4.6msec
|
||||
@@ -233,8 +201,11 @@ uint16_t ReadJ6Pro()
|
||||
cyrf_datainit();
|
||||
phase = J6PRO_CHAN_1;
|
||||
case J6PRO_CHAN_1:
|
||||
//Keep transmit power updated
|
||||
CYRF_SetPower(0);
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(24550);
|
||||
#endif
|
||||
//Keep transmit power updated
|
||||
CYRF_SetPower(0x28);
|
||||
j6pro_build_data_packet();
|
||||
//return 3400;
|
||||
case J6PRO_CHAN_2:
|
||||
@@ -257,15 +228,12 @@ uint16_t ReadJ6Pro()
|
||||
|
||||
uint16_t initJ6Pro()
|
||||
{
|
||||
CYRF_Reset();
|
||||
j6pro_cyrf_init();
|
||||
|
||||
if(IS_AUTOBIND_FLAG_on) {
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
phase = J6PRO_BIND;
|
||||
}
|
||||
else {
|
||||
else
|
||||
phase = J6PRO_CHANSEL;
|
||||
}
|
||||
return 2400;
|
||||
}
|
||||
|
||||
|
||||
112
Multiprotocol/KF606_nrf24l01.ino
Normal file
112
Multiprotocol/KF606_nrf24l01.ino
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
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()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(KF606_PACKET_PERIOD);
|
||||
#endif
|
||||
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
|
||||
@@ -138,19 +138,19 @@ static void __attribute__((unused)) kn_update_packet_control_data()
|
||||
packet[6] = (value >> 8) & 0xFF;
|
||||
packet[7] = value & 0xFF;
|
||||
// Trims, middle is 0x64 (100) range 0-200
|
||||
packet[8] = convert_channel_8b_scale(AUX5,0,200); // 0x64; // T
|
||||
packet[9] = convert_channel_8b_scale(AUX6,0,200); // 0x64; // A
|
||||
packet[10] = convert_channel_8b_scale(AUX7,0,200); // 0x64; // E
|
||||
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 (Servo_AUX1)
|
||||
if (CH5_SW)
|
||||
flags = KN_FLAG_DR;
|
||||
if (Servo_AUX2)
|
||||
if (CH6_SW)
|
||||
flags |= KN_FLAG_TH;
|
||||
if (Servo_AUX3)
|
||||
if (CH7_SW)
|
||||
flags |= KN_FLAG_IDLEUP;
|
||||
if (Servo_AUX4)
|
||||
if (CH8_SW)
|
||||
flags |= KN_FLAG_GYRO3;
|
||||
|
||||
packet[12] = flags;
|
||||
@@ -246,7 +246,7 @@ static void __attribute__((unused)) kn_init()
|
||||
|
||||
NRF24L01_Initialize();
|
||||
|
||||
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, 0x01); // Enable data pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
|
||||
@@ -259,7 +259,7 @@ static void __attribute__((unused)) kn_init()
|
||||
NRF24L01_Activate(0x73);
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
|
||||
// Enable: Dynamic Payload Length to enable PCF
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL));
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, _BV(NRF2401_1D_EN_DPL));
|
||||
|
||||
NRF24L01_SetPower();
|
||||
|
||||
@@ -279,15 +279,17 @@ uint16_t initKN()
|
||||
packet_period = KN_WL_SENDING_PACKET_PERIOD;
|
||||
bind_counter = KN_WL_BIND_COUNT;
|
||||
packet_count = KN_WL_PACKET_SEND_COUNT;
|
||||
seed = KN_WL_PACKET_SEND_COUNT * KN_WL_SENDING_PACKET_PERIOD;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_period = KN_FX_SENDING_PACKET_PERIOD;
|
||||
bind_counter = KN_FX_BIND_COUNT;
|
||||
packet_count = KN_FX_PACKET_SEND_COUNT;
|
||||
seed = KN_FX_PACKET_SEND_COUNT * KN_FX_SENDING_PACKET_PERIOD;
|
||||
}
|
||||
kn_init();
|
||||
phase = IS_AUTOBIND_FLAG_on ? KN_PHASE_PRE_BIND : KN_PHASE_PRE_SEND;
|
||||
phase = IS_BIND_IN_PROGRESS ? KN_PHASE_PRE_BIND : KN_PHASE_PRE_SEND;
|
||||
|
||||
return KN_INIT_WAIT_MS;
|
||||
}
|
||||
@@ -318,6 +320,9 @@ uint16_t kn_callback()
|
||||
case KN_PHASE_SENDING:
|
||||
if(packet_sent >= packet_count)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(seed);
|
||||
#endif
|
||||
packet_sent = 0;
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no >= KN_RF_CH_COUNT) hopping_frequency_no = 0;
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
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
|
||||
// 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
|
||||
@@ -26,27 +27,75 @@
|
||||
#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()
|
||||
{
|
||||
// Servo_AUX8 PAN // H26D
|
||||
// Servo_AUX9 TILT
|
||||
// CH12_SW PAN // H26D
|
||||
// CH13_SW TILT
|
||||
uint8_t pan = 0;
|
||||
packet_count++;
|
||||
if(packet_count & MJXQ_PAN_TILT_COUNT)
|
||||
{
|
||||
if(Servo_AUX8)
|
||||
if(CH12_SW)
|
||||
pan=MJXQ_PAN_UP;
|
||||
if(Servo_data[AUX8]<PPM_MIN_COMMAND)
|
||||
if(Channel_data[CH12]<CHANNEL_MIN_COMMAND)
|
||||
pan=MJXQ_PAN_DOWN;
|
||||
if(Servo_data[AUX9]>PPM_MIN_COMMAND)
|
||||
pan=MJXQ_TILT_UP;
|
||||
if(Servo_data[AUX9]<PPM_MIN_COMMAND)
|
||||
pan=MJXQ_TILT_DOWN;
|
||||
if(CH13_SW)
|
||||
pan+=MJXQ_TILT_UP;
|
||||
if(Channel_data[CH13]<CHANNEL_MIN_COMMAND)
|
||||
pan+=MJXQ_TILT_DOWN;
|
||||
}
|
||||
return pan;
|
||||
}
|
||||
@@ -57,10 +106,10 @@ 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] = convert_channel_s8b(ELEVATOR);
|
||||
packet[5] = MJXQ_CHAN2TRIM(packet[2]); // trim elevator
|
||||
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] = MJXQ_CHAN2TRIM(packet[3]); // trim 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];
|
||||
@@ -72,57 +121,70 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
|
||||
|
||||
packet[14] = 0xC0; // bind value
|
||||
|
||||
// Servo_AUX1 FLIP
|
||||
// Servo_AUX2 LED
|
||||
// Servo_AUX3 PICTURE
|
||||
// Servo_AUX4 VIDEO
|
||||
// Servo_AUX5 HEADLESS
|
||||
// Servo_AUX6 RTH
|
||||
// Servo_AUX7 AUTOFLIP // X800, X600
|
||||
// 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:
|
||||
packet[10] += GET_FLAG(Servo_AUX6, 0x02) //RTH
|
||||
| GET_FLAG(Servo_AUX5, 0x01); //HEADLESS
|
||||
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(Servo_AUX1, 0x01) //FLIP
|
||||
| GET_FLAG(Servo_AUX3, 0x08) //PICTURE
|
||||
| GET_FLAG(Servo_AUX4, 0x10) //VIDEO
|
||||
| GET_FLAG(!Servo_AUX2, 0x20); // air/ground mode
|
||||
| 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:
|
||||
if(Servo_AUX5) //HEADLESS
|
||||
{ // driven trims cause issues when headless is enabled
|
||||
packet[5] = 0x40;
|
||||
packet[6] = 0x40;
|
||||
}
|
||||
packet[10] = GET_FLAG(!Servo_AUX2, 0x02); //LED
|
||||
packet[11] = GET_FLAG(Servo_AUX6, 0x01); //RTH
|
||||
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(Servo_AUX1, 0x04) //FLIP
|
||||
| GET_FLAG(Servo_AUX7, 0x10) //AUTOFLIP
|
||||
| GET_FLAG(Servo_AUX5, 0x20); //HEADLESS
|
||||
| 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(!Servo_AUX2, 0x02) //LED
|
||||
| GET_FLAG(Servo_AUX7, 0x01); //AUTOFLIP
|
||||
| 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(Servo_AUX1, 0x04) //FLIP
|
||||
| GET_FLAG(Servo_AUX3, 0x08) //PICTURE
|
||||
| GET_FLAG(Servo_AUX4, 0x10); //VIDEO
|
||||
| GET_FLAG(CH5_SW, 0x04) //FLIP
|
||||
| GET_FLAG(CH7_SW, 0x08) //PICTURE
|
||||
| GET_FLAG(CH8_SW, 0x10); //VIDEO
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -130,25 +192,35 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
|
||||
uint8_t sum = packet[0];
|
||||
for (uint8_t i=1; i < MJXQ_PACKET_SIZE-1; i++) sum += packet[i];
|
||||
packet[15] = sum;
|
||||
|
||||
// Power on, TX mode, 2byte CRC
|
||||
if (sub_protocol == H26D)
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
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
|
||||
XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no / 2]);
|
||||
|
||||
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
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
if (sub_protocol == H26D)
|
||||
NRF24L01_WritePayload(packet, MJXQ_PACKET_SIZE);
|
||||
else
|
||||
XN297_WritePayload(packet, MJXQ_PACKET_SIZE);
|
||||
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) MJXQ_init()
|
||||
@@ -158,65 +230,109 @@ static void __attribute__((unused)) MJXQ_init()
|
||||
if (sub_protocol == WLH08)
|
||||
memcpy(hopping_frequency, "\x12\x22\x32\x42", MJXQ_RF_NUM_CHANNELS);
|
||||
else
|
||||
if (sub_protocol == H26D)
|
||||
memcpy(hopping_frequency, "\x36\x3e\x46\x2e", MJXQ_RF_NUM_CHANNELS);
|
||||
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_RF_NUM_CHANNELS);
|
||||
memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_ADDRESS_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
|
||||
if (sub_protocol == H26D)
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, addr, MJXQ_ADDRESS_LENGTH);
|
||||
if (sub_protocol == E010 || sub_protocol == PHOENIX)
|
||||
{
|
||||
XN297L_Init();
|
||||
XN297L_SetTXAddr(addr, sizeof(addr));
|
||||
XN297L_HoppingCalib(MJXQ_RF_NUM_CHANNELS);
|
||||
}
|
||||
else
|
||||
XN297_SetTXAddr(addr, MJXQ_ADDRESS_LENGTH);
|
||||
{
|
||||
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 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); // rx pipe 0 (used only for blue board)
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
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()
|
||||
{
|
||||
// haven't figured out txid<-->rf channel mapping for MJX models
|
||||
static const uint8_t rf_map[][4] = {
|
||||
{0x0A, 0x46, 0x3A, 0x42},
|
||||
{0x0A, 0x3C, 0x36, 0x3F},
|
||||
{0x0A, 0x43, 0x36, 0x3F} };
|
||||
if (sub_protocol == H26D)
|
||||
memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS);
|
||||
else
|
||||
if (sub_protocol == WLH08)
|
||||
memcpy(hopping_frequency, rf_map[rx_tx_addr[0]%3], MJXQ_RF_NUM_CHANNELS);
|
||||
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()
|
||||
{
|
||||
// haven't figured out txid<-->rf channel mapping for MJX models
|
||||
static const uint8_t tx_map[][3]={
|
||||
{0xF8, 0x4F, 0x1C},
|
||||
{0xC8, 0x6E, 0x02},
|
||||
{0x48, 0x6A, 0x40} };
|
||||
if (sub_protocol == WLH08)
|
||||
rx_tx_addr[0]&=0xF8; // txid must be multiple of 8
|
||||
else
|
||||
memcpy(rx_tx_addr,tx_map[rx_tx_addr[0]%3],3);
|
||||
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_on)
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(MJXQ_PACKET_PERIOD);
|
||||
#endif
|
||||
MJXQ_send_packet(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#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
|
||||
@@ -37,6 +38,21 @@ enum{
|
||||
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,
|
||||
@@ -48,7 +64,7 @@ const uint8_t h7_mys_byte[] = {
|
||||
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
|
||||
};
|
||||
|
||||
static const u8 ls_mys_byte[] = {
|
||||
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,
|
||||
@@ -63,13 +79,13 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
|
||||
if(sub_protocol != YZ)
|
||||
{ // MT99XX & H7 & LS
|
||||
packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0xE1); // throttle
|
||||
packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0xE1); // rudder
|
||||
packet[2] = convert_channel_8b_scale(AILERON ,0x00,0xE1); // aileron
|
||||
packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0xE1); // elevator
|
||||
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( Servo_AUX1, FLAG_MT_FLIP );
|
||||
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)
|
||||
@@ -77,15 +93,26 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
else
|
||||
if(sub_protocol==MT99)
|
||||
packet[6] |= 0x40 | FLAG_MT_RATE2
|
||||
| GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT )
|
||||
| GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO ); // max rate on MT99xx
|
||||
| GET_FLAG( CH7_SW, FLAG_MT_SNAPSHOT )
|
||||
| GET_FLAG( CH8_SW, FLAG_MT_VIDEO ); // max rate on MT99xx
|
||||
else
|
||||
if(sub_protocol==LS)
|
||||
packet[6] |= 0x40 | FLAG_MT_RATE2;
|
||||
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_MT_RATE2 // max rate
|
||||
| GET_FLAG( Servo_AUX5, 0x10 ); //HEADLESS
|
||||
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;
|
||||
@@ -98,10 +125,10 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
}
|
||||
else
|
||||
{ // YZ
|
||||
packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0x64); // throttle
|
||||
packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0x64); // rudder
|
||||
packet[2] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator
|
||||
packet[3] = convert_channel_8b_scale(AILERON ,0x00,0x64); // aileron
|
||||
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 ++;
|
||||
@@ -111,11 +138,11 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
}
|
||||
packet[4] = yz_p4_seq[yz_seq_num];
|
||||
packet[5] = 0x02 // expert ? (0=unarmed, 1=normal)
|
||||
| GET_FLAG(Servo_AUX4, 0x10) //VIDEO
|
||||
| GET_FLAG(Servo_AUX1, 0x80) //FLIP
|
||||
| GET_FLAG(Servo_AUX5, 0x04) //HEADLESS
|
||||
| GET_FLAG(Servo_AUX3, 0x20); //SNAPSHOT
|
||||
packet[6] = GET_FLAG(Servo_AUX2, 0x80); //LED
|
||||
| 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];
|
||||
@@ -125,7 +152,10 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
if(sub_protocol == LS)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset);
|
||||
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);
|
||||
@@ -159,7 +189,7 @@ static void __attribute__((unused)) MT99XX_init()
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_SetPower();
|
||||
|
||||
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) );
|
||||
|
||||
}
|
||||
|
||||
@@ -174,18 +204,30 @@ static void __attribute__((unused)) MT99XX_initialize_txid()
|
||||
rx_tx_addr[2] = 0x00;
|
||||
}
|
||||
else
|
||||
if(sub_protocol == LS)
|
||||
rx_tx_addr[0] = 0xCC;
|
||||
else //MT99 & H7
|
||||
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_on)
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
MT99XX_send_packet();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bind_counter == 0)
|
||||
@@ -199,7 +241,10 @@ uint16_t MT99XX_callback()
|
||||
if(sub_protocol == LS)
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel
|
||||
else
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
|
||||
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
|
||||
@@ -221,7 +266,8 @@ uint16_t initMT99XX(void)
|
||||
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();
|
||||
|
||||
@@ -246,6 +292,12 @@ uint16_t initMT99XX(void)
|
||||
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];
|
||||
|
||||
@@ -1,624 +0,0 @@
|
||||
# Hey Emacs, this is a -*- makefile -*-
|
||||
#----------------------------------------------------------------------------
|
||||
# WinAVR Makefile
|
||||
#
|
||||
# On command line:
|
||||
#
|
||||
# make all = Make software.
|
||||
#
|
||||
# make clean = Clean out built project files.
|
||||
#
|
||||
# make coff = Convert ELF to AVR COFF.
|
||||
#
|
||||
# make extcoff = Convert ELF to AVR Extended COFF.
|
||||
#
|
||||
# make program = Download the hex file to the device, using avrdude.
|
||||
# Please customize the avrdude settings below first!
|
||||
#
|
||||
# make debug = Start either simulavr or avarice as specified for debugging,
|
||||
# with avr-gdb or avr-insight as the front end for debugging.
|
||||
#
|
||||
# make filename.s = Just compile filename.c into the assembler code only.
|
||||
#
|
||||
# make filename.i = Create a preprocessed source file for use in submitting
|
||||
# bug reports to the GCC project.
|
||||
#
|
||||
# To rebuild project do "make clean" then "make all".
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
|
||||
# MCU name
|
||||
MCU = atxmega32d4
|
||||
|
||||
|
||||
# Processor frequency.
|
||||
# This will define a symbol, F_CPU, in all source code files equal to the
|
||||
# processor frequency. You can then use this symbol in your source code to
|
||||
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
|
||||
# automatically to create a 32-bit value in your source code.
|
||||
# Typical values are:
|
||||
# F_CPU = 1000000
|
||||
# F_CPU = 1843200
|
||||
# F_CPU = 2000000
|
||||
# F_CPU = 3686400
|
||||
# F_CPU = 4000000
|
||||
# F_CPU = 7372800
|
||||
# F_CPU = 8000000
|
||||
# F_CPU = 11059200
|
||||
# F_CPU = 14745600
|
||||
# F_CPU = 16000000
|
||||
# F_CPU = 18432000
|
||||
# F_CPU = 20000000
|
||||
F_CPU = 32000000
|
||||
|
||||
|
||||
# Output format. (can be srec, ihex, binary)
|
||||
FORMAT = ihex
|
||||
|
||||
|
||||
# Target file name (without extension).
|
||||
TARGET = MultiOrange
|
||||
|
||||
|
||||
# Object files directory
|
||||
# To put object files in current directory, use a dot (.), do NOT make
|
||||
# this an empty or blank macro!
|
||||
OBJDIR = .
|
||||
|
||||
|
||||
# List C source files here. (C dependencies are automatically generated.)
|
||||
SRC =
|
||||
|
||||
|
||||
# List C++ source files here. (C dependencies are automatically generated.)
|
||||
CPPSRC = $(TARGET).cpp
|
||||
CPPSRC += Wmath.cpp
|
||||
#CPPSRC += DSM2_cyrf6936.cpp
|
||||
|
||||
# List Assembler source files here.
|
||||
# Make them always end in a capital .S. Files ending in a lowercase .s
|
||||
# will not be considered source files but generated files (assembler
|
||||
# output from the compiler), and will be deleted upon "make clean"!
|
||||
# Even though the DOS/Win* filesystem matches both .s and .S the same,
|
||||
# it will preserve the spelling of the filenames, and gcc itself does
|
||||
# care about how the name is spelled on its command-line.
|
||||
ASRC =
|
||||
|
||||
|
||||
# Optimization level, can be [0, 1, 2, 3, s].
|
||||
# 0 = turn off optimization. s = optimize for size.
|
||||
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
|
||||
OPT = s
|
||||
|
||||
|
||||
# Debugging format.
|
||||
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
|
||||
# AVR Studio 4.10 requires dwarf-2.
|
||||
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
|
||||
#DEBUG = stabs
|
||||
DEBUG = dwarf-2
|
||||
|
||||
|
||||
# List any extra directories to look for include files here.
|
||||
# Each directory must be seperated by a space.
|
||||
# Use forward slashes for directory separators.
|
||||
# For a directory that has spaces, enclose it in quotes.
|
||||
EXTRAINCDIRS =
|
||||
|
||||
|
||||
# Compiler flag to set the C Standard level.
|
||||
# c89 = "ANSI" C
|
||||
# gnu89 = c89 plus GCC extensions
|
||||
# c99 = ISO C99 standard (not yet fully implemented)
|
||||
# gnu99 = c99 plus GCC extensions
|
||||
CSTANDARD = -std=gnu99
|
||||
|
||||
|
||||
# Place -D or -U options here for C sources
|
||||
CDEFS = -DF_CPU=$(F_CPU)UL
|
||||
|
||||
|
||||
# Place -D or -U options here for ASM sources
|
||||
ADEFS = -DF_CPU=$(F_CPU)
|
||||
|
||||
|
||||
# Place -D or -U options here for C++ sources
|
||||
CPPDEFS = -DF_CPU=$(F_CPU)UL
|
||||
#CPPDEFS += -D__STDC_LIMIT_MACROS
|
||||
#CPPDEFS += -D__STDC_CONSTANT_MACROS
|
||||
|
||||
|
||||
|
||||
#---------------- Compiler Options C ----------------
|
||||
# -g*: generate debugging information
|
||||
# -O*: optimization level
|
||||
# -f...: tuning, see GCC manual and avr-libc documentation
|
||||
# -Wall...: warning level
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
# -adhlns...: create assembler listing
|
||||
CFLAGS = -g$(DEBUG)
|
||||
CFLAGS += $(CDEFS)
|
||||
CFLAGS += -O$(OPT)
|
||||
CFLAGS += -funsigned-char
|
||||
CFLAGS += -funsigned-bitfields
|
||||
CFLAGS += -fpack-struct
|
||||
CFLAGS += -fshort-enums
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wno-main
|
||||
CFLAGS += -Wstrict-prototypes
|
||||
#CFLAGS += -mshort-calls
|
||||
#CFLAGS += -fno-unit-at-a-time
|
||||
#CFLAGS += -Wundef
|
||||
#CFLAGS += -Wunreachable-code
|
||||
#CFLAGS += -Wsign-compare
|
||||
CFLAGS += -Wa,-adlns=$(<:%.c=$(OBJDIR)/%.lst)
|
||||
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
||||
CFLAGS += $(CSTANDARD)
|
||||
# Next line dumps rtl file
|
||||
#CFLAGS += -dr
|
||||
#CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
|
||||
|
||||
|
||||
#---------------- Compiler Options C++ ----------------
|
||||
# -g*: generate debugging information
|
||||
# -O*: optimization level
|
||||
# -f...: tuning, see GCC manual and avr-libc documentation
|
||||
# -Wall...: warning level
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
# -adhlns...: create assembler listing
|
||||
CPPFLAGS = -g$(DEBUG)
|
||||
CPPFLAGS += $(CPPDEFS)
|
||||
CPPFLAGS += -O$(OPT)
|
||||
CPPFLAGS += -funsigned-char
|
||||
CPPFLAGS += -funsigned-bitfields
|
||||
CPPFLAGS += -fpack-struct
|
||||
CPPFLAGS += -fshort-enums
|
||||
CPPFLAGS += -fno-exceptions
|
||||
CPPFLAGS += -Wall
|
||||
CFLAGS += -Wundef
|
||||
#CPPFLAGS += -mshort-calls
|
||||
#CPPFLAGS += -fno-unit-at-a-time
|
||||
#CPPFLAGS += -Wstrict-prototypes
|
||||
#CPPFLAGS += -Wunreachable-code
|
||||
#CPPFLAGS += -Wsign-compare
|
||||
CPPFLAGS += -Wa,-adlns=$(<:%.cpp=$(OBJDIR)/%.lst)
|
||||
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
||||
#CPPFLAGS += $(CSTANDARD)
|
||||
#CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
|
||||
|
||||
|
||||
#---------------- Assembler Options ----------------
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
# -adhlns: create listing
|
||||
# -gstabs: have the assembler create line number information; note that
|
||||
# for use in COFF files, additional information about filenames
|
||||
# and function names needs to be present in the assembler source
|
||||
# files -- see avr-libc docs [FIXME: not yet described there]
|
||||
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
|
||||
# dump that will be displayed for a given single line of source input.
|
||||
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
|
||||
|
||||
|
||||
#---------------- Library Options ----------------
|
||||
# Minimalistic printf version
|
||||
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
|
||||
|
||||
# Floating point printf version (requires MATH_LIB = -lm below)
|
||||
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
|
||||
|
||||
# If this is left blank, then it will use the Standard printf version.
|
||||
PRINTF_LIB =
|
||||
#PRINTF_LIB = $(PRINTF_LIB_MIN)
|
||||
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
|
||||
|
||||
|
||||
# Minimalistic scanf version
|
||||
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
|
||||
|
||||
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
|
||||
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
|
||||
|
||||
# If this is left blank, then it will use the Standard scanf version.
|
||||
SCANF_LIB =
|
||||
#SCANF_LIB = $(SCANF_LIB_MIN)
|
||||
#SCANF_LIB = $(SCANF_LIB_FLOAT)
|
||||
|
||||
|
||||
MATH_LIB = -lm
|
||||
|
||||
|
||||
# List any extra directories to look for libraries here.
|
||||
# Each directory must be seperated by a space.
|
||||
# Use forward slashes for directory separators.
|
||||
# For a directory that has spaces, enclose it in quotes.
|
||||
EXTRALIBDIRS =
|
||||
|
||||
|
||||
|
||||
#---------------- External Memory Options ----------------
|
||||
|
||||
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
||||
# used for variables (.data/.bss) and heap (malloc()).
|
||||
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
|
||||
|
||||
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
||||
# only used for heap (malloc()).
|
||||
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
|
||||
|
||||
EXTMEMOPTS =
|
||||
|
||||
|
||||
|
||||
#---------------- Linker Options ----------------
|
||||
# -Wl,...: tell GCC to pass this to linker.
|
||||
# -Map: create map file
|
||||
# --cref: add cross reference to map file
|
||||
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
|
||||
LDFLAGS += $(EXTMEMOPTS)
|
||||
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
|
||||
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
|
||||
#LDFLAGS += -Wl,--section-start=.text=0x00D0
|
||||
#LDFLAGS += -Wl,--section-start=.vectors=0x0080
|
||||
#LDFLAGS += -T avr3-167.ld
|
||||
LDFLAGS += -N
|
||||
|
||||
|
||||
|
||||
#---------------- Programming Options (avrdude) ----------------
|
||||
|
||||
# Programming hardware: alf avr910 avrisp bascom bsd
|
||||
# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500
|
||||
#
|
||||
# Type: avrdude -c ?
|
||||
# to get a full listing.
|
||||
#
|
||||
AVRDUDE_PROGRAMMER = stk500
|
||||
|
||||
# com1 = serial port. Use lpt1 to connect to parallel port.
|
||||
AVRDUDE_PORT = com3
|
||||
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
|
||||
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
|
||||
|
||||
|
||||
# Uncomment the following if you want avrdude's erase cycle counter.
|
||||
# Note that this counter needs to be initialized first using -Yn,
|
||||
# see avrdude manual.
|
||||
#AVRDUDE_ERASE_COUNTER = -y
|
||||
|
||||
# Uncomment the following if you do /not/ wish a verification to be
|
||||
# performed after programming the device.
|
||||
#AVRDUDE_NO_VERIFY = -V
|
||||
|
||||
# Increase verbosity level. Please use this when submitting bug
|
||||
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
|
||||
# to submit bug reports.
|
||||
#AVRDUDE_VERBOSE = -v -v
|
||||
|
||||
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
||||
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
|
||||
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
|
||||
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
|
||||
|
||||
|
||||
|
||||
#---------------- Debugging Options ----------------
|
||||
|
||||
# For simulavr only - target MCU frequency.
|
||||
DEBUG_MFREQ = $(F_CPU)
|
||||
|
||||
# Set the DEBUG_UI to either gdb or insight.
|
||||
# DEBUG_UI = gdb
|
||||
DEBUG_UI = insight
|
||||
|
||||
# Set the debugging back-end to either avarice, simulavr.
|
||||
DEBUG_BACKEND = avarice
|
||||
#DEBUG_BACKEND = simulavr
|
||||
|
||||
# GDB Init Filename.
|
||||
GDBINIT_FILE = __avr_gdbinit
|
||||
|
||||
# When using avarice settings for the JTAG
|
||||
JTAG_DEV = /dev/com1
|
||||
|
||||
# Debugging port used to communicate between GDB / avarice / simulavr.
|
||||
DEBUG_PORT = 4242
|
||||
|
||||
# Debugging host used to communicate between GDB / avarice / simulavr, normally
|
||||
# just set to localhost unless doing some sort of crazy debugging when
|
||||
# avarice is running on a different computer.
|
||||
DEBUG_HOST = localhost
|
||||
|
||||
|
||||
|
||||
#============================================================================
|
||||
|
||||
|
||||
# Define programs and commands.
|
||||
SHELL = sh
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
AR = avr-ar rcs
|
||||
NM = avr-nm
|
||||
AVRDUDE = avrdude
|
||||
REMOVE = rm -f
|
||||
REMOVEDIR = rm -rf
|
||||
COPY = cp
|
||||
WINSHELL = cmd
|
||||
|
||||
|
||||
# Define Messages
|
||||
# English
|
||||
MSG_ERRORS_NONE = Errors: none
|
||||
MSG_BEGIN = -------- begin --------
|
||||
MSG_END = -------- end --------
|
||||
MSG_SIZE_BEFORE = Size before:
|
||||
MSG_SIZE_AFTER = Size after:
|
||||
MSG_COFF = Converting to AVR COFF:
|
||||
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
|
||||
MSG_FLASH = Creating load file for Flash:
|
||||
MSG_EEPROM = Creating load file for EEPROM:
|
||||
MSG_EXTENDED_LISTING = Creating Extended Listing:
|
||||
MSG_SYMBOL_TABLE = Creating Symbol Table:
|
||||
MSG_LINKING = Linking:
|
||||
MSG_COMPILING = Compiling C:
|
||||
MSG_COMPILING_CPP = Compiling C++:
|
||||
MSG_ASSEMBLING = Assembling:
|
||||
MSG_CLEANING = Cleaning project:
|
||||
MSG_CREATING_LIBRARY = Creating library:
|
||||
|
||||
|
||||
|
||||
|
||||
# Define all object files.
|
||||
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
|
||||
|
||||
# Define all listing files.
|
||||
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
|
||||
|
||||
|
||||
# Compiler flags to generate dependency files.
|
||||
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
|
||||
|
||||
|
||||
# Combine all necessary flags and optional flags.
|
||||
# Add target processor to flags.
|
||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
|
||||
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
|
||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Default target.
|
||||
all: begin gccversion sizebefore build sizeafter end
|
||||
|
||||
# Change the build target to build a HEX file or a library.
|
||||
build: elf hex eep lss sym bin
|
||||
#build: lib
|
||||
|
||||
|
||||
elf: $(TARGET).elf
|
||||
hex: $(TARGET).hex
|
||||
bin: $(TARGET).bin
|
||||
eep: $(TARGET).eep
|
||||
lss: $(TARGET).lss
|
||||
sym: $(TARGET).sym
|
||||
LIBNAME=lib$(TARGET).a
|
||||
lib: $(LIBNAME)
|
||||
|
||||
|
||||
|
||||
# Eye candy.
|
||||
# AVR Studio 3.x does not check make's exit code but relies on
|
||||
# the following magic strings to be generated by the compile job.
|
||||
begin:
|
||||
@echo
|
||||
@echo $(MSG_BEGIN)
|
||||
|
||||
end:
|
||||
@echo $(MSG_END)
|
||||
@echo
|
||||
|
||||
|
||||
# Display size of file.
|
||||
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
|
||||
ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf
|
||||
|
||||
sizebefore:
|
||||
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
|
||||
2>/dev/null; echo; fi
|
||||
|
||||
sizeafter:
|
||||
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
|
||||
2>/dev/null; echo; fi
|
||||
|
||||
|
||||
|
||||
# Display compiler version information.
|
||||
gccversion :
|
||||
@$(CC) --version
|
||||
|
||||
|
||||
|
||||
# Program the device.
|
||||
program: $(TARGET).hex $(TARGET).eep
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
|
||||
|
||||
|
||||
# Generate avr-gdb config/init file which does the following:
|
||||
# define the reset signal, load the target file, connect to target, and set
|
||||
# a breakpoint at main().
|
||||
gdb-config:
|
||||
@$(REMOVE) $(GDBINIT_FILE)
|
||||
@echo define reset >> $(GDBINIT_FILE)
|
||||
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
|
||||
@echo end >> $(GDBINIT_FILE)
|
||||
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
|
||||
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
|
||||
ifeq ($(DEBUG_BACKEND),simulavr)
|
||||
@echo load >> $(GDBINIT_FILE)
|
||||
endif
|
||||
@echo break main >> $(GDBINIT_FILE)
|
||||
|
||||
debug: gdb-config $(TARGET).elf
|
||||
ifeq ($(DEBUG_BACKEND), avarice)
|
||||
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
|
||||
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
|
||||
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
|
||||
@$(WINSHELL) /c pause
|
||||
|
||||
else
|
||||
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
|
||||
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
|
||||
endif
|
||||
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
|
||||
|
||||
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||
COFFCONVERT = $(OBJCOPY) --debugging
|
||||
COFFCONVERT += --change-section-address .data-0x800000
|
||||
COFFCONVERT += --change-section-address .bss-0x800000
|
||||
COFFCONVERT += --change-section-address .noinit-0x800000
|
||||
COFFCONVERT += --change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
|
||||
coff: $(TARGET).elf
|
||||
@echo
|
||||
@echo $(MSG_COFF) $(TARGET).cof
|
||||
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
|
||||
|
||||
|
||||
extcoff: $(TARGET).elf
|
||||
@echo
|
||||
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
|
||||
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
|
||||
|
||||
|
||||
|
||||
# Create final output files (.hex, .eep) from ELF output file.
|
||||
%.hex: %.elf
|
||||
@echo
|
||||
@echo $(MSG_FLASH) $@
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
|
||||
%.eep: %.elf
|
||||
@echo
|
||||
@echo $(MSG_EEPROM) $@
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
%.lss: %.elf
|
||||
@echo
|
||||
@echo $(MSG_EXTENDED_LISTING) $@
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# Create a symbol table from ELF output file.
|
||||
%.sym: %.elf
|
||||
@echo
|
||||
@echo $(MSG_SYMBOL_TABLE) $@
|
||||
$(NM) -n $< > $@
|
||||
|
||||
|
||||
|
||||
# Create library from object files.
|
||||
.SECONDARY : $(TARGET).a
|
||||
.PRECIOUS : $(OBJ)
|
||||
%.a: $(OBJ)
|
||||
@echo
|
||||
@echo $(MSG_CREATING_LIBRARY) $@
|
||||
$(AR) $@ $(OBJ)
|
||||
|
||||
|
||||
# Link: create ELF output file from object files.
|
||||
.SECONDARY : $(TARGET).elf
|
||||
.PRECIOUS : $(OBJ)
|
||||
%.elf: $(OBJ)
|
||||
@echo
|
||||
@echo $(MSG_LINKING) $@
|
||||
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
|
||||
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
$(OBJDIR)/%.o : %.c
|
||||
@echo
|
||||
@echo $(MSG_COMPILING) $<
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create object files from C++ source files.
|
||||
$(OBJDIR)/%.o : %.cpp
|
||||
@echo
|
||||
@echo $(MSG_COMPILING_CPP) $<
|
||||
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
%.s : %.c
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C++ source files.
|
||||
%.s : %.cpp
|
||||
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
$(OBJDIR)/%.o : %.S
|
||||
@echo
|
||||
@echo $(MSG_ASSEMBLING) $<
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Create preprocessed source for use in sending a bug report.
|
||||
%.i : %.c
|
||||
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Target: clean project.
|
||||
clean: begin clean_list end
|
||||
|
||||
clean_list :
|
||||
@echo
|
||||
@echo $(MSG_CLEANING)
|
||||
$(REMOVE) $(TARGET).hex
|
||||
$(REMOVE) $(TARGET).eep
|
||||
$(REMOVE) $(TARGET).cof
|
||||
$(REMOVE) $(TARGET).elf
|
||||
$(REMOVE) $(TARGET).map
|
||||
$(REMOVE) $(TARGET).sym
|
||||
$(REMOVE) $(TARGET).lss
|
||||
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
|
||||
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
|
||||
$(REMOVE) $(SRC:.c=.s)
|
||||
$(REMOVE) $(SRC:.c=.d)
|
||||
$(REMOVE) $(SRC:.c=.i)
|
||||
$(REMOVEDIR) .dep
|
||||
|
||||
|
||||
# Create object files directory
|
||||
$(shell mkdir $(OBJDIR) 2>/dev/null)
|
||||
|
||||
|
||||
# Include the dependency files.
|
||||
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
|
||||
|
||||
|
||||
# Listing of phony targets.
|
||||
.PHONY : all begin finish end sizebefore sizeafter gccversion \
|
||||
build elf hex eep lss sym coff extcoff \
|
||||
clean clean_list program debug gdb-config
|
||||
|
||||
|
||||
|
||||
|
||||
62
Multiprotocol/Multi.txt
Normal file
62
Multiprotocol/Multi.txt
Normal file
@@ -0,0 +1,62 @@
|
||||
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,4CH,7CH
|
||||
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,RX6519
|
||||
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
|
||||
52,ZSX,280
|
||||
53,Flyzone,FZ-410
|
||||
54,Scanner
|
||||
55,Frsky_RX
|
||||
56,AFHDS2A_RX
|
||||
57,HoTT
|
||||
58,FX816,P38
|
||||
59,Bayang_RX
|
||||
60,Pelikan
|
||||
61,Tiger
|
||||
63,XN_DUMP,250K,1M,2M,AUTO
|
||||
@@ -1,479 +0,0 @@
|
||||
#define ARDUINO_AVR_PRO 1
|
||||
//#define __AVR_ATmega328P__ 1
|
||||
|
||||
#define XMEGA 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
static void protocol_init(void) ;
|
||||
static void update_aux_flags(void) ;
|
||||
static void PPM_Telemetry_serial_init(void) ;
|
||||
static uint32_t random_id(uint16_t adress, uint8_t create_new) ;
|
||||
static void update_serial_data(void) ;
|
||||
static void Mprotocol_serial_init(void) ;
|
||||
static void module_reset(void) ;
|
||||
static void update_led_status(void) ;
|
||||
static void set_rx_tx_addr(uint32_t id) ;
|
||||
uint16_t limit_channel_100(uint8_t ch) ;
|
||||
|
||||
|
||||
extern void NRF24L01_Reset(void ) ;
|
||||
extern void A7105_Reset(void ) ;
|
||||
extern void CC2500_Reset(void ) ;
|
||||
extern uint8_t CYRF_Reset(void ) ;
|
||||
extern void CYRF_SetTxRxMode(uint8_t mode) ;
|
||||
|
||||
extern void frskyUpdate(void) ;
|
||||
extern uint16_t initDsm2(void) ;
|
||||
extern uint16_t ReadDsm2(void) ;
|
||||
extern uint16_t DevoInit(void) ;
|
||||
extern uint16_t devo_callback(void) ;
|
||||
|
||||
extern void randomSeed(unsigned int seed) ;
|
||||
extern long random(long howbig) ;
|
||||
extern long map(long x, long in_min, long in_max, long out_min, long out_max) ;
|
||||
|
||||
extern uint32_t millis(void) ;
|
||||
extern uint32_t micros(void) ;
|
||||
extern void delayMicroseconds(uint16_t x) ;
|
||||
extern void init(void) ;
|
||||
|
||||
extern int analogRead(uint8_t pin) ;
|
||||
|
||||
#define A6 20
|
||||
#define A7 21
|
||||
|
||||
#define yield()
|
||||
|
||||
//void _delay_us( uint16_t x )
|
||||
//{
|
||||
// delayMicroseconds( x ) ;
|
||||
//}
|
||||
|
||||
#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)
|
||||
|
||||
volatile unsigned long timer0_overflow_count = 0;
|
||||
volatile unsigned long timer0_millis = 0;
|
||||
static unsigned char timer0_fract = 0;
|
||||
|
||||
|
||||
|
||||
//void chipInit()
|
||||
//{
|
||||
// PR.PRGEN = 0 ; // RTC and event system active
|
||||
// PR.PRPC = 0 ; // No power reduction port C
|
||||
// PR.PRPD = 0 ; // No power reduction port D
|
||||
// PMIC.CTRL = 7 ;
|
||||
// OSC.CTRL = 0xC3 ; // unclear
|
||||
// OSC.CTRL |= 0x08 ; // Enable external oscillator
|
||||
// while( ( OSC.STATUS & 0x08 ) == 0 ) ; // Wait for ext osc to be ready
|
||||
// OSC.PLLCTRL = 0xC2 ; // Ext. Osc times 2
|
||||
// OSC.CTRL |= 0x10 ; // Enable PLL
|
||||
// while( ( OSC.STATUS & 0x10 ) == 0 ) ; // Wait PLL ready
|
||||
// CPU_CCP = 0xD8 ; // 0x34
|
||||
// CLK.CTRL = 0 ; // Select 2MHz internal clock
|
||||
// CPU_CCP = 0xD8 ; // 0x34
|
||||
// CLK.CTRL = 0x04 ; // Select PLL as clock (32MHz)
|
||||
// PORTD.OUTSET = 0x17 ;
|
||||
// PORTD.DIRSET = 0xB2 ;
|
||||
// PORTD.DIRCLR = 0x4D ;
|
||||
// PORTD.PIN0CTRL = 0x18 ;
|
||||
// PORTD.PIN2CTRL = 0x18 ;
|
||||
// PORTE.DIRSET = 0x01 ;
|
||||
// PORTE.DIRCLR = 0x02 ;
|
||||
// PORTE.OUTSET = 0x01 ;
|
||||
// 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 ;
|
||||
// PORTC.DIRSET = 0x20 ;
|
||||
// PORTC.OUTCLR = 0x20 ;
|
||||
// SPID.CTRL = 0x51 ;
|
||||
// PORTC.OUTSET = 0x08 ;
|
||||
// PORTC.DIRSET = 0x08 ;
|
||||
// PORTC.PIN3CTRL = 0x18 ;
|
||||
// PORTC.PIN2CTRL = 0x18 ;
|
||||
// USARTC0.BAUDCTRLA = 19 ;
|
||||
// USARTC0.BAUDCTRLB = 0 ;
|
||||
// USARTC0.CTRLB = 0x18 ;
|
||||
// USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) | 0x10 ;
|
||||
// USARTC0.CTRLC = 0x03 ;
|
||||
|
||||
// TCC0.CTRLB = 0 ;
|
||||
// TCC0.CTRLC = 0 ;
|
||||
// TCC0.CTRLD = 0 ;
|
||||
// TCC0.CTRLE = 0 ;
|
||||
// TCC0.INTCTRLA = 0x01 ;
|
||||
// TCC0.INTCTRLB = 0 ;
|
||||
// TCC0.PER = 0x00FF ;
|
||||
// TCC0.CTRLA = 4 ;
|
||||
|
||||
// TCC1.CTRLB = 0 ;
|
||||
// TCC1.CTRLC = 0 ;
|
||||
// TCC1.CTRLD = 0 ;
|
||||
// TCC1.CTRLE = 0 ;
|
||||
// TCC1.INTCTRLA = 0x03 ;
|
||||
// TCC1.INTCTRLB = 0 ;
|
||||
// TCC1.PER = 0xFFFF ;
|
||||
// TCC1.CNT = 0 ;
|
||||
// TCC1.CTRLA = 4 ;
|
||||
|
||||
// TCD0.CTRLA = 4 ;
|
||||
// TCD0.INTCTRLA = 0x03 ;
|
||||
// TCD0.PER = 0x02ED ;
|
||||
|
||||
//// L0EDB() ;
|
||||
|
||||
// NVM.CTRLB &= 0xF7 ; // No EEPROM mapping
|
||||
//}
|
||||
|
||||
|
||||
|
||||
ISR(TCC0_OVF_vect)
|
||||
{
|
||||
// copy these to local variables so they can be stored in registers
|
||||
// (volatile variables must be read from memory on every access)
|
||||
unsigned long m = timer0_millis;
|
||||
unsigned char f = timer0_fract;
|
||||
|
||||
m += MILLIS_INC;
|
||||
f += FRACT_INC;
|
||||
if (f >= FRACT_MAX) {
|
||||
f -= FRACT_MAX;
|
||||
m += 1;
|
||||
}
|
||||
|
||||
timer0_fract = f;
|
||||
timer0_millis = m;
|
||||
timer0_overflow_count++;
|
||||
}
|
||||
|
||||
unsigned long millis()
|
||||
{
|
||||
unsigned long m;
|
||||
uint8_t oldSREG = SREG;
|
||||
|
||||
// disable interrupts while we read timer0_millis or we might get an
|
||||
// inconsistent value (e.g. in the middle of a write to timer0_millis)
|
||||
cli();
|
||||
m = timer0_millis;
|
||||
SREG = oldSREG;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
unsigned long micros()
|
||||
{
|
||||
unsigned long m;
|
||||
uint8_t oldSREG = SREG, t;
|
||||
|
||||
cli();
|
||||
m = timer0_overflow_count;
|
||||
t = TCC0.CNT ;
|
||||
|
||||
if ((TCC0.INTFLAGS & TC0_OVFIF_bm) && (t < 255))
|
||||
m++;
|
||||
|
||||
SREG = oldSREG;
|
||||
|
||||
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
|
||||
}
|
||||
|
||||
void delay(unsigned long ms)
|
||||
{
|
||||
uint16_t start = (uint16_t)micros();
|
||||
|
||||
while (ms > 0) {
|
||||
yield();
|
||||
if (((uint16_t)micros() - start) >= 1000) {
|
||||
ms--;
|
||||
start += 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */
|
||||
void delayMicroseconds(unsigned int us)
|
||||
{
|
||||
// calling avrlib's delay_us() function with low values (e.g. 1 or
|
||||
// 2 microseconds) gives delays longer than desired.
|
||||
//delay_us(us);
|
||||
#if F_CPU >= 20000000L
|
||||
// for the 20 MHz clock on rare Arduino boards
|
||||
|
||||
// for a one-microsecond delay, simply wait 2 cycle and return. The overhead
|
||||
// of the function call yields a delay of exactly a one microsecond.
|
||||
__asm__ __volatile__ (
|
||||
"nop" "\n\t"
|
||||
"nop"); //just waiting 2 cycle
|
||||
if (--us == 0)
|
||||
return;
|
||||
|
||||
// the following loop takes a 1/5 of a microsecond (4 cycles)
|
||||
// per iteration, so execute it five times for each microsecond of
|
||||
// delay requested.
|
||||
us = (us<<2) + us; // x5 us
|
||||
|
||||
// account for the time taken in the preceeding commands.
|
||||
us -= 2;
|
||||
|
||||
#elif F_CPU >= 16000000L
|
||||
// for the 16 MHz clock on most Arduino boards
|
||||
|
||||
// for a one-microsecond delay, simply return. the overhead
|
||||
// of the function call yields a delay of approximately 1 1/8 us.
|
||||
if (--us == 0)
|
||||
return;
|
||||
|
||||
// the following loop takes a quarter of a microsecond (4 cycles)
|
||||
// per iteration, so execute it four times for each microsecond of
|
||||
// delay requested.
|
||||
us <<= 2;
|
||||
|
||||
// account for the time taken in the preceeding commands.
|
||||
us -= 2;
|
||||
#else
|
||||
// for the 8 MHz internal clock on the ATmega168
|
||||
|
||||
// for a one- or two-microsecond delay, simply return. the overhead of
|
||||
// the function calls takes more than two microseconds. can't just
|
||||
// subtract two, since us is unsigned; we'd overflow.
|
||||
if (--us == 0)
|
||||
return;
|
||||
if (--us == 0)
|
||||
return;
|
||||
|
||||
// the following loop takes half of a microsecond (4 cycles)
|
||||
// per iteration, so execute it twice for each microsecond of
|
||||
// delay requested.
|
||||
us <<= 1;
|
||||
|
||||
// partially compensate for the time taken by the preceeding commands.
|
||||
// we can't subtract any more than this or we'd overflow w/ small delays.
|
||||
us--;
|
||||
#endif
|
||||
|
||||
// busy wait
|
||||
__asm__ __volatile__ (
|
||||
"1: sbiw %0,1" "\n\t" // 2 cycles
|
||||
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
|
||||
);
|
||||
}
|
||||
|
||||
#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();
|
||||
|
||||
// on the ATmega168, timer 0 is also used for fast hardware pwm
|
||||
// (using phase-correct PWM would mean that timer 0 overflowed half as often
|
||||
// resulting in different millis() behavior on the ATmega8 and ATmega168)
|
||||
//#if defined(TCCR0A) && defined(WGM01)
|
||||
// sbi(TCCR0A, WGM01);
|
||||
// sbi(TCCR0A, WGM00);
|
||||
//#endif
|
||||
|
||||
|
||||
// TCC0 counts 0-255 at 4uS clock rate
|
||||
EVSYS.CH2MUX = 0x80 + 0x07 ; // Prescaler of 128
|
||||
TCC0.CTRLB = 0 ;
|
||||
TCC0.CTRLC = 0 ;
|
||||
TCC0.CTRLD = 0 ;
|
||||
TCC0.CTRLE = 0 ;
|
||||
TCC0.INTCTRLA = 0x01 ;
|
||||
TCC0.INTCTRLB = 0 ;
|
||||
TCC0.PER = 0x00FF ;
|
||||
TCC0.CTRLA = 0x0A ;
|
||||
|
||||
|
||||
#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
|
||||
|
||||
// PPM interrupt
|
||||
PORTD.DIRCLR = 0x08 ; // D3 is input
|
||||
PORTD.PIN3CTRL = 0x01 ; // Rising edge
|
||||
PORTD.INT0MASK = 0x08 ;
|
||||
PORTD.INTCTRL = 0x02 ; // Medium level interrupt
|
||||
|
||||
// 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 ;
|
||||
}
|
||||
|
||||
#define DEFAULT 1
|
||||
|
||||
uint8_t analog_reference = DEFAULT;
|
||||
|
||||
void analogReference(uint8_t mode)
|
||||
{
|
||||
// can't actually set the register here because the default setting
|
||||
// will connect AVCC and the AREF pin, which would cause a short if
|
||||
// there's something connected to AREF.
|
||||
analog_reference = mode;
|
||||
}
|
||||
|
||||
int analogRead(uint8_t pin)
|
||||
{
|
||||
uint8_t low, high;
|
||||
|
||||
#if defined(analogPinToChannel)
|
||||
#if defined(__AVR_ATmega32U4__)
|
||||
if (pin >= 18) pin -= 18; // allow for channel or pin numbers
|
||||
#endif
|
||||
pin = analogPinToChannel(pin);
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
if (pin >= 54) pin -= 54; // allow for channel or pin numbers
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
if (pin >= 18) pin -= 18; // allow for channel or pin numbers
|
||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
|
||||
if (pin >= 24) pin -= 24; // allow for channel or pin numbers
|
||||
#else
|
||||
if (pin >= 14) pin -= 14; // allow for channel or pin numbers
|
||||
#endif
|
||||
|
||||
#if defined(ADCSRB) && defined(MUX5)
|
||||
// the MUX5 bit of ADCSRB selects whether we're reading from channels
|
||||
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
|
||||
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
|
||||
#endif
|
||||
|
||||
// set the analog reference (high two bits of ADMUX) and select the
|
||||
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
|
||||
// to 0 (the default).
|
||||
#if defined(ADMUX)
|
||||
ADMUX = (analog_reference << 6) | (pin & 0x07);
|
||||
#endif
|
||||
|
||||
// without a delay, we seem to read from the wrong channel
|
||||
//delay(1);
|
||||
|
||||
#if defined(ADCSRA) && defined(ADCL)
|
||||
// start the conversion
|
||||
sbi(ADCSRA, ADSC);
|
||||
|
||||
// ADSC is cleared when the conversion finishes
|
||||
while (bit_is_set(ADCSRA, ADSC));
|
||||
|
||||
// we have to read ADCL first; doing so locks both ADCL
|
||||
// and ADCH until ADCH is read. reading ADCL second would
|
||||
// cause the results of each conversion to be discarded,
|
||||
// as ADCL and ADCH would be locked when it completed.
|
||||
low = ADCL;
|
||||
high = ADCH;
|
||||
#else
|
||||
// we dont have an ADC, return 0
|
||||
low = 0;
|
||||
high = 0;
|
||||
#endif
|
||||
|
||||
// combine the two bytes
|
||||
return (high << 8) | low;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void A7105_Reset()
|
||||
{
|
||||
}
|
||||
void CC2500_Reset()
|
||||
{
|
||||
}
|
||||
void NRF24L01_Reset()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#include "Multiprotocol.ino"
|
||||
|
||||
#include "cyrf6936_SPI.ino"
|
||||
#include "DSM2_cyrf6936.ino"
|
||||
#include "Devo_cyrf6936.ino"
|
||||
|
||||
#include "Telemetry.ino"
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init() ;
|
||||
setup() ;
|
||||
for(;;)
|
||||
{
|
||||
loop() ;
|
||||
}
|
||||
}
|
||||
|
||||
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 ;
|
||||
}
|
||||
322
Multiprotocol/Multi_Names.ino
Normal file
322
Multiprotocol/Multi_Names.ino
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
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(MULTI_NAMES)
|
||||
|
||||
const char STR_FLYSKY[] ="FlySky";
|
||||
const char STR_HUBSAN[] ="Hubsan";
|
||||
const char STR_FRSKYD[] ="FrSky D";
|
||||
const char STR_HISKY[] ="Hisky";
|
||||
const char STR_V2X2[] ="V2x2";
|
||||
const char STR_DSM[] ="DSM";
|
||||
const char STR_DEVO[] ="Devo";
|
||||
const char STR_YD717[] ="YD717";
|
||||
const char STR_KN[] ="KN";
|
||||
const char STR_SYMAX[] ="SymaX";
|
||||
const char STR_SLT[] ="SLT";
|
||||
const char STR_CX10[] ="CX10";
|
||||
const char STR_CG023[] ="CG023";
|
||||
const char STR_BAYANG[] ="Bayang";
|
||||
const char STR_FRSKYX[] ="FrSky X";
|
||||
const char STR_ESKY[] ="ESky";
|
||||
const char STR_MT99XX[] ="MT99XX";
|
||||
const char STR_MJXQ[] ="MJXq";
|
||||
const char STR_SHENQI[] ="Shenqi";
|
||||
const char STR_FY326[] ="FY326";
|
||||
const char STR_SFHSS[] ="SFHSS";
|
||||
const char STR_J6PRO[] ="J6 Pro";
|
||||
const char STR_FQ777[] ="FQ777";
|
||||
const char STR_ASSAN[] ="Assan";
|
||||
const char STR_FRSKYV[] ="FrSky V";
|
||||
const char STR_HONTAI[] ="Hontai";
|
||||
const char STR_AFHDS2A[] ="FSky 2A";
|
||||
const char STR_Q2X2[] ="Q2x2";
|
||||
const char STR_WK2x01[] ="Walkera";
|
||||
const char STR_Q303[] ="Q303";
|
||||
const char STR_GW008[] ="GW008";
|
||||
const char STR_DM002[] ="DM002";
|
||||
const char STR_CABELL[] ="Cabell";
|
||||
const char STR_ESKY150[] ="Esky150";
|
||||
const char STR_H8_3D[] ="H8 3D";
|
||||
const char STR_CORONA[] ="Corona";
|
||||
const char STR_CFLIE[] ="CFlie";
|
||||
const char STR_HITEC[] ="Hitec";
|
||||
const char STR_WFLY[] ="WFly";
|
||||
const char STR_BUGS[] ="Bugs";
|
||||
const char STR_BUGSMINI[] ="BugMini";
|
||||
const char STR_TRAXXAS[] ="Traxxas";
|
||||
const char STR_NCC1701[] ="NCC1701";
|
||||
const char STR_E01X[] ="E01X";
|
||||
const char STR_V911S[] ="V911S";
|
||||
const char STR_GD00X[] ="GD00X";
|
||||
const char STR_V761[] ="V761";
|
||||
const char STR_KF606[] ="KF606";
|
||||
const char STR_REDPINE[] ="Redpine";
|
||||
const char STR_POTENSIC[] ="Potensi";
|
||||
const char STR_ZSX[] ="ZSX";
|
||||
const char STR_FLYZONE[] ="FlyZone";
|
||||
const char STR_SCANNER[] ="Scanner";
|
||||
const char STR_FRSKY_RX[] ="FrSkyRX";
|
||||
const char STR_AFHDS2A_RX[] ="FS2A_RX";
|
||||
const char STR_HOTT[] ="HoTT";
|
||||
const char STR_FX816[] ="FX816";
|
||||
const char STR_BAYANG_RX[] ="BayanRX";
|
||||
const char STR_PELIKAN[] ="Pelikan";
|
||||
const char STR_TIGER[] ="Tiger";
|
||||
const char STR_XN297DUMP[] ="XN297DP";
|
||||
|
||||
const char STR_SUBTYPE_FLYSKY[] = "\x04""Std\0""V9x9""V6x6""V912""CX20";
|
||||
const char STR_SUBTYPE_HUBSAN[] = "\x04""H107""H301""H501";
|
||||
const char STR_SUBTYPE_FRSKYX[] = "\x07""D16\0 ""D16 8ch""LBT(EU)""LBT 8ch";
|
||||
const char STR_SUBTYPE_HISKY[] = "\x05""Std\0 ""HK310";
|
||||
const char STR_SUBTYPE_V2X2[] = "\x06""Std\0 ""JXD506";
|
||||
const char STR_SUBTYPE_DSM[] = "\x06""2 22ms""2 11ms""X 22ms""X 11ms";
|
||||
const char STR_SUBTYPE_DEVO[] = "\x04""8ch\0""10ch""12ch""6ch\0""7ch\0";
|
||||
const char STR_SUBTYPE_YD717[] = "\x07""Std\0 ""SkyWlkr""Syma X4""XINXUN\0""NIHUI\0 ";
|
||||
const char STR_SUBTYPE_KN[] = "\x06""WLtoys""FeiLun";
|
||||
const char STR_SUBTYPE_SYMAX[] = "\x03""Std""X5C";
|
||||
const char STR_SUBTYPE_SLT[] = "\x06""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0";
|
||||
const char STR_SUBTYPE_CX10[] = "\x07""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041";
|
||||
const char STR_SUBTYPE_CG023[] = "\x05""Std\0 ""YD829";
|
||||
const char STR_SUBTYPE_BAYANG[] = "\x07""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4";
|
||||
const char STR_SUBTYPE_MT99[] = "\x06""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805";
|
||||
const char STR_SUBTYPE_MJXQ[] = "\x07""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix";
|
||||
const char STR_SUBTYPE_FY326[] = "\x05""Std\0 ""FY319";
|
||||
const char STR_SUBTYPE_HONTAI[] = "\x07""Std\0 ""JJRC X1""X5C1\0 ""FQ_951";
|
||||
const char STR_SUBTYPE_AFHDS2A[] = "\x08""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS";
|
||||
const char STR_SUBTYPE_Q2X2[] = "\x04""Q222""Q242""Q282";
|
||||
const char STR_SUBTYPE_WK2x01[] = "\x06""WK2801""WK2401""W6_5_1""W6_6_1""W6_HeL""W6_HeI";
|
||||
const char STR_SUBTYPE_Q303[] = "\x06""Std\0 ""CX35\0 ""CX10D\0""CX10WD";
|
||||
const char STR_SUBTYPE_CABELL[] = "\x07""V3\0 ""V3 Telm""-\0 ""-\0 ""-\0 ""-\0 ""F-Safe\0""Unbind\0";
|
||||
const char STR_SUBTYPE_H83D[] = "\x07""Std\0 ""H20H\0 ""H20Mini""H30Mini";
|
||||
const char STR_SUBTYPE_CORONA[] = "\x05""V1\0 ""V2\0 ""FD V3";
|
||||
const char STR_SUBTYPE_HITEC[] = "\x07""Optima\0""Opt Hub""Minima\0";
|
||||
const char STR_SUBTYPE_BUGS_MINI[] = "\x06""Std\0 ""Bugs3H";
|
||||
const char STR_SUBTYPE_TRAXXAS[] = "\x04""6519";
|
||||
const char STR_SUBTYPE_E01X[] = "\x05""E012\0""E015\0""E016H";
|
||||
const char STR_SUBTYPE_GD00X[] = "\x05""GD_V1""GD_V2";
|
||||
const char STR_SUBTYPE_REDPINE[] = "\x04""Fast""Slow";
|
||||
const char STR_SUBTYPE_POTENSIC[] = "\x03""A20";
|
||||
const char STR_SUBTYPE_ZSX[] = "\x07""280JJRC";
|
||||
const char STR_SUBTYPE_FLYZONE[] = "\x05""FZ410";
|
||||
const char STR_SUBTYPE_FX816[] = "\x03""P38";
|
||||
const char STR_SUBTYPE_XN297DUMP[] = "\x07""250Kbps""1Mbps\0 ""2Mbps\0 ""Auto\0 ";
|
||||
const char STR_SUBTYPE_ESKY150[] = "\x03""4CH""7CH";
|
||||
const char STR_SUBTYPE_V911S[] = "\x04""Std\0""E119";
|
||||
|
||||
enum
|
||||
{
|
||||
OPTION_NONE,
|
||||
OPTION_OPTION,
|
||||
OPTION_RFTUNE,
|
||||
OPTION_VIDFREQ,
|
||||
OPTION_FIXEDID,
|
||||
OPTION_TELEM,
|
||||
OPTION_SRVFREQ,
|
||||
OPTION_MAXTHR,
|
||||
OPTION_RFCHAN
|
||||
};
|
||||
|
||||
#define NO_SUBTYPE nullptr
|
||||
|
||||
const mm_protocol_definition multi_protocols[] = {
|
||||
// Protocol number, Protocol String, Number of sub_protocols, Sub_protocol strings, Option type
|
||||
#if defined(FLYSKY_A7105_INO)
|
||||
{PROTO_FLYSKY, STR_FLYSKY, 5, STR_SUBTYPE_FLYSKY, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(HUBSAN_A7105_INO)
|
||||
{PROTO_HUBSAN, STR_HUBSAN, 3, STR_SUBTYPE_HUBSAN, OPTION_VIDFREQ },
|
||||
#endif
|
||||
#if defined(FRSKYD_CC2500_INO)
|
||||
{PROTO_FRSKYD, STR_FRSKYD, 0, NO_SUBTYPE, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(HISKY_NRF24L01_INO)
|
||||
{PROTO_HISKY, STR_HISKY, 2, STR_SUBTYPE_HISKY, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(V2X2_NRF24L01_INO)
|
||||
{PROTO_V2X2, STR_V2X2, 2, STR_SUBTYPE_V2X2, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(DSM_CYRF6936_INO)
|
||||
{PROTO_DSM, STR_DSM, 4, STR_SUBTYPE_DSM, OPTION_MAXTHR },
|
||||
#endif
|
||||
#if defined(DEVO_CYRF6936_INO)
|
||||
{PROTO_DEVO, STR_DEVO, 5, STR_SUBTYPE_DEVO, OPTION_FIXEDID },
|
||||
#endif
|
||||
#if defined(YD717_NRF24L01_INO)
|
||||
{PROTO_YD717, STR_YD717, 5, STR_SUBTYPE_YD717, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(KN_NRF24L01_INO)
|
||||
{PROTO_KN, STR_KN, 2, STR_SUBTYPE_KN, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(SYMAX_NRF24L01_INO)
|
||||
{PROTO_SYMAX, STR_SYMAX, 2, STR_SUBTYPE_SYMAX, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(SLT_NRF24L01_INO)
|
||||
{PROTO_SLT, STR_SLT, 5, STR_SUBTYPE_SLT, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(CX10_NRF24L01_INO)
|
||||
{PROTO_CX10, STR_CX10, 7, STR_SUBTYPE_CX10, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(CG023_NRF24L01_INO)
|
||||
{PROTO_CG023, STR_CG023, 2, STR_SUBTYPE_CG023, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(BAYANG_NRF24L01_INO)
|
||||
{PROTO_BAYANG, STR_BAYANG, 5, STR_SUBTYPE_BAYANG, OPTION_TELEM },
|
||||
#endif
|
||||
#if defined(FRSKYX_CC2500_INO)
|
||||
{PROTO_FRSKYX, STR_FRSKYX, 4, STR_SUBTYPE_FRSKYX, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(ESKY_NRF24L01_INO)
|
||||
{PROTO_ESKY, STR_ESKY, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(MT99XX_NRF24L01_INO)
|
||||
{PROTO_MT99XX, STR_MT99XX, 5, STR_SUBTYPE_MT99, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(MJXQ_NRF24L01_INO)
|
||||
{PROTO_MJXQ, STR_MJXQ, 7, STR_SUBTYPE_MJXQ, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(SHENQI_NRF24L01_INO)
|
||||
{PROTO_SHENQI, STR_SHENQI, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(FY326_NRF24L01_INO)
|
||||
{PROTO_FY326, STR_FY326, 2, STR_SUBTYPE_FY326, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(SFHSS_CC2500_INO)
|
||||
{PROTO_SFHSS, STR_SFHSS, 0, NO_SUBTYPE, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(J6PRO_CYRF6936_INO)
|
||||
{PROTO_J6PRO, STR_J6PRO, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(FQ777_NRF24L01_INO)
|
||||
{PROTO_FQ777, STR_FQ777, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(ASSAN_NRF24L01_INO)
|
||||
{PROTO_ASSAN, STR_ASSAN, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(FRSKYV_CC2500_INO)
|
||||
{PROTO_FRSKYV, STR_FRSKYV, 0, NO_SUBTYPE, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(HONTAI_NRF24L01_INO)
|
||||
{PROTO_HONTAI, STR_HONTAI, 4, STR_SUBTYPE_HONTAI, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(AFHDS2A_A7105_INO)
|
||||
{PROTO_AFHDS2A, STR_AFHDS2A, 4, STR_SUBTYPE_AFHDS2A, OPTION_SRVFREQ },
|
||||
#endif
|
||||
#if defined(CX10_NRF24L01_INO)
|
||||
{PROTO_Q2X2, STR_Q2X2, 3, STR_SUBTYPE_Q2X2, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(WK2x01_CYRF6936_INO)
|
||||
{PROTO_WK2x01, STR_WK2x01, 6, STR_SUBTYPE_WK2x01, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(Q303_NRF24L01_INO)
|
||||
{PROTO_Q303, STR_Q303, 4, STR_SUBTYPE_Q303, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(GW008_NRF24L01_INO)
|
||||
{PROTO_GW008, STR_GW008, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(DM002_NRF24L01_INO)
|
||||
{PROTO_DM002, STR_DM002, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(CABELL_NRF24L01_INO)
|
||||
{PROTO_CABELL, STR_CABELL, 8, STR_SUBTYPE_CABELL, OPTION_OPTION },
|
||||
#endif
|
||||
#if defined(ESKY150_NRF24L01_INO)
|
||||
{PROTO_ESKY150, STR_ESKY150, 2, STR_SUBTYPE_ESKY150, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(H8_3D_NRF24L01_INO)
|
||||
{PROTO_H8_3D, STR_H8_3D, 4, STR_SUBTYPE_H83D, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(CORONA_CC2500_INO)
|
||||
{PROTO_CORONA, STR_CORONA, 3, STR_SUBTYPE_CORONA, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(CFLIE_NRF24L01_INO)
|
||||
{PROTO_CFLIE, STR_CFLIE, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(HITEC_CC2500_INO)
|
||||
{PROTO_HITEC, STR_HITEC, 3, STR_SUBTYPE_HITEC, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(WFLY_CYRF6936_INO)
|
||||
{PROTO_WFLY, STR_WFLY, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(BUGS_A7105_INO)
|
||||
{PROTO_BUGS, STR_BUGS, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(BUGSMINI_NRF24L01_INO)
|
||||
{PROTO_BUGSMINI, STR_BUGSMINI, 2, STR_SUBTYPE_BUGS_MINI, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(TRAXXAS_CYRF6936_INO)
|
||||
{PROTO_TRAXXAS, STR_TRAXXAS, 1, STR_SUBTYPE_TRAXXAS, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(NCC1701_NRF24L01_INO)
|
||||
{PROTO_NCC1701, STR_NCC1701, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(E01X_NRF24L01_INO)
|
||||
{PROTO_E01X, STR_E01X, 3, STR_SUBTYPE_E01X, OPTION_OPTION },
|
||||
#endif
|
||||
#if defined(V911S_NRF24L01_INO)
|
||||
{PROTO_V911S, STR_V911S, 1, STR_SUBTYPE_V911S, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(GD00X_NRF24L01_INO)
|
||||
{PROTO_GD00X, STR_GD00X, 2, STR_SUBTYPE_GD00X, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(V761_NRF24L01_INO)
|
||||
{PROTO_V761, STR_V761, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(KF606_NRF24L01_INO)
|
||||
{PROTO_KF606, STR_KF606, 0, NO_SUBTYPE, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(REDPINE_CC2500_INO)
|
||||
{PROTO_REDPINE, STR_REDPINE, 2, STR_SUBTYPE_REDPINE, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(POTENSIC_NRF24L01_INO)
|
||||
{PROTO_POTENSIC, STR_POTENSIC, 1, STR_SUBTYPE_POTENSIC, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(ZSX_NRF24L01_INO)
|
||||
{PROTO_ZSX, STR_ZSX, 1, STR_SUBTYPE_ZSX, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(FLYZONE_A7105_INO)
|
||||
{PROTO_FLYZONE, STR_FLYZONE, 1, STR_SUBTYPE_FLYZONE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(SCANNER_CC2500_INO)
|
||||
{PROTO_SCANNER, STR_SCANNER, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(FRSKY_RX_CC2500_INO)
|
||||
{PROTO_FRSKY_RX, STR_FRSKY_RX, 0, NO_SUBTYPE, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(AFHDS2A_RX_A7105_INO)
|
||||
{PROTO_AFHDS2A_RX, STR_AFHDS2A_RX,0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(HOTT_CC2500_INO)
|
||||
{PROTO_HOTT, STR_HOTT, 0, NO_SUBTYPE, OPTION_RFTUNE },
|
||||
#endif
|
||||
#if defined(FX816_NRF24L01_INO)
|
||||
{PROTO_FX816, STR_FX816, 1, STR_SUBTYPE_FX816, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(BAYANG_RX_NRF24L01_INO)
|
||||
{PROTO_BAYANG_RX, STR_BAYANG_RX, 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(PELIKAN_A7105_INO)
|
||||
{PROTO_PELIKAN, STR_PELIKAN , 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(TIGER_NRF24L01_INO)
|
||||
{PROTO_TIGER, STR_TIGER , 0, NO_SUBTYPE, OPTION_NONE },
|
||||
#endif
|
||||
#if defined(XN297DUMP_NRF24L01_INO)
|
||||
{PROTO_XN297DUMP, STR_XN297DUMP, 4, STR_SUBTYPE_XN297DUMP, OPTION_RFCHAN },
|
||||
#endif
|
||||
{0x00, nullptr, 0, nullptr, 0 }
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(NCC_PACKET_INTERVAL);
|
||||
#endif
|
||||
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;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -14,9 +14,7 @@
|
||||
*/
|
||||
|
||||
|
||||
//---------------------------
|
||||
// AVR nrf chip bitbang SPI functions
|
||||
//---------------------------
|
||||
#ifdef NRF24L01_INSTALLED
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
|
||||
@@ -29,6 +27,8 @@ 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)
|
||||
@@ -76,6 +76,7 @@ uint8_t NRF24L01_ReadReg(uint8_t reg)
|
||||
NRF_CSN_on;
|
||||
}
|
||||
*/
|
||||
|
||||
static void NRF24L01_ReadPayload(uint8_t * data, uint8_t length)
|
||||
{
|
||||
NRF_CSN_off;
|
||||
@@ -102,6 +103,20 @@ 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;
|
||||
@@ -119,7 +134,8 @@ void NRF24L01_SetBitrate(uint8_t bitrate)
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -145,18 +161,26 @@ void NRF24L01_SetBitrate(uint8_t bitrate)
|
||||
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));
|
||||
@@ -164,13 +188,12 @@ void NRF24L01_SetTxRxMode(enum TXRX_State mode)
|
||||
| (1 << NRF24L01_00_CRCO)
|
||||
| (1 << NRF24L01_00_PWR_UP));
|
||||
delayMicroseconds(130);
|
||||
NRF_CSN_on;
|
||||
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));
|
||||
@@ -179,12 +202,12 @@ void NRF24L01_SetTxRxMode(enum TXRX_State mode)
|
||||
| (1 << NRF24L01_00_PWR_UP)
|
||||
| (1 << NRF24L01_00_PRIM_RX));
|
||||
delayMicroseconds(130);
|
||||
NRF_CSN_on;
|
||||
NRF_CE_on;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_EN_CRC)); //PowerDown
|
||||
NRF_CSN_off;
|
||||
NRF_CE_off;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,23 +223,24 @@ void NRF24L01_Reset()
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_Strobe(0xff); // NOP
|
||||
NRF24L01_ReadReg(0x07);
|
||||
NRF24L01_ReadReg(NRF24L01_07_STATUS);
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
|
||||
uint8_t NRF24L01_packet_ack()
|
||||
{
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)))
|
||||
switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (_BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT)))
|
||||
{
|
||||
case BV(NRF24L01_07_TX_DS):
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
// XN297 emulation layer
|
||||
uint8_t xn297_scramble_enabled=XN297_SCRAMBLED; //enabled by default
|
||||
@@ -225,26 +249,52 @@ 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 };
|
||||
|
||||
// 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};
|
||||
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 };
|
||||
|
||||
// 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};
|
||||
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
|
||||
#ifdef XN297DUMP_NRF24L01_INO
|
||||
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 };
|
||||
#endif
|
||||
|
||||
static uint8_t bit_reverse(uint8_t b_in)
|
||||
{
|
||||
@@ -258,10 +308,10 @@ static uint8_t bit_reverse(uint8_t b_in)
|
||||
}
|
||||
|
||||
static const uint16_t polynomial = 0x1021;
|
||||
static uint16_t crc16_update(uint16_t crc, uint8_t a)
|
||||
static uint16_t crc16_update(uint16_t crc, uint8_t a, uint8_t bits)
|
||||
{
|
||||
crc ^= a << 8;
|
||||
for (uint8_t i = 0; i < 8; ++i)
|
||||
while(bits--)
|
||||
if (crc & 0x8000)
|
||||
crc = (crc << 1) ^ polynomial;
|
||||
else
|
||||
@@ -307,12 +357,12 @@ void XN297_SetRXAddr(const uint8_t* addr, uint8_t len)
|
||||
|
||||
void XN297_Configure(uint8_t flags)
|
||||
{
|
||||
xn297_crc = !!(flags & BV(NRF24L01_00_EN_CRC));
|
||||
flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO));
|
||||
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 u8 mode)
|
||||
void XN297_SetScrambledMode(const uint8_t mode)
|
||||
{
|
||||
xn297_scramble_enabled = mode;
|
||||
}
|
||||
@@ -339,8 +389,7 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len)
|
||||
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;
|
||||
buf[last] = bit_reverse(msg[i]);
|
||||
if(xn297_scramble_enabled)
|
||||
buf[last] ^= xn297_scramble[xn297_addr_len+i];
|
||||
last++;
|
||||
@@ -350,7 +399,7 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len)
|
||||
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 = crc16_update(crc, buf[i], 8);
|
||||
if(xn297_scramble_enabled)
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
|
||||
else
|
||||
@@ -361,19 +410,276 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len)
|
||||
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)
|
||||
{
|
||||
// TODO: if xn297_crc==1, check CRC before filling *msg
|
||||
NRF24L01_ReadPayload(msg, len);
|
||||
for(uint8_t i=0; i<len; i++)
|
||||
uint8_t packet[32];
|
||||
uint8_t scramble_index=0;
|
||||
uint8_t last = 0;
|
||||
static uint8_t pid=0;
|
||||
|
||||
// address
|
||||
if (xn297_addr_len < 4)
|
||||
{
|
||||
msg[i] = bit_reverse(msg[i]);
|
||||
if(xn297_scramble_enabled)
|
||||
msg[i] ^= bit_reverse(xn297_scramble[i+xn297_addr_len]);
|
||||
// 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_rx_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)
|
||||
{ //!!! Don't forget do a +2 and if using CRC add +2 on any of the used NRF24L01_11_RX_PW_Px !!!
|
||||
uint8_t buffer[32];
|
||||
uint8_t pcf_size; // pcf payload size
|
||||
if (xn297_crc)
|
||||
NRF24L01_ReadPayload(buffer, len+4); // Read pcf + payload + CRC
|
||||
else
|
||||
NRF24L01_ReadPayload(buffer, len+2); // Read 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));
|
||||
}
|
||||
|
||||
if (!xn297_crc)
|
||||
return pcf_size; // 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_rx_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+1; ++i)
|
||||
crc = crc16_update(crc, buffer[i], 8);
|
||||
crc = crc16_update(crc, buffer[len+1] & 0xc0, 2);
|
||||
//xorout
|
||||
if (xn297_scramble_enabled)
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled_enhanced[xn297_addr_len-3+len]);
|
||||
#ifdef XN297DUMP_NRF24L01_INO
|
||||
else
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_enhanced[xn297_addr_len - 3 + len]);
|
||||
#endif
|
||||
uint16_t crcxored=(buffer[len+1]<<10)|(buffer[len+2]<<2)|(buffer[len+3]>>6) ;
|
||||
if( crc == crcxored)
|
||||
return pcf_size; // CRC OK
|
||||
return 0; // CRC NOK
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -507,14 +813,14 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len)
|
||||
//Check len
|
||||
if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN))
|
||||
{
|
||||
crc=crc16_update(crc,buffer[pos]);
|
||||
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]);
|
||||
crc=crc16_update(crc,buffer[pos],8);
|
||||
msg[i]=bit_reverse(buffer[pos++]);
|
||||
}
|
||||
//Check CRC
|
||||
@@ -536,14 +842,14 @@ void LT8900_WritePayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
tmp=bit_reverse(len);
|
||||
buffer[pos++]=tmp;
|
||||
crc=crc16_update(crc,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);
|
||||
crc=crc16_update(crc,tmp,8);
|
||||
}
|
||||
//Add CRC
|
||||
if(LT8900_Flags&_BV(LT8900_CRC_ON))
|
||||
@@ -568,3 +874,4 @@ void LT8900_WritePayload(uint8_t* msg, uint8_t len)
|
||||
NRF24L01_WritePayload(LT8900_buffer+LT8900_buffer_start,pos_final+pos-LT8900_buffer_start);
|
||||
}
|
||||
// End of LT8900 emulation
|
||||
#endif
|
||||
128
Multiprotocol/POTENSIC_nrf24l01.ino
Normal file
128
Multiprotocol/POTENSIC_nrf24l01.ino
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(POTENSIC_PACKET_PERIOD);
|
||||
#endif
|
||||
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
|
||||
157
Multiprotocol/Pelikan_a7105.ino
Normal file
157
Multiprotocol/Pelikan_a7105.ino
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Compatible with CADET PRO V4 TX
|
||||
|
||||
#if defined(PELIKAN_A7105_INO)
|
||||
|
||||
#include "iface_a7105.h"
|
||||
|
||||
//#define PELIKAN_FORCE_ID
|
||||
|
||||
#define PELIKAN_BIND_COUNT 400
|
||||
#define PELIKAN_BIND_RF 0x3C
|
||||
#define PELIKAN_NUM_RF_CHAN 0x1D
|
||||
#define PELIKAN_PAQUET_PERIOD 7980
|
||||
|
||||
static void __attribute__((unused)) pelikan_build_packet()
|
||||
{
|
||||
static boolean upper=false;
|
||||
packet[0] = 0x15;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[1] = 0x04; //version??
|
||||
packet[2] = rx_tx_addr[0];
|
||||
packet[3] = rx_tx_addr[1];
|
||||
packet[4] = rx_tx_addr[2];
|
||||
packet[5] = rx_tx_addr[3];
|
||||
packet[6] = 0x05; //??
|
||||
packet[7] = 0x00; //??
|
||||
packet[8] = 0x55; //??
|
||||
packet_length = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
//ID
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[7] = rx_tx_addr[1];
|
||||
packet[12] = rx_tx_addr[2];
|
||||
packet[13] = rx_tx_addr[3];
|
||||
//Channels
|
||||
uint8_t offset=upper?4:0;
|
||||
uint16_t channel=convert_channel_16b_nolimit(CH_AETR[offset++], 153, 871);
|
||||
uint8_t top=(channel>>2) & 0xC0;
|
||||
packet[2] = channel;
|
||||
channel=convert_channel_16b_nolimit(CH_AETR[offset++], 153, 871);
|
||||
top|=(channel>>4) & 0x30;
|
||||
packet[3] = channel;
|
||||
channel=convert_channel_16b_nolimit(CH_AETR[offset++], 153, 871);
|
||||
top|=(channel>>6) & 0x0C;
|
||||
packet[4] = channel;
|
||||
channel=convert_channel_16b_nolimit(CH_AETR[offset], 153, 871);
|
||||
top|=(channel>>8) & 0x03;
|
||||
packet[5] = channel;
|
||||
packet[6] = top;
|
||||
//Check
|
||||
crc8=0x15;
|
||||
for(uint8_t i=1;i<8;i++)
|
||||
crc8+=packet[i];
|
||||
packet[8]=crc8;
|
||||
//Low/Up channel flag
|
||||
packet[9]=upper?0xAA:0x00;
|
||||
upper=!upper;
|
||||
//Hopping counters
|
||||
if(++packet_count>4)
|
||||
{
|
||||
packet_count=0;
|
||||
if(++hopping_frequency_no>=PELIKAN_NUM_RF_CHAN)
|
||||
hopping_frequency_no=0;
|
||||
}
|
||||
packet[10]=hopping_frequency_no;
|
||||
packet[11]=packet_count;
|
||||
|
||||
packet_length = 15;
|
||||
}
|
||||
|
||||
//Check
|
||||
crc8=0x15;
|
||||
for(uint8_t i=1; i<packet_length-1 ;i++)
|
||||
crc8+=packet[i];
|
||||
packet[packet_length-1]=crc8;
|
||||
|
||||
//Send
|
||||
#ifdef DEBUG_SERIAL
|
||||
if(packet[9]==0x00)
|
||||
{
|
||||
debug("C: %02X P(%d):",IS_BIND_IN_PROGRESS?PELIKAN_BIND_RF:hopping_frequency[hopping_frequency_no],packet_length);
|
||||
for(uint8_t i=0;i<packet_length;i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");
|
||||
}
|
||||
#endif
|
||||
A7105_WriteData(packet_length, IS_BIND_IN_PROGRESS?PELIKAN_BIND_RF:hopping_frequency[hopping_frequency_no]);
|
||||
A7105_SetPower();
|
||||
}
|
||||
|
||||
uint16_t ReadPelikan()
|
||||
{
|
||||
#ifndef FORCE_PELIKAN_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
bind_counter--;
|
||||
if (bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
A7105_Strobe(A7105_STANDBY);
|
||||
A7105_WriteReg(A7105_03_FIFOI,0x28);
|
||||
}
|
||||
}
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(PELIKAN_PAQUET_PERIOD);
|
||||
#endif
|
||||
pelikan_build_packet();
|
||||
return PELIKAN_PAQUET_PERIOD;
|
||||
}
|
||||
|
||||
const uint8_t PROGMEM pelikan_hopp[][PELIKAN_NUM_RF_CHAN] = {
|
||||
{ 0x5A,0x46,0x32,0x6E,0x6C,0x58,0x44,0x42,0x40,0x6A,0x56,0x54,0x52,0x3E,0x68,0x66,0x64,0x50,0x3C,0x3A,0x38,0x62,0x4E,0x4C,0x5E,0x4A,0x36,0x5C,0x34 }
|
||||
};
|
||||
|
||||
uint16_t initPelikan()
|
||||
{
|
||||
A7105_Init();
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
A7105_WriteReg(A7105_03_FIFOI,0x10);
|
||||
|
||||
//ID from dump
|
||||
#ifdef PELIKAN_FORCE_ID
|
||||
rx_tx_addr[0]=0x0D; // hopping freq
|
||||
rx_tx_addr[1]=0xF4; // hopping freq
|
||||
rx_tx_addr[2]=0x50; // ID
|
||||
rx_tx_addr[3]=0x18; // ID
|
||||
#endif
|
||||
|
||||
// Fill frequency table
|
||||
rx_tx_addr[0]=0x0D; // hopping freq
|
||||
rx_tx_addr[1]=0xF4; // hopping freq
|
||||
for(uint8_t i=0;i<PELIKAN_NUM_RF_CHAN;i++)
|
||||
hopping_frequency[i]=pgm_read_byte_near(&pelikan_hopp[0][i]);
|
||||
|
||||
hopping_frequency_no=PELIKAN_NUM_RF_CHAN;
|
||||
packet_count=5;
|
||||
return 2400;
|
||||
}
|
||||
#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
|
||||
413
Multiprotocol/Q303_nrf24l01.ino
Normal file
413
Multiprotocol/Q303_nrf24l01.ino
Normal file
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
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)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
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
|
||||
248
Multiprotocol/Redpine_cc2500.ino
Normal file
248
Multiprotocol/Redpine_cc2500.ino
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
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
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
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);
|
||||
return packet_period;
|
||||
}
|
||||
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
|
||||
|
||||
if (sub_protocol==0)
|
||||
packet_period = REDPINE_LOOPTIME_FAST*100;
|
||||
else
|
||||
packet_period = REDPINE_LOOPTIME_SLOW*1000;
|
||||
|
||||
bind_counter=REDPINE_BIND;
|
||||
REDPINE_init(sub_protocol);
|
||||
CC2500_SetTxRxMode(TX_EN); // enable PA
|
||||
return 10000;
|
||||
}
|
||||
#endif
|
||||
@@ -18,20 +18,19 @@
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
#define SFHSS_USE_TUNE_FREQ
|
||||
#define SFHSS_COARSE 0
|
||||
|
||||
#define SFHSS_PACKET_LEN 13
|
||||
#define SFHSS_TX_ID_LEN 2
|
||||
|
||||
uint8_t fhss_code; // 0-27
|
||||
uint8_t fhss_code=0; // 0-27
|
||||
|
||||
enum {
|
||||
SFHSS_START = 0x101,
|
||||
SFHSS_CAL = 0x102,
|
||||
SFHSS_TUNE = 0x103,
|
||||
SFHSS_START = 0x00,
|
||||
SFHSS_CAL = 0x01,
|
||||
SFHSS_DATA1 = 0x02,
|
||||
SFHSS_DATA2 = 0x0b
|
||||
SFHSS_DATA2 = 0x03,
|
||||
SFHSS_TUNE = 0x04
|
||||
};
|
||||
|
||||
#define SFHSS_FREQ0_VAL 0xC4
|
||||
@@ -73,6 +72,20 @@ const PROGMEM uint8_t SFHSS_init_values[] = {
|
||||
/* 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);
|
||||
@@ -84,32 +97,18 @@ static void __attribute__((unused)) SFHSS_tune_chan_fast()
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num*6+16);
|
||||
CC2500_WriteRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3);
|
||||
delayMicroseconds(6);
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[rf_ch_num]);
|
||||
}
|
||||
|
||||
#ifdef SFHSS_USE_TUNE_FREQ
|
||||
static void __attribute__((unused)) SFHSS_tune_freq() {
|
||||
// May be we'll need this tuning routine - some receivers are more sensitive to
|
||||
// frequency impreciseness, and though CC2500 has a procedure to handle it it
|
||||
// may not be applied in receivers, so we need to compensate for it on TX
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
CC2500_WriteReg(CC2500_0F_FREQ0, SFHSS_FREQ0_VAL + SFHSS_COARSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __attribute__((unused)) SFHSS_rf_init()
|
||||
static void __attribute__((unused)) SFHSS_tune_freq()
|
||||
{
|
||||
CC2500_Reset();
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
|
||||
for (uint8_t i = 0; i < 39; ++i)
|
||||
CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i]));
|
||||
//CC2500_WriteRegisterMulti(CC2500_00_IOCFG2, init_values, sizeof(init_values));
|
||||
//CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
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()
|
||||
@@ -123,102 +122,138 @@ static void __attribute__((unused)) SFHSS_calc_next_chan()
|
||||
}
|
||||
}
|
||||
|
||||
// Channel values are 10-bit values between 86 and 906, 496 is the middle.
|
||||
static uint16_t __attribute__((unused)) SFHSS_convert_channel(uint8_t num)
|
||||
{
|
||||
return (uint16_t) (map(limit_channel_100(num),PPM_MIN_100,PPM_MAX_100,86,906));
|
||||
}
|
||||
|
||||
|
||||
// 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()
|
||||
{
|
||||
#define spacer1 0x02 //0b10
|
||||
#define spacer2 (spacer1 << 4)
|
||||
uint8_t ch_offset = state == SFHSS_DATA1 ? 0 : 4;
|
||||
uint16_t ch1 = SFHSS_convert_channel(CH_AETR[ch_offset+0]);
|
||||
uint16_t ch2 = SFHSS_convert_channel(CH_AETR[ch_offset+1]);
|
||||
uint16_t ch3 = SFHSS_convert_channel(CH_AETR[ch_offset+2]);
|
||||
uint16_t ch4 = SFHSS_convert_channel(CH_AETR[ch_offset+3]);
|
||||
|
||||
packet[0] = 0x81; // can be 80, 81, 81 for Orange, only 81 for XK
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
packet[3] = 0;
|
||||
packet[4] = 0;
|
||||
packet[5] = (rf_ch_num << 3) | spacer1 | ((ch1 >> 9) & 0x01);
|
||||
packet[6] = (ch1 >> 1);
|
||||
packet[7] = (ch1 << 7) | spacer2 | ((ch2 >> 5) & 0x1F /*0b11111*/);
|
||||
packet[8] = (ch2 << 3) | spacer1 | ((ch3 >> 9) & 0x01);
|
||||
packet[9] = (ch3 >> 1);
|
||||
packet[10] = (ch3 << 7) | spacer2 | ((ch4 >> 5) & 0x1F /*0b11111*/);
|
||||
packet[11] = (ch4 << 3) | ((fhss_code >> 2) & 0x07 /*0b111 */);
|
||||
packet[12] = (fhss_code << 6) | state;
|
||||
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(IS_DISABLE_CH_MAP_off && ch_offset+i==CH3 && 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()
|
||||
{
|
||||
SFHSS_tune_chan_fast();
|
||||
CC2500_WriteData(packet, SFHSS_PACKET_LEN);
|
||||
}
|
||||
|
||||
uint16_t ReadSFHSS()
|
||||
{
|
||||
switch(state)
|
||||
switch(phase)
|
||||
{
|
||||
case SFHSS_START:
|
||||
rf_ch_num = 0;
|
||||
SFHSS_tune_chan();
|
||||
state = SFHSS_CAL;
|
||||
phase = SFHSS_CAL;
|
||||
return 2000;
|
||||
case SFHSS_CAL:
|
||||
CC2500_ReadRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3);
|
||||
calData[rf_ch_num]=CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
if (++rf_ch_num < 30)
|
||||
SFHSS_tune_chan();
|
||||
else
|
||||
{
|
||||
rf_ch_num = 0;
|
||||
state = SFHSS_DATA1;
|
||||
counter = 0;
|
||||
phase = SFHSS_DATA1;
|
||||
}
|
||||
return 2000;
|
||||
|
||||
/* Work cycle, 6.8ms, second packet 1.65ms after first */
|
||||
/* 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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(6800);
|
||||
#endif
|
||||
SFHSS_build_data_packet();
|
||||
SFHSS_send_packet();
|
||||
state = SFHSS_DATA2;
|
||||
return 1650;
|
||||
phase = SFHSS_DATA2;
|
||||
return SFHSS_DATA2_TIMING; // original 1650
|
||||
case SFHSS_DATA2:
|
||||
SFHSS_build_data_packet();
|
||||
SFHSS_send_packet();
|
||||
SFHSS_calc_next_chan();
|
||||
state = SFHSS_TUNE;
|
||||
return 2000;
|
||||
phase = SFHSS_TUNE;
|
||||
return (SFHSS_PACKET_PERIOD -2000 -SFHSS_DATA2_TIMING); // original 2000
|
||||
case SFHSS_TUNE:
|
||||
#ifdef SFHSS_USE_TUNE_FREQ
|
||||
phase = SFHSS_DATA1;
|
||||
SFHSS_tune_freq();
|
||||
#endif
|
||||
SFHSS_tune_chan_fast();
|
||||
CC2500_SetPower();
|
||||
state = SFHSS_DATA1;
|
||||
return 3150;
|
||||
/*
|
||||
case SFHSS_DATA1:
|
||||
SFHSS_build_data_packet();
|
||||
SFHSS_send_packet();
|
||||
state = SFHSS_DATA2;
|
||||
return 1650;
|
||||
case SFHSS_DATA2:
|
||||
SFHSS_build_data_packet();
|
||||
SFHSS_send_packet();
|
||||
state = SFHSS_CAL2;
|
||||
return 500;
|
||||
case SFHSS_CAL2:
|
||||
SFHSS_tune_freq();
|
||||
// CC2500_SetPower();
|
||||
SFHSS_calc_next_chan();
|
||||
SFHSS_tune_chan();
|
||||
state = SFHSS_DATA1;
|
||||
return 4650;
|
||||
*/
|
||||
return 2000; // original 3150
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -226,9 +261,9 @@ uint16_t ReadSFHSS()
|
||||
// Generate internal id
|
||||
static void __attribute__((unused)) SFHSS_get_tx_id()
|
||||
{
|
||||
uint32_t fixed_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);
|
||||
@@ -250,19 +285,18 @@ static void __attribute__((unused)) SFHSS_get_tx_id()
|
||||
}
|
||||
// fixed_id = 0xBC11;
|
||||
rx_tx_addr[0] = fixed_id >> 8;
|
||||
rx_tx_addr[1] = fixed_id;
|
||||
rx_tx_addr[1] = fixed_id >> 0;
|
||||
}
|
||||
|
||||
uint16_t initSFHSS()
|
||||
{
|
||||
BIND_DONE; // No bind protocol
|
||||
BIND_DONE; // Not a TX bind protocol
|
||||
SFHSS_get_tx_id();
|
||||
|
||||
fhss_code=rx_tx_addr[2]%28; // Initialize it to random 0-27 inclusive
|
||||
fhss_code=random(0xfefefefe)%28; // Initialize it to random 0-27 inclusive
|
||||
|
||||
SFHSS_rf_init();
|
||||
state = SFHSS_START;
|
||||
|
||||
phase = SFHSS_START;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
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"
|
||||
@@ -48,9 +63,13 @@ void SHENQI_send_packet()
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
if(packet_count==1)
|
||||
telemetry_set_input_sync(3000+2508+6*1750);
|
||||
#endif
|
||||
LT8900_SetAddress(rx_tx_addr,4);
|
||||
packet[1]=255-convert_channel_8b(RUDDER);
|
||||
packet[2]=255-convert_channel_8b_scale(THROTTLE,0x60,0xA0);
|
||||
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++;
|
||||
@@ -75,11 +94,13 @@ void SHENQI_send_packet()
|
||||
|
||||
uint16_t SHENQI_callback()
|
||||
{
|
||||
if(IS_BIND_DONE_on)
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
SHENQI_send_packet();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR))
|
||||
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
|
||||
{
|
||||
if(LT8900_ReadPayload(packet, 3))
|
||||
{
|
||||
@@ -101,7 +122,7 @@ uint16_t initSHENQI()
|
||||
SHENQI_init();
|
||||
hopping_frequency_no = 0;
|
||||
packet_count=0;
|
||||
packet_period=100;
|
||||
packet_period=500;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,202 +1,298 @@
|
||||
/*
|
||||
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/slt_nrf24l01.c dated 2015-02-13
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
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();
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xC3\xC3\xAA\x55", 4);
|
||||
NRF24L01_FlushRx();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) SLT_init2()
|
||||
{
|
||||
NRF24L01_FlushTx();
|
||||
packet_sent = 0;
|
||||
hopping_frequency_no = 0;
|
||||
|
||||
// Turn radio power on
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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);
|
||||
}
|
||||
|
||||
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_data(uint8_t *data, 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(data, len);
|
||||
//NRF24L01_PulseCE();
|
||||
packet_sent = 1;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) 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
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
uint16_t v = convert_channel_10b(CH_AETR[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 __attribute__((unused)) SLT_send_bind_packet()
|
||||
{
|
||||
SLT_wait_radio();
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x7E\xB8\x63\xA9", 4);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x50);
|
||||
SLT_send_data(rx_tx_addr, 4);
|
||||
|
||||
// NB: we should wait until the packet's sent before changing TX address!
|
||||
SLT_wait_radio();
|
||||
|
||||
BIND_DONE;
|
||||
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:
|
||||
SLT_send_bind_packet();
|
||||
phase = SLT_DATA1;
|
||||
delay_us = 19000;
|
||||
break;
|
||||
case SLT_DATA1:
|
||||
SLT_build_packet();
|
||||
SLT_send_data(packet, 7);
|
||||
phase = SLT_DATA2;
|
||||
delay_us = 1000;
|
||||
break;
|
||||
case SLT_DATA2:
|
||||
SLT_send_data(packet, 7);
|
||||
phase = SLT_DATA3;
|
||||
delay_us = 1000;
|
||||
break;
|
||||
case SLT_DATA3:
|
||||
SLT_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();
|
||||
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 && (i==CH2 || i==CH3) )
|
||||
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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(sub_protocol==SLT_V1?20000:13730);
|
||||
#endif
|
||||
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
|
||||
147
Multiprotocol/Scanner_cc2500.ino
Normal file
147
Multiprotocol/Scanner_cc2500.ino
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
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(SCANNER_CC2500_INO)
|
||||
|
||||
#include "iface_cc2500.h"
|
||||
|
||||
#define SCAN_MAX_RADIOCHANNEL 249 // 2483 MHz
|
||||
#define SCAN_CHANNEL_LOCK_TIME 90 // with precalibration, channel requires only 90 usec for synthesizer to settle
|
||||
#define SCAN_AVERAGE_INTVL 20
|
||||
#define SCAN_MAX_COUNT 10
|
||||
#define SCAN_CHANS_PER_PACKET 5
|
||||
|
||||
enum ScanStates {
|
||||
SCAN_CHANNEL_CHANGE = 0,
|
||||
SCAN_GET_RSSI = 1,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) Scanner_cc2500_init()
|
||||
{
|
||||
/* Initialize CC2500 chip */
|
||||
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x12); // Packet Automation Control
|
||||
CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x0A); // Frequency Synthesizer Control
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, 0x00); // Frequency Synthesizer Control
|
||||
CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // Frequency Control Word, High Byte
|
||||
CC2500_WriteReg(CC2500_0E_FREQ1, 0x4E); // Frequency Control Word, Middle Byte
|
||||
CC2500_WriteReg(CC2500_0F_FREQ0, 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_SetTxRxMode(RX_EN); // Receive mode
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_Strobe(CC2500_SRX);
|
||||
|
||||
delayMicroseconds(1000); // wait for RX to activate
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) Scanner_calibrate()
|
||||
{
|
||||
for (uint8_t c = 0; c < SCAN_MAX_RADIOCHANNEL; c++)
|
||||
{
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, c);
|
||||
CC2500_Strobe(CC2500_SCAL);
|
||||
delayMicroseconds(900);
|
||||
calData[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||
}
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) Scanner_scan_next()
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num);
|
||||
CC2500_WriteReg(CC2500_25_FSCAL1, calData[rf_ch_num]);
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
CC2500_Strobe(CC2500_SRX);
|
||||
}
|
||||
|
||||
static int __attribute__((unused)) Scanner_scan_rssi()
|
||||
{
|
||||
uint8_t rssi;
|
||||
rssi = CC2500_ReadReg(0x40 | CC2500_34_RSSI); // 0.5 db/count, RSSI value read from the RSSI status register is a 2's complement number
|
||||
uint8_t rssi_rel;
|
||||
if (rssi >= 128) {
|
||||
rssi_rel = rssi - 128; // relative power levels 0-127 (equals -137 to -72 dBm)
|
||||
}
|
||||
else {
|
||||
rssi_rel = rssi + 128; // relative power levels 128-255 (equals -73 to -10 dBm)
|
||||
}
|
||||
return rssi_rel;
|
||||
}
|
||||
|
||||
uint16_t Scanner_callback()
|
||||
{
|
||||
uint8_t rssi,max_rssi;
|
||||
|
||||
//!!!Blocking mode protocol!!!
|
||||
TX_MAIN_PAUSE_off;
|
||||
tx_resume();
|
||||
while(1)
|
||||
{ //Start
|
||||
packet_in[0] = rf_ch_num; // start channel for telemetry packet
|
||||
for(uint8_t i=0;i<SCAN_CHANS_PER_PACKET;i++)
|
||||
{
|
||||
Scanner_scan_next(); // set channel
|
||||
delayMicroseconds(SCAN_CHANNEL_LOCK_TIME); // wait for freq to adjust
|
||||
max_rssi = 0;
|
||||
for(uint8_t j=0;j<SCAN_MAX_COUNT;j++)
|
||||
{
|
||||
rssi = Scanner_scan_rssi();
|
||||
if(rssi >= max_rssi) max_rssi = rssi;
|
||||
delayMicroseconds(SCAN_AVERAGE_INTVL); // wait before next read
|
||||
}
|
||||
packet_in[i+1] = max_rssi;
|
||||
//next channel
|
||||
rf_ch_num++;
|
||||
if (rf_ch_num >= (SCAN_MAX_RADIOCHANNEL + 1))
|
||||
rf_ch_num = 0;
|
||||
}
|
||||
telemetry_link = 1;
|
||||
do
|
||||
{
|
||||
if(Update_All())
|
||||
return 1000; // protocol has changed, give back the control to main
|
||||
}
|
||||
while(telemetry_link == 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t initScanner(void)
|
||||
{
|
||||
rf_ch_num = 0;
|
||||
telemetry_link = 0;
|
||||
Scanner_cc2500_init();
|
||||
CC2500_Strobe(CC2500_SRX);
|
||||
Scanner_calibrate();
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
CC2500_Strobe(CC2500_SRX); // Receive mode
|
||||
return 1250;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -13,7 +13,6 @@
|
||||
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
|
||||
// Last sync with hexfet new_protocols/cx10_nrf24l01.c dated 2015-09-28
|
||||
|
||||
#if defined(SYMAX_NRF24L01_INO)
|
||||
|
||||
@@ -30,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
|
||||
@@ -58,6 +58,7 @@ 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);
|
||||
@@ -65,17 +66,23 @@ static void __attribute__((unused)) SYMAX_read_controls()
|
||||
|
||||
flags=0;
|
||||
// Channel 5
|
||||
if (Servo_AUX1)
|
||||
if (CH5_SW)
|
||||
flags = SYMAX_FLAG_FLIP;
|
||||
// Channel 6
|
||||
if (CH6_SW)
|
||||
flags |= SYMAX_XTRM_RATES;
|
||||
// Channel 7
|
||||
if (Servo_AUX3)
|
||||
if (CH7_SW)
|
||||
flags |= SYMAX_FLAG_PICTURE;
|
||||
// Channel 8
|
||||
if (Servo_AUX4)
|
||||
if (CH8_SW)
|
||||
flags |= SYMAX_FLAG_VIDEO;
|
||||
// Channel 9
|
||||
if (Servo_AUX5)
|
||||
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)
|
||||
@@ -98,9 +105,18 @@ static void __attribute__((unused)) 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;
|
||||
@@ -138,9 +154,15 @@ static void __attribute__((unused)) 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)
|
||||
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);
|
||||
@@ -174,7 +196,7 @@ static void __attribute__((unused)) symax_init()
|
||||
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
|
||||
@@ -292,7 +314,7 @@ static void __attribute__((unused)) symax_set_channels(uint8_t address)
|
||||
|
||||
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)
|
||||
@@ -319,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;
|
||||
@@ -333,10 +355,13 @@ uint16_t symax_callback()
|
||||
else
|
||||
{
|
||||
SYMAX_send_packet(1);
|
||||
counter--;
|
||||
bind_counter--;
|
||||
}
|
||||
break;
|
||||
case SYMAX_DATA:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(SYMAX_PACKET_PERIOD);
|
||||
#endif
|
||||
SYMAX_send_packet(0);
|
||||
break;
|
||||
}
|
||||
|
||||
238
Multiprotocol/TRAXXAS_cyrf6936.ino
Normal file
238
Multiprotocol/TRAXXAS_cyrf6936.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/>.
|
||||
|
||||
Works with Traxxas 6519 receivers https://traxxas.com/sites/default/files/24CompGuide-2016.jpg .
|
||||
*/
|
||||
|
||||
#if defined(TRAXXAS_CYRF6936_INO)
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
//#define TRAXXAS_FORCE_ID
|
||||
|
||||
#define TRAXXAS_CHANNEL 0x05
|
||||
#define TRAXXAS_BIND_CHANNEL 0x2B
|
||||
#define TRAXXAS_PACKET_SIZE 16
|
||||
|
||||
enum {
|
||||
TRAXXAS_BIND_PREP_RX=0,
|
||||
TRAXXAS_BIND_RX,
|
||||
TRAXXAS_BIND_TX1,
|
||||
TRAXXAS_PREP_DATA,
|
||||
TRAXXAS_DATA,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM TRAXXAS_sop_bind[] ={ 0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91 };
|
||||
const uint8_t PROGMEM TRAXXAS_sop_data[] ={ 0xA1, 0x78, 0xDC, 0x3C, 0x9E, 0x82, 0xDC, 0x3C };
|
||||
//const uint8_t PROGMEM TRAXXAS_sop_check[]={ 0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72 };
|
||||
|
||||
const uint8_t PROGMEM TRAXXAS_init_vals[][2] = {
|
||||
//Init from dump
|
||||
{CYRF_0B_PWR_CTRL, 0x00}, // PMU
|
||||
{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_28_CLK_EN, 0x02}, // Force Receive Clock Enable
|
||||
{CYRF_06_RX_CFG, 0x88 | 0x02}, // AGC enabled, Fast Turn Mode enabled, adding overwrite enable to not lockup RX
|
||||
{CYRF_1E_RX_OVERRIDE, 0x08}, // Reject packets with 0 seed
|
||||
{CYRF_03_TX_CFG, 0x08 | CYRF_BIND_POWER}, // 8DR Mode, 32 chip codes
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) TRAXXAS_cyrf_bind_config()
|
||||
{
|
||||
CYRF_PROGMEM_ConfigSOPCode(TRAXXAS_sop_bind);
|
||||
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB, 0x5A);
|
||||
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB, 0x5A);
|
||||
CYRF_ConfigRFChannel(TRAXXAS_BIND_CHANNEL);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) TRAXXAS_cyrf_data_config()
|
||||
{
|
||||
CYRF_PROGMEM_ConfigSOPCode(TRAXXAS_sop_data);
|
||||
#ifdef TRAXXAS_FORCE_ID // data taken from TX dump
|
||||
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB, 0x1B);
|
||||
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB, 0x3F);
|
||||
#else
|
||||
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB, cyrfmfg_id[0]+0xB6);
|
||||
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB, cyrfmfg_id[1]+0x5D);
|
||||
#endif
|
||||
CYRF_ConfigRFChannel(TRAXXAS_CHANNEL);
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) TRAXXAS_send_data_packet()
|
||||
{
|
||||
packet[0] = 0x01;
|
||||
memset(&packet[1],0x00,TRAXXAS_PACKET_SIZE-1);
|
||||
//Steering
|
||||
uint16_t ch = convert_channel_16b_nolimit(RUDDER,500,1000);
|
||||
packet[2]=ch>>8;
|
||||
packet[3]=ch;
|
||||
//Throttle
|
||||
ch = convert_channel_16b_nolimit(THROTTLE,500,1000);
|
||||
packet[4]=ch>>8;
|
||||
packet[5]=ch;
|
||||
//AUX3
|
||||
ch = convert_channel_16b_nolimit(AILERON,500,1000);
|
||||
packet[6]=ch>>8;
|
||||
packet[7]=ch;
|
||||
//AUX4???
|
||||
ch = convert_channel_16b_nolimit(ELEVATOR,500,1000);
|
||||
packet[12]=ch>>8;
|
||||
packet[13]=ch;
|
||||
|
||||
CYRF_SetPower(0x08);
|
||||
CYRF_WriteDataPacketLen(packet, TRAXXAS_PACKET_SIZE);
|
||||
}
|
||||
|
||||
uint16_t ReadTRAXXAS()
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
switch(phase)
|
||||
{
|
||||
case TRAXXAS_BIND_PREP_RX:
|
||||
TRAXXAS_cyrf_bind_config();
|
||||
CYRF_SetTxRxMode(RX_EN); //Receive mode
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive
|
||||
packet_count=100; //Timeout for RX
|
||||
phase=TRAXXAS_BIND_RX;
|
||||
return 700;
|
||||
case TRAXXAS_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);
|
||||
debugln("s=%02X",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==TRAXXAS_PACKET_SIZE)
|
||||
{
|
||||
CYRF_ReadDataPacketLen(packet, TRAXXAS_PACKET_SIZE);
|
||||
debug("RX=");
|
||||
for(uint8_t i=0;i<TRAXXAS_PACKET_SIZE;i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");
|
||||
for(uint8_t i=0;i<6;i++)
|
||||
packet[i+1]=cyrfmfg_id[i];
|
||||
packet[10]=0x01;
|
||||
packet_count=12;
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
phase=TRAXXAS_BIND_TX1;
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
if( --packet_count == 0 )
|
||||
{ // Retry RX
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort
|
||||
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // Force end state
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort
|
||||
if(--bind_counter != 0)
|
||||
phase=TRAXXAS_BIND_PREP_RX; // Retry receiving bind packet
|
||||
else
|
||||
phase=TRAXXAS_PREP_DATA; // Abort binding
|
||||
}
|
||||
return 700;
|
||||
case TRAXXAS_BIND_TX1:
|
||||
CYRF_WriteDataPacketLen(packet, TRAXXAS_PACKET_SIZE);
|
||||
debug("P=");
|
||||
for(uint8_t i=0;i<TRAXXAS_PACKET_SIZE;i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");
|
||||
if(--packet_count==0) // Switch to normal mode
|
||||
phase=TRAXXAS_PREP_DATA;
|
||||
break;
|
||||
case TRAXXAS_PREP_DATA:
|
||||
BIND_DONE;
|
||||
TRAXXAS_cyrf_data_config();
|
||||
phase++;
|
||||
case TRAXXAS_DATA:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(13940);
|
||||
#endif
|
||||
TRAXXAS_send_data_packet();
|
||||
break;
|
||||
}
|
||||
return 13940;
|
||||
}
|
||||
|
||||
uint16_t initTRAXXAS()
|
||||
{
|
||||
CYRF_Reset();
|
||||
|
||||
//Config CYRF registers
|
||||
for(uint8_t i = 0; i < sizeof(TRAXXAS_init_vals) / 2; i++)
|
||||
CYRF_WriteRegister(pgm_read_byte_near(&TRAXXAS_init_vals[i][0]), pgm_read_byte_near(&TRAXXAS_init_vals[i][1]));
|
||||
|
||||
//Read CYRF ID
|
||||
CYRF_GetMfgData(cyrfmfg_id);
|
||||
cyrfmfg_id[0]+=RX_num;
|
||||
|
||||
#ifdef TRAXXAS_FORCE_ID // data taken from TX dump
|
||||
cyrfmfg_id[0]=0x65; // CYRF MFG ID
|
||||
cyrfmfg_id[1]=0xE2;
|
||||
cyrfmfg_id[2]=0x5E;
|
||||
cyrfmfg_id[3]=0x55;
|
||||
cyrfmfg_id[4]=0x4D;
|
||||
cyrfmfg_id[5]=0xFE;
|
||||
#endif
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
bind_counter=100;
|
||||
phase = TRAXXAS_BIND_PREP_RX;
|
||||
}
|
||||
else
|
||||
phase = TRAXXAS_PREP_DATA;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
/*
|
||||
Bind phase 1
|
||||
CHANNEL: 0x2B
|
||||
SOP_CODE: 0x3C 0x37 0xCC 0x91 0xE2 0xF8 0xCC 0x91
|
||||
CRC_SEED_LSB: 0x5A
|
||||
CRC_SEED_MSB: 0x5A
|
||||
RX1: 0x02 0x4A 0xA3 0x2D 0x1A 0x49 0xFE 0x06 0x00 0x00 0x02 0x01 0x06 0x06 0x00 0x00
|
||||
TX1: 0x02 0x65 0xE2 0x5E 0x55 0x4D 0xFE 0xEE 0x00 0x00 0x01 0x01 0x06 0x05 0x00 0x00
|
||||
Note: RX cyrfmfg_id is 0x4A,0xA3,0x2D,0x1A,0x49,0xFE and TX cyrfmfg_id is 0x65,0xE2,0x5E,0x55,0x4D,0xFE
|
||||
|
||||
Bind phase 2 (looks like normal mode?)
|
||||
CHANNEL: 0x05
|
||||
SOP_CODE: 0xA1 0x78 0xDC 0x3C 0x9E 0x82 0xDC 0x3C
|
||||
CRC_SEED_LSB: 0x1B
|
||||
CRC_SEED_MSB: 0x3F
|
||||
RX2: 0x03 0x4A 0xA3 0x2D 0x1A 0x49 0xFE 0x06 0x00 0x00 0x02 0x01 0x06 0x06 0x00 0x00
|
||||
TX2: 0x01 0x65 0x01 0xF4 0x03 0xE7 0x02 0x08 0x00 0x00 0x01 0x01 0x02 0xEE 0x00 0x00
|
||||
Note: TX2 is nearly a normal packet at the exception of the 2nd byte equal to cyrfmfg_id[0]
|
||||
|
||||
Bind phase 3 (check?)
|
||||
CHANNEL: 0x22
|
||||
SOP_CODE: 0x97 0xE5 0x14 0x72 0x7F 0x1A 0x14 0x72
|
||||
CRC_SEED_LSB: 0xA5
|
||||
CRC_SEED_MSB: 0xA5
|
||||
RX3: 0x04 0x4A 0xA3 0x2D 0x1A 0x49 0xFE 0x06 0x00 0x00 0x02 0x01 0x06 0x06 0x00 0x00
|
||||
|
||||
Switch to normal mode
|
||||
CHANNEL: 0x05
|
||||
SOP_CODE: 0xA1 0x78 0xDC 0x3C 0x9E 0x82 0xDC 0x3C
|
||||
CRC_SEED_LSB: 0x1B
|
||||
CRC_SEED_MSB: 0x3F
|
||||
TX3: 0x01 0x00 0x02 0xA8 0x03 0xE7 0x02 0x08 0x00 0x00 0x01 0x01 0x02 0xEE 0x00 0x00
|
||||
*/
|
||||
#endif
|
||||
214
Multiprotocol/TX_Def.h
Normal file
214
Multiprotocol/TX_Def.h
Normal file
@@ -0,0 +1,214 @@
|
||||
// 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
|
||||
#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
|
||||
|
||||
//Channel order
|
||||
#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
|
||||
File diff suppressed because it is too large
Load Diff
182
Multiprotocol/Tiger_nrf24l01.ino
Normal file
182
Multiprotocol/Tiger_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/>.
|
||||
*/
|
||||
// Compatible with Tiger Drone 1400782.
|
||||
|
||||
#if defined(TIGER_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define TIGER_FORCE_ID
|
||||
|
||||
#define TIGER_INITIAL_WAIT 500
|
||||
#define TIGER_PACKET_PERIOD 3940
|
||||
#define TIGER_RF_NUM_CHANNELS 4
|
||||
#define TIGER_BIND_RF_NUM_CHANNELS 8
|
||||
#define TIGER_PAYLOAD_SIZE 16
|
||||
#define TIGER_BIND_COUNT 761 //3sec
|
||||
|
||||
|
||||
static uint8_t __attribute__((unused)) TIGER_convert_channel(uint8_t num)
|
||||
{
|
||||
uint8_t val=convert_channel_8b(num);
|
||||
// 7F..01=left, 00=center, 80..FF=right
|
||||
if(val==0x80)
|
||||
val=0; // 0
|
||||
else
|
||||
if(val>0x80)
|
||||
val--; // 80..FE
|
||||
else
|
||||
{
|
||||
val=0x80-val; // 80..01
|
||||
if(val==0x80)
|
||||
val--; // 7F..01
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) TIGER_send_packet()
|
||||
{
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
//Channels
|
||||
packet[0]=convert_channel_8b(THROTTLE); // 00..FF
|
||||
packet[1]=TIGER_convert_channel(RUDDER); // 7F..01=left, 00=center, 80..FF=right
|
||||
packet[2]=TIGER_convert_channel(ELEVATOR); // 7F..01=down, 00=center, 80..FF=up
|
||||
packet[3]=TIGER_convert_channel(AILERON); // 7F..01=left, 00=center, 80..FF=right
|
||||
//Flags
|
||||
packet[14]= GET_FLAG(CH5_SW, 0x04) //FLIP
|
||||
| GET_FLAG(CH6_SW, 0x10); //LIGHT
|
||||
}
|
||||
//Check
|
||||
crc8=0;
|
||||
for(uint8_t i=0;i<TIGER_PAYLOAD_SIZE-1;i++)
|
||||
crc8+=packet[i];
|
||||
packet[TIGER_PAYLOAD_SIZE-1]=crc8;
|
||||
|
||||
//Hopping frequency
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no>>1]);
|
||||
hopping_frequency_no++;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
if(hopping_frequency_no>=2*TIGER_BIND_RF_NUM_CHANNELS)
|
||||
hopping_frequency_no=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(hopping_frequency_no>=2*(TIGER_BIND_RF_NUM_CHANNELS+TIGER_RF_NUM_CHANNELS))
|
||||
hopping_frequency_no=2*TIGER_BIND_RF_NUM_CHANNELS;
|
||||
}
|
||||
|
||||
//Clear packet status bits and TX FIFO
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
//Send packet
|
||||
XN297_WritePayload(packet, TIGER_PAYLOAD_SIZE);
|
||||
//Set tx_power
|
||||
NRF24L01_SetPower();
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) TIGER_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TX_EN);
|
||||
XN297_SetTXAddr((uint8_t *)"\x68\x94\xA6\xD5\xC3", 5);
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
|
||||
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
|
||||
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
|
||||
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
|
||||
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // No retransmits
|
||||
NRF24L01_SetPower();
|
||||
NRF24L01_Activate(0x73); // Activate feature register
|
||||
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
|
||||
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
|
||||
NRF24L01_Activate(0x73);
|
||||
// Power on, TX mode, 2byte CRC
|
||||
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) TIGER_initialize_txid()
|
||||
{
|
||||
#ifdef TIGER_FORCE_ID
|
||||
rx_tx_addr[0]=0x64;
|
||||
rx_tx_addr[1]=0x39;
|
||||
rx_tx_addr[2]=0x12;
|
||||
rx_tx_addr[3]=0x00;
|
||||
rx_tx_addr[4]=0x00;
|
||||
memcpy(hopping_frequency,"\x0E\x39\x1C\x07\x24\x3E\x2B\x47",TIGER_BIND_RF_NUM_CHANNELS);
|
||||
memcpy(&hopping_frequency[TIGER_BIND_RF_NUM_CHANNELS],"\x36\x41\x37\x4E",TIGER_RF_NUM_CHANNELS);
|
||||
#endif
|
||||
//prepare bind packet
|
||||
memset(&packet[0], 0x00, 4);
|
||||
memset(&packet[4], 0x40, 10);
|
||||
memcpy(&packet[7], rx_tx_addr, 5);
|
||||
packet[14]=0xC0;
|
||||
}
|
||||
|
||||
uint16_t TIGER_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(TIGER_PACKET_PERIOD);
|
||||
#endif
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
if(--bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
XN297_SetTXAddr((uint8_t *)"\x49\xA6\x83\xEB\x4B", 5);
|
||||
}
|
||||
TIGER_send_packet();
|
||||
return TIGER_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initTIGER()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
TIGER_initialize_txid();
|
||||
TIGER_init();
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter=TIGER_BIND_COUNT;
|
||||
return TIGER_INITIAL_WAIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*Bind
|
||||
- RF setup: 1Mbps, scrambled, CRC
|
||||
- TX addr: 0x68 0x94 0xA6 0xD5 0xC3
|
||||
- 8 RF channels: 0x0E 0x39 0x1C 0x07 0x24 0x3E 0x2B 0x47
|
||||
- 2 packets per RF channel, 3940µs between packets
|
||||
- payload 16 bytes: 0x00 0x00 0x00 0x00 0x40 0x40 0x40 0x64 0x39 0x12 0x00 0x00 0x40 0x40 0xC0 0xAF
|
||||
- payload[15]=sum of payload[0..14]
|
||||
- the only difference with normal packets is the payload[14]=0xC0
|
||||
- ??? payload[7..11] TX ID ???
|
||||
|
||||
Normal
|
||||
- RF setup: 1Mbps
|
||||
- TX addr: 0x49 0xA6 0x83 0xEB 0x4B
|
||||
- 4 RF channels: 0x36 0x41 0x37 0x4E
|
||||
- 2 packets per RF channel, 3940µs between packets
|
||||
- payload 16 bytes: 0x00 0x00 0x00 0x00 0x40 0x40 0x40 0x64 0x39 0x12 0x00 0x00 0x40 0x40 0x00 0xEF
|
||||
- payload[15]=sum of payload[0..14]
|
||||
- throttle is on payload[0] 00..FF
|
||||
- rudder is on payload[1] 00=center, 80..FF=right, 01..7F=left
|
||||
- elevator is on payload[2] 00=center, 80..FF=up, 01..7F=down
|
||||
- aileron is on payload[3] 00=center, 80..FF=right, 01..7F=left
|
||||
- trims payload[4..6]
|
||||
- ??? payload[7..11] TX ID ???
|
||||
- ??? payload[12..13] ???
|
||||
- flip is on payload[14] and flag 0x04
|
||||
- light is on payload[14] and flag 0x10
|
||||
*/
|
||||
@@ -21,12 +21,13 @@
|
||||
#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 {
|
||||
@@ -40,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,
|
||||
@@ -54,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.
|
||||
@@ -64,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,
|
||||
@@ -80,7 +83,7 @@ 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
|
||||
@@ -116,19 +119,19 @@ static void __attribute__((unused)) 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));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -170,35 +173,56 @@ static void __attribute__((unused)) V2X2_send_packet(uint8_t bind)
|
||||
//Flags
|
||||
flags=0;
|
||||
// Channel 5
|
||||
if (Servo_AUX1) flags = V2X2_FLAG_FLIP;
|
||||
if (CH5_SW) flags = V2X2_FLAG_FLIP;
|
||||
// Channel 6
|
||||
if (Servo_AUX2) flags |= V2X2_FLAG_LIGHT;
|
||||
if (CH6_SW) flags |= V2X2_FLAG_LIGHT;
|
||||
// Channel 7
|
||||
if (Servo_AUX3) flags |= V2X2_FLAG_CAMERA;
|
||||
if (CH7_SW) flags |= V2X2_FLAG_CAMERA;
|
||||
// Channel 8
|
||||
if (Servo_AUX4) flags |= V2X2_FLAG_VIDEO;
|
||||
if (CH8_SW) flags |= V2X2_FLAG_VIDEO;
|
||||
|
||||
//Flags2
|
||||
// Channel 9
|
||||
if (Servo_AUX5)
|
||||
if (CH9_SW)
|
||||
flags2 = V2X2_FLAG_HEADLESS;
|
||||
// Channel 10
|
||||
if (Servo_AUX6)
|
||||
flags2 |= V2X2_FLAG_MAG_CAL_X;
|
||||
// Channel 11
|
||||
if (Servo_AUX7)
|
||||
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;
|
||||
V2X2_add_pkt_checksum();
|
||||
|
||||
@@ -228,33 +252,35 @@ uint16_t ReadV2x2()
|
||||
return 150;
|
||||
break;
|
||||
case V202_BIND2:
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED) {
|
||||
return PACKET_CHKTIME;
|
||||
}
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
|
||||
return V2X2_PACKET_CHKTIME;
|
||||
V2X2_send_packet(1);
|
||||
if (--counter == 0) {
|
||||
if (--bind_counter == 0)
|
||||
{
|
||||
phase = V202_DATA;
|
||||
BIND_DONE;
|
||||
}
|
||||
break;
|
||||
case V202_DATA:
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED) {
|
||||
return PACKET_CHKTIME;
|
||||
}
|
||||
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
|
||||
return V2X2_PACKET_CHKTIME;
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(V2X2_PACKET_PERIOD);
|
||||
#endif
|
||||
V2X2_send_packet(0);
|
||||
break;
|
||||
}
|
||||
// Packet every 4ms
|
||||
return PACKET_PERIOD;
|
||||
return V2X2_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
uint16_t initV2x2()
|
||||
{
|
||||
v202_init();
|
||||
//
|
||||
if (IS_AUTOBIND_FLAG_on)
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
counter = BIND_COUNT;
|
||||
bind_counter = V2X2_BIND_COUNT;
|
||||
phase = V202_INIT2;
|
||||
}
|
||||
else
|
||||
|
||||
198
Multiprotocol/V761_nrf24l01.ino
Normal file
198
Multiprotocol/V761_nrf24l01.ino
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(V761_PACKET_PERIOD);
|
||||
#endif
|
||||
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
|
||||
191
Multiprotocol/V911S_xn297l.ino
Normal file
191
Multiprotocol/V911S_xn297l.ino
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
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
|
||||
}
|
||||
|
||||
if(sub_protocol==V911S_STD)
|
||||
XN297L_WritePayload(packet, V911S_PACKET_SIZE);
|
||||
else
|
||||
XN297L_WriteEnhancedPayload(packet, V911S_PACKET_SIZE, bind);
|
||||
|
||||
XN297L_SetPower(); // Set tx_power
|
||||
XN297L_SetFreqOffset(); // Set frequency offset
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) V911S_init()
|
||||
{
|
||||
XN297L_Init();
|
||||
if(sub_protocol==V911S_STD)
|
||||
XN297L_SetTXAddr((uint8_t *)"KNBND",5); // V911S Bind address
|
||||
else
|
||||
XN297L_SetTXAddr((uint8_t *)"XPBND",5); // E119 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)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(V911S_PACKET_PERIOD);
|
||||
#endif
|
||||
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
|
||||
if(sub_protocol==V911S_STD)
|
||||
{//V911S
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
//E119
|
||||
rx_tx_addr[0]=0x30;
|
||||
rx_tx_addr[1]=0xFF;
|
||||
rx_tx_addr[2]=0xD1;
|
||||
rx_tx_addr[3]=0x2C;
|
||||
rx_tx_addr[4]=0x2A;
|
||||
for(uint8_t i=0;i<V911S_NUM_RF_CHANNELS;i++)
|
||||
hopping_frequency[i]=0x0E + i*5;
|
||||
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
|
||||
427
Multiprotocol/Validate.h
Normal file
427
Multiprotocol/Validate.h
Normal file
@@ -0,0 +1,427 @@
|
||||
// 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 board file definition version for DIY multi-module boards
|
||||
#define MIN_AVR_BOARD 110
|
||||
#define MIN_ORX_BOARD 110
|
||||
#define MIN_STM32_BOARD 117
|
||||
//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
|
||||
|
||||
// Enable serial debugging if a debugging option was chosen in the IDE
|
||||
#ifdef ARDUINO_MULTI_DEBUG
|
||||
#define DEBUG_SERIAL
|
||||
#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
|
||||
|
||||
// Warning if CHECK_FOR_BOOTLOADER is enabled but no bootloader
|
||||
#if defined(ARDUINO_MULTI_NO_BOOT) && defined(CHECK_FOR_BOOTLOADER)
|
||||
#undef CHECK_FOR_BOOTLOADER
|
||||
#warning "Disabling CHECK_FOR_BOOTLOADER since no bootloader is selected."
|
||||
#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
|
||||
//CC2500
|
||||
#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_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_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_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_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_HOTT_TUNING
|
||||
#if ( FORCE_HOTT_TUNING < -127 ) || ( FORCE_HOTT_TUNING > 127 )
|
||||
#error "The HOTT forced frequency tuning value is outside of the range -127..127."
|
||||
#endif
|
||||
#endif
|
||||
//A7105
|
||||
#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
|
||||
#ifdef FORCE_BUGS_TUNING
|
||||
#if ( FORCE_BUGS_TUNING < -300 ) || ( FORCE_BUGS_TUNING > 300 )
|
||||
#error "The BUGS forced frequency tuning value is outside of the range -300..300."
|
||||
#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_FLYZONE_TUNING
|
||||
#if ( FORCE_FLYZONE_TUNING < -300 ) || ( FORCE_FLYZONE_TUNING > 300 )
|
||||
#error "The Flyzone forced frequency tuning value is outside of the range -300..300."
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FORCE_PELIKAN_TUNING
|
||||
#if ( FORCE_PELIKAN_TUNING < -300 ) || ( FORCE_PELIKAN_TUNING > 300 )
|
||||
#error "The Pelikan 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
|
||||
|
||||
#ifndef USE_A7105_CH15_TUNING
|
||||
#ifndef FORCE_BUGS_TUNING
|
||||
#define FORCE_BUGS_TUNING 0
|
||||
#endif
|
||||
#ifndef FORCE_FLYSKY_TUNING
|
||||
#define FORCE_FLYSKY_TUNING 0
|
||||
#endif
|
||||
#ifndef FORCE_FLYZONE_TUNING
|
||||
#define FORCE_FLYZONE_TUNING 0
|
||||
#endif
|
||||
#ifndef FORCE_PELIKAN_TUNING
|
||||
#define FORCE_PELIKAN_TUNING 0
|
||||
#endif
|
||||
#ifndef FORCE_HUBSAN_TUNING
|
||||
#define FORCE_HUBSAN_TUNING 0
|
||||
#endif
|
||||
#ifndef FORCE_AFHDS2A_TUNING
|
||||
#define FORCE_AFHDS2A_TUNING 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (USE_CYRF6936_CH15_TUNING) && (DSM_THROTTLE_KILL_CH == 15)
|
||||
#error "Error Channel 15 conflict between the CYRF6936 freq tuning and the DSM throttle kill feature."
|
||||
#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
|
||||
#undef FLYZONE_A7105_INO
|
||||
#undef AFHDS2A_RX_A7105_INO
|
||||
#undef PELIKAN_A7105_INO
|
||||
#endif
|
||||
#ifndef CYRF6936_INSTALLED
|
||||
#undef DEVO_CYRF6936_INO
|
||||
#undef DSM_CYRF6936_INO
|
||||
#undef HOTT_CC2500_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 SCANNER_CC2500_INO
|
||||
#undef FRSKY_RX_CC2500_INO
|
||||
#undef HOTT_CC2500_INO
|
||||
#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 FX816_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 POTENSIC_NRF24L01_INO
|
||||
#undef ZSX_NRF24L01_INO
|
||||
#undef BAYANG_RX_NRF24L01_INO
|
||||
#undef TIGER_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_SEND
|
||||
#undef DSM_TELEMETRY
|
||||
#undef MULTI_STATUS
|
||||
#undef MULTI_TELEMETRY
|
||||
#undef SCANNER_TELEMETRY
|
||||
#undef SCANNER_CC2500_INO
|
||||
#undef FRSKY_RX_TELEMETRY
|
||||
#undef FRSKY_RX_CC2500_INO
|
||||
#undef AFHDS2A_RX_TELEMETRY
|
||||
#undef AFHDS2A_RX_A7105_INO
|
||||
#undef HOTT_FW_TELEMETRY
|
||||
#undef BAYANG_RX_TELEMETRY
|
||||
#undef BAYANG_RX_NRF24L01_INO
|
||||
#else
|
||||
#if defined(MULTI_TELEMETRY) && defined(MULTI_STATUS)
|
||||
#error You should choose either MULTI_TELEMETRY or MULTI_STATUS but not both.
|
||||
#endif
|
||||
#if not defined(SCANNER_CC2500_INO) || not defined(SCANNER_TELEMETRY)
|
||||
#undef SCANNER_TELEMETRY
|
||||
#undef SCANNER_CC2500_INO
|
||||
#endif
|
||||
#if not defined(FRSKY_RX_CC2500_INO) || not defined(FRSKY_RX_TELEMETRY)
|
||||
#undef FRSKY_RX_TELEMETRY
|
||||
#undef FRSKY_RX_CC2500_INO
|
||||
#endif
|
||||
#if not defined(AFHDS2A_RX_A7105_INO) || not defined(AFHDS2A_RX_TELEMETRY)
|
||||
#undef AFHDS2A_RX_TELEMETRY
|
||||
#undef AFHDS2A_RX_A7105_INO
|
||||
#endif
|
||||
#if not defined(BAYANG_RX_NRF24L01_INO) || not defined(BAYANG_RX_TELEMETRY)
|
||||
#undef BAYANG_RX_TELEMETRY
|
||||
#undef BAYANG_RX_NRF24L01_INO
|
||||
#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) && not 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_SEND
|
||||
#endif
|
||||
#if not defined (SPORT_TELEMETRY)
|
||||
#undef SPORT_SEND
|
||||
#endif
|
||||
#if not defined(DSM_CYRF6936_INO)
|
||||
#undef DSM_TELEMETRY
|
||||
#endif
|
||||
#if not defined(HOTT_CC2500_INO)
|
||||
#undef HOTT_FW_TELEMETRY
|
||||
#endif
|
||||
#if not defined(HOTT_FW_TELEMETRY) && 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) && not defined(SCANNER_TELEMETRY) && not defined(FRSKY_RX_TELEMETRY) && not defined(AFHDS2A_RX_TELEMETRY) && not defined(BAYANG_RX_TELEMETRY)
|
||||
#undef TELEMETRY
|
||||
#undef INVERT_TELEMETRY
|
||||
#undef MULTI_TELEMETRY
|
||||
#undef MULTI_STATUS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SPORT_TELEMETRY
|
||||
#define SPORT_SEND
|
||||
#endif
|
||||
|
||||
#if not defined(STM32_BOARD)
|
||||
#undef MULTI_SYNC
|
||||
#endif
|
||||
|
||||
#if not defined(MULTI_TELEMETRY)
|
||||
#undef MULTI_SYNC
|
||||
#undef MULTI_NAMES
|
||||
#else
|
||||
#define MULTI_NAMES
|
||||
#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
|
||||
|
||||
//Check if Direct inputs defined correctly
|
||||
#if defined (ENABLE_DIRECT_INPUTS)
|
||||
#if not defined (STM32_BOARD) || not defined (ENABLE_PPM) || defined (ENABLE_SERIAL)
|
||||
#error You can enable dirct inputs only in PPM mode and only for STM32 board.
|
||||
#endif
|
||||
|
||||
#if not defined (DI1_PIN) && not defined (DI2_PIN) && not defined (DI3_PIN) && not defined (DI4_PIN)
|
||||
#error You must define at least 1 direct input pin or undefine ENABLE_DIRECT_INPUTS in config.
|
||||
#endif
|
||||
|
||||
#if not defined (DI_CH1_read) && not defined (DI_CH2_read) && not defined (DI_CH3_read) && not defined (DI_CH4_read)
|
||||
#error You must define at least 1 direct input chanell read macros or undefine ENABLE_DIRECT_INPUTS in config.
|
||||
#endif
|
||||
#endif
|
||||
297
Multiprotocol/WFLY_cyrf6936.ino
Normal file
297
Multiprotocol/WFLY_cyrf6936.ino
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
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()
|
||||
{
|
||||
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;
|
||||
|
||||
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(packet_in, len);
|
||||
debug("RX=");
|
||||
for(uint8_t i=0;i<0x0F;i++)
|
||||
{
|
||||
debug(" %02X",packet_in[i]);
|
||||
if(packet_in[i]==packet[i])
|
||||
check++; // Verify quickly the content
|
||||
sum+=packet_in[i];
|
||||
}
|
||||
debugln(" %02X",packet_in[15]);
|
||||
if(sum==packet_in[15] && check>=10)
|
||||
{ // Good packet received
|
||||
if(packet_in[2]==0x64)
|
||||
{ // Switch to normal mode
|
||||
BIND_DONE;
|
||||
phase=WFLY_PREP_DATA;
|
||||
return 10000;
|
||||
}
|
||||
memcpy((void *)packet,(void *)packet_in,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:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(5371);
|
||||
#endif
|
||||
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
|
||||
504
Multiprotocol/WK2x01_cyrf6936.ino
Normal file
504
Multiprotocol/WK2x01_cyrf6936.ino
Normal file
@@ -0,0 +1,504 @@
|
||||
/*
|
||||
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)
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(2800);
|
||||
#endif
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user