Compare commits

...

223 Commits

Author SHA1 Message Date
Pascal Langer
5f12f99761 Update Validate.h 2020-08-01 19:35:39 +02:00
Pascal Langer
3d98abb6d4 Rename the Flyzone protocol by Height which is the original manufacturer 2020-08-01 19:19:11 +02:00
Pascal Langer
e35879a5d0 RadioLink: fix 2020-08-01 10:19:30 +02:00
Pascal Langer
37138f03ae Few fixes 2020-07-31 15:58:07 +02:00
Pascal Langer
51d39bbd8c RadioLink: add RXs to the supported list 2020-07-31 10:56:34 +02:00
Pascal Langer
0932a1c93f Update Protocols_Details.md 2020-07-31 10:52:37 +02:00
Pascal Langer
19164521e4 Flyzone protocol: 8 channels support 2020-07-31 10:42:10 +02:00
Pascal Langer
df28cfe3cc Radiolink: final version with 64 IDs 2020-07-31 10:41:07 +02:00
Pascal Langer
354878d542 RadioLink: preparation for final 2020-07-28 15:53:58 +02:00
Pascal Langer
695264d59a RadioLink: update 2020-07-28 00:55:47 +02:00
pascallanger
de190f3349 Update Protocols_Details.md 2020-07-25 14:43:52 +02:00
Pascal Langer
b049385094 Update Protocols_Details.md 2020-07-23 21:40:26 +02:00
Pascal Langer
75dc616130 Update RadioLink_cc2500.ino 2020-07-23 15:08:23 +02:00
Pascal Langer
b542f5e7cd RLINK: remove fixed ID 2020-07-23 10:10:08 +02:00
Pascal Langer
f3bee3cded RLINK: Fix voltage values 2020-07-23 10:03:04 +02:00
Pascal Langer
a9b7ab9a06 Update Protocols_Details.md 2020-07-22 20:13:54 +02:00
Pascal Langer
ed019e954e RadioLink: few fixes 2020-07-22 20:05:56 +02:00
Pascal Langer
65186b4356 Add Kyosho to the Lua channel namer exception list 2020-07-22 18:18:35 +02:00
Pascal Langer
e1d4f9a270 RadioLink Surface protocol: initial commit 2020-07-22 15:37:47 +02:00
Pascal Langer
69c95ca153 Fix compilation issues when Telem is disabled 2020-07-22 15:27:06 +02:00
Pascal Langer
e6976fb08d Merge branch 'master' of https://github.com/pascallanger/DIY-Multiprotocol-TX-Module 2020-07-21 01:40:19 +02:00
Pascal Langer
f502ba3659 FrSkyX Cloned: 8 channels option 2020-07-21 01:40:14 +02:00
pascallanger
e6ccc7e7cc Update Protocols_Details.md 2020-07-17 14:21:57 +02:00
Pascal Langer
da9d8851c2 Fix FrSkyX and FrSkyR9 bind options 2020-07-16 10:28:07 +02:00
pascallanger
ad48291d2a Update Protocols_Details.md 2020-07-16 00:02:29 +02:00
Pascal Langer
d6da230369 Flysky AFHDS2A: 16 channels + LQI
Use the 2 new sub protocols to extend the protocol to 16 channels on IBUS
2020-07-15 23:58:41 +02:00
pascallanger
f8ac406a94 Update Frequency_Tuning.md 2020-07-15 20:31:55 +02:00
Pascal Langer
e691ecd167 Update doc 2020-07-15 19:09:56 +02:00
Pascal Langer
930c26a111 Kyosho: new protocol 2020-07-10 15:25:32 +02:00
Pascal Langer
64419a6cf4 V2x2: fix? 2020-07-09 22:49:48 +02:00
Pascal Langer
5c59cddc7a FrSkyR9: FCC initial support 2020-07-06 09:52:43 +02:00
Ben Lye
4c7a51be46 Create folders in LUA script zip file 2020-07-05 16:54:55 +01:00
Ben Lye
7dad0fb89f Update install_drivers.bat
Change to libusbk driver for DFU device
2020-07-05 16:32:56 +01:00
Pascal Langer
adebb3fc5c FrSkyX: clean up 2020-07-05 17:19:29 +02:00
Pascal Langer
5ab00b9d18 FrSkyX: TXQly is the percentage of telemetry received packets (100...0%) 2020-07-05 00:28:43 +02:00
Pascal Langer
fbd5d7cf48 FrSky R9: telemetry TX to RX attempt 2020-07-04 22:43:19 +02:00
Pascal Langer
84132678cc FrSkyR9: TQLY = percentage of telemetry frames per second 2020-07-04 18:40:29 +02:00
Pascal Langer
78421748ba FrSky R9: fix sensors telem? 2020-07-04 17:50:05 +02:00
Pascal Langer
7112f58dae FrSkyX: fix telem 2020-07-04 15:15:55 +02:00
Pascal Langer
e56f737b34 FrSkyX: fix telemetry not stopping when RX is off 2020-07-04 13:33:56 +02:00
Pascal Langer
49d993f613 FrSkyR9: fix independant compilation issue 2020-07-04 11:48:26 +02:00
Pascal Langer
63dd8a9215 Update iface_sx1276.h 2020-07-03 19:51:22 +02:00
Pascal Langer
d5f819dd59 FrSkyR9: initial telemetry support 2020-07-03 19:51:11 +02:00
pascallanger
a68787f16e Update Protocols_Details.md 2020-07-03 18:03:36 +02:00
Pascal Langer
858ef5801c FrSkyX: fix AVR telemetry and may be improve telemetry overall 2020-07-03 17:42:12 +02:00
Pascal Langer
9e0bd29cee FrSkyD: clone mode - additional ID byte 2020-07-03 16:15:47 +02:00
Pascal Langer
15395de579 FrSky R9: adding CH1-8/CH9-16 and Telem ON/OFF (not that telem is supported yet) 2020-07-01 15:39:40 +02:00
Pascal Langer
db4aad04a7 FrSkyR9: fix 868 2020-07-01 14:39:11 +02:00
Pascal Langer
466e4cf227 Update DSM protocol details 2020-06-29 23:31:17 +02:00
Ben Lye
05a3780c38 Add latest STM32 board 2020-06-29 19:55:29 +01:00
pascallanger
85ea91cdbb Update README.md 2020-06-28 19:54:14 +02:00
pascallanger
985d7a6fd9 Update README.md 2020-06-28 19:37:58 +02:00
pascallanger
2a19b8dd45 Update README.md 2020-06-28 19:35:12 +02:00
Pascal Langer
b2b3078861 Update README.md 2020-06-28 19:17:02 +02:00
Pascal Langer
2ac92f5725 Create README.md 2020-06-28 19:15:39 +02:00
Pascal Langer
e2f5afd71e V761 doc updates 2020-06-28 19:07:34 +02:00
Ben Lye
e094ee036d Zip the LUA scripts for release 2020-06-28 16:06:06 +01:00
Ben Lye
2ad7f3e9f2 Fix LUA script copy 2020-06-28 15:13:33 +01:00
Pascal Langer
8e1f2258f8 OpenTX Lua scripts related to Multi 2020-06-27 17:59:06 +02:00
Pascal Langer
5c01bbf284 V761: additional channles 2020-06-27 17:58:29 +02:00
Pascal Langer
647425fc1a Revert "V761 additonal channels"
This reverts commit 7286049d07.
2020-06-27 17:56:19 +02:00
Pascal Langer
7286049d07 V761 additonal channels 2020-06-27 17:55:36 +02:00
Pascal Langer
ce67a065cd V761 - Eachine sub protocol 2020-06-26 17:54:56 +02:00
Ben Lye
8948cb6287 Switch to Arduino CLI instead of IDE for Travis CI builds 2020-06-26 09:56:07 +01:00
pascallanger
4daa5fa2bb Update Advanced_XN297Ldump.md 2020-06-22 10:10:57 +02:00
Pascal Langer
c49a7dae0a Few changes 2020-06-20 22:04:26 +02:00
Pascal Langer
890a042a43 V2X2 new sub proto MR101 and protocol rewrite
MR101 sub proto for Dromida XL
2020-06-20 21:40:03 +02:00
Pascal Langer
c95e576ef3 DSM RX: end bind and increased retry 2020-06-18 10:53:03 +02:00
Pascal Langer
2aa96dd129 SX1276: indent with tabs 2020-06-15 23:34:56 +02:00
AlessandroAU
908634474b Adds SX1276_DetectChip() function (#373)
* Adds SX1276_DetectChip() function

works by testing for 0x12 match in version reg 0x42

* fix build err
2020-06-15 23:03:03 +02:00
AlessandroAU
79b525ee71 Implement datasheet errata recommendation (#372) 2020-06-15 23:02:30 +02:00
Pascal Langer
872b8259ab Q90C VTX channel 2020-06-15 19:39:43 +02:00
Pascal Langer
a14c82708f Update Q90C_nrf24l01.ino 2020-06-15 15:30:31 +02:00
Pascal Langer
7e53778680 Update Q90C_nrf24l01.ino 2020-06-15 15:23:02 +02:00
Pascal Langer
210fbe3b9e Update Q90C_nrf24l01.ino 2020-06-15 14:45:49 +02:00
Pascal Langer
0a5fd72bdc DSM: 3 ch timing on CH13 2020-06-15 14:45:42 +02:00
Pascal Langer
6e1701ecc5 Q90C: Flight Modes 2020-06-14 23:22:27 +02:00
Pascal Langer
a5f627a2d6 Q90C test 2020-06-14 22:28:36 +02:00
Pascal Langer
b4a1f175c6 Update Q90C_nrf24l01.ino 2020-06-14 22:22:13 +02:00
Pascal Langer
e0690fa661 Update Q90C_nrf24l01.ino 2020-06-14 19:10:59 +02:00
Pascal Langer
bd962eff35 DSM: SAFE setting how to 2020-06-14 18:34:38 +02:00
Pascal Langer
b515355249 DSM RX: remove reverse on aileron and rudder 2020-06-13 21:54:18 +02:00
Pascal Langer
d1feef97be DSM: adjust end points, solve SAFE? 2020-06-13 16:20:51 +02:00
Pascal Langer
f52f96d44e DSM: selectable refresh rate 22/11ms when supported 2020-06-12 00:25:09 +02:00
Pascal Langer
944ec62f49 Update DSM_cyrf6936.ino 2020-06-10 09:03:41 +02:00
Pascal Langer
30905014d2 DSM: fix 11ms issue on some RXs? 2020-06-09 23:49:51 +02:00
Pascal Langer
32dbdfc6e3 Fix compilation when telemetry is disabled 2020-06-09 20:08:00 +02:00
Pascal Langer
b2e312b41e FrSkyX: force tuning fix for FrSkyX2 2020-06-07 18:06:19 +02:00
Ben Lye
52f4096197 Force 'noinv' for the T18 5in1 release files
And put it in the file name, just for consistency
2020-06-06 19:16:19 +01:00
Ben Lye
c547ea0c0f Disable some protocols for Atmega CC2500 builds
Trying to get the build to fit again.
2020-06-06 18:47:32 +01:00
Ben Lye
c73ee61128 Add T18 5in1 tests and release builds 2020-06-06 18:47:32 +01:00
Pascal Langer
90b287f1f4 Multi 5-in-1 initial support 2020-06-06 01:57:52 +02:00
Pascal Langer
0316c9eea9 HoTT: telem code cleanup 2020-06-05 22:44:32 +02:00
Pascal Langer
374b46966c FrSkyX: small change 2020-06-05 22:22:13 +02:00
Pascal Langer
3705415927 HoTT: fix telemetry 2020-06-05 22:20:19 +02:00
Pascal Langer
bff68f482e Update Protocols_Details.md 2020-06-03 14:08:09 +02:00
Pascal Langer
32ed758072 Update DSM_Rx_cyrf6936.ino 2020-06-03 12:55:45 +02:00
Pascal Langer
5ce99ee419 Test protocol 2020-06-03 11:43:27 +02:00
Pascal Langer
ceea384a36 Pelikan Lite: force_id update 2020-06-03 10:29:34 +02:00
Pascal Langer
fd3b026e12 Update Pelikan_a7105.ino 2020-06-02 19:10:11 +02:00
Pascal Langer
7e451c13a8 Pelikan: add sub protocol for Lite version 2020-06-02 19:04:05 +02:00
Pascal Langer
3dcf74c2e4 Bayang: renamed CX100 to QX100 2020-06-02 17:17:49 +02:00
Pascal Langer
50f1eca4be Bayang: new subprotocol CX100 2020-06-02 14:59:32 +02:00
Pascal Langer
0d97af5ae2 XN297dump: Auto mode small fix 2020-06-02 14:34:50 +02:00
Pascal Langer
aeb8d67219 HoTT: add subprotocols 2020-06-01 22:55:32 +02:00
Pascal Langer
1f65025036 HoTT: add LBT and telemetry improvment 2020-05-31 23:54:13 +02:00
Pascal Langer
8df3687684 Q90C: channels reverse 2020-05-26 22:26:30 +02:00
MRC3742
adf59a9d0d Misc updates for errors, omissions amd corrections (#359) 2020-05-26 19:52:09 +02:00
Pascal Langer
b9f00bdbc5 Q90C: checksum fix 2020-05-26 12:41:33 +02:00
Pascal Langer
a10e169573 New protocol Q90C 2020-05-24 17:39:14 +02:00
Pascal Langer
317b9a8156 Fix compilation when ESKY150V2 was built without HoTT 2020-05-23 23:34:05 +02:00
Pascal Langer
1c632d462f Update Protocols_Details.md 2020-05-23 22:53:53 +02:00
Pascal Langer
c46b49ccf1 HoTT: cleanup 2020-05-23 22:41:07 +02:00
Pascal Langer
e70708b133 FrSkyX: push more parts to common 2020-05-23 22:39:26 +02:00
Konstantin Tretyakov
62486c2220 JJRC345: Reduce stick sensitivity (#355)
A largely symbolic contribution to record participation in protocol development.
See: https://github.com/DeviationTX/deviation/pull/853
2020-05-23 00:09:46 +02:00
Pascal Langer
cffe66747a JJRC345: last commit 2020-05-22 21:03:01 +02:00
Pascal Langer
b31bbfa04f JJRC345: Change checksum calculation 2020-05-21 23:40:23 +02:00
Pascal Langer
48e4cad3ad JJRC345: add RTH on CH7 2020-05-21 17:49:04 +02:00
Pascal Langer
53f58ce2e1 JJRC345: update 2020-05-21 17:24:11 +02:00
Pascal Langer
eb8b5eac01 JJRC345: update channels range 2020-05-21 11:56:08 +02:00
Pascal Langer
02008a8b2e New protocol JJRC345: WIP
Work in progress
2020-05-21 11:47:51 +02:00
Pascal Langer
5b82599eb9 Update Protocols_Details.md 2020-05-20 12:23:37 +02:00
Pascal Langer
a5e4b2c6fa DSM RX: Fix compilation 2020-05-18 01:30:52 +02:00
Pascal Langer
987753ff73 DSM and DSM RX: fix bind 2020-05-18 01:13:08 +02:00
Pascal Langer
ee080839b1 Update DSM_Rx_cyrf6936.ino 2020-05-17 17:26:43 +02:00
Pascal Langer
4290c75478 HoTT: support for auto sensors discovery and sensors text config 2020-05-17 15:47:56 +02:00
Pascal Langer
cc6be6027d New DSM RX protocol 2020-05-17 15:45:23 +02:00
Pascal Langer
4cfde0a80a Update Protocols_Details.md 2020-05-10 13:41:14 +02:00
Pascal Langer
a77aee0e1a Update Protocols_Details.md 2020-05-09 16:11:36 +02:00
Pascal Langer
6f36473975 Devo basic telemetry 2020-05-09 16:11:10 +02:00
pascallanger
f5720d38bb Update Flash_from_Tx.md 2020-05-09 09:10:09 +02:00
pascallanger
23478d3d21 Update Protocols_Details.md 2020-05-08 22:50:52 +02:00
Pascal Langer
ba72b6dedd eSky150v2 last minute typo... 2020-05-08 20:01:33 +02:00
Pascal Langer
103f595891 New protocol eSky 150 v2
Protocol: 69
No sub protocol
No extended limit
RX outputs is be set automatically to the eSky default TAER
16 channels
2020-05-08 19:55:16 +02:00
Pascal Langer
957d623b4b FrSky D16 LBT v1.x & 2.1: adjust thresholds to match ETSI requirements 2020-05-02 18:20:47 +02:00
Pascal Langer
2be757e609 Skyartec: small changes 2020-04-22 15:02:06 +02:00
Pascal Langer
c4be660a05 Skyartec: activate cc2500 rf tune 2020-04-21 18:27:15 +02:00
Pascal Langer
c1c5f9fe3a Hide Proto Scanner 2020-04-21 12:15:53 +02:00
Pascal Langer
53c0637a85 Fix a bug introduced with Alpha protocols ordering 2020-04-21 11:43:48 +02:00
Pascal Langer
4ae30dc3b0 New protocol: Skyartec 2020-04-18 19:04:38 +02:00
Pascal Langer
fc5fbc9899 Multi_Names update for OpenTX 2020-04-16 17:03:17 +02:00
Pascal Langer
2397bf365b Update Multi_Names.ino 2020-04-16 13:52:10 +02:00
Pascal Langer
42cd17d5f2 Multi Names: if proto invalid give first available proto 2020-04-16 12:07:19 +02:00
Pascal Langer
a35e01bbeb Update Protocols_Details.md 2020-04-15 11:23:40 +02:00
Pascal Langer
b21e8030b3 Fix independant protocols build 2020-04-15 01:30:06 +02:00
Pascal Langer
0984a42fe5 Update Protocols_Details.md 2020-04-13 22:42:41 +02:00
Pascal Langer
ed50d60108 Update Protocols_Details.md 2020-04-13 22:41:37 +02:00
Pascal Langer
a7f72a73e5 Update Protocols_Details.md 2020-04-13 22:31:26 +02:00
Pascal Langer
1c02cb46f5 FrSky Clone mode
Check documentation for full details: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md#FRSKY_RX---55
2020-04-13 22:10:58 +02:00
Pascal Langer
da8fd21177 Update FrSkyL_cc2500.ino 2020-04-11 20:17:02 +02:00
Pascal Langer
7e5cd9819a New protocol FrSkyL: LR12
Model: L9R RX
2 sub protocols: LR12 and LR12_6CH
2020-04-11 20:09:32 +02:00
Pascal Langer
00aecb3ab1 Update Protocols_Details.md 2020-04-10 19:38:49 +02:00
Pascal Langer
cde77a88fd FrSkyRX: added sub_protocol, documentation and more 2020-04-10 19:32:50 +02:00
E1yot
08a555f187 Initial Version of CloneMode (#342)
* Initial Version

* Bugfix and change of the handling of the RX Num.

If RX Num is 63, write a finetune value of 127 to the EEPROM.
A real finetune value of 127 means, the frequency of module is out of range and
the module should be replaced. This way the clone mode should not get unwanted
active by a module with a frequency drift arround 63.
2020-04-10 19:01:01 +02:00
Pascal Langer
4039cbf8af Small corrections 2020-04-07 10:55:54 +02:00
Pascal Langer
3f652fa06c FrSkyX: improve SPort to RX code 2020-04-07 01:43:05 +02:00
Pascal Langer
272d2be3ae Update FrSky_Rx_cc2500.ino 2020-04-05 16:05:51 +02:00
Pascal Langer
7e461344a8 Update Protocols_Details.md 2020-04-05 10:46:26 +02:00
Pascal Langer
8af985a2cb FrSkyRX: check additional ID and use RX num 2020-04-05 10:44:09 +02:00
Pascal Langer
08eee34446 Protocol PROPEL: enhanced telemetry 2020-04-05 09:39:33 +02:00
Pascal Langer
0a5b97a177 New Protocol: PROPEL
Compatible model: PROPEL 74-Z Speeder Bike
Protcol: PROPEL (66)
Sub protocol: none
Autobind protocol
Extended limits not supported
Telemetry supported
14 channels in use due to many features
2020-04-03 19:36:05 +02:00
Bryce Johnson
cab782b38e redpine updates to make released betaflight and deviation builds (#341)
Co-authored-by: Bryce Johnson <bryce@redpinelabs.com>
2020-04-02 12:39:26 +02:00
pascallanger
d1518d763b Add files via upload 2020-03-30 21:22:12 +02:00
Pascal Langer
44a676b809 Update Multiprotocol.h 2020-03-30 18:22:13 +02:00
Pascal Langer
d66709ea87 Update Protocols_Details.md 2020-03-29 19:23:28 +02:00
Pascal Langer
358a77cf7c Update Protocols_Details.md 2020-03-29 19:15:32 +02:00
Pascal Langer
1a631908f4 Update FrSky_Rx_cc2500.ino 2020-03-29 19:09:56 +02:00
Pascal Langer
9f32a1f22b FrSkyRX protocol: chanskip test 2020-03-29 18:49:37 +02:00
Pascal Langer
dfd3386319 FrSkyX v2.1: initial support
Rewrite of the FrSkyX code to support both v1 and v2.1.0 with FCC and LBT.
FrSky v1 accessible as usual
FrSky v2.1.0 accessible through the protocol 64=FrSkyX2 with the same subprotocols as v1
The LBT feature is now fully implemented on the TX and turned on for both v1 LBT and v2.1.0 LBT.
For v2.1.0, to access the bind functions Telem=on/off, CH1-8/9-16 and bidirectional SPort (SxR setup for example), you need to update OpenTX to the latest 2.3.8 nightly (not available yet).
2020-03-29 18:44:03 +02:00
Pascal Langer
3df836e6b8 Hitec: fix a bind issue 2020-03-21 19:00:40 +01:00
Pascal Langer
2b8ed25843 FrSkyD: Change hopping frequencies
WARNING: all receivers must be rebound !!!
2020-03-21 15:17:46 +01:00
Pascal Langer
62250d2f25 ESky: addition of sub-protocol ET4 2020-03-21 15:16:01 +01:00
Pascal Langer
a4e9082f53 SLT CC2500 fix 2020-02-20 17:37:58 +01:00
Pascal Langer
7217e8c41d SLT: fix? 2020-02-18 15:50:54 +01:00
Pascal Langer
a7ac093753 SLT: CC2500 fix 2020-02-17 16:44:02 +01:00
Pascal Langer
5503502bad SLT: fix going from NRF to CC2500 2020-02-17 13:10:57 +01:00
Pascal Langer
5124c2a96d SLT: use the CC2500 emulation layer if requested/available 2020-02-17 11:45:28 +01:00
Pascal Langer
73d7728e08 Change CC2500 emulation layer to support NRF24L01 @250K 2020-02-17 11:44:53 +01:00
Pascal Langer
8b7bd00a48 Update Multi.txt 2020-02-16 20:48:49 +01:00
Pascal Langer
68a6af0eb5 Update E119 channels and flags
Default is high rate
CH5 is calib
2020-02-16 20:18:02 +01:00
Pascal Langer
693f9f58eb V911S: new sub protocol E119
Model: Eachine E119
Protocol: V911S -> 46
Sub protocol: E119 -> 1
CH5: left button ???
CH6: right button ???
2020-02-16 20:05:29 +01:00
Tomer Abramovich
4a01e2d472 missed the last 3 bytes here, loop should continue one more time (#322) 2020-01-24 21:09:37 +01:00
pascallanger
e4fd1f4399 FrSkyR9: 16 channels 2020-01-24 14:59:26 +01:00
pascallanger
0d5fcb0849 FrskyR9 protocol 2020-01-24 12:12:07 +01:00
pascallanger
2236c256ba Merge pull request #320 from UnTraDe/master
initial working version of R9M, 8 CH and BINDING support only
2020-01-24 10:12:19 +01:00
Tomer Abramovich
945ad2e7bd now using FrSkyX_scaleForPXX to scale channel values for FrSky R9 instead of using floating point math 2020-01-23 22:29:57 +02:00
Tomer Abramovich
6f9740f03f moved register definitions to a different file and created higher level functions for using them; added preliminary support for 868 MHz mode, not fully working yet 2020-01-23 22:25:00 +02:00
pascallanger
f9fa4dff73 Update _Config.h 2020-01-22 16:11:42 +01:00
Tomer Abramovich
77bf17967d initial working version of R9M, 8 CH and BINDING support only 2020-01-21 17:42:33 +02:00
pascallanger
7281c0b5bf Comment FRSKYX2 protocol for now 2020-01-21 10:51:07 +01:00
pascallanger
e6cab65560 Fix paranthesis... 2020-01-21 10:29:11 +01:00
pascallanger
cc115323e1 Prep for FrSky X v2 2020-01-20 23:52:17 +01:00
Ben Lye
58665ea7a7 Bubble up errors in release builds 2020-01-17 21:37:16 +00:00
Ben Lye
3920644caf Reduce protocols for debug test builds.
Make the debug builds small enough to pass the buildDefault test.
2020-01-17 21:37:16 +00:00
pascallanger
25aecbf15e XK full ID to address and hop freqs generation 2020-01-16 23:43:29 +01:00
pascallanger
e18d8868d2 Protocol Pelikan: hop freq change with RX_num 2020-01-15 16:28:03 +01:00
pascallanger
c6e5d00a2b Protocol Pelikan: fix rx_tx_addr[1]... 2020-01-14 23:00:50 +01:00
pascallanger
7a5b4dea1a XK X420/X520: 2 valid IDs
IDs are selected using RX num.
2020-01-14 22:51:47 +01:00
pascallanger
5df877f32c Protocol XK X420: Changed bitrate to 1Mbps 2020-01-14 22:05:30 +01:00
pascallanger
c5c7dda2e0 Update XK X420 channel order
Change channel order
Add CH140 for video
2020-01-14 21:25:43 +01:00
pascallanger
492b9e5ed4 New protocol XK
Still work in progress
Subprotocols: X450 and X420 -> not sure if they are subprotocols or just different IDs...
CH5: M-Mode=-100%, 6G-Mode=0%, V-Mode=+100%
CH6: Take off momentary switch
CH7: Emergency stop momentary switch
CH8: 3D/6G momentary switch
CH9: Photo momentary switch
2020-01-14 12:19:12 +01:00
pascallanger
9f721c528d Bayang: rewritten the protocol to be more friendly with main scheduler 2020-01-12 19:42:51 +01:00
pascallanger
7f3c80c2a9 Fix DSM invalid protocol when binding 2020-01-12 18:18:47 +01:00
pascallanger
8f789607e4 Pelikan: add some hopping frequencies 2020-01-12 17:38:30 +01:00
pascallanger
6a9b6ed4be XN297EMU: option=0->nrf24L01, option!=0 -> CC2500
XN297L@250kbps is emulated by default with the NRF24L01. If option (freq tune) is diffrent from 0, the CC2500 module (if installed) will be used instead with option being the freq usual tuning.
2020-01-12 14:06:27 +01:00
pascallanger
953a97dae4 Flyzone: add channel 5 2020-01-12 13:17:17 +01:00
pascallanger
86778c5997 XN297Dump: new auto mode
Automatically:
 - find XN297L packet -> bitrate, scrambling, enhanced...
 - use address to filter incoming packets
 - find all frequencies
 - determine channel order (basic)
 - help to find out the changes by only displaying packets when there is a change in the packet
2020-01-12 13:16:30 +01:00
pascallanger
8c32cdf5fd Pelikan: fix TX and multi ID
Still 1 hopping freq table
2020-01-12 13:00:30 +01:00
pascallanger
d092593e5c Fix FrSky RX bind which could fail if another TX was around 2020-01-12 12:57:16 +01:00
pascallanger
edbf4b6908 Merge pull request #311 from benlye/multi-status-fix
Fix module status on erSkyTX
2020-01-11 10:20:03 +01:00
Ben Lye
43f688d011 Fix module status on erSkyTX 2020-01-10 18:25:56 +00:00
pascallanger
054c3088c3 Merge pull request #305 from Shkolik/Direct_inputs
Direct inputs
2020-01-02 17:29:45 +01:00
Andrew Shkolik
0cedd5bb66 disable myConfig 2019-12-30 16:53:12 -06:00
Andrew Shkolik
1961579fe4 code cleanup 2019-12-30 15:44:16 -06:00
Andrew Shkolik
6906f1652e Inputs logic added 2019-12-24 23:41:04 -06:00
Andrew Shkolik
e2bbe8a422 definitions for direct inputs 2019-12-24 15:03:35 -06:00
pascallanger
8ea4e00d31 Pelikan protocol fix ? 2019-12-20 15:43:44 +01:00
pascallanger
917e27280f Pelikan and Tiger protocol fixes 2019-12-20 09:29:37 +01:00
pascallanger
ec92edfc85 New protocol Tiger
Model: Tiger drone 1400782
Protocol number: 61
No sub_protocol
CH5: Flip
CH6: Light
2019-12-19 23:40:33 +01:00
pascallanger
afd2be6c59 New Pelikan protocol
Protocol number: 60
No sub proto
8 channels AETR...
Extended limit supported
!!Only 1 ID for now!!
2019-12-19 22:39:01 +01:00
pascallanger
a23d50bf0d FrSkyX add bind options CH1-8/CH9-16 & Telem ON/OFF 2019-12-19 17:26:47 +01:00
pascallanger
cace1144db Add TX_LQI (TLQY) comment 2019-12-09 10:47:17 +01:00
pascallanger
0d646ed1a6 Update Protocols_Details.md 2019-12-05 17:14:26 +01:00
71 changed files with 9366 additions and 2427 deletions

View File

@@ -1,14 +1,13 @@
os: linux
dist: bionic
sudo: true
language: c
env:
global:
- IDE_VERSION=1.8.9
matrix:
jobs:
- BOARD="multi4in1:avr:multiatmega328p:bootloader=none"
- BOARD="multi4in1:avr:multiatmega328p:bootloader=optiboot"
- BOARD="multi4in1:avr:multixmega32d4"
- BOARD="multi4in1:STM32F1:multi5in1t18int"
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=none"
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=native"
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=ftdi"
@@ -24,16 +23,8 @@ before_install:
- 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; }
- buildMulti() { start_fold config_diff; travis_time_start; git diff Multiprotocol/_Config.h; end_fold config_diff; exitcode=0; BUILDCMD="arduino-cli compile -b $BOARD Multiprotocol/Multiprotocol.ino --build-path ${TRAVIS_BUILD_DIR}/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; }
@@ -45,81 +36,107 @@ before_install:
# Function to build the release files - dependent on board type
- if [[ "$BOARD" == "multi4in1:avr:multixmega32d4" ]]; then
buildReleaseFiles(){
exitcode=0;
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;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/multi-orangerx-aetr-blue-inv-v$MULTI_VERSION.bin;
cp Multiprotocol/Multi.txt ./binaries/Multi.txt; };
cp Multiprotocol/Multi.txt ./binaries/Multi.txt;
mkdir -p TOOLS/SCRIPTS;
cp Lua_scripts/*.lua TOOLS/SCRIPTS/;
cp Lua_scripts/*.txt TOOLS/SCRIPTS/;
zip ./binaries/MultiLuaScripts.zip TOOLS/SCRIPTS/*;
return $exitcode; };
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";
exitcode=0;
opt_disable CHECK_FOR_BOOTLOADER;
opt_disable $ALL_PROTOCOLS;
opt_enable $A7105_PROTOCOLS;
buildMulti;
exitcode=$((exitcode+$?));
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;
opt_disable HITEC_CC2500_INO REDPINE_CC2500_INO SKYARTEC_CC2500_INO SCANNER_CC2500_INO;
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; };
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin;
return $exitcode; };
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";
exitcode=0;
opt_enable CHECK_FOR_BOOTLOADER;
opt_disable $ALL_PROTOCOLS;
opt_enable $A7105_PROTOCOLS;
buildMulti;
exitcode=$((exitcode+$?));
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;
opt_disable HITEC_CC2500_INO REDPINE_CC2500_INO SKYARTEC_CC2500_INO SCANNER_CC2500_INO;
buildMulti;
exitcode=$((exitcode+$?));
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; };
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin;
return $exitcode; };
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";
exitcode=0;
opt_enable CHECK_FOR_BOOTLOADER;
opt_enable $ALL_PROTOCOLS;
opt_enable MULTI_STATUS;
opt_disable MULTI_TELEMETRY;
buildMulti;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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;
@@ -127,27 +144,33 @@ before_install:
opt_enable MULTI_TELEMETRY;
opt_enable INVERT_TELEMETRY;
buildMulti;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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;
@@ -155,18 +178,23 @@ before_install:
opt_disable MULTI_TELEMETRY;
opt_set NBR_BANKS 5;
buildMulti;
exitcode=$((exitcode+$?));
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;
exitcode=$((exitcode+$?));
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; };
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-ppm-reta-noinv-v$MULTI_VERSION.bin;
return $exitcode; };
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";
exitcode=0;
opt_enable CHECK_FOR_BOOTLOADER;
opt_disable $ALL_PROTOCOLS;
opt_add XN297DUMP_NRF24L01_INO;
@@ -174,6 +202,7 @@ before_install:
opt_disable MULTI_TELEMETRY;
opt_enable INVERT_TELEMETRY;
buildMulti;
exitcode=$((exitcode+$?));
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;
@@ -181,10 +210,13 @@ before_install:
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; };
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-xn297dump-inv-usbdebug-v$MULTI_VERSION.bin;
return $exitcode; };
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";
exitcode=0;
opt_enable CHECK_FOR_BOOTLOADER;
opt_disable $ALL_PROTOCOLS;
opt_add XN297DUMP_NRF24L01_INO;
@@ -192,6 +224,7 @@ before_install:
opt_disable MULTI_TELEMETRY;
opt_enable INVERT_TELEMETRY;
buildMulti;
exitcode=$((exitcode+$?));
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;
@@ -199,40 +232,52 @@ before_install:
opt_enable MULTI_TELEMETRY;
opt_enable INVERT_TELEMETRY;
buildMulti;
exitcode=$((exitcode+$?));
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;
return $exitcode; };
elif [[ "$BOARD" == "multi4in1:STM32F1:multi5in1t18int" ]]; then
buildReleaseFiles(){
printf "\n\e[33;1mBuilding multi-t18int-opentx-aetr-noinv-v$MULTI_VERSION.bin\e[0m";
opt_disable INVERT_TELEMETRY;
exitcode=0;
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;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/multi-t18int-opentx-aetr-noinv-v$MULTI_VERSION.bin;
printf "\n\e[33;1mBuilding multi-t18int-opentx-taer-noinv-v$MULTI_VERSION.bin\e[0m";
opt_replace AETR TAER;
exitcode=0;
buildMulti;
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-opentx-aetr-inv-ftdidebug-v$MULTI_VERSION.bin; };
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/multi-t18int-opentx-taer-noinv-v$MULTI_VERSION.bin;
printf "\n\e[33;1mBuilding multi-t18int-opentx-reta-noinv-v$MULTI_VERSION.bin\e[0m";
opt_replace TAER RETA;
exitcode=0;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/multi-t18int-opentx-reta-noinv-v$MULTI_VERSION.bin;
return $exitcode; };
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
# Install Arduino CLI
- mkdir ~/arduino-cli
- curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=~/arduino-cli sh;
- export PATH=$PATH:$HOME/arduino-cli
# 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
# Update the board url and package index
- arduino-cli core update-index --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json
# Install the STM32 board if needed
- if [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
arduino --install-boards multi4in1:STM32F1;
arduino-cli core install multi4in1:STM32F1 --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json;
fi
# Install the AVR board if needed
- if [[ "$BOARD" =~ "multi4in1:avr:" ]]; then
arduino --install-boards multi4in1:avr;
arduino-cli core install arduino:avr;
arduino-cli core install multi4in1:avr --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json;
fi
before_script:
@@ -260,24 +305,34 @@ before_script:
- 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)
- SX1276_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_SX1276_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
# Get the full set of protocols for each board
- if [[ "$BOARD" =~ "multi4in1:avr:multixmega32d4" ]]; then
ALL_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS);
else
elif [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then
ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS);
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS $SX1276_PROTOCOLS);
fi
- echo $ALL_PROTOCOLS
# Declare all the installed modules
- ALL_RFMODULES=$(echo A7105_INSTALLED CYRF6936_INSTALLED CC2500_INSTALLED NRF24L01_INSTALLED);
- if [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
ALL_RFMODULES=$(echo A7105_INSTALLED CYRF6936_INSTALLED CC2500_INSTALLED NRF24L01_INSTALLED SX1276_INSTALLED);
else
ALL_RFMODULES=$(echo A7105_INSTALLED CYRF6936_INSTALLED CC2500_INSTALLED NRF24L01_INSTALLED);
fi
# 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;
# Trim the enabled protocols down for the STM32 board with debugging
- if [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103c:debug_option=ftdi" ]] || [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103c:debug_option=native" ]]; then
opt_disable $ALL_PROTOCOLS;
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
fi
# Trim the enabled protocols down for the Atmega328p board
@@ -295,7 +350,7 @@ before_script:
- 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
# Build with default configuration - all protocols are enabled for STM32; a subset of protocols for Atmega or STM32 debugging
- buildDefault
# Serial only
@@ -320,12 +375,15 @@ script:
# Restore the default configuration
- cp ./_Config.h.bak Multiprotocol/_Config.h
# 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:
token:
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

View File

@@ -1,11 +1,11 @@
@echo off
echo Installing Maple DFU driver...
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0003 --type 1 --name "Maple DFU" --dest "%~dp0maple-dfu"
echo Installing MULTI-Module DFU Bootloader Driver...
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0003 --type 2 --name "MULTI-Module DFU Bootloader" --dest "%~dp0MULTI-DFU-Bootloader" -b
echo.
echo Installing Maple Serial driver...
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0004 --type 3 --name "Maple Serial" --dest "%~dp0maple-serial"
echo Installing MULTI-Module USB Serial Driver...
"%~dp0wdi-simple" --vid 0x1EAF --pid 0x0004 --type 3 --name "MULTI-Module USB Serial" --dest "%~dp0MULTI-USB-Serial" -b
echo.
pause

View File

@@ -527,6 +527,28 @@
"version": "4.8.3-2014q1"
}]
},
{
"name": "Multi X-in-1 STM32 Boards",
"architecture": "STM32F1",
"version": "1.1.8",
"category": "Contributed",
"help": {
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
},
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.8.tar.gz",
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.8.tar.gz",
"checksum": "SHA-256:e9ed8055ebf72abf37e60e1b8d1c6ee5472132ea7c0a3c4a63fbb8442613e4c2",
"size": "7481800",
"boards": [
{"name": "Multi 4-in-1 (STM32F103C)"},
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
],
"toolsDependencies": [{
"packager": "arduino",
"name": "arm-none-eabi-gcc",
"version": "4.8.3-2014q1"
}]
},
{
"name": "Multi 4-in-1 OrangeRX Board - DEPRECATED, USE MULTI 4-IN-1 AVR BOARDS PACKAGE INSTEAD",
"architecture": "orangerx",

View File

@@ -0,0 +1,171 @@
---- #########################################################################
---- # #
---- # Copyright (C) OpenTX #
-----# #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
--###############################################################################
-- Multi buffer for HoTT description
-- To start operation:
-- Write "HoTT" at address 0..3
-- Write 0xFF at address 4 will request the buffer to be cleared
-- Write 0x0F at address 5
-- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters
-- by 8 lines
-- Write at address 5 sends an order to the RX: 0xXF=start, 0xX7=prev page,
-- 0xXE=next page, 0xX9=enter, 0xXD=next or 0xXB=prev with X being the sensor
-- to request data from 8=RX only, 9=Vario, A=GPS, B=Cust, C=ESC, D=GAM, E=EAM
-- Write at address 4 the value 0xFF will request the buffer to be cleared
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
--###############################################################################
HoTT_Sensor = 0
Timer_128 = 100
local function HoTT_Release()
multiBuffer( 0, 0 )
end
local function HoTT_Send(button)
multiBuffer( 5, 0x80+(HoTT_Sensor*16) + button)
end
local function HoTT_Sensor_Inc()
local detected_sensors=multiBuffer( 4 )
local a
if detected_sensors ~= 0xFF then
repeat
HoTT_Sensor=(HoTT_Sensor+1)%7 -- Switch to next sensor
if HoTT_Sensor ~= 0 then
a = math.floor(detected_sensors/ (2^(HoTT_Sensor-1))) -- shift right
end
until HoTT_Sensor==0 or a % 2 == 1
HoTT_Send( 0x0F )
end
end
local function HoTT_Draw_LCD()
local i
local value
local line
local result
local offset=0
local sensor_name = { "", "+Vario", "+GPS", "+Cust", "+ESC", "+GAM", "+EAM" }
lcd.clear()
if LCD_W == 480 then
--Draw title
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
lcd.drawText(1, 5, "Graupner HoTT: config RX" .. sensor_name[HoTT_Sensor+1] .. " - Menu cycle Sensors", MENU_TITLE_COLOR)
--Draw RX Menu
if multiBuffer( 4 ) == 0xFF then
lcd.drawText(10,50,"No HoTT telemetry...", BLINK)
else
for line = 0, 7, 1 do
for i = 0, 21-1, 1 do
value=multiBuffer( line*21+6+i )
if value > 0x80 then
value = value - 0x80
lcd.drawText(10+i*16,32+20*line,string.char(value).." ",INVERS)
else
lcd.drawText(10+i*16,32+20*line,string.char(value))
end
end
end
end
else
--Draw RX Menu on LCD_W=128
if multiBuffer( 4 ) == 0xFF then
lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE)
else
if Timer_128 ~= 0 then
--Intro page
Timer_128 = Timer_128 - 1
lcd.drawScreenTitle("Graupner Hott",0,0)
lcd.drawText(2,17,"Configuration of RX" .. sensor_name[HoTT_Sensor+1] ,SMLSIZE)
lcd.drawText(2,37,"Press menu to cycle Sensors" ,SMLSIZE)
else
--Menu page
for line = 0, 7, 1 do
for i = 0, 21-1, 1 do
value=multiBuffer( line*21+6+i )
if value > 0x80 then
value = value - 0x80
lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS)
else
lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE)
end
end
end
end
end
end
end
-- Init
local function HoTT_Init()
--Set protocol to talk to
multiBuffer( 0, string.byte('H') )
--test if value has been written
if multiBuffer( 0 ) ~= string.byte('H') then
error("Not enough memory!")
return 2
end
multiBuffer( 1, string.byte('o') )
multiBuffer( 2, string.byte('T') )
multiBuffer( 3, string.byte('T') )
--Request init of the RX buffer
multiBuffer( 4, 0xFF )
--Request RX to send the config menu
HoTT_Send( 0x0F )
HoTT_Sensor = 0;
HoTT_Detected_Sensors=0;
Timer_128 = 100
end
-- Main
local function HoTT_Run(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
elseif event == EVT_VIRTUAL_EXIT then
HoTT_Release()
return 2
else
if event == EVT_VIRTUAL_PREV_PAGE then
killEvents(event)
HoTT_Send( 0x07 )
elseif event == EVT_VIRTUAL_ENTER then
HoTT_Send( 0x09 )
elseif event == EVT_VIRTUAL_PREV then
HoTT_Send( 0x0B )
elseif event == EVT_VIRTUAL_NEXT then
HoTT_Send( 0x0D )
elseif event == EVT_VIRTUAL_NEXT_PAGE then
HoTT_Send( 0x0E )
elseif event == EVT_VIRTUAL_MENU then
Timer_128 = 100
HoTT_Sensor_Inc()
else
HoTT_Send( 0x0F )
end
HoTT_Draw_LCD()
return 0
end
end
return { init=HoTT_Init, run=HoTT_Run }

174
Lua_scripts/MultiChan.txt Normal file
View File

@@ -0,0 +1,174 @@
24,0,Assan,Std,0,CH5,CH6,CH7,CH8
14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
14,5,Bayang,QX100,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
12,0,CX10,Green,1,Flip,Rate
12,1,CX10,Blue,1,Flip,Rate,Pict,Video
12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
7,3,Devo,6CH,0,CH5,CH6
7,4,Devo,7CH,0,CH5,CH6,CH7
33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
6,0,DSM,2_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
6,1,DSM,2_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
6,2,DSM,X_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
16,0,ESKY,Std,0,Gyro,Pitch
16,1,ESKY,ET4,0,Gyro,Pitch
35,0,ESKY150,4CH,0
35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
69,0,ESKY150V2,Std,0,CH5_RA,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
1,0,Flysky,Flysky,0,CH5,CH6,CH7,CH8
1,1,Flysky,V9x9,1,Flip,Light,Pict,Video
1,2,Flysky,V6x6,1,Flip,Light,Pict,Video,HLess,RTH,XCAL,YCAL
1,3,Flysky,V912,1,BtmBtn,TopBtn
1,4,Flysky,CX20,0,CH5,CH6,CH7
28,0,Flysky_AFHDS2A,PWM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
53,0,Height,5ch,0,Gear
53,1,Height,8ch,0,Gear,Gyro,Flap,Light
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
3,0,FrSkyD,D8,0,CH5,CH6,CH7,CH8
3,0,FrSkyD,D8Cloned,0,CH5,CH6,CH7,CH8
67,0,FrSkyL,LR12,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
67,1,FrSkyL,LR12_6CH,0,CH5,CH6
15,0,FrSkyX,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
15,1,FrSkyX,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
15,2,FrSkyX,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
15,3,FrSkyX,D16_8CH_LBT,0,CH5,CH6,CH7,CH8
15,4,FrSkyX,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
15,5,FrSkyX,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,0,FrSkyX2,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,1,FrSkyX2,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
64,2,FrSkyX2,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,3,FrSkyX2,D16_8CH_LBT,1,CH5,CH6,CH7,CH8
64,4,FrSkyX2,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,5,FrSkyX2,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
55,1,FrSkyRX,CloneTX,0
58,0,FX816,P38,1
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
47,0,GD00x,V1,1,Trim,LED,Rate
47,1,GD00x,V2,1,Trim,LED,Rate
32,0,GW008,FY326,1,Flip
36,0,H8_3D,Std,1,Flip,Light,Pict,Video,RTH,FlMode,Cal1
36,1,H8_3D,H20H,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
36,2,H8_3D,H20,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
36,3,H8_3D,H30,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
4,0,Hisky,Std,0,Gear,Pitch,Gyro,CH8
4,1,Hisky,HK310,0,Aux
39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
26,0,Hontai,Std,1,Flip,LED,Pict,Video,HLess,RTH,Calib
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
2,1,Hubsan,H301,0,RTH,Light,Stab,Video
2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
71,0,JJRC345,Std,1,Flip,HLess,RTH
49,0,KF606,Std,1,Trim
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
18,0,MJXQ,WHL08,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,3,MJXQ,H26D,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
44,0,NCC1701,Std,1,Warp
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
60,1,Pelikan,LITE_V4,0,CH5,CH6,CH7,CH8
51,0,Potensic,A20,1,TakLan,Emerg,Mode,HLess
66,0,Propel,74-Z,1,LEDs,RollCW,RolCCW,Fire,Weapon,Calib,AltHol,TakeOf,Land,Train
29,0,Q2x2,Q222,1,Flip,LED,Mod2,Mod1,HLess,RTH,XCal,YCal
29,1,Q2x2,Q242,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
29,2,Q2x2,Q282,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
31,0,Q303,Q303,1,AltHol,Flip,Pict,Video,HLess,RTH,Gimbal
31,1,Q303,C35,1,Arm,VTX,Pict,Video,n-a,RTH,Gimbal
31,2,Q303,CX10D,1,Arm,Flip
31,3,Q303,CX10WD,1,Arm,Flip
72,0,Q90C,Std,0,FMode,VTX+
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
19,0,Shenqi,Cycle,1
68,0,Skyartec,Std,0,CH5,CH6,CH7
11,0,SLT,V1,0,Gear,Pitch
11,1,SLT,V2,0,CH5,CH6,CH7,CH8
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib
11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict
10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess
61,0,Tiger,Std,1,Flip,Light
43,0,Traxxas,6519,0
5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
48,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn
48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn
46,0,V911s,V911s,1,Calib
46,1,V911s,E119,1,Calib
22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
30,1,WK2x01,WK2401,0
30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
52,0,ZSX,280,1,Light

View File

@@ -0,0 +1,311 @@
local toolName = "TNS|Multi chan namer|TNE"
---- #########################################################################
---- # #
---- # Copyright (C) OpenTX #
-----# #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
local protocol_name = ""
local sub_protocol_name = ""
local bind_ch = 0
local module_conf = {}
local module_pos = "Internal"
local file_ok = 0
local done = 0
local protocol = 0
local sub_protocol = 0
local f_seek = 0
local channel_names={}
local num_search = "Searching"
local function drawScreenTitle(title)
if LCD_W == 480 then
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
else
lcd.drawScreenTitle(title, 0, 0)
end
end
function bitand(a, b)
local result = 0
local bitval = 1
while a > 0 and b > 0 do
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
result = result + bitval -- set the current bit
end
bitval = bitval * 2 -- shift left
a = math.floor(a/2) -- shift right
b = math.floor(b/2)
end
return result
end
local function Multi_Draw_LCD(event)
local line = 0
lcd.clear()
drawScreenTitle("Multi channels namer")
--Display settings
local lcd_opt = 0
if LCD_W == 480 then
x_pos = 10
y_pos = 32
y_inc = 20
else
x_pos = 0
y_pos = 9
y_inc = 8
lcd_opt = SMLSIZE
end
--Multi Module detection
if module_conf["Type"] ~= 6 then
if LCD_W == 480 then
lcd.drawText(10,50,"No Multi module configured...", BLINK)
else
--Draw on LCD_W=128
lcd.drawText(2,17,"No Multi module configured...",SMLSIZE)
end
return
else
lcd.drawText(x_pos, y_pos+y_inc*line,module_pos .. " Multi detected.", lcd_opt)
line = line + 1
end
--Channel order
if (ch_order == -1) then
lcd.drawText(x_pos, y_pos+y_inc*line,"Channels order can't be read from Multi...", lcd_opt)
line = line + 1
end
--Can't open file MultiChan.txt
if file_ok == 0 then
lcd.drawText(x_pos, y_pos+y_inc*line,"Can't read MultiChan.txt file...", lcd_opt)
return
end
if ( protocol_name == "" or sub_protocol_name == "" ) and f_seek ~=-1 then
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
if f == nil then return end
lcd.drawText(x_pos, y_pos+y_inc*line,num_search, lcd_opt)
num_search = num_search .. "."
if #num_search > 15 then
num_search = string.sub(num_search,1,9)
end
local proto = 0
local sub_proto = 0
local proto_name = ""
local sub_proto_name = ""
local channels = ""
local nbr_try = 0
local nbr_car = 0
repeat
io.seek(f, f_seek)
local data = io.read(f, 100) -- read 100 characters
if #data ==0 then
f_seek = -1 -- end of file
break
end
proto, sub_proto, proto_name, sub_proto_name, bind_ch, channels = string.match(data,'(%d+),(%d),([%w-_ ]+),([%w-_ ]+),(%d)(.+)')
if proto ~= nil and sub_proto ~= nil and protocol_name ~= nil and sub_protocol_name ~= nil and bind_ch ~= nil then
if tonumber(proto) == protocol and tonumber(sub_proto) == sub_protocol then
protocol_name = proto_name
sub_protocol_name = sub_proto_name
bind_ch = tonumber(bind_ch)
if channels ~= nil then
--extract channel names
nbr_car = string.find(channels, "\r")
if nbr_car == nil then nbr_car = string.find(channels, "\n") end
if nbr_car ~= nil then
channels = string.sub(channels,1,nbr_car-1)
end
local i = 5
for k in string.gmatch(channels, ",([%w-_ ]+)") do
channel_names[i] = k
i = i + 1
end
end
f_seek = -1 -- protocol found
break
end
end
if f_seek ~= -1 then
nbr_car = string.find(data, "\n")
if nbr_car == nil then nbr_car = string.find(data, "\r") end
if nbr_car == nil then
f_seek = -1 -- end of file
break
end
f_seek = f_seek + nbr_car -- seek to next line
nbr_try = nbr_try + 1
end
until nbr_try > 20 or f_seek == -1
io.close(f)
end
if f_seek ~= -1 then
return -- continue searching...
end
--Protocol & Sub_protocol
if protocol_name == "" or sub_protocol_name == "" then
lcd.drawText(x_pos, y_pos+y_inc*line,"Unknown protocol "..tostring(protocol).."/"..tostring(sub_protocol).." ...", lcd_opt)
return
elseif LCD_W > 128 then
lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name .. " / SubProtocol: " .. sub_protocol_name, lcd_opt)
line = line + 1
else
lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name, lcd_opt)
line = line + 1
lcd.drawText(x_pos, y_pos+y_inc*line,"SubProtocol: " .. sub_protocol_name, lcd_opt)
line = line + 1
end
text1=""
text2=""
for i,v in ipairs(channel_names) do
if i<=8 then
if i==1 then
text1 = v
else
text1=text1 .. "," .. v
end
else
if i==9 then
text2 = v
else
text2=text2 .. "," .. v
end
end
end
if LCD_W > 128 then
lcd.drawText(x_pos, y_pos+y_inc*line,"Channels: " .. text1, lcd_opt)
line = line + 1
if text2 ~= "" then
lcd.drawText(x_pos*9, y_pos+y_inc*line,text2, lcd_opt)
line = line + 1
end
end
if event ~= EVT_VIRTUAL_ENTER and done == 0 then
lcd.drawText(x_pos, y_pos+y_inc*line,"<ENT> Save", lcd_opt + INVERS + BLINK)
return
end
lcd.drawText(x_pos, y_pos+y_inc*line,"Setting channel names.", lcd_opt)
line = line + 1
local output, nbr
if done == 0 then
for i,v in ipairs(channel_names) do
output = model.getOutput(i-1)
output["name"] = v
model.setOutput(i-1,output)
nbr = i
end
for i = nbr, 15 do
output = model.getOutput(i)
output["name"] = "n-a"
model.setOutput(i,output)
end
if bind_ch == 1 then
output = model.getOutput(15)
output["name"] = "BindCH"
model.setOutput(15,output)
end
done = 1
end
lcd.drawText(x_pos, y_pos+y_inc*line,"Done!", lcd_opt)
line = line + 1
end
-- Init
local function Multi_Init()
module_conf = model.getModule(0)
if module_conf["Type"] ~= 6 then
module_pos = "External"
module_conf = model.getModule(1)
if module_conf["Type"] ~= 6 then
return
end
end
protocol = module_conf["protocol"]
sub_protocol = module_conf["subProtocol"]
--Exceptions on first 4 channels...
local stick_names = { "Rud", "Ele", "Thr", "Ail" }
if ( protocol == 4 and sub_protocol == 1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
stick_names[2] = "n-a"
stick_names[4] = "n-a"
elseif protocol == 43 then -- Traxxas
stick_names[2] = "Aux4"
stick_names[4] = "Aux3"
elseif ( protocol == 48 and sub_protocol == 0 ) then -- V761 3CH
stick_names[4] = "n-a"
elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816
stick_names[1] = "n-a"
stick_names[2] = "n-a"
end
--Determine fist 4 channels order
local ch_order=module_conf["channelsOrder"]
if (ch_order == -1) then
channel_names[1] = stick_names[defaultChannel(0)+1]
channel_names[2] = stick_names[defaultChannel(1)+1]
channel_names[3] = stick_names[defaultChannel(2)+1]
channel_names[4] = stick_names[defaultChannel(3)+1]
else
channel_names[bitand(ch_order,3)+1] = stick_names[4]
ch_order = math.floor(ch_order/4)
channel_names[bitand(ch_order,3)+1] = stick_names[2]
ch_order = math.floor(ch_order/4)
channel_names[bitand(ch_order,3)+1] = stick_names[3]
ch_order = math.floor(ch_order/4)
channel_names[bitand(ch_order,3)+1] = stick_names[1]
end
--Exceptions on first 4 channels...
if ( protocol == 73 or (protocol == 74 and sub_protocol == 0) ) then -- Kyosho or RadioLink Surface
channel_names[1] = "ST"
channel_names[2] = "THR"
channel_names[3] = "CH3"
channel_names[4] = "CH4"
end
--Check MultiChan.txt
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
if f == nil then return end
file_ok = 1
io.close(f)
end
-- Main
local function Multi_Run(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
else
Multi_Draw_LCD(event)
if event == EVT_VIRTUAL_EXIT then
return 2
end
end
return 0
end
return { init=Multi_Init, run=Multi_Run }

34
Lua_scripts/README.md Normal file
View File

@@ -0,0 +1,34 @@
# Multiprotocol TX Module OpenTX LUA scripts
<img align="right" width=300 src="../docs/images/multi.png" />
If you like this project and want to support further development please consider making a [donation](../docs/Donations.md).
<table cellspacing=0>
<tr>
<td align=center width=200><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol&currency_code=EUR&amount=5&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"><img src="../docs/images/donate_button.png" border="0" name="submit" title="PayPal - Donate €5" alt="Donate €5"/></a><br><b>€5</b></td>
<td align=center width=200><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol&currency_code=EUR&amount=10&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"><img src="../docs/images/donate_button.png" border="0" name="submit" title="PayPal - Donate €10" alt="Donate €10"/></a><br><b>€10</b></td>
<td align=center width=200><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol&currency_code=EUR&amount=15&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"><img src="../docs/images/donate_button.png" border="0" name="submit" title="PayPal - Donate €15" alt="Donate €10"/></a><br><b>€15</b></td>
<td align=center width=200><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol&currency_code=EUR&amount=25&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"><img src="../docs/images/donate_button.png" border="0" name="submit" title="PayPal - Donate €25" alt="Donate €25"/></a><br><b>€25</b></td>
<td align=center width=200><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"><img src="../docs/images/donate_button.png" border="0" name="submit" title="PayPal - Donate" alt="Donate"/></a><br><b>Other</b></td>
</tr>
</table>
## MultiChannelsUpdater.lua
Automatically name the channels based on the loaded Multi protocol and sub protocol including the module channel order convention.
Need OpenTX 2.3.9 or above. Located on the radio SD card under \SCRIPTS\TOOLS. This script needs MultiChan.txt to be present in the same folder.
[![MultiChannelsUpdater](https://img.youtube.com/vi/L58ayXuewyA/0.jpg)](https://www.youtube.com/watch?v=L58ayXuewyA)
## Graupner HoTT.ua
Enable text configuration of the HoTT RX and sensors: Vario, GPS, ESC, GAM and EAM.
Need OpenTX 2.3.9 or above. Located on the radio SD card under \SCRIPTS\TOOLS.
Notes:
- Menu is used to cycle through the detected sensors.
- It's normal to lose the telemetry feed while using the text mode configuration. Telemetry will resume properly if the script is exited by doing a short press on the exit button.
[![Text mode video](https://img.youtube.com/vi/81wd8NlF3Qw/0.jpg)](https://www.youtube.com/watch?v=81wd8NlF3Qw)

View File

@@ -192,9 +192,19 @@ void A7105_AdjustLOBaseFreq(uint8_t cmd)
offset=(int16_t)FORCE_FLYSKY_TUNING;
#endif
break;
case PROTO_FLYZONE:
#ifdef FORCE_FLYZONE_TUNING
offset=(int16_t)FORCE_FLYZONE_TUNING;
case PROTO_HEIGHT:
#ifdef FORCE_HEIGHT_TUNING
offset=(int16_t)FORCE_HEIGHT_TUNING;
#endif
break;
case PROTO_PELIKAN:
#ifdef FORCE_PELIKAN_TUNING
offset=(int16_t)FORCE_PELIKAN_TUNING;
#endif
break;
case PROTO_KYOSHO:
#ifdef FORCE_KYOSHO_TUNING
offset=(int16_t)FORCE_KYOSHO_TUNING;
#endif
break;
case PROTO_AFHDS2A:
@@ -277,8 +287,8 @@ const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
0x01, 0x0f // 30 - 31
};
#endif
#ifdef FLYZONE_A7105_INO
const uint8_t PROGMEM FLYZONE_A7105_regs[] = {
#ifdef HEIGHT_A7105_INO
const uint8_t PROGMEM HEIGHT_A7105_regs[] = {
0xff, 0x42, 0x00, 0x07, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x01, 0x50, // 00 - 0f
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x1f, // 10 - 1f
0x12, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3a, 0x00, 0x3f, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
@@ -293,6 +303,22 @@ const uint8_t PROGMEM HUBSAN_A7105_regs[] = {
0xFF, 0xFF // 30 - 31
};
#endif
#ifdef PELIKAN_A7105_INO
const uint8_t PROGMEM PELIKAN_A7105_regs[] = {
0xff, 0x42, 0x00, 0x0F, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x01, 0x50, // 00 - 0f
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x07, // 10 - 1f
0x16, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x1f, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
0x01, 0x0f // 30 - 31
};
#endif
#ifdef KYOSHO_A7105_INO
const uint8_t PROGMEM KYOSHO_A7105_regs[] = {
0xff, 0x42, 0xff, 0x25, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50, // 00 - 0f
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x40, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0x03, 0x1f, // 10 - 1f
0x1e, 0x00, 0x00, 0xff, 0x00, 0x00, 0x23, 0x70, 0x1F, 0x47, 0x80, 0x57, 0x01, 0x45, 0x19, 0x00, // 20 - 2f
0x01, 0x0f // 30 - 31
};
#endif
#define ID_NORMAL 0x55201041
#define ID_PLUS 0xAA201041
@@ -301,14 +327,22 @@ void A7105_Init(void)
uint8_t *A7105_Regs=0;
uint8_t vco_calibration0, vco_calibration1;
#ifdef FLYZONE_A7105_INO
if(protocol==PROTO_FLYZONE)
#ifdef HEIGHT_A7105_INO
if(protocol==PROTO_HEIGHT)
{
A7105_Regs=(uint8_t*)FLYZONE_A7105_regs;
A7105_Regs=(uint8_t*)HEIGHT_A7105_regs;
A7105_WriteID(0x25A53C45);
}
else
#endif
#ifdef PELIKAN_A7105_INO
if(protocol==PROTO_PELIKAN)
{
A7105_Regs=(uint8_t*)PELIKAN_A7105_regs;
A7105_WriteID(0x06230623);
}
else
#endif
#ifdef BUGS_A7105_INO
if(protocol==PROTO_BUGS)
A7105_Regs=(uint8_t*)BUGS_A7105_regs;
@@ -327,13 +361,15 @@ void A7105_Init(void)
#ifdef FLYSKY_A7105_INO
if(protocol==PROTO_FLYSKY)
A7105_Regs=(uint8_t*)FLYSKY_A7105_regs;
else
#endif
{
#if defined(AFHDS2A_A7105_INO) || defined(AFHDS2A_RX_A7105_INO)
A7105_Regs=(uint8_t*)AFHDS2A_A7105_regs;
#endif
}
#if defined(AFHDS2A_A7105_INO) || defined(AFHDS2A_RX_A7105_INO)
if(protocol==PROTO_AFHDS2A)
A7105_Regs=(uint8_t*)AFHDS2A_A7105_regs;
#endif
#ifdef KYOSHO_A7105_INO
if(protocol==PROTO_KYOSHO)
A7105_Regs=(uint8_t*)KYOSHO_A7105_regs;
#endif
}
for (uint8_t i = 0; i < 0x32; i++)
@@ -347,61 +383,83 @@ void A7105_Init(void)
if(i==0x20) val=0x1E;
}
#endif
#ifdef HEIGHT_A7105_INO
if(protocol==PROTO_HEIGHT && sub_protocol==HEIGHT_8CH)
if(i==0x03) val=0x0A;
#endif
if( val != 0xFF)
A7105_WriteReg(i, val);
}
A7105_Strobe(A7105_STANDBY);
//IF Filter Bank Calibration
A7105_WriteReg(A7105_02_CALC,1);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
// A7105_ReadReg(A7105_22_IF_CALIB_I);
// A7105_ReadReg(A7105_24_VCO_CURCAL);
if(protocol!=PROTO_HUBSAN)
{
//VCO Current Calibration
A7105_WriteReg(A7105_24_VCO_CURCAL,0x13); //Recommended calibration from A7105 Datasheet
//VCO Bank Calibration
A7105_WriteReg(A7105_26_VCO_SBCAL_II,0x3b); //Recommended calibration from A7105 Datasheet
if(protocol==PROTO_KYOSHO)
{//strange calibration...
//IF Filter Bank Calibration
A7105_WriteReg(A7105_02_CALC,0x0F);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
// A7105_ReadReg(A7105_22_IF_CALIB_I);
// A7105_ReadReg(A7105_24_VCO_CURCAL);
// A7105_ReadReg(25_VCO_SBCAL_I);
// A7105_ReadReg(1A_RX_GAIN_II);
// A7105_ReadReg(1B_RX_GAIN_III);
}
//VCO Bank Calibrate channel 0
A7105_WriteReg(A7105_0F_CHANNEL, 0);
A7105_WriteReg(A7105_02_CALC,2);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
vco_calibration0 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
//VCO Bank Calibrate channel A0
A7105_WriteReg(A7105_0F_CHANNEL, 0xa0);
A7105_WriteReg(A7105_02_CALC, 2);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
vco_calibration1 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
if(protocol==PROTO_BUGS)
A7105_SetVCOBand(vco_calibration0 & 0x07, vco_calibration1 & 0x07); // Set calibration band value to best match
else
{
//IF Filter Bank Calibration
A7105_WriteReg(A7105_02_CALC,1);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
// A7105_ReadReg(A7105_22_IF_CALIB_I);
// A7105_ReadReg(A7105_24_VCO_CURCAL);
if(protocol!=PROTO_HUBSAN)
{
switch(protocol)
{
case PROTO_FLYSKY:
vco_calibration1=0x08;
break;
case PROTO_FLYZONE:
vco_calibration1=0x02;
break;
default:
vco_calibration1=0x0A;
break;
}
A7105_WriteReg(A7105_25_VCO_SBCAL_I,vco_calibration1); //Reset VCO Band calibration
//VCO Current Calibration
A7105_WriteReg(A7105_24_VCO_CURCAL,0x13); //Recommended calibration from A7105 Datasheet
//VCO Bank Calibration
A7105_WriteReg(A7105_26_VCO_SBCAL_II,0x3b); //Recommended calibration from A7105 Datasheet
}
//VCO Bank Calibrate channel 0
A7105_WriteReg(A7105_0F_CHANNEL, 0);
A7105_WriteReg(A7105_02_CALC,2);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
vco_calibration0 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
//VCO Bank Calibrate channel A0
A7105_WriteReg(A7105_0F_CHANNEL, 0xa0);
A7105_WriteReg(A7105_02_CALC, 2);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
vco_calibration1 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
if(protocol==PROTO_BUGS)
A7105_SetVCOBand(vco_calibration0 & 0x07, vco_calibration1 & 0x07); // Set calibration band value to best match
else
if(protocol!=PROTO_HUBSAN)
{
switch(protocol)
{
case PROTO_FLYSKY:
vco_calibration1=0x08;
break;
case PROTO_HEIGHT:
vco_calibration1=0x02;
break;
case PROTO_PELIKAN:
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();
A7105_AdjustLOBaseFreq(0);
#ifdef USE_A7105_CH15_TUNING
A7105_AdjustLOBaseFreq(0);
#endif
A7105_Strobe(A7105_STANDBY);
}

View File

@@ -39,7 +39,7 @@ static void __attribute__((unused)) AFHDS2A_Rx_build_telemetry_packet()
packet_in[idx++] = 14; // number of channels in packet
// pack channels
for (uint8_t i = 0; i < 14; i++) {
uint32_t val = packet[9+i*2] | (packet[10+i*2] << 8);
uint32_t val = packet[9+i*2] | ((packet[10+i*2] << 8)&0x0F);
if (val < 860)
val = 860;
// convert ppm (860-2140) to Multi (0-2047)
@@ -90,8 +90,6 @@ uint16_t initAFHDS2A_Rx()
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;

View File

@@ -20,6 +20,10 @@
#define AFHDS2A_RXPACKET_SIZE 37
#define AFHDS2A_NUMFREQ 16
#if not defined TELEMETRY
uint8_t RX_LQI=0;
#endif
enum{
AFHDS2A_PACKET_STICKS,
AFHDS2A_PACKET_SETTINGS,
@@ -65,7 +69,6 @@ static void AFHDS2A_calc_channels()
}
}
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
// telemetry sensors ID
enum{
AFHDS2A_SENSOR_RX_VOLTAGE = 0x00,
@@ -76,10 +79,9 @@ enum{
AFHDS2A_SENSOR_A3_VOLTAGE = 0x03,
};
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
static void AFHDS2A_update_telemetry()
{
if(packet[0]==0xAA && packet[9]==0xFD)
return; // ignore packets which contain the RX configuration: FD FF 32 00 01 00 FF FF FF 05 DC 05 DE FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF
// Read TX RSSI
int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less
if(temp<0) temp=0;
@@ -183,37 +185,64 @@ static void AFHDS2A_build_packet(uint8_t type)
{
case AFHDS2A_PACKET_STICKS:
packet[0] = 0x58;
for(uint8_t ch=0; ch<14; ch++)
//16 channels + RX_LQI on channel 17
for(uint8_t ch=0; ch<num_ch; ch++)
{
uint16_t channelMicros = convert_channel_ppm(CH_AETR[ch]);
packet[9 + ch*2] = channelMicros&0xFF;
packet[10 + ch*2] = (channelMicros>>8)&0xFF;
if(ch == 16 // CH17=RX_LQI
#ifdef AFHDS2A_LQI_CH
|| ch == (AFHDS2A_LQI_CH-1) // override channel with LQI
#endif
)
val = 2000 - 10*RX_LQI;
else
val = convert_channel_ppm(CH_AETR[ch]);
if(ch<14)
{
packet[9 + ch*2] = val;
packet[10 + ch*2] = (val>>8)&0x0F;
}
else
{
packet[10 + (ch-14)*6] |= (val)<<4;
packet[12 + (ch-14)*6] |= (val)&0xF0;
packet[14 + (ch-14)*6] |= (val>>4)&0xF0;
}
}
#ifdef AFHDS2A_LQI_CH
// override channel with LQI
val = 2000 - 10*RX_LQI;
packet[9+((AFHDS2A_LQI_CH-1)*2)] = val & 0xff;
packet[10+((AFHDS2A_LQI_CH-1)*2)] = (val >> 8) & 0xff;
#endif
break;
case AFHDS2A_PACKET_FAILSAFE:
packet[0] = 0x56;
for(uint8_t ch=0; ch<14; ch++)
for(uint8_t ch=0; ch<num_ch; ch++)
{
#ifdef FAILSAFE_ENABLE
uint16_t failsafeMicros = Failsafe_data[CH_AETR[ch]];
if( failsafeMicros!=FAILSAFE_CHANNEL_HOLD && failsafeMicros!=FAILSAFE_CHANNEL_NOPULSES)
if(ch<16)
val = Failsafe_data[CH_AETR[ch]];
else
val = FAILSAFE_CHANNEL_NOPULSES;
if(val!=FAILSAFE_CHANNEL_HOLD && val!=FAILSAFE_CHANNEL_NOPULSES)
{ // Failsafe values
failsafeMicros = (((failsafeMicros<<2)+failsafeMicros)>>3)+860;
packet[9 + ch*2] = failsafeMicros & 0xff;
packet[10+ ch*2] = ( failsafeMicros >> 8) & 0xff;
val = (((val<<2)+val)>>3)+860;
if(ch<14)
{
packet[9 + ch*2] = val;
packet[10 + ch*2] = (val>>8)&0x0F;
}
else
{
packet[10 + (ch-14)*6] &= 0x0F;
packet[10 + (ch-14)*6] |= (val)<<4;
packet[12 + (ch-14)*6] &= 0x0F;
packet[12 + (ch-14)*6] |= (val)&0xF0;
packet[14 + (ch-14)*6] &= 0x0F;
packet[14 + (ch-14)*6] |= (val>>4)&0xF0;
}
}
else
#endif
{ // no values
packet[9 + ch*2] = 0xff;
packet[10+ ch*2] = 0xff;
}
if(ch<14)
{ // no values
packet[9 + ch*2] = 0xff;
packet[10+ ch*2] = 0xff;
}
}
break;
case AFHDS2A_PACKET_SETTINGS:
@@ -224,17 +253,14 @@ static void AFHDS2A_build_packet(uint8_t type)
if(val<50 || val>400) val=50; // default is 50Hz
packet[11]= val;
packet[12]= val >> 8;
if(sub_protocol == PPM_IBUS || sub_protocol == PPM_SBUS)
packet[13] = 0x01; // PPM output enabled
else
packet[13] = 0x00;
packet[13] = sub_protocol & 0x01; // 1 -> PPM output enabled
packet[14]= 0x00;
for(uint8_t i=15; i<37; i++)
packet[i] = 0xff;
packet[18] = 0x05; // ?
packet[19] = 0xdc; // ?
packet[20] = 0x05; // ?
if(sub_protocol == PWM_SBUS || sub_protocol == PPM_SBUS)
if(sub_protocol&2)
packet[21] = 0xdd; // SBUS output enabled
else
packet[21] = 0xde; // IBUS
@@ -352,24 +378,19 @@ uint16_t ReadAFHDS2A()
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((packet[0] == 0xAA && packet[9]!=0xFD) || packet[0] == 0xAC)
{// Normal telemetry packet, ignore packets which contain the RX configuration: AA FD FF 32 00 01 00 FF FF FF 05 DC 05 DE FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF
if(!memcmp(&packet[1], rx_tx_addr, 4))
{ // TX address validated
#ifdef AFHDS2A_LQI_CH
if(packet[0]==0xAA && packet[9]!=0xFD)
{// Normal telemetry packet
for(uint8_t sensor=0; sensor<7; sensor++)
{//read LQI value for RX output
uint8_t index = 9+(4*sensor);
if(packet[index]==AFHDS2A_SENSOR_RX_ERR_RATE && packet[index+2]<=100)
{
RX_LQI=packet[index+2];
break;
}
}
for(uint8_t sensor=0; sensor<7; sensor++)
{//read LQI value for RX output
uint8_t index = 9+(4*sensor);
if(packet[index]==AFHDS2A_SENSOR_RX_ERR_RATE && packet[index+2]<=100)
{
RX_LQI=packet[index+2];
break;
}
#endif
}
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
AFHDS2A_update_telemetry();
#endif
@@ -416,6 +437,10 @@ uint16_t initAFHDS2A()
rx_id[i]=eeprom_read_byte((EE_ADDR)(addr+i));
}
hopping_frequency_no = 0;
if(sub_protocol&0x04)
num_ch=17;
else
num_ch=14;
return 50000;
}
#endif

View File

@@ -126,8 +126,6 @@ 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:

View File

@@ -20,7 +20,8 @@ Multiprotocol is distributed in the hope that it will be useful,
#include "iface_nrf24l01.h"
#define BAYANG_BIND_COUNT 1000
#define BAYANG_PACKET_PERIOD 1000
#define BAYANG_PACKET_PERIOD 2000
#define BAYANG_PACKET_TELEM_PERIOD 5000
#define BAYANG_INITIAL_WAIT 500
#define BAYANG_PACKET_SIZE 15
#define BAYANG_RF_NUM_CHANNELS 4
@@ -46,10 +47,10 @@ enum BAYANG_OPTION_FLAGS {
BAYANG_OPTION_FLAG_ANALOGAUX = 0x02,
};
static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
static void __attribute__((unused)) BAYANG_send_packet()
{
uint8_t i;
if (bind)
if (IS_BIND_IN_PROGRESS)
{
#ifdef BAYANG_HUB_TELEMETRY
if(option & BAYANG_OPTION_FLAG_TELEMETRY)
@@ -66,12 +67,16 @@ static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
else
#endif
packet[0]= 0xA4;
if(sub_protocol==QX100)
packet[0] = 0x53;
for(i=0;i<5;i++)
packet[i+1]=rx_tx_addr[i];
for(i=0;i<4;i++)
packet[i+6]=hopping_frequency[i];
switch (sub_protocol)
{
case QX100:
case X16_AH:
packet[10] = 0x00;
packet[11] = 0x00;
@@ -160,6 +165,7 @@ static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
packet[12] = rx_tx_addr[2]; // txid[2]
packet[13] = 0x34;
break;
case QX100:
case X16_AH:
packet[12] = 0;
packet[13] = 0;
@@ -186,29 +192,15 @@ static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
for (uint8_t i=0; i < BAYANG_PACKET_SIZE-1; i++)
packet[14] += packet[i];
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? rf_ch_num:hopping_frequency[hopping_frequency_no++]);
NRF24L01_WriteReg(NRF24L01_05_RF_CH, IS_BIND_IN_PROGRESS ? 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
NRF24L01_FlushTx();
NRF24L01_SetTxRxMode(TX_EN);
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
XN297_WritePayload(packet, BAYANG_PACKET_SIZE);
NRF24L01_SetPower(); // Set tx_power
}
@@ -233,7 +225,8 @@ static void __attribute__((unused)) BAYANG_check_rx(void)
// compensated battery volts*100/2
v_lipo2 = (packet[5]<<7) + (packet[6]>>2);
// reception in packets / sec
RX_RSSI = packet[7];
RX_LQI = packet[7];
RX_RSSI = RX_LQI;
//Flags
//uint8_t flags = packet[3] >> 3;
// battery low: flags & 1
@@ -242,6 +235,7 @@ static void __attribute__((unused)) BAYANG_check_rx(void)
telemetry_link=1;
}
}
NRF24L01_SetTxRxMode(TXRX_OFF);
}
#endif
@@ -278,58 +272,73 @@ static void __attribute__((unused)) BAYANG_init()
}
}
enum {
BAYANG_BIND=0,
BAYANG_WRITE,
BAYANG_CHECK,
BAYANG_READ,
};
#define BAYANG_CHECK_DELAY 1000 // Time after write phase to check write complete
#define BAYANG_READ_DELAY 600 // Time before read phase
uint16_t BAYANG_callback()
{
if(IS_BIND_DONE)
#ifdef BAYANG_HUB_TELEMETRY
uint16_t start;
#endif
switch(phase)
{
if(packet_count==0)
{
#ifdef MULTI_SYNC
telemetry_set_input_sync((option & BAYANG_OPTION_FLAG_TELEMETRY)?5*BAYANG_PACKET_PERIOD:2*BAYANG_PACKET_PERIOD);
#endif
BAYANG_send_packet(0);
}
packet_count++;
#ifdef BAYANG_HUB_TELEMETRY
if (option & BAYANG_OPTION_FLAG_TELEMETRY)
{ // telemetry is enabled
state++;
if (state > 1000)
{
//calculate telemetry reception packet rate - packets per 1000ms
TX_RSSI = telemetry_counter;
telemetry_counter = 0;
state = 0;
telemetry_lost=0;
}
if (packet_count > 1)
BAYANG_check_rx();
packet_count %= 5;
case BAYANG_BIND:
if (--bind_counter == 0)
{
XN297_SetTXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
#ifdef BAYANG_HUB_TELEMETRY
XN297_SetRXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
#endif
BIND_DONE;
phase++; //WRITE
}
else
#endif
packet_count%=2;
}
else
{
if (bind_counter == 0)
{
XN297_SetTXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
#ifdef BAYANG_HUB_TELEMETRY
XN297_SetRXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
BAYANG_send_packet();
break;
case BAYANG_WRITE:
#ifdef MULTI_SYNC
telemetry_set_input_sync((option & BAYANG_OPTION_FLAG_TELEMETRY)?BAYANG_PACKET_TELEM_PERIOD:BAYANG_PACKET_PERIOD);
#endif
BIND_DONE;
}
else
{
if(packet_count==0)
BAYANG_send_packet(1);
packet_count++;
packet_count%=4;
bind_counter--;
}
BAYANG_send_packet();
#ifdef BAYANG_HUB_TELEMETRY
if (option & BAYANG_OPTION_FLAG_TELEMETRY)
{ // telemetry is enabled
state++;
if (state > 200)
{
state = 0;
//telemetry reception packet rate - packets per second
TX_LQI = telemetry_counter>>1;
telemetry_counter = 0;
telemetry_lost=0;
}
phase++; //CHECK
return BAYANG_CHECK_DELAY;
}
#endif
break;
#ifdef BAYANG_HUB_TELEMETRY
case BAYANG_CHECK:
// switch radio to rx as soon as packet is sent
start=(uint16_t)micros();
while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 1000) // Wait max 1ms
if((NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS)))
break;
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x03);
phase++; // READ
return BAYANG_PACKET_TELEM_PERIOD - BAYANG_CHECK_DELAY - BAYANG_READ_DELAY;
case BAYANG_READ:
BAYANG_check_rx();
phase=BAYANG_WRITE;
return BAYANG_READ_DELAY;
#endif
}
return BAYANG_PACKET_PERIOD;
}
@@ -350,6 +359,7 @@ static void __attribute__((unused)) BAYANG_initialize_txid()
uint16_t initBAYANG(void)
{
BIND_IN_PROGRESS; // autobind protocol
phase=BAYANG_BIND;
bind_counter = BAYANG_BIND_COUNT;
BAYANG_initialize_txid();
BAYANG_init();

View File

@@ -150,6 +150,11 @@ void CC2500_SetPower()
#else
power=CC2500_HIGH_POWER;
#endif
if(IS_LBT_POWER_on)
{
power=CC2500_LBT_POWER;
LBT_POWER_off; // Only accept once
}
if(IS_RANGE_FLAG_on)
power=CC2500_RANGE_POWER;
if(prev_power != power)

View File

@@ -284,7 +284,7 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin
}
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
CYRF_SetTxRxMode(TX_EN);
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Clear abort RX
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX
}
#if defined(DEVO_CYRF6936_INO) || defined(J6PRO_CYRF6936_INO)
@@ -313,6 +313,7 @@ const uint8_t PROGMEM DEVO_j6pro_sopcodes[][8] = {
#endif
};
#endif
static void __attribute__((unused)) CYRF_PROGMEM_ConfigSOPCode(const uint8_t *data)
{
uint8_t code[8];

View File

@@ -140,3 +140,25 @@ uint16_t convert_channel_frsky(uint8_t num)
uint16_t val=Channel_data[num];
return ((val*15)>>4)+1290;
}
// 0-2047, 0 = 817, 1024 = 1500, 2047 = 2182
//64=860,1024=1500,1984=2140//Taranis 125%
static uint16_t __attribute__((unused)) FrSkyX_scaleForPXX( uint8_t i, uint8_t num_chan=8)
{ //mapped 860,2140(125%) range to 64,1984(PXX values);
uint16_t chan_val=convert_channel_frsky(i)-1226;
if(i>=num_chan) chan_val|=2048; // upper channels offset
return chan_val;
}
#ifdef FAILSAFE_ENABLE
static uint16_t __attribute__((unused)) FrSkyX_scaleForPXX_FS( uint8_t i )
{ //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

182
Multiprotocol/DSM.ino Normal file
View File

@@ -0,0 +1,182 @@
#if defined(DSM_CYRF6936_INO) || defined(DSM_RX_CYRF6936_INO)
#include "iface_cyrf6936.h"
uint8_t sop_col;
const uint8_t PROGMEM DSM_pncodes[5][9][8] = {
/* Note these are in order transmitted (LSB 1st) */
{ /* Row 0 */
/* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8},
/* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6},
/* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9},
/* Col 3 */ {0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4},
/* Col 4 */ {0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0},
/* Col 5 */ {0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8},
/* Col 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D},
/* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1},
/* Col 8 */ {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86}
},
{ /* Row 1 */
/* Col 0 */ {0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3},
/* Col 1 */ {0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9},
/* Col 2 */ {0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82},
/* Col 3 */ {0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB},
/* Col 4 */ {0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7},
/* Col 5 */ {0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95},
/* Col 6 */ {0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4},
/* Col 7 */ {0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF},
/* Col 8 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97}
},
{ /* Row 2 */
/* Col 0 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97},
/* Col 1 */ {0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA},
/* Col 2 */ {0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE},
/* Col 3 */ {0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD},
/* Col 4 */ {0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD},
/* Col 5 */ {0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9},
/* Col 6 */ {0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3},
/* Col 7 */ {0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0},
/* Col 8 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E}
},
{ /* Row 3 */
/* Col 0 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E},
/* Col 1 */ {0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7},
/* Col 2 */ {0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1},
/* Col 3 */ {0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4},
/* Col 4 */ {0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6},
/* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80},
/* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88},
/* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88},
/* Col 8 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}
// Wrong values used by Orange TX/RX
// /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40}
},
{ /* Row 4 */
/* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93},
/* Col 1 */ {0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C},
/* Col 2 */ {0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA},
/* Col 3 */ {0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC},
/* Col 4 */ {0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84},
/* Col 5 */ {0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7},
/* Col 6 */ {0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0},
/* Col 7 */ {0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1},
/* Col 8 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}
},
};
static void __attribute__((unused)) DSM_read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len)
{
for(uint8_t i=0;i<len;i++)
buf[i]=pgm_read_byte_near( &DSM_pncodes[row][col][i] );
}
const uint8_t PROGMEM DSM_init_vals[][2] = {
{CYRF_02_TX_CTRL, 0x00}, // All TX interrupt disabled
{CYRF_05_RX_CTRL, 0x00}, // All RX interrupt disabled
{CYRF_28_CLK_EN, 0x02}, // Force receive clock enable
{CYRF_32_AUTO_CAL_TIME, 0x3c}, // Default init value
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
{CYRF_26_XTAL_CFG, 0x08}, // Start delay
{CYRF_06_RX_CFG, 0x4A}, // LNA enabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
{CYRF_1B_TX_OFFSET_LSB, 0x55}, // Default init value
{CYRF_1C_TX_OFFSET_MSB, 0x05}, // Default init value
{CYRF_39_ANALOG_CTRL, 0x01}, // All slow for synth setting time
{CYRF_01_TX_LENGTH, 0x10}, // 16 bytes packet
{CYRF_14_EOP_CTRL, 0x02}, // Set EOP Symbol Count to 2
{CYRF_12_DATA64_THOLD, 0x0a}, // 64 Chip Data PN corelator threshold, default datasheet value is 0x0E
//Below is for bind only
{CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //64 chip codes, SDR mode
{CYRF_10_FRAMING_CFG, 0x4a}, // SOP disabled, no LEN field and SOP correlator of 0x0a but since SOP is disabled...
{CYRF_1F_TX_OVERRIDE, 0x04}, // Disable TX CRC, no ACK, use TX synthesizer
{CYRF_1E_RX_OVERRIDE, 0x14}, // Disable RX CRC, Force receive data rate, use RX synthesizer
};
const uint8_t PROGMEM DSM_data_vals[][2] = {
{CYRF_29_RX_ABORT, 0x20}, // Abort RX operation in case we are coming from bind
{CYRF_0F_XACT_CFG, 0x24}, // Force Idle
{CYRF_29_RX_ABORT, 0x00}, // Clear abort RX
{CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER}, // 64 chip codes, 8DR mode
{CYRF_10_FRAMING_CFG, 0xea}, // SOP enabled, SOP_CODE_ADR 64 chips, Packet len enabled, SOP correlator 0x0A
{CYRF_1F_TX_OVERRIDE, 0x00}, // CRC16 enabled, no ACK
{CYRF_1E_RX_OVERRIDE, 0x00}, // CRC16 enabled, no ACK
};
static void __attribute__((unused)) DSM_cyrf_config()
{
for(uint8_t i = 0; i < sizeof(DSM_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&DSM_init_vals[i][0]), pgm_read_byte_near(&DSM_init_vals[i][1]));
CYRF_WritePreamble(0x333304);
}
static void __attribute__((unused)) DSM_cyrf_configdata()
{
for(uint8_t i = 0; i < sizeof(DSM_data_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&DSM_data_vals[i][0]), pgm_read_byte_near(&DSM_data_vals[i][1]));
}
static uint8_t __attribute__((unused)) DSM_get_pn_row(uint8_t channel, bool dsmx)
{
return (dsmx ? (channel - 2) % 5 : channel % 5);
}
static void __attribute__((unused)) DSM_set_sop_data_crc(bool ch2, bool dsmx)
{
//The crc for channel '1' is NOT(mfgid[0] << 8 + mfgid[1])
//The crc for channel '2' is (mfgid[0] << 8 + mfgid[1])
if(ch2)
CYRF_ConfigCRCSeed(seed); //CH2
else
CYRF_ConfigCRCSeed(~seed); //CH1
uint8_t pn_row = DSM_get_pn_row(hopping_frequency[hopping_frequency_no], dsmx);
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(dsmx)
hopping_frequency_no %=23;
else
hopping_frequency_no %=2;
}
static void __attribute__((unused)) DSM_calc_dsmx_channel()
{
uint8_t idx = 0;
uint32_t id = ~(((uint32_t)cyrfmfg_id[0] << 24) | ((uint32_t)cyrfmfg_id[1] << 16) | ((uint32_t)cyrfmfg_id[2] << 8) | (cyrfmfg_id[3] << 0));
uint32_t id_tmp = id;
while(idx < 23)
{
uint8_t i;
uint8_t count_3_27 = 0, count_28_51 = 0, count_52_76 = 0;
id_tmp = id_tmp * 0x0019660D + 0x3C6EF35F; // Randomization
uint8_t next_ch = ((id_tmp >> 8) % 0x49) + 3; // Use least-significant byte and must be larger than 3
if ( (next_ch ^ cyrfmfg_id[3]) & 0x01 )
continue;
for (i = 0; i < idx; i++)
{
if(hopping_frequency[i] == next_ch)
break;
if(hopping_frequency[i] <= 27)
count_3_27++;
else
if (hopping_frequency[i] <= 51)
count_28_51++;
else
count_52_76++;
}
if (i != idx)
continue;
if ((next_ch < 28 && count_3_27 < 8)
||(next_ch >= 28 && next_ch < 52 && count_28_51 < 7)
||(next_ch >= 52 && count_52_76 < 8))
hopping_frequency[idx++] = next_ch;
}
}
#endif

View File

@@ -0,0 +1,505 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(DSM_RX_CYRF6936_INO)
#include "iface_cyrf6936.h"
//#define DSM_DEBUG_RF
//#define DSM_DEBUG_CH
uint8_t DSM_rx_type;
enum {
DSM_RX_BIND1 = 0,
DSM_RX_BIND2,
DSM_RX_DATA_PREP,
DSM2_RX_SCAN,
DSM_RX_DATA_CH1,
DSM_RX_DATA_CH2,
};
static void __attribute__((unused)) DSM_Rx_init()
{
DSM_cyrf_config();
rx_disable_lna = IS_POWER_FLAG_on;
if(IS_BIND_IN_PROGRESS)
{
//64 SDR Mode is configured so only the 8 first values are needed but need to write 16 values...
uint8_t code[16];
DSM_read_code(code,0,8,8);
CYRF_ConfigDataCode(code, 16);
CYRF_ConfigRFChannel(1);
CYRF_SetTxRxMode(RX_EN); // Force end state read
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive
}
else
{
DSM_cyrf_configdata();
CYRF_WriteRegister(CYRF_06_RX_CFG, rx_disable_lna ? 0x0A:0x4A); // AGC disabled, LNA disabled/enabled, Attenuator disabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
}
}
uint16_t convert_channel_DSM_nolimit(int32_t val)
{
val=(val-0x150)*(CHANNEL_MAX_100-CHANNEL_MIN_100)/(0x6B0-0x150)+CHANNEL_MIN_100;
if(val<0)
val=0;
else
if(val>2047)
val=2047;
return (uint16_t)val;
}
static uint8_t __attribute__((unused)) DSM_Rx_check_packet()
{
uint8_t rx_status=CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_status & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
rx_status |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_status & 0x07) == 0x02)
{ // data received with no errors
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
#ifdef DSM_DEBUG_RF
debugln("l=%d",len);
#endif
if(len>=2 && len<=16)
{
// Read packet
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // Need to set RXOW before data read
CYRF_ReadDataPacketLen(packet, len);
// Check packet ID
if ((DSM_rx_type&0x80) == 0)
{//DSM2
packet[0] ^= 0xff;
packet[1] ^= 0xff;
}
#ifdef DSM_DEBUG_CH
for(uint8_t i=0;i<len;i++)
debug("%02X ",packet[i]);
debugln("");
#endif
if(packet[0] == cyrfmfg_id[2] && packet[1] == cyrfmfg_id[3])
return 0x02; // Packet ok
}
return 0x00; // Wrong size or ID -> nothing received
}
return rx_status; // Return error code
}
static void __attribute__((unused)) DSM_Rx_build_telemetry_packet()
{
uint8_t nbr_bits = 11;
if((DSM_rx_type&0xF0) == 0x00)
nbr_bits=10; // Only DSM_22 is using a resolution of 1024
// Use packet length to calculate the number of channels
len -= 2; // Remove header length
len >>= 1; // Channels are on 2 bytes
if(len==0) return; // No channels...
// Extract channels
uint8_t idx;
for (uint8_t i = 0; i < len; i++)
{
uint16_t value=(packet[i*2+2]<<8) | packet[i*2+3];
if(value!=0xFFFF)
{
idx=(value&0x7FFF)>>nbr_bits; // retrieve channel index
#ifdef DSM_DEBUG_CH
debugln("i=%d,v=%d,u=%X",idx,value&0x7FF,value&0x8000);
#endif
if(idx<13)
{
if(nbr_bits==10) value <<= 1; // switch to 11 bits
value &= 0x7FF;
rx_rc_chan[CH_TAER[idx]]=convert_channel_DSM_nolimit(value);
}
}
}
// Buid telemetry packet
idx=0;
packet_in[idx++] = RX_LQI;
packet_in[idx++] = RX_LQI;
packet_in[idx++] = 0; // start channel
packet_in[idx++] = 12; // number of channels in packet
// Pack channels
uint32_t bits = 0;
uint8_t bitsavailable = 0;
for (uint8_t i = 0; i < 12; i++)
{
bits |= ((uint32_t)rx_rc_chan[i]) << bitsavailable;
bitsavailable += 11;
while (bitsavailable >= 8)
{
packet_in[idx++] = bits & 0xff;
bits >>= 8;
bitsavailable -= 8;
}
}
if(bitsavailable)
packet_in[idx++] = bits & 0xff;
// Send telemetry
telemetry_link = 1;
}
static bool __attribute__((unused)) DSM_Rx_bind_check_validity()
{
uint16_t sum = 384 - 0x10;//
for(uint8_t i = 0; i < 8; i++)
sum += packet_in[i];
if( packet_in[8] != (sum>>8) || packet_in[9] != (sum&0xFF)) //Checksum
return false;
for(uint8_t i = 8; i < 14; i++)
sum += packet_in[i];
if( packet_in[14] != (sum>>8) || packet_in[15] != (sum&0xFF)) //Checksum
return false;
if(memcmp(packet_in,packet_in+4,4)) //Check ID
return false;
return true;
}
static void __attribute__((unused)) DSM_Rx_build_bind_packet()
{
uint16_t sum = 384 - 0x10;//
packet[0] = 0xff ^ cyrfmfg_id[0]; // ID
packet[1] = 0xff ^ cyrfmfg_id[1];
packet[2] = 0xff ^ cyrfmfg_id[2];
packet[3] = 0xff ^ cyrfmfg_id[3];
packet[4] = 0x01; // RX version
packet[5] = num_ch; // Number of channels
packet[6] = DSM_rx_type; // DSM type, let's just send back whatever the TX gave us...
packet[7] = 0x00; // Unknown
for(uint8_t i = 0; i < 8; i++)
sum += packet[i];
packet[8] = sum >> 8;
packet[9] = sum & 0xff;
}
static void __attribute__((unused)) DSM_abort_channel_rx(uint8_t ch)
{
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
CYRF_SetTxRxMode(IS_POWER_FLAG_on ? TXRX_OFF:RX_EN); // Force end state read
if (rx_disable_lna != IS_POWER_FLAG_on && IS_BIND_DONE)
{
rx_disable_lna = IS_POWER_FLAG_on;
CYRF_WriteRegister(CYRF_06_RX_CFG, rx_disable_lna ? 0x0A:0x4A); // AGC disabled, LNA disabled/enabled, Attenuator disabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
}
if(ch&0x02) DSM_set_sop_data_crc(true ,DSM_rx_type&0x80); // Set sop data,crc seed and rf channel using CH1, DSM2/X
if(ch&0x01) DSM_set_sop_data_crc(false,DSM_rx_type&0x80); // Set sop data,crc seed and rf channel using CH1, DSM2/X
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive
}
uint16_t DSM_Rx_callback()
{
uint8_t rx_status;
static uint8_t read_retry=0;
switch (phase)
{
case DSM_RX_BIND1:
if(IS_BIND_DONE) // Abort bind
{
phase = DSM_RX_DATA_PREP;
break;
}
if(packet_count==0)
read_retry=0;
//Check received data
rx_status = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_status & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
rx_status |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_status & 0x07) == 0x02)
{ // data received with no errors
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // Need to set RXOW before data read
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
debugln("RX:%d, CH:%d",len,hopping_frequency_no);
if(len==16)
{
CYRF_ReadDataPacketLen(packet_in, 16);
if(DSM_Rx_bind_check_validity())
{
// store tx info into eeprom
uint16_t temp = DSM_RX_EEPROM_OFFSET;
debug("ID=");
for(uint8_t i=0;i<4;i++)
{
cyrfmfg_id[i]=packet_in[i]^0xFF;
eeprom_write_byte((EE_ADDR)temp++, cyrfmfg_id[i]);
debug(" %02X", cyrfmfg_id[i]);
}
// check num_ch
num_ch=packet_in[11];
if(num_ch>12) num_ch=12;
//check DSM_rx_type
/*packet[12] 1 byte -> max DSM type allowed:
0x01 => 22ms 1024 DSM2 1 packet => number of channels is <8
0x02 => 22ms 1024 DSM2 2 packets => either a number of channel >7
0x12 => 11ms 2048 DSM2 2 packets => can be any number of channels
0xA2 => 22ms 2048 DSMX 1 packet => number of channels is <8
0xB2 => 11ms 2048 DSMX => can be any number of channels
(0x01 or 0xA2) and num_ch < 7 => 22ms else 11ms
&0x80 => false=DSM2, true=DSMX
&0xF0 => false=1024, true=2048 */
DSM_rx_type=packet_in[12];
switch(DSM_rx_type)
{
case 0x01:
if(num_ch>7) DSM_rx_type = 0x02; // Can't be 0x01 with this number of channels
break;
case 0xA2:
if(num_ch>7) DSM_rx_type = 0xB2; // Can't be 0xA2 with this number of channels
break;
case 0x02:
case 0x12:
case 0xB2:
break;
default: // Unknown type, default to DSMX 11ms
DSM_rx_type = 0xB2;
break;
}
eeprom_write_byte((EE_ADDR)temp, DSM_rx_type);
debugln(", num_ch=%d, type=%02X",num_ch, DSM_rx_type);
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
CYRF_SetTxRxMode(TX_EN); // Force end state TX
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84", 16);
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX
DSM_Rx_build_bind_packet();
bind_counter=500;
phase++; // DSM_RX_BIND2;
return 1000;
}
}
DSM_abort_channel_rx(0); // Abort RX operation and receive
if(read_retry==0)
read_retry=8;
}
else
if(rx_status & 0x02) // RX error
DSM_abort_channel_rx(0); // Abort RX operation and receive
packet_count++;
if(packet_count>12)
{
packet_count=1;
if(read_retry)
read_retry--;
if(read_retry==0)
{
packet_count=0;
hopping_frequency_no++; // Change channel
hopping_frequency_no %= 0x50;
hopping_frequency_no |= 0x01; // Odd channels only
CYRF_ConfigRFChannel(hopping_frequency_no);
DSM_abort_channel_rx(0); // Abort RX operation and receive
}
}
return 1000;
case DSM_RX_BIND2:
//Transmit settings back
CYRF_WriteDataPacketLen(packet,10); // Send packet
if(bind_counter--==0)
{
BIND_DONE;
phase++; // DSM_RX_DATA_PREP
}
break;
case DSM_RX_DATA_PREP:
hopping_frequency_no = 0;
read_retry=0;
rx_data_started = false;
pps_counter = 0;
RX_LQI = 100;
DSM_cyrf_configdata();
pps_timer=millis();
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
seed = (cyrfmfg_id[0] << 8) + cyrfmfg_id[1];
if(DSM_rx_type&0x80)
{ // DSMX
DSM_calc_dsmx_channel(); // Build hop table
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
phase=DSM_RX_DATA_CH1;
}
else
{ // DSM2
rf_ch_num=0;
hopping_frequency_no = 0;
hopping_frequency[0] = 3;
hopping_frequency[1] = 0;
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
phase=DSM2_RX_SCAN;
}
break;
case DSM2_RX_SCAN: // Scan for DSM2 frequencies
//Received something ?
rx_status = DSM_Rx_check_packet();
if(rx_status == 0x02)
{ // data received with no errors
debugln("CH%d:Found %d",rf_ch_num+1,hopping_frequency[rf_ch_num]);
read_retry=0;
if(rf_ch_num)
{ // Both CH1 and CH2 found
read_retry=0;
hopping_frequency_no=0;
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
pps_timer=millis();
phase++; // DSM_RX_DATA_CH1
}
else
{
rf_ch_num++; // CH1 found, scan for CH2
hopping_frequency_no = 1;
if(hopping_frequency[1] < 3) // If no CH2 keep then restart from current
hopping_frequency[1]=hopping_frequency[0]+1;
DSM_abort_channel_rx(2); // Abort RX operation, set sop&data&seed&rf using CH2, DSM2/X and receive
}
}
else
{
read_retry++;
if(read_retry>50) // After 50ms
{ // Try next channel
debugln("CH%d:Next channel",rf_ch_num+1);
read_retry=0;
hopping_frequency_no = rf_ch_num;
hopping_frequency[rf_ch_num]++;
if(hopping_frequency[rf_ch_num] > 73) hopping_frequency[rf_ch_num] = 3;
DSM_abort_channel_rx(rf_ch_num+1); // Abort RX operation, set sop&data&seed&rf using CH1/2, DSM2/X and receive
}
else if(rx_status & 0x02)
{ // data received with errors
if((rx_status & 0x01) && rf_ch_num==0)
hopping_frequency[1] = hopping_frequency[0];// Might be CH2 since it's a CRC error so keep it
debugln("CH%d:RX error",rf_ch_num+1);
DSM_abort_channel_rx(0); // Abort RX operation and receive
}
}
return 1000;
case DSM_RX_DATA_CH1:
//Packets per second
if (millis() - pps_timer >= 1000)
{//182pps @11ms, 91pps @22ms
pps_timer = millis();
if(DSM_rx_type!=0xA2 && DSM_rx_type!=0x01) // if 11ms
pps_counter >>=1; // then /2
debugln("%d pps", pps_counter);
RX_LQI = pps_counter; // max=91pps
pps_counter = 0;
}
//Received something ?
rx_status = DSM_Rx_check_packet();
if(rx_status == 0x02)
{ // data received with no errors
#ifdef DSM_DEBUG_RF
debugln("CH1:RX");
#endif
DSM_Rx_build_telemetry_packet();
rx_data_started = true;
pps_counter++;
DSM_abort_channel_rx(2); // Abort RX operation, set sop&data&seed&rf using CH2, DSM2/X and receive
phase++;
return 5000;
}
else
{
read_retry++;
if(rx_data_started && read_retry>6) // After 6*500=3ms
{ // skip to CH2
#ifdef DSM_DEBUG_RF
debugln("CH1:Skip to CH2");
#endif
DSM_abort_channel_rx(2); // Abort RX operation, set sop&data&seed&rf using CH2, DSM2/X and receive
phase++;
return 4000;
}
if(rx_data_started && RX_LQI==0)
{ // communication lost
#ifdef DSM_DEBUG_RF
debugln("CH1:Restart...");
#endif
phase=DSM_RX_DATA_PREP;
return 1000;
}
if(read_retry>250)
{ // move to next RF channel
#ifdef DSM_DEBUG_RF
debugln("CH1:Scan");
#endif
DSM_abort_channel_rx(3); // Abort RX operation, set sop&data&seed&rf using CH2 then CH1, DSM2/X and receive
read_retry=0;
}
else if(rx_status & 0x02)
{ // data received with errors
#ifdef DSM_DEBUG_RF
debugln("CH1:RX error %02X",rx_status);
#endif
DSM_abort_channel_rx(0); // Abort RX operation and receive
}
}
return 500;
case DSM_RX_DATA_CH2:
rx_status = DSM_Rx_check_packet();
if(rx_status == 0x02)
{ // data received with no errors
#ifdef DSM_DEBUG_RF
debugln("CH2:RX");
#endif
DSM_Rx_build_telemetry_packet();
pps_counter++;
}
#ifdef DSM_DEBUG_RF
else
debugln("CH2:No RX");
#endif
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
read_retry=0;
phase=DSM_RX_DATA_CH1;
if(DSM_rx_type==0xA2) //|| DSM_rx_type==0x01 -> not needed for DSM2 since we are ok to listen even if there will be nothing
return 15000; //22ms
else
return 4000; //11ms
}
return 10000;
}
uint16_t initDSM_Rx()
{
DSM_Rx_init();
hopping_frequency_no = 0;
if (IS_BIND_IN_PROGRESS)
{
packet_count=0;
phase = DSM_RX_BIND1;
}
else
{
uint16_t temp = DSM_RX_EEPROM_OFFSET;
debug("ID=");
for(uint8_t i=0;i<4;i++)
{
cyrfmfg_id[i]=eeprom_read_byte((EE_ADDR)temp++);
debug(" %02X", cyrfmfg_id[i]);
}
DSM_rx_type=eeprom_read_byte((EE_ADDR)temp);
debugln(", type=%02X", DSM_rx_type);
phase = DSM_RX_DATA_PREP;
}
return 15000;
}
#endif

View File

@@ -17,6 +17,8 @@
#include "iface_cyrf6936.h"
//#define DSM_GR300
#define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel
//During binding we will send BIND_COUNT/2 packets
@@ -41,10 +43,10 @@ enum {
};
//
uint8_t sop_col;
uint8_t ch_map[14];
const uint8_t PROGMEM DSM_ch_map_progmem[][14] = {
//22+11ms for 4..7 channels
//22+11ms for 3..7 channels
{1, 0, 2, 0xff, 0xff, 0xff, 0xff, 1, 0, 2, 0xff, 0xff, 0xff, 0xff}, //3ch - Guess
{1, 0, 2, 3, 0xff, 0xff, 0xff, 1, 0, 2, 3, 0xff, 0xff, 0xff}, //4ch - Guess
{1, 0, 2, 3, 4, 0xff, 0xff, 1, 0, 2, 3, 4, 0xff, 0xff}, //5ch - Guess
{1, 5, 2, 3, 0, 4, 0xff, 1, 5, 2, 3, 0, 4, 0xff}, //6ch - HP6DSM
@@ -54,123 +56,14 @@ const uint8_t PROGMEM DSM_ch_map_progmem[][14] = {
{1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 8, 0xff, 0xff, 0xff}, //9ch - Guess
{1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 8, 9, 0xff, 0xff}, //10ch - Guess
{1, 5, 2, 3, 6, 10, 0xff, 4, 0, 7, 8, 9, 0xff, 0xff}, //11ch - Guess
{1, 5, 2, 4, 6, 10, 0xff, 0, 7, 3, 8, 9 , 11 , 0xff}, //12ch - DX18
//11ms for 8..12 channels
{1, 5, 2, 4, 6, 10, 0xff, 0, 7, 3, 8, 9 , 11 , 0xff}, //12ch - DX18/DX8G2
//11ms for 8..11 channels
{1, 5, 2, 3, 6, 7, 0xff, 1, 5, 2, 4, 0, 0xff, 0xff}, //8ch - DX7
{1, 5, 2, 3, 6, 7, 0xff, 1, 5, 2, 4, 0, 8, 0xff}, //9ch - Guess
{1, 5, 2, 3, 4, 8, 9, 1, 5, 2, 3, 0, 7, 6 }, //10ch - DX18
{1, 5, 2, 3, 4, 8, 9, 1, 5, 2, 3, 0, 7, 6 }, //10ch - DX18
{1, 5, 2, 3, 4, 8, 9, 1, 10, 2, 3, 0, 7, 6 }, //11ch - Guess
};
const uint8_t PROGMEM DSM_pncodes[5][8][8] = {
/* Note these are in order transmitted (LSB 1st) */
{ /* Row 0 */
/* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8},
/* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6},
/* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9},
/* Col 3 */ {0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4},
/* Col 4 */ {0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0},
/* Col 5 */ {0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8},
/* Col 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D},
/* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1},
/* Col 8 {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86}*/
},
{ /* Row 1 */
/* Col 0 */ {0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3},
/* Col 1 */ {0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9},
/* Col 2 */ {0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82},
/* Col 3 */ {0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB},
/* Col 4 */ {0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7},
/* Col 5 */ {0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95},
/* Col 6 */ {0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4},
/* Col 7 */ {0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF},
/* Col 8 {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97} */
},
{ /* Row 2 */
/* Col 0 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97},
/* Col 1 */ {0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA},
/* Col 2 */ {0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE},
/* Col 3 */ {0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD},
/* Col 4 */ {0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD},
/* Col 5 */ {0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9},
/* Col 6 */ {0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3},
/* Col 7 */ {0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0},
/* Col 8 {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E} */
},
{ /* Row 3 */
/* Col 0 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E},
/* Col 1 */ {0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7},
/* Col 2 */ {0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1},
/* Col 3 */ {0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4},
/* Col 4 */ {0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6},
/* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80},
/* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88},
/* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88},
/* Col 8 {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93} */
// Wrong values used by Orange TX/RX
// /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40}
},
{ /* Row 4 */
/* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93},
/* Col 1 */ {0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C},
/* Col 2 */ {0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA},
/* Col 3 */ {0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC},
/* Col 4 */ {0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84},
/* Col 5 */ {0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7},
/* Col 6 */ {0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0},
/* Col 7 */ {0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1},
/* Col 8 {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8} */
},
};
static void __attribute__((unused)) DSM_read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len)
{
for(uint8_t i=0;i<len;i++)
buf[i]=pgm_read_byte_near( &DSM_pncodes[row][col][i] );
}
static uint8_t __attribute__((unused)) DSM_get_pn_row(uint8_t channel)
{
return ((sub_protocol == DSMX_11 || sub_protocol == DSMX_22 )? (channel - 2) % 5 : channel % 5);
}
const uint8_t PROGMEM DSM_init_vals[][2] = {
{CYRF_02_TX_CTRL, 0x00}, // All TX interrupt disabled
{CYRF_05_RX_CTRL, 0x00}, // All RX interrupt disabled
{CYRF_28_CLK_EN, 0x02}, // Force receive clock enable
{CYRF_32_AUTO_CAL_TIME, 0x3c}, // Default init value
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
{CYRF_06_RX_CFG, 0x4A}, // LNA enabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
{CYRF_1B_TX_OFFSET_LSB, 0x55}, // Default init value
{CYRF_1C_TX_OFFSET_MSB, 0x05}, // Default init value
{CYRF_39_ANALOG_CTRL, 0x01}, // All slow for synth setting time
{CYRF_01_TX_LENGTH, 0x10}, // 16 bytes packet
{CYRF_14_EOP_CTRL, 0x02}, // Set EOP Symbol Count to 2
{CYRF_12_DATA64_THOLD, 0x0a}, // 64 Chip Data PN corelator threshold, default datasheet value is 0x0E
//Below is for bind only
{CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //64 chip codes, SDR mode
{CYRF_10_FRAMING_CFG, 0x4a}, // SOP disabled, no LEN field and SOP correlator of 0x0a but since SOP is disabled...
{CYRF_1F_TX_OVERRIDE, 0x04}, // Disable TX CRC, no ACK, use TX synthesizer
{CYRF_1E_RX_OVERRIDE, 0x14}, // Disable RX CRC, Force receive data rate, use RX synthesizer
};
const uint8_t PROGMEM DSM_data_vals[][2] = {
{CYRF_29_RX_ABORT, 0x20}, // Abort RX operation in case we are coming from bind
{CYRF_0F_XACT_CFG, 0x24}, // Force Idle
{CYRF_29_RX_ABORT, 0x00}, // Clear abort RX
{CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER}, // 64 chip codes, 8DR mode
{CYRF_10_FRAMING_CFG, 0xea}, // SOP enabled, SOP_CODE_ADR 64 chips, Packet len enabled, SOP correlator 0x0A
{CYRF_1F_TX_OVERRIDE, 0x00}, // CRC16 enabled, no ACK
{CYRF_1E_RX_OVERRIDE, 0x00}, // CRC16 enabled, no ACK
};
static void __attribute__((unused)) DSM_cyrf_config()
{
for(uint8_t i = 0; i < sizeof(DSM_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&DSM_init_vals[i][0]), pgm_read_byte_near(&DSM_init_vals[i][1]));
CYRF_WritePreamble(0x333304);
CYRF_ConfigRFChannel(0x61);
}
static void __attribute__((unused)) DSM_build_bind_packet()
{
uint8_t i;
@@ -187,23 +80,26 @@ static void __attribute__((unused)) DSM_build_bind_packet()
sum += packet[i];
packet[8] = sum >> 8;
packet[9] = sum & 0xff;
packet[10] = 0x01; //???
packet[11] = num_ch;
packet[10] = 0x01; // ???
if(sub_protocol==DSM_AUTO)
packet[11] = 12;
else
packet[11] = num_ch;
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]=num_ch<8?0x01:0x02; // DSM2/1024 1 or 2 packets depending on the number of channels
else if(sub_protocol==DSM2_11)
packet[12]=0x12; // DSM2/2048 2 packets
if(sub_protocol==DSMX_22)
else 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
else // DSMX_11 && DSM_AUTO
packet[12]=0xb2; // DSMX/2048 2 packets
packet[13] = 0x00; //???
packet[13] = 0x00; //???
for(i = 8; i < 14; i++)
sum += packet[i];
packet[14] = sum >> 8;
@@ -214,30 +110,24 @@ static void __attribute__((unused)) DSM_initialize_bind_phase()
{
CYRF_ConfigRFChannel(DSM_BIND_CHANNEL); //This seems to be random?
//64 SDR Mode is configured so only the 8 first values are needed but need to write 16 values...
CYRF_ConfigDataCode((const uint8_t*)"\xD7\xA1\x54\xB1\x5E\x89\xAE\x86\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 16);
uint8_t code[16];
DSM_read_code(code,0,8,8);
CYRF_ConfigDataCode(code, 16);
DSM_build_bind_packet();
}
static void __attribute__((unused)) DSM_cyrf_configdata()
{
for(uint8_t i = 0; i < sizeof(DSM_data_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&DSM_data_vals[i][0]), pgm_read_byte_near(&DSM_data_vals[i][1]));
}
static void __attribute__((unused)) DSM_update_channels()
{
prev_option=option;
if(sub_protocol==DSM_AUTO)
num_ch=12; // Force 12 channels in mode Auto
else
num_ch=option & 0x7F; // Remove the Max Throw flag
if(num_ch<4 || num_ch>12)
num_ch=option & 0x0F; // Remove flags 0x80=max_throw, 0x40=11ms
if(num_ch<3 || num_ch>12)
num_ch=6; // Default to 6 channels if invalid choice...
// Create channel map based on number of channels and refresh rate
uint8_t idx=num_ch-4;
if(num_ch>7 && num_ch<11 && (sub_protocol==DSM2_11 || sub_protocol==DSMX_11))
idx+=5; // In 11ms mode change index only for channels 8..10
uint8_t idx=num_ch-3;
if((option & 0x40) && num_ch>7 && num_ch<12)
idx+=5; // In 11ms mode change index only for channels 8..11
for(uint8_t i=0;i<14;i++)
ch_map[i]=pgm_read_byte_near(&DSM_ch_map_progmem[idx][i]);
}
@@ -250,24 +140,26 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
DSM_update_channels();
if (sub_protocol==DSMX_11 || sub_protocol==DSMX_22 )
{
{//DSMX
packet[0] = cyrfmfg_id[2];
packet[1] = cyrfmfg_id[3];
}
else
{
{//DSM2
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
bits=10; // Only DSM2_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;;
uint8_t idx = ch_map[(upper?7:0) + i]; // 1,5,2,3,0,4
uint16_t value = 0xffff;
if((option&0x40) == 0 && num_ch < 8 && upper)
idx=0xff; // in 22ms do not transmit upper channels if <8, is it the right method???
if (idx != 0xff)
{
/* Spektrum own remotes transmit normal values during bind and actually use this (e.g. Nano CP X) to
@@ -275,7 +167,7 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
#ifdef DSM_THROTTLE_KILL_CH
if(idx==CH1 && kill_ch<=604)
{//Activate throttle kill only if channel is throttle and DSM_THROTTLE_KILL_CH below -50%
if(kill_ch<CHANNEL_MIN_100) // restrict val to 0...400
if(kill_ch<CHANNEL_MIN_100) // restrict val to 0...400
kill_ch=0;
else
kill_ch-=CHANNEL_MIN_100;
@@ -284,12 +176,12 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
else
#endif
#ifdef DSM_MAX_THROW
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
#else
if(option & 0x80)
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
else
value=convert_channel_16b_nolimit(CH_TAER[idx],0x150,0x6B0); // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on Redcon 6 channel DSM2 RX
value=convert_channel_16b_nolimit(CH_TAER[idx],0x156,0x6AA); // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on a DX8 G2 dump
#endif
if(bits==10) value>>=1;
value |= (upper && i==0 ? 0x8000 : 0) | (idx << bits);
@@ -299,69 +191,9 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
}
}
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
uint8_t result=1; // assume good packet
uint16_t sum = 384 - 0x10;
for(uint8_t i = 1; i < 9; i++)
@@ -369,7 +201,7 @@ static uint8_t __attribute__((unused)) DSM_Check_RX_packet()
sum += packet_in[i];
if(i<5)
if(packet_in[i] != (0xff ^ cyrfmfg_id[i-1]))
result=0; // bad packet
result=0; // bad packet
}
if( packet_in[9] != (sum>>8) && packet_in[10] != (uint8_t)sum )
result=0;
@@ -390,46 +222,62 @@ uint16_t ReadDsm()
uint8_t len;
#endif
uint8_t start;
#ifdef DSM_GR300
uint16_t timing=5000+(convert_channel_8b(CH13)*100);
debugln("T=%u",timing);
#endif
switch(phase)
{
case DSM_BIND_WRITE:
if(bind_counter--==0)
#if defined DSM_TELEMETRY
phase=DSM_BIND_CHECK; //Check RX answer
phase=DSM_BIND_CHECK; //Check RX answer
#else
phase=DSM_CHANSEL; //Switch to normal mode
phase=DSM_CHANSEL; //Switch to normal mode
#endif
CYRF_WriteDataPacket(packet);
return 10000;
#if defined DSM_TELEMETRY
case DSM_BIND_CHECK:
//64 SDR Mode is configured so only the 8 first values are needed but we need to write 16 values...
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84\xC9\x2C\x06\x93\x86\xB9\x9E\xD7", 16);
CYRF_SetTxRxMode(RX_EN); //Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //Prepare to receive
bind_counter=2*DSM_BIND_COUNT; //Timeout of 4.2s if no packet received
phase++; // change from BIND_CHECK to BIND_READ
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84", 16);
CYRF_SetTxRxMode(RX_EN); //Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //Prepare to receive
bind_counter=2*DSM_BIND_COUNT; //Timeout of 4.2s if no packet received
phase++; // change from BIND_CHECK to BIND_READ
return 2000;
case DSM_BIND_READ:
//Read data from RX
rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_phase & 0x07) == 0x02)
{ // data received with no errors
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
if(len>TELEMETRY_BUFFER_SIZE-2)
len=TELEMETRY_BUFFER_SIZE-2;
CYRF_ReadDataPacketLen(packet_in+1, len);
if(len==10 && DSM_Check_RX_packet())
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80);// Need to set RXOW before data read
if(CYRF_ReadRegister(CYRF_09_RX_COUNT)==10) // Len
{
packet_in[0]=0x80;
telemetry_link=1; // send received data on serial
phase++;
return 2000;
CYRF_ReadDataPacketLen(packet_in+1, 10);
if(DSM_Check_RX_packet())
{
debug("Bind");
for(uint8_t i=0;i<10;i++)
debug(" %02X",packet_in[i+1]);
debugln("");
packet_in[0]=0x80;
packet_in[6]&=0x0F; // It looks like there is a flag 0x40 being added by some receivers
if(packet_in[6]>12) packet_in[6]=12;
else if(packet_in[6]<3) packet_in[6]=6;
telemetry_link=1; // Send received data on serial
phase++;
return 2000;
}
}
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
CYRF_SetTxRxMode(RX_EN); // Force end state read
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive
}
else
if((rx_phase & 0x02) != 0x02)
@@ -441,7 +289,7 @@ uint16_t ReadDsm()
}
if( --bind_counter == 0 )
{ // Exit if no answer has been received for some time
phase++; // DSM_CHANSEL
phase++; // DSM_CHANSEL
return 7000 ;
}
return 7000;
@@ -452,7 +300,7 @@ uint16_t ReadDsm()
CYRF_SetTxRxMode(TX_EN);
hopping_frequency_no = 0;
phase = DSM_CH1_WRITE_A; // in fact phase++
DSM_set_sop_data_crc();
DSM_set_sop_data_crc(phase==DSM_CH1_CHECK_A||phase==DSM_CH1_CHECK_B, sub_protocol==DSMX_11||sub_protocol==DSMX_22);
return 10000;
case DSM_CH1_WRITE_A:
#ifdef MULTI_SYNC
@@ -464,6 +312,11 @@ uint16_t ReadDsm()
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);
#if 0
for(uint8_t i=0;i<16;i++)
debug(" %02X", packet[i]);
debugln("");
#endif
phase++; // change from WRITE to CHECK mode
return DSM_WRITE_DELAY;
case DSM_CH1_CHECK_A:
@@ -487,7 +340,7 @@ uint16_t ReadDsm()
CYRF_SetTxRxMode(TX_EN);
}
#endif
DSM_set_sop_data_crc();
DSM_set_sop_data_crc(phase==DSM_CH1_CHECK_A||phase==DSM_CH1_CHECK_B, sub_protocol==DSMX_11 || sub_protocol==DSMX_22);
phase++; // change from CH1_CHECK to CH2_WRITE
return DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY;
}
@@ -497,6 +350,10 @@ uint16_t ReadDsm()
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
#ifdef DSM_GR300
if(num_ch==3)
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
#endif
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
case DSM_CH2_READ_A:
case DSM_CH2_READ_B:
@@ -521,6 +378,10 @@ uint16_t ReadDsm()
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
phase = DSM_CH2_READ_B;
#ifdef DSM_GR300
if(num_ch==3)
return timing;
#endif
return 11000;
}
if (phase == DSM_CH2_READ_A)
@@ -529,11 +390,11 @@ uint16_t ReadDsm()
phase = DSM_CH1_WRITE_A; //Transmit lower
CYRF_SetTxRxMode(TX_EN); //TX mode
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); //Clear abort RX operation
DSM_set_sop_data_crc();
DSM_set_sop_data_crc(phase==DSM_CH1_CHECK_A||phase==DSM_CH1_CHECK_B, sub_protocol==DSMX_11||sub_protocol==DSMX_22);
return DSM_READ_DELAY;
#else
// No telemetry
DSM_set_sop_data_crc();
DSM_set_sop_data_crc(phase==DSM_CH1_CHECK_A||phase==DSM_CH1_CHECK_B, sub_protocol==DSMX_11||sub_protocol==DSMX_22);
if (phase == DSM_CH2_CHECK_A)
{
if(num_ch > 7 || sub_protocol==DSM2_11 || sub_protocol==DSMX_11)
@@ -541,11 +402,19 @@ uint16_t ReadDsm()
else
{ //Normal mode 22ms
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
#ifdef DSM_GR300
if(num_ch==3)
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
#endif
return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
}
}
else
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower)
#ifdef DSM_GR300
if(num_ch==3)
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
#endif
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY;
#endif
}
@@ -565,6 +434,8 @@ uint16_t initDsm()
cyrfmfg_id[rx_tx_addr[0]%3]^=0x01; //Change a bit so sop_col will be different from 0
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
}
//Calc CRC seed
seed = (cyrfmfg_id[0] << 8) + cyrfmfg_id[1];
//Hopping frequencies
if (sub_protocol == DSMX_11 || sub_protocol == DSMX_22)
DSM_calc_dsmx_channel();

View File

@@ -162,6 +162,33 @@ static void __attribute__((unused)) DEVO_build_data_pkt()
DEVO_add_pkt_suffix();
}
#if defined DEVO_HUB_TELEMETRY
static void __attribute__((unused)) DEVO_parse_telemetry_packet()
{
DEVO_scramble_pkt(); //This will unscramble the packet
debugln("RX");
if ((((uint32_t)packet[15] << 16) | ((uint32_t)packet[14] << 8) | packet[13]) != (MProtocol_id & 0x00ffffff))
return; // ID does not match
//RSSI
TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI) & 0x1F;
TX_RSSI = (TX_RSSI << 1) + TX_RSSI;
RX_RSSI = TX_RSSI;
telemetry_link = 1;
//TODO: FW telemetry https://github.com/DeviationTX/deviation/blob/5efb6a28bea697af9a61b5a0ed2528cc8d203f90/src/protocol/devo_cyrf6936.c#L232
debug("P[0]=%02X",packet[0]);
if (packet[0] == 0x30) // Volt packet
{
v_lipo1 = packet[1] << 1;
v_lipo2 = packet[3] << 1;
}
}
#endif
static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code()
{
/* crc == 0 isn't allowed, so use 1 if the math results in 0 */
@@ -270,6 +297,82 @@ static void __attribute__((unused)) DEVO_BuildPacket()
uint16_t devo_callback()
{
static uint8_t txState=0;
#if defined DEVO_HUB_TELEMETRY
int delay;
if (txState == 0)
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(2400);
#endif
DEVO_BuildPacket();
CYRF_WriteDataPacket(packet);
txState = 1;
return 900;
}
if (txState == 1)
{
int i = 0;
uint8_t reg;
while (! ((reg = CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS)) & 0x02))
{
if (++i >= DEVO_NUM_WAIT_LOOPS)
break;
}
if (((reg & 0x22) == 0x20) || (CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80))
{
CYRF_Reset();
DEVO_cyrf_init();
DEVO_cyrf_set_bound_sop_code();
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
//printf("Rst CYRF\n");
delay = 1500;
txState = 15;
}
else
{
if (phase == DEVO_BOUND)
{
/* exit binding state */
phase = DEVO_BOUND_3;
DEVO_cyrf_set_bound_sop_code();
}
if((packet_count != 0) && (bind_counter == 0))
{
CYRF_SetTxRxMode(RX_EN); //Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
txState = 2;
return 1300;
}
}
if(packet_count == 0)
{
CYRF_SetPower(0x08); //Keep tx power updated
hopping_frequency_ptr = hopping_frequency_ptr == &hopping_frequency[2] ? hopping_frequency : hopping_frequency_ptr + 1;
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
}
delay = 1500;
}
if(txState == 2)
{
uint8_t rx_state = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_state & 0x03) == 0x02)
{ // RXC=1, RXE=0 then 2nd check is required (debouncing)
rx_state |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
}
if((rx_state & 0x07) == 0x02)
{ // good data (complete with no errors)
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
CYRF_ReadDataPacketLen(packet, CYRF_ReadRegister(CYRF_09_RX_COUNT));
DEVO_parse_telemetry_packet();
}
CYRF_SetTxRxMode(TX_EN); //Write mode
delay = 200;
}
txState = 0;
return delay;
#else
if (txState == 0)
{
#ifdef MULTI_SYNC
@@ -298,6 +401,7 @@ uint16_t devo_callback()
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
}
return 1200;
#endif
}
uint16_t DevoInit()

View File

@@ -0,0 +1,141 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(ESKY150V2_CC2500_INO)
#include "iface_nrf250k.h"
//#define ESKY150V2_FORCE_ID
#define ESKY150V2_PAYLOADSIZE 40
#define ESKY150V2_BINDPAYLOADSIZE 150
#define ESKY150V2_NFREQCHANNELS 70
#define ESKY150V2_TXID_SIZE 4
#define ESKY150V2_BIND_CHANNEL 0x00
#define ESKY150V2_PACKET_PERIOD 10000
#define ESKY150V2_BINDING_PACKET_PERIOD 57000
#ifdef ESKY150V2_FORCE_ID
const uint8_t PROGMEM ESKY150V2_hop[ESKY150V2_NFREQCHANNELS]= {
0x07, 0x47, 0x09, 0x27, 0x0B, 0x42, 0x0D, 0x35, 0x17, 0x40, 0x26, 0x3D, 0x16, 0x43, 0x06, 0x2A, 0x24, 0x44,
0x0E, 0x38, 0x20, 0x48, 0x22, 0x2D, 0x2B, 0x39, 0x0F, 0x36, 0x23, 0x46, 0x14, 0x3B, 0x1A, 0x41, 0x10, 0x2E,
0x1E, 0x28, 0x0C, 0x49, 0x1D, 0x3E, 0x29, 0x2C, 0x25, 0x30, 0x1C, 0x2F, 0x1B, 0x33, 0x13, 0x31, 0x0A, 0x37,
0x12, 0x3C, 0x18, 0x4B, 0x11, 0x45, 0x21, 0x4A, 0x1F, 0x3F, 0x15, 0x32, 0x08, 0x3A, 0x19, 0x34 };
/*const uint8_t PROGMEM ESKY150V2_hop2[40]= {
0x19, 0x23, 0x13, 0x1B, 0x09, 0x22, 0x14, 0x27, 0x06, 0x26, 0x16, 0x24, 0x0B, 0x2A, 0x0E, 0x1C, 0x11, 0x1E,
0x08, 0x29, 0x0D, 0x28, 0x18, 0x2D, 0x12, 0x20, 0x0C, 0x1A, 0x10, 0x1D, 0x07, 0x2C, 0x0A, 0x2B, 0x0F, 0x25,
0x15, 0x1F, 0x17, 0x21 };*/
#endif
static void __attribute__((unused)) ESKY150V2_set_freq(void)
{
calc_fh_channels(ESKY150V2_NFREQCHANNELS);
#ifdef ESKY150V2_FORCE_ID
for(uint8_t i=0; i<ESKY150V2_NFREQCHANNELS; i++)
hopping_frequency[i]=pgm_read_byte_near( &ESKY150V2_hop[i] );
#endif
//Bind channel
hopping_frequency[ESKY150V2_NFREQCHANNELS]=ESKY150V2_BIND_CHANNEL;
//Calib all channels
NRF250K_SetFreqOffset(); // Set frequency offset
NRF250K_HoppingCalib(ESKY150V2_NFREQCHANNELS+1);
}
static void __attribute__((unused)) ESKY150V2_send_packet()
{
NRF250K_SetFreqOffset(); // Set frequency offset
NRF250K_Hopping(hopping_frequency_no);
if (++hopping_frequency_no >= ESKY150V2_NFREQCHANNELS)
hopping_frequency_no = 0;
NRF250K_SetPower(); //Set power level
packet[0] = 0xFA; // Unknown
packet[1] = 0x41; // Unknown
packet[2] = 0x08; // Unknown
packet[3] = 0x00; // Unknown
for(uint8_t i=0;i<16;i++)
{
uint16_t channel=convert_channel_16b_limit(CH_TAER[i],200,1000);
packet[4+2*i] = channel;
packet[5+2*i] = channel>>8;
}
NRF250K_WritePayload(packet, ESKY150V2_PAYLOADSIZE);
}
uint16_t ESKY150V2_callback()
{
if(option==0) option=1; //Trick the RF component auto select system
if(IS_BIND_DONE)
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(ESKY150V2_PACKET_PERIOD);
#endif
ESKY150V2_send_packet();
}
else
{
BIND_DONE; //Need full power for bind to work...
NRF250K_SetPower(); //Set power level
BIND_IN_PROGRESS;
NRF250K_WritePayload(packet, ESKY150V2_BINDPAYLOADSIZE);
if (--bind_counter == 0)
{
BIND_DONE;
// Change TX address from bind to normal mode
NRF250K_SetTXAddr(rx_tx_addr, ESKY150V2_TXID_SIZE);
memset(packet,0x00,ESKY150V2_PAYLOADSIZE);
}
return 30000; //ESKY150V2_BINDING_PACKET_PERIOD;
}
return ESKY150V2_PACKET_PERIOD;
}
uint16_t initESKY150V2()
{
if(option==0) option=1; // Trick the RF component auto select system
NRF250K_Init();
ESKY150V2_set_freq();
hopping_frequency_no = 0;
#ifdef ESKY150V2_FORCE_ID // ID taken from TX dump
rx_tx_addr[0]=0x87;rx_tx_addr[1]=0x5B;rx_tx_addr[2]=0x2C;rx_tx_addr[3]=0x5D;
#endif
memset(packet,0x00,ESKY150V2_BINDPAYLOADSIZE);
if(IS_BIND_IN_PROGRESS)
{
NRF250K_SetTXAddr((uint8_t *)"\x73\x73\x74\x63", ESKY150V2_TXID_SIZE); //Bind address
NRF250K_Hopping(ESKY150V2_NFREQCHANNELS); //Bind channel
memcpy(packet,"\x73\x73\x74\x63", ESKY150V2_TXID_SIZE);
memcpy(&packet[ESKY150V2_TXID_SIZE],rx_tx_addr, ESKY150V2_TXID_SIZE);
packet[8]=0x41; //Unknown
packet[9]=0x88; //Unknown
packet[10]=0x41; //Unknown
memset(&packet[11],0xAA,4); //Unknown
memcpy(&packet[15],hopping_frequency,ESKY150V2_NFREQCHANNELS); // hop table
//for(uint8_t i=0; i<40; i++) // Does not seem to be needed
// packet[i+85]=pgm_read_byte_near( &ESKY150V2_hop2[i] );
bind_counter=100;
}
else
NRF250K_SetTXAddr(rx_tx_addr, ESKY150V2_TXID_SIZE);
return 50000;
}
#endif

View File

@@ -18,8 +18,13 @@
#include "iface_nrf24l01.h"
//#define ESKY_ET4_FORCE_ID
#define ESKY_BIND_COUNT 1000
#define ESKY_PACKET_PERIOD 3333
#define ESKY_STD_PACKET_PERIOD 3333
#define ESKY_ET4_PACKET_PERIOD 1190
#define ESKY_ET4_TOTAL_PACKET_PERIOD 20300
#define ESKY_ET4_BIND_PACKET_PERIOD 5000
#define ESKY_PAYLOAD_SIZE 13
#define ESKY_PACKET_CHKTIME 100 // Time to wait for packet to be sent (no ACK, so very short)
@@ -63,28 +68,37 @@ static void __attribute__((unused)) ESKY_init()
static void __attribute__((unused)) ESKY_init2()
{
NRF24L01_FlushTx();
hopping_frequency_no = 0;
uint16_t channel_ord = rx_tx_addr[0] % 74;
hopping_frequency[12] = 10 + (uint8_t)channel_ord; //channel_code
uint8_t channel1, channel2;
channel1 = 10 + (uint8_t)((37 + channel_ord*5) % 74);
channel2 = 10 + (uint8_t)(( channel_ord*5) % 74) ;
if(sub_protocol==ESKY_STD)
{
uint16_t channel_ord = rx_tx_addr[0] % 74;
hopping_frequency[12] = 10 + (uint8_t)channel_ord; //channel_code
uint8_t channel1, channel2;
channel1 = 10 + (uint8_t)((37 + channel_ord*5) % 74);
channel2 = 10 + (uint8_t)(( channel_ord*5) % 74) ;
hopping_frequency[0] = channel1;
hopping_frequency[1] = channel1;
hopping_frequency[2] = channel1;
hopping_frequency[3] = channel2;
hopping_frequency[4] = channel2;
hopping_frequency[5] = channel2;
//end_bytes
hopping_frequency[6] = 6;
hopping_frequency[7] = channel1*2;
hopping_frequency[8] = channel2*2;
hopping_frequency[9] = 6;
hopping_frequency[10] = channel1*2;
hopping_frequency[11] = channel2*2;
hopping_frequency[0] = channel1;
hopping_frequency[1] = channel1;
hopping_frequency[2] = channel1;
hopping_frequency[3] = channel2;
hopping_frequency[4] = channel2;
hopping_frequency[5] = channel2;
//end_bytes
hopping_frequency[6] = 6;
hopping_frequency[7] = channel1*2;
hopping_frequency[8] = channel2*2;
hopping_frequency[9] = 6;
hopping_frequency[10] = channel1*2;
hopping_frequency[11] = channel2*2;
}
else
{ // ESKY_ET4
hopping_frequency[0] = 0x29; //41
hopping_frequency[1] = 0x12; //18
hopping_frequency[6] = 0x87; //135 payload end byte
hopping_frequency[12] = 0x84; //132 indicates which channels to use
}
// Turn radio power on
NRF24L01_SetTxRxMode(TX_EN);
}
@@ -111,20 +125,32 @@ static void __attribute__((unused)) ESKY_send_packet(uint8_t bind)
}
else
{
// Regular packet
// Each data packet is repeated 3 times on one channel, and 3 times on another channel
// For arithmetic simplicity, channels are repeated in rf_channels array
if (hopping_frequency_no == 0)
if (packet_count == 0)
for (uint8_t i = 0; i < 6; i++)
{
uint16_t val=convert_channel_ppm(CH_AETR[i]);
packet[i*2] = val>>8; //high byte of servo timing(1000-2000us)
packet[i*2+1] = val&0xFF; //low byte of servo timing(1000-2000us)
}
rf_ch = hopping_frequency[hopping_frequency_no];
packet[12] = hopping_frequency[hopping_frequency_no+6]; // end_bytes
hopping_frequency_no++;
if (hopping_frequency_no > 6) hopping_frequency_no = 0;
if(sub_protocol==ESKY_STD)
{
// Regular packet
// Each data packet is repeated 3 times on one channel, and 3 times on another channel
// For arithmetic simplicity, channels are repeated in rf_channels array
rf_ch = hopping_frequency[packet_count];
packet[12] = hopping_frequency[packet_count+6]; // end_bytes
packet_count++;
if (packet_count > 6) packet_count = 0;
}
else
{ // ESKY_ET4
// Regular packet
// Each data packet is repeated 14 times alternating between 2 channels
rf_ch = hopping_frequency[packet_count&1];
packet_count++;
if(packet_count>14) packet_count=0;
packet[12] = hopping_frequency[6]; // end_byte
}
}
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
NRF24L01_FlushTx();
@@ -137,9 +163,17 @@ uint16_t ESKY_callback()
if(IS_BIND_DONE)
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(ESKY_PACKET_PERIOD);
if(packet_count==0)
telemetry_set_input_sync(sub_protocol==ESKY_STD?ESKY_STD_PACKET_PERIOD*6:ESKY_ET4_TOTAL_PACKET_PERIOD);
#endif
ESKY_send_packet(0);
if(sub_protocol==ESKY_ET4)
{
if(packet_count==0)
return ESKY_ET4_TOTAL_PACKET_PERIOD-ESKY_ET4_PACKET_PERIOD*13;
else
return ESKY_ET4_PACKET_PERIOD;
}
}
else
{
@@ -150,16 +184,25 @@ uint16_t ESKY_callback()
BIND_DONE;
}
}
return ESKY_PACKET_PERIOD;
return ESKY_STD_PACKET_PERIOD;
}
uint16_t initESKY(void)
{
bind_counter = ESKY_BIND_COUNT;
rx_tx_addr[2] = rx_tx_addr[3]; // Model match
#ifdef ESKY_ET4_FORCE_ID
if(sub_protocol==ESKY_ET4)
{
rx_tx_addr[0]=0x72;
rx_tx_addr[1]=0xBB;
rx_tx_addr[2]=0xCC;
}
#endif
rx_tx_addr[3] = 0xBB;
ESKY_init();
ESKY_init2();
packet_count=0;
return 50000;
}

View File

@@ -17,7 +17,12 @@
/** FrSky D and X routines **/
/******************************/
#if defined(FRSKYX_CC2500_INO) || defined(FRSKY_RX_CC2500_INO)
#if defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYL_CC2500_INO) || defined(FRSKY_RX_CC2500_INO) || defined(FRSKYR9_SX1276_INO)
uint8_t FrSkyFormat=0;
uint8_t FrSkyX_chanskip;
#endif
#if defined(FRSKYX_CC2500_INO) || defined(FRSKYL_CC2500_INO) || defined(FRSKY_RX_CC2500_INO) || defined(FRSKYR9_SX1276_INO)
//**CRC**
const uint16_t PROGMEM FrSkyX_CRC_Short[]={
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
@@ -29,17 +34,84 @@ static uint16_t __attribute__((unused)) FrSkyX_CRCTable(uint8_t val)
val /= 16 ;
return word ^ (0x1081 * val) ;
}
uint16_t FrSkyX_crc(uint8_t *data, uint8_t len)
uint16_t FrSkyX_crc(uint8_t *data, uint8_t len, uint16_t init=0)
{
uint16_t crc = 0;
uint16_t crc = init;
for(uint8_t i=0; i < len; i++)
crc = (crc<<8) ^ FrSkyX_CRCTable((uint8_t)(crc>>8) ^ *data++);
return crc;
}
#endif
#if defined(FRSKYX_CC2500_INO) || defined(FRSKYR9_SX1276_INO)
static void __attribute__((unused)) FrSkyX_channels(uint8_t offset)
{
static uint8_t chan_start=0;
#if defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO)
//packet[7] = FLAGS 00 - standard packet
//10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
//20 - range check packet
#ifdef FAILSAFE_ENABLE
#define FRSKYX_FAILSAFE_TIMEOUT 1032
static uint16_t failsafe_count=0;
static uint8_t FS_flag=0,failsafe_chan=0;
if (FS_flag == 0 && failsafe_count > FRSKYX_FAILSAFE_TIMEOUT && chan_start == 0 && IS_FAILSAFE_VALUES_on)
{
FS_flag = 0x10;
failsafe_chan = 0;
} else if (FS_flag & 0x10 && failsafe_chan < (FrSkyFormat & 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++;
if(protocol==PROTO_FRSKY_R9)
failsafe_count++; // R9 is 20ms, X is 9ms
packet[offset] = FS_flag;
#else
packet[offset] = 0;
#endif
//
packet[offset+1] = 0; //??
//
uint8_t chan_index = chan_start;
uint16_t ch1,ch2;
for(uint8_t i = offset+2; i < 12+offset+2 ; i+=3)
{//12 bytes of channel data
#ifdef FAILSAFE_ENABLE
if( (FS_flag & 0x10) && ((failsafe_chan & 0x07) == (chan_index & 0x07)) )
ch1 = FrSkyX_scaleForPXX_FS(failsafe_chan);
else
#endif
ch1 = FrSkyX_scaleForPXX(chan_index);
chan_index++;
//
#ifdef FAILSAFE_ENABLE
if( (FS_flag & 0x10) && ((failsafe_chan & 0x07) == (chan_index & 0x07)) )
ch2 = FrSkyX_scaleForPXX_FS(failsafe_chan);
else
#endif
ch2 = FrSkyX_scaleForPXX(chan_index);
chan_index++;
//3 bytes per channel
packet[i] = ch1;
packet[i+1]=(((ch1>>8) & 0x0F)|(ch2 << 4));
packet[i+2]=ch2>>4;
}
if(FrSkyFormat & 0x01) //In X8 mode send only 8ch every 9ms
chan_start = 0 ;
else
chan_start^=0x08;
}
#endif
#if defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYL_CC2500_INO) || defined(FRSKY_RX_CC2500_INO)
enum {
FRSKY_BIND = 0,
FRSKY_BIND_DONE = 1000,
@@ -70,11 +142,79 @@ void Frsky_init_hop(void)
hopping_frequency[i]=i>46?0:val;
}
}
void FrSkyX2_init_hop(void)
{
uint16_t id=(rx_tx_addr[2]<<8) + rx_tx_addr[3];
//Increment
uint8_t inc = (id % 46) + 1;
if( inc == 12 || inc ==35 ) inc++; //Exception list from dumps
//Start offset
uint8_t offset = id % 5;
debug("hop: ");
uint8_t channel;
for(uint8_t i=0; i<47; i++)
{
channel = 5 * (uint16_t(inc * i) % 47) + offset;
//Exception list from dumps
if(FrSkyFormat & 2 )// LBT or FCC
{//LBT
if( channel <=1 || channel == 43 || channel == 44 || channel == 87 || channel == 88 || channel == 129 || channel == 130 || channel == 173 || channel == 174)
channel += 2;
else if( channel == 216 || channel == 217 || channel == 218)
channel += 3;
}
else //FCC
if ( channel == 3 || channel == 4 || channel == 46 || channel == 47 || channel == 90 || channel == 91 || channel == 133 || channel == 134 || channel == 176 || channel == 177 || channel == 220 || channel == 221 )
channel += 2;
//Store
hopping_frequency[i] = channel;
debug(" %02X",channel);
}
debugln("");
hopping_frequency[47] = 0; //Bind freq
}
void Frsky_init_clone(void)
{
debugln("Clone mode");
uint16_t temp = FRSKYD_CLONE_EEPROM_OFFSET;
if(protocol==PROTO_FRSKYX)
temp=FRSKYX_CLONE_EEPROM_OFFSET;
else if(protocol==PROTO_FRSKYX2)
temp=FRSKYX2_CLONE_EEPROM_OFFSET;
FrSkyFormat=eeprom_read_byte((EE_ADDR)temp++);
/* FRSKY_RX_D8 =0,
FRSKY_RX_D16FCC =1,
FRSKY_RX_D16LBT =2,
FRSKY_RX_D16v2FCC =3,
FRSKY_RX_D16v2LBT =4,*/
if(protocol==PROTO_FRSKYX)
FrSkyFormat >>= 1;
else
FrSkyFormat >>= 2;
FrSkyFormat <<= 1; //FCC_16/LBT_16
if(sub_protocol==XCLONE_8)
FrSkyFormat++; //FCC_8/LBT_8
rx_tx_addr[3] = eeprom_read_byte((EE_ADDR)temp++);
rx_tx_addr[2] = eeprom_read_byte((EE_ADDR)temp++);
rx_tx_addr[1] = eeprom_read_byte((EE_ADDR)temp++);
memset(hopping_frequency,0x00,50);
if(protocol!=PROTO_FRSKYX2)
{//D8 and D16v1
for (uint8_t ch = 0; ch < 47; ch++)
hopping_frequency[ch] = eeprom_read_byte((EE_ADDR)temp++);
}
else
FrSkyX2_init_hop();
}
#endif
/******************************/
/** FrSky V, D and X routines **/
/******************************/
#if defined(FRSKYV_CC2500_INO) || defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO)
#if defined(FRSKYV_CC2500_INO) || defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYL_CC2500_INO)
const PROGMEM uint8_t FRSKY_common_startreg_cc2500_conf[]= {
CC2500_02_IOCFG0 ,
CC2500_00_IOCFG2 ,
@@ -142,48 +282,68 @@ void Frsky_init_hop(void)
/*15_DEVIATN*/ 0x42 };
#endif
#if defined(FRSKYX_CC2500_INO)
#if defined(FRSKYX_CC2500_INO) || defined(FRSKYL_CC2500_INO)
const PROGMEM uint8_t FRSKYX_cc2500_conf[]= {
//FRSKYX
/*02_IOCFG0*/ 0x06 ,
/*02_IOCFG0*/ 0x06 ,
/*00_IOCFG2*/ 0x06 ,
/*17_MCSM1*/ 0x0c ,
/*17_MCSM1*/ 0x0c , //X2->0x0E -> RX stays in RX and TX stays in TX???
/*18_MCSM0*/ 0x18 ,
/*06_PKTLEN*/ 0x1E ,
/*07_PKTCTRL1*/ 0x04 ,
/*08_PKTCTRL0*/ 0x01 ,
/*08_PKTCTRL0*/ 0x01 , //X2->0x05 -> CRC enabled
/*3E_PATABLE*/ 0xff ,
/*0B_FSCTRL1*/ 0x0A ,
/*0C_FSCTRL0*/ 0x00 ,
/*0D_FREQ2*/ 0x5c ,
/*0E_FREQ1*/ 0x76 ,
/*0F_FREQ0*/ 0x27 ,
/*10_MDMCFG4*/ 0x7B ,
/*11_MDMCFG3*/ 0x61 ,
/*10_MDMCFG4*/ 0x7B ,
/*11_MDMCFG3*/ 0x61 , //X2->0x84 -> bitrate 70K->77K
/*12_MDMCFG2*/ 0x13 ,
/*13_MDMCFG1*/ 0x23 ,
/*14_MDMCFG0*/ 0x7a ,
/*15_DEVIATN*/ 0x51 };
const PROGMEM uint8_t FRSKYXEU_cc2500_conf[]= {
/*02_IOCFG0*/ 0x06 ,
/*02_IOCFG0*/ 0x06 ,
/*00_IOCFG2*/ 0x06 ,
/*17_MCSM1*/ 0x0E ,
/*18_MCSM0*/ 0x18 ,
/*06_PKTLEN*/ 0x23 ,
/*07_PKTCTRL1*/ 0x04 ,
/*08_PKTCTRL0*/ 0x01 ,
/*08_PKTCTRL0*/ 0x01 , //X2->0x05 -> CRC enabled
/*3E_PATABLE*/ 0xff ,
/*0B_FSCTRL1*/ 0x08 ,
/*0C_FSCTRL0*/ 0x00 ,
/*0D_FREQ2*/ 0x5c ,
/*0D_FREQ2*/ 0x5c ,
/*0E_FREQ1*/ 0x80 ,
/*0F_FREQ0*/ 0x00 ,
/*10_MDMCFG4*/ 0x7B ,
/*10_MDMCFG4*/ 0x7B ,
/*11_MDMCFG3*/ 0xF8 ,
/*12_MDMCFG2*/ 0x03 ,
/*13_MDMCFG1*/ 0x23 ,
/*14_MDMCFG0*/ 0x7a ,
/*15_DEVIATN*/ 0x53 };
const PROGMEM uint8_t FRSKYL_cc2500_conf[]= {
/*02_IOCFG0*/ 0x02 ,
/*00_IOCFG2*/ 0x02 ,
/*17_MCSM1*/ 0x0C ,
/*18_MCSM0*/ 0x18 ,
/*06_PKTLEN*/ 0xFF ,
/*07_PKTCTRL1*/ 0x00 ,
/*08_PKTCTRL0*/ 0x02 ,
/*3E_PATABLE*/ 0xFE ,
/*0B_FSCTRL1*/ 0x0A ,
/*0C_FSCTRL0*/ 0x00 ,
/*0D_FREQ2*/ 0x5c ,
/*0E_FREQ1*/ 0x76 ,
/*0F_FREQ0*/ 0x27 ,
/*10_MDMCFG4*/ 0x5C ,
/*11_MDMCFG3*/ 0x3B ,
/*12_MDMCFG2*/ 0x00 ,
/*13_MDMCFG1*/ 0x03 ,
/*14_MDMCFG0*/ 0x7A ,
/*15_DEVIATN*/ 0x47 };
#endif
const PROGMEM uint8_t FRSKY_common_end_cc2500_conf[][2]= {
@@ -227,3 +387,160 @@ void Frsky_init_hop(void)
CC2500_Strobe(CC2500_SIDLE); // Go to idle...
}
#endif
#if defined(FRSKYX_CC2500_INO) || defined(FRSKYR9_SX1276_INO)
uint8_t FrSkyX_TX_Seq, FrSkyX_TX_IN_Seq;
uint8_t FrSkyX_RX_Seq ;
#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 void __attribute__((unused)) FrSkyX_seq_sport(uint8_t start, uint8_t end)
{
for (uint8_t i=start+1;i<=end;i++)
packet[i]=0;
packet[start] = 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[start] |= FrSkyX_TX_IN_Seq&0x03;
packet[start+1] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq&0x03].count;
for (uint8_t i=start+2;i<start+2+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[start] |= FrSkyX_TX_Seq;
uint8_t nbr_bytes=0;
for (uint8_t i=start+2;i<=end;i++)
{
if(SportHead==SportTail)
break; //buffer empty
packet[i]=SportData[SportHead];
FrSkyX_TX_Frames[FrSkyX_TX_Seq].payload[i-start+2]=SportData[SportHead];
SportHead=(SportHead+1) & (MAX_SPORT_BUFFER-1);
nbr_bytes++;
}
packet[start+1]=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[start] |= FrSkyX_TX_IN_Seq;
packet[start+1] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq].count;
for (uint8_t i=start+2;i<start+2+FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq].count;i++)
packet[i] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq].payload[i-start+2];
}
}
else
packet[start] |= 0x08 ; //FrSkyX_TX_Seq=8 at startup
}
if(packet[start+1])
{//Debug
debug("SP: ");
for(uint8_t i=0;i<packet[start+1];i++)
debug("%02X ",packet[start+2+i]);
debugln("");
}
#else
packet[start] |= 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
}
static void __attribute__((unused)) FrSkyX_telem_init(void)
{
FrSkyX_TX_Seq = 0x08 ; // Request init
#ifdef SPORT_SEND
FrSkyX_TX_IN_Seq = 0xFF ; // No sequence received yet
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
#ifdef TELEMETRY
telemetry_lost=1;
telemetry_link=0; //Stop sending telemetry
#endif
}
#endif
#if defined(FRSKYX_CC2500_INO) || defined(FRSKYL_CC2500_INO)
static void __attribute__((unused)) FrSkyX_set_start(uint8_t ch )
{
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_25_FSCAL1, calData[ch]);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[ch]);
}
static void __attribute__((unused)) FrSkyX_init()
{
if(protocol==PROTO_FRSKYL)
FRSKY_init_cc2500(FRSKYL_cc2500_conf);
else
FRSKY_init_cc2500((FrSkyFormat&2)?FRSKYXEU_cc2500_conf:FRSKYX_cc2500_conf); // LBT or FCC
if(protocol==PROTO_FRSKYX2)
{
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05); // Enable CRC
if(!(FrSkyFormat&2))
{ // FCC
CC2500_WriteReg(CC2500_17_MCSM1, 0x0E); //0x0E -> RX stays in RX and TX stays in TX???
CC2500_WriteReg(CC2500_11_MDMCFG3, 0x84); // bitrate 70K->77K
}
}
//
for(uint8_t c=0;c < 48;c++)
{//calibrate hop channels
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR,hopping_frequency[c]);
CC2500_Strobe(CC2500_SCAL);
delayMicroseconds(900);//
calData[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
}
//#######END INIT########
}
static void __attribute__((unused)) FrSkyX_initialize_data(uint8_t adr)
{
CC2500_WriteReg(CC2500_18_MCSM0, 0x8);
CC2500_WriteReg(CC2500_09_ADDR, adr ? 0x03 : rx_tx_addr[3]);
CC2500_WriteReg(CC2500_07_PKTCTRL1,0x05); // check address
}
#endif

View File

@@ -21,6 +21,7 @@ static void __attribute__((unused)) frsky2way_init(uint8_t bind)
{
FRSKY_init_cc2500(FRSKYD_cc2500_conf);
CC2500_WriteReg(CC2500_1B_AGCCTRL2, bind ? 0x43 : 0x03);
CC2500_WriteReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]);
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05);
CC2500_Strobe(CC2500_SIDLE); // Go to idle...
@@ -53,7 +54,7 @@ static void __attribute__((unused)) frsky2way_build_bind_packet()
packet[14] = 0x00;
packet[15] = 0x00;
packet[16] = 0x00;
packet[17] = 0x01;
packet[17] = rx_tx_addr[1];
}
static void __attribute__((unused)) frsky2way_data_frame()
@@ -70,7 +71,7 @@ static void __attribute__((unused)) frsky2way_data_frame()
packet[4] = 0x00;
#endif
packet[5] = 0x01;
packet[5] = rx_tx_addr[1];
//
packet[10] = 0;
packet[11] = 0;
@@ -95,7 +96,23 @@ static void __attribute__((unused)) frsky2way_data_frame()
uint16_t initFrSky_2way()
{
Frsky_init_hop();
//FrskyD init hop
if (sub_protocol==DCLONE)
Frsky_init_clone();
else
{
for(uint8_t i=0;i<50;i++)
{
uint8_t freq = (i * 0x1e) % 0xeb;
if(i == 3 || i == 23 || i == 47)
freq++;
if(i > 47)
freq=0;
hopping_frequency[i]=freq;
}
rx_tx_addr[1]=1; // keep compatibility with already bound RXs
}
packet_count=0;
if(IS_BIND_IN_PROGRESS)
{
@@ -164,7 +181,7 @@ uint16_t ReadFrSky_2way()
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.
frsky_process_telemetry(packet_in,len); //check if valid telemetry packets and buffer them.
}
#endif
}

View File

@@ -0,0 +1,262 @@
/*
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(FRSKYL_CC2500_INO)
#include "iface_cc2500.h"
//#define FRSKYL_FORCE_ID
#define FRSKYL_PACKET_LEN 256
#define FRSKYL_PERIOD 18000
uint8_t FrSkyL_buffer[FRSKYL_PACKET_LEN];
static void __attribute__((unused)) FrSkyL_build_bind_packet()
{
//Header
packet[0] = 0x4E; // Unknown but constant
//Bind packet
memset(&packet[1],0x00,3);
//ID
packet[4 ] = rx_tx_addr[3]; // ID
packet[5 ] = rx_tx_addr[2]; // ID
int idx = ((state -FRSKY_BIND) % 10) * 5;
packet[6 ] = idx;
packet[7 ] = hopping_frequency[idx++];
packet[8 ] = hopping_frequency[idx++];
packet[9 ] = hopping_frequency[idx++];
packet[10] = hopping_frequency[idx++];
packet[11] = hopping_frequency[idx++];
packet[12] = rx_tx_addr[1]; // ID or hw ver?
packet[13] = RX_num;
packet[14] = 0x00; // Unknown but constant
//CRC
uint16_t lcrc = FrSkyX_crc(&packet[1], 14);
packet[15] = lcrc >> 8;
packet[16] = lcrc;
//Debug
/* debug("Bind:");
for(uint8_t i=0;i<17;i++)
debug(" %02X",packet[i]);
debugln("");*/
}
static void __attribute__((unused)) FrSkyL_build_packet()
{
static uint8_t chan_offset=0;
uint16_t chan_0,chan_1;
//Header
packet[0 ] = 0x4E; // Unknown but constant
//ID
packet[1 ] = rx_tx_addr[3]; // ID
packet[2 ] = rx_tx_addr[2]; // ID
packet[3 ] = rx_tx_addr[1]; // ID or hw ver?
//skip_hop
packet[4 ] = (FrSkyX_chanskip<<6)|hopping_frequency_no;
packet[5 ] = FrSkyX_chanskip>>2;
//Channels
uint8_t startChan = chan_offset;
for(uint8_t i = 0; i <9 ; i+=3)
{//9 bytes of channel data
chan_0 = FrSkyX_scaleForPXX(startChan,6);
startChan++;
//
chan_1 = FrSkyX_scaleForPXX(startChan,6);
startChan++;
//
packet[6+i] = lowByte(chan_0); //3 bytes*4
packet[6+i+1]=(((chan_0>>8) & 0x0F)|(chan_1 << 4));
packet[6+i+2]=chan_1>>4;
}
if(sub_protocol & 0x01 ) //6ch mode only??
chan_offset = 0 ;
else
chan_offset^=0x06;
//CRC
uint16_t lcrc = FrSkyX_crc(&packet[1], 14, RX_num);
packet[15] = lcrc >> 8;
packet[16] = lcrc;
//Debug
/*debug("Norm:");
for(uint8_t i=0;i<17;i++)
debug(" %02X",packet[i]);
debugln("");*/
}
static void __attribute__((unused)) FrSkyL_encode_packet(bool type)
{
#define FRSKYL_BIT0 0xED
#define FRSKYL_BIT1 0x712
uint32_t bits = 0;
uint8_t bitsavailable = 0;
uint8_t idx = 0,len=6;
if(type)
{//just replace packet content
idx=66;
len=17;
}
//debugln("Encode:");
for (uint8_t i = 0; i < len; i++)
{
uint8_t tmp=packet[i];
//debug("%02X =",tmp);
for(uint8_t j=0;j<8;j++)
{
bits <<= 11;
if(tmp&0x01)
bits |= FRSKYL_BIT1;
else
bits |= FRSKYL_BIT0;
tmp >>=1;
bitsavailable += 11;
while (bitsavailable >= 8) {
uint32_t bits_tmp=bits>>(bitsavailable-8);
bitsavailable -= 8;
FrSkyL_buffer[idx] = bits_tmp;
//debug(" %02X",FrSkyL_buffer[idx]);
idx++;
}
}
//debugln("");
}
}
uint16_t ReadFrSkyL()
{
static uint8_t written=0, send=0;
switch(send)
{
case 1:
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SFTX);
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, FrSkyL_buffer, 64);
CC2500_Strobe(CC2500_STX);
CC2500_Strobe(CC2500_SIDLE); // This cancels the current transmission???
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, FrSkyL_buffer, 64);
CC2500_Strobe(CC2500_SFTX); // This just clears what we've written???
CC2500_Strobe(CC2500_STX);
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, FrSkyL_buffer, 64);
written=64;
send++;
return 2623;
case 2:
len=FRSKYL_PACKET_LEN-written;
if(len>31)
len=31;
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, FrSkyL_buffer+written, len);
written+=len;
if(len!=31) //everything has been sent
{
send=0;
return 2936;
}
return 1984;
}
switch(state)
{
default:
//Bind
#ifdef MULTI_SYNC
telemetry_set_input_sync(9000);
#endif
FrSkyX_set_start(47);
CC2500_SetPower();
CC2500_Strobe(CC2500_SFRX);
//
FrSkyL_build_bind_packet();
FrSkyL_encode_packet(true);
CC2500_Strobe(CC2500_SIDLE);
if(IS_BIND_DONE)
state = FRSKY_BIND_DONE;
else
{
state++;
send=1;
}
return 537;
case FRSKY_BIND_DONE:
FrSkyX_initialize_data(0);
hopping_frequency_no=0;
BIND_DONE;
state++; //FRSKY_DATA1
break;
case FRSKY_DATA1:
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); //Frequency offset hack
prev_option = option ;
}
FrSkyX_set_start(hopping_frequency_no);
FrSkyL_build_packet();
FrSkyL_encode_packet(true);
CC2500_SetPower();
hopping_frequency_no = (hopping_frequency_no+FrSkyX_chanskip)%47;
send=1;
return 537;
}
return 1;
}
uint16_t initFrSkyL()
{
set_rx_tx_addr(MProtocol_id_master);
rx_tx_addr[1]=0x02; // ID related, hw version?
#ifdef FRSKYL_FORCE_ID
rx_tx_addr[3]=0x0E;
rx_tx_addr[2]=0x1C;
rx_tx_addr[1]=0x02;
#endif
FrSkyX2_init_hop();
while(!FrSkyX_chanskip)
FrSkyX_chanskip=random(0xfefefefe)%47;
FrSkyX_init();
//Prepare frame
memset(FrSkyL_buffer,0x00,FRSKYL_PACKET_LEN-3);
memset(&FrSkyL_buffer[FRSKYL_PACKET_LEN-3],0x55,3);
memset(packet,0xAA,6);
FrSkyL_encode_packet(false);
/*debugln("Frame:");
for(uint16_t i=0;i<FRSKYL_PACKET_LEN;i++)
{
debug(" %02X",FrSkyL_buffer[i]);
if(i%11==10)
debugln("");
}
debugln("");*/
if(IS_BIND_IN_PROGRESS)
{
state = FRSKY_BIND;
FrSkyX_initialize_data(1);
}
else
{
state = FRSKY_DATA1;
FrSkyX_initialize_data(0);
}
return 10000;
}
#endif

View File

@@ -0,0 +1,306 @@
#if defined(FRSKYR9_SX1276_INO)
#include "iface_sx1276.h"
#define DISP_FREQ_TABLE
#define FLEX_FREQ 29
#define FCC_FREQ 43
#define EU_FREQ 19
enum {
FRSKYR9_FREQ=0,
FRSKYR9_DATA,
FRSKYR9_RX1,
FRSKYR9_RX2,
};
void FrSkyR9_set_frequency()
{
uint8_t data[3];
uint16_t num=0;
hopping_frequency_no += FrSkyX_chanskip;
switch(sub_protocol & 0xFD)
{
case R9_868:
if(IS_BIND_DONE) // if bind is in progress use R9_915 instead
{
hopping_frequency_no %= FLEX_FREQ;
num=hopping_frequency_no;
if(hopping_frequency_no>=FLEX_FREQ-2)
num+=FrSkyX_chanskip-FLEX_FREQ+2; // the last 2 values are FrSkyX_chanskip and FrSkyX_chanskip+1
num <<= 5;
num += 0xD700;
break;
}//else use R9_915
case R9_915:
hopping_frequency_no %= FLEX_FREQ;
num=hopping_frequency_no;
if(hopping_frequency_no>=FLEX_FREQ-2)
num+=FrSkyX_chanskip-FLEX_FREQ+2; // the last 2 values are FrSkyX_chanskip and FrSkyX_chanskip+1
num <<= 5;
num += 0xE4C0;
break;
case R9_FCC:
hopping_frequency_no %= FCC_FREQ;
num=hopping_frequency_no;
num <<= 5;
num += 0xE200;
break;
case R9_EU:
hopping_frequency_no %= EU_FREQ;
num=hopping_frequency_no;
num <<= 4;
num += 0xD7D0;
break;
}
data[0] = num>>8;
data[1] = num&0xFF;
data[2] = 0x00;
#ifdef DISP_FREQ_TABLE
if(phase==0xFF)
debugln("F%d=%02X%02X%02X=%lu", hopping_frequency_no, data[0], data[1], data[2], (uint32_t)((data[0]<<16)+(data[1]<<8)+data[2])*61);
#endif
SX1276_WriteRegisterMulti(SX1276_06_FRFMSB, data, 3);
}
static void __attribute__((unused)) FrSkyR9_build_packet()
{
//ID
packet[0] = rx_tx_addr[1];
packet[1] = rx_tx_addr[2];
packet[2] = rx_tx_addr[3];
//Hopping
packet[3] = hopping_frequency_no; // current channel index
packet[4] = FrSkyX_chanskip; // step size and last 2 channels start index
//RX number
packet[5] = RX_num; // receiver number from OpenTX
//Channels
FrSkyX_channels(6); // Set packet[6]=failsafe, packet[7]=0?? and packet[8..19]=channels data
//Bind
if(IS_BIND_IN_PROGRESS)
{// 915 0x01=CH1-8_TELEM_ON 0x41=CH1-8_TELEM_OFF 0xC1=CH9-16_TELEM_OFF 0x81=CH9-16_TELEM_ON
packet[6] = 0x01; // bind indicator
if(sub_protocol & 1)
packet[6] |= 0x20; // 868
if(binding_idx&0x01)
packet[6] |= 0x40; // telem OFF
if(binding_idx&0x02)
packet[6] |= 0x80; // ch9-16
}
//Sequence and send SPort
FrSkyX_seq_sport(20,23); //20=RX|TXseq, 21=bytes count, 22&23=data
//CRC
uint16_t crc = FrSkyX_crc(packet, 24);
packet[24] = crc; // low byte
packet[25] = crc >> 8; // high byte
}
static uint8_t __attribute__((unused)) FrSkyR9_CRC8(uint8_t *p, uint8_t l)
{
uint8_t crc = 0xFF;
for (uint8_t i = 0; i < l; i++)
{
crc = crc ^ p[i];
for ( uint8_t j = 0; j < 8; j++ )
if ( crc & 0x80 )
{
crc <<= 1;
crc ^= 0x07;
}
else
crc <<= 1;
}
return crc;
}
static void __attribute__((unused)) FrSkyR9_build_EU_packet()
{
//ID
packet[0] = rx_tx_addr[1];
packet[1] = rx_tx_addr[2];
packet[2] = rx_tx_addr[3];
//Hopping
packet[3] = FrSkyX_chanskip; // step size and last 2 channels start index
//RX number
packet[4] = RX_num; // receiver number from OpenTX
//Channels
//TODO FrSkyX_channels(5,4); // Set packet[5]=failsafe and packet[6..11]=4 channels data
//Bind
if(IS_BIND_IN_PROGRESS)
{
packet[5] = 0x01; // bind indicator
if((sub_protocol & 2) == 0)
packet[5] |= 0x10; // 16CH
// if(sub_protocol & 1)
// packet[5] |= 0x20; // 868
if(binding_idx&0x01)
packet[5] |= 0x40; // telem OFF
if(binding_idx&0x02)
packet[5] |= 0x80; // ch9-16
}
//Sequence and send SPort
packet[12] = (FrSkyX_RX_Seq << 4)|0x08; //TX=8 at startup
//CRC
packet[13] = FrSkyR9_CRC8(packet, 13);
}
uint16_t initFrSkyR9()
{
//Check frequencies
#ifdef DISP_FREQ_TABLE
phase=0xFF;
FrSkyX_chanskip=1;
hopping_frequency_no=0xFF;
for(uint8_t i=0;i<FCC_FREQ;i++)
FrSkyR9_set_frequency();
#endif
//Reset ID
set_rx_tx_addr(MProtocol_id_master);
//FrSkyX_chanskip
FrSkyX_chanskip = 1 + (random(0xfefefefe) % 24);
debugln("chanskip=%d", FrSkyX_chanskip);
//Set FrSkyFormat
if((sub_protocol & 0x02) == 0)
FrSkyFormat=0; // 16 channels
else
FrSkyFormat=1; // 8 channels
debugln("%dCH", FrSkyFormat&1 ? 8:16);
//EU packet length
if( (sub_protocol & 0xFD) == R9_EU )
packet_length=14;
else
packet_length=26;
//SX1276 Init
SX1276_SetMode(true, false, SX1276_OPMODE_SLEEP);
SX1276_SetMode(true, false, SX1276_OPMODE_STDBY);
// uint8_t buffer[2];
// buffer[0] = 0x00;
// buffer[1] = 0x00;
// SX1276_WriteRegisterMulti(SX1276_40_DIOMAPPING1, buffer, 2);
SX1276_SetDetectOptimize(true, SX1276_DETECT_OPTIMIZE_SF6);
SX1276_ConfigModem1(SX1276_MODEM_CONFIG1_BW_500KHZ, SX1276_MODEM_CONFIG1_CODING_RATE_4_5, true);
SX1276_ConfigModem2(6, false, false);
SX1276_ConfigModem3(false, false);
SX1276_SetPreambleLength(9);
SX1276_SetDetectionThreshold(SX1276_MODEM_DETECTION_THRESHOLD_SF6);
SX1276_SetLna(1, true);
SX1276_SetHopPeriod(0); // 0 = disabled, we hop frequencies manually
SX1276_SetPaDac(true);
SX1276_SetTxRxMode(TX_EN); // Set RF switch to TX
FrSkyX_telem_init();
hopping_frequency_no=0;
phase=FRSKYR9_FREQ;
return 20000; // Start calling FrSkyR9_callback in 20 milliseconds
}
uint16_t FrSkyR9_callback()
{
switch (phase)
{
case FRSKYR9_FREQ:
//Force standby
SX1276_SetMode(true, false, SX1276_OPMODE_STDBY);
//Set frequency
FrSkyR9_set_frequency(); // Set current center frequency
//Set power
// max power: 15dBm (10.8 + 0.6 * MaxPower [dBm])
// output_power: 2 dBm (17-(15-OutputPower) (if pa_boost_pin == true))
SX1276_SetPaConfig(true, 7, 0); // Lowest power for the T18
//Build packet
if( packet_length == 26 )
FrSkyR9_build_packet();
else
FrSkyR9_build_EU_packet();
phase++;
return 460; // Frequency settle time
case FRSKYR9_DATA:
//Set RF switch to TX
SX1276_SetTxRxMode(TX_EN);
//Send packet
SX1276_WritePayloadToFifo(packet, packet_length);
SX1276_SetMode(true, false, SX1276_OPMODE_TX);
#if not defined TELEMETRY
phase=FRSKYR9_FREQ;
return 20000-460;
#else
phase++;
return 11140; // Packet send time
case FRSKYR9_RX1:
//Force standby
SX1276_SetMode(true, false, SX1276_OPMODE_STDBY);
//RX packet size is 13
SX1276_WriteReg(SX1276_22_PAYLOAD_LENGTH, 13);
//Reset pointer
SX1276_WriteReg(SX1276_0D_FIFOADDRPTR, 0x00);
//Set RF switch to RX
SX1276_SetTxRxMode(RX_EN);
//Switch to RX
SX1276_WriteReg(SX1276_01_OPMODE, 0x85);
phase++;
return 7400;
case FRSKYR9_RX2:
if( (SX1276_ReadReg(SX1276_12_REGIRQFLAGS)&0xF0) == (_BV(SX1276_REGIRQFLAGS_RXDONE) | _BV(SX1276_REGIRQFLAGS_VALIDHEADER)) )
{
if(SX1276_ReadReg(SX1276_13_REGRXNBBYTES)==13)
{
SX1276_ReadRegisterMulti(SX1276_00_FIFO,packet_in,13);
if( packet_in[9]==rx_tx_addr[1] && packet_in[10]==rx_tx_addr[2] && FrSkyX_crc(packet_in, 11, rx_tx_addr[1]+(rx_tx_addr[2]<<8))==(packet_in[11]+(packet_in[12]<<8)) )
{
if(packet_in[0]&0x80)
RX_RSSI=packet_in[0]<<1;
else
v_lipo1=(packet_in[0]<<1)+1;
//TX_LQI=~(SX1276_ReadReg(SX1276_19_PACKETSNR)>>2)+1;
TX_RSSI=SX1276_ReadReg(SX1276_1A_PACKETRSSI)-157;
for(uint8_t i=0;i<9;i++)
packet[4+i]=packet_in[i]; // Adjust buffer to match FrSkyX
frsky_process_telemetry(packet,len); // Process telemetry packet
pps_counter++;
if(TX_LQI==0)
TX_LQI++; // Recover telemetry right away
}
}
}
if (millis() - pps_timer >= 1000)
{//1 packet every 20ms
pps_timer = millis();
debugln("%d pps", pps_counter);
TX_LQI = pps_counter<<1; // Max=100%
pps_counter = 0;
}
if(TX_LQI==0)
FrSkyX_telem_init(); // Reset telemetry
else
telemetry_link=1; // Send telemetry out anyway
//Clear all flags
SX1276_WriteReg(SX1276_12_REGIRQFLAGS,0xFF);
phase=FRSKYR9_FREQ;
break;
#endif
}
return 1000;
}
#endif

View File

@@ -1,287 +1,123 @@
/* **************************
* By Midelic on RCGroups *
**************************
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(FRSKYX_CC2500_INO)
#include "iface_cc2500.h"
uint8_t FrSkyX_chanskip;
uint8_t FrSkyX_TX_Seq, FrSkyX_TX_IN_Seq;
uint8_t FrSkyX_RX_Seq ;
#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
#define FrSkyX_FAILSAFE_TIMEOUT 1032
static void __attribute__((unused)) FrSkyX_set_start(uint8_t ch )
{
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_25_FSCAL1, calData[ch]);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[ch]);
}
static void __attribute__((unused)) FrSkyX_init()
{
FRSKY_init_cc2500((sub_protocol&2)?FRSKYXEU_cc2500_conf:FRSKYX_cc2500_conf); // LBT or FCC
//
for(uint8_t c=0;c < 48;c++)
{//calibrate hop channels
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR,hopping_frequency[c]);
CC2500_Strobe(CC2500_SCAL);
delayMicroseconds(900);//
calData[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
}
//#######END INIT########
}
static void __attribute__((unused)) FrSkyX_initialize_data(uint8_t adr)
{
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
CC2500_WriteReg(CC2500_18_MCSM0, 0x8);
CC2500_WriteReg(CC2500_09_ADDR, adr ? 0x03 : rx_tx_addr[3]);
CC2500_WriteReg(CC2500_07_PKTCTRL1,0x05);
}
static void __attribute__((unused)) FrSkyX_build_bind_packet()
{
packet[0] = (sub_protocol & 2 ) ? 0x20 : 0x1D ; // LBT or FCC
packet[1] = 0x03;
packet[2] = 0x01;
//
packet[3] = rx_tx_addr[3];
packet[4] = rx_tx_addr[2];
int idx = ((state -FRSKY_BIND) % 10) * 5;
packet[5] = idx;
packet[6] = hopping_frequency[idx++];
packet[7] = hopping_frequency[idx++];
packet[8] = hopping_frequency[idx++];
packet[9] = hopping_frequency[idx++];
packet[10] = hopping_frequency[idx++];
packet[11] = 0x02;
packet[12] = RX_num;
//
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
memset(&packet[13], 0, limit - 13);
uint16_t lcrc = FrSkyX_crc(&packet[3], limit-3);
//
packet[limit++] = lcrc >> 8;
packet[limit] = lcrc;
//
uint8_t packet_size = 0x1D;
if(protocol==PROTO_FRSKYX && (FrSkyFormat & 2 ))
packet_size=0x20; // FrSkyX V1 LBT
//Header
packet[0] = packet_size; // Number of bytes in the packet (after this one)
packet[1] = 0x03; // Bind packet
packet[2] = 0x01; // Bind packet
//ID
packet[3] = rx_tx_addr[3]; // ID
packet[4] = rx_tx_addr[2]; // ID
if(protocol==PROTO_FRSKYX)
{
int idx = ((state -FRSKY_BIND) % 10) * 5;
packet[5] = idx;
packet[6] = hopping_frequency[idx++];
packet[7] = hopping_frequency[idx++];
packet[8] = hopping_frequency[idx++];
packet[9] = hopping_frequency[idx++];
packet[10] = hopping_frequency[idx++];
packet[11] = rx_tx_addr[1]; // Unknown but constant ID?
packet[12] = RX_num;
//
memset(&packet[13], 0, packet_size - 14);
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
}
else
{
//packet 1D 03 01 0E 1C 02 00 00 32 0B 00 00 A8 26 28 01 A1 00 00 00 3E F6 87 C7 00 00 00 00 C9 C9
packet[5] = rx_tx_addr[1]; // Unknown but constant ID?
packet[6] = RX_num;
//Bind flags
packet[7]=0;
if(binding_idx&0x01)
packet[7] |= 0x40; // Telem off
if(binding_idx&0x02)
packet[7] |= 0x80; // CH9-16
//Unknown bytes
memcpy(&packet[8],"\x32\x0B\x00\x00\xA8\x26\x28\x01\xA1\x00\x00\x00\x3E\xF6\x87\xC7",16);
packet[20]^= 0x0E ^ rx_tx_addr[3]; // Update the ID
packet[21]^= 0x1C ^ rx_tx_addr[2]; // Update the ID
//Xor
for(uint8_t i=3; i<packet_size-1; i++)
packet[i] ^= 0xA7;
}
//CRC
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_size-4);
packet[packet_size-1] = lcrc >> 8;
packet[packet_size] = lcrc;
/*//Debug
debug("Bind:");
for(uint8_t i=0;i<=packet_size;i++)
debug(" %02X",packet[i]);
debugln("");*/
}
// 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 chan_offset=0;
uint16_t chan_0 ;
uint16_t chan_1 ;
//
// data frames sent every 9ms; failsafe every 9 seconds
#ifdef FAILSAFE_ENABLE
static uint16_t failsafe_count=0;
static uint8_t FS_flag=0,failsafe_chan=0;
if (FS_flag == 0 && failsafe_count > 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;
//
uint8_t packet_size = 0x1D;
if(protocol==PROTO_FRSKYX && (FrSkyFormat & 2 ))
packet_size=0x20; // FrSkyX V1 LBT
//Header
packet[0] = packet_size; // Number of bytes in the packet (after this one)
packet[1] = rx_tx_addr[3]; // ID
packet[2] = rx_tx_addr[2]; // ID
packet[3] = rx_tx_addr[1]; // Unknown but constant ID?
//
packet[4] = (FrSkyX_chanskip<<6)|hopping_frequency_no;
packet[5] = FrSkyX_chanskip>>2;
packet[6] = RX_num;
//packet[7] = FLAGS 00 - standard packet
//10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
//20 - range check packet
#ifdef FAILSAFE_ENABLE
packet[7] = FS_flag;
#else
packet[7] = 0;
#endif
packet[8] = 0;
//
uint8_t startChan = chan_offset;
for(uint8_t i = 0; i <12 ; i+=3)
{//12 bytes of channel data
#ifdef FAILSAFE_ENABLE
if( (FS_flag & 0x10) && ((failsafe_chan & 0x07) == (startChan & 0x07)) )
chan_0 = FrSkyX_scaleForPXX_FS(failsafe_chan);
else
#endif
chan_0 = FrSkyX_scaleForPXX(startChan);
startChan++;
//
#ifdef FAILSAFE_ENABLE
if( (FS_flag & 0x10) && ((failsafe_chan & 0x07) == (startChan & 0x07)) )
chan_1 = FrSkyX_scaleForPXX_FS(failsafe_chan);
else
#endif
chan_1 = FrSkyX_scaleForPXX(startChan);
startChan++;
//
packet[9+i] = lowByte(chan_0); //3 bytes*4
packet[9+i+1]=(((chan_0>>8) & 0x0F)|(chan_1 << 4));
packet[9+i+2]=chan_1>>4;
}
if(sub_protocol & 0x01 ) //In X8 mode send only 8ch every 9ms
chan_offset = 0 ;
else
chan_offset^=0x08;
//sequence and send SPort
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
for (uint8_t i=22;i<limit;i++)
packet[i]=0;
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
//Channels
FrSkyX_channels(7); // Set packet[7]=failsafe, packet[8]=0?? and packet[9..20]=channels data
//Sequence and send SPort
FrSkyX_seq_sport(21,packet_size-2); //21=RX|TXseq, 22=bytes count, 23..packet_size-2=data
//CRC
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_size-4);
packet[packet_size-1] = lcrc >> 8;
packet[packet_size] = lcrc;
/*//Debug
debug("Norm:");
for(uint8_t i=0;i<=packet_size;i++)
debug(" %02X",packet[i]);
debugln("");*/
}
uint16_t ReadFrSkyX()
{
static bool transmit=true;
#ifdef DEBUG_SERIAL
static uint16_t fr_time=0;
#endif
switch(state)
{
default:
@@ -301,116 +137,141 @@ uint16_t ReadFrSkyX()
FrSkyX_initialize_data(0);
hopping_frequency_no=0;
BIND_DONE;
state++; //FRSKY_DATA1
state++; //FRSKY_DATA1
break;
case FRSKY_DATA5:
case FRSKY_DATA1:
CC2500_Strobe(CC2500_SIDLE);
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); //Frequency offset hack
prev_option = option ;
}
FrSkyX_set_start(hopping_frequency_no);
FrSkyX_build_packet();
if(FrSkyFormat & 2)
{// LBT
CC2500_Strobe(CC2500_SRX); //Acquire RSSI
state++;
return 400; // LBT
}
case FRSKY_DATA2:
if(FrSkyFormat & 2)
{
uint16_t rssi=0;
for(uint8_t i=0;i<4;i++)
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
rssi>>=2;
#if 0
uint8_t rssi_level=convert_channel_8b(CH16)>>1; //CH16 0..127
if ( rssi > rssi_level && rssi < 128) //test rssi level dynamically
#else
if ( rssi > 14 && rssi < 128) //if RSSI above -65dBm (12=-70) => ETSI requirement
#endif
{
LBT_POWER_on; //Reduce to low power before transmitting
debugln("Busy %d %d",hopping_frequency_no,rssi);
}
}
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SFTX); //Flush the TXFIFO
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
hopping_frequency_no = (hopping_frequency_no+FrSkyX_chanskip)%47;
CC2500_WriteData(packet, packet[0]+1);
state=FRSKY_DATA3;
if(FrSkyFormat & 2)
return 4000; // LBT
else
return 5200; // FCC
case FRSKY_DATA3:
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SFRX); //Flush the RXFIFO
CC2500_SetTxRxMode(RX_EN);
CC2500_Strobe(CC2500_SRX);
state++;
if(FrSkyFormat & 2)
return 4200; // LBT
else
return 3400; // FCC
case FRSKY_DATA4:
#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
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
if (len && len <= 17) //Telemetry frame is 17 bytes
{
//debug("Telem:");
CC2500_ReadData(packet_in, len); //Read what has been received so far
if(len<17)
{//not all bytes were received
uint8_t last_len=CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
if(last_len==17) //All bytes received
{
CC2500_ReadData(packet_in+len, last_len-len); //Finish to read
len=17;
}
}
if(len==17 && (protocol==PROTO_FRSKYX || (protocol==PROTO_FRSKYX2 && (packet_in[len-1] & 0x80))) )
{//Telemetry received with valid crc for FRSKYX2
//Debug
//for(uint8_t i=0;i<len;i++)
// debug(" %02X",packet_in[i]);
if(frsky_process_telemetry(packet_in,len)) //Check and process telemetry packet
{//good packet received
pps_counter++;
if(TX_LQI==0)
TX_LQI++; //Recover telemetry right away
}
}
//debugln("");
}
CC2500_Strobe(CC2500_SFRX); //Flush the RXFIFO
}
FrSkyX_build_packet();
if (millis() - pps_timer >= 900)
{//1 packet every 9ms
pps_timer = millis();
debugln("%d pps", pps_counter);
TX_LQI = pps_counter; //Max=100%
pps_counter = 0;
}
if(TX_LQI==0)
FrSkyX_telem_init(); //Reset telemetry
else
telemetry_link=1; //Send telemetry out anyway
#endif
state = FRSKY_DATA1;
#if not defined(FRSKYX_LBT)
return 500;
#endif // for LBT just continue to DATA1 right away
case FRSKY_DATA1:
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 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_DATA4:
CC2500_Strobe(CC2500_SRX);
state++;
return 3100;
}
return 400; // FCC & LBT
}
return 1;
}
uint16_t initFrSkyX()
{
set_rx_tx_addr(MProtocol_id_master);
Frsky_init_hop();
FrSkyFormat = sub_protocol;
if (sub_protocol==XCLONE_16||sub_protocol==XCLONE_8)
Frsky_init_clone();
else if(protocol==PROTO_FRSKYX)
{
Frsky_init_hop();
rx_tx_addr[1]=0x02; // ID related, hw version?
}
else
{
#ifdef FRSKYX2_FORCE_ID
rx_tx_addr[3]=0x0E;
rx_tx_addr[2]=0x1C;
FrSkyX_chanskip=18;
#endif
rx_tx_addr[1]=0x02; // ID related, hw version?
FrSkyX2_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();
if(IS_BIND_IN_PROGRESS)
@@ -423,14 +284,7 @@ uint16_t initFrSkyX()
state = FRSKY_DATA1;
FrSkyX_initialize_data(0);
}
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
FrSkyX_telem_init();
return 10000;
}
#endif
}
#endif

View File

@@ -17,16 +17,19 @@
#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
#define FRSKY_RX_D16FCC_LENGTH 0x1D+1
#define FRSKY_RX_D16LBT_LENGTH 0x20+1
#define FRSKY_RX_D16v2_LENGTH 0x1D+1
#define FRSKY_RX_D8_LENGTH 0x11+1
#define FRSKY_RX_FORMATS 5
enum
{
FRSKY_RX_D16FCC = 0,
FRSKY_RX_D16LBT,
FRSKY_RX_D8
FRSKY_RX_D8 =0,
FRSKY_RX_D16FCC =1,
FRSKY_RX_D16LBT =2,
FRSKY_RX_D16v2FCC =3,
FRSKY_RX_D16v2LBT =4,
};
enum {
@@ -40,7 +43,7 @@ enum {
const PROGMEM uint8_t frsky_rx_common_reg[][2] = {
{CC2500_02_IOCFG0, 0x01},
{CC2500_18_MCSM0, 0x18},
{CC2500_07_PKTCTRL1, 0x04},
{CC2500_07_PKTCTRL1, 0x05},
{CC2500_3E_PATABLE, 0xFF},
{CC2500_0C_FSCTRL0, 0},
{CC2500_0D_FREQ2, 0x5C},
@@ -62,7 +65,7 @@ const PROGMEM uint8_t frsky_rx_common_reg[][2] = {
{CC2500_2D_TEST1, 0x31},
{CC2500_2E_TEST0, 0x0B},
{CC2500_03_FIFOTHR, 0x07},
{CC2500_09_ADDR, 0x00},
{CC2500_09_ADDR, 0x03},
};
const PROGMEM uint8_t frsky_rx_d16fcc_reg[][2] = {
@@ -116,29 +119,38 @@ static void __attribute__((unused)) frsky_rx_strobe_rx()
}
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 };
const uint8_t frsky_rx_length[] = { FRSKY_RX_D8_LENGTH, FRSKY_RX_D16FCC_LENGTH, FRSKY_RX_D16LBT_LENGTH, FRSKY_RX_D16v2_LENGTH, FRSKY_RX_D16v2_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;
switch (frsky_rx_format)
{
case FRSKY_RX_D16v2FCC:
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]));
if(frsky_rx_format==FRSKY_RX_D16v2FCC)
{
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05); // Enable CRC
CC2500_WriteReg(CC2500_17_MCSM1, 0x0E); // Go/Stay in RX mode
CC2500_WriteReg(CC2500_11_MDMCFG3, 0x84); // bitrate 70K->77K
}
break;
case FRSKY_RX_D16v2LBT:
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]));
if(frsky_rx_format==FRSKY_RX_D16v2LBT)
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05); // Enable CRC
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_23_FSCAL3, 0x89);
break;
}
CC2500_WriteReg(CC2500_0A_CHANNR, 0); // bind channel
rx_disable_lna = IS_POWER_FLAG_on;
@@ -169,16 +181,71 @@ static void __attribute__((unused)) frsky_rx_calibrate()
}
}
static uint8_t __attribute__((unused)) frskyx_rx_check_crc()
static uint8_t __attribute__((unused)) frskyx_rx_check_crc_id(bool bind,bool init)
{
// check D8 checksum
/*debugln("RX");
for(uint8_t i=0; i<packet_length;i++)
debug(" %02X",packet[i]);
debugln("");*/
if(bind && packet[0]!=packet_length-1 && packet[1] !=0x03 && packet[2] != 0x01)
return false;
uint8_t offset=bind?3:1;
// 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;
{
if((packet[packet_length+1] & 0x80) != 0x80) // Check CRC_OK flag in status byte 2
return false; // Bad CRC
if(init)
{//Save TXID
rx_tx_addr[3] = packet[3];
rx_tx_addr[2] = packet[4];
rx_tx_addr[1] = packet[17];
}
else
if(rx_tx_addr[3] != packet[offset] || rx_tx_addr[2] != packet[offset+1] || rx_tx_addr[1] != packet[bind?17:5])
return false; // Bad address
return true; // Full match
}
// Check D16v2 checksum
if (frsky_rx_format == FRSKY_RX_D16v2LBT || frsky_rx_format == FRSKY_RX_D16v2FCC)
if((packet[packet_length+1] & 0x80) != 0x80) // Check CRC_OK flag in status byte 2
return false;
//debugln("HW Checksum ok");
// Check D16 checksum
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_length - 5); // Compute crc
uint16_t rcrc = (packet[packet_length-2] << 8) | (packet[packet_length-1] & 0xff); // Received crc
if(lcrc != rcrc)
return false; // Bad CRC
//debugln("Checksum ok");
if (bind && (frsky_rx_format == FRSKY_RX_D16v2LBT || frsky_rx_format == FRSKY_RX_D16v2FCC))
for(uint8_t i=3; i<packet_length-2; i++) //unXOR bind packet
packet[i] ^= 0xA7;
uint8_t offset2=0;
if (bind && (frsky_rx_format == FRSKY_RX_D16LBT || frsky_rx_format == FRSKY_RX_D16FCC))
offset2=6;
if(init)
{//Save TXID
rx_tx_addr[3] = packet[3];
rx_tx_addr[2] = packet[4];
rx_tx_addr[1] = packet[5+offset2];
rx_tx_addr[0] = packet[6+offset2]; // RXnum
}
else
if(rx_tx_addr[3] != packet[offset] || rx_tx_addr[2] != packet[offset+1] || rx_tx_addr[1] != packet[offset+2+offset2])
return false; // Bad address
//debugln("Address ok");
if(!bind && rx_tx_addr[0] != packet[6])
return false; // Bad RX num
//debugln("Match");
return true; // Full match
}
static void __attribute__((unused)) frsky_rx_build_telemetry_packet()
@@ -189,8 +256,24 @@ static void __attribute__((unused)) frsky_rx_build_telemetry_packet()
uint8_t idx = 0;
uint8_t i;
if (frsky_rx_format == FRSKY_RX_D16FCC || frsky_rx_format == FRSKY_RX_D16LBT) {
// decode D16 channels
if (frsky_rx_format == FRSKY_RX_D8)
{// 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);
}
}
else
{// 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];
@@ -211,22 +294,6 @@ static void __attribute__((unused)) frsky_rx_build_telemetry_packet()
}
}
}
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;
@@ -246,6 +313,49 @@ static void __attribute__((unused)) frsky_rx_build_telemetry_packet()
}
}
static void __attribute__((unused)) frsky_rx_data()
{
uint16_t temp = FRSKY_RX_EEPROM_OFFSET;
frsky_rx_format = eeprom_read_byte((EE_ADDR)temp++) % FRSKY_RX_FORMATS;
rx_tx_addr[3] = eeprom_read_byte((EE_ADDR)temp++);
rx_tx_addr[2] = eeprom_read_byte((EE_ADDR)temp++);
rx_tx_addr[1] = eeprom_read_byte((EE_ADDR)temp++);
rx_tx_addr[0] = RX_num;
frsky_rx_finetune = eeprom_read_byte((EE_ADDR)temp++);
debug("format=%d, ", frsky_rx_format);
debug("addr[3]=%02X, ", rx_tx_addr[3]);
debug("addr[2]=%02X, ", rx_tx_addr[2]);
debug("addr[1]=%02X, ", rx_tx_addr[1]);
debug("rx_num=%02X, ", rx_tx_addr[0]);
debugln("tune=%d", (int8_t)frsky_rx_finetune);
if(frsky_rx_format != FRSKY_RX_D16v2LBT && frsky_rx_format != FRSKY_RX_D16v2FCC)
{//D8 & D16v1
for (uint8_t ch = 0; ch < 47; ch++)
hopping_frequency[ch] = eeprom_read_byte((EE_ADDR)temp++);
}
else
{
FrSkyFormat=frsky_rx_format == FRSKY_RX_D16v2FCC?0:2;
FrSkyX2_init_hop();
}
debug("ch:");
for (uint8_t ch = 0; ch < 47; ch++)
debug(" %02X", hopping_frequency[ch]);
debugln("");
frsky_rx_initialise_cc2500();
frsky_rx_calibrate();
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // FS_AUTOCAL = manual
CC2500_WriteReg(CC2500_09_ADDR, rx_tx_addr[3]); // 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;
}
uint16_t initFrSky_Rx()
{
state = 0;
@@ -254,44 +364,27 @@ uint16_t initFrSky_Rx()
rx_data_started = false;
frsky_rx_finetune = 0;
telemetry_link = 0;
if (IS_BIND_IN_PROGRESS) {
packet_count = 0;
if (IS_BIND_IN_PROGRESS)
{
frsky_rx_format = FRSKY_RX_D8;
frsky_rx_initialise_cc2500();
phase = FRSKY_RX_TUNE_START;
debugln("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;
}
else
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 ((prev_option != option) && (phase >= FRSKY_RX_DATA))
{
if (option == 0)
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
else
@@ -299,149 +392,199 @@ uint16_t FrSky_Rx_callback()
prev_option = option;
}
if (rx_disable_lna != IS_POWER_FLAG_on) {
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) {
if(frskyx_rx_check_crc()) {
switch(phase)
{
case FRSKY_RX_TUNE_START:
if (len == packet_length + 2) //+2=RSSI+LQI+CRC
{
CC2500_ReadData(packet, len);
if(frskyx_rx_check_crc_id(true,true))
{
frsky_rx_finetune = -127;
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
phase = FRSKY_RX_TUNE_LOW;
debugln("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;
frsky_rx_format = (frsky_rx_format + 1) % FRSKY_RX_FORMATS; // switch to next format (D8, D16FCC, D16LBT, D16v2FCC, D16v2LBT)
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 (frskyx_rx_check_crc()) {
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 (frskyx_rx_check_crc()) {
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 (frskyx_rx_check_crc()) {
if (packet[5] <= 0x2D) {
for (ch = 0; ch < 5; ch++)
hopping_frequency[packet[5]+ch] = packet[6+ch];
state |= 1 << (packet[5] / 5);
case FRSKY_RX_TUNE_LOW:
if (len == packet_length + 2) //+2=RSSI+LQI+CRC
{
CC2500_ReadData(packet, len);
if(frskyx_rx_check_crc_id(true,false)) {
tune_low = frsky_rx_finetune;
frsky_rx_finetune = 127;
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
phase = FRSKY_RX_TUNE_HIGH;
debugln("FRSKY_RX_TUNE_HIGH");
frsky_rx_strobe_rx();
return 1000;
}
}
if (state == 0x3ff) {
debugln("bind complete");
frsky_rx_calibrate();
rx_tx_addr[0] = packet[3]; // TXID
rx_tx_addr[1] = packet[4]; // TXID
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);
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[0]);
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[1]);
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[2]);
eeprom_write_byte((EE_ADDR)temp++, frsky_rx_finetune);
for (ch = 0; ch < 47; ch++)
eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[ch]);
BIND_DONE;
}
frsky_rx_finetune += 1;
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
frsky_rx_strobe_rx();
}
return 1000;
return 18000;
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);
case FRSKY_RX_TUNE_HIGH:
if (len == packet_length + 2) //+2=RSSI+LQI+CRC
{
CC2500_ReadData(packet, len);
if(frskyx_rx_check_crc_id(true,false)) {
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;
debugln("FRSKY_RX_TUNE_HIGH");
}
else
{
phase = FRSKY_RX_TUNE_START;
debugln("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 + 2) //+2=RSSI+LQI+CRC
{
CC2500_ReadData(packet, len);
if(frskyx_rx_check_crc_id(true,false)) {
if(frsky_rx_format != FRSKY_RX_D16v2LBT && frsky_rx_format != FRSKY_RX_D16v2FCC)
{// D8 & D16v1
if(packet[5] <= 0x2D)
{
for (ch = 0; ch < 5; ch++)
hopping_frequency[packet[5]+ch] = packet[6+ch];
state |= 1 << (packet[5] / 5);
}
}
else
state=0x3FF; //No hop table for D16v2
if (state == 0x3FF)
{
debugln("Bind complete");
BIND_DONE;
// store format, finetune setting, txid, channel list
uint16_t temp = FRSKY_RX_EEPROM_OFFSET;
if(sub_protocol==FRSKY_CLONE)
{
if(frsky_rx_format==FRSKY_RX_D8)
temp=FRSKYD_CLONE_EEPROM_OFFSET;
else if(frsky_rx_format == FRSKY_RX_D16FCC || frsky_rx_format == FRSKY_RX_D16LBT)
temp=FRSKYX_CLONE_EEPROM_OFFSET;
else
temp=FRSKYX2_CLONE_EEPROM_OFFSET;
}
eeprom_write_byte((EE_ADDR)temp++, frsky_rx_format);
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[3]);
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[2]);
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[1]);
if(sub_protocol==FRSKY_RX)
eeprom_write_byte((EE_ADDR)temp++, frsky_rx_finetune);
if(frsky_rx_format != FRSKY_RX_D16v2FCC && frsky_rx_format != FRSKY_RX_D16v2LBT)
for (ch = 0; ch < 47; ch++)
eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[ch]);
frsky_rx_data();
debugln("FRSKY_RX_DATA");
}
}
frsky_rx_strobe_rx();
}
return 1000;
case FRSKY_RX_DATA:
if (len == packet_length + 2) //+2=RSSI+LQI+CRC
{
CC2500_ReadData(packet, len);
if(frskyx_rx_check_crc_id(false,false))
{
RX_RSSI = packet[len-2];
if(RX_RSSI >= 128)
RX_RSSI -= 128;
else
RX_RSSI += 128;
bool chanskip_valid=true;
// hop to next channel
if (frsky_rx_format != FRSKY_RX_D8)
{//D16v1 & D16v2
if(rx_data_started)
{
if(frsky_rx_chanskip != (((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2)))
{
chanskip_valid=false; // chanskip value has changed which surely indicates a bad frame
packet_count++;
if(packet_count>5) // the TX must have changed chanskip...
frsky_rx_chanskip = ((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2); // chanskip init
}
else
packet_count=0;
}
else
frsky_rx_chanskip = ((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2); // chanskip init
}
hopping_frequency_no = (hopping_frequency_no + frsky_rx_chanskip) % 47;
frsky_rx_set_channel(hopping_frequency_no);
if(chanskip_valid)
{
if (telemetry_link == 0)
{ // send channels to TX
frsky_rx_build_telemetry_packet();
telemetry_link = 1;
}
pps_counter++;
}
rx_data_started = true;
read_retry = 0;
}
}
// packets per second
if (millis() - pps_timer >= 1000) {
pps_timer = millis();
debugln("%d pps", pps_counter);
RX_LQI = pps_counter;
if(pps_counter==0) // no packets for 1 sec or more...
{// restart the search
rx_data_started=false;
packet_count=0;
}
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 (telemetry_link == 0) { // send channels to TX
frsky_rx_build_telemetry_packet();
telemetry_link = 1;
}
rx_data_started = true;
read_retry = 0;
pps_counter++;
if(rx_data_started)
read_retry = 0;
else
read_retry = -50; // retry longer until first packet is catched
}
}
// 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;
break;
}
return 1000;
}

View File

@@ -16,7 +16,7 @@ Multiprotocol is distributed in the hope that it will be useful,
#if defined(GD00X_NRF24L01_INO)
#include "iface_xn297l.h"
#include "iface_nrf250k.h"
//#define FORCE_GD00X_ORIGINAL_ID

View File

@@ -29,10 +29,21 @@ enum {
HOTT_START = 0x00,
HOTT_CAL = 0x01,
HOTT_DATA1 = 0x02,
HOTT_RX1 = 0x03,
HOTT_RX2 = 0x04,
HOTT_DATA2 = 0x03,
HOTT_RX1 = 0x04,
HOTT_RX2 = 0x05,
};
#ifdef HOTT_FW_TELEMETRY
#define HOTT_SENSOR_TYPE 6
#define HOTT_SENSOR_SEARCH_PERIOD 2000
uint8_t HOTT_sensor_cur=0;
uint8_t HOTT_sensor_pages=0;
uint8_t HOTT_sensor_valid=false;
uint8_t HOTT_sensor_ok[HOTT_SENSOR_TYPE];
uint8_t HOTT_sensor_seq=0;
#endif
#define HOTT_FREQ0_VAL 0x6E
// Some important initialization parameters, all others are either default,
@@ -103,7 +114,7 @@ static void __attribute__((unused)) HOTT_tune_freq()
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
phase = HOTT_START; // Restart the tune process if option is changed to get good tuned values
}
}
@@ -134,36 +145,37 @@ static void __attribute__((unused)) HOTT_init()
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);
memcpy(rx_tx_addr,"\x7C\x94\x00\x0D\x50",5); //TX1
memcpy(rx_tx_addr,"\xEA\x4D\x00\x01\x50",5); //TX2
#endif
memset(&packet[30],0xFF,9);
packet[39]=0x07; // unknown and constant
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;
debug("RXID: ");
for(uint8_t i=0;i<5;i++)
{
packet[45+i]=eeprom_read_byte((EE_ADDR)(addr+i));
debug(" %02X",packet[45+i]);
}
debugln("");
}
}
static void __attribute__((unused)) HOTT_data_packet()
static void __attribute__((unused)) HOTT_prep_data_packet()
{
packet[2] = hopping_frequency_no;
packet[3] = 0x00; // used for failsafe but may also be used for additional channels
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)
@@ -210,31 +222,45 @@ static void __attribute__((unused)) HOTT_data_packet()
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(IS_BIND_DONE)
{
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
static uint8_t prev_SerialRX_val=0;
if(HoTT_SerialRX)
{//Text mode
uint8_t sensor=HoTT_SerialRX_val&0xF0;
if((sensor&0x80) && sensor!=0xF0 && (HoTT_SerialRX_val&0x0F) >= 0x07)
{//Valid Text query
if(sensor==0x80) HoTT_SerialRX_val&=0x0F; // RX only
if(prev_SerialRX_val!=HoTT_SerialRX_val)
{
prev_SerialRX_val=HoTT_SerialRX_val;
packet[28] = HoTT_SerialRX_val; // send the button being pressed only once
}
else
packet[28] = HoTT_SerialRX_val | 0x0F; // no button pressed
packet[29] = 0x01; // 0x01->Text config menu
}
}
else
packet[28] = 0xDF; // no touch pressed
packet[29] = 0x01; // 0x01->config menu
{
packet[28] = 0x89+HOTT_sensor_cur; // 0x89/8A/8B/8C/8D/8E during normal packets
if(sub_protocol == HOTT_SYNC)
packet[29] = ((HOTT_sensor_seq+1)<<3) | 2; // Telemetry packet sequence
else
packet[29] = 0x02;
//debugln("28=%02X,29=%02X",packet[28],packet[29]);
}
}
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
{
packet[28] = 0x80; // no sensor
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->text config menu, 0x0A->no more RX telemetry
}
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
CC2500_WriteReg(CC2500_06_PKTLEN, 0x32);
CC2500_WriteData(packet, HOTT_TX_PACKET_LEN);
CC2500_WriteReg(CC2500_06_PKTLEN, HOTT_TX_PACKET_LEN);
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, 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++)
@@ -248,10 +274,6 @@ static void __attribute__((unused)) HOTT_data_packet()
uint16_t ReadHOTT()
{
#ifdef HOTT_FW_TELEMETRY
static uint8_t pps_counter=0;
#endif
switch(phase)
{
case HOTT_START:
@@ -268,38 +290,86 @@ uint16_t ReadHOTT()
hopping_frequency_no = 0;
rf_ch_num=hopping_frequency[hopping_frequency_no];
counter = 0;
CC2500_SetTxRxMode(RX_EN);
phase = HOTT_DATA1;
}
return 2000;
/* Work cycle: 10ms */
case HOTT_DATA1:
//TX
//Set RF freq, setup LBT and prep packet
#ifdef MULTI_SYNC
telemetry_set_input_sync(HOTT_PACKET_PERIOD);
#endif
//Clear all
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SNOP);
CC2500_Strobe(CC2500_SFTX);
CC2500_Strobe(CC2500_SFRX);
CC2500_WriteReg(CC2500_04_SYNC1, 0xD3);
CC2500_WriteReg(CC2500_05_SYNC0, 0x91);
//Set RF freq
HOTT_tune_freq();
HOTT_tune_chan_fast();
HOTT_data_packet();
phase = HOTT_RX1;
return 4500;
//Setup LBT
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0xFF);
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x0C);
CC2500_Strobe(CC2500_SRX);
//Prep packet
HOTT_prep_data_packet();
//Listen
CC2500_WriteReg(CC2500_17_MCSM1, 0x10); //??
CC2500_WriteReg(CC2500_18_MCSM0, 0x18); //??
CC2500_Strobe(CC2500_SRX); //??
phase++; //HOTT_DATA2
return 1095;
case HOTT_DATA2:
//LBT
if((CC2500_ReadReg(CC2500_38_PKTSTATUS | CC2500_READ_BURST)&0x10)==0)
{ //Channel is busy
LBT_POWER_on; // Reduce to low power before transmitting
debugln("Busy %d",rf_ch_num);
}
CC2500_WriteReg(CC2500_17_MCSM1, 0x00); //??
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); //??
CC2500_SetPower();
//Send packet
CC2500_SetTxRxMode(TX_EN);
CC2500_Strobe(CC2500_STX);
phase++; //HOTT_RX1
return 3880;
case HOTT_RX1:
//Clear all
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SFTX);
CC2500_Strobe(CC2500_SFRX);
//RX
if(packet[29] & 0xF8)
{// binary telemetry
CC2500_WriteReg(CC2500_04_SYNC1, 0x2C);
CC2500_WriteReg(CC2500_05_SYNC0, 0x6E);
}
CC2500_SetTxRxMode(RX_EN);
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0xC7);
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x09);
CC2500_WriteReg(CC2500_06_PKTLEN, HOTT_RX_PACKET_LEN);
CC2500_Strobe(CC2500_SRX);
phase = HOTT_RX2;
return 4500;
phase++; //HOTT_RX2
return 4025;
case HOTT_RX2:
//Telemetry
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
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((packet_in[HOTT_RX_PACKET_LEN+1]&0x80) && memcmp(rx_tx_addr,packet_in,5)==0)
{ // CRC OK and TX ID matches
if(IS_BIND_IN_PROGRESS)
{
//GR-16: D4 20 F2 E6 F6 31 BD 01 00 90 00 FF 03 00 9E 1B 00 00 00 00 00 00
//GR-12L: D4 20 F2 E6 F6 6E EE 01 00 B1 00 FF 03 00 0E 08 10 00 02 00 00 00
//Vector: D4 20 F2 E6 F6 00 00 3A 01 A1 00 00 1A 24 35 1A 00 24 00 00 00 1A
// -----TXID----- -----RXID----- ---------------Unknown-------------
debug("B:");
for(uint8_t i=0;i<HOTT_RX_PACKET_LEN;i++)
debug(" %02X", packet_in[i]);
@@ -317,16 +387,16 @@ uint16_t ReadHOTT()
// [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
// Normal telem page 0 = 0x55, 0x32, 0x38, 0x55, 0x64, 0x32, 0xD0, 0x07, 0x00, 0x55
// Page 0 [12] = [21] = [15]
// Page 0 [13] = RX_Voltage Cur*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 [15] = RX_RSSI CC2500 formated (a<128:a/2-71dBm, a>=128:(a-256)/2-71dBm)
// Page 0 [16] = RX_LQI in %
// Page 0 [17] = RX_Voltage Min*10 in V
// Page 0 [18,19] = [19]<<8+[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
@@ -334,22 +404,78 @@ uint16_t ReadHOTT()
// 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[0]= packet_in[HOTT_RX_PACKET_LEN];
packet_in[1]= TX_LQI;
debug("T=");
bool send_telem=true;
if(packet[29]==1)
{ //Text mode
HOTT_sensor_pages = 0;
HOTT_sensor_valid = false;
packet_in[10] = 0x80; // Marking telem Text mode
packet_in[12] = 0;
for(uint8_t i=0; i<HOTT_SENSOR_TYPE;i++)
packet_in[12] |= HOTT_sensor_ok[i]<<i; // Send detected sensors
}
else
{ //Binary sensor
HOTT_sensor_seq++; // Increment RX sequence counter
HOTT_sensor_seq %= 5; // 5 pages in binary mode per sensor
if(state==0 && HOTT_sensor_ok[0]==false && HOTT_sensor_ok[1]==false && HOTT_sensor_ok[2]==false && HOTT_sensor_ok[3]==false && HOTT_sensor_ok[4]==false && HOTT_sensor_ok[5]==false)
HOTT_sensor_seq=0; // No sensors always ask page 0
if(state)
state--;
if( packet_in[11]==1 ) // Page 1
{
if( packet_in[12] == (HOTT_sensor_cur+9)<<4 )
{ //Requested sensor is sending: 0x90/A0/B0/C0/D0/E0
HOTT_sensor_pages = 0; // Sensor first page received
HOTT_sensor_valid = true; // Data from the expected sensor is being received
HOTT_sensor_ok[(packet_in[12]>>4)-9]=true;
}
else
{
HOTT_sensor_valid = false;
HOTT_sensor_pages = 0x1E; // Switch to next sensor
}
}
if(packet_in[11])
{ //Page != 0
if(HOTT_sensor_valid) // Valid
{
packet_in[10] = HOTT_sensor_cur+9; // Mark telem with sensor ID
HOTT_sensor_pages |= 1<<packet_in[11]; // Page received
}
else
send_telem=false; // Do not send
}
else
packet_in[10]=0; // Mark telem with sensor 0=RX
}
debug("T%d=",send_telem);
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;
if(send_telem)
telemetry_link=2;
if((HOTT_sensor_pages&0x1E) == 0x1E) // All 4 pages received from the sensor
{ //Next sensor
uint8_t loop=0;
do
{
HOTT_sensor_cur++; // Switch to next sensor
HOTT_sensor_cur %= HOTT_SENSOR_TYPE;
loop++;
}
while(HOTT_sensor_ok[HOTT_sensor_cur]==false && loop<HOTT_SENSOR_TYPE+1 && state==0);
HOTT_sensor_valid=false;
HOTT_sensor_pages=0;
HOTT_sensor_seq=0;
debugln("Sensor:%02X",HOTT_sensor_cur+9);
}
}
pps_counter++;
#endif
@@ -360,10 +486,18 @@ uint16_t ReadHOTT()
if(packet_count>=100)
{
TX_LQI=pps_counter;
if(pps_counter==0)
{ // lost connection with RX, power cycle? research sensors again.
HOTT_sensor_cur=3;
HOTT_sensor_seq=0;
HOTT_sensor_valid=false;
for(uint8_t i=0; i<HOTT_SENSOR_TYPE;i++)
HOTT_sensor_ok[i]=false; // no sensors detected
state=HOTT_SENSOR_SEARCH_PERIOD;
}
pps_counter=packet_count=0;
}
#endif
CC2500_Strobe(CC2500_SFRX); //Flush the RXFIFO
phase=HOTT_DATA1;
return 1000;
}
@@ -375,10 +509,17 @@ 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;
HOTT_sensor_cur=3;
HOTT_sensor_pages=0;
HOTT_sensor_valid=false;
HOTT_sensor_seq=0;
for(uint8_t i=0; i<HOTT_SENSOR_TYPE;i++)
HOTT_sensor_ok[i]=false; // no sensors detected
packet_count=0;
state=HOTT_SENSOR_SEARCH_PERIOD;
#endif
phase = HOTT_START;
return 10000;

View File

@@ -14,16 +14,16 @@
*/
// Compatible with FZ-410 TX
#if defined(FLYZONE_A7105_INO)
#if defined(HEIGHT_A7105_INO)
#include "iface_a7105.h"
//#define FLYZONE_FORCEID
//#define HEIGHT_FORCEID
#define FLYZONE_BIND_COUNT 220 // 5 sec
#define FLYZONE_BIND_CH 0x18 // TX, RX for bind end is 0x17
#define HEIGHT_BIND_COUNT 220 // 5 sec
#define HEIGHT_BIND_CH 0x18 // TX, RX for bind end is 0x17
static void __attribute__((unused)) flyzone_build_packet()
static void __attribute__((unused)) HEIGHT_build_packet()
{
packet[0] = 0xA5;
packet[1] = rx_tx_addr[2];
@@ -32,12 +32,18 @@ static void __attribute__((unused)) flyzone_build_packet()
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] = 0xFF;
packet[7] = convert_channel_8b(CH5); //00..80..FF
if(sub_protocol == HEIGHT_8CH)
{
packet[8] = convert_channel_8b(CH6); //00..80..FF
packet[9] = convert_channel_8b(CH7); //00..80..FF
packet[10] = convert_channel_8b(CH8); //00..80..FF
}
}
uint16_t ReadFlyzone()
uint16_t ReadHeight()
{
#ifndef FORCE_FLYZONE_TUNING
#ifndef FORCE_HEIGHT_TUNING
A7105_AdjustLOBaseFreq(1);
#endif
if(IS_BIND_IN_PROGRESS)
@@ -45,7 +51,7 @@ uint16_t ReadFlyzone()
packet[0] = 0x1B;
packet[1] = rx_tx_addr[2];
packet[2] = rx_tx_addr[3];
A7105_WriteData(3, FLYZONE_BIND_CH);
A7105_WriteData(3, HEIGHT_BIND_CH);
if (bind_counter--==0)
BIND_DONE;
return 22700;
@@ -58,8 +64,8 @@ uint16_t ReadFlyzone()
#ifdef MULTI_SYNC
telemetry_set_input_sync(20*1500);
#endif
flyzone_build_packet();
A7105_WriteData(8, hopping_frequency[0]);
HEIGHT_build_packet();
A7105_WriteData(sub_protocol?11:8, hopping_frequency[0]);
A7105_SetPower();
}
else
@@ -72,14 +78,14 @@ uint16_t ReadFlyzone()
return 1500;
}
uint16_t initFlyzone()
uint16_t initHeight()
{
A7105_Init();
hopping_frequency[0]=((random(0xfefefefe) & 0x0F)+2)<<2;
hopping_frequency[1]=hopping_frequency[0]+0x50;
#ifdef FLYZONE_FORCEID
#ifdef HEIGHT_FORCEID
rx_tx_addr[2]=0x35;
rx_tx_addr[3]=0xD0;
hopping_frequency[0]=0x18;
@@ -87,7 +93,7 @@ uint16_t initFlyzone()
#endif
phase=255;
bind_counter = FLYZONE_BIND_COUNT;
bind_counter = HEIGHT_BIND_COUNT;
return 2400;
}
#endif

View File

@@ -146,6 +146,11 @@ static void __attribute__((unused)) HITEC_build_packet()
break;
case 0x7B:
packet[5]=hopping_frequency[13]>>1; // if not there the Optima link is jerky...
packet[14]=0x2A;
packet[15]=0x46; // unknown but if 0x45 then 17=0x46, if 0x46 then 17=0x46 or 0x47, if 0x47 then 0x45 or 0x46
packet[16]=0x2A;
packet[17]=0x47;
packet[18]=0x2A;
break;
}
if(sub_protocol==MINIMA)
@@ -302,8 +307,8 @@ uint16_t ReadHITEC()
{ // 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;
for(uint8_t i=5;i<10;i++)
if(packet_in[i]!=i) check=false;
if((packet_in[4]&0xF0)==0x70 && check)
{
bind_phase=packet_in[4]+1;

View 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/>.
*/
// compatible with JJRC345
#if defined(JJRC345_NRF24L01_INO)
#include "iface_nrf24l01.h"
//#define JJRC345_FORCE_ID
#define JJRC345_PACKET_PERIOD 7450 // Timeout for callback in uSec
#define JJRC345_INITIAL_WAIT 500
#define JJRC345_PACKET_SIZE 16
#define JJRC345_RF_BIND_CHANNEL 5
#define JJRC345_BIND_COUNT 500
#define JJRC345_NUM_CHANNELS 4
enum JJRC345_FLAGS {
// flags going to packet[8]
JJRC345_FLAG_HEADLESS = 0x40,
JJRC345_FLAG_RTH = 0x80,
};
static uint8_t __attribute__((unused)) JJRC345_convert_channel(uint8_t num)
{
uint8_t val=convert_channel_8b(num);
// 7E..60..41..01, 80 center, 81..C1..E0..FE
if(val<0x80)
{
val=0x80-val; // 80..01
if(val>0x7E)
val=0x7E; // 7E..01
}
else if(val>0xFE)
val=0xFE; // 81..FE
return val;
}
static void __attribute__((unused)) JJRC345_send_packet()
{
packet[0] = 0x00;
packet[2] = 0x00;
if (IS_BIND_IN_PROGRESS)
{ //00 05 00 0A 46 4A 41 47 00 00 40 46 A5 4A F1 18
packet[1] = JJRC345_RF_BIND_CHANNEL;
packet[4] = hopping_frequency[0];
packet[5] = hopping_frequency[1];
packet[6] = hopping_frequency[2];
packet[7] = hopping_frequency[3];
packet[12] = 0xa5;
}
else
{ //00 41 00 0A 00 80 80 80 00 00 40 46 00 49 F1 18
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
hopping_frequency_no++;
hopping_frequency_no %= JJRC345_NUM_CHANNELS;
packet[1] = hopping_frequency[hopping_frequency_no]; // next packet will be sent on this channel
packet[4] = convert_channel_8b(THROTTLE); // throttle: 00..FF
packet[5] = JJRC345_convert_channel(RUDDER); // rudder: 70..60..41..01, 80 center, 81..C1..E0..F0
packet[6] = JJRC345_convert_channel(ELEVATOR); // elevator: 70..60..41..01, 80 center, 81..C1..E0..F0
packet[7] = JJRC345_convert_channel(AILERON); // aileron: 70..60..41..01, 80 center, 81..C1..E0..F0
if(CH5_SW) //Flip
{
if(packet[6]>0xF0)
packet[6]=0xFF;
else if(packet[6]<0x80 && packet[6]>0x70)
packet[6]=0x7F;
if(packet[7]>0xF0)
packet[7]=0xFF;
else if(packet[7]<0x80 && packet[7]>0x70)
packet[7]=0x7F;
}
packet[12] = 0x02; // Rate: 00-01-02
}
packet[3] = 0x00; // Checksum upper bits
packet[8] = 0x00 // Rudder trim, 00 when not used, 01..1F when trimmed left, 20..3F
| GET_FLAG(CH6_SW,JJRC345_FLAG_HEADLESS) // Headless mode: 00 normal, 40 headless
| GET_FLAG(CH7_SW,JJRC345_FLAG_RTH); // RTH: 80 active
packet[9] = 0; // Elevator trim, 00 when not used, 20..25 when trimmed up, 0..1F when trimmed down
packet[10] = 0x40; // Aileron trim, 40 when not used, 40..5F when trimmed left, 61..7F when trimmed right
packet[11] = hopping_frequency[0]; // First hopping frequency
// Checksum
uint16_t sum=2;
for (uint8_t i = 0; i < 13; i++)
sum += packet[i];
packet[13]=sum;
packet[3]=((sum>>8)<<2)+2;
// TX ID
packet[14] = rx_tx_addr[2];
packet[15] = rx_tx_addr[3];
// Power on, TX mode
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, JJRC345_PACKET_SIZE);
NRF24L01_SetPower(); // Set tx_power
}
static void __attribute__((unused)) JJRC345_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_SetTXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5);
NRF24L01_WriteReg(NRF24L01_05_RF_CH, JJRC345_RF_BIND_CHANNEL); // Bind channel
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); // 1 Mbps
NRF24L01_SetPower();
}
uint16_t JJRC345_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(JJRC345_PACKET_PERIOD);
#endif
if(IS_BIND_IN_PROGRESS)
{
if (bind_counter)
bind_counter--;
else
BIND_DONE;
}
JJRC345_send_packet();
return JJRC345_PACKET_PERIOD;
}
static void __attribute__((unused)) JJRC345_initialize_txid()
{
calc_fh_channels(JJRC345_NUM_CHANNELS);
#ifdef JJRC345_FORCE_ID
//TX 1
rx_tx_addr[2]=0x1B;
rx_tx_addr[3]=0x12;
hopping_frequency[0] = 0x3f;
hopping_frequency[1] = 0x49;
hopping_frequency[2] = 0x47;
hopping_frequency[3] = 0x47;
//TX 2
rx_tx_addr[2]=0xF1;
rx_tx_addr[3]=0x18;
hopping_frequency[0] = 0x46;
hopping_frequency[1] = 0x4A;
hopping_frequency[2] = 0x41;
hopping_frequency[3] = 0x47;
#endif
}
uint16_t initJJRC345(void)
{
BIND_IN_PROGRESS; // autobind protocol
bind_counter = JJRC345_BIND_COUNT;
JJRC345_initialize_txid();
JJRC345_init();
return JJRC345_INITIAL_WAIT;
}
#endif

View File

@@ -16,7 +16,7 @@ Multiprotocol is distributed in the hope that it will be useful,
#if defined(KF606_NRF24L01_INO)
#include "iface_xn297l.h"
#include "iface_nrf250k.h"
//#define FORCE_KF606_ORIGINAL_ID

View File

@@ -0,0 +1,116 @@
/*
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(KYOSHO_A7105_INO)
#include "iface_a7105.h"
//#define KYOSHO_FORCE_ID
//Kyosho constants & variables
#define KYOSHO_BIND_COUNT 2500
static void __attribute__((unused)) kyosho_send_packet()
{
//ID
packet[1] = rx_tx_addr[0];
packet[2] = rx_tx_addr[1];
packet[3] = rx_tx_addr[2];
packet[4] = rx_tx_addr[3];
//unknown may be RX ID on some other remotes
memset(packet+5,0xFF,4);
if(IS_BIND_IN_PROGRESS)
{
packet[ 0] = 0xBC; // bind indicator
packet[ 9] &= 0x01;
packet[ 9] ^= 0x01; // high/ low part of the RF table
packet[10] = 0x00;
//RF table
for(uint8_t i=0; i<16;i++)
packet[i+11]=hopping_frequency[i+(packet[9]<<4)];
//unknwon
packet[27] = 0x05;
packet[28] = 0x00;
memset(packet+29,0xFF,8);
//frequency hop during bind
if(packet[9])
rf_ch_num=0x8C;
else
rf_ch_num=0x0D;
}
else
{
packet[ 0] = 0x58; // normal packet
//14 channels: steering, throttle, ...
for(uint8_t i = 0; i < 14; i++)
{
uint16_t temp=convert_channel_ppm(i);
packet[9 + i*2]=temp&0xFF; // low byte of servo timing(1000-2000us)
packet[10 + i*2]=(temp>>8)&0xFF; // high byte of servo timing(1000-2000us)
}
rf_ch_num=hopping_frequency[hopping_frequency_no];
hopping_frequency_no++;
packet[34] |= (hopping_frequency_no&0x0F)<<4;
packet[36] |= (hopping_frequency_no&0xF0); // last byte is ending with F on the dumps so let's see
hopping_frequency_no &= 0x1F;
}
// debug("ch=%02X P=",rf_ch_num);
// for(uint8_t i=0; i<37; i++)
// debug("%02X ", packet[i]);
// debugln("");
A7105_WriteData(37, rf_ch_num);
}
uint16_t ReadKyosho()
{
#ifndef FORCE_KYOSHO_TUNING
A7105_AdjustLOBaseFreq(1);
#endif
if(IS_BIND_IN_PROGRESS)
{
bind_counter--;
if (bind_counter==0)
BIND_DONE;
}
else
{
A7105_SetPower();
#ifdef MULTI_SYNC
telemetry_set_input_sync(3852);
#endif
}
kyosho_send_packet();
return 3852;
}
uint16_t initKyosho()
{
A7105_Init();
// compute 32 channels from ID
calc_fh_channels(32);
hopping_frequency_no=0;
#ifdef KYOSHO_FORCE_ID
memcpy(rx_tx_addr,"\x3A\x39\x37\x00",4);
memcpy(hopping_frequency,"\x29\x4C\x67\x92\x31\x1C\x77\x18\x23\x6E\x81\x5C\x8F\x5A\x51\x94\x7A\x12\x45\x6C\x7F\x1E\x0D\x88\x63\x8C\x4F\x37\x26\x61\x2C\x8A",32);
#endif
if(IS_BIND_IN_PROGRESS)
bind_counter = KYOSHO_BIND_COUNT;
return 2000;
}
#endif

View File

@@ -18,7 +18,7 @@
#if defined(MJXQ_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_xn297l.h"
#include "iface_nrf250k.h"
#define MJXQ_BIND_COUNT 150
#define MJXQ_PACKET_PERIOD 4000 // Timeout for callback in uSec

View File

@@ -1,9 +1,9 @@
1,Flysky,Flysky,V9x9,V6x6,V912,CX20
2,Hubsan,H107,H301,H501
3,FrskyD
3,FrskyD,D8,Cloned
4,Hisky,Hisky,HK310
5,V2x2,V2x2,JXD506
6,DSM,DSM2-22,DSM2-11,DSMX-22,DSMX-11,AUTO
5,V2x2,V2x2,JXD506,MR101
6,DSM,DSM2_1F,DSM2_2F,DSMX_1F,DSMX_2F,AUTO
7,Devo,8CH,10CH,12CH,6CH,7CH
8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI
9,KN,WLTOYS,FEILUN
@@ -11,9 +11,9 @@
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
14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE,DHD_D4,QX100
15,FrskyX,CH_16,CH_8,EU_16,EU_8,Cloned,Clon_8
16,ESky,Std,ET4
17,MT99xx,MT,H7,YZ,LS,FY805
18,MJXq,WLH08,X600,X800,H26D,E010,H26WH,PHOENIX
19,Shenqi
@@ -25,14 +25,14 @@
25,FrskyV
26,HONTAI,HONTAI,JJRCX1,X5C1,FQ777_951
27,OpnLrs
28,AFHDS2A,PWM_IBUS,PPM_IBUS,PWM_SBUS,PPM_SBUS
28,AFHDS2A,PWM_IBUS,PPM_IBUS,PWM_SBUS,PPM_SBUS,PWM_IB16,PPM_IB16
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
35,ESKY150,4CH,7CH
36,H8_3D,H8_3D,H20H,H20Mini,H30Mini
37,CORONA,COR_V1,COR_V2,FD_V3
38,CFlie
@@ -43,17 +43,32 @@
43,Traxxas,RX6519
44,NCC1701
45,E01X,E012,E015,E016H
46,V911S
47,GD00X,GD_V1,GD_V2
48,V761
46,V911S,V911S,E119
47,GD00x,GD_V1,GD_V2
48,V761,3CH,4CH
49,KF606
50,Redpine,Fast,Slow
51,Potensic,A20
52,ZSX,280
53,Flyzone,FZ-410
53,Height,5ch,8ch
54,Scanner
55,Frsky_RX
55,Frsky_RX,RX,CloneTX
56,AFHDS2A_RX
57,HoTT
57,HoTT,Sync,No_Sync
58,FX816,P38
63,XN_DUMP,250K,1M,2M
59,Bayang_RX
60,Pelikan,Pro,Lite
61,Tiger
62,XK,X450,X420
63,XN_DUMP,250K,1M,2M,AUTO
64,FrskyX2,CH_16,CH_8,EU_16,EU_8,Cloned
65,FrSkyR9,915MHz,868MHz,915_8ch,868_8ch,FCC,--,FCC_8ch,--_8ch
66,PROPEL,74-Z
67,LR12,LR12,LR12_6ch
68,Skyartec
69,ESKYv2,150V2
70,DSM_RX
71,JJRC345
72,Q90C
73,Kyosho
74,RadioLink,Surface

View File

@@ -21,6 +21,7 @@ const char STR_FRSKYD[] ="FrSky D";
const char STR_HISKY[] ="Hisky";
const char STR_V2X2[] ="V2x2";
const char STR_DSM[] ="DSM";
const char STR_DSM_RX[] ="DSM_RX";
const char STR_DEVO[] ="Devo";
const char STR_YD717[] ="YD717";
const char STR_KN[] ="KN";
@@ -29,7 +30,9 @@ const char STR_SLT[] ="SLT";
const char STR_CX10[] ="CX10";
const char STR_CG023[] ="CG023";
const char STR_BAYANG[] ="Bayang";
const char STR_FRSKYL[] ="FrSky L";
const char STR_FRSKYX[] ="FrSky X";
const char STR_FRSKYX2[] ="FrSkyX2";
const char STR_ESKY[] ="ESky";
const char STR_MT99XX[] ="MT99XX";
const char STR_MJXQ[] ="MJXq";
@@ -37,18 +40,21 @@ const char STR_SHENQI[] ="Shenqi";
const char STR_FY326[] ="FY326";
const char STR_SFHSS[] ="SFHSS";
const char STR_J6PRO[] ="J6 Pro";
const char STR_JJRC345[] ="JJRC345";
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_AFHDS2A[] ="FlSky2A";
const char STR_Q2X2[] ="Q2x2";
const char STR_WK2x01[] ="Walkera";
const char STR_Q303[] ="Q303";
const char STR_Q90C[] ="Q90C";
const char STR_GW008[] ="GW008";
const char STR_DM002[] ="DM002";
const char STR_CABELL[] ="Cabell";
const char STR_ESKY150[] ="Esky150";
const char STR_ESKY150V2[] ="EskyV2";
const char STR_H8_3D[] ="H8 3D";
const char STR_CORONA[] ="Corona";
const char STR_CFLIE[] ="CFlie";
@@ -60,27 +66,38 @@ 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_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_HEIGHT[] ="Height";
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_XK[] ="XK";
const char STR_XN297DUMP[] ="XN297DP";
const char STR_FRSKYR9[] ="FrSkyR9";
const char STR_PROPEL[] ="Propel";
const char STR_SKYARTEC[] ="Skyartc";
const char STR_KYOSHO[] ="Kyosho";
const char STR_RLINK[] ="RadLink";
const char STR_TEST[] ="Test";
const char STR_FAKE[] ="Fake";
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_FRSKYD[] = "\x06""D8\0 ""Cloned";
const char STR_SUBTYPE_FRSKYX[] = "\x07""D16\0 ""D16 8ch""LBT(EU)""LBT 8ch""Cloned\0""Clo 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_V2X2[] = "\x06""Std\0 ""JXD506""MR101\0";
const char STR_SUBTYPE_DSM[] = "\x04""2 1F""2 2F""X 1F""X 2F""Auto";
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";
@@ -88,12 +105,12 @@ 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_BAYANG[] = "\x07""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4\0""QX100\0 ";
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_AFHDS2A[] = "\x08""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS""PWM,IB16""PPM,IB16";
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";
@@ -108,10 +125,23 @@ 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_HEIGHT[] = "\x03""5ch""8ch";
const char STR_SUBTYPE_FX816[] = "\x03""P38";
const char STR_SUBTYPE_XN297DUMP[] = "\x07""250Kbps""1Mbps\0 ""2Mbps\0 ";
const char STR_SUBTYPE_ESKY150[] = "\x03""4CH""7CH";
const char STR_SUBTYPE_XN297DUMP[] = "\x07""250Kbps""1Mbps\0 ""2Mbps\0 ""Auto\0 ""NRF\0 ";
const char STR_SUBTYPE_ESKY150[] = "\x03""4ch""7ch";
const char STR_SUBTYPE_ESKY150V2[] = "\x05""150V2";
const char STR_SUBTYPE_V911S[] = "\x05""V911S""E119\0";
const char STR_SUBTYPE_XK[] = "\x04""X450""X420";
const char STR_SUBTYPE_FRSKYR9[] = "\x07""915MHz\0""868MHz\0""915 8ch""868 8ch""FCC\0 ""--\0 ""FCC 8ch""-- 8ch\0";
const char STR_SUBTYPE_ESKY[] = "\x03""Std""ET4";
const char STR_SUBTYPE_PROPEL[] = "\x04""74-Z";
const char STR_SUBTYPE_FRSKY_RX[] = "\x07""RX\0 ""CloneTX";
const char STR_SUBTYPE_FRSKYL[] = "\x08""LR12\0 ""LR12 6ch";
const char STR_SUBTYPE_WFLY[] = "\x06""WFR0xS";
const char STR_SUBTYPE_HOTT[] = "\x07""Sync\0 ""No_Sync";
const char STR_SUBTYPE_PELIKAN[] = "\x04""Pro\0""Lite";
const char STR_SUBTYPE_V761[] = "\x03""3ch""4ch";
const char STR_SUBTYPE_RLINK[] = "\x07""Surface""Air\0 ";
enum
{
@@ -123,191 +153,240 @@ enum
OPTION_TELEM,
OPTION_SRVFREQ,
OPTION_MAXTHR,
OPTION_RFCHAN
OPTION_RFCHAN,
OPTION_RFPOWER,
};
#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, 0, NO_SUBTYPE, OPTION_NONE },
#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(XN297DUMP_NRF24L01_INO)
{PROTO_XN297DUMP, STR_XN297DUMP, 3, STR_SUBTYPE_XN297DUMP, OPTION_RFCHAN },
#endif
{0x00, nullptr, 0, nullptr, 0 }
#if defined(ASSAN_NRF24L01_INO)
{PROTO_ASSAN, STR_ASSAN, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(BAYANG_NRF24L01_INO)
{PROTO_BAYANG, STR_BAYANG, 6, STR_SUBTYPE_BAYANG, OPTION_TELEM },
#endif
#if defined(BAYANG_RX_NRF24L01_INO)
{PROTO_BAYANG_RX, STR_BAYANG_RX, 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(CABELL_NRF24L01_INO)
{PROTO_CABELL, STR_CABELL, 8, STR_SUBTYPE_CABELL, OPTION_OPTION },
#endif
#if defined(CFLIE_NRF24L01_INO)
{PROTO_CFLIE, STR_CFLIE, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(CG023_NRF24L01_INO)
{PROTO_CG023, STR_CG023, 2, STR_SUBTYPE_CG023, OPTION_NONE },
#endif
#if defined(CORONA_CC2500_INO)
{PROTO_CORONA, STR_CORONA, 3, STR_SUBTYPE_CORONA, OPTION_RFTUNE },
#endif
#if defined(CX10_NRF24L01_INO)
{PROTO_CX10, STR_CX10, 7, STR_SUBTYPE_CX10, OPTION_NONE },
#endif
#if defined(DEVO_CYRF6936_INO)
{PROTO_DEVO, STR_DEVO, 5, STR_SUBTYPE_DEVO, OPTION_FIXEDID },
#endif
#if defined(DM002_NRF24L01_INO)
{PROTO_DM002, STR_DM002, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(DSM_CYRF6936_INO)
{PROTO_DSM, STR_DSM, 5, STR_SUBTYPE_DSM, OPTION_MAXTHR },
#endif
#if defined(DSM_RX_CYRF6936_INO)
{PROTO_DSM_RX, STR_DSM_RX, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(E01X_NRF24L01_INO)
{PROTO_E01X, STR_E01X, 3, STR_SUBTYPE_E01X, OPTION_OPTION },
#endif
#if defined(ESKY_NRF24L01_INO)
{PROTO_ESKY, STR_ESKY, 2, STR_SUBTYPE_ESKY, OPTION_NONE },
#endif
#if defined(ESKY150_NRF24L01_INO)
{PROTO_ESKY150, STR_ESKY150, 2, STR_SUBTYPE_ESKY150, OPTION_NONE },
#endif
#if defined(ESKY150V2_CC2500_INO)
{PROTO_ESKY150V2, STR_ESKY150V2, 1, STR_SUBTYPE_ESKY150V2, OPTION_RFTUNE },
#endif
#if defined(FLYSKY_A7105_INO)
{PROTO_FLYSKY, STR_FLYSKY, 5, STR_SUBTYPE_FLYSKY, OPTION_NONE },
#endif
#if defined(AFHDS2A_A7105_INO)
{PROTO_AFHDS2A, STR_AFHDS2A, 6, STR_SUBTYPE_AFHDS2A, OPTION_SRVFREQ },
#endif
#if defined(AFHDS2A_RX_A7105_INO)
{PROTO_AFHDS2A_RX, STR_AFHDS2A_RX,0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(HEIGHT_A7105_INO)
{PROTO_HEIGHT, STR_HEIGHT, 2, STR_SUBTYPE_HEIGHT, OPTION_NONE },
#endif
#if defined(FQ777_NRF24L01_INO)
{PROTO_FQ777, STR_FQ777, 0, NO_SUBTYPE, OPTION_NONE },
#endif
//OpenTX 2.3.x issue: DO NOT CHANGE ORDER below
#if defined(FRSKY_RX_CC2500_INO)
{PROTO_FRSKY_RX, STR_FRSKY_RX, 2, STR_SUBTYPE_FRSKY_RX, OPTION_RFTUNE },
#endif
#if defined(FRSKYD_CC2500_INO)
{PROTO_FRSKYD, STR_FRSKYD, 2, STR_SUBTYPE_FRSKYD, OPTION_RFTUNE },
#endif
#if defined(FRSKYV_CC2500_INO)
{PROTO_FRSKYV, STR_FRSKYV, 0, NO_SUBTYPE, OPTION_RFTUNE },
#endif
#if defined(FRSKYX_CC2500_INO)
{PROTO_FRSKYX, STR_FRSKYX, 6, STR_SUBTYPE_FRSKYX, OPTION_RFTUNE },
{PROTO_FRSKYX2, STR_FRSKYX2, 6, STR_SUBTYPE_FRSKYX, OPTION_RFTUNE },
#endif
//OpenTX 2.3.x issue: DO NOT CHANGE ORDER above
#if defined(FRSKYL_CC2500_INO)
{PROTO_FRSKYL, STR_FRSKYL, 2, STR_SUBTYPE_FRSKYL, OPTION_RFTUNE },
#endif
#if defined(FRSKYR9_SX1276_INO)
{PROTO_FRSKY_R9, STR_FRSKYR9, 8, STR_SUBTYPE_FRSKYR9, OPTION_NONE },
#endif
#if defined(FX816_NRF24L01_INO)
{PROTO_FX816, STR_FX816, 1, STR_SUBTYPE_FX816, OPTION_NONE },
#endif
#if defined(FY326_NRF24L01_INO)
{PROTO_FY326, STR_FY326, 2, STR_SUBTYPE_FY326, OPTION_NONE },
#endif
#if defined(GD00X_NRF24L01_INO)
{PROTO_GD00X, STR_GD00X, 2, STR_SUBTYPE_GD00X, OPTION_RFTUNE },
#endif
#if defined(GW008_NRF24L01_INO)
{PROTO_GW008, STR_GW008, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(H8_3D_NRF24L01_INO)
{PROTO_H8_3D, STR_H8_3D, 4, STR_SUBTYPE_H83D, OPTION_NONE },
#endif
#if defined(HISKY_NRF24L01_INO)
{PROTO_HISKY, STR_HISKY, 2, STR_SUBTYPE_HISKY, OPTION_NONE },
#endif
#if defined(HITEC_CC2500_INO)
{PROTO_HITEC, STR_HITEC, 3, STR_SUBTYPE_HITEC, OPTION_RFTUNE },
#endif
#if defined(HONTAI_NRF24L01_INO)
{PROTO_HONTAI, STR_HONTAI, 4, STR_SUBTYPE_HONTAI, OPTION_NONE },
#endif
#if defined(HOTT_CC2500_INO)
{PROTO_HOTT, STR_HOTT, 2, STR_SUBTYPE_HOTT, OPTION_RFTUNE },
#endif
#if defined(HUBSAN_A7105_INO)
{PROTO_HUBSAN, STR_HUBSAN, 3, STR_SUBTYPE_HUBSAN, OPTION_VIDFREQ },
#endif
#if defined(J6PRO_CYRF6936_INO)
{PROTO_J6PRO, STR_J6PRO, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(JJRC345_NRF24L01_INO)
{PROTO_JJRC345, STR_JJRC345, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(KF606_NRF24L01_INO)
{PROTO_KF606, STR_KF606, 0, NO_SUBTYPE, OPTION_RFTUNE },
#endif
#if defined(KN_NRF24L01_INO)
{PROTO_KN, STR_KN, 2, STR_SUBTYPE_KN, OPTION_NONE },
#endif
#if defined(KYOSHO_A7105_INO)
{PROTO_KYOSHO, STR_KYOSHO, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(MJXQ_NRF24L01_INO)
{PROTO_MJXQ, STR_MJXQ, 7, STR_SUBTYPE_MJXQ, OPTION_RFTUNE },
#endif
#if defined(MT99XX_NRF24L01_INO)
{PROTO_MT99XX, STR_MT99XX, 5, STR_SUBTYPE_MT99, OPTION_NONE },
#endif
#if defined(NCC1701_NRF24L01_INO)
{PROTO_NCC1701, STR_NCC1701, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(PELIKAN_A7105_INO)
{PROTO_PELIKAN, STR_PELIKAN , 2, STR_SUBTYPE_PELIKAN, OPTION_NONE },
#endif
#if defined(POTENSIC_NRF24L01_INO)
{PROTO_POTENSIC, STR_POTENSIC, 1, STR_SUBTYPE_POTENSIC, OPTION_NONE },
#endif
#if defined(PROPEL_NRF24L01_INO)
{PROTO_PROPEL, STR_PROPEL, 1, STR_SUBTYPE_PROPEL, OPTION_NONE },
#endif
#if defined(CX10_NRF24L01_INO)
{PROTO_Q2X2, STR_Q2X2, 3, STR_SUBTYPE_Q2X2, OPTION_NONE },
#endif
#if defined(Q303_NRF24L01_INO)
{PROTO_Q303, STR_Q303, 4, STR_SUBTYPE_Q303, OPTION_NONE },
#endif
#if defined(Q90C_NRF24L01_INO)
{PROTO_Q90C, STR_Q90C, 0, NO_SUBTYPE, OPTION_RFTUNE },
#endif
#if defined(REDPINE_CC2500_INO)
{PROTO_REDPINE, STR_REDPINE, 2, STR_SUBTYPE_REDPINE, OPTION_RFTUNE },
#endif
#if defined(RLINK_CC2500_INO)
{PROTO_RLINK, STR_RLINK, 2, STR_SUBTYPE_RLINK, OPTION_RFTUNE },
#endif
#if defined(SCANNER_CC2500_INO)
// {PROTO_SCANNER, STR_SCANNER, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(SFHSS_CC2500_INO)
{PROTO_SFHSS, STR_SFHSS, 0, NO_SUBTYPE, OPTION_RFTUNE },
#endif
#if defined(SHENQI_NRF24L01_INO)
{PROTO_SHENQI, STR_SHENQI, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(SKYARTEC_CC2500_INO)
{PROTO_SKYARTEC, STR_SKYARTEC, 0, NO_SUBTYPE, OPTION_RFTUNE },
#endif
#if defined(SLT_NRF24L01_INO)
{PROTO_SLT, STR_SLT, 5, STR_SUBTYPE_SLT, OPTION_RFTUNE },
#endif
#if defined(SYMAX_NRF24L01_INO)
{PROTO_SYMAX, STR_SYMAX, 2, STR_SUBTYPE_SYMAX, OPTION_NONE },
#endif
#if defined(TIGER_NRF24L01_INO)
{PROTO_TIGER, STR_TIGER , 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(TRAXXAS_CYRF6936_INO)
{PROTO_TRAXXAS, STR_TRAXXAS, 1, STR_SUBTYPE_TRAXXAS, OPTION_NONE },
#endif
#if defined(V2X2_NRF24L01_INO)
{PROTO_V2X2, STR_V2X2, 3, STR_SUBTYPE_V2X2, OPTION_NONE },
#endif
#if defined(V761_NRF24L01_INO)
{PROTO_V761, STR_V761, 2, STR_SUBTYPE_V761, OPTION_NONE },
#endif
#if defined(V911S_NRF24L01_INO)
{PROTO_V911S, STR_V911S, 2, STR_SUBTYPE_V911S, OPTION_RFTUNE },
#endif
#if defined(WK2x01_CYRF6936_INO)
{PROTO_WK2x01, STR_WK2x01, 6, STR_SUBTYPE_WK2x01, OPTION_NONE },
#endif
#if defined(WFLY_CYRF6936_INO)
{PROTO_WFLY, STR_WFLY, 1, STR_SUBTYPE_WFLY, OPTION_NONE },
#endif
#if defined(XK_NRF24L01_INO)
{PROTO_XK, STR_XK , 2, STR_SUBTYPE_XK, OPTION_RFTUNE },
#endif
#if defined(XN297DUMP_NRF24L01_INO)
{PROTO_XN297DUMP, STR_XN297DUMP, 5, STR_SUBTYPE_XN297DUMP, OPTION_RFCHAN },
#endif
#if defined(YD717_NRF24L01_INO)
{PROTO_YD717, STR_YD717, 5, STR_SUBTYPE_YD717, OPTION_NONE },
#endif
#if defined(ZSX_NRF24L01_INO)
{PROTO_ZSX, STR_ZSX, 1, STR_SUBTYPE_ZSX, OPTION_NONE },
#endif
#if defined(TEST_CC2500_INO)
{PROTO_TEST, STR_TEST, 0, NO_SUBTYPE, OPTION_RFTUNE },
#endif
#if defined(FAKE_NRF24L01_INO)
{PROTO_FAKE, STR_FAKE, 0, NO_SUBTYPE, OPTION_NONE },
#endif
{0x00, nullptr, 0, nullptr, 0 }
};
#endif

View File

@@ -18,8 +18,8 @@
//******************
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_REVISION 0
#define VERSION_PATCH_LEVEL 47
#define VERSION_REVISION 1
#define VERSION_PATCH_LEVEL 49
//******************
// Protocols
@@ -79,14 +79,31 @@ enum PROTOCOLS
PROTO_REDPINE = 50, // =>CC2500
PROTO_POTENSIC = 51, // =>NRF24L01
PROTO_ZSX = 52, // =>NRF24L01
PROTO_FLYZONE = 53, // =>A7105
PROTO_HEIGHT = 53, // =>A7105
PROTO_SCANNER = 54, // =>CC2500
PROTO_FRSKY_RX = 55, // =>CC2500
PROTO_AFHDS2A_RX= 56, // =>A7105
PROTO_HOTT = 57, // =>CC2500
PROTO_FX816 = 58, // =>NRF24L01
PROTO_BAYANG_RX = 59, // =>NRF24L01
PROTO_PELIKAN = 60, // =>A7105
PROTO_TIGER = 61, // =>NRF24L01
PROTO_XK = 62, // =>NRF24L01
PROTO_XN297DUMP = 63, // =>NRF24L01
PROTO_FRSKYX2 = 64, // =>CC2500
PROTO_FRSKY_R9 = 65, // =>SX1276
PROTO_PROPEL = 66, // =>NRF24L01
PROTO_FRSKYL = 67, // =>CC2500
PROTO_SKYARTEC = 68, // =>CC2500
PROTO_ESKY150V2 = 69, // =>CC2500+NRF24L01
PROTO_DSM_RX = 70, // =>CYRF6936
PROTO_JJRC345 = 71, // =>NRF24L01
PROTO_Q90C = 72, // =>NRF24L01 or CC2500
PROTO_KYOSHO = 73, // =>A7105
PROTO_RLINK = 74, // =>CC2500
PROTO_FAKE = 126, // =>CC2500+NRF24L01
PROTO_TEST = 127, // =>CC2500
};
enum Flysky
@@ -97,7 +114,7 @@ enum Flysky
V912 = 3,
CX20 = 4,
};
enum Flyzone
enum Height
{
FZ410 = 0,
};
@@ -113,6 +130,8 @@ enum AFHDS2A
PPM_IBUS = 1,
PWM_SBUS = 2,
PPM_SBUS = 3,
PWM_IB16 = 4,
PPM_IB16 = 5,
};
enum Hisky
{
@@ -183,6 +202,7 @@ enum BAYANG
X16_AH = 2,
IRDRONE = 3,
DHD_D4 = 4,
QX100 = 5,
};
enum MT99XX
{
@@ -202,12 +222,19 @@ enum MJXQ
H26WH = 5,
PHOENIX = 6,
};
enum FRSKYD
{
FRSKYD = 0,
DCLONE = 1,
};
enum FRSKYX
{
CH_16 = 0,
CH_8 = 1,
EU_16 = 2,
EU_8 = 3,
CH_16 = 0,
CH_8 = 1,
EU_16 = 2,
EU_8 = 3,
XCLONE_16 = 4,
XCLONE_8 = 5,
};
enum HONTAI
{
@@ -220,6 +247,7 @@ enum V2X2
{
V2X2 = 0,
JXD506 = 1,
V2X2_MR101 = 2,
};
enum FY326
{
@@ -298,6 +326,75 @@ enum ESKY150
ESKY150_4CH = 0,
ESKY150_7CH = 1,
};
enum V911S
{
V911S_STD = 0,
V911S_E119 = 1,
};
enum XK
{
X450 = 0,
X420 = 1,
};
enum XN297DUMP
{
XN297DUMP_250K = 0,
XN297DUMP_1M = 1,
XN297DUMP_2M = 2,
XN297DUMP_AUTO = 3,
};
enum FRSKY_R9
{
R9_915 = 0,
R9_868 = 1,
R9_915_8CH = 2,
R9_868_8CH = 3,
R9_FCC = 4,
R9_EU = 5,
R9_FCC_8CH = 6,
R9_EU_8CH = 7,
};
enum ESKY
{
ESKY_STD = 0,
ESKY_ET4 = 1,
};
enum FRSKY_RX
{
FRSKY_RX = 0,
FRSKY_CLONE = 1,
};
enum FRSKYL
{
LR12 = 0,
LR12_6CH = 1,
};
enum HOTT
{
HOTT_SYNC = 0,
HOTT_NO_SYNC= 1,
};
enum PELIKAN
{
PELIKAN_PRO = 0,
PELIKAN_LITE= 1,
};
enum V761
{
V761_3CH = 0,
V761_4CH = 1,
};
enum HEIGHT
{
HEIGHT_5CH = 0,
HEIGHT_8CH = 1,
};
#define NONE 0
#define P_HIGH 1
@@ -341,8 +438,8 @@ enum MultiPacketTypes
//***************
//*** Tests ***
//***************
#define IS_FAILSAFE_PROTOCOL ( (protocol==PROTO_HISKY && sub_protocol==HK310) || protocol==PROTO_AFHDS2A || protocol==PROTO_DEVO || protocol==PROTO_SFHSS || protocol==PROTO_WK2x01 || protocol== PROTO_HOTT || protocol==PROTO_FRSKYX )
#define IS_CHMAP_PROTOCOL ( (protocol==PROTO_HISKY && sub_protocol==HK310) || protocol==PROTO_AFHDS2A || protocol==PROTO_DEVO || protocol==PROTO_SFHSS || protocol==PROTO_WK2x01 || protocol== PROTO_DSM || protocol==PROTO_SLT || protocol==PROTO_FLYSKY || protocol==PROTO_ESKY || protocol==PROTO_J6PRO )
#define IS_FAILSAFE_PROTOCOL ( (protocol==PROTO_HISKY && sub_protocol==HK310) || protocol==PROTO_AFHDS2A || protocol==PROTO_DEVO || protocol==PROTO_SFHSS || protocol==PROTO_WK2x01 || protocol== PROTO_HOTT || protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYX2 || protocol==PROTO_FRSKY_R9)
#define IS_CHMAP_PROTOCOL ( (protocol==PROTO_HISKY && sub_protocol==HK310) || protocol==PROTO_AFHDS2A || protocol==PROTO_DEVO || protocol==PROTO_SFHSS || protocol==PROTO_WK2x01 || protocol== PROTO_DSM || protocol==PROTO_SLT || protocol==PROTO_FLYSKY || protocol==PROTO_ESKY || protocol==PROTO_J6PRO || protocol==PROTO_PELIKAN || protocol==PROTO_SKYARTEC || protocol==PROTO_ESKY150V2 || protocol==PROTO_DSM_RX)
//***************
//*** Flags ***
@@ -432,6 +529,11 @@ enum MultiPacketTypes
#define DISABLE_TELEM_on protocol_flags3 |= _BV(3)
#define IS_DISABLE_TELEM_on ( ( protocol_flags3 & _BV(3) ) !=0 )
#define IS_DISABLE_TELEM_off ( ( protocol_flags3 & _BV(3) ) ==0 )
//LBT power
#define LBT_POWER_off protocol_flags3 &= ~_BV(7)
#define LBT_POWER_on protocol_flags3 |= _BV(7)
#define IS_LBT_POWER_on ( ( protocol_flags3 & _BV(7) ) !=0 )
#define IS_LBT_POWER_off ( ( protocol_flags3 & _BV(7) ) ==0 )
// Failsafe
@@ -556,6 +658,7 @@ enum CC2500_POWER
CC2500_POWER_17 = 0xFF // +1dbm
};
#define CC2500_HIGH_POWER CC2500_POWER_17
#define CC2500_LBT_POWER CC2500_POWER_14
#define CC2500_LOW_POWER CC2500_POWER_13
#define CC2500_RANGE_POWER CC2500_POWER_1
#define CC2500_BIND_POWER CC2500_POWER_1
@@ -609,7 +712,11 @@ enum {
#define AFHDS2A_EEPROM_OFFSET2 250 // RX ID, 4 bytes per model id, end is 250+192=442
#define HOTT_EEPROM_OFFSET 442 // RX ID, 5 bytes per model id, end is 320+442=762
#define BAYANG_RX_EEPROM_OFFSET 762 // (5) TX ID + (4) channels, 9 bytes, end is 771
//#define CONFIG_EEPROM_OFFSET 771 // Current configuration of the multimodule
#define FRSKYD_CLONE_EEPROM_OFFSET 771 // (1) format + (3) TX ID + (47) channels, 51 bytes, end is 822
#define FRSKYX_CLONE_EEPROM_OFFSET 822 // (1) format + (3) TX ID + (47) channels, 51 bytes, end is 873
#define FRSKYX2_CLONE_EEPROM_OFFSET 873 // (1) format + (3) TX ID, 4 bytes, end is 877
#define DSM_RX_EEPROM_OFFSET 877 // (4) TX ID + format, 5 bytes, end is 882
//#define CONFIG_EEPROM_OFFSET 882 // Current configuration of the multimodule
//****************************************
//*** MULTI protocol serial definition ***
@@ -680,13 +787,28 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
REDPINE 50
POTENSIC 51
ZSX 52
FLYZONE 53
HEIGHT 53
SCANNER 54
FRSKY_RX 55
AFHDS2A_RX 56
HOTT 57
FX816 58
BAYANG_RX 59
PELIKAN 60
TIGER 61
XK 62
XN297DUMP 63
FRSKYX2 64
FRSKY_R9 65
PROPEL 66
FRSKYL 67
SKYARTEC 68
ESKY150V2 69
DSM_RX 70
JJRC345 71
Q90C 72
KYOSHO 73
RLINK 74
BindBit=> 0x80 1=Bind/0=No
AutoBindBit=> 0x40 1=Yes /0=No
RangeCheck=> 0x20 1=Yes /0=No
@@ -759,11 +881,21 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
E010 4
H26WH 5
PHOENIX 6
sub_protocol==FRSKYD
FRSKYD 0
DCLONE 1
sub_protocol==FRSKYX
CH_16 0
CH_8 1
EU_16 2
EU_8 3
XCLONE 4
sub_protocol==FRSKYX2
CH_16 0
CH_8 1
EU_16 2
EU_8 3
XCLONE 4
sub_protocol==HONTAI
HONTAI 0
JJRCX1 1
@@ -774,9 +906,12 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
PPM_IBUS 1
PWM_SBUS 2
PPM_SBUS 3
PWM_IB16 4
PPM_IB16 5
sub_protocol==V2X2
V2X2 0
JXD506 1
V2X2_MR101 2
sub_protocol==FY326
FY326 0
FY319 1
@@ -831,6 +966,42 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
sub_protocol==ESKY150
ESKY150_4CH 0
ESKY150_7CH 1
sub_protocol==V911S
V911S_STD 0
V911S_E119 1
sub_protocol==XK
X450 0
X420 1
sub_protocol==FRSKY_R9
R9_915 0
R9_868 1
R9_915_8CH 2
R9_868_8CH 3
R9_FCC 4
R9_EU 5
R9_FCC_8CH 6
R9_EU_8CH 7
sub_protocol==ESKY
ESKY_STD 0
ESKY_ET4 1
sub_protocol==FRSKY_RX
FRSKY_RX 0
FRSKY_CLONE 1
sub_protocol==FRSKYL
LR12 0
LR12_6CH 1
sub_protocol==HOTT
HOTT_SYNC 0
HOTT_NO_SYNC 1
sub_protocol==PELIKAN
PELIKAN_PRO 0
PELIKAN_LITE 1
sub_protocol==V761
V761_3CH 0
V761_4CH 1
sub_protocol==HEIGHT
HEIGHT_5CH 0
HEIGHT_8CH 1
Power value => 0x80 0=High/1=Low
Stream[3] = option_protocol;
@@ -853,6 +1024,10 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
Disable_Telemetry => 0x02 0=enable, 1=disable
Disable_CH_Mapping => 0x01 0=enable, 1=disable
Stream[27.. 35] = between 0 and 9 bytes for additional protocol data
Protocol specific use:
FrSkyX and FrSkyX2: Stream[27] during bind Telem on=0x00,off=0x01 | CH1-8=0x00,CH9-16=0x02
FrSkyX and FrSkyX2: Stream[27..34] during normal operation unstuffed SPort data to be sent
HoTT: Stream[27] 1 byte for telemetry type
*/
/*
Multimodule Status
@@ -933,9 +1108,11 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
OPTION_SRVFREQ 6
OPTION_MAXTHR 7
OPTION_RFCHAN 8
OPTION_RFPOWER 9
[19&0x0F] Number of sub protocols
[20..27] Sub protocol name [8], not null terminated if sub prototcol len == 8
If the current protocol is invalid [12..27] are all 0x00.
more information can be added by specifing a longer length of the type, the TX will just ignore these bytes
Type 0x02 Frksy S.port telemetry

View File

@@ -75,7 +75,11 @@ uint32_t blink=0,last_signal=0;
//
uint16_t counter;
uint8_t channel;
uint8_t packet[50];
#ifdef ESKY150V2_CC2500_INO
uint8_t packet[150];
#else
uint8_t packet[50];
#endif
#define NUM_CHN 16
// Servo data
@@ -97,7 +101,7 @@ uint16_t packet_period;
uint8_t packet_count;
uint8_t packet_sent;
uint8_t packet_length;
#ifdef HOTT_CC2500_INO
#if defined(HOTT_CC2500_INO) || defined(ESKY150V2_CC2500_INO)
uint8_t hopping_frequency[75];
#else
uint8_t hopping_frequency[50];
@@ -115,11 +119,13 @@ uint16_t state;
uint8_t len;
uint8_t armed, arm_flags, arm_channel_previous;
uint8_t num_ch;
uint32_t pps_timer;
uint16_t pps_counter;
#ifdef CC2500_INSTALLED
#ifdef SCANNER_CC2500_INO
uint8_t calData[255];
#elif defined(HOTT_CC2500_INO)
#elif defined(HOTT_CC2500_INO) || defined(ESKY150V2_CC2500_INO)
uint8_t calData[75];
#else
uint8_t calData[50];
@@ -179,7 +185,7 @@ volatile uint8_t rx_idx=0, rx_len=0;
// Telemetry
#define TELEMETRY_BUFFER_SIZE 30
#define TELEMETRY_BUFFER_SIZE 32
uint8_t packet_in[TELEMETRY_BUFFER_SIZE];//telemetry receiving packets
#if defined(TELEMETRY)
#ifdef MULTI_SYNC
@@ -227,7 +233,7 @@ uint8_t packet_in[TELEMETRY_BUFFER_SIZE];//telemetry receiving packets
#endif
//RX protocols
#if defined(AFHDS2A_RX_A7105_INO) || defined(FRSKY_RX_CC2500_INO) || defined(BAYANG_RX_NRF24L01_INO)
#if defined(AFHDS2A_RX_A7105_INO) || defined(FRSKY_RX_CC2500_INO) || defined(BAYANG_RX_NRF24L01_INO) || defined(DSM_RX_CYRF6936_INO)
bool rx_data_started;
bool rx_data_received;
bool rx_disable_lna;
@@ -296,12 +302,12 @@ void setup()
PORTE.DIRCLR = 0x02 ;
// Timer1 config
// TCC1 16-bit timer, clocked at 0.5uS
EVSYS.CH3MUX = 0x80 + 0x04 ; // Prescaler of 16
EVSYS.CH3MUX = 0x80 + 0x04 ; // Prescaler of 16
TCC1.CTRLB = 0; TCC1.CTRLC = 0; TCC1.CTRLD = 0; TCC1.CTRLE = 0;
TCC1.INTCTRLA = 0; TIMSK1 = 0;
TCC1.PER = 0xFFFF ;
TCNT1 = 0 ;
TCC1.CTRLA = 0x0B ; // Event3 (prescale of 16)
TCC1.CTRLA = 0x0B ; // Event3 (prescale of 16)
#elif defined STM32_BOARD
//STM32
afio_cfg_debug_ports(AFIO_DEBUG_NONE);
@@ -318,7 +324,7 @@ void setup()
pinMode(RX_INV_pin,OUTPUT);
#if defined TELEMETRY
#if defined INVERT_SERIAL
TX_INV_on; //activate inverter for both serial TX and RX signals
TX_INV_on; // activate inverter for both serial TX and RX signals
RX_INV_on;
#else
TX_INV_off;
@@ -327,15 +333,37 @@ void setup()
#endif
pinMode(BIND_pin,INPUT_PULLUP);
pinMode(PPM_pin,INPUT);
pinMode(S1_pin,INPUT_PULLUP);//dial switch
pinMode(S1_pin,INPUT_PULLUP); // dial switch
pinMode(S2_pin,INPUT_PULLUP);
pinMode(S3_pin,INPUT_PULLUP);
pinMode(S4_pin,INPUT_PULLUP);
//Random pins
pinMode(PB0, INPUT_ANALOG); // set up pin for analog input
#ifdef MULTI_5IN1_INTERNAL
//pinMode(SX1276_RST_pin,OUTPUT); // already done by LED2_pin
pinMode(SX1276_TXEN_pin,OUTPUT); // PB0
pinMode(SX1276_DIO0_pin,INPUT_PULLUP);
#else
//Random pin
pinMode(RND_pin, INPUT_ANALOG); // set up PB0 pin for analog input
#endif
#if defined ENABLE_DIRECT_INPUTS
#if defined (DI1_PIN)
pinMode(DI1_PIN,INPUT_PULLUP);
#endif
#if defined (DI2_PIN)
pinMode(DI2_PIN,INPUT_PULLUP);
#endif
#if defined (DI3_PIN)
pinMode(DI3_PIN,INPUT_PULLUP);
#endif
#if defined (DI4_PIN)
pinMode(DI4_PIN,INPUT_PULLUP);
#endif
#endif
//Timers
init_HWTimer(); //0.5us
init_HWTimer(); //0.5us
#else
//ATMEGA328p
// all inputs
@@ -390,6 +418,10 @@ void setup()
#ifdef NRF_CSN_pin
NRF_CSN_on;
#endif
#ifdef SPI_CSN_pin
SPI_CSN_on;
#endif
// Set SPI lines
#ifdef STM32_BOARD
initSPI2();
@@ -453,7 +485,12 @@ void setup()
#ifdef STM32_BOARD
uint32_t seed=0;
for(uint8_t i=0;i<4;i++)
seed=(seed<<8) | (analogRead(PB0)& 0xFF);
#ifdef RND_pin
seed=(seed<<8) | (analogRead(RND_pin)& 0xFF);
#else
//TODO find something to randomize...
seed=(seed<<8);
#endif
randomSeed(seed);
#else
//Init the seed with a random value created from watchdog timer for all protocols requiring random values
@@ -488,13 +525,18 @@ void setup()
option = FORCE_FRSKYD_TUNING; // Use config-defined tuning value for FrSkyD
else
#endif
#if defined(FORCE_FRSKYL_TUNING) && defined(FRSKYL_CC2500_INO)
if(protocol==PROTO_FRSKYL)
option = FORCE_FRSKYL_TUNING; // Use config-defined tuning value for FrSkyL
else
#endif
#if defined(FORCE_FRSKYV_TUNING) && defined(FRSKYV_CC2500_INO)
if(protocol==PROTO_FRSKYV)
option = FORCE_FRSKYV_TUNING; // Use config-defined tuning value for FrSkyV
else
#endif
#if defined(FORCE_FRSKYX_TUNING) && defined(FRSKYX_CC2500_INO)
if(protocol==PROTO_FRSKYX)
if(protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYX2)
option = FORCE_FRSKYX_TUNING; // Use config-defined tuning value for FrSkyX
else
#endif
@@ -508,11 +550,21 @@ void setup()
option = FORCE_CORONA_TUNING; // Use config-defined tuning value for CORONA
else
#endif
#if defined(FORCE_SKYARTEC_TUNING) && defined(SKYARTEC_CC2500_INO)
if (protocol==PROTO_SKYARTEC)
option = FORCE_SKYARTEC_TUNING; // Use config-defined tuning value for SKYARTEC
else
#endif
#if defined(FORCE_REDPINE_TUNING) && defined(REDPINE_CC2500_INO)
if (protocol==PROTO_REDPINE)
option = FORCE_REDPINE_TUNING; // Use config-defined tuning value for REDPINE
else
#endif
#if defined(FORCE_RADIOLINK_TUNING) && defined(RADIOLINK_CC2500_INO)
if (protocol==PROTO_RADIOLINK)
option = FORCE_RADIOLINK_TUNING; // Use config-defined tuning value for RADIOLINK
else
#endif
#if defined(FORCE_HITEC_TUNING) && defined(HITEC_CC2500_INO)
if (protocol==PROTO_HITEC)
option = FORCE_HITEC_TUNING; // Use config-defined tuning value for HITEC
@@ -567,8 +619,8 @@ void setup()
#endif
#endif //ENABLE_SERIAL
}
LED2_on;
debugln("Init complete");
LED2_on;
}
// Main
@@ -666,8 +718,29 @@ bool Update_All()
if(mode_select!=MODE_SERIAL && IS_PPM_FLAG_on) // PPM mode and a full frame has been received
{
uint32_t chan_or=chan_order;
uint8_t ch;
for(uint8_t i=0;i<PPM_chan_max;i++)
uint8_t ch;
uint8_t channelsCount = PPM_chan_max;
#ifdef ENABLE_DIRECT_INPUTS
#ifdef DI_CH1_read
PPM_data[channelsCount] = DI_CH1_read;
channelsCount++;
#endif
#ifdef DI_CH2_read
PPM_data[channelsCount] = DI_CH2_read;
channelsCount++;
#endif
#ifdef DI_CH3_read
PPM_data[channelsCount] = DI_CH3_read;
channelsCount++;
#endif
#ifdef DI_CH4_read
PPM_data[channelsCount] = DI_CH4_read;
channelsCount++;
#endif
#endif
for(uint8_t i=0;i<channelsCount;i++)
{ // update servo data without interrupts to prevent bad read
uint16_t val;
cli(); // disable global int
@@ -700,7 +773,7 @@ bool Update_All()
update_led_status();
#if defined(TELEMETRY)
#if ( !( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) ) )
if((protocol == PROTO_BAYANG_RX) || (protocol == PROTO_AFHDS2A_RX) || (protocol == PROTO_FRSKY_RX) || (protocol == PROTO_SCANNER) || (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_NCC1701) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_HOTT))
if((protocol == PROTO_BAYANG_RX) || (protocol == PROTO_AFHDS2A_RX) || (protocol == PROTO_FRSKY_RX) || (protocol == PROTO_SCANNER) || (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_NCC1701) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_FRSKYX2) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_HOTT) || (protocol==PROTO_PROPEL) || (protocol==PROTO_DEVO) || (protocol==PROTO_DSM_RX) || (protocol==PROTO_FRSKY_R9) || (protocol==PROTO_RLINK))
#endif
if(IS_DISABLE_TELEM_off)
TelemetryUpdate();
@@ -716,8 +789,8 @@ bool Update_All()
{ // Autobind is on and BIND_CH went down
BIND_CH_PREV_off;
//Request protocol to terminate bind
#if defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYV_CC2500_INO) || defined(AFHDS2A_A7105_INO)
if(protocol==PROTO_FRSKYD || protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYV || protocol==PROTO_AFHDS2A )
#if defined(FRSKYD_CC2500_INO) || defined(FRSKYL_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYV_CC2500_INO) || defined(AFHDS2A_A7105_INO) || defined(FRSKYR9_SX1276_INO)
if(protocol==PROTO_FRSKYD || protocol==PROTO_FRSKYL || protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYX2 || protocol==PROTO_FRSKYV || protocol==PROTO_AFHDS2A || protocol==PROTO_FRSKY_R9)
BIND_DONE;
else
#endif
@@ -975,6 +1048,8 @@ static void protocol_init()
#endif
tx_pause();
init_frskyd_link_telemetry();
pps_timer=millis();
pps_counter=0;
#ifdef BASH_SERIAL
TIMSK0 = 0 ; // Stop all timer 0 interrupts
#ifdef INVERT_SERIAL
@@ -997,7 +1072,8 @@ static void protocol_init()
rx_rc_chan[ch] = 1024;
#endif
#endif
binding_idx=0;
//Set global ID and rx_tx_addr
MProtocol_id = RX_num + MProtocol_id_master;
set_rx_tx_addr(MProtocol_id);
@@ -1044,11 +1120,11 @@ static void protocol_init()
remote_callback = ReadBUGS;
break;
#endif
#if defined(FLYZONE_A7105_INO)
case PROTO_FLYZONE:
#if defined(HEIGHT_A7105_INO)
case PROTO_HEIGHT:
PE1_off; //antenna RF1
next_callback = initFlyzone();
remote_callback = ReadFlyzone;
next_callback = initHeight();
remote_callback = ReadHeight;
break;
#endif
#if defined(AFHDS2A_RX_A7105_INO)
@@ -1058,6 +1134,20 @@ static void protocol_init()
remote_callback = AFHDS2A_Rx_callback;
break;
#endif
#if defined(PELIKAN_A7105_INO)
case PROTO_PELIKAN:
PE1_off; //antenna RF1
next_callback = initPelikan();
remote_callback = ReadPelikan;
break;
#endif
#if defined(KYOSHO_A7105_INO)
case PROTO_KYOSHO:
PE1_off; //antenna RF1
next_callback = initKyosho();
remote_callback = ReadKyosho;
break;
#endif
#endif
#ifdef CC2500_INSTALLED
#if defined(FRSKYD_CC2500_INO)
@@ -1068,6 +1158,14 @@ static void protocol_init()
remote_callback = ReadFrSky_2way;
break;
#endif
#if defined(FRSKYL_CC2500_INO)
case PROTO_FRSKYL:
PE1_off; //antenna RF2
PE2_on;
next_callback = initFrSkyL();
remote_callback = ReadFrSkyL;
break;
#endif
#if defined(FRSKYV_CC2500_INO)
case PROTO_FRSKYV:
PE1_off; //antenna RF2
@@ -1078,6 +1176,11 @@ static void protocol_init()
#endif
#if defined(FRSKYX_CC2500_INO)
case PROTO_FRSKYX:
case PROTO_FRSKYX2:
#ifdef EU_MODULE
if(sub_protocol<2)
break;
#endif
PE1_off; //antenna RF2
PE2_on;
next_callback = initFrSkyX();
@@ -1100,6 +1203,14 @@ static void protocol_init()
remote_callback = ReadCORONA;
break;
#endif
#if defined(SKYARTEC_CC2500_INO)
case PROTO_SKYARTEC:
PE1_off; //antenna RF2
PE2_on;
next_callback = initSKYARTEC();
remote_callback = ReadSKYARTEC;
break;
#endif
#if defined(REDPINE_CC2500_INO)
case PROTO_REDPINE:
PE1_off; //antenna RF2
@@ -1140,6 +1251,22 @@ static void protocol_init()
remote_callback = FrSky_Rx_callback;
break;
#endif
#if defined(ESKY150V2_CC2500_INO)
case PROTO_ESKY150V2:
PE1_off;
PE2_on; //antenna RF2
next_callback = initESKY150V2();
remote_callback = ESKY150V2_callback;
break;
#endif
#if defined(RLINK_CC2500_INO)
case PROTO_RLINK:
PE1_off;
PE2_on; //antenna RF2
next_callback = initRLINK();
remote_callback = RLINK_callback;
break;
#endif
#endif
#ifdef CYRF6936_INSTALLED
#if defined(DSM_CYRF6936_INO)
@@ -1149,6 +1276,13 @@ static void protocol_init()
remote_callback = ReadDsm;
break;
#endif
#if defined(DSM_RX_CYRF6936_INO)
case PROTO_DSM_RX:
PE2_on; //antenna RF4
next_callback = initDSM_Rx();
remote_callback = DSM_Rx_callback;
break;
#endif
#if defined(WFLY_CYRF6936_INO)
case PROTO_WFLY:
PE2_on; //antenna RF4
@@ -1428,13 +1562,63 @@ static void protocol_init()
remote_callback = Bayang_Rx_callback;
break;
#endif
#if defined(TIGER_NRF24L01_INO)
case PROTO_TIGER:
next_callback=initTIGER();
remote_callback = TIGER_callback;
break;
#endif
#if defined(XK_NRF24L01_INO)
case PROTO_XK:
next_callback=initXK();
remote_callback = XK_callback;
break;
#endif
#if defined(PROPEL_NRF24L01_INO)
case PROTO_PROPEL:
next_callback=initPROPEL();
remote_callback = PROPEL_callback;
break;
#endif
#if defined(XN297DUMP_NRF24L01_INO)
case PROTO_XN297DUMP:
next_callback=initXN297Dump();
remote_callback = XN297Dump_callback;
break;
#endif
#if defined(JJRC345_NRF24L01_INO)
case PROTO_JJRC345:
next_callback=initJJRC345();
remote_callback = JJRC345_callback;
break;
#endif
#if defined(Q90C_NRF24L01_INO)
case PROTO_Q90C:
next_callback=initQ90C();
remote_callback = Q90C_callback;
break;
#endif
#if defined(TEST_CC2500_INO)
case PROTO_TEST:
next_callback=initTEST();
remote_callback = TEST_callback;
break;
#endif
#if defined(FAKE_NRF24L01_INO)
case PROTO_FAKE:
next_callback=initFAKE();
remote_callback = FAKE_callback;
break;
#endif
#endif
#ifdef SX1276_INSTALLED
#if defined(FRSKYR9_SX1276_INO)
case PROTO_FRSKY_R9:
next_callback = initFrSkyR9();
remote_callback = FrSkyR9_callback;
break;
#endif
#endif
}
debugln("Protocol selected: %d, sub proto %d, rxnum %d, option %d", protocol, sub_protocol, RX_num, option);
#ifdef MULTI_NAMES
@@ -1533,17 +1717,22 @@ void update_serial_data()
//Forced frequency tuning values for CC2500 protocols
#if defined(FORCE_FRSKYD_TUNING) && defined(FRSKYD_CC2500_INO)
if(protocol==PROTO_FRSKYD)
if(protocol==PROTO_FRSKYD)
option=FORCE_FRSKYD_TUNING; // Use config-defined tuning value for FrSkyD
else
#endif
#if defined(FORCE_FRSKYL_TUNING) && defined(FRSKYL_CC2500_INO)
if(protocol==PROTO_FRSKYL)
option=FORCE_FRSKYL_TUNING; // Use config-defined tuning value for FrSkyL
else
#endif
#if defined(FORCE_FRSKYV_TUNING) && defined(FRSKYV_CC2500_INO)
if(protocol==PROTO_FRSKYV)
option=FORCE_FRSKYV_TUNING; // Use config-defined tuning value for FrSkyV
else
#endif
#if defined(FORCE_FRSKYX_TUNING) && defined(FRSKYX_CC2500_INO)
if(protocol==PROTO_FRSKYX)
if(protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYX2)
option=FORCE_FRSKYX_TUNING; // Use config-defined tuning value for FrSkyX
else
#endif
@@ -1557,11 +1746,21 @@ void update_serial_data()
option=FORCE_CORONA_TUNING; // Use config-defined tuning value for CORONA
else
#endif
#if defined(FORCE_SKYARTEC_TUNING) && defined(SKYARTEC_CC2500_INO)
if (protocol==PROTO_SKYARTEC)
option=FORCE_SKYARTEC_TUNING; // Use config-defined tuning value for SKYARTEC
else
#endif
#if defined(FORCE_REDPINE_TUNING) && defined(REDPINE_CC2500_INO)
if (protocol==PROTO_REDPINE)
option=FORCE_REDPINE_TUNING; // Use config-defined tuning value for REDPINE
else
#endif
#if defined(FORCE_RADIOLINK_TUNING) && defined(RADIOLINK_CC2500_INO)
if (protocol==PROTO_RADIOLINK)
option = FORCE_RADIOLINK_TUNING; // Use config-defined tuning value for RADIOLINK
else
#endif
#if defined(FORCE_HITEC_TUNING) && defined(HITEC_CC2500_INO)
if (protocol==PROTO_HITEC)
option=FORCE_HITEC_TUNING; // Use config-defined tuning value for HITEC
@@ -1649,8 +1848,8 @@ void update_serial_data()
else
if( ((rx_ok_buff[1]&0x80)==0) && ((cur_protocol[1]&0x80)!=0) ) // Bind flag has been reset
{ // Request protocol to end bind
#if defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYV_CC2500_INO) || defined(AFHDS2A_A7105_INO)
if(protocol==PROTO_FRSKYD || protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYV || protocol==PROTO_AFHDS2A )
#if defined(FRSKYD_CC2500_INO) || defined(FRSKYL_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYV_CC2500_INO) || defined(AFHDS2A_A7105_INO) || defined(FRSKYR9_SX1276_INO) || defined(DSM_RX_CYRF6936_INO)
if(protocol==PROTO_FRSKYD || protocol==PROTO_FRSKYL || protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYX2 || protocol==PROTO_FRSKYV || protocol==PROTO_AFHDS2A || protocol==PROTO_FRSKY_R9 || protocol==PROTO_DSM_RX)
BIND_DONE;
else
#endif
@@ -1709,39 +1908,53 @@ void update_serial_data()
#endif
if(rx_len>27)
{ // Data available for the current protocol
#if defined(FRSKYX_CC2500_INO) || defined(FRSKYR9_SX1276_INO)
if((protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYX2 || protocol==PROTO_FRSKY_R9) && rx_len==28)
{//Protocol waiting for 1 byte during bind
binding_idx=rx_ok_buff[27];
}
#endif
#ifdef SPORT_SEND
if(protocol==PROTO_FRSKYX && rx_len==35)
if((protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYX2 || protocol==PROTO_FRSKY_R9) && rx_len==35)
{//Protocol waiting for 8 bytes
#define BYTE_STUFF 0x7D
#define STUFF_MASK 0x20
//debug("SPort_in: ");
SportData[SportTail]=0x7E;
SportTail = (SportTail+1) & (MAX_SPORT_BUFFER-1);
SportData[SportTail]=rx_ok_buff[27]&0x1F;
SportTail = (SportTail+1) & (MAX_SPORT_BUFFER-1);
boolean sport_valid=false;
for(uint8_t i=28;i<28+7;i++)
if(rx_ok_buff[i]!=0) sport_valid=true; //Check that the payload is not full of 0
if((rx_ok_buff[27]&0x1F) > 0x1B) //Check 1st byte validity
sport_valid=false;
if(sport_valid)
{
if(rx_ok_buff[i]==BYTE_STUFF)
{//stuff
SportData[SportTail]=BYTE_STUFF;
SportTail = (SportTail+1) & (MAX_SPORT_BUFFER-1);
SportData[SportTail]=rx_ok_buff[i]^STUFF_MASK;
}
else
SportData[SportTail]=rx_ok_buff[i];
//debug("%02X ",SportData[SportTail]);
SportData[SportTail]=0x7E;
SportTail = (SportTail+1) & (MAX_SPORT_BUFFER-1);
}
uint8_t used = SportTail;
if ( SportHead > SportTail )
used += MAX_SPORT_BUFFER - SportHead ;
else
used -= SportHead ;
if ( used >= MAX_SPORT_BUFFER-(MAX_SPORT_BUFFER>>2) )
{
DATA_BUFFER_LOW_on;
SEND_MULTI_STATUS_on; //Send Multi Status ASAP to inform the TX
debugln("Low buf=%d,h=%d,t=%d",used,SportHead,SportTail);
SportData[SportTail]=rx_ok_buff[27]&0x1F;
SportTail = (SportTail+1) & (MAX_SPORT_BUFFER-1);
for(uint8_t i=28;i<28+7;i++)
{
if( (rx_ok_buff[i]==BYTE_STUFF) || (rx_ok_buff[i]==0x7E) )
{//stuff
SportData[SportTail]=BYTE_STUFF;
SportTail = (SportTail+1) & (MAX_SPORT_BUFFER-1);
SportData[SportTail]=rx_ok_buff[i]^STUFF_MASK;
}
else
SportData[SportTail]=rx_ok_buff[i];
//debug("%02X ",SportData[SportTail]);
SportTail = (SportTail+1) & (MAX_SPORT_BUFFER-1);
}
uint8_t used = SportTail;
if ( SportHead > SportTail )
used += MAX_SPORT_BUFFER - SportHead ;
else
used -= SportHead ;
if ( used >= MAX_SPORT_BUFFER-(MAX_SPORT_BUFFER>>2) )
{
DATA_BUFFER_LOW_on;
SEND_MULTI_STATUS_on; //Send Multi Status ASAP to inform the TX
debugln("Low buf=%d,h=%d,t=%d",used,SportHead,SportTail);
}
}
}
#endif //SPORT_SEND
@@ -1791,6 +2004,9 @@ void modules_reset()
#ifdef NRF24L01_INSTALLED
NRF24L01_Reset();
#endif
#ifdef SX1276_INSTALLED
SX1276_Reset();
#endif
//Wait for every component to reset
delayMilliseconds(100);
@@ -1993,14 +2209,14 @@ void pollBoot()
#if defined(TELEMETRY)
void PPM_Telemetry_serial_init()
{
if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_BAYANG)|| (protocol==PROTO_NCC1701) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI)
if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_BAYANG)|| (protocol==PROTO_NCC1701) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI) || (protocol==PROTO_PROPEL) || (protocol==PROTO_RLINK)
#ifdef TELEMETRY_FRSKYX_TO_FRSKYD
|| (protocol==PROTO_FRSKYX)
|| (protocol==PROTO_FRSKYX) || (protocol==PROTO_FRSKYX2)
#endif
)
initTXSerial( SPEED_9600 ) ;
#ifndef TELEMETRY_FRSKYX_TO_FRSKYD
if(protocol==PROTO_FRSKYX)
if(protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYX2)
initTXSerial( SPEED_57600 ) ;
#endif
if(protocol==PROTO_DSM)
@@ -2059,6 +2275,51 @@ static uint32_t random_id(uint16_t address, uint8_t create_new)
#endif
}
// Generate frequency hopping sequence in the range [02..77]
static void __attribute__((unused)) calc_fh_channels(uint8_t num_ch)
{
uint8_t idx = 0;
uint32_t rnd = MProtocol_id;
uint8_t max=(num_ch/3)+2;
while (idx < num_ch)
{
uint8_t i;
uint8_t count_2_26 = 0, count_27_50 = 0, count_51_74 = 0;
rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
// Use least-significant byte. 73 is prime, so channels 76..77 are unused
uint8_t next_ch = ((rnd >> 8) % 73) + 2;
// Keep a distance of 5 between consecutive channels
if (idx !=0)
{
if(hopping_frequency[idx-1]>next_ch)
{
if(hopping_frequency[idx-1]-next_ch<5)
continue;
}
else
if(next_ch-hopping_frequency[idx-1]<5)
continue;
}
// 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] <= 26)
count_2_26++;
else if (hopping_frequency[i] <= 50)
count_27_50++;
else
count_51_74++;
}
if (i != idx)
continue;
if ( (next_ch <= 26 && count_2_26 < max) || (next_ch >= 27 && next_ch <= 50 && count_27_50 < max) || (next_ch >= 51 && count_51_74 < max) )
hopping_frequency[idx++] = next_ch;//find hopping frequency
}
}
/**************************/
/**************************/
/** Interrupt routines **/

View File

@@ -172,6 +172,10 @@ void NRF24L01_SetPower()
if(prev_power != power)
{
rf_setup = (rf_setup & 0xF9) | (power << 1);
if(power==3)
rf_setup |=0x01; // Si24r01 full power, unused bit for NRF
else
rf_setup &=0xFE;
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup);
prev_power=power;
}
@@ -505,7 +509,7 @@ boolean XN297_ReadPayload(uint8_t* msg, uint8_t len)
//process address
for (uint8_t i = 0; i < xn297_addr_len; ++i)
{
uint8_t b_in=xn297_tx_addr[xn297_addr_len-i-1];
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);
@@ -525,10 +529,13 @@ boolean XN297_ReadPayload(uint8_t* msg, uint8_t len)
}
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
NRF24L01_ReadPayload(buffer, len+2); // pcf + payload
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];
@@ -540,7 +547,35 @@ uint8_t XN297_ReadEnhancedPayload(uint8_t* msg, uint8_t len)
msg[i] ^= bit_reverse((xn297_scramble[xn297_addr_len+i+1] << 2) |
(xn297_scramble[xn297_addr_len+i+2] >> 6));
}
return pcf_size;
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

View File

@@ -0,0 +1,464 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef NRF24L01_INSTALLED
#include "iface_nrf250k.h"
static void __attribute__((unused)) XN297L_Init()
{
#ifdef CC2500_INSTALLED
if(option==0)
#endif
{//NRF
debugln("Using NRF");
PE1_on; //NRF24L01 antenna RF3 by default
PE2_off; //NRF24L01 antenna RF3 by default
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
NRF24L01_SetPower();
return;
}
//CC2500
#ifdef CC2500_INSTALLED
debugln("Using CC2500");
PE1_off; // antenna RF2
PE2_on;
CC2500_Reset();
CC2500_Strobe(CC2500_SIDLE);
// Address Config = No address check
// Base Frequency = 2400
// CRC Autoflush = false
// CRC Enable = false
// Channel Spacing = 333.251953
// Data Format = Normal mode
// Data Rate = 249.939
// Deviation = 126.953125
// Device Address = 0
// Manchester Enable = false
// Modulated = true
// Modulation Format = GFSK
// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word
// RX Filter BW = 203.125000
// Sync Word Qualifier Mode = No preamble/sync
// TX Power = 0
// Whitening = false
// Fast Frequency Hopping - no PLL auto calibration
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x01); // Packet Automation Control
CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x0A); // Frequency Synthesizer Control
CC2500_WriteReg(CC2500_0C_FSCTRL0, option); // Frequency offset hack
CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // Frequency Control Word, High Byte
CC2500_WriteReg(CC2500_0E_FREQ1, 0x4E); // Frequency Control Word, Middle Byte
CC2500_WriteReg(CC2500_0F_FREQ0, 0xC3); // Frequency Control Word, Low Byte
CC2500_WriteReg(CC2500_10_MDMCFG4, 0x8D); // Modem Configuration
CC2500_WriteReg(CC2500_11_MDMCFG3, 0x3B); // Modem Configuration
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x10); // Modem Configuration
CC2500_WriteReg(CC2500_13_MDMCFG1, 0x23); // Modem Configuration
CC2500_WriteReg(CC2500_14_MDMCFG0, 0xA4); // Modem Configuration
CC2500_WriteReg(CC2500_15_DEVIATN, 0x62); // Modem Deviation Setting
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // Main Radio Control State Machine Configuration
CC2500_WriteReg(CC2500_19_FOCCFG, 0x1D); // Frequency Offset Compensation Configuration
CC2500_WriteReg(CC2500_1A_BSCFG, 0x1C); // Bit Synchronization Configuration
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0xC7); // AGC Control
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x00); // AGC Control
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xB0); // AGC Control
CC2500_WriteReg(CC2500_21_FREND1, 0xB6); // Front End RX Configuration
CC2500_WriteReg(CC2500_23_FSCAL3, 0xEA); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_25_FSCAL1, 0x00); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_26_FSCAL0, 0x11); // Frequency Synthesizer Calibration
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
xn297_scramble_enabled=XN297_SCRAMBLED; //enabled by default
#endif
}
static void __attribute__((unused)) XN297L_SetTXAddr(const uint8_t* addr, uint8_t len)
{
#ifdef CC2500_INSTALLED
if(option==0)
#endif
{//NRF
XN297_SetTXAddr(addr,len);
return;
}
//CC2500
#ifdef CC2500_INSTALLED
if (len > 5) len = 5;
if (len < 3) len = 3;
xn297_addr_len = len;
memcpy(xn297_tx_addr, addr, len);
#endif
}
static void __attribute__((unused)) XN297L_WritePayload(uint8_t* msg, uint8_t len)
{
#ifdef CC2500_INSTALLED
if(option==0)
#endif
{//NRF
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(msg, len);
return;
}
//CC2500
#ifdef CC2500_INSTALLED
uint8_t buf[32];
uint8_t last = 0;
uint8_t i;
static const uint16_t initial = 0xb5d2;
// address
for (i = 0; i < xn297_addr_len; ++i)
{
buf[last] = xn297_tx_addr[xn297_addr_len - i - 1];
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[i];
last++;
}
// payload
for (i = 0; i < len; ++i) {
// bit-reverse bytes in packet
buf[last] = bit_reverse(msg[i]);
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[xn297_addr_len+i];
last++;
}
// crc
uint16_t crc = initial;
for (uint8_t i = 0; i < last; ++i)
crc = crc16_update(crc, buf[i], 8);
if(xn297_scramble_enabled)
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
else
crc ^= pgm_read_word(&xn297_crc_xorout[xn297_addr_len - 3 + len]);
buf[last++] = crc >> 8;
buf[last++] = crc & 0xff;
// stop TX/RX
CC2500_Strobe(CC2500_SIDLE);
// flush tx FIFO
CC2500_Strobe(CC2500_SFTX);
// packet length
CC2500_WriteReg(CC2500_3F_TXFIFO, last + 3);
// xn297L preamble
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, (uint8_t*)"\x71\x0f\x55", 3);
// xn297 packet
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buf, last);
// transmit
CC2500_Strobe(CC2500_STX);
#endif
}
static void __attribute__((unused)) XN297L_WriteEnhancedPayload(uint8_t* msg, uint8_t len, uint8_t noack)
{
#ifdef CC2500_INSTALLED
if(option==0)
#endif
{//NRF
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_WriteEnhancedPayload(msg, len, noack);
return;
}
//CC2500
#ifdef CC2500_INSTALLED
uint8_t buf[32];
uint8_t scramble_index=0;
uint8_t last = 0;
static uint8_t pid=0;
// address
for (uint8_t i = 0; i < xn297_addr_len; ++i)
{
buf[last] = xn297_tx_addr[xn297_addr_len-i-1];
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[scramble_index++];
last++;
}
// pcf
buf[last] = (len << 1) | (pid>>1);
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[scramble_index++];
last++;
buf[last] = (pid << 7) | (noack << 6);
// payload
buf[last]|= bit_reverse(msg[0]) >> 2; // first 6 bit of payload
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[scramble_index++];
for (uint8_t i = 0; i < len-1; ++i)
{
last++;
buf[last] = (bit_reverse(msg[i]) << 6) | (bit_reverse(msg[i+1]) >> 2);
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[scramble_index++];
}
last++;
buf[last] = bit_reverse(msg[len-1]) << 6; // last 2 bit of payload
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[scramble_index++] & 0xc0;
// crc
//if (xn297_crc)
{
uint16_t crc = 0xb5d2;
for (uint8_t i = 0; i < last; ++i)
crc = crc16_update(crc, buf[i], 8);
crc = crc16_update(crc, buf[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]);
buf[last++] |= (crc >> 8) >> 2;
buf[last++] = ((crc >> 8) << 6) | ((crc & 0xff) >> 2);
buf[last++] = (crc & 0xff) << 6;
}
pid++;
pid &= 3;
// stop TX/RX
CC2500_Strobe(CC2500_SIDLE);
// flush tx FIFO
CC2500_Strobe(CC2500_SFTX);
// packet length
CC2500_WriteReg(CC2500_3F_TXFIFO, last + 3);
// xn297L preamble
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, (uint8_t*)"\x71\x0F\x55", 3);
// xn297 packet
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buf, last);
// transmit
CC2500_Strobe(CC2500_STX);
#endif
}
static void __attribute__((unused)) XN297L_HoppingCalib(uint8_t num_freq)
{ //calibrate hopping frequencies
#ifdef CC2500_INSTALLED
if(option==0)
#endif
return; //NRF
#ifdef CC2500_INSTALLED
for (uint8_t i = 0; i < num_freq; i++)
{
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[i]*3);
CC2500_Strobe(CC2500_SCAL);
delayMicroseconds(900);
calData[i]=CC2500_ReadReg(CC2500_25_FSCAL1);
}
#endif
}
static void __attribute__((unused)) XN297L_Hopping(uint8_t index)
{
#ifdef CC2500_INSTALLED
if(option==0)
#endif
{//NRF
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[index]);
return;
}
#ifdef CC2500_INSTALLED
// spacing is 333.25 kHz, must multiply xn297 channel by 3
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[index] * 3);
// set PLL calibration
CC2500_WriteReg(CC2500_25_FSCAL1, calData[index]);
#endif
}
static void __attribute__((unused)) XN297L_RFChannel(uint8_t number)
{ //change channel
#ifdef CC2500_INSTALLED
if(option==0)
#endif
{//NRF
NRF24L01_WriteReg(NRF24L01_05_RF_CH, number);
return;
}
#ifdef CC2500_INSTALLED
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, number*3);
CC2500_Strobe(CC2500_SCAL);
delayMicroseconds(900);
#endif
}
static void __attribute__((unused)) XN297L_SetPower()
{
#ifdef CC2500_INSTALLED
if(option==0)
#endif
{//NRF
NRF24L01_SetPower();
return;
}
#ifdef CC2500_INSTALLED
CC2500_SetPower();
#endif
}
static void __attribute__((unused)) XN297L_SetFreqOffset()
{ // Frequency offset
#ifdef CC2500_INSTALLED
if(option==0 && prev_option==0)
#endif
return; //NRF
#ifdef CC2500_INSTALLED
if (prev_option != option)
{
if(prev_option==0 || option==0)
CHANGE_PROTOCOL_FLAG_on;
prev_option = option;
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
}
#endif
}
static void __attribute__((unused)) NRF250K_SetTXAddr(uint8_t* addr, uint8_t len)
{
if (len > 5) len = 5;
if (len < 3) len = 3;
#ifdef CC2500_INSTALLED
if(option==0)
#endif
{//NRF
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, len-2);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, addr, len);
return;
}
//CC2500
#ifdef CC2500_INSTALLED
xn297_addr_len = len;
memcpy(xn297_tx_addr, addr, len);
#endif
}
static void __attribute__((unused)) NRF250K_WritePayload(uint8_t* msg, uint8_t len)
{
#ifdef CC2500_INSTALLED
if(option==0)
#endif
{//NRF
NRF24L01_FlushTx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_MAX_RT));
NRF24L01_WritePayload(msg, len);
return;
}
//CC2500
#ifdef CC2500_INSTALLED
#if defined(ESKY150V2_CC2500_INO)
uint8_t buf[158];
#else
uint8_t buf[35];
#endif
uint8_t last = 0;
uint8_t i;
//nrf preamble
if(xn297_tx_addr[xn297_addr_len - 1] & 0x80)
buf[0]=0xAA;
else
buf[0]=0x55;
last++;
// address
for (i = 0; i < xn297_addr_len; ++i)
buf[last++] = xn297_tx_addr[xn297_addr_len - i - 1];
// payload
for (i = 0; i < len; ++i)
buf[last++] = msg[i];
// crc
uint16_t crc = 0xffff;
for (uint8_t i = 1; i < last; ++i)
crc = crc16_update(crc, buf[i], 8);
buf[last++] = crc >> 8;
buf[last++] = crc & 0xff;
buf[last++] = 0;
//for(uint8_t i=0;i<last;i++)
// debug("%02X ",buf[i]);
//debugln("");
// stop TX/RX
CC2500_Strobe(CC2500_SIDLE);
// flush tx FIFO
CC2500_Strobe(CC2500_SFTX);
// packet length
CC2500_WriteReg(CC2500_3F_TXFIFO, last);
// transmit nrf packet
uint8_t *buff=buf;
uint8_t status;
if(last>63)
{
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buff, 63);
CC2500_Strobe(CC2500_STX);
last-=63;
buff+=63;
while(last)
{//Loop until all the data is sent
do
{// Wait for the FIFO to become available
status=CC2500_ReadReg(CC2500_3A_TXBYTES | CC2500_READ_BURST);
}
while((status&0x7F)>31 && (status&0x80)==0);
if(last>31)
{//Send 31 bytes
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buff, 31);
last-=31;
buff+=31;
}
else
{//Send last bytes
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buff, last);
last=0;
}
}
}
else
{//Send packet
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buff, last);
CC2500_Strobe(CC2500_STX);
}
#endif
}
static boolean __attribute__((unused)) NRF250K_IsPacketSent()
{
#ifdef CC2500_INSTALLED
if(option==0)
#endif
{ //NRF
return NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS);
}
return true; // don't know on the CC2500 how to detect if the packet has been transmitted...
}
#endif

View File

@@ -0,0 +1,293 @@
/*
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_LITE_FORCE_ID
#define PELIKAN_LITE_FORCE_HOP
#define PELIKAN_BIND_COUNT 400
#define PELIKAN_BIND_RF 0x3C
#define PELIKAN_NUM_RF_CHAN 0x1D
#define PELIKAN_PACKET_PERIOD 7980
#define PELIKAN_LITE_PACKET_PERIOD 18000
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];
if(sub_protocol==PELIKAN_PRO)
packet[6] = 0x05; //sub version??
else //PELIKAN_LITE
packet[6] = 0x03; //sub version??
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(sub_protocol==PELIKAN_LITE || ++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()
{
if(phase==0)
{
#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);
if(sub_protocol==PELIKAN_PRO)
A7105_WriteReg(A7105_03_FIFOI,0x28);
else//PELIKAN_LITE
A7105_WriteID(MProtocol_id);
}
}
#ifdef MULTI_SYNC
telemetry_set_input_sync(sub_protocol==PELIKAN_PRO?PELIKAN_PACKET_PERIOD:PELIKAN_LITE_PACKET_PERIOD);
#endif
pelikan_build_packet();
if(sub_protocol==PELIKAN_PRO || IS_BIND_IN_PROGRESS)
return PELIKAN_PACKET_PERIOD;
//PELIKAN_LITE
phase++;
return 942;
}
//PELIKAN_LITE
A7105_Strobe(A7105_TX);
phase++;
if(phase==1)
return 942;
phase=0;
return PELIKAN_LITE_PACKET_PERIOD-942-942;
}
static uint8_t pelikan_firstCh(uint8_t u, uint8_t l)
{
int16_t i;
i = u * 10 + l - 23;
do
{
if (i > 24)
i -= 24;
if (i <= 0)
return 10;
else if ((i > 0) && (i < 13))
return 10 + 12 + (i * 4);
else if ((i > 12) && (i < 24))
return 10 - 2 + ((i - 12) * 4);
}
while (i > 24);
return 0;
}
static uint8_t pelikan_adjust_value(uint8_t value, uint8_t addition, uint8_t limit)
{
uint8_t i;
do
{
i = 0;
if (value > limit) {
value -= 62;
i++;
}
if (value == 24) {
value += addition;
i++;
}
if (value == 48) {
value += addition;
i++;
}
}
while (i > 0);
return value;
}
static uint8_t pelikan_add(uint8_t pfrq,uint8_t a, uint8_t limit)
{
uint8_t nfrq;
nfrq = pfrq + a;
nfrq = pelikan_adjust_value(nfrq, a, limit);
return nfrq;
}
static void __attribute__((unused)) pelikan_init_hop()
{
#define PELIKAN_HOP_LIMIT 70
rx_tx_addr[0] = 0;
rx_tx_addr[1]+= RX_num;
uint8_t high = (rx_tx_addr[1]>>4) % 3; // 0..2
uint8_t low = rx_tx_addr[1] & 0x0F;
if(high==2)
low %= 0x04; // 0..3
else if(high)
low %= 0x0E; // 0..D
else
low %= 0x0F; // 0..E
rx_tx_addr[1] = (high<<4) + low;
uint8_t addition = (20 * high)+ (2 * low) + 8;
uint8_t first_channel = pelikan_firstCh(high, low);
first_channel = pelikan_adjust_value(first_channel, addition, PELIKAN_HOP_LIMIT);
hopping_frequency[0] = first_channel;
debug("%02X", first_channel);
for (uint8_t i = 1; i < PELIKAN_NUM_RF_CHAN; i++)
{
hopping_frequency[i] = pelikan_add(hopping_frequency[i-1], addition, PELIKAN_HOP_LIMIT);
debug(" %02X", hopping_frequency[i]);
}
debugln("");
}
#ifdef PELIKAN_FORCE_ID
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 }
};
#endif
#ifdef PELIKAN_LITE_FORCE_HOP
const uint8_t PROGMEM pelikan_lite_hopp[][PELIKAN_NUM_RF_CHAN] = {
{ 0x46,0x2A,0x3E,0x5A,0x5C,0x24,0x4E,0x32,0x54,0x26,0x2C,0x34,0x56,0x1E,0x3A,0x3C,0x50,0x4A,0x2E,0x42,0x20,0x52,0x28,0x22,0x44,0x58,0x36,0x38,0x4C }
};
#endif
uint16_t initPelikan()
{
A7105_Init();
if(IS_BIND_IN_PROGRESS || sub_protocol==PELIKAN_LITE)
A7105_WriteReg(A7105_03_FIFOI,0x10);
pelikan_init_hop();
//ID from dump
#if defined(PELIKAN_FORCE_ID)
if(sub_protocol==PELIKAN_PRO)
{
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
// Fill frequency table
for(uint8_t i=0;i<PELIKAN_NUM_RF_CHAN;i++)
hopping_frequency[i]=pgm_read_byte_near(&pelikan_hopp[0][i]);
}
#endif
#if defined(PELIKAN_LITE_FORCE_ID) || defined(PELIKAN_LITE_FORCE_HOP)
if(sub_protocol==PELIKAN_LITE)
{
#if defined(PELIKAN_LITE_FORCE_ID)
// ID
rx_tx_addr[2]=0x60;
rx_tx_addr[3]=0x18;
#endif
#if defined(PELIKAN_LITE_FORCE_HOP)
// Hop frequency table
rx_tx_addr[0]=0x04; // hopping freq
rx_tx_addr[1]=0x63; // hopping freq
for(uint8_t i=0;i<PELIKAN_NUM_RF_CHAN;i++)
hopping_frequency[i]=pgm_read_byte_near(&pelikan_lite_hopp[0][i]);
#endif
}
#endif
MProtocol_id=((uint32_t)rx_tx_addr[0]<<24)|((uint32_t)rx_tx_addr[1]<<16)|((uint32_t)rx_tx_addr[2]<<8)|(rx_tx_addr[3]);
if(sub_protocol==PELIKAN_LITE && IS_BIND_DONE)
A7105_WriteID(MProtocol_id);
hopping_frequency_no=PELIKAN_NUM_RF_CHAN;
packet_count=5;
phase=0;
return 2400;
}
#endif

View File

@@ -223,6 +223,8 @@
#define S3_pin PA6
#define S4_pin PA7
//
#define RND_pin PB0
//
#define PE1_pin PB4 //PE1
#define PE2_pin PB5 //PE2
//CS pins
@@ -313,6 +315,20 @@
#define DEBUG_PIN_toggle
#endif
#ifdef MULTI_5IN1_INTERNAL
#undef RND_pin
#define SX1276_RST_pin PA2 //LED2 on other modules
#define SX1276_TXEN_pin PB0 //Random gen on other modules
#define SX1276_DIO0_pin PC13 //Unused on other modules
#define SX1276_RST_on digitalWrite(SX1276_RST_pin,HIGH)
#define SX1276_RST_off digitalWrite(SX1276_RST_pin,LOW)
#define SX1276_TXEN_on digitalWrite(SX1276_TXEN_pin,HIGH)
#define SX1276_RXEN_on digitalWrite(SX1276_TXEN_pin,LOW)
#define IS_DIO0_on ( digitalRead(SX1276_DIO0_pin)==HIGH )
#define IS_DIO0_off ( digitalRead(SX1276_DIO0_pin)==LOW )
#endif
#define cli() noInterrupts()
#define sei() interrupts()
#define delayMilliseconds(x) delay(x)

View File

@@ -0,0 +1,331 @@
/*
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 PROPEL 74-Z Speeder Bike.
#if defined(PROPEL_NRF24L01_INO)
#include "iface_nrf24l01.h"
//#define PROPEL_FORCE_ID
#define PROPEL_INITIAL_WAIT 500
#define PROPEL_PACKET_PERIOD 10000
#define PROPEL_BIND_RF_CHANNEL 0x23
#define PROPEL_PAYLOAD_SIZE 16
#define PROPEL_SEARCH_PERIOD 50 //*10ms
#define PROPEL_BIND_PERIOD 1500
#define PROPEL_PACKET_SIZE 14
#define PROPEL_RF_NUM_CHANNELS 4
#define PROPEL_ADDRESS_LENGTH 5
#define PROPEL_DEFAULT_PERIOD 20
enum {
PROPEL_BIND1 = 0,
PROPEL_BIND2,
PROPEL_BIND3,
PROPEL_DATA1,
};
static uint16_t __attribute__((unused)) PROPEL_checksum()
{
typedef union {
struct {
uint8_t h:1;
uint8_t g:1;
uint8_t f:1;
uint8_t e:1;
uint8_t d:1;
uint8_t c:1;
uint8_t b:1;
uint8_t a:1;
} bits;
uint8_t byte:8;
} byte_bits_t;
uint8_t sum = packet[0];
for (uint8_t i = 1; i < PROPEL_PACKET_SIZE - 2; i++)
sum += packet[i];
byte_bits_t in = { .byte = sum };
byte_bits_t out = { .byte = sum };
out.byte ^= 0x0a;
out.bits.d = !(in.bits.d ^ in.bits.h);
out.bits.c = (!in.bits.c && !in.bits.d && in.bits.g)
|| (in.bits.c && !in.bits.d && !in.bits.g)
|| (!in.bits.c && in.bits.g && !in.bits.h)
|| (in.bits.c && !in.bits.g && !in.bits.h)
|| (in.bits.c && in.bits.d && in.bits.g && in.bits.h)
|| (!in.bits.c && in.bits.d && !in.bits.g && in.bits.h);
out.bits.b = (!in.bits.b && !in.bits.c && !in.bits.d)
|| (in.bits.b && in.bits.c && in.bits.g)
|| (!in.bits.b && !in.bits.c && !in.bits.g)
|| (!in.bits.b && !in.bits.d && !in.bits.g)
|| (!in.bits.b && !in.bits.c && !in.bits.h)
|| (!in.bits.b && !in.bits.g && !in.bits.h)
|| (in.bits.b && in.bits.c && in.bits.d && in.bits.h)
|| (in.bits.b && in.bits.d && in.bits.g && in.bits.h);
out.bits.a = (in.bits.a && !in.bits.b)
|| (in.bits.a && !in.bits.c && !in.bits.d)
|| (in.bits.a && !in.bits.c && !in.bits.g)
|| (in.bits.a && !in.bits.d && !in.bits.g)
|| (in.bits.a && !in.bits.c && !in.bits.h)
|| (in.bits.a && !in.bits.g && !in.bits.h)
|| (!in.bits.a && in.bits.b && in.bits.c && in.bits.g)
|| (!in.bits.a && in.bits.b && in.bits.c && in.bits.d && in.bits.h)
|| (!in.bits.a && in.bits.b && in.bits.d && in.bits.g && in.bits.h);
return (sum << 8) | (out.byte & 0xff);
}
static void __attribute__((unused)) PROPEL_bind_packet(bool valid_rx_id)
{
memset(packet, 0, PROPEL_PACKET_SIZE);
packet[0] = 0xD0;
memcpy(&packet[1], rx_tx_addr, 4); // only 4 bytes sent of 5-byte address
if (valid_rx_id) memcpy(&packet[5], rx_id, 4);
packet[9] = rf_ch_num; // hopping table to be used when switching to normal mode
packet[11] = 0x05; // unknown, 0x01 on TX2??
uint16_t check = PROPEL_checksum();
packet[12] = check >> 8;
packet[13] = check & 0xff;
NRF24L01_WriteReg(NRF24L01_07_STATUS, (_BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT)));
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WritePayload(packet, PROPEL_PACKET_SIZE);
}
static void __attribute__((unused)) PROPEL_data_packet()
{
memset(packet, 0, PROPEL_PACKET_SIZE);
packet[0] = 0xC0;
packet[1] = convert_channel_16b_limit(THROTTLE, 0x2f, 0xcf);
packet[2] = convert_channel_16b_limit(RUDDER , 0xcf, 0x2f);
packet[3] = convert_channel_16b_limit(ELEVATOR, 0x2f, 0xcf);
packet[4] = convert_channel_16b_limit(AILERON , 0xcf, 0x2f);
packet[5] = 0x40; //might be trims but unsused
packet[6] = 0x40; //might be trims but unsused
packet[7] = 0x40; //might be trims but unsused
packet[8] = 0x40; //might be trims but unsused
if (bind_phase)
{//need to send a couple of default packets after bind
bind_phase--;
packet[10] = 0x80; // LEDs
}
else
{
packet[9] = 0x02 // Always fast speed, slow=0x00, medium=0x01, fast=0x02, 0x03=flight training mode
| GET_FLAG( CH14_SW, 0x03) // Flight training mode
| GET_FLAG( CH10_SW, 0x04) // Calibrate
| GET_FLAG( CH12_SW, 0x08) // Take off
| GET_FLAG( CH8_SW, 0x10) // Fire
| GET_FLAG( CH11_SW, 0x20) // Altitude hold=0x20
| GET_FLAG( CH6_SW, 0x40) // Roll CW
| GET_FLAG( CH7_SW, 0x80); // Roll CCW
packet[10] = GET_FLAG( CH13_SW, 0x20) // Land
| GET_FLAG( CH9_SW, 0x40) // Weapon system activted=0x40
| GET_FLAG(!CH5_SW, 0x80); // LEDs
}
packet[11] = 5; // unknown, 0x01 on TX2??
uint16_t check = PROPEL_checksum();
packet[12] = check >> 8;
packet[13] = check & 0xff;
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
hopping_frequency_no &= 0x03;
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, (_BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT)));
NRF24L01_FlushTx();
NRF24L01_WritePayload(packet, PROPEL_PACKET_SIZE);
}
static void __attribute__((unused)) PROPEL_init()
{
NRF24L01_Initialize();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x7f);
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3f); // AA on all pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x3f); // Enable all pipes
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte address
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x36); // retransmit 1ms, 6 times
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x07); // ?? match protocol capture
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x99\x77\x55\x33\x11", PROPEL_ADDRESS_LENGTH); //Bind address
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x99\x77\x55\x33\x11", PROPEL_ADDRESS_LENGTH); //Bind address
NRF24L01_WriteReg(NRF24L01_05_RF_CH, PROPEL_BIND_RF_CHANNEL);
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f); // Enable dynamic payload length
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); // Enable all features
// Beken 2425 register bank 1 initialized here in stock tx capture
// Hopefully won't matter for nRF compatibility
NRF24L01_FlushTx();
NRF24L01_SetTxRxMode(TX_EN);
}
const uint8_t PROGMEM PROPEL_hopping []= { 0x47,0x36,0x27,0x44,0x33,0x0D,0x3C,0x2E,0x1B,0x39,0x2A,0x18 };
static void __attribute__((unused)) PROPEL_initialize_txid()
{
//address last byte
rx_tx_addr[4]=0x11;
//random hopping channel table
rf_ch_num=random(0xfefefefe)&0x03;
for(uint8_t i=0; i<3; i++)
hopping_frequency[i]=pgm_read_byte_near( &PROPEL_hopping[i + 3*rf_ch_num] );
hopping_frequency[3]=0x23;
#ifdef PROPEL_FORCE_ID
if(RX_num&1)
memcpy(rx_tx_addr, (uint8_t *)"\x73\xd3\x31\x30\x11", PROPEL_ADDRESS_LENGTH); //TX1: 73 d3 31 30 11
else
memcpy(rx_tx_addr, (uint8_t *)"\x94\xc5\x31\x30\x11", PROPEL_ADDRESS_LENGTH); //TX2: 94 c5 31 30 11
rf_ch_num = 0x03; //TX1
memcpy(hopping_frequency,(uint8_t *)"\x39\x2A\x18\x23",PROPEL_RF_NUM_CHANNELS); //TX1: 57,42,24,35
rf_ch_num = 0x00; //TX2
memcpy(hopping_frequency,(uint8_t *)"\x47\x36\x27\x23",PROPEL_RF_NUM_CHANNELS); //TX2: 71,54,39,35
rf_ch_num = 0x01; // Manual search
memcpy(hopping_frequency,(uint8_t *)"\x44\x33\x0D\x23",PROPEL_RF_NUM_CHANNELS); //Manual: 68,51,13,35
rf_ch_num = 0x02; // Manual search
memcpy(hopping_frequency,(uint8_t *)"\x3C\x2E\x1B\x23",PROPEL_RF_NUM_CHANNELS); //Manual: 60,46,27,35
#endif
}
uint16_t PROPEL_callback()
{
uint8_t status;
switch (phase)
{
case PROPEL_BIND1:
PROPEL_bind_packet(false); //rx_id unknown
phase++; //BIND2
return PROPEL_BIND_PERIOD;
case PROPEL_BIND2:
status=NRF24L01_ReadReg(NRF24L01_07_STATUS);
if (status & _BV(NRF24L01_07_MAX_RT))
{// Max retry (6) reached
phase = PROPEL_BIND1;
return PROPEL_BIND_PERIOD;
}
if (!(_BV(NRF24L01_07_RX_DR) & status))
return PROPEL_BIND_PERIOD; // nothing received
// received frame, got rx_id, save it
NRF24L01_ReadPayload(packet_in, PROPEL_PACKET_SIZE);
memcpy(rx_id, &packet_in[1], 4);
PROPEL_bind_packet(true); //send bind packet with rx_id
phase++; //BIND3
break;
case PROPEL_BIND3:
if (_BV(NRF24L01_07_RX_DR) & NRF24L01_ReadReg(NRF24L01_07_STATUS))
{
NRF24L01_ReadPayload(packet_in, PROPEL_PACKET_SIZE);
if (packet_in[0] == 0xa3 && memcmp(&packet_in[1],rx_id,4)==0)
{//confirmation from the model
phase++; //PROPEL_DATA1
bind_phase=PROPEL_DEFAULT_PERIOD;
packet_count=0;
BIND_DONE;
break;
}
}
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, PROPEL_ADDRESS_LENGTH);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, PROPEL_ADDRESS_LENGTH);
PROPEL_bind_packet(true); //send bind packet with rx_id
break;
case PROPEL_DATA1:
#ifdef PROPEL_HUB_TELEMETRY
if (_BV(NRF24L01_07_RX_DR) & NRF24L01_ReadReg(NRF24L01_07_STATUS))
{// data received from the model
NRF24L01_ReadPayload(packet_in, PROPEL_PACKET_SIZE);
if (packet_in[0] == 0xa3 && memcmp(&packet_in[1],rx_id,3)==0)
{
telemetry_counter++; //LQI
v_lipo1=packet[5]; //number of life left?
v_lipo2=packet[4]; //bit mask: 0x80=flying, 0x08=taking off, 0x04=landing, 0x00=landed/crashed
if(telemetry_lost==0)
telemetry_link=1;
}
}
packet_count++;
if(packet_count>=100)
{//LQI calculation
packet_count=0;
TX_LQI=telemetry_counter;
RX_RSSI=telemetry_counter;
telemetry_counter = 0;
telemetry_lost=0;
}
#endif
PROPEL_data_packet();
break;
}
return PROPEL_PACKET_PERIOD;
}
uint16_t initPROPEL()
{
BIND_IN_PROGRESS; // autobind protocol
PROPEL_initialize_txid();
PROPEL_init();
hopping_frequency_no = 0;
phase=PROPEL_BIND1;
return PROPEL_INITIAL_WAIT;
}
#endif
// equations for checksum check byte from truth table
// (1) z = a && !b
// || a && !c && !d
// || a && !c && !g
// || a && !d && !g
// || a && !c && !h
// || a && !g && !h
// || !a && b && c && g
// || !a && b && c && d && h
// || !a && b && d && g && h;
//
// (2) y = !b && !c && !d
// || b && c && g
// || !b && !c && !g
// || !b && !d && !g
// || !b && !c && !h
// || !b && !g && !h
// || b && c && d && h
// || b && d && g && h;
//
// (3) x = !c && !d && g
// || c && !d && !g
// || !c && g && !h
// || c && !g && !h
// || c && d && g && h
// || !c && d && !g && h;
//
// (4) w = d && h
// || !d && !h;
//
// (5) v = !e;
//
// (6) u = f;
//
// (7) t = !g;
//
// (8) s = h;

View File

@@ -0,0 +1,176 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// Compatible with Q90C quad.
#if defined(Q90C_NRF24L01_INO)
#include "iface_nrf250k.h"
//#define FORCE_Q90C_ORIGINAL_ID
#define Q90C_BIND_COUNT 250
#define Q90C_PACKET_PERIOD 7336 // 6200 on saimat's TX...
#define Q90C_INITIAL_WAIT 500
#define Q90C_PACKET_SIZE 12
#define Q90C_RF_BIND_CHANNEL 0x33
#define Q90C_RF_NUM_CHANNELS 3
#define Q90C_ADDRESS_LENGTH 5
bool Q90C_VTX;
int16_t Q90C_channel(uint8_t num, int16_t in_min,int16_t in_max, int16_t out_min,int16_t out_max)
{
int32_t val=Channel_data[num];
if(val<in_min) val=in_min;
else if(val>in_max) val=in_max;
val=(val-in_min)*(out_max-out_min)/(in_max-in_min)+out_min;
return (uint16_t)val;
}
static void __attribute__((unused)) Q90C_send_packet()
{
if(IS_BIND_IN_PROGRESS)
{
memcpy(packet, rx_tx_addr, 4);
memcpy(&packet[4], hopping_frequency, 3);
//packet[7] = 0x1e; // 2e on Saimat 1???
packet[10] = 0x4B;
packet[11] = 0x4E;
}
else
{
XN297L_Hopping(hopping_frequency_no++); // RF Freq
hopping_frequency_no %= Q90C_RF_NUM_CHANNELS;
packet[0]= convert_channel_8b(THROTTLE); // 0..255
// A,E,R have weird scaling, 0x00-0xff range (unsigned) but center isn't 7f or 80
// rudder ff-7a-00
if (Channel_data[RUDDER] <= CHANNEL_MID)
packet[1] = Q90C_channel(RUDDER, CHANNEL_MIN_100, CHANNEL_MID, 0xff, 0x7a );
else
packet[1] = Q90C_channel(RUDDER, CHANNEL_MID, CHANNEL_MAX_100, 0x7a, 0x00 );
// elevator 00-88-ff
if (Channel_data[ELEVATOR] <= CHANNEL_MID)
packet[2] = Q90C_channel(ELEVATOR, CHANNEL_MIN_100, CHANNEL_MID, 0x00, 0x88);
else
packet[2] = Q90C_channel(ELEVATOR, CHANNEL_MID, CHANNEL_MAX_100, 0x88, 0xff);
// aileron ff-88-00
if (Channel_data[AILERON] <= CHANNEL_MID)
packet[3] = Q90C_channel(AILERON, CHANNEL_MIN_100, CHANNEL_MID, 0xff, 0x88);
else
packet[3] = Q90C_channel(AILERON, CHANNEL_MID, CHANNEL_MAX_100, 0x88, 0x00);
// required to "arm" (low throttle + aileron to the right)
if (packet[0] < 5 && packet[3] < 25) {
packet[1] = 0x7a;
packet[2] = 0x88;
}
packet[4] = 0x1e; // T trim 00-1e-3c
packet[5] = 0x1e; // R trim 3c-1e-00
packet[6] = 0x1e; // E trim 00-1e-3c
//packet[7] = 0x1e; // A trim 00-1e-3c
packet[8] |= 0x02; // Rudder rate 0=min,1,2=max
if(state!=Channel_data[CH5])
{
state=Channel_data[CH5];
if(state<CHANNEL_MIN_COMMAND)
packet[8] ^= 0x04; // Angle
else if(state>CHANNEL_MAX_COMMAND)
packet[8] ^= 0x10; // Acro
else
packet[8] ^= 0x08; // Horizon
}
if(!Q90C_VTX && CH6_SW)
packet[8] ^= 0x20; // VTX+
Q90C_VTX=CH6_SW;
debugln("8=%02X",packet[8]);
packet[10] = packet_count++;
}
packet[7] = 0x1e; // bind 1e or 2e, normal: A trim 00-1e-3c
// checksum
if(IS_BIND_DONE)
{
uint8_t sum=0;
for (uint8_t i = 0; i < Q90C_PACKET_SIZE - 1; i++)
sum += packet[i];
packet[11] = sum ^ crc8;
}
XN297L_SetFreqOffset(); // Set frequency offset
XN297L_SetPower(); // Set tx_power
XN297L_WriteEnhancedPayload(packet, Q90C_PACKET_SIZE, 0);
}
static void __attribute__((unused)) Q90C_initialize_txid()
{
calc_fh_channels(Q90C_RF_NUM_CHANNELS);
rx_tx_addr[4]=0x4B;
#ifdef FORCE_Q90C_ORIGINAL_ID
//24 03 01 82 18 26 37 1E 00 00 4B 4E
memcpy(rx_tx_addr, (uint8_t*)"\x24\x03\x01\x82\x4B", Q90C_ADDRESS_LENGTH); //Goebish
memcpy(hopping_frequency, (uint8_t*)"\x18\x26\x37", Q90C_RF_NUM_CHANNELS);
//4C 0A 02 01 17 24 36 2E 00 00 4B 4E
memcpy(rx_tx_addr, (uint8_t*)"\x4C\x0A\x02\x01\x4B", Q90C_ADDRESS_LENGTH); //Saimat 1
memcpy(hopping_frequency, (uint8_t*)"\x17\x24\x36", Q90C_RF_NUM_CHANNELS);
//34 13 02 01 18 26 37 1E 00 00 4B 4E
memcpy(rx_tx_addr, (uint8_t*)"\x34\x13\x02\x01\x4B", Q90C_ADDRESS_LENGTH); //Saimat 2
memcpy(hopping_frequency, (uint8_t*)"\x18\x26\x37", Q90C_RF_NUM_CHANNELS);
#endif
crc8=rx_tx_addr[0]^rx_tx_addr[1]^rx_tx_addr[2]^rx_tx_addr[3];
}
static void __attribute__((unused)) Q90C_init()
{
XN297L_Init();
if(IS_BIND_IN_PROGRESS)
XN297L_SetTXAddr((uint8_t*)"\x4F\x43\x54\x81\x81", Q90C_ADDRESS_LENGTH);
else
XN297L_SetTXAddr(rx_tx_addr, Q90C_ADDRESS_LENGTH);
XN297L_HoppingCalib(Q90C_RF_NUM_CHANNELS); // Calibrate all channels
XN297L_RFChannel(Q90C_RF_BIND_CHANNEL); // Set bind channel
}
uint16_t Q90C_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(Q90C_PACKET_PERIOD);
#endif
if(IS_BIND_IN_PROGRESS)
if(--bind_counter==0)
{
BIND_DONE;
XN297L_SetTXAddr(rx_tx_addr, Q90C_ADDRESS_LENGTH);
}
Q90C_send_packet();
return Q90C_PACKET_PERIOD;
}
uint16_t initQ90C()
{
Q90C_initialize_txid();
Q90C_init();
hopping_frequency_no = 0;
packet_count = 0;
bind_counter=Q90C_BIND_COUNT;
//features
state=Channel_data[CH5];
Q90C_VTX=CH6_SW;
packet[8] = 0x00;
packet[9] = 0x00;
return Q90C_INITIAL_WAIT;
}
#endif

View File

@@ -0,0 +1,336 @@
/*
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/>.
*/
// Radiolink surface protocol. TXs: RC4GS,RC6GS. Compatible RXs:R7FG(Std),R6FG,R6F,R8EF,R8FM,R8F,R4FGM
#if defined(RLINK_CC2500_INO)
#include "iface_cc2500.h"
//#define RLINK_FORCE_ID
#define RLINK_TX_PACKET_LEN 33
#define RLINK_RX_PACKET_LEN 15
#define RLINK_TX_ID_LEN 4
#define RLINK_HOP 16
enum {
RLINK_DATA = 0x00,
RLINK_RX1 = 0x01,
RLINK_RX2 = 0x02,
};
const PROGMEM uint8_t RLINK_hopping[][8] = {
/* 4C494E4B */ { 0xBC, 0x5A, 0x70, 0x4E, 0xDF, 0x32, 0x16, 0x89 },
/* 4D494E4B */ { 0x4C, 0xF3, 0xEA, 0x5B, 0x62, 0x9D, 0x01, 0x87 },
/* 4E494E4B */ { 0x86, 0xEA, 0xD0, 0xC9, 0x2B, 0x53, 0x7F, 0x41 },
/* 4F494E4B */ { 0xAC, 0x91, 0x7D, 0x48, 0xE0, 0xB5, 0x32, 0xF6 },
/* 50494E4B */ { 0xD6, 0x7C, 0xA4, 0x93, 0x5F, 0xE1, 0x02, 0xB8 },
/* 51494E4B */ { 0xED, 0x04, 0x73, 0xC8, 0x56, 0xB9, 0x1F, 0xA2 },
/* 52494E4B */ { 0xA7, 0xF0, 0x36, 0xB2, 0x95, 0x4E, 0x1C, 0xD8 },
/* 53494E4B */ { 0x76, 0x8B, 0xA0, 0x3E, 0x51, 0x4C, 0x9D, 0x2F },
/* 54494E4B */ { 0x07, 0x23, 0x16, 0xFD, 0xC9, 0x5B, 0x84, 0xAE },
/* 55494E4B */ { 0xD3, 0xA0, 0x69, 0xBF, 0x12, 0x8C, 0x4E, 0x57 },
/* 56494E4B */ { 0xA6, 0xBE, 0x91, 0xD3, 0x7C, 0x4F, 0x82, 0x50 },
/* 57494E4B */ { 0x91, 0xDA, 0xBC, 0x75, 0x82, 0x36, 0x4E, 0xF0 },
/* 58494E4B */ { 0x9A, 0x27, 0x5C, 0xF4, 0xD8, 0xB0, 0x36, 0xE1 },
/* 59494E4B */ { 0x92, 0xF1, 0x34, 0xA7, 0x5B, 0x0C, 0xED, 0x86 },
/* 5A494E4B */ { 0x8C, 0x2B, 0x51, 0xF9, 0x3E, 0x4A, 0x67, 0xD0 },
/* 5B494E4B */ { 0x5E, 0x3D, 0x67, 0x9B, 0xA2, 0x84, 0xFC, 0x01 },
/* 5C494E4B */ { 0xF9, 0x35, 0xBD, 0x78, 0x26, 0x1C, 0x0E, 0xA4 },
/* 5D494E4B */ { 0xD9, 0x7B, 0x48, 0x0E, 0x2A, 0xCF, 0x13, 0x65 },
/* 5E494E4B */ { 0x07, 0xE4, 0xF9, 0x8A, 0x3C, 0x21, 0xB5, 0xD6 },
/* 5F494E4B */ { 0xEB, 0xFA, 0x29, 0xD1, 0x54, 0x3C, 0x07, 0x86 },
/* 60494E4B */ { 0xDF, 0xCE, 0x0A, 0x32, 0x71, 0x5B, 0x96, 0x48 },
/* 61494E4B */ { 0x19, 0x86, 0xF5, 0x3A, 0x27, 0xDC, 0x0E, 0xB4 },
/* 62494E4B */ { 0xF8, 0x47, 0x9C, 0xE0, 0x2D, 0xBA, 0x15, 0x36 },
/* 63494E4B */ { 0xED, 0x78, 0x01, 0xA3, 0x2B, 0x6C, 0x45, 0xF9 },
/* 64494E4B */ { 0xE0, 0xA2, 0xD4, 0x6B, 0xF5, 0x18, 0x3C, 0x79 },
/* 65494E4B */ { 0x26, 0x90, 0x8B, 0x5D, 0x31, 0xCF, 0xE7, 0x4A },
/* 66494E4B */ { 0x7B, 0x12, 0xA8, 0x4F, 0xC0, 0x65, 0xD9, 0x3E },
/* 67494E4B */ { 0x35, 0xA2, 0x14, 0xBE, 0x06, 0x7D, 0x98, 0xFC },
/* 68494E4B */ { 0xD2, 0xA9, 0x7E, 0x40, 0x6F, 0x83, 0x5C, 0xB1 },
/* 69494E4B */ { 0xE5, 0xB9, 0xC1, 0x04, 0x83, 0x27, 0xA6, 0xFD },
/* 6A494E4B */ { 0x8E, 0x0C, 0x4A, 0x51, 0xFB, 0x63, 0x92, 0x7D },
/* 6B494E4B */ { 0xC7, 0x1D, 0x02, 0x93, 0x45, 0xF8, 0xA6, 0xBE },
/* 6C494E4B */ { 0xC1, 0x64, 0x59, 0x0A, 0x7D, 0x3F, 0x28, 0xEB },
/* 6D494E4B */ { 0xEF, 0x75, 0xAB, 0x94, 0xD2, 0x83, 0x1C, 0x60 },
/* 6E494E4B */ { 0xA1, 0x20, 0x54, 0x68, 0x9E, 0x7B, 0x3D, 0xFC },
/* 6F494E4B */ { 0x3E, 0x60, 0x28, 0xFC, 0xDA, 0x45, 0x9B, 0x71 },
/* 70494E4B */ { 0xB7, 0x0E, 0xA8, 0x23, 0xFC, 0x65, 0x4D, 0x91 },
/* 71494E4B */ { 0x29, 0x34, 0x51, 0x7C, 0xB8, 0xFD, 0x0E, 0x6A },
/* 72494E4B */ { 0x1B, 0x06, 0x3C, 0x89, 0xF5, 0x2A, 0x7E, 0xD4 },
/* 73494E4B */ { 0xF2, 0xC9, 0x63, 0x57, 0x0A, 0xB1, 0x48, 0xDE },
/* 74494E4B */ { 0x24, 0xAE, 0x0C, 0x19, 0x53, 0x7B, 0xF6, 0x8D },
/* 75494E4B */ { 0xEC, 0xD8, 0xF2, 0x4B, 0xA3, 0x51, 0x09, 0x76 },
/* 76494E4B */ { 0x98, 0x71, 0x5E, 0xAD, 0xFC, 0x04, 0x3B, 0x62 },
/* 77494E4B */ { 0xAE, 0xF6, 0xB7, 0x01, 0x52, 0x34, 0x9D, 0x8C },
/* 78494E4B */ { 0x69, 0x48, 0xF1, 0x3C, 0xDB, 0x0E, 0x25, 0xA7 },
/* 79494E4B */ { 0xCF, 0x60, 0x94, 0xAD, 0xB1, 0x82, 0x73, 0xE5 },
/* 7A494E4B */ { 0xFA, 0xC1, 0xD7, 0xB0, 0x53, 0x92, 0x6E, 0x48 },
/* 7B494E4B */ { 0xAC, 0x7D, 0xE5, 0x8B, 0x41, 0x96, 0x2F, 0x30 },
/* 7C494E4B */ { 0xFD, 0xC1, 0xB9, 0x02, 0xE4, 0x87, 0x56, 0x3A },
/* 7D494E4B */ { 0x30, 0xDA, 0x4F, 0x8E, 0x5C, 0xB9, 0x26, 0x71 },
/* 7E494E4B */ { 0xDC, 0xF9, 0x57, 0x30, 0x82, 0x1E, 0x6A, 0x4B },
/* 7F494E4B */ { 0x84, 0x1D, 0x7E, 0x29, 0x3C, 0x65, 0xA0, 0xBF },
/* 80494E4B */ { 0x01, 0xA3, 0xF6, 0xE2, 0x4C, 0x8B, 0x5D, 0x79 },
/* 81494E4B */ { 0xA1, 0x32, 0xE7, 0x08, 0x4D, 0x5B, 0x9F, 0x6C },
/* 82494E4B */ { 0x31, 0x40, 0x67, 0x8F, 0xBA, 0x95, 0x2C, 0xED },
/* 83494E4B */ { 0x91, 0x76, 0xFA, 0x83, 0x20, 0x4B, 0xEC, 0x5D },
/* 84494E4B */ { 0xDB, 0x54, 0xC2, 0x61, 0xF0, 0xA9, 0x87, 0x3E },
/* 85494E4B */ { 0xC0, 0xB4, 0x61, 0xD3, 0x7A, 0x5F, 0x82, 0x9E },
/* 86494E4B */ { 0xD6, 0xCF, 0x9B, 0x75, 0xE1, 0x42, 0x3A, 0x80 },
/* 87494E4B */ { 0xFE, 0xA2, 0xB4, 0x9C, 0x10, 0x7D, 0x56, 0x83 },
/* 88494E4B */ { 0xD2, 0x79, 0x54, 0xEF, 0xC8, 0x0B, 0x36, 0xA1 },
/* 89494E4B */ { 0x8D, 0xCF, 0x23, 0x64, 0xE5, 0x0B, 0x1A, 0x97 },
/* 8A494E4B */ { 0x07, 0xC4, 0xEF, 0x9A, 0x61, 0xD8, 0xB3, 0x52 },
/* 8B494E4B */ { 0x45, 0x6E, 0xBF, 0x8C, 0x9A, 0x2D, 0x31, 0x70 },
#ifdef RLINK_FORCE_ID
/* 3A99223A */ { 0x1F, 0x89, 0x25, 0x06, 0x4E, 0xBD, 0x3A, 0xC7 },
/* FC110D20 */ { 0xBC, 0xFE, 0x59, 0x84, 0x37, 0xA1, 0xD0, 0x62 }
#endif
};
static void __attribute__((unused)) RLINK_load_hopp(uint8_t num)
{
uint8_t inc=3*(rx_tx_addr[0]&3);
for (uint8_t i = 0; i < RLINK_HOP>>1; i++)
{
uint8_t val=pgm_read_byte_near(&RLINK_hopping[num][i]);
hopping_frequency[ i<<1 ]=12*(val>>4 )+inc;
hopping_frequency[(i<<1)+1]=12*(val&0x0F)+inc;
}
// replace one of the channel randomely
rf_ch_num=random(0xfefefefe)%0x11; // 0x00..0x10
if(inc==9) inc=6; // frequency exception
hopping_frequency[rf_ch_num]=12*16+inc;
}
static void __attribute__((unused)) RLINK_init()
{
// channels order depend on ID and currently unknown so using a table of 64 entries...
uint8_t id=rx_tx_addr[3]&0x3F;
memcpy(rx_tx_addr,"\x4C\x49\x4E\x4B",RLINK_TX_ID_LEN);
rx_tx_addr[0] += id;
RLINK_load_hopp(id);
#ifdef RLINK_FORCE_ID
//surface RC6GS
memcpy(rx_tx_addr,"\x3A\x99\x22\x3A",RLINK_TX_ID_LEN);
RLINK_load_hopp(64);
//air T8FB
//memcpy(rx_tx_addr,"\xFC\x11\x0D\x20",RLINK_TX_ID_LEN);
//RLINK_load_hopp(65);
#endif
/* debug("ID:");
for(uint8_t i=0;i<RLINK_TX_ID_LEN;i++)
debug(" 0x%02X",rx_tx_addr[i]);
debugln("");
debug("Hop(%d):", rf_ch_num);
for(uint8_t i=0;i<RLINK_HOP;i++)
debug(" 0x%02X",hopping_frequency[i]);
debugln("");
*/
}
const PROGMEM uint8_t RLINK_init_values[] = {
/* 00 */ 0x5B, 0x06, 0x5C, 0x07, 0xAB, 0xCD, 0x40, 0x04,
/* 08 */ 0x45, 0x00, 0x00, 0x06, 0x00, 0x5C, 0x62, 0x76,
/* 10 */ 0x7A, 0x7F, 0x13, 0x23, 0xF8, 0x44, 0x07, 0x30,
/* 18 */ 0x18, 0x16, 0x6C, 0x43, 0x40, 0x91, 0x87, 0x6B,
/* 20 */ 0xF8, 0x56, 0x10, 0xA9, 0x0A, 0x00, 0x11
};
static void __attribute__((unused)) RLINK_rf_init()
{
CC2500_Strobe(CC2500_SIDLE);
for (uint8_t i = 0; i < 39; ++i)
CC2500_WriteReg(i, pgm_read_byte_near(&RLINK_init_values[i]));
prev_option = option;
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
}
static void __attribute__((unused)) RLINK_tune_freq()
{
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
prev_option = option ;
}
}
static void __attribute__((unused)) RLINK_TIMING_RFSEND_packet()
{
static uint32_t pseudo=0;
uint32_t bits = 0;
uint8_t bitsavailable = 0;
uint8_t idx = 6;
CC2500_Strobe(CC2500_SIDLE);
// packet length
packet[0] = RLINK_TX_PACKET_LEN;
// header
if(sub_protocol)
packet[1] = 0x21; //air 0x21 on dump but it looks to support telemetry at least RSSI
else
{//surface
packet[1] = 0x01;
//radiolink additionnal ID which is working only on a small set of RXs
//if(RX_num) packet[1] |= ((RX_num+2)<<4)+4; // RX number limited to 10 values, 0 is a wildcard
}
if(packet_count>3)
packet[1] |= 0x02; // 0x02 telemetry request flag
// ID
memcpy(&packet[2],rx_tx_addr,RLINK_TX_ID_LEN);
// pack 16 channels on 11 bits values between 170 and 1876, 1023 middle. The last 8 channels are failsafe values associated to the first 8 values.
for (uint8_t i = 0; i < 16; i++)
{
uint32_t val = convert_channel_16b_nolimit(i,170,1876); // allow extended limits
if (val & 0x8000)
val = 0;
else if (val > 2047)
val=2047;
bits |= val << bitsavailable;
bitsavailable += 11;
while (bitsavailable >= 8) {
packet[idx++] = bits & 0xff;
bits >>= 8;
bitsavailable -= 8;
}
}
// hop
pseudo=((pseudo * 0xAA) + 0x03) % 0x7673; // calc next pseudo random value
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[pseudo & 0x0F]);
packet[28]= pseudo;
packet[29]= pseudo >> 8;
packet[30]= 0x00; // unknown
packet[31]= 0x00; // unknown
packet[32]= rf_ch_num; // index of value changed in the RF table
// check
uint8_t sum=0;
for(uint8_t i=1;i<33;i++)
sum+=packet[i];
packet[33]=sum;
// send packet
CC2500_WriteData(packet, RLINK_TX_PACKET_LEN+1);
// packets type
packet_count++;
if(packet_count>5) packet_count=0;
//debugln("C= 0x%02X",hopping_frequency[pseudo & 0x0F]);
//debug("P=");
//for(uint8_t i=1;i<RLINK_TX_PACKET_LEN+1;i++)
// debug(" 0x%02X",packet[i]);
//debugln("");
}
#define RLINK_TIMING_PROTO 20000-100 // -100 for compatibility with R8EF
#define RLINK_TIMING_RFSEND 10500
#define RLINK_TIMING_CHECK 2000
uint16_t RLINK_callback()
{
switch(phase)
{
case RLINK_DATA:
#ifdef MULTI_SYNC
telemetry_set_input_sync(RLINK_TIMING_PROTO);
#endif
RLINK_tune_freq();
RLINK_TIMING_RFSEND_packet();
#if not defined RLINK_HUB_TELEMETRY
return RLINK_TIMING_PROTO;
#else
if(!(packet[1]&0x02))
return RLINK_TIMING_PROTO; //Normal packet
//Telemetry packet
phase++; // RX1
return RLINK_TIMING_RFSEND;
case RLINK_RX1:
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SFRX);
CC2500_SetTxRxMode(RX_EN);
CC2500_Strobe(CC2500_SRX);
phase++; // RX2
return RLINK_TIMING_PROTO-RLINK_TIMING_RFSEND-RLINK_TIMING_CHECK;
case RLINK_RX2:
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
if (len == RLINK_RX_PACKET_LEN + 1 + 2) //Telemetry frame is 15 bytes + 1 byte for length + 2 bytes for RSSI&LQI&CRC
{
//debug("Telem:");
CC2500_ReadData(packet_in, len);
if(packet_in[0]==RLINK_RX_PACKET_LEN && (packet_in[len-1] & 0x80) && memcmp(&packet[2],rx_tx_addr,RLINK_TX_ID_LEN)==0 && packet_in[6]==packet[1])
{//Correct telemetry received: length, CRC, ID and type
//Debug
//for(uint8_t i=0;i<len;i++)
// debug(" %02X",packet_in[i]);
TX_RSSI = packet_in[len-2];
if(TX_RSSI >=128)
TX_RSSI -= 128;
else
TX_RSSI += 128;
RX_RSSI=packet_in[7]; //Should be packet_in[7]-256 but since it's an uint8_t...
v_lipo1=packet_in[8]<<1; //RX Batt
v_lipo2=packet_in[9]<<1; //Batt
telemetry_link=1; //Send telemetry out
pps_counter++;
packet_count=0;
}
//debugln("");
}
if (millis() - pps_timer >= 2000)
{//1 telemetry packet every 100ms
pps_timer = millis();
if(pps_counter<20)
pps_counter*=5;
else
pps_counter=100;
debugln("%d pps", pps_counter);
TX_LQI = pps_counter; //0..100%
pps_counter = 0;
}
CC2500_SetTxRxMode(TX_EN);
phase=RLINK_DATA; // DATA
return RLINK_TIMING_CHECK;
#endif
}
return 0;
}
uint16_t initRLINK()
{
BIND_DONE; // Not a TX bind protocol
RLINK_init();
RLINK_rf_init();
packet_count = 0;
phase = RLINK_DATA;
return 10000;
}
#endif

View File

@@ -17,10 +17,10 @@
#include "iface_cc2500.h"
#define REDPINE_LOOPTIME_FAST 25 //2.5ms
#define REDPINE_LOOPTIME_SLOW 6 //6ms
#define REDPINE_LOOPTIME_FAST 20 //2.0ms
#define REDPINE_LOOPTIME_SLOW 20 //20ms
#define REDPINE_BIND 1000
#define REDPINE_BIND 2000
#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
@@ -105,10 +105,9 @@ static uint16_t ReadREDPINE()
}
if(IS_BIND_IN_PROGRESS)
{
if(bind_counter == REDPINE_BIND)
REDPINE_init(0);
if(bind_counter == REDPINE_BIND/2)
REDPINE_init(1);
if (state == REDPINE_BIND) {
REDPINE_init(0);
}
REDPINE_set_channel(49);
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
@@ -121,7 +120,7 @@ static uint16_t ReadREDPINE()
BIND_DONE;
REDPINE_init(sub_protocol);
}
return 9000;
return 4000;
}
else
{
@@ -149,23 +148,19 @@ static const uint8_t REDPINE_init_data[][3] = {
{CC2500_07_PKTCTRL1, 0x04, 0x04},
{CC2500_08_PKTCTRL0, 0x05, 0x05},
{CC2500_09_ADDR, 0x00, 0x00},
{CC2500_0B_FSCTRL1, 0x0A, 0x0A},
{CC2500_0B_FSCTRL1, 0x0A, 0x06},
{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_0D_FREQ2, 0x5D, 0x5D},
{CC2500_0E_FREQ1, 0x93, 0x93},
{CC2500_0F_FREQ0, 0xB1, 0xB1},
{CC2500_10_MDMCFG4, 0x2D, 0x78},
{CC2500_11_MDMCFG3, 0x3B, 0x93},
{CC2500_12_MDMCFG2, 0x73, 0x03},
{CC2500_13_MDMCFG1, 0x23, 0x22},
{CC2500_14_MDMCFG0, 0x56, 0xF8}, // Chan space
{CC2500_15_DEVIATN, 0x00, 0x44},
{CC2500_17_MCSM1, 0x0c, 0x0c},
{CC2500_18_MCSM0, 0x08, 0x08}, //??? 0x18, 0x18},
{CC2500_18_MCSM0, 0x18, 0x18},
{CC2500_19_FOCCFG, 0x1D, 0x16},
{CC2500_1A_BSCFG, 0x1C, 0x6c},
{CC2500_1B_AGCCTRL2, 0xC7, 0x43},
@@ -181,7 +176,7 @@ static const uint8_t REDPINE_init_data[][3] = {
{CC2500_2C_TEST2, 0x88, 0x88},
{CC2500_2D_TEST1, 0x31, 0x31},
{CC2500_2E_TEST0, 0x0B, 0x0B},
{CC2500_3E_PATABLE, 0xff, 0xff}
{CC2500_3E_PATABLE, 0xff, 0xff}
};
static void REDPINE_init(uint8_t format)
@@ -190,8 +185,9 @@ static void REDPINE_init(uint8_t format)
CC2500_WriteReg(CC2500_06_PKTLEN, REDPINE_PACKET_SIZE);
for (uint8_t i=0; i < ((sizeof REDPINE_init_data) / (sizeof REDPINE_init_data[0])); i++)
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);
@@ -215,7 +211,6 @@ static uint16_t initREDPINE()
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;
@@ -226,8 +221,9 @@ static uint16_t initREDPINE()
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 ((ch <= next_ch + 1) && (ch >= next_ch - 1) && (ch >= 1)) {
break;
}
}
if (i != idx)
continue;

View File

@@ -16,7 +16,7 @@
#if defined(SLT_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_nrf250k.h"
//#define SLT_Q200_FORCE_ID
@@ -25,6 +25,7 @@
#define SLT_PAYLOADSIZE_V2 11
#define SLT_NFREQCHANNELS 15
#define SLT_TXID_SIZE 4
#define SLT_BIND_CHANNEL 0x50
enum{
// flags going to packet[6] (Q200)
@@ -48,30 +49,13 @@ enum {
SLT_DATA2,
SLT_DATA3,
SLT_BIND1,
SLT_BIND2
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);
NRF250K_Init();
NRF250K_SetTXAddr(rx_tx_addr, SLT_TXID_SIZE);
}
static void __attribute__((unused)) SLT_set_freq(void)
@@ -109,21 +93,25 @@ static void __attribute__((unused)) SLT_set_freq(void)
}
}
}
//Bind channel
hopping_frequency[SLT_NFREQCHANNELS]=SLT_BIND_CHANNEL;
//Calib all channels
NRF250K_HoppingCalib(SLT_NFREQCHANNELS+1);
}
static void __attribute__((unused)) SLT_wait_radio()
{
if (packet_sent)
while (!(NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS)));
while (!NRF250K_IsPacketSent());
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);
NRF250K_WritePayload(packet, len);
packet_sent = 1;
}
@@ -132,7 +120,8 @@ 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]);
NRF250K_SetFreqOffset(); // Set frequency offset
NRF250K_Hopping(hopping_frequency_no);
if (++hopping_frequency_no >= SLT_NFREQCHANNELS)
hopping_frequency_no = 0;
@@ -183,23 +172,16 @@ static void __attribute__((unused)) SLT_build_packet()
static void __attribute__((unused)) SLT_send_bind_packet()
{
SLT_wait_radio();
BIND_IN_PROGRESS; //Limit TX power to bind level
NRF24L01_SetPower();
NRF250K_Hopping(SLT_NFREQCHANNELS); //Bind channel
BIND_IN_PROGRESS; //Limit TX power to bind level
NRF250K_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);
NRF250K_SetTXAddr((uint8_t *)"\x7E\xB8\x63\xA9", SLT_TXID_SIZE);
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
@@ -217,6 +199,8 @@ uint16_t SLT_callback()
telemetry_set_input_sync(sub_protocol==SLT_V1?20000:13730);
#endif
SLT_build_packet();
NRF250K_SetPower(); //Change power level
NRF250K_SetTXAddr(rx_tx_addr, SLT_TXID_SIZE);
phase++;
return SLT_TIMING_BUILD;
case SLT_DATA1:
@@ -253,7 +237,6 @@ uint16_t SLT_callback()
}
else
{// Continue to send normal packets
NRF24L01_SetPower(); // Set tx_power
phase = SLT_BUILD;
if(sub_protocol==SLT_V1)
return 20000-SLT_TIMING_BUILD;
@@ -289,8 +272,8 @@ uint16_t initSLT()
/* 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();
SLT_set_freq();
phase = SLT_BUILD;
return 50000;
}

View File

@@ -0,0 +1,246 @@
#ifdef SX1276_INSTALLED
#include "iface_sx1276.h"
bool SX1276_Mode_LoRa=false;
void SX1276_WriteReg(uint8_t address, uint8_t data)
{
SPI_CSN_off;
SPI_Write(address | 0x80); // MSB 1 = write
NOP();
SPI_Write(data);
SPI_CSN_on;
}
uint8_t SX1276_ReadReg(uint8_t address)
{
SPI_CSN_off;
SPI_Write(address & 0x7F);
uint8_t result = SPI_Read();
SPI_CSN_on;
return result;
}
void SX1276_WriteRegisterMulti(uint8_t address, const uint8_t* data, uint8_t length)
{
SPI_CSN_off;
SPI_Write(address | 0x80); // MSB 1 = write
for(uint8_t i = 0; i < length; i++)
SPI_Write(data[i]);
SPI_CSN_on;
}
void SX1276_ReadRegisterMulti(uint8_t address, uint8_t* data, uint8_t length)
{
SPI_CSN_off;
SPI_Write(address & 0x7F);
for(uint8_t i = 0; i < length; i++)
data[i]=SPI_Read();
SPI_CSN_on;
}
uint8_t SX1276_Reset()
{
//TODO when pin is not wired
#ifdef SX1276_RST_pin
SX1276_RST_off;
delayMicroseconds(200);
SX1276_RST_on;
#endif
return 0;
}
bool SX1276_DetectChip() //to be called after reset, verfies the chip has been detected
{
#define SX1276_Detect_MaxAttempts 5
uint8_t i = 0;
bool chipFound = false;
while ((i < SX1276_Detect_MaxAttempts) && !chipFound)
{
uint8_t ChipVersion = SX1276_ReadReg(SX1276_42_VERSION);
if (ChipVersion == 0x12)
{
debugln("SX1276 reg version=%d", ChipVersion);
chipFound = true;
}
else
{
debug("SX1276 not found! attempts: %d", i);
debug(" of ");
debugln("%d SX1276 reg version=%d", SX1276_Detect_MaxAttempts, ChipVersion);
i++;
}
}
if (!chipFound)
{
debugln("SX1276 not detected!!!");
return false;
}
else
{
debugln("Found SX1276 Device!");
return true;
}
}
void SX1276_SetTxRxMode(uint8_t mode)
{
#ifdef SX1276_TXEN_pin
if(mode == TX_EN)
SX1276_TXEN_on;
else
SX1276_RXEN_on;
#endif
}
void SX1276_SetFrequency(uint32_t frequency)
{
uint32_t f = frequency / 61;
uint8_t data[3];
data[0] = f >> 16;
data[1] = f >> 8;
data[2] = f;
SX1276_WriteRegisterMulti(SX1276_06_FRFMSB, data, 3);
}
void SX1276_SetMode(bool lora, bool low_freq_mode, uint8_t mode)
{
uint8_t data = 0x00;
SX1276_Mode_LoRa=lora;
if(lora)
{
data = data | (1 << 7);
data = data & ~(1 << 6);
}
else
{
data = data & ~(1 << 7);
data = data | (1 << 6);
}
if(low_freq_mode)
data = data | (1 << 3);
data = data | mode;
SX1276_WriteReg(SX1276_01_OPMODE, data);
}
void SX1276_SetDetectOptimize(bool auto_if, uint8_t detect_optimize)
{
uint8_t data = SX1276_ReadReg(SX1276_31_DETECTOPTIMIZE);
data = (data & 0b01111000) | detect_optimize;
data = data | (auto_if << 7);
SX1276_WriteReg(SX1276_31_DETECTOPTIMIZE, data);
}
void SX1276_ConfigModem1(uint8_t bandwidth, uint8_t coding_rate, bool implicit_header_mode)
{
uint8_t data = 0x00;
data = data | (bandwidth << 4);
data = data | (coding_rate << 1);
data = data | implicit_header_mode;
SX1276_WriteReg(SX1276_1D_MODEMCONFIG1, data);
if (bandwidth == SX1276_MODEM_CONFIG1_BW_500KHZ) //datasheet errata reconmendation http://caxapa.ru/thumbs/972894/SX1276_77_8_ErrataNote_1.1_STD.pdf
{
SX1276_WriteReg(SX1276_36_LORA_REGHIGHBWOPTIMIZE1, 0x02);
SX1276_WriteReg(SX1276_3A_LORA_REGHIGHBWOPTIMIZE2, 0x64);
}
else
SX1276_WriteReg(SX1276_36_LORA_REGHIGHBWOPTIMIZE1, 0x03);
}
void SX1276_ConfigModem2(uint8_t spreading_factor, bool tx_continuous_mode, bool rx_payload_crc_on)
{
uint8_t data = SX1276_ReadReg(SX1276_1E_MODEMCONFIG2);
data = data & 0b11; // preserve the last 2 bits
data = data | (spreading_factor << 4);
data = data | (tx_continuous_mode << 3);
data = data | (rx_payload_crc_on << 2);
SX1276_WriteReg(SX1276_1E_MODEMCONFIG2, data);
}
void SX1276_ConfigModem3(bool low_data_rate_optimize, bool agc_auto_on)
{
uint8_t data = SX1276_ReadReg(SX1276_26_MODEMCONFIG3);
data = data & 0b11; // preserve the last 2 bits
data = data | (low_data_rate_optimize << 3);
data = data | (agc_auto_on << 2);
SX1276_WriteReg(SX1276_26_MODEMCONFIG3, data);
}
void SX1276_SetPreambleLength(uint16_t length)
{
uint8_t data[2];
data[0] = (length >> 8) & 0xFF; // high byte
data[1] = length & 0xFF; // low byte
SX1276_WriteRegisterMulti(SX1276_20_PREAMBLEMSB, data, 2);
}
void SX1276_SetDetectionThreshold(uint8_t threshold)
{
SX1276_WriteReg(SX1276_37_DETECTIONTHRESHOLD, threshold);
}
void SX1276_SetLna(uint8_t gain, bool high_freq_lna_boost)
{
uint8_t data = SX1276_ReadReg(SX1276_0C_LNA);
data = data & 0b100; // preserve the third bit
data = data | (gain << 5);
if(high_freq_lna_boost)
data = data | 0b11;
SX1276_WriteReg(SX1276_0C_LNA, data);
}
void SX1276_SetHopPeriod(uint8_t freq_hop_period)
{
SX1276_WriteReg(SX1276_24_HOPPERIOD, freq_hop_period);
}
void SX1276_SetPaDac(bool on)
{
uint8_t data = SX1276_ReadReg(SX1276_4D_PADAC);
data = data & 0b11111000; // preserve the upper 5 bits
if(on)
data = data | 0x07;
else
data = data | 0x04;
SX1276_WriteReg(SX1276_4D_PADAC, data);
}
void SX1276_SetPaConfig(bool pa_boost_pin, uint8_t max_power, uint8_t output_power)
{
uint8_t data = 0x00;
data = data | (pa_boost_pin << 7);
data = data | (max_power << 4);
data = data | output_power;
SX1276_WriteReg(SX1276_09_PACONFIG, data);
}
void SX1276_WritePayloadToFifo(uint8_t* payload, uint8_t length)
{
SX1276_WriteReg(SX1276_22_PAYLOAD_LENGTH, length);
SX1276_WriteReg(SX1276_0E_FIFOTXBASEADDR, 0x00);
SX1276_WriteReg(SX1276_0D_FIFOADDRPTR, 0x00);
SX1276_WriteRegisterMulti(SX1276_00_FIFO, payload, length);
}
#endif

View File

@@ -0,0 +1,179 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(SKYARTEC_CC2500_INO)
#include "iface_cc2500.h"
//#define SKYARTEC_FORCE_ID
#define SKYARTEC_COARSE 0x00
#define SKYARTEC_TX_ADDR rx_tx_addr[1]
#define SKYARTEC_TX_CHANNEL rx_tx_addr[0]
enum {
SKYARTEC_PKT1 = 0,
SKYARTEC_SLEEP1,
SKYARTEC_PKT2,
SKYARTEC_SLEEP2,
SKYARTEC_PKT3,
SKYARTEC_SLEEP3,
SKYARTEC_PKT4,
SKYARTEC_SLEEP4,
SKYARTEC_PKT5,
SKYARTEC_SLEEP5,
SKYARTEC_PKT6,
SKYARTEC_LAST,
};
const PROGMEM uint8_t SKYARTEC_init_values[] = {
/* 04 */ 0x13, 0x18, 0xFF, 0x05,
/* 08 */ 0x05, 0x43, 0xCD, 0x09, 0x00, 0x5D, 0x93, 0xB1 + SKYARTEC_COARSE,
/* 10 */ 0x2D, 0x20, 0x73, 0x22, 0xF8, 0x50, 0x07, 0x30,
/* 18 */ 0x18, 0x1D, 0x1C, 0xC7, 0x00, 0xB2, 0x87, 0x6B,
/* 20 */ 0xF8, 0xB6, 0x10, 0xEA, 0x0A, 0x00, 0x11, 0x41,
/* 28 */ 0x00, 0x59, 0x7F, 0x3F, 0x88, 0x31, 0x0B
};
static void __attribute__((unused)) SKYARTEC_rf_init()
{
CC2500_Strobe(CC2500_SIDLE);
for (uint8_t i = 4; i <= 0x2E; ++i)
CC2500_WriteReg(i, pgm_read_byte_near(&SKYARTEC_init_values[i-4]));
prev_option = option;
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
CC2500_Strobe(CC2500_SFTX);
CC2500_Strobe(CC2500_SFRX);
CC2500_Strobe(CC2500_SXOFF);
CC2500_Strobe(CC2500_SIDLE);
}
static void __attribute__((unused)) SKYARTEC_send_data_packet()
{
//13 c5 01 0259 0168 0000 0259 030c 021a 0489 f3 7e 0a
//header
packet[0] = 0x13; //Length
packet[1] = SKYARTEC_TX_ADDR; //Tx Addr?
packet[2] = 0x01; //???
//channels
for(uint8_t i = 0; i < 7; i++)
{
uint16_t value = convert_channel_16b_limit(CH_AETR[i],0x000,0x500);
packet[3+2*i] = value >> 8;
packet[4+2*i] = value & 0xff;
}
//checks
uint8_t xor1 = 0;
for(uint8_t i = 3; i <= 14; i++)
xor1 ^= packet[i];
packet[18] = xor1;
xor1 ^= packet[15];
xor1 ^= packet[16];
packet[17] = xor1;
packet[19] = packet[3] + packet[5] + packet[7] + packet[9] + packet[11] + packet[13];
CC2500_WriteReg(CC2500_04_SYNC1, rx_tx_addr[3]);
CC2500_WriteReg(CC2500_05_SYNC0, rx_tx_addr[2]);
CC2500_WriteReg(CC2500_09_ADDR, SKYARTEC_TX_ADDR);
CC2500_WriteReg(CC2500_0A_CHANNR, SKYARTEC_TX_CHANNEL);
CC2500_WriteData(packet, 20);
}
static void __attribute__((unused)) SKYARTEC_send_bind_packet()
{
//0b 7d 01 01 b2 c5 4a 2f 00 00 c5 d6
packet[0] = 0x0b; //Length
packet[1] = 0x7d;
packet[2] = 0x01;
packet[3] = 0x01;
packet[4] = rx_tx_addr[0];
packet[5] = rx_tx_addr[1];
packet[6] = rx_tx_addr[2];
packet[7] = rx_tx_addr[3];
packet[8] = 0x00;
packet[9] = 0x00;
packet[10] = SKYARTEC_TX_ADDR;
uint8_t xor1 = 0;
for(uint8_t i = 3; i < 11; i++)
xor1 ^= packet[i];
packet[11] = xor1;
CC2500_WriteReg(CC2500_04_SYNC1, 0x7d);
CC2500_WriteReg(CC2500_05_SYNC0, 0x7d);
CC2500_WriteReg(CC2500_09_ADDR, 0x7d);
CC2500_WriteReg(CC2500_0A_CHANNR, 0x7d);
CC2500_WriteData(packet, 12);
}
uint16_t ReadSKYARTEC()
{
if (phase & 0x01)
{
CC2500_Strobe(CC2500_SIDLE);
if (phase == SKYARTEC_LAST)
{
CC2500_SetPower();
// Tune frequency if it has been changed
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
prev_option = option ;
}
phase = SKYARTEC_PKT1;
}
else
phase++;
return 3000;
}
if (phase == SKYARTEC_PKT1 && bind_counter)
{
SKYARTEC_send_bind_packet();
bind_counter--;
if(bind_counter == 0)
BIND_DONE;
}
else
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(6000);
#endif
SKYARTEC_send_data_packet();
}
phase++;
return 3000;
}
uint16_t initSKYARTEC()
{
SKYARTEC_rf_init();
#ifdef SKYARTEC_FORCE_ID
memset(rx_tx_addr,0x00,4);
#endif
if(rx_tx_addr[0]==0) rx_tx_addr[0]=0xB2;
if(rx_tx_addr[1]==0) rx_tx_addr[1]=0xC5;
if(rx_tx_addr[2]==0) rx_tx_addr[2]=0x4A;
if(rx_tx_addr[3]==0) rx_tx_addr[3]=0x2F;
bind_counter = 250;
phase = SKYARTEC_PKT1;
return 10000;
}
#endif

View File

@@ -0,0 +1,63 @@
/*
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(TEST_CC2500_INO)
#include "iface_nrf250k.h"
#define TEST_INITIAL_WAIT 500
#define TEST_PACKET_PERIOD 10000
#define TEST_PAYLOAD_SIZE 10
#define TEST_RF_NUM_CHANNELS 3
uint16_t TEST_callback()
{
option=1;
if(phase)
XN297L_WritePayload(packet, TEST_PAYLOAD_SIZE);
else
{
if(Channel_data[CH5]<CHANNEL_MIN_COMMAND)
hopping_frequency_no=0;
else if(Channel_data[CH5]>CHANNEL_MAX_COMMAND)
hopping_frequency_no=2;
else
hopping_frequency_no=1;
XN297L_Hopping(hopping_frequency_no);
CC2500_WriteReg(CC2500_3E_PATABLE,convert_channel_8b(CH6));
debugln("CH:%d, PWR:%d",hopping_frequency_no,convert_channel_8b(CH6));
}
phase ^= 1;
return TEST_PACKET_PERIOD>>1;
}
uint16_t initTEST()
{
option=1;
hopping_frequency[0]=0;
hopping_frequency[1]=40;
hopping_frequency[2]=80;
XN297L_Init();
XN297L_HoppingCalib(TEST_RF_NUM_CHANNELS); // Calibrate all channels
XN297L_SetTXAddr((uint8_t*)"RADIO", 5);
hopping_frequency_no = 0;
phase=0;
for(uint8_t i=0; i<TEST_PAYLOAD_SIZE; i++)
packet[i]= i;
return TEST_INITIAL_WAIT;
}
#endif

View File

@@ -33,7 +33,6 @@ uint8_t RetrySequence ;
#if defined SPORT_TELEMETRY
#define FRSKY_SPORT_PACKET_SIZE 8
#define FX_BUFFERS 4
uint8_t RxBt = 0;
uint8_t Sport_Data = 0;
uint8_t pktx1[FRSKY_SPORT_PACKET_SIZE*FX_BUFFERS];
@@ -120,12 +119,15 @@ static void telemetry_set_input_sync(uint16_t refreshRate)
static void multi_send_status()
{
#ifdef MULTI_NAMES
if(multi_protocols_index != 0xFF)
multi_send_header(MULTI_TELEMETRY_STATUS, 24);
else
#ifdef MULTI_TELEMETRY
#ifdef MULTI_NAMES
multi_send_header(MULTI_TELEMETRY_STATUS, 24);
#else
multi_send_header(MULTI_TELEMETRY_STATUS, 5);
#endif
#else
multi_send_header(MULTI_TELEMETRY_STATUS, 5);
#endif
multi_send_header(MULTI_TELEMETRY_STATUS, 6);
// Build flags
uint8_t flags=0;
@@ -137,12 +139,21 @@ static void multi_send_status()
{
flags |= 0x04;
#ifdef MULTI_NAMES
if((sub_protocol&0x07) && multi_protocols_index != 0xFF)
if(multi_protocols_index == 0xFF)
{
uint8_t nbr=multi_protocols[multi_protocols_index].nbrSubProto;
if((sub_protocol&0x07)>=nbr)
flags &= ~0x04; //Invalid sub protocol
if(protocol!=PROTO_SCANNER)
flags &= ~0x04; //Invalid protocol
}
else if(sub_protocol&0x07)
{
uint8_t nbr=multi_protocols[multi_protocols_index].nbrSubProto;
//if(protocol==PROTO_DSM) nbr++; //Auto sub_protocol
if((sub_protocol&0x07)>=nbr)
flags &= ~0x04; //Invalid sub protocol
}
#else
if(remote_callback==0)
flags &= ~0x04; //Invalid protocol
#endif
if (IS_WAIT_BIND_on)
flags |= 0x10;
@@ -159,28 +170,37 @@ static void multi_send_status()
flags |= 0x80;
}
Serial_write(flags);
// Version number example: 1.1.6.1
Serial_write(VERSION_MAJOR);
Serial_write(VERSION_MINOR);
Serial_write(VERSION_REVISION);
Serial_write(VERSION_PATCH_LEVEL);
// Channel order
Serial_write(RUDDER<<6|THROTTLE<<4|ELEVATOR<<2|AILERON);
#ifdef MULTI_TELEMETRY
// Channel order
Serial_write(RUDDER<<6|THROTTLE<<4|ELEVATOR<<2|AILERON);
#endif
#ifdef MULTI_NAMES
if(multi_protocols_index != 0xFF)
if(multi_protocols_index == 0xFF) // selection out of list... send first available protocol
{
Serial_write(multi_protocols[0].protocol); // begining of list
Serial_write(multi_protocols[0].protocol); // begining of list
for(uint8_t i=0;i<16;i++)
Serial_write(0x00); // everything else is invalid
}
else
{
// Protocol next/prev
if(multi_protocols[multi_protocols_index+1].protocol != 0)
Serial_write(multi_protocols[multi_protocols_index+1].protocol); // next protocol number
else
Serial_write(protocol); // end of list
Serial_write(multi_protocols[multi_protocols_index].protocol); // end of list
if(multi_protocols_index>0)
Serial_write(multi_protocols[multi_protocols_index-1].protocol); // prev protocol number
else
Serial_write(protocol); // begining of list
Serial_write(multi_protocols[multi_protocols_index].protocol); // begining of list
// Protocol
for(uint8_t i=0;i<7;i++)
Serial_write(multi_protocols[multi_protocols_index].ProtoString[i]); // protocol name
@@ -197,9 +217,9 @@ static void multi_send_status()
}
for(;j<8;j++)
Serial_write(0x00);
// Channels function
//TODO
}
// Channels function
//TODO
#endif
}
#endif
@@ -246,7 +266,7 @@ static void multi_send_status()
}
#endif
#if defined (FRSKY_RX_TELEMETRY) || defined (AFHDS2A_RX_TELEMETRY) || defined (BAYANG_RX_TELEMETRY)
#if defined (FRSKY_RX_TELEMETRY) || defined (AFHDS2A_RX_TELEMETRY) || defined (BAYANG_RX_TELEMETRY) || defined (DSM_RX_CYRF6936_INO)
void receiver_channels_frame()
{
uint16_t len = packet_in[3] * 11; // 11 bit per channel
@@ -327,26 +347,28 @@ void frskySendStuffed()
Serial_write(START_STOP);
}
void frsky_check_telemetry(uint8_t *packet_in,uint8_t len)
bool frsky_process_telemetry(uint8_t *buffer,uint8_t len)
{
if(packet_in[1] != rx_tx_addr[3] || packet_in[2] != rx_tx_addr[2] || len != packet_in[0] + 3 )
return; // Bad address or length...
if(protocol!=PROTO_FRSKY_R9)
{
if(buffer[1] != rx_tx_addr[3] || buffer[2] != rx_tx_addr[2] || len != buffer[0] + 3 )
return false; // Bad address or length...
// RSSI and LQI are the 2 last bytes
TX_RSSI = buffer[len-2];
if(TX_RSSI >=128)
TX_RSSI -= 128;
else
TX_RSSI += 128;
}
telemetry_link|=1; // Telemetry data is available
// RSSI and LQI are the 2 last bytes
TX_RSSI = packet_in[len-2];
if(TX_RSSI >=128)
TX_RSSI -= 128;
else
TX_RSSI += 128;
TX_LQI = packet_in[len-1]&0x7F;
#if defined FRSKYD_CC2500_INO
if (protocol==PROTO_FRSKYD)
{
TX_LQI = buffer[len-1]&0x7F;
//Save current buffer
for (uint8_t i=3;i<len-2;i++)
telemetry_in_buffer[i]=packet_in[i]; // Buffer telemetry values to be sent
telemetry_in_buffer[i]=buffer[i]; // Buffer telemetry values to be sent
//Check incoming telemetry sequence
if(telemetry_in_buffer[6]>0 && telemetry_in_buffer[6]<=10)
@@ -371,8 +393,8 @@ void frsky_check_telemetry(uint8_t *packet_in,uint8_t len)
}
#endif
#if defined SPORT_TELEMETRY && defined FRSKYX_CC2500_INO
if (protocol==PROTO_FRSKYX)
#if defined SPORT_TELEMETRY && (defined FRSKYX_CC2500_INO || defined FRSKYR9_SX1276_INO)
if (protocol==PROTO_FRSKYX||protocol==PROTO_FRSKYX2)
{
/*Telemetry frames(RF) SPORT info
15 bytes payload
@@ -392,29 +414,30 @@ void frsky_check_telemetry(uint8_t *packet_in,uint8_t len)
[12] STRM6 D1 D1 D0 D0
[13] CHKSUM1 --|2 CRC bytes sent by RX (calculated on RX side crc16/table)
[14] CHKSUM2 --|*/
telemetry_lost=0;
uint16_t lcrc = FrSkyX_crc(&packet_in[3], len-7 ) ;
if ( ( (lcrc >> 8) != packet_in[len-4]) || ( (lcrc & 0x00FF ) != packet_in[len-3]) )
return; // Bad CRC
//len=17 -> len-7=10 -> 3..12
uint16_t lcrc = FrSkyX_crc(&buffer[3], len-7 ) ;
if ( ( (lcrc >> 8) != buffer[len-4]) || ( (lcrc & 0x00FF ) != buffer[len-3]) )
return false; // Bad CRC
if(packet_in[4] & 0x80)
RX_RSSI=packet_in[4] & 0x7F ;
if(buffer[4] & 0x80)
RX_RSSI=buffer[4] & 0x7F ;
else
RxBt = (packet_in[4]<<1) + 1 ;
v_lipo1 = (buffer[4]<<1) + 1 ;
#if defined(TELEMETRY_FRSKYX_TO_FRSKYD) && defined(ENABLE_PPM)
if(mode_select != MODE_SERIAL)
{//PPM
v_lipo1=RxBt;
return;
}
return true;
#endif
}
if (protocol==PROTO_FRSKYX||protocol==PROTO_FRSKYX2||protocol==PROTO_FRSKY_R9)
{
telemetry_lost=0;
//Save outgoing telemetry sequence
FrSkyX_TX_IN_Seq=packet_in[5] >> 4;
FrSkyX_TX_IN_Seq=buffer[5] >> 4;
//Check incoming telemetry sequence
uint8_t packet_seq=packet_in[5] & 0x03;
if ( packet_in[5] & 0x08 )
uint8_t packet_seq=buffer[5] & 0x03;
if ( buffer[5] & 0x08 )
{//Request init
FrSkyX_RX_Seq = 0x08 ;
FrSkyX_RX_NextFrame = 0x00 ;
@@ -427,20 +450,20 @@ void frsky_check_telemetry(uint8_t *packet_in,uint8_t len)
{//In sequence
struct t_FrSkyX_RX_Frame *p ;
uint8_t count ;
// packet_in[4] RSSI
// packet_in[5] sequence control
// packet_in[6] payload count
// packet_in[7-12] payload
// buffer[4] RSSI
// buffer[5] sequence control
// buffer[6] payload count
// buffer[7-12] payload
p = &FrSkyX_RX_Frames[packet_seq] ;
count = packet_in[6]; // Payload length
count = buffer[6]; // Payload length
if ( count <= 6 )
{//Store payload
p->count = count ;
for ( uint8_t i = 0 ; i < count ; i++ )
p->payload[i] = packet_in[i+7] ;
p->payload[i] = buffer[i+7] ;
}
else
p->count = 0 ; // Discard
p->count = 0 ; // Discard
p->valid = true ;
FrSkyX_RX_Seq = ( FrSkyX_RX_Seq + 1 ) & 0x03 ; // Move to next sequence
@@ -456,19 +479,19 @@ void frsky_check_telemetry(uint8_t *packet_in,uint8_t len)
{//Not in sequence
struct t_FrSkyX_RX_Frame *q ;
uint8_t count ;
// packet_in[4] RSSI
// packet_in[5] sequence control
// packet_in[6] payload count
// packet_in[7-12] payload
// buffer[4] RSSI
// buffer[5] sequence control
// buffer[6] payload count
// buffer[7-12] payload
if ( packet_seq == ( ( FrSkyX_RX_Seq +1 ) & 3 ) )
{//Received next sequence -> save it
q = &FrSkyX_RX_Frames[packet_seq] ;
count = packet_in[6]; // Payload length
count = buffer[6]; // Payload length
if ( count <= 6 )
{//Store payload
q->count = count ;
for ( uint8_t i = 0 ; i < count ; i++ )
q->payload[i] = packet_in[i+7] ;
q->payload[i] = buffer[i+7] ;
}
else
q->count = 0 ;
@@ -480,6 +503,7 @@ void frsky_check_telemetry(uint8_t *packet_in,uint8_t len)
}
}
#endif
return true;
}
void init_frskyd_link_telemetry()
@@ -507,7 +531,7 @@ void frsky_link_frame()
telemetry_link |= 2 ; // Send hub if available
}
else
{//PROTO_HUBSAN, PROTO_AFHDS2A, PROTO_BAYANG, PROTO_NCC1701, PROTO_CABELL, PROTO_HITEC, PROTO_BUGS, PROTO_BUGSMINI, PROTO_FRSKYX
{//PROTO_HUBSAN, PROTO_AFHDS2A, PROTO_BAYANG, PROTO_NCC1701, PROTO_CABELL, PROTO_HITEC, PROTO_BUGS, PROTO_BUGSMINI, PROTO_FRSKYX, PROTO_FRSKYX2, PROTO_PROPEL, PROTO_DEVO, PROTO_RLINK
frame[1] = v_lipo1;
frame[2] = v_lipo2;
frame[3] = RX_RSSI;
@@ -704,7 +728,7 @@ void sportSendFrame()
case 0:
frame[2] = 0x05;
frame[3] = 0xf1;
frame[4] = 0x02 ;//dummy values if swr 20230f00
frame[4] = 0x02; //dummy values if swr 20230f00
frame[5] = 0x23;
frame[6] = 0x0F;
break;
@@ -719,7 +743,7 @@ void sportSendFrame()
case 4: //BATT
frame[2] = 0x04;
frame[3] = 0xf1;
frame[4] = RxBt;//a1;
frame[4] = v_lipo1; //a1;
break;
default:
if(Sport_Data)
@@ -849,7 +873,7 @@ void TelemetryUpdate()
#endif
#endif
#if defined SPORT_TELEMETRY
if (protocol==PROTO_FRSKYX && telemetry_link
if ((protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYX2||protocol==PROTO_FRSKY_R9) && telemetry_link
#ifdef TELEMETRY_FRSKYX_TO_FRSKYD
&& mode_select==MODE_SERIAL
#endif
@@ -918,8 +942,8 @@ void TelemetryUpdate()
}
#endif
#if defined (FRSKY_RX_TELEMETRY) || defined(AFHDS2A_RX_TELEMETRY) || defined (BAYANG_RX_TELEMETRY)
if ((telemetry_link & 1) && (protocol == PROTO_FRSKY_RX || protocol == PROTO_AFHDS2A_RX || protocol == PROTO_BAYANG_RX))
#if defined (FRSKY_RX_TELEMETRY) || defined(AFHDS2A_RX_TELEMETRY) || defined (BAYANG_RX_TELEMETRY) || defined (DSM_RX_CYRF6936_INO)
if ((telemetry_link & 1) && (protocol == PROTO_FRSKY_RX || protocol == PROTO_AFHDS2A_RX || protocol == PROTO_BAYANG_RX || protocol == PROTO_DSM_RX) )
{
receiver_channels_frame();
telemetry_link &= ~1;
@@ -928,7 +952,7 @@ void TelemetryUpdate()
#endif
if( telemetry_link & 1 )
{ // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs + BugsMini + NCC1701
{ // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs + BugsMini + NCC1701 + PROPEL + RLINK
// FrSkyX telemetry if in PPM
frsky_link_frame();
return;

View 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
*/

View File

@@ -19,7 +19,7 @@
#include "iface_nrf24l01.h"
#define V2X2_MR101_FORCE_ID
#define V2X2_BIND_COUNT 1000
// Timeout for callback in uSec, 4ms=4000us for V202
@@ -51,14 +51,6 @@ enum {
//
enum {
V202_INIT2 = 0,
V202_INIT2_NO_BIND,//1
V202_BIND1,//2
V202_BIND2,//3
V202_DATA//4
};
// 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.
@@ -87,39 +79,29 @@ static void __attribute__((unused)) v202_init()
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
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0xFF); // 4ms retransmit t/o, 15 tries
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x08); // Channel 8
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
// NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0xFF); // 4ms retransmit t/o, 15 tries
// NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x08); // Channel 8
NRF24L01_SetBitrate(sub_protocol==V2X2_MR101?NRF24L01_BR_250K:NRF24L01_BR_1M);
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
// NRF24L01_WriteReg(NRF24L01_08_OBSERVE_TX, 0x00); // no write bits in this field
// NRF24L01_WriteReg(NRF24L01_00_CD, 0x00); // same
NRF24L01_WriteReg(NRF24L01_0C_RX_ADDR_P2, 0xC3); // LSB byte of pipe 2 receive address
NRF24L01_WriteReg(NRF24L01_0D_RX_ADDR_P3, 0xC4);
NRF24L01_WriteReg(NRF24L01_0E_RX_ADDR_P4, 0xC5);
NRF24L01_WriteReg(NRF24L01_0F_RX_ADDR_P5, 0xC6);
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, V2X2_PAYLOADSIZE); // bytes of data payload for pipe 1
NRF24L01_WriteReg(NRF24L01_12_RX_PW_P1, V2X2_PAYLOADSIZE);
NRF24L01_WriteReg(NRF24L01_13_RX_PW_P2, V2X2_PAYLOADSIZE);
NRF24L01_WriteReg(NRF24L01_14_RX_PW_P3, V2X2_PAYLOADSIZE);
NRF24L01_WriteReg(NRF24L01_15_RX_PW_P4, V2X2_PAYLOADSIZE);
NRF24L01_WriteReg(NRF24L01_16_RX_PW_P5, V2X2_PAYLOADSIZE);
NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
// NRF24L01_WriteReg(NRF24L01_0C_RX_ADDR_P2, 0xC3); // LSB byte of pipe 2 receive address
// NRF24L01_WriteReg(NRF24L01_0D_RX_ADDR_P3, 0xC4);
// NRF24L01_WriteReg(NRF24L01_0E_RX_ADDR_P4, 0xC5);
// NRF24L01_WriteReg(NRF24L01_0F_RX_ADDR_P5, 0xC6);
// NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, V2X2_PAYLOADSIZE); // bytes of data payload for pipe 1
// NRF24L01_WriteReg(NRF24L01_12_RX_PW_P1, V2X2_PAYLOADSIZE);
// NRF24L01_WriteReg(NRF24L01_13_RX_PW_P2, V2X2_PAYLOADSIZE);
// NRF24L01_WriteReg(NRF24L01_14_RX_PW_P3, V2X2_PAYLOADSIZE);
// NRF24L01_WriteReg(NRF24L01_15_RX_PW_P4, V2X2_PAYLOADSIZE);
// NRF24L01_WriteReg(NRF24L01_16_RX_PW_P5, V2X2_PAYLOADSIZE);
// NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x66\x88\x68\x68\x68", 5);
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, (uint8_t *)"\x88\x66\x86\x86\x86", 5);
// NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, (uint8_t *)"\x88\x66\x86\x86\x86", 5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x66\x88\x68\x68\x68", 5);
}
static void __attribute__((unused)) V202_init2()
{
NRF24L01_FlushTx();
packet_sent = 0;
hopping_frequency_no = 0;
// 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));
}
static void __attribute__((unused)) V2X2_set_tx_id(void)
@@ -135,20 +117,27 @@ static void __attribute__((unused)) V2X2_set_tx_id(void)
// Strange avoidance of channels divisible by 16
hopping_frequency[i] = (val & 0x0f) ? val : val - 3;
}
#ifdef V2X2_MR101_FORCE_ID
if(sub_protocol==V2X2_MR101)
{
rx_tx_addr[1]=0x83;
rx_tx_addr[2]=0x03;
rx_tx_addr[3]=0xAE;
memcpy(hopping_frequency,"\x05\x12\x08\x0C\x04\x0E\x10",7);
}
#endif
}
static void __attribute__((unused)) V2X2_add_pkt_checksum()
static void __attribute__((unused)) V2X2_send_packet()
{
uint8_t sum = 0;
for (uint8_t i = 0; i < 15; ++i)
sum += packet[i];
packet[15] = sum;
}
uint8_t rf_ch = hopping_frequency[hopping_frequency_no >> 1];
hopping_frequency_no = (hopping_frequency_no + 1) & 0x1F;
if(sub_protocol==V2X2_MR101 && hopping_frequency_no>13)
hopping_frequency_no=0;
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
static void __attribute__((unused)) V2X2_send_packet(uint8_t bind)
{
uint8_t flags2=0;
if (bind)
if (IS_BIND_IN_PROGRESS)
{
flags = V2X2_FLAG_BIND;
packet[0] = 0;
@@ -174,31 +163,35 @@ static void __attribute__((unused)) V2X2_send_packet(uint8_t bind)
flags=0;
// Channel 5
if (CH5_SW) flags = V2X2_FLAG_FLIP;
// Channel 6
if (CH6_SW) flags |= V2X2_FLAG_LIGHT;
// Channel 7
if (CH7_SW) flags |= V2X2_FLAG_CAMERA;
// Channel 8
if (CH8_SW) flags |= V2X2_FLAG_VIDEO;
//Flags2
// Channel 9
if (CH9_SW)
flags2 = V2X2_FLAG_HEADLESS;
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;
if(sub_protocol!=V2X2_MR101)
{//V2X2 & JXD506
// Channel 6
if (CH6_SW) flags |= V2X2_FLAG_LIGHT;
// Channel 7
if (CH7_SW) flags |= V2X2_FLAG_CAMERA;
// Channel 8
if (CH8_SW) flags |= V2X2_FLAG_VIDEO;
//Flags2
// Channel 9
if (CH9_SW)
flags2 = V2X2_FLAG_HEADLESS;
if(sub_protocol==JXD506)
{
// Channel 11
if (CH11_SW)
flags2 |= V2X2_FLAG_EMERGENCY;
}
else
{//V2X2
// Channel 10
if (CH10_SW)
flags2 |= V2X2_FLAG_MAG_CAL_X;
// Channel 11
if (CH11_SW)
flags2 |= V2X2_FLAG_MAG_CAL_Y;
}
}
}
// TX id
@@ -223,16 +216,26 @@ static void __attribute__((unused)) V2X2_send_packet(uint8_t bind)
packet[12] = 0x40;
packet[13] = 0x40;
}
else if(sub_protocol==V2X2_MR101)
{
if (CH10_SW) packet[11] = 0x04; // Motors start/stop
if (CH11_SW) packet[11] |= 0x40; // Auto Land=-100% Takeoff=+100%
if (CH7_SW) flags |= 0x02; // Picture
if (CH8_SW) flags |= 0x01; // Video
if(IS_BIND_IN_PROGRESS)
flags = 0x80;
flags |= (hopping_frequency_no & 0x01)<<6;
}
packet[14] = flags;
V2X2_add_pkt_checksum();
uint8_t sum = packet[0];
for (uint8_t i = 1; i < 15; ++i)
sum += packet[i];
packet[15] = sum;
packet_sent = 0;
uint8_t rf_ch = hopping_frequency[hopping_frequency_no >> 1];
hopping_frequency_no = (hopping_frequency_no + 1) & 0x1F;
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
NRF24L01_FlushTx();
NRF24L01_WritePayload(packet, V2X2_PAYLOADSIZE);
packet_sent = 1;
//packet_sent = 1;
if (! hopping_frequency_no)
NRF24L01_SetPower();
@@ -240,35 +243,26 @@ static void __attribute__((unused)) V2X2_send_packet(uint8_t bind)
uint16_t ReadV2x2()
{
switch (phase) {
case V202_INIT2:
V202_init2();
phase = V202_BIND2;
return 150;
break;
case V202_INIT2_NO_BIND:
V202_init2();
phase = V202_DATA;
return 150;
break;
case V202_BIND2:
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
return V2X2_PACKET_CHKTIME;
V2X2_send_packet(1);
if (--bind_counter == 0)
//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();
if(IS_BIND_IN_PROGRESS)
{
if (--bind_counter == 0)
{
BIND_DONE;
if(sub_protocol==V2X2_MR101)
{
phase = V202_DATA;
BIND_DONE;
#ifdef V2X2_MR101_FORCE_ID
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\xC9\x59\xD2\x65\x34", 5);
memcpy(hopping_frequency,"\x03\x05\x15\x0D\x06\x14\x0B",7);
#endif
}
break;
case V202_DATA:
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;
hopping_frequency_no = 0;
}
}
// Packet every 4ms
return V2X2_PACKET_PERIOD;
@@ -276,15 +270,13 @@ uint16_t ReadV2x2()
uint16_t initV2x2()
{
if(sub_protocol==V2X2_MR101)
BIND_IN_PROGRESS;
//packet_sent = 0;
hopping_frequency_no = 0;
bind_counter = V2X2_BIND_COUNT;
v202_init();
//
if (IS_BIND_IN_PROGRESS)
{
bind_counter = V2X2_BIND_COUNT;
phase = V202_INIT2;
}
else
phase = V202_INIT2_NO_BIND;
V2X2_set_tx_id();
return 50000;
}

View File

@@ -53,6 +53,8 @@ static void __attribute__((unused)) V761_set_checksum()
static void __attribute__((unused)) V761_send_packet()
{
static bool calib=false, prev_ch6=false;
if(phase != V761_DATA)
{
packet[0] = rx_tx_addr[0];
@@ -66,23 +68,44 @@ static void __attribute__((unused)) V761_send_packet()
}
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;
packet[0] = convert_channel_8b(THROTTLE); // Throttle
packet[2] = convert_channel_8b(ELEVATOR)>>1; // Elevator
// Channel 5 - Gyro mode is packet 5
if(CH5_SW) // Mode Expert Gyro off
if(sub_protocol==V761_3CH)
{
packet[1] = convert_channel_8b(RUDDER)>>1; // Rudder
packet[3] = convert_channel_8b(AILERON)>>1; // Aileron
}
else
{
packet[1] = convert_channel_8b(AILERON)>>1; // Aileron
packet[3] = convert_channel_8b(RUDDER)>>1; // Rudder
}
packet[5] = (packet_count++ / 3)<<6;
packet[4] = (packet[5] == 0x40) ? 0x1a : 0x20; // ?
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)
flags = 0x08; // Beginer mode (Gyro on, yaw and pitch rate limited)
else
flags = 0x0a; // Mid Mode ( Gyro on no rate limits)
flags = 0x0a; // Mid Mode ( Gyro on no rate limits)
if(!prev_ch6 && CH6_SW) // -100% -> 100% launch gyro calib
calib=!calib;
prev_ch6 = CH6_SW;
if(calib)
flags |= 0x01; // Gyro calibration
packet[5] |= flags;
packet[6] = 0x80; // unknown
packet[6] = GET_FLAG(CH7_SW, 0x20) // Flip
|GET_FLAG(CH8_SW, 0x08) // RTH activation
|GET_FLAG(CH9_SW, 0x10); // RTH on/off
if(sub_protocol==V761_3CH)
packet[6] |= 0x80; // unknown, set on original V761-1 dump but not on eachine dumps, keeping for compatibility
//packet counter
if(packet_count >= 12)
@@ -120,22 +143,30 @@ static void __attribute__((unused)) V761_init()
static void __attribute__((unused)) V761_initialize_txid()
{
// TODO: try arbitrary rx_tx_addr & frequencies (except hopping_frequency[0])
switch(RX_num%3)
switch(RX_num%5)
{
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);
memcpy(hopping_frequency,(uint8_t *)"\x0D\x21",2);
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);
memcpy(hopping_frequency,(uint8_t *)"\x13\x1D",2);
break;
case 3: //Dump from air on MikeHRC Eachine TX
memcpy(rx_tx_addr,(uint8_t *)"\x08\x03\x00\xA0",4); // To be checked
memcpy(hopping_frequency,(uint8_t *)"\x0D\x21",2); // To be checked
break;
case 4: //Dump from air on Crashanium Eachine TX
memcpy(rx_tx_addr,(uint8_t *)"\x58\x08\x00\xA0",4); // To be checked
memcpy(hopping_frequency,(uint8_t *)"\x0D\x31",3); // To be checked
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);
memcpy(hopping_frequency,(uint8_t *)"\x14\x1e",3);
break;
}
hopping_frequency[2]=hopping_frequency[0]+0x37;
}
uint16_t V761_callback()
@@ -185,10 +216,14 @@ uint16_t V761_callback()
uint16_t initV761(void)
{
BIND_IN_PROGRESS;
bind_counter = V761_BIND_COUNT;
V761_initialize_txid();
phase = V761_BIND1;
if(IS_BIND_IN_PROGRESS)
{
bind_counter = V761_BIND_COUNT;
phase = V761_BIND1;
}
else
phase = V761_DATA;
V761_init();
hopping_frequency_no = 0;
packet_count = 0;

View File

@@ -1,180 +0,0 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// compatible with V911S
#if defined(V911S_NRF24L01_INO)
#include "iface_nrf24l01.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;
}
// Power on, TX mode, 2byte CRC
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
if (!bind)
{
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[channel]);
hopping_frequency_no++;
hopping_frequency_no&=7; // 8 RF channels
}
// clear packet status bits and TX FIFO
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(packet, V911S_PACKET_SIZE);
NRF24L01_SetPower(); // Set tx_power
}
static void __attribute__((unused)) V911S_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_SetTXAddr((uint8_t *)"\x4B\x4E\x42\x4E\x44", 5); // Bind address
NRF24L01_WriteReg(NRF24L01_05_RF_CH, V911S_RF_BIND_CHANNEL); // Bind channel
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
NRF24L01_SetPower();
}
static void __attribute__((unused)) 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
rx_tx_addr[0]=0xA5;
rx_tx_addr[1]=0xFF;
rx_tx_addr[2]=0x70;
rx_tx_addr[3]=0x8D;
rx_tx_addr[4]=0x76;
for(uint8_t i=0;i<V911S_NUM_RF_CHANNELS;i++)
hopping_frequency[i]=0x10+i*5;
hopping_frequency[0]++;
rf_ch_num=0;
#endif
V911S_init();
if(IS_BIND_IN_PROGRESS)
{
bind_counter = V911S_BIND_COUNT;
packet_period= V911S_BIND_PACKET_PERIOD;
}
else
{
XN297_SetTXAddr(rx_tx_addr, 5);
packet_period= V911S_PACKET_PERIOD;
}
hopping_frequency_no=0;
return V911S_INITIAL_WAIT;
}
#endif

View File

@@ -14,9 +14,9 @@
*/
// compatible with V911S
#if defined(V911S_XN297L_INO)
#if defined(V911S_NRF24L01_INO)
#include "iface_xn297l.h"
#include "iface_nrf250k.h"
//#define V911S_ORIGINAL_ID
@@ -30,6 +30,8 @@
// flags going to packet[1]
#define V911S_FLAG_EXPERT 0x04
#define E119_FLAG_EXPERT 0x08
#define E119_FLAG_CALIB 0x40
// flags going to packet[2]
#define V911S_FLAG_CALIB 0x01
@@ -56,10 +58,21 @@ static void __attribute__((unused)) V911S_send_packet(uint8_t bind)
}
if(rf_ch_num&2)
channel=7-channel;
XN297L_Hopping(channel);
hopping_frequency_no++;
hopping_frequency_no&=7; // 8 RF channels
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);
memset(packet+1, 0x00, V911S_PACKET_SIZE - 1);
if(sub_protocol==V911S_STD)
{
packet[ 1]=V911S_FLAG_EXPERT; // short press on left button
packet[ 2]=GET_FLAG(CH5_SW,V911S_FLAG_CALIB); // long press on right button
}
else
packet[ 1]=E119_FLAG_EXPERT // short press on left button
|GET_FLAG(CH5_SW,E119_FLAG_CALIB); // short press on right button
//packet[3..6]=trims TAER signed
uint16_t ch=convert_channel_16b_limit(THROTTLE ,0,0x7FF);
packet[ 7] = ch;
@@ -68,22 +81,31 @@ static void __attribute__((unused)) V911S_send_packet(uint8_t bind)
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(sub_protocol==V911S_STD)
{
packet[10] = ch;
packet[11] = ch>>8;
ch=convert_channel_16b_limit(RUDDER ,0x7FF,0);
packet[11]|= ch<<3;
packet[12] = ch>>5;
}
else
{
ch=0x7FF-ch;
packet[ 9]|= ch<<6;
packet[10] = ch>>2;
packet[11] = ch>>10;
ch=convert_channel_16b_limit(RUDDER ,0x7FF,0);
packet[11]|= ch<<1;
packet[12] = ch>>7;
}
}
if (!bind)
{
XN297L_Hopping(channel);
hopping_frequency_no++;
hopping_frequency_no&=7; // 8 RF channels
}
XN297L_WritePayload(packet, V911S_PACKET_SIZE);
if(sub_protocol==V911S_STD)
XN297L_WritePayload(packet, V911S_PACKET_SIZE);
else
XN297L_WriteEnhancedPayload(packet, V911S_PACKET_SIZE, bind?0:1);
XN297L_SetPower(); // Set tx_power
XN297L_SetFreqOffset(); // Set frequency offset
}
@@ -91,7 +113,10 @@ static void __attribute__((unused)) V911S_send_packet(uint8_t bind)
static void __attribute__((unused)) V911S_init()
{
XN297L_Init();
XN297L_SetTXAddr((uint8_t *)"KNBND",5); // Bind address
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
}
@@ -140,15 +165,30 @@ uint16_t initV911S(void)
{
V911S_initialize_txid();
#ifdef V911S_ORIGINAL_ID
rx_tx_addr[0]=0xA5;
rx_tx_addr[1]=0xFF;
rx_tx_addr[2]=0x70;
rx_tx_addr[3]=0x8D;
rx_tx_addr[4]=0x76;
for(uint8_t i=0;i<V911S_NUM_RF_CHANNELS;i++)
hopping_frequency[i]=0x10+i*5;
hopping_frequency[0]++;
rf_ch_num=0;
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();

View File

@@ -4,10 +4,10 @@
#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)
#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) && not defined(ARDUINO_AVR_DUEMILANOVE)
#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__)
#if F_CPU != 16000000L || not (defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__))
#error You must select the processor type "ATmega328(5V, 16MHz)"
#endif
#endif
@@ -79,6 +79,11 @@
#error "The FrSkyD forced frequency tuning value is outside of the range -127..127."
#endif
#endif
#ifdef FORCE_FRSKYL_TUNING
#if ( FORCE_FRSKYL_TUNING < -127 ) || ( FORCE_FRSKYL_TUNING > 127 )
#error "The FrSkyL 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."
@@ -94,19 +99,29 @@
#error "The HITEC 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
#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_RADIOLINK_TUNING
#if ( FORCE_RADIOLINK_TUNING < -127 ) || ( FORCE_RADIOLINK_TUNING > 127 )
#error "The RADIOLINK 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."
#ifdef FORCE_SKYARTEC_TUNING
#if ( FORCE_SKYARTEC_TUNING < -127 ) || ( FORCE_SKYARTEC_TUNING > 127 )
#error "The SKYARTEC forced frequency tuning value is outside of the range -127..127."
#endif
#endif
//A7105
@@ -125,9 +140,14 @@
#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."
#ifdef FORCE_HEIGHT_TUNING
#if ( FORCE_HEIGHT_TUNING < -300 ) || ( FORCE_HEIGHT_TUNING > 300 )
#error "The Height 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
@@ -135,6 +155,11 @@
#error "The Hubsan forced frequency tuning value is outside of the range -300..300."
#endif
#endif
#ifdef FORCE_KYOSHO_TUNING
#if ( FORCE_KYOSHO_TUNING < -300 ) || ( FORCE_KYOSHO_TUNING > 300 )
#error "The Kyosho forced frequency tuning value is outside of the range -300..300."
#endif
#endif
#ifndef USE_A7105_CH15_TUNING
#ifndef FORCE_BUGS_TUNING
@@ -143,8 +168,14 @@
#ifndef FORCE_FLYSKY_TUNING
#define FORCE_FLYSKY_TUNING 0
#endif
#ifndef FORCE_FLYZONE_TUNING
#define FORCE_FLYZONE_TUNING 0
#ifndef FORCE_HEIGHT_TUNING
#define FORCE_HEIGHT_TUNING 0
#endif
#ifndef FORCE_PELIKAN_TUNING
#define FORCE_PELIKAN_TUNING 0
#endif
#ifndef FORCE_KYOSHO_TUNING
#define FORCE_KYOSHO_TUNING 0
#endif
#ifndef FORCE_HUBSAN_TUNING
#define FORCE_HUBSAN_TUNING 0
@@ -167,79 +198,115 @@
#undef CC25_CSN_pin
#undef NRF24L01_INSTALLED // Disable NRF for OrangeTX module
#undef NRF_CSN_pin
#undef SX1276_INSTALLED // Disable SX1276 for OrangeTX module
#define TELEMETRY // Enable telemetry
#define INVERT_TELEMETRY // Enable invert telemetry
#define DSM_TELEMETRY // Enable DSM telemetry
#endif
//Change/Force RF chip configuration if MULTI_5IN1_INTERNAL
#ifdef MULTI_5IN1_INTERNAL
#if not defined(STM32_BOARD)
#error "Error MULTI_5IN1_INTERNAL is only for STM32 boards."
#endif
#define A7105_INSTALLED
#define CYRF6936_INSTALLED
#define CC2500_INSTALLED
#define NRF24L01_INSTALLED
#define SX1276_INSTALLED
#undef ENABLE_PPM
#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 BUGS_A7105_INO
#undef FLYSKY_A7105_INO
#undef HEIGHT_A7105_INO
#undef HUBSAN_A7105_INO
#undef KYOSHO_A7105_INO
#undef PELIKAN_A7105_INO
#endif
#ifndef CYRF6936_INSTALLED
#undef DEVO_CYRF6936_INO
#undef DSM_CYRF6936_INO
#undef HOTT_CC2500_INO
#undef DSM_RX_CYRF6936_INO
#undef J6PRO_CYRF6936_INO
#undef TRAXXAS_CYRF6936_INO
#undef WFLY_CYRF6936_INO
#undef WK2x01_CYRF6936_INO
#undef TRAXXAS_CYRF6936_INO
#endif
#ifndef CC2500_INSTALLED
#undef CORONA_CC2500_INO
#undef ESKY150V2_CC2500_INO
#undef FRSKYD_CC2500_INO
#undef FRSKYL_CC2500_INO
#undef FRSKYV_CC2500_INO
#undef FRSKYX_CC2500_INO
#undef SFHSS_CC2500_INO
#undef CORONA_CC2500_INO
#undef REDPINE_CC2500_INO
#undef HITEC_CC2500_INO
#undef XN297L_CC2500_EMU
#undef SCANNER_CC2500_INO
#undef FRSKY_RX_CC2500_INO
#undef HITEC_CC2500_INO
#undef HOTT_CC2500_INO
#undef REDPINE_CC2500_INO
#undef RLINK_CC2500_INO
#undef SCANNER_CC2500_INO
#undef SFHSS_CC2500_INO
#undef SKYARTEC_CC2500_INO
#endif
#ifndef NRF24L01_INSTALLED
#undef ASSAN_NRF24L01_INO
#undef BAYANG_NRF24L01_INO
#undef BAYANG_RX_NRF24L01_INO
#undef BUGSMINI_NRF24L01_INO
#undef CABELL_NRF24L01_INO
#undef CFLIE_NRF24L01_INO
#undef CG023_NRF24L01_INO
#undef CX10_NRF24L01_INO
#undef DM002_NRF24L01_INO
#undef E01X_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 ESKY150_NRF24L01_INO
#undef ESKY150V2_CC2500_INO // Use both CC2500 and NRF code
#undef FQ777_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 GW008_NRF24L01_INO
#undef H8_3D_NRF24L01_INO
#undef CFLIE_NRF24L01_INO
#undef BUGSMINI_NRF24L01_INO
#undef HISKY_NRF24L01_INO
#undef HONTAI_NRF24L01_INO
#undef JJRC345_NRF24L01_INO
#undef KF606_NRF24L01_INO
#undef KN_NRF24L01_INO
#undef MJXQ_NRF24L01_INO
#undef MT99XX_NRF24L01_INO
#undef NCC1701_NRF24L01_INO
#undef E01X_NRF24L01_INO
#undef POTENSIC_NRF24L01_INO
#undef PROPEL_NRF24L01_INO
#undef Q303_NRF24L01_INO
#undef Q90C_NRF24L01_INO
#undef SHENQI_NRF24L01_INO
#undef SLT_NRF24L01_INO
#undef SYMAX_NRF24L01_INO
#undef TIGER_NRF24L01_INO
#undef V2X2_NRF24L01_INO
#undef V761_NRF24L01_INO
#undef V911S_NRF24L01_INO
#undef XN297L_CC2500_EMU
#undef POTENSIC_NRF24L01_INO
#undef XK_NRF24L01_INO
#undef YD717_NRF24L01_INO
#undef ZSX_NRF24L01_INO
#undef BAYANG_RX_NRF24L01_INO
#endif
#if not defined(STM32_BOARD)
#undef SX1276_INSTALLED
#endif
#ifndef SX1276_INSTALLED
#undef FRSKYR9_SX1276_INO
#endif
//OpenTX 2.3.x issue
#if defined (FRSKYD_CC2500_INO) || defined(FRSKYV_CC2500_INO) || defined(FRSKYX_CC2500_INO)
#define FRSKYX_CC2500_INO
#define FRSKY_RX_CC2500_INO
#endif
//Make sure telemetry is selected correctly
@@ -269,6 +336,10 @@
#undef HOTT_FW_TELEMETRY
#undef BAYANG_RX_TELEMETRY
#undef BAYANG_RX_NRF24L01_INO
#undef DEVO_HUB_TELEMETRY
#undef PROPEL_HUB_TELEMETRY
#undef RLINK_HUB_TELEMETRY
#undef DSM_RX_CYRF6936_INO
#else
#if defined(MULTI_TELEMETRY) && defined(MULTI_STATUS)
#error You should choose either MULTI_TELEMETRY or MULTI_STATUS but not both.
@@ -292,6 +363,12 @@
#if not defined(BAYANG_NRF24L01_INO)
#undef BAYANG_HUB_TELEMETRY
#endif
#if not defined(DEVO_CYRF6936_INO)
#undef DEVO_HUB_TELEMETRY
#endif
#if not defined(PROPEL_NRF24L01_INO)
#undef PROPEL_HUB_TELEMETRY
#endif
#if not defined(NCC1701_NRF24L01_INO)
#undef NCC1701_HUB_TELEMETRY
#endif
@@ -301,6 +378,9 @@
#if not defined(CABELL_NRF24L01_INO)
#undef CABELL_HUB_TELEMETRY
#endif
#if not defined(RLINK_CC2500_INO)
#undef RLINK_HUB_TELEMETRY
#endif
#if not defined(HUBSAN_A7105_INO)
#undef HUBSAN_HUB_TELEMETRY
#endif
@@ -315,7 +395,7 @@
#if not defined(FRSKYD_CC2500_INO)
#undef HUB_TELEMETRY
#endif
#if not defined(FRSKYX_CC2500_INO)
#if not defined(FRSKYX_CC2500_INO) && not defined(FRSKYR9_SX1276_INO)
#undef SPORT_TELEMETRY
#undef SPORT_SEND
#endif
@@ -328,7 +408,7 @@
#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)
#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(RLINK_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) && not defined(DEVO_HUB_TELEMETRY) && not defined(PROPEL_HUB_TELEMETRY)
#undef TELEMETRY
#undef INVERT_TELEMETRY
#undef MULTI_TELEMETRY
@@ -347,9 +427,7 @@
#if not defined(MULTI_TELEMETRY)
#undef MULTI_SYNC
#undef MULTI_NAMES
#endif
#if defined(MULTI_TELEMETRY)
#else
#define MULTI_NAMES
#endif
@@ -404,3 +482,18 @@
#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

View File

@@ -0,0 +1,217 @@
/*
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 X450 and X420/X520 plane.
#if defined(XK_NRF24L01_INO)
#include "iface_nrf250k.h"
//#define FORCE_XK_ORIGINAL_ID
#define XK_INITIAL_WAIT 500
#define XK_PACKET_PERIOD 4000
#define XK_RF_BIND_NUM_CHANNELS 8
#define XK_RF_NUM_CHANNELS 4
#define XK_PAYLOAD_SIZE 16
#define XK_BIND_COUNT 750 //3sec
static uint16_t __attribute__((unused)) XK_convert_channel(uint8_t num)
{
uint16_t val=convert_channel_10b(num);
// 1FF..01=left, 00=center, 200..3FF=right
if(val==0x200)
val=0; // 0
else
if(val>0x200)
val--; // 200..3FE
else
{
val=0x200-val; // 200..01
if(val==0x200)
val--; // 1FF..01
}
return val;
}
static void __attribute__((unused)) XK_send_packet()
{
memset(packet,0x00,7);
memset(&packet[10],0x00,5);
packet[12]=0x40;
packet[13]=0x40;
if(IS_BIND_IN_PROGRESS)
packet[14] = 0xC0;
else
{
uint16_t val=convert_channel_10b(THROTTLE);
packet[0] = val>>2; // 0..255
//packet[12] |= val & 2;
val=XK_convert_channel(RUDDER);
packet[1] = val>>2;
//packet[12] |= (val & 2)<<2;
val=XK_convert_channel(ELEVATOR);
packet[2] = val>>2;
//packet[13] |= val & 2;
val=XK_convert_channel(AILERON);
packet[3] = val>>2;
//packet[13] |= (val & 2)<<2;
memset(&packet[4],0x40,3); // Trims
if(Channel_data[CH5] > CHANNEL_MAX_COMMAND)
packet[10] = 0x10; // V-Mode
else
if(Channel_data[CH5] > CHANNEL_MIN_COMMAND)
packet[10] = 0x04; // 6G-Mode
//0x00 default M-Mode
packet[10] |= GET_FLAG(CH7_SW,0x80); // Emergency stop momentary switch
packet[11] = GET_FLAG(CH8_SW,0x03) // 3D/6G momentary switch
|GET_FLAG(CH6_SW,0x40); // Take off momentary switch
packet[14] = GET_FLAG(CH9_SW,0x01) // Photo momentary switch
|GET_FLAG(CH10_SW,0x2); // Video momentary switch
}
crc=packet[0];
for(uint8_t i=1; i<XK_PAYLOAD_SIZE-1;i++)
crc+=packet[i];
packet[15]=crc;
// debug("C: %02X, P:",hopping_frequency[(IS_BIND_IN_PROGRESS?0:XK_RF_BIND_NUM_CHANNELS)+(hopping_frequency_no>>1)]);
XN297L_Hopping((IS_BIND_IN_PROGRESS?0:XK_RF_BIND_NUM_CHANNELS)+(hopping_frequency_no>>1));
hopping_frequency_no++;
if(hopping_frequency_no >= (IS_BIND_IN_PROGRESS?XK_RF_BIND_NUM_CHANNELS*2:XK_RF_NUM_CHANNELS*2))
hopping_frequency_no=0;
XN297L_WritePayload(packet, XK_PAYLOAD_SIZE);
// for(uint8_t i=0; i<XK_PAYLOAD_SIZE; i++)
// debug(" %02X",packet[i]);
// debugln("");
XN297L_SetPower(); // Set tx_power
XN297L_SetFreqOffset(); // Set frequency offset
}
const uint8_t PROGMEM XK_bind_hop[XK_RF_BIND_NUM_CHANNELS]= { 0x07, 0x24, 0x3E, 0x2B, 0x47, 0x0E, 0x39, 0x1C }; // Bind
const uint8_t PROGMEM XK_tx_addr[]= { 0xB3, 0x67, 0xE9, 0x98, 0x3A, 0xEC, 0xA6, 0x59, 0xB2, 0x94, 0x2B, 0xA5, 0x37, 0xC5, 0x4A, 0xD3,
0x49, 0xA6, 0x83, 0xEB, 0x4B, 0xC9, 0x59, 0xD2, 0x65, 0x34, 0x6A, 0xD3, 0x2C, 0x96, 0x2A, 0xA9,
0x32, 0xB2, 0xB4, 0x49, 0xD3, 0x37, 0xE9 };
const uint8_t PROGMEM XK_hop[]= { 0x47, 0x3A, 0x4C, 0x39, 0x4D, 0x34, 0x4A, 0x3F, 0x45, 0x3E, 0x4B, 0x3D, 0x3B, 0x48, 0x40, 0x49,
0x46, 0x3C, 0x43, 0x38, 0x35, 0x42, 0x33, 0x44, 0x4E, 0x37, 0x44, 0x35, 0x37, 0x4E, 0x36, 0x41 };
static void __attribute__((unused)) XK_initialize_txid()
{
//bind hop
for(uint8_t i=0; i<XK_RF_BIND_NUM_CHANNELS; i++)
hopping_frequency[i]=pgm_read_byte_near( &XK_bind_hop[i] );
//GID
packet[7]=rx_tx_addr[1];
packet[8]=rx_tx_addr[2];
packet[9]=rx_tx_addr[3];
uint8_t sum=packet[7]+packet[8]+packet[9];
// debugln("GID=%02X %02X %02X, sum=%d", packet[7],packet[8],packet[9],sum);
//Normal hop
uint8_t start=(sum&0x07)<<2;
// debug("start=%d, hop=",start);
for(uint8_t i=0; i<XK_RF_NUM_CHANNELS; i++)
{
hopping_frequency[ i + XK_RF_BIND_NUM_CHANNELS ]=pgm_read_byte_near( &XK_hop[ start + i ] );
// debug("%02X ", hopping_frequency[ i + XK_RF_BIND_NUM_CHANNELS ]);
}
// debugln("");
//Normal packet address
start=(sum&0x1F)+((sum>>5)&0x03);
// debug("start=%d, addr=",start);
for(uint8_t i=0; i<5; i++)
{
rx_tx_addr[i]=pgm_read_byte_near( &XK_tx_addr[ start + i ] );
// debug("%02X ", rx_tx_addr[ i ]);
}
// debugln("");
#ifdef FORCE_XK_ORIGINAL_ID
switch(RX_num%2)
{
default:
//TX1 X8 X450
//GID
packet[7]=0x04;
packet[8]=0x15;
packet[9]=0x22;
//Normal hop
memcpy(&hopping_frequency[XK_RF_BIND_NUM_CHANNELS],(uint8_t*)"\x3B\x48\x40\x49", XK_RF_NUM_CHANNELS); // freq and order verified
//Normal packet address
memcpy(rx_tx_addr,(uint8_t*)"\x2C\x96\x2A\xA9\x32",5);
break;
case 1:
//TX2 X4 X420
//GID
packet[7]=0x13;
packet[8]=0x24;
packet[9]=0x18;
//Normal hop
memcpy(&hopping_frequency[XK_RF_BIND_NUM_CHANNELS],(uint8_t*)"\x36\x41\x37\x4E", XK_RF_NUM_CHANNELS); // freq ok and order from xn297dump auto
//Normal packet address
memcpy(rx_tx_addr,(uint8_t*)"\xA6\x83\xEB\x4B\xC9",5);
break;
}
#endif
}
static void __attribute__((unused)) XK_init()
{
XN297L_Init();
XN297L_SetTXAddr((uint8_t*)"\x68\x94\xA6\xD5\xC3", 5); // Bind address
XN297L_HoppingCalib(XK_RF_BIND_NUM_CHANNELS+XK_RF_NUM_CHANNELS); // Calibrate all channels
}
uint16_t XK_callback()
{
if(sub_protocol==X420)
option=0; // Forcing the use of NRF24L01@1Mbps
#ifdef MULTI_SYNC
telemetry_set_input_sync(XK_PACKET_PERIOD);
#endif
if(IS_BIND_IN_PROGRESS)
if(--bind_counter==0)
{
BIND_DONE;
XN297L_SetTXAddr(rx_tx_addr, 5); // Normal packets address
}
XK_send_packet();
return XK_PACKET_PERIOD;
}
uint16_t initXK()
{
if(sub_protocol==X420)
option=prev_option=0; // Forcing the use of NRF24L01@1Mbps
BIND_IN_PROGRESS; // Autobind protocol
XK_initialize_txid();
XK_init();
if(sub_protocol==X420)
NRF24L01_SetBitrate(NRF24L01_BR_1M); // X420/X520 runs @1Mbps
hopping_frequency_no = 0;
bind_counter=XK_BIND_COUNT;
return XK_INITIAL_WAIT;
}
#endif

View File

@@ -33,6 +33,10 @@
uint8_t address_length;
uint16_t timeH=0;
boolean scramble;
boolean enhanced;
boolean ack;
uint8_t pid;
uint8_t bitrate;
static void __attribute__((unused)) XN297Dump_init()
{
@@ -48,14 +52,14 @@ static void __attribute__((unused)) XN297Dump_init()
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x55\x0F\x71", 3); // set up RX address to xn297 preamble
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, XN297DUMP_MAX_PACKET_LEN); // Enable rx pipe 0
debug("XN297 dump, address length=%d, speed=",address_length);
switch(sub_protocol)
debug("XN297 dump, address length=%d, bitrate=",address_length);
switch(bitrate)
{
case 0:
case XN297DUMP_250K:
NRF24L01_SetBitrate(NRF24L01_BR_250K);
debugln("250K");
break;
case 2:
case XN297DUMP_2M:
NRF24L01_SetBitrate(NRF24L01_BR_2M);
debugln("2M");
break;
@@ -76,9 +80,14 @@ static boolean __attribute__((unused)) XN297Dump_process_packet(void)
{
uint16_t crcxored;
uint8_t packet_sc[XN297DUMP_MAX_PACKET_LEN], packet_un[XN297DUMP_MAX_PACKET_LEN];
enhanced=false;
// init crc
crc = 0xb5d2;
/*debug("P: 71 0F 55 ");
for(uint8_t i=0; i<XN297DUMP_MAX_PACKET_LEN; i++)
debug("%02X ",packet[i]);
debugln("");*/
//Try normal payload
// address
for (uint8_t i = 0; i < address_length; i++)
@@ -142,17 +151,17 @@ static boolean __attribute__((unused)) XN297Dump_process_packet(void)
}
if(packet_length!=0)
{ // Found a valid CRC for the enhanced payload mode
debug("Enhanced ");
enhanced=true;
//check selected address length
if((packet_un[address_length]>>1)!=packet_length-address_length)
{
for(uint8_t i=3;i<=5;i++)
if((packet_un[i]>>1)==packet_length-i)
address_length=i;
debug("Wrong address length selected using %d ", address_length )
debugln("Detected wrong address length, using %d intead", address_length );
}
debug("pid=%d ",((packet_un[address_length]&0x01)<<1)|(packet_un[address_length+1]>>7));
debug("ack=%d ",(packet_un[address_length+1]>>6)&0x01);
pid=((packet_un[address_length]&0x01)<<1)|(packet_un[address_length+1]>>7);
ack=(packet_un[address_length+1]>>6)&0x01;
// address
for (uint8_t i = 0; i < address_length; i++)
packet[address_length-1-i]=packet_un[i];
@@ -175,96 +184,524 @@ static void __attribute__((unused)) XN297Dump_overflow()
}
static uint16_t XN297Dump_callback()
{
static uint32_t time=0;
static uint32_t time=0,*time_rf;
//!!!Blocking mode protocol!!!
TX_MAIN_PAUSE_off;
tx_resume();
while(1)
{
if(option==0xFF && bind_counter>XN297DUMP_PERIOD_SCAN)
{ // Scan frequencies
hopping_frequency_no++;
bind_counter=0;
}
if(hopping_frequency_no!=rf_ch_num)
{ // Channel has changed
if(hopping_frequency_no>XN297DUMP_MAX_RF_CHANNEL)
hopping_frequency_no=0; // Invalid channel 0 by default
rf_ch_num=hopping_frequency_no;
debugln("Channel=%d,0x%02X",hopping_frequency_no,hopping_frequency_no)
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency_no);
// switch to RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
phase=0; // init timer
}
XN297Dump_overflow();
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD) || option != 0xFF)
{
NRF24L01_ReadPayload(packet,XN297DUMP_MAX_PACKET_LEN);
XN297Dump_overflow();
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
if(sub_protocol<XN297DUMP_AUTO)
{
if(option==0xFF && bind_counter>XN297DUMP_PERIOD_SCAN)
{ // Scan frequencies
hopping_frequency_no++;
bind_counter=0;
}
if(hopping_frequency_no!=rf_ch_num)
{ // Channel has changed
if(hopping_frequency_no>XN297DUMP_MAX_RF_CHANNEL)
hopping_frequency_no=0; // Invalid channel 0 by default
rf_ch_num=hopping_frequency_no;
debugln("Channel=%d,0x%02X",hopping_frequency_no,hopping_frequency_no);
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency_no);
// switch to RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
phase=0; // init timer
}
XN297Dump_overflow();
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD) || option != 0xFF)
{
NRF24L01_ReadPayload(packet,XN297DUMP_MAX_PACKET_LEN);
XN297Dump_overflow();
timeL=0;
}
if(phase==0)
{
phase=1;
time=0;
}
else
time=(timeH<<16)+timeL-time;
debug("RX: %5luus C=%d ", time>>1 , hopping_frequency_no);
time=(timeH<<16)+timeL;
if(XN297Dump_process_packet())
{ // valid crc found
debug("S=%c A=",scramble?'Y':'N');
for(uint8_t i=0; i<address_length; i++)
{
debug(" %02X",packet[i]);
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
debug(" P(%d)=",packet_length-address_length);
for(uint8_t i=address_length; i<packet_length; i++)
if((phase&0x01)==0)
{
debug(" %02X",packet[i]);
phase=1;
time=0;
}
else
time=(timeH<<16)+timeL-time;
if(XN297Dump_process_packet())
{ // valid crc found
debug("RX: %5luus C=%d ", time>>1 , hopping_frequency_no);
time=(timeH<<16)+timeL;
if(enhanced)
{
debug("Enhanced ");
debug("pid=%d ",pid);
if(ack) debug("ack ");
}
debug("S=%c A=",scramble?'Y':'N');
for(uint8_t i=0; i<address_length; i++)
{
debug(" %02X",packet[i]);
}
debug(" P(%d)=",packet_length-address_length);
for(uint8_t i=address_length; i<packet_length; i++)
{
debug(" %02X",packet[i]);
}
debugln("");
}
else
{
debugln("RX: %5luus C=%d Bad CRC", time>>1 , hopping_frequency_no);
}
debugln("");
}
else
XN297Dump_overflow();
// restart RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
XN297Dump_overflow();
}
}
else if(sub_protocol==XN297DUMP_AUTO)
{
switch(phase)
{
case 0:
debugln("------------------------");
debugln("Detecting XN297 packets.");
XN297Dump_init();
debug("Trying RF channel: 0");
hopping_frequency_no=0;
bitrate=0;
phase++;
break;
case 1:
if(bind_counter>XN297DUMP_PERIOD_SCAN)
{ // Scan frequencies
hopping_frequency_no++;
bind_counter=0;
if(hopping_frequency_no>XN297DUMP_MAX_RF_CHANNEL)
{
hopping_frequency_no=0;
bitrate++;
bitrate%=3;
debugln("");
XN297Dump_init();
debug("Trying RF channel: 0");
}
if(hopping_frequency_no)
debug(",%d",hopping_frequency_no);
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency_no);
// switch to RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
}
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
NRF24L01_ReadPayload(packet,XN297DUMP_MAX_PACKET_LEN);
if(XN297Dump_process_packet())
{ // valid crc found
debug("\r\n\r\nPacket detected: bitrate=");
switch(bitrate)
{
case XN297DUMP_250K:
NRF24L01_SetBitrate(NRF24L01_BR_250K);
debug("250K");
break;
case XN297DUMP_2M:
NRF24L01_SetBitrate(NRF24L01_BR_2M);
debug("2M");
break;
default:
NRF24L01_SetBitrate(NRF24L01_BR_1M);
debug("1M");
break;
}
debug(" C=%d ", hopping_frequency_no);
if(enhanced)
{
debug("Enhanced ");
debug("pid=%d ",pid);
if(ack) debug("ack ");
}
debug("S=%c A=",scramble?'Y':'N');
for(uint8_t i=0; i<address_length; i++)
{
debug(" %02X",packet[i]);
rx_tx_addr[i]=packet[i];
}
debug(" P(%d)=",packet_length-address_length);
for(uint8_t i=address_length; i<packet_length; i++)
{
debug(" %02X",packet[i]);
}
packet_length=packet_length-address_length;
debugln("\r\n--------------------------------");
phase=2;
debugln("Identifying all RF channels in use.");
bind_counter=0;
hopping_frequency_no=0;
rf_ch_num=0;
packet_count=0;
debug("Trying RF channel: 0");
NRF24L01_Initialize();
XN297_SetScrambledMode(scramble?XN297_SCRAMBLED:XN297_UNSCRAMBLED);
XN297_SetTXAddr(rx_tx_addr,address_length);
XN297_SetRXAddr(rx_tx_addr,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, packet_length + 2 + (enhanced?2:0) ); // 2 extra bytes for xn297 crc
NRF24L01_WriteReg(NRF24L01_05_RF_CH,0);
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));
}
}
}
break;
case 2:
if(bind_counter>XN297DUMP_PERIOD_SCAN)
{ // Scan frequencies
hopping_frequency_no++;
bind_counter=0;
if(packet_count && packet_count<=5)
debug("\r\nTrying RF channel: ");
packet_count=0;
if(hopping_frequency_no>XN297DUMP_MAX_RF_CHANNEL)
{
debug("\r\n\r\n%d RF channels identified:",rf_ch_num);
for(uint8_t i=0;i<rf_ch_num;i++)
debug(" %d",hopping_frequency[i]);
time_rf=(uint32_t*)malloc(rf_ch_num*sizeof(time));
if(time_rf==NULL)
{
debugln("\r\nCan't allocate memory for next phase!!!");
phase=0;
break;
}
debugln("\r\n--------------------------------");
debugln("Identifying RF channels order.");
hopping_frequency_no=1;
phase=3;
packet_count=0;
bind_counter=0;
debugln("Time between CH:%d and CH:%d",hopping_frequency[0],hopping_frequency[hopping_frequency_no]);
time_rf[hopping_frequency_no]=0xFFFFFFFF;
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency[0]);
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
time=(timeH<<16)+timeL;
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
XN297Dump_overflow();
break;
}
debug(",%d",hopping_frequency_no);
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency_no);
// switch to RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
}
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
boolean res;
if(enhanced)
res=XN297_ReadEnhancedPayload(packet, packet_length);
else
res=XN297_ReadPayload(packet, packet_length);
if(res)
{ // valid crc found
XN297Dump_overflow();
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
if(packet_count==0)
{//save channel
hopping_frequency[rf_ch_num]=hopping_frequency_no;
rf_ch_num++;
time=0;
}
else
time=(timeH<<16)+timeL-time;
debug("\r\nRX on channel: %d, Time: %5luus P:",hopping_frequency_no, time>>1);
time=(timeH<<16)+timeL;
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet[i]);
packet_count++;
if(packet_count>5)
{//change channel
bind_counter=XN297DUMP_PERIOD_SCAN+1;
debug("\r\nTrying RF channel: ");
}
}
}
// restart RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
}
XN297Dump_overflow();
break;
case 3:
if(bind_counter>XN297DUMP_PERIOD_SCAN)
{ // Scan frequencies
hopping_frequency_no++;
bind_counter=0;
if(hopping_frequency_no>=rf_ch_num)
{
uint8_t next=0;
debugln("\r\n\r\nChannel order:");
debugln("%d: 0us",hopping_frequency[0]);
uint8_t i=1;
do
{
time=time_rf[i];
if(time!=0xFFFFFFFF)
{
next=i;
for(uint8_t j=2;j<rf_ch_num;j++)
if(time>time_rf[j])
{
next=j;
time=time_rf[j];
}
time_rf[next]=-1;
debugln("%d: %5luus",hopping_frequency[next],time);
i=0;
}
i++;
}
while(i<rf_ch_num);
free(time_rf);
debugln("\r\n--------------------------------");
debugln("Identifying Sticks and features.");
phase=4;
hopping_frequency_no=0;
break;
}
debugln("Time between CH:%d and CH:%d",hopping_frequency[0],hopping_frequency[hopping_frequency_no]);
time_rf[hopping_frequency_no]=-1;
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency[0]);
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
time=(timeH<<16)+timeL;
// switch to RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
}
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
boolean res;
if(enhanced)
res=XN297_ReadEnhancedPayload(packet, packet_length);
else
res=XN297_ReadPayload(packet, packet_length);
if(res)
{ // valid crc found
XN297Dump_overflow();
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
if(packet_count&1)
{
time=(timeH<<16)+timeL-time;
if(time_rf[hopping_frequency_no] > (time>>1))
time_rf[hopping_frequency_no]=time>>1;
debugln("Time: %5luus", time>>1);
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency[0]);
}
else
{
time=(timeH<<16)+timeL;
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency[hopping_frequency_no]);
}
packet_count++;
if(packet_count>6)
{
bind_counter=XN297DUMP_PERIOD_SCAN+1;
packet_count=0;
}
}
}
// restart RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
}
XN297Dump_overflow();
break;
case 4:
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
boolean res;
if(enhanced)
res=XN297_ReadEnhancedPayload(packet, packet_length);
else
res=XN297_ReadPayload(packet, packet_length);
if(res)
{ // valid crc found
if(memcmp(packet_in,packet,packet_length))
{
debug("P:");
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet[i]);
debugln("");
memcpy(packet_in,packet,packet_length);
}
}
}
// restart RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
}
break;
}
}
else
{
if(phase==0)
{
address_length=5;
memcpy(rx_tx_addr, (uint8_t *)"\xC9\x59\xD2\x65\x34", 5);
bitrate=XN297DUMP_250K;
packet_length=16;
hopping_frequency_no=0x03;
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, address_length-2); // RX/TX address length
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, address_length); // set up RX address
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // Enable rx pipe 0
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency_no);
debug("NRF dump, len=%d, rf=%d, address length=%d, bitrate=",packet_length,hopping_frequency_no,address_length);
switch(bitrate)
{
debugln("Bad CRC");
case XN297DUMP_250K:
NRF24L01_SetBitrate(NRF24L01_BR_250K);
debugln("250K");
break;
case XN297DUMP_2M:
NRF24L01_SetBitrate(NRF24L01_BR_2M);
debugln("2M");
break;
default:
NRF24L01_SetBitrate(NRF24L01_BR_1M);
debugln("1M");
break;
}
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
NRF24L01_Activate(0x73);
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
phase++;
}
else
{
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
NRF24L01_ReadPayload(packet, packet_length);
if(memcmp(packet_in,packet,packet_length))
{
debug("P:");
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet[i]);
debugln("");
memcpy(packet_in,packet,packet_length);
}
}
// restart RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
}
}
XN297Dump_overflow();
// restart RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
XN297Dump_overflow();
}
bind_counter++;
if(IS_RX_FLAG_on) // Let the radio update the protocol
{
if(Update_All()) return 10000; // New protocol selected
if(prev_option!=option)
if(prev_option!=option && sub_protocol<XN297DUMP_AUTO)
{ // option has changed
hopping_frequency_no=option;
prev_option=option;
@@ -278,6 +715,10 @@ static uint16_t XN297Dump_callback()
uint16_t initXN297Dump(void)
{
BIND_DONE;
if(sub_protocol<XN297DUMP_AUTO)
bitrate=sub_protocol;
else
bitrate=0;
address_length=RX_num;
if(address_length<3||address_length>5)
address_length=5; //default
@@ -285,7 +726,7 @@ uint16_t initXN297Dump(void)
bind_counter=0;
rf_ch_num=0xFF;
prev_option=option^0x55;
phase=0; // init timer
phase=0; // init
return XN297DUMP_INITIAL_WAIT;
}

View File

@@ -1,223 +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/>.
*/
#include "iface_xn297l.h"
#if defined (XN297L_CC2500_EMU)
static void __attribute__((unused)) XN297L_Init()
{
PE1_off; // antenna RF2
PE2_on;
CC2500_Reset();
CC2500_Strobe(CC2500_SIDLE);
// Address Config = No address check
// Base Frequency = 2400
// CRC Autoflush = false
// CRC Enable = false
// Channel Spacing = 333.251953
// Data Format = Normal mode
// Data Rate = 249.939
// Deviation = 126.953125
// Device Address = 0
// Manchester Enable = false
// Modulated = true
// Modulation Format = GFSK
// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word
// RX Filter BW = 203.125000
// Sync Word Qualifier Mode = No preamble/sync
// TX Power = 0
// Whitening = false
// Fast Frequency Hopping - no PLL auto calibration
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x01); // Packet Automation Control
CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x0A); // Frequency Synthesizer Control
CC2500_WriteReg(CC2500_0C_FSCTRL0, option); // Frequency offset hack
CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // Frequency Control Word, High Byte
CC2500_WriteReg(CC2500_0E_FREQ1, 0x4E); // Frequency Control Word, Middle Byte
CC2500_WriteReg(CC2500_0F_FREQ0, 0xC3); // Frequency Control Word, Low Byte
CC2500_WriteReg(CC2500_10_MDMCFG4, 0x8D); // Modem Configuration
CC2500_WriteReg(CC2500_11_MDMCFG3, 0x3B); // Modem Configuration
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x10); // Modem Configuration
CC2500_WriteReg(CC2500_13_MDMCFG1, 0x23); // Modem Configuration
CC2500_WriteReg(CC2500_14_MDMCFG0, 0xA4); // Modem Configuration
CC2500_WriteReg(CC2500_15_DEVIATN, 0x62); // Modem Deviation Setting
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // Main Radio Control State Machine Configuration
CC2500_WriteReg(CC2500_19_FOCCFG, 0x1D); // Frequency Offset Compensation Configuration
CC2500_WriteReg(CC2500_1A_BSCFG, 0x1C); // Bit Synchronization Configuration
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0xC7); // AGC Control
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x00); // AGC Control
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xB0); // AGC Control
CC2500_WriteReg(CC2500_21_FREND1, 0xB6); // Front End RX Configuration
CC2500_WriteReg(CC2500_23_FSCAL3, 0xEA); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_25_FSCAL1, 0x00); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_26_FSCAL0, 0x11); // Frequency Synthesizer Calibration
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
xn297_scramble_enabled=XN297_SCRAMBLED; //enabled by default
}
static void __attribute__((unused)) XN297L_SetTXAddr(const uint8_t* addr, uint8_t len)
{
if (len > 5) len = 5;
if (len < 3) len = 3;
xn297_addr_len = len;
memcpy(xn297_tx_addr, addr, len);
}
static void __attribute__((unused)) XN297L_WritePayload(uint8_t* msg, uint8_t len)
{
uint8_t buf[32];
uint8_t last = 0;
uint8_t i;
static const uint16_t initial = 0xb5d2;
// address
for (i = 0; i < xn297_addr_len; ++i)
{
buf[last] = xn297_tx_addr[xn297_addr_len - i - 1];
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[i];
last++;
}
// payload
for (i = 0; i < len; ++i) {
// bit-reverse bytes in packet
buf[last] = bit_reverse(msg[i]);
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[xn297_addr_len+i];
last++;
}
// crc
uint16_t crc = initial;
for (uint8_t i = 0; i < last; ++i)
crc = crc16_update(crc, buf[i], 8);
if(xn297_scramble_enabled)
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
else
crc ^= pgm_read_word(&xn297_crc_xorout[xn297_addr_len - 3 + len]);
buf[last++] = crc >> 8;
buf[last++] = crc & 0xff;
// stop TX/RX
CC2500_Strobe(CC2500_SIDLE);
// flush tx FIFO
CC2500_Strobe(CC2500_SFTX);
// packet length
CC2500_WriteReg(CC2500_3F_TXFIFO, last + 3);
// xn297L preamble
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, (uint8_t*)"\x71\x0f\x55", 3);
// xn297 packet
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buf, last);
// transmit
CC2500_Strobe(CC2500_STX);
}
static void __attribute__((unused)) XN297L_HoppingCalib(uint8_t num_freq)
{ //calibrate hopping frequencies
for (uint8_t i = 0; i < num_freq; i++)
{
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[i]*3);
CC2500_Strobe(CC2500_SCAL);
delayMicroseconds(900);
calData[i]=CC2500_ReadReg(CC2500_25_FSCAL1);
}
}
static void __attribute__((unused)) XN297L_Hopping(uint8_t index)
{
// spacing is 333.25 kHz, must multiply xn297 channel by 3
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[index] * 3);
// set PLL calibration
CC2500_WriteReg(CC2500_25_FSCAL1, calData[index]);
}
static void __attribute__((unused)) XN297L_RFChannel(uint8_t number)
{ //change channel
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, number*3);
CC2500_Strobe(CC2500_SCAL);
delayMicroseconds(900);
}
static void __attribute__((unused)) XN297L_SetPower()
{
CC2500_SetPower();
}
static void __attribute__((unused)) XN297L_SetFreqOffset()
{ // Frequency offset
if (prev_option != option)
{
prev_option = option;
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
}
}
#elif defined (NRF24L01_INSTALLED)
static void __attribute__((unused)) XN297L_Init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
NRF24L01_SetPower();
}
static void __attribute__((unused)) XN297L_SetTXAddr(const uint8_t* addr, uint8_t len)
{
XN297_SetTXAddr(addr,len);
}
static void __attribute__((unused)) XN297L_WritePayload(uint8_t* msg, uint8_t len)
{
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(msg, len);
}
static void __attribute__((unused)) XN297L_HoppingCalib(__attribute__((unused)) uint8_t num_freq)
{ //calibrate hopping frequencies
}
static void __attribute__((unused)) XN297L_Hopping(uint8_t index)
{
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[index]);
}
static void __attribute__((unused)) XN297L_RFChannel(uint8_t number)
{ //change channel
NRF24L01_WriteReg(NRF24L01_05_RF_CH, number);
}
static void __attribute__((unused)) XN297L_SetPower()
{
NRF24L01_SetPower();
}
static void __attribute__((unused)) XN297L_SetFreqOffset()
{ // Frequency offset
}
#endif

View File

@@ -16,7 +16,7 @@ Multiprotocol is distributed in the hope that it will be useful,
#if defined(ZSX_NRF24L01_INO)
#include "iface_xn297l.h"
#include "iface_nrf250k.h"
//#define FORCE_ZSX_ORIGINAL_ID

View File

@@ -69,17 +69,20 @@
/****************/
/*** RF CHIPS ***/
/****************/
//There are 4 RF components supported. If one of them is not installed you must comment it using "//".
//There are 5 RF components supported. If one of them is not installed you must comment it using "//".
//If a chip is not installed all associated protocols are automatically disabled.
//4-in-1 modules have all RF chips installed
//4-in-1 modules have the A7105, CYRF6936, CC2500 and NRF24L01 RF chips installed
//5-in-1 modules have all RF chips installed
//!!!If a RF chip is present it MUST be marked as installed!!! or weird things will happen you have been warned.
#define A7105_INSTALLED
#define CYRF6936_INSTALLED
#define CC2500_INSTALLED
#define NRF24L01_INSTALLED
//#define SX1276_INSTALLED // only supported on STM32 modules
//If available use the CC2500 to emulate the XN297L @250Kbps instead of the NRF24L01. Comment to disable.
#define XN297L_CC2500_EMU
//Uncomment (remove //) if you have an internal 5-in-1 Multi module.
//All components are considered to be installed and specifics to that module are automatically configured
//#define MULTI_5IN1_INTERNAL
/** OrangeRX TX **/
//If you compile for the OrangeRX TX module you need to select the correct board type.
@@ -94,12 +97,15 @@
//Uncomment the lines below (remove the "//") and set an appropriate value (replace the "0") to enable. Valid range is -127 to +127.
//#define FORCE_CORONA_TUNING 0
//#define FORCE_FRSKYD_TUNING 0
//#define FORCE_FRSKYL_TUNING 0
//#define FORCE_FRSKYV_TUNING 0
//#define FORCE_FRSKYX_TUNING 0
//#define FORCE_SFHSS_TUNING 0
//#define FORCE_HITEC_TUNING 0
//#define FORCE_HOTT_TUNING 0
//#define FORCE_RADIOLINK_TUNING 0
//#define FORCE_REDPINE_TUNING 0
//#define FORCE_SFHSS_TUNING 0
//#define FORCE_SKYARTEC_TUNING 0
/** A7105 Fine Frequency Tuning **/
//This is required in rare cases where some A7105 modules and/or RXs have an inaccurate crystal oscillator.
@@ -112,8 +118,10 @@
//#define FORCE_AFHDS2A_TUNING 0
//#define FORCE_BUGS_TUNING 0
//#define FORCE_FLYSKY_TUNING 0
//#define FORCE_FLYZONE_TUNING 0
//#define FORCE_HEIGHT_TUNING 0
//#define FORCE_HUBSAN_TUNING 0
//#define FORCE_KYOSHO_TUNING 0
//#define FORCE_PELIKAN_TUNING 0
/** CYRF6936 Fine Frequency Tuning **/
//This is required in rare cases where some CYRF6936 modules and/or RXs have an inaccurate crystal oscillator.
@@ -140,6 +148,7 @@
//If you have 2 Multi modules which you want to share the same ID so you can use either to control the same RC model
// then you can force the ID to a certain known value using the lines below.
//Default is commented, you should uncoment only for test purpose or if you know exactly what you are doing!!!
//The 8 numbers below can be anything between 0...9 and A..F
//#define FORCE_GLOBAL_ID 0x12345678
//Protocols using the CYRF6936 (DSM, Devo, Walkera...) are using the CYRF ID instead which should prevent duplicated IDs.
@@ -158,15 +167,18 @@
//The protocols below need an A7105 to be installed
#define AFHDS2A_A7105_INO
#define AFHDS2A_RX_A7105_INO
#define AFHDS2A_RX_A7105_INO
#define BUGS_A7105_INO
#define FLYSKY_A7105_INO
#define FLYZONE_A7105_INO
#define HEIGHT_A7105_INO
#define HUBSAN_A7105_INO
#define KYOSHO_A7105_INO
#define PELIKAN_A7105_INO
//The protocols below need a CYRF6936 to be installed
#define DEVO_CYRF6936_INO
#define DSM_CYRF6936_INO
#define DSM_RX_CYRF6936_INO
#define J6PRO_CYRF6936_INO
#define TRAXXAS_CYRF6936_INO
#define WFLY_CYRF6936_INO
@@ -174,6 +186,8 @@
//The protocols below need a CC2500 to be installed
#define CORONA_CC2500_INO
#define ESKY150V2_CC2500_INO //Need both CC2500 and NRF
#define FRSKYL_CC2500_INO
#define FRSKYD_CC2500_INO
#define FRSKYV_CC2500_INO
#define FRSKYX_CC2500_INO
@@ -182,7 +196,9 @@
#define HOTT_CC2500_INO
#define SCANNER_CC2500_INO
#define SFHSS_CC2500_INO
#define SKYARTEC_CC2500_INO
#define REDPINE_CC2500_INO
#define RLINK_CC2500_INO
//The protocols below need a NRF24L01 to be installed
#define ASSAN_NRF24L01_INO
@@ -205,33 +221,34 @@
#define HISKY_NRF24L01_INO
#define HONTAI_NRF24L01_INO
#define H8_3D_NRF24L01_INO
#define JJRC345_NRF24L01_INO
#define KF606_NRF24L01_INO
#define KN_NRF24L01_INO
#define MJXQ_NRF24L01_INO
#define MT99XX_NRF24L01_INO
#define NCC1701_NRF24L01_INO
#define POTENSIC_NRF24L01_INO
#define PROPEL_NRF24L01_INO
#define Q303_NRF24L01_INO
#define Q90C_NRF24L01_INO
#define SHENQI_NRF24L01_INO
#define SLT_NRF24L01_INO
#define SYMAX_NRF24L01_INO
#define TIGER_NRF24L01_INO
#define V2X2_NRF24L01_INO
#define V761_NRF24L01_INO
#define V911S_NRF24L01_INO
#define XK_NRF24L01_INO
#define YD717_NRF24L01_INO
#define ZSX_NRF24L01_INO
//The protocols below need a SX1276 to be installed
#define FRSKYR9_SX1276_INO
/***************************/
/*** PROTOCOLS SETTINGS ***/
/***************************/
//FrSkyX specific setting
//-----------------------
//EU LBT setting: if commented the TX will not check if a channel is busy before transmitting.
//!!! Work in progress !!! it's currently known to cause telemerty issues. Enable only if you know what you are doing.
//#define FRSKYX_LBT
//DSM specific settings
//---------------------
//The DSM protocol is using by default the Spektrum throw of 1100..1900us @100% and 1000..2000us @125%.
@@ -240,7 +257,7 @@
//Some models (X-Vert, Blade 230S...) require a special value to instant stop the motor(s).
// You can disable this feature by adding "//" on the line below. You have to specify which channel (14 by default) will be used to kill the throttle channel.
// If the channel 14 is above -50% the throttle is untouched but if it is between -50% and -100%, the throttle output will be forced between -100% and -150%.
// For example, a value of -80% applied on channel 15 will instantly kill the motors on the X-Vert.
// For example, a value of -80% applied on channel 14 will instantly kill the motors on the X-Vert.
#define DSM_THROTTLE_KILL_CH 14
//AFHDS2A specific settings
@@ -248,7 +265,6 @@
//When enabled (remove the "//"), the below setting makes LQI (Link Quality Indicator) available on one of the RX ouput channel (5-14).
//#define AFHDS2A_LQI_CH 14
/**************************/
/*** FAILSAFE SETTINGS ***/
/**************************/
@@ -294,9 +310,12 @@
#define HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define BAYANG_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define BUGS_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define DEVO_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define HUBSAN_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define NCC1701_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define PROPEL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define CABELL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define RLINK_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define HITEC_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to the radios which can decode it like er9x, erskyTX and OpenTX
#define HITEC_FW_TELEMETRY // Forward received telemetry packets to be decoded by erskyTX and OpenTX
#define SCANNER_TELEMETRY // Forward spectrum scanner data to TX
@@ -491,6 +510,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
PPM_IBUS
PWM_SBUS
PPM_SBUS
PWM_IB16
PPM_IB16
PROTO_AFHDS2A_RX
NONE
PROTO_ASSAN
@@ -501,6 +522,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
X16_AH
IRDRONE
DHD_D4
QX100
PROTO_BAYANG_RX
NONE
PROTO_BUGS
@@ -538,27 +560,46 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
DSM2_11
DSMX_22
DSMX_11
PROTO_DSM_RX
NONE
PROTO_E01X
E012
E015
E016H
PROTO_ESKY
NONE
ESKY_STD
ESKY_ET4
PROTO_ESKY150
ESKY150_4CH
ESKY150_7CH
PROTO_ESKY150V2
NONE
PROTO_FLYSKY
Flysky
V9X9
V6X6
V912
CX20
PROTO_FLYZONE
FZ410
PROTO_FQ777
NONE
PROTO_FRSKY_RX
FRSKY_RX
FRSKY_CLONE
PROTO_FRSKYD
NONE
FRSKYD
DCLONE
PROTO_FRSKYL
LR12
LR12_6CH
PROTO_FRSKYR9
R9_915
R9_868
R9_915_8CH
R9_868_8CH
R9_FCC
R9_EU
R9_FCC_8CH
R9_EU_8CH
PROTO_FRSKYV
NONE
PROTO_FRSKYX
@@ -566,8 +607,17 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
CH_8
EU_16
EU_8
XCLONE_16
XCLONE_8
PROTO_FRSKYX2
CH_16
CH_8
EU_16
EU_8
XCLONE
PROTO_FRSKY_RX
NONE
FRSKY_RX
FRSKY_CLONE
PROTO_FX816
NONE
PROTO_FY326
@@ -583,6 +633,9 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
H20H
H20MINI
H30MINI
PROTO_HEIGHT
HEIGHT_5CH
HEIGHT_8CH
PROTO_HISKY
Hisky
HK310
@@ -596,18 +649,23 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
X5C1
FQ777_951
PROTO_HOTT
NONE
HOTT_SYNC
HOTT_NO_SYNC
PROTO_HUBSAN
H107
H301
H501
PROTO_J6PRO
NONE
PROTO_JJRC345
NONE
PROTO_KF606
NONE
PROTO_KN
WLTOYS
FEILUN
PROTO_KYOSHO
NONE
PROTO_MJXQ
WLH08
X600
@@ -624,8 +682,13 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
FY805
PROTO_NCC1701
NONE
PROTO_PELIKAN
PELIKAN_PRO
PELIKAN_LITE
PROTO_POTENSIC
NONE
PROTO_PROPEL
NONE
PROTO_Q2X2
Q222
Q242
@@ -635,15 +698,21 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
CX35
CX10D
CX10WD
PROTO_Q90C
NONE
PROTO_REDPINE
RED_FAST
RED_SLOW
PROTO_RLINK
NONE
PROTO_SCANNER
NONE
PROTO_SFHSS
NONE
PROTO_SHENQI
NONE
PROTO_SKYARTEC
NONE
PROTO_SLT
SLT_V1
SLT_V2
@@ -653,15 +722,20 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
PROTO_SYMAX
SYMAX
SYMAX5C
PROTO_TIGER
NONE
PROTO_TRAXXAS
RX6519
PROTO_V2X2
V2X2
JXD506
V2X2_MR101
PROTO_V761
NONE
V761_3CH
V761_4CH
PROTO_V911S
NONE
V911S_STD
V911S_E119
PROTO_WFLY
NONE
PROTO_WK2x01
@@ -671,6 +745,9 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
W6_6_1
W6_HEL
W6_HEL_I
PROTO_XK
X450
X420
PROTO_YD717
YD717
SKYWLKR
@@ -680,3 +757,29 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
PROTO_ZSX
NONE
*/
/**********************************/
/*** DIRECT INPUTS SETTINGS ***/
/**********************************/
//In this section you can configure the direct inputs.
//It enables switches wired directly to the board
//Direct inputs works only in ppm mode and only for stm_32 boards
//Uncomment following lines to enable derect inputs or define your own configuration in _MyConfig.h
/*
#define ENABLE_DIRECT_INPUTS
#define DI1_PIN PC13
#define IS_DI1_on (digitalRead(DI1_PIN)==LOW)
#define DI2_PIN PC14
#define IS_DI2_on (digitalRead(DI2_PIN)==LOW)
#define DI3_PIN PC15
#define IS_DI3_on (digitalRead(DI3_PIN)==LOW)
//Define up to 4 direct input channels
//CHANNEL1 - 2pos switch
#define DI_CH1_read IS_DI1_on ? PPM_MAX_100*2 : PPM_MIN_100*2
//CHANNEL2 - 3pos switch
#define DI_CH2_read IS_DI2_on ? PPM_MAX_100*2 : (IS_DI2_on ? PPM_MAX_100 + PPM_MIN_100 : PPM_MIN_100*2)
*/

View File

@@ -0,0 +1,34 @@
#ifndef _IFACE_NRF250K_H_
#define _IFACE_NRF250K_H_
#if defined (CC2500_INSTALLED)
#include "iface_cc2500.h"
#endif
#if defined (NRF24L01_INSTALLED)
#include "iface_nrf24l01.h"
#endif
//XN297L
static void __attribute__((unused)) XN297L_Init();
static void __attribute__((unused)) XN297L_SetTXAddr(const uint8_t*, uint8_t);
static void __attribute__((unused)) XN297L_WritePayload(uint8_t*, uint8_t);
static void __attribute__((unused)) XN297L_WriteEnhancedPayload(uint8_t*, uint8_t, uint8_t);
static void __attribute__((unused)) XN297L_HoppingCalib(__attribute__((unused)) uint8_t);
static void __attribute__((unused)) XN297L_Hopping(uint8_t);
static void __attribute__((unused)) XN297L_RFChannel(uint8_t);
static void __attribute__((unused)) XN297L_SetPower();
static void __attribute__((unused)) XN297L_SetFreqOffset();
//NRF250K
#define NRF250K_Init() XN297L_Init()
#define NRF250K_HoppingCalib(X) XN297L_HoppingCalib(X)
#define NRF250K_Hopping(X) XN297L_Hopping(X)
#define NRF250K_RFChannel(X) XN297L_RFChannel(X)
#define NRF250K_SetPower() XN297L_SetPower()
#define NRF250K_SetFreqOffset() XN297L_SetFreqOffset()
static void __attribute__((unused)) NRF250K_SetTXAddr(uint8_t*, uint8_t);
static void __attribute__((unused)) NRF250K_WritePayload(uint8_t*, uint8_t);
static boolean __attribute__((unused)) NRF250K_IsPacketSent();
#endif

View 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/>.
*/
#ifndef _IFACE_SX1276_H_
#define _IFACE_SX1276_H_
enum
{
SX1276_00_FIFO = 0x00,
SX1276_01_OPMODE = 0x01,
SX1276_06_FRFMSB = 0x06,
SX1276_09_PACONFIG = 0x09,
SX1276_0B_OCP = 0x0B,
SX1276_0C_LNA = 0x0C,
SX1276_0D_FIFOADDRPTR = 0x0D,
SX1276_0E_FIFOTXBASEADDR = 0x0E,
SX1276_11_IRQFLAGSMASK = 0x11,
SX1276_12_REGIRQFLAGS = 0x12,
SX1276_13_REGRXNBBYTES = 0x13,
SX1276_19_PACKETSNR = 0x19,
SX1276_1A_PACKETRSSI = 0x1A,
SX1276_1D_MODEMCONFIG1 = 0x1D,
SX1276_1E_MODEMCONFIG2 = 0x1E,
SX1276_20_PREAMBLEMSB = 0x20,
SX1276_22_PAYLOAD_LENGTH = 0x22,
SX1276_24_HOPPERIOD = 0x24,
SX1276_26_MODEMCONFIG3 = 0x26,
SX1276_31_DETECTOPTIMIZE = 0x31,
SX1276_37_DETECTIONTHRESHOLD = 0x37,
SX1276_40_DIOMAPPING1 = 0x40,
SX1276_42_VERSION = 0x42,
SX1276_4D_PADAC = 0x4D
};
enum
{
SX1276_REGIRQFLAGS_CADDETECTED = 0,
SX1276_REGIRQFLAGS_FHSSCHANGECHANNEL = 1,
SX1276_REGIRQFLAGS_CADDONE = 2,
SX1276_REGIRQFLAGS_TXDONE = 3,
SX1276_REGIRQFLAGS_VALIDHEADER = 4,
SX1276_REGIRQFLAGS_PAYLOADCRCERROR = 5,
SX1276_REGIRQFLAGS_RXDONE = 6,
SX1276_REGIRQFLAGS_RXTIMEOUT = 7,
};
enum
{
SX1276_36_LORA_REGHIGHBWOPTIMIZE1 = 0x36,
SX1276_3A_LORA_REGHIGHBWOPTIMIZE2 = 0x3A
};
enum
{
SX1276_OPMODE_SLEEP = 0,
SX1276_OPMODE_STDBY,
SX1276_OPMODE_FSTX,
SX1276_OPMODE_TX,
SX1276_OPMODE_FSRX,
SX1276_OPMODE_RXCONTINUOUS,
SX1276_OPMODE_RXSINGLE,
SX1276_OPMODE_CAD
};
enum
{
SX1276_DETECT_OPTIMIZE_SF7_TO_SF12 = 0x03,
SX1276_DETECT_OPTIMIZE_SF6 = 0x05
};
enum
{
SX1276_MODEM_CONFIG1_BW_7_8KHZ = 0,
SX1276_MODEM_CONFIG1_BW_10_4KHZ,
SX1276_MODEM_CONFIG1_BW_15_6KHZ,
SX1276_MODEM_CONFIG1_BW_20_8KHZ,
SX1276_MODEM_CONFIG1_BW_31_25KHZ,
SX1276_MODEM_CONFIG1_BW_41_7KHZ,
SX1276_MODEM_CONFIG1_BW_62_5KHZ,
SX1276_MODEM_CONFIG1_BW_125KHZ,
SX1276_MODEM_CONFIG1_BW_250KHZ,
SX1276_MODEM_CONFIG1_BW_500KHZ
};
enum
{
SX1276_MODEM_CONFIG1_CODING_RATE_4_5 = 1,
SX1276_MODEM_CONFIG1_CODING_RATE_4_6,
SX1276_MODEM_CONFIG1_CODING_RATE_4_7,
SX1276_MODEM_CONFIG1_CODING_RATE_4_8
};
enum
{
SX1276_MODEM_DETECTION_THRESHOLD_SF7_TO_SF12 = 0x0A,
SX1276_MODEM_DETECTION_THRESHOLD_SF6 = 0x0C,
};
#endif

View File

@@ -1,20 +0,0 @@
#ifndef _IFACE_XN297L_H_
#define _IFACE_XN297L_H_
#if defined (XN297L_CC2500_EMU)
#include "iface_cc2500.h"
#elif defined (NRF24L01_INSTALLED)
#include "iface_nrf24l01.h"
#endif
static void __attribute__((unused)) XN297L_Init();
static void __attribute__((unused)) XN297L_SetTXAddr(const uint8_t*, uint8_t);
static void __attribute__((unused)) XN297L_WritePayload(uint8_t*, uint8_t);
static void __attribute__((unused)) XN297L_HoppingCalib(__attribute__((unused)) uint8_t);
static void __attribute__((unused)) XN297L_Hopping(uint8_t);
static void __attribute__((unused)) XN297L_RFChannel(uint8_t);
static void __attribute__((unused)) XN297L_SetPower();
static void __attribute__((unused)) XN297L_SetFreqOffset();
#endif

View File

@@ -6,24 +6,20 @@ Here are detailed descriptions of every supported protocols (sorted by RF module
The Deviation project (on which this project was based) have a useful list of models and protocols [here](http://www.deviationtx.com/wiki/supported_models).
## Useful notes and definitions
- **Extended limits supported** - A command range of -125%..+125% will be transmitted. Otherwise the default is -100%..+100% only.
- **Channel Order** - The channel order assumed in all the documentation is AETR. You can change this in the compilation settings. The module will take whatever input channel order and will rearrange them to match the output channel order required by the selected protocol.
- **Channel Order** - The channel order assumed in all the documentation is AETR. You can change this in the compilation settings or by using a precompiled firmware. The module will take whatever input channel order you have choosen and will rearrange them to match the output channel order required by the selected protocol.
- **Channel ranges** - A radio output of -100%..0%..+100% will match on the selected protocol -100%,0%,+100%. No convertion needs to be done.
- **Extended limits supported** - A channel range of -125%..+125% will be transmitted. Otherwise it will be truncated to -100%..+100%.
- **Italic numbers** are referring to protocol/sub_protocol numbers that you should use if the radio (serial mode only) is not displaying (yet) the protocol you want to access.
- **Autobind protocol**:
- **Autobind protocol** - The transmitter will automatically initiate a bind sequence on power up or model/protocol selection. This is for models where the receiver expects to rebind every time it is powered up. In these protocols you do not need to press the bind button at power up to bind, it will be done automatically. In case a protocol is not autobind but you want to enable it, change the "Autobind" or "Bind on channel" on OpenTX setting to Y for the specific model/entry.
1. The transmitter will automatically initiate a bind sequence on power up. This is for models where the receiver expects to rebind every time it is powered up. In these protocols you do not need to press the bind button at power up to bind, it will be done automatically. In case a protocol is not autobind but you want to enable it, change the "Autobind" (or "Bind at powerup" on OpenTX) setting to Y for the specific model/entry.
2. Enable Bind from channel feature:
* Bind from channel can be globally enabled/disabled in _config.h using ENABLE_BIND_CH.
* Bind from channel can be locally enabled/disabled by setting Autobind to Y/N per model for serial or per dial switch number for ppm.
* Bind channel can be choosen on any channel between 5 and 16 using BIND_CH in _config.h. Default is 16.
* Bind will only happen if all these elements are happening at the same time:
- Autobind = Y
## Bind on channel feature
* Bind on channel can be globally enabled/disabled in _config.h using ENABLE_BIND_CH. Any channel between 5 and 16 can be used by configuring BIND_CH in _config.h. Default is 16.
* Bind on channel can be locally enabled/disabled by setting "Bind on channel" or "Autobind" per model for serial or per dial switch number for ppm.
* Once activated, any bind will only happen if all these elements are happening at the same time:
- Bind on channel = Y
- Throttle = LOW (<-95%)
- Bind channel is going from -100% to +100%
* Additional notes:
- **It's recommended to combine the bind switch with Throttle cut or throttle at -100% to drive the bind channel. This will prevent to launch a bind while flying** and enable you to use the bind switch for something else.
- Using channel 16 for the bind channel seems the most relevant as only one protocol so far is using 16 channels which is FrSkyX. But even on FrSkyX this feature won't have any impact since there is NO valid reason to have Autobind set to Y for such a protocol.
- Bind channel (16 by default) is going from -100% to +100%
- **It's recommended to combine the bind switch with Throttle cut or throttle at -100% to drive the bind channel. This will prevent to launch a bind while flying** and enable you to use the bind switch for something else.
## Protocol selection in PPM mode
The protocol selection is based on 2 parameters:
@@ -67,8 +63,8 @@ You've upgraded the module but the radio does not display the name of the protoc
Protocol Name|Protocol Number|Sub_Proto 0|Sub_Proto 1|Sub_Proto 2|Sub_Proto 3|Sub_Proto 4|Sub_Proto 5|Sub_Proto 6|Sub_Proto 7|RF Module|Emulation
---|---|---|---|---|---|---|---|---|---|---|---
[Assan](Protocols_Details.md#ASSAN---24)|24|ASSAN||||||||NRF24L01|
[Bayang](Protocols_Details.md#BAYANG---14)|14|Bayang|H8S3D|X16_AH|IRDRONE|DHD_D4||||NRF24L01|XN297
[Bayang RX](Protocols_Details.md#BAYANG-RX---59)|59|||||||||NRF24L01|XN297
[Bayang](Protocols_Details.md#BAYANG---14)|14|Bayang|H8S3D|X16_AH|IRDRONE|DHD_D4|QX100|||NRF24L01|XN297
[Bayang RX](Protocols_Details.md#BAYANG-RX---59)|59|RX||||||||NRF24L01|XN297
[Bugs](Protocols_Details.md#BUGS---41)|41|BUGS||||||||A7105|
[BugsMini](Protocols_Details.md#BUGSMINI---42)|42|BUGSMINI|BUGS3H|||||||NRF24L01|XN297
[Cabell](Protocols_Details.md#Cabell---34)|34|Cabell_V3|C_TELEM|-|-|-|-|F_SAFE|UNBIND|NRF24L01|
@@ -78,59 +74,86 @@ CFlie|38|CFlie||||||||NRF24L01|
[CX10](Protocols_Details.md#CX10---12)|12|GREEN|BLUE|DM007|-|J3015_1|J3015_2|MK33041||NRF24L01|XN297
[Devo](Protocols_Details.md#DEVO---7)|7|Devo|8CH|10CH|12CH|6CH|7CH|||CYRF6936|
[DM002](Protocols_Details.md#DM002---33)|33|DM002||||||||NRF24L01|XN297
[DSM](Protocols_Details.md#DSM---6)|6|DSM2-22|DSM2-11|DSMX-22|DSMX-11|AUTO||||CYRF6936|
[DSM](Protocols_Details.md#DSM---6)|6|DSM2_1F|DSM2_2F|DSMX_1F|DSMX_2F|AUTO||||CYRF6936|
[DSM_RX](Protocols_Details.md#DSM_RX---70)|70|RX||||||||CYRF6936|
[E01X](Protocols_Details.md#E01X---45)|45|E012|E015|E016H||||||NRF24L01|XN297/HS6200
[ESky](Protocols_Details.md#ESKY---16)|16|ESky||||||||NRF24L01|
[ESky](Protocols_Details.md#ESKY---16)|16|ESky|ET4|||||||NRF24L01|
[ESky150](Protocols_Details.md#ESKY150---35)|35|ESKY150||||||||NRF24L01|
[ESky150V2](Protocols_Details.md#ESKY150V2---69)|69|ESky150V2||||||||CC2500|NRF24L01
[Flysky](Protocols_Details.md#FLYSKY---1)|1|Flysky|V9x9|V6x6|V912|CX20||||A7105|
[Flysky AFHDS2A](Protocols_Details.md#FLYSKY-AFHDS2A---28)|28|PWM_IBUS|PPM_IBUS|PWM_SBUS|PPM_SBUS|||||A7105|
[Flysky AFHDS2A RX](Protocols_Details.md#FLYSKY-AFHDS2A-RX---56)|56|||||||||A7105|
[Flyzone](Protocols_Details.md#FLYZONE---53)|53|FZ410||||||||A7105|
[Flysky AFHDS2A](Protocols_Details.md#FLYSKY-AFHDS2A---28)|28|PWM_IBUS|PPM_IBUS|PWM_SBUS|PPM_SBUS|PWM_IBUS16|PPM_IBUS16|||A7105|
[Flysky AFHDS2A RX](Protocols_Details.md#FLYSKY-AFHDS2A-RX---56)|56|RX||||||||A7105|
[FQ777](Protocols_Details.md#FQ777---23)|23|FQ777||||||||NRF24L01|SSV7241
[FrskyD](Protocols_Details.md#FRSKYD---3)|3|FrskyD||||||||CC2500|
[FrskyD](Protocols_Details.md#FRSKYD---3)|3|D8|Cloned|||||||CC2500|
[FrskyL](Protocols_Details.md#FRSKYL---67)|67|LR12|LR12 6CH|||||||CC2500|
[FrskyR9](Protocols_Details.md#FRSKYR9---65)|65|FrskyR9|R9_915|R9_868||||||SX1276|
[FrskyV](Protocols_Details.md#FRSKYV---25)|25|FrskyV||||||||CC2500|
[FrskyX](Protocols_Details.md#FRSKYX---15)|15|CH_16|CH_8|EU_16|EU_8|||||CC2500|
[FrskyX_RX](Protocols_Details.md#FRSKYX_RX---55)|55|FCC|EU_LBT|||||CC2500|
[FrskyX](Protocols_Details.md#FRSKYX---15)|15|CH_16|CH_8|EU_16|EU_8|Cloned|Cloned_8|||CC2500|
[FrskyX2](Protocols_Details.md#FRSKYX2---64)|64|CH_16|CH_8|EU_16|EU_8|Cloned|Cloned_8|||CC2500|
[Frsky_RX](Protocols_Details.md#FRSKY_RX---55)|55|RX|CloneTX|||||||CC2500|
[FX816](Protocols_Details.md#FX816---58)|28|FX816|P38|||||||NRF24L01|
[FY326](Protocols_Details.md#FY326---20)|20|FY326|FY319|||||||NRF24L01|
[GD00X](Protocols_Details.md#GD00X---47)|47|GD_V1*|GD_V2*|||||||NRF24L01|
[GW008](Protocols_Details.md#GW008---32)|32|GW008||||||||NRF24L01|XN297
[H8_3D](Protocols_Details.md#H8_3D---36)|36|H8_3D|H20H|H20Mini|H30Mini|||||NRF24L01|XN297
[Height](Protocols_Details.md#HEIGHT---53)|53|5ch|8ch|||||||A7105|
[Hisky](Protocols_Details.md#HISKY---4)|4|Hisky|HK310|||||||NRF24L01|
[Hitec](Protocols_Details.md#HITEC---39)|39|OPT_FW|OPT_HUB|MINIMA||||||CC2500|
[Hontai](Protocols_Details.md#HONTAI---26)|26|HONTAI|JJRCX1|X5C1|FQ777_951|||||NRF24L01|XN297
[HoTT](Protocols_Details.md#HoTT---57)|57|||||||||CC2500|
[HoTT](Protocols_Details.md#HoTT---57)|57|Sync|No_Sync|||||||CC2500|
[Hubsan](Protocols_Details.md#HUBSAN---2)|2|H107|H301|H501||||||A7105|
[J6Pro](Protocols_Details.md#J6Pro---22)|22|J6PRO||||||||CYRF6936|
[J6Pro](Protocols_Details.md#J6Pro---22)|22|J6Pro||||||||CYRF6936|
[JJRC345](Protocols_Details.md#JJRC345---71)|71|JJRC345||||||||NRF24L01|XN297
[KF606](Protocols_Details.md#KF606---49)|49|KF606*||||||||NRF24L01|XN297
[KN](Protocols_Details.md#KN---9)|9|WLTOYS|FEILUN|||||||NRF24L01|
[Kyosho](Protocols_Details.md#Kyosho---73)|73|||||||||A7105|
[MJXq](Protocols_Details.md#MJXQ---18)|18|WLH08|X600|X800|H26D|E010*|H26WH|PHOENIX*||NRF24L01|XN297
[MT99xx](Protocols_Details.md#MT99XX---17)|17|MT|H7|YZ|LS|FY805||||NRF24L01|XN297
[NCC1701](Protocols_Details.md#NCC1701---44)|44|NCC1701||||||||NRF24L01|
[OpenLRS](Protocols_Details.md#OpenLRS---27)|27|||||||||None|
[Pelikan](Protocols_Details.md#Pelikan---60)|60|Pro|Lite|||||||A7105|
[Potensic](Protocols_Details.md#Potensic---51)|51|A20||||||||NRF24L01|XN297
[PROPEL](Protocols_Details.md#PROPEL---66)|66|74-Z||||||||NRF24L01|
[Q2X2](Protocols_Details.md#Q2X2---29)|29|Q222|Q242|Q282||||||NRF24L01|
[Q303](Protocols_Details.md#Q303---31)|31|Q303|CX35|CX10D|CX10WD|||||NRF24L01|XN297
[Q90C](Protocols_Details.md#Q90C---72)|72|Q90C*||||||||NRF24L01|XN297
[RadioLink](Protocols_Details.md#RadioLink---74)|74|Surface|Air|||||||CC2500|
[Redpine](Protocols_Details.md#Redpine---50)|50|FAST|SLOW|||||||NRF24L01|
[Scanner](Protocols_Details.md#Scanner---54)|54|||||||||CC2500|
[SFHSS](Protocols_Details.md#SFHSS---21)|21|SFHSS||||||||CC2500|
[Shenqi](Protocols_Details.md#Shenqi---19)|19|Shenqi||||||||NRF24L01|LT8900
[SLT](Protocols_Details.md#SLT---11)|11|SLT_V1|SLT_V2|Q100|Q200|MR100||||NRF24L01|
[Skyartec](Protocols_Details.md#Skyartec---68)|68|Skyartec||||||||CC2500|CC2500
[SLT](Protocols_Details.md#SLT---11)|11|SLT_V1|SLT_V2|Q100|Q200|MR100||||NRF24L01|CC2500
[SymaX](Protocols_Details.md#Symax---10)|10|SYMAX|SYMAX5C|||||||NRF24L01|
[Traxxas](Protocols_Details.md#Traxxas---43)|43|RX6519||||||||CYRF6936|
[V2x2](Protocols_Details.md#V2X2---5)|5|V2x2|JXD506|||||||NRF24L01|
[Tiger](Protocols_Details.md#Tiger---61)|61|Tiger||||||||NRF24L01|XN297
[Traxxas](Protocols_Details.md#Traxxas---43)|43|6519 RX||||||||CYRF6936|
[V2x2](Protocols_Details.md#V2X2---5)|5|V2x2|JXD506|MR101||||||NRF24L01|
[V761](Protocols_Details.md#V761---48)|48|V761||||||||NRF24L01|XN297
[V911S](Protocols_Details.md#V911S---46)|46|V911S*||||||||NRF24L01|XN297
[V911S](Protocols_Details.md#V911S---46)|46|V911S*|E119*|||||||NRF24L01|XN297
[WFly](Protocols_Details.md#WFLY---40)|40|WFLY||||||||CYRF6936|
[WK2x01](Protocols_Details.md#WK2X01---30)|30|WK2801|WK2401|W6_5_1|W6_6_1|W6_HEL|W6_HEL_I|||CYRF6936|
[XK](Protocols_Details.md#XK---62)|62|X450|X420|||||||NRF24L01|XN297
[YD717](Protocols_Details.md#YD717---8)|8|YD717|SKYWLKR|SYMAX4|XINXUN|NIHUI||||NRF24L01|
[ZSX](Protocols_Details.md#ZSX---52)|52|280||||||||NRF24L01|XN297
* "*" Sub Protocols designated by * suffix will use the NRF24L01 module by default to emulate the XN297L RF chip. If a CC2500 module is installed it will be used instead as it is proving to be a better option for the XN297L@250kbps. Each specific sub protocol has a more detailed explanation.
* "*" Sub Protocols designated by * suffix are using a XN297L@250kbps which will be emulated by default with the NRF24L01. If option (freq tune) is diffrent from 0, the CC2500 module (if installed) will be used instead. Each specific sub protocol has a more detailed explanation.
# A7105 RF Module
If USE_A7105_CH15_TUNING is enabled, the value of channel 15 is used by all A7105 protocols for tuning the frequency. This is required in rare cases where some A7105 modules and/or RXs have an inaccurate crystal oscillator.
## BUGS - *41*
Models: MJX Bugs 3, 6 and 8
Telemetry enabled for RX & TX RSSI, Battery voltage good/bad
**RX_Num is used to give a number to a given model. You must use a different RX_Num per MJX Bugs. A maximum of 16 Bugs are supported.**
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|---
A|E|T|R|ARM|ANGLE|FLIP|PICTURE|VIDEO|LED
ANGLE: angle is +100%, acro is -100%
## FLYSKY - *1*
Extended limits supported
@@ -169,15 +192,12 @@ Extended limits and failsafe supported
Telemetry enabled protocol:
- by defaut using FrSky Hub protocol (for example er9x): RX(A1), battery voltage FS-CVT01(A2) and RX&TX RSSI
- if using erskyTX and OpenTX: full telemetry information available
- if telemetry is incomplete (missing RX RSSI for example), it means that you have to upgrade your RX firmware to version 1.6 or later. You can do it from an original Flysky TX or using a STLink like explained in [this tutorial](https://www.rcgroups.com/forums/showthread.php?2677694-How-to-upgrade-Flysky-Turnigy-iA6B-RX-to-firmware-1-6-with-a-ST-Link).
Option is used to change the servo refresh rate. A value of 0 gives 50Hz (min), 70 gives 400Hz (max). Specific refresh rate value can be calculated like this option=(refresh_rate-50)/5.
**RX_Num is used to give a number a given RX. You must use a different RX_Num per RX. A maximum of 64 AFHDS2A RXs are supported.**
OpenTX suggested RSSI alarm threshold settings (Telemetry tab): Low=15, Critical=12.
If telemetry is incomplete (missing RX RSSI for example), it means that you have to upgrade your RX firmware to version 1.6 or later. You can do it from an original Flysky TX or using a STLink like explained in [this tutorial](https://www.rcgroups.com/forums/showthread.php?2677694-How-to-upgrade-Flysky-Turnigy-iA6B-RX-to-firmware-1-6-with-a-ST-Link).
AFHDS2A_LQI_CH is a feature which is disabled by defaut in the _config.h file. When enabled, it makes LQI (Link Quality Indicator) available on one of the RX ouput channel (5-14).
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14
@@ -190,6 +210,25 @@ Note that the RX ouput will be AETR whatever the input channel order is.
### Sub_protocol PPM_IBUS - *1*
### Sub_protocol PWM_SBUS - *2*
### Sub_protocol PPM_SBUS - *3*
### Sub_protocol PWM_IBUS16 - *4*
3 additional channels. Need recent or updated RXs.
CH15|CH16|CH17
---|---|---
CH15|CH16|LQI
LQI: Link Quality Indicator
### Sub_protocol PPM_IBUS16 - *5*
3 additional channels. Need recent or updated RXs.
CH15|CH16|CH17
---|---|---
CH15|CH16|LQI
LQI: Link Quality Indicator
## FLYSKY AFHDS2A RX - *56*
The Flysky AFHDS2A receiver protocol enables master/slave trainning, separate access from 2 different radios to the same model,...
@@ -200,14 +239,21 @@ Extended limits supported
Low power: enable/disable the LNA stage on the RF component to use depending on the distance with the TX.
## FLYZONE - *53*
Models using the Flyzone FZ-410 TX: Fokker D.VII Micro EP RTF
## HEIGHT - *53*
Models using the old ARES TX (prior to Hitec RED): Tiger Moth, eRC Micro Stik
### Sub_protocol 5CH - *0*
Models from Height, Flyzone, Rage R/C, eRC and the old ARES (prior to Hitec RED).
CH1|CH2|CH3|CH4
---|---|---|---
A|E|T|R
CH1|CH2|CH3|CH4|CH5
---|---|---|---|---
A|E|T|R|Gear
### Sub_protocol 8CH - *1*
Models from Height and Rage R/C.
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
A|E|T|R|Gear|Gyro|Flap|Light
## HUBSAN - *2*
@@ -242,18 +288,29 @@ H122D: FLIP
H123D: FMODES -> -100%=Sport mode 1,0%=Sport mode 2,+100%=Acro
## BUGS - *41*
Models: MJX Bugs 3, 6 and 8
## Kyosho - *73*
Surface protocol called FHSS introduced in 2017. Transmitters: KT-531P, KT-431PT, Flysky Noble NB4 (fw>2.0.67)...
Telemetry enabled for RX & TX RSSI, Battery voltage good/bad
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14
---|---|---|---|---|---|---|---|---|----|----|----|----|----
STEERING|THROTTLE|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14
**RX_Num is used to give a number to a given model. You must use a different RX_Num per MJX Bugs. A maximum of 16 Bugs are supported.**
## Pelikan - *60*
Extended limits supported
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|---
A|E|T|R|ARM|ANGLE|FLIP|PICTURE|VIDEO|LED
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
A|E|T|R|CH5|CH6|CH7|CH8
ANGLE: angle is +100%, acro is -100%
RX output will match the Pelikan standard AETR independently of the input configuration AETR, RETA... unless on OpenTX 2.3.3+ you use the "Disable channel mapping" feature on the GUI.
### Sub_protocol Pro - *0*
Models: TX: CADET PRO V4, RX: RX-602 V4
### Sub_protocol Lite - *1*
Models: TX: CADET 4 LITE
**Only 1 frequency hopping table**
***
# CC2500 RF Module
@@ -307,7 +364,7 @@ Models: FrSky receivers D4R and D8R. DIY RX-F801 and RX-F802 receivers. Also kno
Extended limits supported
Telemetry enabled for A0, A1, RSSI, TSSI and Hub
Telemetry enabled for A0, A1, RSSI, TX_RSSI, TX_LQI and Hub. Lowest the TX_LQI value is best the quality link is, it's a good indicator of how well the module is tuned.
Option for this protocol corresponds to fine frequency tuning. This value is different for each Module and **must** be accurate otherwise the link will not be stable.
Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it.
@@ -316,12 +373,42 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
### Sub_protocol D8 - *0*
Use the internal multi module Identifier.
### Sub_protocol Cloned - *1*
Use the identifier learnt from another FrSky radio when binding with the FrSkyRX/CloneTX mode.
RX number can't be used anymore and is ignored.
## FRSKYL - *67*
Models: FrSky receivers L9R. Also known as LR12.
Extended limits supported
Option for this protocol corresponds to fine frequency tuning. This value is different for each Module and **must** be accurate otherwise the link will not be stable.
Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it.
### Sub_protocol LR12 - *0*
Refresh rate: 36ms
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
---|---|---|---|---|---|---|---|---|----|----|----
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
### Sub_protocol LR12 6ch - *1*
Refresh rate: 18ms
CH1|CH2|CH3|CH4|CH5|CH6
---|---|---|---|---|---
CH1|CH2|CH3|CH4|CH5|CH6
## FRSKYX - *15*
Models: FrSky receivers X4R, X6R and X8R. Also known as D16.
Models: FrSky v1.xxx receivers X4R, X6R and X8R. Protocol also known as D16 v1 FCC/LBT.
Extended limits and failsafe supported
Telemetry enabled for A1 (RxBatt), A2, RSSI, TSSI and Hub
Telemetry enabled for A1 (RxBatt), A2, RSSI, TX_RSSI, TX_LQI and Hub. Lowest the TX_LQI value is best the quality link is, it's a good indicator of how well the module is tuned.
Option for this protocol corresponds to fine frequency tuning. This value is different for each Module and **must** be accurate otherwise the link will not be stable.
Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it.
@@ -341,26 +428,45 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
### Sub_protocol EU_16 - *2*
EU-LBT protocol 16 channels @18ms. Note that the LBT part is not implemented, the TX transmits right away.
EU-LBT protocol 16 channels @18ms.
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|----
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
### Sub_protocol EU_8 - *3*
EU-LBT protocol 8 channels @9ms. Note that the LBT part is not implemented, the TX transmits right away.
EU-LBT protocol 8 channels @9ms.
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
## FRSKYX_RX - *55*
The FrSkyX receiver protocol enables master/slave trainning, separate access from 2 different radios to the same model,...
### Sub_protocol Cloned - *4*
Use the identifier learnt from another FrSky radio when binding with the FrSkyRX/CloneTX mode.
16 channels.
### Sub_protocol Cloned_8 - *5*
Use the identifier learnt from another FrSky radio when binding with the FrSkyRX/CloneTX mode.
8 channels.
## FRSKYX2 - *64*
Same as [FrskyX](Protocols_Details.md#FRSKYX---15) but for D16 v2.1.0 FCC/LBT.
## FRSKY_RX - *55*
### Sub_protocol RX - *0*
The FrSky receiver protocol enables master/slave trainning, separate access from 2 different radios to the same model,...
Auto detection of the protocol used by a TX transmitting FrSkyD/D8, FrSkyX/D16 v1.xxx FCC/LBT or FrSkyX/D16 v2.1.0 FCC/LBT at bind time.
Available in OpenTX 2.3.3, Trainer Mode Master/Multi
Extended limits supported
For **FrSkyX, RX num must match on the master and slave**. This enables a multi student configuration for example.
Option for this protocol corresponds to fine frequency tuning.
If the value is equal to 0, the RX will auto tune otherwise it will use the indicated value.
This value is different for each Module and **must** be accurate otherwise the link will not be stable.
@@ -368,19 +474,25 @@ Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it.
Low power: enable/disable the LNA stage on the RF component to use depending on the distance with the TX.
### Sub_protocol FCC - *0*
FCC protocol 8 or 16 channels.
### Sub_protocol CloneTX - *1*
This subprotocol makes a clone of a TX identifier transmitting FrSkyD/D8, FrSkyX/D16 v1.xxx FCC/LBT and FrSkyX/D16 v2.1.0 FCC/LBT.
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|----
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
There are 3 slots available, 1 slot for D8 cloning, 1 slot for FrSkyX (D16v1) cloning and 1 slot for FrSkyX2 (D16v2.1.0) cloning.
The same TX or different TXs can be used for each slot but a maximum of 1 per slot.
If you launch the FrSky_RX/CloneTX protocol and do a bind with a TX transmitting with the D8 protocol, it will be saved in the slot D8. Same for D16v1 and D16v2.1 .
Then the system will alow you to enable cloning as you wish for each model using the FrSkyD/X/X2 "Cloned" subprotocol. This way you can have models working with the original MPM indentifier and models which are shared by both the cloned TX and MPM.
### Sub_protocol EU_LBT - *1*
EU_LBT protocol 8 or 16 channels.
Clone mode operation:
- Select the FrSky_RX protocol, subprotocol CloneTX
- Select on the TX to be cloned the protocol you want to clone the identifier from: FrSkyD/D8 or FrSkyX/D16 v1.xxx FCC/LBT or FrSkyX/D16 v2.1.0 FCC/LBT
- Place both the TX and MPM in bind mode
- Wait for the bind to complete
- To use the cloned TX identifier, open a new model select the protocol you just cloned/binded and select the subprotocol "Cloned"
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|----
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
Notes:
- OpenTX 2.3.8 N184 (nightly) or later is needed to have access to the "D8Cloned" and "D16Cloned" subprotocols, D16v2.1 "Cloned" is available under FrSkyX2/Cloned.
- For FrSkyD, only the RX number used during bind is cloned -> you can't use RX num anymore
- For FrSkyX and FrSkyX2, RX number has to be adjusted on each model to match the original TX model
## HITEC - *39*
Models: OPTIMA, MINIMA and MICRO receivers.
@@ -397,30 +509,32 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
### Sub_protocol OPT_FW - *0*
OPTIMA RXs
Full telemetry available on OpenTX 2.3.3+, still in progress for erskyTx.
Full telemetry available on OpenTX 2.3.3+, still in progress for erskyTx. Lowest the TX_LQI value is best the quality link is, it's a good indicator of how well the module is tuned.
**The TX must be close to the RX for the bind negotiation to complete successfully**
### Sub_protocol OPT_HUB - *1*
OPTIMA RXs
Basic telemetry using FrSky Hub on er9x, erskyTX, OpenTX and any radio with FrSky telemetry support with RX voltage, VOLT2 voltage, TX RSSI and TX LQI.
Basic telemetry using FrSky Hub on er9x, erskyTX, OpenTX and any radio with FrSky telemetry support with RX voltage, VOLT2 voltage, TX_RSSI and TX_LQI. Lowest the TX_LQI value is best the quality link is, it's a good indicator of how well the module is tuned.
**The TX must be close to the RX for the bind negotiation to complete successfully**
### Sub_protocol MINIMA - *2*
MINIMA, MICRO and RED receivers
MINIMA, MICRO and RED receivers. Also used by ARES planes.
## HoTT - *57*
Models: Graupner HoTT receivers (tested on GR-12L and GR-16L).
Models: Graupner HoTT receivers (tested on GR-12, GR-12L, GR-16 and Vector).
Extended limits and failsafe supported
Extended limits, failsafe and LBT supported.
**RX_Num is used to give a number a given RX. You must use a different RX_Num per RX. A maximum of 64 HoTT RXs are supported.**
Full telemetry and full text config mode are available starting from OpenTX 2.3.8N226.
**RX_Num is used to give a number to a given RX. You must use a different RX_Num per RX. A maximum of 64 HoTT RXs are supported.**
**Failsafe MUST be configured once with the desired channel values (hold or position) while the RX is up (wait 10+sec for the RX to learn the config) and then failsafe MUST be set to RX/Receiver otherwise the servos will jitter!!!**
The RX features configuration are done using the OpenTX script "Graupner HoTT.lua" .
The RX and sensors/FC features configuration are done through the OpenTX script "Graupner HoTT.lua".
Option for this protocol corresponds to fine frequency tuning. This value is different for each Module and **must** be accurate otherwise the link will not be stable.
Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it.
@@ -429,13 +543,50 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
---|---|---|---|---|---|---|---|---|----|----|----
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
Basic telemetry is available on OpenTX 2.3.3+ with RX voltage, Rx temperature, RX RSSI, RX LQI, TX RSSI and TX LQI.
### Sub_protocol Sync - *0*
Recommended for best telemetry performance.
### Sub_protocol No_Sync - *1*
Telemetry compatibility mode when Sync does not work due to an old firmware on the RX.
You should definitively upgrade your receivers/sensors to the latest firmware versions: https://www.rcgroups.com/forums/showpost.php?p=44668015&postcount=18022
## Scanner - *54*
2.4GHz scanner accessible using the OpenTX 2.3 Spectrum Analyser tool.
## RadioLink - *74*
Extended limits
**64 IDs available, use RX num to scroll through them**
Option for this protocol corresponds to fine frequency tuning. This value is different for each Module and **must** be accurate otherwise the link will not be stable.
Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it.
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|FS_CH1|FS_CH2|FS_CH3|FS_CH4|FS_CH5|FS_CH6|FS_CH7|FS_CH8
FS=FailSafe
### Sub_protocol Surface - *0*
Surface protocol. TXs: RC4GS,RC6GS. Compatible RXs:R7FG(Std),R6FG,R6F,R8EF,R8FM,R8F,R4FGM,R4F and more
CH1=Steering, CH2=Throttle, CH8=Gyro gain
Telemetry: RX_RSSI (for the original value add -256), TX_RSSI, TX_QLY (0..100%), A1=RX_Batt, A2=Batt
### Sub_protocol Air - *1*
Air protocol. TXs: T8FB,T8S. Compatible RXs:R8EF,R8FM,R8SM,R4FG,R4F and more
Telemetry: RX_RSSI (for the original value add -256), TX_RSSI, TX_QLY (0..100%)
## SFHSS - *21*
Models: Futaba RXs and XK models.
Extended limits and failsafe supported
RX output will match the Futaba standard AETR independently of the input configuration AETR, RETA... unless on OpenTX 2.3.3+ you use the "Disable channel mapping" feature on the GUI.
Option for this protocol corresponds to fine frequency tuning. This value is different for each Module and **must** be accurate otherwise the link will not be stable.
Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it.
@@ -443,8 +594,14 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
A|E|T|R|CH5|CH6|CH7|CH8
## Scanner - *54*
2.4GHz scanner accessible using the OpenTX 2.3 Spectrum Analyser tool.
## Skyartec - *68*
Option for this protocol corresponds to fine frequency tuning. This value is different for each Module and **must** be accurate otherwise the link will not be stable.
Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it.
CH1|CH2|CH3|CH4|CH5|CH6|CH7
---|---|---|---|---|---|---
A|E|T|R|CH5|CH6|CH7
***
# CYRF6936 RF Module
@@ -458,7 +615,9 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
---|---|---|---|---|---|---|---|---|---|---|---
A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
Note that the RX ouput will be EATR.
RX output will match the Devo standard EATR independently of the input configuration AETR, RETA... unless on OpenTX 2.3.3+ you use the "Disable channel mapping" feature on the GUI.
Basic telemetry is available if RX supports it: TX_RSSI, A1 and A2
Bind procedure using serial:
- With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode.
@@ -560,33 +719,44 @@ Extended limits supported
Telemetry enabled for TSSI and plugins
option=number of channels from 4 to 12. An invalid option value will end up with 6 channels.
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|----|CH14
---|---|---|---|---|---|---|---|---|----|----|----|----|----
A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|----|TH_KILL
Notes:
- model/type/number of channels indicated on the RX can be different from what the RX is in fact wanting to see. So don't hesitate to test different combinations until you have something working. Using Auto is the best way to find these settings.
- RX output will match the Spektrum standard TAER independently of the input configuration AETR, RETA...
- The "AUTO" sub protocol is recommended to automatically select the best settings for your DSM RX. If the RX doesn't bind or work properly after bind, don't hesitate to test different combinations of sub protocol and number of channels until you have something working.
- Servo refresh rate is 22ms unless you select 11ms available in OpenTX 2.3.10+
- RX output will match the Spektrum standard TAER independently of the input configuration AETR, RETA... unless on OpenTX 2.3.3+ you use the "Disable channel mapping" feature on the GUI.
- RX output will match the Spektrum standard throw (1500µs +/- 400µs -> 1100..1900µs) for a 100% input. This is true for both Serial and PPM input. For PPM, make sure the end points PPM_MIN_100 and PPM_MAX_100 in _config.h are matching your TX ouput. The maximum ouput is 1000..2000µs based on an input of 125%.
- If you want to override the above and get maximum throw (old way) uncomment in _config.h the line #define DSM_MAX_THROW . In this mode to achieve standard throw use a channel weight of 84%.
- If you want to override the above and get maximum throw either uncomment in _config.h the line #define DSM_MAX_THROW or on OpenTX 2.3.3+ use the "Enable max throw" feature on the GUI (0=No,1=Yes). In this mode to achieve standard throw use a channel weight of 84%.
- TH_KILL is a feature which is enabled on channel 14 by default (can be disabled/changed) in the _config.h file. Some models (X-Vert, Blade 230S...) require a special position to instant stop the motor(s). If the channel 14 is above -50% the throttle is untouched but if it is between -50% and -100%, the throttle output will be forced between -100% and -150%. For example, a value of -80% applied on channel 14 will instantly kill the motors on the X-Vert.
- To allow SAFE to be ON with a switch assignment you must remove the bind plug after powering up the RX but before turning on the TX to bind. If you select Autodetect to bind, The MPM will choose DSMX 11ms and Channels 1-7 ( Change to 1-9 if you wish to assign switch above channel 7 ). Then in order to use the manuals diagram of both sticks "Down-Inside" to set a SAFE Select Switch Designation, you must have Throttle and Elevator channels set to Normal direction but the Aileron and Rudder set to Reverse direction. If setting up a new model with all channels set to Normal you can hold both sticks "Down- OUTSIDE" to assign the switch with 5x flips. Tested on a Mode2 radio.
Option=number of channels from 3 to 12. Option|0x80 enables Max Throw. Option|0x40 enables a servo refresh rate of 11ms.
### Sub_protocol DSM2_22 - *0*
DSM2, Resolution 1024, refresh rate 22ms
### Sub_protocol DSM2_11 - *1*
DSM2, Resolution 2048, refresh rate 11ms
### Sub_protocol DSMX_22 - *2*
DSMX, Resolution 2048, refresh rate 22ms
### Sub_protocol DSMX_11 - *3*
DSMX, Resolution 2048, refresh rate 11ms
### Sub_protocol DSM2_1F - *0*
DSM2, Resolution 1024, servo refresh rate can only be 22ms
### Sub_protocol DSM2_2F - *1*
DSM2, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
### Sub_protocol DSMX_1F - *2*
DSMX, Resolution 2048, servo refresh rate can only be 22ms
### Sub_protocol DSMX_2F - *3*
DSMX, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
### Sub_protocol AUTO - *4*
The "AUTO" feature enables the TX to automatically choose what are the best settings for your DSM RX and update your model protocol settings accordingly.
"AUTO" is recommended to automatically select the best settings for your DSM RX.
The current radio firmware which are able to use the "AUTO" feature are erskyTX (9XR Pro, 9Xtreme, Taranis, ...), er9x for M128(9XR)&M2561 and OpenTX (mostly Taranis).
For these firmwares, you must have a telemetry enabled TX and you have to make sure you set the Telemetry "Usr proto" to "DSMx".
Also on er9x you will need to be sure to match the polarity of the telemetry serial (normal or inverted by bitbashing), while on erskyTX you can set "Invert COM1" accordinlgy.
## DSM_RX - *70*
The DSM receiver protocol enables master/slave trainning, separate access from 2 different radios to the same model,...
Notes:
- Automatically detect DSM 2/X 11/22ms 1024/2048res
- Available in OpenTX 2.3.3+, Trainer Mode Master/Multi
- Channels 1..4 are remapped to the module default channel order unless on OpenTX 2.3.3+ you use the "Disable channel mapping" feature on the GUI.
- Extended limits supported
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
---|---|---|---|---|---|---|---|---|----|----|----
A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
## J6Pro - *22*
@@ -674,6 +844,9 @@ CH12|CH13
----|----
TAKE_OFF|EMG_STOP
### Sub_protocol QX100 - *5*
Model: REVELL QX100
## BAYANG RX - *59*
The Bayang receiver protocol enables master/slave trainning, separate access from 2 different radios to the same model,...
@@ -835,6 +1008,12 @@ CH1|CH2|CH3|CH4|CH5|CH6
---|---|---|---|---|---
A|E|T|R|GYRO|PITCH
### Sub_protocol Std - *0*
### Sub_protocol ET4 - *1*
Models compatible with the ET4 transmitter like ESky Big Lama
**Multiple IDs but only one frequency...**
## ESKY150 - *35*
ESky protocol for small models since 2014 (150, 300, 150X, ...)
@@ -852,6 +1031,19 @@ A|E|T|R|FMODE|AUX6|AUX7
FMODE and AUX7 have 4 positions: -100%..-50%=>0, -50%..5%=>1, 5%..50%=>2, 50%..100%=>3
## ESKY150V2 - *69*
ESky protocol for small models: 150 V2, F150 V2, Blade 70s
Notes:
- RX output will match the eSky standard TAER independently of the input configuration AETR, RETA... unless on OpenTX 2.3.3+ you use the "Disable channel mapping" feature on the GUI.
- To run this protocol you need both CC2500 and NRF24L01 to be enabled for code reasons, only the CC2500 is really used.
CH1|CH2|CH3|CH4|CH5 |CH6 |CH7 |CH8 |CH9 |CH10|CH11|CH12|CH13|CH14|CH15|CH16
---|---|---|---|----|----|----|----|----|----|----|----|----|----|----|----
A|E|T|R|CH5 |CH6 |CH7 |CH8 |CH9 |CH10|CH11|CH12|CH13|CH14|CH15|CH16
RATE for the F150 V2 is assigned to channel 5: -100%=low, 100%=high
## FX816 - *58*
Model: FEI XIONG FX816 P38
@@ -883,9 +1075,9 @@ A|E|T|R|FLIP|RTH|HEADLESS|EXPERT
## GD00X - *47*
Model: GD005 C-17 Transport, GD006 DA62 and ZC-Z50
If the model does not respond well to inputs or hard to bind, you can try to set Power to Low. But this protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components used and nothing we can do about it in the firmware.
This protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components.
If a CC2500 rf component is available it will be used in place of the NRF24L01 which might fix the issue mentioned above. Option is used for fine frequency tuning like any CC2500 protocols. Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it if necessary.
If the model does not respond well to inputs or hard to bind, you can try to switch the emulation from the default NRF24L01 RF component to the CC2500 by using an option value (freq tuning) different from 0. Option in this case is used for fine frequency tuning like any CC2500 protocols so check the [Frequency Tuning page](/docs/Frequency_Tuning.md).
CH1|CH2|CH3|CH4|CH5|CH6|CH7
---|---|---|---|---|---|---
@@ -983,12 +1175,19 @@ ARM|
### Sub_protocol FQ777_951 - *3*
## JJRC345 - *71*
Model: JJRC345
CH1|CH2|CH3|CH4|CH5|CH6|CH7
---|---|---|---|---|---|---
A|E|T|R|FLIP|HEADLESS|RTH
## KF606 - *49*
Model: KF606
If the model does not respond well to inputs or hard to bind, you can try to set Power to Low. But this protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components used and nothing we can do about it in the firmware.
This protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components.
If a CC2500 rf component is available it will be used in place of the NRF24L01 which might fix the issue mentioned above. Option is used for fine frequency tuning like any CC2500 protocols. Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it if necessary.
If the model does not respond well to inputs or hard to bind, you can try to switch the emulation from the default NRF24L01 RF component to the CC2500 by using an option value (freq tuning) different from 0. Option in this case is used for fine frequency tuning like any CC2500 protocols so check the [Frequency Tuning page](/docs/Frequency_Tuning.md).
CH1|CH2|CH3|CH4|CH5
---|---|---|---|---
@@ -1013,9 +1212,9 @@ Only 3 TX IDs available, change RX_Num value 0..2 to cycle through them
### Sub_protocol E010 - *4*
15 TX IDs available, change RX_Num value 0..14 to cycle through them
If the model does not respond well to inputs or hard to bind, you can try to set Power to Low. But this protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components used and nothing we can do about it in the firmware.
This protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components.
If a CC2500 rf component is available it will be used in place of the NRF24L01 which might fix the issue mentioned above. Option is used for fine frequency tuning like any CC2500 protocols. Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it if necessary.
If the model does not respond well to inputs or hard to bind, you can try to switch the emulation from the default NRF24L01 RF component to the CC2500 by using an option value (freq tuning) different from 0. Option in this case is used for fine frequency tuning like any CC2500 protocols so check the [Frequency Tuning page](/docs/Frequency_Tuning.md).
### Sub_protocol H26WH - *5*
CH6|
@@ -1045,7 +1244,9 @@ Model: Yi Zhan i6S
Only one model can be flown at the same time since the ID is hardcoded.
If the model does not respond well to inputs or hard to bind, you can try to set Power to Low. But this protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components used and nothing we can do about it in the firmware.
This protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components.
If the model does not respond well to inputs or hard to bind, you can try to switch the emulation from the default NRF24L01 RF component to the CC2500 by using an option value (freq tuning) different from 0. Option in this case is used for fine frequency tuning like any CC2500 protocols so check the [Frequency Tuning page](/docs/Frequency_Tuning.md).
### Sub_protocol LS - *3*
Models: LS114, 124, 215
@@ -1077,7 +1278,7 @@ CH1|CH2|CH3|CH4|CH5
A|E|T|R|Warp
## Potensic - *51*
Models: Potensic A20
Model: Potensic A20
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
@@ -1091,6 +1292,17 @@ MODE: Beginner -100%, Medium 0%, Advanced +100%
HEADLESS: Off -100%, On +100%
## PROPEL - *66*
Model: PROPEL 74-Z Speeder Bike
Autobind protocol
Telemetry: RSSI is equal to TX_LQI which indicates how well the TX receives the RX (0-100%). A1 voltage should indicate the numbers of life remaining (not tested). A2 is giving the model status using a bit mask: 0x80=flying, 0x08=taking off, 0x04=landing, 0x00=landed/crashed
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14
---|---|---|---|---|---|---|---|---|----|----|----|----|----
A|E|T|R|LEDs|RollCW|RollCCW|Fire|Weapons|Calib|Alt_Hold|Take_off|Land|Training
## Q2X2 - *29*
### Sub_protocol Q222 - *0*
Models: Q222 v1 and V686 v2
@@ -1115,7 +1327,10 @@ CH1|CH2|CH3|CH4
A|E|T|R
### Sub_protocol Q303 - *0*
If the model does not respond well to inputs or hard to bind, you can try to set Power to Low. But this protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components used and nothing we can do about it in the firmware.
This protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components.
If the model does not respond well to inputs or hard to bind, you can try to switch the emulation from the default NRF24L01 RF component to the CC2500 by using an option value (freq tuning) different from 0. Option in this case is used for fine frequency tuning like any CC2500 protocols so check the [Frequency Tuning page](/docs/Frequency_Tuning.md).
CH5|CH6|CH7|CH8|CH9|CH10|CH11
---|---|---|---|---|---|---
@@ -1141,6 +1356,19 @@ ARM|FLIP
ARM is 3 positions: -100%=land / 0%=manual / +100%=take off
## Q90C - *72*
This protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components.
If the model does not respond well to inputs or hard to bind, you can try to switch the emulation from the default NRF24L01 RF component to the CC2500 by using an option value (freq tuning) different from 0. Option in this case is used for fine frequency tuning like any CC2500 protocols so check the [Frequency Tuning page](/docs/Frequency_Tuning.md).
CH1|CH2|CH3|CH4|CH5|CH6
---|---|---|---|---|---
A|E|T|R|FMODE|VTX+
FMODE: -100% angle, 0% horizon, +100% acro
VTX+: -100%->+100% channel+
## Redpine - *50*
[Link to the forum](https://www.rcgroups.com/forums/showthread.php?3236043-Redpine-Lowest-latency-RC-protocol)
@@ -1154,13 +1382,17 @@ Model: Shenqiwei 1/20 Mini Motorcycle
CH1|CH2|CH3|CH4
---|---|---|---
| |T|R
-|-|T|R
Throttle +100%=full forward,0%=stop,-100%=full backward.
## SLT - *11*
Autobind protocol
This protocol is known to be problematic because it's using the NRF24L01 with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is a hardware issue with the accuracy of the components. (some Jumper models seem to be using a NRF24L01 clone)
If the model does not respond well to inputs or hard to bind, you can try to switch the emulation from the default NRF24L01 RF component to the CC2500 by using an option value (freq tuning) different from 0. Option in this case is used for fine frequency tuning like any CC2500 protocols so check the [Frequency Tuning page](/docs/Frequency_Tuning.md).
### Sub_protocol V1 - *0*
CH1|CH2|CH3|CH4|CH5|CH6
@@ -1264,28 +1496,89 @@ CH10|CH11|CH12
---|---|---
Start/Stop|EMERGENCY|CAMERA_UP/DN
### Sub_protocol MR101 - *2*
TX: MR101, model: Dromida XL
**Only 1 ID** available. If you have a TX contact me on GitHub or RCGroups.
Autobind protocol
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11
---|---|---|---|---|---|---|---|---|----|----
A|E|T|R|FLIP||PICTURE|VIDEO||MOT_ON_OFF|AUTO
MOT_ON_OFF: momentary switch (you need to maintaint it for at least 1.5sec for on or off)
AUTO: Land=-100% Takeoff=+100%
The model can work with a none centered throttle.
## Tiger - *61*
Autobind protocol
**Only 1 ID**
CH1|CH2|CH3|CH4|CH5|CH6
---|---|---|---|---|---
A|E|T|R|FLIP|LIGHT
## V761 - *48*
Model: Volantex V761 and may be other
Warning: Only 3 IDs, you can cycle through them using RX_Num.
CH1|CH2|CH3|CH4|CH5
---|---|---|---|---
-|E|T|R|GYRO
Warning: **Only 5 IDs**, you can cycle through them using RX_Num.
Gyro: -100%=Beginer mode (Gyro on, yaw and pitch rate limited), 0%=Mid Mode ( Gyro on no rate limits), +100%=Mode Expert Gyro off
Calib: momentary switch, calib will happen one the channel goes from -100% to +100%
Flip: momentary switch: hold flip(+100%), indicate flip direction with Ele or Ail, release flip(-100%)
RTN_ACT and RTN: -100% disable, +100% enable
### Sub_protocol 3CH - *0*
Model: Volantex V761-1, V761-3 and may be others
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
-|E|T|R|GYRO|CALIB|FLIP|RTN_ACT|RTN
### Sub_protocol 4CH - *1*
Model: Volantex V761-4+ and Eachine P51-D, F4U, F22 and may be others
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
A|E|T|R|GYRO|CALIB|FLIP|RTN_ACT|RTN
## V911S - *46*
Models: WLtoys V911S, XK A110
This protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components.
If the model does not respond well to inputs or hard to bind, you can try to set Power to Low. But this protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components used and nothing we can do about it in the firmware.
If a CC2500 rf component is available it will be used in place of the NRF24L01 which might fix the issue mentioned above. Option is used for fine frequency tuning like any CC2500 protocols. Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it if necessary.
If the model does not respond well to inputs or hard to bind, you can try to switch the emulation from the default NRF24L01 RF component to the CC2500 by using an option value (freq tuning) different from 0. Option in this case is used for fine frequency tuning like any CC2500 protocols so check the [Frequency Tuning page](/docs/Frequency_Tuning.md).
CH1|CH2|CH3|CH4|CH5
---|---|---|---|---
A|E|T|R|CALIB
### Sub_protocol V911S - *0*
Models: WLtoys V911S, XK A110
### Sub_protocol E119 - *1*
Models: Eachine E119
## XK - *62*
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|----
A|E|T|R|Flight_modes|Take_off|Emerg stop|3D/6G|Picture|Video
Flight_modes: -100%=M-Mode, 0%=6G-Mode, +100%=V-Mode. CH6-CH10 are mementary switches.
### Sub_protocol X450 - *0*
Models: XK X450 (TX=X8)
This protocol is known to be problematic because it's using the xn297L emulation with a transmission speed of 250kbps therefore it doesn't work very well with every modules, this is an hardware issue with the accuracy of the components.
If the model does not respond well to inputs or hard to bind, you can try to switch the emulation from the default NRF24L01 RF component to the CC2500 by using an option value (freq tuning) different from 0. Option in this case is used for fine frequency tuning like any CC2500 protocols so check the [Frequency Tuning page](/docs/Frequency_Tuning.md).
### Sub_protocol X420 - *1*
Models: XK X420/X520 (TX=X4)
## YD717 - *8*
Autobind protocol
@@ -1307,7 +1600,63 @@ Autobind protocol
CH1|CH2|CH3|CH4|CH5
---|---|---|---|---
||T|R|LIGHT
-|-|T|R|LIGHT
# SX1276 RF Module
## FRSKYR9 - *65*
**R9 RXs must be flashed with latest ACCST.**
Extended limits and failsafe supported.
Full telemetry supported.
Notes:
- The choices of CH1-8/CH9-16 and Telem ON/OFF is available in OpenTX 2.3.10 nightlies. The default is CH1-8 Telem ON.
- Telemetry from TX to RX is available in OpenTX 2.3.10 nightlies.
- Power adjustment is not supported on the T18.
### Sub_protocol R9_915 - *0*
915MHz, 16 channels
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|----
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
### Sub_protocol R9_868 - *1*
868MHz, 16 channels
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|----
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
### Sub_protocol R9_915_8CH - *2*
915MHz, 8 channels
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
### Sub_protocol R9_868_8CH - *3*
868MHz, 8 channels
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
### Sub_protocol R9_FCC - *4*
FCC, 16 channels
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|----
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
### Sub_protocol R9_FCC_8CH - *6*
FCC, 8 channels
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
# OpenLRS module

View File

@@ -6,11 +6,12 @@ To get the XN297L dump feature working on your module you must know:
Procedure to use the XN297L dump feature:
1. Start the Multi module in serial debug mode with the Arduion IDE Serial Monitor open<br> <img src="images/Serial_Monitor_2.png" />
1. Select the protocol 63 or "Custom 63" to enable the XN297L Dump protocol
1. Select the protocol XN297DP, 63 or "Custom 63" to enable the XN297L Dump protocol
1. This protocol parameters are:
* sub_protocol or type or the second number after "Custom 63" is used to set the transmission speed: 0=250Kbps, 1=1Mbps and 2=2Mbps. Any other value will default to 1Mbps.
* sub_protocol or type or the second number after "Custom 63" is used to set the transmission speed: 0=250Kbps, 1=1Mbps, 2=2Mbps and 3=Auto.
* Auto is the recommended mode since it gives many information like channels, timing, order as well as finding bytes meaning
* RX_num or Receiver number sets the address length 3, 4 or 5 bytes. Any other value will default to an address length of 5 bytes.
* option sets the RF channel number used to receive packets between 0..84 . A value of -1 will automatically scan all channels one by one. Any other value will default to the RF channel 0.
Examples:
TBC
TBC

View File

@@ -1,14 +1,21 @@
# Flashing from the Transmitter
For radios running erskyTx and OpenTX, there is an option to flash a precompiled firmware file to the multiprotocol module using the transmitter's Bootloader mode.
For radios running erskyTx and OpenTX, there is an option to flash a precompiled firmware file to the multiprotocol module:
- OpenTX: using the SD card browser
- erskyTX : using the transmitter's Bootloader mode.
## Tools required
* A compatible transmitter running an erskyTx bootloader v2.9 or newer. This is true for both OpenTX and erskyTx.
What you need:
* A precompiled multiprotocol firmware file (.hex for Atmega328p or .bin for STM32)
* A **Flash from TX** bootloader installed on an Atmega328p or STM32 multiprotocol module
* A means to get the firmware file onto the transmitter's SD card
## Radio bootloader and apps
## OpenTX 2.3.3 or newer
1. Copy the firmware file to the radio's SD card - it doesn't matter where you put it
1. Switch the radio on normally and use the radio menu to locate the file on the SD card
1. Highlight the file and press the ENTER button
1. Choose Flash internal module or Flash external module as appropriate
## erskyTX
### How to check the bootloader version
1. Push both horizontals trims inwards (close to each others) while powering on the radio
@@ -35,9 +42,7 @@ For radios running erskyTx and OpenTX, there is an option to flash a precompiled
1. Long press it and select `Flash bootloader`
1. Check by rebooting the radio in bootloader mode that everything is [ok](###-How-to-check-the-bootloader-version)
**Note**: For OpenTX radio, this bootloader is an upgraded version of the existing bootloader shipped with OpenTX. It's providing you the exact same level of default features while adding more through apps. You can go back and forth between the 2 bootloaders without an issue.
## Multimodule upgrade procedure
### Multimodule upgrade procedure
1. Either:
1. Connect the transmitter using a USB cable and power it on, or
1. Remove the SD card from the transmitter and mount it using a suitable reader

View File

@@ -48,16 +48,16 @@ Connection is lost at -73 and +35; the median is -19:
`(-73 + 35) / 2 = -19`
### Finally
Once the **Freq** value is known it should be applied to all other models which use this protocol and, if they were previously bound, the receivers must be re-bound.
For convenience this can be applied once for all per protocol using the FORCE commands described below in `_Config.h` (or `_MyConfig.h`) configuration file.
Usually all RXs using the same protocol&sub_protocol can use the same **Freq** value but it can't harm to do all of them.
If you change the Freq value it is best to rebind the receiver(s).
#### Forced tuning values
Once known-good tuning values have been determined, they can be stored in the configuration file to be automatically applied to all models which use the given protocol.
For convenience the freq value can be applied once for all per protocol using the FORCE commands described below in `_Config.h` (or `_MyConfig.h`) configuration file.
These settings can also be used to force different tuning values for different multiprotocol modules, removing the need to alter the tuning option on the transmitter when swapping between modules. (Assuming that the modules also share a common hardware ID.)
**Note:** If a forced tuning value is set in the configuration, it cannot be overriden by the protocol's **Freq** option on the radio for any model.
Once known-good tuning values have been determined, they can be stored in the configuration file to be automatically applied to all models which use the given protocol.
**Note:** If a forced tuning value is set in the configuration, the protocol's **Freq** option on the radio GUI will be ignored whatever the value is set to.
```
/*******************************/

BIN
docs/images/warning.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB