Compare commits

...

902 Commits

Author SHA1 Message Date
pascallanger
79b09468ac WLV8TX small changes and save few bytes 2026-08-05 00:48:46 +02:00
pascallanger
97fcd0bde0 Update build_release_avr_noboot 2026-08-04 00:32:59 +02:00
pascallanger
463978939b Ares: new protocol
ARES Gamma 370, P-51D Mustang 350, RTF models with 6HPA-Tx and AZS12006-Rx (6 channel).
2026-08-04 00:28:44 +02:00
pascallanger
0a7f74dc06 SLT/SLT6X new subprotocol 2026-08-03 23:51:35 +02:00
pascallanger
3d50a39efb DSM: add XPlus channels
Sent only when number of channels >12
2026-08-03 15:41:23 +02:00
MRC3742
9e0efe321c REALACC/WLV8Tx : WLtoys Cars 284019-A and 284191
Protocol: REALACC
Sub Proto: WL_V8Tx
Ch1: Steering
CH2: Throttle
CH3: GY TRIM (Rate)
CH4: TH TRIM (Rate)
CH5: Steering Trim
2026-08-03 14:36:17 +02:00
pascallanger
3e75c27e95 Update Validate.h
Save Flash space
2026-08-02 23:01:33 +02:00
pascallanger
3151a5a5c6 Update Validate.h
Save Flash space
2026-08-02 22:56:13 +02:00
pascallanger
2348c3c29d Update Validate.h
Save Flash space
2026-08-02 22:54:09 +02:00
pascallanger
968578d59e Update Validate.h
Save flash space
2026-08-02 22:49:00 +02:00
pascallanger
53594ce1a1 Update build_release_avr_optiboot
Disable Radiolink in this build
2026-07-29 09:43:23 +02:00
Eduard
aaaa5f141d RadioLink / DumboRC command packages for P Series (#1164)
* [Codex assisted] RadioLink / DumboRC command packages bridge

Pass "special" packages to and from the module
Allows to replicate "Set Failsafe", "Set Gyro Settings" and "Set Gyro Endpoints" from DDF-350

* RadioLink / DumboRC command packages TX / RX

* RadioLink / DumboRC Helper script channel names

Has max 10 channels
Has no failsafe
Older X series have gyro sense fixed to CH8, also can be used as regular channel

* [Codex] DumboRC P Series settings script

Add script that mimics interaction between DumboRC DDF-350 transmitter and P Series receivers

* [Codex assisted] Split P series into separate subprotocol

Split command exchange into separate subprotocol
Update protocol documentation

* [Codex] Improve LUA script

Clean up, better event handling
2026-07-29 08:18:58 +02:00
pascallanger
1772147e5b Update FQ777_nrf24l01.ino 2026-07-16 20:18:54 +02:00
pascallanger
865f6c1597 FQ777/XBM37: new subprotocol 2026-07-16 18:25:58 +02:00
pascallanger
095acb0975 FX/A570: new subprotocol for VTOL QIDI-570 2026-07-16 17:51:34 +02:00
MRC3742
fc8730976c FX: Add telemetry delay for warnings
* telemetry delay for FX protocol warnings

* Update Protocols_Details.md

---------

Co-authored-by: dellclient <dellclient>
2026-07-16 10:11:51 +02:00
pascallanger
699e796a01 FX/BM26: new subprotocol
Missing files
2026-07-14 22:30:14 +02:00
pascallanger
93bade15d0 FX/BM26: new subprotocol 2026-07-14 22:29:07 +02:00
pascallanger
80d08c25e0 Update Protocols_Details.md 2026-07-14 19:52:07 +02:00
pascallanger
debb17a8fc Update Protocols_Details.md 2026-07-14 19:50:43 +02:00
pascallanger
174efa332b XK2/X4: Stunt flag for the Sky Viper Vector 2026-07-14 19:46:38 +02:00
pascallanger
e5f9f8c840 Hontai/XK170: Optical flag
CH11 enable/disable flow sensor for K270
2026-07-14 19:26:55 +02:00
pascallanger
a23716269b Merge branch 'master' of https://github.com/pascallanger/DIY-Multiprotocol-TX-Module 2026-07-14 18:55:06 +02:00
MRC3742
bfef3364fc Fix for DSM Clone
* fix for DSM clone not working
2026-07-14 18:54:36 +02:00
pascallanger
d62f2d0555 Update Protocols_Details.md 2026-07-14 18:52:32 +02:00
pascallanger
bb59582271 Update XN297Dump_nrf24l01.ino 2026-07-14 18:46:54 +02:00
pascallanger
c6c6fa442b Update WPL_nrf24l01.ino 2026-07-14 18:46:40 +02:00
pascallanger
d95012c30b TRAXXAS: attempt to describe TQi 2026-07-14 18:46:09 +02:00
pascallanger
f71768df39 E129 saving few bytes 2026-07-14 18:44:41 +02:00
pascallanger
7bde06ff50 AFHDS2A: Fix for CROSSOVER-RX
CROSSOVER-RX are sending end of telemetry data despite having sensors after...
2026-07-14 18:44:05 +02:00
pascallanger
51a01d1393 KF606 LED
Add LED channel for KF606 boards
2026-07-14 18:42:14 +02:00
pascallanger
bf38415420 Update SGF22_nrf24l01.ino
Fix tx and freq for none CX10
2025-09-26 17:41:06 +02:00
pascallanger
5ce6c6f544 Update Protocols_Details.md 2025-07-28 11:27:57 +02:00
pascallanger
35f284763a SGF22/CX10 new subprotocol
Only 2 IDs
2025-07-28 11:20:57 +02:00
pascallanger
e35c4d3ce8 WPL 1 ID 2025-07-28 01:06:12 +02:00
pascallanger
ba59605b16 Update WPL_nrf24l01.ino 2025-07-27 19:15:55 +02:00
pascallanger
b88f4d40f4 WPL 5 2025-07-27 18:24:24 +02:00
pascallanger
5ade6bc312 WPL 4th 2025-07-27 16:51:13 +02:00
pascallanger
9e099bc486 WPL 3rd try 2025-07-27 16:42:00 +02:00
pascallanger
48b7430e75 WPL try 2 2025-07-27 16:01:52 +02:00
pascallanger
6385e822c2 MT99xx/SU35: removed autobind 2025-07-27 12:25:14 +02:00
pascallanger
66f8906273 WPL new protocol
Only 1 ID
2025-07-27 12:24:03 +02:00
Jon Sturm
dcbc557bf7 Enable Telemetry on DumbRC receivers (#1111)
Tested with X6FGv1.1, X6FP, X6DC(G)v1.1

I also tested with multiple X6F receivers and some gave RSSI Telem and some gave nothing.
2 of them had the same PCB as the X6FP and neither gave telemetry.
I had a third with the same PCB with the X6FP which did give RSSI
and of my two with an older PCB one gives RSSI telem and the other does not.

Of the receivers I tried only one set packet_in[6] to match the TX packet[1] and it was the
oldest receiver of the ones I own.
2025-05-10 11:51:48 +02:00
pascallanger
e556f5cc40 SGF22 telem improvement? 2025-04-16 07:53:47 +02:00
pascallanger
9ef2415178 Update Protocols_Details.md (#1101) 2025-04-03 18:39:02 +02:00
pascallanger
bc1a809325 Update Protocols_Details.md 2025-04-03 18:36:31 +02:00
pascallanger
082e96e381 DSMR timing 2025-04-02 18:02:44 +02:00
pascallanger
abd26ee113 Update SGF22_nrf24l01.ino 2025-04-02 14:24:18 +02:00
pascallanger
98518b3c92 Update Protocols_Details.md 2025-04-02 14:11:58 +02:00
pascallanger
d19de99172 SGF22 telemetry 2025-04-02 14:10:54 +02:00
pascallanger
13024e3816 Update SGF22_nrf24l01.ino 2025-04-01 23:01:18 +02:00
pascallanger
90fb2d745f Update AFHDS2A_a7105.ino 2025-03-31 22:21:33 +02:00
pascallanger
fa13b67f3a Update Validate.h 2025-03-31 14:56:46 +02:00
pascallanger
10be906bec Update Validate.h 2025-03-31 14:43:42 +02:00
pascallanger
f538884d48 XK2 low batt telemetry 2025-03-28 19:13:13 +01:00
pascallanger
d3e5acf704 Update Protocols_Details.md 2025-03-28 10:33:39 +01:00
pascallanger
2ac4745c62 FX/QF012 telemetry 2025-03-21 21:48:29 +01:00
pascallanger
889e01c7c6 MouldKg update 2025-03-20 17:28:33 +01:00
pascallanger
db5f1f8899 Added AFHDS2A BS4/BS6 support 2025-03-20 14:49:34 +01:00
pascallanger
d091c57e10 MouldKg swap CH5 and CH6 2025-03-14 10:34:15 +01:00
pascallanger
0fcb4b7f1a FX telemetry 2025-03-13 20:15:57 +01:00
pascallanger
432e2e08a4 FX small changes 2025-03-13 19:13:14 +01:00
pascallanger
77efe467ad MouldKg renamed subprotocols 2025-03-13 18:42:34 +01:00
pascallanger
b9c828c878 MouldKg multi 6 ports brick support 2025-03-13 18:29:56 +01:00
pascallanger
99cd4d34d4 MT99xx Trim channels 2025-03-12 17:20:54 +01:00
pascallanger
a9be2a8644 Update MouldKg_nrf24l01.ino 2025-03-12 14:05:53 +01:00
pascallanger
835facd2c3 XK2 Gyro off 2025-03-12 07:45:05 +01:00
pascallanger
9e20e47c5a FX/QF012 details 2 2025-03-12 07:34:47 +01:00
pascallanger
a916275f0d FX/QF012 details 2025-03-12 07:31:32 +01:00
rdba2k
9beade33de Add FX_QF012 subprotocol (#1091) 2025-03-12 07:17:08 +01:00
pascallanger
5ba70c3571 Update Protocols_Details.md 2025-03-10 17:40:46 +01:00
pascallanger
168aa89c57 New SFC protocol WL91x 2025-03-10 17:38:37 +01:00
pascallanger
fa055e991c ASF try 1 2025-02-27 16:56:58 +01:00
pascallanger
5437d88642 DSMR SR6200 test 1 2025-02-26 21:12:34 +01:00
pascallanger
d800f2c333 SLT2 final 2025-02-26 11:31:26 +01:00
pascallanger
78f6af6448 SLT2 last trial? 2025-02-26 00:00:49 +01:00
pascallanger
b04d4a54f7 SLT2 trial 3 2025-02-25 22:08:50 +01:00
pascallanger
ed65c81add SLT2 trial 2 2025-02-25 20:31:46 +01:00
pascallanger
9bdc24c42a SLT2 trial 2025-02-25 15:39:16 +01:00
pascallanger
7107d46d29 SHENQI2 new protocol 2025-02-24 17:04:07 +01:00
pascallanger
825f560cbb Update Protocols_Details.md 2025-02-22 11:51:55 +01:00
pascallanger
ccaec304d5 KAMTOM telemetry 2025-02-22 11:48:03 +01:00
pascallanger
22d45349cc Update Compiling.md (#1078) 2025-02-22 11:36:23 +01:00
pascallanger
5f26d624ad Update Compiling.md 2025-02-22 11:23:49 +01:00
pascallanger
496c07943f KAMTOM new surface protocol
Missing low batt telem
2025-02-21 21:46:18 +01:00
pascallanger
af87b0f6d1 Update UDIRC_ccnrf.ino 2025-02-19 17:16:04 +01:00
pascallanger
2918e63fb4 XN297Emu add ReSendPayload 2025-02-19 11:54:29 +01:00
pascallanger
ed63ef7efe Update UDIRC_ccnrf.ino 2025-02-19 11:33:17 +01:00
pascallanger
36d25c7773 Update UDIRC_ccnrf.ino 2025-02-19 11:21:26 +01:00
pascallanger
a3ef2b94d4 Update MultiChan.txt 2025-02-18 19:32:19 +01:00
pascallanger
ad8b45773d UDIRC new protocol / WIP 2025-02-18 11:18:13 +01:00
pascallanger
b2dec9b331 Update Protocols_Details.md 2025-02-12 11:57:04 +01:00
pascallanger
565aaed0c7 New XK2/P10 sub protocol 2025-02-09 12:01:28 +01:00
pascallanger
2f520f2e91 Update Protocols_Details.md 2025-02-06 12:03:15 +01:00
pascallanger
f1470a80dd Update Protocols_Details.md 2025-02-06 12:00:07 +01:00
pascallanger
b6f78e93a0 Yuxiang multi IDs/Freqs 2025-02-06 11:57:40 +01:00
pascallanger
58bfd3b8b0 New JIABAILE/Gyro subprotocol 2025-02-06 11:56:24 +01:00
pascallanger
9e5e907f4a Hontai/XKK170 new subprotocol 2025-01-30 23:14:15 +01:00
pascallanger
4b68443c8f Update Multiprotocol.h 2025-01-30 10:37:53 +01:00
pascallanger
f092e137c7 Improve DSM telemetry stability? 2025-01-30 10:28:57 +01:00
pascallanger
7b9941e537 Fix DSMR 2025-01-29 19:48:18 +01:00
pascallanger
d03a8787d1 Update Protocols_Details.md 2025-01-29 10:05:23 +01:00
pascallanger
75f79095ae JIABAILE RX ID in EEPROM
Not an autobind protocol anymore.
2025-01-29 09:42:16 +01:00
pascallanger
b901bedad6 Update H36_nrf24l01.ino 2025-01-28 17:51:06 +01:00
pascallanger
dbbef9181a Update H36_nrf24l01.ino 2025-01-28 14:05:45 +01:00
pascallanger
98a54300e0 New H36 protocol - 1 ID 2025-01-28 14:00:38 +01:00
pascallanger
56fa7e788b Update Protocols_Details.md 2025-01-27 17:54:26 +01:00
pascallanger
7af23017ff Update JIABAILE_nrf24l01.ino 2025-01-27 17:37:00 +01:00
pascallanger
a07c23b25f New car protocol JIABAILE 2025-01-27 16:12:21 +01:00
pascallanger
b5b2dc37d4 SGF22 FX922 flags 2025-01-25 17:49:22 +01:00
pascallanger
756af87ec1 SGF22 Flags trial 2025-01-25 11:31:21 +01:00
pascallanger
e5810a2978 QIDI560 new light flag? 2025-01-23 15:49:35 +01:00
pascallanger
eaf71c2f49 XK2 details 2025-01-21 17:06:21 +01:00
pascallanger
546a962d96 XK2 multi IDs 2025-01-20 19:19:31 +01:00
pascallanger
fd150fa109 XK2 2nd ID 2025-01-20 16:28:48 +01:00
pascallanger
9b66711052 MT99X2/SU35 2025-01-19 16:07:45 +01:00
pascallanger
550754c7f9 Merge branch 'master' of https://github.com/pascallanger/DIY-Multiprotocol-TX-Module 2025-01-19 15:59:42 +01:00
rdba2k
729fdd4719 Add MT99xx2/SU35 protocol (#1033)
* Update Multi.txt

* Update Multi_Protos.ino

* Update _Config.h

* Update Multiprotocol.h

* Update MT99xx_ccnrf.ino
2025-01-19 15:59:13 +01:00
pascallanger
2713b18099 Update Protocols_Details.md 2025-01-19 14:57:51 +01:00
pascallanger
5b5e95066a Traxxas TQ2&TQ1 2025-01-19 14:25:41 +01:00
pascallanger
b1f8560509 Update Yuxiang_nrf24l01.ino 2025-01-19 14:25:21 +01:00
Paul
50c18311c9 Update readme and protocol detals with surface/air info (#1034)
* Update readme and protocol detals with surface/air info

* Update Protocols_Details.md

* Update README.md

---------

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2025-01-19 14:18:20 +01:00
Arild Langseid
95746f80a1 Add RF_SIM sub-protocol to SLT-protocol (#1061)
* Added sub-protocol RF_SIM to the SLT protocol

* fixed typo

---------

Co-authored-by: Arild Langseid <arild@langseid.no>
2025-01-19 14:14:32 +01:00
pascallanger
bb7685e7a5 Update Yuxiang_nrf24l01.ino 2025-01-18 12:24:26 +01:00
pascallanger
a44126583e Yuxiang telemetry
Offset=7, Ratio=3.5
2025-01-18 12:19:33 +01:00
pascallanger
7fbca99bf3 Yuxiang bind ok 2025-01-18 00:36:33 +01:00
pascallanger
8db90fb6fc Yuxiang remove CH8 2025-01-16 11:34:07 +01:00
pascallanger
406f5feca5 Yuxiang TX2 2025-01-15 19:07:03 +01:00
pascallanger
0e5834a457 Update XN297Dump_nrf24l01.ino 2025-01-15 12:46:28 +01:00
pascallanger
75445ee4a7 Update Yuxiang_nrf24l01.ino 2025-01-13 20:28:25 +01:00
pascallanger
e724d6970e YuXiang E190 protocol
Only 1 ID, bind might not work...
2025-01-13 20:24:04 +01:00
pascallanger
190ebaefd4 Update XN297Dump_nrf24l01.ino 2025-01-13 20:22:14 +01:00
pascallanger
3fdf417ac9 V761 Beeper feature on CH10 2025-01-07 21:37:32 +01:00
pascallanger
e05bc7c447 Update XN297Dump_nrf24l01.ino 2025-01-07 15:11:32 +01:00
pascallanger
e2876c7e8c Update SGF22_nrf24l01.ino 2024-10-09 10:09:21 +02:00
pascallanger
7acfebc30e Update Protocols_Details.md 2024-10-09 10:01:08 +02:00
pascallanger
af12b21899 Merge branch 'master' of https://github.com/pascallanger/DIY-Multiprotocol-TX-Module 2024-09-26 10:14:30 +02:00
pascallanger
68a4285b2a Update Protocols_Details.md 2024-09-26 10:14:26 +02:00
rdba2k
f58f7800d2 Update SGF22_nrf24l01.ino (#1023)
add sub protocol "J20" to "SGF22" protocol
2024-09-26 10:11:19 +02:00
rdba2k
10b230d2dd Update Multiprotocol.h (#1022)
add sub protocol "J20" to "SGF22" protocol
2024-09-26 10:05:12 +02:00
rdba2k
58b19a2130 Update Multi_Protos.ino (#1021)
add sub protocol "J20" to "SGF22" protocol
2024-09-26 10:04:45 +02:00
rdba2k
1b79d7f80f Update Multi.txt (#1020)
add sub protocol "J20" to "SGF22" protocol
2024-09-26 10:04:07 +02:00
rdba2k
e0299f6c7d Update _Config.h (#1019)
add sub protocol "J20" to "SGF22" protocol
2024-09-26 10:03:39 +02:00
pascallanger
64ea7111ac SGF22: new F22S sub protocol 2024-09-02 18:14:25 +02:00
pascallanger
edaee63f16 Revert main.yml to use the old version of arduino_cli 2024-07-24 16:20:16 +02:00
Peter Feerick
b449212c34 chore(ci): bump setup-arduino-ci version to remove nodejs warning (#995)
* chore(ci): bump setup-arduino-ci version to remove nodejs warning

Gets rid of the numerous  "The following actions
uses Node.js version which is deprecated and will
be forced to run on node20" warnings

* chore: bump arduino-cli ver
2024-07-18 12:57:48 +02:00
pascallanger
edaad73290 Update Validate.h 2024-07-12 16:06:32 +02:00
pascallanger
3d5e43da3b Update Validate.h 2024-07-12 16:03:30 +02:00
pascallanger
b8c5929521 XK2: 1 TX ID but multiple RX IDs? 2024-07-12 10:00:21 +02:00
pascallanger
8685fcae7f Update Protocols_Details.md 2024-07-11 16:44:53 +02:00
pascallanger
6edd2a14a7 E129/C185 new debug flag 2024-07-11 16:20:32 +02:00
Ben Lye
600ffe87d7 Disable SCANNER ... (#989) 2024-06-14 12:14:55 +02:00
pascallanger
c6ff0e27d9 New protocol XK2 for the XK A160S 2024-06-07 20:28:15 +02:00
pascallanger
7a7b4b2e74 Update Protocols_Details.md 2024-05-21 13:16:41 +02:00
pascallanger
8a30bf1c0a Update FX/Q560 doc 2024-05-21 07:42:59 +02:00
pascallanger
dd82cbec63 Update Protocols_Details.md 2024-05-17 17:08:01 +02:00
pascallanger
be4595fe67 Update FX_nrf24l01.ino 2024-05-17 14:45:30 +02:00
pascallanger
54ae77ed7f FX/Q560 new sub protocol 2024-05-17 11:01:54 +02:00
pascallanger
2bdbd7088c Traxxas TQ 1st gen: try 5 2024-05-04 11:36:14 +02:00
pascallanger
1d3ed78622 J6Pro update 2024-05-04 11:34:59 +02:00
pascallanger
79b1c54007 Traxxas TQ 1st gen: try 4 2024-05-03 00:15:03 +02:00
pascallanger
81eb5dc6bc Traxxas TQ 1st gen: try 2 2024-04-29 19:43:24 +02:00
pascallanger
85a0e4bde8 Traxxas TQ 1st gen: try 2 2024-04-27 11:23:19 +02:00
pascallanger
63dfa316e8 Traxxas TQ 1st gen: try 1 2024-04-26 19:25:23 +02:00
pascallanger
9d383432a5 Update SGF22_nrf24l01.ino 2024-04-24 07:00:44 +02:00
pascallanger
6b181db629 SLT try 1e 2024-04-18 10:40:37 +02:00
pascallanger
873279dbe9 SLT new sub_protocol V1_4CH 2024-04-15 14:13:37 +02:00
pascallanger
f35be2984a SLT try 1d 2024-04-14 13:29:28 +02:00
pascallanger
7ddeb31e95 SLT try 1c 2024-04-14 13:23:50 +02:00
pascallanger
7444c44b48 SLT try 1b 2024-04-13 10:22:39 +02:00
pascallanger
08d1dcbed2 SLT try 1a 2024-04-12 18:24:50 +02:00
pascallanger
3e4f4e36c1 SLT try 1 2024-04-12 18:20:01 +02:00
pascallanger
902419dd3d Update Protocols_Details.md 2024-04-08 18:36:42 +02:00
pascallanger
038b3b9225 Update Protocols_Details.md 2024-04-04 17:13:35 +02:00
pascallanger
45f0154f4b Update Protocols_Details.md 2024-04-04 16:15:27 +02:00
pascallanger
e03864e35f Traxxas TQ 6 channels 2024-04-04 16:13:35 +02:00
pascallanger
de35ee09f5 Realacc doc update 2024-04-02 16:42:19 +02:00
pascallanger
c88952c35e REALACC: IDs
Any ID
2024-04-02 12:34:04 +02:00
pascallanger
ffae7dda1d Update SGF22_nrf24l01.ino 2024-03-29 16:24:25 +01:00
pascallanger
4f17f76b39 SGF22: new flag 2024-03-29 16:19:20 +01:00
pascallanger
31ef090508 ASF try 4 2024-03-29 15:55:54 +01:00
pascallanger
04d4e39b87 Update _Config.h 2024-03-27 19:34:28 +01:00
pascallanger
b3537ea75a DSM2_SFC try 3 2024-03-26 16:18:34 +01:00
pascallanger
bccc050165 DSM2_SFC try 2 2024-03-26 14:41:19 +01:00
pascallanger
0f0df176de DSM2_SFC try 1
Servo refresh rate -> frame rate 16.5/11ms
2024-03-26 14:37:26 +01:00
pascallanger
5542e7005d ASF try 3 2024-03-26 11:43:42 +01:00
pascallanger
eb35fefd3e ASF try 2 2024-03-25 15:17:51 +01:00
pascallanger
5acc3a8d01 CYRF6936: Findbestchannels flag addition 2024-03-25 15:11:31 +01:00
pascallanger
9e9c3958c6 ASF: try 1 2024-03-23 11:23:42 +01:00
pascallanger
7f3a93ca4c Kyosho3: increase bind time to 2.5s 2024-03-22 18:24:31 +01:00
pascallanger
debc9de11a New protocol Kyosho3/ASF
Only 1 ID and 1 frequency for now
2024-03-22 18:17:21 +01:00
pascallanger
f117105124 SGF22: Fix none working IDs 2024-03-21 16:33:16 +01:00
pascallanger
2e3520acad DSM2SFC timing update 2024-03-19 20:52:50 +01:00
pascallanger
91af921d98 Update Protocols_Details.md 2024-03-19 15:47:56 +01:00
pascallanger
ab45ec6d1c Update Validate.h 2024-03-19 15:44:29 +01:00
pascallanger
26b0b6bd20 Update DSM_cyrf6936.ino 2024-03-19 15:44:21 +01:00
pascallanger
1b9ce32e89 Update DSM_cyrf6936.ino 2024-03-19 14:11:40 +01:00
pascallanger
332e55831c Update Protocols_Details.md 2024-03-18 17:11:23 +01:00
pascallanger
7051438e5d Update Protocols_Details.md 2024-03-18 17:00:40 +01:00
pascallanger
28467fac57 DSM/DSM2SFC new subprotocol 2024-03-18 16:57:54 +01:00
pascallanger
c7513abad8 Update Multiprotocol.h 2024-03-18 09:02:55 +01:00
pascallanger
e6e13c0fdd Docs update 2024-03-17 15:52:42 +01:00
pascallanger
9579a667fc Update REALACC_nrf24l01.ino 2024-03-17 15:28:33 +01:00
pascallanger
cbedda2471 Merge branch 'master' of https://github.com/pascallanger/DIY-Multiprotocol-TX-Module 2024-03-14 20:23:04 +01:00
pascallanger
f8695befe2 REALACC multi IDs 2024-03-14 20:23:02 +01:00
pascallanger
e951e3146b Update Protocols_Details.md (#955) 2024-03-14 20:22:00 +01:00
pascallanger
4c0b46549f EazyRC multi IDs/RFs 2024-02-28 10:46:10 +01:00
pascallanger
188f8ff9ce Radiolink/RC4G: IDs and RFs 2024-02-26 17:20:08 +01:00
pascallanger
bee6e59582 Update EazyRC_nrf24l01.ino 2024-02-24 09:38:42 +01:00
pascallanger
af47462ba7 EazyRC.2 2024-02-23 19:06:20 +01:00
pascallanger
d6ccd4af54 EazyRC.1 2024-02-23 17:51:38 +01:00
pascallanger
0feedc6fa9 New protocol EazyRC 2024-02-23 17:36:02 +01:00
pascallanger
b5bc7c04fb Rename Traxxas/6519 to Traxxas/TQ 2024-02-23 17:19:09 +01:00
pascallanger
a15371d989 Merge branch 'master' of https://github.com/pascallanger/DIY-Multiprotocol-TX-Module 2024-02-23 11:29:35 +01:00
pascallanger
3c82f37e2b Bumping revision 2024-02-23 11:29:19 +01:00
Ben Lye
4f914a18ae Automated build process updates (#950)
* 4-in-1 air and surface builds

* Disable serial and PPM-only builds for STM32 x-in-1

* More air and surface builds

* Fix 5-in-1 tests

* T18 air, surface, and LBT builds

* Remove CFlie from DIY 5-in-1 AIR

* Bump action versions

* v4 artifact merging

* Improve artifact merge

* Fix merge

* DIY 5-in-1 LBT

* Tweak CI job name

* Add T-Lite 5-in-1 LBT

* CI job restructure
2024-02-23 11:26:30 +01:00
pascallanger
1cbce29970 Remove Radiolink/RC4G when MULTI_AIR 2024-02-23 11:06:48 +01:00
pascallanger
e0c44ed5a8 Remove DSMR when MULTI_AIR 2024-02-23 11:05:02 +01:00
pascallanger
390e5dd654 Remove Kyosho/FHSS&SYNC when MULTI_AIR 2024-02-22 17:40:56 +01:00
pascallanger
968293e599 Remove Hisky/HK310 when MULTI_AIR 2024-02-22 17:29:00 +01:00
pascallanger
09ee173e3b Remove Pelikan/SCX24 when MULTI_AIR
Save flash space
2024-02-22 17:14:20 +01:00
pascallanger
babfee0f9e Update RadioLink_cc2500.ino 2024-02-21 13:43:44 +01:00
pascallanger
72da3c5bc5 Create MULTI_AIR / MULTI_SURFACE 2024-02-21 12:31:23 +01:00
Ben Lye
4df1e65a7f Pelikan SCX24 / HPI TF-41 reversed (#917)
* Pelikan SCX24 / HPI TF-41 reversed

* Save some flash and memory

* Save more flash
2024-02-21 12:17:02 +01:00
pascallanger
1459d690d8 Update SGF22_nrf24l01.ino 2024-02-21 11:41:23 +01:00
pascallanger
8d96066215 Merge XK and Tiger protocols 2024-02-21 11:38:31 +01:00
pascallanger
93a5834dd0 Update TRAXXAS_cyrf6936.ino 2024-02-19 21:53:54 +01:00
pascallanger
5f9ac82ed1 SGF22.5 Multiple IDs, 1 set of frequencies 2024-02-19 18:34:27 +01:00
pascallanger
2108912263 Update TRAXXAS_cyrf6936.ino 2024-02-17 11:03:37 +01:00
pascallanger
72f87cade9 XK: new subprotocol Cars
Removed:
 - deadband which was needed on the planes
- force bind since the cars remember the bind info
-
2024-02-17 11:02:52 +01:00
pascallanger
50bd4850fa Radiolink/RC4G
1 ID / 1 set of frequency
2024-02-16 18:03:32 +01:00
pascallanger
dc1490b9b0 SGF22.4 2024-02-16 10:26:48 +01:00
pascallanger
b18adb0efe SGF22.3 2024-02-16 10:24:44 +01:00
pascallanger
53d5684dfd KN: additional trim and flag 2024-02-15 20:52:01 +01:00
pascallanger
724abbc935 SGF22.2 2024-02-15 18:24:58 +01:00
pascallanger
de610b53fc SGF22.1 2024-02-15 16:28:52 +01:00
pascallanger
dd7ee7bdce SGF22 2024-02-15 16:20:37 +01:00
pascallanger
31a9f6860d New protocol SGF22
Only 1 ID!
2024-02-15 15:51:20 +01:00
pascallanger
4a66ae64c6 Update Protocols_Details.md (#940) 2024-02-06 12:06:34 +01:00
pascallanger
11ae26a431 Update Protocols_Details.md 2024-01-31 19:27:54 +01:00
pascallanger
cdabde5d67 Kyosho FHSS and Syncro
Automatically binding a FHSS or a Syncro RX using FHSS
2024-01-31 19:22:36 +01:00
pascallanger
ce75dd3355 Kyosho FHSS/SYNCRO cleanup 2024-01-30 14:53:28 +01:00
pascallanger
69484b5278 Second try 2024-01-30 14:42:24 +01:00
pascallanger
a90e1f2d3a Update Bluefly_ccnrf.ino
Exclude this protocol since it's not working
2024-01-30 14:36:38 +01:00
pascallanger
5af246bba0 Update _Config.h 2024-01-30 12:33:21 +01:00
pascallanger
75a46858da Update Kyosho_a7105.ino 2024-01-30 12:25:25 +01:00
pascallanger
8ac53657ec Kyosho updqte
fixed crash
2024-01-30 12:06:37 +01:00
pascallanger
2888d3e937 TRAXXAS TQ WIP
It still won't work unless you have some luck. I still need to work on the RF frequency.
2024-01-29 18:59:24 +01:00
pascallanger
3d989a47db Typo... 2024-01-29 18:45:32 +01:00
pascallanger
a7d6d12679 Kyosho Syncro
Sub protocol Syncro for KT-331 and KR-331
2024-01-29 17:00:54 +01:00
pascallanger
457703b881 Update Protocols_Details.md 2024-01-18 12:16:59 +01:00
rdba2k
8e663f2531 Update V911S_ccnrf.ino to add 6G/Senior and light for XK A280 (#929) 2024-01-18 12:07:34 +01:00
pascallanger
8c2fe5f65e Traxxas trial 2023-12-24 15:05:13 +01:00
pascallanger
7549783741 Fix Traxxas for any RX 2023-12-22 21:02:10 +01:00
pascallanger
e6bafaabb7 New protocol: BumbleBee 990A
Preliminary
2023-12-22 21:01:15 +01:00
pascallanger
9286ac84f6 Update MultiChan.txt 2023-12-22 20:58:19 +01:00
pascallanger
ede40ac598 Update Protocols_Details.md (#923) 2023-12-21 18:24:08 +01:00
pascallanger
88fad2dc9f Update Protocols_Details.md (#922) 2023-12-21 18:22:50 +01:00
Frankie Arzu
549d3ad653 Fix for DSM-Auto Bind on Lemon-RX Gen2 (#918)
* #916 Fix for Auto-Bind on Lemon-RX Gen2

Tested with multiple brands (Spektrum, OrangeRX, Lemon-Rx, Admiral).  Even some old DSM 2 receivers.
All work with "Auto" now.   Just in case one needs a LONG bind sending period, when not using "Auto" works the same as before.

* Use 1.8s for Bind Send

Removed the short and long bind count logic.
2023-12-18 12:02:57 +01:00
Frankie Arzu
62aa58d32d Forward Prog v0.56 (#919)
1. NEW Black&White Radios new model setup. Now it can setup completely a plane from zero
2. Color version; simplified code for Tail mixes, and fix Taileron setup
2023-12-17 11:12:14 +01:00
Paul
21a06c2925 FX9603 added to protocol details (#914)
* Allow zero and limit range of enterd values

* FX9603 added to protocol details
2023-12-12 22:43:34 +01:00
pascallanger
9acb3b0e2c DSM.ino: Saved a few bytes 2023-12-01 19:06:15 +01:00
pascallanger
785edde659 Update DSM.ino 2023-12-01 18:29:23 +01:00
pascallanger
7da6d52a84 CYRF data codes are always 16
Removed useless function argument
LOSI now points to the DSM data codes = dependency on DSM
2023-12-01 10:58:56 +01:00
Ben Lye
61cbe45ce2 Disabled protocols in Atmega CYRF builds (#911) 2023-11-30 16:17:21 +01:00
pascallanger
23af33e214 LOSI multi IDs 2023-11-30 16:04:43 +01:00
pascallanger
11db967b8a LOSI multi ID 2023-11-30 16:02:58 +01:00
pascallanger
d419e2b344 Update Losi_cyrf6936.ino 2023-11-30 12:15:02 +01:00
pascallanger
2b69c1184e Update Losi_cyrf6936.ino 2023-11-30 12:10:17 +01:00
pascallanger
1ceed87298 Update Losi_cyrf6936.ino 2023-11-30 09:47:28 +01:00
pascallanger
a1737eab46 PELIKAN: new hopping tables 2023-11-30 09:46:18 +01:00
pascallanger
9cbcafe6cf Update Losi_cyrf6936.ino 2023-11-29 15:40:18 +01:00
pascallanger
495706314f Pelikan: 1 more High ID / frequency table 2023-11-29 15:40:08 +01:00
pascallanger
595511979b Update Losi_cyrf6936.ino 2023-11-27 20:07:12 +01:00
pascallanger
b8d30f47be Update Losi_cyrf6936.ino 2023-11-27 16:59:41 +01:00
pascallanger
b7097bdfb7 LOSI 2023-11-27 15:56:50 +01:00
pascallanger
a682b0e604 Update Losi_cyrf6936.ino 2023-11-22 08:26:03 +01:00
pascallanger
7e7b555809 LOSI: dynamic channel 2023-11-22 07:57:54 +01:00
pascallanger
62ecaa8412 Revert J6Pro changes 2023-11-22 07:57:30 +01:00
pascallanger
5ae052317d Update README.md 2023-11-11 11:50:17 +01:00
pascallanger
f3331ca397 Add pointer to Frank DSM Tools page 2023-11-11 11:48:54 +01:00
pascallanger
ffcfd44127 Bluefly fix? 2023-11-11 01:57:45 +01:00
Ben Lye
5ef944241a Add EU/LBT binaries to the build artifacts (#905)
* Add release LBT builds

* Use friendly build names

* Script cleanup
2023-11-10 17:40:30 +01:00
pascallanger
ab5f75b1b3 BlueFly: New protocol 2023-11-09 18:02:21 +01:00
pascallanger
10ec4dd735 Update Protocols_Details.md 2023-11-09 11:57:26 +01:00
pascallanger
a62d1dcd2e Update Protocols_Details.md 2023-11-08 10:53:57 +01:00
pascallanger
2c9e98e341 Update Protocols_Details.md 2023-10-30 22:48:04 +01:00
pascallanger
0bf94e96b5 E129/C186: New flip flag for C129V2 on CH11 2023-10-30 22:36:09 +01:00
Ben Lye
8d84386c7a Fix LUA script zipping (#898) 2023-10-30 14:44:43 +01:00
Paul
cd721e31d8 Allow zero and limit range of enterd values (#896) 2023-10-24 01:32:38 +02:00
pascallanger
1294ad21cf E129/C186 new circular flight flag 2023-10-23 11:24:37 +02:00
pascallanger
01bc08575f Update Protocols_Details.md 2023-10-10 12:07:16 +02:00
pascallanger
ecfe17915f V761 telemetry fix 2023-10-09 16:53:17 +02:00
pascallanger
f97aa3597d Commented out by default E01X protocol and subprotocols to gain flash space 2023-09-27 15:36:53 +02:00
pascallanger
2e1d763d54 V761 telemetry
A1 (4.4V -> 2.2V), RSSI equal to 100 means that all telem packets are received and TQLY indicates the number of lost telem packets.
2023-09-26 20:04:35 +02:00
Frankie Arzu
93a2cc8b7f Version 0.55 (#883) 2023-09-08 14:33:13 +02:00
pascallanger
abfebb3da4 QIDI-550 model
Using FX/9630
Added trims
!! Need to find out the first RF channel calculation !!
2023-09-02 01:11:37 +02:00
johnnym007
ce5f4ec264 Clone subprotocol for DSM (#877)
* Init WIP

* Adding a gitignore

* removing gitignore

* RX routines added

* Finished adding clone and erase

* Update _Config.h

* Update Multiprotocol.ino

* Ready for testing

* Refactor to call init on cloned/normal change

* Remove vscode files

* remove TODO comment

* remove unnecessary brackets

---------

Co-authored-by: john.moore <john.moore@amulethotkey.com>
2023-08-27 16:08:10 +02:00
pascallanger
a41123deb2 FrSky Archer Bind 2023-08-26 00:04:36 +02:00
pascallanger
fabb65a2bb Fix FrSkyX SPORT 2023-08-12 13:17:06 +02:00
pascallanger
eae1329dfe Add flags for KFPLAN Z61 BF109 2023-08-12 13:16:39 +02:00
Ben Lye
a8ae0a2bd1 Fix builds by using older Arduino CLI (#864)
* Used a fixed version of Arduino CLI

* Bump action versions
2023-06-14 14:08:58 +02:00
Ben Lye
c814cc1bd4 Switch back to non-devel boards for CI/CD (#863) 2023-06-14 13:29:34 +02:00
pascallanger
4e7c1502ff Update Protocols_Details.md 2023-06-04 13:48:04 +02:00
pascallanger
8ddee12de5 Update _Config.h 2023-06-04 12:50:39 +02:00
pascallanger
692bcc1fbb Update Scorpio_cyrf6936.ino 2023-06-04 12:38:09 +02:00
pascallanger
0bb345e3fc J6Pro save some flash space 2023-06-04 12:20:10 +02:00
pascallanger
c193d0b9dd Update Multiprotocol.ino 2023-06-04 12:12:22 +02:00
pascallanger
410ce5cc4c Fixed SX1276 protocol 2023-06-04 12:07:27 +02:00
pascallanger
cefe69a692 Fix SPORT when using FRSKYX (V1) protocol set to EU LBT 2023-06-04 12:03:43 +02:00
pascallanger
daa4ded390 New protocol Scorpio
Model Falco 300
2023-06-04 12:02:37 +02:00
pascallanger
5949fca990 Update Protocols_Details.md (#856) 2023-05-15 08:26:13 +02:00
pascallanger
ed2e2e4f32 Update Protocols_Details.md 2023-05-15 08:17:19 +02:00
Frankie Arzu
b2f8f482bb V0.54 Enhacements (#846)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

* #751

1. Added Warning Screen
2. Correct handling of Unknown lines in Gyro Settings->Initial Setup

* #751

New v0.51 version.
- Added new menus to configure Model/Wing type.  Without it, the initial setup will not work properly.

* #751 More fixes on mixers and servo reverse

-- Fix problem reversing servos when using vtail/delta mix
-- Properly detect ch order of multimodule

* #751 Updated channel naming and docs

Updated readme documentation
Consistent naming of Ch across the code.

* #751 Fix message displaying data path

* #751  More improvements

1. Much easier to select channels > Ch6 for FMode, Gain and Panic channels
2. B&W version for smaller screens (128x64).. Memory footprint still a problem.
3. Fix a lot typos/misspell/grammar in the documentation

* Create DSM_AR636_TextGen.lua

Script to show Telemetry TextGen screens
for AR636 Receiver.
Really useful for BLADE helis using the AR636

Could replace dsmPID.lua

Still needs to be ported to smaller screens.

* #751 Enhancements for Lua Script tools

Enhancements

* Delete DSM_AR636_TextGen.lua

The TextGen functionality is included in DSM_AR636_Tel.lua. No longer needed

* Version 0.54

1. Fix problem with "Attitude Trim" Menu
2. New "MINimalistic" version for radios with very low memory
3. Externalized menu messages shared by all versions. the idea is to allow to translate it into other languages.
4. Correction of TextGen tools to work on black&white radios (some Lua functional differences). TextGen will be working on EdgeTx 2,8.3

---------

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2023-04-16 21:42:31 +02:00
Frankie Arzu
89023d4b55 Remove DSM_AR636_TextGen.lua (#837)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

* #751

1. Added Warning Screen
2. Correct handling of Unknown lines in Gyro Settings->Initial Setup

* #751

New v0.51 version.
- Added new menus to configure Model/Wing type.  Without it, the initial setup will not work properly.

* #751 More fixes on mixers and servo reverse

-- Fix problem reversing servos when using vtail/delta mix
-- Properly detect ch order of multimodule

* #751 Updated channel naming and docs

Updated readme documentation
Consistent naming of Ch across the code.

* #751 Fix message displaying data path

* #751  More improvements

1. Much easier to select channels > Ch6 for FMode, Gain and Panic channels
2. B&W version for smaller screens (128x64).. Memory footprint still a problem.
3. Fix a lot typos/misspell/grammar in the documentation

* Create DSM_AR636_TextGen.lua

Script to show Telemetry TextGen screens
for AR636 Receiver.
Really useful for BLADE helis using the AR636

Could replace dsmPID.lua

Still needs to be ported to smaller screens.

* #751 Enhancements for Lua Script tools

Enhancements

* Delete DSM_AR636_TextGen.lua

The TextGen functionality is included in DSM_AR636_Tel.lua. No longer needed

---------

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2023-03-19 06:19:35 +01:00
Frankie Arzu
66ac007d4c Frankie dsm telemetry lua scripts enhancements (#835)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

* #751

1. Added Warning Screen
2. Correct handling of Unknown lines in Gyro Settings->Initial Setup

* #751

New v0.51 version.
- Added new menus to configure Model/Wing type.  Without it, the initial setup will not work properly.

* #751 More fixes on mixers and servo reverse

-- Fix problem reversing servos when using vtail/delta mix
-- Properly detect ch order of multimodule

* #751 Updated channel naming and docs

Updated readme documentation
Consistent naming of Ch across the code.

* #751 Fix message displaying data path

* #751  More improvements

1. Much easier to select channels > Ch6 for FMode, Gain and Panic channels
2. B&W version for smaller screens (128x64).. Memory footprint still a problem.
3. Fix a lot typos/misspell/grammar in the documentation

* Create DSM_AR636_TextGen.lua

Script to show Telemetry TextGen screens
for AR636 Receiver.
Really useful for BLADE helis using the AR636

Could replace dsmPID.lua

Still needs to be ported to smaller screens.

* #751 Enhancements for Lua Script tools

Enhancements

---------

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2023-03-18 19:31:48 +01:00
Frankie Arzu
139cd4c583 Telemetry TextGen/Screens for BLADE Helis with AR636 (#813)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

* #751

1. Added Warning Screen
2. Correct handling of Unknown lines in Gyro Settings->Initial Setup

* #751

New v0.51 version.
- Added new menus to configure Model/Wing type.  Without it, the initial setup will not work properly.

* #751 More fixes on mixers and servo reverse

-- Fix problem reversing servos when using vtail/delta mix
-- Properly detect ch order of multimodule

* #751 Updated channel naming and docs

Updated readme documentation
Consistent naming of Ch across the code.

* #751 Fix message displaying data path

* #751  More improvements

1. Much easier to select channels > Ch6 for FMode, Gain and Panic channels
2. B&W version for smaller screens (128x64).. Memory footprint still a problem.
3. Fix a lot typos/misspell/grammar in the documentation

* Create DSM_AR636_TextGen.lua

Script to show Telemetry TextGen screens
for AR636 Receiver.
Really useful for BLADE helis using the AR636

Could replace dsmPID.lua

Still needs to be ported to smaller screens.

---------

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2023-02-07 10:48:46 +01:00
richardclli
0fed2486f5 FX9630 protocol support, resolves #801 (#805)
New protocol FX9630
2023-01-16 20:06:27 +01:00
Filip Kotoucek
11c01004bf KF606: subprotocol ZC-Z50v2 Cessna (#797)
Maybe newer iteration of Z50. My plane does not have front propeller.
But if there is one, its just for design. This model does not have front motor.

Thanks @pascallanger for support and reviews.
2023-01-15 21:26:35 +01:00
Frankie Arzu
f49f03d7da Frankie dsm fwrd prg enhancements (#806)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

* #751

1. Added Warning Screen
2. Correct handling of Unknown lines in Gyro Settings->Initial Setup

* #751

New v0.51 version.
- Added new menus to configure Model/Wing type.  Without it, the initial setup will not work properly.

* #751 More fixes on mixers and servo reverse

-- Fix problem reversing servos when using vtail/delta mix
-- Properly detect ch order of multimodule

* #751 Updated channel naming and docs

Updated readme documentation
Consistent naming of Ch across the code.

* #751 Fix message displaying data path

* #751  More improvements

1. Much easier to select channels > Ch6 for FMode, Gain and Panic channels
2. B&W version for smaller screens (128x64).. Memory footprint still a problem.
3. Fix a lot typos/misspell/grammar in the documentation

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2023-01-15 11:27:34 +01:00
Louis Botha
90bb5f8871 Update Protocols_Details.md (#796)
Fixed spelling mistake
2023-01-12 10:59:20 +01:00
Frankie Arzu
401cc76f20 Fix message displaying the DataPath after saving (#787)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

* #751

1. Added Warning Screen
2. Correct handling of Unknown lines in Gyro Settings->Initial Setup

* #751

New v0.51 version.
- Added new menus to configure Model/Wing type.  Without it, the initial setup will not work properly.

* #751 More fixes on mixers and servo reverse

-- Fix problem reversing servos when using vtail/delta mix
-- Properly detect ch order of multimodule

* #751 Updated channel naming and docs

Updated readme documentation
Consistent naming of Ch across the code.

* #751 Fix message displaying data path

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-12-20 23:48:23 +01:00
Frankie Arzu
6297810edc Updated Ch naming across all display, and updated Docs (#786)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

* #751

1. Added Warning Screen
2. Correct handling of Unknown lines in Gyro Settings->Initial Setup

* #751

New v0.51 version.
- Added new menus to configure Model/Wing type.  Without it, the initial setup will not work properly.

* #751 More fixes on mixers and servo reverse

-- Fix problem reversing servos when using vtail/delta mix
-- Properly detect ch order of multimodule

* #751 Updated channel naming and docs

Updated readme documentation
Consistent naming of Ch across the code.

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-12-20 22:58:38 +01:00
Frankie Arzu
01aef0a822 Frankie dsm fwrd prg enhancements (#785)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

* #751

1. Added Warning Screen
2. Correct handling of Unknown lines in Gyro Settings->Initial Setup

* #751

New v0.51 version.
- Added new menus to configure Model/Wing type.  Without it, the initial setup will not work properly.

* #751 More fixes on mixers and servo reverse

-- Fix problem reversing servos when using vtail/delta mix
-- Properly detect ch order of multimodule

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-12-20 10:12:34 +01:00
Frankie Arzu
186730231e Fwrd Programming New Model/Wingtype Setup Menus (#784)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

* #751

1. Added Warning Screen
2. Correct handling of Unknown lines in Gyro Settings->Initial Setup

* #751

New v0.51 version.
- Added new menus to configure Model/Wing type.  Without it, the initial setup will not work properly.

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-12-18 19:45:50 +01:00
pascallanger
770a12ffdf EU 2022-12-08 08:28:45 +01:00
pascallanger
40fa242012 Update Protocols_Details.md 2022-12-06 15:53:42 +01:00
Frankie Arzu
c4e70ab4fd Frankie dsm fwrd prg enhancements (#776)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

* #751

1. Added Warning Screen
2. Correct handling of Unknown lines in Gyro Settings->Initial Setup

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-12-02 08:53:13 +01:00
Frankie Arzu
2da8b3c42a Frankie dsm fwrd prg enhancements (#773)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

* #751 A few final changes

1. Update channel names to include channel number. i.e: Ch5 (Gear)
2,  Fix flight mode display for Heli Receiver
3. i think the unknown lines are to request info about the TX settings

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-12-01 08:57:33 +01:00
Frankie Arzu
38a79c816a Frankie dsm fwrd prg enhancements (#772)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

* #751 more cosmetic things

1. Added AR10360T,
2. Simplify way to configured the hack for more receivers.
3. Change some texts on menus to march spektrum
4. Background color in Spektrum theme to match

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-11-29 23:23:10 +01:00
Frankie Arzu
1d8f1a0857 Frankie dsm fwrd prg enhancements (#771)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

* #766 More enhacements

Added AR630
Make numbers right justified
Cleanup some log messages and line types.
Updated DSM FWD prog documentation

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-11-29 07:46:40 +01:00
Frankie Arzu
5901bac374 #766 Fix for editable Gains + Number formatting (#770)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

* #766  make editable Gain Values

Gains and other settings should be editable even when they are VALUE_NOCHANGING. Flight Mode is an exception that is handled properly. Right align numbers.

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-11-28 20:00:16 +01:00
Frankie Arzu
2e7b1dc904 #766 change validation of required files (#768)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

* #766

Change the way to detect that the files exist. now works on both ETX and OTX

* #766 Strange Flickering in OTX

Strange Flickering happening on OTX. Refreshing the screen on every cycle fixed the problem

* #766 Change way of dectecting EdgeTX

Change way of detecting OTX in multiple versions: OTX 2.3.14 and 2.3.15

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-11-27 15:10:02 +01:00
Frankie Arzu
7052751261 Frankie dsm fwrd prg enhancements (#763)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

* #751

Write documentation about the protocol so that we don't forget later what we know, and enable others to understand the logs and maybe help solve problems.

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-11-21 09:52:15 +01:00
Frankie Arzu
60047e2c73 Frankie dsm fwrd prg enhancements (#762)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

* #751 add check for required libraries

Add check that the required files in DSMLIB exist

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-11-20 18:24:47 +01:00
Frankie Arzu
40b393ac4a Frankie DSM fwrd Prog (more improvements) (#760)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

* #751 Cosmetic and Show Orientation Images

#751
1. Fix problems when text contradictions between Menu/Line Headers and List Values
2. Show Images of RX orientations
3. Able to Hack getting into Initial Setup and other menus who was failing before
4. Custumize the way Flight Mode reports the Value on Screen

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-11-20 18:01:16 +01:00
Frankie Arzu
1c6dc01959 Frankie dsm fwrd prg enhancements (#757)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

* #751 Fix problems With Reset RX

1. Fix problem when trying to Factory Reset. Enter Bind Mode. Save backup, Restore Backup

2. Found a way to advance on the Gyro initial Setup menus.. a bit of a hack, but works.

3. Handle RX resets properly. It needed after initial setup

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-11-18 10:41:59 +01:00
pascallanger
5148449066 FS2A: Turning on/off the LNA during bind. 2022-11-17 20:08:56 +01:00
Frankie Arzu
fcc4d19430 Frankie dsm fwrd prg enhancements (#755)
* #751 DSM Enhancements

 #751 DSM Forward Programming Enhancements (New GUI, etc)

* Make both work on EdgeTx and OpenTX

* #751 Turn OFF simulation by default

Distribution code with RX simulation OFF
Simulation should be only for Development

* #751 Update Readme Documentation

Updated the Readme.txt documentation
and removed compiled luac file that was check in by mistake

Co-authored-by: pascallanger <pascal_langer@yahoo.fr>
2022-11-17 17:50:36 +01:00
richardclli
c80f705fa2 Added MPM for Flysky PL18 PCB and casing design. (#754) 2022-11-17 11:37:11 +01:00
pascallanger
c95db35b41 Update Protocols_Details.md 2022-11-17 10:58:38 +01:00
pascallanger
35f3548992 Compilation option 2022-11-17 10:29:53 +01:00
pascallanger
58f6716035 Update README.md 2022-11-17 09:49:30 +01:00
pascallanger
2b15de0f90 Update README.md 2022-11-17 09:47:22 +01:00
pascallanger
be91409df9 Delete DSM FwdPrg.lua 2022-11-17 09:44:18 +01:00
Frankie Arzu
4d8e440965 Frankie dsm fwrd prg enhancements (#753)
DSM Forward Programming Enhancements (New GUI for Color+Touch and BW, etc). Work on EdgeTx and OpenTX.
2022-11-17 09:42:04 +01:00
pascallanger
2d469d074e Merge branch 'master' of https://github.com/pascallanger/DIY-Multiprotocol-TX-Module 2022-10-30 11:40:11 +01:00
pascallanger
96405d27b5 Extend Kyosho KT-17 bind time 2022-10-30 11:40:07 +01:00
yakulis
75c9fb40a7 Update DSM FwdPrg.lua (#735)
Panic Text Updates - The following strings were updated:
Text[0x00D2]="Panic Channel"
Text[0x008E]="Panic Delay"
Text[0x01FC]="Panic Flight Mode"
2022-10-12 11:35:09 +02:00
Pieter du Preez
cd1c15a45a Added documentation for using dfu-util for flashing STM32 targets. (#727)
This patch adds documentation, explaining how to flash firmware to DFU
capable multimodules.

A dfu-util command was taken and adapted from:
https://github.com/benlye/flash-multi/blob/master/doc/Troubleshooting.md

Using dfu-util is straight forward, easy and very safe.
2022-10-12 11:34:32 +02:00
pascallanger
2bd50f4c8c V761/TOPRC: new sub protocol
Top RC Hobby mini planes
2022-09-26 12:02:38 +02:00
yakulis
4c2ddcbe48 Update DSM FwdPrg.lua (#733)
Reversing 'Off' and 'On' text values in lines #555 and #556.  They are used in the SAFE and AS3X menu items in the DSM Forward Programming section, and they are functioning backwards. This will correct the issue. This is the fix for Issue #728
2022-09-11 06:01:02 -04:00
Ben Lye
d7f9ef6967 Use devel boards in CI workflow (#709) 2022-07-21 10:20:16 +02:00
pascallanger
bfc8c2f9fd Kyosho2/KT-17: only 1 ID 2022-07-20 17:20:27 +02:00
pascallanger
ce6243d6e3 FX/620: IDs 2022-07-17 09:07:28 +02:00
pascallanger
80f9ff4163 Update FX_nrf24l01.ino 2022-07-15 15:44:10 +02:00
pascallanger
d9f8a3989a FX/FX620: only 1 ID 2022-07-15 15:43:04 +02:00
pascallanger
416f7d5c19 FX/FX620 another try 2022-07-12 08:05:41 +02:00
pascallanger
eb24dd5549 FX/FX620
I messed up the hopping, I must have looked at the wrong file.
2022-07-11 11:12:20 +02:00
pascallanger
ba19592973 FX/FX620 debug off 2022-07-11 09:11:11 +02:00
pascallanger
98d8d7fb5f FX/FX620 new protocol 2022-07-11 09:03:31 +02:00
pascallanger
ad0947b0b7 Updated MT99xx/PA18: need someone to test... 2022-07-09 00:43:28 +02:00
pascallanger
c093f21b31 Update README.md 2022-07-08 10:38:13 +02:00
pascallanger
c5a3e305f9 Update Protocols_Details.md 2022-07-08 09:46:58 +02:00
pascallanger
e085602a6c FX816 is not limited to the P38 2022-07-08 09:46:28 +02:00
pascallanger
dee25215cf Update Protocols_Details.md 2022-07-08 09:41:16 +02:00
Michael
ef1bb1ead7 adjusted comment according to change in commit da33df43 (#696) 2022-07-07 11:44:46 +02:00
pascallanger
90170493c0 Update doc 2022-06-30 17:40:55 +02:00
pascallanger
00a9057186 Update Protocols_Details.md 2022-06-28 14:24:19 +02:00
pascallanger
05c300e979 Update Protocols_Details.md 2022-06-28 10:23:20 +02:00
pascallanger
6730ed6246 Update Protocols_Details.md 2022-06-27 17:20:55 +02:00
pascallanger
0a0463652b E129/C186 protocol
C186/E120 models
2022-06-27 16:59:48 +02:00
pascallanger
4f580a4286 Update Hardware.md 2022-06-16 10:36:34 +02:00
Michael
0616cab386 Fixes a problem where setting failsafe values was only possible once after bind and only set values for the first 12 channels. This fix allows setting failsafe values without having to rebind and sets failsafe values correctly for all possible 16 channels. (#695)
Notes for OpenTX/EdgeTX:
This fix doesn't exhibit servo jitter if failsafe mode was left on Custom, however it is still recommended to set failsafe mode back to Receiver after setting failsafe values.
It is still necessary to wait at least 8 seconds switching back from failsafe mode Custom to failsafe mode Receiver as OpenTX/EdgeTX will trigger the data transfer in Custom mode only every 7 seconds.

Bench tested with HoTT receivers GR-16, GR-24pro, GR-32
Flight tested with HoTT receiver GR-24
2022-06-13 14:28:21 +02:00
Michael
175cfa5e93 This is the Graupner HoTT adapted version of the Model Locator script. It uses the Graupner HoTT telemetry sensor "Rssi" instead of the OpenTX sensor "RSSI". (#693)
Reasoning: The OpenTX sensor "RSSI" is populated by the individual OpenTX telemetry protocol implementations and returns a value from 0..100 (percent) originating from the early FrSky implementation. It turns out that FrSky did not really provide a genuine signal strength indicator in units of dbm but a link quality indicator in 0..100%. With Graupner HoTT the link quality indicator is not a good basis for the model locator as it is very non-linear and doesn't change much with distance. Using the Graupner HoTT telemetry sensor "Rssi" which is a true signal strength indicator serves the purpose of locating a model much better as it varies much more with distance.
2022-06-07 10:51:26 +02:00
Pascal Langer
dbfccad568 Update DSM FwdPrg.lua 2022-04-25 10:33:16 +02:00
Pascal Langer
3fe6dc64fa KF606/MIG320: Added LED control 2022-04-15 17:29:25 +02:00
Peter Feerick
49068af59f fix: MultiConfig lua set and reset subProtocol (#672) 2022-03-25 09:12:14 +01:00
pascallanger
fbd81c6e26 Update Protocols_Details.md 2022-02-07 18:49:38 +01:00
Ryan5732
9cac96d6a7 Small Readme Typos (#661) 2022-02-03 14:11:26 +01:00
Pascal Langer
5987aa40a6 Another try on PA18 2022-01-25 15:21:22 +01:00
Pascal Langer
30cb812549 Try PA18 2022-01-24 08:36:00 +01:00
Pascal Langer
0fd2e36046 test PA18 2022-01-23 19:08:46 +01:00
Pascal Langer
8b05e55ebd MT99xx2/PA18: new protocol 2022-01-23 17:56:00 +01:00
Pascal Langer
af71a208fd Ready for release 2022-01-16 11:00:50 +01:00
mheimlich
7e5cb8e884 mention XK A800 in V911S/E119 details (#654) 2022-01-16 10:54:04 +01:00
MattCarothers
8c669ea015 Updated several text fields (#651) 2022-01-09 17:25:11 +01:00
Anders Höglund
acd8379077 A few more Spektrum Fwd Programming text updates (#632)
* DSM FP, Added AR8360T

* DSM FP, Added a few unkown empty lines
2021-11-19 08:37:28 +01:00
Pascal Langer
97c6088715 fix compilation? 2021-11-13 19:08:38 +01:00
Pascal Langer
db017c73b6 HS6200 emulation using CYRF for E01X protocol 2021-11-13 19:03:01 +01:00
Anders Höglund
24aaa0dd0c Text updates in Spektrum Fwd Prog LUA script (#630)
* DSM FP, Added AR636B

* DSM FP, Added AR637TA

* DSM FP, Added On, conflict with AR636B

* DSM FP, Rx name conflict resolved.
2021-11-12 18:37:52 +01:00
Michael
da33df4346 added packet_in[14] to transfer HoTT device warnings to OpenTx (#627) 2021-11-04 14:57:25 +01:00
Pascal Langer
22590ed4f7 Update DSM FwdPrg.lua 2021-10-26 16:34:38 +02:00
Pascal Langer
c0bc64c2aa V911S: increased bind time 2021-10-24 12:03:09 +02:00
Pascal Langer
694d968e8c Update Propel_nrf24l01.ino 2021-10-24 11:04:57 +02:00
Pascal Langer
fff3b8830e MT99xx/A180: F949S flags for RATE, RXLED and 3D6G 2021-10-24 11:04:44 +02:00
Pascal Langer
b740f4cd24 V911S/E119: add 6G_3D channel for P40 plane 2021-10-24 09:57:24 +02:00
Pascal Langer
e247b8b9c1 DSM Fwd Pgm updated 2021-10-20 15:13:56 +02:00
Pascal Langer
4f7af553d1 Update doc 2021-09-17 17:07:15 +02:00
Pascal Langer
570e6f8c64 Update Protocols_Details.md 2021-09-17 09:48:35 +02:00
Pascal Langer
b6e665b567 Devo: fix typo 2021-09-16 16:13:39 +02:00
Pascal Langer
48e82304a0 Update Devo_cyrf6936.ino 2021-09-16 00:30:46 +02:00
Pascal Langer
7b58b9aca0 Devo: support for 2 GPS formats
Use the Fixed ID field, 0/1 first GPS format, +2 for the other format -> 2/3
2021-09-16 00:11:25 +02:00
Pascal Langer
dfcf3f533c Update NRF24l01_SPI.ino 2021-09-16 00:08:47 +02:00
Pascal Langer
4c14925b4f Bump version for release 2021-09-12 19:35:11 +02:00
Pascal Langer
4c74bc869d Update _Config.h 2021-09-11 00:08:09 +02:00
Pascal Langer
45edfa1ec0 AFHDS2A doc update 2021-09-10 23:58:12 +02:00
Pascal Langer
88343b7424 Proto list: fix flags 2021-09-09 08:40:09 +02:00
Pascal Langer
13197840c2 V761: code cleanup 2021-09-09 08:39:37 +02:00
Pascal Langer
ffe4ac68fd Proto list: add number of protocols in the list 2021-09-08 14:30:01 +02:00
Pascal Langer
5bab5f03db Update Multi_Protos.ino 2021-09-08 13:38:25 +02:00
Pascal Langer
ae748e25f8 Update XN297Dump_nrf24l01.ino 2021-09-07 23:17:21 +02:00
Pascal Langer
e9c7959ecb Update V761_nrf24l01.ino 2021-09-07 23:17:11 +02:00
Pascal Langer
bf09855014 Another attempt 2021-09-07 16:59:06 +02:00
Pascal Langer
32bd39f209 Save space in the 5in1 modules 2021-09-07 15:07:37 +02:00
Pascal Langer
940f241b9d Fix compilation issues 2021-09-07 14:29:35 +02:00
Pascal Langer
5c00ce6b88 New 0 protocol: enable to list all protocols and sub protocols 2021-09-07 14:08:24 +02:00
Pascal Langer
016b282246 Multi Status: send frame as soon as a new protocol is selected 2021-09-05 22:15:56 +02:00
Pascal Langer
d6ecac1302 Xerall: few improvements 2021-09-04 11:48:41 +02:00
Ben Lye
901f8ca6b0 Disable some protocols for the DIY 5-in-1 (#618) 2021-09-01 15:20:10 +02:00
Pascal Langer
9c3b6ba9f6 Update Validate.h 2021-09-01 09:45:38 +02:00
Pascal Langer
53ec484028 Update Validate.h 2021-09-01 01:39:26 +02:00
Pascal Langer
246e808cb4 Xerall protocol 2021-09-01 01:21:38 +02:00
Pascal Langer
a7b68dc2aa F949G: will it work? 2021-08-27 10:22:47 +02:00
Pascal Langer
08404f9223 F949G: another try... 2021-08-26 23:43:42 +02:00
Pascal Langer
149554e61c Update MT99xx_ccnrf.ino 2021-08-26 23:23:38 +02:00
Pascal Langer
7b71425db2 F949G test with original radio ID 2021-08-26 23:19:59 +02:00
Pascal Langer
f9cfb7f20f Update Protocols_Details.md 2021-08-26 22:51:57 +02:00
Pascal Langer
506ee43d41 Update _Config.h 2021-08-26 22:35:42 +02:00
Pascal Langer
ebde0915cd MT99xx/F949G: new sub protocol 2021-08-26 22:33:38 +02:00
Pascal Langer
2501656bf4 Update XN297Dump_nrf24l01.ino 2021-08-26 11:52:36 +02:00
Pascal Langer
9356e7654e XN297EMU: allows to send and receive 0 payload length in enhanced mode 2021-08-25 19:07:36 +02:00
Pascal Langer
4f1e5d2452 BUGSMINI: fix
No one has reported an issue but from the look of the code it was broken since some time...
2021-08-25 19:05:24 +02:00
Ben Lye
64c75414d8 Add release build for 64KB CC2500-only module (#615) 2021-08-24 20:54:46 +02:00
Pascal Langer
5147833487 DSM RX: use directly the TX type and channels 2021-08-21 10:14:05 +02:00
Ben Lye
324419241f Prefix release binaries with mm instead of multi (#596)
Better for radios with 128x64 LCDs.
2021-08-16 17:59:07 +02:00
Pascal Langer
1a921b1cdb Disable multi config if telemetry is disabled 2021-07-05 17:08:57 +02:00
Pascal Langer
25c052c0a3 KF606: new sub protocol MIG320 2021-07-04 14:05:42 +02:00
Pascal Langer
a02586cca9 RadioLink: RSSI correction 2021-07-03 14:09:28 +02:00
Pascal Langer
226e082c5a E129 and E010R5 not supported on atmega328p 2021-06-30 09:45:25 +02:00
Pascal Langer
5afdff8477 V911S: Rate channel on CH6 (default is high) 2021-06-28 18:10:44 +02:00
Pascal Langer
c52ac2cefc Fix XN297Dump enhanced payload detection 2021-06-28 18:04:17 +02:00
pascallanger
09f39ea60f Update README.md 2021-06-27 12:38:53 +02:00
Harry Phillips
41e31eae6d Set reserved field in CABELL packet to current channel (#593) 2021-06-24 11:49:47 +02:00
Pascal Langer
dcf20951ba Update Protocols_Details.md 2021-06-20 18:51:23 +02:00
Pascal Langer
6e9ebfd695 Mould King: control up to 4 bricks at the same time 2021-06-20 18:39:27 +02:00
Pascal Langer
c36b112437 Update Multi_Config.ino 2021-06-17 15:42:09 +02:00
Pascal Langer
24fbd44f5b Multi Config: eeprom format for atmega 2021-06-17 15:40:28 +02:00
Pascal Langer
d0db7829e5 Multi config: enabled by default, LUA script update 2021-06-17 15:30:46 +02:00
Pascal Langer
58ed8ca60f Mould King: Analog and digital sub protocols 2021-05-27 19:01:08 +02:00
Pascal Langer
4d2c8ef04e Fix RadioLink: request telemetry every time to time like original instead of all the time 2021-05-25 14:54:17 +02:00
Pascal Langer
438e85c551 MouldKing: match original 2021-05-09 03:36:42 +02:00
Pascal Langer
06b336ee59 Mould King: fix frequencies 2021-05-04 14:58:40 +02:00
pascallanger
a93adeb75e Update Protocols_Details.md 2021-05-04 11:29:44 +02:00
Pascal Langer
802e69563e ... 2021-05-04 10:53:38 +02:00
Pascal Langer
a8897df3f2 New protocol: Mould King 2021-05-04 10:39:13 +02:00
Pascal Langer
7157d3d906 Losi: optimization 2021-05-03 16:57:08 +02:00
Pascal Langer
96b8a500b4 New protocol: Losi 2021-05-03 15:29:24 +02:00
Pascal Langer
51a3ef8ee9 Update XN297Dump_nrf24l01.ino 2021-05-01 18:45:20 +02:00
Pascal Langer
652d6604e7 Update Multiprotocol.h 2021-05-01 18:35:47 +02:00
Pascal Langer
b9028ab4b4 XN297Dump: CC2500 dump @250K 2021-05-01 18:15:34 +02:00
Konstantin Tretyakov
62c509b03c Add the IKEA Ansluta remote-controllable lighting protocol (#566)
* Add the IKEA Ansluta remote-controllable lighting protocol

* Fixes to IKEA Ansluta implementation
2021-04-24 21:46:29 +02:00
Pascal Langer
1648a0780a XK: fix twitch on other channels than rudder 2021-04-24 12:54:17 +02:00
pascallanger
3b1af68ed6 Update FUNDING.yml 2021-04-21 13:17:46 +02:00
pascallanger
aeed7bac57 Create FUNDING.yml 2021-04-20 23:17:50 +02:00
Pascal Langer
2bb76a40f3 Pelikan/SCX24: add second hopping table 2021-04-20 22:24:01 +02:00
Pascal Langer
0c129a45aa SCX24 IDs 2021-04-18 16:41:49 +02:00
Pascal Langer
2a383c7285 Pelikan/SCX24: fix? 2021-04-17 22:55:43 +02:00
Pascal Langer
34f16b0b66 MT99XX/Dragon: batt telemetry correction & low batt flag 2021-04-17 18:31:41 +02:00
Pascal Langer
a9d9c4cdfa Update A7105_SPI.ino 2021-04-17 11:57:00 +02:00
Pascal Langer
4a1c986dd0 Kyosho/FHSS fix? 2021-04-17 11:52:21 +02:00
Pascal Langer
756e9b3213 Update Protocols_Details.md 2021-04-16 15:00:33 +02:00
Pascal Langer
61a284863e Update Protocols_Details.md 2021-04-16 14:59:10 +02:00
Pascal Langer
39410c290b Pelikan/SCX24: new sub protocol 2021-04-16 14:50:53 +02:00
Pascal Langer
9e0684b6cb CABELL: code optimization 2021-04-07 09:02:50 +02:00
Pascal Langer
13add5b9f2 Devo: fix GPS year 2021-04-06 18:15:34 +02:00
Pascal Langer
475cd1af98 Atmega CC2500 build: remove FRSKYL to fit 2021-04-06 10:36:15 +02:00
Pascal Langer
04d08c6d67 FrSkyX2: changed bind bytes 2021-04-06 10:18:48 +02:00
Pascal Langer
6295bb1bbc Packed protocols definition to save space 2021-04-05 17:43:42 +02:00
Pascal Langer
931ba2bd68 Hitec: fix freq tune 2021-04-02 17:42:44 +02:00
Pascal Langer
769fb4ff94 Update Protocols_Details.md 2021-03-30 16:41:29 +02:00
Pascal Langer
aa7c18a2bd FrSkyX: fix the need to rebind RXs 2021-03-30 15:13:00 +02:00
Pascal Langer
f95cfa1261 Update Protocols_Details.md 2021-03-30 14:13:18 +02:00
Pascal Langer
8c12aaf2c1 DSMR: new surface protocol 2021-03-30 12:10:29 +02:00
Pascal Langer
94f73bd54f MT99xx: Added voltage telemetry for the Dragon sub protocol 2021-03-27 11:51:53 +01:00
Pascal Langer
9b3549d4a9 FrSkyX: code review 2021-03-25 10:10:53 +01:00
Pascal Langer
7bc05cb63c Update Multiprotocol.h 2021-03-19 17:11:06 +01:00
Pascal Langer
84780a9d90 Multi Config 2021-03-19 17:06:58 +01:00
Pascal Langer
37e029c612 Bug fix in XN297 emu layer when address is 3 bytes and CC2500 in use 2021-03-17 19:24:42 +01:00
Pascal Langer
c47ed8aca8 E016H has its own protocol now 2021-03-17 18:46:48 +01:00
Pascal Langer
5bb0752d5e Update include to xn297... 2021-03-17 17:19:41 +01:00
Pascal Langer
4a626eaf14 Change XN297 emulation layer
Loads of protocols have been touched by this change. Some testing has been done but please test on all your models.
The XN297 emulation selects in this order:
 - the CC2500 if it is available and bitrate=250K. Configure the option field automatically for RF tune.
 - the NRF for all bitrates if it is available
 - if NRF is not available and bitrate=1M then an invalid protocol is sent automatically to the radio.
CC2500 @250K can now receive normal and enhanced payloads.
OMP protocol supports telemetry on CC2500 and is also for NRF only modules including telemetry.
Separation of E016H (new protocol) from E01X due to different structure.
MJXQ, MT99XX, Q303 and XK: some sub protocols available on CC2500 only.
2021-03-17 17:05:42 +01:00
pascallanger
47de19c8a5 DSM RX output ranges 2021-03-15 08:45:27 +01:00
Pascal Langer
3d4cfa30ac Remove spaces 2021-03-15 08:43:25 +01:00
pascallanger
d658bee05a Add files via upload 2021-03-15 08:39:06 +01:00
pascallanger
820c181394 Update CPPM_HW_Mod.md 2021-03-15 08:07:42 +01:00
pascallanger
c9774f557e Add files via upload 2021-03-15 08:06:24 +01:00
Pascal Langer
b17618a5a8 Update Protocols_Details.md 2021-03-14 19:22:49 +01:00
Pascal Langer
03d0adbd74 CCPM: added comment to disable the telemetry after setup 2021-03-14 19:00:45 +01:00
Pascal Langer
905ee4b1ed Fix module boot issue? 2021-03-14 11:15:24 +01:00
Pascal Langer
dbc33951a4 Fix for module boot issue? 2021-03-13 18:18:07 +01:00
Pascal Langer
732e66cab2 HoTT: fix Text config in Sync mode 2021-03-13 11:01:51 +01:00
pascallanger
0dab92552a Update CPPM_HW_Mod.md 2021-03-08 17:47:28 +01:00
pascallanger
047952537a Update CPPM_HW_Mod.md 2021-03-08 13:39:59 +01:00
pascallanger
d4bf1fb36e Update CPPM_HW_Mod.md 2021-03-08 13:36:43 +01:00
pascallanger
ff817cd098 Update Protocols_Details.md 2021-03-08 11:36:59 +01:00
pascallanger
04ea44ed4b Update CPPM_HW_Mod.md 2021-03-08 11:19:10 +01:00
pascallanger
e23c8e2216 Add files via upload 2021-03-08 10:15:47 +01:00
pascallanger
afb4802a2c Update CPPM_HW_Mod.md 2021-03-07 17:34:16 +01:00
pascallanger
3a5d341514 CPPM hardware mod initial page 2021-03-07 17:31:45 +01:00
pascallanger
b6bcab1604 CPPM hardware mod images 2021-03-07 17:24:15 +01:00
Pascal Langer
0a998d2dc5 Enable CPPM by default 2021-03-07 11:12:49 +01:00
Pascal Langer
7927bc601e CPPM for RX protocols 2021-03-06 18:51:53 +01:00
Pascal Langer
f8cc913898 Update Multiprotocol.ino 2021-03-06 12:00:05 +01:00
Pascal Langer
a5428bc180 Removed SBUS trainer option 2021-03-06 11:33:32 +01:00
Pascal Langer
c0285f81f0 JOYSWAY: fix? 2021-03-05 19:57:33 +01:00
Pascal Langer
600049898a SBUS/CPPM: fixed switching from CPPM to SBUS 2021-03-04 21:28:06 +01:00
Pascal Langer
0e1db8f06b SBUS/CPPM: fixed switching from SBUS to CPPM
There is still an issue from CPPM to SBUS...
2021-03-04 19:02:45 +01:00
Pascal Langer
ec83f1e5a3 Disable SBUS serial when switching to CPPM 2021-03-04 15:23:23 +01:00
Pascal Langer
f8f7769d9c Update DSM subprotocols naming 2021-03-04 10:08:52 +01:00
Pascal Langer
4dacac29c6 SBUS/CPPM: restore normal telemetry on student link lost
Once the setup is done check the "Disable telemetry" box to make sure that there is no interference between the internal module and Multi telemetry.
2021-03-04 09:52:54 +01:00
Pascal Langer
593f3b87f1 SBUS/CPPM: fixed telemetry_link 2021-03-04 09:11:20 +01:00
Pascal Langer
bb70116df0 SBUS and CPPM output 2021-03-03 10:07:19 +01:00
Pascal Langer
d7c24d62ed Update Devo_cyrf6936.ino 2021-03-02 18:32:02 +01:00
Pascal Langer
07df1a8959 DEVO telemetry: reduce the voltage and RSSI refresh frequency 2021-03-02 17:37:28 +01:00
Pascal Langer
ca9e2870ab DEVO: temp telem fix 2021-03-02 16:30:14 +01:00
Pascal Langer
99ca6fa36c DEVO: fix temp telemetry 2021-03-02 16:26:30 +01:00
Pascal Langer
3d82560f71 Update Protocols_Details.md 2021-03-02 16:20:05 +01:00
Pascal Langer
44d362aeb4 DEVO: improve telemetry 2021-03-02 16:14:14 +01:00
Pascal Langer
3d4ed5ad11 SFHSS: Timing debug 2021-03-02 12:01:23 +01:00
Pascal Langer
ca3c2bbdc8 Update Protocols_Details.md 2021-03-02 10:42:25 +01:00
Pascal Langer
90c226c748 LOLI lua script 2021-03-02 10:39:11 +01:00
Pascal Langer
b757283f41 JOYSWAY: new protocol UNTESTED 2021-03-02 10:00:33 +01:00
Pascal Langer
b3132c7bf1 Devo: added telemetry voltage 3 2021-03-02 09:32:59 +01:00
Pascal Langer
9ba56f040a Update Futaba_cc2500.ino 2021-03-01 16:31:11 +01:00
Pascal Langer
ac71b4d981 Update Devo_cyrf6936.ino 2021-03-01 14:02:39 +01:00
Pascal Langer
6bb2c06cf6 Fix compilation 2021-03-01 13:53:39 +01:00
Pascal Langer
2ad3c727fd Few changes... 2021-03-01 13:48:23 +01:00
Pascal Langer
d36af55b84 DEVO: full telemetry 2021-03-01 13:47:44 +01:00
Pascal Langer
f19bb05c7a WFLY: Failsafe values 2021-02-24 16:29:24 +01:00
Pascal Langer
08ea8818fb E010R5: 5th ID 2021-02-24 10:26:58 +01:00
Pascal Langer
59c541d013 MT99xx missing break 2021-02-23 09:52:46 +01:00
Ben Lye
37e2b5f41c Merge pull request #532 from benlye/new-builds
5-in-1 builds for DIY and T-Lite
2021-02-21 19:16:24 +00:00
Ben Lye
614a330cf2 5-in-1 builds for DIY and T-Lite 2021-02-21 18:58:02 +00:00
Pascal Langer
9106548859 T18 default build 2021-02-21 18:56:48 +01:00
Pascal Langer
2f07e79e50 T18 build by default 2021-02-21 18:35:24 +01:00
Pascal Langer
2233f6f862 SX1276: RF power adjustment for DIY & Jumper T-Lite 2021-02-21 16:05:25 +01:00
Pascal Langer
ae842f0bdc MT99XX Dragon telem prep 2021-02-17 10:26:38 +01:00
Ben Lye
4b36656246 Merge pull request #529 from benlye/build-fix
Update MT99xx_nrf24l01.ino
2021-02-16 19:39:55 +00:00
Ben Lye
ea282489f9 Update MT99xx_nrf24l01.ino 2021-02-16 19:34:01 +00:00
Ben Lye
6f2d9430d0 Merge pull request #528 from benlye/build-fix
Disable CCNRF protocols when needed
2021-02-16 18:40:58 +00:00
Pascal Langer
bccd9dc0d9 Fix XK protocol with latest change 2021-02-16 19:38:34 +01:00
Ben Lye
af919fb940 Fix CCNRF_PROTOCOLS 2021-02-16 18:31:40 +00:00
Ben Lye
7dab0de3c5 Update main.yml 2021-02-16 18:26:14 +00:00
Pascal Langer
2c0525421a Update Protocols_Details.md 2021-02-16 19:08:57 +01:00
Pascal Langer
0844ec2efd Add more protocols which can run with the CC2500
Use CC2500 only when emulating NRF250K/XN297_250K
2021-02-16 19:06:23 +01:00
Pascal Langer
49c3af12f9 AFHDS2A: fix issue with fs-x6b 2021-02-14 20:51:15 +01:00
Pascal Langer
96d335f458 Hide scanner from the available protocols 2021-02-13 20:39:00 +01:00
Pascal Langer
eae412fe41 E010r5: 1 more ID 2021-02-13 09:26:03 +01:00
Pascal Langer
0270420531 XN297dump: increase polling 2021-02-12 19:05:39 +01:00
Pascal Langer
93bb117961 RF switch fix... 2021-02-12 16:29:36 +01:00
Pascal Langer
29d1fb00b1 More code optimization 2021-02-12 11:21:42 +01:00
Pascal Langer
5a49d99c4f Update _Config.h 2021-02-11 20:09:40 +01:00
Pascal Langer
d66bf1a5b3 NRF init changed to most likely default 2021-02-11 18:40:29 +01:00
Pascal Langer
b41dccef67 HONTAI: use the global CRC calculation routine 2021-02-11 10:54:55 +01:00
Pascal Langer
addf2c5143 MT99XX/Dragon: beginner and intermediate swapped... 2021-02-11 09:50:41 +01:00
Pascal Langer
ff829f1f7b M-Link telemetry forwarded to OpenTX 2021-02-10 12:31:37 +01:00
Pascal Langer
7ee72976c4 M-Link: added vario 2021-02-10 10:13:51 +01:00
Pascal Langer
dc18e8e5b2 MT99XX: new subproto Dragon 2021-02-10 09:59:30 +01:00
Pascal Langer
97de2aaf3d One file missing in the push... 2021-02-09 18:31:13 +01:00
Pascal Langer
3b8b2ef376 Protocol init function modified 2021-02-09 18:23:33 +01:00
Pascal Langer
d496f62719 Removed depreciated MULTI_STATUS 2021-02-08 09:36:47 +01:00
Pascal Langer
fc978f95ef Disabling AFHDS2A Hub telemetry to fit in flash... 2021-02-07 19:20:12 +01:00
Pascal Langer
596e8c9b55 Update MLINK_cyrf6936.ino 2021-02-07 18:57:59 +01:00
Pascal Langer
0cf58c2990 MLink: added voltage, current, rpm, temp sensors and lqi 2021-02-07 18:51:36 +01:00
Pascal Langer
6ba1c8b118 Update Protocols_Details.md 2021-02-06 10:36:14 +01:00
Pascal Langer
b949ac0fed Update Protocols_Details.md 2021-02-06 10:35:15 +01:00
Pascal Langer
510f892d2f MLink: use only odd channels like original 2021-02-06 10:23:10 +01:00
Pascal Langer
17750e774a M-Link Failsafe 2021-02-06 09:58:36 +01:00
Pascal Langer
be1591c489 Update Protocols_Details.md 2021-02-05 18:44:48 +01:00
Pascal Langer
3b22705166 Exclude MLink from T18 build to save Flash space 2021-02-05 17:21:07 +01:00
Ben Lye
c05c0a5693 Merge pull request #518 from pascallanger/benlye-patch-1
Update main.yml
2021-02-05 16:15:36 +00:00
Ben Lye
d6fc6a3517 Update main.yml
Disable default configuration builds for T18 and 4in1.
2021-02-05 16:09:30 +00:00
Pascal Langer
7bfaee8b4f Update MLINK_cyrf6936.ino 2021-02-05 16:20:42 +01:00
Pascal Langer
89c00e8f17 Initial M-LINK release 2021-02-05 12:28:35 +01:00
pascallanger
447a58966f Update Compiling_STM32.md 2021-02-04 14:19:29 +01:00
pascallanger
74162aa972 Update Compiling_STM32.md 2021-02-04 14:15:57 +01:00
Pascal Langer
78a1e61f7a Update Telemetry.ino 2021-02-04 14:07:15 +01:00
Pascal Langer
a917227ddc Bayang: generic frsky hub function 2021-02-04 12:05:57 +01:00
Pascal Langer
c866d07743 Bayang: add PID to telemetry 2021-02-03 19:44:59 +01:00
Pascal Langer
43d969f962 FrSky RX: sub protocol to erase clone IDs 2021-02-03 16:57:14 +01:00
Pascal Langer
3973b42f81 MT99XX fix bind hopping 2021-02-02 17:55:40 +01:00
Pascal Langer
6046ad81db Update Protocols_Details.md 2021-02-02 14:42:22 +01:00
Pascal Langer
63a9874aea Futaba S-FHSS: another fs throw test 2021-02-02 12:06:54 +01:00
Pascal Langer
89420fe2d4 Futaba S-FHSS: failsafe throw test 2021-02-02 10:06:24 +01:00
Pascal Langer
9769354989 MT99XX: no autobind, 1 ID 2021-02-01 21:31:34 +01:00
Pascal Langer
580b996215 MT99XX: code optimization 2021-02-01 19:26:34 +01:00
Pascal Langer
8f5fb5083f MT99X sub A180: timing 2021-02-01 19:06:47 +01:00
Pascal Langer
821076ce95 MT99XX: code cleanup 2021-02-01 18:25:11 +01:00
Pascal Langer
0bfe1f8e63 MT99XX: new sub protocol A180 2021-02-01 15:21:39 +01:00
Pascal Langer
9c35f6f73c Futaba S-FHSS: Fist attempt to fix failsafe 2021-02-01 11:54:16 +01:00
Pascal Langer
983debe6ce WFLY2: Failsafe working for values, hold and no pulse 2021-01-29 15:41:47 +01:00
Pascal Langer
66704b5a13 AFHDS2A: common timing 2021-01-28 15:41:59 +01:00
Pascal Langer
f11da0c1de DSM: fix low power 2021-01-28 09:09:43 +01:00
Pascal Langer
7676398aab Fix OMP protocol 2021-01-25 11:33:30 +01:00
Pascal Langer
9c6c55fa00 E010r5: added 2 TX IDs 2021-01-21 15:31:37 +01:00
Pascal Langer
5b9ca3ba06 Move the CYRF emulation functions around for future 2021-01-21 12:24:46 +01:00
Pascal Langer
23141b6087 E016Hv2 and ESKY150V2 don't need the NRF code anymore 2021-01-21 11:46:54 +01:00
Pascal Langer
6d4b4bd2c0 Update MultiChannelsUpdater.lua 2021-01-21 09:32:45 +01:00
Pascal Langer
5cec22a757 AFHDS2A RX: trial to fix bind with original TX 2021-01-19 22:50:55 +01:00
pascallanger
153ba2e090 Update Transmitters.md 2021-01-19 12:26:15 +01:00
Pascal Langer
21e8bed52b E016HV2: fixed a left over from protocol reverse engineering 2021-01-19 12:15:23 +01:00
Pascal Langer
ecfc5b0313 End bind as requested by the radio on more protocols 2021-01-19 12:13:24 +01:00
Pascal Langer
2bcebbda45 LOLI: adjust timing 2021-01-18 15:51:35 +01:00
Pascal Langer
52e8d87ab1 LOLI RX configuration script 2021-01-18 11:46:19 +01:00
pascallanger
b613345da4 Update Protocols_Details.md 2021-01-17 17:16:11 +01:00
pascallanger
f2665ca786 Update Protocols_Details.md 2021-01-17 16:53:42 +01:00
Pascal Langer
e3189d3aed E010r5: add GLIDE channel 2021-01-17 15:59:05 +01:00
pascallanger
c829e1c86f Protocol E129: Add E130 model, Protocol E010r5: Add GLIDE channel 2021-01-17 15:57:52 +01:00
pascallanger
8499a508f5 Protocol E129: Add E130 model, Protocol E010r5: Add GLIDE channel 2021-01-17 15:57:42 +01:00
Pascal Langer
50dec0e55d AFHDS2A RX: fixed 2021-01-16 18:33:10 +01:00
Pascal Langer
6f419adb7f Fix CRC in various places 2021-01-16 16:50:45 +01:00
pascallanger
502e8beafb Update Protocols_Details.md 2021-01-16 15:48:40 +01:00
Pascal Langer
5aae065dc0 New protocol: E129 2021-01-16 15:45:19 +01:00
pascallanger
152dbed3fa Add Kyosho FHS details 2021-01-14 08:51:22 +01:00
Pascal Langer
b516bb8d20 Fix AFHDS2A RX 2021-01-12 14:02:13 +01:00
Pascal Langer
30e3e84066 LOLI: RX config 2021-01-11 16:27:59 +01:00
Pascal Langer
8338104266 Update XN297Dump_nrf24l01.ino 2021-01-11 12:37:58 +01:00
Pascal Langer
00c6aa52b9 Fix NCC1701... 2021-01-11 12:33:29 +01:00
Pascal Langer
e5689d2f1b Fix FQ777 2021-01-11 12:30:12 +01:00
Pascal Langer
b51dedcea1 M-Link: still work in progress 2021-01-11 12:13:03 +01:00
Pascal Langer
49f004e53f E010r5: added flip, led and calib channels 2021-01-11 12:12:26 +01:00
Pascal Langer
062fc05eac Fix FrSky RX protocol not ending bind when requested 2021-01-11 09:42:16 +01:00
Pascal Langer
6d080d5d5f New LOLI protocol 2021-01-09 18:39:31 +01:00
Pascal Langer
0955340a93 New protocol: E010r5 2021-01-08 21:16:07 +01:00
Ben Lye
9b2318cc7e Fix EEPROM address variable types (#494) 2020-12-27 09:57:41 +01:00
Pascal Langer
2098cdc5e0 Merge branch 'master' of https://github.com/pascallanger/DIY-Multiprotocol-TX-Module 2020-12-23 10:54:43 +01:00
Pascal Langer
d19b5187c5 AFHDS2A RX: stop bind when requested 2020-12-23 10:54:39 +01:00
pascallanger
2a78b1d6b7 Update README.md 2020-12-22 12:01:05 +01:00
pascallanger
84ae6366eb Update README.md 2020-12-21 16:12:04 +01:00
pascallanger
e5b235ac83 Update README.md 2020-12-21 16:08:03 +01:00
Ben Lye
0195384592 Merge pull request #486 from benlye/actions-3
Various fixes for CI workflow
2020-12-21 14:56:29 +00:00
Ben Lye
0937f832fc Rename the build artifact archive 2020-12-21 14:50:31 +00:00
Ben Lye
c77b4af2a0 Various fixes for CI workflow 2020-12-21 14:33:55 +00:00
pascallanger
b943bae8dd Update README.md 2020-12-21 11:39:35 +01:00
pascallanger
4955978eb6 Update README.md 2020-12-21 11:36:39 +01:00
Ben Lye
df409fddf5 Merge pull request #485 from benlye/store-artifacts
Upload build artifacts to workflow job
2020-12-20 20:15:21 +00:00
Ben Lye
0330c596e4 Upload build artifacts to workflow job 2020-12-20 19:56:28 +00:00
Ben Lye
8c6c58f12f Update main.yml
Only run CI workflow on push or PR if firmware source code has changed.
2020-12-20 19:08:36 +00:00
Ben Lye
4bc08d22b8 Merge pull request #484 from benlye/github-actions
Configure GitHub Actions
2020-12-20 17:44:28 +00:00
Ben Lye
96fb3b20b7 Configure GitHub Actions for testing and releases 2020-12-20 17:11:18 +00:00
Ben Lye
47f713c6c8 Disable Travis 2020-12-20 11:38:34 +00:00
Pascal Langer
443c7a6b99 WFLY2: WBUS <-> PPM 2020-12-20 12:05:43 +01:00
Pascal Langer
e79ca9b7d7 E016H: Calibration on channel 8 2020-12-19 12:16:51 +01:00
Pascal Langer
b94f774f80 WFLY2: Failsafe doc update 2020-12-18 17:34:09 +01:00
Pascal Langer
5614e8bef6 E016H: Multi IDs 2020-12-18 15:30:50 +01:00
Pascal Langer
4ce3a5d298 Renamed protocol E016H to E016HV2 2020-12-18 00:09:13 +01:00
Pascal Langer
f6de3de78c Update Protocols_Details.md 2020-12-17 21:28:42 +01:00
Pascal Langer
8099018132 RLINK: subprotocol DumboRC 2020-12-17 21:24:56 +01:00
Pascal Langer
360dde2e1b E016H: compilation fix 2020-12-17 21:09:13 +01:00
Pascal Langer
cc7b7638d3 Update Protocols_Details.md 2020-12-17 18:23:38 +01:00
Pascal Langer
321e4aee34 E016H v2: new protocol WIP only 1 ID 2020-12-17 18:05:04 +01:00
Pascal Langer
f18847df57 Update Convert.ino 2020-12-17 09:02:11 +01:00
Pascal Langer
a2559a65d3 WFLY2: add switch from PPM <-> WBUS 2020-12-16 18:40:46 +01:00
Pascal Langer
5ac41fdd15 WFLY2: add failsafe (hold/no pulse not available yet) 2020-12-16 16:14:45 +01:00
Pascal Langer
6d38dd2d7a WFLY2: auto stop bind when the RX replies 2020-12-15 23:58:56 +01:00
Ben Lye
667058269c Add latest boards 2020-12-15 09:50:28 +00:00
Ben Lye
ad6f934892 Pin arduino-cli version to 0.13.0 2020-12-15 09:32:34 +00:00
Pascal Langer
714220c349 Update Protocols_Details.md 2020-12-15 10:20:05 +01:00
Pascal Langer
4887fca873 WFLY2: fix bind after code cleanup... 2020-12-15 09:51:11 +01:00
Pascal Langer
cfe80edcb6 WFLY2: update channels throw, bind frequencies 2020-12-14 18:56:12 +01:00
Pascal Langer
484588ff6b WFLY2: documentation 2020-12-14 11:07:21 +01:00
Pascal Langer
1bb059c2a2 WFLY: renamed WFLYRF to WFLY2 2020-12-13 23:15:43 +01:00
Pascal Langer
ef5d9cb6b3 HoTT: update doc for 16 channels 2020-12-13 23:00:47 +01:00
Pascal Langer
37a06c050d HoTT: added support for 16 channels (previously 12) 2020-12-13 22:56:47 +01:00
Pascal Langer
5f0ed395ba WFLYRF: use Radio ID 2020-12-11 13:55:50 +01:00
Pascal Langer
ae27c8b671 WFLYRF: Fixed partial ID for telemetry 2020-12-11 11:23:06 +01:00
Pascal Langer
088bfb9c2f WFLYRF: added ext voltage to A2 2020-12-11 10:57:14 +01:00
Pascal Langer
b01462e36b WFLYRF: fixed normal mode, added telemetry, bind is not working yet 2020-12-11 10:40:00 +01:00
Pascal Langer
abd36dc6a4 WFLY: Track changes in A7105 config (radio has A7106) 2020-12-10 18:57:06 +01:00
Pascal Langer
ebb8a33c1a Fix potential bug with wait loops 2020-12-10 16:52:34 +01:00
Pascal Langer
2b0f663482 WFLY RF: WIP protocol 2020-12-10 16:51:55 +01:00
pascallanger
956e632392 Update Protocols_Details.md 2020-12-10 13:48:04 +01:00
pascallanger
90b6bb8f7d Update Protocols_Details.md 2020-12-08 18:52:13 +01:00
pascallanger
6153e84abf Update README.md 2020-12-08 16:51:52 +01:00
pascallanger
16357f29e9 Add files via upload 2020-12-08 16:48:04 +01:00
Pascal Langer
0b8a5a7539 MLINK protocol: WIP, works only for a few sec... 2020-12-05 19:13:11 +01:00
Pascal Langer
6874e3a6a7 Template for WFLY RF 2020-12-05 19:12:11 +01:00
Pascal Langer
96263ed8a6 Prep for M-LINK 2020-12-04 09:00:17 +01:00
Ben Lye
7bb1cb9ae3 Add STM32 EEPROM initialization at startup (#475) 2020-11-30 18:11:35 +01:00
Pascal Langer
20e32c4cb0 Fix XK450 twitching? 2020-11-30 13:36:29 +01:00
Ben Lye
b4421306c0 Fix compiler errors when telemetry is disabled (#474) 2020-11-30 08:38:21 +01:00
Pascal Langer
e53f723fdb Update DSM FwdPrg.lua 2020-11-25 10:37:47 +01:00
Ben Lye
832a331437 Update Frequency_Tuning.md 2020-11-22 10:09:07 +00:00
Ben Lye
12e66bd84f Add tests for STM32F103C8 board 2020-11-09 11:09:12 +00:00
Pascal Langer
d290cc519f Bayang telemetry OpenTX Ratio and Offset 2020-11-06 10:04:01 +01:00
Ben Lye
f4b19fe33e Add module sub-type to signature
Differentiates between the STM32F1 boards.
2020-11-03 08:08:10 +00:00
pascallanger
767d2c079a Update Protocols_Details.md 2020-10-31 16:24:02 +01:00
pascallanger
7750310be5 Update Protocols_Details.md 2020-10-31 16:06:18 +01:00
Pascal Langer
6de4e1e1dd Protocols order 2020-10-31 15:59:04 +01:00
Ben Lye
627d47f139 C8 MCU flash size check (#461) 2020-10-30 12:21:39 +01:00
pascallanger
36675cf729 Change Travis links 2020-10-30 12:18:15 +01:00
Pascal Langer
33d8234eb3 Update JJRC345_nrf24l01.ino 2020-10-30 12:01:40 +01:00
Pascal Langer
347eb11328 SFHSS name change to Futaba 2020-10-30 12:01:29 +01:00
Ben Lye
5ed61f30e1 STM32 release file name standardization (#451)
Tweak the names of the STM32 serial and CC2500-only release files.
2020-10-11 14:09:42 +01:00
Ben Lye
a633f46f4f Travis release build changes (#450)
* Move the release build steps into separate shell scripts
* Remove builds that we don't need any more
  * Latest builds of er9x and erSkyTx both support MULTI_TELEMETRY so separate OpenTX / erSkyTx builds are no longer needed
  * Radio can switch telemetry inversion on or off automatically so STM32 inv / noinv builds are no longer needed
2020-10-11 12:52:05 +01:00
Pascal Langer
baf9a0f978 Update DSM FwdPrg.lua 2020-10-03 11:06:22 +02:00
Pascal Langer
c98b8fc8bf Flysky: Fix AFHDS and AFHDS2A 2020-10-03 10:52:11 +02:00
Pascal Langer
2fae0a35b8 Merge branch 'master' of https://github.com/pascallanger/DIY-Multiprotocol-TX-Module 2020-10-01 00:18:28 +02:00
Pascal Langer
b04f38ed3d Indicate ratio values to be used for A1 and A2 voltage sensors
OMP, RadioLink, Hubsan, Bayang, ...
2020-10-01 00:18:13 +02:00
pascallanger
60d5dd4101 Update Protocols_Details.md 2020-10-01 00:06:40 +02:00
Pascal Langer
75b7dd1dd7 Kyosho/Hype: channel order & doc 2020-10-01 00:05:20 +02:00
Pascal Langer
aa2717d6ab Kyosho/Hype: bind fix 2020-09-30 20:30:07 +02:00
Pascal Langer
4058f04b39 Kyosho/Hype: another attempt to fix bind... 2020-09-30 11:06:30 +02:00
Pascal Langer
25ebd55c85 Update Protocols_Details.md 2020-09-29 19:14:41 +02:00
Pascal Langer
d00b58c8ed Kyosho/Hype: fix bind 2020-09-29 17:06:01 +02:00
Pascal Langer
e7eb07a5a4 Kyosho: new sub_protocol Hype
Initial release
2020-09-29 11:24:55 +02:00
Ben Lye
a4cac50261 Add builds for modules with only CC2500 2020-09-24 14:09:08 +01:00
Pascal Langer
4f8da64822 OMP: doc update 2020-09-23 23:52:22 +02:00
Pascal Langer
4f89721cd0 RadioLink: any id
Need to rebind RXs...
2020-09-23 23:42:03 +02:00
Pascal Langer
43c2843490 Update AFHDS2A_a7105.ino 2020-09-23 23:08:26 +02:00
Pascal Langer
c152265284 OMP: doc 2020-09-23 23:05:05 +02:00
Pascal Langer
b591b92b4e Update OMP documentation 2020-09-23 09:41:26 +02:00
Pascal Langer
090388aa1b OMP: improve telemetry 2020-09-22 15:15:14 +02:00
Pascal Langer
c6ab696949 AFHDS2A: fix X6B telemetry issue? 2020-09-21 10:57:19 +02:00
Pascal Langer
df45a3ff83 OMP: prevent telemetry voltage from rolling over 2020-09-21 10:50:01 +02:00
pascallanger
fedd04b724 Update Troubleshooting.md 2020-09-19 21:23:51 +02:00
pascallanger
d8630da09d Update Troubleshooting.md 2020-09-19 20:35:44 +02:00
pascallanger
6192f7287e Update README.md 2020-09-18 17:15:18 +02:00
Pascal Langer
5b8a08ab22 OMP: added telemetry 2020-09-18 16:13:45 +02:00
Ben Lye
313b03fb84 Disable PPM/serial in builds as needed 2020-09-17 10:13:00 +01:00
Pascal Langer
5639def6fb Update DSM FwdPrg.lua 2020-09-15 12:05:26 +02:00
Pascal Langer
15a254879c DSM_RX: bind with other radio modules off 2020-09-15 12:03:16 +02:00
pascallanger
5baa9bd256 Update README.md 2020-09-13 11:34:23 +02:00
Pascal Langer
d5346c0eaf Add DISABLE_FLASH_SIZE_CHECK 2020-09-09 16:47:32 +02:00
Pascal Langer
a2213fd6dc DSM Forward Programming: work in progress 2020-09-09 10:45:14 +02:00
Pascal Langer
9b07f12f90 AFHDS2A: add sub proto 2020-09-08 08:49:38 +02:00
Pascal Langer
c9b49483e0 NanoRF 2020-09-07 22:58:37 +02:00
Pascal Langer
e2972a5823 AFHDS2A: enable 16 channels on SBUS 2020-09-07 20:31:47 +02:00
Pascal Langer
d5b3ed832d Update Multiprotocol.ino 2020-09-04 10:59:31 +02:00
Pascal Langer
9fcc030c15 STM32: test flash size 2020-09-04 10:39:30 +02:00
pascallanger
fc81b7ee5a Update Protocols_Details.md 2020-09-03 17:28:54 +02:00
Pascal Langer
f168abc2bb Fixed frame size 2020-08-31 22:21:21 +02:00
pascallanger
fe6778635e Add Realacc R11 protocol 2020-08-30 14:57:56 +02:00
Pascal Langer
65a6c19d02 OMP doc 2020-08-30 14:35:44 +02:00
pascallanger
a32b5561a1 Update Protocols_Details.md 2020-08-30 14:30:28 +02:00
pascallanger
4b4393952e Update README.md 2020-08-24 14:41:10 +02:00
Pascal Langer
ea205b1e69 Bayanf: fix telemetry batt 2020-08-20 19:00:06 +02:00
pascallanger
748140cdee Update Protocols_Details.md 2020-08-18 12:02:08 +02:00
Pascal Langer
e8037c857f OMP fixes 2020-08-17 08:26:42 +02:00
Pascal Langer
15e37cefee OMP: fix? 2020-08-16 18:48:40 +02:00
Pascal Langer
b1e4daf1c2 OMP: new protocol intial release
Untested!!!
2020-08-15 16:17:18 +02:00
Pascal Langer
4e0fccfc63 Update Protocols_Details.md 2020-08-14 19:40:25 +02:00
Pascal Langer
48b90029c4 V761: Work with any ID. Tested on Eachine RX. 2020-08-14 19:39:24 +02:00
Pascal Langer
8b189af2f9 R9: small change 2020-08-13 21:21:34 +02:00
Pascal Langer
030cdd35a2 Update REALACC_nrf24l01.ino 2020-08-11 00:02:19 +02:00
Pascal Langer
3789998ba9 Update ZSX_nrf24l01.ino 2020-08-10 23:54:51 +02:00
Pascal Langer
ea24ab6032 New protocol Realacc 2020-08-10 23:54:33 +02:00
Pascal Langer
1408431649 XN297Dump: increase the number of RF channels to look for 2020-08-10 22:52:50 +02:00
Pascal Langer
6810372064 RadioLink: enable Range test mode 2020-08-10 20:30:19 +02:00
Pascal Langer
708e2ac5f6 V761 bug fix: the model was not reconnecting unless you did a bind first 2020-08-07 15:18:15 +02:00
Pascal Langer
2178f6761d RadioLink: update A2=Batt telemetry value 2020-08-07 15:11:59 +02:00
Pascal Langer
aa5fd82004 Update FrSky_Rx_cc2500.ino 2020-08-05 09:50:40 +02:00
Pascal Langer
660282db2e RX protocols: abort RX bind as requested 2020-08-04 10:42:35 +02:00
Ben Lye
fdd357619b Fix folder structure inside LUA script zip file 2020-08-03 22:39:10 +01:00
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
208 changed files with 128182 additions and 7815 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [pascallanger]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VF2K9T23DRY56&lc=US&item_name=DIY%20Multiprotocol&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted

378
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,378 @@
# Workflow for testing MULTI-Module firmware builds
name: MULTI Test, Build, Deploy, Release
on:
# Trigger the workflow on pushes, except those that are tagged (avoids double-testing releases)
push:
branches:
- '**'
tags-ignore:
- '**'
paths:
- '.github/workflows/**'
- 'buildroot/bin/**'
- 'Multiprotocol/**'
# Trigger the workflow on pull requests to the master branch
pull_request:
branches:
- master
paths:
- '.github/workflows/**'
- 'buildroot/bin/**'
- 'Multiprotocol/**'
# Triggers the workflow on release creation
release:
types:
- created
# Allows the workflow to be triggered manually from the Actions tab
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
# Configure the board matrix
strategy:
fail-fast: false
matrix:
include:
- board: "multi4in1:avr:multiatmega328p:bootloader=none"
name: "ATmega328p"
- board: "multi4in1:avr:multiatmega328p:bootloader=optiboot"
name: "ATmega328p (Optiboot)"
- board: "multi4in1:avr:multixmega32d4"
name: "OrangeRX"
- board: "multi4in1:STM32F1:multistm32f103c8:debug_option=none"
name: "STM32F103 (64KB)"
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
name: "STM32F103 (128KB)"
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=native"
name: "STM32F103 (128KB, USB Debug)"
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi"
name: "STM32F103 (128KB, Serial Debug)"
- board: "multi4in1:STM32F1:multi5in1t18int"
name: "T18 5-in-1 (128KB)"
# Set the build name using the friendly board name
name: "[Test] ${{ matrix.name }}"
# Set the environment variables
env:
BOARD: ${{ matrix.board }}
steps:
- uses: actions/checkout@v4
- name: Install Arduino CLI
uses: arduino/setup-arduino-cli@v2
with:
version: "0.32.2"
- name: Prepare build environment
run: |
echo "Github Ref: $GITHUB_REF"
echo "Event name: ${{ github.event_name }}"
echo "Event action: ${{ github.event.action }}"
echo "Tag name: ${{ github.event.release.tag_name }}"
arduino-cli config init --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json,https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/devel/source/package_multi_4in1_board_devel_index.json
arduino-cli core update-index
if [[ "$BOARD" =~ ":avr:" ]]; then
arduino-cli core install arduino:avr;
fi
if [[ "$BOARD" =~ "multi4in1-devel:avr" ]]; then
arduino-cli core install multi4in1-devel:avr
elif [[ "$BOARD" =~ "multi4in1:avr" ]]; then
arduino-cli core install multi4in1:avr
fi
if [[ "$BOARD" =~ "multi4in1-devel:STM32F1:" ]]; then
arduino-cli core install multi4in1-devel:STM32F1
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
arduino-cli core install multi4in1:STM32F1
fi
chmod +x ${GITHUB_WORKSPACE}/buildroot/bin/*
echo "${GITHUB_WORKSPACE}/buildroot/bin" >> $GITHUB_PATH
mkdir ./build
mkdir ./binaries
- name: Configure MULTI-Module firmware options
run: |
# Load the build functions
source ./buildroot/bin/buildFunctions;
# Get the version
getMultiVersion
echo "MULTI_VERSION=$(echo $MULTI_VERSION)" >> $GITHUB_ENV
# Get all the protocols for this board
getAllProtocols
echo "A7105_PROTOCOLS=$(echo $A7105_PROTOCOLS)" >> $GITHUB_ENV
echo "CC2500_PROTOCOLS=$(echo $CC2500_PROTOCOLS)" >> $GITHUB_ENV
echo "CYRF6936_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS)" >> $GITHUB_ENV
echo "NRF24L01_PROTOCOLS=$(echo $NRF24L01_PROTOCOLS)" >> $GITHUB_ENV
echo "SX1276_PROTOCOLS=$(echo $SX1276_PROTOCOLS)" >> $GITHUB_ENV
echo "CCNRF_INO_PROTOCOLS=$(echo $CCNRF_INO_PROTOCOLS)" >> $GITHUB_ENV
echo "ALL_PROTOCOLS=$(echo $ALL_PROTOCOLS)" >> $GITHUB_ENV
# Get all the RF modules for this board
getAllRFModules
echo "ALL_RFMODULES=$(echo $ALL_RFMODULES)" >> $GITHUB_ENV
# Disable CHECK_FOR_BOOTLOADER when not needed
if [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
opt_disable CHECK_FOR_BOOTLOADER;
fi
# Trim the build down for the Atmega328p board
if [[ "$BOARD" =~ ":avr:multiatmega328p:" ]]; then
opt_disable $ALL_PROTOCOLS
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
fi
# Trim the enabled protocols down for the STM32F103CB board with debugging or the STM32F103C8 board in general
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=ftdi" ]] || [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=native" ]] || [[ "$BOARD" =~ ":STM32F1:multistm32f103c8" ]]; then
opt_disable $ALL_PROTOCOLS;
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
fi
- name: Save default firmware configuration
run: |
cat Multiprotocol/_Config.h
cp Multiprotocol/_Config.h ./_Config.h.bak
- name: Build default configuration
run: |
# Skip the default build for boards where it's too large now
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
printf "Not testing default build for $BOARD.";
else
source ./buildroot/bin/buildFunctions;
buildMulti
fi
- name: Build serial only
run: |
# Skip the serial-only build for boards where it's too large now
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
printf "Not testing serial-only build for $BOARD.";
else
source ./buildroot/bin/buildFunctions;
cp ./_Config.h.bak Multiprotocol/_Config.h
opt_disable ENABLE_PPM;
buildMulti;
fi
- name: Build PPM only
run: |
# Skip the PPM-only build for boards where it's too large now
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
printf "Not testing PPM-only build for $BOARD.";
else
source ./buildroot/bin/buildFunctions;
cp ./_Config.h.bak Multiprotocol/_Config.h
opt_disable ENABLE_SERIAL;
buildMulti;
fi
- name: Build each RF module individually
run: |
# Skip the per-RF module builds for boards which have fixed modules
if [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
printf "Not testing individual RF module builds for $BOARD.";
else
source ./buildroot/bin/buildFunctions;
cp ./_Config.h.bak Multiprotocol/_Config.h;
buildEachRFModule;
fi
- name: Build each protocol individually
run: |
source ./buildroot/bin/buildFunctions;
cp ./_Config.h.bak Multiprotocol/_Config.h;
buildEachProtocol;
build:
runs-on: ubuntu-latest
# Configure the board matrix
strategy:
fail-fast: false
matrix:
include:
- board: "multi4in1:avr:multiatmega328p:bootloader=none"
name: "ATmega328p"
release: "atmega328p"
- board: "multi4in1:avr:multiatmega328p:bootloader=optiboot"
name: "ATmega328p (Optiboot)"
release: "atmega328p-optiboot"
- board: "multi4in1:avr:multixmega32d4"
name: "OrangeRX"
release: "orangerx"
- board: "multi4in1:STM32F1:multistm32f103c8:debug_option=none"
name: "STM32F103 CC2500 (64KB)"
release: "stm32f103-cc2500-64k"
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
name: "STM32F103 CC2500 (128KB)"
release: "stm32f103-cc2500-128k"
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
name: "STM32F103 (128KB)"
release: "stm32f103-128k-4in1"
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=native"
name: "STM32F103 (128KB, USB Debug)"
release: "stm32f103-128k-usb-debug"
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi"
name: "STM32F103 (128KB, Serial Debug)"
release: "stm32f103-128k-serial-debug"
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
name: "STM32F103 5-in-1 (128KB)"
release: "stm32f103-128k-5in1"
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
name: "T-Lite 5-in-1 (128KB)"
release: "tlite-5in1"
- board: "multi4in1:STM32F1:multi5in1t18int"
name: "T18 5-in-1 (128KB)"
release: "t18-5in1"
- board: "none"
name: "Scripts"
release: "scripts"
# Set the build name using the friendly board name
name: "[Build] ${{ matrix.name }}"
# Set the environment variables
env:
BOARD: ${{ matrix.board }}
RELEASE: ${{ matrix.release }}
steps:
- uses: actions/checkout@v4
- name: Install Arduino CLI
uses: arduino/setup-arduino-cli@v2
with:
version: "0.32.2"
- name: Prepare build environment
run: |
echo "Github Ref: $GITHUB_REF"
echo "Event name: ${{ github.event_name }}"
echo "Event action: ${{ github.event.action }}"
echo "Tag name: ${{ github.event.release.tag_name }}"
arduino-cli config init --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json,https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/devel/source/package_multi_4in1_board_devel_index.json
arduino-cli core update-index
if [[ "$BOARD" =~ ":avr:" ]]; then
arduino-cli core install arduino:avr;
fi
if [[ "$BOARD" =~ "multi4in1-devel:avr" ]]; then
arduino-cli core install multi4in1-devel:avr
elif [[ "$BOARD" =~ "multi4in1:avr" ]]; then
arduino-cli core install multi4in1:avr
fi
if [[ "$BOARD" =~ "multi4in1-devel:STM32F1:" ]]; then
arduino-cli core install multi4in1-devel:STM32F1
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
arduino-cli core install multi4in1:STM32F1
fi
chmod +x ${GITHUB_WORKSPACE}/buildroot/bin/*
echo "${GITHUB_WORKSPACE}/buildroot/bin" >> $GITHUB_PATH
mkdir ./build
mkdir ./binaries
- name: Configure MULTI-Module firmware options
run: |
# Load the build functions
source ./buildroot/bin/buildFunctions;
# Get the version
getMultiVersion
echo "MULTI_VERSION=$(echo $MULTI_VERSION)" >> $GITHUB_ENV
# Get all the protocols for this board
getAllProtocols
echo "A7105_PROTOCOLS=$(echo $A7105_PROTOCOLS)" >> $GITHUB_ENV
echo "CC2500_PROTOCOLS=$(echo $CC2500_PROTOCOLS)" >> $GITHUB_ENV
echo "CYRF6936_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS)" >> $GITHUB_ENV
echo "NRF24L01_PROTOCOLS=$(echo $NRF24L01_PROTOCOLS)" >> $GITHUB_ENV
echo "SX1276_PROTOCOLS=$(echo $SX1276_PROTOCOLS)" >> $GITHUB_ENV
echo "CCNRF_INO_PROTOCOLS=$(echo $CCNRF_INO_PROTOCOLS)" >> $GITHUB_ENV
echo "ALL_PROTOCOLS=$(echo $ALL_PROTOCOLS)" >> $GITHUB_ENV
# Disable CHECK_FOR_BOOTLOADER when not needed
if [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
opt_disable CHECK_FOR_BOOTLOADER;
fi
- name: Save default firmware configuration
run: |
cat Multiprotocol/_Config.h
cp Multiprotocol/_Config.h ./_Config.h.bak
- name: Build release files
run: |
source ./buildroot/bin/buildFunctions;
cp ./_Config.h.bak Multiprotocol/_Config.h;
buildReleaseFiles;
ls -al ./binaries;
NUM_FILES=$(ls -l ./binaries | grep ^- | wc -l);
if [ $NUM_FILES -gt 0 ]; then
echo "HAVE_FILES=true" >> $GITHUB_ENV
else
echo "HAVE_FILES=false" >> $GITHUB_ENV
fi
- name: 'Upload Artifacts'
if: env.HAVE_FILES == 'true'
uses: actions/upload-artifact/@v4
with:
name: multi-${{ matrix.release }}
path: ./binaries/
deploy:
name: "[Deploy] Attach Build Artifacts"
runs-on: ubuntu-latest
needs: [test, build]
steps:
- name: Combine and upload build artifacts
uses: actions/upload-artifact/merge@v4
with:
name: multi-test-build
pattern: multi-*
delete-merged: true
retention-days: 90
release:
name: "[Release] Publish Files to Release"
if: github.event_name == 'release' && github.event.action == 'created'
runs-on: ubuntu-latest
needs: deploy
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: multi-test-build
path: ./artifacts/
- name: Display downloaded artifacts
run: ls -R ./artifacts/
- name: Deploy artifacts to release
uses: AButler/upload-release-assets@v3.0
with:
files: './artifacts/*'
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,362 +0,0 @@
dist: bionic
sudo: true
language: c
env:
global:
- IDE_VERSION=1.8.9
matrix:
- BOARD="multi4in1:avr:multiatmega328p:bootloader=none"
- BOARD="multi4in1:avr:multiatmega328p:bootloader=optiboot"
- BOARD="multi4in1:avr:multixmega32d4"
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=none"
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=native"
- BOARD="multi4in1:STM32F1:multistm32f103c:debug_option=ftdi"
notifications:
email: false
before_install:
# Fetch the tag information for the current branch
- git fetch origin --tags
# Publish the buildroot script folder
- chmod +x ${TRAVIS_BUILD_DIR}/buildroot/bin/*
- export PATH=${TRAVIS_BUILD_DIR}/buildroot/bin/:${PATH}
# Arduino IDE adds a lot of noise caused by network traffic; firewall it
- sudo iptables -P INPUT DROP
- sudo iptables -P FORWARD DROP
- sudo iptables -P OUTPUT ACCEPT
- sudo iptables -A INPUT -i lo -j ACCEPT
- sudo iptables -A OUTPUT -o lo -j ACCEPT
- sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Helper functions for the builds
- buildMulti() { start_fold config_diff; travis_time_start; git diff Multiprotocol/_Config.h; end_fold config_diff; exitcode=0; BUILDCMD="arduino --verify --board $BOARD Multiprotocol/Multiprotocol.ino --pref build.path=./build/"; echo $BUILDCMD; $BUILDCMD; if [ $? -ne 0 ]; then exitcode=1; fi; echo; return $exitcode; }
- buildProtocol() { exitcode=0; opt_disable $ALL_PROTOCOLS; opt_enable $1; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
- buildEachProtocol() { exitcodesum=0; for PROTOCOL in $ALL_PROTOCOLS ; do printf "\e[33;1mBuilding $PROTOCOL\e[0m"; buildProtocol $PROTOCOL; if [ $? -ne 0 ]; then exitcodesum=$((exitcodesum + 1)); fi; done; return $exitcodesum; }
- buildRFModule() { exitcode=0; opt_disable $ALL_RFMODULES; opt_enable $1; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
- buildEachRFModule() { exitcodesum=0; for RFMODULE in $ALL_RFMODULES; do printf "\e[33;1mBuilding $RFMODULE\e[0m"; buildRFModule $RFMODULE; if [ $? -ne 0 ]; then exitcodesum=$((exitcodesum + 1)); fi; done; return $exitcodesum; }
- buildDefault() { exitcode=0; printf "\n\e[33;1mBuilding default configuration\e[0m\n"; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
- buildSerialOnly() { exitcode=0; printf "\n\e[33;1mBuilding serial mode only\e[0m\n"; opt_disable ENABLE_PPM; opt_enable ENABLE_SERIAL; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
- buildPPMOnly() { exitcode=0; printf "\n\e[33;1mBuilding PPM mode only\e[0m\n"; opt_enable ENABLE_PPM; opt_disable ENABLE_SERIAL; buildMulti; if [ $? -ne 0 ]; then exitcode=1; fi; return $exitcode; }
# Function to build the release files - dependent on board type
- if [[ "$BOARD" == "multi4in1:avr:multixmega32d4" ]]; then
buildReleaseFiles(){
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;
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;
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;
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;
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;
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;
opt_disable MULTI_STATUS;
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;
opt_disable MULTI_STATUS;
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;
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;
opt_enable MULTI_STATUS;
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;
opt_disable MULTI_STATUS;
opt_enable MULTI_TELEMETRY;
opt_enable INVERT_TELEMETRY;
buildMulti;
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;
opt_enable MULTI_STATUS;
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;
opt_disable MULTI_STATUS;
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;
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
# Set the Multi boards package URL
- arduino --pref "boardsmanager.additional.urls=https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json" --save-prefs
# Install the STM32 board if needed
- if [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
arduino --install-boards multi4in1:STM32F1;
fi
# Install the AVR board if needed
- if [[ "$BOARD" =~ "multi4in1:avr:" ]]; then
arduino --install-boards multi4in1:avr;
fi
before_script:
# Change current working directory to the build dir
- cd ${TRAVIS_BUILD_DIR}
# Create somwhere to put the exported binaries
- mkdir ./binaries
# Log the initial Multi config
- cat Multiprotocol/_Config.h
# Back up the configuration
- cp Multiprotocol/_Config.h ./_Config.h.bak
# Get the firmware version number from the source
- MAJOR_VERSION=$(grep "VERSION_MAJOR" "Multiprotocol/Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
- MINOR_VERSION=$(grep "VERSION_MINOR" "Multiprotocol/Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
- REVISION_VERSION=$(grep "VERSION_REVISION" "Multiprotocol//Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
- PATCH_VERSION=$(grep "VERSION_PATCH" "Multiprotocol//Multiprotocol.h" | awk -v N=3 '{gsub(/\r/,""); print $N}')
- MULTI_VERSION=$MAJOR_VERSION.$MINOR_VERSION.$REVISION_VERSION.$PATCH_VERSION
# Derive the Multi protocols from the Multi source
- A7105_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_A7105_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
- CC2500_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CC2500_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
- CYRF6936_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CYRF6936_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
- NRF24L01_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_NRF24L01_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
- if [[ "$BOARD" =~ "multi4in1:avr:multixmega32d4" ]]; then
ALL_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS);
else
ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS);
fi
- echo $ALL_PROTOCOLS
# Declare all the installed modules
- ALL_RFMODULES=$(echo A7105_INSTALLED CYRF6936_INSTALLED CC2500_INSTALLED NRF24L01_INSTALLED);
# Disable CHECK_FOR_BOOTLOADER when not needed
- if [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=none" ]]; then
opt_disable CHECK_FOR_BOOTLOADER;
fi
# Trim the enabled protocols down for the STM32 board with 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
- if [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then
opt_disable $ALL_PROTOCOLS;
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
fi
# Useful Travis functions
- export -f travis_fold
- export -f travis_nanoseconds
- export -f travis_time_start
- export -f travis_time_finish
- start_fold() { echo -e "travis_fold:start:$1"; }
- end_fold() { echo -e "\ntravis_fold:end:$1\r"; }
script:
# Build with default configuration - all protocols are enabled for STM32; a subset of protocols for Atmega or STM32 debugging
- buildDefault
# Serial only
- buildSerialOnly
# PPM only
- buildPPMOnly
# Re-enable PPM and serial
- opt_enable ENABLE_SERIAL
- opt_enable ENABLE_PPM
# Build for each RF module individually
- buildEachRFModule
# Restore the default configuration
- cp ./_Config.h.bak Multiprotocol/_Config.h
# Build each protocol individually
- buildEachProtocol
# Restore the default configuration
- cp ./_Config.h.bak Multiprotocol/_Config.h
# Builds the files for a release - always built, but only copied to Github if the test is tagged as a release
- buildReleaseFiles
deploy:
provider: releases
api_key:
secure: KGXaoqvd8rbZ3AZtL9Rrn1JYiocGsPaihRUyR8gM8vTfvH9WYAE1+h6SzROQOuJSwr89MvTo3SBOTlM/0PDBnEGLec9Irt7cwO0xf9xM2vPuUG8DYcUzmJJzME9dkn/7qHof1JGgRpp1duUAN1triE9NxhKxL1hbs+tUUbDPAejxwoFNfnta/T4PfD6xmkZNJbneIfYFuFgyLpwwFhuUy9JP7s1AFOiT+fCHxPaZrPn5GsXqAi95Cb7Q3w1iVSt3BmrGxL2j3CeNpWzFY1RrMdc8ay+ppOhSPEIl2vyM7VeLRRBL3EVeFWkiS4ywevqw70wOivTczluv3OeuIJAe5o2UU+w5+59c7+i44Nih23PDAZBhAG5JkLUYUN0XUJpXJ5ZlZsb8IS8sI1txlZa5tNVoXO9+soGEY4rKSpZaPptuENm792CzzAjcaUI9pOFJ/0CBoSCbu5MpM/plkJCMd8fY27EE8cNYvolMuRATNlXs7h9mURGR69pmcR1jFShH+A7Kyp1S1sH19sGCEU16rt2aAtf2FadFg/gKACC2y9rB3wBb4Qnapu2AwNRlTYNuU1+G+kb2FXRwMl04q+38S+cIBHH9NHfdftp9MRPf8Ekatojs92be/Ux21S+hcA7sx/DV22Dl45V6l4mXzR7U4x1nQcdn1SGuy5I4lL6IYCk=
skip_cleanup: true
file_glob: true
file: binaries/*
on:
tags: true

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

@@ -170,6 +170,24 @@
],
"toolsDependencies": []
},
{
"name": "MULTI-Module AVR Boards",
"architecture": "avr",
"version": "1.1.1",
"category": "Contributed",
"help": {
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
},
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.1.1.tar.gz",
"archiveFileName": "package_multi_4in1_avr_board_v1.1.1.tar.gz",
"checksum": "SHA-256:02158258b4dbaca61bedbb6933336200d13b02ad0db981e2dda253682c482e99",
"size": "324512",
"boards": [
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
{"name": "Multi 4-in-1 (OrangeRX)"}
],
"toolsDependencies": []
},
{
"name": "Multi 4-in-1 STM32 Board",
"architecture": "STM32F1",
@@ -527,6 +545,95 @@
"version": "4.8.3-2014q1"
}]
},
{
"name": "Multi X-in-1 STM32 Boards",
"architecture": "STM32F1",
"version": "1.1.8",
"category": "Contributed",
"help": {
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
},
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.8.tar.gz",
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.8.tar.gz",
"checksum": "SHA-256:e9ed8055ebf72abf37e60e1b8d1c6ee5472132ea7c0a3c4a63fbb8442613e4c2",
"size": "7481800",
"boards": [
{"name": "Multi 4-in-1 (STM32F103C)"},
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
],
"toolsDependencies": [{
"packager": "arduino",
"name": "arm-none-eabi-gcc",
"version": "4.8.3-2014q1"
}]
},
{
"name": "Multi X-in-1 STM32 Boards",
"architecture": "STM32F1",
"version": "1.2.0",
"category": "Contributed",
"help": {
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
},
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.2.0.tar.gz",
"archiveFileName": "package_multi_4in1_stm32_board_v1.2.0.tar.gz",
"checksum": "SHA-256:754f08ca2a553701cc9112b645c079b6041107f1bf863648305e560c136a6ac5",
"size": "7496214",
"boards": [
{"name": "Multi 4-in-1 (STM32F103C)"},
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
],
"toolsDependencies": [{
"packager": "arduino",
"name": "arm-none-eabi-gcc",
"version": "4.8.3-2014q1"
}]
},
{
"name": "Multi X-in-1 STM32 Boards",
"architecture": "STM32F1",
"version": "1.2.1",
"category": "Contributed",
"help": {
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
},
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.2.1.tar.gz",
"archiveFileName": "package_multi_4in1_stm32_board_v1.2.1.tar.gz",
"checksum": "SHA-256:c66d34afadc5b21e9e28c4d477fa03a6d55db0b74b59ff2dcb07b4d6ef06da1a",
"size": "7496448",
"boards": [
{"name": "Multi 4-in-1 (STM32F103C)"},
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
],
"toolsDependencies": [{
"packager": "arduino",
"name": "arm-none-eabi-gcc",
"version": "4.8.3-2014q1"
}]
},
{
"name": "MULTI-Module STM32 Boards",
"architecture": "STM32F1",
"version": "1.2.2",
"category": "Contributed",
"help": {
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
},
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.2.2.tar.gz",
"archiveFileName": "package_multi_4in1_stm32_board_v1.2.2.tar.gz",
"checksum": "SHA-256:0fe4a8899438bbc31dc37714acca13968e43d75a47e59143343d83b634d2e47d",
"size": "7485662",
"boards": [
{"name": "Multi X-in-1 STM32F103CB (128KB)"},
{"name": "Multi X-in-1 STM32F103C8 (64KB)"},
{"name": "Multi 5-in-1 (Jumper T18 Internal)"}
],
"toolsDependencies": [{
"packager": "arduino",
"name": "arm-none-eabi-gcc",
"version": "4.8.3-2014q1"
}]
},
{
"name": "Multi 4-in-1 OrangeRX Board - DEPRECATED, USE MULTI 4-IN-1 AVR BOARDS PACKAGE INSTEAD",
"architecture": "orangerx",

View File

@@ -0,0 +1,305 @@
local toolName = "TNS|DumboRC P series|TNE"
-- EdgeTX/Multi bridge:
-- Multi_Buffer[4] is RF payload length, [5..12] is RF payload.
-- Multi rewrites the 00 00 token and checksum from its hop state.
-- Special1 payload: 18 00 00 arg_l arg_h 00. Args: 1 poll, 2 Set GY EPA, 3 Set FS.
-- Special2 payload: 28 00 00 gyro0 gyro1 gyro2 gyro3 00.
-- Gyro word: bit0 enable, bit1 phase, bits2..5 SEN channel selector
-- (0=NULL, 1..7=CH2..CH8), bits6..13 SEN, bits14..21 PCA,
-- bits22..29 AGS, bits30..31 servo frequency (67HZ,250HZ,50HZ,300HZ).
local PROTO_RLINK = 74
local SUB_DUMBORC_P = 4
local TX_READY = 4
local TX_PAYLOAD = 5
local TX_MAX_PAYLOAD = 8
local RX_READY = 14
local RX_PAYLOAD = 15
local RX_MAX_PAYLOAD = 32
local colorLcd = type(lcd.RGB) == "function"
local servoHz = { "67HZ", "250HZ", "50HZ", "300HZ" }
local gyro = { enable = 0, phase = 0, senCh = 0, sen = 0, pca = 0, ags = 0, flags = 0 }
local lines = {}
local sel = 1
local top = 1
local edit = false
local blink = 0
local moduleOk = false
local haveValues = false
local function limit(v, mn, mx)
if v < mn then return mn end
if v > mx then return mx end
return v
end
local function byte(v)
return limit(math.floor(tonumber(v) or 0), 0, 255)
end
local function gyroRaw(v)
return limit(math.floor(tonumber(v) or 0), 0, 200)
end
local function gyroText(v)
local raw = gyroRaw(v)
return tostring(math.floor(raw / 2)) .. (raw % 2 == 0 and ".0" or ".5")
end
local function screenLines()
if colorLcd then return limit(math.floor(((LCD_H or 272) - 46) / 20), 8, 12) end
return 6
end
local function drawTitle(title)
if colorLcd and lcd.drawFilledRectangle then
lcd.drawFilledRectangle(0, 0, LCD_W, 30, COLOR_THEME_SECONDARY1)
lcd.drawText(3, 5, title, COLOR_THEME_PRIMARY2)
elseif lcd.drawScreenTitle then
lcd.drawScreenTitle(title, 0, 0)
else
lcd.drawText(0, 0, title, INVERS)
end
end
local function findModule()
for i = 0, 1 do
local m = model.getModule(i)
if m and m["Type"] == 6 and m["protocol"] == PROTO_RLINK and m["subProtocol"] == SUB_DUMBORC_P then
return true
end
end
return false
end
local function initBuffer()
multiBuffer(0, string.byte("R"))
if multiBuffer(0) ~= string.byte("R") then
error("Not enough memory!")
return
end
multiBuffer(1, string.byte("L"))
multiBuffer(2, string.byte("n"))
multiBuffer(3, string.byte("k"))
multiBuffer(TX_READY, 0)
multiBuffer(RX_READY, 0)
end
local function release()
for i = 0, RX_PAYLOAD + RX_MAX_PAYLOAD - 1 do
multiBuffer(i, 0)
end
end
local function sendPayload(payload)
local len = #payload
if len < 1 or len > TX_MAX_PAYLOAD or multiBuffer(TX_READY) ~= 0 then
return false
end
for i = 1, TX_MAX_PAYLOAD do
multiBuffer(TX_PAYLOAD + i - 1, 0)
end
for i = 1, #payload do
multiBuffer(TX_PAYLOAD + i - 1, byte(payload[i]))
end
multiBuffer(TX_READY, len)
return true
end
local function sendSpecial1(arg)
return sendPayload({ 0x18, 0, 0, arg % 256, math.floor(arg / 256), 0 })
end
local function gyroSelector()
if gyro.senCh < 2 or gyro.senCh > 8 then return 0 end
return gyro.senCh - 1
end
local function sendGyro()
local sen = gyroRaw(gyro.sen)
local pca = gyroRaw(gyro.pca)
local ags = gyroRaw(gyro.ags)
local b0 = gyro.enable + gyro.phase * 2 + gyroSelector() * 4 + (sen % 4) * 64
local b1 = math.floor(sen / 4) + (pca % 4) * 64
local b2 = math.floor(pca / 4) + (ags % 4) * 64
local b3 = math.floor(ags / 4) + limit(gyro.flags, 0, 3) * 64
sendPayload({ 0x28, 0, 0, b0, b1, b2, b3, 0 })
end
local function decodeGyroBytes(b0, b1, b2, b3)
b0 = byte(b0); b1 = byte(b1); b2 = byte(b2); b3 = byte(b3)
gyro.enable = b0 % 2
gyro.phase = math.floor(b0 / 2) % 2
local selector = math.floor(b0 / 4) % 16
gyro.senCh = selector == 0 and 0 or limit(selector + 1, 2, 8)
gyro.sen = gyroRaw(math.floor(b0 / 64) + (b1 % 64) * 4)
gyro.pca = gyroRaw(math.floor(b1 / 64) + (b2 % 64) * 4)
gyro.ags = gyroRaw(math.floor(b2 / 64) + (b3 % 64) * 4)
gyro.flags = math.floor(b3 / 64) % 4
haveValues = true
end
local function pollRx()
local len = multiBuffer(RX_READY)
if not len or len == 0 then return end
if len > RX_MAX_PAYLOAD then
multiBuffer(RX_READY, 0)
return
end
local p = {}
for i = 1, len do
p[i] = multiBuffer(RX_PAYLOAD + i - 1)
end
multiBuffer(RX_READY, 0)
if len == 7 and p[1] == 0x01 then
decodeGyroBytes(p[3], p[4], p[5], p[6])
end
end
local function chText()
if gyro.senCh == 0 then return "NULL" end
return "CH" .. gyro.senCh
end
local function rebuildLines()
lines = {
{ "Poll RX", "action", function() sendSpecial1(1) end },
{ "Gyro", "toggle", "enable" },
{ "Phase", "toggle", "phase" },
{ "SEN Ch", "channel", "senCh" },
{ "SEN", "percent", "sen" },
{ "PCA", "percent", "pca" },
{ "AGS", "percent", "ags" },
{ "Servo Hz", "flags", "flags" },
{ "Send Gyro", "action", sendGyro },
{ "Set GY EPA", "action", function() sendSpecial1(2) end },
{ "Set FS", "action", function() sendSpecial1(3) end },
}
end
local function lineValue(line)
if line[2] == "action" then return ">" end
if not haveValues then return "--" end
if line[2] == "toggle" then return gyro[line[3]] == 0 and "Off" or "On" end
if line[2] == "channel" then return chText() end
if line[2] == "percent" then return gyroText(gyro[line[3]]) end
if line[2] == "flags" then return servoHz[gyro.flags + 1] or tostring(gyro.flags) end
return ""
end
local function changeValue(dir, fast)
local line = lines[sel]
if not line then return end
local step = fast and 20 or 1
haveValues = true
if line[2] == "toggle" then
gyro[line[3]] = dir > 0 and 1 or 0
elseif line[2] == "channel" then
local vals = { 0, 2, 3, 4, 5, 6, 7, 8 }
local pos = 1
for i = 1, #vals do
if vals[i] == gyro.senCh then pos = i end
end
gyro.senCh = vals[limit(pos + dir, 1, #vals)]
elseif line[2] == "percent" then
gyro[line[3]] = gyroRaw(gyro[line[3]] + dir * step)
elseif line[2] == "flags" then
gyro.flags = limit(gyro.flags + dir, 0, 3)
end
end
local function fastRotary()
return getRotEncSpeed() > 1
end
local function handleEvent(event)
local nextEvent = edit and EVT_VIRTUAL_INC or EVT_VIRTUAL_NEXT
local prevEvent = edit and EVT_VIRTUAL_DEC or EVT_VIRTUAL_PREV
if event == nextEvent then
if edit then changeValue(1, fastRotary()) else sel = limit(sel + 1, 1, #lines) end
elseif event == prevEvent then
if edit then changeValue(-1, fastRotary()) else sel = limit(sel - 1, 1, #lines) end
elseif event == EVT_VIRTUAL_NEXT_PAGE then
if edit then changeValue(1, true) else sel = limit(sel + screenLines(), 1, #lines) end
elseif event == EVT_VIRTUAL_PREV_PAGE then
if edit then changeValue(-1, true) else sel = limit(sel - screenLines(), 1, #lines) end
killEvents(event)
elseif event == EVT_VIRTUAL_ENTER then
local line = lines[sel]
if line and line[2] == "action" then
line[3]()
elseif line then
edit = not edit
end
end
local count = screenLines()
if sel < top then top = sel end
if sel >= top + count then top = sel - count + 1 end
end
local function draw()
lcd.clear()
drawTitle("DumboRC P series")
local font = colorLcd and 0 or SMLSIZE
local x = 2
local y = colorLcd and 34 or 9
local dy = colorLcd and 20 or 8
local valueX = colorLcd and 150 or 82
if not moduleOk then
if colorLcd then
lcd.drawText(x, y + dy, "Select Multi RadLink/Dumbo_P", font + BLINK)
else
lcd.drawText(x, y + dy, "Select RadLink", font + BLINK)
lcd.drawText(x, y + dy * 2, "Dumbo_P", font + BLINK)
end
return
end
for i = top, math.min(#lines, top + screenLines() - 1) do
local attr = font
if i == sel then
attr = attr + INVERS
if edit then
blink = (blink + 1) % 30
if blink > 15 then attr = font end
end
end
local yy = y + (i - top) * dy
lcd.drawText(x, yy, lines[i][1], attr)
lcd.drawText(valueX, yy, lineValue(lines[i]), attr)
end
end
local function init()
moduleOk = type(multiBuffer) == "function" and findModule()
rebuildLines()
if moduleOk then initBuffer() end
end
local function run(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
elseif event == EVT_VIRTUAL_EXIT then
if moduleOk then release() end
return 2
end
if moduleOk then
pollRx()
handleEvent(event)
end
draw()
return 0
end
return { init = init, run = run }

View File

@@ -0,0 +1,167 @@
---- #########################################################################
---- # #
---- # Telemetry Widget script for FrSky Horus/Radio Master TX16s #
---- # Copyright (C) EdgeTX #
-----# #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
-- Model Locator by RSSI
-- Offer Shmuely (based on code from Scott Bauer 6/21/2015)
-- Date: 2021
-- ver: 0.1
-- MHA (based on code from Offer Shmuely)
-- Date: 2022
-- ver: 0.11
-- changes: made version for Graupner HoTT. Uses real Rssi data scaled -15db to -115db to 100..0
-- This widget help to find a lost/crashed model based on the RSSI (if still available)
-- The widget produce audio representation (variometer style) of the RSSI from the lost model
-- The widget also display the RSSI in a visible colorized bar (0-100%)
-- There are two way to use it
-- 1. The simple way:
-- walk toward the quad/plane that crashed,
-- as you get closer to your model the beeps will become more frequent with higher pitch (and a visual bar graph as well)
-- until you get close enough to find it visually
-- 2. the more accurate way:
-- turn the antenna straight away (i.e. to point from you, straight away)
-- try to find the weakest signal! (not the highest), i.e. the lowest RSSI you can find, this is the direction to the model.
-- now walk to the side (not toward the model), find again the weakest signal, this is also the direction to your model
-- triangulate the two lines, and it will be :-)
local delayMillis = 100
local nextPlayTime = getTime()
local img = Bitmap.open("/SCRIPTS/TOOLS/Model Locator (by RSSI).png")
--------------------------------------------------------------
local function log(s)
--return;
print("locator: " .. s)
end
--------------------------------------------------------------
-- init_func is called once when model is loaded
local function init()
return 0
end
-- bg_func is called periodically when screen is not visible
local function bg()
return 0
end
-- This function returns green at gvalue, red at rvalue and graduate in between
local function getRangeColor(value, red_value, green_value)
local range = math.abs(green_value - red_value)
if range == 0 then
return lcd.RGB(0, 0xdf, 0)
end
if value == nil then
return lcd.RGB(0, 0xdf, 0)
end
if green_value > red_value then
if value > green_value then
return lcd.RGB(0, 0xdf, 0)
end
if value < red_value then
return lcd.RGB(0xdf, 0, 0)
end
g = math.floor(0xdf * (value - red_value) / range)
r = 0xdf - g
return lcd.RGB(r, g, 0)
else
if value > green_value then
return lcd.RGB(0, 0xdf, 0)
end
if value < red_value then
return lcd.RGB(0xdf, 0, 0)
end
r = math.floor(0xdf * (value - green_value) / range)
g = 0xdf - r
return lcd.RGB(r, g, 0)
end
end
local function main(event)
lcd.clear()
-- fetch uplink rssi (HoTT sensor Rssi)
local rssi = getValue("Rssi")
-- calculate a percentage for the color bar (range -115db to -15db)
local rssiP = rssi
if(rssi ~= 0) then -- rssi < 0 -> telemtry data received
if(rssi >= -15) then -- -15db to -1db => 100%
rssiP = 100
else
if(rssi >= -115) then -- between -115db and -15db => 0% to 100%
rssiP = 100+rssi+15
else
rssiP = 0 -- less than -115 => 0%
end
end
end
lcd.drawBitmap(img, 250, 50, 40)
-- Title
lcd.drawText(3, 3, "Graupner HoTT Rssi Model Locator", 0)
myColor = getRangeColor(rssi, 0, 100)
lcd.setColor(CUSTOM_COLOR, myColor)
-- draw current value
local dx = 0
if rssi < -99 then
dx = -33
end
if rssi == 0 then
lcd.drawText(115, 73, "no telemetry", DBLSIZE + CUSTOM_COLOR)
else
lcd.drawNumber(180+dx, 30, rssi, XXLSIZE + CUSTOM_COLOR)
lcd.drawText(275, 73, "db", 0 + CUSTOM_COLOR)
end
-- draw main bar
lcd.setColor(CUSTOM_COLOR, YELLOW) -- RED / YELLOW
local xMin = 0
local yMin = 270
local xMax = 480
local yMax = 200
local h = 0
local rssiAsX = (rssiP * xMax) / 100
for xx = xMin, rssiAsX, 20 do
lcd.setColor(CUSTOM_COLOR, getRangeColor(xx, xMin, xMax - 40))
h = h + 10
lcd.drawFilledRectangle(xx, yMin - h, 15, h, CUSTOM_COLOR)
end
-- beep
if getTime() >= nextPlayTime then
playFile("/SCRIPTS/TOOLS/Model Locator (by RSSI).wav")
nextPlayTime = getTime() + delayMillis - rssiP
end
return 0
end
return {init = init,run = main,background = bg}

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 }

244
Lua_scripts/MultiChan.txt Normal file
View File

@@ -0,0 +1,244 @@
24,0,Assan,Std,0,CH5,CH6,CH7,CH8
14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
14,5,Bayang,QX100,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
59,1,BayangRX,CPPM,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
12,0,CX10,Green,1,Flip,Rate
12,1,CX10,Blue,1,Flip,Rate,Pict,Video
12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
7,3,Devo,6CH,0,CH5,CH6
7,4,Devo,7CH,0,CH5,CH6,CH7
33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
6,0,DSM,2_1F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
6,1,DSM,2_2F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
6,2,DSM,X_1F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
6,3,DSM,X_2F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
6,5,DSM,R_1F,0,AUX3,AUX4,AUX5
6,6,DSM,2SFC,0
70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
70,1,DSM_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
16,0,ESKY,Std,0,Gyro,Pitch
16,1,ESKY,ET4,0,Gyro,Pitch
35,0,ESKY150,4CH,0
35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
69,0,ESKY150V2,Std,0,CH5_RA,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
1,0,Flysky,Flysky,0,CH5,CH6,CH7,CH8
1,1,Flysky,V9x9,1,Flip,Light,Pict,Video
1,2,Flysky,V6x6,1,Flip,Light,Pict,Video,HLess,RTH,XCAL,YCAL
1,3,Flysky,V912,1,BtmBtn,TopBtn
1,4,Flysky,CX20,0,CH5,CH6,CH7
28,0,Flysky_AFHDS2A,PWM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,4,Flysky_AFHDS2A,Gyro_Off,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,ST_Ga,TH_Ga,Prio,Calib
28,5,Flysky_AFHDS2A,Gyro_On,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,ST_Ga,TH_Ga,Prio,Calib
28,6,Flysky_AFHDS2A,G_On_Rev,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,ST_Ga,TH_Ga,Prio,Calib
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
56,1,Flysky2A_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
53,0,Height,5ch,0,Gear
53,1,Height,8ch,0,Gear,Gyro,Flap,Light
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
3,0,FrSkyD,D8,0,CH5,CH6,CH7,CH8
3,0,FrSkyD,D8Cloned,0,CH5,CH6,CH7,CH8
67,0,FrSkyL,LR12,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
67,1,FrSkyL,LR12_6CH,0,CH5,CH6
15,0,FrSkyX,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
15,1,FrSkyX,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
15,2,FrSkyX,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
15,3,FrSkyX,D16_8CH_LBT,0,CH5,CH6,CH7,CH8
15,4,FrSkyX,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
15,5,FrSkyX,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,0,FrSkyX2,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,1,FrSkyX2,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
64,2,FrSkyX2,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,3,FrSkyX2,D16_8CH_LBT,1,CH5,CH6,CH7,CH8
64,4,FrSkyX2,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
64,5,FrSkyX2,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
55,1,FrSkyRX,CloneTX,0
55,2,FrSkyRX,EraseTX,0
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
58,0,FX,FX816,1
58,1,FX,FX620,1
58,2,FX,9630,1,Rate,Gyro,TrimR,TrimA,TrimE
58,3,FX,Q560,1,FLIP,Gyro,LEDs
58,4,FX,QF012,1,FLIP,Gyro,Invert,Reset
58,5,FX,BM26,1,FLIP,Gyro,LEDs,LED,CALIB
58,6,FX,A570,1,STOP,Rate,Color,LED,TrimR,TrimA,TrimE
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
23,0,FQ777,124,1,Flip,RTH,HLess,Expert
23,1,FQ777,XBM37,1,Rate,Flip,HLess,LED,Pict,Video,RTH,OK,ETrim,Atrim
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
26,4,Hontai,XKK170,1,Rate,Emerg,TakLan,Calib,TrimA,TrimE,Optic
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
2,1,Hubsan,H301,0,RTH,Light,Stab,Video
2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
71,0,JJRC345,JJRC345,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
49,0,KF606,KF606,1,Trim,LED
49,1,KF606,MIG320,1,Trim,LED
49,2,KF606,ZCZ50,1,Trim,UNK
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim,Rtrim,Hover
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim,Rtrim,Hover
73,0,Kyosho,FHSS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
73,1,Kyosho,Hype,0,CH5,CH6
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,Atrim,Etrim
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess,Atrim,Etrim
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess,Atrim,Etrim
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess,Atrim,Etrim
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess,Atrim,Etrim
17,5,MT99XX,A180,0,3D_6G,Rate,3D_6G,n-a,n-a,Atrim,Etrim
17,6,MT99XX,Dragon,0,Mode,RTH,n-a,n-a,n-a,Atrim,Etrim
17,7,MT99XX,F949G,0,6G_3D,Light,Rates,Unk1,Unk2,Atrim,Etrim
92,0,MT99xx2,PA18,0,MODE,FLIP,RTH,n-a,n-a,Atrim,Etrim
92,1,MT99xx2,SU35,0,Mode,LED,LED_FH,Invert,Rate,Atrim,Etrim
44,0,NCC1701,Std,1,Warp
77,0,OMP,M2,0,THold,IdleUp,6G_3D
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
60,1,Pelikan,LITE_V4,0,CH5,CH6,CH7,CH8
60,2,Pelikan,SCX24,0
51,0,Potensic,A20,1,TakLan,Emerg,Mode,HLess
66,0,Propel,74-Z,1,LEDs,RollCW,RolCCW,Fire,Weapon,Calib,AltHol,TakeOf,Land,Train
29,0,Q2x2,Q222,1,Flip,LED,Mod2,Mod1,HLess,RTH,XCal,YCal
29,1,Q2x2,Q242,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
29,2,Q2x2,Q282,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
31,0,Q303,Q303,1,AltHol,Flip,Pict,Video,HLess,RTH,Gimbal
31,1,Q303,C35,1,Arm,VTX,Pict,Video,n-a,RTH,Gimbal
31,2,Q303,CX10D,1,Arm,Flip
31,3,Q303,CX10WD,1,Arm,Flip
72,0,Q90C,Std,0,FMode,VTX+
74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
74,2,RadioLink,DumboRC,0,CH5,CH6,CH7,CH8GY,CH9,CH10,n-a,n-a,n-a,n-a,n-a,n-a
74,3,RadioLink,RC4G,0,CH5,FS_CH1,FS_CH2,FS_CH3,FS_CH4
74,4,RadioLink,Dumbo_P,0,CH5,CH6,CH7,CH8GY,CH9,CH10,n-a,n-a,n-a,n-a,n-a,n-a
76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,ThCut,Rotat
76,1,Realacc,WLV8TX,0,ST_Tr
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
21,0,Futaba,SFHSS,0,CH5,CH6,CH7,CH8
19,0,Shenqi,Cycle,1
68,0,Skyartec,Std,0,CH5,CH6,CH7
11,0,SLT,V1,0,Gear,Pitch
11,1,SLT,V2,0,CH5,CH6,CH7,CH8
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib
11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict
11,5,SLT,V1_4CH,0
11,6,SLT,RF_SIM,0,CH5,CH6,CH7,CH8,CH9,CH10
10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess
43,0,Traxxas,TQ2,0
43,1,Traxxas,TQ1,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,Beep
48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn,Beep
48,2,V761,TOPRC,0,Gyro,Calib,Flip,RtnAct,Rtn
46,0,V911s,V911s,1,Calib,Rate
46,1,V911s,E119,1,Calib,Rate,6G_3D
22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
30,1,WK2x01,WK2401,0
30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video,Flip,Light
62,2,XK,Cars,0,FMode,TakeOf,Emerg,3D_6G,Pict,Video,Flip,Light
99,0,XK2,X4,0,Rate,Mode,Hover,Light,Stunt
99,1,XK2,P10,0,Rate,Mode,Hover,Light,Stunt
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
52,0,ZSX,280,1,Light
78,0,M-Link,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
79,0,WFLY2,RF20x,0,CH5,CH6,CH7,CH8,CH9,CH10
80,0,E016Hv2,E016Hv2,1,TakLan,EmStop,Flip,Calib,HLess,RTH
81,0,E010r5,E010r5,1,Flip,LED,CALIB,HLess,RTH,GLIDE
82,0,LOLI,Std,0,CH5,CH6,CH7,CH8,1SwSePpPw,2SwSePw,3SwSe,4SwSe,5SwSeSb,6SwSe,7SwSePw,8SwSe
83,0,E129,E129,1,TakLan,EmStop,TrimA,TrimE,TrimR
83,1,E129,C186,1,TakLan,EmStop,TrimA,TrimE,TrimR,Loop,Flip,Debug
84,0,JOYSWAY,Std,0
85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH
87,0,IKEA
89,0,LOSI
90,0,MouldKg,A4444,0
90,1,MouldKg,D4444,0
90,2,MouldKg,A664,0
91,0,Xerall,Tank,0,FlTa,TakLan,Rate,HLess,Photo,Video,TrimR,TrimE,TrimA
93,0,Kyosho2,KT-17,0
94,0,Scorpio
95,0,Bluefly,HP100,0,CH5,CH6,CH7,CH8
96,0,BumbleB
97,0,SGF22,F22,1,Mode,Flip,LED,Pict,Video,TrRes,Bal,HiBal
97,1,SGF22,F22S,1,Mode,Flip,LED,Pict,Video,TrRes
97,2,SGF22,J20,1,Mode,Flip,LED,Pict,Video
61,0,EazyRC
98,0,Kyosho3,ASF,0
100,0,YuXiang,Std,0,Lock,Rate,Land,Manual,Flip,Mode,Pitch
102,0,JIABAILE,Std,0,Speed,Light,Flash
102,1,JIABAILE,Gyro,0,Speed,Light,Flash,ST_Tr
103,0,H36,Std,1,Flip,HLess,RTH
104,0,KAMTOM,Std,0,ST_Tr,TH_Tr,TH_DR
105,0,Shenqi2,Std,1
106,0,WL91x,Std,0
107,0,WPL,Std,0,Light,TH_DR,ST_DR
108,0,Ares,6HPA_Tx,0,CH5,CH6

View File

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

533
Lua_scripts/MultiConfig.lua Normal file
View File

@@ -0,0 +1,533 @@
---- #########################################################################
---- # #
---- # Copyright (C) OpenTX #
-----# #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
--###############################################################################
-- Multi buffer for Config description
-- To start operation:
-- Write 0xFF at address 4 will request the buffer to be cleared
-- Write "Conf" at address 0..3
-- Read
-- Read at address 12 gives the current config page
-- Read at address 13..172 gives the current data of the page = 8 lines * 20 caracters
-- Write
-- Write at address 5..11 the command
-- Write 0x01 at address 4 will send the command to the module
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
--###############################################################################
local Version = "v0.2"
local Focus = -1
local Page = 0
local Edit = -1
local Edit_pos = 1
local Menu = { {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""} }
local Menu_value = {}
local Blink = 0
local ModuleNumber = 0
local ModuleType = ""
local Module = {}
local InitialProtocol = 0
local InitialSubProtocol = 0
function bitand(a, b)
local result = 0
local bitval = 1
while a > 0 and b > 0 do
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
result = result + bitval -- set the current bit
end
bitval = bitval * 2 -- shift left
a = math.floor(a/2) -- shift right
b = math.floor(b/2)
end
return result
end
local function Config_Send(page, line, value)
local i
i = (page*16) + line
multiBuffer( 5, i )
for i = 1 , 6 , 1 do
multiBuffer( 5+i, value[i] )
end
multiBuffer( 4, 1 )
end
local function Config_Release()
--Set the protocol back to what it was
Module.protocol = InitialProtocol
Module.subProtocol = InitialSubProtocol
model.setModule(ModuleNumber, Module)
--Stop requesting updates
local i
for i = 3 , 0 , -1 do
multiBuffer( i, 0 )
end
end
local function Config_Page( )
Config_Send(Page, 0, { 0, 0, 0, 0, 0, 0 })
end
local function Config_Draw_Edit( event )
local i
local text
if Menu[Focus].field_type == 0xD0 then
-- Editable Hex value
if Edit == -1 then
-- Init
Edit = 0
Edit_pos = 1
Blink = 0
for i = 1, Menu[Focus].field_len, 1 do
Menu_value[i] = Menu[Focus].field_value[i]
end
end
if Edit == 0 then
-- Not editing value
if event == EVT_VIRTUAL_ENTER then
if Edit_pos > Menu[Focus].field_len then
-- Save or Cancel
Edit = -1
if Edit_pos == Menu[Focus].field_len + 1 then
-- Save
Config_Send(Page, Focus, Menu_value)
end
return
else
-- Switch to edit mode
Edit = 1
end
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
-- Move cursor
Edit_pos = Edit_pos - 1
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < Menu[Focus].field_len + 2 then
-- Move cursor
Edit_pos = Edit_pos + 1
end
else
-- Editing value
if event == EVT_VIRTUAL_ENTER then
-- End edit
Edit = 0
elseif event == EVT_VIRTUAL_PREV then
-- Change value
if Menu_value[Edit_pos] > 0 then
Menu_value[Edit_pos] = Menu_value[Edit_pos] - 1
end
elseif event == EVT_VIRTUAL_NEXT then
-- Change value
if Menu_value[Edit_pos] < 255 then
Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1
end
end
--Blink
Blink = Blink + 1
if Blink > 30 then
Blink = 0
end
end
--Display
if LCD_W == 480 then
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
else
lcd.clear()
end
for i = 1, Menu[Focus].field_len, 1 do
if i==Edit_pos and (Edit ~= 1 or Blink > 15) then
attrib = INVERS
else
attrib = 0
end
if LCD_W == 480 then
lcd.drawText(170+12*2*(i-1), 110, string.format('%02X', Menu_value[i]), attrib)
else
lcd.drawText(17+6*2*(i-1), 10, string.format('%02X', Menu_value[i]), attrib + SMLSIZE)
end
end
if Edit_pos == Menu[Focus].field_len + 1 then
attrib = INVERS
else
attrib = 0
end
if LCD_W == 480 then
lcd.drawText(170, 130, "Save", attrib)
else
lcd.drawText(17, 30, "Save", attrib + SMLSIZE)
end
if Edit_pos == Menu[Focus].field_len + 2 then
attrib = INVERS
else
attrib = 0
end
if LCD_W == 480 then
lcd.drawText(260, 130, "Cancel", attrib)
else
lcd.drawText(77, 30, "Cancel", attrib + SMLSIZE)
end
elseif Menu[Focus].field_type == 0x90 then
-- Action text
if Edit == -1 then
-- Init
Edit = 0
Edit_pos = 2
end
if event == EVT_VIRTUAL_ENTER then
-- Exit
Edit = -1
if Edit_pos == 1 then
-- Yes
Config_Send(Page, Focus, { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA } )
end
return
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
-- Switch to Yes
Edit_pos = Edit_pos - 1
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < 2 then
-- Switch to No
Edit_pos = Edit_pos + 1
end
-- Display
if LCD_W == 480 then
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
else
lcd.clear()
end
if LCD_W == 480 then
lcd.drawText(170, 110, Menu[Focus].field_text .. "?")
else
lcd.drawText(17, 10, Menu[Focus].field_text .. "?", SMLSIZE)
end
if Edit_pos == 1 then
attrib = INVERS
else
attrib = 0
end
if LCD_W == 480 then
lcd.drawText(170, 130, "Yes", attrib)
else
lcd.drawText(17, 30, "Yes", attrib + SMLSIZE)
end
if Edit_pos == 2 then
attrib = INVERS
else
attrib = 0
end
if LCD_W == 480 then
lcd.drawText(260, 130, "No", attrib)
else
lcd.drawText(77, 30, "No", attrib)
end
end
end
local function Config_Next_Prev( event )
-- Next Prev on main menu
local line
if event == EVT_VIRTUAL_PREV then
for line = Focus - 1, 1, -1 do
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
Focus = line
break
end
end
elseif event == EVT_VIRTUAL_NEXT then
for line = Focus + 1, 7, 1 do
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
Focus = line
break
end
end
end
end
local function Config_Draw_Menu()
-- Main menu
local i
local value
local line
local length
local text
lcd.clear()
if LCD_W == 480 then
--Draw title
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
lcd.drawText(1, 5, "Multi Config " .. Version, MENU_TITLE_COLOR)
if multiBuffer(13) == 0x00 then
lcd.drawText(10,50,"No Config telemetry...", BLINK)
end
else
--Draw on LCD_W=128
lcd.drawText(1, 0, "Multi Config " .. Version, SMLSIZE)
if multiBuffer(13) == 0x00 then
lcd.drawText(2,17,"No Config telemetry...",SMLSIZE)
end
end
if multiBuffer(13) ~= 0x00 then
if LCD_W == 480 then
--Draw firmware version and channels order
local ch_order = multiBuffer(17)
local channel_names = {}
channel_names[bitand(ch_order,3)+1] = "A"
ch_order = math.floor(ch_order/4)
channel_names[bitand(ch_order,3)+1] = "E"
ch_order = math.floor(ch_order/4)
channel_names[bitand(ch_order,3)+1] = "T"
ch_order = math.floor(ch_order/4)
channel_names[bitand(ch_order,3)+1] = "R"
lcd.drawText(150, 5, ModuleType.." v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4], MENU_TITLE_COLOR)
else
lcd.drawText(76, 0, "/Fw" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16),SMLSIZE) -- .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4])
end
--Draw Menu
for line = 1, 7, 1 do
--Clear line info
Menu[line].text = ""
Menu[line].field_type = 0
Menu[line].field_len = 0
for i = 1, 7, 1 do
Menu[line].field_value[i] = 0
end
Menu[line].field_text = ""
length = 0
--Read line from buffer
for i = 0, 20-1, 1 do
value=multiBuffer( line*20+13+i )
if value > 0x80 and Menu[line].field_type == 0 then
-- Read field type
Menu[line].field_type = bitand(value, 0xF0)
Menu[line].field_len = bitand(value, 0x0F)
length = Menu[line].field_len
if Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 and Focus == -1 then
-- First actionnable field if nothing was selected
Focus = line;
end
else
if Menu[line].field_type == 0 then
-- Text
if value == 0 then
break -- end of line
end
Menu[line].text = Menu[line].text .. string.char(value)
else
-- Menu specific fields
length = length - 1
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
Menu[line].field_text = Menu[line].field_text .. string.char(value)
else
Menu[line].field_value[Menu[line].field_len-length] = value
end
if length == 0 then
-- End of fields
break
end
end
end
end
-- Display menu text
if Menu[line].text ~= "" then
if Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 or Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
Menu[line].text = Menu[line].text .. ":"
end
if LCD_W == 480 then
lcd.drawText(10,32+20*line,Menu[line].text )
else
lcd.drawText(2,1+8*line,Menu[line].text,SMLSIZE)
end
end
-- Display specific fields
if line == Focus then
attrib = INVERS
else
attrib = 0
end
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
-- Text
if LCD_W == 480 then
lcd.drawText(10+9*#Menu[line].text, 32+20*line, Menu[line].field_text, attrib)
else
lcd.drawText(2+5*#Menu[line].text, 1+8*line, Menu[line].field_text, SMLSIZE + attrib)
end
elseif Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 then
-- Decimal value
value = 0
for i = 1, Menu[line].field_len, 1 do
value = value*256 + value
end
if LCD_W == 480 then
lcd.drawText(10+9*#Menu[line].text, 32+20*line, value, attrib)
else
lcd.drawText(2+5*#Menu[line].text, 1+8*line, value, SMLSIZE + attrib)
end
elseif Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
-- Hex value
text=""
for i = 1, Menu[line].field_len, 1 do
text = text .. string.format('%02X ', Menu[line].field_value[i])
end
if LCD_W == 480 then
lcd.drawText(10+9*#Menu[line].text, 32+20*line, text, attrib)
else
lcd.drawText(2+5*#Menu[line].text, 1+8*line, text, SMLSIZE + attrib)
end
end
end
end
end
-- Init
local function Config_Init()
--Find Multi module
Module_int = model.getModule(0)
Module_ext = model.getModule(1)
if Module_int["Type"] ~= 6 and Module_ext["Type"] ~= 6 then
error("No Multi module detected...")
return 2
end
if Module_int["Type"] == 6 and Module_ext["Type"] == 6 then
error("Two Multi modules detected, turn on only the one to be configured.")
return 2
end
if Module_int["Type"] == 6 then
ModuleNumber = 0
ModuleType = "Internal"
else
ModuleNumber = 1
ModuleType = "External"
end
--Get Module settings and set it to config protocol
Module = model.getModule(ModuleNumber)
InitialProtocol = Module.protocol
InitialSubProtocol = Module.subProtocol
Module.protocol = 86
Module.subProtocol = 0
model.setModule(ModuleNumber, Module)
--pause while waiting for the module to switch to config
for i = 0, 10, 1 do end
--Set protocol to talk to
multiBuffer( 0, string.byte('C') )
--test if value has been written
if multiBuffer( 0 ) ~= string.byte('C') then
error("Not enough memory!")
return 2
end
--Request init of the buffer
multiBuffer( 4, 0xFF )
multiBuffer(13, 0x00 )
--Continue buffer init
multiBuffer( 1, string.byte('o') )
multiBuffer( 2, string.byte('n') )
multiBuffer( 3, string.byte('f') )
-- Test set
-- multiBuffer( 12, 0 )
-- multiBuffer( 13, 1 )
-- multiBuffer( 14, 3 )
-- multiBuffer( 15, 2 )
-- multiBuffer( 16, 62 )
-- multiBuffer( 17, 0 + 1*4 + 2*16 + 3*64)
-- multiBuffer( 33, string.byte('G') )
-- multiBuffer( 34, string.byte('l') )
-- multiBuffer( 35, string.byte('o') )
-- multiBuffer( 36, string.byte('b') )
-- multiBuffer( 37, string.byte('a') )
-- multiBuffer( 38, string.byte('l') )
-- multiBuffer( 39, string.byte(' ') )
-- multiBuffer( 40, string.byte('I') )
-- multiBuffer( 41, string.byte('D') )
-- multiBuffer( 42, 0xD0 + 4 )
-- multiBuffer( 43, 0x12 )
-- multiBuffer( 44, 0x34 )
-- multiBuffer( 45, 0x56 )
-- multiBuffer( 46, 0x78 )
-- multiBuffer( 47, 0x9A )
-- multiBuffer( 48, 0xBC )
-- multiBuffer( 53, 0x90 + 9 )
-- multiBuffer( 54, string.byte('R') )
-- multiBuffer( 55, string.byte('e') )
-- multiBuffer( 56, string.byte('s') )
-- multiBuffer( 57, string.byte('e') )
-- multiBuffer( 58, string.byte('t') )
-- multiBuffer( 59, string.byte(' ') )
-- multiBuffer( 60, string.byte('G') )
-- multiBuffer( 61, string.byte('I') )
-- multiBuffer( 62, string.byte('D') )
-- multiBuffer( 63, 0x00 )
end
-- Main
local function Config_Run(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
elseif event == EVT_VIRTUAL_EXIT then
Config_Release()
return 2
else
Config_Draw_Menu()
if ( event == EVT_VIRTUAL_PREV_PAGE or event == EVT_VIRTUAL_NEXT_PAGE ) and Edit < 1 then
-- Not editing, ok to change page
if event == EVT_VIRTUAL_PREV_PAGE then
killEvents(event)
if Page > 0 then
--Page = Page - 1
--Config_Page()
end
else
--Page = Page + 1
--Config_Page()
end
end
if Focus > 0 then
-- At least one line has an action
if Edit >= 0 then
-- Currently editing
Config_Draw_Edit( event )
elseif event == EVT_VIRTUAL_ENTER then
-- Switch to edit
Config_Draw_Edit( 0 )
elseif event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_NEXT then
-- Main menu selection
Config_Next_Prev( event )
end
end
return 0
end
end
return { init=Config_Init, run=Config_Run }

221
Lua_scripts/MultiLOLI.lua Normal file
View File

@@ -0,0 +1,221 @@
local toolName = "TNS|Multi LOLI RX config|TNE"
---- #########################################################################
---- # #
---- # Copyright (C) OpenTX #
-----# #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
local loli_nok = false
local channels={ { 768, "PWM", 100, 102, "PPM", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH1
{ 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH2
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH3
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH4
{ 102, "SBUS", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH5
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH6
{ 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH7
{ -768, "Servo", 0, -2048, "Switch", -100 } } -- CH8
local sel = 1
local edit = false
local blink = 0
local BLINK_SPEED = 15
local function drawScreenTitle(title)
if LCD_W == 480 then
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
else
lcd.drawScreenTitle(title, 0, 0)
end
end
local function LOLI_Draw_LCD(event)
local line = 0
lcd.clear()
--Display settings
local lcd_opt = 0
if LCD_W == 480 then
drawScreenTitle("Multi - LOLI RX configuration tool")
x_pos = 152
x_inc = 90
y_pos = 40
y_inc = 20
else
x_pos = 5
x_inc = 30
y_pos = 1
y_inc = 8
lcd_opt = SMLSIZE
end
--Multi Module detection
if loli_nok then
if LCD_W == 480 then
lcd.drawText(10,50,"The LOLI protocol is not selected...", lcd_opt)
else
--Draw on LCD_W=128
lcd.drawText(2,17,"LOLI protocol not selected...",SMLSIZE)
end
return
end
--Display current config
if LCD_W == 480 then
line = line + 1
lcd.drawText(x_pos, y_pos+y_inc*line -2, "Channel", lcd_opt)
lcd.drawText(x_pos+x_inc, y_pos+y_inc*line -2, "Function", lcd_opt)
lcd.drawRectangle(x_pos-4, y_pos+y_inc*line -4 , 2*x_inc +2, 188)
lcd.drawLine(x_pos-4, y_pos+y_inc*line +18, x_pos-4 +2*x_inc +1, y_pos+y_inc*line +18, SOLID, 0)
lcd.drawLine(x_pos+x_inc -5, y_pos+y_inc*line -4, x_pos+x_inc -5, y_pos+y_inc*line -5 +188, SOLID, 0)
line = line + 1
end
local out
for i = 1, 8 do
out = getValue("ch"..(i+8))
lcd.drawText(x_pos, y_pos+y_inc*line, "CH"..i, lcd_opt)
for j = 1, #channels[i], 3 do
if out > channels[i][j] then
if sel == i then
invert = INVERS
if edit == true then
blink = blink + 1
if blink > BLINK_SPEED then
invert = 0
if blink > BLINK_SPEED * 2 then
blink = 0
end
end
end
else
invert = 0
end
lcd.drawText(x_pos+x_inc, y_pos+y_inc*line, channels[i][j+1], lcd_opt + invert)
break
end
end
line = line + 1
end
end
local function LOLI_Change_Value(dir)
local pos = 0
local out
--look for the current position
out = getValue("ch"..(sel+8))
for j = 1, #channels[sel], 3 do
if out > channels[sel][j] then
pos = j
break
end
end
--decrement or increment
if dir < 0 and pos > 1 then
pos = pos - 3
elseif dir > 0 and pos + 3 < #channels[sel] then
pos = pos + 3
else
return
end
--delete all mixers for the selected channel
local num_mix = model.getMixesCount(sel-1 +8)
for i = 1, num_mix do
model.deleteMix(sel-1 +8, 0);
end
--create new mixer
local source_max = getFieldInfo("cyc1")
local val = { name = channels[sel][pos+1],
source = source_max.id - 1, -- MAX=100 on TX16S
weight = channels[sel][pos+2],
offset = 0,
switch = 0,
multiplex = 0,
curveType = 0,
curveValue = 0,
flightModes = 0,
carryTrim = false,
mixWarn = 0,
delayUp = 0,
delayDown = 0,
speedUp = 0,
speedDown = 0 }
model.insertMix(sel-1 +8, 0, val)
end
local function LOLI_Menu(event)
if event == EVT_VIRTUAL_NEXT then
if edit == false then
-- not changing a value
if sel < 8 then
sel = sel + 1
end
else
-- need to inc the value
LOLI_Change_Value(1)
end
elseif event == EVT_VIRTUAL_PREV then
if edit == false then
-- not changing a value
if sel > 1 then
sel = sel - 1
end
else
-- need to dec the value
LOLI_Change_Value(-1)
end
elseif event == EVT_VIRTUAL_ENTER then
if edit == false then
edit = true
blink = BLINK_SPEED
else
edit = false
end
end
end
-- Init
local function LOLI_Init()
local module_conf = model.getModule(0)
if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then
module_conf = model.getModule(1)
if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then
loli_nok = true
end
end
end
-- Main
local function LOLI_Run(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
elseif event == EVT_VIRTUAL_EXIT then
return 2
else
LOLI_Menu(event)
LOLI_Draw_LCD(event)
return 0
end
end
return { init=LOLI_Init, run=LOLI_Run }

71
Lua_scripts/README.md Normal file
View File

@@ -0,0 +1,71 @@
# 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>
## MultiConfig
Enables to modify on a Multi module the Global ID, Cyrf ID or format the EEPROM.
Matching the ID of 2 Multi modules enable them to control the same receivers without rebinding. Be carefull the 2 modules should not be used at the same time unless you know what you are doing.
Notes:
- Supported from Multi v1.3.2.85 or above and OpenTX 2.3.12 or above
- The Multi module to be configured must be active, if there is a second Multi module in the radio it must be off
- Located on the radio SD card under \SCRIPTS\TOOLS
[![MultiCconfig](https://img.youtube.com/vi/lGyCV2kpqHU/0.jpg)](https://www.youtube.com/watch?v=lGyCV2kpqHU)
## MultiChannelsUpdater
Automatically name the channels based on the loaded Multi protocol and sub protocol including the module channel order convention.
Need OpenTX 2.3.9 or above. Located on the radio SD card under \SCRIPTS\TOOLS. This script needs MultiChan.txt to be present in the same folder.
[![MultiChannelsUpdater](https://img.youtube.com/vi/L58ayXuewyA/0.jpg)](https://www.youtube.com/watch?v=L58ayXuewyA)
## MultiLOLI
Script to set the channels function (switch, servo, pwm, ppm, sbus) on a [LOLI RX](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md#loli---82)
[![MultiLOLIconfig](https://img.youtube.com/vi/e698pQxfv-A/0.jpg)](https://www.youtube.com/watch?v=e698pQxfv-A)
## Graupner HoTT
Enable text configuration of the HoTT RX and sensors: Vario, GPS, ESC, GAM and EAM.
Need OpenTX 2.3.9 or above. Located on the radio SD card under \SCRIPTS\TOOLS.
Notes:
- Menu/MDL/Model is used to cycle through the detected sensors.
- It's normal to lose the telemetry feed while using the text mode configuration. Telemetry will resume properly if the script is exited by doing a short press on the exit button.
[![Text mode video](https://img.youtube.com/vi/81wd8NlF3Qw/0.jpg)](https://www.youtube.com/watch?v=81wd8NlF3Qw)
## Graupner HoTT Model Locator
This is the Graupner HoTT adapted version of the Model Locator script using RSSI.
The OpenTX sensor "RSSI" is populated by the individual OpenTX telemetry protocol implementations and returns a value from 0..100 (percent) originating from the early FrSky implementation. It turns out that FrSky did not really provide a genuine signal strength indicator in units of dbm but a link quality indicator in 0..100%. With Graupner HoTT the link quality indicator is not a good basis for the model locator as it is very non-linear and doesn't change much with distance. Using the Graupner HoTT telemetry sensor "Rssi" which is a true signal strength indicator serves the purpose of locating a model much better as it varies much more with distance.
## DSM Tools for EdgeTX and OpenTx
Collection of EdgeTx/OpenTX Tools to use with Spektrum Receivers including forward programming. Extract the color or black&white zip version at the root of your SD card.
Frank is maintaining these awesome tools, check out his [repository](https://github.com/frankiearzu/DSMTools). Feel free to ask questions or open issues there.
## DSM PID Flight log gain parameters for Blade micros
Lua telemetry script from [feathering on RCGroups](https://www.rcgroups.com/forums/showpost.php?p=46033341&postcount=20728) to facilitate setting the Gain Parameters on the Blade 150S FBL. It doesn't use Forward Programming but instead it just reads telemetry data from the Multi-module and displays it on a telemetry display.
It is very similar to the Telemetry Based Text Generator functionality on Spektrum transmitters where one doesn't need to rely on the angle of the swashplate to determine selection/value.

Binary file not shown.

Binary file not shown.

127
Lua_scripts/pidDsm.lua Normal file
View File

@@ -0,0 +1,127 @@
--
-- This telemetry script displays the Flight Log Gain
-- Parameters streamed from the Blade 150S Spektrum AR6335A
-- Flybarless Controller.
-- The script facilitates the setting of the FBL's
-- Gain Parameters including PID for both
-- cyclic and tail. It is similar to the Telemetry Based
-- Text Generator available on Spektrum transmitters.
-- Supporting similar Blade micros such as the Fusion 180
-- would possibly require minor modifications to this script.
-- This script reads telemetry data from the Spektrum
-- receiver and thus functionality relies on data being
-- captured by the OpenTX transmitter. A DSM
-- telemetry-ready module is required. Please see the
-- MULTI-Module project at https://www.multi-module.org/.
-- The only supported display is the Taranis'. It may work
-- with higher res screens.
--
-- Sensor names
local PSensor = "FdeA"
local ISensor = "FdeB"
local DSensor = "FdeL"
local RSensor = "FdeR"
local ActiveParamSensor = "Hold"
local tags = {"P", "I", "D"}
local function getPage(iParam)
-- get page from 0-based index
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
local res = (math.floor(iParam/4)==0) and 1 or 2
return res
end
function round(v)
-- round float
local factor = 100
return math.floor(v * factor + 0.5) / factor
end
local function readValue(sensor)
-- read from sensor, round and return
local v = getValue(sensor)
v = round(v)
return v
end
local function readActiveParamValue(sensor)
-- read and return a validated active parameter value
local v = getValue(sensor)
if (v<1 or v>8) then
return nil
end
return v
end
local function readParameters()
-- read and return parameters
local p = readValue(PSensor)
local i = readValue(ISensor)
local d = readValue(DSensor)
local r = readValue(RSensor)
local a = readActiveParamValue(ActiveParamSensor)
return {p,i,d,r,a}
end
local function drawParameters()
-- draw labels and params on screen
local params = readParameters()
local activeParam = params[5]
-- if active gain does not validate then assume
-- Gain Adjustment Mode is disabled
if not activeParam then
lcd.clear()
lcd.drawText(20,30,"Please enter Gain Adjustment Mode")
return
end
local activePage = getPage(activeParam-1)
for iParam=0,7 do
-- highlight selected parameter
local attr = (activeParam==iParam+1) and 2 or 0
-- circular index (per page)
local perPageIndx = iParam % 4 + 1
-- check if displaying cyclic params.
local isCyclicPage = (getPage(iParam)==1)
-- set y draw coord
local y = perPageIndx*10+2
-- labels
local x = isCyclicPage and 6 or 120
-- labels are P,I,D for both pages except for last param
local val = iParam==3 and "Response" or
(iParam==7 and "Filtering" or tags[perPageIndx])
lcd.drawText (x, y, val, attr)
-- gains
-- set all params for non-active page to '--' rather than 'last value'
val = (getPage(iParam)==activePage) and params[perPageIndx] or '--'
x = isCyclicPage and 70 or 180
lcd.drawText (x, y, val, attr)
end
end
local function run_func(event)
-- TODO: calling clear() on every function call redrawing all labels is not ideal
lcd.clear()
lcd.drawText (8, 2, "Cyclic (0...200)")
lcd.drawText (114, 2, "Tail (0...200)")
drawParameters()
end
local function init_func() end
local function bg_func() end
return { run=run_func, background=bg_func, init=init_func }

View File

@@ -27,13 +27,16 @@ void A7105_WriteData(uint8_t len, uint8_t channel)
for (i = 0; i < len; i++)
SPI_Write(packet[i]);
A7105_CSN_on;
if(protocol!=PROTO_FLYSKY)
if(protocol!=PROTO_WFLY2)
{
A7105_Strobe(A7105_STANDBY); //Force standby mode, ie cancel any TX or RX...
A7105_SetTxRxMode(TX_EN); //Switch to PA
if(!(protocol==PROTO_FLYSKY || (protocol==PROTO_KYOSHO && sub_protocol==KYOSHO_HYPE)))
{
A7105_Strobe(A7105_STANDBY); //Force standby mode, ie cancel any TX or RX...
A7105_SetTxRxMode(TX_EN); //Switch to PA
}
A7105_WriteReg(A7105_0F_PLL_I, channel);
A7105_Strobe(A7105_TX);
}
A7105_WriteReg(A7105_0F_PLL_I, channel);
A7105_Strobe(A7105_TX);
}
void A7105_ReadData(uint8_t len)
@@ -107,7 +110,7 @@ void A7105_WriteID(uint32_t ida)
{
A7105_CSN_off;
SPI_Write(A7105_06_ID_DATA); //ex id=0x5475c52a ;txid3txid2txid1txid0
SPI_Write((ida>>24)&0xff); //53
SPI_Write((ida>>24)&0xff); //54
SPI_Write((ida>>16)&0xff); //75
SPI_Write((ida>>8)&0xff); //c5
SPI_Write((ida>>0)&0xff); //2a
@@ -192,9 +195,9 @@ 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:
@@ -202,6 +205,21 @@ void A7105_AdjustLOBaseFreq(uint8_t cmd)
offset=(int16_t)FORCE_PELIKAN_TUNING;
#endif
break;
case PROTO_KYOSHO:
#ifdef FORCE_KYOSHO_TUNING
offset=(int16_t)FORCE_KYOSHO_TUNING;
#endif
break;
case PROTO_JOYSWAY:
#ifdef FORCE_JOYSWAY_TUNING
offset=(int16_t)FORCE_JOYSWAY_TUNING;
#endif
break;
case PROTO_WFLY2:
#ifdef FORCE_WFLY2_TUNING
offset=(int16_t)FORCE_WFLY2_TUNING;
#endif
break;
case PROTO_AFHDS2A:
case PROTO_AFHDS2A_RX:
#ifdef FORCE_AFHDS2A_TUNING
@@ -211,7 +229,7 @@ void A7105_AdjustLOBaseFreq(uint8_t cmd)
}
}
if(offset==1024) // Use channel 15 as an input
offset=convert_channel_16b_nolimit(CH15,-300,300);
offset=convert_channel_16b_nolimit(CH15,-300,300,false);
if(old_offset==offset) // offset is the same as before...
return;
@@ -282,8 +300,8 @@ const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
0x01, 0x0f // 30 - 31
};
#endif
#ifdef FLYZONE_A7105_INO
const uint8_t PROGMEM FLYZONE_A7105_regs[] = {
#ifdef HEIGHT_A7105_INO
const uint8_t PROGMEM HEIGHT_A7105_regs[] = {
0xff, 0x42, 0x00, 0x07, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x01, 0x50, // 00 - 0f
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x1f, // 10 - 1f
0x12, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3a, 0x00, 0x3f, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
@@ -306,6 +324,36 @@ const uint8_t PROGMEM PELIKAN_A7105_regs[] = {
0x01, 0x0f // 30 - 31
};
#endif
#ifdef KYOSHO_A7105_INO
const uint8_t PROGMEM KYOSHO_A7105_regs[] = {
0xff, 0x42, 0xff, 0x25, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50, // 00 - 0f
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x40, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0x03, 0x1f, // 10 - 1f
0x1e, 0x00, 0x00, 0xff, 0x00, 0x00, 0x23, 0x70, 0x1F, 0x47, 0x80, 0x57, 0x01, 0x45, 0x19, 0x00, // 20 - 2f
0x01, 0x0f // 30 - 31
};
const uint8_t PROGMEM KYOSHO_HYPE_A7105_regs[] = {
0xff, 0x42, 0x00, 0x10, 0xC0, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x05, 0x01, 0x04, // 00 - 0f
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x96, 0xc2, 0x1f, // 10 - 1f
0x12, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3a, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
0x01, 0x0f // 30 - 31
};
#endif
#ifdef WFLY2_A7105_INO //A7106 values
const uint8_t PROGMEM WFLY2_A7105_regs[] = {
0xff, 0x62, 0xff, 0x1F, 0x40, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x05, 0x00, 0x64, // 00 - 0f Changes: 0B:19->33, 0C:01,33
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x40, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0x03, 0x0f, // 10 - 1f 1C:4A->0A
0x12, 0x00, 0x00, 0xff, 0x00, 0x00, 0x23, 0x70, 0x15, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f 2B:77->03, 2E:19->18
0x01, 0x0f // 30 - 31
};
#endif
#ifdef JOYSWAY_A7105_INO
const uint8_t PROGMEM JOYSWAY_A7105_regs[] = {
0xff, 0x62, 0xff, 0x0F, 0x00, 0xff, 0xff ,0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0xF5, 0x00, 0x15, // 00 - 0f
0x9E, 0x4B, 0x00, 0x03, 0x56, 0x2B, 0x12, 0x4A, 0x02, 0x80, 0x80, 0x00, 0x0E, 0x91, 0x03, 0x0F, // 10 - 1f
0x16, 0x2A, 0x00, 0xff, 0xff, 0xff, 0x3A, 0x06, 0x1F, 0x47, 0x80, 0x01, 0x05, 0x45, 0x18, 0x00, // 20 - 2f
0x01, 0x0f // 30 - 31
};
#endif
#define ID_NORMAL 0x55201041
#define ID_PLUS 0xAA201041
@@ -314,10 +362,24 @@ void A7105_Init(void)
uint8_t *A7105_Regs=0;
uint8_t vco_calibration0, vco_calibration1;
#ifdef FLYZONE_A7105_INO
if(protocol==PROTO_FLYZONE)
#ifdef JOYSWAY_A7105_INO
if(protocol==PROTO_JOYSWAY)
{
A7105_Regs=(uint8_t*)FLYZONE_A7105_regs;
A7105_Regs=(uint8_t*)JOYSWAY_A7105_regs;
}
else
#endif
#ifdef WFLY2_A7105_INO
if(protocol==PROTO_WFLY2)
{
A7105_Regs=(uint8_t*)WFLY2_A7105_regs;
}
else
#endif
#ifdef HEIGHT_A7105_INO
if(protocol==PROTO_HEIGHT)
{
A7105_Regs=(uint8_t*)HEIGHT_A7105_regs;
A7105_WriteID(0x25A53C45);
}
else
@@ -348,13 +410,20 @@ void A7105_Init(void)
#ifdef FLYSKY_A7105_INO
if(protocol==PROTO_FLYSKY)
A7105_Regs=(uint8_t*)FLYSKY_A7105_regs;
else
#endif
#if defined(AFHDS2A_A7105_INO) || defined(AFHDS2A_RX_A7105_INO)
if(protocol==PROTO_AFHDS2A || protocol==PROTO_AFHDS2A_RX)
A7105_Regs=(uint8_t*)AFHDS2A_A7105_regs;
#endif
#ifdef KYOSHO_A7105_INO
if(protocol==PROTO_KYOSHO)
{
#if defined(AFHDS2A_A7105_INO) || defined(AFHDS2A_RX_A7105_INO)
A7105_Regs=(uint8_t*)AFHDS2A_A7105_regs;
#endif
if(sub_protocol==KYOSHO_HYPE)
A7105_Regs=(uint8_t*)KYOSHO_HYPE_A7105_regs;
else //FHSS && SYNCRO
A7105_Regs=(uint8_t*)KYOSHO_A7105_regs;
}
#endif
}
for (uint8_t i = 0; i < 0x32; i++)
@@ -368,59 +437,86 @@ void A7105_Init(void)
if(i==0x20) val=0x1E;
}
#endif
if( val != 0xFF)
#ifdef HEIGHT_A7105_INO
if(protocol==PROTO_HEIGHT && sub_protocol==HEIGHT_8CH)
if(i==0x03) val=0x0A;
#endif
if( val != 0xff)
A7105_WriteReg(i, val);
}
A7105_Strobe(A7105_STANDBY);
//IF Filter Bank Calibration
A7105_WriteReg(A7105_02_CALC,1);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
// A7105_ReadReg(A7105_22_IF_CALIB_I);
// A7105_ReadReg(A7105_24_VCO_CURCAL);
if(protocol!=PROTO_HUBSAN)
{
//VCO Current Calibration
A7105_WriteReg(A7105_24_VCO_CURCAL,0x13); //Recommended calibration from A7105 Datasheet
//VCO Bank Calibration
A7105_WriteReg(A7105_26_VCO_SBCAL_II,0x3b); //Recommended calibration from A7105 Datasheet
if(protocol==PROTO_KYOSHO && sub_protocol!=KYOSHO_HYPE)
{//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;
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
//VCO Current Calibration
A7105_WriteReg(A7105_24_VCO_CURCAL,0x13); //Recommended calibration from A7105 Datasheet
//VCO Bank Calibration
A7105_WriteReg(A7105_26_VCO_SBCAL_II,0x3b); //Recommended calibration from A7105 Datasheet
}
//VCO Bank Calibrate channel 0
A7105_WriteReg(A7105_0F_CHANNEL, 0);
A7105_WriteReg(A7105_02_CALC,2);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
vco_calibration0 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
//VCO Bank Calibrate channel A0
A7105_WriteReg(A7105_0F_CHANNEL, 0xa0);
A7105_WriteReg(A7105_02_CALC, 2);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
vco_calibration1 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
if(protocol==PROTO_BUGS || protocol==PROTO_WFLY2)
A7105_SetVCOBand(vco_calibration0 & 0x07, vco_calibration1 & 0x07); // Set calibration band value to best match
else
if(protocol!=PROTO_HUBSAN)
{
switch(protocol)
{
case PROTO_FLYSKY:
vco_calibration1=0x08;
break;
case PROTO_HEIGHT:
vco_calibration1=0x02;
break;
case PROTO_PELIKAN:
if(sub_protocol == PELIKAN_SCX24)
{
vco_calibration1=0x0A;
break;
}
case PROTO_KYOSHO: //sub_protocol Hype
vco_calibration1=0x0C;
break;
case PROTO_JOYSWAY:
vco_calibration1=0x09;
break;
default:
vco_calibration1=0x0A;
break;
}
A7105_WriteReg(A7105_25_VCO_SBCAL_I,vco_calibration1); //Reset VCO Band calibration
}
}
A7105_SetTxRxMode(TX_EN);
A7105_SetPower();

View File

@@ -24,10 +24,11 @@
enum {
AFHDS2A_RX_BIND1,
AFHDS2A_RX_BIND2,
AFHDS2A_RX_BIND3,
AFHDS2A_RX_DATA
};
static void __attribute__((unused)) AFHDS2A_Rx_build_telemetry_packet()
static void __attribute__((unused)) AFHDS2A_RX_build_telemetry_packet()
{
uint32_t bits = 0;
uint8_t bitsavailable = 0;
@@ -39,7 +40,7 @@ static void __attribute__((unused)) AFHDS2A_Rx_build_telemetry_packet()
packet_in[idx++] = 14; // number of channels in packet
// pack channels
for (uint8_t i = 0; i < 14; i++) {
uint32_t val = packet[9+i*2] | (packet[10+i*2] << 8);
uint32_t val = packet[9+i*2] | (((packet[10+i*2])&0x0F) << 8);
if (val < 860)
val = 860;
// convert ppm (860-2140) to Multi (0-2047)
@@ -55,13 +56,13 @@ static void __attribute__((unused)) AFHDS2A_Rx_build_telemetry_packet()
}
}
static uint8_t __attribute__((unused)) AFHDS2A_Rx_data_ready()
static uint8_t __attribute__((unused)) AFHDS2A_RX_data_ready()
{
// check if FECF+CRCF Ok
return !(A7105_ReadReg(A7105_00_MODE) & (1 << 5 | 1 << 6 | 1 << 0));
}
uint16_t initAFHDS2A_Rx()
void AFHDS2A_RX_init()
{
uint8_t i;
A7105_Init();
@@ -83,15 +84,12 @@ uint16_t initAFHDS2A_Rx()
hopping_frequency[i] = eeprom_read_byte((EE_ADDR)temp++);
phase = AFHDS2A_RX_DATA;
}
return 1000;
}
#define AFHDS2A_RX_WAIT_WRITE 0x80
uint16_t AFHDS2A_Rx_callback()
uint16_t AFHDS2A_RX_callback()
{
static uint32_t pps_timer = 0;
static uint16_t pps_counter = 0;
static int8_t read_retry;
int16_t temp;
uint8_t i;
@@ -106,22 +104,33 @@ uint16_t AFHDS2A_Rx_callback()
switch(phase) {
case AFHDS2A_RX_BIND1:
if (AFHDS2A_Rx_data_ready()) {
if(IS_BIND_DONE)
{
AFHDS2A_RX_init(); // Abort bind
break;
}
debugln("bind p=%d", phase+1);
if (AFHDS2A_RX_data_ready()) {
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
if ((packet[0] == 0xbb && packet[9] == 0x01) || (packet[0] == 0xbc && packet[9] <= 0x02)) {
memcpy(rx_id, &packet[1], 4); // TX id actually
memcpy(hopping_frequency, &packet[11], AFHDS2A_RX_NUMFREQ);
phase = AFHDS2A_RX_BIND2;
debugln("phase bind2");
}
}
A7105_WriteReg(A7105_0F_PLL_I, (packet_count++ & 1) ? 0x0D : 0x8C); // bind channels
A7105_SetTxRxMode(RX_EN);
A7105_Strobe(A7105_RX);
return 10000;
case AFHDS2A_RX_BIND2:
if(IS_BIND_DONE)
{
AFHDS2A_RX_init(); // Abort bind
break;
}
// got 2nd bind packet from tx ?
if (AFHDS2A_Rx_data_ready()) {
if (AFHDS2A_RX_data_ready()) {
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
if ((packet[0] == 0xBC && packet[9] == 0x02 && packet[10] == 0x00) &&
(memcmp(rx_id, &packet[1], 4) == 0) &&
@@ -132,42 +141,68 @@ uint16_t AFHDS2A_Rx_callback()
eeprom_write_byte((EE_ADDR)temp++, rx_id[i]);
for (i = 0; i < AFHDS2A_RX_NUMFREQ; i++)
eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[i]);
BIND_DONE;
phase = AFHDS2A_RX_DATA;
return 3850;
phase = AFHDS2A_RX_BIND3;
debugln("phase bind3");
packet_count = 0;
}
}
case AFHDS2A_RX_BIND3:
debugln("bind p=%d", phase+1);
// transmit response packet
packet[0] = 0xBC;
memcpy(&packet[1], rx_id, 4);
memcpy(&packet[5], rx_tx_addr, 4);
packet[9] = 0x01;
//packet[9] = 0x01;
packet[10] = 0x00;
memset(&packet[11], 0xFF, 26);
A7105_SetTxRxMode(TX_EN);
rx_disable_lna = !IS_POWER_FLAG_on;
A7105_WriteData(AFHDS2A_RX_RXPACKET_SIZE, packet_count++ & 1 ? 0x0D : 0x8C);
if(phase == AFHDS2A_RX_BIND3 && packet_count > 20)
{
debugln("done");
BIND_DONE;
AFHDS2A_RX_init(); // Restart protocol
break;
}
phase |= AFHDS2A_RX_WAIT_WRITE;
return 1700;
case AFHDS2A_RX_BIND2 | AFHDS2A_RX_WAIT_WRITE:
//Wait for TX completion
pps_timer = micros();
while (micros() - pps_timer < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
while ((uint32_t)(micros() - pps_timer) < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
if (!(A7105_ReadReg(A7105_00_MODE) & 0x01))
break;
A7105_Strobe(A7105_RX);
case AFHDS2A_RX_BIND3 | AFHDS2A_RX_WAIT_WRITE:
phase &= ~AFHDS2A_RX_WAIT_WRITE;
return 10000;
case AFHDS2A_RX_DATA:
if (AFHDS2A_Rx_data_ready()) {
if (AFHDS2A_RX_data_ready()) {
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
if (memcmp(&packet[1], rx_id, 4) == 0 && memcmp(&packet[5], rx_tx_addr, 4) == 0) {
if (packet[0] == 0x58 && packet[37] == 0x00 && telemetry_link == 0) { // standard packet, send channels to TX
if (memcmp(&packet[1], rx_id, 4) == 0 && memcmp(&packet[5], rx_tx_addr, 4) == 0)
{
#if 0
//if(packet[0] == 0xAA)
{
for(uint8_t i=0;i<AFHDS2A_RX_TXPACKET_SIZE;i++)
debug(" %02X",packet[i]);
debugln("");
}
#endif
if (packet[0] == 0x58 && packet[37] == 0x00 && (telemetry_link&0x7F) == 0)
{ // standard packet, send channels to TX
int rssi = min(A7105_ReadReg(A7105_1D_RSSI_THOLD),160);
RX_RSSI = map16b(rssi, 160, 8, 0, 128);
AFHDS2A_Rx_build_telemetry_packet();
AFHDS2A_RX_build_telemetry_packet();
telemetry_link = 1;
#ifdef SEND_CPPM
if(sub_protocol>0)
telemetry_link |= 0x80; // Disable telemetry output
#endif
}
rx_data_started = true;
read_retry = 10; // hop to next channel

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;
@@ -91,15 +93,19 @@ static void AFHDS2A_update_telemetry()
if (option & 0x80)
{// forward 0xAA and 0xAC telemetry to TX, skip rx and tx id to save space
packet_in[0]= TX_RSSI;
debug("T(%02X)=",packet[0]);
//Fix for CROSSOVER-RX,
if(packet[17+8]==0xFF && packet[21+8]==0xFC && packet[25+8]==0xFF)
packet[17+8]=0xFE; // RX_ERR_RATE needed for TX to validate the telem
#if 0
debug("T(%02X)=",packet[0]);
for(uint8_t i=9;i < AFHDS2A_RXPACKET_SIZE; i++)
debug(" %02X",packet[i]);
debugln("");
#endif
for(uint8_t i=9;i < AFHDS2A_RXPACKET_SIZE; i++)
{
packet_in[i-8]=packet[i];
debug(" %02X",packet[i]);
}
packet_in[29]=packet[0]; // 0xAA Normal telemetry, 0xAC Extended telemetry
telemetry_link=2;
debugln("");
return;
}
#endif
@@ -183,37 +189,52 @@ 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<17; ch++)
{
uint16_t channelMicros = convert_channel_ppm(CH_AETR[ch]);
packet[9 + ch*2] = channelMicros&0xFF;
packet[10 + ch*2] = (channelMicros>>8)&0xFF;
val = convert_channel_ppm(sub_protocol<AFHDS2A_GYRO_OFF?CH_AETR[ch]:ch); // No remapping for BS receivers
if(ch<14)
{
packet[9 + ch*2] = val;
packet[10 + ch*2] = (val>>8)&0x0F;
}
else
{
if(ch == 16) //CH17=RX_LQI
val = 2000 - 10*RX_LQI;
packet[10 + (ch-14)*6] |= (val)<<4;
packet[12 + (ch-14)*6] |= (val)&0xF0;
packet[14 + (ch-14)*6] |= (val>>4)&0xF0;
}
}
{
uint8_t next_hop = (hopping_frequency_no+1)&0x0F;
packet[34] |= next_hop<<4;
packet[36] |= next_hop?0x80:0x90;
}
#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<16; ch++)
{ // Failsafe values
#ifdef FAILSAFE_ENABLE
uint16_t failsafeMicros = Failsafe_data[CH_AETR[ch]];
if( failsafeMicros!=FAILSAFE_CHANNEL_HOLD && failsafeMicros!=FAILSAFE_CHANNEL_NOPULSES)
{ // Failsafe values
failsafeMicros = (((failsafeMicros<<2)+failsafeMicros)>>3)+860;
packet[9 + ch*2] = failsafeMicros & 0xff;
packet[10+ ch*2] = ( failsafeMicros >> 8) & 0xff;
}
val = Failsafe_data[protocol==PROTO_AFHDS2A?CH_AETR[ch]:ch]; // No remapping for BS receivers
if(val!=FAILSAFE_CHANNEL_HOLD && val!=FAILSAFE_CHANNEL_NOPULSES)
val = (((val<<2)+val)>>3)+860;
else
#endif
{ // no values
packet[9 + ch*2] = 0xff;
packet[10+ ch*2] = 0xff;
}
val = 0x0FFF;
if(ch<14)
{
packet[9 + ch*2] = val;
packet[10 + ch*2] = (val>>8)&0x0F;
}
else
{
packet[10 + (ch-14)*6] |= (val)<<4;
packet[12 + (ch-14)*6] |= (val)&0xF0;
packet[14 + (ch-14)*6] |= (val>>4)&0xF0;
}
}
break;
case AFHDS2A_PACKET_SETTINGS:
@@ -224,32 +245,65 @@ 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
memset(&packet[15],0xFF,22);
#ifndef MULTI_AIR
if(sub_protocol < AFHDS2A_GYRO_OFF)
{
#endif
packet[13] = sub_protocol & 0x01; // 1 -> PPM output enabled
packet[14] = 0x00; // ?
packet[18] = 0x05; // ?
packet[19] = 0xdc; // ?
packet[20] = 0x05; // ?
if(sub_protocol&2)
packet[21] = 0xdd; // SBUS output enabled
else
packet[21] = 0xde; // IBUS
#ifndef MULTI_AIR
}
else
packet[13] = 0x00;
packet[14]= 0x00;
for(uint8_t i=15; i<37; i++)
packet[i] = 0xff;
packet[18] = 0x05; // ?
packet[19] = 0xdc; // ?
packet[20] = 0x05; // ?
if(sub_protocol == PWM_SBUS || sub_protocol == PPM_SBUS)
packet[21] = 0xdd; // SBUS output enabled
else
packet[21] = 0xde; // IBUS
{//BS receivers
if(sub_protocol == AFHDS2A_GYRO_OFF)
{
memset(&packet[15],0x00,4);
packet[22] = 0xFC; // ?
}
else
{//AFHDS2A_GYRO_ON & AFHDS2A_GYRO_ON_REV
packet[15] = convert_channel_16b_limit(CH13,0,100); // ST Gain
packet[16] = convert_channel_16b_limit(CH14,0,100); // TH Gain
packet[17] = convert_channel_16b_limit(CH15,0,100); // Priority
if(sub_protocol == AFHDS2A_GYRO_ON_REV)
packet[17] |= 0x80; // Reverse
packet[18] = CH16_SW?(0x32|0x80):0x32; // Calib|50?
packet[19] = 0x64; // 100?
packet[20] = 0x64; // 100?
packet[22] = 0xFE; // ?
}
}
#endif
break;
}
packet[37] = 0x00;
}
#define AFHDS2A_WAIT_WRITE 0x80
uint16_t ReadAFHDS2A()
#ifdef STM32_BOARD
#define AFHDS2A_WRITE_TIME 1550
#else
#define AFHDS2A_WRITE_TIME 1700
#endif
uint16_t AFHDS2A_callback()
{
static uint8_t packet_type;
static uint16_t packet_counter;
uint8_t data_rx;
uint8_t data_rx=0;
uint16_t start;
#ifndef MULTI_AIR
static uint16_t Prev_Channel[4] = { 0,0,0,0 };
#endif
#ifndef FORCE_AFHDS2A_TUNING
A7105_AdjustLOBaseFreq(1);
#endif
@@ -259,13 +313,20 @@ uint16_t ReadAFHDS2A()
case AFHDS2A_BIND2:
case AFHDS2A_BIND3:
AFHDS2A_build_bind_packet();
data_rx=A7105_ReadReg(A7105_00_MODE); // Check if something has been received...
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, packet_count%2 ? 0x0d : 0x8c);
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5 | 1<<6)))
{ // FECF+CRCF Ok
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5)) && !(data_rx & 1)) // removed FECF check due to issues with fs-x6b -> & (1<<5 | 1<<6)
{ // RX+CRCF Ok
A7105_ReadData(AFHDS2A_RXPACKET_SIZE);
#if 0
debug("RX");
for(uint8_t i=0; i<AFHDS2A_RXPACKET_SIZE ; i++)
debug(" %02X", packet[i]);
debugln("");
#endif
if(packet[0] == 0xbc && packet[9] == 0x01)
{
uint8_t addr;
uint16_t addr;
if(RX_num<16)
addr=AFHDS2A_EEPROM_OFFSET+RX_num*4;
else
@@ -277,33 +338,33 @@ uint16_t ReadAFHDS2A()
}
phase = AFHDS2A_BIND4;
packet_count++;
return 3850;
break;
}
}
packet_count++;
if(IS_BIND_DONE)
{ // exit bind if asked to do so from the GUI
phase = AFHDS2A_BIND4;
return 3850;
break;
}
phase |= AFHDS2A_WAIT_WRITE;
return 1700;
return AFHDS2A_WRITE_TIME;
case AFHDS2A_BIND1|AFHDS2A_WAIT_WRITE:
case AFHDS2A_BIND2|AFHDS2A_WAIT_WRITE:
case AFHDS2A_BIND3|AFHDS2A_WAIT_WRITE:
//Wait for TX completion
start=micros();
while ((uint16_t)micros()-start < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
while ((uint16_t)((uint16_t)micros()-start) < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
break;
A7105_SetPower();
A7105_SetTxRxMode(TXRX_OFF); // Turn LNA off since we are in near range and we want to prevent swamping
A7105_SetTxRxMode((packet_count & 0x40) ? TXRX_OFF : RX_EN); // Turn LNA off time to time since we are in near range and we want to prevent swamping
A7105_Strobe(A7105_RX);
phase &= ~AFHDS2A_WAIT_WRITE;
phase++;
if(phase > AFHDS2A_BIND3)
phase = AFHDS2A_BIND1;
return 2150;
return 3850-AFHDS2A_WRITE_TIME;
case AFHDS2A_BIND4:
AFHDS2A_build_bind_packet();
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, packet_count%2 ? 0x0d : 0x8c);
@@ -315,7 +376,7 @@ uint16_t ReadAFHDS2A()
phase = AFHDS2A_DATA_INIT;
BIND_DONE;
}
return 3850;
break;
case AFHDS2A_DATA_INIT:
packet_counter=0;
packet_type = AFHDS2A_PACKET_STICKS;
@@ -325,15 +386,41 @@ uint16_t ReadAFHDS2A()
telemetry_set_input_sync(3850);
#endif
AFHDS2A_build_packet(packet_type);
if((A7105_ReadReg(A7105_00_MODE) & 0x01)) // Check if something has been received...
data_rx=0;
else
data_rx=1; // Yes
data_rx=A7105_ReadReg(A7105_00_MODE); // Check if something has been received...
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, hopping_frequency[hopping_frequency_no++]);
if(hopping_frequency_no >= AFHDS2A_NUMFREQ)
hopping_frequency_no = 0;
hopping_frequency_no &= 0x0F; // AFHDS2A_NUMFREQ
#if 0
for(uint8_t i=0; i<AFHDS2A_TXPACKET_SIZE; i++)
debug(" %02X",packet[i]);
debugln("");
#endif
#ifndef MULTI_AIR
if(sub_protocol > AFHDS2A_GYRO_OFF)
{//Gyro is on
//Check if gyro settings have changed
uint16_t val;
for(uint8_t i=0;i<4;i++)
{
val = Channel_data[CH13+i] - Prev_Channel[i];
if(val&0x8000) val ^= 0xFFFF;
if(val > 10)
{//This setting has significantly changed
Prev_Channel[i] = Channel_data[CH13+i];
packet_sent = 5;
}
}
}
if(packet_sent && (packet_counter%5)==0)
{//Inform the RX of the change
packet_type = AFHDS2A_PACKET_SETTINGS;
packet_sent--;
}
else
#endif
if(!(packet_counter % 1313))
{//Send settings every 5s
packet_type = AFHDS2A_PACKET_SETTINGS;
}
else
{
#ifdef FAILSAFE_ENABLE
@@ -344,32 +431,27 @@ uint16_t ReadAFHDS2A()
}
else
#endif
packet_type = AFHDS2A_PACKET_STICKS; // todo : check for settings changes
packet_type = AFHDS2A_PACKET_STICKS; // todo : check for settings changes
}
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5 | 1<<6)) && data_rx==1)
{ // RX+FECF+CRCF Ok
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5)) && !(data_rx & 1)) // removed FECF check due to issues with fs-x6b -> & (1<<5 | 1<<6)
{ // RX+CRCF Ok
A7105_ReadData(AFHDS2A_RXPACKET_SIZE);
if(packet[0] == 0xAA && packet[9] == 0xFC)
packet_type=AFHDS2A_PACKET_SETTINGS; // RX is asking for settings
packet_type=AFHDS2A_PACKET_SETTINGS; // RX is asking for settings
else
if(packet[0] == 0xAA || packet[0] == 0xAC)
{
if((packet[0] == 0xAA && packet[9]!=0xFD) || packet[0] == 0xAC)
{// Normal telemetry packet, ignore packets which contain the RX configuration: AA FD FF 32 00 01 00 FF FF FF 05 DC 05 DE FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF
if(!memcmp(&packet[1], rx_tx_addr, 4))
{ // TX address validated
#ifdef AFHDS2A_LQI_CH
if(packet[0]==0xAA && packet[9]!=0xFD)
{// Normal telemetry packet
for(uint8_t sensor=0; sensor<7; sensor++)
{//read LQI value for RX output
uint8_t index = 9+(4*sensor);
if(packet[index]==AFHDS2A_SENSOR_RX_ERR_RATE && packet[index+2]<=100)
{
RX_LQI=packet[index+2];
break;
}
}
for(uint8_t sensor=0; sensor<7; sensor++)
{//read LQI value for RX output
uint8_t index = 9+(4*sensor);
if(packet[index]==AFHDS2A_SENSOR_RX_ERR_RATE && packet[index+2]<=100)
{
RX_LQI=packet[index+2];
break;
}
#endif
}
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
AFHDS2A_update_telemetry();
#endif
@@ -378,23 +460,23 @@ uint16_t ReadAFHDS2A()
}
packet_counter++;
phase |= AFHDS2A_WAIT_WRITE;
return 1700;
return AFHDS2A_WRITE_TIME;
case AFHDS2A_DATA|AFHDS2A_WAIT_WRITE:
//Wait for TX completion
start=micros();
while ((uint16_t)micros()-start < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
while ((uint16_t)((uint16_t)micros()-start) < 700) // Wait max 700µs, using serial+telemetry exit in about 120µs
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
break;
A7105_SetPower();
A7105_SetTxRxMode(RX_EN);
A7105_Strobe(A7105_RX);
phase &= ~AFHDS2A_WAIT_WRITE;
return 2150;
return 3850-AFHDS2A_WRITE_TIME;
}
return 3850; // never reached, please the compiler
return 3850;
}
uint16_t initAFHDS2A()
void AFHDS2A_init()
{
A7105_Init();
@@ -407,7 +489,7 @@ uint16_t initAFHDS2A()
{
phase = AFHDS2A_DATA_INIT;
//Read RX ID from EEPROM based on RX_num, RX_num must be uniq for each RX
uint8_t addr;
uint16_t addr;
if(RX_num<16)
addr=AFHDS2A_EEPROM_OFFSET+RX_num*4;
else
@@ -416,6 +498,6 @@ uint16_t initAFHDS2A()
rx_id[i]=eeprom_read_byte((EE_ADDR)(addr+i));
}
hopping_frequency_no = 0;
return 50000;
packet_sent = 0;
}
#endif

View File

@@ -33,19 +33,14 @@ enum {
ASSAN_DATA5
};
void ASSAN_init()
void ASSAN_RF_init()
{
NRF24L01_Initialize();
//Specifics to ASSAN
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x02); // 4 bytes rx/tx address
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x80\x80\x80\xB8", ASSAN_ADDRESS_LENGTH); // Bind address
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x80\x80\x80\xB8", ASSAN_ADDRESS_LENGTH); // Bind address
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x80\x80\x80\xB8", ASSAN_ADDRESS_LENGTH); // Bind address
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, ASSAN_PACKET_SIZE);
NRF24L01_SetPower();
}
void ASSAN_send_packet()
@@ -169,17 +164,16 @@ static void __attribute__((unused)) ASSAN_initialize_txid()
hopping_frequency[1]=freq2;
}
uint16_t initASSAN()
void ASSAN_init()
{
ASSAN_initialize_txid();
ASSAN_init();
ASSAN_RF_init();
hopping_frequency_no = 0;
if(IS_BIND_IN_PROGRESS)
phase=ASSAN_BIND0;
else
phase=ASSAN_DATA0;
return 1000;
}
#endif

View File

@@ -115,7 +115,7 @@ void delayMilliseconds(unsigned long ms)
uint16_t lms = ms ;
while (lms > 0) {
if (((uint16_t)micros() - start) >= 1000) {
if ((uint16_t)((uint16_t)micros() - start) >= 1000) {
lms--;
start += 1000;
}

View File

@@ -0,0 +1,254 @@
/*
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 ARES 6HPA transmitter
#if defined(ARES_CC2500_INO)
#include "iface_cc2500.h"
//#define ARES_FORCE_ID
#define ARES_COARSE 0
#define ARES_PACKET_LEN 17
#define ARES_NUM_FREQUENCIES 60
enum {
ARES_START = 0x00,
ARES_CALIB = 0x01,
ARES_PREP = 0x02,
ARES_DATA = 0x03,
};
// CC2500 register init values captured from the ARES 6HPA transmitter
const PROGMEM uint8_t ARES_init_values[] = {
/* 00 */ 0x06, 0x2E, 0x2E, 0x07, 0x5A, 0x60, 0x30, 0x04,
/* 08 */ 0x05, 0x00, 0x00, 0x06, 0x00, 0x5C, 0xB1, 0x3B + ARES_COARSE,
/* 10 */ 0x6A, 0xF8, 0x03, 0x23, 0x7A, 0x44, 0x07, 0x30,
/* 18 */ 0x18, 0x16, 0x6C, 0x43, 0x40, 0x91, 0x87, 0x6B,
/* 20 */ 0xF8, 0x56, 0x10, 0xA9, 0x0A, 0x00, 0x11
};
// Fixed hopping sequence captured from the ARES 6HPA transmitter.
// This is a permutation of 60 channel values spread across the band.
static const PROGMEM uint8_t ARES_hop[] = {
0xB0, 0x6F, 0x1D, 0xB4, 0x74, 0x20, 0xB8, 0xD8,
0x24, 0xBC, 0xDC, 0x28, 0x48, 0xE0, 0x2C, 0x4C,
0xE4, 0x90, 0x50, 0xE8, 0x94, 0x54, 0xEC, 0x00,
0x98, 0x58, 0x04, 0x9B, 0x5C, 0x08, 0xA0, 0xC0,
0x0C, 0xA4, 0xC3, 0x10, 0x30, 0xC6, 0x14, 0x34,
0xCC, 0x78, 0x38, 0xD0, 0x7C, 0x3C, 0xD4, 0x80,
0x40, 0x60, 0x84, 0x44, 0x64, 0x88, 0xA8, 0x68,
0x8C, 0xAC, 0x6C, 0x18
};
static void __attribute__((unused)) ARES_CC2500_init()
{
CC2500_Strobe(CC2500_SRES);
delayMilliseconds(1);
CC2500_Strobe(CC2500_SIDLE);
for (uint8_t i = 0; i < 39; ++i)
CC2500_WriteReg(i, pgm_read_byte_near(&ARES_init_values[i]));
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
prev_option = option;
// Write PATABLE to max power (0xFF for all 8 entries) as captured
for (uint8_t i = 0; i < 8; i++)
CC2500_WriteReg(CC2500_3E_PATABLE, 0xFF);
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
}
// Load hopping table
static void __attribute__((unused)) ARES_RF_channels()
{
for (uint8_t i = 0; i < ARES_NUM_FREQUENCIES; i++)
hopping_frequency[i] = pgm_read_byte_near(&ARES_hop[i]);
}
static void __attribute__((unused)) ARES_tune_chan()
{
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[hopping_frequency_no]);
CC2500_Strobe(CC2500_SFTX);
CC2500_Strobe(CC2500_SCAL);
}
static void __attribute__((unused)) ARES_change_chan_fast()
{
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[hopping_frequency_no]);
CC2500_WriteReg(CC2500_25_FSCAL1, calData[hopping_frequency_no]);
}
// Advance the hop counter: cycles through 0-58 with step, inserting 59 when wrapping through 0
static uint8_t __attribute__((unused)) ARES_next_counter(uint8_t current, uint8_t step)
{
if (current == 59)
return 0;
uint8_t next = (current + step) % 59;
if (next == 0)
return 59;
return next;
}
static void __attribute__((unused)) ARES_build_packet()
{
// Length byte: 16 data bytes follow
packet[0] = 0x10;
// TX ID
packet[1] = rx_tx_addr[1];
packet[2] = rx_tx_addr[2];
packet[3] = rx_tx_addr[3];
// 6 channels encoded as interleaved 12-bit values in bytes 4-12
uint16_t ch[6];
for (uint8_t i = 0; i < 6; i++)
ch[i] = convert_channel_16b_nolimit(i, 1820, 3300, false);
packet[4] = ch[0] >> 4;
packet[5] = ((ch[0] & 0x0F) << 4) | (ch[1] & 0x0F);
packet[6] = ch[1] >> 4;
packet[7] = ch[2] >> 4;
packet[8] = ((ch[2] & 0x0F) << 4) | (ch[3] & 0x0F);
packet[9] = ch[3] >> 4;
packet[10] = ch[4] >> 4;
packet[11] = ((ch[4] & 0x0F) << 4) | (ch[5] & 0x0F);
packet[12] = ch[5] >> 4;
// Byte 16: counter step size (stored in crc, set to 1-58 in ARES_init)
uint8_t step = crc;
// Bytes 13-15: running counter with rotating bit 7 frame indicator
// The counter cycles 0-58 with a step, inserting 59 before wrapping to 0
// Each group of 3 packets has 3 consecutive counter values
// packet_count holds the current counter value
uint8_t c0 = packet_count;
uint8_t c1 = ARES_next_counter(c0, step);
uint8_t c2 = ARES_next_counter(c1, step);
// Frame indicator: each data frame is sent 3 times
// bind_phase tracks position 0/1/2 within the group of 3
packet[13] = c0;
packet[14] = c1;
packet[15] = c2;
packet[16] = step;
// Set the rotating frame bit (bit 7) on one of bytes 13-15
switch (bind_phase)
{
case 0:
packet[13] |= 0x80;
break;
case 1:
packet[14] |= 0x80;
break;
case 2:
packet[15] |= 0x80;
break;
}
}
static void __attribute__((unused)) ARES_send_packet()
{
ARES_change_chan_fast();
CC2500_SetPower();
CC2500_WriteData(packet, ARES_PACKET_LEN);
}
#define ARES_PACKET_PERIOD 6670 // 6.67ms between packets
#define ARES_PREP_TIMING 2000
uint16_t ARES_callback()
{
switch(phase)
{
case ARES_START:
ARES_CC2500_init();
hopping_frequency_no = 0;
bind_phase = 0;
ARES_tune_chan();
phase = ARES_CALIB;
return ARES_PREP_TIMING;
case ARES_CALIB:
calData[hopping_frequency_no] = CC2500_ReadReg(CC2500_25_FSCAL1);
hopping_frequency_no++;
if (hopping_frequency_no < ARES_NUM_FREQUENCIES)
ARES_tune_chan();
else
{
hopping_frequency_no = 0;
phase = ARES_PREP;
}
return ARES_PREP_TIMING;
case ARES_PREP:
if (prev_option != option)
{
phase = ARES_START;
return ARES_PREP_TIMING;
}
#ifdef MULTI_SYNC
telemetry_set_input_sync(ARES_PACKET_PERIOD);
#endif
ARES_build_packet();
phase = ARES_DATA;
// Fall through
case ARES_DATA:
ARES_send_packet();
hopping_frequency_no++;
if (hopping_frequency_no >= ARES_NUM_FREQUENCIES)
hopping_frequency_no = 0;
bind_phase++;
if (bind_phase >= 3)
{
bind_phase = 0;
// Advance counter to start of next group
uint8_t step = crc;
packet_count = ARES_next_counter(packet_count, step);
packet_count = ARES_next_counter(packet_count, step);
packet_count = ARES_next_counter(packet_count, step);
}
phase = ARES_PREP;
return ARES_PACKET_PERIOD;
}
return 0;
}
void ARES_init()
{
BIND_DONE; // Autobind protocol - no TX-initiated bind phase
ARES_RF_channels();
// rx_tx_addr[1] and [2] are already set from MProtocol_id by the framework
// RX_num (0-63) in byte 3 provides model match
rx_tx_addr[3] = RX_num;
// Counter step and start from capture
crc = 23;
packet_count = 35;
#ifdef ARES_FORCE_ID
rx_tx_addr[1] = 0xDC;
rx_tx_addr[2] = 0xCC;
rx_tx_addr[3] = 0x00;
#endif
phase = ARES_START;
}
#endif

View File

@@ -16,7 +16,7 @@
#if defined(BUGSMINI_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_xn297.h"
#define BUGSMINI_INITIAL_WAIT 500
#define BUGSMINI_PACKET_INTERVAL 6840
@@ -57,22 +57,10 @@ enum {
#define BUGSMINI_FLAG_ANGLE 0x02 // angle/acro mode (set is angle mode)
#define BUGSMINI_FLAG_ALTHOLD 0x04 // angle/altitude hold mode (set is altitude mode)
static void __attribute__((unused)) BUGSMINI_init()
static void __attribute__((unused)) BUGSMINI_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, BUGSMINI_RX_PAYLOAD_SIZE); // bytes of data payload for rx pipe 1
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x07);
NRF24L01_SetBitrate(NRF24L01_BR_1M);
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00); // Set feature bits on
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
//XN297_HoppingCalib(BUGSMINI_NUM_RF_CHANNELS*2);
}
static void __attribute__((unused)) BUGSMINI_check_arming()
@@ -95,7 +83,7 @@ static void __attribute__((unused)) BUGSMINI_check_arming()
}
}
static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind)
static void __attribute__((unused)) BUGSMINI_send_packet()
{
BUGSMINI_check_arming(); // sets globals arm_flags and armed
@@ -107,7 +95,7 @@ static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind)
packet[1] = BUGSMINI_txid[0];
packet[2] = BUGSMINI_txid[1];
packet[3] = BUGSMINI_txid[2];
if(bind)
if(IS_BIND_IN_PROGRESS)
{
packet[4] = 0x00;
packet[5] = 0x7d;
@@ -159,15 +147,14 @@ static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind)
hopping_frequency_no++;
if(hopping_frequency_no >= BUGSMINI_NUM_RF_CHANNELS)
hopping_frequency_no = 0;
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? hopping_frequency[hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS] : hopping_frequency[hopping_frequency_no]);
XN297_Hopping(IS_BIND_IN_PROGRESS ? hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS : hopping_frequency_no);
}
// Power on, TX mode, 2byte CRC
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
// Send
XN297_SetPower();
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, BUGSMINI_TX_PAYLOAD_SIZE);
NRF24L01_SetPower();
}
// compute final address for the rxid received during bind
@@ -231,37 +218,37 @@ static void __attribute__((unused)) BUGSMINI_make_address()
// Something wrong happened if we arrive here....
}
#if defined(BUGS_HUB_TELEMETRY)
static void __attribute__((unused)) BUGSMINI_update_telemetry()
{
#if defined(BUGS_HUB_TELEMETRY)
uint8_t checksum = 0x6d;
for(uint8_t i=1; i<12; i++)
checksum += packet[i];
if(packet[0] == checksum)
checksum += packet_in[i];
if(packet_in[0] == checksum)
{
RX_RSSI = packet[3];
RX_RSSI = packet_in[3];
if(sub_protocol==BUGS3H)
{
if(packet[11] & 0x40)
if(packet_in[11] & 0x40)
v_lipo1 = 0x40; // Warning
else if(packet[11] & 0x80)
else if(packet_in[11] & 0x80)
v_lipo1 = 0x20; // Critical
else
v_lipo1 = 0x80; // Ok
}
else
{
if(packet[11] & 0x80)
if(packet_in[11] & 0x80)
v_lipo1 = 0x80; // Ok
else if(packet[11] & 0x40)
else if(packet_in[11] & 0x40)
v_lipo1 = 0x40; // Warning
else
v_lipo1 = 0x20; // Critical
}
telemetry_link=1;
}
#endif
}
#endif
uint16_t BUGSMINI_callback()
{
@@ -269,58 +256,52 @@ uint16_t BUGSMINI_callback()
switch(phase)
{
case BUGSMINI_BIND1:
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
if( XN297_IsRX() )
{ // RX fifo data ready
XN297_ReadPayload(packet, BUGSMINI_RX_PAYLOAD_SIZE);
XN297_ReadPayload(packet, BUGSMINI_RX_PAYLOAD_SIZE); // Not checking the CRC??
base_adr=BUGSMINI_EEPROM_OFFSET+(RX_num&0x0F)*2;
eeprom_write_byte((EE_ADDR)(base_adr+0),packet[1]); // Save rxid in EEPROM
eeprom_write_byte((EE_ADDR)(base_adr+1),packet[2]); // Save rxid in EEPROM
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
eeprom_write_byte((EE_ADDR)(base_adr+0),packet[1]); // Save rxid in EEPROM
eeprom_write_byte((EE_ADDR)(base_adr+1),packet[2]); // Save rxid in EEPROM
BUGSMINI_make_address();
XN297_SetTXAddr(rx_tx_addr, 5);
XN297_SetRXAddr(rx_tx_addr, 5);
XN297_SetRXAddr(rx_tx_addr, BUGSMINI_RX_PAYLOAD_SIZE);
phase = BUGSMINI_DATA1;
BIND_DONE;
return BUGSMINI_PACKET_INTERVAL;
break;
}
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
BUGSMINI_send_packet(1);
BUGSMINI_send_packet();
phase = BUGSMINI_BIND2;
return BUGSMINI_WRITE_WAIT;
case BUGSMINI_BIND2:
// switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)
| _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
phase = BUGSMINI_BIND1;
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
case BUGSMINI_DATA1:
#ifdef MULTI_SYNC
telemetry_set_input_sync(BUGSMINI_PACKET_INTERVAL);
#endif
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready => read only 12 bytes to not overwrite channel change flag
XN297_ReadPayload(packet, 12);
BUGSMINI_update_telemetry();
}
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
BUGSMINI_send_packet(0);
#if defined(BUGS_HUB_TELEMETRY)
if( XN297_IsRX() )
{
XN297_ReadPayload(packet_in, BUGSMINI_RX_PAYLOAD_SIZE); // Not checking the CRC??
BUGSMINI_update_telemetry();
}
#endif
BUGSMINI_send_packet();
#if not defined(BUGS_HUB_TELEMETRY)
break;
#else
phase = BUGSMINI_DATA2;
return BUGSMINI_WRITE_WAIT;
case BUGSMINI_DATA2:
// switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushRx();
NRF24L01_SetTxRxMode(RX_EN);
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)
| _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
phase = BUGSMINI_DATA1;
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
#endif
}
return BUGSMINI_PACKET_INTERVAL;
}
@@ -357,28 +338,27 @@ static void __attribute__((unused)) BUGSMINI_initialize_txid()
BUGSMINI_txhash = pgm_read_byte_near( &BUGSMINI_tx_hash[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS] );
}
uint16_t initBUGSMINI()
void BUGSMINI_init()
{
BUGSMINI_initialize_txid();
BUGSMINI_RF_init();
memset(packet, (uint8_t)0, BUGSMINI_TX_PAYLOAD_SIZE);
BUGSMINI_init();
if(IS_BIND_IN_PROGRESS)
{
XN297_SetTXAddr((const uint8_t*)"mjxRC", 5);
XN297_SetRXAddr((const uint8_t*)"mjxRC", 5);
XN297_SetRXAddr((const uint8_t*)"mjxRC", BUGSMINI_RX_PAYLOAD_SIZE);
phase = BUGSMINI_BIND1;
}
else
{
BUGSMINI_make_address();
XN297_SetTXAddr(rx_tx_addr, 5);
XN297_SetRXAddr(rx_tx_addr, 5);
XN297_SetRXAddr(rx_tx_addr, BUGSMINI_RX_PAYLOAD_SIZE);
phase = BUGSMINI_DATA1;
}
armed = 0;
arm_flags = BUGSMINI_FLAG_DISARM; // initial value from captures
arm_channel_previous = BUGSMINI_CH_SW_ARM;
return BUGSMINI_INITIAL_WAIT;
}
#endif

View File

@@ -0,0 +1,196 @@
/*
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(BUMBLEB_CCNRF_INO)
#include "iface_xn297.h"
#define FORCE_BUMBLEB_ORIGINAL_ID
#define BUMBLEB_TELEM_DEBUG
#define BUMBLEB_PACKET_PERIOD 10200
#define BUMBLEB_RF_BIND_CHANNEL 42
#define BUMBLEB_RF_NUM_CHANNELS 2
#define BUMBLEB_PAYLOAD_SIZE 7
static void __attribute__((unused)) BUMBLEB_send_packet()
{
packet[6] = 0x00;
if(IS_BIND_IN_PROGRESS)
{
packet[0] = rx_tx_addr[0];
packet[1] = rx_tx_addr[1];
packet[2] = 0x54; //???
packet[3] = 0x58; //???
hopping_frequency_no ^= 0x01;
packet[4] = hopping_frequency[hopping_frequency_no];
}
else
{
//hopping frequency
XN297_Hopping(hopping_frequency_no);
hopping_frequency_no ^= 0x01;
packet[0] = 0x20
|GET_FLAG(CH6_SW,0x80); // High rate
packet[1] = convert_channel_8b_limit_deadband(AILERON,0xBF,0xA0,0x81,40); // Aileron: Max values:BD..A0..82
if(packet[1] < 0xA0)
packet[1] = 0x20 - packet[1]; // Reverse low part of aileron
packet[2] = convert_channel_8b(CH5)>>2; // 01..20..3F
if(CH7_SW) // Drive trim from aileron
{
uint8_t ch=convert_channel_8b(AILERON);
if(ch > 0x5A && ch < 0x80-0x07)
packet[2] = ch - 0x5A;
else if(ch < 0x5A)
{
if(ch < 0x5A-0x20)
packet[2] = 0;
else
packet[2] = ch - (0x5A-0x20);
}
else if(packet[1] == 0x89)
packet[2] = 0x20;
else if(ch > 0xA5)
{
if(ch > 0xA9+0x1F)
packet[2] = 0x3F;
else
packet[2] = ch - 0x89;
}
else if(ch > 0xA5-0x1F)
packet[2] = ch - (0xA5-0x1F-0x20);
}
else
packet[2] = convert_channel_8b(CH5)>>2; // 01..20..3F
packet[3] = convert_channel_8b(THROTTLE)>>2; // 00..3F
packet[4] = hopping_frequency[hopping_frequency_no];
}
packet[5] = packet[0];
for(uint8_t i=1;i<BUMBLEB_PAYLOAD_SIZE-2;i++)
packet[5] += packet[i];
#if 0
debug("P:");
for(uint8_t i=0;i<BUMBLEB_PAYLOAD_SIZE;i++)
debug(" %02X", packet[i]);
debugln("");
#endif
XN297_SetPower(); // Set tx_power
XN297_SetFreqOffset(); // Set frequency offset
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, BUMBLEB_PAYLOAD_SIZE);
}
static void __attribute__((unused)) BUMBLEB_RF_init()
{
//Config CC2500
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_250K);
XN297_SetTXAddr((uint8_t*)"\x55\x55\x55\x55\x55", 5);
XN297_HoppingCalib(BUMBLEB_RF_NUM_CHANNELS); // Calibrate all channels
XN297_RFChannel(BUMBLEB_RF_BIND_CHANNEL); // Set bind channel
XN297_SetRXAddr(rx_tx_addr, BUMBLEB_PAYLOAD_SIZE);
}
static void __attribute__((unused)) BUMBLEB_initialize_txid()
{
calc_fh_channels(BUMBLEB_RF_NUM_CHANNELS);
rx_tx_addr[0] = rx_tx_addr[2];
rx_tx_addr[1] = rx_tx_addr[3];
#ifdef FORCE_BUMBLEB_ORIGINAL_ID
rx_tx_addr[0] = 0x33;
rx_tx_addr[1] = 0x65;
hopping_frequency[0] = 2;
hopping_frequency[1] = 40;
#endif
rx_tx_addr[2] = rx_tx_addr[3] = rx_tx_addr[4] = 0x55;
}
enum {
BUMBLEB_BIND = 0x00,
BUMBLEB_BINDRX = 0x01,
BUMBLEB_DATA = 0x02,
};
#define BUMBLEB_WRITE_TIME 850
uint16_t BUMBLEB_callback()
{
bool rx;
switch(phase)
{
case BUMBLEB_BIND:
rx = XN297_IsRX(); // Needed for the NRF24L01 since otherwise the bit gets cleared
BUMBLEB_send_packet();
if( rx )
{ // a packet has been received
#ifdef BUMBLEB_TELEM_DEBUG
debug("RX :");
#endif
if(XN297_ReadPayload(packet_in, BUMBLEB_PAYLOAD_SIZE))
{ // packet with good CRC
#ifdef BUMBLEB_TELEM_DEBUG
debug("OK :");
for(uint8_t i=0;i<BUMBLEB_PAYLOAD_SIZE;i++)
debug(" %02X",packet_in[i]);
#endif
// packet_in = 4F 71 55 52 58 61 AA
rx_tx_addr[2] = packet_in[0];
rx_tx_addr[3] = packet_in[1];
//rx_tx_addr[4] = packet_in[2]; // to test with other planes...
XN297_SetTXAddr(rx_tx_addr, 5);
BIND_DONE;
phase = BUMBLEB_DATA;
break;
}
}
phase++;
return BUMBLEB_WRITE_TIME;
case BUMBLEB_BINDRX:
{
uint16_t start=(uint16_t)micros();
while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 500)
{
if(XN297_IsPacketSent())
break;
}
}
XN297_SetTxRxMode(RX_EN);
phase = BUMBLEB_BIND;
return BUMBLEB_PACKET_PERIOD-BUMBLEB_WRITE_TIME;
case BUMBLEB_DATA:
#ifdef MULTI_SYNC
telemetry_set_input_sync(BUMBLEB_PACKET_PERIOD);
#endif
BUMBLEB_send_packet();
break;
}
return BUMBLEB_PACKET_PERIOD;
}
void BUMBLEB_init()
{
BUMBLEB_initialize_txid();
BUMBLEB_RF_init();
hopping_frequency_no = 0;
BIND_IN_PROGRESS; // autobind protocol
phase = BUMBLEB_BIND;
}
#endif

View File

@@ -15,7 +15,7 @@ Multiprotocol is distributed in the hope that it will be useful,
#if defined(BAYANG_RX_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_xn297.h"
#define BAYANG_RX_PACKET_SIZE 15
#define BAYANG_RX_RF_NUM_CHANNELS 4
@@ -27,28 +27,15 @@ enum {
BAYANG_RX_DATA
};
static void __attribute__((unused)) Bayang_Rx_init_nrf24l01()
static void __attribute__((unused)) Bayang_Rx_RF_init()
{
const uint8_t bind_address[BAYANG_RX_ADDRESS_LENGTH] = { 0,0,0,0,0 };
NRF24L01_Initialize();
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr(bind_address, BAYANG_RX_ADDRESS_LENGTH);
XN297_SetRXAddr(bind_address, BAYANG_RX_ADDRESS_LENGTH);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, BAYANG_RX_PACKET_SIZE + 2); // 2 extra bytes for xn297 crc
NRF24L01_WriteReg(NRF24L01_05_RF_CH, BAYANG_RX_RF_BIND_CHANNEL);
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
NRF24L01_Activate(0x73);
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushRx();
NRF24L01_SetTxRxMode(RX_EN);
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
XN297_SetRXAddr(bind_address, BAYANG_RX_PACKET_SIZE);
XN297_RFChannel(BAYANG_RX_RF_BIND_CHANNEL);
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
}
static uint8_t __attribute__((unused)) Bayang_Rx_check_validity() {
@@ -98,10 +85,10 @@ static void __attribute__((unused)) Bayang_Rx_build_telemetry_packet()
}
}
uint16_t initBayang_Rx()
void BAYANG_RX_init()
{
uint8_t i;
Bayang_Rx_init_nrf24l01();
Bayang_Rx_RF_init();
hopping_frequency_no = 0;
rx_data_started = false;
rx_data_received = false;
@@ -115,91 +102,101 @@ uint16_t initBayang_Rx()
rx_tx_addr[i] = eeprom_read_byte((EE_ADDR)temp++);
for (i = 0; i < BAYANG_RX_RF_NUM_CHANNELS; i++)
hopping_frequency[i] = eeprom_read_byte((EE_ADDR)temp++);
//XN297_HoppingCalib(BAYANG_RX_RF_NUM_CHANNELS);
XN297_SetTXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
XN297_SetRXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
XN297_SetRXAddr(rx_tx_addr, BAYANG_RX_PACKET_SIZE);
phase = BAYANG_RX_DATA;
}
return 1000;
}
uint16_t Bayang_Rx_callback()
uint16_t BAYANG_RX_callback()
{
uint8_t i;
static int8_t read_retry;
static uint16_t pps_counter;
static uint32_t pps_timer = 0;
switch (phase) {
case BAYANG_RX_BIND:
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) {
// data received from TX
if (XN297_ReadPayload(packet, BAYANG_RX_PACKET_SIZE) && ( packet[0] == 0xA4 || packet[0] == 0xA2 ) && Bayang_Rx_check_validity()) {
// store tx info into eeprom
uint16_t temp = BAYANG_RX_EEPROM_OFFSET;
for (i = 0; i < 5; i++) {
rx_tx_addr[i] = packet[i + 1];
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[i]);
}
for (i = 0; i < 4; i++) {
hopping_frequency[i] = packet[i + 6];
eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[i]);
}
XN297_SetTXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
XN297_SetRXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
BIND_DONE;
phase = BAYANG_RX_DATA;
}
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
}
break;
case BAYANG_RX_DATA:
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) {
if (XN297_ReadPayload(packet, BAYANG_RX_PACKET_SIZE) && packet[0] == 0xA5 && Bayang_Rx_check_validity()) {
if (telemetry_link == 0) {
Bayang_Rx_build_telemetry_packet();
telemetry_link = 1;
}
rx_data_started = true;
rx_data_received = true;
read_retry = 8;
pps_counter++;
}
}
// packets per second
if (millis() - pps_timer >= 1000) {
pps_timer = millis();
debugln("%d pps", pps_counter);
RX_LQI = pps_counter >> 1;
pps_counter = 0;
}
// frequency hopping
if (read_retry++ >= 8) {
hopping_frequency_no++;
if (hopping_frequency_no >= BAYANG_RX_RF_NUM_CHANNELS)
hopping_frequency_no = 0;
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
if (rx_data_started)
switch (phase)
{
case BAYANG_RX_BIND:
if(IS_BIND_DONE)
{
if(rx_data_received)
{ // In sync
rx_data_received = false;
read_retry = 5;
return 1500;
BAYANG_RX_init(); // Abort bind
break;
}
if ( XN297_IsRX() )
{
debugln("RX");
// data received from TX
if (XN297_ReadPayload(packet, BAYANG_RX_PACKET_SIZE) && ( packet[0] == 0xA4 || packet[0] == 0xA2 ) && Bayang_Rx_check_validity())
{
// store tx info into eeprom
uint16_t temp = BAYANG_RX_EEPROM_OFFSET;
for (i = 0; i < 5; i++) {
rx_tx_addr[i] = packet[i + 1];
eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[i]);
}
for (i = 0; i < 4; i++) {
hopping_frequency[i] = packet[i + 6];
eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[i]);
}
//XN297_HoppingCalib(BAYANG_RX_RF_NUM_CHANNELS);
XN297_SetTXAddr(rx_tx_addr, BAYANG_RX_ADDRESS_LENGTH);
XN297_SetRXAddr(rx_tx_addr, BAYANG_RX_PACKET_SIZE);
BIND_DONE;
phase = BAYANG_RX_DATA;
}
XN297_SetTxRxMode(RX_EN);
}
break;
case BAYANG_RX_DATA:
if ( XN297_IsRX() ) {
if (XN297_ReadPayload(packet, BAYANG_RX_PACKET_SIZE) && packet[0] == 0xA5 && Bayang_Rx_check_validity()) {
if ((telemetry_link & 0x7F) == 0) {
Bayang_Rx_build_telemetry_packet();
telemetry_link = 1;
#ifdef SEND_CPPM
if(sub_protocol>0)
telemetry_link |= 0x80; // Disable telemetry output
#endif
}
rx_data_started = true;
rx_data_received = true;
read_retry = 8;
pps_counter++;
}
}
// packets per second
if (millis() - pps_timer >= 1000) {
pps_timer = millis();
debugln("%d pps", pps_counter);
RX_LQI = pps_counter >> 1;
pps_counter = 0;
}
// frequency hopping
if (read_retry++ >= 8) {
hopping_frequency_no++;
if (hopping_frequency_no >= BAYANG_RX_RF_NUM_CHANNELS)
hopping_frequency_no = 0;
XN297_Hopping(hopping_frequency_no);
XN297_SetTxRxMode(RX_EN);
if (rx_data_started)
{
if(rx_data_received)
{ // In sync
rx_data_received = false;
read_retry = 5;
return 1500;
}
else
{ // packet lost
read_retry = 0;
if(RX_LQI==0) // communication lost
rx_data_started=false;
}
}
else
{ // packet lost
read_retry = 0;
if(RX_LQI==0) // communication lost
rx_data_started=false;
}
read_retry = -16; // retry longer until first packet is caught
}
else
read_retry = -16; // retry longer until first packet is caught
}
return 250;
return 250;
}
return 1000;
}

View File

@@ -17,7 +17,7 @@ Multiprotocol is distributed in the hope that it will be useful,
#if defined(BAYANG_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_xn297.h"
#define BAYANG_BIND_COUNT 1000
#define BAYANG_PACKET_PERIOD 2000
@@ -67,12 +67,16 @@ static void __attribute__((unused)) BAYANG_send_packet()
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;
@@ -93,6 +97,8 @@ static void __attribute__((unused)) BAYANG_send_packet()
}
else
{
XN297_Hopping(hopping_frequency_no++);
hopping_frequency_no%=BAYANG_RF_NUM_CHANNELS;
uint16_t val;
uint8_t dyntrim = 1;
switch (sub_protocol)
@@ -139,19 +145,19 @@ static void __attribute__((unused)) BAYANG_send_packet()
if(CH13_SW)
packet[3] |= BAYANG_FLAG_EMG_STOP;
//Aileron
val = convert_channel_10b(AILERON);
val = convert_channel_10b(AILERON, false);
packet[4] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
packet[5] = val & 0xFF;
//Elevator
val = convert_channel_10b(ELEVATOR);
val = convert_channel_10b(ELEVATOR, false);
packet[6] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
packet[7] = val & 0xFF;
//Throttle
val = convert_channel_10b(THROTTLE);
val = convert_channel_10b(THROTTLE, false);
packet[8] = (val>>8) + 0x7C;
packet[9] = val & 0xFF;
//Rudder
val = convert_channel_10b(RUDDER);
val = convert_channel_10b(RUDDER, false);
packet[10] = (val>>8) + (dyntrim ? ((val>>2) & 0xFC) : 0x7C);
packet[11] = val & 0xFF;
}
@@ -161,6 +167,7 @@ static void __attribute__((unused)) BAYANG_send_packet()
packet[12] = rx_tx_addr[2]; // txid[2]
packet[13] = 0x34;
break;
case QX100:
case X16_AH:
packet[12] = 0;
packet[13] = 0;
@@ -187,84 +194,61 @@ static void __attribute__((unused)) BAYANG_send_packet()
for (uint8_t i=0; i < BAYANG_PACKET_SIZE-1; i++)
packet[14] += packet[i];
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;
// 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));
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, BAYANG_PACKET_SIZE);
NRF24L01_SetPower(); // Set tx_power
}
#ifdef BAYANG_HUB_TELEMETRY
static void __attribute__((unused)) BAYANG_check_rx(void)
{
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
if( XN297_IsRX() )
{ // data received from model
XN297_ReadPayload(packet, BAYANG_PACKET_SIZE);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 255);
NRF24L01_FlushRx();
XN297_ReadPayload(packet, BAYANG_PACKET_SIZE); // Strange can't test the CRC since it seems to be disabled on telemetry packets...
uint8_t check = packet[0];
for (uint8_t i=1; i < BAYANG_PACKET_SIZE-1; i++)
check += packet[i];
// decode data , check sum is ok as well, since there is no crc
if (packet[0] == 0x85 && packet[14] == check)
if (packet[0] == 0x85 && packet[14] == check && telemetry_link == 0)
{
// uncompensated battery volts*100/2
v_lipo1 = (packet[3]<<7) + (packet[4]>>2);
v_lipo1 = (packet[3]<<7) + (packet[4]>>1);
// compensated battery volts*100/2
v_lipo2 = (packet[5]<<7) + (packet[6]>>2);
v_lipo2 = (packet[5]<<7) + (packet[6]>>1);
// reception in packets / sec
RX_LQI = packet[7];
RX_RSSI = RX_LQI;
//Flags
//uint8_t flags = packet[3] >> 3;
// battery low: flags & 1
telemetry_link=1;
#if defined HUB_TELEMETRY
// Multiplexed P, I, D values in packet[8] and packet[9].
// The two most significant bits specify which term is sent.
// Remaining 14 bits represent the value: 0 .. 16383
frsky_send_user_frame(0x24+(packet[8]>>6), packet[9], packet[8] & 0x3F ); //0x24 = ACCEL_X_ID, so ACCEL_X_ID=P, ACCEL_Y_ID=I, ACCEL_Z_ID=D
#endif
telemetry_counter++;
if(telemetry_lost==0)
telemetry_link=1;
if(telemetry_lost)
telemetry_link=0; // Don't send anything yet
}
}
NRF24L01_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(TXRX_OFF);
}
#endif
static void __attribute__((unused)) BAYANG_init()
static void __attribute__((unused)) BAYANG_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t *)"\x00\x00\x00\x00\x00", BAYANG_ADDRESS_LENGTH);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, BAYANG_PACKET_SIZE);
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // No retransmits
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
NRF24L01_Activate(0x73);
//XN297_HoppingCalib(BAYANG_RF_NUM_CHANNELS);
switch (sub_protocol)
{
case X16_AH:
case IRDRONE:
rf_ch_num = BAYANG_RF_BIND_CHANNEL_X16_AH;
break;
default:
rf_ch_num = BAYANG_RF_BIND_CHANNEL;
break;
}
//Set bind channel
uint8_t ch = BAYANG_RF_BIND_CHANNEL;
if(sub_protocol == X16_AH || sub_protocol == IRDRONE)
ch = BAYANG_RF_BIND_CHANNEL_X16_AH;
XN297_RFChannel(ch);
}
enum {
@@ -289,7 +273,7 @@ uint16_t BAYANG_callback()
{
XN297_SetTXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
#ifdef BAYANG_HUB_TELEMETRY
XN297_SetRXAddr(rx_tx_addr, BAYANG_ADDRESS_LENGTH);
XN297_SetRXAddr(rx_tx_addr, BAYANG_PACKET_SIZE);
#endif
BIND_DONE;
phase++; //WRITE
@@ -324,9 +308,9 @@ uint16_t BAYANG_callback()
// 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)))
if(XN297_IsPacketSent())
break;
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x03);
XN297_SetTxRxMode(RX_EN);
phase++; // READ
return BAYANG_PACKET_TELEM_PERIOD - BAYANG_CHECK_DELAY - BAYANG_READ_DELAY;
case BAYANG_READ:
@@ -351,15 +335,14 @@ static void __attribute__((unused)) BAYANG_initialize_txid()
hopping_frequency_no=0;
}
uint16_t initBAYANG(void)
void BAYANG_init(void)
{
BIND_IN_PROGRESS; // autobind protocol
phase=BAYANG_BIND;
bind_counter = BAYANG_BIND_COUNT;
BAYANG_initialize_txid();
BAYANG_init();
BAYANG_RF_init();
packet_count=0;
return BAYANG_INITIAL_WAIT+BAYANG_PACKET_PERIOD;
}
#endif
#endif

View File

@@ -48,6 +48,7 @@ Bit(s) Bitmask Option Comment
11 0x400 MULTI_STATUS Indicates if MULTI_STATUS is defined
12 0x800 MULTI_TELEMETRY Indicates if MULTI_TELEMETRY is defined
13 0x1000 DEBUG_SERIAL Indicates if DEBUG_SERIAL is defined
14-16 0xE000 Module sub-type Reads as a three-bit value indicating a number from 0-7 which maps to a module sub-type (right-shift 13 bits to read)
The 8-byte version number is the version number zero-padded to a fixed width of two-bytes per segment and no separator.
E.g. 1.2.3.45 becomes 01020345.
@@ -60,9 +61,15 @@ OpenTX 2 10
Module types are mapped to the following decimal / binary values:
Module Type Decimal Value Binary Valsue
AVR 0 00
STM32 1 01
OrangeRX 2 10
AVR (Atmega328p) 0 00
STM32 (F103) 1 01
OrangeRX (Xmega) 2 10
Module sub-type is currently used for STM32F103 only and is mapped as follows:
Module Type Sub Type Decimal Value Binary Value
STM32 (F103) STM32F103CB 0 000
STM32 (F103) STM32F103C8 1 001
STM32 (F103) T18 5in1 2 010
Channel orders are mapped to the following decimal / binary values:
Channel Order Decimal Value Binary Value
@@ -109,6 +116,17 @@ RTEA 23 10111
bool firmwareFlag_DEBUG_SERIAL = true;
#endif
// STM32 Module sub-type flags
#if defined (MCU_STM32F103CB)
bool firmwareFlag_MCU_STM32F103CB = true;
#endif
#if defined (MCU_STM32F103C8)
bool firmwareFlag_MCU_STM32F103C8 = true;
#endif
#if defined (MULTI_5IN1_INTERNAL)
bool firmwareFlag_MULTI_5IN1_INTERNAL = true;
#endif
// Channel order flags
#if defined (AETR)
bool firmwareFlag_ChannelOrder_AETR = true;

View File

@@ -0,0 +1,118 @@
/*
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 BLUEFLY HP100
#if defined(BLUEFLY_CCNRF_INO)
#include "iface_nrf250k.h"
#define BLUEFLY_PACKET_PERIOD 6000
#define BLUEFLY_PACKET_SIZE 12
#define BLUEFLY_RF_BIND_CHANNEL 81
#define BLUEFLY_NUM_RF_CHANNELS 15
#define BLUEFLY_BIND_COUNT 800
#define BLUEFLY_TXID_SIZE 5
static void __attribute__((unused)) BLUEFLY_send_packet()
{
if(IS_BIND_IN_PROGRESS)
{
memset(packet, 0x55, BLUEFLY_PACKET_SIZE);
memcpy(packet, rx_tx_addr, BLUEFLY_TXID_SIZE);
packet[5] = hopping_frequency[0];
}
else
{
NRF250K_Hopping(hopping_frequency_no);
hopping_frequency_no++;
if(hopping_frequency_no >= BLUEFLY_NUM_RF_CHANNELS);
hopping_frequency_no = 0;
packet[8] = packet[9] = 0;
for(uint8_t i=0; i<8 ; i++)
{
uint16_t ch = convert_channel_16b_limit(CH_AETR[i], 0, 1000);
packet[ i] = ch;
ch &= 0x300;
ch >>= 2;
packet[8 + (i>3?0:1)] = (packet[8 + (i>3?0:1)] >> 2) | ch;
}
// Checksum
uint8_t l, h, t;
l = h = 0xff;
for (uint8_t i=0; i<10; ++i)
{
h ^= packet[i];
h ^= h >> 4;
t = h;
h = l;
l = t;
t = (l<<4) | (l>>4);
h ^= ((t<<2) | (t>>6)) & 0x1f;
h ^= t & 0xf0;
l ^= ((t<<1) | (t>>7)) & 0xe0;
}
packet[10] = h;
packet[11] = l;
}
NRF250K_WritePayload(packet, BLUEFLY_PACKET_SIZE);
NRF250K_SetPower(); // Set tx_power
NRF250K_SetFreqOffset(); // Set frequency offset
}
static void __attribute__((unused)) BLUEFLY_RF_init()
{
NRF250K_Init();
NRF250K_SetTXAddr((uint8_t *)"\x32\xAA\x45\x45\x78", BLUEFLY_TXID_SIZE); // BLUEFLY Bind address
NRF250K_HoppingCalib(BLUEFLY_NUM_RF_CHANNELS); // Calibrate all channels
NRF250K_RFChannel(BLUEFLY_RF_BIND_CHANNEL); // Set bind channel
}
static void __attribute__((unused)) BLUEFLY_initialize_txid()
{
uint8_t start = (rx_tx_addr[3] % 47) + 2;
for(uint8_t i=0;i<BLUEFLY_NUM_RF_CHANNELS;i++)
hopping_frequency[i] = start + i*2;
hopping_frequency_no=0;
}
uint16_t BLUEFLY_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(BLUEFLY_PACKET_PERIOD);
#endif
if(bind_counter)
{
bind_counter--;
if (bind_counter == 0)
{
BIND_DONE;
NRF250K_SetTXAddr(rx_tx_addr, BLUEFLY_TXID_SIZE);
}
}
BLUEFLY_send_packet();
return BLUEFLY_PACKET_PERIOD;
}
void BLUEFLY_init(void)
{
BLUEFLY_initialize_txid();
BLUEFLY_RF_init();
bind_counter = IS_BIND_IN_PROGRESS ? BLUEFLY_BIND_COUNT : 1;
}
#endif

View File

@@ -315,7 +315,7 @@ static void __attribute__((unused)) BUGS_increment_counts()
// FIFO config is one less than desired value
#define BUGS_FIFO_SIZE_RX 15
#define BUGS_FIFO_SIZE_TX 21
uint16_t ReadBUGS(void)
uint16_t BUGS_callback(void)
{
uint8_t mode, base_adr;
uint16_t rxid;
@@ -340,7 +340,7 @@ uint16_t ReadBUGS(void)
case BUGS_BIND_2:
//Wait for TX completion
start=micros();
while ((uint16_t)micros()-start < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
while ((uint16_t)((uint16_t)micros()-start) < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
break;
A7105_SetTxRxMode(RX_EN);
@@ -399,7 +399,7 @@ uint16_t ReadBUGS(void)
case BUGS_DATA_2:
//Wait for TX completion
start=micros();
while ((uint16_t)micros()-start < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
while ((uint16_t)((uint16_t)micros()-start) < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
break;
A7105_SetTxRxMode(RX_EN);
@@ -437,7 +437,7 @@ uint16_t ReadBUGS(void)
return packet_period;
}
uint16_t initBUGS(void)
void BUGS_init(void)
{
uint16_t rxid=0;
uint8_t base_adr=BUGS_EEPROM_OFFSET+(RX_num&0x0F)*2;
@@ -459,8 +459,6 @@ uint16_t initBUGS(void)
armed = 0;
arm_flags = BUGS_FLAG_DISARM; // initial value from captures
arm_channel_previous = BUGS_CH_SW_ARM;
return 10000;
}
#endif

View File

@@ -190,7 +190,9 @@ static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
}
TxPacket.option = (bindMode) ? (option & (~CABELL_OPTION_MASK_CHANNEL_REDUCTION)) : option; //remove channel reduction if in bind mode
}
TxPacket.reserved = 0;
rf_ch_num = CABELL_getNextChannel (hopping_frequency,CABELL_RADIO_CHANNELS, rf_ch_num);
TxPacket.reserved = rf_ch_num & 0x3F;
TxPacket.modelNum = RX_num;
uint16_t checkSum = TxPacket.modelNum + TxPacket.option + TxPacket.RxMode + TxPacket.reserved; // Start Calculate checksum
@@ -244,7 +246,6 @@ static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
TxPacket.checkSum_LSB = checkSum & 0x00FF;
// Set channel for next transmission
rf_ch_num = CABELL_getNextChannel (hopping_frequency,CABELL_RADIO_CHANNELS, rf_ch_num);
NRF24L01_WriteReg(NRF24L01_05_RF_CH,rf_ch_num);
//NRF24L01_FlushTx(); //just in case things got hung up
@@ -255,7 +256,7 @@ static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
*p |= (packet_count++)<<7; // This causes the 8th bit of the first byte to toggle with each xmit so consecutive payloads are not identical.
// This is a work around for a reported bug in clone NRF24L01 chips that mis-took this case for a re-transmit of the same packet.
CABELL_SetPower();
NRF24L01_SetPower();
NRF24L01_WritePayload((uint8_t*)&TxPacket, packetSize);
#if defined CABELL_HUB_TELEMETRY
@@ -279,39 +280,44 @@ static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
static void __attribute__((unused)) CABELL_getChannelSequence (uint8_t outArray[], uint8_t numChannels, uint64_t permutation)
{
/* This procedure initializes an array with the sequence progression of channels.
* This is not the actual channels itself, but the sequence base to be used within bands of
* This is not the actual channels itself, but the sequence base to be used within bands of
* channels.
*
*
* There are numChannels! permutations for arranging the channels
* one of these permutations will be calculated based on the permutation input
* permutation should be between 1 and numChannels! but the routine will constrain it
* if these bounds are exceeded. Typically the radio's unique TX ID should be used.
*
*
* The maximum numChannels is 20. Anything larger than this will cause the uint64_t
* variables to overflow, yielding unknown results (possibly infinite loop?). Therefor
* this routine constrains the value.
*/
*/
uint8_t i; //iterator counts numChannels
uint64_t indexOfNextSequenceValue;
uint64_t numChannelsFactorial=1;
uint32_t indexOfNextSequenceValue;
uint32_t numChannelsFactorial=1;
uint32_t perm32 ;
uint8_t sequenceValue;
numChannels = constrain(numChannels,1,20);
numChannels = constrain(numChannels,1,9);
for (i = 1; i <= numChannels;i++)
{
numChannelsFactorial *= i; // Calculate n!
outArray[i-1] = i-1; // Initialize array with the sequence
numChannelsFactorial *= i; // Calculate n!
outArray[i-1] = i-1; // Initialize array with the sequence
}
permutation = (permutation % numChannelsFactorial) + 1; // permutation must be between 1 and n! or this algorithm will infinite loop
perm32 = permutation >> 8 ; // Shift 40 bit input to 32 bit
perm32 = (perm32 % numChannelsFactorial); // permutation must be between 1 and n! or this algorithm will infinite loop
perm32 <<= 8 ; // Shift back 8 bits
perm32 += permutation & 0x00FF ; // Tack on least 8 bits
perm32 = (perm32 % numChannelsFactorial) + 1; // permutation must be between 1 and n! or this algorithm will infinite loop
//Rearrange the array elements based on the permutation selected
for (i=0, permutation--; i<numChannels; i++ )
for (i=0, perm32--; i<numChannels; i++ )
{
numChannelsFactorial /= ((uint64_t)numChannels)-i;
indexOfNextSequenceValue = i+(permutation/numChannelsFactorial);
permutation %= numChannelsFactorial;
numChannelsFactorial /= numChannels-i;
indexOfNextSequenceValue = i+(perm32/numChannelsFactorial);
perm32 %= numChannelsFactorial;
//Copy the value in the selected array position
sequenceValue = outArray[indexOfNextSequenceValue];
@@ -356,48 +362,18 @@ static void __attribute__((unused)) CABELL_setAddress()
}
//-----------------------------------------------------------------------------------------
static void __attribute__((unused)) CABELL_init()
static void __attribute__((unused)) CABELL_RF_init()
{
NRF24L01_Initialize();
CABELL_SetPower();
NRF24L01_SetBitrate(NRF24L01_BR_250K); // slower data rate gives better range/reliability
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes
NRF24L01_SetTxRxMode(TX_EN); //Power up and 16 bit CRC
CABELL_setAddress();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01);
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x20); // 32 byte packet length
NRF24L01_WriteReg(NRF24L01_12_RX_PW_P1, 0x20); // 32 byte packet length
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x5F); // no retransmits
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F); // Enable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x04); // Enable dynamic Payload Length
NRF24L01_Activate(0x73);
prev_power = NRF_POWER_0;
}
//-----------------------------------------------------------------------------------------
static void CABELL_SetPower() // This over-ride the standard Set Power to allow an flag in option to indicate max power setting
// Note that on many modules max power may actually be worse than the normal high power setting
// test and only use max if it helps the range
{
if(IS_BIND_DONE && !IS_RANGE_FLAG_on && ((option & CABELL_OPTION_MASK_MAX_POWER_OVERRIDE) != 0))
{ // If we are not in range or bind mode and power setting override is in effect, then set max power, else standard power logic
if(prev_power != NRF_POWER_3) // prev_power is global variable for NRF24L01; NRF_POWER_3 is max power
{
uint8_t rf_setup = NRF24L01_ReadReg(NRF24L01_06_RF_SETUP);
rf_setup = (rf_setup & 0xF9) | (NRF_POWER_3 << 1);
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup);
prev_power=NRF_POWER_3;
}
}
else
NRF24L01_SetPower();
NRF24L01_SetTxRxMode(TX_EN); // Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
}
//-----------------------------------------------------------------------------------------
@@ -414,7 +390,7 @@ uint16_t CABELL_callback()
else if (bind_counter == 0)
{
BIND_DONE;
CABELL_init(); // non-bind address
CABELL_RF_init(); // non-bind address
}
else
{
@@ -425,17 +401,15 @@ uint16_t CABELL_callback()
}
//-----------------------------------------------------------------------------------------
uint16_t initCABELL(void)
void CABELL_init(void)
{
if (IS_BIND_DONE)
bind_counter = 0;
else
bind_counter = CABELL_BIND_COUNT;
CABELL_init();
CABELL_RF_init();
packet_period = CABELL_PACKET_PERIOD;
return packet_period;
}
#endif

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)
@@ -158,4 +163,128 @@ void CC2500_SetPower()
prev_power=power;
}
}
void __attribute__((unused)) CC2500_SetFreqOffset()
{
if(prev_option != option)
{
prev_option = option;
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
}
}
void __attribute__((unused)) CC2500_250K_Init()
{
CC2500_Strobe(CC2500_SIDLE);
// Address Config = No address check
// Base Frequency = 2400
// CRC Autoflush = false
// CRC Enable = false
// Channel Spacing = 333.251953
// Data Format = Normal mode
// Data Rate = 249.939
// Deviation = 126.953125
// Device Address = 0
// Manchester Enable = false
// Modulated = true
// Modulation Format = GFSK
// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word
// RX Filter BW = 203.125000
// Sync Word Qualifier Mode = No preamble/sync
// TX Power = 0
// Whitening = false
// Fast Frequency Hopping - no PLL auto calibration
/* //Previous config
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x01); // Packet Automation Control
CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x0A); // Frequency Synthesizer Control
CC2500_WriteReg(CC2500_0C_FSCTRL0, option); // Frequency offset hack
CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // Frequency Control Word, High Byte
CC2500_WriteReg(CC2500_0E_FREQ1, 0x4E); // Frequency Control Word, Middle Byte
CC2500_WriteReg(CC2500_0F_FREQ0, 0xC3); // Frequency Control Word, Low Byte
CC2500_WriteReg(CC2500_10_MDMCFG4, 0x8D); // Modem Configuration
CC2500_WriteReg(CC2500_11_MDMCFG3, 0x3B); // Modem Configuration
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x10); // Modem Configuration
CC2500_WriteReg(CC2500_13_MDMCFG1, 0x23); // Modem Configuration
CC2500_WriteReg(CC2500_14_MDMCFG0, 0xA4); // Modem Configuration
CC2500_WriteReg(CC2500_15_DEVIATN, 0x62); // Modem Deviation Setting
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // Main Radio Control State Machine Configuration
CC2500_WriteReg(CC2500_19_FOCCFG, 0x1D); // Frequency Offset Compensation Configuration
CC2500_WriteReg(CC2500_1A_BSCFG, 0x1C); // Bit Synchronization Configuration
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0xC7); // AGC Control
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x00); // AGC Control
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xB0); // AGC Control
CC2500_WriteReg(CC2500_21_FREND1, 0xB6); // Front End RX Configuration
CC2500_WriteReg(CC2500_23_FSCAL3, 0xEA); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_25_FSCAL1, 0x00); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_26_FSCAL0, 0x11); // Frequency Synthesizer Calibration
*/
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // Packet Automation Control, address check true auto append RSSI & LQI
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x00); // Packet Automation Control, fixed packet len
CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x0A); // Frequency Synthesizer Control (IF Frequency)
CC2500_WriteReg(CC2500_0C_FSCTRL0, 0x00); // Frequency Synthesizer Control
CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // Frequency Control Word, High Byte
CC2500_WriteReg(CC2500_0E_FREQ1, 0x4E); // Frequency Control Word, Middle Byte
CC2500_WriteReg(CC2500_0F_FREQ0, 0xC5); // Frequency Control Word, Low Byte
CC2500_WriteReg(CC2500_10_MDMCFG4, 0x3D); // Modem Configuration Set to 406kHz BW filter
CC2500_WriteReg(CC2500_11_MDMCFG3, 0x3B); // Modem Configuration
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x10); // Modem Configuration, GFSK, no preambule and no sync word -> TX by default
CC2500_WriteReg(CC2500_13_MDMCFG1, 0x03); // Modem Configuration, 2 bytes of preamble
CC2500_WriteReg(CC2500_14_MDMCFG0, 0xA4); // Modem Configuration
CC2500_WriteReg(CC2500_15_DEVIATN, 0x62); // Modem Deviation Setting
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // Main Radio Control State Machine Configuration
CC2500_WriteReg(CC2500_19_FOCCFG, 0x1D); // Frequency Offset Compensation Configuration
CC2500_WriteReg(CC2500_1A_BSCFG, 0x1C); // Bit Synchronization Configuration
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0xC7); // AGC Control
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x00); // AGC Control
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xB0); // AGC Control
CC2500_WriteReg(CC2500_21_FREND1, 0xB6); // Front End RX Configuration
CC2500_WriteReg(CC2500_23_FSCAL3, 0xEA); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_25_FSCAL1, 0x00); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_26_FSCAL0, 0x11); // Frequency Synthesizer Calibration
//Prep RX
// Set first 3 bytes of rx addr in [0]->SYNC1, [1]->SYNC0 and [2]->ADDR
// CC2500_WriteReg(CC2500_04_SYNC1, [0]); // Sync word, high byte
// CC2500_WriteReg(CC2500_05_SYNC0, [1]); // Sync word, low byte
// CC2500_WriteReg(CC2500_09_ADDR, [2]); // Set addr
//RX
// CC2500_WriteReg(CC2500_12_MDMCFG2, 0x12); // Modem Configuration, GFSK, 16/16 Sync Word TX&RX
//TX
// CC2500_WriteReg(CC2500_12_MDMCFG2, 0x10); // Modem Configuration, GFSK, no preambule and no sync word
// need to set packet length before sending/receiving
// CC2500_WriteReg(CC2500_06_PKTLEN, cc2500_packet_len); // Packet len, fix packet len
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
}
void __attribute__((unused)) CC2500_250K_HoppingCalib(uint8_t num_freq)
{
for (uint8_t i = 0; i < num_freq; i++)
{
CC2500_Strobe(CC2500_SIDLE);
// spacing is 333.25 kHz, must multiply channel by 3
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[i]*3);
// calibrate
CC2500_Strobe(CC2500_SCAL);
delayMicroseconds(900);
calData[i]=CC2500_ReadReg(CC2500_25_FSCAL1);
}
}
void __attribute__((unused)) CC2500_250K_Hopping(uint8_t index)
{
// spacing is 333.25 kHz, must multiply channel by 3
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[index] * 3);
// set PLL calibration
CC2500_WriteReg(CC2500_25_FSCAL1, calData[index]);
}
void __attribute__((unused)) CC2500_250K_RFChannel(uint8_t number)
{
CC2500_Strobe(CC2500_SIDLE);
// spacing is 333.25 kHz, must multiply channel by 3
CC2500_WriteReg(CC2500_0A_CHANNR, number*3);
// calibrate
CC2500_Strobe(CC2500_SCAL);
delayMicroseconds(900);
}
#endif

View File

@@ -644,37 +644,24 @@ static uint8_t crtp_log_setup_state_machine()
return state_machine_completed;
}
static int cflie_init()
static void CFLIE_RF_init()
{
NRF24L01_Initialize();
// CRC, radio on
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x01); // Auto Acknowledgement for data pipe 0
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, TX_ADDR_SIZE-2); // 5-byte RX/TX address
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x13); // 3 retransmits, 500us delay
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num); // Defined in initialize_rx_tx_addr
NRF24L01_SetBitrate(data_rate); // Defined in initialize_rx_tx_addr
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, TX_ADDR_SIZE);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, TX_ADDR_SIZE);
// this sequence necessary for module from stock tx
NRF24L01_ReadReg(NRF24L01_1D_FEATURE);
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_ReadReg(NRF24L01_1D_FEATURE);
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x01); // Enable Dynamic Payload Length on pipe 0
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x06); // Enable Dynamic Payload Length, enable Payload with ACK
// 50ms delay in callback
return 50000;
NRF24L01_SetTxRxMode(TX_EN); // Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
}
// TODO: Fix telemetry
@@ -749,7 +736,7 @@ static int cflie_init()
// }
// }
static uint16_t cflie_callback()
static uint16_t CFLIE_callback()
{
switch (phase) {
case CFLIE_INIT_SEARCH:
@@ -799,7 +786,7 @@ static uint16_t cflie_callback()
}
// Generate address to use from TX id and manufacturer id (STM32 unique id)
static uint8_t initialize_rx_tx_addr()
static uint8_t CFLIE_initialize_rx_tx_addr()
{
rx_tx_addr[0] =
rx_tx_addr[1] =
@@ -844,19 +831,15 @@ static uint8_t initialize_rx_tx_addr()
return CFLIE_INIT_SEARCH;
}
uint16_t initCFlie(void)
void CFLIE_init(void)
{
BIND_IN_PROGRESS; // autobind protocol
phase = initialize_rx_tx_addr();
phase = CFLIE_initialize_rx_tx_addr();
crtp_log_setup_state = CFLIE_CRTP_LOG_SETUP_STATE_INIT;
packet_count=0;
int delay = cflie_init();
// debugln("CFlie init!");
return delay;
CFLIE_RF_init();
}
#endif

View File

@@ -16,7 +16,7 @@
#if defined(CG023_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_xn297.h"
#define CG023_PACKET_PERIOD 8200 // Timeout for callback in uSec
#define CG023_INITIAL_WAIT 500
@@ -49,7 +49,7 @@ enum YD829_FLAGS {
YD829_FLAG_STILL = 0x80,
};
static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
static void __attribute__((unused)) CG023_send_packet()
{
// throttle : 0x00 - 0xFF
throttle=convert_channel_8b(THROTTLE);
@@ -62,10 +62,16 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
// aileron : 0x43 - 0x7F - 0xBB
aileron = convert_channel_16b_limit(AILERON, 0x43, 0xBB);
if (bind)
if (IS_BIND_IN_PROGRESS)
{
packet[0]= 0xaa;
XN297_RFChannel(CG023_RF_BIND_CHANNEL);
}
else
{
packet[0]= 0x55;
XN297_RFChannel(hopping_frequency_no);
}
// transmitter id
packet[1] = rx_tx_addr[0];
packet[2] = rx_tx_addr[1];
@@ -85,7 +91,7 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
if(sub_protocol==CG023)
{
// rate
packet[13] = CG023_FLAG_RATE_HIGH
packet[13] = CG023_FLAG_RATE_HIGH
| GET_FLAG(CH5_SW,CG023_FLAG_FLIP)
| GET_FLAG(CH6_SW,CG023_FLAG_LED_OFF)
| GET_FLAG(CH7_SW,CG023_FLAG_STILL)
@@ -95,7 +101,7 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
else
{// YD829
// rate
packet[13] = YD829_FLAG_RATE_HIGH
packet[13] = YD829_FLAG_RATE_HIGH
| GET_FLAG(CH5_SW,YD829_FLAG_FLIP)
| GET_FLAG(CH7_SW,YD829_FLAG_STILL)
| GET_FLAG(CH8_SW,YD829_FLAG_VIDEO)
@@ -103,79 +109,52 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
}
packet[14] = 0;
// Power on, TX mode, 2byte CRC
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
if (bind)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, CG023_RF_BIND_CHANNEL);
else
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency_no);
// clear packet status bits and TX FIFO
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
// Send
XN297_SetTxRxMode(TX_EN);
XN297_SetPower();
XN297_WritePayload(packet, CG023_PACKET_SIZE);
NRF24L01_SetPower(); // Set tx_power
}
static void __attribute__((unused)) CG023_init()
static void __attribute__((unused)) CG023_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_SetTXAddr((uint8_t *)"\x26\xA8\x67\x35\xCC", 5);
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
XN297_SetTXAddr((uint8_t *)"\x26\xA8\x67\x35\xCC", 5);
}
uint16_t CG023_callback()
{
if(IS_BIND_DONE)
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
CG023_send_packet(0);
}
else
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
if(bind_counter)
{
bind_counter--;
if (bind_counter == 0)
BIND_DONE;
else
{
CG023_send_packet(1);
bind_counter--;
}
}
CG023_send_packet();
return packet_period;
}
static void __attribute__((unused)) CG023_initialize_txid()
{
rx_tx_addr[0]= 0x80 | (rx_tx_addr[0] % 0x40);
if( rx_tx_addr[0] == 0xAA) // avoid using same freq for bind and data channel
if( rx_tx_addr[0] == 0xAA) // avoid using same freq for bind and data channel
rx_tx_addr[0] ++;
hopping_frequency_no = rx_tx_addr[0] - 0x7D; // rf channel for data packets
}
uint16_t initCG023(void)
void CG023_init(void)
{
BIND_IN_PROGRESS; // autobind protocol
bind_counter = CG023_BIND_COUNT;
CG023_initialize_txid();
CG023_init();
CG023_RF_init();
if(sub_protocol==CG023)
packet_period=CG023_PACKET_PERIOD;
else // YD829
packet_period=YD829_PACKET_PERIOD;
return CG023_INITIAL_WAIT+YD829_PACKET_PERIOD;
}
#endif

View File

@@ -17,19 +17,19 @@
#if defined(CX10_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_xn297.h"
#define CX10_BIND_COUNT 4360 // 6 seconds
#define CX10_BIND_COUNT 4360 // 6 seconds
#define CX10_PACKET_SIZE 15
#define CX10A_PACKET_SIZE 19 // CX10 blue board packets have 19-byte payload
#define CX10A_PACKET_SIZE 19 // CX10 blue board packets have 19-byte payload
#define Q2X2_PACKET_SIZE 21
#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
#define CX10A_PACKET_PERIOD 6000
#define CX10_INITIAL_WAIT 500
// flags
#define CX10_FLAG_FLIP 0x10 // goes to rudder channel
#define CX10_FLAG_FLIP 0x10 // goes to rudder channel
#define CX10_FLAG_MODE_MASK 0x03
#define CX10_FLAG_HEADLESS 0x04
// flags2
@@ -46,12 +46,12 @@ enum {
CX10_DATA
};
static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind)
static void __attribute__((unused)) CX10_Write_Packet()
{
uint8_t offset = 0;
if(sub_protocol == CX10_BLUE)
offset = 4;
packet[0] = bind ? 0xAA : 0x55;
packet[0] = IS_BIND_IN_PROGRESS ? 0xAA : 0x55;
packet[1] = rx_tx_addr[0];
packet[2] = rx_tx_addr[1];
packet[3] = rx_tx_addr[2];
@@ -62,57 +62,57 @@ static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind)
uint16_t throttle=convert_channel_16b_limit(THROTTLE,1000,2000);
uint16_t rudder= convert_channel_16b_limit(RUDDER ,2000,1000);
// Channel 5 - flip flag
packet[12+offset] = GET_FLAG(CH5_SW,CX10_FLAG_FLIP); // flip flag applied on rudder
packet[12+offset] = GET_FLAG(CH5_SW,CX10_FLAG_FLIP); // flip flag applied on rudder
// Channel 6 - rate mode is 2 lsb of packet 13
if(CH6_SW) // rate 3 / headless on CX-10A
if(CH6_SW) // rate 3 / headless on CX-10A
flags = 0x02;
else
if(Channel_data[CH6] < CHANNEL_MIN_COMMAND)
flags = 0x00; // rate 1
flags = 0x00; // rate 1
else
flags = 0x01; // rate 2
uint8_t flags2=0; // packet 14
flags = 0x01; // rate 2
uint8_t flags2=0; // packet 14
uint8_t video_state=packet[14] & 0x21;
switch(sub_protocol)
{
case CX10_BLUE:
flags |= GET_FLAG(!CH7_SW, 0x10) // Channel 7 - picture
|GET_FLAG( CH8_SW, 0x08); // Channel 8 - video
flags |= GET_FLAG(!CH7_SW, 0x10) // Channel 7 - picture
|GET_FLAG( CH8_SW, 0x08); // Channel 8 - video
break;
case F_Q282:
case F_Q242:
case F_Q222:
memcpy(&packet[15], "\x10\x10\xaa\xaa\x00\x00", 6);
//FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL
flags2 = GET_FLAG(CH5_SW, 0x80) // Channel 5 - FLIP
|GET_FLAG(!CH6_SW, 0x40) // Channel 6 - LED
|GET_FLAG(CH9_SW, 0x08) // Channel 9 - HEADLESS
|GET_FLAG(CH11_SW, 0x04) // Channel 11 - XCAL
|GET_FLAG(CH12_SW, 0x02); // Channel 12 - YCAL or Start/Stop motors on JXD 509
flags2 = GET_FLAG(CH5_SW, 0x80) // Channel 5 - FLIP
|GET_FLAG(!CH6_SW, 0x40) // Channel 6 - LED
|GET_FLAG(CH9_SW, 0x08) // Channel 9 - HEADLESS
|GET_FLAG(CH11_SW, 0x04) // Channel 11 - XCAL
|GET_FLAG(CH12_SW, 0x02); // Channel 12 - YCAL or Start/Stop motors on JXD 509
if(sub_protocol==F_Q242)
{
flags=2;
flags2|= GET_FLAG(CH7_SW,0x01) // Channel 7 - picture
|GET_FLAG(CH8_SW,0x10); // Channel 8 - video
flags2|= GET_FLAG(CH7_SW,0x01) // Channel 7 - picture
|GET_FLAG(CH8_SW,0x10); // Channel 8 - video
packet[17]=0x00;
packet[18]=0x00;
}
else
{ // F_Q282 & F_Q222
flags=3; // expert
if(CH8_SW) // Channel 8 - F_Q282 video / F_Q222 Module 1
flags=3; // expert
if(CH8_SW) // Channel 8 - F_Q282 video / F_Q222 Module 1
{
if (!(video_state & 0x20)) video_state ^= 0x21;
}
else
if (video_state & 0x20) video_state &= 0x01;
flags2 |= video_state
|GET_FLAG(CH7_SW,0x10); // Channel 7 - F_Q282 picture / F_Q222 Module 2
|GET_FLAG(CH7_SW,0x10); // Channel 7 - F_Q282 picture / F_Q222 Module 2
}
if(CH10_SW) flags |=0x80; // Channel 10 - RTH
if(CH10_SW) flags |=0x80; // Channel 10 - RTH
break;
case DM007:
aileron = 3000 - aileron;
@@ -128,16 +128,16 @@ static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind)
if(CH8_SW) packet[12] &= ~CX10_FLAG_FLIP;
case JC3015_1:
//FLIP|MODE|PICTURE|VIDEO
flags2= GET_FLAG(CH7_SW,_BV(3)) // Channel 7
|GET_FLAG(CH8_SW,_BV(4)); // Channel 8
flags2= GET_FLAG(CH7_SW,_BV(3)) // Channel 7
|GET_FLAG(CH8_SW,_BV(4)); // Channel 8
break;
case MK33041:
elevator = 3000 - elevator;
//FLIP|MODE|PICTURE|VIDEO|HEADLESS|RTH
flags|=GET_FLAG(CH7_SW,_BV(7)) // Channel 7 - picture
|GET_FLAG(CH10_SW,_BV(2)); // Channel 10 - rth
flags2=GET_FLAG(CH8_SW,_BV(0)) // Channel 8 - video
|GET_FLAG(CH9_SW,_BV(5)); // Channel 9 - headless
flags|=GET_FLAG(CH7_SW,_BV(7)) // Channel 7 - picture
|GET_FLAG(CH10_SW,_BV(2)); // Channel 10 - rth
flags2=GET_FLAG(CH8_SW,_BV(0)) // Channel 8 - video
|GET_FLAG(CH9_SW,_BV(5)); // Channel 9 - headless
break;
}
packet[5+offset] = lowByte(aileron);
@@ -151,39 +151,23 @@ static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind)
packet[13+offset]=flags;
packet[14+offset]=flags2;
// Power on, TX mode, 2byte CRC
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
if (bind)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, CX10_RF_BIND_CHANNEL);
else
// Send
if(IS_BIND_DONE)
{
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
XN297_Hopping(hopping_frequency_no++);
hopping_frequency_no %= CX10_NUM_RF_CHANNELS;
}
// clear packet status bits and TX FIFO
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, packet_length);
NRF24L01_SetPower();
}
static void __attribute__((unused)) CX10_init()
static void __attribute__((unused)) CX10_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc",5);
XN297_SetRXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc",5);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // rx pipe 0 (used only for blue board)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, CX10_RF_BIND_CHANNEL);
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
XN297_SetRXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", packet_length);
XN297_RFChannel(CX10_RF_BIND_CHANNEL);
}
uint16_t CX10_callback()
@@ -197,42 +181,39 @@ uint16_t CX10_callback()
}
else
{
CX10_Write_Packet(1);
CX10_Write_Packet();
bind_counter--;
}
break;
case CX10_BIND2:
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
// switch to TX mode
if( XN297_IsRX() )
{ // RX fifo data ready
XN297_ReadPayload(packet, packet_length);
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
if(packet[9] == 1)
debugln("RX");
if(XN297_ReadPayload(packet, packet_length) && packet[9] == 1)
{
BIND_DONE;
XN297_SetTxRxMode(TXRX_OFF);
phase = CX10_DATA;
break;
}
}
else
{
// switch to TX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushTx();
NRF24L01_SetTxRxMode(TX_EN);
CX10_Write_Packet(1);
delayMicroseconds(400);
// switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushRx();
NRF24L01_SetTxRxMode(RX_EN);
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
XN297_SetTxRxMode(TXRX_OFF);
CX10_Write_Packet();
// wait for packet to be sent
while( !XN297_IsPacketSent()); //delayMicroseconds(400);
}
// switch to RX mode
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
break;
case CX10_DATA:
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
CX10_Write_Packet(0);
CX10_Write_Packet();
break;
}
return packet_period;
@@ -260,9 +241,13 @@ static void __attribute__((unused)) CX10_initialize_txid()
}
}
uint16_t initCX10(void)
void CX10_init(void)
{
BIND_IN_PROGRESS; // autobind protocol
if(protocol == PROTO_Q2X2)
sub_protocol|=0x08; // Increase the number of sub_protocols for CX-10
if(sub_protocol==CX10_BLUE)
{
packet_length = CX10A_PACKET_SIZE;
@@ -285,8 +270,7 @@ uint16_t initCX10(void)
bind_counter = CX10_BIND_COUNT;
}
CX10_initialize_txid();
CX10_init();
return CX10_INITIAL_WAIT+packet_period;
CX10_RF_init();
}
#endif

View File

@@ -79,13 +79,24 @@ uint8_t CYRF_Reset()
void CYRF_GetMfgData(uint8_t data[])
{
#ifndef FORCE_CYRF_ID
/* Fuses power on */
CYRF_WriteRegister(CYRF_25_MFG_ID, 0xFF);
if(eeprom_read_byte((EE_ADDR)EEPROM_CID_INIT_OFFSET)==0xf0)
{//read Cyrf ID from EEPROM
for(uint8_t i=0;i<6;i++)
data[i] = eeprom_read_byte((EE_ADDR)EEPROM_CID_OFFSET+i);
}
else
{//read Cyrf ID and store it EEPROM
/* Fuses power on */
CYRF_WriteRegister(CYRF_25_MFG_ID, 0xFF);
CYRF_ReadRegisterMulti(CYRF_25_MFG_ID, data, 6);
CYRF_ReadRegisterMulti(CYRF_25_MFG_ID, data, 6);
for(uint8_t i=0;i<6;i++)
eeprom_write_byte((EE_ADDR)EEPROM_CID_OFFSET+i, data[i]);
eeprom_write_byte((EE_ADDR)EEPROM_CID_INIT_OFFSET, 0xf0);
/* Fuses power off */
CYRF_WriteRegister(CYRF_25_MFG_ID, 0x00);
/* Fuses power off */
CYRF_WriteRegister(CYRF_25_MFG_ID, 0x00);
}
#else
memcpy(data,FORCE_CYRF_ID,6);
#endif
@@ -98,14 +109,14 @@ void CYRF_SetTxRxMode(uint8_t mode)
{
if(mode==TXRX_OFF)
{
if(protocol!=PROTO_WFLY)
if( protocol!=PROTO_WFLY && protocol!=PROTO_MLINK )
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // 4=IDLE, 8=TX, C=RX
CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x00); // XOUT=0 PACTL=0
}
else
{
//Set the post tx/rx state
if(protocol!=PROTO_WFLY)
if( protocol!=PROTO_WFLY && protocol!=PROTO_MLINK )
CYRF_WriteRegister(CYRF_0F_XACT_CFG, mode == TX_EN ? 0x28 : 0x2C); // 4=IDLE, 8=TX, C=RX
if(mode == TX_EN)
#ifdef ORANGE_TX_BLUE
@@ -168,10 +179,10 @@ void CYRF_SetPower(uint8_t val)
/*
*
*/
void CYRF_ConfigCRCSeed(uint16_t crc)
void CYRF_ConfigCRCSeed(uint16_t crc_seed)
{
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB,crc & 0xff);
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB,crc >> 8);
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB,crc_seed & 0xff);
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB,crc_seed >> 8);
}
/*
* these are the recommended sop codes from Cyrpress
@@ -184,11 +195,11 @@ void CYRF_ConfigSOPCode(const uint8_t *sopcodes)
CYRF_WriteRegisterMulti(CYRF_22_SOP_CODE, sopcodes, 8);
}
void CYRF_ConfigDataCode(const uint8_t *datacodes, uint8_t len)
void CYRF_ConfigDataCode(const uint8_t *datacodes)
{
//NOTE: This can also be implemented as:
//for(i = 0; i < len; i++) WriteRegister)0x23, datacodes[i];
CYRF_WriteRegisterMulti(CYRF_23_DATA_CODE, datacodes, len);
//for(i = 0; i < 16; i++) WriteRegister)0x23, datacodes[i];
CYRF_WriteRegisterMulti(CYRF_23_DATA_CODE, datacodes, 16);
}
void CYRF_WritePreamble(uint32_t preamble)
@@ -238,7 +249,7 @@ void CYRF_WriteDataPacket(const uint8_t dpbuffer[])
}
*/
//NOTE: This routine will reset the CRC Seed
void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uint8_t min, uint8_t max)
void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uint8_t min, uint8_t max, uint8_t forced)
{
#define NUM_FREQ 80
#define FREQ_OFFSET 4
@@ -258,7 +269,12 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin
delayMilliseconds(1);
for(i = 0; i < NUM_FREQ; i++)
{
CYRF_ConfigRFChannel(i);
if(((i&1) && forced == FIND_CHANNEL_EVEN) || (!(i&1) && forced == FIND_CHANNEL_ODD))
{
rssi[i] = 0xFF;
continue;
}
CYRF_ConfigRFChannel(i); //protocol==PROTO_LOSI?i|1:i);
delayMicroseconds(270); //slow channel require 270usec for synthesizer to settle
if( !(CYRF_ReadRegister(CYRF_05_RX_CTRL) & 0x80)) {
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80); //Prepare to receive
@@ -284,10 +300,10 @@ 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)
#if defined(DEVO_CYRF6936_INO) || defined(J6PRO_CYRF6936_INO) || defined(TRAXXAS_CYRF6936_INO)
const uint8_t PROGMEM DEVO_j6pro_sopcodes[][8] = {
/* Note these are in order transmitted (LSB 1st) */
{0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91},
@@ -300,7 +316,7 @@ const uint8_t PROGMEM DEVO_j6pro_sopcodes[][8] = {
{0xB9, 0x8E, 0x19, 0x74, 0x6F, 0x65, 0x18, 0x74},
{0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49},
{0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72},
#if defined(J6PRO_CYRF6936_INO)
#if defined(J6PRO_CYRF6936_INO) || defined(TRAXXAS_CYRF6936_INO)
{0x82, 0xC7, 0x90, 0x36, 0x21, 0x03, 0xFF, 0x17},
{0xE2, 0xF8, 0xCC, 0x91, 0x3C, 0x37, 0xCC, 0x91}, //Note: the '03' was '9E' in the Cypress recommended table
{0xAD, 0x39, 0xA2, 0x0F, 0x9B, 0xC5, 0xA1, 0x0F}, //The following are the same as the 1st 8 above,
@@ -310,14 +326,86 @@ const uint8_t PROGMEM DEVO_j6pro_sopcodes[][8] = {
{0xB6, 0x31, 0xAE, 0x46, 0x5A, 0xCC, 0xAE, 0x46},
{0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C},
{0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74},
{0x62, 0xDF, 0xC1, 0x49, 0xDF, 0xB1, 0xC0, 0x49}, //j6pro bind
#endif
};
#endif
static void __attribute__((unused)) CYRF_PROGMEM_ConfigSOPCode(const uint8_t *data)
{
uint8_t code[8];
//debug("SOP:");
for(uint8_t i=0;i<8;i++)
{
code[i]=pgm_read_byte_near(&data[i]);
//debug(" %02X",code[i]);
}
//debugln("");
CYRF_ConfigSOPCode(code);
}
//CYRF GFSK 1Mb functions
const uint8_t PROGMEM CYRF_GFSK1M_init_vals[][2] = {
{CYRF_02_TX_CTRL, 0x00}, // transmit err & complete interrupts disabled
{CYRF_05_RX_CTRL, 0x00}, // receive err & complete interrupts disabled
{CYRF_28_CLK_EN, 0x02}, // Force Receive Clock Enable, MUST be set
{CYRF_32_AUTO_CAL_TIME, 0x3c}, // must be set to 3C
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // must be set to 14
{CYRF_06_RX_CFG, 0x48}, // LNA manual control, Rx Fast Turn Mode Enable
{CYRF_1B_TX_OFFSET_LSB, 0x00}, // Tx frequency offset LSB
{CYRF_1C_TX_OFFSET_MSB, 0x00}, // Tx frequency offset MSB
{CYRF_0F_XACT_CFG, 0x24}, // Force End State, transaction end state = idle
{CYRF_03_TX_CFG, 0x00}, // GFSK mode
{CYRF_12_DATA64_THOLD, 0x0a}, // 64 Chip Data PN Code Correlator Threshold = 10
{CYRF_0F_XACT_CFG, 0x04}, // Transaction End State = idle
{CYRF_39_ANALOG_CTRL, 0x01}, // synth setting time for all channels is the same as for slow channels
{CYRF_0F_XACT_CFG, 0x24}, //Force IDLE
{CYRF_29_RX_ABORT, 0x00}, //Clear RX abort
{CYRF_12_DATA64_THOLD, 0x0a}, //set pn correlation threshold
{CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold
{CYRF_29_RX_ABORT, 0x0f}, //Clear RX abort?
{CYRF_03_TX_CFG, 0x00}, // GFSK mode
{CYRF_10_FRAMING_CFG, 0x4a}, // 0b11000000 //set sop len and threshold
{CYRF_1F_TX_OVERRIDE, 0x04}, //disable tx CRC
{CYRF_1E_RX_OVERRIDE, 0x14}, //disable rx crc
{CYRF_14_EOP_CTRL, 0x00}, //set EOP sync == 0
};
static void __attribute__((unused)) CYRF_GFSK1M_Init(uint8_t payload_length, uint8_t preamble_len)
{
for(uint8_t i = 0; i < sizeof(CYRF_GFSK1M_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&CYRF_GFSK1M_init_vals[i][0]), pgm_read_byte_near(&CYRF_GFSK1M_init_vals[i][1]));
CYRF_WriteRegister(CYRF_01_TX_LENGTH, payload_length);
CYRF_WritePreamble(0xAAAA00 | preamble_len);
CYRF_SetPower(0x00);
CYRF_SetTxRxMode(TX_EN);
}
static void __attribute__((unused)) CYRF_GFSK1M_SendPayload(uint8_t *buffer, uint8_t len)
{
uint8_t send=len>16 ? 16 : len;
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
CYRF_WriteRegisterMulti(CYRF_20_TX_BUFFER, buffer, send); // Fill the buffer with 16 bytes max
CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x80); // Start send
buffer += send;
len -= send;
while(len>8)
{
while((CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS)&0x10) == 0); // Wait that half of the buffer is empty
CYRF_WriteRegisterMulti(CYRF_20_TX_BUFFER, buffer, 8); // Add 8 bytes to the buffer
buffer+=8;
len-=8;
}
if(len)
{
while((CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS)&0x10) == 0); // Wait that half of the buffer is empty
CYRF_WriteRegisterMulti(CYRF_20_TX_BUFFER, buffer, len); // Add the remaining bytes to the buffer
}
}
#define CYRF_GFSK1M_SetPower() CYRF_SetPower(0x00)
#endif

View File

@@ -32,9 +32,15 @@ uint16_t convert_channel_ppm(uint8_t num)
}
// Channel value 100% is converted to 10bit values 0<->1023
uint16_t convert_channel_10b(uint8_t num)
uint16_t convert_channel_10b(uint8_t num, bool failsafe)
{
uint16_t val=Channel_data[num];
uint16_t val;
#ifdef FAILSAFE_ENABLE
if(failsafe)
val=Failsafe_data[num]; // 0<->2047
else
#endif
val=Channel_data[num];
val=((val<<2)+val)>>3;
if(val<=128) return 0;
if(val>=1152) return 1023;
@@ -91,9 +97,15 @@ int16_t convert_channel_16b_limit(uint8_t num,int16_t min,int16_t max)
}
// Channel value -125%<->125% is scaled to 16bit value with no limit
int16_t convert_channel_16b_nolimit(uint8_t num, int16_t min, int16_t max)
int16_t convert_channel_16b_nolimit(uint8_t num, int16_t min, int16_t max, bool failsafe)
{
int32_t val=Channel_data[num]; // 0<->2047
int32_t val;
#ifdef FAILSAFE_ENABLE
if(failsafe)
val=Failsafe_data[num]; // 0<->2047
else
#endif
val=Channel_data[num]; // 0<->2047
val=(val-CHANNEL_MIN_100)*(max-min)/(CHANNEL_MAX_100-CHANNEL_MIN_100)+min;
return (uint16_t)val;
}
@@ -151,14 +163,14 @@ static uint16_t __attribute__((unused)) FrSkyX_scaleForPXX( uint8_t i, uint8_t
}
#ifdef FAILSAFE_ENABLE
static uint16_t __attribute__((unused)) FrSkyX_scaleForPXX_FS( uint8_t i )
static uint16_t __attribute__((unused)) FrSkyX_scaleForPXX_FS( uint8_t i, uint8_t num_chan=8)
{ //mapped 1,2046(125%) range to 64,1984(PXX values);
uint16_t chan_val=((Failsafe_data[i]*15)>>4)+64;
if(Failsafe_data[i]==FAILSAFE_CHANNEL_NOPULSES)
chan_val=FAILSAFE_CHANNEL_NOPULSES;
else if(Failsafe_data[i]==FAILSAFE_CHANNEL_HOLD)
chan_val=FAILSAFE_CHANNEL_HOLD;
if(i>7) chan_val|=2048; // upper channels offset
if(i>=num_chan) chan_val|=2048; // upper channels offset
return chan_val;
}
#endif

View File

@@ -61,7 +61,6 @@ static void __attribute__((unused)) CORONA_rf_init()
CC2500_WriteReg(CC2500_15_DEVIATN, 0x50);
}
prev_option = option;
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
//not sure what they are doing to the PATABLE since basically only the first byte is used and it's only 8 bytes long. So I think they end up filling the PATABLE fully with 0xFF
@@ -72,7 +71,7 @@ static void __attribute__((unused)) CORONA_rf_init()
}
// Generate id and hopping freq
static void __attribute__((unused)) CORONA_init()
static void __attribute__((unused)) CORONA_TXID_init()
{
#ifdef CORONA_FORCE_ID
// Example of ID and channels taken from dumps
@@ -256,17 +255,13 @@ static uint16_t __attribute__((unused)) CORONA_build_packet()
return packet_period;
}
uint16_t ReadCORONA()
uint16_t CORONA_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(22000);
#endif
// Tune frequency if it has been changed
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
prev_option = option ;
}
CC2500_SetFreqOffset();
if(IS_BIND_IN_PROGRESS)
{
@@ -281,7 +276,7 @@ uint16_t ReadCORONA()
return packet_period;
}
uint16_t initCORONA()
void CORONA_init()
{
switch(sub_protocol)
{
@@ -298,9 +293,8 @@ uint16_t initCORONA()
state=400; // Used by V2 to send RF channels + ID for 2.65s at startup
hopping_frequency_no=0;
fdv3_id_send = 0;
CORONA_init();
CORONA_TXID_init();
CORONA_rf_init();
return 10000;
}
#endif

View File

@@ -16,7 +16,7 @@
#if defined(DM002_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_xn297.h"
#define DM002_PACKET_PERIOD 6100 // Timeout for callback in uSec
#define DM002_INITIAL_WAIT 500
@@ -24,7 +24,6 @@
#define DM002_RF_BIND_CHANNEL 0x27
#define DM002_BIND_COUNT 655 // 4 seconds
enum DM002_FLAGS {
// flags going to packet[9]
DM002_FLAG_FLIP = 0x01,
@@ -37,10 +36,10 @@ enum DM002_FLAGS {
DM002_FLAG_CAMERA2 = 0x80,
};
static void __attribute__((unused)) DM002_send_packet(uint8_t bind)
static void __attribute__((unused)) DM002_send_packet()
{
memcpy(packet+5,(uint8_t *)"\x00\x7F\x7F\x7F\x00\x00\x00",7);
if(bind)
if(IS_BIND_IN_PROGRESS)
{
packet[0] = 0xAA;
packet[1] = rx_tx_addr[0];
@@ -75,63 +74,40 @@ static void __attribute__((unused)) DM002_send_packet(uint8_t bind)
packet_count&=0x0F;
packet[10] = packet_count;
packet_count++;
XN297_Hopping(hopping_frequency_no);
}
//CRC
for(uint8_t i=0;i<DM002_PACKET_SIZE-1;i++)
packet[11]+=packet[i];
// Power on, TX mode, 2byte CRC
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
if (bind)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, DM002_RF_BIND_CHANNEL);
else
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
// clear packet status bits and TX FIFO
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
//Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, DM002_PACKET_SIZE);
NRF24L01_SetPower(); // Set tx_power
}
static void __attribute__((unused)) DM002_init()
static void __attribute__((unused)) DM002_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t *)"\x26\xA8\x67\x35\xCC", 5);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
XN297_RFChannel(DM002_RF_BIND_CHANNEL);
}
uint16_t DM002_callback()
{
if(IS_BIND_DONE)
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(DM002_PACKET_PERIOD);
#endif
DM002_send_packet(0);
}
else
#ifdef MULTI_SYNC
telemetry_set_input_sync(DM002_PACKET_PERIOD);
#endif
if (bind_counter)
{
bind_counter--;
if (bind_counter == 0)
{
BIND_DONE;
XN297_SetTXAddr(rx_tx_addr, 5);
}
else
{
DM002_send_packet(1);
bind_counter--;
}
}
DM002_send_packet();
return DM002_PACKET_PERIOD;
}
@@ -155,13 +131,12 @@ static void __attribute__((unused)) DM002_initialize_txid()
}
}
uint16_t initDM002(void)
void DM002_init(void)
{
BIND_IN_PROGRESS; // autobind protocol
bind_counter = DM002_BIND_COUNT;
DM002_initialize_txid();
DM002_init();
return DM002_INITIAL_WAIT;
DM002_RF_init();
}
#endif

180
Multiprotocol/DSM.ino Normal file
View File

@@ -0,0 +1,180 @@
#if defined(DSM_CYRF6936_INO) || defined(DSM_RX_CYRF6936_INO)
#include "iface_cyrf6936.h"
uint8_t sop_col;
const uint8_t PROGMEM DSM_pncodes[][8] = {
/* Note these are in order transmitted (LSB 1st) */
/* 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},
/* 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},
/* 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},
/* Row 4 */
/* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}, // Wrong values used by Orange TX/RX Row 3 Col 8: {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40}
/* 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},
/* 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}
};
static void __attribute__((unused)) DSM_read_code(uint8_t *buf, uint8_t row, uint8_t col)
{
row--;
if(row>4)
row = 4;
for(uint8_t i=0;i<8;i++)
buf[i]=pgm_read_byte_near( &DSM_pncodes[row*8+col][i] );
}
const uint8_t PROGMEM DSM_init_vals[][2] = {
{CYRF_02_TX_CTRL, 0x00}, // All TX interrupt disabled
{CYRF_05_RX_CTRL, 0x00}, // All RX interrupt disabled
{CYRF_28_CLK_EN, 0x02}, // Force receive clock enable
{CYRF_32_AUTO_CAL_TIME, 0x3c}, // Default init value
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
{CYRF_26_XTAL_CFG, 0x08}, // Start delay
{CYRF_06_RX_CFG, 0x4A}, // LNA enabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
{CYRF_1B_TX_OFFSET_LSB, 0x55}, // Default init value
{CYRF_1C_TX_OFFSET_MSB, 0x05}, // Default init value
{CYRF_39_ANALOG_CTRL, 0x01}, // All slow for synth setting time
{CYRF_01_TX_LENGTH, 0x10}, // 16 bytes packet
{CYRF_14_EOP_CTRL, 0x02}, // Set EOP Symbol Count to 2
{CYRF_12_DATA64_THOLD, 0x0a}, // 64 Chip Data PN corelator threshold, default datasheet value is 0x0E
//Below is for bind only
{CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //64 chip codes, SDR mode
{CYRF_10_FRAMING_CFG, 0x4a}, // SOP disabled, no LEN field and SOP correlator of 0x0a but since SOP is disabled...
{CYRF_1F_TX_OVERRIDE, 0x04}, // Disable TX CRC, no ACK, use TX synthesizer
{CYRF_1E_RX_OVERRIDE, 0x14}, // Disable RX CRC, Force receive data rate, use RX synthesizer
};
const uint8_t PROGMEM DSM_data_vals[][2] = {
{CYRF_29_RX_ABORT, 0x20}, // Abort RX operation in case we are coming from bind
{CYRF_0F_XACT_CFG, 0x24}, // Force Idle
{CYRF_29_RX_ABORT, 0x00}, // Clear abort RX
{CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER}, // 64 chip codes, 8DR mode
{CYRF_10_FRAMING_CFG, 0xea}, // SOP enabled, SOP_CODE_ADR 64 chips, Packet len enabled, SOP correlator 0x0A
{CYRF_1F_TX_OVERRIDE, 0x00}, // CRC16 enabled, no ACK
{CYRF_1E_RX_OVERRIDE, 0x00}, // CRC16 enabled, no ACK
};
static void __attribute__((unused)) DSM_cyrf_config()
{
for(uint8_t i = 0; i < sizeof(DSM_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&DSM_init_vals[i][0]), pgm_read_byte_near(&DSM_init_vals[i][1]));
CYRF_WritePreamble(0x333304);
}
static void __attribute__((unused)) DSM_cyrf_configdata()
{
for(uint8_t i = 0; i < sizeof(DSM_data_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&DSM_data_vals[i][0]), pgm_read_byte_near(&DSM_data_vals[i][1]));
}
static uint8_t __attribute__((unused)) DSM_get_pn_row(uint8_t channel, bool dsmx)
{
if(protocol == PROTO_DSM && sub_protocol == DSMR)
return (channel + 2) % 5;
return (dsmx ? (channel - 2) % 5 : channel % 5);
}
static void __attribute__((unused)) DSM_set_sop_data_crc(bool ch2, bool dsmx)
{
//The crc for channel '1' is NOT(mfgid[0] << 8 + mfgid[1])
//The crc for channel '2' is (mfgid[0] << 8 + mfgid[1])
if(ch2)
CYRF_ConfigCRCSeed(seed); //CH2
else
CYRF_ConfigCRCSeed(~seed); //CH1, DSMR only use CH1
uint8_t pn_row = DSM_get_pn_row(hopping_frequency[hopping_frequency_no], dsmx);
uint8_t code[16];
#if 0
debug_time();
debug(" crc:%04X,row:%d,col:%d,rf:%02X",(~seed)&0xffff,pn_row,sop_col,hopping_frequency[hopping_frequency_no]);
#endif
DSM_read_code(code,pn_row,sop_col); // pn_row between 0 and 4, sop_col between 0 and 7
CYRF_ConfigSOPCode(code);
DSM_read_code(code,pn_row,7 - sop_col); // 7-sop_col between 0 and 7
DSM_read_code(code+8,pn_row,7 - sop_col + 1); // 7-sop_col+1 between 1 and 8
CYRF_ConfigDataCode(code);
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,527 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(DSM_RX_CYRF6936_INO)
#include "iface_cyrf6936.h"
//#define DSM_DEBUG_RF
//#define DSM_DEBUG_CH
uint8_t DSM_rx_type;
enum {
DSM_RX_BIND1 = 0,
DSM_RX_BIND2,
DSM_RX_DATA_PREP,
DSM2_RX_SCAN,
DSM_RX_DATA_CH1,
DSM_RX_DATA_CH2,
};
static void __attribute__((unused)) DSM_RX_RF_init()
{
DSM_cyrf_config();
rx_disable_lna = IS_POWER_FLAG_on;
if(IS_BIND_IN_PROGRESS)
{
//64 SDR Mode is configured so only the 8 first values are needed but need to write 16 values...
uint8_t code[16];
DSM_read_code(code,0,8);
CYRF_ConfigDataCode(code);
CYRF_ConfigRFChannel(1);
CYRF_SetTxRxMode(RX_EN); // Force end state read
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive
}
else
{
DSM_cyrf_configdata();
CYRF_WriteRegister(CYRF_06_RX_CFG, rx_disable_lna ? 0x0A:0x4A); // AGC disabled, LNA disabled/enabled, Attenuator disabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
}
}
uint16_t convert_channel_DSM_nolimit(int32_t val)
{
val=(val-0x150)*(CHANNEL_MAX_100-CHANNEL_MIN_100)/(0x6B0-0x150)+CHANNEL_MIN_100;
if(val<0)
val=0;
else
if(val>2047)
val=2047;
return (uint16_t)val;
}
static uint8_t __attribute__((unused)) DSM_RX_check_packet()
{
uint8_t rx_status=CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_status & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
rx_status |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_status & 0x07) == 0x02)
{ // data received with no errors
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
#ifdef DSM_DEBUG_RF
debugln("l=%d",len);
#endif
if(len>=2 && len<=16)
{
// Read packet
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // Need to set RXOW before data read
CYRF_ReadDataPacketLen(packet, len);
// Check packet ID
if ((DSM_rx_type&0x80) == 0)
{//DSM2
packet[0] ^= 0xff;
packet[1] ^= 0xff;
}
#ifdef DSM_DEBUG_CH
for(uint8_t i=0;i<len;i++)
debug("%02X ",packet[i]);
debugln("");
#endif
if(packet[0] == cyrfmfg_id[2] && packet[1] == cyrfmfg_id[3])
return 0x02; // Packet ok
}
return 0x00; // Wrong size or ID -> nothing received
}
return rx_status; // Return error code
}
static void __attribute__((unused)) DSM_RX_build_telemetry_packet()
{
uint8_t nbr_bits = 11;
if((DSM_rx_type&0xF0) == 0x00)
nbr_bits=10; // Only DSM_22 is using a resolution of 1024
// Use packet length to calculate the number of channels
len -= 2; // Remove header length
len >>= 1; // Channels are on 2 bytes
if(len==0) return; // No channels...
// Extract channels
uint8_t idx;
for (uint8_t i = 0; i < len; i++)
{
uint16_t value=(packet[i*2+2]<<8) | packet[i*2+3];
if(value!=0xFFFF)
{
idx=(value&0x7FFF)>>nbr_bits; // retrieve channel index
#ifdef DSM_DEBUG_CH
debugln("i=%d,v=%d,u=%X",idx,value&0x7FF,value&0x8000);
#endif
if(idx<13)
{
if(nbr_bits==10) value <<= 1; // switch to 11 bits
value &= 0x7FF;
rx_rc_chan[CH_TAER[idx]]=convert_channel_DSM_nolimit(value);
}
}
}
// Buid telemetry packet
idx=0;
packet_in[idx++] = RX_LQI;
packet_in[idx++] = RX_LQI;
packet_in[idx++] = 0; // start channel
packet_in[idx++] = 12; // number of channels in packet
// Pack channels
uint32_t bits = 0;
uint8_t bitsavailable = 0;
for (uint8_t i = 0; i < 12; i++)
{
bits |= ((uint32_t)rx_rc_chan[i]) << bitsavailable;
bitsavailable += 11;
while (bitsavailable >= 8)
{
packet_in[idx++] = bits & 0xff;
bits >>= 8;
bitsavailable -= 8;
}
}
if(bitsavailable)
packet_in[idx++] = bits & 0xff;
// Send telemetry
telemetry_link = 1;
#ifdef SEND_CPPM
if(sub_protocol>0)
telemetry_link |= 0x80; // Disable telemetry output
#endif
}
static bool __attribute__((unused)) DSM_RX_bind_check_validity()
{
uint16_t sum = 384 - 0x10;//
for(uint8_t i = 0; i < 8; i++)
sum += packet_in[i];
if( packet_in[8] != (sum>>8) || packet_in[9] != (sum&0xFF)) //Checksum
return false;
for(uint8_t i = 8; i < 14; i++)
sum += packet_in[i];
if( packet_in[14] != (sum>>8) || packet_in[15] != (sum&0xFF)) //Checksum
return false;
if(memcmp(packet_in,packet_in+4,4)) //Check ID
return false;
return true;
}
static void __attribute__((unused)) DSM_RX_build_bind_packet()
{
uint16_t sum = 384 - 0x10;//
packet[0] = 0xff ^ cyrfmfg_id[0]; // ID
packet[1] = 0xff ^ cyrfmfg_id[1];
packet[2] = 0xff ^ cyrfmfg_id[2];
packet[3] = 0xff ^ cyrfmfg_id[3];
packet[4] = 0x01; // RX version
packet[5] = num_ch; // Number of channels
packet[6] = DSM_rx_type; // DSM type, let's just send back whatever the TX gave us...
packet[7] = 0x00; // Unknown
for(uint8_t i = 0; i < 8; i++)
sum += packet[i];
packet[8] = sum >> 8;
packet[9] = sum & 0xff;
}
static void __attribute__((unused)) DSM_abort_channel_rx(uint8_t ch)
{
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
CYRF_SetTxRxMode(IS_POWER_FLAG_on ? TXRX_OFF:RX_EN); // Force end state read
if (rx_disable_lna != IS_POWER_FLAG_on && IS_BIND_DONE)
{
rx_disable_lna = IS_POWER_FLAG_on;
CYRF_WriteRegister(CYRF_06_RX_CFG, rx_disable_lna ? 0x0A:0x4A); // AGC disabled, LNA disabled/enabled, Attenuator disabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
}
if(ch&0x02) DSM_set_sop_data_crc(true ,DSM_rx_type&0x80); // Set sop data,crc seed and rf channel using CH1, DSM2/X
if(ch&0x01) DSM_set_sop_data_crc(false,DSM_rx_type&0x80); // Set sop data,crc seed and rf channel using CH1, DSM2/X
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive
}
uint16_t DSM_RX_callback()
{
uint8_t rx_status;
static uint8_t read_retry=0;
if(sub_protocol == DSM_ERASE)
{
if(packet_count)
packet_count--;
else
BIND_DONE;
return 10000; // Nothing to do...
}
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++)
{
if (sub_protocol == DSM_CLONE && i == 3)
cyrfmfg_id[i]=(packet_in[i]^RX_num)^0xFF;
else
cyrfmfg_id[i]=packet_in[i]^0xFF;
eeprom_write_byte((EE_ADDR)temp++, cyrfmfg_id[i]);
debug(" %02X", cyrfmfg_id[i]);
}
// save num_ch
num_ch=packet_in[11];
// store DSM_rx_type
/*packet[12] 1 byte -> max DSM type allowed:
0x01 => 22ms 1024 DSM2 1 packet => number of channels is <8
0x02 => 22ms 1024 DSM2 2 packets => either a number of channel >7
0x12 => 11ms 2048 DSM2 2 packets => can be any number of channels
0x23 => DX3R DSM2 2 surface packets
0xA2 => 22ms 2048 DSMX 1 packet => number of channels is <8
0xB2 => 11ms 2048 DSMX => can be any number of channels
(0x01 or 0xA2) and num_ch < 7 => 22ms else 11ms
&0x80 => false=DSM2, true=DSMX
&0xF0 => false=1024, true=2048 */
DSM_rx_type=packet_in[12];
debugln(", num_ch=%d, type=%02X",num_ch, DSM_rx_type);
eeprom_write_byte((EE_ADDR)temp, DSM_rx_type);
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
CYRF_SetTxRxMode(TX_EN); // Force end state TX
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84");
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
//Copy clone values to EEPROM
if (sub_protocol == DSM_CLONE)
{
uint16_t temp = DSM_CLONE_EEPROM_OFFSET;
for(uint8_t i=0; i<4; i++)
eeprom_write_byte((EE_ADDR)temp++, cyrfmfg_id[i]);
eeprom_write_byte((EE_ADDR)temp, 0xF0);
}
}
break;
case DSM_RX_DATA_PREP:
hopping_frequency_no = 0;
read_retry=0;
rx_data_started = false;
pps_counter = 0;
RX_LQI = 100;
DSM_cyrf_configdata();
pps_timer=millis();
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
seed = (cyrfmfg_id[0] << 8) + cyrfmfg_id[1];
if(DSM_rx_type&0x80)
{ // DSMX
DSM_calc_dsmx_channel(); // Build hop table
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
phase=DSM_RX_DATA_CH1;
}
else
{ // DSM2
rf_ch_num=0;
hopping_frequency_no = 0;
hopping_frequency[0] = 3;
hopping_frequency[1] = 0;
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
phase=DSM2_RX_SCAN;
}
break;
case DSM2_RX_SCAN: // Scan for DSM2 frequencies
//Received something ?
rx_status = DSM_RX_check_packet();
if(rx_status == 0x02)
{ // data received with no errors
debugln("CH%d:Found %d",rf_ch_num+1,hopping_frequency[rf_ch_num]);
read_retry=0;
if(rf_ch_num)
{ // Both CH1 and CH2 found
read_retry=0;
hopping_frequency_no=0;
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
pps_timer=millis();
phase++; // DSM_RX_DATA_CH1
}
else
{
rf_ch_num++; // CH1 found, scan for CH2
hopping_frequency_no = 1;
if(hopping_frequency[1] < 3) // If no CH2 keep then restart from current
hopping_frequency[1]=hopping_frequency[0]+1;
DSM_abort_channel_rx(2); // Abort RX operation, set sop&data&seed&rf using CH2, DSM2/X and receive
}
}
else
{
read_retry++;
if(read_retry>50) // After 50ms
{ // Try next channel
debugln("CH%d:Next channel",rf_ch_num+1);
read_retry=0;
hopping_frequency_no = rf_ch_num;
hopping_frequency[rf_ch_num]++;
if(hopping_frequency[rf_ch_num] > 73) hopping_frequency[rf_ch_num] = 3;
DSM_abort_channel_rx(rf_ch_num+1); // Abort RX operation, set sop&data&seed&rf using CH1/2, DSM2/X and receive
}
else if(rx_status & 0x02)
{ // data received with errors
if((rx_status & 0x01) && rf_ch_num==0)
hopping_frequency[1] = hopping_frequency[0];// Might be CH2 since it's a CRC error so keep it
debugln("CH%d:RX error",rf_ch_num+1);
DSM_abort_channel_rx(0); // Abort RX operation and receive
}
}
return 1000;
case DSM_RX_DATA_CH1:
//Packets per second
if (millis() - pps_timer >= 1000)
{//182pps @11ms, 91pps @22ms
pps_timer = millis();
if(DSM_rx_type!=0xA2 && DSM_rx_type!=0x01) // if 11ms
pps_counter >>=1; // then /2
debugln("%d pps", pps_counter);
RX_LQI = pps_counter; // max=91pps
pps_counter = 0;
}
//Received something ?
rx_status = DSM_RX_check_packet();
if(rx_status == 0x02)
{ // data received with no errors
#ifdef DSM_DEBUG_RF
debugln("CH1:RX");
#endif
DSM_RX_build_telemetry_packet();
rx_data_started = true;
pps_counter++;
DSM_abort_channel_rx(2); // Abort RX operation, set sop&data&seed&rf using CH2, DSM2/X and receive
phase++;
return 5000;
}
else
{
read_retry++;
if(rx_data_started && read_retry>6) // After 6*500=3ms
{ // skip to CH2
#ifdef DSM_DEBUG_RF
debugln("CH1:Skip to CH2");
#endif
DSM_abort_channel_rx(2); // Abort RX operation, set sop&data&seed&rf using CH2, DSM2/X and receive
phase++;
return 4000;
}
if(rx_data_started && RX_LQI==0)
{ // communication lost
#ifdef DSM_DEBUG_RF
debugln("CH1:Restart...");
#endif
phase=DSM_RX_DATA_PREP;
return 1000;
}
if(read_retry>250)
{ // move to next RF channel
#ifdef DSM_DEBUG_RF
debugln("CH1:Scan");
#endif
DSM_abort_channel_rx(3); // Abort RX operation, set sop&data&seed&rf using CH2 then CH1, DSM2/X and receive
read_retry=0;
}
else if(rx_status & 0x02)
{ // data received with errors
#ifdef DSM_DEBUG_RF
debugln("CH1:RX error %02X",rx_status);
#endif
DSM_abort_channel_rx(0); // Abort RX operation and receive
}
}
return 500;
case DSM_RX_DATA_CH2:
rx_status = DSM_RX_check_packet();
if(rx_status == 0x02)
{ // data received with no errors
#ifdef DSM_DEBUG_RF
debugln("CH2:RX");
#endif
DSM_RX_build_telemetry_packet();
pps_counter++;
}
#ifdef DSM_DEBUG_RF
else
debugln("CH2:No RX");
#endif
DSM_abort_channel_rx(1); // Abort RX operation, set sop&data&seed&rf using CH1, DSM2/X and receive
read_retry=0;
phase=DSM_RX_DATA_CH1;
if(DSM_rx_type==0xA2) //|| DSM_rx_type==0x01 -> not needed for DSM2 since we are ok to listen even if there will be nothing
return 15000; //22ms
else
return 4000; //11ms
}
return 10000;
}
void DSM_RX_init()
{
DSM_RX_RF_init();
hopping_frequency_no = 0;
if (IS_BIND_IN_PROGRESS)
{
if(sub_protocol == DSM_ERASE)
{
// Clear all cloned addresses
uint16_t addr = DSM_CLONE_EEPROM_OFFSET;
for(uint8_t i=0; i<6; i++)
eeprom_write_byte((EE_ADDR)(addr++), 0xFF);
packet_count = 100;
}
else
{
packet_count=0;
phase = DSM_RX_BIND1;
}
}
else
{
uint16_t temp = DSM_RX_EEPROM_OFFSET;
if (sub_protocol == DSM_CLONE || sub_protocol == DSM_ERASE )
temp = DSM_CLONE_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)DSM_RX_EEPROM_OFFSET+4);
debugln(", type=%02X", DSM_rx_type);
phase = DSM_RX_DATA_PREP;
}
}
#endif

View File

@@ -17,11 +17,24 @@
#include "iface_cyrf6936.h"
#define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel
//#define DSM_DEBUG_FWD_PGM
//#define DEBUG_BIND 1
//During binding we will send BIND_COUNT/2 packets
#define CLONE_BIT_MASK 0x20
#define MODE_11MS_BIT_MASK 0x40
#define MAX_THROW_BIT_MASK 0x80
#define DSM_BIND_CHANNEL 0x0D //13 This can be any odd channel
#define DSM2_SFC_PERIOD 16500
//During binding we will send BIND_COUNT packets
//One packet each 10msec
#define DSM_BIND_COUNT 300
//
// Most RXs seems to work properly with a long BIND send count (3s): Spektrum, OrangeRX.
// Lemon-RX G2s seems to have a timeout waiting for the channel to get quiet after the
// first good BIND packet.. If using 3s (300), Lemon-RX will not transmit the BIND-Response packet.
#define DSM_BIND_COUNT 180 // About 1.8s
#define DSM_BIND_COUNT_READ 600 // About 4.2s of waiting for Response
enum {
DSM_BIND_WRITE=0,
@@ -40,11 +53,18 @@ enum {
DSM_CH2_READ_B,
};
#if defined(DSM_X_PLUS)
#define XP_CH CH13 // X-Plus channel placeholder in frame
uint8_t x_plus_ch = 0; // X-Plus channel currently multiplexing
#else
#define XP_CH 0xff // No Channel
#endif
//
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 +74,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, XP_CH, 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 +98,31 @@ static void __attribute__((unused)) DSM_build_bind_packet()
sum += packet[i];
packet[8] = sum >> 8;
packet[9] = sum & 0xff;
packet[10] = 0x01; //???
packet[11] = num_ch;
packet[10] = 0x01; // ???
if(sub_protocol==DSM_AUTO)
packet[11] = 12;
else
packet[11] = num_ch; // DX5 DSMR sends 0x48...
//packet[11] = 3; // DX3R
if (sub_protocol==DSM2_22)
packet[12]=num_ch<8?0x01:0x02; // DSM2/1024 1 or 2 packets depending on the number of channels
if(sub_protocol==DSM2_11)
packet[12]=0x12; // DSM2/2048 2 packets
if(sub_protocol==DSMX_22)
if (sub_protocol==DSMR)
packet[12] = 0xa2;
else if (sub_protocol==DSM2_SFC)
packet[12] = 0x23; // DX3R
else if (sub_protocol==DSM2_1F)
packet[12] = num_ch<8?0x01:0x02; // DSM2/1024 1 or 2 packets depending on the number of channels
else if(sub_protocol==DSM2_2F)
packet[12] = 0x12; // DSM2/2048 2 packets
else if(sub_protocol==DSMX_1F)
#if defined DSM_TELEMETRY
packet[12] = 0xb2; // DSMX/2048 2 packets
#else
packet[12] = num_ch<8? 0xa2 : 0xb2; // DSMX/2048 1 or 2 packets depending on the number of channels
#endif
if(sub_protocol==DSMX_11 || sub_protocol==DSM_AUTO) // Force DSMX/1024 in mode Auto
packet[12]=0xb2; // DSMX/1024 2 packets
packet[13] = 0x00; //???
else // DSMX_2F && DSM_AUTO
packet[12] = 0xb2; // DSMX/2048 2 packets
packet[13] = 0x00; //???
for(i = 8; i < 14; i++)
sum += packet[i];
packet[14] = sum >> 8;
@@ -214,30 +133,34 @@ 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);
CYRF_ConfigDataCode(code);
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=6; // Default to 6 channels if invalid choice...
#ifndef MULTI_AIR
if(sub_protocol==DSMR && num_ch>7)
num_ch=7; // Max 7 channels in DSMR
if(sub_protocol==DSM2_SFC && num_ch>5)
num_ch=5; // Max 5 channels in DSM2_SFC
#endif
// 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(idx > 9)
idx = 9;
if((option & MODE_11MS_BIT_MASK) && 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]);
}
@@ -245,37 +168,66 @@ static void __attribute__((unused)) DSM_update_channels()
static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
{
uint8_t bits = 11;
// Check if clone flag has changed
if((prev_option&CLONE_BIT_MASK) != (option&CLONE_BIT_MASK))
{
DSM_init();
prev_option^=CLONE_BIT_MASK;
}
if(prev_option!=option)
DSM_update_channels();
if (sub_protocol==DSMX_11 || sub_protocol==DSMX_22 )
{
if (sub_protocol==DSMX_2F || sub_protocol==DSMX_1F)
{//DSMX
packet[0] = cyrfmfg_id[2];
packet[1] = cyrfmfg_id[3];
}
else
{
{//DSM2 && DSMR
packet[0] = (0xff ^ cyrfmfg_id[2]);
packet[1] = (0xff ^ cyrfmfg_id[3]);
if(sub_protocol==DSM2_22)
bits=10; // Only DSM_22 is using a resolution of 1024
if(sub_protocol==DSM2_1F)
bits=10; // Only DSM2_1F is using a resolution of 1024
}
#ifdef DSM_THROTTLE_KILL_CH
#ifndef MULTI_AIR
if(sub_protocol == DSMR || sub_protocol == DSM2_SFC)
{ // 12 bits, full range, no reassignment
for (uint8_t i = 0; i < 7; i++)
{
uint16_t value = 0x0000;
if(i < num_ch)
{
value=Channel_data[i]<<1;
if(sub_protocol == DSM2_SFC)
value |= i<<12;
}
packet[i*2+2] = (value >> 8) & 0xff;
packet[i*2+3] = (value >> 0) & 0xff;
}
return;
}
#endif
#if defined(DSM_THROTTLE_KILL_CH)
uint16_t kill_ch=Channel_data[DSM_THROTTLE_KILL_CH-1];
#endif
for (uint8_t i = 0; i < 7; i++)
{
uint8_t idx = ch_map[(upper?7:0) + i];//1,5,2,3,0,4
uint16_t value = 0xffff;;
if (idx != 0xff)
uint8_t idx = ch_map[(upper?7:0) + i]; // 1,5,2,3,0,4
uint16_t value = 0xffff;
if((option & MODE_11MS_BIT_MASK) == 0 && num_ch < 8 && upper)
idx=0xff; // in 22ms do not transmit upper channels if <8, is it the right method???
else if (idx != 0xff)
{
/* Spektrum own remotes transmit normal values during bind and actually use this (e.g. Nano CP X) to
select the transmitter mode (e.g. computer vs non-computer radio), so always send normal output */
#ifdef DSM_THROTTLE_KILL_CH
if(idx==CH1 && kill_ch<=604)
#if defined(DSM_THROTTLE_KILL_CH)
if(idx==CH1 && kill_ch<=604 && num_ch<=12)
{//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;
@@ -283,85 +235,67 @@ 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
#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
{
#if defined(DSM_X_PLUS)
if (idx==XP_CH) { // X-Plus special channel placeholder
idx = XP_CH + x_plus_ch; // Encode CH13-CH16 instead
}
#endif
#ifdef DSM_MAX_THROW
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
#else
if(option & MAX_THROW_BIT_MASK)
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],0x156,0x6AA,false); // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on a DX8 G2 dump
#endif
}
#if defined(DSM_X_PLUS)
if (idx >= XP_CH) { // X-Plus Channel
// Multiplexing 4 chanels on the same frame channel placeholder for channel 13 (ID=12) over time (Refresh cycle 88ms)
// CH13-16 lower frame, and Ch17-20 upper. We only do lower right now, since MM cannot handle more than 16ch
// Channel value is 9 bits, and upper 2 bits is the X-Plus channel (CH13..CH16).
if(num_ch>12)
{
value >>= 2; // Convert to 9 bits
value |= (XP_CH << 11) | (x_plus_ch << 9); // constant 12 (4 bits), XPlus Ch (2 bits), Value (9 bits)
x_plus_ch = (x_plus_ch + 1) % 4; // only 0..3
}
else
value=convert_channel_16b_nolimit(CH_TAER[idx],0x150,0x6B0); // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on Redcon 6 channel DSM2 RX
#endif
if(bits==10) value>>=1;
value |= (upper && i==0 ? 0x8000 : 0) | (idx << bits);
value = 0xffff;
}
else
#endif
{ // Regular channel
if(bits==10) value>>=1;
value |= (upper && i==0 ? 0x8000 : 0) | (idx << bits);
}
}
packet[i*2+2] = (value >> 8) & 0xff;
packet[i*2+3] = (value >> 0) & 0xff;
packet[i*2+2] = value >> 8;
packet[i*2+3] = value;
}
}
static void __attribute__((unused)) DSM_set_sop_data_crc()
{
//The crc for channel '1' is NOT(mfgid[0] << 8 + mfgid[1])
//The crc for channel '2' is (mfgid[0] << 8 + mfgid[1])
uint16_t crc = (cyrfmfg_id[0] << 8) + cyrfmfg_id[1];
if(phase==DSM_CH1_CHECK_A||phase==DSM_CH1_CHECK_B)
CYRF_ConfigCRCSeed(crc); //CH2
else
CYRF_ConfigCRCSeed(~crc); //CH1
uint8_t pn_row = DSM_get_pn_row(hopping_frequency[hopping_frequency_no]);
uint8_t code[16];
DSM_read_code(code,pn_row,sop_col,8); // pn_row between 0 and 4, sop_col between 1 and 7
CYRF_ConfigSOPCode(code);
DSM_read_code(code,pn_row,7 - sop_col,8); // 7-sop_col between 0 and 6
DSM_read_code(code+8,pn_row,7 - sop_col + 1,8); // 7-sop_col+1 between 1 and 7
CYRF_ConfigDataCode(code, 16);
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
hopping_frequency_no++;
if(sub_protocol == DSMX_11 || sub_protocol == DSMX_22)
hopping_frequency_no %=23;
else
hopping_frequency_no %=2;
}
static void __attribute__((unused)) DSM_calc_dsmx_channel()
{
uint8_t idx = 0;
uint32_t id = ~(((uint32_t)cyrfmfg_id[0] << 24) | ((uint32_t)cyrfmfg_id[1] << 16) | ((uint32_t)cyrfmfg_id[2] << 8) | (cyrfmfg_id[3] << 0));
uint32_t id_tmp = id;
while(idx < 23)
{
uint8_t i;
uint8_t count_3_27 = 0, count_28_51 = 0, count_52_76 = 0;
id_tmp = id_tmp * 0x0019660D + 0x3C6EF35F; // Randomization
uint8_t next_ch = ((id_tmp >> 8) % 0x49) + 3; // Use least-significant byte and must be larger than 3
if ( (next_ch ^ cyrfmfg_id[3]) & 0x01 )
continue;
for (i = 0; i < idx; i++)
{
if(hopping_frequency[i] == next_ch)
break;
if(hopping_frequency[i] <= 27)
count_3_27++;
else
if (hopping_frequency[i] <= 51)
count_28_51++;
else
count_52_76++;
#ifdef DSM_FWD_PGM
if(upper==0 && DSM_SerialRX && (DSM_SerialRX_val[0]&0xF8)==0x70 )
{ // Send forward programming data if available
for(uint8_t i=0; i<(DSM_SerialRX_val[0]&0x07);i++)
{
packet[i*2+4]=0x70+i;
packet[i*2+5]=DSM_SerialRX_val[i+1];
}
DSM_SerialRX=false;
#ifdef DSM_DEBUG_FWD_PGM
debug("FWD=");
for(uint8_t i=4; i<16;i++)
debug(" %02X",packet[i]);
debugln("");
#endif
}
if (i != idx)
continue;
if ((next_ch < 28 && count_3_27 < 8)
||(next_ch >= 28 && next_ch < 52 && count_28_51 < 7)
||(next_ch >= 52 && count_52_76 < 8))
hopping_frequency[idx++] = next_ch;
}
#endif
}
static uint8_t __attribute__((unused)) DSM_Check_RX_packet()
{
uint8_t result=1; // assume good packet
uint8_t result=1; // assume good packet
uint16_t sum = 384 - 0x10;
for(uint8_t i = 1; i < 9; i++)
@@ -369,67 +303,98 @@ static uint8_t __attribute__((unused)) DSM_Check_RX_packet()
sum += packet_in[i];
if(i<5)
if(packet_in[i] != (0xff ^ cyrfmfg_id[i-1]))
result=0; // bad packet
result=0; // bad packet
}
if( packet_in[9] != (sum>>8) && packet_in[10] != (uint8_t)sum )
result=0;
return result;
}
uint16_t ReadDsm()
uint16_t DSM_callback()
{
#if defined MULTI_EU
if(sub_protocol == DSM2_1F || sub_protocol == DSM2_2F || sub_protocol == DSM2_SFC)
{
SUB_PROTO_INVALID;
return 11000;
}
#endif
#if defined MULTI_AIR
if(sub_protocol == DSMR || sub_protocol == DSM2_SFC)
{
SUB_PROTO_INVALID;
return 11000;
}
#endif
#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
#ifdef STM32_BOARD
#define DSM_WRITE_DELAY 1600 // Time after write to verify write complete
#define DSM_READ_DELAY 300 // Time before write to check read phase, and switch channels.
#else
#define DSM_WRITE_DELAY 1950 // Time after write to verify write complete
#define DSM_READ_DELAY 600 // Time before write to check read phase, and switch channels.
#endif
#define DSM_READ_DELAY 600 // Time before write to check read phase, and switch channels. Was 400 but 600 seems what the 328p needs to read a packet
#if defined DSM_TELEMETRY
uint8_t rx_phase;
uint8_t len;
uint8_t length;
#endif
uint8_t start;
//debugln("P=%d",phase);
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
#if DEBUG_BIND
debugln("Bind Check");
#endif
//64 SDR Mode is configured so only the 8 first values are needed
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84");
CYRF_SetTxRxMode(RX_EN); //Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //Prepare to receive
bind_counter=DSM_BIND_COUNT_READ; //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())
{
#if DEBUG_BIND
debug("Bind");
for(uint8_t i=0;i<10;i++)
debug(" %02X",packet_in[i+1]);
debugln("");
#endif
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 +406,10 @@ uint16_t ReadDsm()
}
if( --bind_counter == 0 )
{ // Exit if no answer has been received for some time
phase++; // DSM_CHANSEL
#if DEBUG_BIND
debugln("Bind Read TIMEOUT");
#endif
phase++; // DSM_CHANSEL
return 7000 ;
}
return 7000;
@@ -451,20 +419,45 @@ uint16_t ReadDsm()
DSM_cyrf_configdata();
CYRF_SetTxRxMode(TX_EN);
hopping_frequency_no = 0;
phase = DSM_CH1_WRITE_A; // in fact phase++
DSM_set_sop_data_crc();
phase = DSM_CH1_WRITE_A; // in fact phase++
#ifndef MULTI_AIR
if(sub_protocol == DSMR)
DSM_set_sop_data_crc(false, true);
else
#endif
DSM_set_sop_data_crc(true, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F); //prep CH1
return 10000;
case DSM_CH1_WRITE_A:
#ifdef MULTI_SYNC
telemetry_set_input_sync(11000); // Always request 11ms spacing even if we don't use half of it in 22ms mode
if(sub_protocol!=DSM2_SFC || option&0x40) // option&40 in this case is 16.5ms/11ms frame rate for DSM2_SFC
telemetry_set_input_sync(11000); // Always request 11ms spacing even if we don't use half of it in 22ms mode
else
telemetry_set_input_sync(DSM2_SFC_PERIOD);
#endif
#ifndef MULTI_AIR
if(sub_protocol == DSMR)
CYRF_SetPower(0x08); //Keep transmit power in sync
else
#endif
CYRF_SetPower(0x28); //Keep transmit power in sync
case DSM_CH1_WRITE_B:
DSM_build_data_packet(phase == DSM_CH1_WRITE_B); // build lower or upper channels
case DSM_CH2_WRITE_A:
case DSM_CH2_WRITE_B:
DSM_build_data_packet(phase == DSM_CH1_WRITE_B||phase == DSM_CH2_WRITE_B); // build lower or upper channels
CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags
CYRF_WriteDataPacket(packet);
phase++; // change from WRITE to CHECK mode
CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags
//debugln_time("");
#ifndef MULTI_AIR
if(sub_protocol==DSM2_SFC)
CYRF_WriteDataPacketLen(packet,2*(num_ch+1));
else
#endif
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:
case DSM_CH1_CHECK_B:
@@ -475,7 +468,7 @@ uint16_t ReadDsm()
if((CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80) == 0x00)
break;
if(phase==DSM_CH1_CHECK_A || phase==DSM_CH1_CHECK_B)
if((phase==DSM_CH1_CHECK_A || phase==DSM_CH1_CHECK_B) && sub_protocol!=DSMR)
{
#if defined DSM_TELEMETRY
// reset cyrf6936 if freezed after switching from TX to RX
@@ -487,35 +480,62 @@ uint16_t ReadDsm()
CYRF_SetTxRxMode(TX_EN);
}
#endif
DSM_set_sop_data_crc();
phase++; // change from CH1_CHECK to CH2_WRITE
DSM_set_sop_data_crc(true, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F); // prep CH2
phase++; // change from CH1_CHECK to CH2_WRITE
return DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY;
}
if (phase == DSM_CH2_CHECK_A)
CYRF_SetPower(0x28); //Keep transmit power in sync
#if defined DSM_TELEMETRY
phase++; // change from CH2_CHECK to CH2_READ
CYRF_SetTxRxMode(RX_EN); //Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
#ifndef MULTI_AIR
if(sub_protocol==DSMR || sub_protocol == DSM2_SFC)
{
phase = DSM_CH2_READ_B;
if(sub_protocol == DSM2_SFC)
{
if(option&0x40) // option&40 in this case is 16.5ms/11ms frame rate for DSM2_SFC
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
else
return DSM2_SFC_PERIOD - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
}
return 10900 - DSM_WRITE_DELAY - DSM_READ_DELAY; //Was 11000 but the SR6200A needs 10900 to report telemetry correctly
}
#endif
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
case DSM_CH2_READ_A:
case DSM_CH2_READ_B:
//Read telemetry
rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
//debug("ST1:%02X ",rx_phase);
if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
//debug("ST2:%02X ",rx_phase);
if((rx_phase & 0x07) == 0x02)
{ // good data (complete with no errors)
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
if(len>TELEMETRY_BUFFER_SIZE-2)
len=TELEMETRY_BUFFER_SIZE-2;
CYRF_ReadDataPacketLen(packet_in+1, len);
length=CYRF_ReadRegister(CYRF_09_RX_COUNT);
//debug("RX(%d)",length);
if(length>TELEMETRY_BUFFER_SIZE-2)
length=TELEMETRY_BUFFER_SIZE-2;
CYRF_ReadDataPacketLen(packet_in+1, length);
#ifdef DSM_DEBUG_FWD_PGM
//debug(" %02X", packet_in[1]);
if(packet_in[1]==9)
{
for(uint8_t i=0;i<length;i++)
debug(" %02X", packet_in[i+1]);
debugln("");
}
#endif
packet_in[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;// store RSSI of the received telemetry signal
//for(uint8_t i=0;i<length+1;i++)
// debug(" %02X", packet_in[i]);
telemetry_link=1;
}
//debugln("");
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
if (phase == DSM_CH2_READ_A && (sub_protocol==DSM2_22 || sub_protocol==DSMX_22) && num_ch < 8) // 22ms mode
if (phase == DSM_CH2_READ_A && (sub_protocol==DSM2_1F || sub_protocol==DSMX_1F) && num_ch < 8) // 22ms mode
{
CYRF_SetTxRxMode(RX_EN); // Force end state read
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
@@ -529,18 +549,27 @@ uint16_t ReadDsm()
phase = DSM_CH1_WRITE_A; //Transmit lower
CYRF_SetTxRxMode(TX_EN); //TX mode
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); //Clear abort RX operation
DSM_set_sop_data_crc();
DSM_set_sop_data_crc(false, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F||sub_protocol==DSMR);
return DSM_READ_DELAY;
#else
// No telemetry
DSM_set_sop_data_crc();
DSM_set_sop_data_crc(phase==DSM_CH1_CHECK_A||phase==DSM_CH1_CHECK_B, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F);
if (phase == DSM_CH2_CHECK_A)
{
if(num_ch > 7 || sub_protocol==DSM2_11 || sub_protocol==DSMX_11)
if(num_ch > 7 || sub_protocol==DSM2_2F || sub_protocol==DSMX_2F)
phase = DSM_CH1_WRITE_B; //11ms mode or upper to transmit change from CH2_CHECK_A to CH1_WRITE_A
else
{ //Normal mode 22ms
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
#ifndef MULTI_AIR
if(sub_protocol==DSM2_SFC)
{
if(option&0x40) // option&40 in this case is 16.5ms/11ms frame rate for DSM2_SFC
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
else
return DSM2_SFC_PERIOD - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
}
#endif
return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
}
}
@@ -552,26 +581,110 @@ uint16_t ReadDsm()
return 0;
}
uint16_t initDsm()
#ifndef MULTI_AIR
const uint8_t PROGMEM DSMR_ID_FREQ[][4 + 23] = {
{ 0x71, 0x74, 0x1c, 0xe4, 0x11, 0x2f, 0x17, 0x3d, 0x23, 0x3b, 0x0f, 0x21, 0x25, 0x49, 0x1d, 0x13, 0x4d, 0x1f, 0x41, 0x4b, 0x47, 0x05, 0x27, 0x15, 0x19, 0x3f, 0x07 },
{ 0xfe, 0xfe, 0xfe, 0xfe, 0x45, 0x31, 0x33, 0x4b, 0x11, 0x29, 0x49, 0x3f, 0x09, 0x13, 0x47, 0x21, 0x1d, 0x43, 0x1f, 0x05, 0x41, 0x19, 0x1b, 0x2d, 0x15, 0x4d, 0x0f },
{ 0xfe, 0xff, 0xff, 0xff, 0x2a, 0x06, 0x22, 0x28, 0x16, 0x24, 0x38, 0x0e, 0x32, 0x2e, 0x14, 0x3a, 0x04, 0x44, 0x0c, 0x42, 0x1c, 0x4a, 0x10, 0x36, 0x3c, 0x48, 0x26 },
{ 0xff, 0xfe, 0xff, 0xff, 0x28, 0x34, 0x48, 0x46, 0x3a, 0x12, 0x18, 0x32, 0x14, 0x42, 0x16, 0x40, 0x22, 0x44, 0x1c, 0x0a, 0x36, 0x20, 0x10, 0x0c, 0x3c, 0x26, 0x2e },
{ 0xff, 0xff, 0xfe, 0xff, 0x3c, 0x16, 0x04, 0x48, 0x1e, 0x4a, 0x10, 0x18, 0x22, 0x28, 0x38, 0x40, 0x20, 0x06, 0x3e, 0x42, 0x30, 0x1a, 0x2c, 0x1c, 0x46, 0x14, 0x34 },
{ 0xff, 0xff, 0xff, 0xfe, 0x4d, 0x39, 0x1b, 0x13, 0x45, 0x2f, 0x0d, 0x3d, 0x0b, 0x11, 0x47, 0x2d, 0x19, 0x1d, 0x23, 0x35, 0x33, 0x3b, 0x21, 0x31, 0x17, 0x0f, 0x43 },
{ 0xff, 0xff, 0xff, 0xff, 0x14, 0x28, 0x2e, 0x32, 0x3e, 0x10, 0x38, 0x0e, 0x12, 0x06, 0x2c, 0x26, 0x30, 0x4c, 0x34, 0x16, 0x04, 0x3a, 0x42, 0x48, 0x36, 0x46, 0x1a },
{ 0x00, 0xff, 0xff, 0xff, 0x3e, 0x30, 0x42, 0x24, 0x06, 0x0e, 0x14, 0x1c, 0x08, 0x10, 0x20, 0x22, 0x04, 0x32, 0x0c, 0x44, 0x3c, 0x46, 0x4a, 0x26, 0x4c, 0x48, 0x1e },
{ 0xff, 0x00, 0xff, 0xff, 0x38, 0x0e, 0x22, 0x2a, 0x44, 0x3a, 0x4a, 0x3e, 0x16, 0x20, 0x36, 0x24, 0x46, 0x18, 0x1e, 0x12, 0x1c, 0x30, 0x2c, 0x14, 0x06, 0x0c, 0x40 },
{ 0x00, 0x00, 0xff, 0xff, 0x06, 0x4c, 0x26, 0x08, 0x46, 0x3e, 0x30, 0x12, 0x38, 0x1c, 0x04, 0x4a, 0x2c, 0x1a, 0x20, 0x3a, 0x18, 0x36, 0x28, 0x2e, 0x22, 0x40, 0x10 },
{ 0xff, 0xff, 0x00, 0xff, 0x12, 0x06, 0x3c, 0x2a, 0x22, 0x38, 0x48, 0x4c, 0x32, 0x44, 0x26, 0x16, 0x0c, 0x28, 0x2c, 0x36, 0x1c, 0x1a, 0x42, 0x10, 0x08, 0x4a, 0x34 },
{ 0x00, 0xff, 0x00, 0xff, 0x04, 0x4c, 0x4a, 0x28, 0x2a, 0x24, 0x14, 0x1e, 0x40, 0x48, 0x44, 0x2c, 0x2e, 0x1a, 0x12, 0x46, 0x3a, 0x0e, 0x18, 0x1c, 0x20, 0x10, 0x42 },
{ 0xff, 0x00, 0x00, 0xff, 0x06, 0x10, 0x14, 0x16, 0x48, 0x18, 0x44, 0x2c, 0x0a, 0x26, 0x24, 0x42, 0x36, 0x30, 0x38, 0x3e, 0x0c, 0x3c, 0x34, 0x46, 0x2a, 0x32, 0x0e },
{ 0x00, 0x00, 0x00, 0xff, 0x2c, 0x0a, 0x46, 0x28, 0x38, 0x24, 0x14, 0x06, 0x04, 0x10, 0x18, 0x30, 0x12, 0x20, 0x3a, 0x1a, 0x32, 0x3c, 0x3e, 0x4a, 0x1e, 0x44, 0x36 },
{ 0x00, 0x00, 0x00, 0x00, 0x45, 0x23, 0x07, 0x37, 0x4b, 0x13, 0x3d, 0x31, 0x19, 0x2b, 0x2f, 0x2d, 0x1f, 0x4d, 0x3f, 0x1b, 0x43, 0x27, 0x3b, 0x11, 0x05, 0x0d, 0x17 },
{ 0xff, 0xff, 0xff, 0x00, 0x0b, 0x4b, 0x1d, 0x39, 0x09, 0x0f, 0x49, 0x25, 0x07, 0x35, 0x3b, 0x05, 0x33, 0x17, 0x2d, 0x11, 0x2b, 0x29, 0x1f, 0x45, 0x1b, 0x41, 0x47 },
{ 0x00, 0xff, 0xff, 0x00, 0x41, 0x35, 0x11, 0x25, 0x29, 0x27, 0x33, 0x47, 0x4d, 0x31, 0x05, 0x37, 0x15, 0x1f, 0x23, 0x07, 0x1b, 0x0f, 0x3b, 0x49, 0x19, 0x3f, 0x0b },
{ 0xff, 0x00, 0xff, 0x00, 0x25, 0x47, 0x05, 0x0b, 0x45, 0x1f, 0x2b, 0x27, 0x2d, 0x09, 0x07, 0x43, 0x49, 0x29, 0x4d, 0x39, 0x33, 0x41, 0x17, 0x0f, 0x15, 0x19, 0x3b },
{ 0x00, 0x00, 0xff, 0x00, 0x3b, 0x05, 0x21, 0x0d, 0x1b, 0x43, 0x17, 0x2d, 0x1d, 0x25, 0x4b, 0x35, 0x4d, 0x3f, 0x07, 0x09, 0x37, 0x41, 0x15, 0x1f, 0x0f, 0x27, 0x29 },
{ 0xff, 0xff, 0x00, 0x00, 0x2b, 0x35, 0x1b, 0x1d, 0x0f, 0x47, 0x09, 0x0d, 0x45, 0x41, 0x21, 0x11, 0x2f, 0x43, 0x27, 0x33, 0x4b, 0x37, 0x13, 0x19, 0x4d, 0x23, 0x17 },
{ 0x00, 0xff, 0x00, 0x00, 0x1b, 0x1d, 0x33, 0x13, 0x2b, 0x27, 0x09, 0x41, 0x25, 0x17, 0x19, 0x2d, 0x4b, 0x37, 0x45, 0x11, 0x21, 0x0d, 0x3d, 0x4d, 0x07, 0x39, 0x43 },
{ 0xff, 0x00, 0x00, 0x00, 0x37, 0x27, 0x43, 0x4b, 0x39, 0x13, 0x07, 0x0d, 0x25, 0x17, 0x29, 0x1b, 0x1d, 0x45, 0x19, 0x2d, 0x0b, 0x3d, 0x15, 0x47, 0x1f, 0x21, 0x4d } };
#endif
void DSM_init()
{
CYRF_GetMfgData(cyrfmfg_id);
//Model match
cyrfmfg_id[3]^=RX_num;
if(sub_protocol == DSMR)
{
#ifndef MULTI_AIR
if(option&CLONE_BIT_MASK)
SUB_PROTO_INVALID;
else
{
//SUB_PROTO_VALID;
uint8_t row = rx_tx_addr[3]%22;
for(uint8_t i=0; i< 4; i++)
cyrfmfg_id[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i]);
for(uint8_t i=0; i< 23; i++)
hopping_frequency[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i+4]);
}
#endif
}
else
{
if(option&CLONE_BIT_MASK)
{
if(eeprom_read_byte((EE_ADDR)DSM_CLONE_EEPROM_OFFSET+4)==0xF0)
{
//read cloned ID from EEPROM
uint16_t temp = DSM_CLONE_EEPROM_OFFSET;
for(uint8_t i=0;i<4;i++)
cyrfmfg_id[i] = eeprom_read_byte((EE_ADDR)temp++);
cyrfmfg_id[3]^=RX_num; //Model match
#if DEBUG_BIND
debugln("Using cloned ID");
debug("Clone ID=")
for(uint8_t i=0;i<4;i++)
debug("%02x ", cyrfmfg_id[i]);
debugln("");
#endif
}
else
{
SUB_PROTO_INVALID;
#if DEBUG_BIND
debugln("No valid cloned ID");
#endif
}
}
else
{
//SUB_PROTO_VALID;
CYRF_GetMfgData(cyrfmfg_id);
cyrfmfg_id[3]^=RX_num; //Model match
}
}
//Calc sop_col
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
//Fix for OrangeRX using wrong DSM_pncodes by preventing access to "Col 8"
if(sop_col==0)
{
cyrfmfg_id[rx_tx_addr[0]%3]^=0x01; //Change a bit so sop_col will be different from 0
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
//We cannot manipulate the ID if we are cloning
if(!(option&CLONE_BIT_MASK))
{
//Fix for OrangeRX using wrong DSM_pncodes by preventing access to "Col 8"
if(sop_col==0 && sub_protocol != DSMR)
{
cyrfmfg_id[rx_tx_addr[0]%3]^=0x01; //Change a bit so sop_col will be different from 0
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
}
}
//Calc CRC seed
seed = (cyrfmfg_id[0] << 8) + cyrfmfg_id[1];
//Hopping frequencies
if (sub_protocol == DSMX_11 || sub_protocol == DSMX_22)
if (sub_protocol == DSMX_2F || sub_protocol == DSMX_1F)
DSM_calc_dsmx_channel();
else
else if(sub_protocol != DSMR)
{
uint8_t tmpch[10];
CYRF_FindBestChannels(tmpch, 10, 5, 3, 75);
CYRF_FindBestChannels(tmpch, 10, 5, 3, 75, FIND_CHANNEL_ANY);
//
uint8_t idx = random(0xfefefefe) % 10;
hopping_frequency[0] = tmpch[idx];
@@ -583,6 +696,7 @@ uint16_t initDsm()
}
hopping_frequency[1] = tmpch[idx];
}
//
DSM_cyrf_config();
CYRF_SetTxRxMode(TX_EN);
@@ -594,10 +708,12 @@ uint16_t initDsm()
DSM_initialize_bind_phase();
phase = DSM_BIND_WRITE;
bind_counter=DSM_BIND_COUNT;
#if DEBUG_BIND
debugln("Bind Started: write count=%d",bind_counter);
#endif
}
else
phase = DSM_CHANSEL;//
return 10000;
phase = DSM_CHANSEL;
}
#endif

View File

@@ -55,14 +55,14 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix()
{
uint8_t bind_state;
#ifdef ENABLE_PPM
if(mode_select && option==0 && IS_BIND_DONE) //PPM mode and option not already set and bind is finished
if(mode_select && (option&0x01)==0 && IS_BIND_DONE) //PPM mode and option not already set and bind is finished
{
BIND_SET_INPUT;
BIND_SET_PULLUP; // set pullup
if(IS_BIND_BUTTON_on)
{
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num),0x01); // Set fixed id mode for the current model
option=1;
option |= 0x01;
}
BIND_SET_OUTPUT;
}
@@ -72,7 +72,7 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix()
MProtocol_id = RX_num + MProtocol_id_master;
bind_counter=DEVO_BIND_COUNT;
}
if (option)
if (option&0x01)
{
if (bind_counter > 0)
bind_state = 0xc0;
@@ -146,7 +146,7 @@ static void __attribute__((unused)) DEVO_build_data_pkt()
uint8_t sign = 0x0b;
for (uint8_t i = 0; i < 4; i++)
{
int16_t value=convert_channel_16b_nolimit(CH_EATR[ch_idx * 4 + i],-1600,1600);//range -1600..+1600
int16_t value=convert_channel_16b_nolimit(CH_EATR[ch_idx * 4 + i],-1600,1600,false);//range -1600..+1600
if(value < 0)
{
value = -value;
@@ -162,6 +162,165 @@ static void __attribute__((unused)) DEVO_build_data_pkt()
DEVO_add_pkt_suffix();
}
#if defined DEVO_HUB_TELEMETRY
static uint32_t __attribute__((unused)) DEVO_text_to_int(uint8_t *ptr, uint8_t len)
{
uint32_t value = 0;
for(uint8_t i = 0; i < len; i++)
value = value * 10 + (ptr[i] - '0');
return value;
}
static void __attribute__((unused)) DEVO_float_to_ints(uint8_t *ptr, uint16_t *value, uint16_t *decimal)
{
bool seen_decimal = false;
*value = 0;
*decimal = 0;
for(uint8_t i = 0; i < 7; i++)
{
if(ptr[i] == '.')
{
seen_decimal = true;
continue;
}
if(ptr[i] < '0' || ptr[i] > '9')
{
if(*value != 0 || seen_decimal)
return;
}
else
{
if(seen_decimal)
*decimal = *decimal * 10 + (ptr[i] - '0');
else
*value = *value * 10 + (ptr[i] - '0');
}
}
}
static void __attribute__((unused)) DEVO_parse_telemetry_packet()
{ // Telemetry packets every 2.4ms
DEVO_scramble_pkt(); //This will unscramble the packet
debugln("RX");
if ((((uint32_t)packet[15] << 16) | ((uint32_t)packet[14] << 8) | packet[13]) != (MProtocol_id & 0x00ffffff))
return; // ID does not match
if((telemetry_link & 3) != 0)
{
debugln("S%d",telemetry_link);
return; // Previous telemetry not sent yet...
}
//Debug telem RX
//for(uint8_t i=0;i<12;i++)
// debug("%02X ",packet[i]);
//debugln("");
#if defined HUB_TELEMETRY
//Telemetry https://github.com/DeviationTX/deviation/blob/5efb6a28bea697af9a61b5a0ed2528cc8d203f90/src/protocol/devo_cyrf6936.c#L232
uint16_t val, dec;
uint32_t val32;
switch(packet[0])
{
case 0x30: // Volt and RPM packet
//RSSI and voltage
TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI) & 0x1F;
TX_RSSI = (TX_RSSI << 1) + TX_RSSI;
RX_RSSI = TX_RSSI;
telemetry_link |= 1;
v_lipo1 = packet[1] << 1;
v_lipo2 = packet[3] << 1;
//packet[5] = 127; // 12.7V
if(packet[5] != 0)
{
val = (packet[5]*11)/21; // OpenTX strange transformation??
dec = val;
val /= 10;
dec -= val*10;
frsky_send_user_frame(0x3A, val, 0x00); // volt3
frsky_send_user_frame(0x3B, dec, 0x00); // volt3
}
val = packet[7] * 120; // change to RPM
frsky_send_user_frame(0x03, val, val>>8); // RPM
break;
case 0x31: // Temperature packet
//memcpy(&packet[1],"\x29\x2A\x2B\x00\x00\x00\x00\x00\x00\x00\x00\x00",12); // 21°, 22°, 23°
for(uint8_t i=0; i<2;i++)
if(packet[i+1]!=0xff)
{
val = packet[i+1];
val -= 20;
frsky_send_user_frame(0x02 + i*3, val, val>>8); // temp 1 & 2
}
break;
// GPS Data
case 0x32: // Longitude
//memcpy(&packet[1],"\x30\x33\x30\x32\x30\x2e\x38\x32\x37\x30\x45\xfb",12); // 030°20.8270E in ddmm.mmmm
//memcpy(&packet[1],"\x31\x31\x37\x31\x31\x2e\x35\x39\x34\x37\x57\xfb",12); // RX705 sends 117°11.5947W which should be 11706.95685W in ddmm.mmmm
val = DEVO_text_to_int(&packet[1], 3)*100; // dd00
val32 = DEVO_text_to_int(&packet[4], 2) * 10000 + DEVO_text_to_int(&packet[7], 4); // mmmmmm
if(option&0x02) // if RX705 GPS format
val32 = (val32*3)/5; // then * 6/10 correction
dec = val32/10000;
val = val + dec; // dddmm
frsky_send_user_frame(0x12 , val, val>>8);
val = val32 - dec*10000; // .mmmm
frsky_send_user_frame(0x12+8, val, val>>8);
frsky_send_user_frame(0x1A+8, packet[11], 0x00); // 'E'/'W'
break;
case 0x33: // Latitude
//memcpy(&packet[1],"\x35\x39\x35\x34\x2e\x37\x37\x37\x36\x4e\x07\x00",12); // 59°54.776N in ddmm.mmmm
//memcpy(&packet[1],"\x31\x37\x31\x31\x2e\x35\x39\x34\x37\x4e\xfb\x00",12); // RX705 sends 17°11.5947N which should be 1706.95685N in ddmm.mmmm
val = DEVO_text_to_int(&packet[1], 2)*100; // dd00
val32 = DEVO_text_to_int(&packet[3], 2) * 10000 + DEVO_text_to_int(&packet[6], 4); // mmmmmm
if(option&0x02) // if RX705 GPS format
val32 = (val32*3)/5; // then * 6/10 correction
dec = val32/10000;
val = val + dec; // dddmm
frsky_send_user_frame(0x13 , val, val>>8);
val = val32 - dec*10000; // .mmmm
frsky_send_user_frame(0x13+8, val, val>>8);
frsky_send_user_frame(0x1B+8, packet[10], 0x00); // 'N'/'S'
break;
case 0x34: // Altitude
//memcpy(&packet[1],"\x31\x32\x2e\x38\x00\x00\x00\x4d\x4d\x4e\x45\xfb",12); // 12.8 MMNE
DEVO_float_to_ints(&packet[1], &val, &dec);
frsky_send_user_frame(0x10, val, val>>8);
frsky_send_user_frame(0x21, dec, dec>>8);
break;
case 0x35: // Speed
//memcpy(&packet[1],"\x00\x00\x00\x00\x00\x00\x30\x2e\x30\x30\x00\x00",12); // 0.0
DEVO_float_to_ints(&packet[1], &val, &dec);
frsky_send_user_frame(0x11 , val, val>>8);
frsky_send_user_frame(0x11+8, dec, dec>>8);
break;
case 0x36: // Time
//memcpy(&packet[1],"\x31\x38\x32\x35\x35\x32\x31\x35\x31\x30\x31\x32",12); // "182552151012" = 2012-10-15 18:25:52 (UTC)
if(packet[1]!=0)
{
frsky_send_user_frame(0x15, DEVO_text_to_int(&packet[9], 2), DEVO_text_to_int(&packet[7], 2)); // month, day
val = 2000 + DEVO_text_to_int(&packet[11], 2); // year
frsky_send_user_frame(0x16, val, val>>8);
frsky_send_user_frame(0x17, DEVO_text_to_int(&packet[1], 2), DEVO_text_to_int(&packet[3], 2)); // hour, min
frsky_send_user_frame(0x18, DEVO_text_to_int(&packet[5], 2), 0x00); // second
}
break;
}
#else
if(packet[0] == 0x30)
{
TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI) & 0x1F;
TX_RSSI = (TX_RSSI << 1) + TX_RSSI;
RX_RSSI = TX_RSSI;
telemetry_link |= 1;
v_lipo1 = packet[1] << 1;
v_lipo2 = packet[3] << 1;
}
#endif
}
#endif
static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code()
{
/* crc == 0 isn't allowed, so use 1 if the math results in 0 */
@@ -206,7 +365,7 @@ static void __attribute__((unused)) DEVO_cyrf_init()
static void __attribute__((unused)) DEVO_set_radio_channels()
{
CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80);
CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80, FIND_CHANNEL_ANY);
hopping_frequency[3] = hopping_frequency[0];
hopping_frequency[4] = hopping_frequency[1];
}
@@ -267,9 +426,85 @@ static void __attribute__((unused)) DEVO_BuildPacket()
packet_count = 0;
}
uint16_t devo_callback()
uint16_t DEVO_callback()
{
static uint8_t txState=0;
#if defined DEVO_HUB_TELEMETRY
int delay;
if (txState == 0)
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(2400);
#endif
DEVO_BuildPacket();
CYRF_WriteDataPacket(packet);
txState = 1;
return 900;
}
if (txState == 1)
{
int i = 0;
uint8_t reg;
while (! ((reg = CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS)) & 0x02))
{
if (++i >= DEVO_NUM_WAIT_LOOPS)
break;
}
if (((reg & 0x22) == 0x20) || (CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80))
{
CYRF_Reset();
DEVO_cyrf_init();
DEVO_cyrf_set_bound_sop_code();
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
//printf("Rst CYRF\n");
delay = 1500;
txState = 15;
}
else
{
if (phase == DEVO_BOUND)
{
/* exit binding state */
phase = DEVO_BOUND_3;
DEVO_cyrf_set_bound_sop_code();
}
if((packet_count != 0) && (bind_counter == 0))
{
CYRF_SetTxRxMode(RX_EN); //Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
txState = 2;
return 1300;
}
}
if(packet_count == 0)
{
CYRF_SetPower(0x08); //Keep tx power updated
hopping_frequency_ptr = hopping_frequency_ptr == &hopping_frequency[2] ? hopping_frequency : hopping_frequency_ptr + 1;
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
}
delay = 1500;
}
if(txState == 2)
{
uint8_t rx_state = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((rx_state & 0x03) == 0x02)
{ // RXC=1, RXE=0 then 2nd check is required (debouncing)
rx_state |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
}
if((rx_state & 0x07) == 0x02)
{ // good data (complete with no errors)
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
CYRF_ReadDataPacketLen(packet, CYRF_ReadRegister(CYRF_09_RX_COUNT));
DEVO_parse_telemetry_packet();
}
CYRF_SetTxRxMode(TX_EN); //Write mode
delay = 200;
}
txState = 0;
return delay;
#else
if (txState == 0)
{
#ifdef MULTI_SYNC
@@ -298,10 +533,26 @@ uint16_t devo_callback()
CYRF_ConfigRFChannel(*hopping_frequency_ptr);
}
return 1200;
#endif
}
uint16_t DevoInit()
void DEVO_init()
{
#ifdef ENABLE_PPM
if(mode_select) //PPM mode
{
if(IS_BIND_BUTTON_FLAG_on)
{
option &= 0xFE;
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num),option); // reset to autobind mode for the current model
}
else
{
option=eeprom_read_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num)); // load previous mode: autobind or fixed id
if(option > 3) option = 0; // if invalid then it should be autobind
}
}
#endif //ENABLE_PPM
switch(sub_protocol)
{
case 1:
@@ -332,8 +583,13 @@ uint16_t DevoInit()
packet_count = 0;
prev_option=option;
if(option==0)
if(option&0x01)
{
phase = DEVO_BOUND_1;
bind_counter = 0;
DEVO_cyrf_set_bound_sop_code();
}
else
{
MProtocol_id = ((uint32_t)(hopping_frequency[0] ^ cyrfmfg_id[0] ^ cyrfmfg_id[3]) << 16)
| ((uint32_t)(hopping_frequency[1] ^ cyrfmfg_id[1] ^ cyrfmfg_id[4]) << 8)
@@ -343,13 +599,6 @@ uint16_t DevoInit()
phase = DEVO_BIND;
BIND_IN_PROGRESS;
}
else
{
phase = DEVO_BOUND_1;
bind_counter = 0;
DEVO_cyrf_set_bound_sop_code();
}
return 2400;
}
#endif

View File

@@ -0,0 +1,151 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(E010R5_CYRF6936_INO)
#include "iface_rf2500.h"
#define E010R5_FORCE_ID
#define E010R5_PAYLOAD_SIZE 14
static void __attribute__((unused)) E010R5_build_data_packet()
{
packet[ 0] = 0x0D; // Packet length
packet[ 1] = convert_channel_8b(THROTTLE);
packet[ 2] = convert_channel_s8b(RUDDER);
packet[ 3] = convert_channel_s8b(ELEVATOR);
packet[ 4] = convert_channel_s8b(AILERON);
packet[ 5] = 0x20; // Trim Rudder
packet[ 6] = 0x20; // Trim Elevator
packet[ 7] = 0x20; // Trim Aileron
packet[ 8] = 0x01 // Flags: high=0x01, low=0x00
| GET_FLAG(CH5_SW, 0x04) // flip=0x04
| GET_FLAG(CH6_SW, 0x08) // led=0x08
| GET_FLAG(CH8_SW, 0x10) // headless=0x10
| GET_FLAG(CH9_SW, 0x20); // one key return=0x20
packet[ 9] = IS_BIND_IN_PROGRESS ? 0x80 : 0x00 // Flags: bind=0x80
| GET_FLAG(CH7_SW, 0x20) // calib=0x20
| GET_FLAG(CH10_SW, 0x01); // strange effect=0x01=long press on right button
packet[10] = rx_tx_addr[0];
packet[11] = rx_tx_addr[1];
packet[12] = rx_tx_addr[2];
packet[13] = 0x9D; // Check
for(uint8_t i=0;i<13;i++)
packet[13] += packet[i];
RF2500_BuildPayload(packet);
}
uint16_t E010R5_callback()
{
//Bind
if(bind_counter)
if(--bind_counter==0)
BIND_DONE;
//Send packet
RF2500_SendPayload();
//Timing and hopping
packet_count++;
switch(packet_count)
{
case 1:
case 2:
case 4:
case 5:
return 1183;
default:
hopping_frequency_no++;
hopping_frequency_no &= 3;
if(IS_BIND_IN_PROGRESS)
rf_ch_num = 0x30 + (hopping_frequency_no<<3);
else
rf_ch_num = hopping_frequency[hopping_frequency_no];
RF2500_RFChannel(rf_ch_num);
RF2500_SetPower();
packet_count = 0;
case 3:
E010R5_build_data_packet();
return 3400;
}
return 0;
}
void E010R5_init()
{
BIND_IN_PROGRESS; // Autobind protocol
bind_counter = 2600;
//RF2500 emu init
RF2500_Init(E010R5_PAYLOAD_SIZE, false); // 14 bytes, not scrambled
RF2500_SetTXAddr((uint8_t*)"\x0E\x54\x96\xEE"); // Same address for bind and normal packets
rx_tx_addr[0]=0x00;
hopping_frequency[0]=0x35; //53
#ifdef E010R5_FORCE_ID
switch(rx_tx_addr[3]%5)
{
case 0:
//TX1
//hopping_frequency[0]=0x35; //53
hopping_frequency[1]=0x30; //48
rx_tx_addr[1]=0x45;
rx_tx_addr[2]=0x46;
break;
case 1:
//TX2
//hopping_frequency[0]=0x35; //53
hopping_frequency[1]=0x3C; //60
rx_tx_addr[1]=0x1B;
rx_tx_addr[2]=0x9E;
break;
case 2:
//TX4
hopping_frequency[0]=0x30; //48
hopping_frequency[1]=0x38; //56
rx_tx_addr[1]=0x2E;
rx_tx_addr[2]=0xAE;
break;
case 3:
//TX5
//hopping_frequency[0]=0x35; //53
hopping_frequency[1]=0x41; //65
rx_tx_addr[0]=0x0D;
rx_tx_addr[1]=0xB9;
rx_tx_addr[2]=0xFC;
break;
default:
//TX3
hopping_frequency[0]=0x30; //48
hopping_frequency[1]=0x38; //56
rx_tx_addr[1]=0x17;
rx_tx_addr[2]=0x0D;
break;
}
#endif
// This is the same as the E010 v1...
hopping_frequency[2]=hopping_frequency[0]+0x10;
hopping_frequency[3]=hopping_frequency[1]+0x10;
E010R5_build_data_packet();
RF2500_RFChannel(hopping_frequency[0]);
hopping_frequency_no=0;
packet_count=0;
}
#endif

View File

@@ -0,0 +1,157 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(E016HV2_CC2500_INO)
#include "iface_cc2500.h"
//#define FORCE_E016HV2_ORIGINAL_ID
#define E016HV2_INITIAL_WAIT 500
#define E016HV2_PACKET_PERIOD 10000
#define E016HV2_RF_BIND_CHANNEL 5
#define E016HV2_PAYLOAD_SIZE 11
#define E016HV2_BIND_COUNT 300 //3sec
static void __attribute__((unused)) E016HV2_send_packet()
{
//payload length (after this byte)
packet[0 ] = 0x0A;
//bind indicator
if(IS_BIND_IN_PROGRESS)
{
packet[1 ] = 0x02;
if(bind_counter)
bind_counter--;
else
{
BIND_DONE;
CC2500_250K_RFChannel(rf_ch_num); // Set main channel
}
}
else
packet[1 ] = 0x20;
//ID
packet[2 ] = rx_tx_addr[2];
packet[3 ] = rx_tx_addr[3];
//channels TREA
uint8_t channel;
if(IS_BIND_IN_PROGRESS)
channel=0x64; // Throttle must be centered during bind
else
channel=convert_channel_8b_limit_deadband(THROTTLE,0x00,0x64,0xC8, 20);
packet[4 ] = channel;
channel=convert_channel_16b_limit(RUDDER,0x00,0xC8);
packet[5 ] = channel;
channel=convert_channel_16b_limit(ELEVATOR,0x00,0xC8);
packet[6 ] = channel;
channel=convert_channel_16b_limit(AILERON,0x00,0xC8);
packet[7 ] = channel;
//flags
if(CH8_SW && !phase) //toggle calib flag
flags ^= 0x40;
phase=CH8_SW;
packet[8 ] = GET_FLAG(CH7_SW, 0x01) // 0x01=Flip
| GET_FLAG(CH9_SW, 0x02) // 0x02=Headless
| GET_FLAG(CH10_SW, 0x04) // 0x04=One Key Return
| flags; // 0x40=Calib
packet[9 ] = 0x02; // Speed control 0x00:low, 0x01:medium, 0x02:high
packet[10] = GET_FLAG(CH5_SW, 0x01) // 0x01=TakeOff/Land (momentary switch)
| GET_FLAG(CH6_SW, 0x04); // 0x04=Emergeny Stop (momentary switch)
CC2500_SetPower(); // Set tx_power
CC2500_SetFreqOffset(); // Set frequency offset
//Build real packet and send it
static uint8_t pid=0;
crc=0;
// stop TX/RX
CC2500_Strobe(CC2500_SIDLE);
// flush tx FIFO
CC2500_Strobe(CC2500_SFTX);
// packet length
CC2500_WriteReg(CC2500_3F_TXFIFO, 6 + 4 + 1 + 11 + 2); // preamble + address + packet_control + payload + crc
// preamble+address
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, (uint8_t*)"\xAA\xAA\xAA\xAA\xAA\xAA\xE7\xE7\xE7\xE7", 10);
// packet control
CC2500_WriteReg(CC2500_3F_TXFIFO, 0x50+(pid<<2));
pid++;
// payload
//debug("P:")
for (uint8_t i = 0; i < E016HV2_PAYLOAD_SIZE; ++i)
{
uint8_t byte = (bit_reverse(packet[i])<<1) | (packet[i+1]&0x01);
//debug(" %02X",byte)
CC2500_WriteReg(CC2500_3F_TXFIFO,byte);
crc16_update(byte, 8);
}
// crc
CC2500_WriteReg(CC2500_3F_TXFIFO,crc >> 8);
CC2500_WriteReg(CC2500_3F_TXFIFO,crc);
//debugln(" %04X",crc)
// transmit
CC2500_Strobe(CC2500_STX);
}
uint16_t E016HV2_callback()
{
E016HV2_send_packet();
return E016HV2_PACKET_PERIOD;
}
void E016HV2_init()
{
//Config CC2500
CC2500_250K_Init();
CC2500_250K_RFChannel(E016HV2_RF_BIND_CHANNEL); // Set bind channel
#ifdef FORCE_E016HV2_ORIGINAL_ID
rx_tx_addr[2]=0x27;
rx_tx_addr[3]=0x1B;
//rf_ch_num = 44;
#endif
//General ID
//3F1B -> 68,2C1B -> 49,2B1B -> 48,2A1B -> 47,291B -> 46,281B -> 45,271B -> 44,261B -> 43,251B -> 42
//241B -> no bind,231B -> no bind,221B -> 71,211B -> 70,201B -> 69,1F1B -> 68,1E1B -> 67,1D1B -> 66,1C1B -> 65,1B1B -> 64,1A1B -> 63,191B -> 62,181B -> 61,171B -> 60,161B -> 59
//0C1B -> 49,051B -> 42,041B -> no bind,031B -> no bind,021B -> 71,011B -> 70,001B -> no bind
if(rx_tx_addr[2]<3) rx_tx_addr[2]+=3; // rx_tx_addr[2]=0 is invalid
if(rx_tx_addr[3]==0) rx_tx_addr[3]+=64; // rx_tx_addr[3]=0 is invalid
rf_ch_num = (rx_tx_addr[2] + rx_tx_addr[3]) % 32 + 42;
if(rf_ch_num>71) // channels 72 and 73 are invalid
{
rx_tx_addr[2]-=2;
rf_ch_num-=2;
}
phase=CH8_SW;
flags=0;
bind_counter = E016HV2_BIND_COUNT;
BIND_IN_PROGRESS; // Autobind protocol
}
#endif

View File

@@ -0,0 +1,154 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// compatible with E016H
#if defined(E016H_NRF24L01_INO)
#include "iface_xn297.h"
//Protocols constants
#define E016H_BIND_COUNT 500
#define E016H_ADDRESS_LENGTH 5
#define E016H_PACKET_PERIOD 4080
#define E016H_PACKET_SIZE 10
#define E016H_BIND_CHANNEL 80
#define E016H_NUM_CHANNELS 4
//Channels
#define E016H_STOP_SW CH5_SW
#define E016H_FLIP_SW CH6_SW
#define E016H_HEADLESS_SW CH8_SW
#define E016H_RTH_SW CH9_SW
// E016H flags packet[1]
#define E016H_FLAG_CALIBRATE 0x80
#define E016H_FLAG_STOP 0x20
#define E016H_FLAG_FLIP 0x04
// E016H flags packet[3]
#define E016H_FLAG_HEADLESS 0x10
#define E016H_FLAG_RTH 0x04
// E016H flags packet[7]
#define E016H_FLAG_TAKEOFF 0x80
#define E016H_FLAG_HIGHRATE 0x08
static void __attribute__((unused)) E016H_send_packet()
{
uint8_t can_flip = 0, calibrate = 1;
if(IS_BIND_IN_PROGRESS)
{
memcpy(packet, &rx_tx_addr[1], 4);
memcpy(&packet[4], hopping_frequency, 4);
packet[8] = 0x23;
}
else
{
// trim commands
packet[0] = 0;
// aileron
uint16_t val = convert_channel_16b_limit(AILERON, 0, 0x3ff);
can_flip |= (val < 0x100) || (val > 0x300);
packet[1] = val >> 8;
packet[2] = val & 0xff;
if(val < 0x300) calibrate = 0;
// elevator
val = convert_channel_16b_limit(ELEVATOR, 0x3ff, 0);
can_flip |= (val < 0x100) || (val > 0x300);
packet[3] = val >> 8;
packet[4] = val & 0xff;
if(val < 0x300) calibrate = 0;
// throttle
val = convert_channel_16b_limit(THROTTLE, 0, 0x3ff);
packet[5] = val >> 8;
packet[6] = val & 0xff;
if(val > 0x100) calibrate = 0;
// rudder
val = convert_channel_16b_limit(RUDDER, 0, 0x3ff);
packet[7] = val >> 8;
packet[8] = val & 0xff;
if(val > 0x100) calibrate = 0;
// flags
packet[1] |= GET_FLAG(E016H_STOP_SW, E016H_FLAG_STOP)
| (can_flip ? GET_FLAG(E016H_FLIP_SW, E016H_FLAG_FLIP) : 0)
| (calibrate ? E016H_FLAG_CALIBRATE : 0);
packet[3] |= GET_FLAG(E016H_HEADLESS_SW, E016H_FLAG_HEADLESS)
| GET_FLAG(E016H_RTH_SW, E016H_FLAG_RTH);
packet[7] |= E016H_FLAG_HIGHRATE;
// frequency hopping
XN297_Hopping(hopping_frequency_no++ & 0x03);
}
// checksum
packet[9] = packet[0];
for (uint8_t i=1; i < E016H_PACKET_SIZE-1; i++)
packet[9] += packet[i];
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, E016H_PACKET_SIZE);
}
static void __attribute__((unused)) E016H_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t *)"\x5a\x53\x46\x30\x31", 5); // bind address
//XN297_HoppingCalib(E016H_NUM_CHANNELS);
XN297_RFChannel(E016H_BIND_CHANNEL);
}
uint16_t E016H_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
if(bind_counter)
{
bind_counter--;
if (bind_counter == 0)
{
XN297_SetTXAddr(rx_tx_addr, E016H_ADDRESS_LENGTH);
BIND_DONE;
}
}
E016H_send_packet();
return E016H_PACKET_PERIOD;
}
static void __attribute__((unused)) E016H_initialize_txid()
{
// tx id
rx_tx_addr[0] = 0xa5;
rx_tx_addr[1] = 0x00;
// rf channels
uint32_t lfsr=random(0xfefefefe);
for(uint8_t i=0; i<E016H_NUM_CHANNELS; i++)
{
hopping_frequency[i] = (lfsr & 0xFF) % 80;
lfsr>>=8;
}
}
void E016H_init()
{
BIND_IN_PROGRESS;
E016H_initialize_txid();
E016H_RF_init();
bind_counter = E016H_BIND_COUNT;
hopping_frequency_no = 0;
}
#endif

View File

@@ -0,0 +1,239 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// compatible with E012 and E015
#if defined(E01X_CYRF6936_INO)
#include "iface_hs6200.h"
//Protocols constants
#define E01X_BIND_COUNT 500
#define E01X_INITIAL_WAIT 500
#define E01X_ADDRESS_LENGTH 5
#define E012_PACKET_PERIOD 4525
#define E012_RF_BIND_CHANNEL 0x3c
#define E012_NUM_RF_CHANNELS 4
#define E012_PACKET_SIZE 15
//#define E015_FORCE_ID
#define E015_PACKET_PERIOD 9000
#define E015_RF_CHANNEL 0x2d // 2445 MHz
#define E015_PACKET_SIZE 10
#define E015_BIND_PACKET_SIZE 9
//Channels
#define E01X_ARM_SW CH5_SW
#define E016H_STOP_SW CH5_SW
#define E01X_FLIP_SW CH6_SW
#define E01X_LED_SW CH7_SW
#define E01X_HEADLESS_SW CH8_SW
#define E01X_RTH_SW CH9_SW
// E012 flags packet[1]
#define E012_FLAG_FLIP 0x40
#define E012_FLAG_HEADLESS 0x10
#define E012_FLAG_RTH 0x04
// E012 flags packet[7]
#define E012_FLAG_EXPERT 0x02
// E015 flags packet[6]
#define E015_FLAG_DISARM 0x80
#define E015_FLAG_ARM 0x40
// E015 flags packet[7]
#define E015_FLAG_FLIP 0x80
#define E015_FLAG_HEADLESS 0x10
#define E015_FLAG_RTH 0x08
#define E015_FLAG_LED 0x04
#define E015_FLAG_EXPERT 0x02
#define E015_FLAG_INTERMEDIATE 0x01
static void __attribute__((unused)) E015_check_arming()
{
uint8_t arm_channel = E01X_ARM_SW;
if (arm_channel != arm_channel_previous)
{
arm_channel_previous = arm_channel;
if (arm_channel)
{
armed = 1;
arm_flags ^= E015_FLAG_ARM;
}
else
{
armed = 0;
arm_flags ^= E015_FLAG_DISARM;
}
}
}
static void __attribute__((unused)) E01X_send_packet()
{
if(sub_protocol==E012)
{
packet_length=E012_PACKET_SIZE;
packet[0] = rx_tx_addr[1];
if(IS_BIND_IN_PROGRESS)
{
rf_ch_num = E012_RF_BIND_CHANNEL;
packet[1] = 0xaa;
memcpy(&packet[2], hopping_frequency, E012_NUM_RF_CHANNELS);
memcpy(&packet[6], rx_tx_addr, E01X_ADDRESS_LENGTH);
}
else
{
rf_ch_num = hopping_frequency[hopping_frequency_no++];
hopping_frequency_no %= E012_NUM_RF_CHANNELS;
packet[1] = 0x01
| GET_FLAG(E01X_RTH_SW, E012_FLAG_RTH)
| GET_FLAG(E01X_HEADLESS_SW, E012_FLAG_HEADLESS)
| GET_FLAG(E01X_FLIP_SW, E012_FLAG_FLIP);
packet[2] = convert_channel_16b_limit(AILERON, 0xc8, 0x00); // aileron
packet[3] = convert_channel_16b_limit(ELEVATOR, 0x00, 0xc8); // elevator
packet[4] = convert_channel_16b_limit(RUDDER, 0xc8, 0x00); // rudder
packet[5] = convert_channel_16b_limit(THROTTLE, 0x00, 0xc8); // throttle
packet[6] = 0xaa;
packet[7] = E012_FLAG_EXPERT; // rate (0-2)
packet[8] = 0x00;
packet[9] = 0x00;
packet[10]= 0x00;
}
packet[11] = 0x00;
packet[12] = 0x00;
packet[13] = 0x56;
packet[14] = rx_tx_addr[2];
}
else
{ // E015
rf_ch_num = E015_RF_CHANNEL;
if(IS_BIND_IN_PROGRESS)
{
packet[0] = 0x18;
packet[1] = 0x04;
packet[2] = 0x06;
// data phase address
memcpy(&packet[3], rx_tx_addr, E01X_ADDRESS_LENGTH);
packet[8] = 0x63; // unknown calculation
// checksum
//packet[8] = packet[3];
//for(uint8_t i=4; i<8; i++)
// packet[8] += packet[i];
packet_length=E015_BIND_PACKET_SIZE;
}
else
{
E015_check_arming();
packet[0] = convert_channel_16b_limit(THROTTLE, 0, 225); // throttle
packet[1] = convert_channel_16b_limit(RUDDER, 225, 0); // rudder
packet[2] = convert_channel_16b_limit(AILERON, 0, 225); // aileron
packet[3] = convert_channel_16b_limit(ELEVATOR, 225, 0); // elevator
packet[4] = 0x20; // elevator trim
packet[5] = 0x20; // aileron trim
packet[6] = arm_flags;
packet[7] = E015_FLAG_EXPERT
| GET_FLAG(E01X_FLIP_SW, E015_FLAG_FLIP)
| GET_FLAG(E01X_LED_SW, E015_FLAG_LED)
| GET_FLAG(E01X_HEADLESS_SW,E015_FLAG_HEADLESS)
| GET_FLAG(E01X_RTH_SW, E015_FLAG_RTH);
packet[8] = 0;
// checksum
packet[9] = packet[0];
for(uint8_t i=1; i<9; i++)
packet[9] += packet[i];
packet_length=E015_PACKET_SIZE;
}
}
HS6200_RFChannel(rf_ch_num);
HS6200_SetPower();
delayMicroseconds(270); // Wait for RF channel to settle
HS6200_SendPayload(packet, packet_length);
}
static void __attribute__((unused)) E01X_RF_init()
{
HS6200_Init(true); // CRC enabled
if(sub_protocol==E012)
HS6200_SetTXAddr((uint8_t *)"\x55\x42\x9C\x8F\xC9", E01X_ADDRESS_LENGTH);
else //E015
HS6200_SetTXAddr((uint8_t *)"\x62\x54\x79\x38\x53", E01X_ADDRESS_LENGTH);
}
uint16_t E01X_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
if(bind_counter)
{
bind_counter--;
if (bind_counter == 0)
{
HS6200_SetTXAddr(rx_tx_addr, E01X_ADDRESS_LENGTH);
BIND_DONE;
}
}
E01X_send_packet();
return packet_period;
}
static void __attribute__((unused)) E012_initialize_txid()
{
// rf channels
uint32_t lfsr=random(0xfefefefe);
for(uint8_t i=0; i<E012_NUM_RF_CHANNELS; i++)
{
hopping_frequency[i] = 0x10 + ((lfsr & 0xff) % 0x32);
lfsr>>=8;
}
}
void E01X_init()
{
BIND_IN_PROGRESS;
if(sub_protocol==E012)
{
E012_initialize_txid();
packet_period=E012_PACKET_PERIOD;
}
else //E015
{
#ifdef E015_FORCE_ID
rx_tx_addr[0] = 0x06;
rx_tx_addr[1] = 0xC6;
rx_tx_addr[2] = 0xB7;
rx_tx_addr[3] = 0x56;
rx_tx_addr[4] = 0x8A;
#endif
//force the sum to give 0x63 since the id calculation is unknown
uint8_t sum=0x63;
for(uint8_t i=0; i < 4; i++)
sum -= rx_tx_addr[i];
rx_tx_addr[4] = sum;
packet_period=E015_PACKET_PERIOD;
armed = 0;
arm_flags = 0;
arm_channel_previous = E01X_ARM_SW;
}
E01X_RF_init();
bind_counter = E01X_BIND_COUNT;
hopping_frequency_no = 0;
}
#endif

View File

@@ -1,352 +0,0 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// compatible with E012 and E015
#if defined(E01X_NRF24L01_INO)
#include "iface_nrf24l01.h"
//Protocols constants
#define E01X_BIND_COUNT 500
#define E01X_INITIAL_WAIT 500
#define E01X_ADDRESS_LENGTH 5
#define E012_PACKET_PERIOD 4525
#define E012_RF_BIND_CHANNEL 0x3c
#define E012_NUM_RF_CHANNELS 4
#define E012_PACKET_SIZE 15
#define E015_PACKET_PERIOD 4500 // stock Tx=9000, but let's send more packets ...
#define E015_RF_CHANNEL 0x2d // 2445 MHz
#define E015_PACKET_SIZE 10
#define E015_BIND_PACKET_SIZE 9
#define E016H_PACKET_PERIOD 4080
#define E016H_PACKET_SIZE 10
#define E016H_BIND_CHANNEL 80
#define E016H_NUM_CHANNELS 4
//Channels
#define E01X_ARM_SW CH5_SW
#define E016H_STOP_SW CH5_SW
#define E01X_FLIP_SW CH6_SW
#define E01X_LED_SW CH7_SW
#define E01X_HEADLESS_SW CH8_SW
#define E01X_RTH_SW CH9_SW
// E012 flags packet[1]
#define E012_FLAG_FLIP 0x40
#define E012_FLAG_HEADLESS 0x10
#define E012_FLAG_RTH 0x04
// E012 flags packet[7]
#define E012_FLAG_EXPERT 0x02
// E015 flags packet[6]
#define E015_FLAG_DISARM 0x80
#define E015_FLAG_ARM 0x40
// E015 flags packet[7]
#define E015_FLAG_FLIP 0x80
#define E015_FLAG_HEADLESS 0x10
#define E015_FLAG_RTH 0x08
#define E015_FLAG_LED 0x04
#define E015_FLAG_EXPERT 0x02
#define E015_FLAG_INTERMEDIATE 0x01
// E016H flags packet[1]
#define E016H_FLAG_CALIBRATE 0x80
#define E016H_FLAG_STOP 0x20
#define E016H_FLAG_FLIP 0x04
// E016H flags packet[3]
#define E016H_FLAG_HEADLESS 0x10
#define E016H_FLAG_RTH 0x04
// E016H flags packet[7]
#define E016H_FLAG_TAKEOFF 0x80
#define E016H_FLAG_HIGHRATE 0x08
static void __attribute__((unused)) E015_check_arming()
{
uint8_t arm_channel = E01X_ARM_SW;
if (arm_channel != arm_channel_previous)
{
arm_channel_previous = arm_channel;
if (arm_channel)
{
armed = 1;
arm_flags ^= E015_FLAG_ARM;
}
else
{
armed = 0;
arm_flags ^= E015_FLAG_DISARM;
}
}
}
static void __attribute__((unused)) E01X_send_packet(uint8_t bind)
{
uint8_t can_flip = 0, calibrate = 1;
if(sub_protocol==E012)
{
packet_length=E012_PACKET_SIZE;
packet[0] = rx_tx_addr[1];
if(bind)
{
packet[1] = 0xaa;
memcpy(&packet[2], hopping_frequency, E012_NUM_RF_CHANNELS);
memcpy(&packet[6], rx_tx_addr, E01X_ADDRESS_LENGTH);
rf_ch_num=E012_RF_BIND_CHANNEL;
}
else
{
packet[1] = 0x01
| GET_FLAG(E01X_RTH_SW, E012_FLAG_RTH)
| GET_FLAG(E01X_HEADLESS_SW, E012_FLAG_HEADLESS)
| GET_FLAG(E01X_FLIP_SW, E012_FLAG_FLIP);
packet[2] = convert_channel_16b_limit(AILERON, 0xc8, 0x00); // aileron
packet[3] = convert_channel_16b_limit(ELEVATOR, 0x00, 0xc8); // elevator
packet[4] = convert_channel_16b_limit(RUDDER, 0xc8, 0x00); // rudder
packet[5] = convert_channel_16b_limit(THROTTLE, 0x00, 0xc8); // throttle
packet[6] = 0xaa;
packet[7] = E012_FLAG_EXPERT; // rate (0-2)
packet[8] = 0x00;
packet[9] = 0x00;
packet[10]= 0x00;
rf_ch_num=hopping_frequency[hopping_frequency_no++];
hopping_frequency_no %= E012_NUM_RF_CHANNELS;
}
packet[11] = 0x00;
packet[12] = 0x00;
packet[13] = 0x56;
packet[14] = rx_tx_addr[2];
}
else if(sub_protocol==E015)
{ // E015
if(bind)
{
packet[0] = 0x18;
packet[1] = 0x04;
packet[2] = 0x06;
// data phase address
memcpy(&packet[3], rx_tx_addr, E01X_ADDRESS_LENGTH);
// checksum
packet[8] = packet[3];
for(uint8_t i=4; i<8; i++)
packet[8] += packet[i];
packet_length=E015_BIND_PACKET_SIZE;
}
else
{
E015_check_arming();
packet[0] = convert_channel_16b_limit(THROTTLE, 0, 225); // throttle
packet[1] = convert_channel_16b_limit(RUDDER, 225, 0); // rudder
packet[2] = convert_channel_16b_limit(AILERON, 0, 225); // aileron
packet[3] = convert_channel_16b_limit(ELEVATOR, 225, 0); // elevator
packet[4] = 0x20; // elevator trim
packet[5] = 0x20; // aileron trim
packet[6] = arm_flags;
packet[7] = E015_FLAG_EXPERT
| GET_FLAG(E01X_FLIP_SW, E015_FLAG_FLIP)
| GET_FLAG(E01X_LED_SW, E015_FLAG_LED)
| GET_FLAG(E01X_HEADLESS_SW,E015_FLAG_HEADLESS)
| GET_FLAG(E01X_RTH_SW, E015_FLAG_RTH);
packet[8] = 0;
// checksum
packet[9] = packet[0];
for(uint8_t i=1; i<9; i++)
packet[9] += packet[i];
packet_length=E015_PACKET_SIZE;
}
}
else
{ // E016H
packet_length=E016H_PACKET_SIZE;
if(bind)
{
rf_ch_num=E016H_BIND_CHANNEL;
memcpy(packet, &rx_tx_addr[1], 4);
memcpy(&packet[4], hopping_frequency, 4);
packet[8] = 0x23;
}
else
{
// trim commands
packet[0] = 0;
// aileron
uint16_t val = convert_channel_16b_limit(AILERON, 0, 0x3ff);
can_flip |= (val < 0x100) || (val > 0x300);
packet[1] = val >> 8;
packet[2] = val & 0xff;
if(val < 0x300) calibrate = 0;
// elevator
val = convert_channel_16b_limit(ELEVATOR, 0x3ff, 0);
can_flip |= (val < 0x100) || (val > 0x300);
packet[3] = val >> 8;
packet[4] = val & 0xff;
if(val < 0x300) calibrate = 0;
// throttle
val = convert_channel_16b_limit(THROTTLE, 0, 0x3ff);
packet[5] = val >> 8;
packet[6] = val & 0xff;
if(val > 0x100) calibrate = 0;
// rudder
val = convert_channel_16b_limit(RUDDER, 0, 0x3ff);
packet[7] = val >> 8;
packet[8] = val & 0xff;
if(val > 0x100) calibrate = 0;
// flags
packet[1] |= GET_FLAG(E016H_STOP_SW, E016H_FLAG_STOP)
| (can_flip ? GET_FLAG(E01X_FLIP_SW, E016H_FLAG_FLIP) : 0)
| (calibrate ? E016H_FLAG_CALIBRATE : 0);
packet[3] |= GET_FLAG(E01X_HEADLESS_SW, E016H_FLAG_HEADLESS)
| GET_FLAG(E01X_RTH_SW, E016H_FLAG_RTH);
packet[7] |= E016H_FLAG_HIGHRATE;
// frequency hopping
rf_ch_num=hopping_frequency[hopping_frequency_no++ & 0x03];
}
// checksum
packet[9] = packet[0];
for (uint8_t i=1; i < E016H_PACKET_SIZE-1; i++)
packet[9] += packet[i];
}
// Power on, TX mode, CRC enabled
if(sub_protocol==E016H)
XN297_Configure( _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
else //E012 & E015
HS6200_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
if(sub_protocol==E016H)
XN297_WritePayload(packet, packet_length);
else
HS6200_WritePayload(packet, packet_length);
// Check and adjust transmission power. We do this after
// transmission to not bother with timeout after power
// settings change - we have plenty of time until next
// packet.
NRF24L01_SetPower();
}
static void __attribute__((unused)) E01X_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
if(sub_protocol==E012)
HS6200_SetTXAddr((uint8_t *)"\x55\x42\x9C\x8F\xC9", E01X_ADDRESS_LENGTH);
else if(sub_protocol==E015)
HS6200_SetTXAddr((uint8_t *)"\x62\x54\x79\x38\x53", E01X_ADDRESS_LENGTH);
else //E016H
XN297_SetTXAddr((uint8_t *)"\x5a\x53\x46\x30\x31", 5); // bind address
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1 Mbps
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01); // Set feature bits on
NRF24L01_Activate(0x73);
}
uint16_t E01X_callback()
{
if(IS_BIND_IN_PROGRESS)
{
if (bind_counter == 0)
{
if(sub_protocol==E016H)
XN297_SetTXAddr(rx_tx_addr, E01X_ADDRESS_LENGTH);
else
HS6200_SetTXAddr(rx_tx_addr, E01X_ADDRESS_LENGTH);
BIND_DONE;
}
else
{
E01X_send_packet(1);
bind_counter--;
}
}
else
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
E01X_send_packet(0);
}
return packet_period;
}
static void __attribute__((unused)) E012_initialize_txid()
{
// rf channels
uint32_t lfsr=random(0xfefefefe);
for(uint8_t i=0; i<E012_NUM_RF_CHANNELS; i++)
{
hopping_frequency[i] = 0x10 + ((lfsr & 0xff) % 0x32);
lfsr>>=8;
}
}
static void __attribute__((unused)) E016H_initialize_txid()
{
// tx id
rx_tx_addr[0] = 0xa5;
rx_tx_addr[1] = 0x00;
// rf channels
uint32_t lfsr=random(0xfefefefe);
for(uint8_t i=0; i<E016H_NUM_CHANNELS; i++)
{
hopping_frequency[i] = (lfsr & 0xFF) % 80;
lfsr>>=8;
}
}
uint16_t initE01X()
{
BIND_IN_PROGRESS;
if(sub_protocol==E012)
{
E012_initialize_txid();
packet_period=E012_PACKET_PERIOD;
}
else if(sub_protocol==E015)
{
packet_period=E015_PACKET_PERIOD;
rf_ch_num=E015_RF_CHANNEL;
armed = 0;
arm_flags = 0;
arm_channel_previous = E01X_ARM_SW;
}
else
{ // E016H
E016H_initialize_txid();
packet_period=E016H_PACKET_PERIOD;
}
E01X_init();
bind_counter = E01X_BIND_COUNT;
hopping_frequency_no = 0;
return E01X_INITIAL_WAIT;
}
#endif

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/>.
*/
#if defined(E129_CYRF6936_INO)
#include "iface_rf2500.h"
//#define E129_FORCE_ID
//#define C186_FORCE_ID
#define E129_BIND_CH 0x2D //45
#define E129_PAYLOAD_SIZE 16
#define C186_PAYLOAD_SIZE 19
static void __attribute__((unused)) E129_build_data_packet()
{
//Build the packet
memset(packet,0,packet_length);
packet[ 0] = packet_length - 1; // Packet length
if(IS_BIND_IN_PROGRESS)
{
packet[ 1] = 0xA4;
packet[ 2] = bit_reverse(rx_tx_addr[2]);
packet[ 3] = bit_reverse(rx_tx_addr[3]);
packet[ 4] = bit_reverse(rx_tx_addr[0]);
packet[ 5] = bit_reverse(rx_tx_addr[1]);
for(uint8_t i=0; i<4; i++)
packet[6+i]=hopping_frequency[i]-2;
}
else
{
packet[ 1] = 0xA6; // Set to A5 every few packets??
//Flags
packet[ 2] = 0xF7; // E129 High rate 0xF7, low 0xF4
if(sub_protocol == E129_C186)
{
packet[ 2] = 0xFA; // High rate 0xFA, medium 0xF7, low 0xF4
packet[13] = bit_reverse(rx_tx_addr[2]);
packet[14] = bit_reverse(rx_tx_addr[3]);
packet[15] = bit_reverse(rx_tx_addr[0]);
packet[16] = bit_reverse(rx_tx_addr[1]);
}
packet[ 3] = GET_FLAG(CH10_SW, 0x40) // C159: loop flight 0x40
| GET_FLAG(CH11_SW, 0x08); // C129V2: flip
//Other flags seen in packet[3]
// Flag 0x04 is set on some helis (C159/C190)
// E129 Mode: short press=0x20->0x00->0x20->..., long press=0x10->0x30->0x10->... => C186 throttle trim is doing the same:up=short press and down=long press
packet[ 4] = GET_FLAG(CH5_SW, 0x20) // Take off/Land 0x20
| GET_FLAG(CH6_SW, 0x04) // Emergency stop 0x04
| GET_FLAG(CH12_SW, 0x80); // C190: debug mode->remote THR trim down sets 0x80
//Other flags seen in packet[4]
// C190 remote LANDING sets 0x10
// C190 remote THR trim down sets 0x80
//Channels and trims
uint16_t val = convert_channel_10b(AILERON,false);
uint8_t trim = convert_channel_8b(CH7) & 0xFC;
packet[ 5] = trim | (val >>8); // Trim (0x00..0x1F..0x3E) << 2 | channel >> 8
packet[ 6] = val; // channel (0x000...0x200...0x3FF)
val = convert_channel_10b(ELEVATOR,false);
trim = convert_channel_8b(CH8) & 0xFC;
packet[ 7] = trim | (val >>8); // Trim (0x00..0x1F..0x3E) << 2 | channel >> 8
packet[ 8] = val; // channel (0x000...0x200...0x3FF)
if(packet_count>200)
val = convert_channel_10b(THROTTLE,false);
else
{//Allow bind to complete with throttle not centered
packet_count++;
val=0x200;
}
packet[ 9] = (0x1F<<2) | (val >>8); // Trim (0x00..0x1F..0x3E) << 2 | channel >> 8
packet[10] = val; // channel (0x000...0x200...0x3FF)
val = convert_channel_10b(RUDDER,false);
trim = convert_channel_8b(CH9) & 0xFC;
packet[11] = trim | (val >>8); // Trim (0x00..0x1F..0x3E) << 2 | channel >> 8
packet[12] = val; // channel (0x000...0x200...0x3FF)
}
//Check
for(uint8_t i=0;i<packet_length-2;i++)
packet[packet_length-2] += packet[i];
if(sub_protocol == E129_C186)
packet[packet_length-2] -= 0x80;
RF2500_BuildPayload(packet);
}
uint16_t E129_callback()
{
//Set RF channel
if(phase==0)
RF2500_RFChannel(IS_BIND_IN_PROGRESS ? E129_BIND_CH : hopping_frequency[hopping_frequency_no]);
//Send packet
RF2500_SendPayload();
//E129 sends twice on same channel, not the C186 but there is a bug somewhere if I don't send the packets back to back
if(phase==0)
{
phase++;
return 1260;
}
//Bind
if(bind_counter)
if(--bind_counter==0)
{
BIND_DONE;
RF2500_SetTXAddr(rx_tx_addr); // 4 bytes of address
}
//Build packet
E129_build_data_packet();
//Set power
RF2500_SetPower();
//Hopp
hopping_frequency_no++;
hopping_frequency_no &= 3;
phase=0;
if(sub_protocol==E129_E129)
return 5200-1260;
return 5500-1260; //E129_C186
}
void E129_init()
{
BIND_IN_PROGRESS; // Autobind protocol
bind_counter = 384; // ~2sec
//RF2500 emu init
packet_length = sub_protocol == E129_E129?E129_PAYLOAD_SIZE:C186_PAYLOAD_SIZE;
RF2500_Init(packet_length, true); // 16/19 bytes, Scrambled
//Freq hopping
calc_fh_channels(4);
for(uint8_t i=0; i<4; i++)
if(hopping_frequency[i]==E129_BIND_CH)
hopping_frequency[i]++;
#ifdef E129_FORCE_ID
rx_tx_addr[0]=0xC1;
rx_tx_addr[1]=0x22;
rx_tx_addr[2]=0x05;
rx_tx_addr[3]=0xA3;
hopping_frequency[0]=0x3C; //60
hopping_frequency[1]=0x49; //73
hopping_frequency[2]=0x4B; //75
hopping_frequency[3]=0x41; //65
#endif
#ifdef C186_FORCE_ID
rx_tx_addr[0]=0x91;
rx_tx_addr[1]=0x02;
rx_tx_addr[2]=0x5D;
rx_tx_addr[3]=0x33;
hopping_frequency[0]=0x44 + 2;
hopping_frequency[1]=0x41 + 2;
hopping_frequency[2]=0x43 + 2;
hopping_frequency[3]=0x49 + 2;
#endif
RF2500_SetTXAddr((uint8_t*)"\xE2\x32\xE0\xC8"); // 4 bytes of bind address
E129_build_data_packet();
hopping_frequency_no=0;
packet_count=0;
phase=0;
}
#endif

View File

@@ -23,7 +23,7 @@
#define ESKY150_BINDING_PACKET_PERIOD 2000
#define ESKY150_SENDING_PACKET_PERIOD 4800
static void __attribute__((unused)) ESKY150_init()
static void __attribute__((unused)) ESKY150_RF_init()
{
//Original TX always sets for channelx 0x22 and 0x4a
// Use channels 2..79
@@ -31,25 +31,16 @@ static void __attribute__((unused)) ESKY150_init()
hopping_frequency[1] = hopping_frequency[0] + 40;
NRF24L01_Initialize();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)));
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x02); // 4-byte RX/TX address
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // Disable retransmit
NRF24L01_SetPower();
NRF24L01_SetBitrate(NRF24L01_BR_2M);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, ESKY150_PAYLOADSIZE); // bytes of data payload for pipe 0
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, ESKY150_TX_ADDRESS_SIZE);
NRF24L01_Activate(0x73);
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
// Enable: Dynamic Payload Length, Payload with ACK , W_TX_PAYLOAD_NOACK
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, _BV(NRF2401_1D_EN_DPL) | _BV(NRF2401_1D_EN_ACK_PAY) | _BV(NRF2401_1D_EN_DYN_ACK));
NRF24L01_Activate(0x73);
NRF24L01_FlushTx();
// Turn radio power on
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_SetTxRxMode(TX_EN); // Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
}
static void __attribute__((unused)) ESKY150_bind_init()
@@ -171,16 +162,15 @@ uint16_t ESKY150_callback()
return ESKY150_SENDING_PACKET_PERIOD;
}
uint16_t initESKY150(void)
void ESKY150_init(void)
{
ESKY150_init();
ESKY150_RF_init();
if(IS_BIND_IN_PROGRESS)
{
bind_counter=3000;
ESKY150_bind_init();
}
hopping_frequency_no=0;
return 10000;
}
#endif

View File

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

View File

@@ -35,14 +35,10 @@ static void __attribute__((unused)) ESKY_set_data_address()
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4);
}
static void __attribute__((unused)) ESKY_init()
static void __attribute__((unused)) ESKY_RF_init()
{
NRF24L01_Initialize();
// 2-bytes CRC, radio off
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
if (IS_BIND_IN_PROGRESS)
{
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3-byte RX/TX address for bind packets
@@ -51,11 +47,7 @@ static void __attribute__((unused)) ESKY_init()
}
else
ESKY_set_data_address();
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // No auto retransmission
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 50); // Channel 50 for bind packets
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, ESKY_PAYLOAD_SIZE); // bytes of data payload for pipe 0
NRF24L01_WriteReg(NRF24L01_12_RX_PW_P1, ESKY_PAYLOAD_SIZE);
NRF24L01_WriteReg(NRF24L01_13_RX_PW_P2, ESKY_PAYLOAD_SIZE);
@@ -65,7 +57,7 @@ static void __attribute__((unused)) ESKY_init()
NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
}
static void __attribute__((unused)) ESKY_init2()
static void __attribute__((unused)) ESKY_TXID_init()
{
NRF24L01_FlushTx();
if(sub_protocol==ESKY_STD)
@@ -187,7 +179,7 @@ uint16_t ESKY_callback()
return ESKY_STD_PACKET_PERIOD;
}
uint16_t initESKY(void)
void ESKY_init(void)
{
bind_counter = ESKY_BIND_COUNT;
rx_tx_addr[2] = rx_tx_addr[3]; // Model match
@@ -200,10 +192,9 @@ uint16_t initESKY(void)
}
#endif
rx_tx_addr[3] = 0xBB;
ESKY_init();
ESKY_init2();
ESKY_RF_init();
ESKY_TXID_init();
packet_count=0;
return 50000;
}
#endif

View File

@@ -0,0 +1,166 @@
/*
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(EAZYRC_NRF24L01_INO)
#include "iface_xn297.h"
//#define FORCE_EAZYRC_ORIGINAL_ID
#define EAZYRC_PAYLOAD_SIZE 10
#define EAZYRC_RF_NUM_CHANNELS 4
#define EAZYRC_BIND_CHANNEL 18
#define EAZYRC_PACKET_PERIOD 5000
enum {
EAZYRC_BINDTX=0,
EAZYRC_BINDRX,
EAZYRC_DATA,
};
static void __attribute__((unused)) EAZYRC_send_packet()
{
//Bind:
// TX: C=18 S=Y A= AA BB CC DD EE P(10)= 1A A0 01 00 00 00 1E 00 78 51
// packet[0..2]=tx_addr, packet[6]=first rf channel, packet[8]=unk, packet[9]=sum(packet[0..8])
// RX: C=18 S=Y A= AA BB CC DD EE P(10)= 41 AD 01 1A A0 01 1E 00 87 4F
// packet[0..2]=rx_addr, packet[3..5]=tx_addr, packet[6]=first rf channel, packet[8]=unk but swapped, packet[9]=sum(packet[0..8])
//Normal: C=30 S=Y A= 1A A0 41 AD 02 P(10)= 7F 7F 1F 19 00 00 1E 00 AB FF
// packet[0]=THR, packet[1]=ST, packet[2]=unk, packet[3]=unk, packet[6]=first rf channel, packet[8]=unk, packet[9]=sum(packet[0..8])
//Bound : C=18 S=Y A= AA BB CC DD EE P(10)= 1A A0 01 41 AD 01 1E 00 79 41
// packet[0..2]=tx_addr, packet[3..5]=rx_addr, packet[6]=first rf channel, packet[8]=unk, packet[9]=sum(packet[0..8])
// sent every 12 packets in normal mode, but is it really needed if the car loose power then you need to rebind...
//Packet period around 5ms with a large jitter
memset(&packet[3], 0x00, 7);
if(IS_BIND_IN_PROGRESS)
{
memcpy(&packet,rx_tx_addr,3);
packet[6] = hopping_frequency[0];
packet[8] = 0x78; //??? packet type?
}
else
{
XN297_Hopping(hopping_frequency_no);
hopping_frequency_no++;
hopping_frequency_no &= 3;
packet[0] = convert_channel_8b(THROTTLE);
packet[1] = convert_channel_8b(AILERON);
packet[2] = 0x1F; //??? additional channel?
packet[3] = 0x19; //??? additional channel?
packet[6] = hopping_frequency[0];
packet[8] = 0xAB; //??? packet type?
}
for(uint8_t i=0;i<EAZYRC_PAYLOAD_SIZE-1;i++)
packet[9] += packet[i];
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, EAZYRC_PAYLOAD_SIZE);
#ifdef DEBUG_SERIAL
for(uint8_t i=0; i < len; i++)
debug("%02X ", packet[i]);
debugln();
#endif
}
static void __attribute__((unused)) EAZYRC_initialize_txid()
{
rx_tx_addr[1] = rx_tx_addr[3];
hopping_frequency[0] = (rx_tx_addr[3]%20) + 0x1E; // Wild guess... First channel between 30 and 49so a full range of 30 to 79
#ifdef FORCE_EAZYRC_ORIGINAL_ID
rx_tx_addr[0] = 0x1A;
rx_tx_addr[1] = 0xA0;
rx_tx_addr[2] = 0x01;
hopping_frequency[0] = 0x1E;
#endif
rx_tx_addr[2] = 0x01; // Not sure if this is needed...
for(uint8_t i=1; i<EAZYRC_RF_NUM_CHANNELS; i++)
hopping_frequency[i] = hopping_frequency[0] + 10*i;
}
static void __attribute__((unused)) EAZYRC_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t*)"\xAA\xBB\xCC\xDD\xEE", 5);
XN297_SetRXAddr((uint8_t*)"\xAA\xBB\xCC\xDD\xEE", EAZYRC_PAYLOAD_SIZE);
XN297_RFChannel(EAZYRC_BIND_CHANNEL);
}
uint16_t EAZYRC_callback()
{
uint8_t rf,n;
uint16_t addr;
switch(phase)
{
case EAZYRC_BINDTX:
if(XN297_IsRX())
{
//Example: TX: C=18 S=Y A= AA BB CC DD EE P(10)= 1A A0 01 00 00 00 1E 00 78 51
// packet[0..2]=tx_addr, packet[6]=first rf channel, packet[8]=unk, packet[9]=sum(packet[0..8])
// RX: C=18 S=Y A= AA BB CC DD EE P(10)= 41 AD 01 1A A0 01 1E 00 87 4F
// packet[0..2]=rx_addr, packet[3..5]=tx_addr, packet[6]=first rf channel, packet[8]=unk but swapped, packet[9]=sum(packet[0..8])
XN297_ReadPayload(packet_in, EAZYRC_PAYLOAD_SIZE);
#ifdef DEBUG_SERIAL
for(uint8_t i=0; i < EAZYRC_PAYLOAD_SIZE; i++)
debug("%02X ", packet_in[i]);
debugln();
#endif
//could check the validity of the packet by looking at the sum...
if(memcmp(&packet_in[3],&rx_tx_addr,3)==0)
{//TX ID match, TX addr to use: 1A A0 41 AD 02
rx_tx_addr[4] = rx_tx_addr[2] + packet_in[2]; //wild guess
rx_tx_addr[2] = packet_in[0];
rx_tx_addr[3] = packet_in[1];
BIND_DONE;
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTXAddr(rx_tx_addr, 5);
phase = EAZYRC_DATA;
return 5000;
}
}
XN297_SetTxRxMode(TXRX_OFF);
EAZYRC_send_packet();
phase++;
return 1000;
case EAZYRC_BINDRX:
//Wait for the packet transmission to finish
while(XN297_IsPacketSent()==false);
//Switch to RX
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
phase = EAZYRC_BINDTX;
return 10000;
case EAZYRC_DATA:
#ifdef MULTI_SYNC
telemetry_set_input_sync(EAZYRC_PACKET_PERIOD);
#endif
EAZYRC_send_packet();
break;
}
return EAZYRC_PACKET_PERIOD;
}
void EAZYRC_init()
{
BIND_IN_PROGRESS;
EAZYRC_initialize_txid();
EAZYRC_RF_init();
phase = EAZYRC_BINDTX;
packet_count = 0;
hopping_frequency_no = 0;
}
#endif

View File

@@ -31,6 +31,19 @@ enum {
FQ777_FLAG_FLIP = 0x80,
};
enum {
XBM37_B5_OK = 0x80,
XBM37_B6_RATE_LOW = 0x00,
XBM37_B6_RATE_MID = 0x01,
XBM37_B6_RATE_HIGH = 0x02,
XBM37_B6_LED_OFF = 0x04,
XBM37_B6_RTH = 0x08,
XBM37_B6_HEADLESS = 0x10,
XBM37_B6_VIDEO = 0x20,
XBM37_B6_PICTURE = 0x40,
XBM37_B6_FLIP = 0x80,
};
const uint8_t ssv_xor[] = {0x80,0x44,0x64,0x75,0x6C,0x71,0x2A,0x36,0x7C,0xF1,0x6E,0x52,0x9,0x9D,0x1F,0x78,0x3F,0xE1,0xEE,0x16,0x6D,0xE8,0x73,0x9,0x15,0xD7,0x92,0xE7,0x3,0xBA};
uint8_t FQ777_bind_addr [] = {0xe7,0xe7,0xe7,0xe7,0x67};
@@ -52,24 +65,18 @@ static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, ui
header[0] = (addr[4] >> 7);
// calculate the crc
union
{
uint8_t bytes[2];
uint16_t val;
} crc;
crc.val=0x3c18;
crc=0x3c18;
for (i = 0; i < 7; ++i)
crc.val=crc16_update(crc.val,header[i],8);
crc16_update(header[i],8);
for (i = 0; i < *len; ++i)
crc.val=crc16_update(crc.val,payload[i],8);
crc16_update(payload[i],8);
// encode payload and crc
// xor with this:
for (i = 0; i < *len; ++i)
payload[i] ^= ssv_xor[i];
crc.bytes[1] ^= ssv_xor[i++];
crc.bytes[0] ^= ssv_xor[i++];
crc ^= ssv_xor[i++]<<8;
crc ^= ssv_xor[i++];
// pack the pcf, payload, and crc into packed_payload
packed_payload[0] = pcf >> 1;
@@ -78,27 +85,36 @@ static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, ui
for (i = 0; i < *len - 1; ++i)
packed_payload[i+2] = (payload[i] << 7) | (payload[i+1] >> 1);
packed_payload[i+2] = (payload[i] << 7) | (crc.val >> 9);
packed_payload[i+2] = (payload[i] << 7) | (crc >> 9);
++i;
packed_payload[i+2] = (crc.val >> 1 & 0x80 ) | (crc.val >> 1 & 0x7F);
packed_payload[i+2] = (crc >> 1 & 0x80 ) | (crc >> 1 & 0x7F);
++i;
packed_payload[i+2] = (crc.val << 7);
packed_payload[i+2] = (crc << 7);
*len += 4;
}
static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
static void __attribute__((unused)) FQ777_send_packet()
{
uint8_t packet_len = FQ777_PACKET_SIZE;
uint8_t packet_ori[8];
if (bind)
if (IS_BIND_IN_PROGRESS)
{
// 4,5,6 = address fields
// last field is checksum of address fields
// Byte 0 is always 0x20; bytes 1-3 are sub-protocol specific
packet_ori[0] = 0x20;
packet_ori[1] = 0x15;
packet_ori[2] = 0x05;
packet_ori[3] = 0x06;
if (sub_protocol == XBM37)
{
packet_ori[1] = 0x14;
packet_ori[2] = 0x07;
packet_ori[3] = 0x03;
}
else // FQ777
{
packet_ori[1] = 0x15;
packet_ori[2] = 0x05;
packet_ori[3] = 0x06;
}
// Bytes 4-6: address fields, byte 7: checksum of address fields (shared by both protocols)
packet_ori[4] = rx_tx_addr[0];
packet_ori[5] = rx_tx_addr[1];
packet_ori[6] = rx_tx_addr[2];
@@ -106,36 +122,64 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
}
else
{
// throt, yaw, pitch, roll, trims, flags/left button,00,right button
//0-3 0x00-0x64
//4 roll/pitch/yaw trims. cycles through one trim at a time - 0-40 trim1, 40-80 trim2, 80-C0 trim3 (center: A0 20 60)
//5 flags for throttle button, two buttons above throttle - def: 0x40
//6 00 ??
//7 checksum - add values in other fields
if (sub_protocol == XBM37)
{
packet_ori[0] = convert_channel_16b_limit(THROTTLE,0xE1,0); // reverse channel
packet_ori[1] = convert_channel_16b_limit(RUDDER,0,0xE1);
packet_ori[2] = convert_channel_16b_limit(AILERON,0xE1,0); // reverse channel
packet_ori[3] = convert_channel_16b_limit(ELEVATOR,0xE1,0); // reverse channel
packet_ori[4] = (convert_channel_8b(CH13) >> 2) + 1; // ele trim (01..20..40) front ^ plus 0x01, back - minus 0x01 per click
packet_ori[5] = 0x3F - (convert_channel_8b(CH14) >> 2) // ail trim (40..20..01) left <- plus 0x01, right -> minus 0x01 per click
| GET_FLAG(CH12_SW, XBM37_B5_OK); // bit7 = OK button ...unknown use for this model?
// Trims are usually done through the radio configuration but leaving the code here just in case...
uint8_t trim_mod = packet_count % 144;
uint8_t trim_val = 0;
if (36 <= trim_mod && trim_mod < 72) // yaw
trim_val = 0x20; // don't modify yaw trim
else
if (108 < trim_mod && trim_mod) // pitch
trim_val = 0xA0;
else // roll
trim_val = 0x60;
uint8_t rate_bits;
if (CH5_SW)
rate_bits = XBM37_B6_RATE_HIGH; // high rate
else if (Channel_data[CH5] < CHANNEL_MIN_COMMAND)
rate_bits = XBM37_B6_RATE_LOW; // low rate
else
rate_bits = XBM37_B6_RATE_MID; // medium rate
packet_ori[0] = convert_channel_16b_limit(THROTTLE,0,0x64);
packet_ori[1] = convert_channel_16b_limit(RUDDER,0,0x64);
packet_ori[2] = convert_channel_16b_limit(ELEVATOR,0,0x64);
packet_ori[3] = convert_channel_16b_limit(AILERON,0,0x64);
packet_ori[4] = trim_val; // calculated above
packet_ori[5] = GET_FLAG(CH5_SW, FQ777_FLAG_FLIP)
| GET_FLAG(CH7_SW, FQ777_FLAG_HEADLESS)
| GET_FLAG(!CH6_SW, FQ777_FLAG_RETURN)
| GET_FLAG(CH8_SW,FQ777_FLAG_EXPERT);
packet_ori[6] = 0x00;
// calculate checksum
packet_ori[6] = rate_bits // bits[1:0] = rate
| GET_FLAG(CH8_SW, XBM37_B6_LED_OFF) // bit2 = LED off
| GET_FLAG(CH11_SW, XBM37_B6_RTH) // bit3 = RTH
| GET_FLAG(CH7_SW, XBM37_B6_HEADLESS) // bit4 = headless
| GET_FLAG(CH10_SW, XBM37_B6_VIDEO) // bit5 = video
| GET_FLAG(CH9_SW, XBM37_B6_PICTURE) // bit6 = picture
| GET_FLAG(CH6_SW, XBM37_B6_FLIP); // bit7 = flip
}
else // FQ777
{
// throt, yaw, pitch, roll, trims, flags/left button,00,right button
//0-3 0x00-0x64
//4 roll/pitch/yaw trims. cycles through one trim at a time - 0-40 trim1, 40-80 trim2, 80-C0 trim3 (center: A0 20 60)
//5 flags for throttle button, two buttons above throttle - def: 0x40
//6 00 ??
//7 checksum - add values in other fields
// Trims are usually done through the radio configuration but leaving the code here just in case...
uint8_t trim_mod = packet_count % 144;
uint8_t trim_val = 0;
if (36 <= trim_mod && trim_mod < 72) // yaw
trim_val = 0x20; // don't modify yaw trim
else
if (108 < trim_mod && trim_mod) // pitch
trim_val = 0xA0;
else // roll
trim_val = 0x60;
packet_ori[0] = convert_channel_16b_limit(THROTTLE,0,0x64);
packet_ori[1] = convert_channel_16b_limit(RUDDER,0,0x64);
packet_ori[2] = convert_channel_16b_limit(ELEVATOR,0,0x64);
packet_ori[3] = convert_channel_16b_limit(AILERON,0,0x64);
packet_ori[4] = trim_val; // calculated above
packet_ori[5] = GET_FLAG(CH5_SW, FQ777_FLAG_FLIP)
| GET_FLAG(CH7_SW, FQ777_FLAG_HEADLESS)
| GET_FLAG(!CH6_SW, FQ777_FLAG_RETURN)
| GET_FLAG(CH8_SW,FQ777_FLAG_EXPERT);
packet_ori[6] = 0x00;
}
// Data packet checksum: sum of bytes 0-6 (not applied to bind packets)
uint8_t checksum = 0;
for (int i = 0; i < 7; ++i)
checksum += packet_ori[i];
@@ -144,7 +188,7 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
packet_count++;
}
ssv_pack_dpl( (0 == bind) ? rx_tx_addr : FQ777_bind_addr, hopping_frequency_no, &packet_len, packet_ori, packet);
ssv_pack_dpl( IS_BIND_IN_PROGRESS ? FQ777_bind_addr : rx_tx_addr, hopping_frequency_no, &packet_len, packet_ori, packet);
NRF24L01_WriteReg(NRF24L01_00_CONFIG,_BV(NRF24L01_00_PWR_UP));
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
@@ -156,30 +200,21 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind)
NRF24L01_WritePayload(packet, packet_len);
}
static void __attribute__((unused)) FQ777_init()
static void __attribute__((unused)) FQ777_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, FQ777_bind_addr, 5);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x00);
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
NRF24L01_SetBitrate(NRF24L01_BR_250K);
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
NRF24L01_Activate(0x73);
}
uint16_t FQ777_callback()
{
if(bind_counter!=0)
#ifdef MULTI_SYNC
telemetry_set_input_sync(FQ777_PACKET_PERIOD);
#endif
if(bind_counter)
{
FQ777_send_packet(1);
bind_counter--;
if (bind_counter == 0)
{
@@ -187,31 +222,29 @@ uint16_t FQ777_callback()
BIND_DONE;
}
}
else
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(FQ777_PACKET_PERIOD);
#endif
FQ777_send_packet(0);
}
FQ777_send_packet();
return FQ777_PACKET_PERIOD;
}
uint16_t initFQ777(void)
void FQ777_init(void)
{
BIND_IN_PROGRESS; // autobind protocol
bind_counter = FQ777_BIND_COUNT;
packet_count=0;
hopping_frequency[0] = 0x4D;
hopping_frequency[1] = 0x43;
hopping_frequency[2] = 0x27;
// Sub-protocol hop channel table: first 3 channels differ; channel[3]=0x07 is shared
static const uint8_t hop_ch[2][3] = {
{0x4D, 0x43, 0x27}, // FQ777
{0x49, 0x34, 0x26}, // XBM-37
};
hopping_frequency[0] = hop_ch[sub_protocol][0];
hopping_frequency[1] = hop_ch[sub_protocol][1];
hopping_frequency[2] = hop_ch[sub_protocol][2];
hopping_frequency[3] = 0x07;
hopping_frequency_no=0;
rx_tx_addr[2] = 0x00;
rx_tx_addr[2] = (sub_protocol == XBM37) ? (RX_num & 0x3F) : 0x00; // XBM-37 uses receiver number (0-63) for model match capability
rx_tx_addr[3] = 0xe7;
rx_tx_addr[4] = 0x67;
FQ777_init();
return FQ777_INITIAL_WAIT;
FQ777_RF_init();
}
#endif

View File

@@ -1,113 +0,0 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// Compatible with FEI XIONG P38 plane.
#if defined(FX816_NRF24L01_INO)
#include "iface_nrf24l01.h"
#define FX816_INITIAL_WAIT 500
#define FX816_PACKET_PERIOD 10000
#define FX816_RF_BIND_CHANNEL 0x28 //40
#define FX816_RF_NUM_CHANNELS 4
#define FX816_PAYLOAD_SIZE 6
#define FX816_BIND_COUNT 300 //3sec
static void __attribute__((unused)) FX816_send_packet()
{
packet[0] = IS_BIND_IN_PROGRESS?0x55:0xAA;
packet[1] = rx_tx_addr[0];
packet[2] = rx_tx_addr[1];
uint8_t val=convert_channel_8b(AILERON);
#define FX816_SWITCH 20
if(val>127+FX816_SWITCH)
packet[3] = 1;
else if(val<127-FX816_SWITCH)
packet[3] = 2;
else
packet[3] = 0;
packet[4] = convert_channel_16b_limit(THROTTLE,0,100);
val=0;
for(uint8_t i=0;i<FX816_PAYLOAD_SIZE-1;i++)
val+=packet[i];
packet[5]=val;
NRF24L01_WriteReg(NRF24L01_05_RF_CH, IS_BIND_IN_PROGRESS ? FX816_RF_BIND_CHANNEL:hopping_frequency[hopping_frequency_no++]);
hopping_frequency_no%=FX816_RF_NUM_CHANNELS;
// clear packet status bits and TX FIFO
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(packet, FX816_PAYLOAD_SIZE);
// Power on, TX mode, 2byte CRC
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
NRF24L01_SetPower(); // Set tx_power
}
static void __attribute__((unused)) FX816_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // No retransmits
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01);
NRF24L01_Activate(0x73);
}
static void __attribute__((unused)) FX816_initialize_txid()
{
//Only 8 IDs: the RX led does not indicate frame loss.
//I didn't open the plane to find out if I could connect there so this is the best I came up with with few trial and errors...
rx_tx_addr[0]=0x35+(rx_tx_addr[3]&0x07); //Original dump=0x35
rx_tx_addr[1]=0x09; //Original dump=0x09
memcpy(hopping_frequency,"\x09\x1B\x30\x42",FX816_RF_NUM_CHANNELS); //Original dump=9=0x09,27=0x1B,48=0x30,66=0x42
for(uint8_t i=0;i<FX816_RF_NUM_CHANNELS;i++)
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
}
uint16_t FX816_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(FX816_PACKET_PERIOD);
#endif
if(IS_BIND_IN_PROGRESS)
if(--bind_counter==0)
BIND_DONE;
FX816_send_packet();
return FX816_PACKET_PERIOD;
}
uint16_t initFX816()
{
BIND_IN_PROGRESS; // autobind protocol
FX816_initialize_txid();
FX816_init();
hopping_frequency_no = 0;
bind_counter=FX816_BIND_COUNT;
return FX816_INITIAL_WAIT;
}
#endif

View File

@@ -0,0 +1,415 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// Compatible with FEI XIONG P38 plane.
#if defined(FX_NRF24L01_INO)
#include "iface_xn297.h"
#define FX_BIND_COUNT 300 //3sec
#define FX_SWITCH 20
#define FX_NUM_CHANNELS 4
#define FX816_PACKET_PERIOD 10000
#define FX816_BIND_CHANNEL 40
#define FX816_PAYLOAD_SIZE 6
#define FX816_CH_OFFSET 3
#define FX620_PACKET_PERIOD 3250
#define FX620_BIND_PACKET_PERIOD 4500
#define FX620_BIND_CHANNEL 18
#define FX620_PAYLOAD_SIZE 7
#define FX620_CH_OFFSET 1
#define FX9630_PACKET_PERIOD 8124 //8156 on QIDI-560
#define FX9630_BIND_CHANNEL 51
#define FX9630_PAYLOAD_SIZE 8
#define FX9630_NUM_CHANNELS 3
#define FX9630_WRITE_TIME 500
#define FX_QF012_PACKET_PERIOD 12194
#define FX_QF012_RX_PAYLOAD_SIZE 3
#define FX_BM26_BIND_CHANNEL 40
#define FX_BM26_PACKET_PERIOD 14066
#define FX_A570_PACKET_PERIOD 10270
//#define FORCE_FX620_ID
//#define FORCE_FX9630_ID
//#define FORCE_QIDI_ID
//#define FORCE_FX_A570_ID
enum
{
FX_DATA=0,
FX_RX,
};
static void __attribute__((unused)) FX_send_packet()
{
static uint8_t trim_ch = 0;
//Hopp
if(IS_BIND_DONE)
{
XN297_Hopping(hopping_frequency_no++);
if(sub_protocol >= FX9630)
{ // FX9630 & FX_Q560 & FX_QF012 & FX_A570
if (hopping_frequency_no >= FX9630_NUM_CHANNELS)
{
hopping_frequency_no = 0;
if(sub_protocol == FX9630)
{
trim_ch++;
trim_ch &= 3;
}
else // FX_Q560 & FX_QF012 & FX_A570
trim_ch = 0;
}
}
else // FX816 & FX620
{
hopping_frequency_no &= 0x03;
}
}
memset(packet,0x00,packet_length);
//Channels
uint8_t val;
if (sub_protocol == FX816 || sub_protocol == FX620)
{
uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET;
val=convert_channel_8b(AILERON);
if(val>127+FX_SWITCH)
packet[offset] = sub_protocol == FX816 ? 1:0xFF;
else if(val<127-FX_SWITCH)
packet[offset] = sub_protocol == FX816 ? 2:0x00;
else
packet[offset] = sub_protocol == FX816 ? 0:0x7F;
packet[offset+1] = convert_channel_16b_limit(THROTTLE,0,100); //FX816:0x00..0x63, FX620:0x00..0x5E but that should work
}
else if (sub_protocol == FX_A570)
{
packet[0] = convert_channel_16b_limit(THROTTLE,0x1C,0xE4);
packet[1] = convert_channel_16b_limit(AILERON,0xE4,0x1C);
packet[2] = convert_channel_16b_limit(ELEVATOR,0xE4,0x1C);
packet[3] = convert_channel_16b_limit(RUDDER,0x1C,0xE4);
// Trims - Ruddder L:01 R:02, Aileron L:03 R:04, Elevator Fwd:05 Back:06
packet[4] = (Channel_data[CH10] < CHANNEL_MIN_COMMAND ? 0x01 : GET_FLAG(CH10_SW, 0x02)) // Rudder trim
| (Channel_data[CH11] < CHANNEL_MIN_COMMAND ? 0x03 : GET_FLAG(CH11_SW, 0x04)) // Aileron trim
| (Channel_data[CH12] < CHANNEL_MIN_COMMAND ? 0x06 : GET_FLAG(CH12_SW, 0x05)); // Elevator trim
packet[5] = GET_FLAG(CH5_SW, 0x40) // motors stop
// A570 flight modes = 0>vertical flight(3 axis mode):00, 1>flat flight(6G):02, 2>vertical flight(2 axis mode):04
| (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x04 : 0x02))
| GET_FLAG(CH7_SW, 0x01) // 0:low rate, 1:high rate
| GET_FLAG(CH8_SW, 0x08) // LED color change
| GET_FLAG(CH9_SW, 0x10); // LED off
}
else
{ // FX9630 & FX_Q560 & FX_QF012 & FX_BM26
packet[0] = convert_channel_8b(THROTTLE);
packet[1] = convert_channel_8b(AILERON);
packet[2] = 0xFF - convert_channel_8b(ELEVATOR);
packet[3] = convert_channel_8b(RUDDER);
if ( sub_protocol == FX_BM26 ) // BM26 Ail, Elev, Rud range between 0x00-0x3F-0x7F
{
packet[1] >>= 1;
packet[2] >>= 1;
packet[3] >>= 1;
}
val = trim_ch==0 ? 0x20 : (convert_channel_8b(trim_ch + CH6) >> 2); // no trim on Throttle
packet[4] = val; // Trim for channel x 0C..20..34
packet[5] = (trim_ch << 4) // channel x << 4
| GET_FLAG(CH5_SW, (sub_protocol == FX_QF012 ? 0x08 : 0x01)) // DR toggle swich: 0 small throw, 1 large throw / Q560 acrobatic / QF012 Special effects
// FX9630 =>0:6G small throw, 1:6G large throw, 2:3D
// QIDI-550=>0:3D, 1:6G, 2:Torque
// QF012=>0:beginner(6G), 1:mid(3D), 2:expert(Gyro off)
| (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x04 : 0x02));
if(sub_protocol == FX_Q560)
packet[5] |= GET_FLAG(CH7_SW, 0x18); // Q560 LED flag 0x10 conflicting with trim_ch... Corrected on new boards using 0x08 instead
else if (sub_protocol == FX_QF012)
packet[5] |= GET_FLAG(CH7_SW, 0x40) // QF012 invert flight
| GET_FLAG(CH8_SW, 0x80); // QF012 Restore fine tunning midpoint
else if ( sub_protocol == FX_BM26 )
{
packet[5] &= 0xC0;
packet[5] += 0x40;
// BM26 P51=>0:beginner(6G), 1:mid(3D), 2:expert(Gyro off)
packet[5] |= (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x08 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x0C : 0x0A));
packet[6] = GET_FLAG( CH5_SW, 0x20) // 6G Roll
| GET_FLAG(!CH7_SW, 0x08) // Light control switch, default on
| GET_FLAG(!CH8_SW, 0x10) // Turn signal switch, default on
| GET_FLAG( CH9_SW, 0x01); // Gyro Calibration
}
}
//Bind and specifics
if(sub_protocol == FX816)
{
if(IS_BIND_IN_PROGRESS)
packet[0] = 0x55;
else
packet[0] = 0xAA;
packet[1] = rx_tx_addr[0];
packet[2] = rx_tx_addr[1];
}
else if(sub_protocol == FX620)
{
if(IS_BIND_IN_PROGRESS)
{
memcpy(packet,rx_tx_addr,3);
packet[3] = hopping_frequency[0];
if(bind_counter > (FX_BIND_COUNT >> 1))
packet[5] = 0x78;
}
else
{
packet[0] = 0x1F; // Is it based on ID??
packet[5] = 0xAB; // Is it based on ID??
}
}
else // FX9630 & FX_Q560 & FX_QF012 & FX_BM26 & FX_A570
{
if(IS_BIND_IN_PROGRESS)
{
memcpy(packet,rx_tx_addr, 4);
packet[4] = hopping_frequency[1];
packet[5] = hopping_frequency[2];
packet[7] = 0x55;
}
}
//Check
uint8_t last_packet_idx = packet_length-1;
if (sub_protocol >= FX9630 && IS_BIND_IN_PROGRESS)
last_packet_idx--;
val=0;
for(uint8_t i=0;i<last_packet_idx;i++)
val+=packet[i];
if (sub_protocol >= FX9630)
val = val ^ 0xFF;
packet[last_packet_idx]=val;
if ( IS_BIND_IN_PROGRESS && sub_protocol == FX_BM26 ) packet[7] = packet[6];
//Debug
#if 0
for(uint8_t i=0;i<packet_length;i++)
debug("%02X ",packet[i]);
debugln("");
#endif
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, packet_length);
}
static void __attribute__((unused)) FX_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
packet_length = FX9630_PAYLOAD_SIZE; // default
if(sub_protocol == FX816)
{
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
XN297_RFChannel(FX816_BIND_CHANNEL);
packet_period = FX816_PACKET_PERIOD;
packet_length = FX816_PAYLOAD_SIZE;
}
else if(sub_protocol == FX620)
{
XN297_SetTXAddr((uint8_t *)"\xaa\xbb\xcc", 3);
XN297_RFChannel(FX620_BIND_CHANNEL);
packet_period = FX620_BIND_PACKET_PERIOD;
packet_length = FX620_PAYLOAD_SIZE;
}
else if (sub_protocol == FX_BM26)
{
XN297_SetTXAddr((uint8_t *)"\x12\x34\x10\x10", 4);
XN297_RFChannel(FX_BM26_BIND_CHANNEL);
packet_period = FX_BM26_PACKET_PERIOD;
}
else if(sub_protocol == FX_A570)
{
XN297_SetTXAddr((uint8_t *)"\x56\x78\x92\x13", 4);
XN297_RFChannel(FX9630_BIND_CHANNEL);
packet_period = FX_A570_PACKET_PERIOD;
}
else // FX9630 & FX_Q560 & FX_QF012
{
XN297_SetTXAddr((uint8_t *)"\x56\x78\x90\x12", 4);
XN297_RFChannel(FX9630_BIND_CHANNEL);
packet_period = sub_protocol == FX_QF012 ? FX_QF012_PACKET_PERIOD : FX9630_PACKET_PERIOD;
}
}
static void __attribute__((unused)) FX_initialize_txid()
{
if(sub_protocol == FX816)
{
//Only 8 IDs: the RX led does not indicate frame loss.
//I didn't open the plane to find out if I could connect there so this is the best I came up with with few trial and errors...
rx_tx_addr[0]=0x35+(rx_tx_addr[3]&0x07); //Original dump=0x35
rx_tx_addr[1]=0x09; //Original dump=0x09
memcpy(hopping_frequency,"\x09\x1B\x30\x42",FX_NUM_CHANNELS); //Original dump=9=0x09,27=0x1B,48=0x30,66=0x42
for(uint8_t i=0;i<FX_NUM_CHANNELS;i++)
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
}
else if(sub_protocol == FX620)
{
rx_tx_addr[0] = rx_tx_addr[3];
hopping_frequency[0] = 0x18 + rx_tx_addr[3]&0x07; // just to try something
#ifdef FORCE_FX620_ID
memcpy(rx_tx_addr,(uint8_t*)"\x34\xA9\x32",3);
hopping_frequency[0] = 0x18; //on dump: 24 34 44 54
#endif
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
hopping_frequency[i] = i*10 + hopping_frequency[0];
}
else // FX9630 & FX_Q560 & FX_QF012 & FX_BM26 & FX_A570
{
//??? Need to find out how the first RF channel is calculated ???
hopping_frequency[0] = sub_protocol == FX_BM26? 0x0C : 0x13;
if (sub_protocol == FX_A570) hopping_frequency[0] = 0x0E;
//Other 2 RF channels are sent during the bind phase so they can be whatever
hopping_frequency[1] = RX_num & 0x0F + 0x1A;
hopping_frequency[2] = rx_tx_addr[3] & 0x0F + 0x38;
#ifdef FORCE_FX9630_ID
memcpy(rx_tx_addr,(uint8_t*)"\xCE\x31\x9B\x73", 4);
memcpy(hopping_frequency,"\x13\x1A\x38", FX9630_NUM_CHANNELS); //Original dump=>19=0x13,26=0x1A,56=0x38
#endif
#ifdef FORCE_QIDI_ID
memcpy(rx_tx_addr,(uint8_t*)"\x23\xDC\x76\xA2", 4);
memcpy(hopping_frequency,"\x08\x25\x33", FX9630_NUM_CHANNELS); //Original dump=>08=0x08,37=0x25,51=0x33
//QIDI-560 #1
//memcpy(rx_tx_addr,(uint8_t*)"\x38\xC7\x6D\x8D", 4);
//memcpy(hopping_frequency,"\x0D\x20\x3A", FX9630_NUM_CHANNELS);
#endif
// BM26 rx_tx_addr: "\x17\x03\x00\x00", hopping_frequency: 0x0C,0x30,0x43(12,48,67)
#ifdef FORCE_FX_A570_ID
memcpy(rx_tx_addr,(uint8_t*)"\xA9\x56\xFC\x1C", 4);
memcpy(hopping_frequency,"\x0E\x1F\x39", FX9630_NUM_CHANNELS); //Original dump=>14=0x0E,31=0x1F,57=0x39
#endif
}
}
uint16_t FX_callback()
{
#ifdef FX_HUB_TELEMETRY
bool rx=false;
static uint8_t telem_count = 0;
switch(phase)
{
case FX_DATA:
rx = XN297_IsRX();
XN297_SetTxRxMode(TXRX_OFF);
#endif
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
if(bind_counter)
if(--bind_counter==0)
{
BIND_DONE;
if(sub_protocol == FX620)
{
XN297_SetTXAddr(rx_tx_addr, 3);
packet_period = FX620_PACKET_PERIOD;
}
else if(sub_protocol >= FX9630)
{ // FX9630 & FX_Q560 & FX_QF012
XN297_SetTXAddr(rx_tx_addr, 4);
#ifdef FX_HUB_TELEMETRY
XN297_SetRXAddr(rx_tx_addr, FX_QF012_RX_PAYLOAD_SIZE);
#endif
}
}
FX_send_packet();
#ifdef FX_HUB_TELEMETRY
if (sub_protocol == FX816 || sub_protocol == FX620 || sub_protocol == FX_A570)
break;
if(rx)
{
debug("RX");
if(XN297_ReadPayload(packet_in, FX_QF012_RX_PAYLOAD_SIZE))
{//Good CRC
telemetry_link = 1;
telemetry_lost = 0;
telem_count = 0;
if ( sub_protocol == FX_BM26 )
v_lipo1 = packet_in[0] < packet_in[2] ? 60:81; // packets: AA 00 55 -> 55 00 AA = low voltage 3.7V
else
v_lipo1 = packet_in[1] ? 60:81; // packets: A5 00 11 -> A5 01 11 = low voltage 3.7V
#if 0
for(uint8_t i=0; i < FX_QF012_RX_PAYLOAD_SIZE; i++)
debug(" %02X", packet_in[i]);
#endif
}
debugln();
}
if(telem_count > 4*63) // Around 3.5 sec with no telemetry
telemetry_lost = 1;
else
{
telem_count++;
if(!telemetry_lost && (telem_count & 0x3F) == 0)
{// Should have received a telem packet but... Send telem to the radio to keep it alive
telemetry_link = 1;
#if 0
debugln("Miss");
#endif
}
}
phase++;
return FX9630_WRITE_TIME;
default: //FX_RX
/* { // Wait for packet to be sent before switching to receive mode
uint16_t start=(uint16_t)micros(), count=0;
while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 500)
{
if(XN297_IsPacketSent())
break;
count++;
}
debug("%d",count);
} */
//Switch to RX
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
phase = FX_DATA;
return packet_period - FX9630_WRITE_TIME;
}
#endif
return packet_period;
}
void FX_init()
{
BIND_IN_PROGRESS; // autobind protocol
FX_initialize_txid();
FX_RF_init();
hopping_frequency_no = 0;
bind_counter=FX_BIND_COUNT;
#ifdef FX_HUB_TELEMETRY
RX_RSSI = 100; // Dummy value
telemetry_lost = 1;
phase = FX_DATA;
#endif
}
#endif

View File

@@ -88,34 +88,25 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
NRF24L01_SetPower(); // Set tx_power
}
static void __attribute__((unused)) FY326_init()
static void __attribute__((unused)) FY326_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
if(sub_protocol==FY319)
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // Five-byte rx/tx address
else
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x15\x59\x23\xc6\x29", 5);
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x15\x59\x23\xc6\x29", 5);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, FY326_PACKET_SIZE);
NRF24L01_WriteReg(NRF24L01_05_RF_CH, FY326_RF_BIND_CHANNEL);
NRF24L01_SetBitrate(NRF24L01_BR_250K);
NRF24L01_SetPower();
NRF24L01_Activate(0x73);
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f);
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
NRF24L01_Activate(0x73);
//Switch to RX
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushRx();
NRF24L01_SetTxRxMode(RX_EN);
}
@@ -209,20 +200,19 @@ static void __attribute__((unused)) FY326_initialize_txid()
hopping_frequency[i]=rx_tx_addr[0] & ~0x80;
}
uint16_t initFY326(void)
void FY326_init(void)
{
BIND_IN_PROGRESS; // autobind protocol
rxid = 0xAA;
bind_counter = FY326_BIND_COUNT;
FY326_initialize_txid();
FY326_init();
FY326_RF_init();
if(sub_protocol==FY319)
{
phase=FY319_BIND1;
}
else
phase=FY326_BIND1;
return FY326_INITIAL_WAIT;
}
#endif

View File

@@ -0,0 +1,108 @@
/*
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(FAKE_NRF24L01_INO)
#include "iface_nrf250k.h"
static void __attribute__((unused)) FAKE_send_packet()
{
for(uint8_t i=0;i<5;i++)
packet[i]=i;
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, 5);
}
static void __attribute__((unused)) FAKE_init()
{
// BIND_IN_PROGRESS;
//CC2500
option=1;
XN297L_Init();
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x01); // Packet Automation Control
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x00); // Packet Automation Control
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x12); // Modem Configuration
CC2500_WriteReg(CC2500_13_MDMCFG1, 0x13); // Modem Configuration
CC2500_WriteReg(CC2500_04_SYNC1, 0x11);
CC2500_WriteReg(CC2500_05_SYNC0, 0x33);
CC2500_WriteReg(CC2500_09_ADDR, 0x99);
CC2500_WriteReg(CC2500_06_PKTLEN, 10);
CC2500_SetTxRxMode(RX_EN);
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SRX);
//CC2500_SetTxRxMode(TX_EN);
XN297L_RFChannel(0);
//NRF
/* option=0;
PE1_on; //NRF24L01 antenna RF3 by default
PE2_off; //NRF24L01 antenna RF3 by default
NRF24L01_Initialize();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x7f);
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00);//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_250K); // 1Mbps
NRF24L01_SetPower();
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x99\x33\x11\xAA\xAA", 5); //Bind address
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x99\x33\x11\xAA\xAA", 5); //Bind address
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0);
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
*/
/*NRF24L01_FlushTx();
NRF24L01_SetTxRxMode(TX_EN);*/
}
uint16_t FAKE_callback()
{
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
if(len) debug("L=%d, ",len);
if(len && len < sizeof(packet_in))
{
CC2500_ReadData(packet_in, len);
debug("P:");
for(uint8_t i=0;i<len;i++)
debug(" %02X", packet_in[i]);
}
if(len) debugln("");
CC2500_Strobe(CC2500_SFRX);
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SRX);
option=0;
//FAKE_send_packet();
PE1_off; //antenna RF2
PE2_on;
/*packet[0]=0x99;
for(uint8_t i=1;i<5;i++)
packet[i]=i;
CC2500_WriteData(packet, 5);*/
return 10000;
}
uint16_t initFAKE()
{
FAKE_init();
return 5000;
}
#endif

View File

@@ -12,7 +12,7 @@
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// Last sync with hexfet new_protocols/flysky_a7105.c dated 2015-09-28
// Last sync with hexfet new_protocols/FLYSKY_a7105.c dated 2015-09-28
#if defined(FLYSKY_A7105_INO)
@@ -53,7 +53,7 @@ enum {
const uint8_t PROGMEM V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ?
0x49, 0x49, 0x49, 0x49, 0x49, };
static void __attribute__((unused)) flysky_apply_extension_flags()
static void __attribute__((unused)) FLYSKY_apply_extension_flags()
{
switch(sub_protocol)
{
@@ -129,7 +129,7 @@ static void __attribute__((unused)) flysky_apply_extension_flags()
}
}
static void __attribute__((unused)) flysky_build_packet(uint8_t init)
static void __attribute__((unused)) FLYSKY_send_packet()
{
uint8_t i;
//servodata timing range for flysky.
@@ -137,7 +137,7 @@ static void __attribute__((unused)) flysky_build_packet(uint8_t init)
//+100% =~ 0x07ca//=1994us(max)
//Center = 0x5d9//=1497us(center)
//channel order AIL;ELE;THR;RUD;CH5;CH6;CH7;CH8
packet[0] = init ? 0xaa : 0x55;
packet[0] = IS_BIND_IN_PROGRESS ? 0xaa : 0x55;
packet[1] = rx_tx_addr[3];
packet[2] = rx_tx_addr[2];
packet[3] = rx_tx_addr[1];
@@ -150,36 +150,32 @@ static void __attribute__((unused)) flysky_build_packet(uint8_t init)
packet[5 + i*2]=temp&0xFF; //low byte of servo timing(1000-2000us)
packet[6 + i*2]=(temp>>8)&0xFF; //high byte of servo timing(1000-2000us)
}
flysky_apply_extension_flags();
FLYSKY_apply_extension_flags();
A7105_SetPower();
A7105_WriteData(21, IS_BIND_IN_PROGRESS ? 0x01:hopping_frequency[hopping_frequency_no & 0x0F]);
hopping_frequency_no++;
}
uint16_t ReadFlySky()
uint16_t FLYSKY_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
#ifndef FORCE_FLYSKY_TUNING
A7105_AdjustLOBaseFreq(1);
#endif
if(IS_BIND_IN_PROGRESS)
if(bind_counter)
{
flysky_build_packet(1);
A7105_WriteData(21, 1);
bind_counter--;
if (bind_counter==0)
BIND_DONE;
}
else
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
flysky_build_packet(0);
A7105_WriteData(21, hopping_frequency[hopping_frequency_no & 0x0F]);
A7105_SetPower();
}
hopping_frequency_no++;
FLYSKY_send_packet();
return packet_period;
}
const uint8_t PROGMEM tx_channels[8][4] = {
const uint8_t PROGMEM FLYSKY_tx_channels[8][4] = {
{ 0x12, 0x34, 0x56, 0x78},
{ 0x18, 0x27, 0x36, 0x45},
{ 0x41, 0x82, 0x36, 0x57},
@@ -190,7 +186,7 @@ const uint8_t PROGMEM tx_channels[8][4] = {
{ 0x71, 0x86, 0x43, 0x52}
};
uint16_t initFlySky()
void FLYSKY_init()
{
uint8_t chanrow;
uint8_t chanoffset;
@@ -208,7 +204,7 @@ uint16_t initFlySky()
chanoffset=rx_tx_addr[3]/16;
for(uint8_t i=0;i<16;i++)
{
temp=pgm_read_byte_near(&tx_channels[chanrow>>1][i>>2]);
temp=pgm_read_byte_near(&FLYSKY_tx_channels[chanrow>>1][i>>2]);
if(i&0x02)
temp&=0x0F;
else
@@ -242,6 +238,5 @@ uint16_t initFlySky()
bind_counter = FLYSKY_BIND_COUNT;
else
bind_counter = 0;
return 2400;
}
#endif

View File

@@ -17,6 +17,11 @@
/** FrSky D and X routines **/
/******************************/
#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[]={
@@ -29,7 +34,7 @@ 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, uint8_t init=0)
uint16_t FrSkyX_crc(uint8_t *data, uint8_t len, uint16_t init=0)
{
uint16_t crc = init;
for(uint8_t i=0; i < len; i++)
@@ -38,6 +43,73 @@ uint16_t FrSkyX_crc(uint8_t *data, uint8_t len, uint8_t init=0)
}
#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;
//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 {
@@ -50,8 +122,6 @@ enum {
FRSKY_DATA5,
};
uint8_t FrSkyFormat=0;
void Frsky_init_hop(void)
{
uint8_t val;
@@ -115,11 +185,18 @@ void Frsky_init_clone(void)
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++);
@@ -210,7 +287,7 @@ void Frsky_init_clone(void)
//FRSKYX
/*02_IOCFG0*/ 0x06 ,
/*00_IOCFG2*/ 0x06 ,
/*17_MCSM1*/ 0x0c , //X2->0x0E -> Go/Stay in RX mode
/*17_MCSM1*/ 0x0c , //X2->0x0E -> RX stays in RX and TX stays in TX???
/*18_MCSM0*/ 0x18 ,
/*06_PKTLEN*/ 0x1E ,
/*07_PKTCTRL1*/ 0x04 ,
@@ -298,7 +375,6 @@ void Frsky_init_clone(void)
val=option;
CC2500_WriteReg(reg,val);
}
prev_option = option ; // Save option to monitor FSCTRL0 change
for(uint8_t i=0;i<17;i++)
{
uint8_t reg=pgm_read_byte_near(&FRSKY_common_end_cc2500_conf[i][0]);
@@ -311,23 +387,120 @@ void Frsky_init_clone(void)
}
#endif
#if defined(FRSKYX_CC2500_INO) || defined(FRSKYL_CC2500_INO)
uint8_t FrSkyX_chanskip;
uint8_t FrSkyX_TX_Seq, FrSkyX_TX_IN_Seq;
uint8_t FrSkyX_RX_Seq ;
#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
#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)
{
uint8_t count;
uint8_t payload[8];
} ;
// Store FrskyX telemetry
struct t_FrSkyX_TX_Frame FrSkyX_TX_Frames[4] ;
for (uint8_t i=start+1;i<=end;i++)
packet[i]=0;
packet[start] = FrSkyX_RX_Seq << 4;
#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
#define FRSKYX_FAILSAFE_TIMEOUT 1032
#if defined(FRSKYX_CC2500_INO) || defined(FRSKYL_CC2500_INO)
static void __attribute__((unused)) FrSkyX_set_start(uint8_t ch )
{
CC2500_Strobe(CC2500_SIDLE);
@@ -335,7 +508,7 @@ static void __attribute__((unused)) FrSkyX_set_start(uint8_t ch )
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[ch]);
}
static void __attribute__((unused)) FrSkyX_init()
static void __attribute__((unused)) FrSkyX_RF_init()
{
if(protocol==PROTO_FRSKYL)
FRSKY_init_cc2500(FRSKYL_cc2500_conf);
@@ -346,7 +519,7 @@ static void __attribute__((unused)) FrSkyX_init()
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05); // Enable CRC
if(!(FrSkyFormat&2))
{ // FCC
CC2500_WriteReg(CC2500_17_MCSM1, 0x0E); // Go/Stay in RX mode
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
}
}

View File

@@ -17,12 +17,12 @@
#include "iface_cc2500.h"
static void __attribute__((unused)) frsky2way_init(uint8_t bind)
static void __attribute__((unused)) FRSKYD_RF_init()
{
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_1B_AGCCTRL2, IS_BIND_IN_PROGRESS ? 0x43 : 0x03);
CC2500_WriteReg(CC2500_09_ADDR, IS_BIND_IN_PROGRESS ? 0x03 : rx_tx_addr[3]);
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05);
CC2500_Strobe(CC2500_SIDLE); // Go to idle...
//
@@ -32,7 +32,7 @@ static void __attribute__((unused)) frsky2way_init(uint8_t bind)
//#######END INIT########
}
static void __attribute__((unused)) frsky2way_build_bind_packet()
static void __attribute__((unused)) FRSKYD_build_bind_packet()
{
//11 03 01 d7 2d 00 00 1e 3c 5b 78 00 00 00 00 00 00 01
//11 03 01 19 3e 00 02 8e 2f bb 5c 00 00 00 00 00 00 01
@@ -54,10 +54,10 @@ 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()
static void __attribute__((unused)) FRSKYD_data_frame()
{//pachet[4] is telemetry user frame counter(hub)
//11 d7 2d 22 00 01 c9 c9 ca ca 88 88 ca ca c9 ca 88 88
//11 57 12 00 00 01 f2 f2 f2 f2 06 06 ca ca ca ca 18 18
@@ -71,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;
@@ -94,12 +94,13 @@ static void __attribute__((unused)) frsky2way_data_frame()
}
}
uint16_t initFrSky_2way()
void FRSKYD_init(void)
{
//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;
@@ -109,25 +110,26 @@ uint16_t initFrSky_2way()
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)
{
frsky2way_init(1);
FRSKYD_RF_init();
state = FRSKY_BIND;
}
else
{
state = FRSKY_BIND_DONE;
}
return 10000;
}
uint16_t ReadFrSky_2way()
uint16_t FRSKYD_callback(void)
{
if (state < FRSKY_BIND_DONE)
{
frsky2way_build_bind_packet();
FRSKYD_build_bind_packet();
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, 0x00);
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
@@ -141,10 +143,10 @@ uint16_t ReadFrSky_2way()
}
if (state == FRSKY_BIND_DONE)
{
state = FRSKY_DATA2;
frsky2way_init(0);
counter = 0;
BIND_DONE;
FRSKYD_RF_init();
counter = 0;
state = FRSKY_DATA2;
}
else
if (state == FRSKY_DATA5)
@@ -178,7 +180,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
}
@@ -200,14 +202,10 @@ uint16_t ReadFrSky_2way()
}
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[counter % 47]);
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
prev_option = option ;
}
CC2500_SetFreqOffset();
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
CC2500_Strobe(CC2500_SFRX);
frsky2way_data_frame();
FRSKYD_data_frame();
CC2500_WriteData(packet, packet[0]+1);
state++;
}

View File

@@ -137,7 +137,7 @@ static void __attribute__((unused)) FrSkyL_encode_packet(bool type)
}
}
uint16_t ReadFrSkyL()
uint16_t FRSKYL_callback()
{
static uint8_t written=0, send=0;
switch(send)
@@ -200,11 +200,7 @@ uint16_t ReadFrSkyL()
break;
case FRSKY_DATA1:
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); //Frequency offset hack
prev_option = option ;
}
CC2500_SetFreqOffset();
FrSkyX_set_start(hopping_frequency_no);
FrSkyL_build_packet();
FrSkyL_encode_packet(true);
@@ -216,7 +212,7 @@ uint16_t ReadFrSkyL()
return 1;
}
uint16_t initFrSkyL()
void FRSKYL_init()
{
set_rx_tx_addr(MProtocol_id_master);
rx_tx_addr[1]=0x02; // ID related, hw version?
@@ -231,7 +227,7 @@ uint16_t initFrSkyL()
while(!FrSkyX_chanskip)
FrSkyX_chanskip=random(0xfefefefe)%47;
FrSkyX_init();
FrSkyX_RF_init();
//Prepare frame
memset(FrSkyL_buffer,0x00,FRSKYL_PACKET_LEN-3);
@@ -257,6 +253,5 @@ uint16_t initFrSkyL()
state = FRSKY_DATA1;
FrSkyX_initialize_data(0);
}
return 10000;
}
#endif

View File

@@ -1,96 +1,194 @@
#if defined(FRSKYR9_SX1276_INO)
#include "iface_sx1276.h"
#define FREQ_MAP_SIZE 29
#define DISP_FREQ_TABLE
// TODO the channel spacing is equal, consider calculating the new channel instead of using lookup tables (first_chan + index * step)
#define FLEX_FREQ 29
#define FCC_FREQ 43
#define EU_FREQ 19
static uint32_t FrSkyR9_freq_map_915[FREQ_MAP_SIZE] =
{
914472960,
914972672,
915472384,
915972096,
916471808,
916971520,
917471232,
917970944,
918470656,
918970368,
919470080,
919969792,
920469504,
920969216,
921468928,
921968640,
922468352,
922968064,
923467776,
923967488,
924467200,
924966912,
925466624,
925966336,
926466048,
926965760,
927465472,
// last two determined by FrSkyR9_step
0,
0
enum {
FRSKYR9_FREQ=0,
FRSKYR9_DATA,
FRSKYR9_RX1,
FRSKYR9_RX2,
};
static uint32_t FrSkyR9_freq_map_868[FREQ_MAP_SIZE] =
void FrSkyR9_set_frequency()
{
859504640,
860004352,
860504064,
861003776,
861503488,
862003200,
862502912,
863002624,
863502336,
864002048,
864501760,
865001472,
865501184,
866000896,
866500608,
867000320,
867500032,
867999744,
868499456,
868999168,
869498880,
869998592,
870498304,
870998016,
871497728,
871997440,
872497152,
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;
// last two determined by FrSkyR9_step
0,
0
};
#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 uint8_t FrSkyR9_step = 1;
static uint32_t* FrSkyR9_freq_map = FrSkyR9_freq_map_915;
uint16_t initFrSkyR9()
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);
}
void FRSKYR9_init()
{
//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);
if(sub_protocol & 0x01)
FrSkyR9_freq_map = FrSkyR9_freq_map_868;
//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
FrSkyR9_freq_map = FrSkyR9_freq_map_915;
FrSkyR9_step = 1 + (random(0xfefefefe) % 24);
FrSkyR9_freq_map[27] = FrSkyR9_freq_map[FrSkyR9_step];
FrSkyR9_freq_map[28] = FrSkyR9_freq_map[FrSkyR9_step+1];
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);
@@ -106,103 +204,116 @@ uint16_t initFrSkyR9()
SX1276_SetPreambleLength(9);
SX1276_SetDetectionThreshold(SX1276_MODEM_DETECTION_THRESHOLD_SF6);
SX1276_SetLna(1, true);
SX1276_SetHopPeriod(0); // 0 = disabled, we hope frequencies manually
SX1276_SetPaDac(true);
hopping_frequency_no = 0;
// TODO this can probably be shorter
return 20000; // start calling FrSkyR9_callback in 20 milliseconds
SX1276_SetHopPeriod(0); // 0 = disabled, we hop frequencies manually
//RF Power
SX1276_SetPaDac(false); // Disable 20dBm mode
#if MULTI_5IN1_INTERNAL == JP_T18
SX1276_SetPaConfig(true, 7, 0); // Lowest power for the T18: 2dBm
#else
SX1276_SetPaConfig(true, 7, option); // Use PA_HP on PA_BOOST, power=17-(15-option) dBm with option equal or lower to 15
#endif
SX1276_SetOcp(true,27); // Set OCP to max 240mA
SX1276_SetTxRxMode(TX_EN); // Set RF switch to TX
//Enable all IRQ flags
SX1276_WriteReg(SX1276_11_IRQFLAGSMASK,0x00);
FrSkyX_telem_init();
hopping_frequency_no=0;
phase=FRSKYR9_FREQ;
}
uint16_t FrSkyR9_callback()
uint16_t FRSKYR9_callback()
{
SX1276_SetMode(true, false, SX1276_OPMODE_STDBY);
//SX1276_WriteReg(SX1276_11_IRQFLAGSMASK, 0xbf); // use only RxDone interrupt
// uint8_t buffer[2];
// buffer[0] = 0x00;
// buffer[1] = 0x00;
// SX1276_WriteRegisterMulti(SX1276_40_DIOMAPPING1, buffer, 2); // RxDone interrupt mapped to DIO0 (the rest are not used because of the REG_IRQ_FLAGS_MASK)
// SX1276_WriteReg(REG_PAYLOAD_LENGTH, 13);
// SX1276_WriteReg(REG_FIFO_ADDR_PTR, 0x00);
// SX1276_WriteReg(SX1276_01_OPMODE, 0x85); // RXCONTINUOUS
// delay(10); // 10 ms
// SX1276_WriteReg(SX1276_01_OPMODE, 0x81); // STDBY
//SX1276_WriteReg(SX1276_09_PACONFIG, 0xF0);
// 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);
SX1276_SetFrequency(FrSkyR9_freq_map[hopping_frequency_no]); // set current center frequency
delayMicroseconds(500);
packet[0] = 0x3C; // ????
packet[1] = rx_tx_addr[3]; // unique radio id
packet[2] = rx_tx_addr[2]; // unique radio id
packet[3] = hopping_frequency_no; // current channel index
packet[4] = FrSkyR9_step; // step size and last 2 channels start index
packet[5] = RX_num; // receiver number from OpenTX
// binding mode: 0x00 regular / 0x41 bind?
if(IS_BIND_IN_PROGRESS)
packet[6] = 0x41;
else
packet[6] = 0x00;
// TODO
packet[7] = 0x00; // fail safe related (looks like the same sequence of numbers as FrskyX protocol)
// two channel are spread over 3 bytes.
// each channel is 11 bit + 1 bit (msb) that states whether
// it's part of the upper channels (9-16) or lower (1-8) (0 - lower 1 - upper)
#define CH_POS 8
static uint8_t chan_start=0;
uint8_t chan_index = chan_start;
for(int i = 0; i < 12; i += 3)
switch (phase)
{
// map channel values (0-2047) to (64-1984)
uint16_t ch1 = FrSkyX_scaleForPXX(chan_index);
uint16_t ch2 = FrSkyX_scaleForPXX(chan_index + 1);
packet[CH_POS + i] = ch1;
packet[CH_POS + i + 1] = (ch1 >> 8) | (ch2 << 4);
packet[CH_POS + i + 2] = (ch2 >> 4);
chan_index += 2;
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 ( (if pa_boost_pin == true))
#if MULTI_5IN1_INTERNAL != JP_T18
if(option != prev_option)
{ // Set RF power if it has changed
SX1276_SetPaConfig(true, 7, option); // Use PA_HP on PA_BOOST, power=17-(15-option) dBm with option equal or lower to 15
prev_option = option;
}
#endif
//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);
//Clear all IRQ flags
SX1276_WriteReg(SX1276_12_REGIRQFLAGS,0xFF);
//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
phase=FRSKYR9_FREQ;
break;
#endif
}
if((sub_protocol & 0x02) == 0)
chan_start ^= 0x08; // Alternate between lower and upper when 16 channels is used
packet[20] = 0x08; // ????
packet[21] = 0x00; // ????
packet[22] = 0x00; // ????
packet[23] = 0x00; // ????
uint16_t crc = FrSkyX_crc(packet, 24);
packet[24] = crc; // low byte
packet[25] = crc >> 8; // high byte
SX1276_WritePayloadToFifo(packet, 26);
hopping_frequency_no = (hopping_frequency_no + FrSkyR9_step) % FREQ_MAP_SIZE;
SX1276_SetMode(true, false, SX1276_OPMODE_TX);
// need to clear RegIrqFlags?
return 19400;
return 1000;
}
#endif

View File

@@ -113,7 +113,7 @@ static void __attribute__((unused)) FRSKYV_build_data_packet()
packet[14] = FRSKYV_crc8(crc8, packet, 14);
}
uint16_t ReadFRSKYV()
uint16_t FRSKYV_callback(void)
{
if(IS_BIND_DONE)
{ // Normal operation
@@ -122,11 +122,7 @@ uint16_t ReadFRSKYV()
#endif
uint8_t chan = FRSKYV_calc_channel();
CC2500_Strobe(CC2500_SIDLE);
if (option != prev_option)
{
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
prev_option=option;
}
CC2500_SetFreqOffset();
CC2500_WriteReg(CC2500_0A_CHANNR, chan * 5 + 6);
FRSKYV_build_data_packet();
@@ -152,7 +148,7 @@ uint16_t ReadFRSKYV()
return 53460;
}
uint16_t initFRSKYV()
void FRSKYV_init(void)
{
//ID is 15 bits. Using rx_tx_addr[2] and rx_tx_addr[3] since we want to use RX_Num for model match
rx_tx_addr[2]&=0x7F;
@@ -162,7 +158,6 @@ uint16_t initFRSKYV()
seed = 1;
binding_idx=0;
phase = FRSKYV_DATA1;
return 10000;
}
#endif

View File

@@ -19,17 +19,14 @@
static void __attribute__((unused)) FrSkyX_build_bind_packet()
{
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
packet[0] = packet_length; // 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
packet[3] = rx_tx_addr[3]; // ID
packet[4] = rx_tx_addr[2]; // ID
if(protocol==PROTO_FRSKYX)
{
@@ -40,10 +37,10 @@ static void __attribute__((unused)) FrSkyX_build_bind_packet()
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[11] = rx_tx_addr[1]; // ID
packet[12] = RX_num;
//
memset(&packet[13], 0, packet_size - 14);
memset(&packet[13], 0, packet_length - 14);
if(binding_idx&0x01)
memcpy(&packet[13],(void *)"\x55\xAA\x5A\xA5",4); // Telem off
if(binding_idx&0x02)
@@ -52,69 +49,46 @@ static void __attribute__((unused)) FrSkyX_build_bind_packet()
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?
//Unknown bytes
if(state & 0x01)
memcpy(&packet[7],"\x00\xCC\x00\x00\x00\x70\x14\x15\x00\xD3\x08\x00\x00\xCE\xE2\x85\xC7\x00\x00\x00\x00",21);
else
memcpy(&packet[7],"\x27\xFB\x00\x00\x00\xBC\xEF\x19\x00\x26\x07\x00\x00\xB7\xED\x85\xC7\xA7\xA7\xA7\xA7",21);
//ID
packet[5] = rx_tx_addr[1]; // 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
//Replace the ID
packet[20] ^= rx_tx_addr[3]; // Update the ID
packet[21] ^= rx_tx_addr[2]; // Update the ID
packet[22] ^= rx_tx_addr[1] & 0x3F; // Update the ID
//Xor
for(uint8_t i=3; i<packet_size-1; i++)
for(uint8_t i=3; i<packet_length-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;
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_length-4);
packet[packet_length-1] = lcrc >> 8;
packet[packet_length] = lcrc;
/*//Debug
debug("Bind:");
for(uint8_t i=0;i<=packet_size;i++)
for(uint8_t i=0;i<=packet_length;i++)
debug(" %02X",packet[i]);
debugln("");*/
}
#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 < (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++;
#endif
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[0] = packet_length; // 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?
@@ -122,138 +96,31 @@ static void __attribute__((unused)) FrSkyX_build_packet()
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(FrSkyFormat & 0x01 ) //In X8 mode send only 8ch every 9ms
chan_offset = 0 ;
else
chan_offset^=0x08;
//Channels
FrSkyX_channels(7); // Set packet[7]=failsafe, packet[8]=0?? and packet[9..20]=channels data
//sequence and send SPort
for (uint8_t i=22;i<packet_size-1;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<packet_size-1;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
//Sequence and send SPort
FrSkyX_seq_sport(21,packet_length-((protocol==PROTO_FRSKYX && (FrSkyFormat & 2 )) ? 4 : 2)); //21=RX|TXseq, 22=bytes count, 23..packet_length-2=data
//CRC
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_size-4);
packet[packet_size-1] = lcrc >> 8;
packet[packet_size] = lcrc;
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_length-4);
packet[packet_length-1] = lcrc >> 8;
packet[packet_length] = lcrc;
/*//Debug
debug("Norm:");
for(uint8_t i=0;i<=packet_size;i++)
for(uint8_t i=0;i<=packet_length;i++)
debug(" %02X",packet[i]);
debugln("");*/
}
uint16_t ReadFrSkyX()
uint16_t FRSKYX_callback()
{
#if defined MULTI_EU
if(sub_protocol == CH_16 || sub_protocol == CH_8)
return 9000;
#endif
switch(state)
{
default:
@@ -268,28 +135,24 @@ uint16_t ReadFrSkyX()
state = FRSKY_BIND_DONE;
else
state++;
return 9000;
break;
case FRSKY_BIND_DONE:
FrSkyX_initialize_data(0);
hopping_frequency_no=0;
BIND_DONE;
state++; //FRSKY_DATA1
state++; //FRSKY_DATA1
break;
case FRSKY_DATA1:
CC2500_Strobe(CC2500_SIDLE);
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); //Frequency offset hack
prev_option = option ;
}
CC2500_SetFreqOffset();
FrSkyX_set_start(hopping_frequency_no);
FrSkyX_build_packet();
if(FrSkyFormat & 2)
{// LBT
CC2500_Strobe(CC2500_SRX); //Acquire RSSI
CC2500_Strobe(CC2500_SRX); //Acquire RSSI
state++;
return 400; // LBT v2.1
return 400; // LBT
}
case FRSKY_DATA2:
if(FrSkyFormat & 2)
@@ -299,135 +162,130 @@ uint16_t ReadFrSkyX()
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
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 > 72 && rssi < 128) //LBT and RSSI between -36 and -8.5 dBm
if ( rssi > 14 && rssi < 128) //if RSSI above -65dBm (12=-70) => ETSI requirement
#endif
{
POWER_FLAG_off; // Reduce to low power before transmitting
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);
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 v2.1
return 4000; // LBT
else
return 5200; // FCC v2.1
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 4100; // LBT v2.1
return 4200; // LBT
else
return 3300; // FCC v2.1
case FRSKY_DATA4:
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
{
//debug("Telem:");
packet_count=0;
CC2500_ReadData(packet_in, len);
#if defined TELEMETRY
if(protocol==PROTO_FRSKYX || (protocol==PROTO_FRSKYX2 && (packet_in[len-1] & 0x80)) )
{//with valid crc for FRSKYX2
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]);
frsky_check_telemetry(packet_in,len); //Check and parse telemetry packets
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
}
}
#endif
//debugln("");
}
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
//debugln("");
}
CC2500_Strobe(CC2500_SFRX); //Flush the RXFIFO
}
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;
return 500; // FCC & LBT v2.1
}
return 1;
return 400; // FCC & LBT
}
return 9000;
}
uint16_t initFrSkyX()
void FRSKYX_init()
{
set_rx_tx_addr(MProtocol_id_master);
FrSkyFormat = sub_protocol;
if (sub_protocol==XCLONE)
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
if(protocol==PROTO_FRSKYX)
Frsky_init_hop();
else
{
#ifdef FRSKYX2_FORCE_ID
rx_tx_addr[3]=0x0E;
rx_tx_addr[2]=0x1C;
FrSkyX_chanskip=18;
#endif
FrSkyX2_init_hop();
}
rx_tx_addr[1]=0x02; // ID related, hw version?
FrSkyX2_init_hop();
}
if(protocol==PROTO_FRSKYX && (FrSkyFormat & 2 ))
packet_length = 0x20; // FrSkyX V1 LBT
else
packet_length = 0x1D;
packet_count=0;
while(!FrSkyX_chanskip)
FrSkyX_chanskip=random(0xfefefefe)%47;
FrSkyX_init();
FrSkyX_RF_init();
if(IS_BIND_IN_PROGRESS)
{
memset(packet, 0, packet_length);
state = FRSKY_BIND;
FrSkyX_initialize_data(1);
}
else
{
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
binding_idx=0; // CH1-8 and Telem on
return 10000;
}
state = FRSKY_BIND_DONE;
FrSkyX_telem_init();
}
#endif

View File

@@ -40,7 +40,7 @@ enum {
FRSKY_RX_DATA,
};
const PROGMEM uint8_t frsky_rx_common_reg[][2] = {
const PROGMEM uint8_t FRSKY_RX_common_reg[][2] = {
{CC2500_02_IOCFG0, 0x01},
{CC2500_18_MCSM0, 0x18},
{CC2500_07_PKTCTRL1, 0x05},
@@ -68,7 +68,7 @@ const PROGMEM uint8_t frsky_rx_common_reg[][2] = {
{CC2500_09_ADDR, 0x03},
};
const PROGMEM uint8_t frsky_rx_d16fcc_reg[][2] = {
const PROGMEM uint8_t FRSKY_RX_d16fcc_reg[][2] = {
{CC2500_17_MCSM1, 0x0C},
{CC2500_0E_FREQ1, 0x76},
{CC2500_0F_FREQ0, 0x27},
@@ -81,7 +81,7 @@ const PROGMEM uint8_t frsky_rx_d16fcc_reg[][2] = {
{CC2500_15_DEVIATN, 0x51},
};
const PROGMEM uint8_t frsky_rx_d16lbt_reg[][2] = {
const PROGMEM uint8_t FRSKY_RX_d16lbt_reg[][2] = {
{CC2500_17_MCSM1, 0x0E},
{CC2500_0E_FREQ1, 0x80},
{CC2500_0F_FREQ0, 0x00},
@@ -94,7 +94,7 @@ const PROGMEM uint8_t frsky_rx_d16lbt_reg[][2] = {
{CC2500_15_DEVIATN, 0x53},
};
const PROGMEM uint8_t frsky_rx_d8_reg[][2] = {
const PROGMEM uint8_t FRSKY_RX_d8_reg[][2] = {
{CC2500_17_MCSM1, 0x0C},
{CC2500_0E_FREQ1, 0x76},
{CC2500_0F_FREQ0, 0x27},
@@ -107,32 +107,32 @@ const PROGMEM uint8_t frsky_rx_d8_reg[][2] = {
{CC2500_15_DEVIATN, 0x42},
};
static uint8_t frsky_rx_chanskip;
static int8_t frsky_rx_finetune;
static uint8_t frsky_rx_format;
static uint8_t FRSKY_RX_chanskip;
static int8_t FRSKY_RX_finetune;
static uint8_t FRSKY_RX_format;
static void __attribute__((unused)) frsky_rx_strobe_rx()
static void __attribute__((unused)) FRSKY_RX_strobe_rx()
{
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SFRX);
CC2500_Strobe(CC2500_SRX);
}
static void __attribute__((unused)) frsky_rx_initialise_cc2500() {
const uint8_t frsky_rx_length[] = { FRSKY_RX_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];
static void __attribute__((unused)) FRSKY_RX_initialise_cc2500() {
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]));
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)
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)
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
@@ -141,36 +141,36 @@ static void __attribute__((unused)) frsky_rx_initialise_cc2500() {
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)
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]));
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;
CC2500_SetTxRxMode(rx_disable_lna ? TXRX_OFF : RX_EN); // lna disable / enable
frsky_rx_strobe_rx();
FRSKY_RX_strobe_rx();
delayMicroseconds(1000); // wait for RX to activate
}
static void __attribute__((unused)) frsky_rx_set_channel(uint8_t channel)
static void __attribute__((unused)) FRSKY_RX_set_channel(uint8_t channel)
{
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[channel]);
if(frsky_rx_format == FRSKY_RX_D8)
if(FRSKY_RX_format == FRSKY_RX_D8)
CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
CC2500_WriteReg(CC2500_25_FSCAL1, calData[channel]);
frsky_rx_strobe_rx();
FRSKY_RX_strobe_rx();
}
static void __attribute__((unused)) frsky_rx_calibrate()
static void __attribute__((unused)) FRSKY_RX_calibrate()
{
frsky_rx_strobe_rx();
FRSKY_RX_strobe_rx();
for (unsigned c = 0; c < 47; c++)
{
CC2500_Strobe(CC2500_SIDLE);
@@ -193,7 +193,7 @@ static uint8_t __attribute__((unused)) frskyx_rx_check_crc_id(bool bind,bool ini
uint8_t offset=bind?3:1;
// Check D8 checksum
if (frsky_rx_format == FRSKY_RX_D8)
if (FRSKY_RX_format == FRSKY_RX_D8)
{
if((packet[packet_length+1] & 0x80) != 0x80) // Check CRC_OK flag in status byte 2
return false; // Bad CRC
@@ -201,15 +201,16 @@ static uint8_t __attribute__((unused)) frskyx_rx_check_crc_id(bool bind,bool ini
{//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])
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 (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");
@@ -221,12 +222,12 @@ static uint8_t __attribute__((unused)) frskyx_rx_check_crc_id(bool bind,bool ini
return false; // Bad CRC
//debugln("Checksum ok");
if (bind && (frsky_rx_format == FRSKY_RX_D16v2LBT || frsky_rx_format == FRSKY_RX_D16v2FCC))
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))
if (bind && (FRSKY_RX_format == FRSKY_RX_D16LBT || FRSKY_RX_format == FRSKY_RX_D16FCC))
offset2=6;
if(init)
{//Save TXID
@@ -247,7 +248,7 @@ static uint8_t __attribute__((unused)) frskyx_rx_check_crc_id(bool bind,bool ini
return true; // Full match
}
static void __attribute__((unused)) frsky_rx_build_telemetry_packet()
static void __attribute__((unused)) FRSKY_RX_build_telemetry_packet()
{
uint16_t raw_channel[8];
uint32_t bits = 0;
@@ -255,7 +256,7 @@ static void __attribute__((unused)) frsky_rx_build_telemetry_packet()
uint8_t idx = 0;
uint8_t i;
if (frsky_rx_format == FRSKY_RX_D8)
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]);
@@ -298,7 +299,7 @@ static void __attribute__((unused)) frsky_rx_build_telemetry_packet()
packet_in[idx++] = RX_LQI;
packet_in[idx++] = RX_RSSI;
packet_in[idx++] = 0; // start channel
packet_in[idx++] = frsky_rx_format == FRSKY_RX_D8 ? 8 : 16; // number of channels in packet
packet_in[idx++] = FRSKY_RX_format == FRSKY_RX_D8 ? 8 : 16; // number of channels in packet
// pack channels
for (i = 0; i < packet_in[3]; i++) {
@@ -312,29 +313,29 @@ static void __attribute__((unused)) frsky_rx_build_telemetry_packet()
}
}
static void __attribute__((unused)) frsky_rx_data()
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;
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);
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)
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;
FrSkyFormat=FRSKY_RX_format == FRSKY_RX_D16v2FCC?0:2;
FrSkyX2_init_hop();
}
debug("ch:");
@@ -342,52 +343,74 @@ static void __attribute__((unused)) frsky_rx_data()
debug(" %02X", hopping_frequency[ch]);
debugln("");
frsky_rx_initialise_cc2500();
frsky_rx_calibrate();
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);
CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
else
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
frsky_rx_set_channel(hopping_frequency_no);
FRSKY_RX_set_channel(hopping_frequency_no);
phase = FRSKY_RX_DATA;
}
uint16_t initFrSky_Rx()
void FRSKY_RX_init()
{
state = 0;
frsky_rx_chanskip = 1;
hopping_frequency_no = 0;
rx_data_started = false;
frsky_rx_finetune = 0;
telemetry_link = 0;
packet_count = 0;
if (IS_BIND_IN_PROGRESS)
if(sub_protocol == FRSKY_ERASE)
{
frsky_rx_format = FRSKY_RX_D8;
frsky_rx_initialise_cc2500();
phase = FRSKY_RX_TUNE_START;
debugln("FRSKY_RX_TUNE_START");
if(IS_BIND_IN_PROGRESS)
{// Clear all cloned addresses
uint16_t addr[]={ FRSKYD_CLONE_EEPROM_OFFSET+1, FRSKYX_CLONE_EEPROM_OFFSET+1, FRSKYX2_CLONE_EEPROM_OFFSET+1 };
for(uint8_t i=0; i<3;i++)
for(uint8_t j=0; j<3;j++)
eeprom_write_byte((EE_ADDR)(addr[i]+j), 0xFF);
packet_count = 100;
}
}
else
frsky_rx_data();
return 1000;
{
FRSKY_RX_chanskip = 1;
hopping_frequency_no = 0;
rx_data_started = false;
FRSKY_RX_finetune = 0;
telemetry_link = 0;
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
FRSKY_RX_data();
}
}
uint16_t FrSky_Rx_callback()
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(sub_protocol == FRSKY_ERASE)
{
if(packet_count)
packet_count--;
else
BIND_DONE;
return 10000; // Nothing to do...
}
if(IS_BIND_DONE && phase != FRSKY_RX_DATA)
FRSKY_RX_init(); // Abort bind
if ((prev_option != option) && (phase >= FRSKY_RX_DATA))
{
if (option == 0)
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
else
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
prev_option = option;
@@ -408,19 +431,20 @@ uint16_t FrSky_Rx_callback()
CC2500_ReadData(packet, len);
if(frskyx_rx_check_crc_id(true,true))
{
frsky_rx_finetune = -127;
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
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();
FRSKY_RX_strobe_rx();
state = 0;
return 1000;
}
}
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();
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:
@@ -428,18 +452,18 @@ uint16_t FrSky_Rx_callback()
{
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);
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();
FRSKY_RX_strobe_rx();
return 1000;
}
}
frsky_rx_finetune += 1;
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
frsky_rx_strobe_rx();
FRSKY_RX_finetune += 1;
CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
FRSKY_RX_strobe_rx();
return 18000;
case FRSKY_RX_TUNE_HIGH:
@@ -447,9 +471,9 @@ uint16_t FrSky_Rx_callback()
{
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);
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;
@@ -460,13 +484,13 @@ uint16_t FrSky_Rx_callback()
phase = FRSKY_RX_TUNE_START;
debugln("FRSKY_RX_TUNE_START");
}
frsky_rx_strobe_rx();
FRSKY_RX_strobe_rx();
return 1000;
}
}
frsky_rx_finetune -= 1;
CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune);
frsky_rx_strobe_rx();
FRSKY_RX_finetune -= 1;
CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
FRSKY_RX_strobe_rx();
return 18000;
case FRSKY_RX_BIND:
@@ -474,7 +498,7 @@ uint16_t FrSky_Rx_callback()
{
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)
if(FRSKY_RX_format != FRSKY_RX_D16v2LBT && FRSKY_RX_format != FRSKY_RX_D16v2FCC)
{// D8 & D16v1
if(packet[5] <= 0x2D)
{
@@ -484,7 +508,7 @@ uint16_t FrSky_Rx_callback()
}
}
else
state=0x3FF; //No hop table for D16v2
state = 0x3FF; //No hop table for D16v2
if (state == 0x3FF)
{
debugln("Bind complete");
@@ -493,27 +517,27 @@ uint16_t FrSky_Rx_callback()
uint16_t temp = FRSKY_RX_EEPROM_OFFSET;
if(sub_protocol==FRSKY_CLONE)
{
if(frsky_rx_format==FRSKY_RX_D8)
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)
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++, 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)
if(sub_protocol == FRSKY_RX || sub_protocol == FRSKY_CPPM) // FRSKY_RX, FRSKY_CPPM
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();
FRSKY_RX_data();
debugln("FRSKY_RX_DATA");
}
}
frsky_rx_strobe_rx();
FRSKY_RX_strobe_rx();
}
return 1000;
@@ -530,31 +554,35 @@ uint16_t FrSky_Rx_callback()
RX_RSSI += 128;
bool chanskip_valid=true;
// hop to next channel
if (frsky_rx_format != FRSKY_RX_D8)
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)))
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
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
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);
hopping_frequency_no = (hopping_frequency_no + FRSKY_RX_chanskip) % 47;
FRSKY_RX_set_channel(hopping_frequency_no);
if(chanskip_valid)
{
if (telemetry_link == 0)
if ((telemetry_link & 0x7F) == 0)
{ // send channels to TX
frsky_rx_build_telemetry_packet();
FRSKY_RX_build_telemetry_packet();
telemetry_link = 1;
#ifdef SEND_CPPM
if(sub_protocol == FRSKY_CPPM)
telemetry_link |= 0x80; // Disable telemetry output
#endif
}
pps_counter++;
}
@@ -578,8 +606,8 @@ uint16_t FrSky_Rx_callback()
// 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);
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

View File

@@ -14,10 +14,12 @@
*/
// Last sync with main deviation/sfhss_cc2500.c dated 2016-03-23
#if defined(SFHSS_CC2500_INO)
#if defined(FUTABA_CC2500_INO)
#include "iface_cc2500.h"
//#define SFHSS_DEBUG_TIMING
#define SFHSS_COARSE 0
#define SFHSS_PACKET_LEN 13
@@ -79,7 +81,6 @@ static void __attribute__((unused)) SFHSS_rf_init()
for (uint8_t i = 0; i < 39; ++i)
CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i]));
prev_option = option;
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
CC2500_SetTxRxMode(TX_EN);
@@ -125,7 +126,7 @@ static void __attribute__((unused)) SFHSS_calc_next_chan()
// Channel values are 12-bit values between 1020 and 2020, 1520 is the middle.
// Futaba @140% is 2070...1520...970
// Values grow down and to the right.
static void __attribute__((unused)) SFHSS_build_data_packet()
static void __attribute__((unused)) SFHSS_send_packet()
{
uint16_t ch[4];
// command.bit0 is the packet number indicator: =0 -> SFHSS_DATA1, =1 -> SFHSS_DATA2
@@ -165,16 +166,14 @@ static void __attribute__((unused)) SFHSS_build_data_packet()
// 3584-4095 -> looks to be used for the throttle channel with values ranging from 880µs to 1520µs
for(uint8_t i=0;i<4;i++)
{
ch[i]=Failsafe_data[CH_AETR[ch_offset+i]];
if(ch[i]==FAILSAFE_CHANNEL_HOLD)
uint16_t val=Failsafe_data[CH_AETR[ch_offset+i]];
if(val==FAILSAFE_CHANNEL_HOLD)
ch[i]=1024;
else if(ch[i]==FAILSAFE_CHANNEL_NOPULSES)
else if(val==FAILSAFE_CHANNEL_NOPULSES)
ch[i]=0;
else
{ //Use channel value
ch[i]=(ch[i]>>1)+2560;
//if(IS_DISABLE_CH_MAP_off && ch_offset+i==CH3 && ch[i]<3072) // Throttle
// ch[i]+=1024;
ch[i] = convert_channel_16b_nolimit(CH_AETR[ch_offset+i],3571,2571,true); //3472,2672: not enough throw
}
}
}
@@ -182,7 +181,7 @@ static void __attribute__((unused)) SFHSS_build_data_packet()
#endif
{ //Normal data
for(uint8_t i=0;i<4;i++)
ch[i] = convert_channel_16b_nolimit(CH_AETR[ch_offset+i],2020,1020);
ch[i] = convert_channel_16b_nolimit(CH_AETR[ch_offset+i],2020,1020,false);
}
@@ -203,15 +202,17 @@ static void __attribute__((unused)) SFHSS_build_data_packet()
packet[10] = (ch[2] << 7) | ((ch[3] >> 5) & 0x7F );
packet[11] = (ch[3] << 3) | ((fhss_code >> 2) & 0x07 );
packet[12] = (fhss_code << 6) | command;
}
static void __attribute__((unused)) SFHSS_send_packet()
{
CC2500_WriteData(packet, SFHSS_PACKET_LEN);
}
uint16_t ReadSFHSS()
uint16_t SFHSS_callback()
{
#ifdef SFHSS_DEBUG_TIMING
static uint16_t prev_adjust_timing=1024;
uint16_t adjust_timing = (Channel_data[CH15]>>3) - (1024>>3); // +-102 @ 100%
#endif
switch(phase)
{
case SFHSS_START:
@@ -238,16 +239,27 @@ uint16_t ReadSFHSS()
#ifdef MULTI_SYNC
telemetry_set_input_sync(6800);
#endif
SFHSS_build_data_packet();
SFHSS_send_packet();
phase = SFHSS_DATA2;
#ifdef SFHSS_DEBUG_TIMING
return SFHSS_DATA2_TIMING - adjust_timing;
#else
return SFHSS_DATA2_TIMING; // original 1650
#endif
case SFHSS_DATA2:
SFHSS_build_data_packet();
SFHSS_send_packet();
SFHSS_calc_next_chan();
phase = SFHSS_TUNE;
return (SFHSS_PACKET_PERIOD -2000 -SFHSS_DATA2_TIMING); // original 2000
#ifdef SFHSS_DEBUG_TIMING
if(prev_adjust_timing != adjust_timing)
{
debugln("A:%d",(uint16_t)(SFHSS_DATA2_TIMING - adjust_timing));
prev_adjust_timing = adjust_timing;
}
return SFHSS_PACKET_PERIOD -2000 -(SFHSS_DATA2_TIMING - adjust_timing);
#else
return SFHSS_PACKET_PERIOD -2000 -SFHSS_DATA2_TIMING; // original 2000
#endif
case SFHSS_TUNE:
phase = SFHSS_DATA1;
SFHSS_tune_freq();
@@ -288,7 +300,7 @@ static void __attribute__((unused)) SFHSS_get_tx_id()
rx_tx_addr[1] = fixed_id >> 0;
}
uint16_t initSFHSS()
void SFHSS_init()
{
BIND_DONE; // Not a TX bind protocol
SFHSS_get_tx_id();
@@ -297,7 +309,6 @@ uint16_t initSFHSS()
SFHSS_rf_init();
phase = SFHSS_START;
return 10000;
}
#endif

View File

@@ -14,9 +14,9 @@ Multiprotocol is distributed in the hope that it will be useful,
*/
// Compatible with GD005 C-17 and GD006 DA62 planes.
#if defined(GD00X_NRF24L01_INO)
#if defined(GD00X_CCNRF_INO)
#include "iface_nrf250k.h"
#include "iface_xn297.h"
//#define FORCE_GD00X_ORIGINAL_ID
@@ -113,7 +113,7 @@ static void __attribute__((unused)) GD00X_send_packet()
if(IS_BIND_DONE)
{
XN297L_Hopping(hopping_frequency_no);
XN297_Hopping(hopping_frequency_no);
if(sub_protocol==GD_V1)
{
hopping_frequency_no++;
@@ -121,21 +121,22 @@ static void __attribute__((unused)) GD00X_send_packet()
}
}
XN297L_WritePayload(packet, packet_length);
XN297L_SetPower(); // Set tx_power
XN297L_SetFreqOffset(); // Set frequency offset
// Send
XN297_SetFreqOffset();
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, packet_length);
}
static void __attribute__((unused)) GD00X_init()
static void __attribute__((unused)) GD00X_RF_init()
{
XN297L_Init();
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_250K);
if(sub_protocol==GD_V1)
XN297L_SetTXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5);
XN297_SetTXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5);
else
XN297L_SetTXAddr((uint8_t*)"GDKNx", 5);
XN297L_HoppingCalib(sub_protocol==GD_V1?GD00X_RF_NUM_CHANNELS:GD00X_V2_RF_NUM_CHANNELS); // Calibrate all channels
XN297L_RFChannel(sub_protocol==GD_V1?GD00X_RF_BIND_CHANNEL:GD00X_V2_RF_BIND_CHANNEL); // Set bind channel
XN297_SetTXAddr((uint8_t*)"GDKNx", 5);
XN297_HoppingCalib(sub_protocol==GD_V1?GD00X_RF_NUM_CHANNELS:GD00X_V2_RF_NUM_CHANNELS); // Calibrate all channels
XN297_RFChannel(sub_protocol==GD_V1?GD00X_RF_BIND_CHANNEL:GD00X_V2_RF_BIND_CHANNEL); // Set bind channel
}
static void __attribute__((unused)) GD00X_initialize_txid()
@@ -204,28 +205,27 @@ static void __attribute__((unused)) GD00X_initialize_txid()
uint16_t GD00X_callback()
{
if(IS_BIND_IN_PROGRESS)
if(--bind_counter==0)
BIND_DONE;
GD00X_send_packet();
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
if(bind_counter)
if(--bind_counter==0)
BIND_DONE;
GD00X_send_packet();
return packet_period;
}
uint16_t initGD00X()
void GD00X_init()
{
BIND_IN_PROGRESS; // autobind protocol
GD00X_initialize_txid();
GD00X_init();
GD00X_RF_init();
hopping_frequency_no = 0;
bind_counter=GD00X_BIND_COUNT;
packet_period=sub_protocol==GD_V1?GD00X_PACKET_PERIOD:GD00X_V2_BIND_PACKET_PERIOD;
packet_length=sub_protocol==GD_V1?GD00X_PAYLOAD_SIZE:GD00X_V2_PAYLOAD_SIZE;
packet_count=0;
len=0;
return GD00X_INITIAL_WAIT;
}
#endif

View File

@@ -19,7 +19,7 @@ Multiprotocol is distributed in the hope that it will be useful,
#if defined(GW008_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_xn297.h"
#define GW008_INITIAL_WAIT 500
#define GW008_PACKET_PERIOD 2400
@@ -32,10 +32,10 @@ enum {
GW008_DATA
};
static void __attribute__((unused)) GW008_send_packet(uint8_t bind)
static void __attribute__((unused)) GW008_send_packet()
{
packet[0] = rx_tx_addr[0];
if(bind)
if(IS_BIND_IN_PROGRESS)
{
packet[1] = 0x55;
packet[2] = hopping_frequency[0];
@@ -47,6 +47,9 @@ static void __attribute__((unused)) GW008_send_packet(uint8_t bind)
}
else
{
XN297_Hopping((hopping_frequency_no++)/2);
hopping_frequency_no %= 8;
packet[1] = 0x01 | GET_FLAG(CH5_SW, 0x40); // flip
packet[2] = convert_channel_16b_limit(AILERON , 200, 0); // aileron
packet[3] = convert_channel_16b_limit(ELEVATOR, 0, 200); // elevator
@@ -63,38 +66,21 @@ static void __attribute__((unused)) GW008_send_packet(uint8_t bind)
}
packet[14] = rx_tx_addr[1];
// Power on, TX mode, CRC enabled
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? GW008_RF_BIND_CHANNEL : hopping_frequency[(hopping_frequency_no++)/2]);
hopping_frequency_no %= 8;
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WriteEnhancedPayload(packet, GW008_PAYLOAD_SIZE, 0);
NRF24L01_SetPower(); // Set tx_power
}
static void __attribute__((unused)) GW008_init()
static void __attribute__((unused)) GW008_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5);
XN297_SetRXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01);
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, GW008_PAYLOAD_SIZE+2); // payload + 2 bytes for pcf
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
NRF24L01_SetBitrate(NRF24L01_BR_1M);
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01); // Set feature bits on
NRF24L01_Activate(0x73);
XN297_SetRXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", GW008_PAYLOAD_SIZE);
//XN297_HoppingCalib(8);
XN297_RFChannel(GW008_RF_BIND_CHANNEL);
}
static void __attribute__((unused)) GW008_initialize_txid()
@@ -109,53 +95,48 @@ uint16_t GW008_callback()
switch(phase)
{
case GW008_BIND1:
if((NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) && // RX fifo data ready
if(XN297_IsRX() && // RX fifo data ready
XN297_ReadEnhancedPayload(packet, GW008_PAYLOAD_SIZE) == GW008_PAYLOAD_SIZE && // check payload size
packet[0] == rx_tx_addr[0] && packet[14] == rx_tx_addr[1]) // check tx id
{
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(TX_EN);
rx_tx_addr[2] = packet[13];
BIND_DONE;
phase = GW008_DATA;
}
else
{
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
GW008_send_packet(1);
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(TX_EN);
GW008_send_packet();
phase = GW008_BIND2;
return 850; // minimum value 750 for STM32
}
break;
case GW008_BIND2:
// switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushRx();
NRF24L01_SetTxRxMode(RX_EN);
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)
| _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
phase = GW008_BIND1;
return 5000;
break;
case GW008_DATA:
#ifdef MULTI_SYNC
telemetry_set_input_sync(GW008_PACKET_PERIOD);
#endif
GW008_send_packet(0);
GW008_send_packet();
break;
}
return GW008_PACKET_PERIOD;
}
uint16_t initGW008()
void GW008_init()
{
BIND_IN_PROGRESS; // autobind protocol
GW008_initialize_txid();
phase = GW008_BIND1;
GW008_init();
GW008_RF_init();
hopping_frequency_no = 0;
return GW008_INITIAL_WAIT;
}
#endif

View File

@@ -0,0 +1,132 @@
/*
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(H36_NRF24L01_INO)
#include "iface_xn297.h"
//#define FORCE_H36_ORIGINAL_ID
#define H36_PAYLOAD_SIZE 13
#define H36_RF_NUM_CHANNELS 4
#define H36_BIND_PACKET_PERIOD 10285
#define H36_BIND_COUNT 648 //3sec
enum {
H36_DATA1=0,
H36_DATA2,
H36_DATA3,
H36_DATA4,
};
static void __attribute__((unused)) H36_send_packet()
{
if(IS_BIND_DONE && phase == H36_DATA1)
{
hopping_frequency_no++;
hopping_frequency_no&=3;
XN297_Hopping(hopping_frequency_no);
}
packet[0] = 0x2E; // constant?
memcpy(&packet[2],rx_tx_addr,3);
if(IS_BIND_IN_PROGRESS)
{//Bind
memcpy(&packet[5],hopping_frequency,4);
memset(&packet[9], 0x00, 3);
packet[12] = 0xED; // constant?
bind_counter--;
if(bind_counter == 0)
BIND_DONE;
}
else
{//Normal
packet[5] = convert_channel_8b(THROTTLE);
packet[6] = convert_channel_8b(RUDDER);
packet[7] = convert_channel_8b(ELEVATOR);
packet[8] = convert_channel_8b(AILERON);
packet[9] = GET_FLAG(CH6_SW, 0x02) //Headless
|GET_FLAG(CH7_SW, 0x04); //RTH(temporary)
packet[10] = 0x20; //Trim A centered(0x20)
packet[11] = CH5_SW?0x60:0x20; //Flip(0x40)|Trim E centered(0x20)
packet[12] = 0xA0; //High(0x80)/Low(0x40) rates|Trim R centered(0x20)?
}
//crc
packet[1]=0xAA;
for(uint8_t i=5;i<12;i++)
packet[1] ^= packet[i];
//Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, H36_PAYLOAD_SIZE);
#ifdef DEBUG_SERIAL
debug("H%d P",hopping_frequency_no);
for(uint8_t i=0; i < H36_PAYLOAD_SIZE; i++)
debug(" %02X", packet[i]);
debugln();
#endif
}
static void __attribute__((unused)) H36_initialize_txid()
{
rx_tx_addr[0] = rx_tx_addr[3];
calc_fh_channels(4);
#ifdef FORCE_H36_ORIGINAL_ID
if(!RX_num)
{
memcpy(rx_tx_addr,(uint8_t *)"\x00\x11\x00",3);
memcpy(hopping_frequency,(uint8_t *)"\x36\x3A\x31\x2B",4); //54, 58, 49, 43
}
#endif
}
static void __attribute__((unused)) H36_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t*)"\xCC\x6C\x47\x90\x53", 5);
XN297_RFChannel(50); //Bind channel
}
uint16_t H36_callback()
{
H36_send_packet();
switch(phase)
{
case H36_DATA1:
phase++;
return 1830;
case H36_DATA2:
case H36_DATA3:
phase++;
return 3085;
default://DATA4
#ifdef MULTI_SYNC
telemetry_set_input_sync(18500);
#endif
phase = H36_DATA1;
break;
}
return 10500;
}
void H36_init()
{
BIND_IN_PROGRESS; // Autobind protocol
H36_initialize_txid();
H36_RF_init();
phase = H36_DATA1;
hopping_frequency_no = 0;
bind_counter = H36_BIND_COUNT;
}
#endif

View File

@@ -19,7 +19,7 @@
#if defined(H8_3D_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_xn297.h"
#define H8_3D_PACKET_PERIOD 1800
#define H20H_PACKET_PERIOD 9340
@@ -50,7 +50,7 @@ enum H8_3D_FLAGS_2 {
H8_3D_FLAG_CAM_UP = 0x04,
};
static void __attribute__((unused)) H8_3D_send_packet(uint8_t bind)
static void __attribute__((unused)) H8_3D_send_packet()
{
if(sub_protocol==H20H)
packet[0] = 0x14;
@@ -63,7 +63,7 @@ static void __attribute__((unused)) H8_3D_send_packet(uint8_t bind)
packet[4] = rx_tx_addr[3];
packet[8] = rx_tx_addr[0]+rx_tx_addr[1]+rx_tx_addr[2]+rx_tx_addr[3]; // txid checksum
memset(&packet[9], 0, 10);
if (bind)
if (IS_BIND_IN_PROGRESS)
{
packet[5] = 0x00;
packet[6] = 0x00;
@@ -122,18 +122,16 @@ static void __attribute__((unused)) H8_3D_send_packet(uint8_t bind)
sum += packet[i];
packet[19] = sum; // data checksum
// Power on, TX mode, 2byte CRC
// Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
// RF channel
if(sub_protocol!=H20H)
{ // H8_3D, H20MINI, H30MINI
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? hopping_frequency[0] : hopping_frequency[hopping_frequency_no++]);
XN297_RFChannel(IS_BIND_IN_PROGRESS ? hopping_frequency[0] : hopping_frequency[hopping_frequency_no++]);
hopping_frequency_no %= H8_3D_RF_NUM_CHANNELS;
}
else
{ //H20H
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? H20H_BIND_RF : hopping_frequency[packet_count>>3]);
if(!bind)
{ // H20H
XN297_RFChannel(IS_BIND_IN_PROGRESS ? H20H_BIND_RF : hopping_frequency[packet_count>>3]);
if(IS_BIND_DONE)
{
packet_count++;
if(packet_count>15)
@@ -147,55 +145,39 @@ static void __attribute__((unused)) H8_3D_send_packet(uint8_t bind)
}
}
// clear packet status bits and TX FIFO
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, H8_3D_PACKET_SIZE);
NRF24L01_SetPower(); // Set tx_power
}
static void __attribute__((unused)) H8_3D_init()
static void __attribute__((unused)) H8_3D_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
if(sub_protocol==H20H)
XN297_SetTXAddr((uint8_t *)"\xEE\xDD\xCC\xBB\x11", 5);
else // H8_3D, H20MINI, H30MINI
XN297_SetTXAddr((uint8_t *)"\xC4\x57\x09\x65\x21", 5);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
}
uint16_t H8_3D_callback()
{
if(IS_BIND_DONE)
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
H8_3D_send_packet(0);
}
else
if(bind_counter)
{
bind_counter--;
if (bind_counter == 0)
{
BIND_DONE;
packet_count=0;
}
else
{
H8_3D_send_packet(1);
bind_counter--;
}
}
#ifdef MULTI_SYNC
else
telemetry_set_input_sync(packet_period);
#endif
H8_3D_send_packet();
return packet_period;
}
@@ -238,12 +220,12 @@ static void __attribute__((unused)) H8_3D_initialize_txid()
}
}
uint16_t initH8_3D(void)
void H8_3D_init(void)
{
BIND_IN_PROGRESS; // autobind protocol
bind_counter = H8_3D_BIND_COUNT;
H8_3D_initialize_txid();
H8_3D_init();
H8_3D_RF_init();
switch(sub_protocol)
{
case H8_3D:
@@ -257,7 +239,6 @@ uint16_t initH8_3D(void)
packet_period=H20MINI_PACKET_PERIOD;
break;
}
return H8_3D_INITIAL_WAIT;
}
#endif

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,
@@ -75,7 +86,6 @@ static void __attribute__((unused)) HOTT_rf_init()
for (uint8_t i = 0; i < 39; ++i)
CC2500_WriteReg(i, pgm_read_byte_near(&HOTT_init_values[i]));
prev_option = option;
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
CC2500_SetTxRxMode(TX_EN);
@@ -103,7 +113,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
}
}
@@ -127,114 +137,146 @@ const uint8_t PROGMEM HOTT_hop[][HOTT_NUM_RF_CHANNELS]=
};
const uint16_t PROGMEM HOTT_hop_val[] = { 0xC06B, 0xC34A, 0xDB24, 0x8E09, 0x272E, 0x217F, 0x155B, 0xEDE8, 0x1D31, 0x0986, 0x56F7, 0x6454, 0xC42D, 0x01D2, 0xC253, 0x1180 };
static void __attribute__((unused)) HOTT_init()
static void __attribute__((unused)) HOTT_TXID_init()
{
packet[0] = pgm_read_word_near( &HOTT_hop_val[num_ch] );
packet[1] = pgm_read_word_near( &HOTT_hop_val[num_ch] )>>8;
for(uint8_t i=0; i<HOTT_NUM_RF_CHANNELS; i++)
hopping_frequency[i]=pgm_read_byte_near( &HOTT_hop[num_ch][i] );
#ifdef HOTT_FORCE_ID
memcpy(rx_tx_addr,"\x7C\x94\x00\x0D\x50",5);
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;
uint16_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()
{
packet[2] = hopping_frequency_no;
packet[3] = 0x00; // used for failsafe but may also be used for additional channels
static void __attribute__((unused)) HOTT_prep_data_packet() {
static uint8_t upper = 0; // toggles between sending channels 1..8,9..12 and 1..8,13..16
packet[2] = hopping_frequency_no; // send next frequency to be used
packet[3] = upper; // indicate upper or lower channels (only supporting 16 channels)
#ifdef FAILSAFE_ENABLE
static uint8_t failsafe_count=0;
if(IS_FAILSAFE_VALUES_on && IS_BIND_DONE)
{
failsafe_count++;
if(failsafe_count>=3)
{
FAILSAFE_VALUES_off;
failsafe_count=0;
static uint8_t failsafe_count = 0; // failsafe packet state machine (need to send two packets)
if(IS_FAILSAFE_VALUES_on && IS_BIND_DONE) { // if TX wants to send failsafe data and RX is connected
failsafe_count++; // prepare to send next packet
if(failsafe_count >= 3) { // done sending two failsafe channel data packets
FAILSAFE_VALUES_off;
failsafe_count = 0;
}
}
else
failsafe_count=0;
failsafe_count = 0;
#endif
// Channels value are PPM*2, -100%=1100µs, +100%=1900µs, order TAER
//
// Note: failsafe packets are differnt to normal operation packets
// normal operation toggles between sending channels 1..8,9..12 and 1..8,13..16 using bit0 as high/low indicator in packet[3]
// while failsafe packets send channels 1..12, 13..24 (and probably 25..32) using bit0 in packet[3] as packet type indicator
// packet[3] = 0x40 -> failsafe packet with data for channels 1..12
// packet[3] = 0x41 -> failsafe packet with data for channels 13..24
//
uint16_t val;
for(uint8_t i=4;i<28;i+=2)
{
val=Channel_data[(i-4)>>1];
val=(((val<<2)+val)>>2)+860*2; // value range 860<->2140 *2 <-> -125%<->+125%
for(uint8_t i = 0 ; i < 12*2 ; i += 2) { // working 12 channels (using 2 bytes per channel)
uint8_t chIndex = i >> 1 ; // normal operation channel number
uint8_t fschIndex = chIndex; // linear channel number for failsafe
if(upper && chIndex >= 8) chIndex += 4; // for normal operation toggle between channels 1..8,9..12 and 1..8,13..16
val = Channel_data[chIndex]; // get normal operation channel data
val = (((val << 2) + val) >> 2)+ 860*2; // convert channel data 0..2047 to 1720..4278 <-> -125%<->+125%
// val = (val*5/4+860*2)
#ifdef FAILSAFE_ENABLE
if(failsafe_count==1)
{ // first failsafe packet
packet[3]=0x40;
uint16_t fs=Failsafe_data[(i-4)>>1];
if( fs == FAILSAFE_CHANNEL_HOLD || fs == FAILSAFE_CHANNEL_NOPULSES)
val|=0x8000; // channel hold flag
else
{
val=(((fs<<2)+fs)>>2)+860*2; // value range 860<->2140 *2 <-> -125%<->+125%
val|=0x4000; // channel specific position flag
if(failsafe_count == 1 || failsafe_count == 2) {// failsafe data needs to be sent to RX
uint16_t fs = 0x8000; // default failsafe mode is hold
if(failsafe_count == 1) { // send fail safe packet containing channels 1..12
packet[3] = 0x40; // indicate packet has failsafe values for channels 1..12
fs = Failsafe_data[fschIndex]; // get failsafe channel data
} else { // send fail safe packet containing channels 13..24
packet[3] = 0x41; // indicate packet has failsafe values for channels 13..24
if(fschIndex < 4) // we only work 16 channels so send channels 13..16, rest default
fs = Failsafe_data[fschIndex+12]; // get failsafe channel data 13..16
}
if( fs == FAILSAFE_CHANNEL_HOLD || // treat HOLD and NOPULSES as channel hold
fs == FAILSAFE_CHANNEL_NOPULSES)
val = 0x8000; // set channel failsafe mode hold flag
else {
val = (((fs << 2) + fs) >> 2) +860*2; // convert channel data 0..2047 to 1720..4278 <-> -125%<->+125%
val |= 0x4000; // set channel failsafe mode position flag
}
}
else if(failsafe_count==2)
{ // second failsafe packet=timing?
packet[3]=0x50;
if(i==4)
val=2;
else
val=0;
}
}
#endif
packet[i] = val;
packet[i+1] = val>>8;
packet[i + 4] = val; // first channel data at packet[4] and packet[5]
packet[i + 4+1] = val >> 8;
}
upper ^= 0x01; // toggle to upper and lower channels
packet[28] = 0x80; // no sensor
packet[29] = 0x02; // 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
#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
}
else
packet[28] = 0x0F; // RX, no button pressed
if(sub_protocol == HOTT_SYNC)
packet[29] = ((HOTT_sensor_seq+1)<<3) | 1; // Telemetry packet sequence
else
packet[29] = 0x01; // 0x01->Text config menu
}
else
packet[28] = 0xDF; // no touch pressed
packet[29] = 0x01; // 0x01->config menu
}
else
{
packet[28] = 0x8C; // unknown 0x80 when bind starts then when RX replies start normal, 0x89/8A/8B/8C/8D/8E during normal packets, 0x0F->config menu
packet[29] = 0x02; // unknown 0x02 when bind starts then when RX replies cycle in sequence 0x1A/22/2A/0A/12, 0x02 during normal packets, 0x01->config menu, 0x0A->no more RX telemetry
{
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
}
//debugln("28=%02X,29=%02X",packet[28],packet[29]);
}
#endif
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++)
@@ -246,12 +288,8 @@ static void __attribute__((unused)) HOTT_data_packet()
rf_ch_num=hopping_frequency[hopping_frequency_no];
}
uint16_t ReadHOTT()
uint16_t HOTT_callback()
{
#ifdef HOTT_FW_TELEMETRY
static uint8_t pps_counter=0;
#endif
switch(phase)
{
case HOTT_START:
@@ -268,65 +306,113 @@ 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)
{// Sync 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]);
debugln("");
uint8_t addr=HOTT_EEPROM_OFFSET+RX_num*5;
uint16_t addr=HOTT_EEPROM_OFFSET+RX_num*5;
for(uint8_t i=0; i<5; i++)
eeprom_write_byte((EE_ADDR)(addr+i),packet_in[5+i]);
BIND_DONE;
HOTT_init();
HOTT_TXID_init();
}
#ifdef HOTT_FW_TELEMETRY
else
{ //Telemetry
// [0..4] = TXID
// [5..9] = RXID
// [10] = 0x40 bind, 0x00 normal, 0x80 config menu
// [10] = holds warnings issued by hott devices
// [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 [20] = 0x00 ??
// 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] = rx events
//
// 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 +420,81 @@ 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=");
uint8_t hott_warnings = packet_in[10]; // save warnings from hott devices
bool send_telem=true;
HOTT_sensor_seq++; // Increment RX sequence counter
if(packet[29] & 1)
{ //Text mode
HOTT_sensor_seq %= 19; // 19 pages in 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 %= 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]);
}
packet_in[14] = hott_warnings; // restore saved warnings from hott devices
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,28 +505,42 @@ 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;
}
return 0;
}
uint16_t initHOTT()
void HOTT_init()
{
num_ch=random(0xfefefefe)%16;
HOTT_init();
HOTT_TXID_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;
}
#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/>.
*/
#ifdef CYRF6936_INSTALLED
#include "iface_hs6200.h"
static bool HS6200_crc;
static uint16_t HS6200_crc_init;
static uint8_t HS6200_address_length, HS6200_tx_addr[5];
static void __attribute__((unused)) HS6200_Init(bool crc_en)
{
CYRF_GFSK1M_Init(32, 1); //Dummy number of bytes for now
HS6200_crc = crc_en;
}
static void __attribute__((unused)) HS6200_SetTXAddr(const uint8_t* addr, uint8_t addr_len)
{
// precompute address crc
crc = 0xffff;
for(uint8_t i=0; i<addr_len; i++)
crc16_update(addr[addr_len-1-i], 8);
HS6200_crc_init=crc;
memcpy(HS6200_tx_addr, addr, addr_len);
HS6200_address_length = addr_len;
}
static uint16_t __attribute__((unused)) HS6200_calc_crc(uint8_t* msg, uint8_t len)
{
uint8_t pos;
crc = HS6200_crc_init;
// pcf + payload
for(pos=0; pos < len-1; pos++)
crc16_update(msg[pos], 8);
// last byte (1 bit only)
if(len > 0)
crc16_update(msg[pos+1], 1);
return crc;
}
static void __attribute__((unused)) HS6200_SendPayload(uint8_t* msg, uint8_t len)
{
static const uint8_t HS6200_scramble[] = { 0x80,0xf5,0x3b,0x0d,0x6d,0x2a,0xf9,0xbc,0x51,0x8e,0x4c,0xfd,0xc1,0x65,0xd0 }; // todo: find all 32 bytes ...
uint8_t payload[32];
const uint8_t no_ack = 1; // never ask for an ack
static uint8_t pid;
uint8_t pos = 0;
if(len > sizeof(HS6200_scramble))
len = sizeof(HS6200_scramble);
// address
for(int8_t i=HS6200_address_length-1; i>=0; i--)
payload[pos++] = HS6200_tx_addr[i];
// guard bytes
payload[pos++] = HS6200_tx_addr[0];
payload[pos++] = HS6200_tx_addr[0];
// packet control field
payload[pos++] = ((len & 0x3f) << 2) | (pid & 0x03);
payload[pos] = (no_ack & 0x01) << 7;
pid++;
// scrambled payload
if(len > 0)
{
payload[pos++] |= (msg[0] ^ HS6200_scramble[0]) >> 1;
for(uint8_t i=1; i<len; i++)
payload[pos++] = ((msg[i-1] ^ HS6200_scramble[i-1]) << 7) | ((msg[i] ^ HS6200_scramble[i]) >> 1);
payload[pos] = (msg[len-1] ^ HS6200_scramble[len-1]) << 7;
}
// crc
if(HS6200_crc)
{
uint16_t crc = HS6200_calc_crc(&payload[HS6200_address_length+2], len+2);
uint8_t hcrc = crc >> 8;
uint8_t lcrc = crc & 0xff;
payload[pos++] |= (hcrc >> 1);
payload[pos++] = (hcrc << 7) | (lcrc >> 1);
payload[pos++] = lcrc << 7;
}
#if 0
debug("E:");
for(uint8_t i=0; i<pos; i++)
debug(" %02X",payload[i]);
debugln("");
#endif
//CYRF wants LSB first
for(uint8_t i=0; i<pos; i++)
payload[i]=bit_reverse(payload[i]);
//Send
CYRF_WriteRegister(CYRF_01_TX_LENGTH, pos);
CYRF_GFSK1M_SendPayload(payload, pos);
}
#endif

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];
@@ -33,11 +33,17 @@ static void __attribute__((unused)) flyzone_build_packet()
packet[5] = convert_channel_8b(THROTTLE); //00..FF
packet[6] = convert_channel_8b(RUDDER); //00..80..FF
packet[7] = convert_channel_8b(CH5); //00..80..FF
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 HEIGHT_callback()
{
#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()
void HEIGHT_init()
{
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,8 +93,7 @@ uint16_t initFlyzone()
#endif
phase=255;
bind_counter = FLYZONE_BIND_COUNT;
return 2400;
bind_counter = HEIGHT_BIND_COUNT;
}
#endif
// Normal packet is 8 bytes: 0xA5 0xAF 0x59 0x84 0x7A 0x00 0x80 0xFF

View File

@@ -24,44 +24,7 @@
//
uint8_t bind_buf_arry[4][10];
// HiSky protocol uses TX id as an address for nRF24L01, and uses frequency hopping sequence
// which does not depend on this id and is passed explicitly in binding sequence. So we are free
// to generate this sequence as we wish. It should be in the range [02..77]
static void __attribute__((unused)) calc_fh_channels()
{
uint8_t idx = 0;
uint32_t rnd = MProtocol_id;
while (idx < HISKY_FREQUENCE_NUM)
{
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 the distance 2 between the channels - either odd or even
if (((next_ch ^ (uint8_t)rx_tx_addr[3]) & 0x01 )== 0)
continue;
// Check that it's not duplicated and spread uniformly
for (i = 0; i < idx; i++) {
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 < 8) || (next_ch >= 27 && next_ch <= 50 && count_27_50 < 8) || (next_ch >= 51 && count_51_74 < 8) )
hopping_frequency[idx++] = next_ch;//find hopping frequency
}
}
static void __attribute__((unused)) build_binding_packet(void)
static void __attribute__((unused)) HISKY_build_binding_packet(void)
{
uint8_t i;
uint16_t sum=0;
@@ -95,28 +58,23 @@ static void __attribute__((unused)) build_binding_packet(void)
}
}
static void __attribute__((unused)) hisky_init()
static void __attribute__((unused)) HISKY_RF_init()
{
NRF24L01_Initialize();
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable p0 rx
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address (byte -2)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); // binding packet must be set in channel 81
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 10); // payload size = 10
#ifndef MULTI_AIR
if(sub_protocol==HK310)
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
else
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower(); // Set power
NRF24L01_SetTxRxMode(TX_EN); // TX mode, 2-bytes CRC, radio on
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
#endif
}
// HiSky channel sequence: AILE ELEV THRO RUDD GEAR PITCH, channel data value is from 0 to 1000
// Channel 7 - Gyro mode, 0 - 6 axis, 3 - 3 axis
static void __attribute__((unused)) build_ch_data()
static void __attribute__((unused)) HISKY_build_ch_data()
{
uint16_t temp;
uint8_t i,j;
@@ -133,9 +91,16 @@ static void __attribute__((unused)) build_ch_data()
}
}
uint16_t hisky_cb()
uint16_t HISKY_callback()
{
phase++;
#ifdef MULTI_AIR
if(sub_protocol==HK310)
{
SUB_PROTO_INVALID;
return 10000;
}
#else
if(sub_protocol==HK310)
switch(phase)
{
@@ -176,6 +141,7 @@ uint16_t hisky_cb()
phase=8;
break;
}
#endif
switch(phase)
{
case 1:
@@ -223,7 +189,7 @@ uint16_t hisky_cb()
#ifdef MULTI_SYNC
telemetry_set_input_sync(9000);
#endif
build_ch_data();
HISKY_build_ch_data();
break;
case 8:
break;
@@ -236,9 +202,10 @@ uint16_t hisky_cb()
return 1000; // send 1 binding packet and 1 data packet per 9ms
}
static void __attribute__((unused)) initialize_tx_id()
static void __attribute__((unused)) HISKY_initialize_tx_id()
{
//Generate frequency hopping table
#ifndef MULTI_AIR
if(sub_protocol==HK310)
{
// for HiSky surface protocol, the transmitter always generates hop channels in sequential order.
@@ -248,14 +215,18 @@ static void __attribute__((unused)) initialize_tx_id()
hopping_frequency[i]=hopping_frequency_no++; // Sequential order hop channels...
}
else
calc_fh_channels();
#endif
// HiSky air protocol uses TX id as an address for nRF24L01, and uses frequency hopping sequence
// which does not depend on this id and is passed explicitly in binding sequence. So we are free
// to generate this sequence as we wish. It should be in the range [02..77]
calc_fh_channels(HISKY_FREQUENCE_NUM);
}
uint16_t initHiSky()
void HISKY_init()
{
initialize_tx_id();
build_binding_packet();
hisky_init();
HISKY_initialize_tx_id();
HISKY_build_binding_packet();
HISKY_RF_init();
phase = 0;
hopping_frequency_no = 0;
binding_idx = 0;
@@ -264,7 +235,6 @@ uint16_t initHiSky()
bind_counter = HISKY_BIND_COUNT;
else
bind_counter = 0;
return 1000;
}
#endif

View File

@@ -54,9 +54,9 @@ static void __attribute__((unused)) HITEC_CC2500_init()
for (uint8_t i = 0; i < 39; ++i)
CC2500_WriteReg(i, pgm_read_byte_near(&HITEC_init_values[i]));
prev_option = option;
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
prev_option = option;
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
}
@@ -165,7 +165,7 @@ static void __attribute__((unused)) HITEC_build_packet()
packet[0] = 0x1A; // 26 bytes to follow
for(uint8_t i=0;i<9;i++)
{
uint16_t ch = convert_channel_16b_nolimit(i,0x1B87,0x3905);
uint16_t ch = convert_channel_16b_nolimit(i,0x1B87,0x3905,false);
packet[4+2*i] = ch >> 8;
packet[5+2*i] = ch & 0xFF;
}
@@ -220,7 +220,7 @@ static void __attribute__((unused)) HITEC_send_packet()
packet[23] >>= 1; // packet sequence
}
uint16_t ReadHITEC()
uint16_t HITEC_callback()
{
switch(phase)
{
@@ -390,7 +390,7 @@ uint16_t ReadHITEC()
return 0;
}
uint16_t initHITEC()
void HITEC_init()
{
HITEC_RF_channels();
#ifdef HITEC_FORCE_ID // ID and channels taken from dump
@@ -400,7 +400,6 @@ uint16_t initHITEC()
memcpy((void *)hopping_frequency,(void *)"\x00\x3A\x4A\x32\x0C\x58\x2A\x10\x26\x20\x08\x60\x68\x70\x78\x80\x88\x56\x5E\x66\x6E",HITEC_NUM_FREQUENCE);
#endif
phase = HITEC_START;
return 10000;
}
/* Full telemetry

View File

@@ -15,175 +15,199 @@
#if defined(HONTAI_NRF24L01_INO)
#include "iface_nrf24l01.h"
#include "iface_xn297.h" // mix of nrf and xn297 at 1Mb...
#define HONTAI_BIND_COUNT 80
#define HONTAI_PACKET_PERIOD 13500
#define FQ777_951_PACKET_PERIOD 10000
#define HONTAI_INITIAL_WAIT 500
#define HONTAI_BIND_PACKET_SIZE 10
#define HONTAI_PACKET_SIZE 12
#define HONTAI_RF_BIND_CHANNEL 0
#define HONTAI_BIND_COUNT 80
#define HONTAI_PACKET_PERIOD 13500
#define FQ777_951_PACKET_PERIOD 10000
#define HONTAI_INITIAL_WAIT 500
#define HONTAI_BIND_PACKET_SIZE 10
#define HONTAI_PACKET_SIZE 12
#define HONTAI_RF_BIND_CHANNEL 0
#define HONTAI_XKK170_RF_BIND_CHANNEL 20
#define HONTAI_XKK170_PACKET_PERIOD 8085
//#define FORCE_HONTAI_XKK170_ORIGINAL_ID
enum{
HONTAI_FLAG_FLIP = 0x01,
HONTAI_FLAG_PICTURE = 0x02,
HONTAI_FLAG_VIDEO = 0x04,
HONTAI_FLAG_HEADLESS = 0x08,
HONTAI_FLAG_RTH = 0x10,
HONTAI_FLAG_CALIBRATE = 0x20,
HONTAI_FLAG_FLIP = 0x01,
HONTAI_FLAG_PICTURE = 0x02,
HONTAI_FLAG_VIDEO = 0x04,
HONTAI_FLAG_HEADLESS = 0x08,
HONTAI_FLAG_RTH = 0x10,
HONTAI_FLAG_CALIBRATE = 0x20,
};
// proudly swiped from http://www.drdobbs.com/implementing-the-ccitt-cyclical-redundan/199904926
#define HONTAI_POLY 0x8408
static void __attribute__((unused)) crc16(uint8_t *data_p, uint8_t length)
static void __attribute__((unused)) HONTAI_send_packet()
{
uint16_t crc = 0xffff;
length -= 2;
do
{
for (uint8_t i = 0, data = (uint8_t)*data_p++;
i < 8;
i++, data >>= 1)
{
if ((crc & 0x01) ^ (data & 0x01))
crc = (crc >> 1) ^ HONTAI_POLY;
else
crc >>= 1;
}
} while (--length);
crc = ~crc;
*data_p++ = crc & 0xff;
*data_p = crc >> 8;
}
static void __attribute__((unused)) HONTAI_send_packet(uint8_t bind)
{
if (bind)
if (IS_BIND_IN_PROGRESS)
{
memcpy(packet, rx_tx_addr, 5);
memset(&packet[5], 0, 3);
//if(sub_protocol == HONTAI_XKK170)
// packet[6] = 0xD2;
packet_length = HONTAI_BIND_PACKET_SIZE;
}
else
{
/*if(sub_protocol == JJRCX1)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
else*/
XN297_Hopping(hopping_frequency_no++);
hopping_frequency_no %= 3;
memset(packet,0,HONTAI_PACKET_SIZE);
packet[3] = convert_channel_16b_limit(THROTTLE, 0, 127) << 1; // Throttle
packet[4] = convert_channel_16b_limit(AILERON, 63, 0); // Aileron
packet[5] = convert_channel_16b_limit(ELEVATOR, 0, 63); // Elevator
packet[6] = convert_channel_16b_limit(RUDDER, 0, 63); // Rudder
if(sub_protocol == X5C1)
packet[7] = convert_channel_16b_limit(AILERON, 0, 63)-31; // Aileron trim
for(uint8_t i=0; i<4; i++)
packet[i+3] = convert_channel_8b(CH_TAER[i]);
if(sub_protocol != HONTAI_XKK170)
{
//Drive trims
packet[7] = (packet[4]>>3)-16;
packet[8] = (packet[6]>>3)-16;
packet[9] = (packet[5]>>3)-16;
//Reverse aileron
packet[4] ^= 0xFF;
//Limit range
for(uint8_t i=3; i<7; i++)
packet[i] >>= 2; //00..63
}
else
packet[7] = convert_channel_16b_limit(AILERON, 0, 32)-16; // Aileron trim
packet[8] = convert_channel_16b_limit(RUDDER, 0, 32)-16; // Rudder trim
if (sub_protocol == X5C1)
packet[9] = convert_channel_16b_limit(ELEVATOR, 0, 63)-31; // Elevator trim
else
packet[9] = convert_channel_16b_limit(ELEVATOR, 0, 32)-16; // Elevator trim
{//K170
//packet[2] = 0xAB; //This value keeps changing when touching any button... Left over from debug?
//Sticks
for(uint8_t i=1; i<4; i++)
packet[i+3] = convert_channel_16b_limit(CH_TAER[i],0x28,0xD8);
packet[6] ^= 0xFF; //Reverse rudder
//flags
packet[1] = GET_FLAG(CH8_SW, 0x04) //Gyro calibration (momentary)
|GET_FLAG(CH11_SW, 0x10); //XK K270 optical flow switch
// |GET_FLAG(CH_SW, 0x08) //Unk long press second top right button (momentary)
// |GET_FLAG(CH_SW, 0x10) //Unk short press second top right button (toggle)
// |GET_FLAG(CH_SW, 0x40) //Unk short press second top left button (momentary)
// |GET_FLAG(CH_SW, 0x80); //Unk long press second top left button (momentary)
uint8_t rate = 0x80; //Mid rate
if(CH5_SW)
rate = 0xC0; //High rate
else if(Channel_data[CH5] < CHANNEL_MIN_COMMAND)
rate = 0x40; //Low rate
packet[8] = rate
|GET_FLAG(CH7_SW, 0x04) //Take-off/Landing (momentary)
|GET_FLAG(CH6_SW, 0x10); //Emergency (momentary)
//Trims
packet[7] = ((convert_channel_8b(CH9)^0xFF)>>2)-31; // Trim Aileron
packet[9] = ( convert_channel_8b(CH10) >>2)-32; // Trim Elevator
}
switch(sub_protocol)
{
case HONTAI:
packet[0] = 0x0B;
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
packet[4] |= GET_FLAG(CH10_SW, 0x80) // RTH
packet[4] |= GET_FLAG(CH10_SW, 0x80) // RTH
| GET_FLAG(CH9_SW, 0x40); // Headless
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
| GET_FLAG(CH5_SW, 0x40); // Flip
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
break;
case JJRCX1:
packet[0] = GET_FLAG(CH6_SW, 0x02); // Arm
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
packet[4] |= 0x80; // unknown
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
packet[4] |= 0x80; // unknown
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
| GET_FLAG(CH5_SW, 0x40); // Flip
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
packet[8] = 0xC0 // high rate, no rudder trim
| GET_FLAG(CH10_SW, 0x02) // RTH
packet[8] = 0xC0 // high rate, no rudder trim
| GET_FLAG(CH10_SW, 0x02) // RTH
| GET_FLAG(CH9_SW, 0x01); // Headless
break;
case X5C1:
packet[0] = 0x0B;
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
packet[4] = 0x80 // unknown
packet[4] = 0x80 // unknown
| GET_FLAG(CH6_SW, 0x40); // Lights
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
| GET_FLAG(CH5_SW, 0x40); // Flip
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
packet[8] = 0xC0 // high rate, no rudder trim
| GET_FLAG(CH10_SW, 0x02) // RTH
packet[7] <<= 1; // Aileron trim
packet[8] = 0xC0 // high rate, no rudder trim
| GET_FLAG(CH10_SW, 0x02) // RTH
| GET_FLAG(CH9_SW, 0x01); // Headless
packet[9] <<= 1; // Elevator trim
break;
case FQ777_951:
packet[0] = GET_FLAG(CH7_SW, 0x01) // Picture
| GET_FLAG(CH8_SW, 0x02); // Video
packet[3] |= GET_FLAG(CH5_SW, 0x01); // Flip
packet[4] |= 0xC0; // High rate (mid=0xa0, low=0x60)
packet[4] |= 0xC0; // High rate (mid=0xa0, low=0x60)
packet[5] |= GET_FLAG(CH11_SW, 0x80); // Calibrate
packet[6] |= GET_FLAG(CH9_SW, 0x40); // Headless
break;
}
packet_length = HONTAI_PACKET_SIZE;
}
crc16(packet, bind ? HONTAI_BIND_PACKET_SIZE:HONTAI_PACKET_SIZE);
if(sub_protocol != HONTAI_XKK170)
{
// CRC 16 bits reflected in and out
crc=0xFFFF;
for(uint8_t i=0; i< packet_length-2; i++)
crc16_update(bit_reverse(packet[i]),8);
crc ^= 0xFFFF;
packet[packet_length-2]=bit_reverse(crc>>8);
packet[packet_length-1]=bit_reverse(crc);
}
else
memset(&packet[packet_length-2], 0xAA, 2);
// Power on, TX mode, 2byte CRC
if(sub_protocol == JJRCX1)
/*if(sub_protocol == JJRCX1)
{
NRF24L01_SetPower();
NRF24L01_SetTxRxMode(TX_EN);
else
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? HONTAI_RF_BIND_CHANNEL : hopping_frequency[hopping_frequency_no++]);
hopping_frequency_no %= 3;
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
}
else*/
{
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
}
if(sub_protocol == JJRCX1)
NRF24L01_WritePayload(packet, bind ? HONTAI_BIND_PACKET_SIZE:HONTAI_PACKET_SIZE);
NRF24L01_WritePayload(packet, packet_length);
else
XN297_WritePayload(packet, bind ? HONTAI_BIND_PACKET_SIZE:HONTAI_PACKET_SIZE);
NRF24L01_SetPower();
XN297_WritePayload(packet, packet_length);
#ifdef DEBUG_SERIAL
for(uint8_t i=0; i < packet_length; i++)
debug("%02X ", packet[i]);
debugln();
#endif
}
static void __attribute__((unused)) HONTAI_init()
static void __attribute__((unused)) HONTAI_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
if(sub_protocol == JJRCX1)
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xd2\xb5\x99\xb3\x4a", 5);
else
XN297_SetTXAddr((const uint8_t*)"\xd2\xb5\x99\xb3\x4a", 5);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M); // this will select the nrf and initialize it, therefore both sub protocols can use common instructions
if(sub_protocol == JJRCX1)
{
//NRF24L01_Initialize();
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xd2\xb5\x99\xb3\x4a", 5);
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0xff); // JJRC uses dynamic payload length
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f); // match other stock settings even though AA disabled...
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
//NRF24L01_WriteReg(NRF24L01_05_RF_CH, HONTAI_RF_BIND_CHANNEL);
}
else
{
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00);
memcpy(rx_id,(const uint8_t*)"\xD2\xB5\x99\xB3\x41",5);
if(sub_protocol == HONTAI_XKK170)
rx_id[4] = 0x4A;
XN297_SetTXAddr(rx_id, 5);
//XN297_HoppingCalib(3);
}
NRF24L01_Activate(0x73); // Deactivate feature register
XN297_RFChannel(sub_protocol==HONTAI_XKK170?HONTAI_XKK170_RF_BIND_CHANNEL:HONTAI_RF_BIND_CHANNEL);
}
const uint8_t PROGMEM HONTAI_hopping_frequency_nonels[][3] = {
{0x05, 0x19, 0x28}, // Hontai
{0x0a, 0x1e, 0x2d}}; // JJRC X1
const uint8_t PROGMEM HONTAI_hopping_frequency[3] = { 0x05, 0x19, 0x28 };
const uint8_t PROGMEM HONTAI_addr_vals[4][16] = {
{0x24, 0x26, 0x2a, 0x2c, 0x32, 0x34, 0x36, 0x4a, 0x4c, 0x4e, 0x54, 0x56, 0x5a, 0x64, 0x66, 0x6a},
@@ -201,39 +225,78 @@ static void __attribute__((unused)) HONTAI_init2()
data_tx_addr[2] = pgm_read_byte_near( &HONTAI_addr_vals[2][ rx_tx_addr[4] & 0x0f]);
data_tx_addr[3] = pgm_read_byte_near( &HONTAI_addr_vals[3][(rx_tx_addr[4] >> 4) & 0x0f]);
data_tx_addr[4] = 0x24;
#ifdef DEBUG_SERIAL
debug("A N");
for(uint8_t i=0; i < 5; i++)
debug(" %02X", data_tx_addr[i]);
debugln();
#endif
if(sub_protocol == JJRCX1)
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, data_tx_addr, sizeof(data_tx_addr));
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, data_tx_addr, 5);
else
XN297_SetTXAddr(data_tx_addr, sizeof(data_tx_addr));
XN297_SetTXAddr(data_tx_addr, 5);
//Hopping frequency table
uint8_t val;
for(uint8_t i=0;i<3;i++)
hopping_frequency[i]=pgm_read_byte_near( &HONTAI_hopping_frequency_nonels[sub_protocol == JJRCX1?1:0][i] );
{
if(sub_protocol==HONTAI_XKK170)
val = 60+10*i;
else
{
val = pgm_read_byte_near( &HONTAI_hopping_frequency[i] );
if(sub_protocol == JJRCX1)
val += 5;
}
hopping_frequency[i] = val;
}
hopping_frequency_no=0;
#ifdef DEBUG_SERIAL
debug("H");
for(uint8_t i=0; i < 3; i++)
debug(" %d(%02X)", hopping_frequency[i], hopping_frequency[i]);
debugln();
#endif
}
static void __attribute__((unused)) HONTAI_initialize_txid()
{
rx_tx_addr[4] = rx_tx_addr[2];
if(sub_protocol == HONTAI || sub_protocol == FQ777_951)
{
rx_tx_addr[0] = 0x4c; // first three bytes some kind of model id? - set same as stock tx
rx_tx_addr[1] = 0x4b;
rx_tx_addr[2] = 0x3a;
// First three bytes some kind of model id? - set same as stock tx
if(sub_protocol == JJRCX1 || sub_protocol == X5C1)
{//JJRCX1 & X5C1
rx_tx_addr[0] = 0x4B;
rx_tx_addr[1] = 0x59;
rx_tx_addr[2] = 0x3A;
}
else
{
rx_tx_addr[0] = 0x4b; // JJRC X1
rx_tx_addr[1] = 0x59;
rx_tx_addr[2] = 0x3a;
{//HONTAI, FQ777_951, HONTAI_XKK170
rx_tx_addr[0] = 0x4C;
rx_tx_addr[1] = 0x4B;
rx_tx_addr[2] = 0x3A;
#ifdef FORCE_HONTAI_XKK170_ORIGINAL_ID
if(sub_protocol == HONTAI_XKK170)
{
rx_tx_addr[3] = 0x5A;
rx_tx_addr[4] = 0x06;
}
#endif
}
#ifdef DEBUG_SERIAL
debug("A B");
for(uint8_t i=0; i < 5; i++)
debug(" %02X", rx_tx_addr[i]);
debugln();
#endif
}
uint16_t HONTAI_callback()
{
if(bind_counter!=0)
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
if(bind_counter)
{
HONTAI_send_packet(1);
bind_counter--;
if (bind_counter == 0)
{
@@ -241,24 +304,22 @@ uint16_t HONTAI_callback()
BIND_DONE;
}
}
else
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
HONTAI_send_packet(0);
}
HONTAI_send_packet();
return packet_period;
}
uint16_t initHONTAI()
void HONTAI_init()
{
BIND_IN_PROGRESS; // autobind protocol
bind_counter = HONTAI_BIND_COUNT;
HONTAI_RF_init();
HONTAI_initialize_txid();
HONTAI_init();
packet_period = sub_protocol == FQ777_951 ? FQ777_951_PACKET_PERIOD : HONTAI_PACKET_PERIOD;
return HONTAI_INITIAL_WAIT;
if(sub_protocol == FQ777_951)
packet_period = FQ777_951_PACKET_PERIOD;
else if(sub_protocol == HONTAI_XKK170)
packet_period = HONTAI_XKK170_PACKET_PERIOD;
else
packet_period = HONTAI_PACKET_PERIOD;
}
#endif

View File

@@ -285,7 +285,7 @@ static uint8_t __attribute__((unused)) hubsan_check_integrity()
}
#endif
uint16_t ReadHubsan()
uint16_t HUBSAN_callback()
{
#ifdef HUBSAN_HUB_TELEMETRY
static uint8_t rfMode=0;
@@ -446,7 +446,7 @@ uint16_t ReadHubsan()
return 0;
}
uint16_t initHubsan()
void HUBSAN_init()
{
const uint8_t allowed_ch[] = {0x14, 0x1e, 0x28, 0x32, 0x3c, 0x46, 0x50, 0x5a, 0x64, 0x6e, 0x78, 0x82};
A7105_Init();
@@ -467,7 +467,6 @@ uint16_t initHubsan()
}
packet_count=0;
bind_phase=0;
return 10000;
}
#endif

View File

@@ -0,0 +1,122 @@
/*
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 module makes it possible to bind to and control the IKEA "Ansluta" line
// of remote-controlled lights.
// To bind, first switch the receiver into binding mode, then the TX.
// Once bound, the TX can send one of three commands:
// lights off, lights dimmed 50% and lights on.
// Those are mapped to throttle ranges 0..0x55, 0x56..0xAA, 0xAB..0xFF.
#if defined(IKEAANSLUTA_CC2500_INO)
#include "iface_cc2500.h"
#define IKEAANSLUTA_BIND_COUNT 30 // ~ 2sec autobind/65ms per loop = 30 binding packets
// Commands
#define IKEAANSLUTA_LIGHT_OFF 0x01
#define IKEAANSLUTA_LIGHT_DIM 0x02 // 50% dimmed light
#define IKEAANSLUTA_LIGHT_ON 0x03
#define IKEAANSLUTA_PAIR 0xFF
void IKEAANSLUTA_send_command(uint8_t command){
CC2500_Strobe(CC2500_SIDLE);
packet[4] = option;
packet[5] = command;
CC2500_WriteData(packet, 8);
}
uint16_t IKEAANSLUTA_callback(void)
{
if (bind_counter) {
IKEAANSLUTA_send_command(IKEAANSLUTA_PAIR);
if(--bind_counter == 0) {
BIND_DONE;
CC2500_SetPower();
}
}
else {
uint8_t throttle = convert_channel_8b(THROTTLE);
uint8_t cmd = throttle <= 0x55 ? IKEAANSLUTA_LIGHT_OFF :
throttle <= 0xAA ? IKEAANSLUTA_LIGHT_DIM :
IKEAANSLUTA_LIGHT_ON;
IKEAANSLUTA_send_command(cmd);
}
return 65535; // 65ms loop cycle is more than enough here (we could make it even longer if not for uint16_t)
}
// Register initialization values as a continuous memory block (to save on flash memory)
const PROGMEM uint8_t IKEAANSLUTA_init_values[] = {
0xFF, // CC2500_06_PKTLEN
0x04, // CC2500_07_PKTCTRL1
0x05, // CC2500_08_PKTCTRL0
0x00, // CC2500_09_ADDR (unused, default)
0x10, // CC2500_0A_CHANNR
0x09, // CC2500_0B_FSCTRL1
0x00, // CC2500_0C_FSCTRL0
0x5D, // CC2500_0D_FREQ2
0x93, // CC2500_0E_FREQ1
0xB1, // CC2500_0F_FREQ0
0x2D, // CC2500_10_MDMCFG4
0x3B, // CC2500_11_MDMCFG3
0x73, // CC2500_12_MDMCFG2
0xA2, // CC2500_13_MDMCFG1
0xF8, // CC2500_14_MDMCFG0
0x01, // CC2500_15_DEVIATN
0x07, // CC2500_16_MCSM2
0x30, // CC2500_17_MCSM1
0x18, // CC2500_18_MCSM0
0x1D, // CC2500_19_FOCCFG
0x1C, // CC2500_1A_BSCFG
0xC7, // CC2500_1B_AGCCTRL2
0x00, // CC2500_1C_AGCCTRL1
0xB2, // CC2500_1D_AGCCTRL0
0x87, // CC2500_1E_WOREVT1 (unused, default)
0x6b, // CC2500_1F_WOREVT0 (unused, default)
0xf8, // CC2500_20_WORCTRL (unused, default)
0xB6, // CC2500_21_FREND1
0x10, // CC2500_22_FREND0
0xEA, // CC2500_23_FSCAL3
0x0A, // CC2500_24_FSCAL2
0x00, // CC2500_25_FSCAL1
0x11, // CC2500_26_FSCAL0
0x41, // CC2500_27_RCCTRL1
0x00, // CC2500_28_RCCTRL0
};
void IKEAANSLUTA_init(void)
{
if (IS_BIND_DONE) bind_counter = 0;
else bind_counter = IKEAANSLUTA_BIND_COUNT;
// All packets we send are the same
packet[0] = 0x06;
packet[1] = 0x55;
packet[2] = 0x01;
// Bytes 3&4 are the transmitter address (to which the RX binds)
// Byte 5 is the command.
packet[3] = rx_tx_addr[3]; // <pseudorandom tx-fixed value> + <rx_num>
// packet[4] = option;
// packet[5] = 0x00; // Command goes here
packet[6] = 0xAA;
packet[7] = 0xFF;
// Configure & initialize CC2500
for (uint8_t i = 0; i <= CC2500_28_RCCTRL0-CC2500_06_PKTLEN; ++i)
CC2500_WriteReg(CC2500_06_PKTLEN+i, pgm_read_byte_near(&IKEAANSLUTA_init_values[i]));
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower();
}
#endif

View File

@@ -35,8 +35,7 @@ enum PktState {
J6PRO_CHAN_4,
};
const uint8_t PROGMEM j6pro_bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49};
const uint8_t j6pro_data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f};
const uint8_t j6pro_data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f}; // unneeded since this is the default table after a reset
static void __attribute__((unused)) j6pro_build_bind_packet()
{
@@ -59,7 +58,7 @@ static void __attribute__((unused)) j6pro_build_data_packet()
packet[0] = 0xaa; //FIXME what is this?
for (i = 0; i < 12; i++)
{
value = convert_channel_10b(CH_AETR[i]);
value = convert_channel_10b(CH_AETR[i], false);
packet[i+1] = value & 0xff;
upperbits |= (value >> 8) << (i * 2);
}
@@ -84,7 +83,9 @@ static void __attribute__((unused)) j6pro_cyrf_init()
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xee);
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x00);
CYRF_ConfigDataCode(j6pro_data_code, 16);
//Same as default reset but issues if not configured...
CYRF_ConfigDataCode(j6pro_data_code);
CYRF_WritePreamble(0x333302);
CYRF_GetMfgData(cyrfmfg_id);
@@ -97,7 +98,7 @@ static void __attribute__((unused)) cyrf_bindinit()
/* Use when binding */
CYRF_SetPower(0x28); //Deviation using max power, replaced by bind power...
//CYRF_ConfigRFChannel(0x52);
CYRF_PROGMEM_ConfigSOPCode(j6pro_bind_sop_code);
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[19]);
CYRF_ConfigCRCSeed(0x0000);
//CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
//CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80);
@@ -111,8 +112,8 @@ static void __attribute__((unused)) cyrf_datainit()
{
/* Use when already bound */
uint8_t sop_idx = (0xff & (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[5])) % 19;
uint16_t crc = (0xff & (cyrfmfg_id[1] - cyrfmfg_id[4] + cyrfmfg_id[5])) |
((0xff & (cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[4] + cyrfmfg_id[5])) << 8);
crc = (0xff & (cyrfmfg_id[1] - cyrfmfg_id[4] + cyrfmfg_id[5])) |
((0xff & (cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[4] + cyrfmfg_id[5])) << 8);
//CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24);
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[sop_idx]);
CYRF_ConfigCRCSeed(crc);
@@ -122,11 +123,11 @@ static void __attribute__((unused)) j6pro_set_radio_channels()
{
//FIXME: Query free channels
//lowest channel is 0x08, upper channel is 0x4d?
CYRF_FindBestChannels(hopping_frequency, 3, 5, 8, 77);
CYRF_FindBestChannels(hopping_frequency, 3, 5, 8, 77, FIND_CHANNEL_ANY);
hopping_frequency[3] = hopping_frequency[0];
}
uint16_t ReadJ6Pro()
uint16_t J6PRO_callback()
{
uint16_t start;
@@ -226,7 +227,7 @@ uint16_t ReadJ6Pro()
return 0;
}
uint16_t initJ6Pro()
void J6PRO_init()
{
j6pro_cyrf_init();
@@ -234,7 +235,6 @@ uint16_t initJ6Pro()
phase = J6PRO_BIND;
else
phase = J6PRO_CHANSEL;
return 2400;
}
#endif

View File

@@ -0,0 +1,450 @@
/*
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(JIABAILE_NRF24L01_INO)
#include "iface_xn297.h"
//#define FORCE_JIABAILE_ORIGINAL_ID
//#define FORCE_JIABAILE_GYRO_ORIGINAL_ID
#define JIABAILE_PAYLOAD_SIZE 8
#define JIABAILE_RX_PAYLOAD_SIZE 7
#define JIABAILE_RF_NUM_CHANNELS 3
#define JIABAILE_BIND_PACKET_PERIOD 12700
#define JIABAILE_PACKET_PERIOD 2408
#define JIABAILE_GYRO_PACKET_PERIOD 8205
#define JIABAILE_BIND_COUNT 160 //2 sec
#define JIABAILE_WRITE_TIME 1000
enum {
JIABAILE_BIND=0,
JIABAILE_RX,
JIABAILE_PREP_DATA,
JIABAILE_DATA,
};
static uint8_t __attribute__((unused)) JIABAILE_channel(uint8_t num)
{
uint8_t val=convert_channel_16b_limit(num,0,100);
if(val > 50+num)
{
packet[3] |= 0x01;
return val-50;
}
if(val < 50-num)
{
packet[3] |= 0x02;
return 50-val;
}
return 0;
}
static void __attribute__((unused)) JIABAILE_send_packet()
{
if(!(sub_protocol == JIABAILE_GYRO && IS_BIND_IN_PROGRESS))
{
hopping_frequency_no++;
if(hopping_frequency_no > 2)
hopping_frequency_no = 0;
XN297_Hopping(hopping_frequency_no);
}
if(sub_protocol == JIABAILE_STD)
{//Std
memcpy(packet,rx_tx_addr,3);
memset(&packet[3], 0x00, 4);
if(IS_BIND_DONE)
{//Normal
packet[4] = convert_channel_16b_limit(RUDDER,0,50)-25; //ST Trim
packet[6] = JIABAILE_channel(AILERON); //ST
packet[3] ^= 0x03; //Reverse ST channel
packet[3] <<= 2; //Move ST channel where it should be
packet[5] = JIABAILE_channel(ELEVATOR); //TH
packet[3] |= GET_FLAG(CH5_SW, 0x20) //Low speed
|GET_FLAG(CH7_SW, 0x40) //Flash light
|GET_FLAG(!CH6_SW, 0x80); //Light
if(!CH5_SW && Channel_data[CH5] > CHANNEL_MIN_COMMAND)
packet[3] |= 0x10; //Mid speed
}
else
{
bind_counter--;
if(!bind_counter)
{
BIND_DONE;
phase = JIABAILE_PREP_DATA;
}
}
packet[7] = 0x55 + hopping_frequency[hopping_frequency_no];
for(uint8_t i=0;i<JIABAILE_PAYLOAD_SIZE-1;i++)
packet[7] += packet[i];
}
else
{//Gyro
if(bind_counter)
{
bind_counter--;
if(!bind_counter)
{
BIND_DONE;
XN297_SetTXAddr(rx_tx_addr, 4);
}
}
uint8_t crc_pos;
if(IS_BIND_IN_PROGRESS)
{
memcpy(packet,rx_tx_addr,4);
packet[4] = hopping_frequency[1];
packet[5] = hopping_frequency[2];
crc_pos = 6;
packet[7] = 0x55;
}
else
{
packet[0] = convert_channel_16b_limit(CH2,0x60,0xA0); //Throttle
packet[1] = convert_channel_16b_limit(CH1,0x40,0xC0); //Steering
if(Channel_data[CH5] < CHANNEL_MIN_COMMAND)
packet[2] = 0x02; //High speed
else if(CH5_SW)
packet[2] = 0x00; //Low speed
else
packet[2] = 0x01; //Mid speed
packet[3] = convert_channel_8b(CH3) ^0xFF; //Gyro
uint8_t val = GET_FLAG(CH6_SW, 0x04) //Light
|GET_FLAG(CH7_SW, 0x08); //Flash
if(Channel_data[CH4] > CHANNEL_MAX_COMMAND)
val |= 0x01; //Trim right
else if(Channel_data[CH4] < CHANNEL_MIN_COMMAND)
val |= 0x02; //Trim left
packet[4] = val;
packet[5] = packet[6] = 0x00; //?
crc_pos = 7;
}
uint8_t sum=0;
for(uint8_t i=0; i<crc_pos; i++)
sum += packet[i];
sum ^= 0xFF;
packet[crc_pos] = sum;
}
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, JIABAILE_PAYLOAD_SIZE);
#if 0
debug("B%d ",bind_counter);
debug("H%d RF%d",hopping_frequency_no,hopping_frequency[hopping_frequency_no]);
for(uint8_t i=0; i < JIABAILE_PAYLOAD_SIZE; i++)
debug(" %02X", packet[i]);
debugln();
#endif
}
static void __attribute__((unused)) JIABAILE_initialize_txid()
{
if(sub_protocol == JIABAILE_STD)
{//Std
rx_tx_addr[0] = rx_tx_addr[3];
#ifdef FORCE_JIABAILE_ORIGINAL_ID
memcpy(rx_tx_addr,(uint8_t *)"\xCB\x03\xA5",3);
//memcpy(rx_tx_addr,(uint8_t *)"\x3D\x08\xA2",3);
//Normal frequencies are calculated from the car ID...
//memcpy(&hopping_frequency[3],(uint8_t *)"\x23\x2D\x4B",3); //35,45,75
memcpy(&hopping_frequency[3],(uint8_t *)"\x24\x43\x4C",3); //36,67,76
#endif
//Bind frequencies
memcpy(hopping_frequency,(uint8_t *)"\x07\x27\x45",3); //7,39,69
}
else
{//Gyro
rx_tx_addr[0] += RX_num;
uint8_t val = (rx_tx_addr[0] & 0x0F) + 5; //5..20
for(uint8_t i=0; i<3; i++)
hopping_frequency[i] = val+ 20*i; //hopping_frequency[1,2] could be whatever but...
#ifdef FORCE_JIABAILE_GYRO_ORIGINAL_ID
if(RX_num)
{
memcpy(rx_tx_addr,(uint8_t *)"\x7D\x82\x28\xC2",4);
memcpy(hopping_frequency,(uint8_t *)"\x12\x1B\x35",3); //18,27,53
}
else
{
memcpy(rx_tx_addr,(uint8_t *)"\x0C\xF3\x59\xB3",4);
memcpy(hopping_frequency,(uint8_t *)"\x11\x1C\x36",3); //17,28,54
}
#endif
debugln("ID: %02X %02X %02X %02X, HOP: %2d %2d %2d",rx_tx_addr[0],rx_tx_addr[1],rx_tx_addr[2],rx_tx_addr[3],hopping_frequency[0],hopping_frequency[1],hopping_frequency[2]);
}
}
static void __attribute__((unused)) JIABAILE_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
//Bind address
if(sub_protocol == JIABAILE_STD)
{//Std
memcpy(rx_id,(uint8_t*)"\xA7\x07\x57\xA7\x26", 5);
XN297_SetTXAddr(rx_id, 5);
XN297_SetRXAddr(rx_id, JIABAILE_RX_PAYLOAD_SIZE);
}
else
{//Gyro
XN297_SetTXAddr((uint8_t*)"\x14\x41\x11\x13", 4);
XN297_RFChannel(0x29); //41
}
}
uint16_t JIABAILE_callback()
{
uint8_t sum;
uint16_t addr;
switch(phase)
{
case JIABAILE_BIND:
phase++; // JIABAILE_RX but is overwritten if RX or bind timeout
if(XN297_IsRX())
{
if(XN297_ReadPayload(packet_in, JIABAILE_RX_PAYLOAD_SIZE))
{//CRC OK
#ifdef DEBUG_SERIAL
debug("RX");
for(uint8_t i=0; i < JIABAILE_RX_PAYLOAD_SIZE; i++)
debug(" %02X", packet_in[i]);
debugln();
#endif
//RX: CB 03 A5 9D 05 A2 68
if(memcmp(packet_in,rx_tx_addr,3)==0)
{//TX ID match
//Check packet
sum=0xAA + hopping_frequency[hopping_frequency_no];
for(uint8_t i=0; i < JIABAILE_RX_PAYLOAD_SIZE-1; i++)
sum+=packet_in[i];
if(sum==packet_in[6])
{
//Write the RXID
#ifdef DEBUG_SERIAL
debug("RXID ");
for(uint8_t i=0; i < 3; i++)
debug(" %02X", packet_in[3+i]);
debugln();
#endif
addr=JIABAILE_EEPROM_OFFSET+RX_num*3;
for(uint8_t i=0;i<3;i++)
eeprom_write_byte((EE_ADDR)(addr+i),packet_in[3+i]);
//Switch to normal mode
BIND_DONE;
phase = JIABAILE_PREP_DATA;
}
#ifdef DEBUG_SERIAL
else
debug("Wrong Sum");
}
else
debug("Wrong TX ID");
}
else
debug("Bad CRC");
debugln("");
#else
}
}
#endif
}
XN297_SetTxRxMode(TXRX_OFF);
JIABAILE_send_packet();
return JIABAILE_WRITE_TIME;
case JIABAILE_RX:
//Wait for the packet transmission to finish
while(XN297_IsPacketSent()==false);
//Switch to RX
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
phase = JIABAILE_BIND;
return JIABAILE_BIND_PACKET_PERIOD - JIABAILE_WRITE_TIME;
case JIABAILE_PREP_DATA:
//Read the RXID
addr=JIABAILE_EEPROM_OFFSET+RX_num*3;
for(uint8_t i=0;i<3;i++)
rx_id[i+1] = eeprom_read_byte((EE_ADDR)(addr+i));
#ifdef DEBUG_SERIAL
debug("RXID ");
for(uint8_t i=0; i < 3; i++)
debug(" %02X", rx_id[i+1]);
#endif
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTXAddr(rx_id, 5);
//Set the normal frequencies
sum=rx_id[1]&0x07;
hopping_frequency[0] = (sum>4?30:8) + sum;
if(sum==4 || sum ==7)
hopping_frequency[0]++;
hopping_frequency[1] = 40 + sum;
if((sum & 0x06) == 0x06)
hopping_frequency[1] += 21;
hopping_frequency[2] = 70 + sum;
#ifdef DEBUG_SERIAL
debug(" RF");
for(uint8_t i=0; i < 3; i++)
debug(" %d", hopping_frequency[i]);
debugln();
#endif
phase++;
default: //JIABAILE_DATA
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
JIABAILE_send_packet();
break;
}
return packet_period;
}
void JIABAILE_init()
{
JIABAILE_initialize_txid();
JIABAILE_RF_init();
if(sub_protocol == JIABAILE_STD)
{//Std
if(IS_BIND_IN_PROGRESS)
{
phase = JIABAILE_BIND;
bind_counter = JIABAILE_BIND_COUNT;
}
else
phase = JIABAILE_PREP_DATA;
packet_period = JIABAILE_PACKET_PERIOD;
}
else
{//Gyro
phase = JIABAILE_DATA;
bind_counter = IS_BIND_IN_PROGRESS?JIABAILE_BIND_COUNT>>2:1;
packet_period = JIABAILE_GYRO_PACKET_PERIOD;
}
hopping_frequency_no = 0;
}
#endif
/*
// CAR RX debug code
static void __attribute__((unused)) JIABAILE_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
//Bind address
memcpy(rx_id,(uint8_t*)"\xA7\x07\x57\xA7\x26", 5);
XN297_SetTXAddr(rx_id, 5);
XN297_SetRXAddr(rx_id, JIABAILE_PAYLOAD_SIZE);
XN297_RFChannel(7);
rx_tx_addr[0] = 0x00;
rx_tx_addr[1] = RX_num;
rx_tx_addr[2] = 0x00;
}
uint16_t JIABAILE_callback()
{
switch(phase)
{
case JIABAILE_BIND:
if(XN297_IsRX())
{
if(XN297_ReadPayload(packet_in, JIABAILE_PAYLOAD_SIZE))
{//CRC OK
XN297_SetTxRxMode(TXRX_OFF);
#ifdef DEBUG_SERIAL
debug("RX Bind");
for(uint8_t i=0; i < JIABAILE_PAYLOAD_SIZE; i++)
debug(" %02X", packet_in[i]);
debugln();
#endif
memcpy(packet,packet_in,3);
memcpy(&packet[3],rx_tx_addr,3);
packet[6]=0xAA + 7;
for(uint8_t i=0; i < JIABAILE_RX_PAYLOAD_SIZE-1; i++)
packet[6]+=packet[i];
XN297_SetTxRxMode(TX_EN);
memcpy(&rx_id[1],rx_tx_addr,3);
bind_counter = 10;
phase = JIABAILE_RX;
}
}
return JIABAILE_WRITE_TIME;
case JIABAILE_RX:
if(bind_counter)
{
bind_counter--;
XN297_WritePayload(packet, JIABAILE_RX_PAYLOAD_SIZE);
#ifdef DEBUG_SERIAL
debug("TX Bind");
for(uint8_t i=0; i < JIABAILE_RX_PAYLOAD_SIZE; i++)
debug(" %02X", packet[i]);
debugln();
#endif
return JIABAILE_PACKET_PERIOD;
}
//Wait for the packet transmission to finish
//while(XN297_IsPacketSent()==false);
//Switch to RX
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetRXAddr(rx_id, JIABAILE_PAYLOAD_SIZE);
hopping_frequency_no++;
if(hopping_frequency_no>84)
hopping_frequency_no = 0;
debug(".");
XN297_RFChannel(hopping_frequency_no);
XN297_SetTxRxMode(RX_EN);
phase = JIABAILE_DATA;
return JIABAILE_BIND_PACKET_PERIOD;
case JIABAILE_DATA:
if(XN297_IsRX())
{
debugln("");
if(XN297_ReadPayload(packet_in, JIABAILE_PAYLOAD_SIZE))
{//CRC OK
#ifdef DEBUG_SERIAL
debug("CH=%d=%02X P:",hopping_frequency_no,hopping_frequency_no);
for(uint8_t i=0; i < JIABAILE_PAYLOAD_SIZE; i++)
debug(" %02X", packet_in[i]);
#endif
//Check packet
uint8_t sum=0x55 + hopping_frequency_no;
for(uint8_t i=0; i < JIABAILE_PAYLOAD_SIZE-1; i++)
sum+=packet_in[i];
if(sum==packet_in[7])
{
debug("Good channel");
}
else
debug("Wrong Sum");
}
else
debug("Bad CRC");
debugln("");
}
phase = JIABAILE_RX;
break;
}
return JIABAILE_PACKET_PERIOD;
}
void JIABAILE_init()
{
JIABAILE_RF_init();
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
phase = JIABAILE_BIND;
hopping_frequency_no = 7;
}
*/

View File

@@ -0,0 +1,183 @@
/*
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_xn297.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 SKYTMBLR_RF_BIND_CHANNEL 40
#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,
// flags going to packet[9]
SKYTMBLR_FLAG_UNK1 = 0x40,
SKYTMBLR_FLAG_UNK2 = 0x80,
// flags going to packet[10]
SKYTMBLR_FLAG_LED = 0x40,
SKYTMBLR_FLAG_UNK3 = 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] = (sub_protocol == JJRC345 ? JJRC345_RF_BIND_CHANNEL:SKYTMBLR_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
XN297_Hopping(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) // 0x40 HeadLess
| GET_FLAG(CH7_SW ,JJRC345_FLAG_RTH); // 0x80 RTH
packet[9] = 0x00 // Elevator trim, 00 when not used, 20..25 when trimmed up, 0..1F when trimmed down
| GET_FLAG(CH9_SW ,SKYTMBLR_FLAG_UNK1) // 0x40 Unknown
| GET_FLAG(CH10_SW,SKYTMBLR_FLAG_UNK2); // 0x80 Unknown
packet[10] = 0x00 // Aileron trim, 00 when not used, 00..1F when trimmed left, 21..3F when trimmed right
| GET_FLAG(!CH8_SW,SKYTMBLR_FLAG_LED) // 0x40 LED
| GET_FLAG(CH11_SW,SKYTMBLR_FLAG_UNK3); // 0x80 Unknown
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];
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, JJRC345_PACKET_SIZE);
}
static void __attribute__((unused)) JJRC345_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5);
//XN297_HoppingCalib(JJRC345_NUM_CHANNELS);
XN297_RFChannel(sub_protocol == JJRC345 ? JJRC345_RF_BIND_CHANNEL:SKYTMBLR_RF_BIND_CHANNEL); // Bind channel
}
uint16_t JJRC345_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(JJRC345_PACKET_PERIOD);
#endif
if(bind_counter)
{
bind_counter--;
if (bind_counter==0)
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
}
void JJRC345_init(void)
{
BIND_IN_PROGRESS; // autobind protocol
bind_counter = JJRC345_BIND_COUNT;
JJRC345_initialize_txid();
JJRC345_RF_init();
}
#endif

View File

@@ -0,0 +1,115 @@
/*
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(JOYSWAY_A7105_INO)
#include "iface_a7105.h"
//#define JOYSWAY_FORCE_ID
static void __attribute__((unused)) JOYSWAY_send_packet()
{
static uint8_t next_ch = 0x30;
//RF frequency
if (packet_count == 254)
{
packet_count = 0;
A7105_WriteID(0x5475c52a);
rf_ch_num = 0x0a;
}
else if (packet_count == 2)
{
A7105_WriteID(MProtocol_id);
rf_ch_num = 0x30;
}
else
{
if (packet_count & 0x01)
rf_ch_num = 0x30;
else
rf_ch_num = next_ch;
}
if (! (packet_count & 0x01))
{
next_ch++;
if (next_ch >= 0x45)
next_ch = 0x30;
}
//Payload
packet[0] = packet_count == 0 ? 0xdd : 0xff;
//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];
packet[5] = 0x00;
//Channels
for (uint8_t i = 0; i < 4; i++)
packet[ 6 + (i & 0x01) + ((i & 0x02)<<1)] = convert_channel_16b_limit(i, 0x00, 0xCC);
packet[8] = 0x64;
packet[9] = 0x64;
packet[12] = 0x64;
packet[13] = 0x64;
packet[14] = packet_count == 0 ? 0x30 : 0xaa;
//Check
uint8_t value = 0;
for (uint8_t i = 0; i < 15; i++)
value += packet[i];
packet[15] = value;
//Send
#if 0
debug("ch=%02X P=",rf_ch_num);
for(uint8_t i=0; i<16; i++)
debug("%02X ", packet[i]);
debugln("");
#endif
A7105_WriteData(16, rf_ch_num);
A7105_SetPower();
packet_count++;
}
uint16_t JOYSWAY_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(6000);
#endif
#ifndef FORCE_JOYSWAY_TUNING
A7105_AdjustLOBaseFreq(1);
#endif
JOYSWAY_send_packet();
return 6000;
}
void JOYSWAY_init()
{
BIND_DONE; // not a bind protocol
MProtocol_id &= 0x00FFFFFF;
MProtocol_id |= 0xF8000000;
#ifdef JOYSWAY_FORCE_ID
MProtocol_id = 0xf82dcaa0;
#endif
set_rx_tx_addr(MProtocol_id);
A7105_Init();
packet_count = 2;
}
#endif

View File

@@ -0,0 +1,180 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// Compatible with KF606 plane.
#if defined(KF606_CCNRF_INO)
#include "iface_xn297.h"
//#define FORCE_KF606_ORIGINAL_ID
//#define FORCE_MIG320_ORIGINAL_ID
//#define FORCE_ZCZ50_ORIGINAL_ID
#define KF606_INITIAL_WAIT 500
#define KF606_PACKET_PERIOD 3000
#define KF606_RF_BIND_CHANNEL 7
#define KF606_PAYLOAD_SIZE 4
#define KF606_BIND_COUNT 857 //3sec
#define KF606_RF_NUM_CHANNELS 2
static void __attribute__((unused)) KF606_send_packet()
{
uint8_t len = KF606_PAYLOAD_SIZE;
if(IS_BIND_IN_PROGRESS)
{
if(sub_protocol != KF606_ZCZ50)
{
packet[0] = 0xAA;
memcpy(&packet[1],rx_tx_addr,3);
}
else
memcpy(packet,rx_tx_addr,4);
}
else
{
XN297_Hopping(hopping_frequency_no);
hopping_frequency_no ^= 1; // 2 RF channels
packet[0] = 0x55;
if(sub_protocol == KF606_ZCZ50) len--;
packet[len-3] = convert_channel_8b(THROTTLE); // 0..255
// Deadband is needed on aileron, 40 gives +-6%
packet[len-2] = convert_channel_8b_limit_deadband(AILERON,0x00,0x80,0xFF,40); // Aileron: High rate:2B..80..DA
uint8_t p3;
p3 = convert_channel_8b(CH5)>>3; // Aileron trim must be on a separated channel 01..10..1F
p3 += (packet[2]-0x80)>>3; // Drive trims for more aileron authority
if(p3 > 0x80)
p3 = 0x01;
else if(p3 > 0x1F)
p3 = 0x1F;
p3 |= GET_FLAG(CH6_SW, 0xC0); // 0xC0 and 0xE0 are both turning the LED off, not sure if there is another hidden feature
packet[len-1] = p3;
}
if(sub_protocol == KF606_MIG320)
{
len++;
packet[4] = 0; // additional channel?
}
#if 0
for(uint8_t i=0; i<len; i++)
debug("%02X ",packet[i]);
debugln("");
#endif
// Send
XN297_SetPower();
XN297_SetFreqOffset();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, len);
}
static void __attribute__((unused)) KF606_initialize_txid()
{
rx_tx_addr[0]=rx_tx_addr[3]; // Use RX_num;
hopping_frequency[0]=(rx_tx_addr[0]&0x3F)+9;
hopping_frequency[1]=hopping_frequency[0]+3;
#ifdef FORCE_KF606_ORIGINAL_ID
//TX1
rx_tx_addr[0]=0x57;
rx_tx_addr[1]=0x02;
rx_tx_addr[2]=0x00;
hopping_frequency[0]=0x20;
hopping_frequency[1]=0x23;
//TX2
rx_tx_addr[0]=0x25;
rx_tx_addr[1]=0x04;
rx_tx_addr[2]=0x00;
hopping_frequency[0]=0x2E;
hopping_frequency[1]=0x31;
#endif
#ifdef FORCE_MIG320_ORIGINAL_ID
rx_tx_addr[0]=0xBB;
rx_tx_addr[1]=0x13;
rx_tx_addr[2]=0x00;
hopping_frequency[0]=68;
hopping_frequency[1]=71;
#endif
if(sub_protocol == KF606_ZCZ50)
{
rx_tx_addr[1] = rx_tx_addr[0];
rx_tx_addr[0]=0xAA;
}
#ifdef FORCE_ZCZ50_ORIGINAL_ID
rx_tx_addr[0]=0xAA;
rx_tx_addr[1]=0x67;
rx_tx_addr[2]=0x64;
rx_tx_addr[3]=0x01;
hopping_frequency[0]=48;
hopping_frequency[1]=51;
#endif
}
static void __attribute__((unused)) KF606_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_250K);
XN297_SetTXAddr((uint8_t*)"\xe7\xe7\xe7\xe7\xe7", 5);
XN297_HoppingCalib(KF606_RF_NUM_CHANNELS); // Calibrate all channels
XN297_RFChannel(KF606_RF_BIND_CHANNEL); // Set bind channel
}
uint16_t KF606_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(KF606_PACKET_PERIOD);
#endif
if(bind_counter)
if(--bind_counter==0)
{
BIND_DONE;
XN297_SetTXAddr(rx_tx_addr, sub_protocol != KF606_ZCZ50 ? 3 : 4);
}
KF606_send_packet();
return KF606_PACKET_PERIOD;
}
void KF606_init()
{
BIND_IN_PROGRESS; // autobind protocol
KF606_initialize_txid();
KF606_RF_init();
hopping_frequency_no = 0;
bind_counter=KF606_BIND_COUNT;
}
#endif
// MIG320 protocol
// Bind
// 250K C=7 S=Y A= E7 E7 E7 E7 E7 P(5)= AA BB 13 00 00
// 3ms on ch7
// Normal
// 250K C=68 S=Y A= BB 13 00 P(5)= 55 00 80 10 00
// P[1] = THR 00..FF
// P[2] = AIL 2B..80..DA
// P[3] = TRIM 01..10..1F
// channels 68=BB&3F+9 and 71
// ZCZ50v2 protocol (with fake front propeller)
// Bind
// 250K C=7 S=Y A= E7 E7 E7 E7 E7 P(4)= AA 67 64 01
// 3ms on ch7
// Normal
// 250K C=48 S=Y A= AA 67 64 01 P(3)= 00 80 10
// P[0] = THR 0x00..0xFF
// P[1] = AIL low rate 0x52..0x80..0xB1, high rate: 0x41..0x80..0xC3
// P[2] = TRIM 0x01..0x10..0x1F + UNKNOWN 0x00 or 0xC0

View File

@@ -1,112 +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 KF606 plane.
#if defined(KF606_NRF24L01_INO)
#include "iface_nrf250k.h"
//#define FORCE_KF606_ORIGINAL_ID
#define KF606_INITIAL_WAIT 500
#define KF606_PACKET_PERIOD 3000
#define KF606_RF_BIND_CHANNEL 7
#define KF606_PAYLOAD_SIZE 4
#define KF606_BIND_COUNT 857 //3sec
#define KF606_RF_NUM_CHANNELS 2
static void __attribute__((unused)) KF606_send_packet()
{
if(IS_BIND_IN_PROGRESS)
{
packet[0] = 0xAA;
memcpy(&packet[1],rx_tx_addr,3);
}
else
{
packet[0]= 0x55;
packet[1]= convert_channel_8b(THROTTLE); // 0..255
// Deadband is needed on aileron, 40 gives +-6%
packet[2]=convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, Low rates:50..80..AF, High rates:3E..80..C1
// Aileron trim must be on a separated channel C1..D0..DF
packet[3]= convert_channel_16b_limit(CH5,0xC1,0xDF);
}
if(IS_BIND_DONE)
{
XN297L_Hopping(hopping_frequency_no);
hopping_frequency_no ^= 1; // 2 RF channels
}
XN297L_WritePayload(packet, KF606_PAYLOAD_SIZE);
XN297L_SetPower(); // Set tx_power
XN297L_SetFreqOffset(); // Set frequency offset
}
static void __attribute__((unused)) KF606_initialize_txid()
{
rx_tx_addr[0]=rx_tx_addr[3]; // Use RX_num;
hopping_frequency[0]=(rx_tx_addr[0]&0x3F)+9;
hopping_frequency[1]=hopping_frequency[0]+3;
#ifdef FORCE_KF606_ORIGINAL_ID
//TX1
rx_tx_addr[0]=0x57;
rx_tx_addr[1]=0x02;
rx_tx_addr[2]=0x00;
hopping_frequency[0]=0x20;
hopping_frequency[0]=0x23;
//TX2
rx_tx_addr[0]=0x25;
rx_tx_addr[1]=0x04;
rx_tx_addr[2]=0x00;
hopping_frequency[0]=0x2E;
hopping_frequency[0]=0x31;
#endif
}
static void __attribute__((unused)) KF606_init()
{
XN297L_Init();
XN297L_SetTXAddr((uint8_t*)"\xe7\xe7\xe7\xe7\xe7", 5);
XN297L_HoppingCalib(KF606_RF_NUM_CHANNELS); // Calibrate all channels
XN297L_RFChannel(KF606_RF_BIND_CHANNEL); // Set bind channel
}
uint16_t KF606_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(KF606_PACKET_PERIOD);
#endif
if(IS_BIND_IN_PROGRESS)
if(--bind_counter==0)
{
BIND_DONE;
XN297_SetTXAddr(rx_tx_addr, 3);
}
KF606_send_packet();
return KF606_PACKET_PERIOD;
}
uint16_t initKF606()
{
BIND_IN_PROGRESS; // autobind protocol
KF606_initialize_txid();
KF606_init();
hopping_frequency_no = 0;
bind_counter=KF606_BIND_COUNT;
return KF606_INITIAL_WAIT;
}
#endif

View File

@@ -63,7 +63,7 @@ enum {
KN_FLAG_DR = 0x01, // Dual Rate: 1 - full range
KN_FLAG_TH = 0x02, // Throttle Hold: 1 - hold
KN_FLAG_IDLEUP = 0x04, // Idle up: 1 - 3D
KN_FLAG_RES1 = 0x08,
KN_FLAG_RES1 = 0x08, // HoverDebugging
KN_FLAG_RES2 = 0x10,
KN_FLAG_RES3 = 0x20,
KN_FLAG_GYRO3 = 0x40, // 0 - 6G mode, 1 - 3G mode
@@ -125,35 +125,29 @@ static void __attribute__((unused)) kn_bind_init()
static void __attribute__((unused)) kn_update_packet_control_data()
{
uint16_t value;
value = convert_channel_10b(THROTTLE);
value = convert_channel_10b(THROTTLE, false);
packet[0] = (value >> 8) & 0xFF;
packet[1] = value & 0xFF;
value = convert_channel_10b(AILERON);
value = convert_channel_10b(AILERON, false);
packet[2] = (value >> 8) & 0xFF;
packet[3] = value & 0xFF;
value = convert_channel_10b(ELEVATOR);
value = convert_channel_10b(ELEVATOR, false);
packet[4] = (value >> 8) & 0xFF;
packet[5] = value & 0xFF;
value = convert_channel_10b(RUDDER);
value = convert_channel_10b(RUDDER, false);
packet[6] = (value >> 8) & 0xFF;
packet[7] = value & 0xFF;
// Trims, middle is 0x64 (100) range 0-200
packet[8] = convert_channel_16b_limit(CH9,0,200); // 0x64; // T
packet[9] = convert_channel_16b_limit(CH10,0,200); // 0x64; // A
packet[10] = convert_channel_16b_limit(CH11,0,200); // 0x64; // E
packet[11] = 0x64; // R
packet[11] = convert_channel_16b_limit(CH12,0,200); // 0x64; // R
flags=0;
if (CH5_SW)
flags = KN_FLAG_DR;
if (CH6_SW)
flags |= KN_FLAG_TH;
if (CH7_SW)
flags |= KN_FLAG_IDLEUP;
if (CH8_SW)
flags |= KN_FLAG_GYRO3;
packet[12] = flags;
packet[12] = GET_FLAG(CH5_SW, KN_FLAG_DR)
|GET_FLAG(CH6_SW, KN_FLAG_TH)
|GET_FLAG(CH7_SW, KN_FLAG_IDLEUP)
|GET_FLAG(CH8_SW, KN_FLAG_GYRO3)
|GET_FLAG(CH13_SW, KN_FLAG_RES1); //Hover debugging
packet[13] = 0x00;
if(sub_protocol==WLTOYS)
@@ -239,40 +233,25 @@ static void __attribute__((unused)) kn_calculate_freqency_hopping_channels()
// V977 needs payload length in the packet. We should configure 24L01 to enable Packet Control Field(PCF)
// Some RX reg settings are actually for enable PCF
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) kn_init()
static void __attribute__((unused)) KN_RF_init()
{
kn_calculate_tx_addr();
kn_calculate_freqency_hopping_channels();
NRF24L01_Initialize();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // Disable retransmit
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x20); // bytes of data payload for pipe 0
NRF24L01_Activate(0x73);
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
// Enable: Dynamic Payload Length to enable PCF
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, _BV(NRF2401_1D_EN_DPL));
NRF24L01_SetPower();
NRF24L01_FlushTx();
// Turn radio power on
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_SetBitrate(NRF24L01_BR_1M); //USE1MBPS_YES ? NRF24L01_BR_1M : NRF24L01_BR_250K;
NRF24L01_SetTxRxMode(TX_EN); // Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
}
//================================================================================================
// Private Functions
//================================================================================================
uint16_t initKN()
void KN_init()
{
if(sub_protocol==WLTOYS)
{
@@ -288,13 +267,11 @@ uint16_t initKN()
packet_count = KN_FX_PACKET_SEND_COUNT;
seed = KN_FX_PACKET_SEND_COUNT * KN_FX_SENDING_PACKET_PERIOD;
}
kn_init();
KN_RF_init();
phase = IS_BIND_IN_PROGRESS ? KN_PHASE_PRE_BIND : KN_PHASE_PRE_SEND;
return KN_INIT_WAIT_MS;
}
uint16_t kn_callback()
uint16_t KN_callback()
{
switch (phase)
{

View File

@@ -0,0 +1,185 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(KAMTOM_NRF24L01_INO)
#include "iface_xn297.h"
//#define FORCE_KAMTOM_ORIGINAL_ID
#define KAMTOM_PAYLOAD_SIZE 16
#define KAMTOM_RF_NUM_CHANNELS 4
#define KAMTOM_BIND_COUNT 2000
#define KAMTOM_WRITE_TIME 650
#define KAMTOM_BIND_CHANNEL 0x28 //40
#define KAMTOM_PACKET_PERIOD 3585
enum {
KAMTOM_DATA,
KAMTOM_RX,
};
static void __attribute__((unused)) KAMTOM_send_packet()
{
if(bind_counter)
{
bind_counter--;
if(!bind_counter)
BIND_DONE;
}
memset(packet, 0x00, 16);
if(IS_BIND_DONE)
{//Normal
XN297_Hopping(hopping_frequency_no);
hopping_frequency_no++;
hopping_frequency_no &= 3;
//RXID
packet[0] = rx_tx_addr[0];
packet[2] = rx_tx_addr[1];
//Next RF channel
packet[1] = hopping_frequency[hopping_frequency_no];
//Channels and trims
for(uint8_t i=0; i<6; i++)
{
packet[4+i] = convert_channel_s8b(CH_TAER[i]);
if(i>3) //ST_TR and TH_TR
packet[4+i] >>= 2;
}
//packet[11] = 0x00; //??
//TH_DR
packet[12] = convert_channel_16b_limit(CH7,0x25,0x64);
}
else
{
packet[1] = KAMTOM_BIND_CHANNEL;
memcpy(&packet[4],hopping_frequency,4);
packet[12] = 0xA5;
}
packet[10] = 0x40; //??
//Checksum
uint16_t sum = packet[1];
for(uint8_t i=4;i<13;i++)
sum += packet[i];
packet[13] = sum;
packet[3] = (sum>>6) & 0xFC;
//TXID
packet[14] = rx_tx_addr[2];
packet[15] = rx_tx_addr[3];
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WriteEnhancedPayload(packet, KAMTOM_PAYLOAD_SIZE,false);
#if 0
//def DEBUG_SERIAL
for(uint8_t i=0; i < KAMTOM_PAYLOAD_SIZE; i++)
debug("%02X ", packet[i]);
debugln();
#endif
}
static void __attribute__((unused)) KAMTOM_initialize_txid()
{
calc_fh_channels(4);
#ifdef FORCE_KAMTOM_ORIGINAL_ID
rx_tx_addr[0] = 0xC7;
rx_tx_addr[1] = 0x78;
rx_tx_addr[2] = 0x2C;
rx_tx_addr[3] = 0x25;
hopping_frequency[0] = 59;
hopping_frequency[1] = 59;
hopping_frequency[2] = 71;
hopping_frequency[3] = 65;
#endif
}
static void __attribute__((unused)) KAMTOM_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
//Address
XN297_SetTXAddr((uint8_t*)"\xCC\xDD\xEE\xDD", 4);
XN297_SetRXAddr((uint8_t*)"\xCC\xDD\xEE\xDD", KAMTOM_PAYLOAD_SIZE);
XN297_RFChannel(KAMTOM_BIND_CHANNEL);
}
uint16_t KAMTOM_callback()
{
static bool rx=false;
switch(phase)
{
case KAMTOM_DATA:
rx = XN297_IsRX();
XN297_SetTxRxMode(TXRX_OFF);
#ifdef MULTI_SYNC
telemetry_set_input_sync(KAMTOM_PACKET_PERIOD);
#endif
KAMTOM_send_packet();
if(rx)
{
uint8_t val=XN297_ReadEnhancedPayload(packet_in, KAMTOM_PAYLOAD_SIZE);
if(val==KAMTOM_PAYLOAD_SIZE)
{
BIND_DONE;
if(packet_in[0] == 0xA0 && packet_in[14] == rx_tx_addr[2] && packet_in[15] == rx_tx_addr[3])
{//Good packet with our TXID
rx_tx_addr[0] = packet_in[9];
rx_tx_addr[1] = packet_in[10];
#ifdef KAMTOM_HUB_TELEMETRY
v_lipo1 = packet_in[1] == 0x03 ? 0x00:0xFF; // low voltage
telemetry_link = 1;
#endif
}
#if 0
for(uint8_t i=0; i < KAMTOM_PAYLOAD_SIZE; i++)
debug(" %02X", packet_in[i]);
debugln();
#endif
}
}
phase++;
return KAMTOM_WRITE_TIME;
default: //KAMTOM_RX
//{ // Wait for packet to be sent before switching to receive mode
// uint16_t start=(uint16_t)micros();
// while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 500)
// if(XN297_IsPacketSent())
// break;
//}
//Switch to RX
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
phase = KAMTOM_DATA;
return KAMTOM_PACKET_PERIOD - KAMTOM_WRITE_TIME;
}
return 0;
}
void KAMTOM_init()
{
KAMTOM_initialize_txid();
KAMTOM_RF_init();
bind_counter = KAMTOM_BIND_COUNT;
phase = KAMTOM_DATA;
hopping_frequency_no = 0;
#ifdef KAMTOM_HUB_TELEMETRY
RX_RSSI = 100; // Dummy value
#endif
}
#endif

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(KYOSHO2_NRF24L01_INO)
#include "iface_nrf24l01.h"
#define KYOSHO2_PACKET_PERIOD 1120
#define KYOSHO2_BIND_PACKET_PERIOD 1600
#define KYOSHO2_BIND_COUNT 6000 // about 9sec
#define KYOSHO2_BIND_CHANNEL 0x50
#define KYOSHO2_PAYLOAD_SIZE 28
#define KYOSHO2_RF_CHANNELS 15
#define KYOSHO2_START_RF_CHANNEL 0x13 // No idea where it comes from... ID or unknown bytes during the bind?
#define KYOSHO2_NUM_CHANNEL 10 // Only 4 on the dumps but there is space for 10 channels in the payload...
#define FORCE_KYOSHO2_ID
bool KYOSHO2_resend;
//
static void __attribute__((unused)) KYOSHO2_send_packet()
{
if(KYOSHO2_resend == true)
{
NRF24L01_Strobe(NRF24L01_E3_REUSE_TX_PL);
if(IS_BIND_DONE)
KYOSHO2_resend = false;
return;
}
memset(packet,0x00,KYOSHO2_PAYLOAD_SIZE);
if(IS_BIND_IN_PROGRESS)
{
memcpy(packet, (uint8_t*)"\x01\x02\x05\x08\x1A\x2B\x3C\x4D", 8); // unknown bytes, parameters on how to build the rf channels?
memcpy(&packet[8], rx_tx_addr, 4);
}
else
{
memcpy(packet, rx_tx_addr, 4);
//Hopp
packet[6] = hopping_frequency_no + KYOSHO2_START_RF_CHANNEL;
packet[7] = hopping_frequency[hopping_frequency_no];
NRF24L01_WriteReg(NRF24L01_05_RF_CH, packet[6+(rf_ch_num&0x01)]);
rf_ch_num++;
//Channels
uint16_t temp;
for (uint8_t i = 0; i< KYOSHO2_NUM_CHANNEL; i++)
{
temp=convert_channel_16b_limit(i,0,0x3FF);
packet[8+i*2] = temp >> 8;
packet[9+i*2] = temp;
}
}
//Send
NRF24L01_WriteReg(NRF24L01_07_STATUS, (_BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT))); // Reset flags
NRF24L01_FlushTx();
NRF24L01_WritePayload(packet,KYOSHO2_PAYLOAD_SIZE);
NRF24L01_SetPower();
KYOSHO2_resend = true;
#if 0
for(uint8_t i=0;i<KYOSHO2_PAYLOAD_SIZE;i++)
debug("%02X ", packet[i]);
debugln("");
#endif
}
static void __attribute__((unused)) KYOSHO2_RF_init()
{
NRF24L01_Initialize();
NRF24L01_WriteReg(NRF24L01_05_RF_CH, KYOSHO2_BIND_CHANNEL);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\x69\x53\x10\xAC\xEF", 5);
}
static void __attribute__((unused)) KYOSHO2_initialize_tx_id()
{
hopping_frequency_no = rx_tx_addr[3]%KYOSHO2_RF_CHANNELS;
hopping_frequency[0] = 0x4A;
#ifdef FORCE_KYOSHO2_ID
memcpy(rx_tx_addr, (uint8_t*)"\x0A\xBD\x31\xDF", 4);
hopping_frequency[0] = 0x4A; // No idea where it comes from... ID or unknown bytes during the bind?
#endif
for(uint8_t i=1;i<KYOSHO2_RF_CHANNELS;i++)
{
if(hopping_frequency[i-1]+5 < 0x50)
hopping_frequency[i] = hopping_frequency[i-1]+5;
else
hopping_frequency[i] = hopping_frequency[i-1]-0x21;
}
#if 0
for(uint8_t i=0;i<KYOSHO2_RF_CHANNELS;i++)
debugln("1:%02X, 2: %02X", i + KYOSHO2_START_RF_CHANNEL, hopping_frequency[i]);
debugln("Selected 1:%02X, 2: %02X", hopping_frequency_no + KYOSHO2_START_RF_CHANNEL, hopping_frequency[hopping_frequency_no]);
#endif
}
uint16_t KYOSHO2_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(KYOSHO2_PACKET_PERIOD);
#endif
KYOSHO2_send_packet();
if(bind_counter)
{
if(--bind_counter==0)
{
BIND_DONE;
KYOSHO2_resend = false;
}
return KYOSHO2_BIND_PACKET_PERIOD;
}
return KYOSHO2_PACKET_PERIOD;
}
void KYOSHO2_init()
{
KYOSHO2_initialize_tx_id();
KYOSHO2_RF_init();
rf_ch_num = 0;
if(IS_BIND_IN_PROGRESS)
bind_counter = KYOSHO2_BIND_COUNT;
else
bind_counter = 0;
KYOSHO2_resend = false;
}
#endif

View File

@@ -0,0 +1,124 @@
/*
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(KYOSHO3_CYRF6936_INO)
#include "iface_cyrf6936.h"
//#define KYOSHO3_FORCE_ID
//#define KYOSHO3_DEBUG
#define KYOSHO3_BIND_PACKET_SIZE 4
#define KYOSHO3_PACKET_SIZE 9
const uint8_t PROGMEM KYOSHO3_init_vals[][2] = {
//Init from dump
{CYRF_0B_PWR_CTRL, 0x00}, // PMU
{CYRF_32_AUTO_CAL_TIME, 0x3C}, // Default init value
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
{CYRF_03_TX_CFG, 0x28 | CYRF_BIND_POWER}, // 8DR Mode, 64 chip codes
{CYRF_10_FRAMING_CFG, 0xA4}, // SOP and LEN enable
{CYRF_1F_TX_OVERRIDE, 0x05}, // Disable CRC, Data invert
{CYRF_1E_RX_OVERRIDE, 0x04}, // CRC check disabled
//{CYRF_11_DATA32_THOLD, 0x04}, // ???Using 64 chip...
{CYRF_12_DATA64_THOLD, 0x0E}, // Default
{CYRF_06_RX_CFG, 0x52}, // AGC disabled, LNA enabled, override enabled
};
static uint16_t __attribute__((unused)) KYOSHO3_send_packet()
{
CYRF_SetPower(0x28);
if(IS_BIND_IN_PROGRESS)
{
if(--bind_counter==0)
BIND_DONE;
packet[0] = 0xAA;
//ID
memcpy(&packet[1],&rx_tx_addr[1],3);
CYRF_WriteDataPacketLen(packet, KYOSHO3_BIND_PACKET_SIZE);
#ifdef KYOSHO3_DEBUG
debug("P:");
for(uint8_t i=0;i<KYOSHO3_BIND_PACKET_SIZE;i++)
debug(" %02X",packet[i]);
debugln("");
#endif
return 2434;
}
else
{
//ID
memcpy(packet,&rx_tx_addr[1],3);
//Channels
for(uint8_t i=0;i<4;i++)
{
packet[3] >>= 2;
packet[3] |= Channel_data[i]<<6;
packet[4+i] = Channel_data[i]>>3;
}
//Checksum
packet[8] = packet[3];
for(uint8_t i=4;i<8;i++)
packet[8] += packet[i];
//Timing
phase ^= 0x01;
CYRF_WriteDataPacketLen(packet, KYOSHO3_PACKET_SIZE);
#ifdef KYOSHO3_DEBUG
debug("P:");
for(uint8_t i=0;i<KYOSHO3_PACKET_SIZE;i++)
debug(" %02X",packet[i]);
debugln("");
#endif
if(phase)
return 9047;
}
return 6957;
}
uint16_t KYOSHO3_callback()
{
return KYOSHO3_send_packet();
}
void KYOSHO3_init()
{
//Config CYRF registers
for(uint8_t i = 0; i < sizeof(KYOSHO3_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&KYOSHO3_init_vals[i][0]), pgm_read_byte_near(&KYOSHO3_init_vals[i][1]));
CYRF_WritePreamble(0x333304);
//Find a free even channel
CYRF_FindBestChannels(hopping_frequency,1,1,0x04,0x50, FIND_CHANNEL_EVEN);
#ifdef KYOSHO3_FORCE_ID // data taken from TX dump
rx_tx_addr[1] = 0x01;
rx_tx_addr[2] = 0xAB;
rx_tx_addr[3] = 0x31;
hopping_frequency[0] = 0x04;
#endif
#ifdef KYOSHO3_DEBUG
debugln("ID: %02X %02X %02X",rx_tx_addr[1],rx_tx_addr[2],rx_tx_addr[3]);
debugln("RF CH: %02X",hopping_frequency[0]);
#endif
if(IS_BIND_IN_PROGRESS)
CYRF_ConfigRFChannel(0x04);
else
CYRF_ConfigRFChannel(hopping_frequency[0]);
bind_counter = 8217;
phase = 0;
}
#endif

View File

@@ -0,0 +1,226 @@
/*
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_FHSS
//#define KYOSHO_FORCE_ID_HYPE
//#define KYOSHO_FORCE_ID_SYNCRO
//Kyosho constants & variables
#define KYOSHO_BIND_COUNT 2500
#ifndef MULTI_AIR
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)];
//TX type
packet[27] = (bind_counter & 0x40) ? 0x05:0x07; // FHSS is 5 and Syncro is 7
//Unknown
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
//FHSS 14 channels: steering, throttle, ...
//Syncro 6 channels: steering, throttle, ...
for(uint8_t i = 0; i < 14; i++) //needed? i < (sub_protocol==KYOSHO_FHSS?14:6); 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)
}
// if(sub_protocol==KYOSHO_SYNCRO) // needed?
// {
// memcpy(&packet[21],&hopping_frequency[11],6);
// packet[27] = 0x07;
// packet[28] = 0x00;
// memset(packet+29,0xFF,8);
// packet[34] = 0x0F;
// packet[36] = 0x0F;
// }
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;
}
#if 0
debug("ch=%02X P=",rf_ch_num);
for(uint8_t i=0; i<37; i++)
debug("%02X ", packet[i]);
debugln("");
#endif
A7105_WriteData(37, rf_ch_num);
}
#endif //MULTI_AIR
static void __attribute__((unused)) KYOSHO_hype_send_packet()
{
if(IS_BIND_IN_PROGRESS)
{
if(packet_sent==0)
{//build the packet and send it
packet[0] = rx_tx_addr[1];
packet[1] = rx_tx_addr[3];
//RF table
for(uint8_t i=0; i<15;i++)
packet[i+2]=hopping_frequency[i];
A7105_WriteData(17, 0x01);
packet_sent++;
packet_period=1421;
#if 0
debug("ch=01 P=");
for(uint8_t i=0; i<17; i++)
debug("%02X ", packet[i]);
debugln("");
#endif
}
else
A7105_Strobe(A7105_TX); //only send
}
else
{
//original TX is only refreshing the packet every 20ms and keep repeating the same packet in between (STROBE_TX)
//build packet=6 channels with order AETR
for(uint8_t i=0;i<6;i++)
packet[i] = convert_channel_8b(CH_AETR[i]);
//set RF channel
rf_ch_num=hopping_frequency[hopping_frequency_no];
hopping_frequency_no++;
if(hopping_frequency_no>14)
hopping_frequency_no = 0;
//send it
A7105_WriteData(6, rf_ch_num);
packet_period=931; //packet period fluctuates a lot on the original TX from one packet to the other but stable if looking over a period of 40ms
#if 0
debug("ch=%02X P=",rf_ch_num);
for(uint8_t i=0; i<6; i++)
debug("%02X ", packet[i]);
debugln("");
#endif
}
}
uint16_t KYOSHO_callback()
{
#ifndef FORCE_KYOSHO_TUNING
A7105_AdjustLOBaseFreq(1);
#endif
if(IS_BIND_IN_PROGRESS)
{
bind_counter--;
if (bind_counter==0)
{
BIND_DONE;
if(sub_protocol==KYOSHO_HYPE)
{
A7105_WriteID(MProtocol_id);
A7105_WriteReg(A7105_03_FIFOI,0x05);
}
}
}
else
{
if(hopping_frequency_no==0)
A7105_SetPower();
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
}
if(sub_protocol==KYOSHO_HYPE)
KYOSHO_hype_send_packet();
else //FHSS && SYNCRO
#ifndef MULTI_AIR
KYOSHO_send_packet();
#else
SUB_PROTO_INVALID;
#endif
return packet_period;
}
void KYOSHO_init()
{
A7105_Init();
// compute channels from ID
calc_fh_channels(sub_protocol==KYOSHO_HYPE?15:32);
hopping_frequency_no=0;
#ifdef KYOSHO_FORCE_ID_FHSS
if(sub_protocol==KYOSHO_FHSS)
{
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
#ifdef KYOSHO_FORCE_ID_SYNCRO
if(sub_protocol==KYOSHO_FHSS)
{
memcpy(rx_tx_addr,"\x00\xC2\x24\x00",4);
memcpy(hopping_frequency,"\x73\x12\x7D\x88\x63\x4A\x8D\x60\x57\x16\x5D\x8B\x25\x53\x6E\x3C\x41\x70\x20\x83\x2A\x19\x94\x2F\x91\x4C\x47\x36\x78\x10\x5A\x31",32);
}
#endif
if(sub_protocol==KYOSHO_HYPE)
{
MProtocol_id &= 0x00FF00FF;
rx_tx_addr[0] = 0xAF - (rx_tx_addr[1]&0x0F);
rx_tx_addr[2] = 0xFF - rx_tx_addr[3];
MProtocol_id |= (rx_tx_addr[0]<<24) + (rx_tx_addr[2]<<8);
#ifdef KYOSHO_FORCE_ID_HYPE
MProtocol_id=0xAF90738C;
set_rx_tx_addr(MProtocol_id);
memcpy(hopping_frequency,"\x27\x1B\x63\x75\x03\x39\x57\x69\x87\x0F\x7B\x3F\x33\x51\x6F",15);
#endif
if(IS_BIND_IN_PROGRESS)
A7105_WriteID(0xAF00FF00);
else
{
A7105_WriteID(MProtocol_id);
A7105_WriteReg(A7105_03_FIFOI,0x05);
}
}
if(IS_BIND_IN_PROGRESS)
bind_counter = KYOSHO_BIND_COUNT;
packet_sent=0;
packet_period=3852; //FHSS
}
#endif

View File

@@ -0,0 +1,300 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(LOLI_NRF24L01_INO)
#include "iface_nrf24l01.h"
#define LOLI_BIND_CHANNEL 33
#define LOLI_PACKET_SIZE 11
#define LOLI_NUM_CHANNELS 5
static void __attribute__((unused)) LOLI_RF_init()
{
NRF24L01_Initialize();
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"LOVE!", 5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"LOVE!", 5);
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, LOLI_PACKET_SIZE); // RX FIFO size
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
}
// flags going to packet[1] for packet type 0xa2 (Rx config)
#define LOLI_FLAG_PWM7 0x02
#define LOLI_FLAG_PWM2 0x04
#define LOLI_FLAG_PWM1 0x08
#define LOLI_FLAG_SBUS 0x40
#define LOLI_FLAG_PPM 0x80
// flags going to packet[2] for packet type 0xa2 (Rx config)
#define LOLI_FLAG_SW8 0x01
#define LOLI_FLAG_SW7 0x02
#define LOLI_FLAG_SW6 0x04
#define LOLI_FLAG_SW5 0x08
#define LOLI_FLAG_SW4 0x10
#define LOLI_FLAG_SW3 0x20
#define LOLI_FLAG_SW2 0x40
#define LOLI_FLAG_SW1 0x80
#ifdef LOLI_NRF24L01_INO
uint8_t LOLI_P1, LOLI_P2;
#endif
static void __attribute__((unused)) LOLI_send_packet()
{
if(IS_BIND_IN_PROGRESS)
{
packet[0] = 0xa0;
memcpy(&packet[1], hopping_frequency, LOLI_NUM_CHANNELS);
memcpy(&packet[6], rx_tx_addr, 5);
rf_ch_num = LOLI_BIND_CHANNEL;
}
else
{
//Check RX config
uint8_t P1=0;
uint8_t P2=0;
//ch1: PWM/PPM
if(Channel_data[CH1+8] > CHANNEL_MAX_COMMAND)
P1|=LOLI_FLAG_PWM1;
else if(Channel_data[CH1+8] > CHANNEL_SWITCH)
P1|=LOLI_FLAG_PPM;
//ch2: PWM
if(Channel_data[CH2+8] > CHANNEL_MAX_COMMAND)
P1|=LOLI_FLAG_PWM2;
//ch5: SBUS
if(Channel_data[CH5+8] > CHANNEL_SWITCH)
P1|=LOLI_FLAG_SBUS;
//ch7: PWM
if(Channel_data[CH7+8] > CHANNEL_MAX_COMMAND)
P1|=LOLI_FLAG_PWM7;
//switches
for(uint8_t i=0;i<8;i++)
if(Channel_data[i+8]<CHANNEL_MIN_COMMAND)
P2 |= 1 << (7-i);
if(LOLI_P1!=P1 || LOLI_P2!=P2)
flags=10;
if(flags)
{// Send RX config since P1 or P2 have changed
LOLI_P1=P1;LOLI_P2=P2;
packet[0] = 0xa2;
packet[1] = LOLI_P1; // CH1:LOLI_FLAG_PPM || LOLI_FLAG_PWM1, CH2:LOLI_FLAG_PWM2, CH5:LOLI_FLAG_SBUS, CH7:LOLI_FLAG_PWM7
packet[2] = LOLI_P2; // CHx switch bit(8-x)=1
flags--;
}
else
{// Normal packet
#ifdef FAILSAFE_ENABLE
packet[0] = IS_FAILSAFE_VALUES_on ? 0xa0 : 0xa1;
#else
packet[0] = 0xa1;
#endif
//Build channels
uint8_t ch=0, offset=1;
uint16_t val;
for(uint8_t i=0;i<2;i++)
{
val = convert_channel_10b(ch++, IS_FAILSAFE_VALUES_on);
packet[offset++] = val >> 2;
packet[offset ] = val << 6;
val = convert_channel_10b(ch++, IS_FAILSAFE_VALUES_on);
packet[offset++]|= val >> 4;
packet[offset ] = val << 4;
val = convert_channel_10b(ch++, IS_FAILSAFE_VALUES_on);
packet[offset++]|= val >> 6;
packet[offset ] = val << 2;
val = convert_channel_10b(ch++, IS_FAILSAFE_VALUES_on);
packet[offset++]|= val >> 8;
packet[offset++] = val & 0xff;
}
FAILSAFE_VALUES_off; // Failsafe values are sent if they were available
}
if (++hopping_frequency_no > LOLI_NUM_CHANNELS-1)
hopping_frequency_no = 0;
rf_ch_num = hopping_frequency[hopping_frequency_no];
}
#if 0
debug("P(%02X):",rf_ch_num);
for(uint8_t i=0; i<LOLI_PACKET_SIZE; i++)
debug(" %02X",packet[i]);
debugln("");
#endif
//Send packet
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num);
NRF24L01_SetPower();
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0a); // 8bit CRC, TX
NRF24L01_FlushTx();
NRF24L01_WritePayload(packet, LOLI_PACKET_SIZE);
}
enum{
LOLI_BIND1,
LOLI_BIND2,
LOLI_BIND3,
LOLI_PREP_DATA,
LOLI_DATA1,
LOLI_DATA2,
LOLI_SET_RX_CONFIG,
LOLI_SET_FAILSAFE
};
#define LOLI_WRITE_TIME 1000
uint16_t LOLI_callback()
{
switch (phase)
{
case LOLI_BIND1:
if(bind_counter)
if(--bind_counter==0)
{
phase=LOLI_PREP_DATA;
break;
}
// send bind packet
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0a); // 8bit CRC, TX
LOLI_send_packet();
phase++;
return 2000;
case LOLI_BIND2:
// switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushRx();
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x3b); // 8bit CRC, RX
phase++;
packet_count = 0;
return 2000;
case LOLI_BIND3:
// got bind response ?
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{
NRF24L01_ReadPayload(packet, LOLI_PACKET_SIZE);
if (packet[0] == 'O' && packet[1] == 'K')
{
debugln("Bind OK");
phase++; // LOLI_PREP_DATA
break;
}
}
packet_count++;
if (packet_count > 50)
phase = LOLI_BIND1;
return 1000;
case LOLI_PREP_DATA:
BIND_DONE;
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushRx();
packet_count = 0;
//defaut RX config with servo outputs
LOLI_P1=0;LOLI_P2=0;flags=10;
phase++;
case LOLI_DATA1:
#ifdef LOLI_HUB_TELEMETRY
// Check telemetry
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
NRF24L01_ReadPayload(packet, LOLI_PACKET_SIZE);
#if 0
debug("T:");
for(uint8_t i=0; i<LOLI_PACKET_SIZE; i++)
debug(" %02X",packet[i]);
debugln("");
#endif
RX_RSSI = packet[0]<<1;
uint16_t val=((packet[1] << 8) | packet[2])/10;
if(val > 255) val=255;
v_lipo1 = val;
val=((packet[3] << 8) | packet[4])/10;
if(val > 255) val=255;
v_lipo2 = val;
telemetry_link = 1;
telemetry_counter++; // TX LQI counter
if(telemetry_lost)
{
telemetry_lost = 0;
packet_count = 100;
telemetry_counter = 100;
}
}
//LQI
packet_count++;
if(packet_count>=100)
{
packet_count=0;
TX_LQI=telemetry_counter;
if(telemetry_counter==0)
telemetry_lost = 1;
telemetry_counter = 0;
}
#endif
// Send data packet
LOLI_send_packet();
#ifdef LOLI_HUB_TELEMETRY
phase ++;
return LOLI_WRITE_TIME;
case LOLI_DATA2:
// Wait for packet to be sent
while( (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS)) == 0);
// Switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushRx();
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x3b); // 8bit CRC, RX
phase = LOLI_DATA1;
return 20000 - LOLI_WRITE_TIME;
#else
break;
#endif
}
return 20000;
}
void LOLI_init()
{
rx_tx_addr[1] %= 0x30;
calc_fh_channels(LOLI_NUM_CHANNELS);
for (uint8_t i=0; i < LOLI_NUM_CHANNELS; i++)
if (hopping_frequency[i] == LOLI_BIND_CHANNEL)
hopping_frequency[i]++;
if (IS_BIND_IN_PROGRESS)
{
bind_counter=250;
phase = LOLI_BIND1;
}
else
phase = LOLI_PREP_DATA;
LOLI_RF_init();
}
#endif

View File

@@ -0,0 +1,216 @@
/*
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(LOSI_CYRF6936_INO)
#include "iface_cyrf6936.h"
//#define LOSI_FORCE_ID
/* Using DSM.ino data codes since they are the same
const uint8_t LOSI_data_code[][8] = {
//(Freq-1)%5=0
{ 0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3 },
{ 0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9 },
{ 0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82 },
{ 0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB },
{ 0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7 },
{ 0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95 },
{ 0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4 },
{ 0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF },
//(Freq-1)%5=1
{ 0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97 },
{ 0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA },
{ 0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE },
{ 0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD },
{ 0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD },
{ 0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9 },
{ 0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3 },
{ 0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0 },
//(Freq-1)%5=2
{ 0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E },
{ 0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7 },
{ 0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1 },
{ 0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4 },
{ 0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6 },
{ 0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80 },
{ 0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88 },
{ 0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88 },
//(Freq-1)%5=3
{ 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93 },
{ 0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C },
{ 0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA },
{ 0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC },
{ 0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84 },
{ 0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7 },
{ 0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0 },
{ 0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1 },
//(Freq-1)%5=4
{ 0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8 },
{ 0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6 },
{ 0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9 },
{ 0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4 },
{ 0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0 },
{ 0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8 },
{ 0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D },
{ 0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1 },
//Bind
{ 0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86 }
};*/
static uint16_t __attribute__((unused)) LOSI_check(uint16_t val)
{
const uint8_t PROGMEM tab[] = { 0xF1, 0xDA, 0xB6, 0xC8 };
uint8_t res = crc8, tmp;
uint16_t calc = val>>2; // don't care about the 2 first bits
for(uint8_t i=0; i<5; i++)
{
tmp=pgm_read_byte_near(&tab[i&0x03]);
if(calc&0x0001)
res ^= tmp>>4;
calc >>= 1;
if(calc&0x0001)
res ^= tmp;
calc >>= 1;
}
return val ^ (res<<12);
}
static void __attribute__((unused)) LOSI_send_packet()
{
memcpy(packet, rx_tx_addr, 4);
if(IS_BIND_IN_PROGRESS)
{
memcpy(&packet[4], rx_tx_addr, 4);
crc = 0x0170;
for(uint8_t i=0; i < 8; i++)
crc += packet[i];
packet[8] = crc >> 8;
packet[9] = crc;
}
else
{
for(uint8_t i=0; i<3; i++)
{
uint16_t val = LOSI_check(Channel_data[i]<<1);
packet[4+i*2] = val >> 8;
packet[5+i*2] = val;
}
}
CYRF_SetPower(0x38);
CYRF_WriteDataPacketLen(packet, 0x0A);
#if 0
for(uint8_t i=0; i < 0x0A; i++)
debug("%02X ", packet[i]);
debugln();
#endif
}
static void __attribute__((unused)) LOSI_cyrf_init()
{
/* Initialise CYRF chip */
CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C);
CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x48);
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
//CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24);
CYRF_SetPower(0x38); // 64 SDR mode -> 8 bytes data code
CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0A);
CYRF_WriteRegister(CYRF_39_ANALOG_CTRL, 0x01);
CYRF_WritePreamble(0x333304);
//CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x00);
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0x4A);
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x04); // No CRC
//CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x14);
//CYRF_WriteRegister(CYRF_14_EOP_CTRL, 0x02);
uint8_t code[16];
DSM_read_code(code,0,8); // Load bind data code by default
CYRF_ConfigDataCode(code);
}
uint16_t LOSI_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
if(bind_counter)
{
bind_counter--;
if(bind_counter==0)
{
BIND_DONE;
// Load normal data code
uint8_t code[16];
DSM_read_code(code,hopping_frequency[0] % 5,(rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2]) % 8);
CYRF_ConfigDataCode(code);
packet_period = 19738;
}
}
LOSI_send_packet();
return packet_period;
}
void LOSI_init()
{
LOSI_cyrf_init();
CYRF_FindBestChannels(hopping_frequency, 1, 0, 0x07, 0x4F, FIND_CHANNEL_ODD); // 0x07 and 0x4F are unknown limits, this routine resets the CRC Seed to 0
crc8 = 0;
crc8 = (uint16_t)LOSI_check(((rx_tx_addr[2]&0x0F) << 8) + rx_tx_addr[3]) >> 12;
#ifdef LOSI_FORCE_ID
/*
rx_tx_addr[0] = 0x47;
rx_tx_addr[1] = 0x52;
rx_tx_addr[2] = 0xAE;
rx_tx_addr[3] = 0xAA;
crc8 = 0x0B;
num_ch = 0x07;
//Data codes for hopping_frequency[0] % 5
//{ 0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1, 0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86 },
//{ 0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF, 0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97 },
//{ 0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0, 0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E },
//{ 0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93 },
//{ 0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1, 0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8 }
*/
rx_tx_addr[0] = 0x56;
rx_tx_addr[1] = 0x52;
rx_tx_addr[2] = 0x22;
rx_tx_addr[3] = 0x8A;
crc8 = 0x0F;
num_ch = 0x02;
//Data codes for hopping_frequency[0] % 5
//{ 0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9, 0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4 },
//{ 0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82, 0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB },
//{ 0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE, 0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD },
//{ 0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1, 0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4 },
//{ 0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA, 0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC }
// Note: crc8=00..0F and num_ch=00..07
// num_ch = (rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2]) % 8;
// crc8 = (uint16_t)LOSI_check(((rx_tx_addr[2]&0x0F) << 8) + rx_tx_addr[3]) >> 12;
#endif
CYRF_ConfigRFChannel(hopping_frequency[0]);
bind_counter = IS_BIND_IN_PROGRESS?300:1;
packet_period = 8763;
}
#endif

View File

@@ -15,10 +15,9 @@
// compatible with MJX WLH08, X600, X800, H26D, Eachine E010
// Last sync with hexfet new_protocols/mjxq_nrf24l01.c dated 2016-01-17
#if defined(MJXQ_NRF24L01_INO)
#if defined(MJXQ_CCNRF_INO)
#include "iface_nrf24l01.h"
#include "iface_nrf250k.h"
#include "iface_xn297.h"
#define MJXQ_BIND_COUNT 150
#define MJXQ_PACKET_PERIOD 4000 // Timeout for callback in uSec
@@ -103,6 +102,12 @@ static uint8_t __attribute__((unused)) MJXQ_pan_tilt_value()
#define MJXQ_CHAN2TRIM(X) (((X) & 0x80 ? (X) : 0x7f - (X)) >> 1)
static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
{
//RF freq
hopping_frequency_no++;
XN297_Hopping(hopping_frequency_no / 2);
hopping_frequency_no %= 2 * MJXQ_RF_NUM_CHANNELS; // channels repeated
//Build packet
packet[0] = convert_channel_8b(THROTTLE);
packet[1] = convert_channel_s8b(RUDDER);
packet[4] = 0x40; // rudder does not work well with dyntrim
@@ -192,38 +197,29 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
uint8_t sum = packet[0];
for (uint8_t i=1; i < MJXQ_PACKET_SIZE-1; i++) sum += packet[i];
packet[15] = sum;
hopping_frequency_no++;
if (sub_protocol == E010 || sub_protocol == PHOENIX)
// Send
XN297_SetTxRxMode(TX_EN);
XN297_SetPower();
#ifdef NRF24L01_INSTALLED
if (sub_protocol == H26D || sub_protocol == H26WH)
{
XN297L_Hopping(hopping_frequency_no / 2);
XN297L_SetFreqOffset();
XN297L_SetPower();
XN297L_WritePayload(packet, MJXQ_PACKET_SIZE);
//NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no / 2]);
//NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
//NRF24L01_FlushTx();
//NRF24L01_SetTxRxMode(TX_EN);
//NRF24L01_SetPower();
NRF24L01_WritePayload(packet, MJXQ_PACKET_SIZE);
}
else
{
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no / 2]);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
// Power on, TX mode, 2byte CRC and send packet
if (sub_protocol == H26D || sub_protocol == H26WH)
{
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_WritePayload(packet, MJXQ_PACKET_SIZE);
}
else
{
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
XN297_WritePayload(packet, MJXQ_PACKET_SIZE);
}
NRF24L01_SetPower();
#endif
{//E010, PHOENIX, WLH08, X600, X800
XN297_SetFreqOffset();
XN297_WritePayload(packet, MJXQ_PACKET_SIZE);
}
hopping_frequency_no %= 2 * MJXQ_RF_NUM_CHANNELS; // channels repeated
}
static void __attribute__((unused)) MJXQ_init()
static void __attribute__((unused)) MJXQ_RF_init()
{
uint8_t addr[MJXQ_ADDRESS_LENGTH];
memcpy(addr, "\x6d\x6a\x77\x77\x77", MJXQ_ADDRESS_LENGTH);
@@ -239,32 +235,20 @@ static void __attribute__((unused)) MJXQ_init()
}
if (sub_protocol == E010 || sub_protocol == PHOENIX)
{
XN297L_Init();
XN297L_SetTXAddr(addr, sizeof(addr));
XN297L_HoppingCalib(MJXQ_RF_NUM_CHANNELS);
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_250K);
XN297_SetTXAddr(addr, MJXQ_ADDRESS_LENGTH);
XN297_HoppingCalib(MJXQ_RF_NUM_CHANNELS);
}
else
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M); // this will select the nrf and initialize it, therefore both H26 sub protocols can use common instructions
#ifdef NRF24L01_INSTALLED
if (sub_protocol == H26D || sub_protocol == H26WH)
{
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, addr, MJXQ_ADDRESS_LENGTH);
}
else
#endif
XN297_SetTXAddr(addr, MJXQ_ADDRESS_LENGTH);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, MJXQ_PACKET_SIZE);
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
//NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, MJXQ_PACKET_SIZE); // no RX???
}
}
@@ -285,7 +269,7 @@ static void __attribute__((unused)) MJXQ_init2()
hopping_frequency[i]=pgm_read_byte_near( &E010_map_rfchan[rx_tx_addr[3]&0x0F][i] );
hopping_frequency[i+2]=hopping_frequency[i]+0x10;
}
XN297L_HoppingCalib(MJXQ_RF_NUM_CHANNELS);
XN297_HoppingCalib(MJXQ_RF_NUM_CHANNELS);
break;
case WLH08:
// do nothing
@@ -350,14 +334,13 @@ uint16_t MJXQ_callback()
return MJXQ_PACKET_PERIOD;
}
uint16_t initMJXQ(void)
void MJXQ_init(void)
{
BIND_IN_PROGRESS; // autobind protocol
bind_counter = MJXQ_BIND_COUNT;
MJXQ_initialize_txid();
MJXQ_init();
MJXQ_RF_init();
packet_count=0;
return MJXQ_INITIAL_WAIT+MJXQ_PACKET_PERIOD;
}
#endif

View File

@@ -0,0 +1,608 @@
/*
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(MLINK_CYRF6936_INO)
#include "iface_cyrf6936.h"
//#define MLINK_FORCE_ID
#define MLINK_BIND_COUNT 696 // around 20s
#define MLINK_NUM_FREQ 78
#define MLINK_BIND_CHANNEL 0x01
#define MLINK_PACKET_SIZE 8
enum {
MLINK_BIND_TX=0,
MLINK_BIND_PREP_RX,
MLINK_BIND_RX,
MLINK_PREP_DATA,
MLINK_SEND1,
MLINK_SEND2,
MLINK_SEND3,
MLINK_CHECK3,
MLINK_RX,
MLINK_BUILD4,
};
uint8_t MLINK_Data_Code[16], MLINK_CRC_Init, MLINK_Unk_6_2;
const uint8_t PROGMEM MLINK_init_vals[][2] = {
//Init from dump
{ CYRF_01_TX_LENGTH, 0x08 }, // Length of packet
{ CYRF_02_TX_CTRL, 0x40 }, // Clear TX Buffer
{ CYRF_03_TX_CFG, 0x3C }, //0x3E in normal mode, 0x3C in bind mode: SDR 64 chip codes (=8 bytes data code used)
{ CYRF_05_RX_CTRL, 0x00 },
{ CYRF_06_RX_CFG, 0x93 }, // AGC enabled, overwrite enable, valid flag enable
{ CYRF_0B_PWR_CTRL, 0x00 },
//{ CYRF_0C_XTAL_CTRL, 0x00 }, // Set to GPIO on reset
//{ CYRF_0D_IO_CFG, 0x00 }, // Set to GPIO on reset
//{ CYRF_0E_GPIO_CTRL, 0x00 }, // Set by the CYRF_SetTxRxMode function
{ CYRF_0F_XACT_CFG, 0x04 }, // end state idle
{ CYRF_10_FRAMING_CFG, 0x00 }, // SOP disabled
{ CYRF_11_DATA32_THOLD, 0x05 }, // not used???
{ CYRF_12_DATA64_THOLD, 0x0F }, // 64 Chip Data PN Code Correlator Threshold
{ CYRF_14_EOP_CTRL, 0x05 }, // 5 consecutive noncorrelations symbol for EOP
{ CYRF_15_CRC_SEED_LSB, 0x00 }, // not used???
{ CYRF_16_CRC_SEED_MSB, 0x00 }, // not used???
{ CYRF_1B_TX_OFFSET_LSB,0x00 },
{ CYRF_1C_TX_OFFSET_MSB,0x00 },
{ CYRF_1D_MODE_OVERRIDE,0x00 },
{ CYRF_1E_RX_OVERRIDE, 0x14 }, // RX CRC16 is disabled and Force Receive Data Rate
{ CYRF_1F_TX_OVERRIDE, 0x04 }, // TX CRC16 is disabled
{ CYRF_26_XTAL_CFG, 0x08 },
{ CYRF_29_RX_ABORT, 0x00 },
{ CYRF_32_AUTO_CAL_TIME,0x3C },
{ CYRF_35_AUTOCAL_OFFSET,0x14 },
{ CYRF_39_ANALOG_CTRL, 0x03 }, // Receive invert and all slow
};
static void __attribute__((unused)) MLINK_cyrf_config()
{
for(uint8_t i = 0; i < sizeof(MLINK_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&MLINK_init_vals[i][0]), pgm_read_byte_near(&MLINK_init_vals[i][1]));
CYRF_WritePreamble(0x333304);
CYRF_SetTxRxMode(TX_EN);
}
static void __attribute__((unused)) MLINK_send_bind_packet()
{
uint8_t p_c=packet_count>>1;
memset(packet, p_c<0x16?0x00:0xFF, MLINK_PACKET_SIZE-1);
packet[0]=0x0F; // bind
packet[1]=p_c;
switch(p_c)
{
case 0x00:
packet[2]=0x40; //unknown but seems constant
packet[4]=0x01; //unknown but seems constant
packet[5]=0x03; //unknown but seems constant
packet[6]=0xE3; //unknown but seems constant
break;
case 0x05:
packet[6]=MLINK_CRC_Init; //CRC init value
break;
case 0x06:
packet[2]=MLINK_Unk_6_2; //unknown and different
//Start of hopping frequencies
for(uint8_t i=0;i<4;i++)
packet[i+3]=hopping_frequency[i];
break;
case 0x15:
packet[6]=0x51; //unknown but seems constant
break;
case 0x16:
packet[2]=0x51; //unknown but seems constant
packet[3]=0xEC; //unknown but seems constant
packet[4]=0x05; //unknown but seems constant
break;
case 0x1A:
packet[1]=0xFF;
memset(&packet[2],0x00,5);
break;
}
if(p_c>=0x01 && p_c<=0x04)
{//DATA_CODE
uint8_t p_c_5=(p_c-1)*5;
for(uint8_t i=0;i<5;i++)
if(i+p_c_5<16)
packet[i+2]=MLINK_Data_Code[i+p_c_5];
}
else
if(p_c>=0x07 && p_c<=0x15)
{//Hopping frequencies
uint8_t p_c_5=5*(p_c-6)-1;
for(uint8_t i=0;i<5;i++)
if(i+p_c_5<MLINK_NUM_FREQ)
packet[i+2]=hopping_frequency[i+p_c_5];
}
else
if(p_c>0x19)
{
packet[1]=0xFF;
memset(&packet[2], 0x00, MLINK_PACKET_SIZE-3);
}
//Calculate CRC
crc8=0xFF; // Init = 0xFF
for(uint8_t i=0;i<MLINK_PACKET_SIZE-1;i++)
crc8_update(bit_reverse(packet[i]));
packet[7] = bit_reverse(crc8); // CRC reflected out
//Debug
#if 0
debug("P(%02d):",p_c);
for(uint8_t i=0;i<8;i++)
debug(" %02X",packet[i]);
debugln("");
#endif
//Send packet
CYRF_WriteDataPacketLen(packet, MLINK_PACKET_SIZE);
}
static void __attribute__((unused)) MLINK_send_data_packet()
{
static uint8_t tog=0;
uint8_t start;
#ifdef FAILSAFE_ENABLE
static uint8_t fs=0;
if(IS_FAILSAFE_VALUES_on && phase==MLINK_SEND1)
{
fs=10; // Original radio is sending 70 packets
FAILSAFE_VALUES_off;
}
if(fs)
{// Failsafe packets
switch(phase)
{
case MLINK_SEND2:
packet[0]=0x06;
start=17;
break;
case MLINK_SEND3:
packet[0]=0x84;
start=5;
fs--;
break;
default: //MLINK_SEND1:
packet[0]=0x05;
start=11;
break;
}
//Pack 6 channels per packet
for(uint8_t i=0;i<6;i++)
{
uint8_t val=start<16 ? convert_channel_16b_nolimit(start,426 >> 4,3448 >> 4,true) : 0x00;
start--; // switch to next channel
packet[i+1]=val;
}
}
else
#endif
{// Normal packets
if(hopping_frequency_no==0)
tog=1;
//Channels to be sent
if(phase==MLINK_SEND1 || ((hopping_frequency_no%5==0) && (phase==MLINK_SEND2)))
{
if((hopping_frequency_no&1)==0)
packet[0] = 0x09; //10,8,6
else
packet[0] = 0x01; //11,9,7
}
else
if(phase==MLINK_SEND2)
{
if(tog)
packet[0] = 0x02; //x,15,13
else
packet[0] = 0x0A; //x,14,12
tog^=1;
}
else
{//phase==MLINK_SEND3
if((hopping_frequency_no&1)==0)
packet[0] = 0x88; //4,2,0
else
packet[0] = 0x80; //5,3,1
}
//Start channel
start=4+6*(packet[0]&3);
if((packet[0]&0x08)==0)
start++;
//Channels 426..1937..3448
for(uint8_t i=0;i<3;i++)
{
uint16_t val=start<16 ? convert_channel_16b_nolimit(start,426,3448,false) : 0x0000;
start-=2; // switch to next channel
packet[i*2+1]=val>>8;
packet[i*2+2]=val;
}
}
//Calculate CRC
crc8=bit_reverse(hopping_frequency_no + MLINK_CRC_Init); // Init = relected freq index + offset
for(uint8_t i=0;i<MLINK_PACKET_SIZE-1;i++)
crc8_update(bit_reverse(packet[i]));
packet[7] = bit_reverse(crc8); // CRC reflected out
//Send
CYRF_WriteDataPacketLen(packet, MLINK_PACKET_SIZE);
//Debug
#if 0
debug("P(%02d):",hopping_frequency_no);
for(uint8_t i=0;i<8;i++)
debug(" %02X",packet[i]);
debugln("");
#endif
}
#ifdef MLINK_HUB_TELEMETRY
static void __attribute__((unused)) MLINK_Send_Telemetry()
{ // not sure how MLINK telemetry works, the 2 RXs I have are sending something completly different...
telemetry_counter += 2; // TX LQI counter
telemetry_link = 1;
if(packet_in[0]==0x13)
{ // RX-9-DR : 13 1A C8 00 01 64 00
uint8_t id;
for(uint8_t i=1; i<5; i+=3)
{//2 sensors per packet
id=0x00;
switch(packet_in[i]&0x0F)
{
case 1: //voltage
if((packet_in[i]&0xF0) == 0x00)
v_lipo1 = packet_in[i+1]; // Rx_Batt*20
else
v_lipo2 = packet_in[i+1];
break;
case 2: //current
id = 0x28;
break;
case 3: //vario
id = 0x30;
break;
case 5: //rpm
id = 0x03;
break;
case 6: //temp
id = 0x02;
break;
case 10: //lqi
RX_RSSI=RX_LQI=packet_in[i+1]>>1;
break;
}
#if defined HUB_TELEMETRY
if(id)
{
uint16_t val=((packet_in[i+2]&0x80)<<8)|((packet_in[i+2]&0x7F)<<7)|(packet_in[i+1]>>1); //remove the alarm LSB bit, move the sign bit to MSB
frsky_send_user_frame(id, val, val>>8);
}
#endif
}
}
else
if(packet_in[0]==0x03)
{ // RX-5 : 03 15 23 00 00 01 02
//Incoming packet values
RX_RSSI = packet_in[2]<<1; // Looks to be the RX RSSI value
RX_LQI = packet_in[5]; // Looks to be connection lost
}
else
RX_RSSI = TX_LQI;
// Read TX RSSI
TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;
if(telemetry_lost)
{
telemetry_lost = 0;
packet_count = 50;
telemetry_counter = 100;
}
}
#endif
#ifdef MLINK_FW_TELEMETRY
static void __attribute__((unused)) MLINK_Send_Telemetry()
{
telemetry_counter += 2; // TX LQI counter
telemetry_link = 4;
// Read TX RSSI
TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;
if(telemetry_lost)
{
telemetry_lost = 0;
packet_count = 50;
telemetry_counter = 100;
}
}
#endif
uint16_t MLINK_callback()
{
uint8_t status;
uint16_t start;
switch(phase)
{
case MLINK_BIND_RX:
//debugln("RX");
status=CYRF_ReadRegister(CYRF_05_RX_CTRL);
if( (status&0x80) == 0 )
{//Packet received
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
debugln("L=%02X",len)
if( len==8 )
{
CYRF_ReadDataPacketLen(packet, len*2);
debug("RX=");
for(uint8_t i=0;i<8;i++)
debug(" %02X",packet[i*2]);
debugln("");
//Check CRC
crc8=0xFF; // Init = 0xFF
for(uint8_t i=0;i<MLINK_PACKET_SIZE-1;i++)
crc8_update(bit_reverse(packet[i<<1]));
if(packet[14] == bit_reverse(crc8))
{// CRC is ok
debugln("CRC ok");
if(packet[0]==0x7F)
packet_count=3; // Start sending bind payload
else if(packet_count > 0x19*2)
{
if(packet[0] == 0x8F)
packet_count++;
else if(packet[0] == 0x9F)
packet_count=0x80; // End bind
else
packet_count=0; // Restart bind...
}
}
}
}
else
packet_count=0;
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // Force end state
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort
phase=MLINK_BIND_TX; // Retry sending bind packet
CYRF_SetTxRxMode(TX_EN); // Transmit mode
if(packet_count)
return 18136;
case MLINK_BIND_TX:
if(--bind_counter==0 || packet_count>=0x1B*2)
{ // Switch to normal mode
BIND_DONE;
phase=MLINK_PREP_DATA;
return 22720;
}
MLINK_send_bind_packet();
if(packet_count == 0 || packet_count > 0x19*2)
{
phase++; // MLINK_BIND_PREP_RX
return 4700; // Original is 4900
}
packet_count++;
if(packet_count&1)
return 6000;
return 22720;
case MLINK_BIND_PREP_RX:
start=micros();
while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 200) // Wait max 200µs for TX to finish
if((CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80) == 0x00)
break; // Packet transmission complete
CYRF_SetTxRxMode(RX_EN); // Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x82); // Prepare to receive
phase++; //MLINK_BIND_RX
if(packet_count > 0x19*2)
return 28712; // Give more time to the RX to confirm that the bind is ok...
return 28712-4700;
case MLINK_PREP_DATA:
CYRF_ConfigDataCode(MLINK_Data_Code);
MLINK_CRC_Init += 0xED;
hopping_frequency_no = 0x00;
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
CYRF_SetPower(0x38);
#if defined(MLINK_HUB_TELEMETRY) || defined(MLINK_FW_TELEMETRY)
packet_count = 0;
telemetry_lost = 1;
#endif
phase++;
case MLINK_SEND1:
MLINK_send_data_packet();
phase++;
return 4880+1111;
case MLINK_SEND2:
MLINK_send_data_packet();
phase++;
if(hopping_frequency_no%5==0)
return 4617+1017;
return 4617+1422;
case MLINK_SEND3:
MLINK_send_data_packet();
phase++;
return 4611;
case MLINK_CHECK3:
//Switch to next channel
hopping_frequency_no++;
if(hopping_frequency_no>=MLINK_NUM_FREQ)
hopping_frequency_no=0;
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
//Receive telemetry
if(hopping_frequency_no%5==0)
{//Receive telemetry
CYRF_SetTxRxMode(RX_EN); // Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x82); // Prepare to receive
phase++; //MLINK_RX
return 8038+2434+410-1000;
}
else
CYRF_SetPower(0x38);
phase=MLINK_SEND1;
return 4470;
case MLINK_RX:
#if defined(MLINK_HUB_TELEMETRY) || defined(MLINK_FW_TELEMETRY)
//TX LQI calculation
packet_count++;
if(packet_count>=50)
{
packet_count=0;
TX_LQI=telemetry_counter;
if(telemetry_counter==0)
telemetry_lost = 1;
telemetry_counter = 0;
}
#endif
status=CYRF_ReadRegister(CYRF_05_RX_CTRL);
debug("T(%02X):",status);
if( (status&0x80) == 0 )
{//Packet received
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
debug("(%X)",len)
if( len && len <= MLINK_PACKET_SIZE )
{
CYRF_ReadDataPacketLen(packet_in, len*2);
#if defined(MLINK_HUB_TELEMETRY) || defined(MLINK_FW_TELEMETRY)
if(len==MLINK_PACKET_SIZE)
{
for(uint8_t i=0;i<8;i++)
//Check CRC
crc8=bit_reverse(MLINK_CRC_Init);
for(uint8_t i=0;i<MLINK_PACKET_SIZE-1;i++)
{
packet_in[i]=packet_in[i<<1];
crc8_update(bit_reverse(packet_in[i]));
debug(" %02X",packet_in[i]);
}
if(packet_in[14] == bit_reverse(crc8)) // Packet CRC is ok
MLINK_Send_Telemetry();
else
debug(" NOK");
}
#endif
}
}
debugln("");
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // Force end state
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort
CYRF_SetTxRxMode(TX_EN); // Transmit mode
phase=MLINK_SEND2;
return 1000;
}
return 1000;
}
static void __attribute__((unused)) MLINK_shuffle_freqs(uint32_t seed, uint8_t *hop)
{
randomSeed(seed);
for(uint8_t i=0; i < MLINK_NUM_FREQ/2; i++)
{
uint8_t r = random(0xfefefefe) % (MLINK_NUM_FREQ/2);
uint8_t tmp = hop[r];
hop[r] = hop[i];
hop[i] = tmp;
}
}
void MLINK_init()
{
MLINK_cyrf_config();
//Init ID and RF freqs
for(uint8_t i=0; i < MLINK_NUM_FREQ/2; i++)
{
hopping_frequency[i ] = (i<<1) + 3;
hopping_frequency[i+MLINK_NUM_FREQ/2] = (i<<1) + 3;
}
// part1
memcpy(MLINK_Data_Code ,rx_tx_addr,4);
MLINK_shuffle_freqs(MProtocol_id, hopping_frequency);
// part2
MProtocol_id ^= 0x6FBE3201;
set_rx_tx_addr(MProtocol_id);
memcpy(MLINK_Data_Code+4,rx_tx_addr,4);
MLINK_shuffle_freqs(MProtocol_id, &hopping_frequency[MLINK_NUM_FREQ/2]);
// part3
MLINK_CRC_Init = rx_tx_addr[3]; //value sent during bind then used to init the CRC
MLINK_Unk_6_2 = 0x3A; //unknown value sent during bind but doesn't seem to matter
#ifdef MLINK_FORCE_ID
if(RX_num)
{
//Cockpit SX
memcpy(MLINK_Data_Code,"\x4C\x97\x9D\xBF\xB8\x3D\xB5\xBE",8);
memcpy(hopping_frequency,"\x0D\x41\x09\x43\x17\x2D\x05\x31\x13\x3B\x1B\x3D\x0B\x41\x11\x45\x09\x2B\x17\x4D\x19\x3F\x03\x3F\x0F\x37\x1F\x47\x1B\x49\x07\x35\x27\x2F\x15\x33\x23\x39\x1F\x33\x19\x45\x0D\x2D\x11\x35\x0B\x47\x25\x3D\x21\x37\x1D\x3B\x05\x2F\x21\x39\x23\x4B\x03\x31\x25\x29\x07\x4F\x1D\x4B\x15\x4D\x13\x4F\x0F\x49\x29\x2B\x27\x43",MLINK_NUM_FREQ);
MLINK_Unk_6_2 = 0x3A; //unknown value sent during bind but doesn't seem to matter
MLINK_CRC_Init = 0x07; //value sent during bind then used to init the CRC
}
else
{
//HFM3
memcpy(MLINK_Data_Code,"\xC0\x90\x8F\xBB\x7C\x8E\x2B\x8E",8);
memcpy(hopping_frequency,"\x05\x41\x27\x4B\x17\x33\x11\x39\x0F\x3F\x05\x2F\x13\x2D\x25\x31\x1F\x2D\x25\x35\x03\x41\x1B\x43\x09\x3D\x1F\x29\x1D\x35\x0D\x3B\x19\x49\x23\x3B\x17\x47\x1D\x2B\x13\x37\x0B\x31\x23\x33\x29\x3F\x07\x37\x07\x43\x11\x2B\x1B\x39\x0B\x4B\x03\x4F\x21\x47\x0F\x4D\x15\x45\x21\x4F\x09\x3D\x19\x2F\x15\x45\x0D\x49\x27\x4D",MLINK_NUM_FREQ);
MLINK_Unk_6_2 = 0x02; //unknown value but doesn't seem to matter
MLINK_CRC_Init = 0x3E; //value sent during bind then used to init the CRC
}
//Other TX
//MLINK_Unk_6_2 = 0x7e; //unknown value but doesn't seem to matter
//MLINK_CRC_Init = 0xA2; //value sent during bind then used to init the CRC
#endif
for(uint8_t i=0;i<8;i++)
MLINK_Data_Code[i+8]=MLINK_Data_Code[7-i];
debug("ID:")
for(uint8_t i=0;i<16;i++)
debug(" %02X", MLINK_Data_Code[i]);
debugln("");
debugln("CRC init: %02X", MLINK_CRC_Init)
debug("RF:")
for(uint8_t i=0;i<MLINK_NUM_FREQ;i++)
debug(" %02X", hopping_frequency[i]);
debugln("");
if(IS_BIND_IN_PROGRESS)
{
packet_count = 0;
bind_counter = MLINK_BIND_COUNT;
CYRF_ConfigDataCode((uint8_t*)"\x6F\xBE\x32\x01\xDB\xF1\x2B\x01\xE3\x5C\xFA\x02\x97\x93\xF9\x02"); //Bind data code
CYRF_ConfigRFChannel(MLINK_BIND_CHANNEL);
phase = MLINK_BIND_TX;
}
else
phase = MLINK_PREP_DATA;
}
#endif

View File

@@ -0,0 +1,565 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// compatible with MT99xx, Eachine H7, Yi Zhan i6S, LS114/124, QF009 Su35
// Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29
#if defined(MT99XX_CCNRF_INO)
#include "iface_xn297.h"
#define MT99XX_BIND_COUNT 928
#define MT99XX_PACKET_PERIOD_FY805 2460
#define MT99XX_PACKET_PERIOD_MT 2625
#define MT99XX_PACKET_PERIOD_YZ 3125
#define MT99XX_PACKET_PERIOD_A180 3400 // timing changes between the packets 2 x 27220 then 1x 26080, it seems that it is only on the first RF channel which jitters by 1.14ms but hard to pinpoint with XN297dump
#define MT99XX_PACKET_PERIOD_DRAGON 1038 // there is a pause of 2x1038 between two packets, no idea why and how since it is not even stable on a same dump...
#define MT99XX_PACKET_PERIOD_DRAGON_TELEM 10265 // long pause to receive the telemetry packets, 3 are sent by the RX one after the other
#define MT99XX_PACKET_PERIOD_F949G 3450
#define MT99XX_PACKET_PERIOD_PA18 1338
#define MT99XX_INITIAL_WAIT 500
#define MT99XX_PACKET_SIZE 9
//#define FORCE_A180_ID
//#define FORCE_DRAGON_ID
//#define FORCE_F949G_ID
#define FORCE_PA18_ID1
//#define FORCE_PA18_ID2
enum {
MT99XX_DATA,
MT99XX_RX,
MT99XX_CHECK,
};
enum{
// flags going to packet[6] (MT99xx, H7)
FLAG_MT_RATE1 = 0x01, // (H7 & A180 high rate)
FLAG_MT_RATE2 = 0x02, // (MT9916 only)
FLAG_MT_VIDEO = 0x10,
FLAG_MT_SNAPSHOT= 0x20,
FLAG_MT_FLIP = 0x80,
};
enum{
// flags going to packet[6] (LS)
FLAG_LS_INVERT = 0x01,
FLAG_LS_RATE = 0x02,
FLAG_LS_HEADLESS= 0x10,
FLAG_LS_SNAPSHOT= 0x20,
FLAG_LS_VIDEO = 0x40,
FLAG_LS_FLIP = 0x80,
};
enum{
// flags going to packet[7] (FY805)
FLAG_FY805_HEADLESS= 0x10,
};
enum{
// flags going to packet[6] (A180)
FLAG_A180_3D6G = 0x01,
FLAG_A180_RATE = 0x02,
};
enum{
// flags going to packet[6] (DRAGON)
FLAG_DRAGON_RATE = 0x01,
FLAG_DRAGON_RTH = 0x80,
FLAG_DRAGON_UNK = 0x04,
};
enum{
// flags going to packet[6] (F949G)
FLAG_F949G_LIGHT = 0x01,
FLAG_F949G_RATES = 0x02,
FLAG_F949G_3D6G = 0x20,
FLAG_BF109_RATES = 0x01, // short press right
FLAG_BF109_LIGHT = 0x02, // short press left
FLAG_BF109_UNK1 = 0x08, // long press right
FLAG_BF109_UNK2 = 0x10, // long press left
};
enum{
// flags going to packet[6] (PA18)
FLAG_PA18_RTH = 0x08,
FLAG_PA18_FLIP = 0x80,
};
enum{
// flags going to packet[6] (QF009 Su35)
FLAG_SU35_6G = 0x00,
FLAG_SU35_3D = 0x40,
FLAG_SU35_HIRATE = 0x01,
FLAG_SU35_LED = 0x02,
FLAG_SU35_FLASH = 0x04,
FLAG_SU35_INVERT = 0x08,
};
const uint8_t h7_mys_byte[] = {
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
};
const uint8_t ls_mys_byte[] = {
0x05, 0x15, 0x25, 0x06, 0x16, 0x26,
0x07, 0x17, 0x27, 0x00, 0x10, 0x20,
0x01, 0x11, 0x21, 0x02, 0x12, 0x22,
0x03, 0x13, 0x23, 0x04, 0x14, 0x24
};
const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60};
#ifdef MT99XX_HUB_TELEMETRY
const uint8_t DRAGON_seq[] = {0x20, 0x60, 0x20, 0x80};
#endif
static void __attribute__((unused)) MT99XX_send_packet()
{
static uint8_t seq_num=0;
//Set RF freq
if(sub_protocol == LS)
XN297_RFChannel(0x2D); // LS always transmits on the same channel
else
if(sub_protocol==FY805)
XN297_RFChannel(0x4B); // FY805 always transmits on the same channel
else // MT99 & H7 & YZ & A180 & DRAGON & F949G & PA18
XN297_Hopping(hopping_frequency_no);
if(IS_BIND_IN_PROGRESS)
{
//Bind packet
packet[0] = 0x20;
switch(sub_protocol)
{
case YZ:
packet[1] = 0x15;
packet[2] = 0x05;
packet[3] = 0x06;
break;
case LS:
packet[1] = 0x14;
packet[2] = 0x05;
packet[3] = 0x11;
break;
case FY805:
packet[1] = 0x15;
packet[2] = 0x12;
packet[3] = 0x17;
break;
default: // MT99 & H7 & A180 & DRAGON & F949G & PA18
packet[1] = 0x14;
packet[2] = 0x03;
packet[3] = 0x25;
break;
}
packet[4] = rx_tx_addr[0];
packet[5] = rx_tx_addr[1];
packet[6] = rx_tx_addr[2];
if(sub_protocol == PA18+8)
{
packet[7] = num_ch; // checksum offset
packet[8] = 0x55; // fixed
}
else
{ // all others
packet[7] = crc8; // checksum offset
if(sub_protocol != F949G)
packet[8] = 0xAA; // fixed
else
packet[8] = 0x00;
}
}
else
{
if(sub_protocol != YZ)
{ // MT99XX & H7 & LS & FY805 & A180 & DRAGON & F949G & PA18
packet[0] = convert_channel_16b_limit(THROTTLE,0xE1,0x00); // throttle
packet[1] = convert_channel_16b_limit(RUDDER ,0x00,0xE1); // rudder
packet[2] = convert_channel_16b_limit(AILERON ,0xE1,0x00); // aileron
packet[3] = convert_channel_16b_limit(ELEVATOR,0x00,0xE1); // elevator
packet[4] = (convert_channel_8b(CH10) ^ 0xFF) >> 2; // aileron trim (3F..20..00)
packet[5] = convert_channel_8b(CH11) >> 2; // elevator trim (00..20..3F)
packet[6] = GET_FLAG( CH5_SW, FLAG_MT_FLIP );
if(sub_protocol != PA18+8)
packet[7] = h7_mys_byte[hopping_frequency_no]; // next rf channel index ?
else
packet[7] = (packet[7]&0xBF)|0x20;
switch(sub_protocol)
{
case MT99:
packet[6] |= 0x40 | FLAG_MT_RATE2 // max rate on MT99xx
| GET_FLAG( CH7_SW, FLAG_MT_SNAPSHOT )
| GET_FLAG( CH8_SW, FLAG_MT_VIDEO );
break;
case H7:
packet[6] |= FLAG_MT_RATE1; // max rate on H7
break;
case LS:
packet[6] |= FLAG_LS_RATE // max rate
| GET_FLAG( CH6_SW, FLAG_LS_INVERT ) // invert
| GET_FLAG( CH7_SW, FLAG_LS_SNAPSHOT ) // snapshot
| GET_FLAG( CH8_SW, FLAG_LS_VIDEO ) // video
| GET_FLAG( CH9_SW, FLAG_LS_HEADLESS ); // Headless
packet[7] = ls_mys_byte[seq_num++];
if(seq_num >= sizeof(ls_mys_byte))
seq_num=0;
break;
case FY805:
packet[6]=0x20;
//Rate 0x01?
//Flip ?
packet[7]=0x01
|GET_FLAG( CH5_SW, FLAG_MT_FLIP )
|GET_FLAG( CH9_SW, FLAG_FY805_HEADLESS ); //HEADLESS
crc8=0;
break;
case A180:
packet[6] = GET_FLAG( !CH6_SW,FLAG_A180_RATE) // 0x02, A180=RATE, F949S=LED
|GET_FLAG( CH5_SW, FLAG_A180_3D6G ) // 0x01, A180=3D_6G, F949S=RATE
|GET_FLAG( CH7_SW, 0x20 ); // 0x20, F949S=3D_6G
packet[7] = 0x00;
break;
case DRAGON:
if(CH5_SW) // Advanced mode
packet[5] |= 0x80;
else
if(Channel_data[CH5] > CHANNEL_MIN_COMMAND) // Beginner mode
packet[5] |= 0x40;
packet[6] = FLAG_DRAGON_RATE
| GET_FLAG( CH6_SW, FLAG_DRAGON_RTH );
#ifdef MT99XX_HUB_TELEMETRY
//Telemetry
if(hopping_frequency_no == 0)
{
seq_num++;
seq_num &= 0x03;
packet_count++;
if(packet_count > 11)
packet_count = 0;
}
if(packet_count > 10) // Telemetry packet request every 10 or 11 packets
{
packet[6] |= 0x04; // Request telemetry flag
phase = MT99XX_RX;
}
packet[7] = DRAGON_seq[seq_num]; // seq: 20 80 20 60 20 80 20 60... 80 changes to 80+batt from telem
if(seq_num==3)
packet[7] |= v_lipo1;
#else
packet[7] = 0x20;
#endif
break;
case F949G:
packet[6] = GET_FLAG( CH5_SW, FLAG_F949G_3D6G )
| GET_FLAG( CH6_SW, FLAG_F949G_LIGHT ) //FLAG_BF109_RATES
| GET_FLAG(!CH7_SW, FLAG_F949G_RATES ) //FLAG_BF109_LIGHT
| GET_FLAG( CH8_SW, FLAG_BF109_UNK1 ) //BF109 long press right, temporary flag
| GET_FLAG( CH9_SW, FLAG_BF109_UNK2 ); //BF109 long press left, temporary flag
packet[7] = 0x00;
break;
case PA18+8:
if(Channel_data[CH5] > CHANNEL_MAX_COMMAND) // Expert mode
packet[5] = 0xA0;
else
if(Channel_data[CH5] > CHANNEL_MIN_COMMAND) // Intermediate mode
packet[5] = 0x60;
packet[6] = GET_FLAG( CH6_SW, FLAG_PA18_FLIP ) // Flip
| GET_FLAG( CH7_SW, FLAG_PA18_RTH ); // RTH
if(hopping_frequency_no == 0)
packet[7] ^= 0x40;
break;
case SU35+8:
packet[6] = FLAG_SU35_6G
| GET_FLAG( CH5_SW, FLAG_SU35_3D )
| GET_FLAG( !CH6_SW, FLAG_SU35_LED )
| GET_FLAG( CH7_SW, FLAG_SU35_FLASH )
| GET_FLAG( CH8_SW, FLAG_SU35_INVERT )
| GET_FLAG( CH9_SW, FLAG_SU35_HIRATE );
break;
}
uint8_t result=crc8;
for(uint8_t i=0; i<8; i++)
result += packet[i];
if(sub_protocol == PA18+8)
result += num_ch;
packet[8] = result;
}
else
{ // YZ
packet[0] = convert_channel_16b_limit(THROTTLE,0x00,0x64); // throttle
packet[1] = convert_channel_16b_limit(RUDDER ,0x64,0x00); // rudder
packet[2] = convert_channel_16b_limit(ELEVATOR,0x00,0x64); // elevator
packet[3] = convert_channel_16b_limit(AILERON ,0x64,0x00); // aileron
if(packet_count++ >= 23)
{
seq_num ++;
if(seq_num > 2)
seq_num = 0;
packet_count=0;
}
packet[4] = yz_p4_seq[seq_num];
packet[5] = 0x02 // expert ? (0=unarmed, 1=normal)
| GET_FLAG(CH8_SW, 0x10) //VIDEO
| GET_FLAG(CH5_SW, 0x80) //FLIP
| GET_FLAG(CH9_SW, 0x04) //HEADLESS
| GET_FLAG(CH7_SW, 0x20); //SNAPSHOT
packet[6] = GET_FLAG(CH6_SW, 0x80); //LED
packet[7] = packet[0];
for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++)
packet[7] += packet[idx];
packet[8] = 0xff;
}
}
//Hopp
hopping_frequency_no++;
if(sub_protocol == YZ || sub_protocol == A180 || sub_protocol == DRAGON || sub_protocol == F949G || sub_protocol == PA18+8)
hopping_frequency_no++; // skip every other channel
if(hopping_frequency_no > 15)
hopping_frequency_no = 0;
// Send
XN297_SetPower();
XN297_SetFreqOffset();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, MT99XX_PACKET_SIZE);
#if 1
for(uint8_t i=0; i<MT99XX_PACKET_SIZE; i++)
debug(" %02X",packet[i]);
debugln();
#endif
}
static void __attribute__((unused)) MT99XX_RF_init()
{
if(sub_protocol == YZ)
XN297_Configure(XN297_CRCEN, XN297_UNSCRAMBLED, XN297_250K);
else if(sub_protocol == F949G)
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_250K);
else
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5);
XN297_HoppingCalib(16);
#ifdef MT99XX_HUB_TELEMETRY
XN297_SetRXAddr(rx_tx_addr, MT99XX_PACKET_SIZE);
#endif
}
static void __attribute__((unused)) MT99XX_initialize_txid()
{
num_ch = rx_tx_addr[1]; // PA18
rx_tx_addr[1] = rx_tx_addr[3]; // RX_Num
switch(sub_protocol)
{
case YZ:
rx_tx_addr[0] = 0x53; // test (SB id)
rx_tx_addr[1] = 0x00;
rx_tx_addr[2] = 0x00;
break;
case FY805:
rx_tx_addr[0] = 0x81; // test (SB id)
rx_tx_addr[1] = 0x0F;
rx_tx_addr[2] = 0x00;
break;
case LS:
rx_tx_addr[0] = 0xCC;
break;
#ifdef FORCE_A180_ID
case A180:
rx_tx_addr[0] = 0x84; // MikeHRC ID
rx_tx_addr[1] = 0x62;
rx_tx_addr[2] = 0x4A;
//crc8 = 0x30
//channel_offset = 0x03;
break;
#endif
#ifdef FORCE_DRAGON_ID
case DRAGON:
rx_tx_addr[0] = 0x6C; // Laurie ID
rx_tx_addr[1] = 0x00;
rx_tx_addr[2] = 0x22;
//crc8 = 0x8E
//channel_offset = 0x06
break;
#endif
#ifdef FORCE_F949G_ID
case F949G:
rx_tx_addr[0] = 0x7E; // LilTeo14 ID
rx_tx_addr[1] = 0x2F;
rx_tx_addr[2] = 0x29;
//crc8 = 0xD6
//channel_offset = 0x03
break;
#endif
#ifdef FORCE_PA18_ID1
case PA18+8:
rx_tx_addr[0] = 0xC9; // zebble ID
rx_tx_addr[1] = 0x02;
rx_tx_addr[2] = 0x13;
num_ch = 0x89; // additional crc init. How is this calculated? or could it be random?
//crc8 = 0xDE
//channel_offset = 0x03
//1Mb C=5 S=Y A= C9 02 13 CC CC P(9)= E1 70 70 70 20 20 00 20 1A -> 0x91 + 0x89 => 0x1A
// S=Y A= C9 02 13 CC CC P(9)= E1 70 70 70 20 A0 00 20 9A -> 0x11 + 0x89 => 0x9A
//bind S=Y A= CC CC CC CC CC P(9)= 20 14 03 25 C9 02 13 89 55
break;
#endif
#ifdef FORCE_PA18_ID2
case PA18+8:
rx_tx_addr[0] = 0x0E;
rx_tx_addr[1] = 0x05;
rx_tx_addr[2] = 0x13;
num_ch = 0xD1; // additional crc init. How is this calculated? or could it be random?
//crc8 = 0x28
//channel_offset = 0x00
//1Mb C=2 S=Y A= 0E 05 13 CC CC P(9)= E1 70 70 70 20 60 00 60 E2 -> 0x11 + 0xD1 => 0xE2
//bind S=Y A= CC CC CC CC CC P(9)= 20 14 03 25 0E 05 13 D1 55
break;
#endif
default: //MT99 & H7 & A180 & DRAGON & F949G & PA18
rx_tx_addr[2] = 0x00;
if(sub_protocol == PA18+8)
rx_tx_addr[2] = 0x13;
break;
}
rx_tx_addr[3] = 0xCC;
rx_tx_addr[4] = 0xCC;
crc8 = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2];
//memcpy(hopping_frequency,"\x02\x48\x0C\x3e\x16\x34\x20\x2A\x2A\x20\x34\x16\x3e\x0c\x48\x02",16);
for(uint8_t i=0; i<8; i++)
{
hopping_frequency[(i<<1) ]=0x02 + (10*i);
hopping_frequency[(i<<1)+1]=0x48 - (10*i);
}
hopping_frequency_no=0;
}
uint16_t MT99XX_callback()
{
switch(phase)
{
case MT99XX_DATA:
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
if(bind_counter)
{
bind_counter--;
if (bind_counter == 0)
{
// set tx address for data packets
XN297_SetTXAddr(rx_tx_addr, 5);
// set rf channels
uint8_t channel_offset = ((crc8>>4) + (crc8 & 0x0f)) % 8;
for(uint8_t i=0;i<16;i++)
hopping_frequency[i] += channel_offset;
XN297_HoppingCalib(16);
BIND_DONE;
}
}
MT99XX_send_packet();
break;
#ifdef MT99XX_HUB_TELEMETRY
case MT99XX_RX:
//Switch to RX
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
phase++;
return MT99XX_PACKET_PERIOD_DRAGON_TELEM - MT99XX_PACKET_PERIOD_DRAGON - 500;
case MT99XX_CHECK:
//Check telem
if(XN297_IsRX())
{
//debug("RX");
if(XN297_ReadPayload(packet_in, MT99XX_PACKET_SIZE))
{
// C=48 S=Y A= 6C 00 22 CC CC P(9)= 6C 00 22 27 00 00 00 00 60
// C=48 S=Y A= 6C 00 22 CC CC P(9)= 6C 00 22 28 00 00 00 00 61
// C=18 S=Y A= 6C 00 22 CC CC P(9)= 6C 00 22 24 00 00 00 00 5D
// 6C 00 22 = TX address, 27/28/24=vbatt, check = sum(P[0..7]) + AB
// D2 EE 00 25 00 00 00 00 90 -> check also + AB
//for(uint8_t i=0; i<MT99XX_PACKET_SIZE; i++)
// debug(" %02X",packet_in[i]);
uint8_t check=0xAB;
for(uint8_t i=0; i<8; i++)
check += packet_in[i];
if(packet_in[8] == check && packet_in[0] == rx_tx_addr[0] && packet_in[1] == rx_tx_addr[1] && packet_in[2] == rx_tx_addr[2])
{ // checksum and address are ok
// debug(" OK");
v_lipo1 = packet_in[3] & 0x7F; // Batt
v_lipo2 = packet_in[3] & 0x80; // Low batt flag
RX_RSSI=100;
telemetry_link = 1;
}
}
//debugln("");
}
//Switch to TX
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(TX_EN);
phase=MT99XX_DATA;
return 500;
#endif
}
return packet_period;
}
void MT99XX_init(void)
{
if(protocol == PROTO_MT99XX2)
sub_protocol|=0x08; // Increase the number of sub_protocols for MT99XX
bind_counter = MT99XX_BIND_COUNT;
if(IS_BIND_DONE)
{
if(sub_protocol != A180 && sub_protocol != DRAGON && sub_protocol != F949G && sub_protocol != PA18+8 && sub_protocol != SU35+8)
BIND_IN_PROGRESS; // autobind protocol
else
bind_counter = 1;
}
MT99XX_initialize_txid();
MT99XX_RF_init();
switch(sub_protocol)
{
case YZ:
packet_period = MT99XX_PACKET_PERIOD_YZ;
break;
case FY805:
packet_period = MT99XX_PACKET_PERIOD_FY805;
break;
case F949G:
case A180:
packet_period = MT99XX_PACKET_PERIOD_A180;
break;
case PA18+8:
packet_period = MT99XX_PACKET_PERIOD_PA18;
break;
default:
packet_period = MT99XX_PACKET_PERIOD_MT;
break;
}
packet_count=0;
phase=MT99XX_DATA;
}
#endif

View File

@@ -1,310 +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 MT99xx, Eachine H7, Yi Zhan i6S and LS114/124
// Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29
#if defined(MT99XX_NRF24L01_INO)
#include "iface_nrf24l01.h"
#define MT99XX_BIND_COUNT 928
#define MT99XX_PACKET_PERIOD_FY805 2460
#define MT99XX_PACKET_PERIOD_MT 2625
#define MT99XX_PACKET_PERIOD_YZ 3125
#define MT99XX_INITIAL_WAIT 500
#define MT99XX_PACKET_SIZE 9
#define checksum_offset rf_ch_num
#define channel_offset phase
enum{
// flags going to packet[6] (MT99xx, H7)
FLAG_MT_RATE1 = 0x01, // (H7 high rate)
FLAG_MT_RATE2 = 0x02, // (MT9916 only)
FLAG_MT_VIDEO = 0x10,
FLAG_MT_SNAPSHOT= 0x20,
FLAG_MT_FLIP = 0x80,
};
enum{
// flags going to packet[6] (LS)
FLAG_LS_INVERT = 0x01,
FLAG_LS_RATE = 0x02,
FLAG_LS_HEADLESS= 0x10,
FLAG_LS_SNAPSHOT= 0x20,
FLAG_LS_VIDEO = 0x40,
FLAG_LS_FLIP = 0x80,
};
enum{
// flags going to packet[7] (FY805)
FLAG_FY805_HEADLESS= 0x10,
};
enum {
MT99XX_INIT = 0,
MT99XX_BIND,
MT99XX_DATA
};
const uint8_t h7_mys_byte[] = {
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
};
static const uint8_t ls_mys_byte[] = {
0x05, 0x15, 0x25, 0x06, 0x16, 0x26,
0x07, 0x17, 0x27, 0x00, 0x10, 0x20,
0x01, 0x11, 0x21, 0x02, 0x12, 0x22,
0x03, 0x13, 0x23, 0x04, 0x14, 0x24
};
static void __attribute__((unused)) MT99XX_send_packet()
{
const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60};
static uint8_t yz_seq_num=0;
static uint8_t ls_counter=0;
if(sub_protocol != YZ)
{ // MT99XX & H7 & LS
packet[0] = convert_channel_16b_limit(THROTTLE,0xE1,0x00); // throttle
packet[1] = convert_channel_16b_limit(RUDDER ,0x00,0xE1); // rudder
packet[2] = convert_channel_16b_limit(AILERON ,0xE1,0x00); // aileron
packet[3] = convert_channel_16b_limit(ELEVATOR,0x00,0xE1); // elevator
packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00)
packet[5] = 0x20; // roll trim (0x00-0x20-0x3f)
packet[6] = GET_FLAG( CH5_SW, FLAG_MT_FLIP );
packet[7] = h7_mys_byte[hopping_frequency_no]; // next rf channel index ?
if(sub_protocol==H7)
packet[6]|=FLAG_MT_RATE1; // max rate on H7
else
if(sub_protocol==MT99)
packet[6] |= 0x40 | FLAG_MT_RATE2
| GET_FLAG( CH7_SW, FLAG_MT_SNAPSHOT )
| GET_FLAG( CH8_SW, FLAG_MT_VIDEO ); // max rate on MT99xx
else
if(sub_protocol==FY805)
{
packet[6]=0x20;
//Rate 0x01?
//Flip ?
packet[7]=0x01
|GET_FLAG( CH5_SW, FLAG_MT_FLIP )
|GET_FLAG( CH9_SW, FLAG_FY805_HEADLESS ); //HEADLESS
checksum_offset=0;
}
else //LS
{
packet[6] |= FLAG_LS_RATE // max rate
| GET_FLAG( CH6_SW, FLAG_LS_INVERT ) //INVERT
| GET_FLAG( CH7_SW, FLAG_LS_SNAPSHOT ) //SNAPSHOT
| GET_FLAG( CH8_SW, FLAG_LS_VIDEO ) //VIDEO
| GET_FLAG( CH9_SW, FLAG_LS_HEADLESS ); //HEADLESS
packet[7] = ls_mys_byte[ls_counter++];
if(ls_counter >= sizeof(ls_mys_byte))
ls_counter=0;
}
uint8_t result=checksum_offset;
for(uint8_t i=0; i<8; i++)
result += packet[i];
packet[8] = result;
}
else
{ // YZ
packet[0] = convert_channel_16b_limit(THROTTLE,0x00,0x64); // throttle
packet[1] = convert_channel_16b_limit(RUDDER ,0x64,0x00); // rudder
packet[2] = convert_channel_16b_limit(ELEVATOR,0x00,0x64); // elevator
packet[3] = convert_channel_16b_limit(AILERON ,0x64,0x00); // aileron
if(packet_count++ >= 23)
{
yz_seq_num ++;
if(yz_seq_num > 2)
yz_seq_num = 0;
packet_count=0;
}
packet[4] = yz_p4_seq[yz_seq_num];
packet[5] = 0x02 // expert ? (0=unarmed, 1=normal)
| GET_FLAG(CH8_SW, 0x10) //VIDEO
| GET_FLAG(CH5_SW, 0x80) //FLIP
| GET_FLAG(CH9_SW, 0x04) //HEADLESS
| GET_FLAG(CH7_SW, 0x20); //SNAPSHOT
packet[6] = GET_FLAG(CH6_SW, 0x80); //LED
packet[7] = packet[0];
for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++)
packet[7] += packet[idx];
packet[8] = 0xff;
}
if(sub_protocol == LS)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel
else
if(sub_protocol==FY805)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x4B); // FY805 always transmits on the same channel
else
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(packet, MT99XX_PACKET_SIZE);
hopping_frequency_no++;
if(sub_protocol == YZ)
hopping_frequency_no++; // skip every other channel
if(hopping_frequency_no > 15)
hopping_frequency_no = 0;
NRF24L01_SetPower();
}
static void __attribute__((unused)) MT99XX_init()
{
NRF24L01_Initialize();
if(sub_protocol == YZ)
XN297_SetScrambledMode(XN297_UNSCRAMBLED);
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_FlushTx();
XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes address
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no auto retransmit
if(sub_protocol == YZ)
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps (nRF24L01+ only)
else
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) );
}
static void __attribute__((unused)) MT99XX_initialize_txid()
{
rx_tx_addr[3] = 0xCC;
rx_tx_addr[4] = 0xCC;
if(sub_protocol == YZ)
{
rx_tx_addr[0] = 0x53; // test (SB id)
rx_tx_addr[1] = 0x00;
rx_tx_addr[2] = 0x00;
}
else
if(sub_protocol == FY805)
{
rx_tx_addr[0] = 0x81; // test (SB id)
rx_tx_addr[1] = 0x0F;
rx_tx_addr[2] = 0x00;
}
else
if(sub_protocol == LS)
rx_tx_addr[0] = 0xCC;
else //MT99 & H7
rx_tx_addr[2] = 0x00;
checksum_offset = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2];
channel_offset = (((checksum_offset & 0xf0)>>4) + (checksum_offset & 0x0f)) % 8;
}
uint16_t MT99XX_callback()
{
if(IS_BIND_DONE)
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
MT99XX_send_packet();
}
else
{
if (bind_counter == 0)
{
// set tx address for data packets
XN297_SetTXAddr(rx_tx_addr, 5);
BIND_DONE;
}
else
{
if(sub_protocol == LS)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel
else
if(sub_protocol==FY805)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x4B); // FY805 always transmits on the same channel
else
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(packet, MT99XX_PACKET_SIZE); // bind packet
hopping_frequency_no++;
if(sub_protocol == YZ)
hopping_frequency_no++; // skip every other channel
if(hopping_frequency_no > 15)
hopping_frequency_no = 0;
bind_counter--;
}
}
return packet_period;
}
uint16_t initMT99XX(void)
{
BIND_IN_PROGRESS; // autobind protocol
bind_counter = MT99XX_BIND_COUNT;
memcpy(hopping_frequency,"\x02\x48\x0C\x3e\x16\x34\x20\x2A\x2A\x20\x34\x16\x3e\x0c\x48\x02",16);
hopping_frequency_no=0;
MT99XX_initialize_txid();
MT99XX_init();
packet[0] = 0x20;
packet_period = MT99XX_PACKET_PERIOD_MT;
switch(sub_protocol)
{ // MT99 & H7
case MT99:
case H7:
packet[1] = 0x14;
packet[2] = 0x03;
packet[3] = 0x25;
break;
case YZ:
packet_period = MT99XX_PACKET_PERIOD_YZ;
packet[1] = 0x15;
packet[2] = 0x05;
packet[3] = 0x06;
break;
case LS:
packet[1] = 0x14;
packet[2] = 0x05;
packet[3] = 0x11;
break;
case FY805:
packet_period = MT99XX_PACKET_PERIOD_FY805;
packet[1] = 0x15;
packet[2] = 0x12;
packet[3] = 0x17;
break;
}
packet[4] = rx_tx_addr[0];
packet[5] = rx_tx_addr[1];
packet[6] = rx_tx_addr[2];
packet[7] = checksum_offset; // checksum offset
packet[8] = 0xAA; // fixed
packet_count=0;
return MT99XX_INITIAL_WAIT+MT99XX_PACKET_PERIOD_MT;
}
#endif

View File

@@ -0,0 +1,248 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(MOULDKG_NRF24L01_INO)
#include "iface_xn297.h"
//#define FORCE_MOULDKG_ORIGINAL_ID
#define MOULDKG_PACKET_PERIOD 5000
#define MOULDKG_BIND_PACKET_PERIOD 12000
#define MOULDKG_TX_BIND_CHANNEL 11
#define MOULDKG_RX_BIND_CHANNEL 76
#define MOULDKG_PAYLOAD_SIZE_DIGIT 5
#define MOULDKG_PAYLOAD_SIZE_ANALOG 10
#define MOULDKG_BIND_PAYLOAD_SIZE 7
#define MOULDKG_BIND_COUNT 300
#define MOULDKG_RF_NUM_CHANNELS 4
enum {
MOULDKG_BINDTX=0,
MOULDKG_BINDRX,
MOULDKG_PREP_DATA,
MOULDKG_PREP_DATA1,
MOULDKG_DATA,
};
uint8_t MOULDKG_RX_id[4*3];
static void __attribute__((unused)) MOULDKG_send_packet()
{
uint8_t len = MOULDKG_BIND_PAYLOAD_SIZE;
memcpy(&packet[1],rx_tx_addr,3);
if(IS_BIND_IN_PROGRESS)
{
packet[0] = 0xC0;
memset(&packet[4], 0x00, 3);
}
else
{
uint8_t n = num_ch<<2;
if(sub_protocol == MOULDKG_ANALOG4 || sub_protocol == MOULDKG_ANALOG6 )
{
packet[0] = 0x36;
const uint8_t ch[]={ 1,0,2,3,5,4 };
if(sub_protocol == MOULDKG_ANALOG6)
n += num_ch<<1;
for(uint8_t i=0;i<6;i++)
{
if( (i > 3 && sub_protocol == MOULDKG_ANALOG4) || i + n > 15)
packet[i+4] = 0x80; //Centered channel
else
packet[i+4] = convert_channel_8b(ch[i]+n);
}
len = MOULDKG_PAYLOAD_SIZE_ANALOG;
}
else
{//DIGIT
len = MOULDKG_PAYLOAD_SIZE_DIGIT;
uint8_t val=0;
if(packet_count&1)
{
packet[0] = 0x31;
//Button B
if(Channel_data[CH2+n]>CHANNEL_MAX_COMMAND) val |= 0x40;
else if(Channel_data[CH2+n]<CHANNEL_MIN_COMMAND) val |= 0x80;
//Button C
if(Channel_data[CH3+n]>CHANNEL_MAX_COMMAND) val |= 0x10;
else if(Channel_data[CH3+n]<CHANNEL_MIN_COMMAND) val |= 0x20;
}
else
{
packet[0] = 0x30;
val = 0x60;
// | GET_FLAG(CH5_SW, 0x80) // Button E
// | GET_FLAG(CH6_SW, 0x10); // Button F
}
//Button A
if(Channel_data[CH1+n]>CHANNEL_MAX_COMMAND) val |= 0x01;
else if(Channel_data[CH1+n]<CHANNEL_MIN_COMMAND) val |= 0x02;
//Button D
if(Channel_data[CH4+n]>CHANNEL_MAX_COMMAND) val |= 0x04;
else if(Channel_data[CH4+n]<CHANNEL_MIN_COMMAND) val |= 0x08;
packet[4]= val;
}
}
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, len);
#if 0
for(uint8_t i=0; i < len; i++)
debug("%02X ", packet[i]);
debugln();
#endif
}
static void __attribute__((unused)) MOULDKG_initialize_txid()
{
//rx_tx_addr[0] = rx_tx_addr[3]; // Use RX_num;
#ifdef FORCE_MOULDKG_ORIGINAL_ID
rx_tx_addr[0]=0x57;
rx_tx_addr[1]=0x1B;
rx_tx_addr[2]=0xF8;
#endif
}
static void __attribute__((unused)) MOULDKG_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t*)"KDH", 3);
XN297_SetRXAddr((uint8_t*)"KDH", MOULDKG_BIND_PAYLOAD_SIZE);
}
uint16_t MOULDKG_callback()
{
uint8_t rf,n;
uint16_t addr;
switch(phase)
{
case MOULDKG_BINDTX:
if(XN297_IsRX())
{
//Example: TX: C=11 S=Y A= 4B 44 48 P(7)= C0 37 02 4F 00 00 00
// RX: C=76 S=Y A= 4B 44 48 P(7)= 5A 37 02 4F 03 0D 8E
// 03 0D 8E => RF channels 0F,1C,39,3C
XN297_ReadPayload(packet_in, MOULDKG_BIND_PAYLOAD_SIZE);
for(uint8_t i=0; i < MOULDKG_BIND_PAYLOAD_SIZE; i++)
debug("%02X ", packet_in[i]);
debugln();
//Not sure if I should test packet_in[0]
if(memcmp(&packet_in[1],&packet[1],3)==0)
{//TX ID match
if(option == 0)
{
memcpy(MOULDKG_RX_id,&packet_in[4],3);
phase = MOULDKG_PREP_DATA1;
}
else
{// Store RX ID
addr=MOULDKG_EEPROM_OFFSET+RX_num*3;
for(uint8_t i=0;i<3;i++)
eeprom_write_byte((EE_ADDR)(addr+i),packet_in[4+i]);
phase = MOULDKG_PREP_DATA;
}
break;
}
}
XN297_RFChannel(MOULDKG_TX_BIND_CHANNEL); // Set TX bind channel
XN297_SetTxRxMode(TXRX_OFF);
MOULDKG_send_packet();
phase++;
return 600;
case MOULDKG_BINDRX:
//Wait for the packet transmission to finish
while(XN297_IsPacketSent()==false);
//Switch to RX
XN297_SetTxRxMode(TXRX_OFF);
XN297_RFChannel(MOULDKG_RX_BIND_CHANNEL); // Set RX bind channel
XN297_SetTxRxMode(RX_EN);
phase = MOULDKG_BINDTX;
return MOULDKG_BIND_PACKET_PERIOD-600;
case MOULDKG_PREP_DATA:
addr=MOULDKG_EEPROM_OFFSET+RX_num*3;
debug("RXID: ");
for(uint8_t i=0;i<3*4;i++)
{ // load 4 consecutive RX IDs
MOULDKG_RX_id[i]=eeprom_read_byte((EE_ADDR)(addr+i));
debug(" %02X",MOULDKG_RX_id[i]);
}
debugln("");
case MOULDKG_PREP_DATA1:
//Switch to normal mode
BIND_DONE;
XN297_SetTxRxMode(TXRX_OFF);
phase = MOULDKG_DATA;
break;
case MOULDKG_DATA:
#ifdef MULTI_SYNC
if(num_ch==0)
telemetry_set_input_sync(MOULDKG_PACKET_PERIOD);
#endif
if(option == 0) option++;
if(num_ch<option)
{
//Set RX ID address
n = num_ch*3;
XN297_SetTXAddr(&MOULDKG_RX_id[n], 3);
//Set frequency based on current RX ID and packet number
rf = 0x0C;
if(packet_count & 0x04)
{
n++;
rf += 0x20;
}
if(packet_count & 0x02)
rf += 0x10 + (MOULDKG_RX_id[n] >> 4);
else
rf += MOULDKG_RX_id[n] & 0x0F;
XN297_RFChannel(rf);
#if 1
debugln("num_ch=%d,packet_count=%d,rf=%02X,ID=%02X %02X %02X",num_ch,packet_count,rf,MOULDKG_RX_id[num_ch*3],MOULDKG_RX_id[num_ch*3+1],MOULDKG_RX_id[num_ch*3+2]);
#endif
MOULDKG_send_packet();
if(num_ch==0)
packet_count++;
}
num_ch++;
num_ch &= 0x03;
break;
}
return MOULDKG_PACKET_PERIOD/4;
}
void MOULDKG_init()
{
if(option == 0)
BIND_IN_PROGRESS;
MOULDKG_initialize_txid();
MOULDKG_RF_init();
bind_counter = MOULDKG_BIND_COUNT;
if(IS_BIND_IN_PROGRESS)
phase = MOULDKG_BINDTX;
else
phase = MOULDKG_PREP_DATA;
packet_count = 0;
num_ch = 0;
}
#endif
// Analog
// Bind TX: C=11 S=Y A= 4B 44 48 P(7)= C0 46 01 00 00 00 00
// Bind RX: 5A 46 01 00 63 82 4E
// Norm: C=15 S=Y A= 63 82 4E P(10)= 36 46 01 00 80 80 80 80 00 00

View File

@@ -2,30 +2,30 @@
2,Hubsan,H107,H301,H501
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,DSMR_1F,DSMR,DSM2_SFC
7,Devo,8CH,10CH,12CH,6CH,7CH
8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI
9,KN,WLTOYS,FEILUN
10,SymaX,SYMAX,SYMAX5C
11,SLT,SLT_V1,SLT_V2,Q100,Q200,MR100
11,SLT,SLT_V1,SLT_V2,Q100,Q200,MR100,V1_4CH,RF_SIM,SLT6TX
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,Cloned
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
17,MT99xx,MT,H7,YZ,LS,FY805,A180,Dragon,F949G
18,MJXq,WLH08,X600,X800,H26D,E010,H26WH,PHOENIX
19,Shenqi
20,FY326,FY326,FY319
21,SFHSS
21,Futaba,SFHSS
22,J6PRO
23,FQ777
23,FQ777,124,XBM37
24,ASSAN
25,FrskyV
26,HONTAI,HONTAI,JJRCX1,X5C1,FQ777_951
26,HONTAI,HONTAI,JJRCX1,X5C1,FQ777_951,XKK170
27,OpnLrs
28,AFHDS2A,PWM_IBUS,PPM_IBUS,PWM_SBUS,PPM_SBUS
28,AFHDS2A,PWM_IBUS,PPM_IBUS,PWM_SBUS,PPM_SBUS,Gyro_Off,Gyro_On,G_On_Rev
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
@@ -37,32 +37,70 @@
37,CORONA,COR_V1,COR_V2,FD_V3
38,CFlie
39,Hitec,OPT_FW,OPT_HUB,MINIMA
40,WFLY
40,WFLY,WFR0x
41,BUGS
42,BUGSMINI,BUGSMINI,BUGS3H
43,Traxxas,RX6519
43,Traxxas,TQ
44,NCC1701
45,E01X,E012,E015,E016H
45,E01X,E012,E015
46,V911S,V911S,E119
47,GD00x,GD_V1,GD_V2
48,V761
49,KF606
48,V761,3CH,4CH,TOPRC
49,KF606,KF606,MIG320,ZCZ50
50,Redpine,Fast,Slow
51,Potensic,A20
52,ZSX,280
53,Flyzone,FZ-410
53,Height,5ch,8ch
54,Scanner
55,Frsky_RX,RX,CloneTX
56,AFHDS2A_RX
57,HoTT
58,FX816,P38
59,Bayang_RX
60,Pelikan
61,Tiger
62,XK,X450,X420
55,Frsky_RX,Multi,CloneTX,EraseTX,CPPM
56,AFHDS2A_RX,Multi,CPPM
57,HoTT,Sync,No_Sync
58,FX,FX816,FX620,9630,Q560,QF012,BM26,A570
59,Bayang_RX,Multi,CPPM
60,Pelikan,Pro,Lite,SCX24
61,EazyRC
62,XK,X450,X420,Cars
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
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,Multi,CloneTX,EraseTX,CPPM
71,JJRC345,JJRC345,SkyTmblr
72,Q90C
73,Kyosho,FHSS,Hype
74,RadioLink,Surface,Air,DumboRC,RC4G,Dumbo_P
75,---
76,Realacc,R11,WLV8TX
77,OMP
78,M-Link
79,WFLY,RF20x
80,E016H,E016Hv2
81,E010r5
82,LOLI
83,E129,E129,C186
84,JOYSWAY
85,E016H
87,IKEA
88,WILLIFM
89,Losi
90,MouldKg,A4444,D4444,A664
91,Xerall
92,MT99xx,PA18,SU35
93,Kyosho2,KT-17
94,Scorpio
95,BlueFly
96,BumbleB
97,SGF22,F22,F22S,J20
98,Kyosho3
99,XK2,X4,P10
100,YuXiang
102,JIABAILE,STD,GYRO
103,H36
104,KAMTOM
105,Shenqi2
106,WL91x
107,WPL
108,0,Ares

View File

@@ -0,0 +1,192 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(MULTI_CONFIG_INO)
#ifdef CYRF6936_INSTALLED
#include "iface_cyrf6936.h"
#endif
void CONFIG_write_GID(uint32_t id)
{
for(uint8_t i=0;i<4;i++)
eeprom_write_byte((EE_ADDR)EEPROM_ID_OFFSET+i,id >> (i*8));
//eeprom_write_byte((EE_ADDR)(EEPROM_ID_OFFSET+10),0xf0);
}
void CONFIG_write_CID(uint8_t *data)
{
for(uint8_t i=0;i<6;i++)
eeprom_write_byte((EE_ADDR)EEPROM_CID_OFFSET+i, data[i]);
//eeprom_write_byte((EE_ADDR)EEPROM_CID_INIT_OFFSET, 0xf0);
}
uint16_t CONFIG_callback()
{
static uint8_t line=0, page=0;
uint32_t id=0;
// [0] = page<<4|line number
// [1..6] = max 6 bytes
if(CONFIG_SerialRX)
{
debug("config");
for(uint8_t i=0; i<7; i++)
debug("%02X ",CONFIG_SerialRX_val[i]);
debugln("");
CONFIG_SerialRX = false;
switch(CONFIG_SerialRX_val[0]&0x0F)
{
//case 0:
// Page change
// break;
case 1:
for(uint8_t i=0; i<4; i++)
{
id <<= 8;
id |= CONFIG_SerialRX_val[i+1];
}
debugln("Update ID to %lx", id);
CONFIG_write_GID(id);
break;
case 2:
if(CONFIG_SerialRX_val[1]==0xAA)
{
#define STM32_UUID ((uint32_t *)0x1FFFF7E8)
id = STM32_UUID[0] ^ STM32_UUID[1] ^ STM32_UUID[2];
debugln("Reset GID to %lx", id);
CONFIG_write_GID(id);
}
break;
#ifdef CYRF6936_INSTALLED
case 4:
debug("Update CID to ");
for(uint8_t i=0; i<6; i++)
debug("%02X ",CONFIG_SerialRX_val[i+1]);
debugln("");
CONFIG_write_CID(&CONFIG_SerialRX_val[1]);
case 5:
if(CONFIG_SerialRX_val[1]==0xAA)
{
uint8_t data[6];
CYRF_WriteRegister(CYRF_25_MFG_ID, 0xFF); /* Fuses power on */
CYRF_ReadRegisterMulti(CYRF_25_MFG_ID, data, 6);
CYRF_WriteRegister(CYRF_25_MFG_ID, 0x00); /* Fuses power off */
debug("Reset CID to ");
for(uint8_t i=0; i<6; i++)
debug("%02X ",data[i]);
debugln("");
CONFIG_write_CID(data);
}
break;
#endif
case 7:
if(CONFIG_SerialRX_val[1]==0xAA)
{
debugln("Format EE");
#if defined(STM32_BOARD)
EEPROM.format();
#else
for (uint16_t i = 0; i < 512; i++)
eeprom_write_byte((EE_ADDR)i, 0xFF);
#endif
}
break;
}
}
if( telemetry_link )
return 10000;
// [0] = page<<4|line number
// line=0: VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_PATCH_LEVEL, Channel order:RUDDER<<6|THROTTLE<<4|ELEVATOR<<2|AILERON
// [1..21] = max 20 characters, any displayable chars followed by:
// 0x00 : end of line
// 0x80+len: selectable text to follow
// 0x90+len: selectable text to follow with "Are you sure?"
// 0xA0+len: not editable dec value
// 0xB0+len: editable dec value
// 0xC0+len: not editable hex value
// 0xD0+len: editable hex value
memset(&packet_in[1],0,20);
do
{
packet_in[0] = (page<<4) | line;
switch(line)
{
case 0:
packet_in[1]=VERSION_MAJOR;
packet_in[2]=VERSION_MINOR;
packet_in[3]=VERSION_REVISION;
packet_in[4]=VERSION_PATCH_LEVEL;
packet_in[5]=RUDDER<<6|THROTTLE<<4|ELEVATOR<<2|AILERON;
break;
case 1:
//Global ID
#ifndef FORCE_GLOBAL_ID
memcpy(&packet_in[1],"Global ID",9);
packet_in[10] = 0xD0 + 4;
#else
memcpy(&packet_in[1],"Fixed ID ",9);
packet_in[10] = 0xC0 + 4;
#endif
MProtocol_id_master = random_id(EEPROM_ID_OFFSET,false);
set_rx_tx_addr(MProtocol_id_master);
for(uint8_t i=0; i<4; i++)
packet_in[11+i]=rx_tx_addr[i];
break;
#if defined(STM32_BOARD) && not defined(FORCE_GLOBAL_ID)
case 2:
//Reset global ID
packet_in[1] = 0x90+9;
memcpy(&packet_in[2],"Reset GID",9);
break;
#endif
#ifdef CYRF6936_INSTALLED
case 4:
//Cyrf ID
#ifndef FORCE_CYRF_ID
memcpy(&packet_in[1],"Cyrf ID",7);
packet_in[8] = 0xD0 + 6;
CYRF_GetMfgData(&packet_in[9]);
#else
memcpy(&packet_in[1],"Fixed CID",9);
packet_in[10] = 0xC0 + 6;
CYRF_GetMfgData(&packet_in[11]);
#endif
break;
#ifndef FORCE_CYRF_ID
case 5:
//Reset Cyrf ID
packet_in[1] = 0x90+9;
memcpy(&packet_in[2],"Reset CID",9);
break;
#endif
#endif
case 7:
packet_in[1] = 0x90+13;
memcpy(&packet_in[2],"Format EEPROM",13);
break;
}
line++;
line %= 8;
}
while(packet_in[1]==0); // next line if empty
telemetry_link = 1;
return 10000;
}
void CONFIG_init()
{
}
#endif

View File

@@ -1,354 +0,0 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(MULTI_NAMES)
const char STR_FLYSKY[] ="FlySky";
const char STR_HUBSAN[] ="Hubsan";
const char STR_FRSKYD[] ="FrSky D";
const char STR_HISKY[] ="Hisky";
const char STR_V2X2[] ="V2x2";
const char STR_DSM[] ="DSM";
const char STR_DEVO[] ="Devo";
const char STR_YD717[] ="YD717";
const char STR_KN[] ="KN";
const char STR_SYMAX[] ="SymaX";
const char STR_SLT[] ="SLT";
const char STR_CX10[] ="CX10";
const char STR_CG023[] ="CG023";
const char STR_BAYANG[] ="Bayang";
const char STR_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";
const char STR_SHENQI[] ="Shenqi";
const char STR_FY326[] ="FY326";
const char STR_SFHSS[] ="SFHSS";
const char STR_J6PRO[] ="J6 Pro";
const char STR_FQ777[] ="FQ777";
const char STR_ASSAN[] ="Assan";
const char STR_FRSKYV[] ="FrSky V";
const char STR_HONTAI[] ="Hontai";
const char STR_AFHDS2A[] ="FSky 2A";
const char STR_Q2X2[] ="Q2x2";
const char STR_WK2x01[] ="Walkera";
const char STR_Q303[] ="Q303";
const char STR_GW008[] ="GW008";
const char STR_DM002[] ="DM002";
const char STR_CABELL[] ="Cabell";
const char STR_ESKY150[] ="Esky150";
const char STR_H8_3D[] ="H8 3D";
const char STR_CORONA[] ="Corona";
const char STR_CFLIE[] ="CFlie";
const char STR_HITEC[] ="Hitec";
const char STR_WFLY[] ="WFly";
const char STR_BUGS[] ="Bugs";
const char STR_BUGSMINI[] ="BugMini";
const char STR_TRAXXAS[] ="Traxxas";
const char STR_NCC1701[] ="NCC1701";
const char STR_E01X[] ="E01X";
const char STR_V911S[] ="V911S";
const char STR_GD00X[] ="GD00x";
const char STR_V761[] ="V761";
const char STR_KF606[] ="KF606";
const char STR_REDPINE[] ="Redpine";
const char STR_POTENSIC[] ="Potensi";
const char STR_ZSX[] ="ZSX";
const char STR_FLYZONE[] ="FlyZone";
const char STR_SCANNER[] ="Scanner";
const char STR_FRSKY_RX[] ="FrSkyRX";
const char STR_AFHDS2A_RX[] ="FS2A_RX";
const char STR_HOTT[] ="HoTT";
const char STR_FX816[] ="FX816";
const char STR_BAYANG_RX[] ="BayanRX";
const char STR_PELIKAN[] ="Pelikan";
const char STR_TIGER[] ="Tiger";
const char STR_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_SUBTYPE_FLYSKY[] = "\x04""Std\0""V9x9""V6x6""V912""CX20";
const char STR_SUBTYPE_HUBSAN[] = "\x04""H107""H301""H501";
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";
const char STR_SUBTYPE_HISKY[] = "\x05""Std\0 ""HK310";
const char STR_SUBTYPE_V2X2[] = "\x06""Std\0 ""JXD506";
const char STR_SUBTYPE_DSM[] = "\x06""2 22ms""2 11ms""X 22ms""X 11ms";
const char STR_SUBTYPE_DEVO[] = "\x04""8ch\0""10ch""12ch""6ch\0""7ch\0";
const char STR_SUBTYPE_YD717[] = "\x07""Std\0 ""SkyWlkr""Syma X4""XINXUN\0""NIHUI\0 ";
const char STR_SUBTYPE_KN[] = "\x06""WLtoys""FeiLun";
const char STR_SUBTYPE_SYMAX[] = "\x03""Std""X5C";
const char STR_SUBTYPE_SLT[] = "\x06""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0";
const char STR_SUBTYPE_CX10[] = "\x07""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041";
const char STR_SUBTYPE_CG023[] = "\x05""Std\0 ""YD829";
const char STR_SUBTYPE_BAYANG[] = "\x07""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4";
const char STR_SUBTYPE_MT99[] = "\x06""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805";
const char STR_SUBTYPE_MJXQ[] = "\x07""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix";
const char STR_SUBTYPE_FY326[] = "\x05""Std\0 ""FY319";
const char STR_SUBTYPE_HONTAI[] = "\x07""Std\0 ""JJRC X1""X5C1\0 ""FQ_951";
const char STR_SUBTYPE_AFHDS2A[] = "\x08""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS";
const char STR_SUBTYPE_Q2X2[] = "\x04""Q222""Q242""Q282";
const char STR_SUBTYPE_WK2x01[] = "\x06""WK2801""WK2401""W6_5_1""W6_6_1""W6_HeL""W6_HeI";
const char STR_SUBTYPE_Q303[] = "\x06""Std\0 ""CX35\0 ""CX10D\0""CX10WD";
const char STR_SUBTYPE_CABELL[] = "\x07""V3\0 ""V3 Telm""-\0 ""-\0 ""-\0 ""-\0 ""F-Safe\0""Unbind\0";
const char STR_SUBTYPE_H83D[] = "\x07""Std\0 ""H20H\0 ""H20Mini""H30Mini";
const char STR_SUBTYPE_CORONA[] = "\x05""V1\0 ""V2\0 ""FD V3";
const char STR_SUBTYPE_HITEC[] = "\x07""Optima\0""Opt Hub""Minima\0";
const char STR_SUBTYPE_BUGS_MINI[] = "\x06""Std\0 ""Bugs3H";
const char STR_SUBTYPE_TRAXXAS[] = "\x04""6519";
const char STR_SUBTYPE_E01X[] = "\x05""E012\0""E015\0""E016H";
const char STR_SUBTYPE_GD00X[] = "\x05""GD_V1""GD_V2";
const char STR_SUBTYPE_REDPINE[] = "\x04""Fast""Slow";
const char STR_SUBTYPE_POTENSIC[] = "\x03""A20";
const char STR_SUBTYPE_ZSX[] = "\x07""280JJRC";
const char STR_SUBTYPE_FLYZONE[] = "\x05""FZ410";
const char STR_SUBTYPE_FX816[] = "\x03""P38";
const char STR_SUBTYPE_XN297DUMP[] = "\x07""250Kbps""1Mbps\0 ""2Mbps\0 ""Auto\0 ";
const char STR_SUBTYPE_ESKY150[] = "\x03""4CH""7CH";
const char STR_SUBTYPE_V911S[] = "\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";
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";
enum
{
OPTION_NONE,
OPTION_OPTION,
OPTION_RFTUNE,
OPTION_VIDFREQ,
OPTION_FIXEDID,
OPTION_TELEM,
OPTION_SRVFREQ,
OPTION_MAXTHR,
OPTION_RFCHAN
};
#define NO_SUBTYPE nullptr
const mm_protocol_definition multi_protocols[] = {
// Protocol number, Protocol String, Number of sub_protocols, Sub_protocol strings, Option type
#if defined(ASSAN_NRF24L01_INO)
{PROTO_ASSAN, STR_ASSAN, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(BAYANG_NRF24L01_INO)
{PROTO_BAYANG, STR_BAYANG, 5, 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(E01X_NRF24L01_INO)
{PROTO_E01X, STR_E01X, 3, STR_SUBTYPE_E01X, OPTION_OPTION },
#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, 4, STR_SUBTYPE_DSM, OPTION_MAXTHR },
#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(FLYSKY_A7105_INO)
{PROTO_FLYSKY, STR_FLYSKY, 5, STR_SUBTYPE_FLYSKY, OPTION_NONE },
#endif
#if defined(AFHDS2A_A7105_INO)
{PROTO_AFHDS2A, STR_AFHDS2A, 4, 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(FLYZONE_A7105_INO)
{PROTO_FLYZONE, STR_FLYZONE, 1, STR_SUBTYPE_FLYZONE, 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, 5, STR_SUBTYPE_FRSKYX, OPTION_RFTUNE },
{PROTO_FRSKYX2, STR_FRSKYX2, 5, 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, 4, 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, 0, NO_SUBTYPE, 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(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(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 , 0, NO_SUBTYPE, 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, 4, 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(REDPINE_CC2500_INO)
{PROTO_REDPINE, STR_REDPINE, 2, STR_SUBTYPE_REDPINE, 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_NONE },
#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, 2, STR_SUBTYPE_V2X2, OPTION_NONE },
#endif
#if defined(V761_NRF24L01_INO)
{PROTO_V761, STR_V761, 0, NO_SUBTYPE, OPTION_NONE },
#endif
#if defined(V911S_NRF24L01_INO)
{PROTO_V911S, STR_V911S, 2, STR_SUBTYPE_V911S, OPTION_RFTUNE },
#endif
#if defined(WFLY_CYRF6936_INO)
{PROTO_WFLY, STR_WFLY, 1, STR_SUBTYPE_WFLY, OPTION_NONE },
#endif
#if defined(WK2x01_CYRF6936_INO)
{PROTO_WK2x01, STR_WK2x01, 6, STR_SUBTYPE_WK2x01, 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, 4, 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
{0x00, nullptr, 0, nullptr, 0 }
};
#endif

View File

@@ -0,0 +1,633 @@
/*
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/>.
*/
const char STR_FLYSKY[] ="FlySky";
const char STR_HUBSAN[] ="Hubsan";
const char STR_FRSKYD[] ="FrSky D";
const char STR_HISKY[] ="Hisky";
const char STR_V2X2[] ="V2x2";
const char STR_DSM[] ="DSM";
const char STR_DSM_RX[] ="DSM_RX";
const char STR_DEVO[] ="Devo";
const char STR_YD717[] ="YD717";
const char STR_KN[] ="KN";
const char STR_SYMAX[] ="SymaX";
const char STR_SLT[] ="SLT";
const char STR_CX10[] ="CX10";
const char STR_CG023[] ="CG023";
const char STR_BAYANG[] ="Bayang";
const char STR_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_MT99XX2[] ="MT99XX2";
const char STR_MJXQ[] ="MJXq";
const char STR_SHENQI[] ="Shenqi";
const char STR_SHENQI2[] ="Shenqi2";
const char STR_FY326[] ="FY326";
const char STR_FUTABA[] ="Futaba";
const char STR_J6PRO[] ="J6 Pro";
const char STR_JJRC345[] ="JJRC345";
const char STR_JOYSWAY[] ="JOYSWAY";
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[] ="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_H36[] ="H36";
const char STR_H8_3D[] ="H8 3D";
const char STR_CORONA[] ="Corona";
const char STR_CFLIE[] ="CFlie";
const char STR_HITEC[] ="Hitec";
const char STR_WFLY[] ="WFLY";
const char STR_WFLY2[] ="WFLY2";
const char STR_BUGS[] ="Bugs";
const char STR_BUGSMINI[] ="BugMini";
const char STR_TRAXXAS[] ="Traxxas";
const char STR_NCC1701[] ="NCC1701";
const char STR_E01X[] ="E01X";
const char STR_V911S[] ="V911S";
const char STR_GD00X[] ="GD00x";
const char STR_V761[] ="V761";
const char STR_KF606[] ="KF606";
const char STR_REDPINE[] ="Redpine";
const char STR_POTENSIC[] ="Potensi";
const char STR_ZSX[] ="ZSX";
const char STR_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_FX[] ="FX";
const char STR_BAYANG_RX[] ="BayanRX";
const char STR_PELIKAN[] ="Pelikan";
const char STR_XK[] ="XK";
const char STR_XK2[] ="XK2";
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_KYOSHO2[] ="Kyosho2";
const char STR_RLINK[] ="RadLink";
const char STR_REALACC[] ="Realacc";
const char STR_OMP[] ="OMP";
const char STR_MLINK[] ="M-Link";
const char STR_TEST[] ="Test";
const char STR_NANORF[] ="NanoRF";
const char STR_E016HV2[] ="E016Hv2";
const char STR_E010R5[] ="E010r5";
const char STR_LOLI[] ="LOLI";
const char STR_E129[] ="E129";
const char STR_E016H[] ="E016H";
const char STR_IKEAANSLUTA[]="Ansluta";
const char STR_CONFIG[] ="Config";
const char STR_LOSI[] ="Losi";
const char STR_MOULDKG[] ="MouldKg";
const char STR_XERALL[] ="Xerall";
const char STR_SCORPIO[] ="Scorpio";
const char STR_BLUEFLY[] ="BlueFly";
const char STR_BUMBLEB[] ="BumbleB";
const char STR_SGF22[] ="SGF22";
const char STR_EAZYRC[] ="EazyRC";
const char STR_KYOSHO3[] ="Kyosho3";
const char STR_YUXIANG[] ="YuXiang";
const char STR_UDIRC[] ="UDIRC";
const char STR_JIABAILE[] ="JIABAILE";
const char STR_KAMTOM[] ="KAMTOM";
const char STR_WL91X[] ="WL91x";
const char STR_WPL[] ="WPL";
const char STR_ARES[] ="ARES";
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_FRSKYD[] = "\x06""D8\0 ""Cloned";
#ifndef MULTI_EU
const char STR_SUBTYPE_FRSKYX[] = "\x07""D16\0 ""D16 8ch""LBT(EU)""LBT 8ch""Cloned\0""Clo 8ch";
#else
const char STR_SUBTYPE_FRSKYX[] = "\x07""--->\0 ""--->\0 ""LBT(EU)""LBT 8ch""Cloned\0""Clo 8ch";
#endif
const char STR_SUBTYPE_HISKY[] = "\x05""Std\0 ""HK310";
const char STR_SUBTYPE_V2X2[] = "\x06""Std\0 ""JXD506""MR101\0";
#ifndef MULTI_EU
const char STR_SUBTYPE_DSM[] = "\x04""2 1F""2 2F""X 1F""X 2F""Auto""R 1F""2SFC";
#else
const char STR_SUBTYPE_DSM[] = "\x04""--->""--->""X 1F""X 2F""Auto""R 1F""----";
#endif
const char STR_SUBTYPE_DEVO[] = "\x04""8ch\0""10ch""12ch""6ch\0""7ch\0";
const char STR_SUBTYPE_YD717[] = "\x07""Std\0 ""SkyWlkr""Syma X4""XINXUN\0""NIHUI\0 ";
const char STR_SUBTYPE_KN[] = "\x06""WLtoys""FeiLun";
const char STR_SUBTYPE_SYMAX[] = "\x03""Std""X5C";
const char STR_SUBTYPE_SLT[] = "\x06""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0""V1_4ch""RF_SIM""SLT6TX";
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\0""QX100\0 ";
const char STR_SUBTYPE_MT99[] = "\x06""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805\0""A180\0 ""Dragon""F949G\0";
const char STR_SUBTYPE_MT992[] = "\x04""PA18""SU35";
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_FQ777[] = "\x05""124\0 ""XBM37";
const char STR_SUBTYPE_HONTAI[] = "\x06""Std\0 ""JJRCX1""X5C1\0 ""FQ_951""XKK170";
const char STR_SUBTYPE_AFHDS2A[] = "\x08""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS""Gyro_Off""Gyro_On\0""G_On_Rev";
const char STR_SUBTYPE_Q2X2[] = "\x04""Q222""Q242""Q282";
const char STR_SUBTYPE_WK2x01[] = "\x06""WK2801""WK2401""W6_5_1""W6_6_1""W6_HeL""W6_HeI";
const char STR_SUBTYPE_Q303[] = "\x06""Std\0 ""CX35\0 ""CX10D\0""CX10WD";
const char STR_SUBTYPE_CABELL[] = "\x07""V3\0 ""V3 Telm""-\0 ""-\0 ""-\0 ""-\0 ""F-Safe\0""Unbind\0";
const char STR_SUBTYPE_H83D[] = "\x07""Std\0 ""H20H\0 ""H20Mini""H30Mini";
const char STR_SUBTYPE_CORONA[] = "\x05""V1\0 ""V2\0 ""FD V3";
const char STR_SUBTYPE_HITEC[] = "\x07""Optima\0""Opt Hub""Minima\0";
const char STR_SUBTYPE_BUGS_MINI[] = "\x06""Std\0 ""Bugs3H";
const char STR_SUBTYPE_TRAXXAS[] = "\x03""TQ2""TQ1";
const char STR_SUBTYPE_E01X[] = "\x05""E012\0""E015\0";
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_HEIGHT[] = "\x03""5ch""8ch";
const char STR_SUBTYPE_XN297DUMP[] = "\x07""250Kbps""1Mbps\0 ""2Mbps\0 ""Auto\0 ""NRF\0 ""CC2500\0""XN297\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""Cars";
const char STR_SUBTYPE_XK2[] = "\x03""X4\0""P10";
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_FRSKYL[] = "\x08""LR12\0 ""LR12 6ch";
const char STR_SUBTYPE_WFLY[] = "\x05""WFR0x";
const char STR_SUBTYPE_WFLY2[] = "\x05""RF20x";
const char STR_SUBTYPE_HOTT[] = "\x07""Sync\0 ""No_Sync";
const char STR_SUBTYPE_PELIKAN[] = "\x05""Pro\0 ""Lite\0""SCX24";
const char STR_SUBTYPE_V761[] = "\x05""3ch\0 ""4ch\0 ""TOPRC";
const char STR_SUBTYPE_RLINK[] = "\x07""Surface""Air\0 ""DumboRC""RC4G\0 ""Dumbo_P";
const char STR_SUBTYPE_REALACC[] = "\x06""R11\0 ""WLV8TX";
const char STR_SUBTYPE_KYOSHO[] = "\x04""FHSS""Hype";
const char STR_SUBTYPE_KYOSHO2[] = "\x05""KT-17";
const char STR_SUBTYPE_KYOSHO3[] = "\x03""ASF";
const char STR_SUBTYPE_FUTABA[] = "\x05""SFHSS";
const char STR_SUBTYPE_JJRC345[] = "\x08""JJRC345\0""SkyTmblr";
const char STR_SUBTYPE_MOULDKG[] = "\x05""A4444""D4444""A664\0";
const char STR_SUBTYPE_KF606[] = "\x06""KF606\0""MIG320""ZCZ50\0";
const char STR_SUBTYPE_E129[] = "\x04""E129""C186";
const char STR_SUBTYPE_FX[] = "\x05""FX816""FX620""9630\0""Q560\0""QF012""BM26\0""A570\0";
const char STR_SUBTYPE_SGF22[] = "\x04""F22\0""F22S""J20\0""CX10";
const char STR_SUBTYPE_JIABAILE[] = "\x04""Std\0""Gyro";
#define NO_SUBTYPE nullptr
#ifdef SEND_CPPM
const char STR_SUB_FRSKY_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX""CPPM\0 ";
const char STR_SUB_DSM_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX""CPPM\0 ";
#define FRCPPM 4
#define DSMCPPM 4
const char STR_CPPM[] = "\x05""Multi""CPPM\0";
#define NBR_CPPM 2
#else
const char STR_SUB_FRSKY_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX";
const char STR_SUB_DSM_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX";
#define FRCPPM 3
#define DSMCPPM 3
#define STR_CPPM NO_SUBTYPE
#define NBR_CPPM 0
#endif
enum
{
OPTION_NONE,
OPTION_OPTION,
OPTION_RFTUNE,
OPTION_VIDFREQ,
OPTION_FIXEDID,
OPTION_TELEM,
OPTION_SRVFREQ,
OPTION_MAXTHR,
OPTION_RFCHAN,
OPTION_RFPOWER,
OPTION_WBUS,
};
const mm_protocol_definition multi_protocols[] = {
// Protocol number, Protocol String, Sub_protocol strings, Number of sub_protocols, Option type, Failsafe, ChMap, RF switch, Init, Callback
#if defined(MULTI_CONFIG_INO)
{PROTO_CONFIG, STR_CONFIG, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, 0, CONFIG_init, CONFIG_callback },
#endif
#if defined(ARES_CC2500_INO)
{PROTO_ARES, STR_ARES, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_CC2500, ARES_init, ARES_callback },
#endif
#if defined(ASSAN_NRF24L01_INO)
{PROTO_ASSAN, STR_ASSAN, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, ASSAN_init, ASSAN_callback },
#endif
#if defined(BAYANG_NRF24L01_INO)
{PROTO_BAYANG, STR_BAYANG, STR_SUBTYPE_BAYANG, 6, OPTION_TELEM, 0, 0, SW_NRF, BAYANG_init, BAYANG_callback },
#endif
#if defined(BAYANG_RX_NRF24L01_INO)
{PROTO_BAYANG_RX, STR_BAYANG_RX, STR_CPPM, NBR_CPPM, OPTION_NONE, 0, 0, SW_NRF, BAYANG_RX_init, BAYANG_RX_callback },
#endif
#if defined(BLUEFLY_CCNRF_INO)
{PROTO_BLUEFLY, STR_BLUEFLY, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, BLUEFLY_init, BLUEFLY_callback },
#endif
#if defined(BUMBLEB_CCNRF_INO)
{PROTO_BUMBLEB, STR_BUMBLEB, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, BUMBLEB_init, BUMBLEB_callback },
#endif
#if defined(BUGS_A7105_INO)
{PROTO_BUGS, STR_BUGS, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_A7105, BUGS_init, BUGS_callback },
#endif
#if defined(BUGSMINI_NRF24L01_INO)
{PROTO_BUGSMINI, STR_BUGSMINI, STR_SUBTYPE_BUGS_MINI, 2, OPTION_NONE, 0, 0, SW_NRF, BUGSMINI_init, BUGSMINI_callback },
#endif
#if defined(CABELL_NRF24L01_INO)
{PROTO_CABELL, STR_CABELL, STR_SUBTYPE_CABELL, 8, OPTION_OPTION, 0, 0, SW_NRF, CABELL_init, CABELL_callback },
#endif
#if defined(CFLIE_NRF24L01_INO)
{PROTO_CFLIE, STR_CFLIE, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, CFLIE_init, CFLIE_callback }, // review protocol
#endif
#if defined(CG023_NRF24L01_INO)
{PROTO_CG023, STR_CG023, STR_SUBTYPE_CG023, 2, OPTION_NONE, 0, 0, SW_NRF, CG023_init, CG023_callback },
#endif
#if defined(CORONA_CC2500_INO)
{PROTO_CORONA, STR_CORONA, STR_SUBTYPE_CORONA, 3, OPTION_RFTUNE, 0, 0, SW_CC2500, CORONA_init, CORONA_callback },
#endif
#if defined(CX10_NRF24L01_INO)
{PROTO_CX10, STR_CX10, STR_SUBTYPE_CX10, 7, OPTION_NONE, 0, 0, SW_NRF, CX10_init, CX10_callback },
#endif
#if defined(DEVO_CYRF6936_INO)
{PROTO_DEVO, STR_DEVO, STR_SUBTYPE_DEVO, 5, OPTION_FIXEDID, 1, 1, SW_CYRF, DEVO_init, DEVO_callback },
#endif
#if defined(DM002_NRF24L01_INO)
{PROTO_DM002, STR_DM002, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, DM002_init, DM002_callback },
#endif
#if defined(DSM_CYRF6936_INO)
{PROTO_DSM, STR_DSM, STR_SUBTYPE_DSM, 7, OPTION_MAXTHR, 0, 1, SW_CYRF, DSM_init, DSM_callback },
#endif
#if defined(DSM_RX_CYRF6936_INO)
{PROTO_DSM_RX, STR_DSM_RX, STR_SUB_DSM_RX, DSMCPPM, OPTION_NONE, 0, 1, SW_CYRF, DSM_RX_init, DSM_RX_callback },
#endif
#if defined(E010R5_CYRF6936_INO)
{PROTO_E010R5, STR_E010R5, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CYRF, E010R5_init, E010R5_callback },
#endif
#if defined(E016H_NRF24L01_INO)
{PROTO_E016H, STR_E016H, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, E016H_init, E016H_callback },
#endif
#if defined(E016HV2_CC2500_INO)
{PROTO_E016HV2, STR_E016HV2, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_CC2500, E016HV2_init, E016HV2_callback },
#endif
#if defined(E01X_CYRF6936_INO)
{PROTO_E01X, STR_E01X, STR_SUBTYPE_E01X, 2, OPTION_NONE, 0, 0, SW_CYRF, E01X_init, E01X_callback },
#endif
#if defined(E129_CYRF6936_INO)
{PROTO_E129, STR_E129, STR_SUBTYPE_E129, 2, OPTION_NONE, 0, 0, SW_CYRF, E129_init, E129_callback },
#endif
#if defined(EAZYRC_NRF24L01_INO)
{PROTO_EAZYRC, STR_EAZYRC, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, EAZYRC_init, EAZYRC_callback },
#endif
#if defined(ESKY_NRF24L01_INO)
{PROTO_ESKY, STR_ESKY, STR_SUBTYPE_ESKY, 2, OPTION_NONE, 0, 1, SW_NRF, ESKY_init, ESKY_callback },
#endif
#if defined(ESKY150_NRF24L01_INO)
{PROTO_ESKY150, STR_ESKY150, STR_SUBTYPE_ESKY150, 2, OPTION_NONE, 0, 0, SW_NRF, ESKY150_init, ESKY150_callback },
#endif
#if defined(ESKY150V2_CC2500_INO)
{PROTO_ESKY150V2, STR_ESKY150V2, STR_SUBTYPE_ESKY150V2, 1, OPTION_RFTUNE, 0, 1, SW_CC2500, ESKY150V2_init, ESKY150V2_callback },
#endif
#if defined(FLYSKY_A7105_INO)
{PROTO_FLYSKY, STR_FLYSKY, STR_SUBTYPE_FLYSKY, 5, OPTION_NONE, 0, 1, SW_A7105, FLYSKY_init, FLYSKY_callback },
#endif
#if defined(AFHDS2A_A7105_INO)
{PROTO_AFHDS2A, STR_AFHDS2A, STR_SUBTYPE_AFHDS2A, 7, OPTION_SRVFREQ, 1, 1, SW_A7105, AFHDS2A_init, AFHDS2A_callback },
#endif
#if defined(AFHDS2A_RX_A7105_INO)
{PROTO_AFHDS2A_RX, STR_AFHDS2A_RX,STR_CPPM, NBR_CPPM, OPTION_NONE, 0, 0, SW_A7105, AFHDS2A_RX_init, AFHDS2A_RX_callback },
#endif
#if defined(FQ777_NRF24L01_INO)
{PROTO_FQ777, STR_FQ777, STR_SUBTYPE_FQ777, 2, OPTION_NONE, 0, 0, SW_NRF, FQ777_init, FQ777_callback },
#endif
//OpenTX 2.3.x issue: DO NOT CHANGE ORDER below
#if defined(FRSKY_RX_CC2500_INO)
{PROTO_FRSKY_RX, STR_FRSKY_RX, STR_SUB_FRSKY_RX, FRCPPM, OPTION_RFTUNE, 0, 0, SW_CC2500, FRSKY_RX_init, FRSKY_RX_callback },
#endif
#if defined(FRSKYD_CC2500_INO)
{PROTO_FRSKYD, STR_FRSKYD, STR_SUBTYPE_FRSKYD, 2, OPTION_RFTUNE, 0, 0, SW_CC2500, FRSKYD_init, FRSKYD_callback },
#endif
#if defined(FRSKYV_CC2500_INO)
{PROTO_FRSKYV, STR_FRSKYV, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_CC2500, FRSKYV_init, FRSKYV_callback },
#endif
#if defined(FRSKYX_CC2500_INO)
{PROTO_FRSKYX, STR_FRSKYX, STR_SUBTYPE_FRSKYX, 6, OPTION_RFTUNE, 1, 0, SW_CC2500, FRSKYX_init, FRSKYX_callback },
{PROTO_FRSKYX2, STR_FRSKYX2, STR_SUBTYPE_FRSKYX, 6, OPTION_RFTUNE, 1, 0, SW_CC2500, FRSKYX_init, FRSKYX_callback },
#endif
//OpenTX 2.3.x issue: DO NOT CHANGE ORDER above
#if defined(FRSKYL_CC2500_INO)
{PROTO_FRSKYL, STR_FRSKYL, STR_SUBTYPE_FRSKYL, 2, OPTION_RFTUNE, 0, 0, SW_CC2500, FRSKYL_init, FRSKYL_callback },
#endif
#if defined(FRSKYR9_SX1276_INO)
#if MULTI_5IN1_INTERNAL == T18
{PROTO_FRSKY_R9, STR_FRSKYR9, STR_SUBTYPE_FRSKYR9, 8, OPTION_NONE, 1, 0, 0, FRSKYR9_init, FRSKYR9_callback },
#else // DIY & T-Lite
{PROTO_FRSKY_R9, STR_FRSKYR9, STR_SUBTYPE_FRSKYR9, 8, OPTION_RFPOWER, 1, 0, 0, FRSKYR9_init, FRSKYR9_callback },
#endif
#endif
#if defined(FUTABA_CC2500_INO)
{PROTO_FUTABA, STR_FUTABA, STR_SUBTYPE_FUTABA, 1, OPTION_RFTUNE, 1, 1, SW_CC2500, SFHSS_init, SFHSS_callback },
#endif
#if defined(FX_NRF24L01_INO)
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 7, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
#endif
#if defined(FY326_NRF24L01_INO)
{PROTO_FY326, STR_FY326, STR_SUBTYPE_FY326, 2, OPTION_NONE, 0, 0, SW_NRF, FY326_init, FY326_callback },
#endif
#if defined(GD00X_CCNRF_INO)
{PROTO_GD00X, STR_GD00X, STR_SUBTYPE_GD00X, 2, OPTION_RFTUNE, 0, 0, SW_NRF, GD00X_init, GD00X_callback },
#endif
#if defined(GW008_NRF24L01_INO)
{PROTO_GW008, STR_GW008, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, GW008_init, GW008_callback },
#endif
#if defined(H36_NRF24L01_INO)
{PROTO_H36, STR_H36, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, H36_init, H36_callback },
#endif
#if defined(H8_3D_NRF24L01_INO)
{PROTO_H8_3D, STR_H8_3D, STR_SUBTYPE_H83D, 4, OPTION_NONE, 0, 0, SW_NRF, H8_3D_init, H8_3D_callback },
#endif
#if defined(HEIGHT_A7105_INO)
{PROTO_HEIGHT, STR_HEIGHT, STR_SUBTYPE_HEIGHT, 2, OPTION_NONE, 0, 0, SW_A7105, HEIGHT_init, HEIGHT_callback },
#endif
#if defined(HISKY_NRF24L01_INO)
{PROTO_HISKY, STR_HISKY, STR_SUBTYPE_HISKY, 2, OPTION_NONE, 1, 1, SW_NRF, HISKY_init, HISKY_callback },
#endif
#if defined(HITEC_CC2500_INO)
{PROTO_HITEC, STR_HITEC, STR_SUBTYPE_HITEC, 3, OPTION_RFTUNE, 0, 0, SW_CC2500, HITEC_init, HITEC_callback },
#endif
#if defined(HONTAI_NRF24L01_INO)
{PROTO_HONTAI, STR_HONTAI, STR_SUBTYPE_HONTAI, 5, OPTION_NONE, 0, 0, SW_NRF, HONTAI_init, HONTAI_callback },
#endif
#if defined(HOTT_CC2500_INO)
{PROTO_HOTT, STR_HOTT, STR_SUBTYPE_HOTT, 2, OPTION_RFTUNE, 1, 0, SW_CC2500, HOTT_init, HOTT_callback },
#endif
#if defined(HUBSAN_A7105_INO)
{PROTO_HUBSAN, STR_HUBSAN, STR_SUBTYPE_HUBSAN, 3, OPTION_VIDFREQ, 0, 0, SW_A7105, HUBSAN_init, HUBSAN_callback },
#endif
#if defined(IKEAANSLUTA_CC2500_INO)
{PROTO_IKEAANSLUTA,STR_IKEAANSLUTA,NO_SUBTYPE, 0, OPTION_OPTION, 0, 0, SW_CC2500, IKEAANSLUTA_init,IKEAANSLUTA_callback },
#endif
#if defined(J6PRO_CYRF6936_INO)
{PROTO_J6PRO, STR_J6PRO, NO_SUBTYPE, 0, OPTION_NONE, 0, 1, SW_CYRF, J6PRO_init, J6PRO_callback },
#endif
#if defined(JIABAILE_NRF24L01_INO)
{PROTO_JIABAILE, STR_JIABAILE, STR_SUBTYPE_JIABAILE, 2, OPTION_NONE, 0, 0, SW_NRF, JIABAILE_init, JIABAILE_callback },
#endif
#if defined(JJRC345_NRF24L01_INO)
{PROTO_JJRC345, STR_JJRC345, STR_SUBTYPE_JJRC345, 2, OPTION_NONE, 0, 0, SW_NRF, JJRC345_init, JJRC345_callback },
#endif
#if defined(JOYSWAY_A7105_INO)
{PROTO_JOYSWAY, STR_JOYSWAY, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_A7105, JOYSWAY_init, JOYSWAY_callback },
#endif
#if defined(KAMTOM_NRF24L01_INO)
{PROTO_KAMTOM, STR_KAMTOM, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, KAMTOM_init, KAMTOM_callback },
#endif
#if defined(KF606_CCNRF_INO)
{PROTO_KF606, STR_KF606, STR_SUBTYPE_KF606, 3, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback },
#endif
#if defined(KN_NRF24L01_INO)
{PROTO_KN, STR_KN, STR_SUBTYPE_KN, 2, OPTION_NONE, 0, 0, SW_NRF, KN_init, KN_callback },
#endif
#if defined(KYOSHO_A7105_INO)
{PROTO_KYOSHO, STR_KYOSHO, STR_SUBTYPE_KYOSHO, 2, OPTION_NONE, 0, 1, SW_A7105, KYOSHO_init, KYOSHO_callback },
#endif
#if defined(KYOSHO2_NRF24L01_INO)
{PROTO_KYOSHO2, STR_KYOSHO2, STR_SUBTYPE_KYOSHO2, 1, OPTION_NONE, 0, 0, SW_NRF, KYOSHO2_init, KYOSHO2_callback },
#endif
#if defined(KYOSHO3_CYRF6936_INO)
{PROTO_KYOSHO3, STR_KYOSHO3, STR_SUBTYPE_KYOSHO3, 1, OPTION_NONE, 0, 0, SW_CYRF, KYOSHO3_init, KYOSHO3_callback },
#endif
#if defined(LOLI_NRF24L01_INO)
{PROTO_LOLI, STR_LOLI, NO_SUBTYPE, 0, OPTION_NONE, 1, 0, SW_NRF, LOLI_init, LOLI_callback },
#endif
#if defined(LOSI_CYRF6936_INO)
{PROTO_LOSI, STR_LOSI, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CYRF, LOSI_init, LOSI_callback },
#endif
#if defined(MJXQ_CCNRF_INO)
{PROTO_MJXQ, STR_MJXQ, STR_SUBTYPE_MJXQ, 7, OPTION_NONE, 0, 0, SW_NRF, MJXQ_init, MJXQ_callback },
#endif
#if defined(MLINK_CYRF6936_INO)
{PROTO_MLINK, STR_MLINK, NO_SUBTYPE, 0, OPTION_NONE, 1, 0, SW_CYRF, MLINK_init, MLINK_callback },
#endif
#if defined(MOULDKG_NRF24L01_INO)
{PROTO_MOULDKG, STR_MOULDKG, STR_SUBTYPE_MOULDKG, 3, OPTION_OPTION, 0, 0, SW_NRF, MOULDKG_init, MOULDKG_callback },
#endif
#if defined(MT99XX_CCNRF_INO)
{PROTO_MT99XX, STR_MT99XX, STR_SUBTYPE_MT99, 8, OPTION_NONE, 0, 0, SW_NRF, MT99XX_init, MT99XX_callback },
#endif
#if defined(MT99XX_CCNRF_INO)
{PROTO_MT99XX2, STR_MT99XX2, STR_SUBTYPE_MT992, 2, OPTION_NONE, 0, 0, SW_NRF, MT99XX_init, MT99XX_callback },
#endif
#if defined(NCC1701_NRF24L01_INO)
{PROTO_NCC1701, STR_NCC1701, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, NCC_init, NCC_callback },
#endif
#if defined(OMP_CCNRF_INO)
{PROTO_OMP, STR_OMP, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, OMP_init, OMP_callback },
#endif
#if defined(PELIKAN_A7105_INO)
{PROTO_PELIKAN, STR_PELIKAN, STR_SUBTYPE_PELIKAN, 3, OPTION_NONE, 0, 1, SW_A7105, PELIKAN_init, PELIKAN_callback },
#endif
#if defined(POTENSIC_NRF24L01_INO)
{PROTO_POTENSIC, STR_POTENSIC, STR_SUBTYPE_POTENSIC, 1, OPTION_NONE, 0, 0, SW_NRF, POTENSIC_init, POTENSIC_callback },
#endif
#if defined(PROPEL_NRF24L01_INO)
{PROTO_PROPEL, STR_PROPEL, STR_SUBTYPE_PROPEL, 1, OPTION_NONE, 0, 0, SW_NRF, PROPEL_init, PROPEL_callback },
#endif
#if defined(CX10_NRF24L01_INO)
{PROTO_Q2X2, STR_Q2X2, STR_SUBTYPE_Q2X2, 3, OPTION_NONE, 0, 0, SW_NRF, CX10_init, CX10_callback },
#endif
#if defined(Q303_CCNRF_INO)
{PROTO_Q303, STR_Q303, STR_SUBTYPE_Q303, 4, OPTION_NONE, 0, 0, SW_NRF, Q303_init, Q303_callback },
#endif
#if defined(Q90C_CCNRF_INO)
{PROTO_Q90C, STR_Q90C, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, Q90C_init, Q90C_callback },
#endif
#if defined(RLINK_CC2500_INO)
{PROTO_RLINK, STR_RLINK, STR_SUBTYPE_RLINK, 5, OPTION_RFTUNE, 0, 0, SW_CC2500, RLINK_init, RLINK_callback },
#endif
#if defined(REALACC_NRF24L01_INO)
{PROTO_REALACC, STR_REALACC, STR_SUBTYPE_REALACC, 2, OPTION_NONE, 0, 0, SW_NRF, REALACC_init, REALACC_callback },
#endif
#if defined(REDPINE_CC2500_INO)
{PROTO_REDPINE, STR_REDPINE, STR_SUBTYPE_REDPINE, 2, OPTION_RFTUNE, 0, 0, SW_CC2500, REDPINE_init, REDPINE_callback },
#endif
#if defined(SCANNER_CC2500_INO)
{PROTO_SCANNER, STR_SCANNER, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CC2500, SCANNER_init, SCANNER_callback },
#endif
#if defined(SCORPIO_CYRF6936_INO)
{PROTO_SCORPIO, STR_SCORPIO, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CYRF, SCORPIO_init, SCORPIO_callback },
#endif
#if defined(SGF22_NRF24L01_INO)
{PROTO_SGF22, STR_SGF22, STR_SUBTYPE_SGF22, 4, OPTION_NONE, 0, 0, SW_NRF, SGF22_init, SGF22_callback },
#endif
#if defined(SHENQI_NRF24L01_INO)
{PROTO_SHENQI, STR_SHENQI, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, SHENQI_init, SHENQI_callback },
#endif
#if defined(SHENQI2_NRF24L01_INO)
{PROTO_SHENQI2, STR_SHENQI2, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, SHENQI2_init, SHENQI2_callback },
#endif
#if defined(SKYARTEC_CC2500_INO)
{PROTO_SKYARTEC, STR_SKYARTEC, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 1, SW_CC2500, SKYARTEC_init, SKYARTEC_callback },
#endif
#if defined(SLT_CCNRF_INO)
{PROTO_SLT, STR_SLT, STR_SUBTYPE_SLT, 8, OPTION_RFTUNE, 0, 1, SW_NRF, SLT_init, SLT_callback },
#endif
#if defined(SYMAX_NRF24L01_INO)
{PROTO_SYMAX, STR_SYMAX, STR_SUBTYPE_SYMAX, 2, OPTION_NONE, 0, 0, SW_NRF, SYMAX_init, SYMAX_callback },
#endif
#if defined(TRAXXAS_CYRF6936_INO)
{PROTO_TRAXXAS, STR_TRAXXAS, STR_SUBTYPE_TRAXXAS, 2, OPTION_NONE, 0, 0, SW_CYRF, TRAXXAS_init, TRAXXAS_callback },
#endif
#if defined(UDIRC_CCNRF_INO)
{PROTO_UDIRC, STR_UDIRC, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, UDIRC_init, UDIRC_callback },
#endif
#if defined(V2X2_NRF24L01_INO)
{PROTO_V2X2, STR_V2X2, STR_SUBTYPE_V2X2, 3, OPTION_NONE, 0, 0, SW_NRF, V2X2_init, V2X2_callback },
#endif
#if defined(V761_NRF24L01_INO)
{PROTO_V761, STR_V761, STR_SUBTYPE_V761, 3, OPTION_NONE, 0, 0, SW_NRF, V761_init, V761_callback },
#endif
#if defined(V911S_CCNRF_INO)
{PROTO_V911S, STR_V911S, STR_SUBTYPE_V911S, 2, OPTION_RFTUNE, 0, 0, SW_NRF, V911S_init, V911S_callback },
#endif
#if defined(WFLY_CYRF6936_INO)
{PROTO_WFLY, STR_WFLY, STR_SUBTYPE_WFLY, 1, OPTION_NONE, 1, 0, SW_CYRF, WFLY_init, WFLY_callback },
#endif
#if defined(WFLY2_A7105_INO)
{PROTO_WFLY2, STR_WFLY2, STR_SUBTYPE_WFLY2, 1, OPTION_OPTION, 1, 0, SW_A7105, WFLY2_init, WFLY2_callback },
// {PROTO_WFLY2, STR_WFLY2, STR_SUBTYPE_WFLY2, 1, OPTION_WBUS, 1, 0, SW_A7105, WFLY2_init, WFLY2_callback },// crash OpenTX...
#endif
#if defined(WK2x01_CYRF6936_INO)
{PROTO_WK2x01, STR_WK2x01, STR_SUBTYPE_WK2x01, 6, OPTION_NONE, 1, 1, SW_CYRF, WK_init, WK_callback },
#endif
#if defined(WL91X_CCNRF_INO)
{PROTO_WL91X, STR_WL91X, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, WL91X_init, WL91X_callback },
#endif
#if defined(WPL_NRF24L01_INO)
{PROTO_WPL, STR_WPL, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, WPL_init, WPL_callback },
#endif
#if defined(XERALL_NRF24L01_INO)
{PROTO_XERALL, STR_XERALL, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, XERALL_init, XERALL_callback },
#endif
#if defined(XK_CCNRF_INO)
{PROTO_XK, STR_XK, STR_SUBTYPE_XK, 3, OPTION_RFTUNE, 0, 0, SW_NRF, XK_init, XK_callback },
#endif
#if defined(XK2_CCNRF_INO)
{PROTO_XK2, STR_XK2, STR_SUBTYPE_XK2, 2, OPTION_RFTUNE, 0, 0, SW_NRF, XK2_init, XK2_callback },
#endif
#if defined(XN297DUMP_NRF24L01_INO)
{PROTO_XN297DUMP, STR_XN297DUMP, STR_SUBTYPE_XN297DUMP, 7, OPTION_RFCHAN, 0, 0, SW_NRF, XN297Dump_init, XN297Dump_callback },
#endif
#if defined(YD717_NRF24L01_INO)
{PROTO_YD717, STR_YD717, STR_SUBTYPE_YD717, 5, OPTION_NONE, 0, 0, SW_NRF, YD717_init, YD717_callback },
#endif
#if defined(YUXIANG_NRF24L01_INO)
{PROTO_YUXIANG, STR_YUXIANG, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, YUXIANG_init, YUXIANG_callback },
#endif
#if defined(ZSX_NRF24L01_INO)
{PROTO_ZSX, STR_ZSX, STR_SUBTYPE_ZSX, 1, OPTION_NONE, 0, 0, SW_NRF, ZSX_init, ZSX_callback },
#endif
#if defined(TEST_CC2500_INO)
{PROTO_TEST, STR_TEST, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, TEST_init, TEST_callback },
#endif
#if defined(NANORF_NRF24L01_INO)
{PROTO_NANORF, STR_NANORF, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, NANORF_init, NANORF_callback },
#endif
{0xFF, nullptr, nullptr, 0, 0, 0, 0, 0, nullptr, nullptr }
};
#ifdef MULTI_TELEMETRY
uint16_t PROTOLIST_callback()
{
if(option != prev_option)
{//Only send once
/* Type 0x11 Protocol list export via telemetry. Used by the protocol PROTO_PROTOLIST=0, the list entry is given by the Option field.
length: variable
data[0] = protocol number, 0xFF is an invalid list entry (Option value too large), Option == 0xFF -> number of protocols in the list
data[1..n] = protocol name null terminated
data[n+1] = flags
flags>>4 Option text number to be displayed (check multi status for description)
flags&0x01 failsafe supported
flags&0x02 Channel Map Disabled supported
data[n+2] = number of sub protocols
data[n+3] = sub protocols text length, only sent if nbr_sub != 0
data[n+4..] = sub protocol names, only sent if nbr_sub != 0
*/
prev_option = option;
if(option >= (sizeof(multi_protocols)/sizeof(mm_protocol_definition)) - 1)
{//option is above the end of the list
//Header
multi_send_header(MULTI_TELEMETRY_PROTO, 1);
if(option == 0xFF)
Serial_write((sizeof(multi_protocols)/sizeof(mm_protocol_definition)) - 1); //Nbr proto
else
Serial_write(0xFF); //Error
}
else
{//valid option value
uint8_t proto_len = strlen(multi_protocols[option].ProtoString) + 1;
uint8_t nbr_sub = multi_protocols[option].nbrSubProto;
uint8_t sub_len = 0;
if(nbr_sub)
sub_len = multi_protocols[option].SubProtoString[0];
//Header
multi_send_header(MULTI_TELEMETRY_PROTO, 1 + proto_len + 1 + 1 + (nbr_sub?1:0) + (nbr_sub * sub_len));
//Protocol number
Serial_write(multi_protocols[option].protocol);
//Protocol name
for(uint8_t i=0;i<proto_len;i++)
{
Serial_write(multi_protocols[option].ProtoString[i]);
//debug("%c",multi_protocols[option].ProtoString[i]);
}
//Flags
uint8_t flags=0;
#ifdef FAILSAFE_ENABLE
if(multi_protocols[option].failSafe)
flags |= 0x01; //Failsafe supported
#endif
if(multi_protocols[option].chMap)
flags |= 0x02; //Disable_ch_mapping supported
Serial_write( flags | (multi_protocols[option].optionType<<4)); // flags && option type
//debug(" Flag=%02X",flags | (multi_protocols[option].optionType<<4));
//Number of sub protocols
Serial_write(nbr_sub);
//debug(" NSub=%02X ",nbr_sub);
if(nbr_sub !=0 )
{//Sub protocols length and texts
for(uint8_t i=0;i<=nbr_sub*sub_len;i++)
{
Serial_write(multi_protocols[option].SubProtoString[i]);
//debug("%c",multi_protocols[option].SubProtoString[i]);
}
}
//debugln("");
}
}
return 1000;
}
#endif

Some files were not shown because too many files have changed in this diff Show More