Compare commits

...

320 Commits

Author SHA1 Message Date
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
173 changed files with 120549 additions and 2417 deletions

View File

@ -1,6 +1,6 @@
# Workflow for testing MULTI-Module firmware builds
name: CI
name: MULTI Test, Build, Deploy, Release
on:
# Trigger the workflow on pushes, except those that are tagged (avoids double-testing releases)
@ -32,33 +32,45 @@ on:
workflow_dispatch:
jobs:
build:
test:
runs-on: ubuntu-latest
# Configure the board matrix
strategy:
fail-fast: false
matrix:
board: [
"multi4in1:avr:multiatmega328p:bootloader=none",
"multi4in1:avr:multiatmega328p:bootloader=optiboot",
"multi4in1:avr:multixmega32d4",
"multi4in1:STM32F1:multi5in1t18int",
"multi4in1:STM32F1:multistm32f103cb:debug_option=none",
"multi4in1:STM32F1:multistm32f103cb:debug_option=native",
"multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi",
"multi4in1:STM32F1:multistm32f103c8:debug_option=none"
]
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@v2
- uses: actions/checkout@v4
- name: Install Arduino CLI
uses: arduino/setup-arduino-cli@v1.1.1
uses: arduino/setup-arduino-cli@v2
with:
version: "0.32.2"
- name: Prepare build environment
run: |
@ -67,15 +79,22 @@ jobs:
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
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" =~ "multi4in1:avr:" ]]; then
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:STM32F1:" ]]; then
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
@ -109,18 +128,18 @@ jobs:
echo "ALL_RFMODULES=$(echo $ALL_RFMODULES)" >> $GITHUB_ENV
# Disable CHECK_FOR_BOOTLOADER when not needed
if [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=none" ]]; then
if [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
opt_disable CHECK_FOR_BOOTLOADER;
fi
# Trim the build down for the Atmega328p board
if [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then
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" == "multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi" ]] || [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=native" ]] || [[ "$BOARD" =~ "multi4in1:STM32F1:multistm32f103c8" ]]; then
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
@ -133,7 +152,7 @@ jobs:
- name: Build default configuration
run: |
# Skip the default build for boards where it's too large now
if [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" == "multi4in1:STM32F1:multi5in1t18int" ]]; then
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
printf "Not testing default build for $BOARD.";
else
source ./buildroot/bin/buildFunctions;
@ -142,23 +161,38 @@ jobs:
- name: Build serial only
run: |
source ./buildroot/bin/buildFunctions;
cp ./_Config.h.bak Multiprotocol/_Config.h
opt_disable ENABLE_PPM;
buildMulti;
# 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: |
source ./buildroot/bin/buildFunctions;
cp ./_Config.h.bak Multiprotocol/_Config.h
opt_disable ENABLE_SERIAL;
buildMulti;
# 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: |
source ./buildroot/bin/buildFunctions;
cp ./_Config.h.bak Multiprotocol/_Config.h;
buildEachRFModule;
# 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: |
@ -166,6 +200,128 @@ jobs:
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;
@ -180,16 +336,43 @@ jobs:
echo "HAVE_FILES=false" >> $GITHUB_ENV
fi
- name: Deploy files to release
if: github.event_name == 'release' && github.event.action == 'created' && env.HAVE_FILES == 'true'
uses: AButler/upload-release-assets@v2.0
with:
files: './binaries/*'
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: 'Upload Artifacts'
if: env.HAVE_FILES == 'true'
uses: actions/upload-artifact@v2
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
path: ./binaries/
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,768 +0,0 @@
local toolName = "TNS|DSM Forward Programming v0.2|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. #
---- # #
---- #########################################################################
--###############################################################################
-- Multi buffer for DSM description
-- Multi_Buffer[0..2]=="DSM" -> Lua script is running
-- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent
-- Multi_Buffer[4..9]=6 bytes of TX to RX data
-- Multi_Buffer[10..25]=16 bytes of RX to TX data
--
-- To start operation:
-- Write 0x00 at address 3
-- Write 0x00 at address 10
-- Write "DSM" at address 0..2
--###############################################################################
local RX_VERSION, WAIT_CMD, MENU_TITLE, MENU_LINES, MENU_VALUES, VALUE_CHANGING, VALUE_CHANGING_WAIT, VALUE_CHANGED, EXIT, EXIT_DONE = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
local MENU, LIST_MENU_NOCHANGING, LIST_MENU1, LIST_MENU2, VALUE_NOCHANGING = 0x1C, 0x6C, 0x0C, 0x4C, 0x60
local Phase = RX_VERSION
local Waiting_RX = 0
local Text = {}
local RxName = {}
local Retry=100
local Blink = 0
local Value_Changed=0
local Menu = { Cur=nil, Id=nil, Title="", Prev=nil, PrevId=nil, Next=nil, NextId=nil, Back=nil, BackId=nil, CurLine=nil, SelLine=nil, EditLine=nil }
local Line = {}
local RX = { Name="", Version="" }
-- used for debug
local rxAnswer = ""
local debugLine = 0
------------------------------------------------------------------------------------------------------------
local function GetDebugInfo(lineNr) -- used for debug
local i
debugLine = lineNr
rxAnswer = "RX:"
for i=10, 25 do
rxAnswer = rxAnswer.." "..string.format("%02X", multiBuffer(i))
end
end
------------------------------------------------------------------------------------------------------------
local function conv_int16(number)
if number >= 0x8000 then
return number - 0x10000
end
return number
end
------------------------------------------------------------------------------------------------------------
local function Get_Text(index)
out = Text[index]
if out == nil then -- unknown...
out = "Unknown_"..string.format("%X",index)
end
return out
end
------------------------------------------------------------------------------------------------------------
local function Get_RxName(index)
out = RxName[index]
if out == nil then -- unknown...
out = "Unknown_"..string.format("%X",index)
end
return out
end
------------------------------------------------------------------------------------------------------------
local function DSM_Release()
multiBuffer( 0, 0 )
Phase = EXIT_DONE
end
------------------------------------------------------------------------------------------------------------
local function DSM_Send(...)
local arg = {...}
for i = 1 , #arg do
multiBuffer( 3+i, arg[i])
end
multiBuffer( 3, 0x70+#arg)
end
------------------------------------------------------------------------------------------------------------
local function Value_Add(dir)
local line=Line[Menu.SelLine]
Speed = getRotEncSpeed()
if Speed == ROTENC_MIDSPEED then
line.Val = line.Val + (5 * dir)
elseif Speed == ROTENC_HIGHSPEED then
line.Val = line.Val + (15 * dir)
else
line.Val = line.Val + dir
end
if line.Val > line.Max then
line.Val = line.Max
elseif line.Val < line.Min then
line.Val = line.Min
end
if Line[Menu.SelLine].Type ~= LIST_MENU_NOCHANGING then
Phase = VALUE_CHANGING
Waiting_RX = 0
end
end
------------------------------------------------------------------------------------------------------------
local function DSM_Menu(event)
local Speed = 0
if event == EVT_VIRTUAL_EXIT then
if Phase == RX_VERSION then
DSM_Release()
else
Phase = EXIT
Waiting_RX = 0
end
elseif event == EVT_VIRTUAL_NEXT then
if Menu.EditLine == nil then
-- not changing a value
if Menu.SelLine ~= nil then
if Menu.SelLine < 7 then
local num = Menu.SelLine
for i = Menu.SelLine + 1, 6, 1 do
if Line[i].Type ~= nil and Line[i].Next ~= nil and Line[i].Type ~= VALUE_NOCHANGING then
Menu.SelLine=i
break
end
end
if num == Menu.SelLine then
if Menu.Next ~= 0 then -- Next
Menu.SelLine = 7
elseif Menu.Prev ~= 0 then -- Prev
Menu.SelLine = 8
end
end
elseif Menu.Prev ~= 0 then -- Prev
Menu.SelLine = 8
end
end
else -- need to inc the value
Value_Add(1)
end
elseif event == EVT_VIRTUAL_PREV then
if Menu.EditLine == nil then
if Menu.SelLine ~= nil then
if Menu.SelLine == 8 and Menu.Next ~= 0 then
Menu.SelLine = 7
elseif Menu.SelLine > 0 then
if Menu.SelLine > 6 then
Menu.SelLine = 7
end
local num = Menu.SelLine
for i = Menu.SelLine-1, 0, -1 do
if Line[i].Type ~= nil and Line[i].Next ~= nil and Line[i].Type ~= VALUE_NOCHANGING then
Menu.SelLine=i
break
end
end
if num == Menu.SelLine then -- Back
Menu.SelLine = -1
end
else
Menu.SelLine = -1 -- Back
end
end
else -- need to dec the value
Value_Add(-1)
end
elseif event == EVT_VIRTUAL_ENTER_LONG then
if Menu.EditLine ~= nil then
-- reset the value to default
if Line[Menu.SelLine].Type ~= LIST_MENU_NOCHANGING then
Line[Menu.SelLine].Val = Line[Menu.SelLine].Def
Phase = VALUE_CHANGING
Waiting_RX = 0
end
end
elseif event == EVT_VIRTUAL_ENTER then
if Menu.SelLine == -1 then -- Back
Menu.Cur = Menu.Back
Menu.Id = Menu.BackId
Menu.SelLine = 0
Phase = MENU_TITLE
Waiting_RX = 0
elseif Menu.SelLine == 7 then -- Next
Menu.Cur = Menu.Next
Menu.Id = Menu.NextId
Menu.SelLine = 0
Phase = MENU_TITLE
Waiting_RX = 0
elseif Menu.SelLine == 8 then -- Prev
Menu.Cur = Menu.Prev
Menu.Id = Menu.PrevId
Menu.SelLine = 0
Phase = MENU_TITLE
Waiting_RX = 0
elseif Menu.SelLine ~= nil and Line[Menu.SelLine].Next ~= nil then
if Line[Menu.SelLine].Type == MENU then -- Next menu exist
Menu.Cur = Line[Menu.SelLine].Next
Menu.Id = Line[Menu.SelLine].NextId
Phase = MENU_TITLE
Waiting_RX = 0
else
-- value entry
if Menu.EditLine == Menu.SelLine then
Menu.EditLine = nil
Value_Changed = 0
Phase = VALUE_CHANGED
Waiting_RX = 0
else
Menu.EditLine = Menu.SelLine
end
end
end
end
end
------------------------------------------------------------------------------------------------------------
local function DSM_Send_Receive()
if Waiting_RX == 0 then
Waiting_RX = 1
-- Need to send a request
if Phase == RX_VERSION then -- request RX version
DSM_Send(0x11,0x06,0x00,0x14,0x00,0x00)
elseif Phase == WAIT_CMD then -- keep connection open
DSM_Send(0x00,0x04,0x00,0x00)
elseif Phase == MENU_TITLE then -- request menu title
if Menu.Cur == nil then
DSM_Send(0x12,0x06,0x00,0x14,0x00,0x00) -- first menu only
Menu.Cur = 0
else
DSM_Send(0x16,0x06,Menu.Id,Menu.Cur,0x00,Menu.SelLine)
end
elseif Phase == MENU_LINES then -- request menu lines
if Menu.CurLine == nil then
DSM_Send(0x13,0x04,Menu.Id,Menu.Cur) -- line 0
elseif Menu.CurLine >= 0x80 then
local last_byte={0x40,0x01,0x02,0x04,0x00,0x00} -- unknown...
DSM_Send(0x20,0x06,Menu.CurLine-0x80,Menu.CurLine-0x80,0x00,last_byte[Menu.CurLine-0x80+1]) -- line X
else
DSM_Send(0x14,0x06,Menu.Id,Menu.Cur,0x00,Menu.CurLine) -- line X
end
elseif Phase == MENU_VALUES then -- request menu values
DSM_Send(0x15,0x06,Menu.Id,Menu.Cur,Line[Menu.CurLine].ValId,Line[Menu.CurLine].Next) -- line X
elseif Phase == VALUE_CHANGING then -- send value
local value=Line[Menu.SelLine].Val
if value < 0 then
value = 0x10000 + value
end
DSM_Send(0x18,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next,bit32.rshift(value,8),bit32.band(value,0xFF)) -- send current value
Phase = VALUE_CHANGING_WAIT
elseif Phase == VALUE_CHANGED then -- send value
if Value_Changed == 0 then
local value=Line[Menu.SelLine].Val
if value < 0 then
value = 0x10000 + value
end
DSM_Send(0x18,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next,bit32.rshift(value,8),bit32.band(value,0xFF)) -- send current value
Value_Changed = Value_Changed + 1
Waiting_RX = 0
elseif Value_Changed == 1 then
DSM_Send(0x19,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next) -- validate
-- Value_Changed = Value_Changed + 1
-- Waiting_RX = 0
--elseif Value_Changed == 2 then
-- DSM_Send(0x1B,0x06,0x10,Menu.SelLine) -- validate again?
-- Value_Changed = Value_Changed + 1
end
elseif Phase == VALUE_CHANGING_WAIT then
DSM_Send(0x1A,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next)
elseif Phase == EXIT then
DSM_Send(0x1F,0x02,0xAA)
end
multiBuffer(10,0x00);
Retry = 50
-- -- -- -- -- -- -- -- -- -- -- -- receive part -- -- -- -- -- -- -- -- -- -- -- -- --
elseif multiBuffer(10) == 0x09 then
-- Answer received
-- GetDebugInfo(292) -- used for debug
--if multiBuffer(11) == 0x00 then -- waiting for commands?
if multiBuffer(11) == 0x01 then -- read version
--ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 0x00 0x00 0x00 0x00 0x00 0x00 0x00
RX.Name = Get_RxName(multiBuffer(13))
RX.Version = multiBuffer(14).."."..multiBuffer(15).."."..multiBuffer(16)
Phase = MENU_TITLE
elseif multiBuffer(11) == 0x02 then -- read menu title
--ex: 0x09 0x02 0x4F 0x10 0xA5 0x00 0x00 0x00 0x50 0x10 0x10 0x10 0x00 0x00 0x00 0x00
Menu.Cur = multiBuffer(12)
Menu.Id = multiBuffer(13)
Menu.Title = Get_Text(multiBuffer(14)+multiBuffer(15)*256)
Menu.Prev = multiBuffer(16)
Menu.PrevId = multiBuffer(17)
Menu.Next = multiBuffer(18)
Menu.NextId = multiBuffer(19)
Menu.Back = multiBuffer(20)
Menu.BackId = multiBuffer(21)
for i = 0, 6 do -- clear menu
Line[i] = { Menu = nil, Id = nil, Type = nil, Text="", Next = nil, NextId = nil, ValLine = nil, ValId = nil, Min, Max, Def, Val, Unit, Step }
end
Menu.CurLine = nil
if Menu.Next ~= 0 then
Menu.SelLine = 7 -- highlight Next
else
Menu.SelLine = -1 -- highlight Back
end
Blink = 0
Phase = MENU_LINES
elseif multiBuffer(11) == 0x03 then -- read menu lines
--ex: 0x09 0x03 0x00 0x10 0x00 0x1C 0xF9 0x00 0x10 0x10 0x00 0x00 0x00 0x00 0x03 0x00
-- Menu Id line Type Text_idx Next V_Id Val_Min Val_Max Val_Def
--ex: 0x09 0x03 0x61 0x10 0x00 0x6C 0x50 0x00 0x00 0x10 0x36 0x00 0x49 0x00 0x36 0x00
Menu.CurLine = multiBuffer(14)
local line = Line[Menu.CurLine]
line.Menu = multiBuffer(12)
line.Id = multiBuffer(13) -- not quite sure yet
line.Type = multiBuffer(15) -- not quite sure yet: 1C is text menu only, 4C/6C is text followed by text list, C0 is text followed by percentage value, 0C new list type
line.Text = Get_Text(multiBuffer(16)+multiBuffer(17)*256)
--if multiBuffer(18) == Menu.Cur then
-- line.Next = nil
--else
line.Next = multiBuffer(18) -- not quite sure yet: 1C=text menu=>next menu, others=>identifier of line number of the value
--end
if Menu.SelLine == -1 and line.Next ~= nil then -- Auto select first line of the menu
Menu.SelLine = Menu.CurLine
end
line.NextId = multiBuffer(19) -- not quite sure yet
line.ValLine = multiBuffer(18) -- not quite sure yet
line.ValId = multiBuffer(19) -- not quite sure yet
line.Min = conv_int16(multiBuffer(20)+multiBuffer(21)*256)
line.Max = conv_int16(multiBuffer(22)+multiBuffer(23)*256)
line.Def = conv_int16(multiBuffer(24)+multiBuffer(25)*256)
if line.Type == MENU then
-- nothing to do on menu entries
elseif line.Type == LIST_MENU_NOCHANGING or line.Type == LIST_MENU1 or line.Type == LIST_MENU2 then
line.Val = nil --line.Def - line.Min -- use default value not sure if needed
line.Def = line.Min -- pointer to the start of the list in Text
line.Max = line.Max - line.Min -- max index
line.Min = 0 -- min index
else -- default to numerical value
line.Val = nil --line.Def -- use default value not sure if needed
end
if line.Type ~= MENU and line.Type ~= VALUE_NOCHANGING then -- updatable value to follow
line.Text = line.Text..":"
end
Phase = MENU_LINES
elseif multiBuffer(11) == 0x04 then -- read menu values
--ex: 0x09 0x04 0x53 0x10 0x00 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
-- Menu MeId line VaId Value
--ex: 0x09 0x04 0x61 0x10 0x02 0x10 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
-- Identify the line and update the value
for i = 0, 6 do
if Line[i] ~= nil and Line[i].Type ~= nil then
if Line[i].Type ~= MENU and Line[i].Next == multiBuffer(14) then -- identifier of line number stored in .Next
Line[i].Val = conv_int16(multiBuffer(16)+multiBuffer(17)*256)
Menu.CurLine = i
break
end
end
end
Phase = MENU_VALUES
elseif multiBuffer(11) == 0x05 then -- unknown... need to get through the lines...
Menu.CurLine = 0x80 + multiBuffer(12)
Phase = MENU_LINES
elseif multiBuffer(11) == 0xA7 then -- answer to EXIT command
DSM_Release()
elseif multiBuffer(11) == 0x00 and Phase == VALUE_CHANGING then
Phase = VALUE_CHANGING_WAIT
end
-- Data processed
Waiting_RX = 0
multiBuffer(10,0x00)
Retry = 50
else
Retry = Retry - 1
if Retry <= 0 then
-- Retry the RX request
Retry = 50
Waiting_RX = 0
if Phase == EXIT then
DSM_Release()
end
if Phase ~= RX_VERSION and Phase ~= VALUE_CHANGING_WAIT then
Phase = WAIT_CMD
end
end
end
end
------------------------------------------------------------------------------------------------------------
local function DSM_Display()
lcd.clear()
if LCD_W == 480 then
--lcd.drawText(10,55,debugLine.." "..rxAnswer) -- draw debug info
--Draw title
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
lcd.drawText(1, 5, "DSM Forward Programming", MENU_TITLE_COLOR)
--Draw RX Menu
if Phase == RX_VERSION then
lcd.drawText(10,50,"No compatible DSM RX...", BLINK)
else
if Menu.Title ~= nil then
local attrib=0;
lcd.drawText(80,32,Menu.Title,MIDSIZE)
for i = 0, 6 do
if i == Menu.SelLine then
attrib = INVERS
else
attrib = 0
end
if Line[i] ~= nil and Line[i].Type ~= nil then
if Line[i].Type ~= MENU then -- list/value
if Line[i].Val ~= nil then
local text=""
if Line[i].Type == LIST_MENU_NOCHANGING or Line[i].Type == LIST_MENU1 or Line[i].Type == LIST_MENU2 then
text = Get_Text(Line[i].Val+Line[i].Def)
elseif ( Line[i].Min == 0 and Line[i].Max == 100) or ( Line[i].Min == -100 and Line[i].Max == 100) or ( Line[i].Min == 0 and Line[i].Max == 150) or ( Line[i].Min == -150 and Line[i].Max == 150) then
text = Line[i].Val.." %"
else
--text = Line[i].Val .." T="..Line[i].Type -- used for debug
text = Line[i].Val
end
if Menu.EditLine == Menu.SelLine then -- blink edited entry
Blink = Blink + 1
if Blink > 25 then
attrib = 0
if Blink > 50 then
Blink = 0
end
end
end
lcd.drawText(240,32+20*(i+2), text, attrib) -- display value
end
attrib = 0
end
lcd.drawText(10,32+20*(i+2), Line[i].Text, attrib) -- display text
end
end
if Menu.SelLine == -1 then
lcd.drawText(437,32, "Back", INVERS)
else
lcd.drawText(437,32, "Back", 0)
end
lcd.drawRectangle(437-5, 32-2, 47, 25)
if Menu.Next ~= 0 then
if Menu.SelLine == 7 then
lcd.drawText(437,220, "Next",INVERS)
else
lcd.drawText(437,220, "Next")
end
lcd.drawRectangle(437-5, 220-2, 47, 25)
end
if Menu.Prev ~= 0 then
if Menu.SelLine == 8 then
lcd.drawText(5,220, "Prev",INVERS)
else
lcd.drawText(5,220, "Prev")
end
lcd.drawRectangle(5-5, 220-2, 47, 25)
end
end
lcd.drawText(170,252, "RX "..RX.Name.." v"..RX.Version) -- display RX info
end
else
-- --Draw RX Menu on LCD_W=128
-- if multiBuffer( 4 ) == 0xFF then
-- lcd.drawText(2,17,"No compatible DSM RX...",SMLSIZE)
-- else
-- if Retry_128 ~= 0 then
-- --Intro page
-- Retry_128 = Retry_128 - 1
-- lcd.drawScreenTitle("DSM Forward Programming",0,0)
-- lcd.drawText(2,17,"Press Prev Page for previous Menu" ,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 DSM_Init()
--Set protocol to talk to
multiBuffer( 0, string.byte('D') )
--test if value has been written
if multiBuffer( 0 ) ~= string.byte('D') then
error("Not enough memory!")
return 2
end
--Init TX buffer
multiBuffer( 3, 0x00 )
--Init RX buffer
multiBuffer( 10, 0x00 )
--Init telemetry
multiBuffer( 0, string.byte('D') )
multiBuffer( 1, string.byte('S') )
multiBuffer( 2, string.byte('M') )
--RX names--
RxName[0x0001]="AR636B"
RxName[0x0014]="SPM4651T"
RxName[0x0015]="AR637T"
RxName[0x0016]="AR637TA"
RxName[0x0018]="FC6250HX"
RxName[0x001A]="AR8360T"
RxName[0x001E]="AR631"
--Text to be displayed -> need to use a file instead?
Text[0x0001]="On"
Text[0x0002]="Off"
Text[0x0003]="Inh"
Text[0x0004]="Act"
Text[0x000C]="Inhibit?" --?
Text[0x000D]="Gear"
--Lists--
Text[0x002E]="11ms"
Text[0x002F]="22ms"
Text[0x0032]="1 X"
Text[0x0033]="2 X"
Text[0x0034]="4 X"
Text[0x0035]="Inhibit?" --?
Text[0x0036]="Throttle"
Text[0x0037]="Aileron"
Text[0x0038]="Elevator"
Text[0x0039]="Rudder"
Text[0x003A]="Gear"
--******
--This part is strange since the AR637T needs
for i=1,7 do -- 3B..41
Text[0x003A+i]="Aux"..i
end
for i=1,8 do -- 41..49
Text[0x0041+i]="XPlus-"..i
end
--But FOTO-PETE reports that it should be:
Text[0x0040]="Roll"
Text[0x0041]="Pitch"
Text[0x0042]="Yaw"
Text[0x0043]="Gain" -- FC6250HX
Text[0x0045]="Differential"
Text[0x0046]="Priority"
Text[0x0049]="Output Setup" -- FC6250HX
--******
Text[0x004A]="Failsafe"
Text[0x004B]="Main Menu"
Text[0x004E]="Position"
Text[0x0050]="Outputs"
Text[0x0051]="Output Channel 1"
Text[0x0052]="Output Channel 2"
Text[0x0053]="Output Channel 3"
Text[0x0054]="Output Channel 4"
Text[0x0055]="Output Channel 5"
Text[0x0056]="Output Channel 6"
--Text[0x005E]="Inhibit"
Text[0x005F]="Hold Last"
Text[0x0060]="Preset"
--Text[0x0061]="Custom"
--Messages--
Text[0x0071]="Proportional"
Text[0x0072]="Integral"
Text[0x0073]="Derivate"
Text[0x0078]="FM Channel"
Text[0x0080]="Orientation"
Text[0x0082]="Heading"
Text[0x0085]="Frame Rate"
Text[0x0086]="System Setup"
Text[0x0087]="F-Mode Setup"
Text[0x0088]="Enabled F-Modes"
Text[0x0089]="Gain Channel"
Text[0x008A]="Gain Sensitivity"
Text[0x008B]="Panic"
Text[0x0090]="Apply"
Text[0x0092]="Start"
Text[0x0093]="Complete"
Text[0x0094]="Done"
Text[0x0097]="Factory Reset"
Text[0x0099]="Advanced Setup"
Text[0x009A]="Capture Failsafe Positions"
Text[0x009C]="Custom Failsafe"
Text[0x00A5]="First Time Setup"
Text[0x00AA]="Capture Gyro Gains"
Text[0x00AD]="Gain Channel Select"
Text[0x00B0]="Self-Level/Angle Dem"
Text[0x00B1]="Envelope"
Text[0x00B5]="Inhibit"
Text[0x00B6]="FM1"
Text[0x00B7]="FM2"
Text[0x00B8]="FM3"
Text[0x00B9]="FM4"
Text[0x00BA]="FM5"
Text[0x00BB]="FM6"
Text[0x00BC]="FM7"
Text[0x00BD]="FM8"
Text[0x00BE]="FM9"
Text[0x00BF]="FM10"
Text[0x00C7]="Calibrate Sensor"
Text[0x00CA]="SAFE/Panic Mode Setup"
Text[0x00D3]="Swashplate"
Text[0x00D5]="Agility"
Text[0x00D8]="Stop"
Text[0x00DA]="SAFE"
Text[0x00DB]="Stability"
Text[0x00DC]="@ per sec"
Text[0x00DD]="Tail rotor"
Text[0x00DE]="Setup"
Text[0x00DF]="AFR"
Text[0x00E0]="Collective"
Text[0x00E1]="Subtrim"
Text[0x00E2]="Phasing"
Text[0x00E4]="E-Ring"
Text[0x00E7]="Left"
Text[0x00E8]="Right"
Text[0x00F2]="Fixed"
Text[0x00F3]="Adjustable"
Text[0x00F9]="Gyro settings"
Text[0x00FE]="Stick Priority"
Text[0x0100]="Make sure the model has been"
Text[0x0101]="configured, including wing type,"
Text[0x0102]="reversing, travel, trimmed, etc."
Text[0x0103]="before continuing setup."
Text[0x0106]="Any wing type, channel assignment,"
Text[0x0107]="subtrim, or servo reversing changes"
Text[0x0108]="require running through initial"
Text[0x0109]="setup again."
Text[0x0190]="Relearn Servo Settings"
Text[0x019C]="Enter Receiver Bind Mode"
Text[0x01D7]="SAFE Select Channel"
Text[0x01DC]="AS3X"
Text[0x01DD]="AS3X Settings"
Text[0x01DE]="AS3X Gains"
Text[0x01E0]="Rate Gains"
Text[0x01E2]="SAFE Settings"
Text[0x01E3]="SAFE Gains"
Text[0x01E6]="Attitude Trim"
Text[0x01E7]="Envelope"
Text[0x01E9]="Roll Right"
Text[0x01EA]="Roll Left"
Text[0x01EB]="Pitch Down"
Text[0x01EC]="Pitch Up"
Text[0x01EE]="Throttle to Pitch"
Text[0x01EF]="Low Thr to Pitch"
Text[0x01F0]="High Thr to Pitch"
Text[0x01F3]="Threshold"
Text[0x01F4]="Angle"
Text[0x01F6]="Failsafe Angles"
Text[0x01F8]="Safe Mode"
Text[0x01F9]="SAFE Select"
Text[0x01FD]="SAFE Failsafe FMode"
Text[0x0208]="Decay"
Text[0x0209]="Save to Backup"
Text[0x020A]="Restore from Backup"
Text[0x020D]="First Time SAFE Setup"
Text[0x021A]="Set the model level,"
Text[0x021B]="and press Continue."
Text[0x021C]="" -- empty??
Text[0x021D]="" -- empty??
Text[0x021F]="Set the model on its nose,"
Text[0x0220]="and press Continue. If the"
Text[0x0221]="orientation on the next"
Text[0x0222]="screen is wrong go back"
Text[0x0223]="and try again."
Text[0x0224]="Continue"
Text[0x0226]="Angle Limits"
Text[0x0227]="Other settings"
Text[0x0229]="Set Orientation Manually"
Text[0x022B]="WARNING!"
Text[0x022C]="This will reset the"
Text[0x022D]="configuration to factory"
Text[0x022E]="defaults. This does not"
Text[0x022F]="affect the backup config."
Text[0x0230]="" -- empty??
Text[0x0231]="This will overwrite the"
Text[0x0232]="backup memory with your"
Text[0x0233]="current configuartion."
Text[0x0234]="" -- blank line
Text[0x0235]="" -- blank line
Text[0x0236]="This will overwrite the"
Text[0x0237]="current config with"
Text[0x0238]="that which is in"
Text[0x0239]="the backup memory."
Text[0x023A]="" -- blank line
Text[0x023D]="Copy Flight Mode Settings"
Text[0x0240]="Utilities"
Text[0x024C]="Gains will be captured on"
Text[0x024D]="Captured gains will be"
Text[0x024E]="Gains on"
Text[0x024F]="were captured and changed"
Text[0x0250]="from Adjustable to Fixed"
Text[0x0254]="Postive = Up, Negative = Down"
Text[0x0263]="Fixed/Adjustable Gains"
Text[0x0266]="Heading Gain"
Text[0x0267]="Positive = Nose Up/Roll Right"
Text[0x0268]="Negative = Nose Down/Roll Left"
Text[0x0269]="SAFE - Throttle to Pitch"
Text[0x026A]="Use CAUTION for Yaw gain!"
Text[0x8000]="FLIGHT MODE"
Text[0x8001]="Flight Mode 1"
Text[0x8002]="Flight Mode 2"
Text[0x8003]="Flight Mode 3"
end
------------------------------------------------------------------------------------------------------------
-- Main
local function DSM_Run(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
else
DSM_Menu(event)
DSM_Send_Receive()
DSM_Display()
end
if Phase == EXIT_DONE then
return 2
else
return 0
end
end
return { init=DSM_Init, run=DSM_Run }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,790 @@
local toolName = "TNS|DSM Forward Prog v0.56 (Color) |TNE"
local VERSION = "v0.56"
---- #########################################################################
---- # #
---- # Copyright (C) OpenTX #
-----# #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
------------------------------------------------------------------------------
-- This script library is a rewrite of the original DSM forward programming Lua
-- Script. The goal is to make it easier to understand, mantain, and to
-- separate the GUI from the DSM Forward programming engine/logic
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
-- Rewrite/Enhancements By: Francisco Arzu
------------------------------------------------------------------------------
local SIMULATION_ON = true -- false: dont show simulation menu, TRUE: show simulation menu
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
local USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX)
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
local IMAGE_PATH = DSMLIB_PATH .. "img/"
local Log = assert(loadScript(DSMLIB_PATH.."DsmLogLib.lua"), "Not-Found: DSMLIB/DsmLogLib.lua")()
local menuLib = assert(loadScript(DSMLIB_PATH.."DsmMenuLib.lua"), "Not-Found: DSMLIB/DsmMenuLib.lua")(Log, DEBUG_ON)
local modelLib = assert(loadScript(DSMLIB_PATH.."DsmModelLib.lua"), "Not-Found: DSMLIB/DsmModelLib.lua")(Log, DEBUG_ON)
local menuProcessor = assert(loadScript(DSMLIB_PATH.."DsmMainMenuLib.lua"), "Not-Found: DSMLIB/DsmMainMenuLib.lua")(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
local PHASE = menuLib.PHASE
local LINE_TYPE = menuLib.LINE_TYPE
local DISP_ATTR = menuLib.DISP_ATTR
local DSM_Context = menuLib.DSM_Context
local lastRefresh=0 -- Last time the screen was refreshed
local REFRESH_GUI_MS = 300/10 -- 300ms.. Screen Refresh Rate.. to not waste CPU time (in 10ms units to be compatible with getTime())
local originalValue = nil
local touchButtonArea = {}
local EDIT_BUTTON = { DEFAULT=1001, DEC_10=1002, DEC_1=1003, INC_1=1004, INC_10=5, OK=1006, ESC=1007 }
local IS_EDGETX = false -- DEFAULT until Init changed it
local LCD_Y_MENU_TITLE = 20
local LCD_W_MENU_TITLE = LCD_W-100
local LCD_X_LINE_MENU = 30
local LCD_W_LINE_MENU = 350
local LCD_X_LINE_TITLE = 30
local LCD_X_LINE_VALUE = 230
local LCD_X_LINE_DEBUG = 390
local LCD_Y_LINE_START = LCD_Y_MENU_TITLE + 30
local LCD_Y_LINE_HEIGHT = 27
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT)
-- TOOL BG COLOR
local LCD_TOOL_BGCOLOR = TEXT_BGCOLOR
-- TOOL HEADER
local LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR
local LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR
-- MENU HEADER
local LCD_MENU_COLOR = MENU_TITLE_COLOR
local LCD_MENU_BGCOLOR = MENU_TITLE_BGCOLOR
-- LINE SELECTED
local LCD_SELECTED_COLOR = TEXT_INVERTED_COLOR
local LCD_SELECTED_BGCOLOR = TEXT_INVERTED_BGCOLOR
local LCD_EDIT_BGCOLOR = MENU_TITLE_BGCOLOR -- WARNING_COLOR
-- NORMAL TEXT
local LCD_NORMAL_COLOR = TEXT_COLOR
local LCD_DISABLE_COLOR = TEXT_DISABLE_COLOR
local LCD_DEBUG_COLOR = LINE_COLOR
-- NORMAL BOX FRAME COLOR
local LCD_BOX_COLOR = TEXT_DISABLE_COLOR
local warningScreenON = true
--------------------- lcd.sizeText replacement -------------------------------------------------
-- EdgeTx dont have lcd.sizeText, so we do an equivalent one using the string length and 5px per character
local function my_lcd_sizeText(s)
if (s==nil) then return 20 end
-- return: If IS_EDGETX then lcd.sizeText() else string.len()
return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10)
end
local function GUI_SwitchToRX()
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
-- local dsmChannelInfo, description = modelLib.CreateDSMPortChannelInfo()
menuProcessor.done()
Log.LOG_close() -- Reset the log
Log.LOG_open()
menuProcessor = nil
collectgarbage("collect")
modelLib.ReadTxModelData()
modelLib.ST_LoadFileData()
modelLib.CreateDSMPortChannelInfo()
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")
menuProcessor = dsmLib(Log, menuLib, modelLib, DEBUG_ON)
dsmLib = nil
collectgarbage("collect")
menuProcessor.init(toolName) -- Initialize Library
DSM_Context.Refresh_Display = true
end
local function GUI_SwitchToSIM()
menuProcessor.done()
Log.LOG_close()
menuProcessor = nil
collectgarbage("collect")
local simLib = assert(loadScript(DSMLIB_PATH.."DsmSimMenuLib.lua"), "Not-Found: DSMLIB/DsmSimMenuLib.lua")
menuProcessor = simLib(Log, menuLib, modelLib, DEBUG_ON)
simLib = nil
collectgarbage("collect")
menuProcessor.init(toolName) -- Initialize Library
DSM_Context.Refresh_Display = true
end
local function GUI_SwitchToSetupMenu()
menuProcessor.done()
menuProcessor = nil
collectgarbage("collect")
local setupLib = assert(loadScript(DSMLIB_PATH.."DsmSetupMenuLib.lua"), "Not-Found: DSMLIB/DsmSetupMenuLib.lua")
menuProcessor = setupLib(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
setupLib = nil
collectgarbage("collect")
menuProcessor.init(toolName) -- Initialize Library
DSM_Context.Refresh_Display = true
end
local function GUI_SwitchToMainMenu()
print("SWITCHING TO MAIN MENU")
menuProcessor.done()
menuProcessor = nil
collectgarbage("collect")
local mainMenuLib = assert(loadScript(DSMLIB_PATH.."DsmMainMenuLib.lua"), "Not-Found: DSMLIB/DsmMainMenuLib.lua")
menuProcessor = mainMenuLib(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
mainMenuLib = nil
collectgarbage("collect")
menuProcessor.init(toolName) -- Initialize Library
DSM_Context.Refresh_Display = true
end
--------------------- Toucch Button Helpers ------------------------------------------------------------
local function GUI_addTouchButton(x,y,w,h,line)
-- Add new button info to end of the array
touchButtonArea[#touchButtonArea+1] = {x=x, y=y, w=w, h=h, line=line}
end
local function GUI_getTouchButton(x,y)
for i = 1, #touchButtonArea do
local button = touchButtonArea[i]
-- is the coordinate inside the button area??
if (x >= button.x and x <= (button.x+button.w) and y >= button.y and (y <= button.y+button.h)) then
return button.line
end
end
return nil
end
local function GUI_clearTouchButtons()
touchButtonArea = {}
end
---------- Return Color to display Menu Lines ----------------------------------------------------------------
local function GUI_GetTextColor(lineNum)
local ctx = DSM_Context
local txtColor = LCD_NORMAL_COLOR
-- Gray Out any other line except the one been edited
if (ctx.isEditing() and ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
return txtColor
end
local function GUI_GetFrameColor(lineNum) -- Frame Color for Value/Menu Boxes
local ctx = DSM_Context
local txtColor = LCD_BOX_COLOR
-- Gray Out any other line except the one been edited
if (ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
return txtColor
end
--------------------------------------------------------------------------------------------------------
-- Display Text inside a Rectangle. Inv: true means solid rectangle, false=only perimeter
local function GUI_Display_Boxed_Text(lineNum,x,y,w,h,text,inv, isNumber)
local ctx = DSM_Context
local txtColor = GUI_GetTextColor(lineNum)
local frameColor = GUI_GetFrameColor(lineNum)
-- If editing this lineNum, chose EDIT Color, else SELECTED Color
local selectedBGColor = (ctx.EditLine==lineNum and LCD_EDIT_BGCOLOR) or LCD_SELECTED_BGCOLOR
if (inv) then
txtColor = LCD_SELECTED_COLOR
lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor)
else
lcd.drawRectangle(x-5, y-2, w, h, frameColor)
end
if (isNumber) then
lcd.drawNumber(x+w-10 , y, text, txtColor + RIGHT)
else
lcd.drawText(x , y, text, txtColor)
end
end
------ Display Pre/Next/Back buttons
local function GUI_Diplay_Button(x,y,w,h,text,selected)
GUI_Display_Boxed_Text(-1,x,y,w,h,text,selected, false)
end
------ Display MENU type of lines (Navigation, SubHeaders, and plain text comments)
local function GUI_Display_Line_Menu(lineNum,line,selected)
-- Menu Lines can be navidation to other Menus (if Selectable)
-- Or SubHeaders or Messages
local txtColor = GUI_GetTextColor(lineNum)
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
local x = LCD_X_LINE_MENU
if menuLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes
GUI_Display_Boxed_Text(lineNum,x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT, line.Text,selected, false)
GUI_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum)
else
-- Non Selectable Menu Lines, plain text
-- Can be use for sub headers or just regular text lines (like warnings)
local bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
if menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
local tw = my_lcd_sizeText(line.Text)+4
x = LCD_X_LINE_VALUE - tw -- Right
elseif menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
local tw = my_lcd_sizeText(line.Text)
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
end
lcd.drawText(x, y, line.Text, txtColor + bold)
end
end
------ Display NAME : VALUES type of lines
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
-- This Displays Name and Value Pairs
local txtColor = GUI_GetTextColor(lineNum)
local bold = 0
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
local x = LCD_X_LINE_TITLE
---------- NAME Part
local header = line.Text
-- ONLY do this for Flight Mode (Right Align or Centered)
if (menuLib.isFlightModeLine(line)) then
-- Display Header + Value together
header = menuLib.GetFlightModeValue(line)
-- Bold Text???
bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
if menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
local tw = my_lcd_sizeText(header)+4
x = LCD_X_LINE_VALUE - tw -- Right
elseif menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
local tw = my_lcd_sizeText(header)
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
end
else
-- No Flight Mode, no effects here
header = header .. ":"
end
lcd.drawText(x, y, header, txtColor + bold) -- display Line Header
--------- VALUE PART, Skip for Flight Mode since already show the value
if (value==nil) then return end
if not menuLib.isFlightModeLine(line) then
if menuLib.isSelectableLine(line) then
--if (editing) then -- Any Special color/effect when editing??
-- value = "["..value .. "]"
--end
-- Can select/edit value, Box it
local tw = math.max(my_lcd_sizeText(value)+10,45) -- Width of the Text in the lcd
GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected, not menuLib.isListLine(line))
GUI_addTouchButton(LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,lineNum)
lcd.drawText(LCD_X_LINE_VALUE+tw+5, y, (line.Format or ""), txtColor + bold)
else -- Not Editable, Plain Text
lcd.drawText(LCD_X_LINE_VALUE, y, value, txtColor)
end
end
end
local function GUI_Display_Menu(menu)
local ctx = DSM_Context
local w= LCD_W_MENU_TITLE
-- Center Header
local tw = my_lcd_sizeText(menu.Text)
local x = w/2 - tw/2 -- Center of Screen - Center of Text
lcd.drawFilledRectangle(0, LCD_Y_MENU_TITLE-2, w, LCD_Y_LINE_HEIGHT-2, LCD_MENU_BGCOLOR)
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text, LCD_MENU_COLOR + BOLD)
-- Back Button
if menu.BackId ~= 0 then
GUI_Diplay_Button(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,"Back",ctx.SelLine == menuLib.BACK_BUTTON)
GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,menuLib.BACK_BUTTON)
end
-- Next Button
if menu.NextId ~= 0 then
GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == menuLib.NEXT_BUTTON)
GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,menuLib.NEXT_BUTTON)
end
-- Prev Button
if menu.PrevId ~= 0 then
GUI_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == menuLib.PREV_BUTTON)
GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,menuLib.PREV_BUTTON)
end
end
------------------------------------------------------------------------------------------------------------
-- Display the EDIT mode buttons when editing a value
local function GUI_Display_Edit_Buttons(line)
GUI_clearTouchButtons() -- Only this buttons can be touched
local x = 15 -- Inittial X position
local w = 55 -- Width of the buttons
local showPrev = line.Val > line.Min
local showNext = line.Val < line.Max
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,"ESC",true)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.ESC)
x=x+w+10
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," Def",true)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT)
x=x+w+10
if (not menuLib.isListLine(line)) then
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," << ",showPrev)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_10)
end
x=x+w+10
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," <",showPrev)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_1)
x=x+w+10
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >",showNext)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1)
x=x+w+10
if (not menuLib.isListLine(line)) then
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >>",showNext)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_10)
end
x=x+w+10
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," OK",true)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.OK)
end
local function GUI_ShowBitmap(x,y,imgData)
-- imgData format "bitmap.png|alt message"
local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|'
local imgName, imgMsg = f(), f()
lcd.drawText(x, y, imgMsg or "") -- Alternate Image MSG
local imgPath = IMAGE_PATH .. (imgName or "")
local bitmap = Bitmap.open(imgPath)
if (bitmap~=nil) then
lcd.drawBitmap(bitmap, x,y+20)
end
end
------------------------------------------------------------------------------------------------------------
local function GUI_Display()
local ctx = DSM_Context
lcd.clear(LCD_TOOL_BGCOLOR)
GUI_clearTouchButtons()
if LCD_W ~= 480 then
-- Different Resolution.. Maybe just adjusting some of the constants will work, adjust it in DSM_Init??
-- LCD_X_LINE_TITLE, LCD_Y_LINE_START, etc
lcd.drawText(LCD_X_LINE_TITLE,100,"Only supported in Color Radios of 480 resolution", BLINK)
return
end
local header = "DSM Forward Programming "..VERSION.." "
if ctx.Phase ~= PHASE.RX_VERSION then
header = header .. ctx.RX.Name.." v"..ctx.RX.Version
end
--Draw title
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
-- Getting RX Version
if ctx.Phase == PHASE.RX_VERSION then
if (ctx.isReset) then
lcd.drawText(LCD_X_LINE_TITLE,100, menuLib.Get_Text(0x301), BLINK) -- Resetting...
else
lcd.drawText(LCD_X_LINE_TITLE,100,menuLib.Get_Text(0x300), BLINK) -- Not valid RX
end
return
end
local menu = ctx.Menu
if menu.Text == nil then return end
----- Draw RX Menu ---------
GUI_Display_Menu(menu)
-- Sending TX Information???
if (ctx.Phase==PHASE.MENU_REQ_TX_INFO) then
--lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor)
--lcd.drawRectangle(x-5, y-2, w, h, frameColor)
lcd.drawText(LCD_X_LINE_TITLE,100, "Sending CH"..(ctx.CurLine+1)) -- Channel Info
return
end
for i = 0, menuLib.MAX_MENU_LINES do
local line = ctx.MenuLines[i]
if line ~= nil and line.Type ~= 0 then
if line.Type == LINE_TYPE.MENU then
GUI_Display_Line_Menu(i, line, i == ctx.SelLine)
else
local value = nil
if line.Val ~= nil then
value = line.Val
if menuLib.isListLine(line) then -- for Lists of Strings, get the text
value = menuLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
-- Complentary IMAGE for this value to Display??
local offset = 0
if (line.Type==LINE_TYPE.LIST_MENU_ORI) then offset = offset + 0x100 end --FH6250 hack
local imgData = menuLib.Get_List_Text_Img(line.Val + line.TextStart + offset)
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_START, imgData)
end
end
end -- if Line[i]~=nil
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
end
end -- if ~MENU
end -- for
if IS_EDGETX and ctx.isEditing() then
-- Display Touch button for Editing values
GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine])
end
end
-------------------------------------------------------------------------------------------------------------
local function GUI_RotEncVal(line, dir) -- return encoder speed to inc or dec values
if menuLib.isListLine(line) then return dir end
local inc = 0
local Speed = getRotEncSpeed()
if Speed == ROTENC_MIDSPEED then inc = (5 * dir)
elseif Speed == ROTENC_HIGHSPEED then inc = (15 * dir)
else inc = dir end
return inc
end
------------------------------------------------------------------------------------
-- Translate Tap/Touch of EDIT buttons to equivalent Key events
local function GUI_Translate_Edit_Buttons(button)
local event = EVT_TOUCH_TAP
local editInc = nil
if (button==EDIT_BUTTON.ESC) then -- ESC
event = EVT_VIRTUAL_EXIT
elseif (button==EDIT_BUTTON.DEFAULT) then -- Default
event = EVT_VIRTUAL_ENTER_LONG
elseif (button==EDIT_BUTTON.DEC_10) then -- -10
event = EVT_VIRTUAL_PREV
editInc = -10
elseif (button==EDIT_BUTTON.DEC_1) then -- -1
event = EVT_VIRTUAL_PREV
editInc = -1
elseif (button==EDIT_BUTTON.INC_1) then -- +1
event = EVT_VIRTUAL_NEXT
editInc = 1
elseif (button==EDIT_BUTTON.INC_10) then -- + 10
event = EVT_VIRTUAL_NEXT
editInc = 10
elseif (button==EDIT_BUTTON.OK) then -- OK
event = EVT_VIRTUAL_ENTER
else
end
return event, editInc
end
------------------------------------------------------------------------------------------------------------
-- Handle Events comming from the GUI
local function GUI_HandleEvent(event, touchState)
local ctx = DSM_Context
local menu = ctx.Menu
local menuLines = ctx.MenuLines
local editInc = nil
if (IS_EDGETX) then
if (event == EVT_TOUCH_TAP and ctx.isEditing()) then -- Touch and Editing
local button = GUI_getTouchButton(touchState.x, touchState.y)
if (button) then
event, editInc = GUI_Translate_Edit_Buttons(button)
end
end
if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing
if (DEBUG_ON) then Log.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",menuLib.phase2String(ctx.Phase),touchState.x, touchState.y) end
local button = GUI_getTouchButton(touchState.x, touchState.y)
if button then
-- Found a valid line
ctx.SelLine = button
ctx.Refresh_Display=true
if event == EVT_TOUCH_TAP then -- EVT_TOUCH_FIRST only move focus
event = EVT_VIRTUAL_ENTER
end
end
end
end -- IS_EDGETX
if event == EVT_VIRTUAL_EXIT then
ctx.Refresh_Display=true
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_EXIT\n",menuLib.phase2String(ctx.Phase)) end
if ctx.Phase == PHASE.RX_VERSION then
menuLib.ChangePhase(PHASE.EXIT_DONE) -- Just Exit the Script
else
if ctx.isEditing() then -- Editing a Line, need to restore original value
local line = ctx.MenuLines[ctx.EditLine]
line.Val = originalValue
menuLib.Value_Write_Validate(line)
elseif (menu.BackId > 0 ) then -- Back??
ctx.SelLine = menuLib.BACK_BUTTON
event = EVT_VIRTUAL_ENTER
else
menuLib.ChangePhase(PHASE.EXIT)
end
end
end
if ctx.Phase == PHASE.RX_VERSION then return end
if event == EVT_VIRTUAL_NEXT then
ctx.Refresh_Display=true
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_NEXT\n",menuLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then -- Editing a Line, need to inc the value
local line=ctx.MenuLines[ctx.EditLine]
menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, 1))
else -- not editing, move selected line to NEXT
menuLib.MoveSelectionLine(1)
end
return
end
if event == EVT_VIRTUAL_PREV then
ctx.Refresh_Display=true
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_PREV\n",menuLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then -- Editiing a line, need to dec the value
local line=ctx.MenuLines[ctx.EditLine]
menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, -1))
else -- not editing, move selected line to PREV
menuLib.MoveSelectionLine(-1)
end
return
end
if event == EVT_VIRTUAL_ENTER_LONG then
ctx.Refresh_Display=true
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",menuLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then
-- reset the value to default
menuLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed
end
return
end
if event == EVT_VIRTUAL_ENTER then
ctx.Refresh_Display=true
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",menuLib.phase2String(ctx.Phase), ctx.SelLine) end
if ctx.SelLine == menuLib.BACK_BUTTON then -- Back
if (menu.BackId==0xFFF9) then
-- SPECIAL Main Menu
GUI_SwitchToMainMenu()
else
menuLib.GotoMenu(menu.BackId,0x80)
end
elseif ctx.SelLine == menuLib.NEXT_BUTTON then -- Next
menuLib.GotoMenu(menu.NextId,0x82)
elseif ctx.SelLine == menuLib.PREV_BUTTON then -- Prev
menuLib.GotoMenu(menu.PrevId,0x81)
elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Navigate to Menu
if (menuLines[ctx.SelLine].ValId==0xFFF1) then
-- SPECIAL Simulation menu to Simulator
GUI_SwitchToSIM()
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
-- SPECIAL Simulation menu to go to RX
GUI_SwitchToRX()
elseif (menuLines[ctx.SelLine].ValId==0xFFF3) then
-- SPECIAL Settup Menu
GUI_SwitchToSetupMenu()
elseif (menuLines[ctx.SelLine].ValId==0xFFF9) then
-- SPECIAL Settup Menu
GUI_SwitchToMainMenu()
else
menuLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
end
else -- Enter on a Value
if ctx.isEditing() then -- already editing a Line????
menuLib.Value_Write_Validate(menuLines[ctx.SelLine])
else -- Edit the current value
ctx.EditLine = ctx.SelLine
originalValue = menuLines[ctx.SelLine].Val
menuLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
end
end
end
end
end
local function init_colors()
-- osName in OpenTX is nil, otherwise is EDGETX
local ver, radio, maj, minor, rev, osname = getVersion()
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
IS_EDGETX = string.sub(osname,1,1) == 'E'
if (IS_EDGETX and USE_SPECKTRUM_COLORS) then
-- SPECKTRUM COLORS (only works on EDGETX)
LCD_TOOL_BGCOLOR = LIGHTWHITE
-- TOOL HEADER
LCD_TOOL_HDR_COLOR = WHITE
LCD_TOOL_HDR_BGCOLOR = DARKBLUE
-- MENU HEADER
LCD_MENU_COLOR = WHITE
LCD_MENU_BGCOLOR = DARKGREY
-- LINE SELECTED
LCD_SELECTED_COLOR = WHITE
LCD_SELECTED_BGCOLOR = ORANGE
LCD_EDIT_BGCOLOR = RED
-- NORMAL TEXT
LCD_NORMAL_COLOR = BLACK
LCD_DISABLE_COLOR = LIGHTGREY
LCD_DEBUG_COLOR = BLUE
-- NORMAL BOX FRAME COLOR
LCD_BOX_COLOR = LIGHTGREY
end
end
local function GUI_Warning(event,touchState)
lcd.clear(LCD_TOOL_BGCOLOR)
local header = "DSM Forward Programming "..VERSION.." "
--Draw title
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
lcd.drawText(100,20,"INFO", BOLD)
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", 0)
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", 0)
lcd.drawText(5,80,"the TX before your start Fwrd programming your RX.", 0)
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", 0)
lcd.drawText(5,150,"TX Gyro Servo settings are sent to the RX during 'Initial Setup'", 0)
lcd.drawText(5,170,"as well as when using RX 'Relearn Servo Settings'", 0)
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD)
lcd.drawText(100,250," OK ", INVERS + BOLD)
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER or event == EVT_TOUCH_TAP then
warningScreenON = false
end
return 0
end
------------------------------------------------------------------------------------------------------------
-- Init
local function DSM_Init()
Log.LOG_open()
init_colors()
modelLib.ReadTxModelData()
modelLib.ST_LoadFileData()
modelLib.CreateDSMPortChannelInfo()
menuLib.Init()
menuProcessor.init()
return 0
end
------------------------------------------------------------------------------------------------------------
-- Main
local function DSM_Run(event,touchState)
local ctx = DSM_Context
if event == nil then
error("Cannot be run as a model script!")
Log.LOG_close()
return 2
end
if (warningScreenON) then
return GUI_Warning(event,touchState)
end
GUI_HandleEvent(event,touchState)
local ret = menuProcessor.run() -- Handle Send and Receive DSM Forward Programming Messages
if ctx.Phase == PHASE.INIT then return 0 end
local refreshInterval = REFRESH_GUI_MS
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
if (ctx.Phase == PHASE.RX_VERSION or ctx.Phase==PHASE.MENU_REQ_TX_INFO) then -- Requesting RX Message Version usea BLINK?
ctx.Refresh_Display=true
refreshInterval = 20 -- 200ms
end
if (not IS_EDGETX) then -- OPENTX NEEDS REFRESH ON EVERY CYCLE
GUI_Display()
-- Refresh display only if needed and no faster than 300ms, utilize more CPU to speedup DSM communications
elseif (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
GUI_Display()
ctx.Refresh_Display=false
lastRefresh=getTime()
end
if ctx.Phase == PHASE.EXIT_DONE then
Log.LOG_close()
return 2
else
return 0
end
end
return { init=DSM_Init, run=DSM_Run }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,951 @@
local toolName = "TNS|DSM Frwd Prog v0.56a (MIN-SETUP)|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 VERSION = "v0.56"
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
local DATA_PATH = "/MODELS/DSMDATA"
local LOG_FILE = "/LOGS/dsm_min_log.txt"
-- Phase
local PH_INIT = 0
local PH_RX_VER, PH_TITLE = 1, 2
local PH_VAL_CHANGING, PH_VAL_EDITING, PH_VAL_EDIT_END = 6, 7, 8
local PH_WAIT_CMD, PH_EXIT_REQ, PH_EXIT_DONE = 9, 10, 11
-- Line Types
local LT_MENU, LT_LIST_NC = 0x1C, 0x6C
local Phase = PH_INIT
local Text = {}
local List_Text = {}
local List_Text_Img = {}
local originalValue = 0
local ctx_SelLine = 0 -- Current Selected Line
local ctx_EditLine = nil -- Current Editing Line
local Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 }
local MenuLines = {}
local logFile = nil
local LCD_W_BUTTONS = 19
local LCD_H_BUTTONS = 10
local LCD_X_MAX = 128
local LCD_X_RIGHT_BUTTONS = LCD_X_MAX - LCD_W_BUTTONS - 1
local LCD_Y_LINE_HEIGHT = 7
local LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2
local TEXT_ATTR = SMLSIZE
local TX_CHANNELS = 12
local AT_PLANE = 0
local aircraft_type_text = {[0]="Plane","Heli","Glider","Drone"}
local WT_A1 = 0
local WT_A2 = 1
local WT_FLPR = 2
local WT_A1_F1 = 3
local WT_A2_F1 = 4
local WT_A2_F2 = 5
local WT_ELEVON_A = 6
local WT_ELEVON_B = 7
local wing_type_text = {[0]="Normal","Dual Ail","Flapperon", "Ail + Flp","Dual Ail + Flp","Dual Ail/Flp","Elevon A","Elevon B"}
local TT_R1 = 0
local TT_R1_E1 = 1
local TT_R1_E2 = 2
local TT_R2_E1 = 3
local TT_R2_E2 = 4
local TT_VT_A = 5
local TT_VT_B = 6
local TT_TLRN_A = 7
local TT_TLRN_B = 8
local TT_TLRN_A_R2 = 9
local TT_TLRN_B_R2 = 10
local tail_type_text = {[0]="Rud Only","Normal","Rud + Dual Ele","Dual Rud + Elv","Dual Rud/Ele",
"VTail A","VTail B","Taileron A","Taileron B",
"Taileron A + Dual Rud","Taileron B + Dual Rud"
}
local MT_NORMAL = 0
local MT_REVERSE = 1
local P1 = 0
local P2 = 1
local P3 = 2
local P4 = 3
local P5 = 4
local P6 = 5
local P7 = 6
local P8 = 7
--local P9 = 8
--local P10 = 9
local MV_AIRCRAFT_TYPE = 1001
local MV_WING_TYPE = 1002
local MV_TAIL_TYPE = 1003
local MV_CH_BASE = 1010
local MV_CH_THR = 1010
local MV_CH_L_AIL = 1011
local MV_CH_R_AIL = 1012
local MV_CH_L_FLP = 1013
local MV_CH_R_FLP = 1014
local MV_CH_L_RUD = 1015
local MV_CH_R_RUD = 1016
local MV_CH_L_ELE = 1017
local MV_CH_R_ELE = 1018
local MV_PORT_BASE = 1020
local MV_P1_MODE = 1020
--local MV_P2_MODE = 1021
--local MV_P3_MODE = 1022
--local MV_P4_MODE = 1023
--local MV_P5_MODE = 1024
local MV_P6_MODE = 1025
--local MV_P7_MODE = 1026
--local MV_P8_MODE = 1027
--local MV_P9_MODE = 1028
--local MV_P10_MODE = 1029
local MV_DATA_END = 1040
-- MENU DATA Management
local M_DB = {} -- Store the variables used in the Menus.
local lastGoodMenu=0
local currATyp = -1
local currTTyp = -1
local currWTyp = -1
local menuDataChanged = false
local MODEL = {
modelName = "", -- The name of the model comming from OTX/ETX
hashName = nil,
modelOutputChannel = {}, -- Output information from OTX/ETX
TX_CH_TEXT= { },
PORT_TEXT = { },
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
}
local function gc()
collectgarbage("collect")
end
--[[
local function gcTable(t)
if type(t)=="table" then
for i,v in pairs(t) do
if type(v) == "table" then
gcTable(v)
end
t[i] = nil
end
end
gc()
return t
end
--]]
local function LOG_open()
logFile = io.open(LOG_FILE, "w") -- Truncate Log File
end
local function LOG_write(...)
if (logFile == nil) then LOG_open() end
local str = string.format(...)
io.write(logFile, str)
end
local function LOG_close()
if (logFile ~= nil) then io.close(logFile) end
end
-- Saves MENU_DATA to a file
local function ST_SaveFileData()
local fname = MODEL.hashName
print("Saving File:"..fname)
local dataFile = assert(io.open(DATA_PATH .. "/" .. fname, "w"),"Please create "..DATA_PATH.." folder") -- write File
-- Foreach MENU_DATA with a value write Var_Id:Value into file
for i = 0, MV_DATA_END do
if (M_DB[i]~=nil) then
io.write(dataFile,string.format("%s:%s\n",i,M_DB[i]))
end
end
io.close(dataFile)
end
local function tailTypeCompatible(a,b)
local function normalize(tt)
if (tt==TT_TLRN_A or tt==TT_TLRN_B) then
return TT_TLRN_A
elseif (tt==TT_TLRN_A_R2 or tt==TT_TLRN_B_R2) then
return TT_TLRN_A_R2
elseif (tt==TT_VT_A or tt==TT_VT_B) then
return TT_VT_A
else
return tt
end
end
return (normalize(a)==normalize(b))
end
local function ST_PlaneWingInit(wingType)
--print("Change Plane WingType:"..wing_type_text[wingType])
M_DB[MV_WING_TYPE] = wingType
-- Clear all Wing Data
M_DB[MV_CH_L_AIL] = nil
M_DB[MV_CH_R_AIL] = nil
M_DB[MV_CH_L_FLP] = nil
M_DB[MV_CH_R_FLP] = nil
M_DB[MV_CH_THR] = P1
-- Default Channel Assisgments for each Wing type
if (wingType==WT_A1) then
M_DB[MV_CH_L_AIL] = P2
elseif (wingType==WT_A2 or wingType==WT_FLPR) then
M_DB[MV_CH_L_AIL] = P6
M_DB[MV_CH_R_AIL] = P2
elseif (wingType==WT_A1_F1) then
M_DB[MV_CH_L_AIL] = P2
M_DB[MV_CH_L_FLP] = P6
elseif (wingType==WT_A2_F1) then
M_DB[MV_CH_L_AIL] = P6
M_DB[MV_CH_R_AIL] = P2
M_DB[MV_CH_L_FLP] = P5
elseif (wingType==WT_A2_F2) then
M_DB[MV_CH_L_AIL] = P6
M_DB[MV_CH_R_AIL] = P2
M_DB[MV_CH_R_FLP] = P5
M_DB[MV_CH_L_FLP] = P7
elseif (wingType==WT_ELEVON_A) then
M_DB[MV_CH_L_AIL] = P2
M_DB[MV_CH_R_AIL] = P3
elseif (wingType==WT_ELEVON_B) then
M_DB[MV_CH_L_AIL] = P3
M_DB[MV_CH_R_AIL] = P2
else -- Assume normal
print("ERROR: Invalid Wing Type")
end
end
local function ST_PlaneTailInit(tailType)
if (M_DB[MV_WING_TYPE]==WT_ELEVON_A or
M_DB[MV_WING_TYPE]==WT_ELEVON_B) then
tailType = TT_R1 -- Delta only have ruder
end
--print("Change Plane Tail Type:"..tail_type_text[tailType])
-- Clear all data for Tail
M_DB[MV_TAIL_TYPE] = tailType
M_DB[MV_CH_L_ELE] = nil
M_DB[MV_CH_R_ELE] = nil
M_DB[MV_CH_L_RUD] = nil
M_DB[MV_CH_R_RUD] = nil
-- Setup Channels for different Tail types
if (tailType == TT_R1) then
M_DB[MV_CH_L_RUD] = P4
elseif (tailType == TT_R1_E1) then
M_DB[MV_CH_L_ELE] = P3
M_DB[MV_CH_L_RUD] = P4
elseif (tailType == TT_R1_E2) then
M_DB[MV_CH_L_ELE] = P5
M_DB[MV_CH_R_ELE] = P3
M_DB[MV_CH_L_RUD] = P4
elseif (tailType == TT_R2_E1) then
M_DB[MV_CH_L_ELE] = P3
M_DB[MV_CH_L_RUD] = P4
M_DB[MV_CH_R_RUD] = P5
elseif (tailType == TT_R2_E2) then
M_DB[MV_CH_L_ELE] = P5
M_DB[MV_CH_R_ELE] = P3
M_DB[MV_CH_L_RUD] = P4
M_DB[MV_CH_R_RUD] = P6
elseif (tailType == TT_VT_A or tailType == TT_VT_B) then
M_DB[MV_CH_L_ELE] = P3
M_DB[MV_CH_R_ELE] = P4
elseif (tailType == TT_TLRN_A or tailType == TT_TLRN_B or
tailType == TT_TLRN_A_R2 or tailType == TT_TLRN_B_R2) then
M_DB[MV_CH_L_RUD] = P4
M_DB[MV_CH_L_ELE] = P5
M_DB[MV_CH_R_ELE] = P3
else -- Assume Normal
print("ERROR:invalid Tail Type")
end
if (tailType == TT_TLRN_A_R2 or tailType == TT_TLRN_B_R2) then
M_DB[MV_CH_R_RUD] = P8
end
end
local function ST_AircraftInit(aircraftType)
M_DB[MV_AIRCRAFT_TYPE] = aircraftType
ST_PlaneWingInit(WT_A1)
ST_PlaneTailInit(TT_R1_E1)
end
-- Setup Initial Default Data for the Menus
local function ST_Default_Data()
ST_AircraftInit(AT_PLANE)
for i=0,9 do
M_DB[MV_P1_MODE+i] = MT_NORMAL + MODEL.modelOutputChannel[P1+i].revert
end
end
local function MenuLinePostProcessing(line)
line.MenuId = Menu.MenuId
if line.Type == LT_MENU then
-- nothing to do on menu entries
line.Val=nil
elseif line.Type == LT_LIST_NC then
-- Normalize Min/Max to be relative to Zero
line.TextStart = line.Min
line.Def = line.Def - line.Min -- normalize default value
line.Max = line.Max - line.Min -- normalize max index
line.Min = 0 -- min index
end
end
local function portUse(p)
local out = nil
if p==M_DB[MV_CH_THR] then out = "Thr"
elseif p == M_DB[MV_CH_L_AIL] then
out=(M_DB[MV_CH_R_AIL] and "Ail_L") or "Ail"
elseif p == M_DB[MV_CH_R_AIL] then out="Ail_R"
elseif p == M_DB[MV_CH_L_ELE] then
out=(M_DB[MV_CH_R_ELE] and "Ele_L") or "Ele"
elseif p == M_DB[MV_CH_R_ELE] then out="Ele_R"
elseif p == M_DB[MV_CH_L_RUD] then
out=(M_DB[MV_CH_R_RUD] and "Rud_L") or "Rud"
elseif p == M_DB[MV_CH_R_RUD] then out="Rud-R"
elseif p == M_DB[MV_CH_L_FLP] then
out=(M_DB[MV_CH_R_FLP] and "Flp_L") or "Flp"
elseif p == M_DB[MV_CH_R_FLP] then out="Flp_R"
else
out = ""
end
return out
end
-- Creates the menus to Render with the GUI
local function ST_LoadMenu(menuId)
local function Header(p)
return MODEL.PORT_TEXT[p].." "..portUse(p)
end
local function generateGyroReverse(menuId, P_BASE, V_BASE)
for i=0,4 do
MenuLines[i] = { Type = LT_LIST_NC, Text=Header(P_BASE+i), TextId = 0, ValId = V_BASE+i, Min=45, Max=46, Def=45, Val=M_DB[V_BASE+i] }
end
MenuLines[5] = { Type = LT_MENU, Text="Only TAER affects AS3X/SAFE react dir", TextId = 0, ValId = menuId }
MenuLines[6] = { Type = LT_MENU, Text="If changes, RX 'Relearn Servo'", TextId = 0, ValId = menuId }
ctx_SelLine = 0
end
-- Begin
for i = 0, 6 do -- clear menu
MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0 }
end
if (menuId==0x1000) then -- MAIN MENU
Menu = { MenuId = 0x1000, Text = "Save-Exit ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
if (true) then
MenuLines[4] = { Type = LT_MENU, Text="Save Changes", TextId = 0, ValId = 0x1005 }
MenuLines[5] = { Type = LT_MENU, Text="Discard Changes", TextId = 0, ValId = 0xFFF9 }
ctx_SelLine = 4
end
lastGoodMenu = menuId
elseif (menuId==0x1001) then -- MODEL SETUP
local backId = 0xFFF9 -- No changes, just exit
local title = "Setup ("..MODEL.modelName..")"
if (menuDataChanged) then
backId = 0x1000 -- Go to Save menu
title = title.." *"
end
Menu = { MenuId = 0x1001, Text = title, PrevId = 0, NextId = 0, BackId = backId, TextId=0 }
MenuLines[0] = { Type = LT_MENU, Text = "Aircraft Setup", ValId = 0x1010,TextId=0 }
MenuLines[1] = { Type = LT_MENU, Text = "Wing & Tail Channels ", ValId = 0x1020, TextId=0 }
MenuLines[3] = { Type = LT_MENU, Text = "Gyro Channel Reverse", ValId = 0x1030, TextId=0 }
MenuLines[5] = { Type = LT_MENU, Text = "WARNING: Changing of Aircraft", ValId = 0x1001, TextId=0 }
MenuLines[6] = { Type = LT_MENU, Text = "deletes prev Ch/Port assgmt.", ValId = 0x1001, TextId=0 }
ctx_SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x1005) then
ST_SaveFileData()
menuDataChanged = false
local msg1 = "Data saved to: "
local msg2 = " ../DSMLIB/"..MODEL.hashName
Menu = { MenuId = 0x1005, Text = "Config Saved", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
MenuLines[2] = { Type = LT_MENU, Text=msg1, TextId = 0, ValId = 0x1005 }
MenuLines[3] = { Type = LT_MENU, Text=msg2, TextId = 0, ValId = 0x1005 }
MenuLines[6] = { Type = LT_MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 }
ctx_SelLine = 6
lastGoodMenu = menuId
elseif (menuId==0x1010) then
Menu = { MenuId = 0x1010, Text = "Aircraft", PrevId = 0, NextId = 0x1011, BackId = 0x1001, TextId=0 }
MenuLines[5] = { Type = LT_LIST_NC, Text="Aircraft Type", TextId = 0, ValId = MV_AIRCRAFT_TYPE, Min=15, Max=15, Def=15, Val=M_DB[MV_AIRCRAFT_TYPE] }
ctx_SelLine = 5
lastGoodMenu = menuId
elseif (menuId==0x1011) then
Menu = { MenuId = 0x1011, Text = "Model Type: "..aircraft_type_text[currATyp], PrevId = 0, NextId = 0x1020, BackId = 0x1010, TextId=0 }
MenuLines[5] = { Type = LT_LIST_NC, Text="Wing Type", TextId = 0, ValId = MV_WING_TYPE, Min=20, Max=27, Def=20, Val=M_DB[MV_WING_TYPE] }
MenuLines[6] = { Type = LT_LIST_NC, Text="Tail Type", TextId = 0, ValId = MV_TAIL_TYPE, Min=30, Max=40, Def=30, Val=M_DB[MV_TAIL_TYPE] }
ctx_SelLine = 5
lastGoodMenu = menuId
elseif (menuId==0x1020) then
------ WING SETUP -------
local thr = M_DB[MV_CH_THR]
local leftAil = M_DB[MV_CH_L_AIL]
local rightAil = M_DB[MV_CH_R_AIL]
local leftFlap = M_DB[MV_CH_L_FLP]
local rightFlap = M_DB[MV_CH_R_FLP]
local thrText = "Thr"
local leftAilText = "Left Ail"
local rightAilText = "Right Ail"
local leftFlapText = "Left Flap"
local rightFlapText = "Right Flap"
if (rightAil==nil) then leftAilText = "Aileron" end
if (rightFlap==nil) then leftFlapText = "Flap" end
local title = aircraft_type_text[currATyp].." Wing:"..wing_type_text[currWTyp]
Menu = { MenuId = 0x1020, Text = title, PrevId = 0, NextId = 0x1021, BackId = 0x1011, TextId=0 }
MenuLines[0] = { Type = LT_LIST_NC, Text=thrText, TextId = 0, ValId = MV_CH_THR, Min=0, Max=10, Def=0, Val= thr }
MenuLines[2] = { Type = LT_LIST_NC, Text=leftAilText, TextId = 0, ValId = MV_CH_L_AIL, Min=0, Max=9, Def=0, Val= leftAil }
if (rightAil) then
MenuLines[3] = { Type = LT_LIST_NC, Text=rightAilText, TextId = 0, ValId = MV_CH_R_AIL, Min=0, Max=9, Def=0, Val= rightAil }
end
if (leftFlap) then
MenuLines[4] = { Type = LT_LIST_NC, Text=leftFlapText, TextId = 0, ValId = MV_CH_L_FLP, Min=0, Max=9, Def=0, Val= leftFlap }
end
if (rightFlap) then
MenuLines[5] = { Type = LT_LIST_NC, Text=rightFlapText, TextId = 0, ValId = MV_CH_R_FLP, Min=0, Max=9, Def=0, Val= rightFlap }
end
ctx_SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x1021) then
------ TAIL SETUP -------
local leftRud = M_DB[MV_CH_L_RUD]
local rightRud = M_DB[MV_CH_R_RUD]
local leftEle = M_DB[MV_CH_L_ELE]
local rightEle = M_DB[MV_CH_R_ELE]
local leftRudText = "Left Rud"
local rightRudText = "Right Rud"
local leftElvText = "Left Ele"
local rightElvText = "Right Ele"
if (rightRud==nil) then leftRudText = "Rud" end
if (rightEle==nil) then leftElvText = "Ele" end
local title = aircraft_type_text[currATyp].." Tail:"..tail_type_text[currTTyp]
Menu = { MenuId = 0x1021, Text = title, PrevId = 0, NextId = 0x1001, BackId = 0x1020, TextId=0 }
if (leftRud) then
MenuLines[1] = { Type = LT_LIST_NC, Text=leftRudText, TextId = 0, ValId = MV_CH_L_RUD, Min=0, Max=9, Def=0, Val= leftRud}
end
if (rightRud) then
MenuLines[2] = { Type = LT_LIST_NC, Text=rightRudText, TextId = 0, ValId = MV_CH_R_RUD, Min=0, Max=9, Def=0, Val=rightRud }
end
if (leftEle) then
MenuLines[4] = { Type = LT_LIST_NC, Text=leftElvText, TextId = 0, ValId = MV_CH_L_ELE, Min=0, Max=9, Def=0, Val=leftEle }
end
if (rightEle) then
MenuLines[5] = { Type = LT_LIST_NC, Text=rightElvText, TextId = 0, ValId = MV_CH_R_ELE, Min=0, Max=9, Def=0, Val=rightEle }
end
ctx_SelLine = 1
lastGoodMenu = menuId
elseif (menuId==0x1030) then
Menu = { MenuId = 0x1030, Text = "Gyro Reverse (Port 1-5)", PrevId = 0, NextId = 0x1031, BackId = 0x1001, TextId=0 }
generateGyroReverse(menuId,P1,MV_P1_MODE)
lastGoodMenu = menuId
elseif (menuId==0x1031) then
Menu = { MenuId = 0x1031, Text = "Gyro Reverse (Port 6-10)", PrevId = 0x1030, NextId = 0, BackId = 0x1001, TextId=0 }
generateGyroReverse(menuId,P6,MV_P6_MODE)
lastGoodMenu = menuId
elseif (menuId==0xFFF9) then
ChangePhase(PH_EXIT_DONE)
return
else
Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
ctx_SelLine = -1 -- BACK BUTTON
end
for i = 0, 6 do
if (MenuLines[i].Type > 0) then
MenuLinePostProcessing(MenuLines[i])
end
end
gc()
end
-- Inital List and Image Text for this menus
local function ST_Init_Text(rxId)
-- Channel Names use the Port Text Retrived from OTX/ETX
local p = 0
for i = 0, 9 do List_Text[i] = MODEL.PORT_TEXT[i] end
List_Text[10] = "--"
-- Aircraft Type
List_Text[15+AT_PLANE] = "Airplane";
-- Wing Types
p = 20+WT_A1; List_Text[p] = "Single Ail"; --List_Text_Img[p] = "x.png|Single Aileron"
p = 20+WT_A2; List_Text[p] = "Dual Ail"; --List_Text_Img[p] = "x.png|Dual Aileron"
p = 20+WT_FLPR; List_Text[p] = "Flaperon"; --List_Text_Img[p] = "x.png|Flaperon"
p = 20+WT_A1_F1; List_Text[p] = "Ail + Flap"; --List_Text_Img[p] = "x.png|Aileron + Flap"
p = 20+WT_A2_F1; List_Text[p] = "Dual Ail + Flap"; --List_Text_Img[p] = "x.png|Dual Aileron + Flap"
p = 20+WT_A2_F2; List_Text[p] = "Dual Ail + Dual Flap"; --List_Text_Img[p] = "x.png|Dual Aileron + Dual Flap"
p = 20+WT_ELEVON_A; List_Text[p] = "Delta A"; --List_Text_Img[p] = "x.png|Delta/Elevon A"
p = 20+WT_ELEVON_B; List_Text[p] = "Delta B"; --List_Text_Img[p] = "x.png|Delta/Elevon B"
-- Tail Types
p = 30+TT_R1; List_Text[p] = "Rudder Only"; --List_Text_Img[p] = "x.png|Rudder Only"
p = 30+TT_R1_E1; List_Text[p] = "Rud + Ele"; --List_Text_Img[p] = "x.png|Tail Normal"
p = 30+TT_R1_E2; List_Text[p] = "Rud + Dual Ele"; --List_Text_Img[p] = "x.png|Rud + Dual Ele"
p = 30+TT_R2_E1; List_Text[p] = "Dual Rud + Ele"; --List_Text_Img[p] = "x.png|Dual Rud + Ele"
p = 30+TT_R2_E2; List_Text[p] = "Dual Rud + Dual Ele"; --List_Text_Img[p] = "x.png|Dual Rud + Dual Elev"
p = 30+TT_VT_A; List_Text[p] = "V-Tail A"; --List_Text_Img[p] = "x.png|V-Tail A"
p = 30+TT_VT_B; List_Text[p] = "V-Tail B"; --List_Text_Img[p] = "x.png|V-Tail B"
p = 30+TT_TLRN_A; List_Text[p] = "Taileron A"; --List_Text_Img[p] = "x.png|Taileron A"
p = 30+TT_TLRN_B; List_Text[p] = "Taileron B"; --List_Text_Img[p] = "x.png|Taileron B"
p = 30+TT_TLRN_A_R2; List_Text[p] = "Taileron A + 2x Rud"; --List_Text_Img[p] = "x.png|Taileron A + Dual Rud"
p = 30+TT_TLRN_B_R2; List_Text[p] = "Taileron B + 2x Rud"; --List_Text_Img[p] = "x.png|Taileron B + Dual Rud"
-- Servo Reverse
List_Text[45+MT_NORMAL] = "Normal"
List_Text[45+MT_REVERSE] = "Reverse"
end
-- Initial Setup
local function ST_Init()
ST_Init_Text(0)
gc()
-- Setup default Data if no data loaded
menuDataChanged = false
if (M_DB[MV_AIRCRAFT_TYPE]==nil) then
ST_Default_Data()
menuDataChanged = true
end
currATyp = M_DB[MV_AIRCRAFT_TYPE]
currWTyp = M_DB[MV_WING_TYPE]
currTTyp = M_DB[MV_TAIL_TYPE]
Phase = PH_RX_VER
end
----- Line Type
local function isSelectable(line)
if (line.Type == LT_MENU and line.ValId == line.MenuId) then return false end -- Menu to same page
if (line.Type ~= LT_MENU and line.Max == 0) then return false end -- Read only data line
if (line.Type ~= 0 and line.TextId < 0x8000) then return true end -- Not Flight Mode
return false;
end
local function isListLine(line)
return line.Type==LT_LIST_NC
end
local function isEditing()
return ctx_EditLine ~= nil
end
-----------------------
local function Get_Text(index)
local out = Text[index] or string.format("Unknown_%X", index)
return out
end
local function Get_Text_Value(index)
local out = List_Text[index] or Get_Text(index)
return out
end
function ChangePhase(newPhase)
Phase = newPhase
end
local function Value_Add(dir)
local line = MenuLines[ctx_SelLine]
local inc = dir
line.Val = line.Val + inc
if line.Val > line.Max then
line.Val = line.Max
elseif line.Val < line.Min then
line.Val = line.Min
end
end
--------------
local function GotoMenu(menuId, lastSelectedLine)
Menu.MenuId = menuId
ctx_SelLine = lastSelectedLine
ChangePhase(PH_TITLE)
end
local function DSM_HandleEvent(event)
if event == EVT_VIRTUAL_EXIT then
if Phase == PH_RX_VER then
Phase = PH_EXIT_DONE -- Exit program
else
if isEditing() then -- Editing a Line, need to restore original value
MenuLines[ctx_EditLine].Val = originalValue
event = EVT_VIRTUAL_ENTER
else
if (Menu.BackId > 0 ) then -- Back??
ctx_SelLine = -1 --Back Button
event = EVT_VIRTUAL_ENTER
else
ChangePhase(PH_EXIT_REQ)
end
end
end
end -- Exit
if Phase == PH_RX_VER then return end -- nothing else to do
if event == EVT_VIRTUAL_NEXT then
if isEditing() then -- Editting?
Value_Add(1)
else
if ctx_SelLine < 7 then -- On a regular line
local num = ctx_SelLine -- Find the prev selectable
for i = ctx_SelLine + 1, 6, 1 do
local line = MenuLines[i]
if isSelectable(line) then
ctx_SelLine = i
break
end
end
if num == ctx_SelLine then -- No Selectable Line
if Menu.NextId ~= 0 then
ctx_SelLine = 7 -- Next
elseif Menu.PrevId ~= 0 then
ctx_SelLine = 8 -- Prev
end
end
elseif Menu.PrevId ~= 0 then
ctx_SelLine = 8 -- Prev
end
end
return
end
if event == EVT_VIRTUAL_PREV then
if isEditing() then -- In Edit Mode
Value_Add(-1)
else
if ctx_SelLine == 8 and Menu.NextId ~= 0 then
ctx_SelLine = 7 -- Next
elseif ctx_SelLine > 0 then
if ctx_SelLine > 6 then
ctx_SelLine = 7 --NEXT
end
local num = ctx_SelLine -- Find Prev Selectable line
for i = ctx_SelLine - 1, 0, -1 do
local line = MenuLines[i]
if isSelectable(line) then
ctx_SelLine = i
break
end
end
if num == ctx_SelLine then -- No Selectable Line
if (Menu.BackId > 0) then
ctx_SelLine = -1 -- Back
end
end
else
ctx_SelLine = -1 -- Back
end
end
return
end
if event == EVT_VIRTUAL_ENTER then
if ctx_SelLine == -1 then -- Back
GotoMenu(Menu.BackId, 0x80)
elseif ctx_SelLine == 7 then -- Next
GotoMenu(Menu.NextId, 0x82)
elseif ctx_SelLine == 8 then -- Prev
GotoMenu(Menu.PrevId, 0x81)
elseif ctx_SelLine >= 0 and MenuLines[ctx_SelLine].Type == LT_MENU then
GotoMenu(MenuLines[ctx_SelLine].ValId, ctx_SelLine) -- ValId is the next menu
else
-- value entry
if isEditing() then
ctx_EditLine = nil -- Done Editting
ChangePhase(PH_VAL_EDIT_END)
else -- Start Editing
ctx_EditLine = ctx_SelLine
originalValue = MenuLines[ctx_SelLine].Val
ChangePhase(PH_VAL_EDITING)
end
end
end
end
local function DSM_Send_Receive()
if Phase == PH_RX_VER then -- request RX version
Phase = PH_TITLE
Menu.MenuId = 0x01001
Refresh_Display = true
elseif Phase == PH_WAIT_CMD then
elseif Phase == PH_TITLE then -- request menu title
ST_LoadMenu(Menu.MenuId)
if (Phase~=PH_EXIT_DONE) then
Phase = PH_WAIT_CMD
end
Refresh_Display = true
elseif Phase == PH_VAL_EDIT_END then -- send value
local line = MenuLines[ctx_SelLine] -- Updated Value of SELECTED line
-- Update the menu data from the line
if (M_DB[line.ValId] ~= line.Val ) then
M_DB[line.ValId] = line.Val
print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val))
menuDataChanged=true
end
-- Did the Wing type change?
local wt = M_DB[MV_WING_TYPE]
if (currWTyp ~= wt) then
currWTyp = wt
ST_PlaneWingInit(currWTyp)
-- DELTA has only RUDER
if (currWTyp==WT_ELEVON_A or currWTyp==WT_ELEVON_B) then
M_DB[MV_TAIL_TYPE] = TT_R1
end
end
--- Did the tail changed?
local tt = M_DB[MV_TAIL_TYPE]
if (currTTyp ~= tt) then
if (not tailTypeCompatible(currTTyp,tt)) then
ST_PlaneTailInit(tt)
end
currTTyp = tt
end
Phase = PH_WAIT_CMD
elseif Phase == PH_EXIT_REQ then
Phase=PH_EXIT_DONE
end
end
-----
local function showBitmap(x, y, imgDesc)
local f = string.gmatch(imgDesc, '([^%|]+)') -- Iterator over values split by '|'
local imgName, imgMsg = f(), f()
f = string.gmatch(imgMsg or "", '([^%:]+)') -- Iterator over values split by ':'
local p1, p2 = f(), f()
lcd.drawText(x, y, p1 or "", TEXT_ATTR) -- Alternate Image MSG
lcd.drawText(x, y + LCD_Y_LINE_HEIGHT, p2 or "", TEXT_ATTR) -- Alternate Image MSG
gc()
end
local function drawButton(x, y, text, active)
local attr = TEXT_ATTR
if (active) then attr = attr + INVERS end
lcd.drawText(x, y, text, attr)
end
local function DSM_Display()
lcd.clear()
--Draw RX Menu
if Phase == PH_RX_VER then
return
end
-- display Program version or RX version
local msg = "FProg "..VERSION
lcd.drawText(40, LCD_Y_LOWER_BUTTONS, msg, TEXT_ATTR)
if Menu.MenuId == 0 then return end; -- No Title yet
-- Got a Menu
lcd.drawText(1, 0, Menu.Text, TEXT_ATTR + INVERS)
local y = LCD_Y_LINE_HEIGHT + 2
for i = 0, 6 do
local attrib = TEXT_ATTR
if (i == ctx_SelLine) then attrib = attrib + INVERS end -- Selected Line
local line = MenuLines[i]
if line ~= nil and line.Type ~= 0 then
local heading = line.Text
local text = nil
if line.Type ~= LT_MENU then -- list/value
if line.Val ~= nil then
if isListLine(line) then
local textId = line.Val + line.TextStart
text = Get_Text_Value(textId)
--local imgDesc = List_Text_Img[textId]
--if (imgDesc and i == ctx_SelLine) then -- Optional Image and Msg for selected value
-- showBitmap(1, 20, imgDesc)
--end
else
text = line.Val
end
end -- if is Value
if (ctx_EditLine == i) then -- Editing a Line
attrib = BLINK + INVERS + TEXT_ATTR
end
lcd.drawText(LCD_X_MAX, y, text or "--", attrib + RIGHT) -- display value
--lcd.drawText(LCD_X_MAX, y, line.Format or "", TEXT_ATTR + RIGHT) -- display Format
attrib = TEXT_ATTR
end
lcd.drawText(1, y, heading, attrib) -- display text
end
y = y + LCD_Y_LINE_HEIGHT
end -- for
if Menu.BackId~=0 then
drawButton(LCD_X_RIGHT_BUTTONS, 0, "Back", ctx_SelLine == -1)
end
if Menu.NextId~=0 then
drawButton(LCD_X_RIGHT_BUTTONS, LCD_Y_LOWER_BUTTONS, "Next", ctx_SelLine == 7)
end
if Menu.PrevId~=0 then
drawButton(1, LCD_Y_LOWER_BUTTONS, "Prev", ctx_SelLine == 8)
end
end
------------------------------------------------------------------------------------------------------------
-- Init
local function DSM_Init()
--LOG_open()
ST_Init()
gc()
if (LCD_W > 128) then
TEXT_ATTR = 0
LCD_Y_LINE_HEIGHT = 25
LCD_X_MAX = 300
LCD_X_RIGHT_BUTTONS = LCD_X_MAX - 30
LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2
end
Phase = PH_RX_VER
end
-- Main
local function DSM_Run(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
end
DSM_Display()
DSM_HandleEvent(event)
DSM_Send_Receive()
gc()
if Phase == PH_EXIT_DONE then
LOG_close()
return 2
else
return 0
end
end
---
-- Load Model Config
gc()
local r = assert(loadScript(DSMLIB_PATH.."DsmMIN_P1.lua"), "Not-Found: DSMLIB/DsmMIN_P1.lua")
(MODEL,M_DB, LOG_write)
gc()
----
return { init = DSM_Init, run = DSM_Run }

View File

@ -0,0 +1,813 @@
---- #########################################################################
---- # #
---- # Copyright (C) OpenTX/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. #
---- # #
---- #########################################################################
------------------------------------------------------------------------------
-- This script library is a rewrite of the original DSM forward programming Lua
-- Script. The goal is to make it easier to understand, mantain, and to
-- separate the GUI from the DSM Forward programming engine/logic
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
-- Rewrite/Enhancements By: Francisco Arzu
--
------------------------------------------------------------------------------
--###############################################################################
-- Multi buffer for DSM description
-- Multi_Buffer[0..2]=="DSM" -> Lua script is running
-- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent
-- Multi_Buffer[4..9]=6 bytes of TX to RX data
-- Multi_Buffer[10..25]=16 bytes of RX to TX data
--
-- To start operation:
-- Write 0x00 at address 3
-- Write 0x00 at address 10
-- Write "DSM" at address 0..2
--###############################################################################
local Log, menuLib, modelLib, DEBUG_ON = ... -- Get Debug_ON from parameters. -- 0=NO DEBUG, 1=HIGH LEVEL 2=MORE DETAILS
local LIB_VERSION = "0.55"
local MSG_FILE = "/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt"
local PHASE = menuLib.PHASE
local LINE_TYPE = menuLib.LINE_TYPE
local CH_TYPE = modelLib.CH_TYPE
local CH_MIX_TYPE = modelLib.CH_MIX_TYPE
local DISP_ATTR = menuLib.DISP_ATTR
local DSM_Context = menuLib.DSM_Context
local MODEL = modelLib.MODEL
local MAX_MENU_LINES = menuLib.MAX_MENU_LINES
local BACK_BUTTON = menuLib.BACK_BUTTON
local NEXT_BUTTON = menuLib.NEXT_BUTTON
local PREV_BUTTON = menuLib.PREV_BUTTON
local SEND_TIMEOUT = 2000 / 10 -- Home many 10ms intervals to wait on sending data to tx to keep connection open (2s)
local TXInactivityTime = 0 -- Next time to do heartbeat after inactivity
local RXInactivityTime = 0 -- To check RX disconnection
local TxInfo_Type = 0
local TxInfo_Step = 0
local Change_Step = 0
local IS_EDGETX = false
------------------------------------------------------------------------------------------------------------
local function multiBuffer2String() -- used for debug
local i
local rxAnswer = "RX:"
for i = 10, 25 do
rxAnswer = rxAnswer .. string.format(" %02X", multiBuffer(i))
end
return rxAnswer
end
---------------- DSM Values <-> Int16 Manipulation --------------------------------------------------------
local function int16_LSB(number) -- Less Significat byte
local r,x = bit32.band(number, 0xFF)
return r
end
local function int16_MSB(number) -- Most signifcant byte
return bit32.rshift(number, 8)
end
local function Dsm_to_Int16(lsb, msb) -- Componse an Int16 value
return bit32.lshift(msb, 8) + lsb
end
local function Dsm_to_SInt16(lsb,msb) -- Componse a SIGNED Int16 value
local value = bit32.lshift(msb, 8) + lsb
if value >= 0x8000 then -- Negative value??
return value - 0x10000
end
return value
end
local function sInt16ToDsm(value) -- Convent to SIGNED DSM Value
if value < 0 then
value = 0x10000 + value
end
return value
end
------------------------------------------------------------------------------------------------------------
local function DSM_send(...)
local arg = { ... }
for i = 1, #arg do
multiBuffer(3 + i, arg[i])
end
multiBuffer(3, 0x70 + #arg)
if (DEBUG_ON > 1) then
local str = ""
for i = 1, #arg do
str = str .. string.format("%02X ", arg[i])
end
LOG_write("DSM_SEND: [%s]\n", str)
end
end
-------------------------------------------------------------------------------------------------
local function DSM_StartConnection()
if (DEBUG_ON) then Log.LOG_write("DSM_StartConnection()\n") end
--Set protocol to talk to
multiBuffer( 0, string.byte('D') )
--test if value has been written
if multiBuffer( 0 ) ~= string.byte('D') then
if (DEBUG_ON) then Log.LOG_write("Not Enouth memory\n") end
error("Not enough memory!")
return 2
end
--Init TX buffer
multiBuffer( 3, 0x00 )
--Init RX buffer
multiBuffer( 10, 0x00 )
--Init telemetry
multiBuffer( 0, string.byte('D') )
multiBuffer( 1, string.byte('S') )
multiBuffer( 2, string.byte('M') )
return 0
end
local function DSM_ReleaseConnection()
if (DEBUG_ON) then Log.LOG_write("DSM_ReleaseConnection()\n") end
multiBuffer(0, 0)
end
--------------------------------------------------------------------------------------------------------
-- REEQUEST Messages to RX
local function DSM_sendHeartbeat()
-- keep connection open
if (DEBUG_ON) then Log.LOG_write("SEND DSM_sendHeartbeat()\n") end
DSM_send(0x00, 0x04, 0x00, 0x00)
end
local function DSM_getRxVerson()
local TX_CAP=0x14 -- Capabilities??
local TX_MAX_CH = modelLib.TX_CHANNELS - 6 --number of channels after 6 (6Ch=0, 10ch=4, etc)
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getRxVersion(Ch:0x%X,Cap:0x%X)\n",TX_MAX_CH,TX_CAP) end
DSM_send(0x11, 0x06, TX_MAX_CH, TX_CAP, 0x00, 0x00)
end
local function DSM_getMainMenu()
local TX_CAP=0x14 -- Capabilities??
local TX_MAX_CH = modelLib.TX_CHANNELS - 6 --number of channels after 6 (6Ch=0, 10ch=4, etc)
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getMainMenu(Ch:0x%X,Cap:0x%X) -- TX_Channels=%d\n",TX_MAX_CH,TX_CAP,TX_MAX_CH+6) end
DSM_send(0x12, 0x06, TX_MAX_CH, TX_CAP, 0x00, 0x00) -- first menu only
end
local function DSM_getMenu(menuId, latSelLine)
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getMenu(MenuId=0x%X LastSelectedLine=%s)\n", menuId, latSelLine) end
DSM_send(0x16, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, latSelLine)
end
local function DSM_getFirstMenuLine(menuId)
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getFirstMenuLine(MenuId=0x%X)\n", menuId) end
DSM_send(0x13, 0x04, int16_MSB(menuId), int16_LSB(menuId)) -- line 0
end
local function DSM_getNextMenuLine(menuId, curLine)
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getNextLine(MenuId=0x%X,LastLine=%s)\n", menuId, curLine) end
DSM_send(0x14, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, curLine) -- line X
end
local function DSM_getNextMenuValue(menuId, valId, text)
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getNextMenuValue(MenuId=0x%X, LastValueId=0x%X) Extra: Text=\"%s\"\n", menuId, valId,
text)
end
DSM_send(0x15, 0x06, int16_MSB(menuId), int16_LSB(menuId), int16_MSB(valId), int16_LSB(valId)) -- line X
end
local function DSM_updateMenuValue(valId, val, text, line)
local value = sInt16ToDsm(val)
if (DEBUG_ON) then Log.LOG_write("SEND DSM_updateValue(ValueId=0x%X,val=%d) Extra: Text=\"%s\" Value=%s\n", valId, val, text, menuLib.lineValue2String(line)) end
DSM_send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value)) -- send current value
end
local function DSM_validateMenuValue(valId, text, line)
if (DEBUG_ON) then Log.LOG_write("SEND DSM_validateValue(ValueId=0x%X) Extra: Text=\"%s\" Value=%s\n", valId, text, menuLib.lineValue2String(line)) end
DSM_send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId))
end
local function DSM_editingValue(lineNum, text, line)
if (DEBUG_ON) then Log.LOG_write("SEND DSM_editingValue(lineNo=0x%X) Extra: Text=\"%s\" Val=%s\n", lineNum, text, menuLib.lineValue2String(line)) end
DSM_send(0x1A, 0x04, int16_MSB(lineNum), int16_LSB(lineNum))
end
local function DSM_editingValueEnd(lineNum, text, line)
if (DEBUG_ON) then Log.LOG_write("SEND DSM_editingValueEnd(lineNo=0x%X) Extra: Text=\"%s\" Value=%s\n", lineNum, text, menuLib.lineValue2String(line)) end
DSM_send(0x1B, 0x04, int16_MSB(lineNum), int16_LSB(lineNum))
end
-- Send the functionality of the RX channel Port (channel)
local function DSM_sendTxChInfo_20(portNo)
local b1,b2 = MODEL.DSM_ChannelInfo[portNo][0] or 0, MODEL.DSM_ChannelInfo[portNo][1] or 0
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxChInfo(#%d DATA= %02X %02X %02X %02X) %s\n", portNo,
portNo, portNo, b1, b2, modelLib.channelType2String(b1,b2)) -- DATA part
end
DSM_send(0x20, 0x06, portNo, portNo, b1, b2)
end
local function DSM_sendTxSubtrim_21(portNo)
local usage = MODEL.DSM_ChannelInfo[portNo][1] or 0
local leftTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].min/10))
local rightTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].max/10))
local subTrim = math.floor(MODEL.modelOutputChannel[portNo].offset/10)
-- Center at 100%: 142-1906 (0 8E 07 72)
local left = 142
local right = 1906
if (bit32.band(usage,CH_TYPE.THR)>0) then
left = 0
right = 2047
end
left = math.floor (left - (leftTravel -100) *8.8 + subTrim*2)
right = math.floor (right + (rightTravel -100) *8.8 + subTrim*2)
if (left<0) then left=0 end
if (right>2027) then right=2047 end
local b1,b2,b3,b4 = int16_MSB(left), int16_LSB(left), int16_MSB(right), int16_LSB(right)
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxSubtrim(#%d DATA=%02X %02X %02X %02X) Range(%d - %d) ER L/R:(%d - %d)x8 ST:(%d)x2\n", portNo,
b1,b2,b3,b4, left, right, leftTravel-100, rightTravel-100, subTrim) -- DATA part
end
DSM_send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it.
end
local function DSM_sendTxServoTravel_23(portNo)
local leftTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].min/10))
local rightTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].max/10))
local debugInfo = string.format("Travel L/R (%d - %d)",leftTravel,rightTravel)
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxServoTravel(#%d DATA= %02X %02X %02X %02X) %s\n", portNo,
0x00, leftTravel, 0x00, rightTravel, debugInfo) -- DATA part
end
DSM_send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel)
end
local function DSM_sentTxInfo(menuId,portNo)
-- TxInfo_Type=0 : AR636B Main Menu (Send port/Channel info + SubTrim + Travel)
-- TxInfo_Type=1 : AR630-637 Famly Main Menu (Only Send Port/Channel usage Msg 0x20)
-- TxInfo_Type=1F : AR630-637 Initial Setup/Relearn Servo Settings (Send port/Channel info + SubTrim + Travel +0x24/Unknown)
if (TxInfo_Step == 0) then
-- AR630 family: Both TxInfo_Type (ManinMenu=0x1, Other First Time Configuration = 0x1F)
DSM_sendTxChInfo_20(portNo)
if (TxInfo_Type == 0x1F) then
TxInfo_Step = 1
end
if (TxInfo_Type == 0x00) then
TxInfo_Step = 2
end
elseif (TxInfo_Step == 1) then
DSM_sendTxServoTravel_23(portNo)
TxInfo_Step = 2
elseif (TxInfo_Step == 2) then
DSM_sendTxSubtrim_21(portNo)
if (TxInfo_Type == 0x00) then
TxInfo_Step = 5 -- End Step
else
TxInfo_Step = 3
end
elseif (TxInfo_Step == 3) then
-- 24,6: 0 83 5A B5
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo,
0x00, 0x83, 0x5A, 0xB5) -- DATA part
end
DSM_send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown
TxInfo_Step = 4
elseif (TxInfo_Step == 4) then
-- 24,6: 6 80 25 4B
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo,
0x06, 0x80, 0x25, 0x4B) -- DATA part
end
DSM_send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown
TxInfo_Step = 5
elseif (TxInfo_Step == 5) then
-- 22,4: 0 0
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo_End(#%d)\n", portNo)
end
DSM_send(0x22, 0x04, 0x00, 0x00)
TxInfo_Step = 0
end
if (TxInfo_Step > 0) then
DSM_Context.SendDataToRX = 1 -- keep Transmitig
end
end
-----------------------------------------------------------------------------------------------------------
local function DSM_sendRequest()
-- Send the proper Request message depending on the Phase
local ctx = DSM_Context
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
if ctx.Phase == PHASE.RX_VERSION then -- request RX version
DSM_getRxVerson()
elseif ctx.Phase == PHASE.WAIT_CMD then -- keep connection open
DSM_sendHeartbeat()
elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title
if ctx.Menu.MenuId == 0 then -- First time loading a menu ?
DSM_getMainMenu()
else
DSM_getMenu(ctx.Menu.MenuId, ctx.SelLine)
if (ctx.Menu.MenuId == 0x0001) then -- Executed the Reset Menu??
if (DEBUG_ON) then Log.LOG_write("RX Reset!!!\n") end
-- Start again retriving RX info
ctx.Menu.MenuId = 0
ctx.isReset = true
ctx.Phase = PHASE.RX_VERSION
end
end
elseif ctx.Phase == PHASE.MENU_REQ_TX_INFO then
DSM_sentTxInfo(ctx.Menu.MenuId, ctx.CurLine)
elseif ctx.Phase == PHASE.MENU_LINES then -- request next menu lines
if ctx.CurLine == -1 then -- No previous menu line loaded ?
DSM_getFirstMenuLine(ctx.Menu.MenuId)
else
DSM_getNextMenuLine(ctx.Menu.MenuId, ctx.CurLine)
end
elseif ctx.Phase == PHASE.MENU_VALUES then -- request menu values
local line = ctx.MenuLines[ctx.CurLine]
DSM_getNextMenuValue(ctx.Menu.MenuId, line.ValId, line.Text)
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
if (Change_Step==0) then
DSM_updateMenuValue(line.ValId, line.Val, line.Text, line)
if line.Type == menuLib.LINE_TYPE.LIST_MENU then -- Validation on every Step??
Change_Step=1; ctx.SendDataToRX=1 -- Send inmediatly after
else
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
end
else
DSM_validateMenuValue(line.ValId, line.Text, line)
Change_Step=0
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
end
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
local line = ctx.MenuLines[ctx.SelLine]
DSM_editingValue(line.lineNum, line.Text, line)
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
local line = ctx.MenuLines[ctx.SelLine] -- Update Value of SELECTED line
if (Change_Step==0) then
DSM_updateMenuValue(line.ValId, line.Val, line.Text, line)
Change_Step=1; ctx.SendDataToRX=1 -- Send inmediatly after
elseif (Change_Step==1) then
DSM_validateMenuValue(line.ValId, line.Text, line)
Change_Step=2; ctx.SendDataToRX=1 -- Send inmediatly after
else
DSM_editingValueEnd(line.lineNum, line.Text, line)
Change_Step=0
ctx.Phase = PHASE.WAIT_CMD
end
elseif ctx.Phase == PHASE.EXIT then
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TX_Exit()\n") end
DSM_send(0x1F, 0x02, 0xFF, 0xFF) -- 0xAA
end
end
-----------------------------------------------------------------------------------------------------------
-- Parsing Responses
local function DSM_parseRxVersion()
--ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 v2.22.1 00 14?? 8ch SAFE
-- 0x09 0x01 0x00 0x18 0x05 0x06 0x34 0x00 0x12 v5.6.52 00 12??? 6ch FC6250
local rxId = multiBuffer(13)
DSM_Context.RX.Id = rxId
DSM_Context.RX.Name = menuLib.Get_RxName(rxId)
DSM_Context.RX.Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16)
if (DEBUG_ON) then Log.LOG_write("RESPONSE Receiver=%s Version %s Cap:0x%02X\n",
DSM_Context.RX.Name, DSM_Context.RX.Version, multiBuffer(18)) end
end
local function DSM_parseMenu()
--ex: 0x09 0x02 0x4F 0x10 0xA5 0x00 0x00 0x00 0x50 0x10 0x10 0x10 0x00 0x00 0x00 0x00
-- MenuID TextID PrevID NextID BackID
local ctx = DSM_Context
local menu = ctx.Menu
menu.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
menu.TextId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15))
menu.Text = menuLib.Get_Text(menu.TextId)
menu.PrevId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17))
menu.NextId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19))
menu.BackId = Dsm_to_Int16(multiBuffer(20), multiBuffer(21))
for i = 0, MAX_MENU_LINES do -- clear menu
ctx.MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0, Text = "", TextId = 0, ValId = 0, Min=0, Max=0, Def=0, Val=nil }
end
ctx.CurLine = -1
menuLib.MenuPostProcessing(menu)
if (DEBUG_ON) then Log.LOG_write("RESPONSE Menu: %s\n", menuLib.menu2String(menu)) end
return menu
end
local function DSM_parseMenuLine()
--ex: 0x09 0x03 0x00 0x10 0x00 0x1C 0xF9 0x00 0x10 0x10 0x00 0x00 0x00 0x00 0x03 0x00
--ex: 0x09 0x03 0x61 0x10 0x00 0x6C 0x50 0x00 0x00 0x10 0x36 0x00 0x49 0x00 0x36 0x00
--ex: 0x09 0x03 0x65 0x10 0x00 0x0C 0x51 0x00 0x00 0x10 0x00 0x00 0xF4 0x00 0x2E 0x00
-- MenuLSB MenuMSB line Type TextID NextLSB NextMSB Val_Min Val_Max Val_Def
local ctx = DSM_Context
local i = multiBuffer(14)
local type = multiBuffer(15)
local line = ctx.MenuLines[i]
-- are we trying to override existing line
if (line.Type > 0 and type == 0) then
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuLine: ERROR. Trying to ZERO Override: %s\n", menuLib.menuLine2String(line)) end
return ctx.MenuLines[ctx.CurLine]
end
ctx.CurLine = i
line.lineNum = i
line.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
line.Type = type
line.TextId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17))
line.Text = nil -- Fill at Post processing
line.ValId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19))
-- Singed int values
line.Min = Dsm_to_SInt16(multiBuffer(20), multiBuffer(21))
line.Max = Dsm_to_SInt16(multiBuffer(22), multiBuffer(23))
line.Def = Dsm_to_SInt16(multiBuffer(24), multiBuffer(25))
line.Val=nil
menuLib.MenuLinePostProcessing(line)
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuLine: %s\n", menuLib.menuLine2String(line)) end
if (line.MenuId~=ctx.Menu.MenuId) then
-- Going Back too fast: Stil receiving lines from previous menu
ctx.Menu.MenuId = line.MenuId
Log.LOG_write("WARNING: Overriding current Menu from Line\n")
end
return line
end
local function DSM_parseMenuValue()
--ex: 0x09 0x04 0x53 0x10 0x00 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
--ex: 0x09 0x04 0x61 0x10 0x02 0x10 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
-- MenuLSB MenuMSB ValLSB ValMSB V_LSB V_MSB
-- Identify the line and update the value
local ctx = DSM_Context
local menuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15))
local value = Dsm_to_SInt16(multiBuffer(16), multiBuffer(17)) --Signed int
local updatedLine = nil
for i = 0, MAX_MENU_LINES do -- Find the menu line for this value
local line = ctx.MenuLines[i]
if line ~= nil and line.Type ~= 0 then
if line.Type ~= LINE_TYPE.MENU and line.ValId == valId then -- identifier of ValueId stored in the line
line.Val = value
ctx.CurLine = i
updatedLine = line
break
end
end
end
if (updatedLine == nil) then
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuValue: ERROR, Cant find Menu Line with MenuId=%X, ValID=%X to update\n", menuId, valId) end
else
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuValue: UPDATED: %s\n", menuLib.menuLine2String(updatedLine))
end
end
return updatedLine ~= nil
end
local function DSM_parseReqTxInfo()
local portNo = multiBuffer(12)
TxInfo_Type = multiBuffer(13)
if (DEBUG_ON) then Log.LOG_write("RESPONSE ReqTXChannelInfo(#%d %s InfoType=0x%0X)\n",
portNo, MODEL.PORT_TEXT[portNo], TxInfo_Type) end
TxInfo_Step = 0
return portNo
end
------------------------------------------------------------------------------------------------------------
local function DSM_processResponse()
local ctx = DSM_Context
local cmd = multiBuffer(11) -- Response Command
if (DEBUG_ON > 1) then Log.LOG_write("%s: RESPONSE %s \n", menuLib.phase2String(ctx.Phase), multiBuffer2String()) end
if (DEBUG_ON and cmd > 0x00) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
if cmd == 0x01 then -- read version
DSM_parseRxVersion()
--Lib.Init_Text(DSM_Context.RX.Id)
ctx.isReset = false -- no longer resetting
ctx.Phase = PHASE.MENU_TITLE
ctx.Menu.MenuId = 0
elseif cmd == 0x02 then -- read menu title
local menu = DSM_parseMenu()
-- Update Selected Line navigation
if menu.NextId ~= 0 then
ctx.SelLine = NEXT_BUTTON -- highlight Next
else
ctx.SelLine = BACK_BUTTON -- highlight Back
end
if (ctx.Menu.MenuId == 0x0001) then -- Still in RESETTING MENU???
-- Star from Start
if (DEBUG_ON) then Log.LOG_write("RX Reset: Still not done, restart again!!!\n") end
ctx.Menu.MenuId = 0
ctx.Phase = PHASE.RX_VERSION
else
ctx.Phase = PHASE.MENU_LINES
end
elseif cmd == 0x03 then -- menu lines
local line = DSM_parseMenuLine()
-- Update Selected line navigation
if (ctx.SelLine == BACK_BUTTON or ctx.SelLine == NEXT_BUTTON or ctx.SelLine == PREV_BUTTON)
and menuLib.isSelectableLine(line) then -- Auto select the current line
ctx.SelLine = line.lineNum
end
ctx.Phase = PHASE.MENU_LINES
elseif cmd == 0x04 then -- read menu values
if DSM_parseMenuValue() then
ctx.Phase = PHASE.MENU_VALUES
else
ctx.Phase = PHASE.WAIT_CMD
end
elseif cmd == 0x05 then -- Request TX Info
local portNo = DSM_parseReqTxInfo()
ctx.CurLine = portNo
ctx.Phase = PHASE.MENU_REQ_TX_INFO
elseif cmd == 0xA7 then -- answer to EXIT command
if (DEBUG_ON) then Log.LOG_write("RESPONSE RX Exit\n") end
if (ctx.Phase==PHASE.EXIT) then -- Expected RX Exit
ctx.Phase = PHASE.EXIT_DONE
else -- UnExpected RX Exit
DSM_ReleaseConnection()
error("RX Connection Drop")
end
elseif cmd == 0x00 then -- NULL response (or RX heartbeat)
-- 09 00 01 00 00 00 00 00 00 00 00 00 00 00 00
-- 09 00 7E 00 20 9E 28 00 20 9E 28 00 20 8D 7E : After TX Heartbeat one of this (FC6250)
-- 09 00 18 00 20 08 00 00 00 08 00 00 00 98 AE AR8360T
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: RESPONSE RX Heartbeat --Context: 0x%02X\n",
menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase), multiBuffer(12)) end
else
if (DEBUG_ON) then Log.LOG_write("RESPONSE Unknown Command (0x%X) DATA=%s\n", cmd, multiBuffer2String()) end
end
return cmd
end
------------------------------------------------------------------------------------------------------------
local function DSM_Send_Receive()
local ctx = DSM_Context
-- Receive part: Process incoming messages if there is nothing to send
if ctx.SendDataToRX == 0 and multiBuffer(10) == 0x09 then
local cmd = DSM_processResponse()
multiBuffer(10, 0x00) -- Clear Response Buffer to know that we are done with the response
RXInactivityTime = getTime() + SEND_TIMEOUT*4 -- Reset RX Inactivity timeout
if (cmd > 0x00) then -- RX HeartBeat ??
-- Only change to SEND mode if we received a valid response (Ignore heartbeat)
ctx.SendDataToRX = 1
ctx.Refresh_Display = true
end
else
if (getTime() > RXInactivityTime and ctx.Phase ~= PHASE.RX_VERSION and ctx.Phase ~= PHASE.EXIT_DONE) then
if (ctx.isEditing()) then -- If Editing, Extend Timeout
RXInactivityTime = getTime() + SEND_TIMEOUT*4
else
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: RX INACTIVITY TIMEOUT\n", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
DSM_ReleaseConnection()
error("RX Disconnected")
end
end
end
-----TX Part --------------------------------------
if ctx.SendDataToRX == 1 then -- Need to send a request
ctx.SendDataToRX = 0
DSM_sendRequest()
TXInactivityTime = getTime() + SEND_TIMEOUT -- Reset Inactivity timeout
else
-- Check if enouth time has passed from last transmit/receive activity
if getTime() > TXInactivityTime then
ctx.SendDataToRX = 1 -- Switch to Send mode to send heartbeat
ctx.Refresh_Display = true
-- Only change to WAIT_CMD if we are NOT wating for RX version
if ctx.Phase ~= PHASE.RX_VERSION then
-- Phase = If IsEditing then VALUE_CHANGING_WAIT else WAIT_CMD
ctx.Phase = (ctx.isEditing() and PHASE.VALUE_CHANGING_WAIT) or PHASE.WAIT_CMD
end
end
end
end
-- Init
local function DSM_Init(toolName)
local dateTime = getDateTime()
local dateStr = dateTime.year.."-"..dateTime.mon.."-"..dateTime.day.." "..dateTime.hour..":"..dateTime.min
local ver, radio, maj, minor, rev, osname = getVersion()
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
IS_EDGETX = string.sub(osname,1,1) == 'E'
if (DEBUG_ON) then
Log.LOG_write("---------------DSM New Session %s ----------------\n", toolName, dateStr)
Log.LOG_write("Radio Info: %s\n", radio .. " " .. (osname or "OpenTx") .. " " .. ver)
Log.LOG_write("Date : %s\n", dateStr)
Log.LOG_write("DsmLib Version : %s\n", LIB_VERSION)
end
end
local function DSM_Init_Text_Exceptions()
-- Apply special restrictions to some Values
local function getTxChText(ch)
return " ("..(MODEL.TX_CH_TEXT[ch] or "--")..")"
end
local List_Values = menuLib.List_Values
local List_Text = menuLib.List_Text
local Text = menuLib.Text
Log.LOG_write("Initializing TEXT Exception\n")
-- Channel selection for SAFE MODE and GAINS on FC6250HX
--List_Text[0x000C] = "Inhibit?" --?
for i = 0, 7 do
List_Text[0x000D + i] = "Ch"..(i+5) ..getTxChText(i+4)
end -- Aux channels (Ch5 and Greater)
-- Servo Output values..
local servoOutputValues = {0x0003,0x002D,0x002E,0x002F} --Inh (GAP), 5.5ms, 11ms, 22ms. Fixing L_m1 with 0..244 range!
--List_Text[0x002D] = "5.5ms"
--[0x002E] = "11ms"
--List_Text[0x002F] = "22ms"
-- Gain Values
local gainValues = {0x0032,0x0033,0x0034} -- 1X, 2X, 4X -- Fixing L_m1 with 0..244 range!
--List_Text[0x0032] = "1 X"
--[0x0033] = "2 X"
-- List_Text[0x0034] = "4 X"
-- List of Channels for Safe, Gains, Panic, except FC6250HX that uses other range (0x00C..0x015)
-- the valid range Starts with GEAR if enabled (Thr,Ail,Ele,Rud are not valid, the RX reject them )
-- Valid Values: Inhibit? (GAP), Gear,Aux1..Aux7,X-Plus-1..XPlus-8
local channelValues = {0x0035,0x0036,0x0037,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049}
--List_Text[0x0035] = "Inhibit?"
for i = 0, 11 do
List_Text[0x0036 + i] = "Ch"..(i+1) .. getTxChText(i)
end -- Channels on AR637T
for i = 1, 8 do -- 41..49
List_Text[0x0041 + i] = "Ch"..(i+12)
end
-- Flight mode channel selection
--Text[0x0078] = "FM Channel"
List_Values[0x0078]=channelValues
-- Gain channel selection
--Text[0x0089] = "Gain Channel"
List_Values[0x0089]=channelValues
-- Gain Sensitivity selection
--Text[0x008A] = "Gain Sensitivity/r";
List_Values[0x008A]=gainValues -- Right Alight, (L_M1 was wide open range 0->244)
-- Safe mode options, Ihnibit + this values
local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope
--List_Text[0x00B0] = "Self-Level/Angle Dem"
--List_Text[0x00B1] = "Envelope"
--Text[0x00D2] = "Panic Channel"
List_Values[0x00D2]=channelValues
--Inh, Self-Level/Angle Dem, Envelope -- (L_M was wide open range 0->244)
--Text[0x01F8] = "Safe Mode";
List_Values[0x01F8]=safeModeOptions
end
-- Initial Setup
local function FP_Init(toolname)
DSM_Context.Phase = PHASE.INIT
DSM_Init(toolname)
menuLib.clearAllText()
end
local initStep=0
local FileState = {}
local function Message_Init()
lcd.clear()
if (initStep == 0) then
if (IS_EDGETX) then
-- Load all messages at once
menuLib.LoadTextFromFile(MSG_FILE,13)
initStep=1
else
-- load messages incrementally to avoid "CPU Limit"
lcd.drawText(30, 50, "Loading Msg file: "..(FileState.lineNo or 0))
if (menuLib.INC_LoadTextFromFile(MSG_FILE, FileState)==1) then
initStep=1
end
end
elseif (initStep == 1) then
DSM_Init_Text_Exceptions()
DSM_Context.Phase = PHASE.RX_VERSION
DSM_StartConnection()
end
end
local function FP_Run()
if (DSM_Context.Phase==PHASE.INIT) then
Message_Init()
return 0
end
return DSM_Send_Receive()
end
local function FP_Done()
local ctx = menuLib.DSM_Context
ctx.Phase = PHASE.EXIT_DONE
DSM_ReleaseConnection()
end
return { init=FP_Init, run=FP_Run, done=FP_Done }

View File

@ -0,0 +1,33 @@
local LogLib = { }
local LOG_FILE = "/LOGS/dsm_log.txt"
local logFile = nil
local logCount=0
function LogLib.LOG_open()
logFile = io.open(LOG_FILE, "w") -- Truncate Log File
end
function LogLib.LOG_write(...)
if (logFile==nil) then LogLib.LOG_open() end
local str = string.format(...)
if (str==nil) then return end
io.write(logFile, str)
str = string.gsub(str,"\n"," ") -- Elimitate return from line, since print will do it
print(str)
if (logCount > 10) then -- Close an re-open the file
io.close(logFile)
logFile = io.open(LOG_FILE, "a")
logCount =0
end
end
function LogLib.LOG_close()
if (logFile~=nil) then io.close(logFile) end
end
return LogLib

View File

@ -0,0 +1,167 @@
local MODEL, M_DATA, LOG_write = ...
--[[
local MODEL = {
modelName = "", -- The name of the model comming from OTX/ETX
hashName = "",
modelOutputChannel = {}, -- Output information from OTX/ETX
TX_CH_TEXT= { [0]=""},
PORT_TEXT = { [0]=""},
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
}
-- MENU DATA Management
local M_DATA = {} -- Store the variables used in the Menus.
--]]
local DATA_PATH = "/MODELS/DSMDATA"
local TX_CHANNELS = 12
local MV_DATA_END = 1040
local function hashName(mName)
local c=10000;
local prefix = string.gsub(mName,"%.","_") -- Change any "." to "_"
prefix = string.gsub(prefix,"% ","_") -- Change any space to "_"
prefix = string.sub(prefix,1,5) -- Take the first 5 characters
-- Simple Hash of the Model Name adding each character
for i = 1, #mName do
local ch = string.byte(mName,i,i)
c=c+ch
end
return (prefix .. c) -- Return Prefix + Hash
end
-- Load Menu Data from a file
local function ST_LoadFileData()
local fname = hashName(MODEL.modelName)..".txt"
MODEL.hashName = fname
-- Clear Menu Data
for i = 0, MV_DATA_END do
M_DATA[i]=nil
end
print("Loading File:"..fname)
local dataFile = io.open(DATA_PATH .. "/".. fname, "r") -- read File
-- cannot read file???
if (dataFile==nil) then return 0 end
local line = io.read(dataFile, 5000)
io.close(dataFile)
if #line == 0 then return 0 end -- No data??
-- Process the input, each line is "Var_Id : Value" format
-- Store it into MANU_DATA
local i=0
for k, v in string.gmatch(line, "(%d+):(%d+)") do
M_DATA[k+0]=v+0 -- do aritmentic to convert string to number
i=i+1
end
-- Return 0 if no lines processed, 1 otherwise
if (i > 0) then return 1 else return 0 end
end
local function getModuleChannelOrder(num)
--Determine fist 4 channels order
local ch_n={}
local st_n = {[0]= "R", "E", "T", "A" }
local c_ord=num -- ch order
if (c_ord == -1) then
ch_n[0] = st_n[3]
ch_n[1] = st_n[1]
ch_n[2] = st_n[2]
ch_n[3] = st_n[0]
else
ch_n[bit32.band(c_ord,3)] = st_n[3]
c_ord = math.floor(c_ord/4)
ch_n[bit32.band(c_ord,3)] = st_n[1]
c_ord = math.floor(c_ord/4)
ch_n[bit32.band(c_ord,3)] = st_n[2]
c_ord = math.floor(c_ord/4)
ch_n[bit32.band(c_ord,3)] = st_n[0]
end
local s = ""
for i=0,3 do
s=s..ch_n[i]
end
return s
end
local function ReadTxModelData()
local TRANSLATE_AETR_TO_TAER=false
local table = model.getInfo() -- Get the model name
MODEL.modelName = table.name
local module = model.getModule(0) -- Internal
if (module==nil or module.Type~=6) then module = model.getModule(1) end -- External
if (module~=nil) then
if (module.Type==6 ) then -- MULTI-MODULE
local chOrder = module.channelsOrder
local s = getModuleChannelOrder(chOrder)
LOG_write("MultiChannel Ch Order: [%s] %s\n",chOrder,s)
if (s=="AETR") then TRANSLATE_AETR_TO_TAER=true
else TRANSLATE_AETR_TO_TAER=false
end
end
end
-- Read Ch1 to Ch10
local i= 0
for i = 0, TX_CHANNELS-1 do
local ch = model.getOutput(i) -- Zero base
if (ch~=nil) then
MODEL.modelOutputChannel[i] = ch
if (string.len(ch.name)==0) then
ch.formatCh = string.format("TX:Ch%i",i+1)
else
ch.formatCh = string.format("TX:Ch%i/%s",i+1,ch.name or "--")
end
end
end
-- Translate AETR to TAER
if (TRANSLATE_AETR_TO_TAER) then
LOG_write("Applying AETR -> TAER translation\n")
local ail = MODEL.modelOutputChannel[0]
local elv = MODEL.modelOutputChannel[1]
local thr = MODEL.modelOutputChannel[2]
MODEL.modelOutputChannel[0] = thr
MODEL.modelOutputChannel[1] = ail
MODEL.modelOutputChannel[2] = elv
end
-- Create the Port Text to be used
LOG_write("Ports/Channels:\n")
for i = 0, TX_CHANNELS-1 do
local ch = MODEL.modelOutputChannel[i]
if (ch~=nil) then
MODEL.TX_CH_TEXT[i] = ch.formatCh
MODEL.PORT_TEXT[i] = string.format("P%i (%s) ",i+1,MODEL.TX_CH_TEXT[i])
LOG_write("Port%d %s [%d,%d] Rev=%d, Off=%d, ppmC=%d, syn=%d\n",i+1,MODEL.TX_CH_TEXT[i],math.floor(ch.min/10),math.floor(ch.max/10), ch.revert, ch.offset, ch.ppmCenter, ch.symetrical)
end
end
end
-- Main Program
LOG_write("Reading Model Info\n")
ReadTxModelData()
local r = ST_LoadFileData()
return r

View File

@ -0,0 +1,282 @@
local MODEL, M_DATA, LOG_write = ...
--[[
local MODEL = {
modelName = "", -- The name of the model comming from OTX/ETX
hashName = "",
modelOutputChannel = {}, -- Output information from OTX/ETX
TX_CH_TEXT= { [0]=""},
PORT_TEXT = { [0]=""},
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
}
-- MENU DATA Management
local M_DATA = {} -- Store the variables used in the Menus.
--]]
local TX_CHANNELS = 12
local AT_PLANE = 0
local aircraft_type_text = {[0]="Plane","Heli","Glider","Drone"}
--[[
local WT_A1 = 0
local WT_A2 = 1
local WT_FLPR = 2
local WT_A1_F1 = 3
local WT_A2_F1 = 4
local WT_A2_F2 = 5
--]]
local WT_ELEVON_A = 6
local WT_ELEVON_B = 7
local wing_type_text = {[0]="Normal","Dual Ail","Flapperon", "Ail + Flp","Dual Ail + Flp","Dual Ail/Flp","Elevon A","Elevon B"}
--[[
local TT_R1 = 0
local TT_R1_E1 = 1
local TT_R1_E2 = 2
local TT_R2_E1 = 3
local TT_R2_E2 = 4
--]]
local TT_VT_A = 5
local TT_VT_B = 6
local TT_TLRN_A = 7
local TT_TLRN_B = 8
local TT_TLRN_A_R2 = 9
local TT_TLRN_B_R2 = 10
local tail_type_text = {[0]="Rud Only","Normal","Rud + Dual Ele","Dual Rud + Elv","Dual Rud/Ele",
"VTail A","VTail B","Taileron A","Taileron B","Taileron A + Dual Rud","Taileron B + Dual Rud"}
local MV_AIRCRAFT_TYPE = 1001
local MV_WING_TYPE = 1002
local MV_TAIL_TYPE = 1003
local MV_CH_BASE = 1010
local MV_CH_THR = 1010
local MV_CH_L_AIL = 1011
local MV_CH_R_AIL = 1012
local MV_CH_L_FLP = 1013
local MV_CH_R_FLP = 1014
local MV_CH_L_RUD = 1015
local MV_CH_R_RUD = 1016
local MV_CH_L_ELE = 1017
local MV_CH_R_ELE = 1018
local MV_PORT_BASE = 1020
local MV_DATA_END = 1040
--Channel Types --
local CT_NONE = 0x00
local CT_AIL = 0x01
local CT_ELE = 0x02
local CT_RUD = 0x04
local CT_REVERSE = 0x20
local CT_THR = 0x40
local CT_SLAVE = 0x80
-- Seems like Reverse Mix is complement of the 3 bits
local CMT_NORM = 0x00 -- 0000
local CMT_AIL = 0x10 -- 0001 Taileron
local CMT_ELE = 0x20 -- 0010 For VTIAL and Delta-ELEVON
local CMT_RUD = 0x30 -- 0011 For VTIAL
local CMT_RUD_REV = 0x40 -- 0100 For VTIAL
local CMT_ELE_REV = 0x50 -- 0101 For VTIAL and Delta-ELEVON A
local CMT_AIL_REV = 0x60 -- 0110 Taileron
local CMT_NORM_REV = 0x70 -- 0111
local MT_NORMAL = 0
local MT_REVERSE = 1
local function channelType2String(byte1, byte2)
local s = ""
if (byte2==0) then return s end;
if (bit32.band(byte2,CT_AIL)>0) then s=s.."Ail" end
if (bit32.band(byte2,CT_ELE)>0) then s=s.."Ele" end
if (bit32.band(byte2,CT_RUD)>0) then s=s.."Rud" end
if (bit32.band(byte2,CT_THR)>0) then s=s.."Thr" end
if (bit32.band(byte2,CT_REVERSE)>0) then s=s.."-" end
if (bit32.band(byte2,CT_SLAVE)>0) then s=s.." Slv" end
if (byte1==CMT_NORM) then s=s.." "
elseif (byte1==CMT_AIL) then s=s.." M_Ail"
elseif (byte1==CMT_ELE) then s=s.." M_Ele"
elseif (byte1==CMT_RUD) then s=s.." M_Rud"
elseif (byte1==CMT_RUD_REV) then s=s.." M_Rud-"
elseif (byte1==CMT_ELE_REV) then s=s.." M_Ele-"
elseif (byte1==CMT_AIL_REV) then s=s.." M_Ail-"
elseif (byte1==CMT_NORM_REV) then s=s.." M-"
end
return s;
end
-- This Creates the Servo Settings that will be used to pass to
-- Forward programming
local function CreateDSMPortChannelInfo()
local function ApplyWingMixA(b2)
-- ELEVON
if (b2==CT_AIL+CT_ELE) then return CMT_ELE end; -- 0x03
if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_NORM end; -- 0x83
end
local function ApplyWingMixB(b2)
-- ELEVON
if (b2==CT_AIL+CT_ELE) then return CMT_NORM end; -- 0x03
if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_ELE end; -- 0x83
end
local function ApplyTailMixA(b2)
-- VTAIL
-- Default normal/reverse behaviour
if (b2==CT_RUD+CT_ELE) then return CMT_NORM end; -- 0x06
if (b2==CT_RUD+CT_ELE+CT_SLAVE) then return CMT_ELE end; -- 0x86
--TAILERON
-- Default normal/reverse behaviour
if (b2==CT_AIL+CT_ELE) then return CMT_NORM end; -- 0x03
if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_AIL end; -- 0x83
end
local function ApplyTailMixB(b2)
-- VTAIL
-- Default normal/reverse behaviour
if (b2==CT_RUD+CT_ELE) then return CMT_NORM end; -- 0x06
if (b2==CT_RUD+CT_ELE+CT_SLAVE) then return CMT_RUD end; -- 0x86
--TAILERON
if (b2==CT_AIL+CT_ELE) then return CMT_AIL end; -- 0x03
if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_NORM end; -- 0x83
end
local function reverseMix(b)
if (b==CMT_NORM) then return CMT_NORM_REV end;
if (b==CMT_AIL) then return CMT_AIL_REV end;
if (b==CMT_ELE) then return CMT_ELE_REV end;
if (b==CMT_RUD) then return CMT_RUD_REV end;
return b
end
local DSM_Ch = MODEL.DSM_ChannelInfo
for i=0, TX_CHANNELS-1 do
DSM_Ch[i] = {[0]= CMT_NORM, CT_NONE, nil} -- Initialize with no special function
end
--local aircraftType = M_DATA[MV_AIRCRAFT_TYPE]
local wingType = M_DATA[MV_WING_TYPE]
local tailType = M_DATA[MV_TAIL_TYPE]
local thrCh = M_DATA[MV_CH_THR]
local lAilCh = M_DATA[MV_CH_L_AIL]
local rAilCh = M_DATA[MV_CH_R_AIL]
local lElevCh = M_DATA[MV_CH_L_ELE]
local rElevCh = M_DATA[MV_CH_R_ELE]
local lRudCh = M_DATA[MV_CH_L_RUD]
local rRudCh = M_DATA[MV_CH_R_RUD]
-- Channels in menu vars are Zero base, Channel info is 1 based
-- THR
if (thrCh~=nil and thrCh < 10) then DSM_Ch[thrCh][1]= CT_THR end
-- AIL (Left and Right)
if (lAilCh~=nil) then DSM_Ch[lAilCh][1] = CT_AIL end
if (rAilCh~=nil) then DSM_Ch[rAilCh][1] = CT_AIL+CT_SLAVE end
-- ELE (Left and Right)
if (lElevCh~=nil) then DSM_Ch[lElevCh][1] = CT_ELE end
if (rElevCh~=nil) then DSM_Ch[rElevCh][1] = CT_ELE+CT_SLAVE end
-- RUD (Left and Right)
if (lRudCh~=nil) then DSM_Ch[lRudCh][1] = CT_RUD end
if (rRudCh~=nil) then DSM_Ch[rRudCh][1] = CT_RUD+CT_SLAVE end
-- VTAIL: RUD + ELE
if (tailType==TT_VT_A) then
DSM_Ch[lElevCh][1] = CT_RUD+CT_ELE
DSM_Ch[rElevCh][1] = CT_RUD+CT_ELE+CT_SLAVE
elseif (tailType==TT_VT_B) then
DSM_Ch[lElevCh][1] = CT_RUD+CT_ELE+CT_SLAVE
DSM_Ch[rElevCh][1] = CT_RUD+CT_ELE
end
-- TAILERRON: 2-ELE + AIL
if (tailType==TT_TLRN_A or tailType==TT_TLRN_A_R2) then
DSM_Ch[lElevCh][1] = CT_AIL+CT_ELE
DSM_Ch[rElevCh][1] = CT_AIL+CT_ELE+CT_SLAVE
elseif (tailType==TT_TLRN_B or tailType==TT_TLRN_B_R2) then
DSM_Ch[lElevCh][1] = CT_AIL+CT_ELE+CT_SLAVE
DSM_Ch[rElevCh][1] = CT_AIL+CT_ELE
end
---- ELEVON : AIL + ELE
if (wingType==WT_ELEVON_A) then
DSM_Ch[lAilCh][1] = CT_AIL+CT_ELE
DSM_Ch[rAilCh][1] = CT_AIL+CT_ELE+CT_SLAVE
elseif (wingType==WT_ELEVON_B) then
DSM_Ch[lAilCh][1] = CT_AIL+CT_ELE+CT_SLAVE
DSM_Ch[rAilCh][1] = CT_AIL+CT_ELE
end
------MIXES ---------
-- TAIL Mixes (Elevator and VTail)
if (tailType==TT_VT_A or tailType==TT_TLRN_A or tailType==TT_TLRN_A_R2) then
DSM_Ch[lElevCh][0] = ApplyTailMixA(DSM_Ch[lElevCh][1])
DSM_Ch[rElevCh][0] = ApplyTailMixA(DSM_Ch[rElevCh][1])
elseif (tailType==TT_VT_B or tailType==TT_TLRN_B or tailType==TT_TLRN_B_R2) then
DSM_Ch[lElevCh][0] = ApplyTailMixB(DSM_Ch[lElevCh][1])
DSM_Ch[rElevCh][0] = ApplyTailMixB(DSM_Ch[rElevCh][1])
end
---- ELEVON : AIL + ELE
if (wingType==WT_ELEVON_A) then
DSM_Ch[lAilCh][0] = ApplyWingMixA(DSM_Ch[lAilCh][1])
DSM_Ch[rAilCh][0] = ApplyWingMixA(DSM_Ch[rAilCh][1])
elseif (wingType==WT_ELEVON_B) then
DSM_Ch[lAilCh][0] = ApplyWingMixB(DSM_Ch[lAilCh][1])
DSM_Ch[rAilCh][0] = ApplyWingMixB(DSM_Ch[rAilCh][1])
end
-- Apply Gyro Reverse as needed for each channel as long as it is used
for i=0, TX_CHANNELS-1 do
if (M_DATA[MV_PORT_BASE+i]==MT_REVERSE and DSM_Ch[i][1]>0) then
DSM_Ch[i][0]=reverseMix(DSM_Ch[i][0])
DSM_Ch[i][1]=DSM_Ch[i][1]+CT_REVERSE
end
end
-- Show how it looks
for i=0, 9 do
local b1,b2 = DSM_Ch[i][0], DSM_Ch[i][1]
local s1 = channelType2String(b1,b2)
local s = string.format("%s (%02X %02X) %s\n", MODEL.PORT_TEXT[i],
b1, b2,s1)
DSM_Ch[i][2]=s1
LOG_write(s)
end
--MODEL.AirWingTailDesc = string.format("Aircraft(%s) Wing(%s) Tail(%s)",aircraft_type_text[aircraftType],wing_type_text[wingType],tail_type_text[tailType])
end
-- Main Program
LOG_write("Creating DSMPort Info\n")
CreateDSMPortChannelInfo()

View File

@ -0,0 +1,90 @@
local Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON = ... -- Get DebugON from parameters
local MAIN_MENU_LIB_VERSION = "0.56"
local MODEL = modelLib.MODEL
local PHASE = menuLib.PHASE
local LINE_TYPE = menuLib.LINE_TYPE
local lastGoodMenu=0
-- Creates the menus to Render with the GUI
local function ST_LoadMenu(menuId)
local ctx = menuLib.DSM_Context
menuLib.clearMenuLines()
if (menuId==0x1000) then -- MAIN MENU
ctx.Menu = { MenuId = 0x1000, Text = "Main Menu ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, Text = "Model Setup", ValId = 0xFFF3,TextId=0 }
if (SIMULATION_ON) then
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, Text = "RX Simulator (GUI dev only)", ValId = 0xFFF1, TextId=0 } -- Menu 0xFFF2 to SIMULATOR
end
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text = "Forward Programming RX", ValId = 0xFFF2, TextId=0 } -- Menu 0xFFF2 to Real RX
ctx.SelLine = 6
lastGoodMenu = menuId
else
--print("NOT IMPLEMENTED")
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
ctx.SelLine = menuLib.BACK_BUTTON
end
menuLib.PostProcessMenu()
end
local function Main_Send_Receive()
local ctx = menuLib.DSM_Context
if ctx.Phase == PHASE.RX_VERSION then -- Just Init RX Version
ctx.RX.Name = "Main Menu"
ctx.RX.Version = MAIN_MENU_LIB_VERSION
ctx.Phase = PHASE.MENU_TITLE
ctx.Menu.MenuId = 0
ctx.Refresh_Display = true
elseif ctx.Phase == PHASE.WAIT_CMD then
elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title
if ctx.Menu.MenuId == 0 then -- First time loading a menu ?
ST_LoadMenu(0x01000)
else
ST_LoadMenu(ctx.Menu.MenuId)
end
ctx.Phase = PHASE.WAIT_CMD
ctx.Refresh_Display = true
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
--if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
--if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
local line = ctx.MenuLines[ctx.SelLine]
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
--if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
--if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
--if (DEBUG_ON) then Log.LOG_write("SEND SIM_validateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
ctx.Phase = PHASE.WAIT_CMD
elseif ctx.Phase == PHASE.EXIT then
ctx.Phase=PHASE.EXIT_DONE
return 1
end
return 0
end
local function Main_Init()
local ctx = menuLib.DSM_Context
ctx.Phase = PHASE.RX_VERSION
end
local function Main_Done()
local ctx = menuLib.DSM_Context
ctx.Phase = PHASE.EXIT_DONE
end
return { init=Main_Init, run=Main_Send_Receive, done=Main_Done }

View File

@ -0,0 +1,788 @@
--- #########################################################################
---- # #
---- # Copyright (C) OpenTX/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. #
---- # #
---- #########################################################################
------------------------------------------------------------------------------
-- This script library is a rewrite of the original DSM forward programming Lua
-- Script. The goal is to make it easier to understand, mantain, and to
-- separate the GUI from the DSM Forward programming engine/logic
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
-- Rewrite/Enhancements By: Francisco Arzu
local Log, DEBUG_ON = ... -- Parameters
local MenuLib = { }
local PHASE = {
INIT = 0,
RX_VERSION = 1,
WAIT_CMD = 2,
MENU_TITLE = 3,
MENU_REQ_TX_INFO = 4,
MENU_LINES = 5,
MENU_VALUES = 6,
VALUE_CHANGING = 7,
VALUE_CHANGING_WAIT = 8,
VALUE_CHANGE_END = 9,
EXIT = 10,
EXIT_DONE = 11
}
local LINE_TYPE = {
MENU = 0x1C,
LIST_MENU = 0x0C, -- List: INC Change + Validate
LIST_MENU_NC = 0x6C, -- List: No Incremental Change
LIST_MENU_NC2 = 0x6D, -- List: No Incremental Change (Frame Rate Herz)
LIST_MENU_TOG = 0x4C, -- List: Incremental Change, sometimes bolean/Toggle menu (if only 2 values)
LIST_MENU_ORI = 0xCC, -- List: Incremental Change, Orientation Heli
VALUE_NUM_I8_NC = 0x60, -- 8 bit number, no incremental change
VALUE_PERCENT = 0xC0, -- 8 bit number, Signed, percent
VALUE_DEGREES = 0xE0, -- 8 bit number, Signed, Degress
VALUE_NUM_I8 = 0x40, -- 8 bit number
VALUE_NUM_I16 = 0x41, -- 16 Bit number
VALUE_NUM_SI16 = 0xC1, -- 16 bit number, Signed
LT_EMPTY = 0x00
}
-- Bug in Lua compiler, confusing with global BOLD and RIGHT
local DISP_ATTR = {
_BOLD = 0x01, _RIGHT=0x02, _CENTER=0x04, PERCENT = 0x10, DEGREES=0x20, FORCED_MENU = 0x40
}
--RX IDs--
local RX = {
AR636B = 0x0001,
SPM4651T = 0x0014,
AR637T = 0x0015,
AR637TA = 0x0016,
FC6250HX = 0x0018,
AR630 = 0x0019,
AR8360T = 0x001A,
AR10360T = 0x001C,
AR631 = 0x001E
}
local DSM_Context = {
Phase = PHASE.INIT,
Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 },
MenuLines = {},
RX = { Id=0, Name = "", Version = "" },
Refresh_Display = true,
SendDataToRX = 1,
SelLine = 0, -- Current Selected Line
EditLine = nil, -- Current Editing Line
CurLine = -1, -- Current Line Requested/Parsed via h message protocol
isReset = false -- false when starting from scracts, true when starting from Reset
}
function DSM_Context.isEditing() return DSM_Context.EditLine~=nil end
local MAX_MENU_LINES = 6
local BACK_BUTTON = -1 -- Tread it as a display line #-1
local NEXT_BUTTON = MAX_MENU_LINES + 1 -- Tread it as a display line #7
local PREV_BUTTON = MAX_MENU_LINES + 2 -- Tread it as a display line #7
-- Text Arrays for Display Text and Debuging
local PhaseText = {}
local LineTypeText = {}
local Text = {} -- Text for Menu and Menu Lines (Headers only)
local List_Text = {} -- Messages for List Options (values only)
local List_Text_Img = {} -- If the Text has Attached Images
local List_Values = {} -- Additiona restrictions on List Values when non contiguos (L_M1 lines has this problem)
local Flight_Mode = {[0]="Fligh Mode"}
local RxName = {}
local StartTime = 0
------------------------------------------------------------------------------------------------------------
-- Get Elapsed Time since we started running the Script. Return a float in format: Seconds.Milliseconds
function MenuLib.getElapsedTime()
local t = getTime()
if (StartTime == 0) then StartTime = t end
return ((t - StartTime) * 10) / 1000
end
------------- Line Type helper functions ------------------------------------------------------------------
-- Check if the text are Flight modes, who will be treated different for Display
function MenuLib.isFlightModeLine(line)
return (line.TextId >= 0x8000 and line.TextId <= 0x8003)
end
function MenuLib.isSelectableLine(line) -- is the display line Selectable??
-- values who are not selectable
if (line.Type == 0) then return false end -- Empty Line
if (line.Type == LINE_TYPE.MENU and line.ValId == line.MenuId and bit32.band(line.TextAttr, DISP_ATTR.FORCED_MENU)==0) then return false end -- Menu that navigates to Itself?
if (line.Min==0 and line.Max==0 and line.Def==0) then return false end -- Values with no Range are only for display
if (line.Type == LINE_TYPE.VALUE_NUM_I8_NC and MenuLib.isFlightModeLine(line)) then return false end -- Flight mode is not Selectable
return true
end
function MenuLib.isEditableLine(line) -- is the display line editable??
-- values who are not editable
if (line.Type == 0 or line.Type == LINE_TYPE.MENU) then return false end -- Menus are not editable
if (line.Min==0 and line.Max==0 and line.Def==0) then return false end -- Values with no Range are only for display
if (line.Type == LINE_TYPE.VALUE_NUM_I8_NC and MenuLib.isFlightModeLine(line)) then return false end -- Flight mode is not Editable
-- any other is Editable
return true
end
function MenuLib.isListLine(line) -- is it a List of options??
if (line.Type == LINE_TYPE.LIST_MENU_NC or line.Type == LINE_TYPE.LIST_MENU or
line.Type == LINE_TYPE.LIST_MENU_TOG or line.Type == LINE_TYPE.LIST_MENU_NC2 or
line.Type == LINE_TYPE.LIST_MENU_ORI) then return true end
return false
end
function MenuLib.isPercentValueLineByMinMax(line)
return
(line.Min == 0 and line.Max == 100) or ( line.Min == -100 and line.Max == 100) or
( line.Min == 0 and line.Max == 150) or ( line.Min == -150 and line.Max == 150)
end
function MenuLib.isPercentValueLine(line) -- is it a Percent value??
if (line.Type == LINE_TYPE.VALUE_PERCENT) then return true end
return false
end
function MenuLib.isNumberValueLine(line) -- is it a number ??
if (MenuLib.isListLine(line) or line.Type == LINE_TYPE.MENU or line.Type == 0) then return false
else return true end
end
function MenuLib.isIncrementalValueUpdate(line)
if (line.Type == LINE_TYPE.LIST_MENU_NC or line.Type == LINE_TYPE.LIST_MENU_NC2 or
line.Type == LINE_TYPE.VALUE_NUM_I8_NC or line.Type == LINE_TYPE.VALUE_DEGREES) then return false end
return true
end
------------------------------------------------------------------------------------------------------------
function MenuLib.Get_Text(index)
if (index >= 0x8000) then
return Flight_Mode[0]
end
local out = Text[index] -- Find in regular header first
if out== nil then
out = List_Text[index] -- Try list values, don't think is necesary, but just playing Safe
end
if out == nil then -- unknown...
out = "Unknown_" .. string.format("%X", index)
end
return out
end
function MenuLib.Get_List_Text(index)
local out = List_Text[index] -- Try to find the message in List_Text
if out == nil then
out = Text[index] -- Try list headers, don't think is necesary, but just playing Safe
end
if out == nil then -- unknown...
out = "UnknownLT_" .. string.format("%X", index)
end
return out
end
function MenuLib.Get_List_Text_Img(index)
local out = List_Text_Img[index]
return out
end
function MenuLib.Get_List_Values(index)
local out = List_Values[index]
return out
end
function MenuLib.Get_RxName(index)
local out = RxName[index]
return out or ("RX_" .. string.format("%X", index))
end
----------- Debugging 2-String functions -------------------------------------------------------------------
function MenuLib.phase2String(index)
local out = PhaseText[index]
return out or ("Phase_" .. string.format("%X", index))
end
function MenuLib.lineType2String(index)
local out = LineTypeText[index]
return out or ("LT_" .. string.format("%X", index or 0xFF))
end
function MenuLib.lineValue2String(l)
if (DEBUG_ON == 0) then
return ""
end
if (l ~= nil and l.Val ~= nil) then
local value = l.Val
if MenuLib.isListLine(l) then
value = value .. "|\"" .. MenuLib.Get_List_Text(l.Val + l.TextStart) .. "\""
else
value = value..(l.Format or "")
end
return value
end
return "nil"
end
function MenuLib.menu2String(m)
local txt = "Menu[]"
if (m ~= nil) then
txt = string.format("M[Id=0x%X P=0x%X N=0x%X B=0x%X Text=\"%s\"[0x%X]]",
m.MenuId, m.PrevId, m.NextId, m.BackId, m.Text, m.TextId)
end
return txt
end
function MenuLib.menuLine2String(l)
local txt = "Line[]"
if (l ~= nil) then
local value = ""
local range = ""
if l.Type~=LINE_TYPE.MENU then
value = "Val="..MenuLib.lineValue2String(l)
if MenuLib.isListLine(l) then
range = string.format("NL=(%s->%s,%s,S=%s) ",l.Min, l.Max, l.Def, l.TextStart )
range = range .. (l.MinMaxOrig or "")
else
range = string.format("[%s->%s,%s]",l.Min, l.Max, l.Def)
end
end
txt = string.format("L[#%s T=%s VId=0x%X Text=\"%s\"[0x%X] %s %s MId=0x%X A=0x%X]",
l.lineNum, MenuLib.lineType2String(l.Type), l.ValId,
l.Text, l.TextId,
value,
range,
l.MenuId,
l.TextAttr
)
end
return txt
end
-----------------------------------------------------------------------------------------------------------
-- Post Procssing Line from Raw values receive by RX or Simulation
function MenuLib.isDisplayAttr(attr, bit)
return (bit32.band(attr,bit)>0)
end
function MenuLib.ExtractDisplayAttr(text1, attr)
local text = text1, pos;
for i=1,2 do
text, pos = string.gsub(text, "/c$", "")
if (pos>0) then -- CENTER
attr = bit32.bor(attr, DISP_ATTR._CENTER)
end
text, pos = string.gsub(text, "/r$", "")
if (pos>0) then -- RIGHT
attr = bit32.bor(attr, DISP_ATTR._RIGHT)
end
text, pos = string.gsub(text, "/p$", "")
if (pos>0) then -- Percent TEXT
attr = bit32.bor(attr, DISP_ATTR.PERCENT)
end
text, pos = string.gsub(text, "/b$", "")
if (pos>0) then -- BOLD TEXT
attr = bit32.bor(attr, DISP_ATTR._BOLD)
end
text, pos = string.gsub(text, "/m$", "")
if (pos>0) then -- FORCED MENU Button
attr = bit32.bor(attr, DISP_ATTR.FORCED_MENU)
end
end
return text, attr
end
function MenuLib.MenuPostProcessing(menu)
menu.Text, menu.TextAttr = MenuLib.ExtractDisplayAttr(menu.Text,menu.TextAttr or 0)
end
function MenuLib.MenuLinePostProcessing(line)
if (line.Text==nil) then
line.Text = MenuLib.Get_Text(line.TextId) -- Get Textual Line headeing text
end
-- Text formatting options
line.Text, line.TextAttr = MenuLib.ExtractDisplayAttr(line.Text,line.TextAttr or 0)
if line.Type == LINE_TYPE.MENU then
-- nothing to do on menu entries
line.Val=nil
elseif MenuLib.isListLine(line) then
-- Original Range for Debugging
line.MinMaxOrig = "[" .. line.Min .. "->" .. line.Max .. "," .. line.Def .. "]"
-- Normalize Min/Max to be relative to Zero
line.TextStart = line.Min
line.Def = line.Def - line.Min -- normalize default value
line.Max = line.Max - line.Min -- normalize max index
line.Min = 0 -- min index
else -- default to numerical value
if MenuLib.isPercentValueLine(line) or MenuLib.isPercentValueLineByMinMax(line) then
-- either explicit Percent or NO-Change value, but range is %Percent
line.Format ="%"
line.TextAttr = bit32.bor(line.TextAttr,DISP_ATTR.PERCENT)
elseif (line.Type == LINE_TYPE.VALUE_DEGREES) then
line.Format ="o"
line.TextAttr = bit32.bor(line.TextAttr,DISP_ATTR.DEGREES)
end
end
line.MinMaxDebug = MenuLib.lineType2String(line.Type).." "..(line.MinMaxOrig or "")
end
function MenuLib.ChangePhase(newPhase)
DSM_Context.Phase = newPhase
DSM_Context.SendDataToRX = 1
end
function MenuLib.Value_Add(line, inc)
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Add(%s,%s)\n",
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), inc, MenuLib.menuLine2String(line)) end
local skipIncrement = false
local values = nil
local origVal = line.Val
-- Use local validation for LIST_MENU1 when the range is wide open
-- Also use if for some LIST_MENU0 that the Range seems incorrect
if (MenuLib.isListLine(line)) then -- and line.Type==LINE_TYPE.LIST_MENU1 and line.Min==0 and line.Max==244) then
values = MenuLib.Get_List_Values(line.TextId)
end
if (values~=nil) then -- Inc/Dec based on a list of predefined Values Local to Script (values not contiguous),
-- locate current value in values array
-- Values are Zero normalized to the Start of the List (line.TextStart)
for i = 1, #values do
if ((values[i]-line.TextStart)==origVal) then
skipIncrement = true
if (inc==-1 and i > 1) then -- PREV
line.Val = values[i-1]-line.TextStart
elseif (inc==1 and i < #values) then -- NEXT
line.Val = values[i+1]-line.TextStart
end
break
end
end
end
if not skipIncrement then
-- Do it Sequentially
line.Val = line.Val + inc
if line.Val > line.Max then
line.Val = line.Max
elseif line.Val < line.Min then
line.Val = line.Min
end
end
if (origVal~=line.Val and MenuLib.isIncrementalValueUpdate(line)) then
-- Update RX value on every change
MenuLib.ChangePhase(PHASE.VALUE_CHANGING)
end
end
function MenuLib.Value_Default(line)
local origVal = line.Val
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Default(%s)\n",
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), MenuLib.menuLine2String(line)) end
line.Val = line.Def
if (origVal~=line.Val and MenuLib.isIncrementalValueUpdate(line)) then
-- Update RX value on every change
MenuLib.ChangePhase(PHASE.VALUE_CHANGING)
end
end
function MenuLib.Value_Write_Validate(line)
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Write_Validate(%s)\n",
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), MenuLib.menuLine2String(line)) end
MenuLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Update + Validate value in RX
DSM_Context.EditLine = nil -- Exit Edit Mode (By clearing the line editing)
end
function MenuLib.GotoMenu(menuId, lastSelectedLine)
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_GotoMenu(0x%X,LastSelectedLine=%d)\n",
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), menuId, lastSelectedLine) end
DSM_Context.Menu.MenuId = menuId
DSM_Context.SelLine = lastSelectedLine
-- Request to load the menu Again
MenuLib.ChangePhase(PHASE.MENU_TITLE)
end
function MenuLib.MoveSelectionLine(dir)
local ctx = DSM_Context
local menu = ctx.Menu
local menuLines = ctx.MenuLines
if (dir == 1) then -- NEXT
if ctx.SelLine <= MAX_MENU_LINES then
local num = ctx.SelLine
for i = ctx.SelLine + 1, MAX_MENU_LINES, 1 do
if MenuLib.isSelectableLine(menuLines[i]) then
ctx.SelLine = i
break
end
end
if num == ctx.SelLine then
if menu.NextId ~= 0 then -- Next
ctx.SelLine = NEXT_BUTTON
elseif menu.PrevId ~= 0 then -- Prev
ctx.SelLine = PREV_BUTTON
end
end
elseif menu.PrevId ~= 0 then -- Prev
ctx.SelLine = PREV_BUTTON
end
return
end
if (dir == -1) then -- PREV
if ctx.SelLine == PREV_BUTTON and menu.NextId ~= 0 then
ctx.SelLine = NEXT_BUTTON
elseif ctx.SelLine > 0 then
if ctx.SelLine > MAX_MENU_LINES then
ctx.SelLine = NEXT_BUTTON
end
local num = ctx.SelLine
for i = ctx.SelLine - 1, 0, -1 do
if MenuLib.isSelectableLine(menuLines[i]) then
ctx.SelLine = i
break
end
end
if num == ctx.SelLine then -- can't find previous selectable line, then SELECT Back
if (menu.BackId ~= 0) then ctx.SelLine = BACK_BUTTON end
end
else
if (menu.BackId ~= 0) then ctx.SelLine = BACK_BUTTON end -- Back
end
end
end
-- Clear each line of the menu
function MenuLib.clearMenuLines()
local ctx = DSM_Context
for i = 0, MAX_MENU_LINES do -- clear menu
ctx.MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0, Text = "", TextId = 0, ValId = 0, Min=0, Max=0, Def=0, TextStart=0, Val=nil }
end
end
-- Post processing needed for each menu
function MenuLib.PostProcessMenu()
local ctx = DSM_Context
if (ctx.Menu.Text==nil) then
ctx.Menu.Text = MenuLib.Get_Text(ctx.Menu.TextId)
MenuLib.MenuPostProcessing (ctx.Menu)
end
--if (DEBUG_ON) then Log.LOG_write("SIM RESPONSE Menu: %s\n", MenuLib.menu2String(ctx.Menu)) end
for i = 0, MenuLib.MAX_MENU_LINES do -- clear menu
local line = ctx.MenuLines[i]
if (line.Type~=0) then
line.MenuId = ctx.Menu.MenuId
line.lineNum = i
MenuLib.MenuLinePostProcessing(line) -- Do the same post processing as if they come from the RX
--if (DEBUG_ON) then Log.LOG_write("SIM RESPONSE MenuLine: %s\n", MenuLib.menuLine2String(line)) end
end
end
end
function MenuLib.GetFlightModeValue(line)
local ret = line.Text.." "
local val = line.Val
if (val==nil) then return ret.."--" end
-- Adjust the displayed value for Flight mode line as needed
if (DSM_Context.RX.Id == RX.FC6250HX) then
-- Helicopter Flights modes
if (val==0) then ret = ret .. "1 / HOLD"
elseif (val==1) then ret = ret .. "2 / Normal"
elseif (val==2) then ret = ret .. "3 / Stunt 1"
elseif (val==3) then ret = ret .. "4 / Stunt 2"
elseif (val==4) then ret = ret .. "5 / Panic"
else
ret = ret .. " " .. (val + 1)
end
else
-- No adjustment needed
if (val==190) then
ret=ret.."Err:Out of Range"
else
ret=ret..(val + 1)
end
end
return ret
end
function MenuLib.Init()
print("MenuLib.Init()")
-- Phase Names
PhaseText[PHASE.INIT] = "INIT"
PhaseText[PHASE.RX_VERSION] = "RX_VERSION"
PhaseText[PHASE.WAIT_CMD] = "WAIT_CMD"
PhaseText[PHASE.MENU_TITLE] = "MENU_TITLE"
PhaseText[PHASE.MENU_REQ_TX_INFO] = "MENU_REQ_TX_INFO"
PhaseText[PHASE.MENU_LINES] = "MENU_LINES"
PhaseText[PHASE.MENU_VALUES] = "MENU_VALUES"
PhaseText[PHASE.VALUE_CHANGING] = "VALUE_CHANGING"
PhaseText[PHASE.VALUE_CHANGING_WAIT] = "VALUE_EDITING"
PhaseText[PHASE.VALUE_CHANGE_END] = "VALUE_CHANGE_END"
PhaseText[PHASE.EXIT] = "EXIT"
PhaseText[PHASE.EXIT_DONE] = "EXIT_DONE"
-- Line Types
LineTypeText[LINE_TYPE.MENU] = "M"
LineTypeText[LINE_TYPE.LIST_MENU_NC] = "LM_nc"
LineTypeText[LINE_TYPE.LIST_MENU] = "LM"
LineTypeText[LINE_TYPE.LIST_MENU_TOG] = "LM_tog"
LineTypeText[LINE_TYPE.LIST_MENU_NC2] = "LM_nc2"
LineTypeText[LINE_TYPE.LIST_MENU_ORI] = "LM_ori"
LineTypeText[LINE_TYPE.VALUE_NUM_I8_NC] = "V_nc"
LineTypeText[LINE_TYPE.VALUE_PERCENT] = "V_%"
LineTypeText[LINE_TYPE.VALUE_DEGREES] = "V_de"
LineTypeText[LINE_TYPE.VALUE_NUM_I8] = "V_i8"
LineTypeText[LINE_TYPE.VALUE_NUM_I16] = "V_i16"
LineTypeText[LINE_TYPE.VALUE_NUM_SI16] = "V_s16"
LineTypeText[LINE_TYPE.LT_EMPTY] = "Z"
DSM_Context.Phase = PHASE.RX_VERSION
end
function MenuLib.clearAllText()
local function clearTable(t)
for i, v in ipairs(t) do t[i] = nil end
end
clearTable(Text)
clearTable(List_Text)
clearTable(List_Text_Img)
clearTable(List_Values)
end
function MenuLib.LoadTextFromFile(fileName, mem)
local function rtrim(s)
local n = string.len(s)
while n > 0 and string.find(s, "^%s", n) do n = n - 1 end
return string.sub(s, 1, n)
end
--print(string.format("Loading messages from [%s]",fileName))
local dataFile = io.open(fileName, "r") -- read File
-- cannot read file???
assert(dataFile, "Cannot load Message file:" .. fileName)
local data = io.read(dataFile, mem * 1024) -- read up to 10k characters (newline char also counts!)
io.close(dataFile)
collectgarbage("collect")
local lineNo = 0
for line in string.gmatch(data, "[^\r\n]+") do
lineNo = lineNo + 1
--print(string.format("Line [%d]: %s",lineNo,line))
-- Remove Comments
local s = string.find(line, "--", 1, true)
if (s ~= nil) then
line = string.sub(line, 1, s - 1)
end
line = rtrim(line)
if (string.len(line) > 0) then
local a, b, c = string.match(line, "%s*(%a*)%s*|%s*(%w*)%s*|(.*)%s*")
--print(string.format("[%s] [%s] [%s]",a,b,c))
if (a ~= nil) then
local index = tonumber(b)
if (index == nil) then
assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, lineNo, b))
elseif (a == "T") then
Text[index] = c
elseif (a == "LT") then
List_Text[index] = c
elseif (a == "LI") then
List_Text_Img[index] = c
elseif (a == "FM") then
Flight_Mode[0] = c
elseif (a == "RX") then
RxName[index] = c
else
assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, lineNo, a))
end
end
end
if (lineNo % 50 == 0) then
collectgarbage("collect")
end
end -- For
--print(string.format("Loaded [%d] messages",lineNo))
data = nil
end
function MenuLib.INC_LoadTextFromFile(fileName, FileState)
-----------------------
local function rtrim(s)
local n = string.len(s)
while n > 0 and string.find(s, "^%s", n) do n = n - 1 end
return string.sub(s, 1, n)
end
local function GetTextInfoFromFile(pos)
local dataFile = io.open(fileName, "r")
io.seek(dataFile,pos)
local buff = io.read(dataFile, 100)
io.close(dataFile)
local line=""
local index=""
local type=""
local pipe=0
local comment=0
local newPos = pos
-- Parse the line:
-- Format: TT|0x999|Text -- Comment
for i=1,#buff do
newPos=newPos+1
local ch = string.sub(buff,i,i)
if (pipe < 2 and ch=="|") then pipe=pipe+1 -- Count pipes pos (Type | Index | .....)
elseif (ch=="\r") then -- Ignore CR
elseif (ch=="\n") then break -- LF, end of line
elseif (ch=="-") then -- March comments
comment=comment+1
if (comment==2) then pipe=6 end -- Comment part of line
else
-- regular char
comment=0
if (pipe==0) then type=type..ch -- in TT (Type)
elseif (pipe==1) then index=index..ch -- in Index
elseif (pipe<6) then line=line..ch end -- in Text
end -- Regular char
end -- For
return type, index, rtrim(line), newPos
end
-----------------------------------------------------------
if (FileState.state==nil) then -- Initial State
FileState.state=1
FileState.lineNo=0
FileState.filePos=0
end
if FileState.state==1 then
for l=1,10 do -- do 10 lines at a time
local type, sIndex, text
local lineStart = FileState.filePos
type, sIndex, text, FileState.filePos = GetTextInfoFromFile(FileState.filePos)
--print(string.format("T=%s, I=%s, T=%s LS=%d, FP=%d",type,sIndex,text,lineStart, FileState.filePos))
if (lineStart==FileState.filePos) then -- EOF
FileState.state=2 --EOF State
return 1
end
FileState.lineNo = FileState.lineNo + 1
type = rtrim(type)
if (string.len(type) > 0 and string.len(sIndex) > 0) then
local index = tonumber(sIndex)
if (index == nil) then
assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, FileState.lineNo, sIndex))
elseif (type == "T") then
Text[index] = text
elseif (type == "LT") then
List_Text[index] = text
elseif (type == "LI") then
List_Text_Img[index] = text
elseif (type == "FM") then
Flight_Mode[0] = text
elseif (type == "RX") then
RxName[index] = text
else
assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, FileState.lineNo, type))
end
end
end -- for
end -- if
return 0
end
-- Export some Constants and Variables
MenuLib.PHASE = PHASE
MenuLib.LINE_TYPE = LINE_TYPE
MenuLib.DISP_ATTR = DISP_ATTR
MenuLib.RX = RX
MenuLib.MAX_MENU_LINES = MAX_MENU_LINES
MenuLib.BACK_BUTTON = BACK_BUTTON
MenuLib.NEXT_BUTTON = NEXT_BUTTON
MenuLib.PREV_BUTTON = PREV_BUTTON
MenuLib.DSM_Context = DSM_Context
MenuLib.Text = Text
MenuLib.List_Text = List_Text
MenuLib.List_Text_Img = List_Text_Img
MenuLib.List_Values = List_Values
MenuLib.LOG_open = Log.LOG_open
MenuLib.LOG_write = Log.LOG_write
MenuLib.LOG_Close = Log.LOG_close
return MenuLib

View File

@ -0,0 +1,789 @@
local Log, DEBUG_ON = ...
local DATA_PATH = "/MODELS/DSMDATA" -- Path to store model settings files
local TX_CHANNELS = 12
-- MODEL information from ETX/OTX
local ModelLib = {}
local MODEL = {
modelName = "", -- The name of the model comming from OTX/ETX
modelOutputChannel = {}, -- Output information from OTX/ETX
AirWingTailDesc = "",
TX_CH_TEXT = {},
PORT_TEXT = {},
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
}
--Channel Types --
local CH_TYPE = {
NONE = 0x00,
AIL = 0x01,
ELE = 0x02,
RUD = 0x04,
REVERSE = 0x20,
THR = 0x40,
SLAVE = 0x80,
}
-- Seems like Reverse Mix is complement of the 3 bits
local CH_MIX_TYPE = {
MIX_NORM = 0x00, -- 0000
MIX_AIL = 0x10, -- 0001 Taileron
MIX_ELE = 0x20, -- 0010 For VTIAL and Delta-ELEVON
MIX_RUD = 0x30, -- 0011 For VTIAL
MIX_RUD_REV = 0x40, -- 0100 For VTIAL
MIX_ELE_REV = 0x50, -- 0101 For VTIAL and Delta-ELEVON A
MIX_AIL_REV = 0x60, -- 0110 Taileron
MIX_NORM_REV = 0x70 -- 0111
}
local AIRCRAFT_TYPE = {
PLANE = 0,
HELI = 1,
GLIDER = 2,
DRONE = 3
}
local aircraft_type_text = {[0]="Plane","Heli","Glider","Drone"}
local WING_TYPE = {
AIL_1 = 0, --1
AIL_2 = 1, --2
FLAPERON = 2, --2
AIL_1_FLP_1 = 3, --2
AIL_2_FLP_1 = 4, --3
AIL_2_FLP_2 = 5, --4
ELEVON_A = 6, --2
ELEVON_B = 7 --2
}
local wing_type_text = {[0]="Normal","Dual Ail","Flapperon", "Ail + Flp","Dual Ail + Flp","Dual Ail/Flp","Elevon A","Elevon B"}
local TAIL_TYPE = {
RUD_1 = 0, -- 1
RUD_1_ELEV_1 = 1, -- 2
RUD_1_ELEV_2 = 2, -- 3
RUD_2_ELEV_1 = 3, -- 3
RUD_2_ELEV_2 = 4, -- 4
VTAIL_A = 5, -- 2
VTAIL_B = 6, -- 2
TRAILERON_A = 7, -- 3
TRAILERON_B = 8, -- 3
TRAILERON_A_R2 = 9, -- 3
TRAILERON_B_R2 = 10 -- 3
}
local tail_type_text = {[0]="Rud Only","Normal","Rud + Dual Ele","Dual Rud + Elv","Dual Rud/Ele",
"VTail A","VTail B","Taileron A","Taileron B","Taileron A + 2x Rud","Taileron B + 2x Rud"}
local CH_MODE_TYPE = {
NORMAL = 0,
REVERSE = 1,
USE_TX = 3
}
local PORT = {
PORT1 = 0,
PORT2 = 1,
PORT3 = 2,
PORT4 = 3,
PORT5 = 4,
PORT6 = 5,
PORT7 = 6,
PORT8 = 7,
PORT9 = 8,
PORT10 = 9,
PORT11 = 10,
PORT12 = 11
}
local MEMU_VAR = {
AIRCRAFT_TYPE = 1001,
WING_TYPE = 1002,
TAIL_TYPE = 1003,
CH_BASE = 1010,
CH_THR = 1010,
CH_L_AIL = 1011,
CH_R_AIL = 1012,
CH_L_FLP = 1013,
CH_R_FLP = 1014,
CH_L_RUD = 1015,
CH_R_RUD = 1016,
CH_L_ELE = 1017,
CH_R_ELE = 1018,
PORT_BASE = 1020,
PORT1_MODE = 1020,
PORT2_MODE = 1021,
PORT3_MODE = 1022,
PORT4_MODE = 1023,
PORT5_MODE = 1024,
PORT6_MODE = 1025,
PORT7_MODE = 1026,
PORT8_MODE = 1027,
PORT9_MODE = 1028,
PORT10_MODE = 1029,
PORT11_MODE = 1030,
PORT12_MODE = 1031,
DATA_END = 1040
}
-- MENU DATA Management
local MENU_DATA = {} -- Store the variables used in the Menus.
---- DSM_ChannelInfo ---------------------------------
-- First byte describe Special Mixing (Vtail/Elevon = 0x20)
--VTAIL
--(0x00 0x06) CH_TYPE.ELE+CH_TYPE.RUD (0x02+0x04 = 0x06)
--(0x20 0x86) CH_TYPE.ELE+CH_TYPE.RUD+CH_TYPE.SLAVE (0x02+0x04+0x80 = 0x86)
-- The 2nd byte describes the functionality of the port
--
-- Single Example: CH_TYPE.AIL (0x01) Aileron
-- Reverse Example: CH_TYPE.AIL+CH_TYPE.REVERSE (0x01+0x20=0x21) Reverse Aileron
-- Slave Example: CH_TYPE.AIL+CH_TYPE.SLAVE (0x01+0x80) -- 2nd servo Aileron
-- Elevon Example: CH_TYPE.AIL+CH_TYPE.ELE (0x01+0x02 = 0x03) -- Elevon
-- Elevon Example: CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE (0x01+0x02+0x80 = 0x83) -- Slave Elevon
-- RudElv (VTail) Example: CH_TYPE.ELE+CH_TYPE.RUD (0x02+0x04 = 0x06) -- Rudevator
-- RudElv (VTail) Example: CH_TYPE.ELE+CH_TYPE.RUD+CH_TYPE.SLAVE (0x02+0x04+0x80 = 0x86) -- Rudevator Slave
-- DEFAULT Simple Plane Port configuration (The Configuration tool will overrride this)
MODEL.DSM_ChannelInfo= {[0]= -- Start array at position 0
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.THR}, -- Ch1 Thr (0x40)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.AIL}, -- Ch2 Ail (0x01)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.ELE}, -- Ch2 ElE (0x02)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.RUD}, -- Ch4 Rud (0x04)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch5 Gear (0x00)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch6 Aux1 (0x00)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch7 Aux2 (0x00)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch8 Aux3 (0x00)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch9 Aux4 (0x00)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch10 Aux5 (0x00)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch11 Aux6 (0x00)
{[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE} -- Ch12 Aux7 (0x00)
}
function ModelLib.printChannelSummary(a,w,t)
-- Summary
print("CHANNEL INFORMATION")
print("Aircraft:".. (aircraft_type_text[MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]] or "--"))
print("Wing Type:".. (wing_type_text[MENU_DATA[MEMU_VAR.WING_TYPE]] or "--"))
print("Tail Type:".. (tail_type_text[MENU_DATA[MEMU_VAR.TAIL_TYPE]] or "--"))
print("Thr:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_THR] or 30)] or "--")) -- use fake ch30 for non existing channels
print("LAil:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_AIL] or 30)] or "--"))
print("RAil:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_AIL] or 30)] or "--"))
print("LFlp:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_FLP] or 30)] or "--"))
print("RFlp:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_FLP] or 30)] or "--"))
print("LEle:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_ELE] or 30)] or "--"))
print("REle:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_ELE] or 30)] or "--"))
print("LRud:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_RUD] or 30)] or "--"))
print("RRud:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_RUD] or 30)] or "--"))
end
function ModelLib.printServoReverseInfo()
print("SERVO Normal/Reverse INFORMATION")
for i=0, TX_CHANNELS-1 do
local s="--"
if (MENU_DATA[MEMU_VAR.PORT1_MODE+i] or 0) == 0 then s="NORMAL" else s="REVERSE" end
print(string.format("Port%d: %s", i+1, s))
end
end
function ModelLib.channelType2String(byte1, byte2)
local s = ""
if (byte2==0) then return s end;
if (bit32.band(byte2,CH_TYPE.AIL)>0) then s=s.."Ail" end
if (bit32.band(byte2,CH_TYPE.ELE)>0) then s=s.."Ele" end
if (bit32.band(byte2,CH_TYPE.RUD)>0) then s=s.."Rud" end
if (bit32.band(byte2,CH_TYPE.THR)>0) then s=s.."Thr" end
if (bit32.band(byte2,CH_TYPE.REVERSE)>0) then s=s.."-" end
if (bit32.band(byte2,CH_TYPE.SLAVE)>0) then s=s.." Slv" end
if (byte1==CH_MIX_TYPE.MIX_NORM) then s=s.." "
elseif (byte1==CH_MIX_TYPE.MIX_AIL) then s=s.." M_Ail"
elseif (byte1==CH_MIX_TYPE.MIX_ELE) then s=s.." M_Ele"
elseif (byte1==CH_MIX_TYPE.MIX_RUD) then s=s.." M_Rud"
elseif (byte1==CH_MIX_TYPE.MIX_RUD_REV) then s=s.." M_Rud-"
elseif (byte1==CH_MIX_TYPE.MIX_ELE_REV) then s=s.." M_Ele-"
elseif (byte1==CH_MIX_TYPE.MIX_AIL_REV) then s=s.." M_Ail-"
elseif (byte1==CH_MIX_TYPE.MIX_NORM_REV) then s=s.." M-"
end
return s;
end
-------------------------------------------------------------------------------------------------
-- Read the model information from OTX/ETX
local function getModuleChannelOrder(num)
--Determine fist 4 channels order
local channel_names={}
local stick_names = {[0]= "R", "E", "T", "A" }
local ch_order=num
if (ch_order == -1) then
channel_names[0] = stick_names[3]
channel_names[1] = stick_names[1]
channel_names[2] = stick_names[2]
channel_names[3] = stick_names[0]
else
channel_names[bit32.band(ch_order,3)] = stick_names[3]
ch_order = math.floor(ch_order/4)
channel_names[bit32.band(ch_order,3)] = stick_names[1]
ch_order = math.floor(ch_order/4)
channel_names[bit32.band(ch_order,3)] = stick_names[2]
ch_order = math.floor(ch_order/4)
channel_names[bit32.band(ch_order,3)] = stick_names[0]
end
local s = ""
for i=0,3 do
s=s..channel_names[i]
end
return s
end
function ModelLib.ReadTxModelData()
local TRANSLATE_AETR_TO_TAER=false
local table = model.getInfo() -- Get the model name
MODEL.modelName = table.name
local module = model.getModule(0) -- Internal
if (module==nil or module.Type~=6) then module = model.getModule(1) end -- External
if (module~=nil) then
if (module.Type==6 ) then -- MULTI-MODULE
local chOrder = module.channelsOrder
local s = getModuleChannelOrder(chOrder)
Log.LOG_write("MultiChannel Ch Order: [%s] %s\n",chOrder,s)
if (s=="AETR") then TRANSLATE_AETR_TO_TAER=true
else TRANSLATE_AETR_TO_TAER=false
end
end
end
Log.LOG_write("MODEL NAME = %s\n",MODEL.modelName)
-- Read Ch1 to Ch10
local i= 0
for i = 0, TX_CHANNELS-1 do
local ch = model.getOutput(i) -- Zero base
if (ch~=nil) then
MODEL.modelOutputChannel[i] = ch
if (string.len(ch.name)==0) then
ch.formatCh = string.format("TX:Ch%i",i+1)
else
ch.formatCh = string.format("TX:Ch%i/%s",i+1,ch.name or "--")
end
end
end
-- Translate AETR to TAER
-- TODO: Check if there is a way to know how to the TX is configured, since if it is
-- already TAER, is not needed
if (TRANSLATE_AETR_TO_TAER) then
Log.LOG_write("Applying AETR -> TAER translation\n")
local ail = MODEL.modelOutputChannel[0]
local elv = MODEL.modelOutputChannel[1]
local thr = MODEL.modelOutputChannel[2]
MODEL.modelOutputChannel[0] = thr
MODEL.modelOutputChannel[1] = ail
MODEL.modelOutputChannel[2] = elv
end
-- Create the Port Text to be used
Log.LOG_write("Ports/Channels:\n")
for i = 0, TX_CHANNELS-1 do
local ch = MODEL.modelOutputChannel[i]
if (ch~=nil) then
MODEL.TX_CH_TEXT[i] = ch.formatCh
MODEL.PORT_TEXT[i] = string.format("P%i (%s) ",i+1,MODEL.TX_CH_TEXT[i])
Log.LOG_write("Port%d %s [%d,%d] Rev=%d, Off=%d, ppmC=%d, syn=%d\n",i+1,MODEL.TX_CH_TEXT[i],math.floor(ch.min/10),math.floor(ch.max/10), ch.revert, ch.offset, ch.ppmCenter, ch.symetrical)
end
end
end
----------------------- FILE MANAGEMENT ---------------------------------------------
-- Create a fairly unique name for a model..combination of name and a hash
-- TODO: Check with ETX why we can't get the filename used to store the model info
-- Improvement request??
function ModelLib.hashName(mName)
local c=10000;
local prefix = string.gsub(mName,"%.","_") -- Change any "." to "_"
prefix = string.gsub(prefix,"% ","_") -- Change any space to "_"
prefix = string.sub(prefix,1,5) -- Take the first 5 characters
-- Simple Hash of the Model Name adding each character
for i = 1, #mName do
local ch = string.byte(mName,i,i)
c=c+ch
end
return (prefix .. c) -- Return Prefix + Hash
end
-- Load Menu Data from a file
function ModelLib.ST_LoadFileData()
local fname = ModelLib.hashName(MODEL.modelName)..".txt"
-- Clear Menu Data
for i = 0, MEMU_VAR.DATA_END do
MENU_DATA[i]=nil
end
print("Loading File:"..fname)
local dataFile = io.open(DATA_PATH .. "/".. fname, "r") -- read File
-- cannot read file???
if (dataFile==nil) then return 0 end
local line = io.read(dataFile, 5000)
io.close(dataFile)
if #line == 0 then return 0 end -- No data??
-- Process the input, each line is "Var_Id : Value" format
-- Store it into MANU_DATA
local i=0
for k, v in string.gmatch(line, "(%d+):(%d+)") do
--print(string.format("Read MENU_DATA[%d]:[%d]",k, v))
MENU_DATA[k+0]=v+0 -- do aritmentic to convert string to number
i=i+1
end
local currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
local currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
local currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
print("Validation")
print(string.format("AIRCRAFT_TYPE(%d)=%s", MEMU_VAR.AIRCRAFT_TYPE,aircraft_type_text[currAircraftType]))
print(string.format("WING_TYPE(%d)=%s", MEMU_VAR.WING_TYPE, wing_type_text[currWingType]))
print(string.format("TAIL_TYPE(%d)=%s", MEMU_VAR.TAIL_TYPE, tail_type_text[currTailType]))
ModelLib.printChannelSummary()
ModelLib.printServoReverseInfo()
-- Return 0 if no lines processed, 1 otherwise
if (i > 0) then return 1 else return 0 end
end
-- Saves MENU_DATA to a file
function ModelLib.ST_SaveFileData()
local fname = ModelLib.hashName(MODEL.modelName)..".txt"
print("Saving File:"..fname)
local dataFile = assert(io.open(DATA_PATH .. "/" .. fname, "w"),"Please create "..DATA_PATH.." folder") -- write File
-- Foreach MENU_DATA with a value write Var_Id:Value into file
for i = 0, MEMU_VAR.DATA_END do
if (MENU_DATA[i]~=nil) then
--print(string.format("Write MENU_DATA[%s] : %s",i,MENU_DATA[i]))
io.write(dataFile,string.format("%s:%s\n",i,MENU_DATA[i]))
end
end
io.close(dataFile)
end
-- This Creates the Servo Settings that will be used to pass to
-- Forward programming
function ModelLib.CreateDSMPortChannelInfo()
local function ApplyWingMixA(b2)
-- ELEVON
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_ELE end; -- 0x03
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x83
end
local function ApplyWingMixB(b2)
-- ELEVON
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x03
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_ELE end; -- 0x83
end
local function ApplyTailMixA(b2)
-- VTAIL
-- Default normal/reverse behaviour
if (b2==CH_TYPE.RUD+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x06
if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_ELE end; -- 0x86
--TAILERON
-- Default normal/reverse behaviour
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x03
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_AIL end; -- 0x83
end
local function ApplyTailMixB(b2)
-- VTAIL
-- Default normal/reverse behaviour
if (b2==CH_TYPE.RUD+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x06
if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_RUD end; -- 0x86
--TAILERON
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_AIL end; -- 0x03
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x83
end
local function reverseMix(b)
if (b==CH_MIX_TYPE.MIX_NORM) then return CH_MIX_TYPE.MIX_NORM_REV end;
if (b==CH_MIX_TYPE.MIX_AIL) then return CH_MIX_TYPE.MIX_AIL_REV end;
if (b==CH_MIX_TYPE.MIX_ELE) then return CH_MIX_TYPE.MIX_ELE_REV end;
if (b==CH_MIX_TYPE.MIX_RUD) then return CH_MIX_TYPE.MIX_RUD_REV end;
return b
end
local DSM_ChannelInfo = MODEL.DSM_ChannelInfo
for i=0, TX_CHANNELS-1 do
DSM_ChannelInfo[i] = {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE} -- Initialize with no special function
end
local aircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
local wingType = MENU_DATA[MEMU_VAR.WING_TYPE]
local tailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
local thrCh = MENU_DATA[MEMU_VAR.CH_THR]
local lAilCh = MENU_DATA[MEMU_VAR.CH_L_AIL]
local rAilCh = MENU_DATA[MEMU_VAR.CH_R_AIL]
local lflapCh = MENU_DATA[MEMU_VAR.CH_L_FLP]
local rflapCh = MENU_DATA[MEMU_VAR.CH_R_FLP]
local lElevCh = MENU_DATA[MEMU_VAR.CH_L_ELE]
local rElevCh = MENU_DATA[MEMU_VAR.CH_R_ELE]
local lRudCh = MENU_DATA[MEMU_VAR.CH_L_RUD]
local rRudCh = MENU_DATA[MEMU_VAR.CH_R_RUD]
-- Channels in menu vars are Zero base, Channel info is 1 based
-- THR
if (thrCh~=nil and thrCh < 10) then DSM_ChannelInfo[thrCh][1]= CH_TYPE.THR end
-- AIL (Left and Right)
if (lAilCh~=nil) then DSM_ChannelInfo[lAilCh][1] = CH_TYPE.AIL end
if (rAilCh~=nil) then DSM_ChannelInfo[rAilCh][1] = CH_TYPE.AIL+CH_TYPE.SLAVE end
-- ELE (Left and Right)
if (lElevCh~=nil) then DSM_ChannelInfo[lElevCh][1] = CH_TYPE.ELE end
if (rElevCh~=nil) then DSM_ChannelInfo[rElevCh][1] = CH_TYPE.ELE+CH_TYPE.SLAVE end
-- RUD (Left and Right)
if (lRudCh~=nil) then DSM_ChannelInfo[lRudCh][1] = CH_TYPE.RUD end
if (rRudCh~=nil) then DSM_ChannelInfo[rRudCh][1] = CH_TYPE.RUD+CH_TYPE.SLAVE end
-- VTAIL: RUD + ELE
if (tailType==TAIL_TYPE.VTAIL_A or tailType==TAIL_TYPE.VTAIL_B) then
DSM_ChannelInfo[lElevCh][1] = CH_TYPE.RUD+CH_TYPE.ELE
DSM_ChannelInfo[rElevCh][1] = CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE
end
-- TAILERRON: 2-ELE + AIL
if (tailType==TAIL_TYPE.TRAILERON_A or tailType==TAIL_TYPE.TRAILERON_A_R2 or
tailType==TAIL_TYPE.TRAILERON_B or tailType==TAIL_TYPE.TRAILERON_B_R2) then
DSM_ChannelInfo[lElevCh][1] = CH_TYPE.AIL+CH_TYPE.ELE
DSM_ChannelInfo[rElevCh][1] = CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE
end
---- ELEVON : AIL + ELE
if (wingType==WING_TYPE.ELEVON_A or wingType==WING_TYPE.ELEVON_B) then
DSM_ChannelInfo[lAilCh][1] = CH_TYPE.AIL+CH_TYPE.ELE
DSM_ChannelInfo[rAilCh][1] = CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE
end
------MIXES ---------
-- TAIL Mixes (Elevator and VTail)
if (tailType==TAIL_TYPE.VTAIL_A or tailType==TAIL_TYPE.TRAILERON_A or tailType==TAIL_TYPE.TRAILERON_A_R2) then
DSM_ChannelInfo[lElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[lElevCh][1])
DSM_ChannelInfo[rElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[rElevCh][1])
elseif (tailType==TAIL_TYPE.VTAIL_B or tailType==TAIL_TYPE.TRAILERON_B or tailType==TAIL_TYPE.TRAILERON_B_R2) then
DSM_ChannelInfo[lElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[lElevCh][1])
DSM_ChannelInfo[rElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[rElevCh][1])
end
---- Wing Mixes
if (wingType==WING_TYPE.ELEVON_A) then
DSM_ChannelInfo[lAilCh][0] = ApplyWingMixA(DSM_ChannelInfo[lAilCh][1])
DSM_ChannelInfo[rAilCh][0] = ApplyWingMixA(DSM_ChannelInfo[rAilCh][1])
elseif (wingType==WING_TYPE.ELEVON_B) then
DSM_ChannelInfo[lAilCh][0] = ApplyWingMixB(DSM_ChannelInfo[lAilCh][1])
DSM_ChannelInfo[rAilCh][0] = ApplyWingMixB(DSM_ChannelInfo[rAilCh][1])
end
-- Apply Gyro Reverse as needed for each channel as long as it is used
for i=0, TX_CHANNELS-1 do
if (MENU_DATA[MEMU_VAR.PORT_BASE+i]==CH_MODE_TYPE.REVERSE and DSM_ChannelInfo[i][1]>0) then
DSM_ChannelInfo[i][0]=reverseMix(DSM_ChannelInfo[i][0])
DSM_ChannelInfo[i][1]=DSM_ChannelInfo[i][1]+CH_TYPE.REVERSE
end
end
-- Show how it looks
for i=0, 9 do
local b1,b2 = DSM_ChannelInfo[i][0], DSM_ChannelInfo[i][1]
print(string.format("%s (%02X %02X) %s", MODEL.PORT_TEXT[i],
b1, b2, ModelLib.channelType2String(b1,b2)))
end
MODEL.AirWingTailDesc = string.format("Aircraft(%s) Wing(%s) Tail(%s)",aircraft_type_text[aircraftType],wing_type_text[wingType],tail_type_text[tailType])
end
function ModelLib.ST_PlaneWingInit(wingType)
print("Change Plane WingType:"..wing_type_text[wingType])
MENU_DATA[MEMU_VAR.WING_TYPE] = wingType
-- Clear all Wing Data
MENU_DATA[MEMU_VAR.CH_L_AIL] = nil
MENU_DATA[MEMU_VAR.CH_R_AIL] = nil
MENU_DATA[MEMU_VAR.CH_L_FLP] = nil
MENU_DATA[MEMU_VAR.CH_R_FLP] = nil
MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT1
-- Default Channel Assisgments for each Wing type
if (wingType==WING_TYPE.AIL_1) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
elseif (wingType==WING_TYPE.AIL_2) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
elseif (wingType==WING_TYPE.FLAPERON) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
elseif (wingType==WING_TYPE.AIL_1_FLP_1) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT6
elseif (wingType==WING_TYPE.AIL_2_FLP_1) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5
elseif (wingType==WING_TYPE.AIL_2_FLP_2) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
MENU_DATA[MEMU_VAR.CH_R_FLP] = PORT.PORT5
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT7
elseif (wingType==WING_TYPE.ELEVON_A) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT3
elseif (wingType==WING_TYPE.ELEVON_B) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT3
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
else -- Assume normal
print("ERROR: Invalid Wing Type")
end
ModelLib.printChannelSummary()
end
function ModelLib.ST_PlaneTailInit(tailType)
if (MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_A or
MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_B) then
tailType = TAIL_TYPE.RUD_1 -- Delta only have ruder
end
print("Change Plane Tail Type:"..tail_type_text[tailType])
-- Clear all data for Tail
MENU_DATA[MEMU_VAR.TAIL_TYPE] = tailType
MENU_DATA[MEMU_VAR.CH_L_ELE] = nil
MENU_DATA[MEMU_VAR.CH_R_ELE] = nil
MENU_DATA[MEMU_VAR.CH_L_RUD] = nil
MENU_DATA[MEMU_VAR.CH_R_RUD] = nil
-- Setup Channels for different Tail types
if (tailType == TAIL_TYPE.RUD_1) then
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
elseif (tailType == TAIL_TYPE.RUD_1_ELEV_1) then
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
elseif (tailType == TAIL_TYPE.RUD_1_ELEV_2) then
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
elseif (tailType == TAIL_TYPE.RUD_2_ELEV_1) then
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT5
elseif (tailType == TAIL_TYPE.RUD_2_ELEV_2) then
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT6
elseif (tailType == TAIL_TYPE.VTAIL_A or tailType == TAIL_TYPE.VTAIL_B) then
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT4
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
elseif (tailType == TAIL_TYPE.TRAILERON_A or tailType==TAIL_TYPE.TRAILERON_A_R2 or
tailType == TAIL_TYPE.TRAILERON_B or tailType==TAIL_TYPE.TRAILERON_B_R2) then
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
else -- Assume Normal
print("ERROR:invalid Tail Type")
end
if (tailType == TAIL_TYPE.TRAILERON_A_R2 or tailType==TAIL_TYPE.TRAILERON_B_R2) then
MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT7
end
ModelLib.printChannelSummary()
end
function ModelLib.ST_GliderWingInit(wingType)
print("Change Glider WingType:"..wing_type_text[wingType])
MENU_DATA[MEMU_VAR.WING_TYPE] = wingType
-- Clear all Wing Data
MENU_DATA[MEMU_VAR.CH_L_AIL] = nil
MENU_DATA[MEMU_VAR.CH_R_AIL] = nil
MENU_DATA[MEMU_VAR.CH_L_FLP] = nil
MENU_DATA[MEMU_VAR.CH_R_FLP] = nil
MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT6
-- Default Channel Assisgments for each Wing type
if (wingType==WING_TYPE.AIL_1) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
elseif (wingType==WING_TYPE.AIL_2) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
elseif (wingType==WING_TYPE.AIL_2_FLP_1) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5
elseif (wingType==WING_TYPE.AIL_2_FLP_2) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5
MENU_DATA[MEMU_VAR.CH_R_FLP] = PORT.PORT6
MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT7
elseif (wingType==WING_TYPE.ELEVON_A) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
elseif (wingType==WING_TYPE.ELEVON_B) then
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT1
else -- Assume normal
print("ERROR: Invalid Wing Type")
end
ModelLib.printChannelSummary()
end
function ModelLib.ST_GliderTailInit(tailType)
if (MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_A) then
tailType = TAIL_TYPE.RUD_1 -- Delta only have ruder
end
print("Change Glider Tail Type:"..tail_type_text[tailType])
-- Clear all data for Tail
MENU_DATA[MEMU_VAR.TAIL_TYPE] = tailType
MENU_DATA[MEMU_VAR.CH_L_ELE] = nil
MENU_DATA[MEMU_VAR.CH_R_ELE] = nil
MENU_DATA[MEMU_VAR.CH_L_RUD] = nil
MENU_DATA[MEMU_VAR.CH_R_RUD] = nil
-- Setup Channels for different Tail types
if (tailType == TAIL_TYPE.RUD_1) then
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
elseif (tailType == TAIL_TYPE.RUD_1_ELEV_1) then
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
elseif (tailType == TAIL_TYPE.VTAIL_A) then
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT4
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
elseif (tailType == TAIL_TYPE.VTAIL_B) then
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT4
else -- Assume Normal
print("ERROR: Invalid Tail Type")
end
ModelLib.printChannelSummary()
end
function ModelLib.ST_AircraftInit(aircraftType)
MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] = aircraftType
print("Change Aircraft:".. aircraft_type_text[aircraftType])
-- Setup Default Aircraft Wing/Tail
if (aircraftType==AIRCRAFT_TYPE.PLANE) then
ModelLib.ST_PlaneWingInit(WING_TYPE.AIL_1)
ModelLib.ST_PlaneTailInit(TAIL_TYPE.RUD_1_ELEV_1)
elseif (aircraftType==AIRCRAFT_TYPE.GLIDER) then
ModelLib.ST_GliderWingInit(WING_TYPE.AIL_1)
ModelLib.ST_GliderTailInit(TAIL_TYPE.RUD_1_ELEV_1)
else
ModelLib.ST_PlaneWingInit(WING_TYPE.AIL_1)
ModelLib.ST_PlaneTailInit(TAIL_TYPE.RUD_1_ELEV_1)
end
end
-- Setup Initial Default Data for the Menus
function ModelLib.ST_Default_Data()
print("Initializing Menu DATA")
ModelLib.ST_AircraftInit(AIRCRAFT_TYPE.PLANE)
print("Initializing Servo Reverse from TX output settings")
MENU_DATA[MEMU_VAR.PORT1_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT1].revert
MENU_DATA[MEMU_VAR.PORT2_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT2].revert
MENU_DATA[MEMU_VAR.PORT3_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT3].revert
MENU_DATA[MEMU_VAR.PORT4_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT4].revert
MENU_DATA[MEMU_VAR.PORT5_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT5].revert
MENU_DATA[MEMU_VAR.PORT6_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT6].revert
MENU_DATA[MEMU_VAR.PORT7_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT7].revert
MENU_DATA[MEMU_VAR.PORT8_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT8].revert
MENU_DATA[MEMU_VAR.PORT9_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT9].revert
MENU_DATA[MEMU_VAR.PORT10_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT10].revert
ModelLib.printServoReverseInfo()
end
ModelLib.TX_CHANNELS = TX_CHANNELS
ModelLib.MODEL = MODEL
ModelLib.CH_TYPE = CH_TYPE
ModelLib.CH_MODE_TYPE = CH_MODE_TYPE
ModelLib.AIRCRAFT_TYPE = AIRCRAFT_TYPE
ModelLib.WING_TYPE = WING_TYPE
ModelLib.TAIL_TYPE = TAIL_TYPE
ModelLib.MENU_DATA = MENU_DATA
ModelLib.MEMU_VAR = MEMU_VAR
ModelLib.PORT = PORT
ModelLib.DATA_PATH = DATA_PATH
ModelLib.aircraft_type_text = aircraft_type_text
ModelLib.wing_type_text = wing_type_text
ModelLib.tail_type_text = tail_type_text
return ModelLib

View File

@ -0,0 +1,467 @@
---- #########################################################################
---- # #
---- # Copyright (C) OpenTX #
-----# #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
------------------------------------------------------------------------------
-- This scrip does the airplane Setup similar to how a a Spektrum radio does
-- it. You can select the plane type, the Wing type, etc.
-- This settings are needed for ForwardProgramming to send the TX aircraft
-- configuration to the RX when in Initial Setup
-- Author: Francisco Arzu
------------------------------------------------------------------------------
local Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON = ... -- Get DebugON from parameters
local SETUP_LIB_VERSION = "0.56"
local DATA_PATH = modelLib.DATA_PATH
local PHASE = menuLib.PHASE
local LINE_TYPE = menuLib.LINE_TYPE
local MODEL = modelLib.MODEL
local AIRCRAFT_TYPE = modelLib.AIRCRAFT_TYPE
local WING_TYPE = modelLib.WING_TYPE
local TAIL_TYPE = modelLib.TAIL_TYPE
local CH_MODE_TYPE = modelLib.CH_MODE_TYPE
local PORT = modelLib.PORT
local MEMU_VAR = modelLib.MEMU_VAR
local MENU_DATA = modelLib.MENU_DATA
local SetupLib = {}
local lastGoodMenu=0
------------------- Model Setup Helper functions ----------------------
local currAircraftType = -1 -- Current AircraftType selected, and to detect change
local currTailType = -1 -- Current WingType selected, and to detect change
local currWingType = -1 -- Current TailType selected, and to detect change
local menuDataChanged = false -- Flag to notify if any data has changed
local function tailTypeCompatible(a,b)
local function normalize(tt)
if (tt==TAIL_TYPE.TRAILERON_A or tt==TAIL_TYPE.TRAILERON_B) then
return TAIL_TYPE.TRAILERON_A
elseif (tt==TAIL_TYPE.TRAILERON_A_R2 or tt==TAIL_TYPE.TRAILERON_B_R2) then
return TAIL_TYPE.TRAILERON_A_R2
elseif (tt==TAIL_TYPE.VTAIL_A or tt==TAIL_TYPE.VTAIL_B) then
return TAIL_TYPE.VTAIL_A
else
return tt
end
end
return (normalize(a)==normalize(b))
end
-- Creates the menus to Render with the GUI
local function ST_LoadMenu(menuId)
local ctx = menuLib.DSM_Context
local function portUse(p)
local out = ""
if p==MENU_DATA[MEMU_VAR.CH_THR] then out = "Thr"
elseif p == MENU_DATA[MEMU_VAR.CH_L_AIL] then
out=(MENU_DATA[MEMU_VAR.CH_R_AIL] and "Ail_L") or "Ail"
elseif p == MENU_DATA[MEMU_VAR.CH_R_AIL] then out="Ail_R"
elseif p == MENU_DATA[MEMU_VAR.CH_L_ELE] then
out=(MENU_DATA[MEMU_VAR.CH_R_ELE] and "Ele_L") or "Ele"
elseif p == MENU_DATA[MEMU_VAR.CH_R_ELE] then out="Ele_R"
elseif p == MENU_DATA[MEMU_VAR.CH_L_RUD] then
out=(MENU_DATA[MEMU_VAR.CH_R_RUD] and "Rud_L") or "Rud"
elseif p == MENU_DATA[MEMU_VAR.CH_R_RUD] then out="Rud_R"
elseif p == MENU_DATA[MEMU_VAR.CH_L_FLP] then
out=(MENU_DATA[MEMU_VAR.CH_R_FLP] and "Flp_L") or "Flp"
elseif p == MENU_DATA[MEMU_VAR.CH_R_FLP] then out="Flp_R"
end
return out
end
local function formatTXRevert(port)
local out = " " .. modelLib.channelType2String(MODEL.DSM_ChannelInfo[port][0], MODEL.DSM_ChannelInfo[port][1]);
return out
end
local function Header(p)
return MODEL.PORT_TEXT[p].." "..portUse(p)
end
menuLib.clearMenuLines()
if (menuId==0x1000) then -- MAIN MENU
ctx.Menu = { MenuId = 0x1000, Text = "Save-Exit ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
if (true) then
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, Text="Save Changes", TextId = 0, ValId = 0x1005 }
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Discard Changes", TextId = 0, ValId = 0x1006 }
ctx.SelLine = 4
end
lastGoodMenu = menuId
elseif (menuId==0x1001) then -- MODEL SETUP
local backId = 0xFFF9 -- No changes, just exit
local title = "Model Setup ("..MODEL.modelName..")"
if (menuDataChanged) then
backId = 0x1000 -- Go to Save menu
title = title.." *"
end
ctx.Menu = { MenuId = 0x1001, Text = title, PrevId = 0, NextId = 0, BackId = backId, TextId=0 }
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, Text = "Aircraft Type Setup", ValId = 0x1010,TextId=0 }
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, Text = "Wing & Tail Channels ", ValId = 0x1020, TextId=0 }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text = "Gyro Channel Reverse", ValId = 0x1030, TextId=0 }
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text = "WARNING: Changing of Aircraft or Wing will", ValId = 0x1001, TextId=0 }
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text = "delete previous Channel/Port assigments.", ValId = 0x1001, TextId=0 }
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x1005) then
modelLib.printChannelSummary()
modelLib.ST_SaveFileData()
menuDataChanged = false
local msg1 = "Data saved to: "
local msg2 = " "..DATA_PATH.."/"..modelLib.hashName(MODEL.modelName)..".txt"
ctx.Menu = { MenuId = 0x1005, Text = "Config Saved", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, Text=msg1, TextId = 0, ValId = 0x1005 }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text=msg2, TextId = 0, ValId = 0x1005 }
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 }
ctx.SelLine = 6
lastGoodMenu = menuId
elseif (menuId==0x1006) then
modelLib.ST_LoadFileData()
menuDataChanged = false
currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
local msg1 = "Data restored from: "
local msg2 = " "..DATA_PATH.."/"..modelLib.hashName(MODEL.modelName)..".txt"
ctx.Menu = { MenuId = 0x1006, Text = "Discart Changes", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, Text=msg1, TextId = 0, ValId = 0x1006 }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text=msg2, TextId = 0, ValId = 0x1006 }
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 }
ctx.SelLine = 6
lastGoodMenu = menuId
elseif (menuId==0x1010) then
modelLib.printChannelSummary()
ctx.Menu = { MenuId = 0x1010, Text = "Aircraft Type", PrevId = 0, NextId = 0x1011, BackId = 0x1001, TextId=0 }
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Aircraft Type", TextId = 0, ValId = MEMU_VAR.AIRCRAFT_TYPE, Min=50, Max=53, Def=50, Val=MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] }
ctx.SelLine = 5
lastGoodMenu = menuId
elseif (menuId==0x1011) then
ctx.Menu = { MenuId = 0x1011, Text = "Model Type:"..modelLib.aircraft_type_text[currAircraftType], PrevId = 0, NextId = 0x1020, BackId = 0x1010, TextId=0 }
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Wing Type", TextId = 0, ValId = MEMU_VAR.WING_TYPE, Min=100, Max=107, Def=100, Val=MENU_DATA[MEMU_VAR.WING_TYPE] }
ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Tail Type", TextId = 0, ValId = MEMU_VAR.TAIL_TYPE, Min=200, Max=210, Def=200, Val=MENU_DATA[MEMU_VAR.TAIL_TYPE] }
ctx.SelLine = 5
lastGoodMenu = menuId
elseif (menuId==0x1020) then
------ WING SETUP -------
local thr = MENU_DATA[MEMU_VAR.CH_THR]
local leftAil = MENU_DATA[MEMU_VAR.CH_L_AIL]
local rightAil = MENU_DATA[MEMU_VAR.CH_R_AIL]
local leftFlap = MENU_DATA[MEMU_VAR.CH_L_FLP]
local rightFlap = MENU_DATA[MEMU_VAR.CH_R_FLP]
local thrText = "Thr"
local leftAilText = "Left Aileron"
local rightAilText = "Right Aileron"
local leftFlapText = "Left Flap"
local rightFlapText = "Right Flap"
if (rightAil==nil) then leftAilText = "Aileron" end
if (rightFlap==nil) then leftFlapText = "Flap" end
local title = modelLib.aircraft_type_text[currAircraftType].." Wing:"..modelLib.wing_type_text[currWingType]
ctx.Menu = { MenuId = 0x1020, Text = title, PrevId = 0, NextId = 0x1021, BackId = 0x1011, TextId=0 }
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=thrText, TextId = 0, ValId = MEMU_VAR.CH_THR, Min=0, Max=10, Def=0, Val= thr }
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftAilText, TextId = 0, ValId = MEMU_VAR.CH_L_AIL, Min=0, Max=9, Def=0, Val= leftAil }
if (rightAil~=nil) then
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightAilText, TextId = 0, ValId = MEMU_VAR.CH_R_AIL, Min=0, Max=9, Def=0, Val= rightAil }
end
if (leftFlap~=nil) then
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftFlapText, TextId = 0, ValId = MEMU_VAR.CH_L_FLP, Min=0, Max=9, Def=0, Val= leftFlap }
end
if (rightFlap~=nil) then
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightFlapText, TextId = 0, ValId = MEMU_VAR.CH_R_FLP, Min=0, Max=9, Def=0, Val= rightFlap }
end
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x1021) then
------ TAIL SETUP -------
local leftRud = MENU_DATA[MEMU_VAR.CH_L_RUD]
local rightRud = MENU_DATA[MEMU_VAR.CH_R_RUD]
local leftEle = MENU_DATA[MEMU_VAR.CH_L_ELE]
local rightEle = MENU_DATA[MEMU_VAR.CH_R_ELE]
local leftRudText = "Left Rudder"
local rightRudText = "Right Rudder"
local leftElvText = "Left Elevator"
local rightElvText = "Right Elevator"
if (rightRud==nil) then leftRudText = "Rudder" end
if (rightEle==nil) then leftElvText = "Elevator" end
local title = modelLib.aircraft_type_text[currAircraftType].." Tail:"..modelLib.tail_type_text[currTailType]
ctx.Menu = { MenuId = 0x1021, Text = title, PrevId = 0, NextId = 0x1001, BackId = 0x1020, TextId=0 }
if (leftRud~=nil) then
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftRudText, TextId = 0, ValId = MEMU_VAR.CH_L_RUD, Min=0, Max=9, Def=0, Val= leftRud}
end
if (rightRud~=nil) then
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightRudText, TextId = 0, ValId = MEMU_VAR.CH_R_RUD, Min=0, Max=9, Def=0, Val=rightRud }
end
if (leftEle~=nil) then
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftElvText, TextId = 0, ValId = MEMU_VAR.CH_L_ELE, Min=0, Max=9, Def=0, Val=leftEle }
end
if (rightEle~=nil) then
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightElvText, TextId = 0, ValId = MEMU_VAR.CH_R_ELE, Min=0, Max=9, Def=0, Val=rightEle }
end
ctx.SelLine = 1
lastGoodMenu = menuId
elseif (menuId==0x1030) then
modelLib.CreateDSMPortChannelInfo()
modelLib.printChannelSummary()
ctx.Menu = { MenuId = 0x1030, Text = "Gyro Channel Reverse (Port 1-5)", PrevId = 0, NextId = 0x1031, BackId = 0x1001, TextId=0 }
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT1), TextId = 0, ValId = MEMU_VAR.PORT1_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT1_MODE], Format = formatTXRevert(PORT.PORT1) }
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT2), TextId = 0, ValId = MEMU_VAR.PORT2_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT2_MODE], Format = formatTXRevert(PORT.PORT2) }
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT3), TextId = 0, ValId = MEMU_VAR.PORT3_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT3_MODE], Format = formatTXRevert(PORT.PORT3) }
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT4), TextId = 0, ValId = MEMU_VAR.PORT4_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT4_MODE], Format = formatTXRevert(PORT.PORT4) }
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT5), TextId = 0, ValId = MEMU_VAR.PORT5_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT5_MODE], Format = formatTXRevert(PORT.PORT5) }
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Only Thr/Ail/Rud/Ele. This affects AS3X/SAFE reaction dir./b", TextId = 0, ValId = 0x1030 }
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Any changes, use RX 'Relearn Servo Settings'/b", TextId = 0, ValId = 0x1030 }
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x1031) then
modelLib.CreateDSMPortChannelInfo()
modelLib.printChannelSummary()
ctx.Menu = { MenuId = 0x1031, Text = "Gyro Channel Reverse (Port 6-10)", PrevId = 0x1030, NextId = 0, BackId = 0x1001, TextId=0 }
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT6), TextId = 0, ValId = MEMU_VAR.PORT6_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT6_MODE], Format = formatTXRevert(PORT.PORT6) }
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT7), TextId = 0, ValId = MEMU_VAR.PORT7_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT7_MODE], Format = formatTXRevert(PORT.PORT7) }
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT8), TextId = 0, ValId = MEMU_VAR.PORT8_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT8_MODE], Format = formatTXRevert(PORT.PORT8) }
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT9), TextId = 0, ValId = MEMU_VAR.PORT9_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT9_MODE], Format = formatTXRevert(PORT.PORT9) }
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT10), TextId = 0, ValId = MEMU_VAR.PORT10_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT10_MODE], Format = formatTXRevert(PORT.PORT10) }
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Only Thr/Ail/Rud/Ele. This affects AS3X/SAFE reaction dir./b", TextId = 0, ValId = 0x1031 }
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Any changes, use RX 'Relearn Servo Settings'/b", TextId = 0, ValId = 0x1031 }
ctx.SelLine = 0
lastGoodMenu = menuId
else
print("NOT IMPLEMENTED")
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
ctx.SelLine = menuLib.BACK_BUTTON
end
menuLib.PostProcessMenu()
end
-- ST_SendReceive
-- Main state machine for the Setup menu
local function ST_SendReceive()
local ctx = menuLib.DSM_Context
--if (DEBUG_ON>1) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
if ctx.Phase == PHASE.RX_VERSION then -- request RX version
ctx.RX.Name = "MODEL SETUP"
ctx.RX.Version = SETUP_LIB_VERSION
ctx.Phase = PHASE.MENU_TITLE
ctx.Menu.MenuId = 0x01001
ctx.Refresh_Display = true
elseif ctx.Phase == PHASE.WAIT_CMD then
elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title
ST_LoadMenu(ctx.Menu.MenuId)
ctx.Phase = PHASE.WAIT_CMD
ctx.Refresh_Display = true
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
if (MENU_DATA[line.ValId] ~= line.Val ) then
MENU_DATA[line.ValId] = line.Val
print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val))
menuDataChanged=true
end
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
local line = ctx.MenuLines[ctx.SelLine]
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
-- Update the menu data from the line
if (MENU_DATA[line.ValId] ~= line.Val ) then
MENU_DATA[line.ValId] = line.Val
print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val))
menuDataChanged=true
end
-- Did the aircraft type change?
if (currAircraftType ~= MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]) then
currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
modelLib.ST_AircraftInit(currAircraftType)
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
end
-- Did the Wing type change?
if (currWingType ~= MENU_DATA[MEMU_VAR.WING_TYPE]) then
if (currAircraftType==AIRCRAFT_TYPE.GLIDER) then
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
modelLib.ST_GliderWingInit(currWingType)
else
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
modelLib.ST_PlaneWingInit(currWingType)
end
-- DELTA has only RUDER
if ((currWingType==WING_TYPE.ELEVON_A or currWingType==WING_TYPE.ELEVON_B) and TAIL_TYPE~=TAIL_TYPE.RUD_1) then
MENU_DATA[MEMU_VAR.TAIL_TYPE] = TAIL_TYPE.RUD_1
end
end
--- Did the tail changed?
local ntt = MENU_DATA[MEMU_VAR.TAIL_TYPE]
if (currTailType ~= ntt) then
if (currAircraftType==AIRCRAFT_TYPE.GLIDER) then
currTailType = ntt
modelLib.ST_GliderTailInit(currTailType)
else
if (not tailTypeCompatible(currTailType,ntt)) then
modelLib.ST_PlaneTailInit(ntt)
end
currTailType = ntt
end
end
ctx.Phase = PHASE.WAIT_CMD
elseif ctx.Phase == PHASE.EXIT then
ctx.Phase=PHASE.EXIT_DONE
end
end
------------------------------------------------------------------------------------------------------------
-- Inital List and Image Text for this menus
local function ST_Init_Text(rxId)
menuLib.clearAllText()
local List_Values = menuLib.List_Values
local List_Text = menuLib.List_Text
local Text = menuLib.Text
local List_Text_Img = menuLib.List_Text_Img
-- Channel Names use the Port Text Retrived from OTX/ETX
for i = 0, 9 do List_Text[i] = MODEL.PORT_TEXT[i] end
List_Text[10]="--"
-- Aircraft Type
List_Text[50+AIRCRAFT_TYPE.PLANE] = "Airplane"; --List_Text_Img[50+AIRCRAFT_TYPE.PLANE] = "at_plane.png|Airplane"
List_Text[50+AIRCRAFT_TYPE.GLIDER] = "Glider (Partial work)"; --List_Text_Img[50+AIRCRAFT_TYPE.GLIDER] = "at_glider.png|Glider"
List_Text[50+AIRCRAFT_TYPE.HELI] = "Helicopter (Not done)"; --List_Text_Img[50+AIRCRAFT_TYPE.HELI] = "at_heli.png|Helicopter"
List_Text[50+AIRCRAFT_TYPE.DRONE] = "Drone (not done)"; --List_Text_Img[50+AIRCRAFT_TYPE.DRONE] = "at_drone.png|Drone"
-- Wing Types
List_Text[100+WING_TYPE.AIL_1] = "Single Ail"; List_Text_Img[100+WING_TYPE.AIL_1] = "wt_1ail.png|Single Aileron"
List_Text[100+WING_TYPE.AIL_2] = "Dual Ail"; List_Text_Img[100+WING_TYPE.AIL_2] = "wt_2ail.png|Dual Aileron"
List_Text[100+WING_TYPE.FLAPERON] = "Flaperon"; List_Text_Img[100+WING_TYPE.FLAPERON] = "wt_flaperon.png|Flaperon"
List_Text[100+WING_TYPE.AIL_1_FLP_1] = "Ail + Flap"; List_Text_Img[100+WING_TYPE.AIL_1_FLP_1] = "wt_1ail_1flp.png|Aileron + Flap"
List_Text[100+WING_TYPE.AIL_2_FLP_1] = "Dual Ail + Flap"; List_Text_Img[100+WING_TYPE.AIL_2_FLP_1] = "wt_2ail_1flp.png|Dual Aileron + Flap"
List_Text[100+WING_TYPE.AIL_2_FLP_2] = "Dual Ail + Dual Flap"; List_Text_Img[100+WING_TYPE.AIL_2_FLP_2] = "wt_2ail_2flp.png|Dual Aileron + Dual Flap"
List_Text[100+WING_TYPE.ELEVON_A] = "Delta/Elevon A"; List_Text_Img[100+WING_TYPE.ELEVON_A] = "wt_elevon.png|Delta/Elevon A"
List_Text[100+WING_TYPE.ELEVON_B] = "Delta/Elevon B"; List_Text_Img[100+WING_TYPE.ELEVON_B] = "wt_elevon.png|Delta/Elevon B"
-- Tail Types
List_Text[200+TAIL_TYPE.RUD_1] = "Rudder Only"; List_Text_Img[200+TAIL_TYPE.RUD_1] = "tt_1rud.png|Rudder Only"
List_Text[200+TAIL_TYPE.RUD_1_ELEV_1] = "Rud + Ele"; List_Text_Img[200+TAIL_TYPE.RUD_1_ELEV_1] = "tt_1rud_1ele.png|Tail Normal"
List_Text[200+TAIL_TYPE.RUD_1_ELEV_2] = "Rud + Dual Ele"; List_Text_Img[200+TAIL_TYPE.RUD_1_ELEV_2] = "tt_1rud_2ele.png|Rud + Dual Elev"
List_Text[200+TAIL_TYPE.RUD_2_ELEV_1] = "Dual Rud + Ele"; List_Text_Img[200+TAIL_TYPE.RUD_2_ELEV_1] = "tt_2rud_1ele.png|Dual Rud + Elev"
List_Text[200+TAIL_TYPE.RUD_2_ELEV_2] = "Dual Rud + Dual Ele"; List_Text_Img[200+TAIL_TYPE.RUD_2_ELEV_2] = "tt_2rud_2ele.png|Dual Rud + Dual Elev"
List_Text[200+TAIL_TYPE.VTAIL_A] = "V-Tail A"; List_Text_Img[200+TAIL_TYPE.VTAIL_A] = "tt_vtail.png|V-Tail A"
List_Text[200+TAIL_TYPE.VTAIL_B] = "V-Tail B"; List_Text_Img[200+TAIL_TYPE.VTAIL_B] = "tt_vtail.png|V-Tail B"
List_Text[200+TAIL_TYPE.TRAILERON_A] = "Taileron A"; List_Text_Img[200+TAIL_TYPE.TRAILERON_A] = "tt_taileron.png|Taileron A"
List_Text[200+TAIL_TYPE.TRAILERON_B] = "Taileron B"; List_Text_Img[200+TAIL_TYPE.TRAILERON_B] = "tt_taileron.png|Taileron B"
List_Text[200+TAIL_TYPE.TRAILERON_A_R2] = "Taileron A + 2x Rud"; List_Text_Img[200+TAIL_TYPE.TRAILERON_A_R2] = "tt_taileron2.png|Taileron A + Dual Rud"
List_Text[200+TAIL_TYPE.TRAILERON_B_R2] = "Taileron B + 2x Rud"; List_Text_Img[200+TAIL_TYPE.TRAILERON_B_R2] = "tt_taileron2.png|Taileron B + Dual Rud"
-- Servo Reverse
if (LCD_W > 128) then
List_Text[300+CH_MODE_TYPE.NORMAL] = "Normal "
List_Text[300+CH_MODE_TYPE.REVERSE] = "Reverse"
else
List_Text[300+CH_MODE_TYPE.NORMAL] = "Nor"
List_Text[300+CH_MODE_TYPE.REVERSE] = "Rev"
end
end
-- Initial Setup
local function ST_Init()
-- Initialize text (use RX_ID 0)
ST_Init_Text(0)
-- Setup default Data, and load a file if exist
--modelLib.ST_Default_Data()
if (modelLib.ST_LoadFileData()==0) then -- Did not load a file
modelLib.ST_Default_Data()
modelLib.ST_SaveFileData() -- Save Defaults
end
menuDataChanged = false
currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
local ctx = menuLib.DSM_Context
ctx.Phase = PHASE.RX_VERSION
end
local function ST_Done()
local ctx = menuLib.DSM_Context
ctx.Phase = PHASE.EXIT_DONE
end
return { init=ST_Init, run=ST_SendReceive, done=ST_Done }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
-- OVERRIDES Messges for MIN 128x64 screns
-- FORMAT <LineType>|<Msg#>|<Text>
-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX)
-- IMPORTANT: NO EMPTY LINES
--
T |0x0097|DONT USE: Factory Reset
T |0x0098|DONT USE: Factory Reset
T |0x00A5|DONT USE: First Time Setup
T |0x0190|DONT USE: Relearn Servo Settings
T |0x020D|DONT USE: First Time SAFE Setup

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

View File

@ -0,0 +1,437 @@
-- FORMAT <LineType>|<Msg#>|<Text>
-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX)
-- NO EMPTY LINES
-- Formmatting at end of line: /c=Center, /r=Right, /b=Bold, /m=menu
LT|0x0001|Off
LT|0x0002|On
-- Ihn/Act List Options
LT|0x0003|Inh
LT|0x0004|Act
--
-- Channel selection for SAFE MODE and GAINS on FC6250HX
LT|0x000C|Inh
LT|0x000D|Ch5
LT|0x000E|Ch6
LT|0x000F|Ch7
LT|0x0010|Ch8
LT|0x0011|Ch9
LT|0x0012|Ch10
LT|0x0013|Ch11
LT|0x0014|Ch12
--
-- Servo Output values
LT|0x002D|5.5ms
LT|0x002E|11ms
LT|0x002F|22ms
--
-- Gain Multiplier Values
LT|0x0032|1 X
LT|0x0033|2 X
LT|0x0034|4 X
--
LT|0x0035|Inh
LT|0x0036|Thr
LT|0x0037|Ail
LT|0x0038|Ele
LT|0x0039|Rud
LT|0x003A|Ch5
LT|0x003B|Ch6
LT|0x003C|Ch7
LT|0x003D|Ch8
LT|0x003E|Ch9
LT|0x003F|Ch10
LT|0x0040|Ch11
LT|0x0041|Ch12
LT|0x0042|Ch13
LT|0x0043|Ch14
LT|0x0044|Ch15
LT|0x0045|Ch16
LT|0x0046|Ch17
LT|0x0047|Ch18
LT|0x0048|Ch19
LT|0x0049|Ch20
--
T |0x0040|Roll
T |0x0041|Pitch
T |0x0042|Yaw
T |0x0043|Gain/c/b
T |0x0045|Differential
T |0x0046|Priority
T |0x0049|Output Setup
T |0x004A|Failsafe
T |0x004B|Main Menu
T |0x004E|Position
--
T |0x0050|Outputs
T |0x0051|Output Channel 1
T |0x0052|Output Channel 2
T |0x0053|Output Channel 3
T |0x0054|Output Channel 4
T |0x0055|Output Channel 5
T |0x0056|Output Channel 6
T |0x0057|Output Channel 7
T |0x0058|Output Channel 8
T |0x0059|Output Channel 9
T |0x005A|Output Channel 10
--
-- FailSafe Options
--LT|0x005E|Inh
LT|0x005F|Hold Last
LT|0x0060|Preset
--LT|0x0061|Custom
--
T |0x0071|Proportional
T |0x0072|Integral
T |0x0073|Derivate
T |0x0078|FM Channel
T |0x007F|Attitude Gain
--
T |0x0080|Orientation
T |0x0082|Heading
T |0x0085|Frame Rate
T |0x0086|System Setup
T |0x0087|F-Mode Setup
T |0x0088|Enabled F-Modes
T |0x0089|Gain Channel
T |0x008A|Gain Sensitivity/r -- Right Align
T |0x008B|Panic
T |0x008E|Panic Delay
--
LT|0x0187|No Freq --???? unset Freq
LT|0x0088|70hz
LT|0x0089|90hz
LT|0x008A|200hz
LT|0x008B|333hz
LT|0x008C|490hz
LT|0x008D|560hz
LT|0x008E|Normal
LT|0x008F|Reversed
-- FC6250HX: Callibration
T |0x0090|Apply
T |0x0091|Begin
T |0x0092|Start
T |0x0093|Complete
T |0x0094|Done
--
-- FC6250HX: Swashplate Type
--
LT|0x0090|Normal
LI|0x0090|h_swp_norm.png|Normal
LT|0x0091|3 Servos 120 Y
LI|0x0091|h_swp_3_120.png|3 Servos 120 Y
LT|0x0092|3 Servos 120 Y-Inv
LI|0x0092|h_swp_3_120inv.png|3 Servos 120 Y-Inv
LT|0x0093|3 Servos 135 Y
LI|0x0093|h_swp_3_135.png|3 Servos 135 Y
LT|0x0094|3 Servos 135 Y-Inv
LI|0x0094|h_swp_3_135inv.png|3 Servos 135 Y-Inv
LT|0x0095|3 Servos 140 Y
LI|0x0095|h_swp_3_140.png|3 Servos 140 Y
LT|0x0096|3 Servos 140 Y-Inv
LI|0x0096|h_swp_3_140inv.png|3 Servos 140 Y-Inv
LT|0x0097|3 Servos 90 T
LI|0x0097|h_swp_3_90.png|3 Servos 90 T
LT|0x0098|3 Servos 90 T-Inv
LI|0x0098|h_swp_3_90inv.png|3 Servos 90 T-Inv
--
T |0x0097|Factory Reset
T |0x0098|Factory Reset
T |0x0099|Advanced Setup
T |0x009A|Capture Failsafe Positions
T |0x009C|Custom Failsafe
--
T |0x009F|Save Settings -- Save & Reboot RX
--
T |0x00A5|First Time Setup
T |0x00AA|Capture Gyro Gains
T |0x00AD|Gain Channel Select
T |0x00AF|Dynamic
LT|0x00B0|Self-Level
LT|0x00B1|Envelope
--
-- Flight Modes List Options
LT|0x00B5|Inh
LT|0x00B6|FM1
LT|0x00B7|FM2
LT|0x00B8|FM3
LT|0x00B9|FM4
LT|0x00BA|FM5
LT|0x00BB|FM6
LT|0x00BC|FM7
LT|0x00BD|FM8
LT|0x00BE|FM9
LT|0x00BF|FM10
--
T |0x00BE|Unknown_BE -- Used in Reset menu (0x0001) while the RX is rebooting
--
T |0x00C7|Calibrate Sensor
T |0x00C8|Sensor is Calibrating.. Wait
T |0x00CA|SAFE & Panic Mode Setup
--
T |0x00CD|Level model & capt attitude/m -- SPECIAL MENU to itself who is not a comment
T |0x00CE|Error TX Conf
T |0x00CF|Invalid TX Ch Conf 1
T |0x00D0|Invalid TX Ch Conf 2
--
-- RX Orientations for AR631/AR637, Optionally attach an Image + Alt Text to display
LT|0x00CB|Pos 1
LI|0x00CB|rx_pos_1.png|Pilot View: RX Label Up, Pins Back
LT|0x00CC|Pos 2
LI|0x00CC|rx_pos_2.png|Pilot View: RX Label Left, Pins Back
LT|0x00CD|Pos 3
LI|0x00CD|rx_pos_3.png|Pilot View: RX Label Down, Pins Back
LT|0x00CE|Pos 4
LI|0x00CE|rx_pos_4.png|Pilot View: RX Label Right, Pins Back
LT|0x00CF|Pos 5
LI|0x00CF|rx_pos_5.png|Pilot View: RX Label UP, Pins to Front
LT|0x00D0|Pos 6
LI|0x00D0|rx_pos_6.png|Pilot View: RX Label Left, Pins Front
LT|0x00D1|Pos 7
LI|0x00D1|rx_pos_7.png|Pilot View: RX Label Down, Pins Front
LT|0x00D2|Pos 8
LI|0x00D2|rx_pos_8.png|Pilot View: RX Label Right, Pins Front
LT|0x00D3|Pos 9
LI|0x00D3|rx_pos_9.png|Pilot View: RX Label Up, Pins Left
LT|0x00D4|Pos 10
LI|0x00D4|rx_pos_10.png|Pilot View: RX Label Back, Pins Left
LT|0x00D5|Pos 11
LI|0x00D5|rx_pos_11.png|Pilot View: RX Label Down, Pins Left
LT|0x00D6|Pos 12
LI|0x00D6|rx_pos_12.png|Pilot View: RX Label Front, Pins Left
LT|0x00D7|Pos 13
LI|0x00D7|rx_pos_13.png|Pilot View: RX Label Up, Pins Right
LT|0x00D8|Pos 14
LI|0x00D8|rx_pos_14.png|Pilot View: RX Label Back, Pins Right
LT|0x00D9|Pos 15
LI|0x00D9|rx_pos_15.png|Pilot View: RX Label Down, Pins Right
LT|0x00DA|Pos 16
LI|0x00DA|rx_pos_16.png|Pilot View: RX Label Front, Pins Right
LT|0x00DB|Pos 17
LI|0x00DB|rx_pos_17.png|Pilot View: RX Label Back, Pins Down
LT|0x00DC|Pos 18
LI|0x00DC|rx_pos_18.png|Pilot View: RX Label Left, Pins Down
LT|0x00DD|Pos 19
LI|0x00DD|rx_pos_19.png|Pilot View: RX Label Front, Pins Down
LT|0x00DE|Pos 20
LI|0x00DE|rx_pos_20.png|Pilot View: RX Label Right, Pins Down
LT|0x00DF|Pos 21
LI|0x00DF|rx_pos_21.png|Pilot View: RX Label Back, Pins Up
LT|0x00E0|Pos 22
LI|0x00E0|rx_pos_22.png|Pilot View: RX Label Left, Pins Up
LT|0x00E1|Pos 23
LI|0x00E1|rx_pos_23.png|Pilot View: RX Label Front, Pins Up
LT|0x00E2|Pos 24
LI|0x00E2|rx_pos_24.png|Pilot View: RX Label Right, Pins Up
LT|0x00E3|Pos Invalid
LI|0x00E3|rx_pos_25.png|Cannot detect orientation of RX
--
-- RX Orientations images for FC5250 (HACK add 0x100 internally to differenciate for helis)
LI|0x01CB|h_rx_pos_1.png|Pilot View: RX Label Up, Pins Front
LI|0x01CC|h_rx_pos_2.png|Pilot View: RX Label Left, Pins Front
LI|0x01CD|h_rx_pos_3.png|Pilot View: RX Label Down, Pins Front
LI|0x01CE|h_rx_pos_4.png|Pilot View: RX Label Right, Pins Front
LI|0x01CF|h_rx_pos_5.png|Pilot View: RX Label UP, Pins to Back
LI|0x01D0|h_rx_pos_6.png|Pilot View: RX Label Left, Pins Back
LI|0x01D1|h_rx_pos_7.png|Pilot View: RX Label Down, Pins Back
LI|0x01D2|h_rx_pos_8.png|Pilot View: RX Label Right, Pins Back
--
T |0x00D1|Receiver will Reboot/b
T |0x00D2|Panic Channel
T |0x00D3|Swashplate
T |0x00D5|Agility
T |0x00D8|Stop
T |0x00DA|SAFE/c/b -- Center + Bold
T |0x00DB|Stability
T |0x00DC|@ per sec
T |0x00DD|Tail rotor
T |0x00DE|Setup
T |0x00DF|AFR
T |0x00E0|Collective
T |0x00E1|Subtrim
T |0x00E2|Phasing
T |0x00E3|Pre-Comp
T |0x00E4|E-Ring
T |0x00E5|Swash Type
T |0x00E6|Travel
T |0x00E7|Left
T |0x00E8|Right
T |0x00EA|Low Throttle
--
T |0x00F2|Governor
T |0x00F4|Soft Start
--
LT|0x00F2|Fixed
LT|0x00F3|Adjustable
LT|0x00F4|Inh
LT|0x00F5|Nitro
--
T |0x00F6|Direction
T |0x00F8|Settings -- ?? validate on a Spektrum radio
T |0x00F9|Gyro settings
T |0x00FE|Stick Priority/c/b
--
T |0x0100|Make sure the model has been
T |0x0101|configured, including wing type,
T |0x0102|reversing, travel, trimmed, etc.
T |0x0103|before continuing setup.
T |0x0104|
T |0x0105| -- Blank
--
T |0x0106|Any wing type, channel assignment,
T |0x0107|subtrim, or servo reversing changes
T |0x0108|require running through initial
T |0x0109|setup again.
T |0x010A|
T |0x010B|
--
T |0x0190|Relearn Servo Settings
T |0x019C|Enter Receiver Bind Mode
T |0x01AA|Offset
T |0x01D7|SAFE Select Channel
T |0x01DC|AS3X/c/b -- Center + Bold
T |0x01DD|AS3X Settings
T |0x01DE|AS3X Gains
T |0x01E0|Rate Gains/c/b
T |0x01E2|SAFE Settings
T |0x01E3|SAFE Gains
T |0x01E6|Attitude Trim/c/b
T |0x01E7|Envelope
T |0x01E9|Roll Right
T |0x01EA|Roll Left
T |0x01EB|Pitch Down
T |0x01EC|Pitch Up
T |0x01EE|Thr to Pitch
T |0x01EF|Low Thr to Pitch/c/b
T |0x01F0|High Thr to Pitch/c/b
T |0x01F1|Filter
T |0x01F3|Threshold
T |0x01F4|Angle
T |0x01F6|Failsafe Angles/c/b
T |0x01F8|Safe Mode
T |0x01F9|SAFE Select
T |0x01FC|Panic F-Mode
T |0x01FD|FailSafe Flight Mode -- Safe Flight Mode
T |0x0201|Throttle
T |0x0204|Hover
T |0x0208|Decay
T |0x0209|Save to Backup
T |0x020A|Restore from Backup
T |0x020D|First Time SAFE Setup
--
-- First time safe setup Page 3 :
T |0x020E|AS3X gains must be tuned
T |0x020F|and active in SAFE Flight Modes
T |0x0210|to help reduce wobble.
T |0x0211|
T |0x0212|
T |0x0213| -- Blank
--
-- AS3X orientation Setting menu (Level)
T |0x021A|Set the model level,
T |0x021B|and press Continue.
T |0x021C|
T |0x021D| -- Blank
--
-- AS3X orientation Setting menu (Nose down)
T |0x021F|Set the model on its nose,
T |0x0220|and press Continue. If the
T |0x0221|orientation on the next
T |0x0222|screen is wrong go back
T |0x0223|and try again.
T |0x0224|Continue
--
T |0x0226|Angle Limits/c/b
T |0x0227|Other settings
T |0x0229|Set Orientation Manually
--
-- Factory Default Warning
T |0x022B|WARNING!
T |0x022C|This will reset the
T |0x022D|configuration to factory
T |0x022E|defaults. This does not
T |0x022F|affect the backup config.
T |0x0230| -- Blank
--
-- Backup Warning
T |0x0231|This will overwrite the
T |0x0232|backup memory with your
T |0x0233|current configuartion.
T |0x0234|
T |0x0235| -- Blank
--
-- Restore from Backup Warning
T |0x0236|This will overwrite the
T |0x0237|current config with
T |0x0238|that which is in
T |0x0239|the backup memory.
T |0x023A| -- Blank
--
-- Utilities Copy flight modes
T |0x023D|Copy F-Mode Settings
T |0x023E|Source F-Mode
T |0x023F|Target F-Mode
--
T |0x0240|Utilities
--
-- Gain Capture Page
T |0x024C|Gains will be captured on
T |0x024D|Captured gains will be
T |0x024E|Gains on
T |0x024F|were captured and changed
T |0x0250|from Adjustable to Fixed
--
-- Utilities, Copy flight mode (Copy Confirmation, oveerriding FM)
T |0x0251|Are you sure you want to ovewrite the "Target"
T |0x0252|with the "Source" ?
T |0x0253| -- Blank
--
T |0x0254|Pos = Up, Neg = Down
--
-- First time safe setup Page 1 (maybe ask to select Flight Mode cannel)
T |0x0255|Before setting up SAFE
T |0x0256|a Flight Mode channel
T |0x0257|most be configured.
--
-- First time safe setup Page 2 (something related for flight mode)
T |0x025A|Select the desired flight mode
T |0x025B|switch position to adjust settings
T |0x025C|for each flight mode
T |0x025D|
T |0x025E| -- Blank
--
-- Utilities, Copy flight mode (Confirm)
T |0x0259|YES
T |0x0260|WARNING: "Target"
T |0x0261|F-Mode will be overwritten
T |0x0262|by "Source"
--
T |0x0263|Fixed/Adjustable Gains/c/b
T |0x0266|Heading Gain/c/b
T |0x0267|Pos = Nose Up/Roll Right
T |0x0268|Neg = Nose Down/Roll Left
T |0x0269|SAFE - Thr to Pitch
T |0x026A|Use CAUTION for Yaw gain!/b
--
T |0x026B|Head Speed
T |0x026C|Pinion
T |0x026D|Main Gear
T |0x026F|RPM Sensor
T |0x0272|Show Advanced Menus
--
T |0x0300|No compatible DSM RX...
T |0x0301|Waiting for RX to Restart
--
FM|0x8000|Flight Mode/c/b
--
RX|0x0001|AR636
RX|0x0014|SPM4651T
RX|0x0015|AR637T
RX|0x0016|AR637TA
RX|0x0018|FC6250HX
RX|0x0019|AR630
RX|0x001A|AR8360T
RX|0x001B|AR8020T
RX|0x001C|AR10360T
RX|0x001E|AR631

View File

@ -0,0 +1,22 @@
# Credits
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
Rewrite/Enhancements by: Francisco Arzu
Thanks to all the people volunteered to test it.
Release Notes for
## COLOR Radios
Read more [Color radios](./readme_color.md)
![main-menu](https://user-images.githubusercontent.com/32604366/230751340-dd118f36-1884-405b-b12b-81cba16c7321.png)
![flight-mode-setup](https://user-images.githubusercontent.com/32604366/230751281-0c71ff4a-179f-41fd-9290-302a6e0fe821.png)
## Black & White Radios (Small Screens)
Read more [black & whire radios](./readme_bw.md)
![image](https://github.com/frankiearzu/DSMTools/assets/32604366/be03ad40-3e2f-45e1-8f50-d231c3931169)
![image](https://github.com/frankiearzu/DSMTools/assets/32604366/5010a361-1234-4c83-97b2-2eb6ae0d1061)
![image](https://github.com/frankiearzu/DSMTools/assets/32604366/0d4e04dc-90d7-4322-9ad1-f57cbde49029)
![IMG_3024](https://user-images.githubusercontent.com/32604366/230123260-614f4e5e-9546-4439-9196-db885894083f.jpg)

View File

@ -0,0 +1,181 @@
# Credits
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
Rewrite/Enhancements by: Francisco Arzu
Thanks to all the people volunteered to test it.
# Introduction (v0.56 Black & White Small Radios)
!!!!!NEW!!!!!!: Finally was able to create the Plane Setup for Smaller Radios
There is still significant memory limitations in some of this radios, so the Setup and FP was split in two files.
The file 'DSM FwdPrg_56_STUP.lua' is the new one to create the planes setup that works together with 'DSM FwdPrg_56_MIN.lua'
# How to Use it
Step #1: Make sure that the /MODELS/DSMDATA folder exist.
Step #2: Run the "DSM FwdPrg_56_STUP" first to setup the plane wing, tail and channels to use for each surface. At the end it will ask you to "save" the configuration. That saves a file in the /MODELS/DSMDATA folder.
![image](https://github.com/frankiearzu/DSMTools/assets/32604366/be03ad40-3e2f-45e1-8f50-d231c3931169)
![image](https://github.com/frankiearzu/DSMTools/assets/32604366/5010a361-1234-4c83-97b2-2eb6ae0d1061)
![image](https://github.com/frankiearzu/DSMTools/assets/32604366/0d4e04dc-90d7-4322-9ad1-f57cbde49029)
Why the RX needs to know the Plane Setup?? The AS3X/Gyro and SAFE needs to know what surfaces to move to do the proper correction in flight. It needs to know what channels are you using for ailerons, elevarors and rudders (could be 1 or 2 of each). Also if you have special Wing like a delta wing, the elevator and aileron functions are on the same channels.. same with V-Trails, Ruder/Elevator are combined. All this information is shared with the RX during "First Time Setup" as well as "Relearn Servo Setting". Older version of 0.55 MIN hardcoded this info to be a plain 4-ch regular plane, thats why we discourage to use those function.
Step #3: Run the "DSM FwdPrg_56_MIN". It uses the model configuration created in step #2 to properly tell the receiver the plane configuration for initial setup. If you get "Cannot load model config", that means that the file was not created on step #2. Once it shows the intial forward programming page for your receiver, usuall "Gyro Settings and Other Settings". You can properly setup the a plane from initial setup... if you are not familiar with this step, view some of the videos. There are already multiple videos showing how to do it EdgeTX color version, or the Spektrum official videos, the menus are the same.
## Dealing with Low memory
On my FrSky QX7 (Probably the one with the lower memory compared to Radiomaster Boxter and maybe Zorro), it will give you "not enouth memory"
the very first time you try to run it since is compiling + running. Try to run them at least 2 times again, this times wll just run (not compile).
In some ocations that keeps giving memory problems, i have to restart the radio, and try to run it right after restart.
After it runs fine, and you try to run it the 2nd time and gives "not enouth memory", you have restart the radio.. for me this is random..
sometimes i can run it many times consecutively.. but once it gives memory error, have to restart to be able to run again.
Once it starts, it should work find after... is the statup who loads what it needs to memory.
I am running EdgeTX 2.9.2 (there was some memory cleanup in 2.9.0, and 2.9.1 to get a bit more memory)
I left version 0.55 in the files, since it uses less memory, it can change the mayority of FP parameters, but cannot setup plane or Relearn Servo Settings
(don't execute the menus who say 'DON'T USE!!').. v0.55 and v0.56 MINs can co-exist.
Video of how to deal with memory:
https://www.youtube.com/watch?v=kG3RfVa_brU
# Deployment
Uncompress the Zip file (ZIP version) into your local computer.
In another window, open your TX SDCard and go to `/SCRIPTS/TOOLS`.
When upgrading from a previous version of this tool, delete your `/SCRIPTS/TOOLS/DSMLIB` before copying the new one (if you customized the menu messages, inside `DSMLIB` do a backup of the message files first)
1. The zip file has the same structure as your SDCard. If you want to copy all the content of the zip file into your SDCard, it will create all the directories and files in the right place.
For the MINimalistic version, Your TX SDCard should looks like this:
/SCRIPTS/TOOLS
DSM FwdPrg_56_MIN.lua -- Minimalistic version for radios with LOW memory (Can setup planes)
DSM FwdPrg_56_STUP.lua -- `NEW!` Setup plane for minimalistic version (LOW Memory radios)
DSM FwdPrg_55_MIN.lua -- Uses less memory than v56, but cannot do initial setup of the plane
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
DsmFwPrgMIN_P1.lua -- Part1 of extra files for Min
DsmFwPrgMIN_P2.lua -- Part2 of extra files for Min
msg_fwdp_en.txt -- Menu messages in English (common for all radios)
MIN_msg_fwdp_en.txt -- Menu messages in English (overrides for 128x164 resolution)
### Other Directories/Files
/LOGS/dsm_log.txt --Readable log of the last RX/TX session, usefull for debugging problems
# NOTE for FC6250HX FC+RX version
For the full size FC6250HX, Only use V0.55 or newer.
DO NOT use previous versions to do the Setup -> Gyro Settings -> Orientation. The problem was that it did not have the orientation messages.. and you are were choosing blind. The calibration will never stop until you place the RX in the right orientation, even after restarting the RX (if flashing red, is not in the right orientation.. if flashshing white is in the right orientation). If you run into this problem, and lights are blinking red, rotate the FC on the longer axis until you get white blinking.. keep it stable, will blink white faster andlet calibration finishes.. after that is back to normal.
OpenTX: When you enter "forward programming" you will hear "Telemetry lost" and "Telemetry recovered".. The FC led will blink white, but when exit FP, will blink red...is not problem.. but will need to be power cycled to get blinking green again.. i think is something related to temporarilly loosing the connection with the radio..researching the OpenTX code since it only happens with this helis FC.
# Common Questions
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
- All Spektrum RX are 20 channels internally, even if it only has 6 external Ch/Ports to connect servos.
- Make sure that when you bind your RX, you select the proper range of channels to use.. By default, ch1-ch8.
- You have to mapped a Switch/Slider to the channel, togling/moving will select the channel on the menu field.
- The RX validates the channels, and it does not detect signal on a channel, it will not allow to select it..that is why is important to move the switch/slider, so that the RX knows that is a valid channel.
# Changes and fixes
v0.56:
1. Fix Tail-Type "Taileron" functionality that was not working. Also validated V-Tail and Delta wings.
2. Added Taileron and two Rudder config (Many Freewing Jets like F18,F16, etc)
3. Gyro-Reverse Screen now shows what is the channel/port used for (Ail, Ele, Rud, etc)
4. COLOR ONLY: Gyro-Reverse Screen now shows what information that shared with the RX about each channel (Role, Slave, Reverse).
5. NEW!! Initial version of Plane Setup for B&W radios
V0.55:
1. Finally found where the TX reports to the RX how many channels is transmiting. The TX now reports itself as a 12ch radio instead of 6h. (DSM Multi-Module limit). This fixes a few things:
a. Many places where you have to select channels > CH6 for Flight-Mode, Gains, Panic now works properly with the scroller. The radio is still validating that you are not selecting an invalid channel. For example, if you have an additional AIL on CH6, it will not allow you to use CH6 for FM or Gains.. it just move to the next valid one.
b. When setting up AIL/ELE on channels greater than CH6, on previous versions SAFE/AS3X was not moving them.. now they work up correctly. Set them up in the first in CH1-CH10. Why CH10?? Thats what fits on the reverse screen, otherwise, have to add more screens.
c. Some individual Gain channels was not allowing to setup on CH greater than CH6. Now is fixed.
2. User Interface:
a. `RTN` Key now works as `Back` when the screen has a `Back`. Makes it easy for navigation.. Presing `RTN` on the main screen exists the tool.
b. Much faster refresh of the menus. Optimize the process of send/recive menu data from the RX.
3. Support for FC6250HX (the one with separate RX).. Setup Swashplate type, RX orientation works properly.. This are menu options that the smaller version that comes in the
Blade 230S did not have.
V0.54 Beta:
- First version for the small screens, and limited memory. Only can change existing values, it cannot setup a brand new plane or new RX from Zero
- Fix problem on editing the SAFE Mode Attitude Trim
- First version with externalize merges, so that it can be translated to other languages
# Tested Radios and RXs
- Radio: FrSky QX7: Due to limited memory, could be that the first time is does not start (not enouth memory to compile+run), but try again after a fresh TX restart.
- AR631/AR637xx
- FC6250HX (Blade 230S V2 Helicopter)
- FC6250HX (Separate RX.. use only V55 or newer of this tool)
- AR636 (Blade 230S V1 Heli firmware 4.40)
Please report if you have tested it with other receivers to allow us to update the documentation. Code should work up to 10 channels for the main surfaces (Ail/Ele/etc). All Spektrum RX are internally 20 channels, so you can use Ch7 for Flight Mode even if your RX is only 6 channels (See common Questions)
# Messages Displayed in the GUI
If in a screen you get text that looks like `Unknown_XX` (ex: Unknown_D3), that message has not been setup in the script in english. If you can determine what the proper message is, you can send us a message to be added to the library.
The `XX` represents a Hex Number (0..9,A..F) message ID.
If you want to fix it in your local copy, all messages are in the file `SCRIPT\TOOS\DSMLIB\msg_fwdp_en.txt`. (english version)
Example::
T |0x0080|Orientation
T |0x0082|Heading
T |0x0085|Frame Rate
T |0x0086|System Setup
T |0x0087|F-Mode Setup
T |0x0088|Enabled F-Modes
T |0x0089|Gain Channel
T |0x008A|Gain Sensitivity/r -- Right Align
T |0x008B|Panic
T |0x008E|Panic Delay
For example, if you get `Unknown_9D` in the GUI and your now that it should say **NEW Text**, you can edit the lua script to look like this:
T |0x009D|NEW Text -- NEW Text added for AR98xx
# Local Language Support
Some settings that can change (top of Lua file):
`local LANGUAGE = "en"`
If you want to translate the menu messages to another language (like french), copy the file `msg_fwdp_en.txt` into `msg_fwdp_fr.txt`, translate it, and change the language in the lua file to `"fr"`.
# LOG File
The log file of the last use of the script is located at `/LOGS/dsm_log.txt`. **It is overridden on every start to avoid filling up the SD card**. So if you want to keep it, copy or rename it before starting the script again. (it can be renamed in the TX by browsing the SD card)
The log is human readable, and can help use debug problems remotrly
# Validation of data by the RX
When you change a value in the GUI, the RX validates that the value is valid. This applies to channels as well as values.
---
# Version 0.54
First version for Small Radios
### Known Problems:
- Currently cannot setup a plane from scratch.. (Working on it).
- The first time you run it, it will give you "not enouth memory", but should work the 2nd time after the first compilation (creation of .luac). After that, it should start right away.
# Version 0.2
Original Version from Pascal Langer

View File

@ -0,0 +1,284 @@
# Credits
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
Rewrite/Enhancements by: Francisco Arzu
Thanks to all the people volunteered to test it.
# Introduction (v0.56)
NOTE: Unless you use special tail types, probably not worth the upgrade. The changes are mostly cosmetic on the Gyro Reverse page to show extra information.
In 0.56, focused on validating and fixing the Wing and Tail type special mixing. Vtail/Delta was working but Taileron was not. The Gyro Reverse screen now show what type of servo information is sharing with the TX. This affects the Gyro AS3X and SAFE behaviour, you still needs to set your TX with the proper mixes to do V-Tail/Taileron/etc.
- The first is the "Role" of the port (`Ail/Ele/Rud/Thr`). Combination is posible for for special types of wing/tails: Vtail:`EleRud`, Delta & Taileron: `AilEle`.
- The `-` (Minus) is Reverse.
- Information is if it the Master or Slave (Master is implicit)
- The type of mix applied: for V-Tail, the left/right Elevators (`EleRud`) uses `M_Rud` (Mix Rudder), For Delta, the left/right Ailerons (`AilEle`) uses `M_Ele` (Mix Elevator), and finally the Tailerons, the the left/right Elevators (`AilEle`) uses `M_Ail` (Mix Aileron). Looks like the Mixes are for the entire RX and only needs to be set in one of the ports, The difference between the "A" and "B" configuration is just if the mix is set on the Master or Slave port (like Taileron_A or Taileron_B) and affects the direction.. sometimes you have to try both. Start by setting the right direction for the primary roll, and then use the A/B configurations. For exmaple, in Taileron, the primary roll is Elevators, the secondary roll is Aileron (Mix Aileron). Below is a Taileron example: Two independent Elevators and 2 independent ailerons.
![image](https://github.com/frankiearzu/DSMTools/assets/32604366/4bbeb234-c92c-4663-b464-549df1c134a0)
![image](https://github.com/frankiearzu/DSMTools/assets/32604366/f8fa62b4-9843-4d81-9c67-7c8bfcf252f2)
With spektrum constantly updating its firmware, you only need to update the message file if you see in the screen any message "Unknown_xyz".
This script library enhances the original DSM Forward Programming tool. DSM Forward Programming is needed to setup many of the new Spektrum Receivers with Gyro AS3X/SAFE features. For the Gyro (/Safe) to correct the plane in flight, it needs to move the right surfaces therefore the RX needs to know the configuration of the plane (Wing Type, Tail Type, Mixers, Servo Assignments, Servo Reverse). That info tells the RX where the aileron(s) are (one or two), where the elevator(s) are (one or two), V-Tail, Delta Wing, etc.
Since EdgeTx/OpenTx doesnt have an equivalent setup that is stored in the radio, we have to create our own version. This info is stored inside the `/MODELS/DSMDATA` directory/folder (which needs to be created by manually).
During `"Gyro Settings->initial setup"`, the RX asks the TX for model information behind the scenes. After setup, `"Gyro Settings->System Tools-> Relearn Servo Settings"` requests the TX servo configuration and stores it in the RX.
# Deployment
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first). Also you can delete the previous DSM_FwdProg*.* from /SCRIPTS/TOOLS.
Uncompress the Zip file (ZIP version) into your local computer.
In another window, open your TX SDCard.
1. The zip file has the same structure as your SDCard. If you want to copy all the content of the zip file into your SDCard top level folder, it will create all the directories and files in the right place.
2. Make sure to check that `/MODELS/DSMDATA` is there. The script will complain at startup if it does not exist. Here the script saves the Spektrun settings for each of your models.
Your TX SDCard should looks like this:
/SCRIPTS/TOOLS/ -- you only need one of the 3 to save some space in your TOOLS screen
DSM FwdPrg_56_Color.lua -- Color and touch radios
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
DsmFwPrgLib.lua -- DSM Protocol Message and Menu engine
DsmFwPrgSIMLib.lua -- Simulation of AR631, FC6250HX (For GUI development)
SetupLib.lua -- Model Setup Screens
msg_fwdp_en.txt -- `NEW!` Messages for forward programing externalized. To support other langs (english)
... a few other files
/SCRIPTS/TOOLS/DSMLIB/img -- Images for RX orientations
Other Directories
/MODELS/DSMDATA --(ALL CAPITALS) Data of model config (Wing Type, Servo Assignments)
/LOGS/dsm_log.txt --Readable log of the last RX/TX session, usefull for debugging problems
# NOTE for FC6250HX FC+RX version
For the full size FC6250HX, Only use V0.55 or newer.
DO NOT use previous versions to do the Setup -> Gyro Settings -> Orientation. The problem was that it did not have the orientation messages.. and you are were choosing blind. The calibration will never stop until you place the RX in the right orientation, even after restarting the RX (if flashing red, is not in the right orientation.. if flashshing white is in the right orientation). If you run into this problem, and lights are blinking red, rotate the FC on the longer axis until you get white blinking.. keep it stable, will blink white faster andlet calibration finishes.. after that is back to normal.
OpenTX: When you enter "forward programming" you will hear "Telemetry lost" and "Telemetry recovered".. The FC led will blink white, but when exit FP, will blink red...is not problem.. but will need to be power cycled to get blinking green again.. i think is something related to temporarilly loosing the connection with the radio..researching the OpenTX code since it only happens with this helis FC.
# Common Questions
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
- V0.55 and newer: Problem solved.. Should allow you to select up to 12ch with the switch technique or with the scroller.
- V0.53/0.54: The RX is listening to channel changes for this options. Configure the Switch to the channel, togling once the switch will select the channel on the menu field.
2. `Only able to switch to Fligh-mode 2 and 3, but not 1:`
Check that the module "Enable max throw" is OFF in you Multi-Module settings (where you do BIND), otherwise the TX signals will be out of range.
The multi-module is already adjusting the TX/FrSky servo range internally to match Spektrum.
3. `Why Ch1 says Ch1 (TX:Ch3/Thr)?`:
Radios with Multi-Module are usually configured to work the standard AETR convention. Spektrum uses TAER. The multi-module does the conversion when transmitting the signals. So `Spektrum Ch1 (Throttle)` really comes from the `TX Ch3`. We show both information (+name from the TX output). If your multi-module/radio is setup as TAER, the script will not do the re-arrangement.
4. `If i change the model name, the original model settings are lost.` This is correct, the model name is used to generate the file name (inside /MODEL/DSMDATA) who stores the model configuration. Currently EdgeTx and OpenTX has differt features where i could get either the Model Name or the YAML file where the EdgeTX model configuration is stored.. to keep the code compatible, the model name is used.
5. `Reversing a channel in my TX do not reverse the AS3X/SAFE reaction.` Correct, the chanel stick direction and the Gyro direction are two separate things.
5.1: First, you have setup your model so that the sticks and switches moves the surfaces in the right direction.
5.2: Go to the script, `Model Setup` and setup your wing type, tail type, and select the channel assigment for each surface. Leave the servo settings the same as the values in the TX to start.
5.3: Go to `Forward programming->Gyro Setting->Initial Setup` (New/factory reset), or `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` (not new). This will load your current Gyro servo settings into the plane's RX. This moves the current servo TX settings to the RX, so it is now in a known state.
5.4: Verify that the AS3X and SAFE reacts in the proper direction. You can use the Flight mode configured as "Safe Mode: Auto-Level" to see if it moves the surfaces in the right direction.
5.5: If a surface don't move in the right direction, go to the `Model Setup->Gyro Channel Reverse` to reverse the Gyro on the channels needed, and do again the `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` to tranfer the new settings to the RX.
5.6: Specktrum TX always passes the TX servo reverse as the Gyro Reverse, but on many OpenTX/EdgeTX radios, the Rud/Ail are usually reversed by default compared to Specktrum. So far i don't think that i can use this as a rule, that is why the `Gyro Channel Reverse` page exist.
---
---
# Changes and fixes
V0.56:
1. Fix Tail-Type "Taileron" functionality that was not working. Also validated V-Tail and Delta wings.
2. Added Taileron and two Rudder config (Many Freewing Jets like F18,F16, etc)
3. Gyro-Reverse Screen now shows what is the channel/port used for (Ail, Ele, Rud, etc)
4. COLOR ONLY: Gyro-Reverse Screen now shows what information that shared with the RX about each channel (Role, Slave, Reverse).
5. NEW!! Initial version of Plane Setup for B&W radios
V0.55a:
1. Fix loading external messages file for OpenTX.
V0.55:
1. Finally found where the TX reports to the RX how many channels is transmiting. The TX now reports itself as a 12ch radio instead of 6h. (DSM Multi-Module limit). This fixes a few things:
a. Many places where you have to select channels > CH6 for Flight-Mode, Gains, Panic now works properly with the scroller. The radio is still validating that you are not selecting an invalid channel. For example, if you have an additional AIL on CH6, it will not allow you to use CH6 for FM or Gains.. it just move to the next valid one.
b. When setting up AIL/ELE on channels greater than CH6, on previous versions SAFE/AS3X was not moving them.. now they work up correctly. Set them up in the first in CH1-CH10. Why CH10?? Thats what fits on the reverse screen, otherwise, have to add more screens.
c. Some individual Gain channels was not allowing to setup on CH greater than CH6. Now is fixed.
2. User Interface:
a. `RTN` Key now works as `Back` when the screen has a `Back`. Makes it easy for navigation.. Presing `RTN` on the main screen exists the tool.
b. Much faster refresh of the menus. Optimize the process of send/recive menu data from the RX.
3. The TX now comunicates the SubTrim positions to the RX during `Relearn Servo Setting`. This changes the center of movement to one side or another. Really not much difference with small amounts of subtrim, previous versions where asuming subtrim of 0. When you have an extreame subtrim to one side, it was not moving simetrically.
4. Support for FC6250HX (the one with separate RX).. Setup Swashplate type, RX orientation works properly.. This are menu options that the smaller version that comes in the
Blade 230S did not have.
V0.54:
1. Fix a problem in the Attitude Trim page (`Gyro Settings->System Setup->SAFE/Panic Setup->Attitude Trim`). It was not saving the values after exiting the menu. This is to change what SAFE considers "Level" flying.
2. Wings 2-Ail 2-Flaps had a bug on the 2nd flap.
3. New Minimalistic script (`DsmFwdPrg_05_MIN.lua`): For radios with very low memory (FrSky QX7, RM Zorro, others). It can only change existing settings, but does not have the Plane Setup menus to setup a completly new plane. In some radios, the very first time it runs (compile + run), it might give you a `not enouth memory` error.. try to run it again.
4. External menu message file (DSMLIB/msg_fwdp_en.txt and MIN_msg_fwdp_en.txt). Intial work to do localization and different languages.
V0.53:
1. Improved channel selection (Flight mode, Panic Channel, Gains Channel). Now during editing a channel, you can select any channel (>Ch4). Also, of you toggle the switch/channel it will populate the screen.
2. Support for smaller screens (128x64) in B&W. The problem with this older radios is memory. In some, it does not have enouth memory to load the additional DSMLIB libraries.
3. Fix formatting problem with some TX channel names who could affect the screen.. for example, rud channel should show "Ch4/rud", but shows "Ch4ud" because /r is for right justify formatting on messages. Now the formatting is only if it appears at the end of the message.
V0.52:
1. Menus to be able to configure Plane in a similar way as Spektrum Radio (v0.52)
2. Make "Gyro Settings"->"Initial Setup" works (Tested on AR631,AR637xx with PLANE type of aircraft)
3. Properly reset and restart after initial configuration and SAFE changes.
4. Write Log of the conversation between RX/TX. To be used for debugging a problem is reported.
5. Provide a simulation of RX to do GUI development in Companion, and understand patterns of how the data is organized.
# Tested Hardware
- AR631/AR637xx
- FC6250HX (Blade 230S V2 Helicopter; FC+RX in one, mini version)
- FC6250HX (Separate RX.. use only V55 or newer of this tool)
- AR636 (Blade 230S V1 Heli firmware 4.40)
- Radiomaster TX16S (All versions)
Please report if you have tested it with other receivers to allow us to update the documentation. Code should work up to 10 channels for the main surfaces (Ail/Ele/etc). All Spektrum RX are internally 20 channels, so you can use Ch7 for Flight Mode even if your RX is only 6 channels (See common Questions)
# Messages Displayed in the GUI
If in a screen you get text that looks like `Unknown_XX` (ex: Unknown_D3), that message has not been setup in the script in english. If you can determine what the proper message is, you can send us a message to be added to the library.
The `XX` represents a Hex Number (0..9,A..F) message ID.
### Version 0.53 and older:
If you want to fix it in your local copy, all messages are towards the end in the file `SCRIPT\TOOS\DSMLIB\DsmFwPrgLib.lua`. Messages for Headers are stored in `Text` and messages for Options are stored in `List_Text`. Lua scripts are text files, and can be edited with Notepad or equivalent.
Portion of DsmFwPrgLib.lua:
Text[0x0097] = "Factory Reset"
Text[0x0098] = "Factory Reset" -- FC6250HX: Title
Text[0x0099] = "Advanced Setup"
Text[0x009A] = "Capture Failsafe Positions"
Text[0x009C] = "Custom Failsafe"
Text[0x009F] = "Save & Reset RX" -- TODO: Find the Proper Spektrum Value ??
Text[0x00A5] = "First Time Setup"
Text[0x00AA] = "Capture Gyro Gains"
Text[0x00AD] = "Gain Channel Select"
-- Safe mode options, Inhibit + the values
local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope
List_Text[0x00B0] = "Self-Level/Angle Dem"
List_Text[0x00B1] = "Envelope"
For example, if you get `Unknown_9D` in the GUI and your now that it should say **NEW Text**, you can edit the lua script to look like this:
Text[0x009A] = "Capture Failsafe Positions"
Text[0x009C] = "Custom Failsafe"
Text[0x009D] = "NEW Text" -- NEW Text added for AR98xx
Text[0x009F] = "Save & Reset RX" -- TODO: Find the proper Spektrum text
### Version 0.54 and newer:
The menu messages are stored in DSMLIB/msg_fwdp_en.txt (For english). Just add the message there. MIN_msg_fwdp_en.txt has shorter messages overrides for screens who are smaller (for minimalistic 128x64 version). The reference to the message file is at the file `/DSMLIB/DsmFwPrgLib.lua` if you want to change to use another language.
T |0x0097|Factory Reset
LT|0x00B0|Self-Level/Angle Dem
LT|0x00B1|Envelope
# LOG File
The log file of the last use of the script is located at `/LOGS/dsm_log.txt`. **It is overridden on every start to avoid filling up the SD card**. So if you want to keep it, copy or rename it before starting the script again. (it can be renamed in the TX by browsing the SD card)
The log is human readable. The first number is the number of seconds since the start, and then what is the current state of the Library, and what has been sent and received. The info in the log can be easily used to create a new simulation for that RX in the future.
Example Log:
5.340 WAIT_CMD: DSM_GotoMenu(0x1010,LastSelectedLine=0)
5.350 MENU_TITLE: SEND DSM_getMenu(MenuId=0x1010 LastSelectedLine=0)
5.440 MENU_TITLE: RESPONSE Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
5.490 MENU_LINES: SEND DSM_getFirstMenuLine(MenuId=0x1010)
5.590 MENU_LINES: RESPONSE MenuLine: L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ]
5.640 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=0)
5.740 MENU_LINES: RESPONSE MenuLine: L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ]
5.790 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=1)
5.850 MENU_LINES: RESPONSE MenuLine: L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ]
5.910 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=2)
5.970 MENU_LINES: RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
6.020 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=3
# Validation of data by the RX
The RX validates the data. if you change to an invalid channel or do a invalid number range, the RX will change it at the end of editing the field.
---
# Version 0.53
- Improve Channel selection in menus
- Support smaller screens 128x64 in the black/white mode.
# Version 0.52
- Fix Reversing of Servos
- Properly detect Multimodule Ch settings AETR
---
# Version 0.51 (volunteer testing version, not for production)
- New Screens to Configure Model (Wing Type/Tail Tail, etc)
- Finally got understanding that the previous unknown 0x05 lines are to send Model/Servo data to RX.
- Fix use of AR636B (Firmware version 4.40.0 for Blade 230 heli, is the only one with Forward Programming)
- Aircraft types: Tested With Plane type only.. Glider and other in progress
### Known Problems:
- 4-Servo Wing type (Dual Ail/Tail) in planes give conflicting servo assignments by defaults.. Solution choose your own Ch.
- Glider, Heli, Drone: Still in development. In glider, only a few wing type works.. needs to restrict menu options for the only valid one.
# Version 0.5
- Make the code more readable and understandable
- Separate the DSM Forwards Programming logic from the GUI
- Log the communication with the RX on a /LOGS/dsm_log.txt to allow to debug it easier
and see the exchange of data between the RX/TX
- Created a black/white Text only version with only Key/Roller Inputs
- Created a nicer GUI for EdgeTX touch screen color Radios
- RX simulation for GUI development: turn on `SIMULATION_ON=true` in the beginning of the lua file
- Test it on AR631, AR637xx, FC6250HX (Helicopter)
### Some settings that can change (top of Lua file):
SIMULATION_ON = false -- FALSE: hide similation menu (DEFAULT), TRUE: show RX simulation menu
DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm_log.txt)
USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX, OpenTX handle colors different)
### Known Problems:
1. **Incorrect List Value Options:** Some Menu List line (`LINE_TYPE.LIST_MENU1` or `L_m1` in logs), the range (min/max) of valid values seems to be incorrect, but the RX corrects the values.
in the MINimalistic version, the RX is doing all the range validation, and will show invalid options temporarilly. In an Spektrum radio, it happens so fast, that you don't notice it, but in LUA scripts who are slower, you can see it in the screen.
In the COLOR version, The code has hardcoded the valid ranges to avoid this problem.
2. Glider/Heli/Drone wing types not ready.
For Helicopter, use airplane normal wing and normal tail
# Version 0.2
Original Version from Pascal Langer

View File

@ -0,0 +1,683 @@
local toolName = "TNS|DSM AR636 Telemetry|TNE"
---- ######################################################################### #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
------------------------------------------------------------------------------
-- Developer: Francisco Arzu
-- Original idea taken from DsmPID.lua.. don't know who is the author
--
local DEBUG_ON = false
--
local TEXT_SIZE = 0 -- NORMAL
local X_COL1_HEADER = 6
local X_COL1_DATA = 60
local X_COL2_HEADER = 170
local X_COL2_DATA = 220
local Y_LINE_HEIGHT = 20
local Y_HEADER = 0
local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2
local X_DATA_LEN = 80
local X_DATA_SPACE = 5
local function getPage(iParam)
-- get page from 0-based index
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
local res = (math.floor(iParam/4)==0) and 0 or 1
return res
end
local function round(v)
-- round float
local factor = 100
return math.floor(v * factor + 0.5) / factor
end
local function readValue(sensor)
-- read from sensor, round and return
local v = getValue(sensor)
--v = round(v)
return v
end
local function readValueById(sensor)
local i = getFieldInfo(sensor)
if (i==nil) then return nil end
local v = getValue(i.id)
return v
end
local function readBatValue(sensor)
-- read from sensor, round and return
local v = getValue(sensor)
if (v==nil) then return "--" end
return string.format("%2.2f",v)
end
local function readActiveParamValue(sensor)
-- read and return a validated active parameter value
local v = getValue(sensor)
if (v<1 or v>8) then
return -1
end
return v
end
local function drawPIDScreen()
-- draw labels and params on screen
local pageId = getValue("FLss")
lcd.clear()
-- if active gain does not validate then assume
-- Gain Adjustment Mode is disabled
if not (pageId==4401 or pageId==4402) then
lcd.drawText(0,0,"BLADE Gain Adjustment", TEXT_SIZE +INVERS)
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Gain Adjustment Mode",TEXT_SIZE)
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/R + Low/R + Panic (3 sec)",TEXT_SIZE)
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: Right Stk: Up/Down to select, Left/Right change value",TEXT_SIZE)
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE)
return
end
local activePage = (pageId % 100)-1 --Last 2 digits, make it zero base
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Cyclic (0-200)", TEXT_SIZE + INVERS)
lcd.drawText (X_COL2_HEADER, Y_HEADER, "Tail (0-200)", TEXT_SIZE + INVERS)
local p = readValue("FdeA")
local i = readValue("FdeB")
local d = readValue("FdeL")
local r = readValue("FdeR")
local titles = {[0]="P:", "I:", "D:", "Resp:", "P:","I:","D:", "Filt:"}
local values = {[0]=p,i,d,r,p,i,d,r}
local activeParam = readActiveParamValue("Hold")-1
for iParam=0,7 do
-- highlight selected parameter
local attr = (activeParam==iParam) and INVERS or 0
-- circular index (per page)
local perPageIndx = (iParam % 4)
-- set y draw coord
local y = (perPageIndx+1)*Y_LINE_HEIGHT+Y_DATA
-- check if displaying cyclic params.
local isCyclicPage = (getPage(iParam)==0)
-- labels
local x = isCyclicPage and X_COL1_HEADER or X_COL2_HEADER
-- labels are P,I,D for both pages except for last param
local val = titles[iParam]
lcd.drawText (x, y, val, TEXT_SIZE)
-- gains
-- set all params for non-active page to '--' rather than 'last value'
val = (getPage(iParam)==activePage) and values[iParam] or '--'
x = isCyclicPage and X_COL1_DATA or X_COL2_DATA
if (val~=16384) then -- Active value
lcd.drawText (x, y, val, attr + TEXT_SIZE)
end
end
end
local function drawFlightLogScreen()
-- draw labels and params on screen
local h = getValue("Hold")
local activeParam = h-1 -- H
lcd.clear()
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS)
-- read and return parameters
local a = getValue("FdeA")
local b = getValue("FdeB")
local l = getValue("FdeL")
local r = getValue("FdeR")
local f = getValue("FLss")
local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"}
local values = {[0]=a,b,l,r,f,h}
local y = Y_LINE_HEIGHT+Y_DATA
for iParam=0,3 do -- A,B,L,R
-- highlight selected parameter (rund)
local attr = ((activeParam%4)==iParam) and INVERS or 0
-- labels
local x = X_COL1_HEADER
local val = titles[iParam]
lcd.drawText (x, y, val, TEXT_SIZE)
-- Values
val = values[iParam]
x = X_COL1_DATA + X_DATA_LEN
if (val~=16384) then -- Active value
lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT)
end
y = y + Y_LINE_HEIGHT
end
y = Y_LINE_HEIGHT+Y_DATA
for iParam=4,5 do -- F, H
-- labels
local x = X_COL2_HEADER
local val = titles[iParam]
lcd.drawText (x, y, val, TEXT_SIZE + BOLD)
-- Values
val = values[iParam]
x = X_COL2_DATA + X_DATA_LEN
lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD)
y = y + Y_LINE_HEIGHT
end
-- Bat
y = y + Y_LINE_HEIGHT
local bat = readBatValue("A2") or "--"
lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE)
lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT)
lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE)
end
local function servoAdjustScreen()
-- draw labels and params on screen
local pageId = getValue("FLss") -- FLss
local activeParam = getValue("Hold")-1 -- Hold
lcd.clear()
lcd.drawText (0, Y_HEADER, "BLADE Servo SubTrim", TEXT_SIZE + INVERS)
if pageId~=1234 then
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Servo Adjustment Mode",TEXT_SIZE)
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/L + Low/R + Panic (3 sec)",TEXT_SIZE)
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: R Stk: Up/Down to select, Left/Right change value",TEXT_SIZE)
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE)
return
end
local a = getValue("FdeA")
local b = getValue("FdeB")
local l = getValue("FdeL")
local titles = {[0]="Servo1:", "Servo2:", "Servo3:"}
local values = {[0]=a,b,l}
for iParam=0,#values do -- S1,S2,S3
-- highlight selected parameter
local attr = (activeParam==iParam) and INVERS or 0
-- set y draw coord
local y = (iParam+1)*Y_LINE_HEIGHT+Y_HEADER
-- labels
local x = X_COL1_HEADER
local val = titles[iParam]
lcd.drawText (x, y, val, TEXT_SIZE)
val = values[iParam]
x = X_COL1_DATA
if (val~=16384) then -- Active value
lcd.drawText (x, y, val, attr + TEXT_SIZE)
end
end
end
local function Unsigned_to_SInt16(value)
if value >= 0x8000 then -- Negative value??
return value - 0x10000
end
return value
end
local function getDegreesValue(sensor)
local i = getFieldInfo(sensor)
if (i==nil) then return "-unk-" end
local v = getValue(i.id)
if v==nil then return "---" end
local vs = Unsigned_to_SInt16(v)
return string.format("%0.1f o",vs/10)
end
local function getDecHexValue(sensor)
local i = getFieldInfo(sensor)
if (i==nil) then return "-unk-" end
local v = getValue(i.id)
if v==nil then return "---" end
local vs = Unsigned_to_SInt16(v)
return string.format("%d (0x%04X)",vs,v)
end
local function drawVersionScreen()
local paramV = getValue("FdeA")
local B = getValue("FdeB")
local rxId = getValue("FdeL")
local firmware = getValue("FLss")
local prodId = getValue("Hold")
local bat = readBatValue("A2")
lcd.clear()
lcd.drawText (0, Y_HEADER, "BLADE Version", TEXT_SIZE + INVERS)
--Product ID
local val = "ID_".. prodId
if (prodId==243) then val = "Blade 230 V1"
elseif (prodId==250) then val = "Blade 230 V2 (not Smart)"
elseif (prodId==149) then val = "Blade 250 CFX"
end
local y = Y_DATA
local x_data1 = X_COL1_DATA+X_DATA_LEN
lcd.drawText (X_COL1_HEADER, y, "Prod:", TEXT_SIZE)
lcd.drawText (x_data1, y, val, TEXT_SIZE)
-- RX
val = "ID_"..rxId
if (rxId==1) then val = "AR636"
end
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER, y, "RX:", TEXT_SIZE)
lcd.drawText (x_data1, y, val, TEXT_SIZE)
-- Firmware
val = string.format("%0.2f",firmware/100)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER, y, "Firmware:", TEXT_SIZE)
lcd.drawText (x_data1, y, val, TEXT_SIZE)
-- ParamV
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER, y, "Params:", TEXT_SIZE)
lcd.drawText (x_data1, y, paramV, TEXT_SIZE)
-- Bat
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER, y, "Bat:", TEXT_SIZE)
lcd.drawText (x_data1, y, bat, TEXT_SIZE)
y = y + Y_LINE_HEIGHT
lcd.drawText(X_COL1_HEADER,y,"Press Panic for 3s",TEXT_SIZE)
y = y + Y_LINE_HEIGHT
lcd.drawText(X_COL1_HEADER,y,"Usually Panic is Ch7 on a switch and Revesed",TEXT_SIZE)
end
local function parseFlightMode(v)
-- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0= off, 1=init, 2=Hold, 3=Running) GG=???
if v==nil then return "---" end
local fm = bit32.rshift(v, 12)
local status = bit32.band(bit32.rshift(v, 8),0xF)
local res = " "..fm.." "
if (fm==0) then res = res .. " NORMAL"
elseif (fm==1) then res = res .. " INTERMEDIATE"
elseif (fm==2) then res = res .. " ADVANCED"
elseif (fm==5) then res = res .. " PANIC"
end
if (status==2) then res=res .. " HOLD" end
if (DEBUG_ON) then
res = res .. string.format(" (0x%04X)",v)
end
return res
end
local function drawAlpha6Monitor()
lcd.clear()
local RxStatus = readValueById("2402") -- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0=init, 2=Ready, 3=Sensor Fault) GG=???
local ARoll = getDegreesValue("2406") --Att Roll
local APitch = getDegreesValue("2408") --Att Pitch
local AYaw = getDegreesValue("240B") --Att Yaw
lcd.drawText (0,0, "BLADE Alpha6 Monitor", TEXT_SIZE+INVERS)
local y = Y_DATA
local x_data1 = X_COL1_DATA+X_DATA_LEN
local x_data2 = X_COL1_DATA+X_DATA_LEN*2
local x_data3 = X_COL1_DATA+X_DATA_LEN*3
-- Flight Mode
lcd.drawText (0,y, "F-Mode:"..parseFlightMode(RxStatus), TEXT_SIZE)
y = y + Y_LINE_HEIGHT
lcd.drawText (x_data1,y, "Attitude", TEXT_SIZE+BOLD + RIGHT)
lcd.drawText (x_data2,y, "Gyro", TEXT_SIZE+BOLD + RIGHT)
lcd.drawText (x_data3,y, "Gain", TEXT_SIZE+BOLD + RIGHT)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Rol:", TEXT_SIZE)
lcd.drawText (x_data1,y, ARoll, TEXT_SIZE + RIGHT)
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
lcd.drawText (x_data1,y, APitch, TEXT_SIZE + RIGHT)
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
lcd.drawText (x_data1,y, AYaw, TEXT_SIZE + RIGHT)
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
y = y + Y_LINE_HEIGHT + Y_LINE_HEIGHT
lcd.drawText (0,y, "Bat: "..readBatValue("A2").." v", TEXT_SIZE)
-- Debug Values
if (DEBUG_ON) then
local s2400 = getDecHexValue("2400")
local s2402 = getDecHexValue("2402")
local s2404 = getDecHexValue("2404")
local s240D = getDecHexValue("240D")
local s1G00 = getDecHexValue("1G00")
local s1G02 = getDecHexValue("1G02")
local s1G04 = getDecHexValue("1G04")
local s1G06 = getDecHexValue("1G06")
local s1G08 = getDecHexValue("1G08")
local s1G0B = getDecHexValue("1G0B")
local s1G0D = getDecHexValue("1G0D")
local titles = {[0]=
"2400","2402/FM-S-?",
"2404","240D",
"1G00","1G02","1G04",
"1G06","1G08","1G0B","1G0D"}
local values = {[0]=
s2400,s2402,s2404,s240D,
s1G00,s1G02,s1G04,
s1G06,s1G08,s1G0B,s1G0D}
-- draw labels and params on screen
y = Y_LINE_HEIGHT*2 + Y_HEADER
for iParam=0,#titles do -- ??
-- labels
local x = X_COL1_HEADER+220
local val = titles[iParam]
lcd.drawText (x, y, val, TEXT_SIZE)
val = values[iParam]
x = X_COL1_DATA+250
lcd.drawText (x, y, val, TEXT_SIZE)
y = y + Y_LINE_HEIGHT
end
end
end
local function readAlpha3arameters()
end
local function drawAS3XMonitor()
lcd.clear()
local s1G00 = getDecHexValue("1G00")
local s1G02 = getDecHexValue("1G02")
local s1G04 = getDecHexValue("1G04")
local s1G06 = getDecHexValue("1G06")
local s1G08 = getDecHexValue("1G08")
local s1G0B = getDecHexValue("1G0B")
local s1G0D = getDecHexValue("1G0D")
local s6C00 = getDecHexValue("6C00")
local s6C02 = getDecHexValue("6C02")
local s6C04 = getDecHexValue("6C04")
local RRoll = bit32.rshift(getValue("1G00") or 0,8)
local RPitch = bit32.band(getValue("1G00") or 0,0xFF)
local RYaw = bit32.rshift(getValue("1G02") or 0,8)
local HRoll = bit32.band(getValue("1G02") or 0,0xFF)
local HPitch = bit32.rshift(getValue("1G04") or 0,8)
local HYaw = bit32.band(getValue("1G04") or 0,0xFF)
local ARoll = bit32.rshift(getValue("1G06") or 0,8)
local APitch = bit32.band(getValue("1G06") or 0,0xFF)
local AYaw = bit32.rshift(getValue("1G08") or 0,8)
lcd.drawText (0,0, "Plane AR636 AS3X Gains", TEXT_SIZE+INVERS)
local y = Y_DATA
local x_data1 = X_COL1_DATA+X_DATA_LEN
local x_data2 = X_COL1_DATA+X_DATA_LEN*2
local x_data3 = X_COL1_DATA+X_DATA_LEN*3.1
-- Flight Mode
--lcd.drawText (0,y, "F-Mode: "..(nil or "--"), TEXT_SIZE)
y = y + Y_LINE_HEIGHT
lcd.drawText (x_data1,y, "Rate", TEXT_SIZE+BOLD + RIGHT)
lcd.drawText (x_data2,y, "Head", TEXT_SIZE+BOLD + RIGHT)
lcd.drawText (x_data3+X_DATA_SPACE*3,y, "Actual", TEXT_SIZE+BOLD + RIGHT)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Roll %:", TEXT_SIZE)
lcd.drawText (x_data1,y, RRoll, TEXT_SIZE + RIGHT)
lcd.drawText (x_data2,y, HRoll, TEXT_SIZE + RIGHT)
lcd.drawText (x_data3,y, ARoll, TEXT_SIZE + RIGHT)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Pitch %:", TEXT_SIZE)
lcd.drawText (x_data1,y, RPitch, TEXT_SIZE + RIGHT)
lcd.drawText (x_data2,y, HPitch, TEXT_SIZE + RIGHT)
lcd.drawText (x_data3,y, APitch, TEXT_SIZE + RIGHT)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Yaw %:", TEXT_SIZE)
lcd.drawText (x_data1,y, RYaw, TEXT_SIZE + RIGHT)
lcd.drawText (x_data2,y, HYaw, TEXT_SIZE + RIGHT)
lcd.drawText (x_data3,y, AYaw, TEXT_SIZE + RIGHT)
-- Debug Values
if (DEBUG_ON) then
local Alpha3Tags = {[0]=
"1G00/RA+RE","1G02/RY+HA","1G04R HP+HY","1G06/AR+AP","1G08/AY+?","1G0B","1G0D","6C00","6C02","6C04"}
local params = {[0]=
s1G00,s1G02,s1G04,s1G06,s1G08,s1G0B,s1G0D,s6C00,s6C02,s6C04 }
y = Y_LINE_HEIGHT*2 + Y_HEADER
for iParam=0,#Alpha3Tags do -- ??
-- labels
local x = X_COL1_HEADER+220
local val = Alpha3Tags[iParam]
lcd.drawText (x, y, val, TEXT_SIZE)
val = params[iParam]
x = X_COL1_DATA+250
lcd.drawText (x, y, val, TEXT_SIZE)
y = y + Y_LINE_HEIGHT
end
end
end
local function openTelemetryRaw(i2cId)
--Init telemetry (Spectrun Telemetry Raw STR)
multiBuffer( 0, string.byte('S') )
multiBuffer( 1, string.byte('T') )
multiBuffer( 2, string.byte('R') )
multiBuffer( 3, i2cId ) -- Monitor this teemetry data
multiBuffer( 4, 0 ) -- Allow to get Data
end
local function closeTelemetryRaw()
multiBuffer(0, 0) -- Destroy the STR header
multiBuffer(3, 0) -- Not requesting any Telementry ID
end
local lineText = {nil}
local I2C_TEXT_GEN = 0x0C
local function drawTextGen(event)
if (multiBuffer(0)~=string.byte('S')) then -- First time run???
openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN
lineText = {nil}
end
-- Proces TEXT GEN Telementry message
if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received
local instanceNo = multiBuffer( 5 )
local lineNo = multiBuffer( 6 )
local line = ""
for i=0,13 do
line = line .. string.char(multiBuffer( 7 + i ))
end
multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message
lineText[lineNo]=line
end
lcd.clear()
-- Header
if (lineText[0]) then
lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS)
else
lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS)
end
-- Menu lines
local y = Y_DATA
for i=1,8 do
if (lineText[i]) then
lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE)
end
y = y + Y_LINE_HEIGHT
end
if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data
closeTelemetryRaw()
end
end
local telPage = 1
local telPageSelected = 0
local pageTitle = {[0]="Main", "Blade Version", "Blade Servo Adjust","Blade Gyro Adjust", "Blade Alpha6 Monitor", "Plane AS3X Monitor", "TextGen", "Flight Log"}
local function drawMainScreen(event)
lcd.clear()
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (AR636)", TEXT_SIZE + INVERS)
for iParam=1,#pageTitle do
-- highlight selected parameter
local attr = (telPage==iParam) and INVERS or 0
-- set y draw coord
local y = (iParam-1)*Y_LINE_HEIGHT+Y_DATA
-- labels
local x = X_COL1_HEADER
local val = pageTitle[iParam]
lcd.drawText (x, y, val, attr + TEXT_SIZE)
end
if event == EVT_VIRTUAL_PREV then
if (telPage>1) then telPage = telPage - 1 end
elseif event == EVT_VIRTUAL_NEXT then
if (telPage<#pageTitle) then telPage = telPage + 1 end
elseif event == EVT_VIRTUAL_ENTER then
telPageSelected = telPage
end
end
local pageDraw = {[0]=drawMainScreen, drawVersionScreen, servoAdjustScreen,drawPIDScreen, drawAlpha6Monitor, drawAS3XMonitor, drawTextGen, drawFlightLogScreen}
local function run_func(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
end
-- draw specific page
pageDraw[telPageSelected](event)
if event == EVT_VIRTUAL_EXIT then
if (telPageSelected==0) then return 1 end -- on Main?? Exit Script
telPageSelected = 0 -- any page, return to Main
end
return 0
end
local function init_func()
if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens
TEXT_SIZE = SMLSIZE
X_COL1_HEADER = 0
X_COL1_DATA = 20
X_COL2_HEADER = 60
X_COL2_DATA = 90
X_DATA_LEN = 28
X_DATA_SPACE = 1
Y_LINE_HEIGHT = 8
Y_DATA = Y_HEADER + Y_LINE_HEIGHT
end
end
return { run=run_func, init=init_func }

View File

@ -0,0 +1,603 @@
local toolName = "TNS|DSM Smart RX Telemetry|TNE"
---- ######################################################################### #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
------------------------------------------------------------------------------
-- Developer: Francisco Arzu
local DEBUG_ON = false
--
local TEXT_SIZE = 0 -- NORMAL
local X_COL1_HEADER = 6
local X_COL1_DATA = 60
local X_COL2_HEADER = 170
local X_COL2_DATA = 220
local Y_LINE_HEIGHT = 20
local Y_HEADER = 0
local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2
local X_DATA_LEN = 80
local X_DATA_SPACE = 5
local function getPage(iParam)
-- get page from 0-based index
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
local res = (math.floor(iParam/4)==0) and 0 or 1
return res
end
local function round(v)
-- round float
local factor = 100
return math.floor(v * factor + 0.5) / factor
end
local function readValue(sensor)
-- read from sensor, round and return
local v = getValue(sensor)
--v = round(v)
return v
end
local function readValueById(sensor)
local i = getFieldInfo(sensor)
if (i==nil) then return nil end
local v = getValue(i.id)
return v
end
local function readBatValue(sensor)
-- read from sensor, round and return
local v = getValue(sensor)
if (v==nil) then return v end
return string.format("%2.2f",v)
end
local function readActiveParamValue(sensor)
-- read and return a validated active parameter value
local v = getValue(sensor)
if (v<1 or v>8) then
return -1
end
return v
end
local function drawFlightLogScreen(event)
-- draw labels and params on screen
local h = getValue("Hold")
local activeParam = h-1 -- H
lcd.clear()
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS)
-- read and return parameters
local a = getValue("FdeA")
local b = getValue("FdeB")
local l = getValue("FdeL")
local r = getValue("FdeR")
local f = getValue("FLss")
local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"}
local values = {[0]=a,b,l,r,f,h}
local y = Y_LINE_HEIGHT+Y_DATA
for iParam=0,3 do -- A,B,L,R
-- highlight selected parameter (rund)
local attr = ((activeParam%4)==iParam) and INVERS or 0
-- labels
local x = X_COL1_HEADER
local val = titles[iParam]
lcd.drawText (x, y, val, TEXT_SIZE)
-- Values
val = values[iParam]
x = X_COL1_DATA + X_DATA_LEN
if (val~=16384) then -- Active value
lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT)
end
y = y + Y_LINE_HEIGHT
end
y = Y_LINE_HEIGHT+Y_DATA
for iParam=4,5 do -- F, H
-- labels
local x = X_COL2_HEADER
local val = titles[iParam]
lcd.drawText (x, y, val, TEXT_SIZE + BOLD)
-- Values
val = values[iParam]
x = X_COL2_DATA + X_DATA_LEN
lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD)
y = y + Y_LINE_HEIGHT
end
-- Bat
y = y + Y_LINE_HEIGHT
local bat = readBatValue("A2") or "--"
lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE)
lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT)
lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE)
end
local function Unsigned_to_SInt16(value)
if value >= 0x8000 then -- Negative value??
return value - 0x10000
end
return value
end
local function getDegreesValue(sensor)
local i = getFieldInfo(sensor)
if (i==nil) then return "-unk-" end
local v = getValue(i.id)
if v==nil then return "---" end
local vs = Unsigned_to_SInt16(v)
return string.format("%0.1f o",vs/10)
end
local function getDecHexValue(sensor)
local i = getFieldInfo(sensor)
if (i==nil) then return "-unk-" end
local v = getValue(i.id)
if v==nil then return "---" end
local vs = Unsigned_to_SInt16(v)
return string.format("%d (0x%04X)",vs,v)
end
local as3xData = {[0]=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
local function drawAS3XSettings(event, page)
local s0500 = getDecHexValue("0500")
local s0502 = getDecHexValue("0502")
local s0504 = getDecHexValue("0504")
local s0506 = getDecHexValue("0506")
local s0508 = getDecHexValue("0508")
local s050B = getDecHexValue("050B")
local s050D = getDecHexValue("050D")
local d0500 = readValueById("0500") or 0
local flags = bit32.rshift(d0500,8)
local state = bit32.band(d0500,0xFF)
local flagsMsg=""
-- flags bits: Safe Envelop, ?, Angle Demand, Stab
if (bit32.band(flags,0x1)~=0) then flagsMsg=flagsMsg.."AS3X Stab" end
-- This one, only one should show
if (bit32.band(flags,0x2)~=0) then flagsMsg=flagsMsg..", Angle Demand"
elseif (bit32.band(flags,0x8)~=0) then flagsMsg=flagsMsg..", Safe Envelope"
elseif (bit32.band(flags,0x4)~=0) then flagsMsg=flagsMsg..", AS3X Heading" end
local d0502 = readValueById("0502") or 0 -- 0x?F?S
local fm = bit32.band(bit32.rshift(d0502,8),0xF) -- 0,1,2
local axis = bit32.band(d0502,0xF) -- 0=Gains,1=Headings,2=Angle Limits (cointinus iterating to provide all values)
local d0504 = readValueById("0504") or 0
local d0506 = readValueById("0506") or 0
local d0508 = readValueById("0508") or 0
local d0 = bit32.rshift(d0504,8)
local d1 = bit32.band(d0504,0xFF)
local d2 = bit32.rshift(d0506,8)
local d3 = bit32.band(d0506,0xFF)
local d4 = bit32.rshift(d0508,8)
local d5 = bit32.band(d0508,0xFF)
--axis: 0=Gains+Headings (RG,PG,YG,RH,PH,YH), 1=Safe Gains (R,P,Y),2=Angle Limits(L,R,U,D)
--Constantly changing from 0..2 to represent different data, thats why we have to store the values
--in a script/global variable, and not local to the function
local s = axis*6
as3xData[s+0] = d0
as3xData[s+1] = d1
as3xData[s+2] = d2
as3xData[s+3] = d3
as3xData[s+4] = d4
as3xData[s+5] = d5
lcd.clear()
lcd.drawText (0,0, "AS3X/SAFE Settings", TEXT_SIZE + INVERS)
local y = Y_DATA
-- Flight Mode
lcd.drawText (X_COL1_HEADER,y, "FM: "..(fm+1), TEXT_SIZE)
lcd.drawText (X_COL1_DATA+X_DATA_LEN*0.3,y, "Flags: "..flags, TEXT_SIZE)
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "State: "..state, TEXT_SIZE)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, flagsMsg, TEXT_SIZE)
y = y + Y_LINE_HEIGHT
if (page==1) then
lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "AS3X Gains", TEXT_SIZE+BOLD)
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "AS3X Headings", TEXT_SIZE+BOLD)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE)
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[0], TEXT_SIZE + RIGHT) -- Roll G
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[3], TEXT_SIZE + RIGHT) -- Roll H
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y,as3xData[1], TEXT_SIZE + RIGHT) -- Pitch G
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[4], TEXT_SIZE + RIGHT) -- Pitch H
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[2], TEXT_SIZE + RIGHT) -- Yaw G
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[5], TEXT_SIZE + RIGHT) -- Yaw H
end
if (page==2) then
local x_data1 = X_COL1_DATA+X_DATA_LEN
local x_data2 = X_COL2_HEADER+X_DATA_LEN*1.6
lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "SAFE Gains", TEXT_SIZE+BOLD)
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.1,y, "Angle Limits", TEXT_SIZE+BOLD)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE)
lcd.drawText (x_data1,y, as3xData[6], TEXT_SIZE + RIGHT)
lcd.drawText (X_COL2_HEADER,y, "Roll R:", TEXT_SIZE)
lcd.drawText (x_data2,y, as3xData[12], TEXT_SIZE + RIGHT)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
lcd.drawText (x_data1,y,as3xData[7], TEXT_SIZE + RIGHT)
lcd.drawText (X_COL2_HEADER,y, "Roll L:", TEXT_SIZE)
lcd.drawText (x_data2,y,as3xData[13], TEXT_SIZE + RIGHT)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
lcd.drawText (x_data1,y, as3xData[8], TEXT_SIZE + RIGHT)
lcd.drawText (X_COL2_HEADER,y, "Pitch U:", TEXT_SIZE)
lcd.drawText (x_data2,y, as3xData[14], TEXT_SIZE + RIGHT)
y = y + Y_LINE_HEIGHT
lcd.drawText (X_COL2_HEADER,y, "Pitch D:", TEXT_SIZE)
lcd.drawText (x_data2,y, as3xData[15], TEXT_SIZE + RIGHT)
end
-- Debug Values
if (DEBUG_ON) then
local titles = {[0]=
"0500","0502","0504","0506","0508","050B","050D"}
local values = {[0]=
s0500,s0502,s0504,s0506,s0508,s050B,s050D }
y = Y_LINE_HEIGHT*2 + Y_HEADER
for iParam=0,#titles do -- ??
-- labels
local x = X_COL1_HEADER+250
local val = titles[iParam]
lcd.drawText (x, y, val, TEXT_SIZE)
val = values[iParam] or "--"
x = X_COL1_DATA+250
lcd.drawText (x, y, val, TEXT_SIZE)
y = y + Y_LINE_HEIGHT
end
end
end
local function drawAS3XSettingsP1(event)
drawAS3XSettings(event, 1)
end
local function drawAS3XSettingsP2(event)
drawAS3XSettings(event, 2)
end
local function doFloat(v)
if v==nil then return 0.0 end
local vs = string.format("%1.2f",v)
return vs + 0.0
end
local ESC_Title={[0]="","RPM:","Volts:","Motor:","Mot Out:","Throttle:","FET Temp:", "BEC V:", "BEC T:", "BEC A:"}
local ESC_uom={[0]="","","V","A","%","%","C", "V","C","A"}
local ESC_Status={[0]=0,0,0,0,0,0,0,0,0,0,0}
local ESC_Min={[0]=0,0,0,0,0,0,0,0,0,0,0}
local ESC_Max={[0]=0,0,0,0,0,0,0,0,0,0,0}
local function drawESCStatus(event)
lcd.clear()
ESC_Status[1] = getValue("Erpm") -- RPM
ESC_Status[2] = doFloat(getValue("EVIN")) -- Volts
ESC_Status[3] = doFloat(getValue("ECUR")) -- Current
ESC_Status[4] = doFloat(getValue("EOUT")) -- % Output
ESC_Status[5] = doFloat(getValue("ETHR")) -- Throttle % (EOUT)
ESC_Status[6] = getValue("TFET") -- Temp FET
ESC_Status[7] = doFloat(getValue("VBEC")) -- Volts BEC
ESC_Status[8] = getValue("TBEC") -- Temp BEC
ESC_Status[9] = doFloat(getValue("CBEC")) -- Current BEC
for i=1,9 do
if (ESC_Status~=nil) then
if (ESC_Min[i]==0) then
ESC_Min[i]=ESC_Status[i]
else
ESC_Min[i] = math.min(ESC_Min[i],ESC_Status[i])
end
ESC_Max[i] = math.max(ESC_Max[i],ESC_Status[i])
end
end
lcd.drawText (0,0, "ESC", TEXT_SIZE+INVERS)
local y = 0
local x_data = X_COL1_DATA+X_DATA_LEN*1.5
local x_data2 = X_COL2_DATA+X_DATA_LEN*0.5
local x_data3 = x_data2 + X_DATA_LEN*0.8
lcd.drawText (x_data,y , "Status", TEXT_SIZE+BOLD+RIGHT)
lcd.drawText (x_data2,y, "Min", TEXT_SIZE+BOLD+RIGHT)
lcd.drawText (x_data3,y, "Max", TEXT_SIZE+BOLD+RIGHT)
y = Y_DATA
for i=1,9 do
lcd.drawText (X_COL1_HEADER,y, ESC_Title[i], TEXT_SIZE + BOLD)
lcd.drawText (x_data,y, ESC_Status[i] or "--", TEXT_SIZE + RIGHT)
lcd.drawText (x_data + X_DATA_SPACE,y, ESC_uom[i], TEXT_SIZE)
lcd.drawText (x_data2,y, ESC_Min[i] or "--", TEXT_SIZE + RIGHT)
lcd.drawText (x_data3,y, ESC_Max[i] or "--", TEXT_SIZE + RIGHT)
y = y + Y_LINE_HEIGHT
end
end
local function drawBATStatus(event)
local Title={[0]="","Bat:","Temp:","Rem :","Curr:","Used:","Imbal:","Cycles:", "RX:", "BCpT?:"}
local uom={[0]="","V","C","%","mAh","mAh","mV","", "V",""}
local Values={[0]=0,0,0,0,0,0,0,0,0,0,0}
local CellValues={[0]=0,0,0,0,0,0,0,0,0,0,0}
lcd.clear()
local ESC_Volts = getValue("EVIN") or 0 -- Volts
local ESC_Current = getValue("ECUR") or 0 -- Current
Values[1] = 0 -- compute later
Values[2] = getValue("BTmp") -- Current (C)
Values[3] = nil -- Remaining???
Values[4] = getValue("BCur") -- Current (mAh)
Values[5] = getValue("BUse") -- Current Used (mAh)
Values[6] = getValue("CLMa") -- 0.0 (mV) Imbalance
Values[7] = getValue("Cycl") -- Cycles
Values[8] = readBatValue("A2") -- v
Values[9] = getValue("BCpT") -- Current (mAh) ????
--- Total Voltange Calculation
local VTotal=0
for i=1,10 do
CellValues[i] = getValue("Cel"..i)
VTotal = VTotal + CellValues[i]
end
if (VTotal==0) then -- No Inteligent Battery,use intelligent ESC if any
VTotal = ESC_Volts
Values[4] = string.format("%d",ESC_Current * 1000)
end
Values[1] = string.format("%2.2f",VTotal)
--- SCREEN
lcd.drawText (X_COL1_HEADER,0, "Battery Stats", TEXT_SIZE+INVERS)
local y = Y_DATA
local x_data = X_COL1_DATA+X_DATA_LEN+X_DATA_SPACE*3
for i=2,9 do
lcd.drawText (X_COL1_HEADER, y, Title[i], TEXT_SIZE + BOLD)
lcd.drawText (x_data, y, Values[i] or "--", TEXT_SIZE + RIGHT)
lcd.drawText (x_data+X_DATA_SPACE, y, uom[i], TEXT_SIZE)
y = y + Y_LINE_HEIGHT
end
y = Y_DATA
x_data = X_COL2_DATA+X_DATA_LEN+X_DATA_SPACE*5
for i=1,8 do
if ((CellValues[i] or 0) > 0) then
lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,y, "Cel "..i..":", TEXT_SIZE + BOLD)
lcd.drawText (x_data,y, string.format("%2.2f",CellValues[i] or 0), TEXT_SIZE + RIGHT)
lcd.drawText (x_data+X_DATA_SPACE,y, "v", TEXT_SIZE)
end
y = y + Y_LINE_HEIGHT
end
lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,0, Title[1], TEXT_SIZE + INVERS + BOLD)
lcd.drawText (x_data,0, string.format("%2.2f",Values[1] or 0), TEXT_SIZE + INVERS+ RIGHT)
lcd.drawText (x_data+X_DATA_SPACE, 0, uom[1], TEXT_SIZE + INVERS)
end
local function openTelemetryRaw(i2cId)
--Init telemetry (Spectrun Telemetry Raw STR)
multiBuffer( 0, string.byte('S') )
multiBuffer( 1, string.byte('T') )
multiBuffer( 2, string.byte('R') )
multiBuffer( 3, i2cId ) -- Monitor this teemetry data
multiBuffer( 4, 0 ) -- Allow to get Data
end
local function closeTelemetryRaw()
multiBuffer(0, 0) -- Destroy the STR header
multiBuffer(3, 0) -- Not requesting any Telementry ID
end
local lineText = {nil}
local I2C_TEXT_GEN = 0x0C
local function drawTextGen(event)
if (multiBuffer(0)~=string.byte('S')) then -- First time run???
openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN
lineText = {nil}
end
-- Proces TEXT GEN Telementry message
if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received
local instanceNo = multiBuffer( 5 )
local lineNo = multiBuffer( 6 )
local line = ""
for i=0,13 do
line = line .. string.char(multiBuffer( 7 + i ))
end
multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message
lineText[lineNo]=line
end
lcd.clear()
-- Header
if (lineText[0]) then
lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS)
else
lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS)
end
-- Menu lines
local y = Y_DATA
for i=1,8 do
if (lineText[i]) then
lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE)
end
y = y + Y_LINE_HEIGHT
end
if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data
closeTelemetryRaw()
end
end
local telPage = 1
local telPageSelected = 0
local pageTitle = {[0]="Main", "AS3X Settings", "SAFE Settings", "ESC Status", "Battery Status","TextGen","Flight Log"}
local function drawMainScreen(event)
lcd.clear()
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (Smart RXs)", TEXT_SIZE + INVERS)
for iParam=1,#pageTitle do
-- highlight selected parameter
local attr = (telPage==iParam) and INVERS or 0
-- set y draw coord
local y = (iParam)*Y_LINE_HEIGHT+Y_DATA
-- labels
local x = X_COL1_HEADER
local val = pageTitle[iParam]
lcd.drawText (x, y, val, attr + TEXT_SIZE)
end
if event == EVT_VIRTUAL_PREV then
if (telPage>1) then telPage = telPage - 1 end
elseif event == EVT_VIRTUAL_NEXT then
if (telPage<#pageTitle) then telPage = telPage + 1 end
elseif event == EVT_VIRTUAL_ENTER then
telPageSelected = telPage
end
end
local pageDraw = {[0]=drawMainScreen, drawAS3XSettingsP1, drawAS3XSettingsP2, drawESCStatus, drawBATStatus, drawTextGen, drawFlightLogScreen}
local function run_func(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
end
-- draw specific page
pageDraw[telPageSelected](event)
if event == EVT_VIRTUAL_EXIT then
if (telPageSelected==0) then return 1 end -- on Main?? Exit Script
telPageSelected = 0 -- any page, return to Main
end
return 0
end
local function init_func()
if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens
TEXT_SIZE = SMLSIZE
X_COL1_HEADER = 0
X_COL1_DATA = 20
X_COL2_HEADER = 60
X_COL2_DATA = 90
X_DATA_LEN = 28
X_DATA_SPACE = 1
Y_LINE_HEIGHT = 8
Y_DATA = Y_HEADER + Y_LINE_HEIGHT
end
end
return { run=run_func, init=init_func }

View File

@ -35,6 +35,7 @@
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
@ -53,10 +54,9 @@
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
28,6,Flysky_AFHDS2A,PWM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
28,7,Flysky_AFHDS2A,PPM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
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
@ -86,7 +86,11 @@
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,FX816,Std,1
58,0,FX,816,1
58,1,FX,620,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
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
@ -106,6 +110,7 @@
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
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
@ -116,9 +121,11 @@
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
49,0,KF606,KF606,1,Trim
49,1,KF606,MIG320,1,Trim,LED
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
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
@ -126,14 +133,16 @@
18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
17,5,MT99XX,A180,0,3D_6G
17,6,MT99XX,Dragon,0,Mode,RTH
17,7,MT99XX,F949G,0,6G_3D,Light
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
@ -152,7 +161,8 @@
74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
74,2,RadioLink,DumboRC,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,UNK
74,3,RadioLink,RC4G,0,CH5,FS_CH1,FS_CH2,FS_CH3,FS_CH4
76,0,Realacc,Std,1,Flip,Light,Calib,HLess,RTH,ThCut,Rotat
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
@ -163,14 +173,17 @@
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
61,0,Tiger,Std,1,Flip,Light
43,0,Traxxas,6519,0
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
48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn
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
@ -181,7 +194,10 @@
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
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
99,1,XK2,P10,0,Rate,Mode,Hover,Light
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
@ -194,12 +210,28 @@
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
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,Analog,0
90,1,MouldKg,Digit,0
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
92,0,MT99xx2,PA18,0,MODE,FLIP,RTH
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

View File

@ -257,7 +257,7 @@ local function Multi_Init()
stick_names[4] = "Aux3"
elseif ( protocol == 48 and sub_protocol == 0 ) then -- V761 3CH
stick_names[4] = "n-a"
elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816
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

View File

@ -135,10 +135,14 @@ local function Config_Draw_Edit( event )
Edit = 0
elseif event == EVT_VIRTUAL_PREV then
-- Change value
Menu_value[Edit_pos] = Menu_value[Edit_pos] - 1
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
Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1
if Menu_value[Edit_pos] < 255 then
Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1
end
end
--Blink
Blink = Blink + 1
@ -319,9 +323,6 @@ local function Config_Draw_Menu()
--Read line from buffer
for i = 0, 20-1, 1 do
value=multiBuffer( line*20+13+i )
if value == 0 then
break -- end of line
end
if value > 0x80 and Menu[line].field_type == 0 then
-- Read field type
Menu[line].field_type = bitand(value, 0xF0)
@ -334,6 +335,9 @@ local function Config_Draw_Menu()
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

View File

@ -58,17 +58,11 @@ This is the Graupner HoTT adapted version of the Model Locator script using RSSI
The OpenTX sensor "RSSI" is populated by the individual OpenTX telemetry protocol implementations and returns a value from 0..100 (percent) originating from the early FrSky implementation. It turns out that FrSky did not really provide a genuine signal strength indicator in units of dbm but a link quality indicator in 0..100%. With Graupner HoTT the link quality indicator is not a good basis for the model locator as it is very non-linear and doesn't change much with distance. Using the Graupner HoTT telemetry sensor "Rssi" which is a true signal strength indicator serves the purpose of locating a model much better as it varies much more with distance.
## DSM Forward Programming
## DSM Tools for EdgeTX and OpenTx
Navigation is mainly done using the scroll wheel and ENT. Short press on ENT will edit a value. When editing a value a long ENT press will restore the value to its default. To exit the script and terminate all current operations correctly short press RTN (if you don't do this the RX might not store the changes).
Collection of EdgeTx/OpenTX Tools to use with Spektrum Receivers including forward programming. Located on the radio SD card under \SCRIPTS\TOOLS, make sure to copy the DSMLIB folder!
This is a work in progress. It's only available for color screens (Horus, TX16S, T16, T18...).
If some text appears as Unknown_xxx, please report xxx and what the exact text display should be.
Need OpenTX 2.3.10 nightly or above. Located on the radio SD card under \SCRIPTS\TOOLS.
[![DSM Forward Programming](https://img.youtube.com/vi/sjIaDw5j9nE/0.jpg)](https://www.youtube.com/watch?v=sjIaDw5j9nE)
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

View File

@ -418,10 +418,10 @@ void A7105_Init(void)
#ifdef KYOSHO_A7105_INO
if(protocol==PROTO_KYOSHO)
{
if(sub_protocol==KYOSHO_FHSS)
A7105_Regs=(uint8_t*)KYOSHO_A7105_regs;
else
if(sub_protocol==KYOSHO_HYPE)
A7105_Regs=(uint8_t*)KYOSHO_HYPE_A7105_regs;
else //FHSS && SYNCRO
A7105_Regs=(uint8_t*)KYOSHO_A7105_regs;
}
#endif
}
@ -446,7 +446,7 @@ void A7105_Init(void)
}
A7105_Strobe(A7105_STANDBY);
if(protocol==PROTO_KYOSHO && sub_protocol==KYOSHO_FHSS)
if(protocol==PROTO_KYOSHO && sub_protocol!=KYOSHO_HYPE)
{//strange calibration...
//IF Filter Bank Calibration
A7105_WriteReg(A7105_02_CALC,0x0F);

View File

@ -183,8 +183,18 @@ uint16_t AFHDS2A_RX_callback()
case AFHDS2A_RX_DATA:
if (AFHDS2A_RX_data_ready()) {
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
if (memcmp(&packet[1], rx_id, 4) == 0 && memcmp(&packet[5], rx_tx_addr, 4) == 0) {
if (packet[0] == 0x58 && packet[37] == 0x00 && (telemetry_link&0x7F) == 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();

View File

@ -93,15 +93,16 @@ 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]);
#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
@ -186,16 +187,40 @@ static void AFHDS2A_build_packet(uint8_t type)
case AFHDS2A_PACKET_STICKS:
packet[0] = 0x58;
//16 channels + RX_LQI on channel 17
for(uint8_t ch=0; ch<num_ch; ch++)
for(uint8_t ch=0; ch<17; ch++)
{
if(ch == 16 // CH17=RX_LQI
#ifdef AFHDS2A_LQI_CH
|| ch == (AFHDS2A_LQI_CH-1) // override channel with LQI
#endif
)
val = 2000 - 10*RX_LQI;
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
val = convert_channel_ppm(CH_AETR[ch]);
{
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;
}
break;
case AFHDS2A_PACKET_FAILSAFE:
packet[0] = 0x56;
for(uint8_t ch=0; ch<16; ch++)
{ // Failsafe values
#ifdef FAILSAFE_ENABLE
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
val = 0x0FFF;
if(ch<14)
{
packet[9 + ch*2] = val;
@ -209,42 +234,6 @@ static void AFHDS2A_build_packet(uint8_t type)
}
}
break;
case AFHDS2A_PACKET_FAILSAFE:
packet[0] = 0x56;
for(uint8_t ch=0; ch<num_ch; ch++)
{
#ifdef FAILSAFE_ENABLE
if(ch<16)
val = Failsafe_data[CH_AETR[ch]];
else
val = FAILSAFE_CHANNEL_NOPULSES;
if(val!=FAILSAFE_CHANNEL_HOLD && val!=FAILSAFE_CHANNEL_NOPULSES)
{ // Failsafe values
val = (((val<<2)+val)>>3)+860;
if(ch<14)
{
packet[9 + ch*2] = val;
packet[10 + ch*2] = (val>>8)&0x0F;
}
else
{
packet[10 + (ch-14)*6] &= 0x0F;
packet[10 + (ch-14)*6] |= (val)<<4;
packet[12 + (ch-14)*6] &= 0x0F;
packet[12 + (ch-14)*6] |= (val)&0xF0;
packet[14 + (ch-14)*6] &= 0x0F;
packet[14 + (ch-14)*6] |= (val>>4)&0xF0;
}
}
else
#endif
if(ch<14)
{ // no values
packet[9 + ch*2] = 0xff;
packet[10+ ch*2] = 0xff;
}
}
break;
case AFHDS2A_PACKET_SETTINGS:
packet[0] = 0xaa;
packet[9] = 0xfd;
@ -253,17 +242,43 @@ 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;
packet[13] = sub_protocol & 0x01; // 1 -> PPM output enabled
packet[14]= 0x00;
for(uint8_t i=15; i<37; i++)
packet[i] = 0xff;
packet[18] = 0x05; // ?
packet[19] = 0xdc; // ?
packet[20] = 0x05; // ?
if(sub_protocol&2)
packet[21] = 0xdd; // SBUS 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[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;
@ -283,6 +298,9 @@ uint16_t AFHDS2A_callback()
static uint16_t packet_counter;
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
@ -292,10 +310,17 @@ uint16_t AFHDS2A_callback()
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))) // removed FECF check due to issues with fs-x6b -> & (1<<5 | 1<<6)
{ // 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)
{
uint16_t addr;
@ -330,7 +355,7 @@ uint16_t AFHDS2A_callback()
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++;
@ -360,10 +385,39 @@ uint16_t AFHDS2A_callback()
AFHDS2A_build_packet(packet_type);
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
@ -441,9 +495,6 @@ void AFHDS2A_init()
rx_id[i]=eeprom_read_byte((EE_ADDR)(addr+i));
}
hopping_frequency_no = 0;
if(sub_protocol&0x04)
num_ch=17;
else
num_ch=14;
packet_sent = 0;
}
#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

@ -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

@ -195,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)
@ -249,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
@ -269,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(protocol==PROTO_LOSI?i|1: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
@ -298,7 +303,7 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin
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},
@ -311,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,
@ -321,6 +326,7 @@ 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
@ -328,8 +334,13 @@ const uint8_t PROGMEM DEVO_j6pro_sopcodes[][8] = {
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);
}

View File

@ -4,9 +4,45 @@
uint8_t sop_col;
const uint8_t PROGMEM DSM_pncodes[5][9][8] = {
const uint8_t PROGMEM DSM_pncodes[][8] = {
/* Note these are in order transmitted (LSB 1st) */
{ /* Row 0 */
/* 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},
@ -16,59 +52,15 @@ const uint8_t PROGMEM DSM_pncodes[5][9][8] = {
/* 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)
static void __attribute__((unused)) DSM_read_code(uint8_t *buf, uint8_t row, uint8_t col)
{
for(uint8_t i=0;i<len;i++)
buf[i]=pgm_read_byte_near( &DSM_pncodes[row][col][i] );
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] = {
@ -137,11 +129,11 @@ static void __attribute__((unused)) DSM_set_sop_data_crc(bool ch2, bool dsmx)
debug_time();
debug(" crc:%04X,row:%d,col:%d,rf:%02X",(~seed)&0xffff,pn_row,sop_col,hopping_frequency[hopping_frequency_no]);
#endif
DSM_read_code(code,pn_row,sop_col,8); // pn_row between 0 and 4, sop_col between 1 and 7
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,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);
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++;

View File

@ -39,8 +39,8 @@ static void __attribute__((unused)) DSM_RX_RF_init()
{
//64 SDR Mode is configured so only the 8 first values are needed but need to write 16 values...
uint8_t code[16];
DSM_read_code(code,0,8,8);
CYRF_ConfigDataCode(code, 16);
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
@ -214,6 +214,15 @@ 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:
@ -240,10 +249,14 @@ uint16_t DSM_RX_callback()
{
// store tx info into eeprom
uint16_t temp = DSM_RX_EEPROM_OFFSET;
debug("ID=");
for(uint8_t i=0;i<4;i++)
{
cyrfmfg_id[i]=packet_in[i]^0xFF;
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]);
}
@ -254,6 +267,7 @@ uint16_t DSM_RX_callback()
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
@ -264,7 +278,7 @@ uint16_t DSM_RX_callback()
eeprom_write_byte((EE_ADDR)temp, DSM_rx_type);
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
CYRF_SetTxRxMode(TX_EN); // Force end state TX
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84", 16);
CYRF_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;
@ -303,6 +317,14 @@ uint16_t DSM_RX_callback()
{
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:
@ -470,20 +492,34 @@ void DSM_RX_init()
if (IS_BIND_IN_PROGRESS)
{
packet_count=0;
phase = DSM_RX_BIND1;
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)temp);
DSM_rx_type=eeprom_read_byte((EE_ADDR)DSM_RX_EEPROM_OFFSET+4);
debugln(", type=%02X", DSM_rx_type);
phase = DSM_RX_DATA_PREP;
}
}

View File

@ -18,14 +18,21 @@
#include "iface_cyrf6936.h"
//#define DSM_DEBUG_FWD_PGM
//#define DEBUG_BIND 1
//#define DSM_GR300
#define CLONE_BIT_MASK 0x20
#define DSM_BIND_CHANNEL 0x0D //13 This can be any odd channel
#define DSM2_SFC_PERIOD 16500
#define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel
//During binding we will send BIND_COUNT/2 packets
//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,
@ -87,9 +94,12 @@ static void __attribute__((unused)) DSM_build_bind_packet()
packet[11] = 12;
else
packet[11] = num_ch; // DX5 DSMR sends 0x48...
//packet[11] = 3; // DX3R
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)
@ -102,7 +112,6 @@ static void __attribute__((unused)) DSM_build_bind_packet()
#endif
else // DSMX_2F && DSM_AUTO
packet[12] = 0xb2; // DSMX/2048 2 packets
packet[13] = 0x00; //???
for(i = 8; i < 14; i++)
@ -116,8 +125,8 @@ 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...
uint8_t code[16];
DSM_read_code(code,0,8,8);
CYRF_ConfigDataCode(code, 16);
DSM_read_code(code,0,8);
CYRF_ConfigDataCode(code);
DSM_build_bind_packet();
}
@ -129,8 +138,13 @@ static void __attribute__((unused)) DSM_update_channels()
if(num_ch<3 || num_ch>12)
num_ch=6; // Default to 6 channels if invalid choice...
if(sub_protocol==DSMR && num_ch>7)
num_ch=7; // Max 7 channels in DSMR
#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-3;
@ -143,7 +157,13 @@ 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();
@ -160,19 +180,25 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
bits=10; // Only DSM2_1F is using a resolution of 1024
}
if(sub_protocol == DSMR)
{
for (uint8_t i = 0; i < 7; i++)
{
uint16_t value = 0x0000;
if(i < num_ch)
value=Channel_data[i]<<1;
packet[i*2+2] = (value >> 8) & 0xff;
packet[i*2+3] = (value >> 0) & 0xff;
#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;
}
return;
}
#endif
#ifdef DSM_THROTTLE_KILL_CH
uint16_t kill_ch=Channel_data[DSM_THROTTLE_KILL_CH-1];
#endif
@ -249,24 +275,34 @@ static uint8_t __attribute__((unused)) DSM_Check_RX_packet()
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;
#ifdef DSM_GR300
uint16_t timing=5000+(convert_channel_8b(CH13)*100);
debugln("T=%u",timing);
#endif
//debugln("P=%d",phase);
switch(phase)
{
case DSM_BIND_WRITE:
@ -280,11 +316,14 @@ uint16_t DSM_callback()
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", 16);
#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=2*DSM_BIND_COUNT; //Timeout of 4.2s if no packet received
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:
@ -300,10 +339,12 @@ uint16_t DSM_callback()
CYRF_ReadDataPacketLen(packet_in+1, 10);
if(DSM_Check_RX_packet())
{
debug("Bind");
for(uint8_t i=0;i<10;i++)
debug(" %02X",packet_in[i+1]);
debugln("");
#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;
@ -328,6 +369,9 @@ uint16_t DSM_callback()
}
if( --bind_counter == 0 )
{ // Exit if no answer has been received for some time
#if DEBUG_BIND
debugln("Bind Read TIMEOUT");
#endif
phase++; // DSM_CHANSEL
return 7000 ;
}
@ -339,25 +383,38 @@ uint16_t DSM_callback()
CYRF_SetTxRxMode(TX_EN);
hopping_frequency_no = 0;
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:
CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags
CYRF_WriteDataPacket(packet);
//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]);
@ -394,41 +451,52 @@ uint16_t DSM_callback()
phase++; // change from CH2_CHECK to CH2_READ
CYRF_SetTxRxMode(RX_EN); //Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
if(sub_protocol==DSMR)
{
phase = DSM_CH2_READ_B;
return 11000 - DSM_WRITE_DELAY - DSM_READ_DELAY;
}
#ifdef DSM_GR300
if(num_ch==3)
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
#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<len;i++)
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_1F || sub_protocol==DSMX_1F) && num_ch < 8) // 22ms mode
{
@ -436,10 +504,6 @@ uint16_t DSM_callback()
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
phase = DSM_CH2_READ_B;
#ifdef DSM_GR300
if(num_ch==3)
return timing;
#endif
return 11000;
}
if (phase == DSM_CH2_READ_A)
@ -460,19 +524,20 @@ uint16_t DSM_callback()
else
{ //Normal mode 22ms
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
#ifdef DSM_GR300
if(num_ch==3)
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
#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 ;
}
}
else
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower)
#ifdef DSM_GR300
if(num_ch==3)
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
#endif
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY;
#endif
}
@ -480,6 +545,7 @@ uint16_t DSM_callback()
}
#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 },
@ -503,32 +569,73 @@ const uint8_t PROGMEM DSMR_ID_FREQ[][4 + 23] = {
{ 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()
{
if(sub_protocol == DSMR)
{
uint8_t row = rx_tx_addr[3]%22;
for(uint8_t i=0; i< 4; i++)
cyrfmfg_id[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i]);
for(uint8_t i=0; i< 23; i++)
hopping_frequency[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i+4]);
#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
{
CYRF_GetMfgData(cyrfmfg_id);
//Model match
cyrfmfg_id[3]^=RX_num;
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++);
#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);
//Model match
cyrfmfg_id[3]^=RX_num;
}
}
//Calc sop_col
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
//Fix for OrangeRX using wrong DSM_pncodes by preventing access to "Col 8"
if(sop_col==0 && 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;
//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
@ -540,7 +647,7 @@ void DSM_init()
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];
@ -564,9 +671,12 @@ void DSM_init()
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;//
phase = DSM_CHANSEL;
}
#endif

View File

@ -365,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];
}

View File

@ -41,7 +41,8 @@ static void __attribute__((unused)) E129_build_data_packet()
}
else
{
packet[ 1] = 0xA6;
packet[ 1] = 0xA6; // Set to A5 every few packets??
//Flags
if(sub_protocol == E129_E129)
packet[ 2] = 0xF7; // High rate 0xF7, low 0xF4
@ -53,9 +54,18 @@ static void __attribute__((unused)) E129_build_data_packet()
packet[15] = bit_reverse(rx_tx_addr[0]);
packet[16] = bit_reverse(rx_tx_addr[1]);
}
//packet[ 3] = 0x00; // E129 Mode: short press=0x20->0x00->0x20->..., long press=0x10->0x30->0x10->... => C186 throttle trim is doing the same:up=short press and down=long press
packet[ 4] = GET_FLAG(CH5_SW, 0x20) // Take off/Land 0x20
| GET_FLAG(CH6_SW, 0x04); // Emergency stop 0x04
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;
@ -80,13 +90,11 @@ static void __attribute__((unused)) E129_build_data_packet()
packet[12] = val; // channel (0x000...0x200...0x3FF)
}
//Check
if(sub_protocol == E129_E129)
packet[packet_length-2] = packet[0] + packet[1];
else
packet[packet_length-2] = 0x24 + packet[0] + (packet[1]&0x03); // ??
for(uint8_t i=2;i<packet_length-2;i++)
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);
}

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

@ -1,100 +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_xn297.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()
{
if(IS_BIND_IN_PROGRESS)
packet[0] = 0x55;
else
{
XN297_Hopping(hopping_frequency_no++);
hopping_frequency_no%=FX816_RF_NUM_CHANNELS;
packet[0] = 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;
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, FX816_PAYLOAD_SIZE);
}
static void __attribute__((unused)) FX816_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
//XN297_HoppingCalib(FX816_RF_NUM_CHANNELS);
XN297_RFChannel(FX816_RF_BIND_CHANNEL);
}
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(bind_counter)
if(--bind_counter==0)
BIND_DONE;
FX816_send_packet();
return FX816_PACKET_PERIOD;
}
void FX816_init()
{
BIND_IN_PROGRESS; // autobind protocol
FX816_initialize_txid();
FX816_RF_init();
hopping_frequency_no = 0;
bind_counter=FX816_BIND_COUNT;
}
#endif

View File

@ -0,0 +1,337 @@
/*
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 FORCE_FX620_ID
//#define FORCE_FX9630_ID
//#define FORCE_QIDI_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
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
trim_ch = 0;
}
}
else // FX816 & FX620
{
hopping_frequency_no &= 0x03;
}
}
memset(packet,0x00,packet_length);
//Channels
uint8_t val;
if (sub_protocol >= FX9630)
{ // FX9630 & FX_Q560 & FX_QF012
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);
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 // FX816 & FX620
{
uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET;
val=convert_channel_8b(AILERON);
if(val>127+FX_SWITCH)
packet[offset] = sub_protocol == FX816 ? 1:0xFF;
else if(val<127-FX_SWITCH)
packet[offset] = sub_protocol == FX816 ? 2:0x00;
else
packet[offset] = sub_protocol == FX816 ? 0:0x7F;
packet[offset+1] = convert_channel_16b_limit(THROTTLE,0,100); //FX816:0x00..0x63, FX620:0x00..0x5E but that should work
}
//Bind and specifics
if(sub_protocol == FX816)
{
if(IS_BIND_IN_PROGRESS)
packet[0] = 0x55;
else
packet[0] = 0xAA;
packet[1] = rx_tx_addr[0];
packet[2] = rx_tx_addr[1];
}
else if(sub_protocol == FX620)
{
if(IS_BIND_IN_PROGRESS)
{
memcpy(packet,rx_tx_addr,3);
packet[3] = hopping_frequency[0];
if(bind_counter > (FX_BIND_COUNT >> 1))
packet[5] = 0x78;
}
else
{
packet[0] = 0x1F; // Is it based on ID??
packet[5] = 0xAB; // Is it based on ID??
}
}
else // FX9630 & FX_Q560 & FX_QF012
{
if(IS_BIND_IN_PROGRESS)
{
memcpy(packet,rx_tx_addr, 4);
packet[4] = hopping_frequency[1];
packet[5] = hopping_frequency[2];
packet[7] = 0x55;
}
}
//Check
uint8_t last_packet_idx = packet_length-1;
if (sub_protocol >= FX9630 && IS_BIND_IN_PROGRESS)
last_packet_idx--;
val=0;
for(uint8_t i=0;i<last_packet_idx;i++)
val+=packet[i];
if (sub_protocol >= FX9630)
val = val ^ 0xFF;
packet[last_packet_idx]=val;
//Debug
#if 0
for(uint8_t i=0;i<packet_length;i++)
debug("%02X ",packet[i]);
debugln("");
#endif
// Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, packet_length);
}
static void __attribute__((unused)) FX_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
if(sub_protocol == FX816)
{
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
XN297_RFChannel(FX816_BIND_CHANNEL);
packet_period = FX816_PACKET_PERIOD;
packet_length = FX816_PAYLOAD_SIZE;
}
else if(sub_protocol == FX620)
{
XN297_SetTXAddr((uint8_t *)"\xaa\xbb\xcc", 3);
XN297_RFChannel(FX620_BIND_CHANNEL);
packet_period = FX620_BIND_PACKET_PERIOD;
packet_length = FX620_PAYLOAD_SIZE;
}
else // FX9630 & 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;
packet_length = FX9630_PAYLOAD_SIZE;
}
}
static void __attribute__((unused)) FX_initialize_txid()
{
if(sub_protocol == FX816)
{
//Only 8 IDs: the RX led does not indicate frame loss.
//I didn't open the plane to find out if I could connect there so this is the best I came up with with few trial and errors...
rx_tx_addr[0]=0x35+(rx_tx_addr[3]&0x07); //Original dump=0x35
rx_tx_addr[1]=0x09; //Original dump=0x09
memcpy(hopping_frequency,"\x09\x1B\x30\x42",FX_NUM_CHANNELS); //Original dump=9=0x09,27=0x1B,48=0x30,66=0x42
for(uint8_t i=0;i<FX_NUM_CHANNELS;i++)
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
}
else if(sub_protocol == FX620)
{
rx_tx_addr[0] = rx_tx_addr[3];
hopping_frequency[0] = 0x18 + rx_tx_addr[3]&0x07; // just to try something
#ifdef FORCE_FX620_ID
memcpy(rx_tx_addr,(uint8_t*)"\x34\xA9\x32",3);
hopping_frequency[0] = 0x18; //on dump: 24 34 44 54
#endif
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
hopping_frequency[i] = i*10 + hopping_frequency[0];
}
else // FX9630 & FX_Q560 & FX_QF012
{
//??? Need to find out how the first RF channel is calculated ???
hopping_frequency[0] = 0x13;
//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
}
}
uint16_t FX_callback()
{
#ifdef FX_HUB_TELEMETRY
bool rx=false;
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 < FX9630)
break;
if(rx)
{
debug("RX");
if(XN297_ReadPayload(packet_in, FX_QF012_RX_PAYLOAD_SIZE))
{//Good CRC
//packets: A5 00 11 -> A5 01 11
telemetry_link = 1;
v_lipo1 = packet_in[1] ? 60:81; // 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();
}
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
phase = FX_DATA;
#endif
}
#endif

View File

@ -51,9 +51,9 @@ static void __attribute__((unused)) FrSkyX_build_bind_packet()
//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
//Unknown bytes
if(state & 0x01)
memcpy(&packet[7],"\x00\x18\x0A\x00\x00\xE0\x02\x0B\x01\xD3\x08\x00\x00\x4C\xFE\x87\xC7",17);
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\xAD\x02\x00\x00\x64\xC8\x46\x00\x64\x00\x00\x00\xFB\xF6\x87\xC7",17);
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;
@ -63,8 +63,9 @@ static void __attribute__((unused)) FrSkyX_build_bind_packet()
if(binding_idx&0x02)
packet[7] |= 0x80; // CH9-16
//Replace the ID
packet[20] ^= 0x0E ^ rx_tx_addr[3]; // Update the ID
packet[21] ^= 0x1C ^ rx_tx_addr[2]; // Update 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_length-1; i++)
packet[i] ^= 0xA7;
@ -100,7 +101,7 @@ static void __attribute__((unused)) FrSkyX_build_packet()
FrSkyX_channels(7); // Set packet[7]=failsafe, packet[8]=0?? and packet[9..20]=channels data
//Sequence and send SPort
FrSkyX_seq_sport(21,packet_length-2); //21=RX|TXseq, 22=bytes count, 23..packet_length-2=data
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_length-4);
@ -116,6 +117,10 @@ static void __attribute__((unused)) FrSkyX_build_packet()
uint16_t FRSKYX_callback()
{
#if defined MULTI_EU
if(sub_protocol == CH_16 || sub_protocol == CH_8)
return 9000;
#endif
switch(state)
{
default:

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

@ -66,8 +66,10 @@ static void __attribute__((unused)) HISKY_RF_init()
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
#endif
}
// HiSky channel sequence: AILE ELEV THRO RUDD GEAR PITCH, channel data value is from 0 to 1000
@ -92,6 +94,13 @@ static void __attribute__((unused)) HISKY_build_ch_data()
uint16_t HISKY_callback()
{
phase++;
#ifdef MULTI_AIR
if(sub_protocol==HK310)
{
SUB_PROTO_INVALID;
return 10000;
}
#else
if(sub_protocol==HK310)
switch(phase)
{
@ -132,6 +141,7 @@ uint16_t HISKY_callback()
phase=8;
break;
}
#endif
switch(phase)
{
case 1:
@ -195,6 +205,7 @@ uint16_t HISKY_callback()
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.
@ -204,10 +215,11 @@ static void __attribute__((unused)) HISKY_initialize_tx_id()
hopping_frequency[i]=hopping_frequency_no++; // Sequential order hop channels...
}
else
calc_fh_channels(HISKY_FREQUENCE_NUM);
#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);
}
void HISKY_init()

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