Compare commits

...

157 Commits

Author SHA1 Message Date
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
106 changed files with 10033 additions and 5163 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-devel:avr:multiatmega328p:bootloader=none",
"multi4in1-devel:avr:multiatmega328p:bootloader=optiboot",
"multi4in1-devel:avr:multixmega32d4",
"multi4in1-devel:STM32F1:multi5in1t18int",
"multi4in1-devel:STM32F1:multistm32f103cb:debug_option=none",
"multi4in1-devel:STM32F1:multistm32f103cb:debug_option=native",
"multi4in1-devel:STM32F1:multistm32f103cb:debug_option=ftdi",
"multi4in1-devel: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@v1.1.2
with:
version: "0.32.2"
- name: Prepare build environment
run: |
@@ -149,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: |
@@ -173,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@v1.1.2
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;
@@ -187,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,549 +0,0 @@
local toolName = "TNS|DSM Forward Prog v0.54 (Text B&W) |TNE"
local VERSION = "v0.54"
---- #########################################################################
---- # #
---- # 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 = false -- FALSE: don't show simulation menu (DEFAULT), 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 DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON)
local PHASE = dsmLib.PHASE
local LINE_TYPE = dsmLib.LINE_TYPE
local DISP_ATTR = dsmLib.DISP_ATTR
local DSM_Context = dsmLib.DSM_Context
local IS_EDGETX = false -- DEFAULT until Init changed it
local LCD_W_USABLE = LCD_W-10
-- X for Menu Lines
local LCD_X_LINE_MENU = 10
-- X offsets for (Title: [Value] debugInfo) lines
local LCD_X_LINE_TITLE = 10
local LCD_X_LINE_VALUE = 230
local LCD_X_LINE_DEBUG = 390
-- Line Height: make it smaller debugging info tp LCD (some space buttom)
local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27
-- Y offsets
local LCD_Y_MENU_TITLE = 20
-- Y offet
local LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 30
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT
local LCD_W_BUTTONS = 47
local LCD_H_BUTTONS = 25
local LCD_X_RIGHT_BUTTONS = LCD_W - LCD_W_BUTTONS - 5
local TEXT_SIZE = 0 -- NORMAL
local lastRefresh=0 -- Last time the screen was refreshed
local REFRESH_GUI_MS = 500/10 -- 500ms.. Screen Refresh Rate.. to not use unneded CPU time (in 10ms units to be compatible with getTime())
local originalValue = nil
local warningScreenON = true
------------------------------------------------------------------------------------------------------------
local function GUI_SwitchToRX()
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
local dsmChannelInfo, description = dsmLib.CreateDSMPortChannelInfo()
dsmLib.ReleaseConnection()
dsmLib.LOG_close()
SIMULATION_ON = false
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
DSM_Context = dsmLib.DSM_Context
dsmLib.Init(toolName) -- Initialize Library
dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library
dsmLib.StartConnection()
DSM_Context.Refresh_Display = true
end
local function GUI_SwitchToSIM()
dsmLib.ReleaseConnection()
dsmLib.LOG_close()
SIMULATION_ON = true
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
DSM_Context = dsmLib.DSM_Context
dsmLib.Init(toolName) -- Initialize Library
dsmLib.StartConnection()
DSM_Context.Refresh_Display = true
end
local function openTx_lcd_sizeText(s)
return string.len(s)*5
end
local function GUI_Diplay_Button(x,y,w,h,text,selected)
local attr = (selected) and INVERS or 0 -- INVERS if line Selected
if (TEXT_SIZE~=SMLSIZE) then
lcd.drawText(x+5,y+2, text, attr + TEXT_SIZE)
lcd.drawRectangle(x, y, w, h, LINE_COLOR)
else -- SMALL Screen
lcd.drawText(x,y, text, attr + TEXT_SIZE)
end
end
local function GUI_Display_Menu(menu)
local ctx = DSM_Context
local w= LCD_W_USABLE - LCD_W_BUTTONS - 10 -- usable Width for the Menu/Lines
-- Center Header
local tw = openTx_lcd_sizeText(menu.Text)
local x = w/2 - tw/2 -- Center of Screen - Center of Text
if (x < 0) then x=0 end -- in case text is too wide
local bold = BOLD
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text,bold + TEXT_SIZE)
-- Back
if menu.BackId ~= 0 then
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_MENU_TITLE,LCD_W_BUTTONS,LCD_H_BUTTONS,"Back",ctx.SelLine == dsmLib.BACK_BUTTON)
end
-- Next ?
if menu.NextId ~= 0 then
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON)
end
-- Prev?
if menu.PrevId ~= 0 then
GUI_Diplay_Button(0,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON)
end
-- Debug into LCD
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),TEXT_SIZE + WARNING_COLOR) end -- Phase we are in
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_MENU,240,dsmLib.menu2String(menu),TEXT_SIZE + WARNING_COLOR) end -- Menu Info
end
local function GUI_Display_Line_Menu(x,y,w,h,line,selected)
local attr = (selected and INVERS) or 0 -- INVERS if line Selected
local bold = 0
local text = line.Text
if dsmLib.isSelectableLine(line) then
-- Menu Line
text = text .. " >"
else -- SubHeaders and plain text lines
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
local tw = openTx_lcd_sizeText(line.Text)+4
x = LCD_X_LINE_VALUE - tw -- Right
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
local tw = openTx_lcd_sizeText(line.Text)
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
end
if (x < 0) then x=0 end -- in case text is too wide
end
lcd.drawText(x,y, text, attr + bold + TEXT_SIZE)
end
------------------------------------------------------------------------------------------------------------
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
local bold = 0
local y = LCD_Y_LINE_FIRST+(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 (dsmLib.isFlightModeLine(line)) then
-- Display Header + Value together
header = dsmLib.GetFlightModeValue(line)
-- Flight mode display attributes
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
local tw = openTx_lcd_sizeText(header)+4
x = LCD_X_LINE_VALUE - tw -- Right
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
local tw = openTx_lcd_sizeText(header)
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
end
if (x < 0) then x=0 end -- in case text is too wide
else
-- No Flight Mode, no effects here
header = header .. ":"
end
lcd.drawText(x, y, header, bold + TEXT_SIZE) -- display Line Header
--------- VALUE PART, Skip for Flight Mode since already show the value
if not dsmLib.isFlightModeLine(line) then
local attrib = 0
if selected then
attrib = INVERS
if editing then -- blink editing entry
attrib = attrib + BLINK
value = "[" .. value .. "]"
end
end
value = value .. " " .. (line.Format or "") -- Append % if needed
lcd.drawText(LCD_X_LINE_VALUE,y, value, attrib + TEXT_SIZE) -- display value
end
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG,y, line.MinMaxDebug or "", TEXT_SIZE + WARNING_COLOR) end -- display debug
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()
if (LCD_W > 128) then
lcd.drawText(x, y, imgMsg or "", TEXT_SIZE) -- Alternate Image MSG
else
local f = string.gmatch(imgMsg, '([^%:]+)') -- Iterator over values split by ':'
local msg1,msg2 = f(), f()
lcd.drawText(x, y, (msg1 or "")..":", TEXT_SIZE) -- Alternate Image MSG
lcd.drawText(x, y+10, msg2 or "", TEXT_SIZE) -- Alternate Image MSG
end
-- NO IMAGES in Text B&W
--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()
local header = "DSM Fwrd Programming "
if (TEXT_SIZE==SMLSIZE) then -- Small Screen no title
header = ""
end
if ctx.Phase ~= PHASE.RX_VERSION then
header = header .. ctx.RX.Name.." v"..ctx.RX.Version
end
--Draw title
if (TEXT_SIZE~=SMLSIZE) then -- ignore tool title small size screens
lcd.drawFilledRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR)
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
else -- Small Screen
lcd.drawText(20, LCD_Y_LOWER_BUTTONS+1, header, TEXT_SIZE)
end
--Draw RX Menu
if ctx.Phase == PHASE.RX_VERSION then
if (ctx.isReset) then
lcd.drawText(LCD_X_LINE_TITLE,50,dsmLib.Get_Text(0x301), BLINK + TEXT_SIZE) -- Resetting
else
lcd.drawText(LCD_X_LINE_TITLE,50,dsmLib.Get_Text(0x300), BLINK + TEXT_SIZE) -- Waiting for RX Version
end
else
local menu = ctx.Menu
if menu.Text ~= nil then
GUI_Display_Menu(menu)
for i = 0, dsmLib.MAX_MENU_LINES do
local line = ctx.MenuLines[i]
if i == ctx.SelLine then
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_TITLE,255,dsmLib.menuLine2String(line),TEXT_SIZE + WARNING_COLOR) end
end
if line ~= nil and line.Type ~= 0 then
if line.Type == LINE_TYPE.MENU then
-- Menu Line
GUI_Display_Line_Menu(LCD_X_LINE_MENU,LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*i), 350, LCD_Y_LINE_HEIGHT, line, i == ctx.SelLine)
else
-- list/value line
local value = line.Val
if line.Val ~= nil then
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_FIRST+LCD_Y_LINE_HEIGHT, imgData)
end
end
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
end
end -- if ~MENU
end -- if Line[i]~=nil
end -- for
end
end
end
-------------------------------------------------------------------------------------------------------------
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
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
------------------------------------------------------------------------------------------------------------
local function GUI_HandleEvent(event, touchState)
local ctx = DSM_Context
local menu = ctx.Menu
local menuLines = ctx.MenuLines
if event == EVT_VIRTUAL_EXIT then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.Phase == PHASE.RX_VERSION then
dsmLib.ReleaseConnection()
else
if ctx.isEditing() then -- Editing a Line, need to restore original value
ctx.MenuLines[ctx.EditLine].Val = originalValue
dsmLib.Value_Write_Validate(menuLines[ctx.EditLine])
else
dsmLib.ChangePhase(PHASE.EXIT) -- Exit
end
end
return
end
if event == EVT_VIRTUAL_NEXT then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then -- Editing a Line, need to inc the value
local line=ctx.MenuLines[ctx.EditLine]
dsmLib.Value_Add(line, GUI_RotEncVal(1))
else -- not editing, move selected line to NEXT
dsmLib.MoveSelectionLine(1)
end
return
end
if event == EVT_VIRTUAL_PREV then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then -- Editiing a line, need to dec the value
local line=ctx.MenuLines[ctx.EditLine]
dsmLib.Value_Add(line, GUI_RotEncVal(-1))
else -- not editing, move selected line to PREV
dsmLib.MoveSelectionLine(-1)
end
return
end
if event == EVT_VIRTUAL_ENTER_LONG then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then
-- reset the value to default
dsmLib.Value_Default( menuLines[ctx.EditLine]) -- Update RX value as needed
end
return
end
if event == EVT_VIRTUAL_ENTER then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
dsmLib.GotoMenu(menu.BackId,0x80)
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
dsmLib.GotoMenu(menu.NextId,0x82)
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
dsmLib.GotoMenu(menu.PrevId,0x81)
elseif menuLines[ctx.SelLine].ValId ~= 0 then
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Next menu exist
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()
else
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
end
else
-- Editing a Line????
if ctx.isEditing() then
-- Change the Value and exit edit
dsmLib.Value_Write_Validate(menuLines[ctx.SelLine])
else
-- enter Edit the current line
ctx.EditLine = ctx.SelLine
originalValue = menuLines[ctx.SelLine].Val
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
end
end
end
end
end
local function init_screen_pos()
-- 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 LCD_W == 480 then -- TX16
-- use defaults in the script header
elseif LCD_W == 128 then --TX12 (128x64) -- Still needs some work on the vertical
DEBUG_ON_LCD = false -- no space for this
TEXT_SIZE = SMLSIZE
LCD_W_USABLE = 128
LCD_W_BUTTONS = 16
LCD_H_BUTTONS = 10
LCD_X_RIGHT_BUTTONS = 128 - LCD_W_BUTTONS - 3
LCD_X_LINE_MENU = 0
-- X offsets for (Title: [Value] debugInfo) lines
LCD_X_LINE_TITLE = 0
LCD_X_LINE_VALUE = 75
LCD_X_LINE_DEBUG = 110
LCD_Y_LINE_HEIGHT = 7
LCD_Y_MENU_TITLE = 0
LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 8
LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + (7 * LCD_Y_LINE_HEIGHT)
end
end
local function GUI_Warning(event)
lcd.clear()
local header = "DSM Forward Programming "..VERSION.." "
--Draw title
if (LCD_W > 128) then
lcd.drawFilledRectangle(0, 0, LCD_W, 17, TITLE_BGCOLOR)
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
lcd.drawText(100,20,"INFO", BOLD)
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", TEXT_SIZE)
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", TEXT_SIZE)
lcd.drawText(5,80,"the TX before your start programming your RX.", TEXT_SIZE)
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", TEXT_SIZE)
lcd.drawText(5,150,"TX Servo settings are sent to the RX during 'Initial Setup'", TEXT_SIZE)
lcd.drawText(5,170,"as well as when using RX menu 'Relearn Servo Settings'", TEXT_SIZE)
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD+TEXT_SIZE)
lcd.drawText(100,250," OK ", INVERS + BOLD + TEXT_SIZE)
else
lcd.drawText(0,15,"Make sure you setup your plane", TEXT_SIZE)
lcd.drawText(0,22,"first. Wing and Tail type.", TEXT_SIZE)
lcd.drawText(0,30,"TX Servo settings are sent to ", TEXT_SIZE)
lcd.drawText(0,37,"the RX during 'Initial Setup' and ", TEXT_SIZE)
lcd.drawText(0,45,"ALWAYS TEST Gyro reactions", TEXT_SIZE)
lcd.drawText(0,52,"before flying!!!", TEXT_SIZE)
lcd.drawText(10,0," OK ", INVERS + BOLD + TEXT_SIZE)
end
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER then
warningScreenON = false
end
return 0
end
------------------------------------------------------------------------------------------------------------
-- Init
local function DSM_Init()
init_screen_pos()
dsmLib.Init(toolName) -- Initialize Library
return dsmLib.StartConnection()
end
------------------------------------------------------------------------------------------------------------
-- Main
local function DSM_Run(event)
local ctx = DSM_Context
if event == nil then
error("Cannot be run as a model script!")
dsmLib.LOG_close()
return 2
end
if (warningScreenON) then
return GUI_Warning(event)
end
GUI_HandleEvent(event)
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
local refreshInterval = REFRESH_GUI_MS
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
if (ctx.EditLine or (ctx.Phase == PHASE.RX_VERSION)) then -- Editing or Requesting RX Version?
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 500ms, 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
dsmLib.LOG_close()
return 2
else
return 0
end
end
return { init=DSM_Init, run=DSM_Run }

View File

@@ -1,5 +1,5 @@
local toolName = "TNS|DSM Forward Prog v0.54 (Color+Touch) |TNE"
local VERSION = "v0.54"
local toolName = "TNS|DSM Forward Prog v0.56 (Color) |TNE"
local VERSION = "v0.56"
---- #########################################################################
---- # #
@@ -27,19 +27,21 @@ local VERSION = "v0.54"
-- Rewrite/Enhancements By: Francisco Arzu
------------------------------------------------------------------------------
local SIMULATION_ON = false -- FALSE:don't show simulation memu (DEFAULT), TRUE: show simulation menu
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 DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
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 dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON)
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 = dsmLib.PHASE
local LINE_TYPE = dsmLib.LINE_TYPE
local DISP_ATTR = dsmLib.DISP_ATTR
local DSM_Context = dsmLib.DSM_Context
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
@@ -63,7 +65,7 @@ local LCD_X_LINE_DEBUG = 390
local LCD_Y_LINE_START = LCD_Y_MENU_TITLE + 30
local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27
local LCD_Y_LINE_HEIGHT = 27
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT)
@@ -93,6 +95,7 @@ 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
@@ -100,31 +103,76 @@ end
local function GUI_SwitchToRX()
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
local dsmChannelInfo, description = dsmLib.CreateDSMPortChannelInfo()
-- local dsmChannelInfo, description = modelLib.CreateDSMPortChannelInfo()
menuProcessor.done()
Log.LOG_close() -- Reset the log
Log.LOG_open()
menuProcessor = nil
collectgarbage("collect")
dsmLib.ReleaseConnection()
dsmLib.LOG_close()
modelLib.ReadTxModelData()
modelLib.ST_LoadFileData()
modelLib.CreateDSMPortChannelInfo()
SIMULATION_ON = false
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
DSM_Context = dsmLib.DSM_Context
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")
menuProcessor = dsmLib(Log, menuLib, modelLib, DEBUG_ON)
dsmLib.Init(toolName) -- Initialize Library
dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library
dsmLib.StartConnection()
dsmLib = nil
collectgarbage("collect")
menuProcessor.init(toolName) -- Initialize Library
DSM_Context.Refresh_Display = true
end
local function GUI_SwitchToSIM()
dsmLib.ReleaseConnection()
dsmLib.LOG_close()
menuProcessor.done()
Log.LOG_close()
SIMULATION_ON = true
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
DSM_Context = dsmLib.DSM_Context
menuProcessor = nil
collectgarbage("collect")
dsmLib.Init(toolName) -- Initialize Library
dsmLib.StartConnection()
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
@@ -203,19 +251,19 @@ local function GUI_Display_Line_Menu(lineNum,line,selected)
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
local x = LCD_X_LINE_MENU
if dsmLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes
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 = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
local bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
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 dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
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
@@ -235,17 +283,17 @@ local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
---------- NAME Part
local header = line.Text
-- ONLY do this for Flight Mode (Right Align or Centered)
if (dsmLib.isFlightModeLine(line)) then
if (menuLib.isFlightModeLine(line)) then
-- Display Header + Value together
header = dsmLib.GetFlightModeValue(line)
header = menuLib.GetFlightModeValue(line)
-- Bold Text???
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
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 dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
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
@@ -256,15 +304,18 @@ local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
lcd.drawText(x, y, header, txtColor + bold) -- display Line Header
--------- VALUE PART, Skip for Flight Mode since already show the value
if not dsmLib.isFlightModeLine(line) then
if dsmLib.isSelectableLine(line) then
--------- 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 dsmLib.isListLine(line))
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)
@@ -273,8 +324,6 @@ local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
end
end
-- Debug info for line Value RANGE when Debug on LCD
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG, y, line.MinMaxDebug or "", SMLSIZE + LCD_DEBUG_COLOR) end -- display debug Min/Max
end
local function GUI_Display_Menu(menu)
@@ -290,23 +339,19 @@ local function GUI_Display_Menu(menu)
-- 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 == dsmLib.BACK_BUTTON)
GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,dsmLib.BACK_BUTTON)
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 == dsmLib.NEXT_BUTTON)
GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.NEXT_BUTTON)
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 == dsmLib.PREV_BUTTON)
GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.PREV_BUTTON)
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
-- Debug on LCD, Show the menu Indo and Phase we are on
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),SMLSIZE+LCD_DEBUG_COLOR) end -- Phase we are in
if (DEBUG_ON_LCD) then lcd.drawText(0,240,dsmLib.menu2String(menu),SMLSIZE+LCD_DEBUG_COLOR) end -- Menu Info
end
------------------------------------------------------------------------------------------------------------
@@ -328,7 +373,7 @@ local function GUI_Display_Edit_Buttons(line)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT)
x=x+w+10
if (not dsmLib.isListLine(line)) then
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
@@ -342,7 +387,7 @@ local function GUI_Display_Edit_Buttons(line)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1)
x=x+w+10
if (not dsmLib.isListLine(line)) then
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
@@ -373,74 +418,86 @@ local function GUI_Display()
lcd.clear(LCD_TOOL_BGCOLOR)
GUI_clearTouchButtons()
if LCD_W == 480 then
local header = "DSM Forward Programming "..VERSION.." "
if ctx.Phase ~= PHASE.RX_VERSION then
header = header .. "RX "..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)
--Draw RX Menu
if ctx.Phase == PHASE.RX_VERSION then
if (ctx.isReset) then
lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x301), BLINK) -- Waiting for Restart
else
lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x300), BLINK) -- Waiting for RX
end
else
local menu = ctx.Menu
if menu.Text ~= nil then
GUI_Display_Menu(menu)
for i = 0, dsmLib.MAX_MENU_LINES do
local line = ctx.MenuLines[i]
if i == ctx.SelLine then
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
if (DEBUG_ON_LCD) then lcd.drawText(0,255,dsmLib.menuLine2String(line),SMLSIZE + LCD_DEBUG_COLOR) end
end
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
if line.Val ~= nil then
local value = line.Val
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
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
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
end
end -- if ~MENU
end -- if Line[i]~=nil
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
end
else
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(dir) -- return encoder speed to inc or dec values
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()
@@ -499,7 +556,7 @@ local function GUI_HandleEvent(event, touchState)
end
if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",dsmLib.phase2String(ctx.Phase),touchState.x, touchState.y) end
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
@@ -514,64 +571,73 @@ local function GUI_HandleEvent(event, touchState)
if event == EVT_VIRTUAL_EXIT then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_EXIT\n",menuLib.phase2String(ctx.Phase)) end
if ctx.Phase == PHASE.RX_VERSION then
dsmLib.ReleaseConnection() -- Just Exit the Script
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
dsmLib.Value_Write_Validate(line)
menuLib.Value_Write_Validate(line)
elseif (menu.BackId > 0 ) then -- Back??
ctx.SelLine = menuLib.BACK_BUTTON
event = EVT_VIRTUAL_ENTER
else
dsmLib.ChangePhase(PHASE.EXIT)
menuLib.ChangePhase(PHASE.EXIT)
end
end
return
end
if ctx.Phase == PHASE.RX_VERSION then return end
if event == EVT_VIRTUAL_NEXT then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
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]
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(1))
menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, 1))
else -- not editing, move selected line to NEXT
dsmLib.MoveSelectionLine(1)
menuLib.MoveSelectionLine(1)
end
return
end
if event == EVT_VIRTUAL_PREV then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
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]
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(-1))
menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, -1))
else -- not editing, move selected line to PREV
dsmLib.MoveSelectionLine(-1)
menuLib.MoveSelectionLine(-1)
end
return
end
if event == EVT_VIRTUAL_ENTER_LONG then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
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
dsmLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed
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 dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",dsmLib.phase2String(ctx.Phase), ctx.SelLine) end
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
dsmLib.GotoMenu(menu.BackId,0x80)
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
dsmLib.GotoMenu(menu.NextId,0x82)
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
dsmLib.GotoMenu(menu.PrevId,0x81)
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
@@ -581,16 +647,22 @@ local function GUI_HandleEvent(event, touchState)
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
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
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????
dsmLib.Value_Write_Validate(menuLines[ctx.SelLine])
menuLib.Value_Write_Validate(menuLines[ctx.SelLine])
else -- Edit the current value
ctx.EditLine = ctx.SelLine
originalValue = menuLines[ctx.SelLine].Val
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
menuLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
end
end
end
@@ -655,9 +727,16 @@ end
------------------------------------------------------------------------------------------------------------
-- Init
local function DSM_Init()
Log.LOG_open()
init_colors()
dsmLib.Init(toolName) -- Initialize Library
return dsmLib.StartConnection()
modelLib.ReadTxModelData()
modelLib.ST_LoadFileData()
modelLib.CreateDSMPortChannelInfo()
menuLib.Init()
menuProcessor.init()
return 0
end
------------------------------------------------------------------------------------------------------------
@@ -667,7 +746,7 @@ local function DSM_Run(event,touchState)
if event == nil then
error("Cannot be run as a model script!")
dsmLib.LOG_close()
Log.LOG_close()
return 2
end
@@ -677,12 +756,15 @@ local function DSM_Run(event,touchState)
GUI_HandleEvent(event,touchState)
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
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) then -- Requesting RX Message Version usea BLINK?
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
@@ -697,7 +779,7 @@ local function DSM_Run(event,touchState)
end
if ctx.Phase == PHASE.EXIT_DONE then
dsmLib.LOG_close()
Log.LOG_close()
return 2
else
return 0

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

@@ -1,467 +0,0 @@
# Forward Programing Protocol
## Introduction
DSM, DSMX and DSM Forward Programming are propietary protocol from the **Spektrum** radio brand. Since they don't make this information public, we have to reverse engineer it by analyzing the data exchanged between the RX and TX.
This document descrives what we know so far.
Thanks to **Pascal Langer** (Author of the Multi-Module) for the initial reverse engineering of the protocol and first version of the code that has been used for a while (Version 0.2)
Thanks to **Francisco Arzu** for taking the time to continue the work on reverse engineering, documenting and making the code more understandable.
New Capabilities in Version 0.5
- Log files of the conversation between RX/TX
- Improve the GUI (EdgeTX touch screen)
- Reversed engineer other things to make it work completly.
# Menu Title and Lines
The menu to be displayed is stored at the RX, the GUI only renders the menu title and menu lines received. The tipical conversation with the RX will be to ask for a menu (using the menuId number), and then wait for the data to come. The first thing will be the Menu (header) data, later we request the next 6 lines (one at a time), and optionally the values for each line.
A typical exchange will look like this in the log:
SEND DSM_getMenu(MenuId=0x1010 LastSelectedLine=0)
RESPONSE Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
SEND DSM_getFirstMenuLine(MenuId=0x1010)
RESPONSE MenuLine: L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ]
SEND DSM_getNextLine(MenuId=0x1010,LastLine=0)
RESPONSE MenuLine: L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ]
SEND DSM_getNextLine(MenuId=0x1010,LastLine=1)
RESPONSE MenuLine: L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ]
SEND DSM_getNextLine(MenuId=0x1010,LastLine=2)
RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
## Menu
The menu has the following information:
Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
- `MenuId`: The menu ID number of the menu (hex, 16 bit number)
- `PrevId`: The menu ID of the previous menu (for navigation), Log show as `"P="`
- `NextId`: The menu ID of the next menu (for navigation), Log shows as `"N="`
- `BackId`: The menu ID of the back menu (for navigation), Log shows as `"B="`
- `TextId`: The message number to display (16 bits, Hex). Log shows as [`0xXX`] after the message.
- `Text`: Retrived using the `TextId` from the script message `Text` array.
## Menu Lines
The menu lines has the following information:
L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1021 ]
L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ]
L[#2 T=LM VId=0x1002 Text="AS3X"[0x1DC] Val=1|"Act" NL=(0->1,0,S=3) [3->4,3] MId=0x1021 ]
- `MenuId`: of the menu they beling to. Log show as `"MId="` at the end.
- `LineNum`: Line number (0..5). The line number in the screen. Log show as # in the beginning
- `Type`: Type of Line, Log shows as `"T="` (explanation later)
- `TextId`: The message number to display (16 bits, Hex). Log shows as [`0xXXXX`] after the message.
- `Text`: Retrived using the `TextId` from the script message `Text` array.
- `ValueId`: The value or menu ID of the line. Log shows as `"VId="` (16 bits, Hex).
- `Value Range`: Shows as [`Min`->`Max`, `Default`]. This is the RAW data comming from the RX
- `NL`: Computed Normalized LIST (0 reference) for List Values. Source is the RAW range. For example, for lines of list of values. `[3->4,3]` is tranlated to `NL=(0->1,0,S=3)` since the value is also normalize to 0. `"S="` means the initial entry in the `List_Text` array
- `Val`: Current value for line who hold data. Relative to 0 for List Values. For List Values, the log will show the translation of the value to display text. example: `Val=1|"Act"` that is coming from `List_Value[4]`
## Type of Menu Lines
- `LINE_TYPE.MENU (Log: "T=M")`: This could be regular text or a navigation to another menu. if `ValueId` is the same as the current MenuId (`MId=`), is a plain text line (navigation to itself). If the `ValueId` is not the current menuId, then `ValueId` is the MenuId to navigate to.
We have found only one exception to the plain text rule, a true navigation to itself, in that case, in the text of the menu, you can use the "/M" flag at the end of the text to force it to be a menu button.
Example, FM_Channel is a navigation to menuId=0x7CA6.
L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ]
- `LINE_TYPE.LIST_MENU_NC (Log T=LM_nc)`: This is a line that shows as text in the GUI. The numeric value is translated to the proper text. The range is important, since it descrives the range of posible values. No incremental RX changes, only at the end.
Example: List of Values, List_Text[] starts at 53, ends at 85, with a default of 85. When normalized to 0, is a range from 0->32 for the numeric value. The Display value `Aux1` is retrive from `List_Text[6+53]`.
L[#0 T=LM_nc VId=0x1000 Text="FM Channel"[0x78] Val=6|"Aux1" NL=(0->32,0,S=53) [53->85,53] MId=0x7CA6 ]
- `LINE_TYPE.LIST_MENU_TOG (Log T=L_tog)`: Mostly the same as LIST_MENU_NC, but is just 2 values. (ON/OFF, Ihn/Act, etc). Should be a toggle in the GUI.
L[#2 T=LM_tog VId=0x1002 Text="AS3X"[0x1DC] Val=1|"Act" NL=(0->1,0,S=3) [3->4,3] MId=0x1021 ]
- `LINE_TYPE.LIST_MENU (Log T=LM)`: Mostly the same as LIST_MENU_NC, but incremental changes to the RX. Some times, it comes with a strange range `[0->244,Default]`. Usually this means that the values are not contiguos range; usually Ihn + Range. Still haven't found where in the data the correct range comes from.
Example: Valid Values: 3, 176->177 (Inh, Self-Level/Angle Dem, Envelope)
L[#3 T=LM VId=0x1003 Text="Safe Mode"[0x1F8] Val=176|"Self-Level/Angle Dem" NL=(0->244,3,S=0) [0->244,3] MId=0x1021 ]
- `LINE_TYPE.VALUE_NUM_I8_NC (Log: "T=V_nc")`: This line is editable, but is not updated to the RX incrementally, but only at the end. The Flight Mode line is of this type, so we have to check the TextId to differenciate between Flight mode and an Editable Value.
Fligh Mode TextId is between 0x8000 and 0x8003
Example, Flight mode comes from Variable ValId=0x1000, with current value of 1. Range of the Value is 0..10.
L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1021 ]
- `LINE_TYPE.VALUE_NUM_I8 (Log T=V_i8)`: 8 bit number (1 byte)
- `LINE_TYPE.VALUE_NUM_I16' (Log T=V_i16)`: 16 Bit number (2 bytes)
- `LINE_TYPE.VALUE_NUM_SI16 (Log T=V_si16)`: Signed 16 bit number (2 bytes)
- `LINE_TYPE.VALUE_PERCENT (Log T=L_%)`: Shows a Percent Value. 1 Byte value.
- `LINE_TYPE.VALUE_DEGREES (Log T=L_de)`: Shows a Degrees VAlue. 1 Byte value.
## LIST_TYPE Bitmap
TYPE|Sum|Hex|7 Signed|6 Valid Min/Max??|5 No-Inc-Changing|4 Menu|3 List-Menu|2 text / number|1|0 - 16 bits
|-|-|-|-|-|-|-|-|-|-|-
|MENU|Text|0x1C|0|0|0|1|1|1|0|0
|LIST_MENU|Text|0x0C|0|0|0|0|1|1|0|0
|LIST_MENU_TOG|Text|0x4C|0|1|0|0|1|1|0|0
|LIST_MENU_NC|Text, NC|0x6C|0|1|1|0|1|1|0|0
|VALUE_NUM_I8_NC|I8, NC|0x60|0|1|1|0|0|0|0|0
|VALUE_PERCENT|S8|0xC0|1|1|0|0|0|0|0|0
|VALUE_DEGREES|S8 NC|0xE0|1|1|1|0|0|0|0|0
|VALUE_NUM_I8|I8|0x40|0|1|0|0|0|0|0|0
|VALUE_NUM_I16|I16|0x41|0|1|0|0|0|0|0|1
|VALUE_NUM_SI16|S16|0xC1|1|1|0|0|0|0|0|1
## Important Behavioral differences when updating values
Values who are editable, are updated to RX as they change. For example, when changing attitude trims, the servo moves as we change the value in real-time.
LIST_MENU_NC, VALUE_NUM_I8_NC don't update the RX as it changes. It changes only in the GUI, and only update the RX at the end when confirmed the value. (NO-INC-CHANGES Bit)
After finishing updating a value, a validation command is sent. RX can reject the current value, and will change it to the nearest valid value.
## Special Menus
Seems like menuId=0x0001 is special. When you navigate to this menu, the RX reboots.
When this happens, we need to start from the beginning as if it was a new connection.
# Send and Receive messages
To comunicate with the Multi-Module, Lua scripts in OpenTx/EdgeTx has access to the `Multi_Buffer`. Writting to it will send data to RX, received data will be read from it.
For our specific case, this is how the Multi_Buffer is used:
|0..2|3|4..9|10..25
|--|--|--|--
|DSM|0x70+len|TX->RX data|RX->TX Data
To write a new DSM Fwd Programing command, write the data to address 4..9, and later set the address 3 with the length.
When receiving data, address 10 will have the message type we are receiving, or 0 if nothing has been received.
## Starting a new DSM Forward programming Connection
- Write 0x00 at address 3
- Write 0x00 at address 10
- Write "DSM" at address 0..2
## Disconnect
- Write 0x00 at address 0
# Request Messages (TX->RX)
## DSM_sendHeartbeat()
keep connection open.. We need to send it every 2-3 seconds, otherwise the RX will force close the connection by sending the TX an Exit_Confirm message.
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg| Len? | ?? | ??
0x00|0x04|0x00|0x00
SEND DSM_sendHeartbeat()
DSM_SEND: [00 04 00 00 ]
## DSM_getRxVersion()
Request the RX information
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg| Len? | ?? | ?? |??|??
0x11|0x06|0x00|0x14|0x00|0x00
SEND DSM_getRxVersion()
DSM_SEND: [11 06 00 14 00 00 ]
## DSM_getMainMenu()
Request data for the main menu of the RX
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg| Len? | ?? | ?? |??|??
0x12|0x06|0x00|0x14|0x00|0x00
SEND DSM_getMainMenu()
DSM_SEND: [12 06 00 14 00 00 ]
## DSM_getMenu(menuId, lastSelLine)
Request data for Menu with ID=`menuId`. lastSelLine is the line that was selected to navigate to that menu. Most menus works with 0, but for some special "Enter Bind Mode", "Factory Reset", "Save to Backup" they will not work if we send 0, has to be the line who was selected in the confirmation menu line "Apply".
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (line#)??| LSB (line#)
0x16|0x06|0x10|0x60|0x00|0x01
SEND DSM_getMenu(MenuId=0x1060 LastSelectedLine=1)
DSM_SEND: [16 06 10 60 00 01 ]
## DSM_getFirstMenuLine(menuId)
Request the first line of a menu identified as `menuId`. The response will be the first line of the menu. Some times, it return lines shown as `'MenuUknownLine_0x05'` that we still are trying to understand what they are for.
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg|Len? | MSB (menuId) | LSB (MenuId)
0x13|0x04|0x10|0x60
SEND DSM_getFirstMenuLine(MenuId=0x1000)
DSM_SEND: [13 04 10 00 ]
## DSM_getNextMenuLine(menuId, curLine)
Request the retrival of the next line following the current line. Response is either the next line, or the next value, or nothing.
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (line#)??| LSB (line#)
0x14|0x06|0x10|0x60|0x00|0x01
SEND DSM_getNextLine(MenuId=0x1000,LastLine=1)
DSM_SEND: [14 06 10 00 00 01 ]
## DSM_getNextMenuValue(menuId, valId, text)
Retrive the next value after the last `ValId` of the current `menuId`. text is just for debugging purposes to show the header of the value been retrived.
The Response is a Menu Value or nothing if no more data.
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (ValId)| LSB (ValId)
0x15|0x06|0x10|0x61|0x10|0x00
SEND DSM_getNextMenuValue(MenuId=0x1061, LastValueId=0x1000) Extra: Text="Outputs"
DSM_SEND: [15 06 10 61 10 00 ]
## DSM_updateMenuValue(valId, val, text, line)
Updates the value identified as `valId` with the numeric value `val`. `text` and `line` are there to add debugging info. No response is expected.
If the value is negative, it has to be translated to the proper DSM negative representaion.
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg|Len? | MSB (ValId) | LSB (ValId) | MSB (Value)| LSB (Value)
0x18|0x06|0x??|0x??|0x??|0x??
DSM_updateMenuValue(valId, val, text, line)
-->DSM_send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value))
## DSM_validateMenuValue(valId, text, line)
Validates the value identified as `valId`. `text` and `line` are there to add debugging info. The RX can response an Update value if the value is not valid and needs to be corrected.
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg|Len? | MSB (ValId) | LSB (ValId)
0x19|0x06|0x??|0x??
DSM_validateMenuValue(valId, text, line)
-> DSM_send(0x19, 0x06, int16_MSB(valId), int16_LSB(valId))
## DSM_menuValueChangingWait(valId, text, line)
Durin editing, this serves as a heartbeat that we are editing the value. The value identified as `valId`. `text` and `line` are there to add debugging info. The RX can response an Update value or a NUL response.
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg|Len?? | MSB (ValId) | LSB (ValId)
0x1A|0x06|0x??|0x??
DSM_menuValueChangingWait(valId, text, line)
->DSM_send(0x1A, 0x06, int16_MSB(valId), int16_LSB(valId))
## DSM_exitRequest()
Request to end the DSM Frd Prog connection. Will reponse with an exit confirmation.
|4|5|6|7|8|9|10
|--|--|--|--|--|--|--
Msg|Len?? | ??
0x1F|0x02|0xAA
CALL DSM_exitRequest()
DSM_SEND: [1F 02 AA ]
# Response Messages (RX->TX)
All responses will have the a response byte in Multi_Buffer[10]=0x09, and the type of message in Multi_Buffer[11].
## RX Version Response
Returns the information about the current RX.
The Display text of name name of the RX is retrive from the `RX_Name` array.
|10|11|12|13|14|15|16
|--|--|--|--|--|--|--
|Resp|Msg|?? |RxId|Major|Minor|Patch
|0x09|0x01|0x00|0x1E|0x02|0x26|0x05
RESPONSE RX: 09 01 00 1E 02 26 05
RESPONSE Receiver=AR631 Version 2.38.5
## Menu Response
Returns the menu information to display and navigation.
The Display text for the menu is retrive from the `Text` array.
|10|11|12|13|14|15|16|17|18|19|20|21
|--|--|--|--|--|--|--|--|--|--|--|--
|Resp|Msg|LSB (menuId)|MSB (menuId)|LSB (TextId)|MSB (TextId)|LSB (PrevId)|MSB (PrevId)|LSB (NextId)|MSB (NextId)|LSB (BackId)|MSB (BackId)
|0x09|0x02|0x5E|0x10|0x27|0x02|0x00|0x00|0x00|0x00|0x00|0x10
RESPONSE RX: 09 02 5E 10 27 02 00 00 00 00 00 10 00 00 00 00
RESPONSE Menu: M[Id=0x105E P=0x0 N=0x0 B=0x1000 Text="Other settings"[0x227]]
## Menu Line Response
Returns the menu line information.
The Display text for the menu line is retrive from the `Text` array.
`Min`,`Max` and `Default` can be signed numbers.
|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25
|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
|Resp|Msg|LSB (menuId)|MSB (menuId)|Line#|Line Type|LSB (TextId)|MSB (TextId)|LSB (ValId)|MSB (ValId)|LSB (Min)|MSB (Min)|LSB (Max)|MSB (Max)|LSB (Def)|MSB (Def)
|0x09|0x03|0x61|0x10|0x00|0x6C|0x50|0x00|0x00|0x10|0x36|0x00|0x49|0x00|0x36|0x00
RESPONSE RX: 09 03 61 10 00 6C 50 00 00 10 36 00 49 00 36 00
RESPONSE MenuLine: L[#0 T=LM_nc VId=0x1000 Text="Outputs"[0x50] Val=nil NL=(0->19,0,S=54) [54->73,54] MId=0x1061 ]
## Menu Line Value Response
Returns the Value for a line.
The response updates the Value in the line identified by `ValId`.
The Display text for the Value, when it is a list, is retrive from the `List_Text` array.
|10|11|12|13|14|15|16|17
|--|--|--|--|--|--|--|--
|Resp|Msg|LSB (menuId)|MSB (menuId)|LSB (ValId)|MSB (ValId)|LSB (Value)|MSB (Value)
|0x09|0x04|0x61|0x10|0x00|0x10|0x00|0x00
RESPONSE RX: 09 04 61 10 00 10 00 00
RESPONSE MenuValue: UPDATED: L[#0 T=L_m0 VId=0x1000 Text="Outputs"[0x50] Val=0|"Throttle" NL=(0->19,0,S=54) [54->73,54] MId=0x1061 ]
## Exit Response
Response from a Exit Request.
|10|11
|--|--
|Resp|Msg
|0x09|0x07
RESPONSE RX: 09 A7
RESPONSE Exit Confirm
## NULL Response
Can be use as a response, or heartbeat from the RX to keep the connection open.
|10|11
|--|--
|Resp|Msg
|0x09|0x00
RESPONSE RX: 09 00
RESPONSE NULL
# Unknown Lines
TOTALLY UNKNOWN WHAT THIS ARE FOR.. but only works for the Main Menu..
Other menus they just loop on line=0 forever.
## DSM_getNextUknownLine_0x05(menuId, curLine)
Request the retrival of the next Unknown line following the current line. Response is either the next unknow line, next menu line, or the next value, or nothing.
|4|5|6|7|8|9| Comment
|--|--|--|--|--|--|--
Msg|Len? | Line# | Line# | 0x00 | Formula(line#)??
0x20|0x06|0x00|0x00|0x00|0x40 | LastLineLine=0 retrieval
0x20|0x06|0x01|0x01|0x00|0x01| LastLineLine=1 retrieval
0x20|0x06|0x02|0x02|0x00|0x02| LastLineLine=2 retrieval
0x20|0x06|0x03|0x03|0x00|0x04| LastLineLine=3 retrieval
0x20|0x06|0x04|0x04|0x00|0x00| LastLineLine=4 retrieval
0x20|0x06|0x05|0x05|0x00|0x00| LastLineLine=5 retrieval
## Unknown Line Response
We still don't know what is this for, but we have to retrive them and skip then. Works for main menu, but when it happens in another menus, usually we stay in an infinite loop retrieving line=0
|10|11|12|13|14|15|16|17
|--|--|--|--|--|--|--|--
|Resp|Msg|LSB (line#)
|0x09|0x05|0x00|0x01|0x00|0x00|0x00|0x07
|0x09|0x05|0x01|0x01|0x00|0x00|0x00|0x07
## Interaction on Main Menu
This is the normal interaction for the main menu. As you can see, it iterates on the 6 Unknow lines (0..5), and afterwards, it starts sending normal menu lines.
SEND DSM_getFirstMenuLine(MenuId=0x1000)
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
CALL DSM_getNextUknownLine_0x05(LastLine=0)
RESPONSE MenuUknownLine_0x05: LineNum=1 DATA=RX: 09 05 01 01 00 00 00 07 00 00 00 00 00 00 00 00
CALL DSM_getNextUknownLine_0x05(LastLine=1)
RESPONSE MenuUknownLine_0x05: LineNum=2 DATA=RX: 09 05 02 01 00 00 00 07 00 00 00 00 00 00 00 00
CALL DSM_getNextUknownLine_0x05(LastLine=2)
RESPONSE MenuUknownLine_0x05: LineNum=3 DATA=RX: 09 05 03 01 00 00 00 07 00 00 00 00 00 00 00 00
CALL DSM_getNextUknownLine_0x05(LastLine=3)
RESPONSE MenuUknownLine_0x05: LineNum=4 DATA=RX: 09 05 04 01 00 00 00 07 00 00 00 00 00 00 00 00
CALL DSM_getNextUknownLine_0x05(LastLine=4)
RESPONSE MenuUknownLine_0x05: LineNum=5 DATA=RX: 09 05 05 01 00 00 00 07 00 00 00 00 00 00 00 00
CALL DSM_getNextUknownLine_0x05(LastLine=5)
RESPONSE MenuLine: L[#0 T=M VId=0x1010 Text="Gyro settings"[0xF9] MId=0x1000 ]
## Other menus
If it hapen on other menus. Usualy stays in an infinite loop until it crash/exits.
The screen will show **"Error: Cannot Load Menu Lines from RX"**
The log will look like:
DSM_getMenu(MenuId=0x104F LastSelectedLine=1)
RESPONSE Menu: M[Id=0x104F P=0x0 N=0x0 B=0x1000 Text="First Time Setup"[0x4A]]
SEND DSM_getFirstMenuLine(MenuId=0x104F)
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
CALL DSM_getNextUknownLine_0x05(LastLine=0)
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
ERROR: Received Same menu line
CALL DSM_getNextUknownLine_0x05(LastLine=0)
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
ERROR: Received Same menu line
We found that sometimes, Overriding LastSelectedLine to 0 solves the problem for some specific menus. Not for all (for other, is the oposite (0->1)). But at least no unknown lines are returned with this hack for AR631/AR637. Maybe others also needed.
**Overriding to Zero is not a good solution for every menu. Some menus needs the LastLine to know the behaviour (for example, Factory Reset the RX, Save Backup, Restore Backup, Enter Bind Mode, Some sensor Calibration). Thats why we cannot do it blindly.**
Here is the current code to fix some of this problems in AR631/AR637.
Function `DSM_SelLine_HACK()`
if (ctx.RX.Id == RX.AR637T or ctx.RX.Id == RX.AR637TA or ctx.RX.Id == RX.AR631) then
-- AR631/AR637 Hack for "First time Setup" or
-- "First Time AS3X Setup", use 0 instead of the ctx.SelLine=5
if (ctx.Menu.MenuId == 0x104F or ctx.Menu.MenuId==0x1055) then
LOG_write("First time Setup Menu HACK: Overrideing LastSelectedLine to ZERO\n")
ctx.SelLine = 0
end
-- DID NOT WORK: AR631/AR637 Hack for "Relearn Servo Settings", use 1 instead
-- of the ctx.SelLine=0
--if (ctx.Menu.MenuId == 0x1023) then
-- LOG_write("Relearn Servo Settings HACK: Overrideing LastSelectedLine to 1\n")
-- ctx.SelLine = 1
--end
Now it retrives properly the menu:
Log shows:
First time Setup Menu HACK: Overrideing LastSelectedLine to ZERO
DSM_getMenu(MenuId=0x104F LastSelectedLine=0)
RESPONSE Menu: M[Id=0x104F P=0x0 N=0x0 B=0x105E Text="First Time Setup"[0x4A]]
SEND DSM_getFirstMenuLine(MenuId=0x104F)
.. Good menu data

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

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 }

View File

@@ -25,13 +25,12 @@
------------------------------------------------------------------------------
local DEBUG_ON = ... -- Get DebugON from parameters
local Log, menuLib, modelLib, DEBUG_ON = ... -- Get DebugON from parameters
local SIM_LIB_VERSION = "0.56"
local MSG_FILE = "/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt"
local dsmLib = assert(loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua"))(DEBUG_ON)
local PHASE = dsmLib.PHASE
local LINE_TYPE = dsmLib.LINE_TYPE
local Get_Text = dsmLib.Get_Text
local PHASE = menuLib.PHASE
local LINE_TYPE = menuLib.LINE_TYPE
local SimLib = {}
@@ -39,46 +38,12 @@ local lastGoodMenu=0
local RX_loadMenu = nil
local RX_Initialized = true
local IS_EDGETX = false
local function SIM_StartConnection()
return 0
end
local function SIM_ReleaseConnection()
end
local function clearMenuLines()
local ctx = dsmLib.DSM_Context
for i = 0, dsmLib.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
local function PostProcessMenu()
local ctx = dsmLib.DSM_Context
if (ctx.Menu.Text==nil) then
ctx.Menu.Text = dsmLib.Get_Text(ctx.Menu.TextId)
dsmLib.MenuPostProcessing (ctx.Menu)
end
if (DEBUG_ON) then dsmLib.LOG_write("SIM RESPONSE Menu: %s\n", dsmLib.menu2String(ctx.Menu)) end
for i = 0, dsmLib.MAX_MENU_LINES do -- clear menu
local line = ctx.MenuLines[i]
if (line.Type~=0) then
line.MenuId = ctx.Menu.MenuId
line.lineNum = i
dsmLib.MenuLinePostProcessing(line) -- Do the same post processing as if they come from the RX
if (DEBUG_ON) then dsmLib.LOG_write("SIM RESPONSE MenuLine: %s\n", dsmLib.menuLine2String(line)) end
end
end
end
local function AR631_loadMenu(menuId)
clearMenuLines()
local ctx = dsmLib.DSM_Context
menuLib.clearMenuLines()
local ctx = menuLib.DSM_Context
if (menuId==0x1000) then
--M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"]
@@ -665,7 +630,7 @@ local function AR631_loadMenu(menuId)
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0102, ValId = 0x104F }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0103, ValId = 0x104F }
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x0104, ValId = 0x104F }
ctx.SelLine = dsmLib.NEXT_BUTTON
ctx.SelLine = menuLib.NEXT_BUTTON
lastGoodMenu = menuId
elseif (menuId==0x1050) then
@@ -681,7 +646,7 @@ local function AR631_loadMenu(menuId)
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0108, ValId = 0x1050 }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0109, ValId = 0x1050 }
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x010A, ValId = 0x1050 }
ctx.SelLine = dsmLib.NEXT_BUTTON
ctx.SelLine = menuLib.NEXT_BUTTON
lastGoodMenu = menuId
elseif (menuId==0x1051) then
--M[Id=0x1051 P=0x0 N=0x0 B=0x1010 Text="First Time Setup"]
@@ -1024,34 +989,43 @@ local function AR631_loadMenu(menuId)
elseif (menuId==0x0001) then
-- Save Settings and Reboot
ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 }
ctx.SelLine = dsmLib.BACK_BUTTON
ctx.SelLine = menuLib.BACK_BUTTON
else
print("NOT IMPLEMENTED")
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
ctx.SelLine = dsmLib.BACK_BUTTON
ctx.SelLine = menuLib.BACK_BUTTON
end
PostProcessMenu()
menuLib.PostProcessMenu()
end
local function FC6250HX_loadMenu(menuId)
clearMenuLines()
local ctx = dsmLib.DSM_Context
menuLib.clearMenuLines()
local ctx = menuLib.DSM_Context
if (menuId==0x1000) then
--M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"[0x4B]]
--L[#0 T=M VId=0x1100 Text="Swashplate"[0xD3] MId=0x1000 ]
--L[#1 T=M VId=0x1200 [0->0,2] Text="Tail rotor"[0xDD] MId=0x1000 ]
--L[#2 T=M VId=0x1400 [0->0,2] Text="SAFE"[0xDA] MId=0x1000 ]
--L[#4 T=M VId=0x1300 [0->0,2] Text="Setup"[0xDE] MId=0x1000 ]
--L[#2 T=M VId=0x1280 Text="Governor"[0xF2]
--L[#3 T=M VId=0x1400 [0->0,2] Text="SAFE"[0xDA] MId=0x1000 ]
--L[#5 T=M VId=0x1300 [0->0,2] Text="Setup"[0xDE] MId=0x1000 ]
--L[#6 T=M VId=0x1700 [0->0,2] Text="System Setup"[0x86] MId=0x1000 ]
ctx.Menu = { MenuId = 0x1000, TextId = 0x004B, PrevId = 0, NextId = 0, BackId = 0 }
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xD3, ValId = 0x1100 }
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xDD, ValId = 0x1200 }
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xDA, ValId = 0x1400 }
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0xDE, ValId = 0x1300 }
if (not RX_Initialized) then
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xF2, ValId = 0x1280 }
end
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xDA, ValId = 0x1400 }
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0xDE, ValId = 0x1300 }
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x86, ValId = 0x1700 }
ctx.SelLine = 0
lastGoodMenu = menuId
@@ -1129,12 +1103,34 @@ local function FC6250HX_loadMenu(menuId)
ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x72, ValId = 0x1216, Min=0, Max=255, Def=95, Val=95 }
ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x73, ValId = 0x1217, Min=0, Max=255, Def=45, Val=45 }
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x1280) then -- TODO
--M[Id=0x1200 P=0x0 N=0x0 B=0x1000 Text="Governor"[0xF0]]
--L[#4 T=V_i8 VId=0x1215 Text="Proportional"[0x71] Val=100 [0->255,100] MId=0x1200 ]
--L[#5 T=V_i8 VId=0x1216 Text="Integral"[0x72] Val=95 [0->255,95] MId=0x1200 ]
--L[#3 T=V_nc VId=0x1214 Text=" FLIGHT MODE"[0x8000] Val=1 [0->5,0] MId=0x1200 ]
--L[#6 T=V_i8 VId=0x1217 Text="Head Speed"[0x26B] Val=45 [0->255,45] MId=0x1200 ]
ctx.Menu = { MenuId = 0x1280, TextId = 0xDD, PrevId = 0, NextId = 0, BackId = 0x1000 }
ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x92, ValId = 0x1212, Min=5, Max=200, Def=25, Val=25 }
ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xD8, ValId = 0x1213, Min=5, Max=200, Def=26, Val=100 }
ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8000, ValId = 0x1214, Min=0, Max=5, Def=0, Val=1 }
ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x71, ValId = 0x1215, Min=0, Max=255, Def=100, Val=100 }
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x1300) then
--M[Id=0x1300 P=0x0 N=0x0 B=0x1000 Text="Setup"[0xDE]]
--L[#0 T=M VId=0x1310 Text="Swashplate"[0xD3] MId=0x1300 ]
--L[#1 T=M VId=0x1360 Text="Tail rotor"[0xDD] MId=0x1300 ]
-- L[#2 T=M VId=0x13C0 Text="Throttle"[0x201] MId=0x1300 A=0x0]
-- L[#3 T=M VId=0x13B0 Text="Gyro settings"[0xF9] MId=0x1300 A=0x0]
--L[#4 T=LM_nc VId=0x1701 Text="FM Channel"[0x78] val=1 NL=(0->8,1,S=12) [12->20,13] MId=0x1300 ]
--L[#5 T=LM_nc VId=0x1702 Text="Gain Channel"[0x89] val=0 NL=(0->8,1,S=12)] [12->20,13] MId=0x1300 ]
--L[#6 T=LM_nc VId=0x1703 Text="Output Channel 6"[0x56] val=1 NL=(0->12,0,S=53) [53->65,53] MId=0x1300 ]
@@ -1142,6 +1138,12 @@ local function FC6250HX_loadMenu(menuId)
ctx.Menu = { MenuId = 0x1300, TextId = 0xDE, PrevId = 0, NextId = 0, BackId = 0x1000 }
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xD3, ValId = 0x1310 }
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xDD, ValId = 0x1360 }
if (not RX_Initialized) then
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x201, ValId = 0x13C0 }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xF9, ValId = 0x13B0 }
end
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x78, ValId = 0x1701, Min=12, Max=20, Def=13, Val=1 }
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x89, ValId = 0x1702, Min=12, Max=20, Def=13, Val=0 }
ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x56, ValId = 0x1702, Min=53, Max=65, Def=53, Val=1 }
@@ -1182,12 +1184,27 @@ local function FC6250HX_loadMenu(menuId)
lastGoodMenu = menuId
elseif (menuId==0x1330) then
--M[Id=0x1330 P=0x0 N=0x0 B=0x1310 Text="Output Setup"[0x49]]
--L[#0 T=M VId=0x1331 Text="Subtrim"[0xE1] MId=0x1330 ]
---- Full version
--L[#0 T=LM_nc2 VId=0x1331 Text="Frame Rate"[0x85] Val=nil NL=(0->5,0,S=136) [136->141,136] MId=0x1330 A=0x0]
--L[#1 T=M VId=0x1334 Text="Swash Type"[0xE5] MId=0x1330 A=0x0]
--L[#2 T=M VId=0x1332 Text="Direction"[0xF6] MId=0x1330 A=0x0]
--L[#3 T=M VId=0x1331 Text="Subtrim"[0xE1] MId=0x1330 ]
ctx.Menu = { MenuId = 0x1330, TextId = 0x49, PrevId = 0, NextId = 0, BackId = 0x1310 }
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xE1, ValId = 0x1331 }
ctx.SelLine = 0
if (not RX_Initialized) then
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x85, ValId = 0x1331, Min=136, Max=141, Def=136, Val=0 }
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xE5, ValId = 0x1334 }
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xF6, ValId = 0x1332 }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xE1, ValId = 0x1331 }
ctx.SelLine = 0
else
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xE1, ValId = 0x1331 }
ctx.SelLine = 0
end
lastGoodMenu = menuId
elseif (menuId==0x1331) then
--M[Id=0x1331 P=0x0 N=0x0 B=0x1330 Text="Subtrim"[0xE1]]
@@ -1202,6 +1219,28 @@ local function FC6250HX_loadMenu(menuId)
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x1332) then
--M[Id=0x1332 P=0x0 N=0x0 B=0x1330 Text="Direction"[0xF6]]
--L[#0 T=LM_tog VId=0x1333 Text="Output Channel 1"[0x51] Val=nil NL=(0->1,0,S=142) [142->143,142] MId=0x1332 A=0x0]
--L[#1 T=LM_tog VId=0x1334 Text="Output Channel 2"[0x52] Val=nil NL=(0->1,0,S=142) [142->143,142] MId=0x1332 A=0x0]
--L[#2 T=LM_tog VId=0x1335 Text="Output Channel 3"[0x53] Val=nil NL=(0->1,0,S=142) [142->143,142] MId=0x1332 A=0x0]
ctx.Menu = { MenuId = 0x1332, TextId = 0xF6, PrevId = 0, NextId = 0, BackId = 0x1330 }
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x51, ValId = 0x1333, Min=142, Max=143, Def=142, Val=0 }
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x52, ValId = 0x1334, Min=142, Max=143, Def=142, Val=0 }
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x53, ValId = 0x1335, Min=142, Max=143, Def=142, Val=0 }
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x1334) then
-- M[Id=0x1334 P=0x0 N=0x0 B=0x1330 Text="Swashplate"[0xD3]]
-- L[#6 T=LM_tog VId=0x1335 Text="Swash Type"[0xE5] Val=nil NL=(0->8,0,S=144) [144->152,144] MId=0x1334 A=0x0]
ctx.Menu = { MenuId = 0x1334, TextId = 0xD3, PrevId = 0, NextId = 0, BackId = 0x1330 }
ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0xE5, ValId = 0x1335, Min=144, Max=152, Def=144, Val=0 }
ctx.SelLine = 6
lastGoodMenu = menuId
elseif (menuId==0x1360) then
--M[Id=0x1360 P=0x0 N=0x0 B=0x1300 Text="Tail rotor"[0xDD]]
--L[#0 T=M VId=0x1390 Text="Advanced Setup"[0x99] MId=0x1360 ]
@@ -1224,6 +1263,100 @@ local function FC6250HX_loadMenu(menuId)
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x13B0) then
-- M[Id=0x13B0 P=0x0 N=0x0 B=0x1300 Text="Gyro settings"[0xF9]]
-- L[#0 T=M VId=0x13B1 Text="Orientation"[0x80] MId=0x13B0 A=0x0]
ctx.Menu = { MenuId = 0x13B0, TextId = 0xF9, PrevId = 0, NextId = 0, BackId = 0x1300 }
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x80, ValId = 0x13B1 }
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x13B1) then
-- M[Id=0x13B1 P=0x0 N=0x0 B=0x13B5 Text="Gyro settings"[0xF9]]
--L[#6 T=LM_ori VId=0x13B2 Text="Orientation"[0x80] Val=nil NL=(0->7,0,S=203) [203->210,203] MId=0x13B1 A=0x0]
ctx.Menu = { MenuId = 0x13B1, TextId = 0xF9, PrevId = 0, NextId = 0, BackId = 0x13B5 }
ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_ORI, TextId = 0x80, ValId = 0x13B2, Min=203, Max=210, Def=203, Val=0 }
ctx.SelLine = 6
lastGoodMenu = menuId
elseif (menuId==0x13B5) then
--M[Id=0x13B5 P=0x0 N=0x0 B=0x13B0 Text="Calibrate Sensor"[0xC7]]
--L[#3 T=M VId=0x13B6 Text="Begin"[0x91] MId=0x13B5 A=0x0]
ctx.Menu = { MenuId = 0x13B5, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x13B0 }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x91, ValId = 0x13B6 }
ctx.SelLine = 3
lastGoodMenu = menuId
elseif (menuId==0x13B6) then
--M[Id=0x13B6 P=0x0 N=0x0 B=0x13B0 Text="Calibrate Sensor"[0xC7]]
--L[#3 T=M VId=0x13B0 Text="Sensor is Calibrating.. Wait"[0xC8] MId=0x13B6 A=0x0]
ctx.Menu = { MenuId = 0x13B6, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x13B0 }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xC8, ValId = 0x17F1 }
ctx.SelLine = 3
lastGoodMenu = menuId
elseif (menuId==0x13C0) then
--M[Id=0x13C0 P=0x0 N=0x0 B=0x1300 Text="Throttle"[0x201]]
--L[#0 T=M VId=0x13C1 Text="Failsafe"[0x4A] MId=0x13C0 A=0x0]
--L[#1 T=V_% VId=0x13C2 Text="Hover"[0x204] Val=nil [0->100,65] MId=0x13C0 A=0x10]
--L[#2 T=M VId=0x13D0 Text="Governor"[0xF2] MId=0x13C0 A=0x0]
--L[#4 T=V_nc VId=0x13C3 Text="Flight Mode"[0x8000] Val=nil [0->5,0] MId=0x13C0 A=0x5]
--L[#5 T=V_% VId=0x13C4 Text="Offset"[0x1AA] Val=nil [-25->25,0] MId=0x13C0 A=0x10]
--L[#6 T=V_i8 VId=0x13C5 Text="Soft Start"[0xF4] Val=nil [0->250,0] MId=0x13C0 A=0x0]
ctx.Menu = { MenuId = 0x13C0, TextId = 0x201, PrevId = 0, NextId = 0, BackId = 0x1300 }
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x4A, ValId = 0x13C1 }
ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x204, ValId = 0x13C2, Min=0, Max=100, Def=65, Val=65 }
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xF2, ValId = 0x13D0 }
ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8000, ValId = 0x13C3, Min=0, Max=5, Def=0, Val=1 }
ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x1AA, ValId = 0x13C4, Min=-25, Max=25, Def=0, Val=0 }
ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xF4, ValId = 0x13C5, Min=0, Max=250, Def=0, Val=1 }
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x13C1) then
--M[Id=0x13C1 P=0x0 N=0x0 B=0x13C0 Text="Failsafe"[0x4A]]
--L[#2 T=M VId=0x13C3 Text="Capture Failsafe Positions"[0x9A] MId=0x13C1 A=0x0]
ctx.Menu = { MenuId = 0x13C1, TextId = 0x4A, PrevId = 0, NextId = 0, BackId = 0x13C0 }
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x9A, ValId = 0x13C3 }
ctx.SelLine = 2
lastGoodMenu = menuId
elseif (menuId==0x13D0) then
--M[Id=0x13D0 P=0x0 N=0x0 B=0x13C0 Text="Governor"[0xF2]]
--L[#0 T=LM_ori VId=0x13D1 Text="Governor"[0xF2] Val=nil NL=(0->1,0,S=244) [244->245,244] MId=0x13D0 A=0x0]
--L[#1 T=V_i8 VId=0x13D2 Text="Main Gear"[0x26D] Val=nil [1->255,170] MId=0x13D0 A=0x0]
--L[#2 T=V_i8 VId=0x13D3 Text="Pinion"[0x26C] Val=nil [1->255,20] MId=0x13D0 A=0x0]
--L[#3 T=V_i8 VId=0x13D5 Text="Low Throttle"[0xEA] Val=nil [1->100,75] MId=0x13D0 A=0x0]
--L[#4 T=V_i8 VId=0x13D6 Text="Filter"[0x1F1] Val=nil [1->65,35] MId=0x13D0 A=0x0]
--L[#5 T=M VId=0x13E0 Text="RPM Sensor"[0x26F] MId=0x13D0 A=0x0]
ctx.Menu = { MenuId = 0x13D0, TextId = 0xF2, PrevId = 0, NextId = 0, BackId = 0x13C0 }
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_ORI, TextId = 0x0F2, ValId = 0x13D1, Min=244, Max=245, Def=244, Val=0 }
ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x26D, ValId = 0x13D2, Min=1, Max=255, Def=170, Val=170 }
ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x26C, ValId = 0x13D3, Min=1, Max=255, Def=20, Val=20 }
ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x0EA, ValId = 0x13D5, Min=1, Max=100, Def=75, Val=75 }
ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x1F1, ValId = 0x13D6, Min=1, Max=65, Def=35, Val=35 }
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x26F, ValId = 0x13E0 }
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x13E0) then
--M[Id=0x13E0 P=0x0 N=0x0 B=0x13D0 Text="Governor"[0xF2]]
--L[#0 T=LM_ori VId=0x13D1 Text="RPM Sensor"[0x26F] Val=nil NL=(0->1,0,S=244) [244->245,244] MId=0x13D0 A=0x0]
ctx.Menu = { MenuId = 0x13E0, TextId = 0xF2, PrevId = 0, NextId = 0, BackId = 0x13D0 }
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x26F, ValId = 0x13E3, Min=142, Max=143, Def=142, Val=0 }
ctx.SelLine = 3
lastGoodMenu = menuId
elseif (menuId==0x1400) then
--M[Id=0x1400 P=0x0 N=0x0 B=0x1000 Text="SAFE"[0xDA]]
--L[#0 T=M VId=0x1410 Text="Stability"[0xDB] MId=0x1400 ]
@@ -1306,30 +1439,29 @@ local function FC6250HX_loadMenu(menuId)
lastGoodMenu = menuId
elseif (menuId==0x17F1) then
--M[Id=0x17F1 P=0x0 N=0x0 B=0x1700 Text="Calibrate Sensor"[0xC7]]
--L[#3 T=M VId=0x17F1 Text="Complete"[0xC8] MId=0x17F0 ]
--L[#3 T=M VId=0x17F1 Text="Complete"[0x93] MId=0x17F0 ]
ctx.Menu = { MenuId = 0x17F1, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x1700 }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xC8, ValId = 0x1700 }
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x93, ValId = 0x1700 }
ctx.SelLine = 3
lastGoodMenu = menuId
elseif (menuId==0x0001) then
-- Save Settings and Reboot
ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 }
ctx.SelLine = dsmLib.BACK_BUTTON
ctx.SelLine = menuLib.BACK_BUTTON
else
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
ctx.SelLine = dsmLib.BACK_BUTTON
ctx.SelLine = menuLib.BACK_BUTTON
end
PostProcessMenu()
menuLib.PostProcessMenu()
end
local function loadMenu(menuId)
clearMenuLines()
local ctx = dsmLib.DSM_Context
menuLib.clearMenuLines()
local ctx = menuLib.DSM_Context
if (menuId==0x1000) then
--M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"]
@@ -1337,35 +1469,41 @@ local function loadMenu(menuId)
--L[#1 T=M VId=0x105E val=nil [0->0,2] Text="Other settings" MId=0x1000 ]
ctx.Menu = { MenuId = 0x1000, Text = "RX SIMULATION", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
ctx.MenuLines[0] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR631 (NEW)", ValId = 0x1001,TextId=0 }
ctx.MenuLines[1] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR631 (INITIALIZED)", ValId = 0x1002, TextId=0 }
ctx.MenuLines[0] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR630/631/637 (NEW)", ValId = 0x1001,TextId=0 }
ctx.MenuLines[1] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR630/631/637 (INITIALIZED)", ValId = 0x1002, TextId=0 }
ctx.MenuLines[4] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "FC6250HX", ValId = 0x1005, TextId=0 }
ctx.MenuLines[5] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "FC6250HX (UNLOCKED)", ValId = 0x1006, TextId=0 }
ctx.SelLine = 0
lastGoodMenu = menuId
elseif (menuId==0x1001) then
RX_Initialized = false
ctx.RX.Id = dsmLib.RX.AR631
dsmLib.Init_Text(ctx.RX.Id)
ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM'
ctx.RX.Version = "2.38.5"
ctx.RX.Id = menuLib.RX.AR631
ctx.RX.Name = "AR630/631/637-SIM"
ctx.RX.Version = "2.38.5"
RX_loadMenu = AR631_loadMenu
RX_loadMenu(0x01000)
elseif (menuId==0x1002) then
ctx.RX.Id = dsmLib.RX.AR631
dsmLib.Init_Text(ctx.RX.Id)
ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM'
RX_Initialized = true
ctx.RX.Id = menuLib.RX.AR631
ctx.RX.Name = "AR630/631/637-SIM"
ctx.RX.Version = "2.38.5"
RX_loadMenu = AR631_loadMenu
RX_loadMenu(0x01000)
elseif (menuId==0x1005) then
ctx.RX.Id = dsmLib.RX.FC6250HX
dsmLib.Init_Text(ctx.RX.Id)
ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM'
RX_Initialized = true
ctx.RX.Id = menuLib.RX.FC6250HX
ctx.RX.Name = "FC6250HX-SIM"
ctx.RX.Version = "5.6.255"
RX_loadMenu = FC6250HX_loadMenu
RX_loadMenu(0x01000)
elseif (menuId==0x1006) then
RX_Initialized = false
ctx.RX.Id = menuLib.RX.FC6250HX
ctx.RX.Name = "FC6250HX-SIM"
ctx.RX.Version = "5.6.52"
RX_loadMenu = FC6250HX_loadMenu
RX_loadMenu(0x01000)
end
@@ -1375,13 +1513,14 @@ end
local function SIM_Send_Receive()
local ctx = dsmLib.DSM_Context
--if (DEBUG_ON) then dsmLib.LOG_write("%3.3f %s: ", dsmLib.getElapsedTime(), dsmLib.phase2String(ctx.Phase)) end
local ctx = menuLib.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
ctx.RX.Name = "SIMULATOR"
ctx.RX.Version = "0.54"
ctx.RX.Version = SIM_LIB_VERSION
ctx.Phase = PHASE.MENU_TITLE
ctx.Menu.MenuId=0
ctx.Refresh_Display = true
RX_loadMenu = loadMenu
@@ -1399,8 +1538,8 @@ local function SIM_Send_Receive()
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
if (DEBUG_ON) then dsmLib.LOG_write("%3.3f %s: ", dsmLib.getElapsedTime(), dsmLib.phase2String(ctx.Phase)) end
if (DEBUG_ON) then dsmLib.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, dsmLib.lineValue2String(line)) end
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
@@ -1408,9 +1547,9 @@ local function SIM_Send_Receive()
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 dsmLib.LOG_write("%3.3f %s: ", dsmLib.getElapsedTime(), dsmLib.phase2String(ctx.Phase)) end
if (DEBUG_ON) then dsmLib.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, dsmLib.lineValue2String(line)) end
if (DEBUG_ON) then dsmLib.LOG_write("SEND SIM_validateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, dsmLib.lineValue2String(line)) end
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
@@ -1418,56 +1557,40 @@ local function SIM_Send_Receive()
end
end
------------------------------------------------------------------------------------------------------------
-- Lib EXPORTS
local FileState = {}
-- Export Constants
SimLib.PHASE = dsmLib.PHASE
SimLib.LINE_TYPE = dsmLib.LINE_TYPE
SimLib.RX = dsmLib.RX
SimLib.DISP_ATTR = dsmLib.DISP_ATTR
-- Initial Setup
local function Sim_Init()
local ctx = menuLib.DSM_Context
ctx.Phase = PHASE.INIT
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'
end
local function SIM_Done()
local ctx = menuLib.DSM_Context
ctx.Phase = PHASE.EXIT_DONE
end
SimLib.BACK_BUTTON = dsmLib.BACK_BUTTON
SimLib.NEXT_BUTTON = dsmLib.NEXT_BUTTON
SimLib.PREV_BUTTON = dsmLib.PREV_BUTTON
SimLib.MAX_MENU_LINES = dsmLib.MAX_MENU_LINES
local function SIM_Run()
if (menuLib.DSM_Context.Phase == PHASE.INIT) then
if (IS_EDGETX) then
menuLib.LoadTextFromFile(MSG_FILE,13)
menuLib.DSM_Context.Phase = PHASE.RX_VERSION
else -- Incremental initialization
lcd.clear()
lcd.drawText(30, 50, "Loading Msg file: "..(FileState.lineNo or 0))
if (menuLib.INC_LoadTextFromFile(MSG_FILE, FileState)==1) then
menuLib.DSM_Context.Phase = PHASE.RX_VERSION
end
return
end
end
return SIM_Send_Receive()
end
-- Export Shared Context Variables
SimLib.DSM_Context = dsmLib.DSM_Context
-- Export Functions
SimLib.LOG_write = dsmLib.LOG_write
SimLib.LOG_close = dsmLib.LOG_close
SimLib.getElapsedTime = dsmLib.getElapsedTime
SimLib.Get_Text = dsmLib.Get_Text
SimLib.Get_List_Text = dsmLib.Get_List_Text
SimLib.Get_List_Text_Img = dsmLib.Get_List_Text_Img
SimLib.phase2String = dsmLib.phase2String
SimLib.menu2String = dsmLib.menu2String
SimLib.menuLine2String = dsmLib.menuLine2String
SimLib.isSelectableLine = dsmLib.isSelectableLine
SimLib.isEditableLine = dsmLib.isEditableLine
SimLib.isListLine = dsmLib.isListLine
SimLib.isPercentValueLine = dsmLib.isPercentValueLine
SimLib.isNumberValueLine = dsmLib.isNumberValueLine
SimLib.isDisplayAttr = dsmLib.isDisplayAttr
SimLib.isFlightModeLine = dsmLib.isFlightModeLine
SimLib.GetFlightModeValue = dsmLib.GetFlightModeValue
SimLib.StartConnection = SIM_StartConnection -- Override Function
SimLib.ReleaseConnection = SIM_ReleaseConnection -- Override Function
SimLib.ChangePhase = dsmLib.ChangePhase
SimLib.Value_Add = dsmLib.Value_Add
SimLib.Value_Default = dsmLib.Value_Default
SimLib.Value_Write_Validate = dsmLib.Value_Write_Validate
SimLib.GotoMenu = dsmLib.GotoMenu
SimLib.MoveSelectionLine = dsmLib.MoveSelectionLine
SimLib.Send_Receive = SIM_Send_Receive -- Override Function
SimLib.Init = dsmLib.Init
SimLib.Init_Text = dsmLib.Init_Text
return SimLib
return { init=Sim_Init, run=SIM_Run, done=SIM_Done }

View File

@@ -6,10 +6,5 @@
T |0x0097|DONT USE: Factory Reset
T |0x0098|DONT USE: Factory Reset
T |0x00A5|DONT USE: First Time Setup
T |0x00B0|Self-Lev/Ang Dem
T |0x00CD|Level model & capt attitude
T |0x0190|DONT USE: Relearn Servo Settings
T |0x020D|DONT USE: First Time SAFE Setup
T |0x0254|Pos = Up, Neg = Down
T |0x0267|Pos = Nose Up/Roll Right
T |0x0268|Neg = Nose Down/Roll Left

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.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

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.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -9,7 +9,7 @@ LT|0x0003|Inh
LT|0x0004|Act
--
-- Channel selection for SAFE MODE and GAINS on FC6250HX
LT|0x000C|Inhibit?
LT|0x000C|Inh
LT|0x000D|Ch5
LT|0x000E|Ch6
LT|0x000F|Ch7
@@ -29,7 +29,7 @@ LT|0x0032|1 X
LT|0x0033|2 X
LT|0x0034|4 X
--
LT|0x0035|Inh?
LT|0x0035|Inh
LT|0x0036|Thr
LT|0x0037|Ail
LT|0x0038|Ele
@@ -69,9 +69,13 @@ 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|Inhibit
--LT|0x005E|Inh
LT|0x005F|Hold Last
LT|0x0060|Preset
--LT|0x0061|Custom
@@ -79,8 +83,8 @@ LT|0x0060|Preset
T |0x0071|Proportional
T |0x0072|Integral
T |0x0073|Derivate
--
T |0x0078|FM Channel
T |0x007F|Attitude Gain
--
T |0x0080|Orientation
T |0x0082|Heading
@@ -93,18 +97,46 @@ 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
--
-- FC6250HX: Callibration Menu -> Begin..Start, Complete, Done
T |0x0091|Begin
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
@@ -115,11 +147,11 @@ T |0x00A5|First Time Setup
T |0x00AA|Capture Gyro Gains
T |0x00AD|Gain Channel Select
T |0x00AF|Dynamic
T |0x00B0|Self-Level/Angle Dem
T |0x00B1|Envelope
LT|0x00B0|Self-Level
LT|0x00B1|Envelope
--
-- Flight Modes List Options
LT|0x00B5|Inhibit
LT|0x00B5|Inh
LT|0x00B6|FM1
LT|0x00B7|FM2
LT|0x00B8|FM3
@@ -134,9 +166,13 @@ LT|0x00BF|FM10
T |0x00BE|Unknown_BE -- Used in Reset menu (0x0001) while the RX is rebooting
--
T |0x00C7|Calibrate Sensor
T |0x00CA|SAFE/Panic Mode Setup
T |0x00C8|Sensor is Calibrating.. Wait
T |0x00CA|SAFE & Panic Mode Setup
--
T |0x00CD|Level model and capture attitude/m -- SPECIAL MENU to itself who is not a comment
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
@@ -190,6 +226,16 @@ 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
@@ -204,14 +250,21 @@ 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
@@ -222,13 +275,15 @@ 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| -- Blank
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| -- Blank
T |0x010A|
T |0x010B|
--
T |0x0190|Relearn Servo Settings
T |0x019C|Enter Receiver Bind Mode
@@ -249,6 +304,7 @@ 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
@@ -267,14 +323,14 @@ T |0x020D|First Time SAFE Setup
T |0x020E|AS3X gains must be tuned
T |0x020F|and active in SAFE Flight Modes
T |0x0210|to help reduce wobble.
T |0x0211| -- Blank
T |0x0212| -- Blank
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| -- Blank
T |0x021C|
T |0x021D| -- Blank
--
-- AS3X orientation Setting menu (Nose down)
@@ -283,8 +339,8 @@ 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
@@ -301,7 +357,7 @@ T |0x0230| -- Blank
T |0x0231|This will overwrite the
T |0x0232|backup memory with your
T |0x0233|current configuartion.
T |0x0234| -- Blank
T |0x0234|
T |0x0235| -- Blank
--
-- Restore from Backup Warning
@@ -309,7 +365,7 @@ 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 line
T |0x023A| -- Blank
--
-- Utilities Copy flight modes
T |0x023D|Copy F-Mode Settings
@@ -330,7 +386,7 @@ T |0x0251|Are you sure you want to ovewrite the "Target"
T |0x0252|with the "Source" ?
T |0x0253| -- Blank
--
T |0x0254|Postive = Up, Negative = Down
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
@@ -341,7 +397,7 @@ T |0x0257|most be configured.
T |0x025A|Select the desired flight mode
T |0x025B|switch position to adjust settings
T |0x025C|for each flight mode
T |0x025D| -- Blank
T |0x025D|
T |0x025E| -- Blank
--
-- Utilities, Copy flight mode (Confirm)
@@ -352,11 +408,17 @@ T |0x0262|by "Source"
--
T |0x0263|Fixed/Adjustable Gains/c/b
T |0x0266|Heading Gain/c/b
T |0x0267|Positive = Nose Up/Roll Right
T |0x0268|Negative = Nose Down/Roll Left
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
--

View File

@@ -4,224 +4,19 @@ Rewrite/Enhancements by: Francisco Arzu
Thanks to all the people volunteered to test it.
# Introduction (v0.54)
Release Notes for
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.
## COLOR Radios
Read more [Color radios](./readme_color.md)
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).
![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)
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 configuration and stores it in the RX.
## Black & White Radios (Small Screens)
Read more [black & whire radios](./readme_bw.md)
# Deployment
Make sure to manually create `/MODELS/DSMDATA` . The script will complain at startup if it does not exist. Here the script saves the Spektrun settings for each of your models.
![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)
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 your images, inside "DSMLIB/img" do a backup first)
Copy the entire DSMLIB folder.
Copy the main script you want to use (Color or B&W).
Your TX SDCard should looks like this:
/SCRIPTS/TOOLS
DSM FwdPrg_05_BW.lua -- black/white text only
DSM FwdPrg_05_Color.lua -- Color and touch radios
DSM FwdPrg_05_MIN.lua -- `NEW!` Minimalistic version for radios with LOW memory (cannot setup new planes)
/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
/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
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)
# Common Questions
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
V0.53 and newer: 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. `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.
3. `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.
4. `Reversing a channel in my TX do not reverse the AS3X/SAFE reaction.` Correct, the channel stick direction and the Gyro direction are two separate things.
4.1: First, you have setup your model so that the sticks and switches moves the surfaces in the right direction.
4.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.
4.3: AR63X family: Go to `Forward programming->Gyro Setting->Initial Setup` (New/factory reset), or `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` (not new RX). This will load your current Gyro servo settings into the plane's RX.
4.4: Verify that the AS3X and SAFE reacts in the proper direction. You can use the Flight mode confugured as "Safe Mode: Auto-Level" to see if it moves the surfaces in the right direction.
4.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.
4.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.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_en.txt and msg_MIN_es.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)
- AR636 (Blade 230S V1 Heli firmware 4.40)
- Radiomaster TX16S (All versions)
- FrSky QX7, Radimaster Boxter (Minimalistic version)
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,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

@@ -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
@@ -88,6 +89,8 @@
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
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
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
@@ -118,9 +121,10 @@
49,0,KF606,KF606,1,Trim
49,1,KF606,MIG320,1,Trim,LED
49,2,KF606,ZCZ50,1,Trim,UNK
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
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
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
@@ -154,7 +158,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
@@ -165,10 +170,10 @@
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
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,TQ,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
@@ -184,7 +189,8 @@
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
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
@@ -197,7 +203,7 @@
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
84,0,JOYSWAY,Std,0
85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH
87,0,IKEA
@@ -207,3 +213,9 @@
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,Std,1,Mode,Flip,LED,Pict,Video,TrRes
61,1,EazyRC
98,0,Kyosho3,ASF,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,15 +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
This is a work in progress. It's available for color(+touch) and B&W screens.
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!
Work on OpenTX and EdgeTX. Located on the radio SD card under \SCRIPTS\TOOLS, make sure to copy the DSMLIB folder along with DSM FwdPrg_05_Color.lua or DSM FwdPrg_05_BW.lua.
[![DSM Forward Programming](https://img.youtube.com/vi/sjIaDw5j9nE/0.jpg)](https://www.youtube.com/watch?v=sjIaDw5j9nE)
If some text appears as Unknown_xxx, please report xxx and what the exact text display should be.
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

@@ -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
@@ -250,8 +276,18 @@ 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)
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
@@ -265,12 +301,7 @@ uint16_t DSM_callback()
uint8_t len;
#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:
@@ -284,11 +315,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:
@@ -304,10 +338,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;
@@ -332,6 +368,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 ;
}
@@ -343,25 +382,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]);
@@ -398,14 +450,19 @@ 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 11000 - DSM_WRITE_DELAY - DSM_READ_DELAY;
}
#endif
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
case DSM_CH2_READ_A:
@@ -440,10 +497,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)
@@ -464,19 +517,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
}
@@ -484,6 +538,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 },
@@ -507,32 +562,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
@@ -544,7 +640,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];
@@ -568,9 +664,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

@@ -53,9 +53,11 @@ 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, flag 0x04 is also set on this heli
| GET_FLAG(CH11_SW, 0x08); // C129V2 flip
// Other flags in packet[3] => 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
//Channels and trims
uint16_t val = convert_channel_10b(AILERON,false);
uint8_t trim = convert_channel_8b(CH7) & 0xFC;
@@ -80,13 +82,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

@@ -33,7 +33,7 @@ Multiprotocol is distributed in the hope that it will be useful,
#define FX620_PAYLOAD_SIZE 7
#define FX620_CH_OFFSET 1
#define FX9630_PACKET_PERIOD 8124
#define FX9630_PACKET_PERIOD 8124 //8156 on QIDI-560
#define FX9630_BIND_PACKET_PERIOD 8124
#define FX9630_BIND_CHANNEL 51
#define FX9630_PAYLOAD_SIZE 8
@@ -41,18 +41,30 @@ Multiprotocol is distributed in the hope that it will be useful,
//#define FORCE_FX620_ID
//#define FORCE_FX9630_ID
//#define FORCE_QIDI_ID
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)
{
if(sub_protocol >= FX9630)
{ // FX9630 & FX_Q560
XN297_SetTXAddr(rx_tx_addr, 4);
if (hopping_frequency_no > FX9630_NUM_CHANNELS)
if (hopping_frequency_no >= FX9630_NUM_CHANNELS)
{
hopping_frequency_no = 0;
if(sub_protocol == FX9630)
{
trim_ch++;
if(trim_ch > 3) trim_ch = 0;
}
else // FX_Q560
trim_ch = 0;
}
}
else // FX816 and FX620
{
@@ -64,15 +76,21 @@ static void __attribute__((unused)) FX_send_packet()
//Channels
uint8_t val;
if (sub_protocol == FX9630)
{
if (sub_protocol >= FX9630)
{ // FX9630 & FX_Q560
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);
packet[4] = 0x20;
packet[5] = GET_FLAG(CH5_SW, 0x01); // DR toggle swich: 0 small throw, 1 large throw
packet[5] |= (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x02 : 0x01)) << 1; // Mode A(0) : 6D small throw, B(1) : 6D large throw, C(2) : 3D
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, 0x01) // DR toggle swich: 0 small throw, 1 large throw
// FX9630 =>0:6G small throw, 1:6G large throw, 2:3D
// QIDI-550=>0:3D, 1:6G, 2:Torque
| (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, 0x10);
}
else // FX816 and FX620
{
@@ -112,7 +130,7 @@ static void __attribute__((unused)) FX_send_packet()
packet[5] = 0xAB; // Is it based on ID??
}
}
else // FX9630
else // FX9630 & FX_Q560
{
if(IS_BIND_IN_PROGRESS)
{
@@ -125,12 +143,12 @@ static void __attribute__((unused)) FX_send_packet()
//Check
uint8_t last_packet_idx = packet_length-1;
if (sub_protocol == FX9630 && IS_BIND_IN_PROGRESS)
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)
if (sub_protocol >= FX9630)
val = val ^ 0xFF;
packet[last_packet_idx]=val;
@@ -164,7 +182,7 @@ static void __attribute__((unused)) FX_RF_init()
packet_period = FX620_BIND_PACKET_PERIOD;
packet_length = FX620_PAYLOAD_SIZE;
}
else // FX9630
else // FX9630 & FX_Q560
{
XN297_SetTXAddr((uint8_t *)"\x56\x78\x90\x12", 4);
XN297_RFChannel(FX9630_BIND_CHANNEL);
@@ -196,16 +214,25 @@ static void __attribute__((unused)) FX_initialize_txid()
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
hopping_frequency[i] = i*10 + hopping_frequency[0];
}
else // FX9630
else // FX9630 & FX_Q560
{
#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
memcpy(hopping_frequency,"\x13\x1A\x38", FX9630_NUM_CHANNELS); //Original dump=>19=0x13,26=0x1A,56=0x38
#else
hopping_frequency[0] = 0x13; // constant
hopping_frequency[0] = 0x13; // constant???
hopping_frequency[1] = RX_num & 0x0F + 0x1A;
hopping_frequency[2] = rx_tx_addr[3] & 0x0F + 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
//??? Need to find out how the first RF channel is calculated ???
}
}

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);

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()

View File

@@ -35,8 +35,7 @@ enum PktState {
J6PRO_CHAN_4,
};
const uint8_t PROGMEM j6pro_bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49};
const uint8_t j6pro_data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f};
const uint8_t j6pro_data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f}; // unneeded since this is the default table after a reset
static void __attribute__((unused)) j6pro_build_bind_packet()
{
@@ -84,7 +83,9 @@ static void __attribute__((unused)) j6pro_cyrf_init()
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xee);
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x00);
CYRF_ConfigDataCode(j6pro_data_code, 16);
//Same as default reset but issues if not configured...
CYRF_ConfigDataCode(j6pro_data_code);
CYRF_WritePreamble(0x333302);
CYRF_GetMfgData(cyrfmfg_id);
@@ -97,7 +98,7 @@ static void __attribute__((unused)) cyrf_bindinit()
/* Use when binding */
CYRF_SetPower(0x28); //Deviation using max power, replaced by bind power...
//CYRF_ConfigRFChannel(0x52);
CYRF_PROGMEM_ConfigSOPCode(j6pro_bind_sop_code);
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[19]);
CYRF_ConfigCRCSeed(0x0000);
//CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
//CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80);
@@ -122,7 +123,7 @@ static void __attribute__((unused)) j6pro_set_radio_channels()
{
//FIXME: Query free channels
//lowest channel is 0x08, upper channel is 0x4d?
CYRF_FindBestChannels(hopping_frequency, 3, 5, 8, 77);
CYRF_FindBestChannels(hopping_frequency, 3, 5, 8, 77, FIND_CHANNEL_ANY);
hopping_frequency[3] = hopping_frequency[0];
}

View File

@@ -63,7 +63,7 @@ enum {
KN_FLAG_DR = 0x01, // Dual Rate: 1 - full range
KN_FLAG_TH = 0x02, // Throttle Hold: 1 - hold
KN_FLAG_IDLEUP = 0x04, // Idle up: 1 - 3D
KN_FLAG_RES1 = 0x08,
KN_FLAG_RES1 = 0x08, // HoverDebugging
KN_FLAG_RES2 = 0x10,
KN_FLAG_RES3 = 0x20,
KN_FLAG_GYRO3 = 0x40, // 0 - 6G mode, 1 - 3G mode
@@ -141,19 +141,13 @@ static void __attribute__((unused)) kn_update_packet_control_data()
packet[8] = convert_channel_16b_limit(CH9,0,200); // 0x64; // T
packet[9] = convert_channel_16b_limit(CH10,0,200); // 0x64; // A
packet[10] = convert_channel_16b_limit(CH11,0,200); // 0x64; // E
packet[11] = 0x64; // R
packet[11] = convert_channel_16b_limit(CH12,0,200); // 0x64; // R
flags=0;
if (CH5_SW)
flags = KN_FLAG_DR;
if (CH6_SW)
flags |= KN_FLAG_TH;
if (CH7_SW)
flags |= KN_FLAG_IDLEUP;
if (CH8_SW)
flags |= KN_FLAG_GYRO3;
packet[12] = flags;
packet[12] = GET_FLAG(CH5_SW, KN_FLAG_DR)
|GET_FLAG(CH6_SW, KN_FLAG_TH)
|GET_FLAG(CH7_SW, KN_FLAG_IDLEUP)
|GET_FLAG(CH8_SW, KN_FLAG_GYRO3)
|GET_FLAG(CH13_SW, KN_FLAG_RES1); //Hover debugging
packet[13] = 0x00;
if(sub_protocol==WLTOYS)

View File

@@ -0,0 +1,121 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(KYOSHO3_CYRF6936_INO)
#include "iface_cyrf6936.h"
//#define KYOSHO3_FORCE_ID
//#define KYOSHO3_DEBUG
#define KYOSHO3_BIND_PACKET_SIZE 4
#define KYOSHO3_PACKET_SIZE 9
const uint8_t PROGMEM KYOSHO3_init_vals[][2] = {
//Init from dump
{CYRF_0B_PWR_CTRL, 0x00}, // PMU
{CYRF_32_AUTO_CAL_TIME, 0x3C}, // Default init value
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
{CYRF_03_TX_CFG, 0x28 | CYRF_BIND_POWER}, // 8DR Mode, 64 chip codes
{CYRF_10_FRAMING_CFG, 0xA4}, // SOP and LEN enable
{CYRF_1F_TX_OVERRIDE, 0x05}, // Disable CRC, Data invert
{CYRF_1E_RX_OVERRIDE, 0x04}, // CRC check disabled
//{CYRF_11_DATA32_THOLD, 0x04}, // ???Using 64 chip...
{CYRF_12_DATA64_THOLD, 0x0E}, // Default
{CYRF_06_RX_CFG, 0x52}, // AGC disabled, LNA enabled, override enabled
};
static uint16_t __attribute__((unused)) KYOSHO3_send_packet()
{
CYRF_SetPower(0x28);
if(IS_BIND_IN_PROGRESS)
{
if(--bind_counter==0)
BIND_DONE;
packet[0] = 0xAA;
//ID
memcpy(&packet[1],&rx_tx_addr[1],3);
CYRF_WriteDataPacketLen(packet, KYOSHO3_BIND_PACKET_SIZE);
#ifdef KYOSHO3_DEBUG
debug("P:");
for(uint8_t i=0;i<KYOSHO3_BIND_PACKET_SIZE;i++)
debug(" %02X",packet[i]);
debugln("");
#endif
return 2434;
}
else
{
//ID
memcpy(packet,&rx_tx_addr[1],3);
//Channels
for(uint8_t i=0;i<4;i++)
{
packet[3] >>= 2;
packet[3] |= Channel_data[i]<<6;
packet[4+i] = Channel_data[i]>>3;
}
//Checksum
packet[8] = packet[3];
for(uint8_t i=4;i<8;i++)
packet[8] += packet[i];
//Timing
phase ^= 0x01;
CYRF_WriteDataPacketLen(packet, KYOSHO3_PACKET_SIZE);
#ifdef KYOSHO3_DEBUG
debug("P:");
for(uint8_t i=0;i<KYOSHO3_PACKET_SIZE;i++)
debug(" %02X",packet[i]);
debugln("");
#endif
if(phase)
return 9047;
}
return 6957;
}
uint16_t KYOSHO3_callback()
{
return KYOSHO3_send_packet();
}
void KYOSHO3_init()
{
//Config CYRF registers
for(uint8_t i = 0; i < sizeof(KYOSHO3_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&KYOSHO3_init_vals[i][0]), pgm_read_byte_near(&KYOSHO3_init_vals[i][1]));
CYRF_WritePreamble(0x333304);
//Find a free even channel
CYRF_FindBestChannels(hopping_frequency,1,1,0x04,0x50, FIND_CHANNEL_EVEN);
#ifdef KYOSHO3_FORCE_ID // data taken from TX dump
rx_tx_addr[1] = 0x01;
rx_tx_addr[2] = 0xAB;
rx_tx_addr[3] = 0x31;
hopping_frequency[0] = 0x04;
#endif
#ifdef KYOSHO3_DEBUG
debugln("ID: %02X %02X %02X",rx_tx_addr[1],rx_tx_addr[2],rx_tx_addr[3]);
debugln("RF CH: %02X",hopping_frequency[0]);
#endif
CYRF_ConfigRFChannel(hopping_frequency[0]);
bind_counter = 8217;
phase = 0;
}
#endif

View File

@@ -19,10 +19,12 @@
//#define KYOSHO_FORCE_ID_FHSS
//#define KYOSHO_FORCE_ID_HYPE
//#define KYOSHO_FORCE_ID_SYNCRO
//Kyosho constants & variables
#define KYOSHO_BIND_COUNT 2500
#ifndef MULTI_AIR
static void __attribute__((unused)) KYOSHO_send_packet()
{
//ID
@@ -32,7 +34,7 @@ static void __attribute__((unused)) KYOSHO_send_packet()
packet[4] = rx_tx_addr[3];
//unknown may be RX ID on some other remotes
memset(packet+5,0xFF,4);
if(IS_BIND_IN_PROGRESS)
{
packet[ 0] = 0xBC; // bind indicator
@@ -42,8 +44,9 @@ static void __attribute__((unused)) KYOSHO_send_packet()
//RF table
for(uint8_t i=0; i<16;i++)
packet[i+11]=hopping_frequency[i+(packet[9]<<4)];
//unknwon
packet[27] = 0x05;
//TX type
packet[27] = (bind_counter & 0x40) ? 0x05:0x07; // FHSS is 5 and Syncro is 7
//Unknown
packet[28] = 0x00;
memset(packet+29,0xFF,8);
//frequency hop during bind
@@ -55,13 +58,23 @@ static void __attribute__((unused)) KYOSHO_send_packet()
else
{
packet[ 0] = 0x58; // normal packet
//14 channels: steering, throttle, ...
for(uint8_t i = 0; i < 14; i++)
//FHSS 14 channels: steering, throttle, ...
//Syncro 6 channels: steering, throttle, ...
for(uint8_t i = 0; i < 14; i++) //needed? i < (sub_protocol==KYOSHO_FHSS?14:6); i++)
{
uint16_t temp=convert_channel_ppm(i);
packet[9 + i*2]=temp&0xFF; // low byte of servo timing(1000-2000us)
packet[10 + i*2]=(temp>>8)&0xFF; // high byte of servo timing(1000-2000us)
uint16_t temp = convert_channel_ppm(i);
packet[ 9 + i*2] = temp&0xFF; // low byte of servo timing(1000-2000us)
packet[10 + i*2] = (temp>>8)&0xFF; // high byte of servo timing(1000-2000us)
}
// if(sub_protocol==KYOSHO_SYNCRO) // needed?
// {
// memcpy(&packet[21],&hopping_frequency[11],6);
// packet[27] = 0x07;
// packet[28] = 0x00;
// memset(packet+29,0xFF,8);
// packet[34] = 0x0F;
// packet[36] = 0x0F;
// }
rf_ch_num=hopping_frequency[hopping_frequency_no];
hopping_frequency_no++;
packet[34] |= (hopping_frequency_no&0x0F)<<4;
@@ -76,6 +89,7 @@ static void __attribute__((unused)) KYOSHO_send_packet()
#endif
A7105_WriteData(37, rf_ch_num);
}
#endif //MULTI_AIR
static void __attribute__((unused)) KYOSHO_hype_send_packet()
{
@@ -150,10 +164,14 @@ uint16_t KYOSHO_callback()
telemetry_set_input_sync(packet_period);
#endif
}
if(sub_protocol==KYOSHO_FHSS)
KYOSHO_send_packet();
else//HYPE
if(sub_protocol==KYOSHO_HYPE)
KYOSHO_hype_send_packet();
else //FHSS && SYNCRO
#ifndef MULTI_AIR
KYOSHO_send_packet();
#else
SUB_PROTO_INVALID;
#endif
return packet_period;
}
@@ -162,7 +180,7 @@ void KYOSHO_init()
A7105_Init();
// compute channels from ID
calc_fh_channels(sub_protocol==KYOSHO_FHSS?32:15);
calc_fh_channels(sub_protocol==KYOSHO_HYPE?15:32);
hopping_frequency_no=0;
#ifdef KYOSHO_FORCE_ID_FHSS
@@ -172,6 +190,13 @@ void KYOSHO_init()
memcpy(hopping_frequency,"\x29\x4C\x67\x92\x31\x1C\x77\x18\x23\x6E\x81\x5C\x8F\x5A\x51\x94\x7A\x12\x45\x6C\x7F\x1E\x0D\x88\x63\x8C\x4F\x37\x26\x61\x2C\x8A",32);
}
#endif
#ifdef KYOSHO_FORCE_ID_SYNCRO
if(sub_protocol==KYOSHO_FHSS)
{
memcpy(rx_tx_addr,"\x00\xC2\x24\x00",4);
memcpy(hopping_frequency,"\x73\x12\x7D\x88\x63\x4A\x8D\x60\x57\x16\x5D\x8B\x25\x53\x6E\x3C\x41\x70\x20\x83\x2A\x19\x94\x2F\x91\x4C\x47\x36\x78\x10\x5A\x31",32);
}
#endif
if(sub_protocol==KYOSHO_HYPE)
{
MProtocol_id &= 0x00FF00FF;

View File

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

View File

@@ -421,7 +421,7 @@ uint16_t MLINK_callback()
case MLINK_PREP_DATA:
CYRF_ConfigDataCode(MLINK_Data_Code,16);
CYRF_ConfigDataCode(MLINK_Data_Code);
MLINK_CRC_Init += 0xED;
hopping_frequency_no = 0x00;
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
@@ -597,7 +597,7 @@ void MLINK_init()
{
packet_count = 0;
bind_counter = MLINK_BIND_COUNT;
CYRF_ConfigDataCode((uint8_t*)"\x6F\xBE\x32\x01\xDB\xF1\x2B\x01\xE3\x5C\xFA\x02\x97\x93\xF9\x02",16); //Bind data code
CYRF_ConfigDataCode((uint8_t*)"\x6F\xBE\x32\x01\xDB\xF1\x2B\x01\xE3\x5C\xFA\x02\x97\x93\xF9\x02"); //Bind data code
CYRF_ConfigRFChannel(MLINK_BIND_CHANNEL);
phase = MLINK_BIND_TX;
}

View File

@@ -83,7 +83,12 @@ enum{
enum{
// flags going to packet[6] (F949G)
FLAG_F949G_LIGHT = 0x01,
FLAG_F949G_RATES = 0x02,
FLAG_F949G_3D6G = 0x20,
FLAG_BF109_RATES = 0x01, // short press right
FLAG_BF109_LIGHT = 0x02, // short press left
FLAG_BF109_UNK1 = 0x08, // long press right
FLAG_BF109_UNK2 = 0x10, // long press left
};
enum{
// flags going to packet[6] (PA18)
@@ -248,9 +253,11 @@ static void __attribute__((unused)) MT99XX_send_packet()
#endif
break;
case F949G:
packet[6] = 0x02
| GET_FLAG( CH5_SW, FLAG_F949G_3D6G )
| GET_FLAG( CH6_SW, FLAG_F949G_LIGHT );
packet[6] = GET_FLAG( CH5_SW, FLAG_F949G_3D6G )
| GET_FLAG( CH6_SW, FLAG_F949G_LIGHT ) //FLAG_BF109_RATES
| GET_FLAG(!CH7_SW, FLAG_F949G_RATES ) //FLAG_BF109_LIGHT
| GET_FLAG( CH8_SW, FLAG_BF109_UNK1 ) //BF109 long press right, temporary flag
| GET_FLAG( CH9_SW, FLAG_BF109_UNK2 ); //BF109 long press left, temporary flag
packet[7] = 0x00;
break;
case PA18+8:

View File

@@ -3,12 +3,12 @@
3,FrskyD,D8,Cloned
4,Hisky,Hisky,HK310
5,V2x2,V2x2,JXD506,MR101
6,DSM,DSM2_1F,DSM2_2F,DSMX_1F,DSMX_2F,AUTO,DSMR_1F
6,DSM,DSM2_1F,DSM2_2F,DSMX_1F,DSMX_2F,AUTO,DSMR_1F,DSMR,DSM2_SFC
7,Devo,8CH,10CH,12CH,6CH,7CH
8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI
9,KN,WLTOYS,FEILUN
10,SymaX,SYMAX,SYMAX5C
11,SLT,SLT_V1,SLT_V2,Q100,Q200,MR100
11,SLT,SLT_V1,SLT_V2,Q100,Q200,MR100,V1_4CH
12,CX10,GREEN,BLUE,DM007,---,J3015_1,J3015_2,MK33041
13,CG023,CG023,YD829
14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE,DHD_D4,QX100
@@ -40,7 +40,7 @@
40,WFLY,WFR0x
41,BUGS
42,BUGSMINI,BUGSMINI,BUGS3H
43,Traxxas,RX6519
43,Traxxas,TQ
44,NCC1701
45,E01X,E012,E015
46,V911S,V911S,E119
@@ -55,11 +55,11 @@
55,Frsky_RX,Multi,CloneTX,EraseTX,CPPM
56,AFHDS2A_RX,Multi,CPPM
57,HoTT,Sync,No_Sync
58,FX,816,620,9630
58,FX,816,620,9630,Q560
59,Bayang_RX,Multi,CPPM
60,Pelikan,Pro,Lite,SCX24
61,Tiger
62,XK,X450,X420
61,EazyRC
62,XK,X450,X420,Cars
63,XN_DUMP,250K,1M,2M,AUTO
64,FrskyX2,CH_16,CH_8,EU_16,EU_8,Cloned
65,FrSkyR9,915MHz,868MHz,915_8ch,868_8ch,FCC,--,FCC_8ch,--_8ch
@@ -67,13 +67,13 @@
67,LR12,LR12,LR12_6ch
68,Skyartec
69,ESKYv2,150V2
70,DSM_RX,Multi,CPPM
70,DSM_RX,Multi,CloneTX,EraseTX,CPPM
71,JJRC345,JJRC345,SkyTmblr
72,Q90C
73,Kyosho,FHSS,Hype
74,RadioLink,Surface,Air,DumboRC
74,RadioLink,Surface,Air,DumboRC,RC4G
75,---
76,Realacc,R11
76,Realacc
77,OMP
78,M-Link
79,WFLY,RF20x
@@ -90,3 +90,8 @@
91,Xerall
92,MT99xx,PA18
93,Kyosho2,KT-17
94,Scorpio
95,BlueFly
96,BumbleB
97,SGF22
98,Kyosho3

View File

@@ -78,10 +78,9 @@ const char STR_SCANNER[] ="Scanner";
const char STR_FRSKY_RX[] ="FrSkyRX";
const char STR_AFHDS2A_RX[] ="FS2A_RX";
const char STR_HOTT[] ="HoTT";
const char STR_FX[] ="FX";
const char STR_FX[] ="FX";
const char STR_BAYANG_RX[] ="BayanRX";
const char STR_PELIKAN[] ="Pelikan";
const char STR_TIGER[] ="Tiger";
const char STR_XK[] ="XK";
const char STR_XN297DUMP[] ="XN297DP";
const char STR_FRSKYR9[] ="FrSkyR9";
@@ -105,6 +104,12 @@ const char STR_CONFIG[] ="Config";
const char STR_LOSI[] ="Losi";
const char STR_MOULDKG[] ="MouldKg";
const char STR_XERALL[] ="Xerall";
const char STR_SCORPIO[] ="Scorpio";
const char STR_BLUEFLY[] ="BlueFly";
const char STR_BUMBLEB[] ="BumbleB";
const char STR_SGF22[] ="SGF22";
const char STR_EAZYRC[] ="EazyRC";
const char STR_KYOSHO3[] ="Kyosho3";
const char STR_SUBTYPE_FLYSKY[] = "\x04""Std\0""V9x9""V6x6""V912""CX20";
const char STR_SUBTYPE_HUBSAN[] = "\x04""H107""H301""H501";
@@ -117,15 +122,15 @@ const char STR_SUBTYPE_FRSKYD[] = "\x06""D8\0 ""Cloned";
const char STR_SUBTYPE_HISKY[] = "\x05""Std\0 ""HK310";
const char STR_SUBTYPE_V2X2[] = "\x06""Std\0 ""JXD506""MR101\0";
#ifndef MULTI_EU
const char STR_SUBTYPE_DSM[] = "\x04""2 1F""2 2F""X 1F""X 2F""Auto""R 1F";
const char STR_SUBTYPE_DSM[] = "\x04""2 1F""2 2F""X 1F""X 2F""Auto""R 1F""2SFC";
#else
const char STR_SUBTYPE_DSM[] = "\x04""--->""--->""X 1F""X 2F""Auto""R 1F";
const char STR_SUBTYPE_DSM[] = "\x04""--->""--->""X 1F""X 2F""Auto""R 1F""----";
#endif
const char STR_SUBTYPE_DEVO[] = "\x04""8ch\0""10ch""12ch""6ch\0""7ch\0";
const char STR_SUBTYPE_YD717[] = "\x07""Std\0 ""SkyWlkr""Syma X4""XINXUN\0""NIHUI\0 ";
const char STR_SUBTYPE_KN[] = "\x06""WLtoys""FeiLun";
const char STR_SUBTYPE_SYMAX[] = "\x03""Std""X5C";
const char STR_SUBTYPE_SLT[] = "\x06""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0";
const char STR_SUBTYPE_SLT[] = "\x06""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0""V1_4ch";
const char STR_SUBTYPE_CX10[] = "\x07""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041";
const char STR_SUBTYPE_CG023[] = "\x05""Std\0 ""YD829";
const char STR_SUBTYPE_BAYANG[] = "\x07""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4\0""QX100\0 ";
@@ -143,7 +148,7 @@ const char STR_SUBTYPE_H83D[] = "\x07""Std\0 ""H20H\0 ""H20Mini""H30Min
const char STR_SUBTYPE_CORONA[] = "\x05""V1\0 ""V2\0 ""FD V3";
const char STR_SUBTYPE_HITEC[] = "\x07""Optima\0""Opt Hub""Minima\0";
const char STR_SUBTYPE_BUGS_MINI[] = "\x06""Std\0 ""Bugs3H";
const char STR_SUBTYPE_TRAXXAS[] = "\x04""6519";
const char STR_SUBTYPE_TRAXXAS[] = "\x03""TQ2""TQ1";
const char STR_SUBTYPE_E01X[] = "\x05""E012\0""E015\0";
const char STR_SUBTYPE_GD00X[] = "\x05""GD_V1""GD_V2";
const char STR_SUBTYPE_REDPINE[] = "\x04""Fast""Slow";
@@ -154,7 +159,7 @@ const char STR_SUBTYPE_XN297DUMP[] = "\x07""250Kbps""1Mbps\0 ""2Mbps\0 ""Auto\0
const char STR_SUBTYPE_ESKY150[] = "\x03""4ch""7ch";
const char STR_SUBTYPE_ESKY150V2[] = "\x05""150V2";
const char STR_SUBTYPE_V911S[] = "\x05""V911S""E119\0";
const char STR_SUBTYPE_XK[] = "\x04""X450""X420";
const char STR_SUBTYPE_XK[] = "\x04""X450""X420""Cars";
const char STR_SUBTYPE_FRSKYR9[] = "\x07""915MHz\0""868MHz\0""915 8ch""868 8ch""FCC\0 ""--\0 ""FCC 8ch""-- 8ch\0";
const char STR_SUBTYPE_ESKY[] = "\x03""Std""ET4";
const char STR_SUBTYPE_PROPEL[] = "\x04""74-Z";
@@ -164,26 +169,30 @@ const char STR_SUBTYPE_WFLY2[] = "\x05""RF20x";
const char STR_SUBTYPE_HOTT[] = "\x07""Sync\0 ""No_Sync";
const char STR_SUBTYPE_PELIKAN[] = "\x05""Pro\0 ""Lite\0""SCX24";
const char STR_SUBTYPE_V761[] = "\x05""3ch\0 ""4ch\0 ""TOPRC";
const char STR_SUBTYPE_RLINK[] = "\x07""Surface""Air\0 ""DumboRC";
const char STR_SUBTYPE_REALACC[] = "\x03""R11";
const char STR_SUBTYPE_RLINK[] = "\x07""Surface""Air\0 ""DumboRC""RC4G\0 ";
const char STR_SUBTYPE_KYOSHO[] = "\x04""FHSS""Hype";
const char STR_SUBTYPE_KYOSHO2[] = "\x05""KT-17";
const char STR_SUBTYPE_KYOSHO3[] = "\x03""ASF";
const char STR_SUBTYPE_FUTABA[] = "\x05""SFHSS";
const char STR_SUBTYPE_JJRC345[] = "\x08""JJRC345\0""SkyTmblr";
const char STR_SUBTYPE_MOULKG[] = "\x06""Analog""Digit\0";
const char STR_SUBTYPE_MOULDKG[] = "\x06""Analog""Digit\0";
const char STR_SUBTYPE_KF606[] = "\x06""KF606\0""MIG320""ZCZ50\0";
const char STR_SUBTYPE_E129[] = "\x04""E129""C186";
const char STR_SUBTYPE_FX[] = "\x04""816\0""620\0""9630";
const char STR_SUBTYPE_FX[] = "\x04""816\0""620\0""9630""Q560";
#define NO_SUBTYPE nullptr
#ifdef SEND_CPPM
const char STR_SUB_FRSKY_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX""CPPM\0 ";
const char STR_SUB_DSM_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX""CPPM\0 ";
#define FRCPPM 4
#define DSMCPPM 4
const char STR_CPPM[] = "\x05""Multi""CPPM\0";
#define NBR_CPPM 2
#else
const char STR_SUB_FRSKY_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX";
const char STR_SUB_DSM_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX";
#define FRCPPM 3
#define DSMCPPM 3
#define STR_CPPM NO_SUBTYPE
#define NBR_CPPM 0
#endif
@@ -217,6 +226,12 @@ const mm_protocol_definition multi_protocols[] = {
#if defined(BAYANG_RX_NRF24L01_INO)
{PROTO_BAYANG_RX, STR_BAYANG_RX, STR_CPPM, NBR_CPPM, OPTION_NONE, 0, 0, SW_NRF, BAYANG_RX_init, BAYANG_RX_callback },
#endif
#if defined(BLUEFLY_CCNRF_INO)
{PROTO_BLUEFLY, STR_BLUEFLY, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, BLUEFLY_init, BLUEFLY_callback },
#endif
#if defined(BUMBLEB_CCNRF_INO)
{PROTO_BUMBLEB, STR_BUMBLEB, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, BUMBLEB_init, BUMBLEB_callback },
#endif
#if defined(BUGS_A7105_INO)
{PROTO_BUGS, STR_BUGS, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_A7105, BUGS_init, BUGS_callback },
#endif
@@ -245,10 +260,10 @@ const mm_protocol_definition multi_protocols[] = {
{PROTO_DM002, STR_DM002, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, DM002_init, DM002_callback },
#endif
#if defined(DSM_CYRF6936_INO)
{PROTO_DSM, STR_DSM, STR_SUBTYPE_DSM, 6, OPTION_MAXTHR, 0, 1, SW_CYRF, DSM_init, DSM_callback },
{PROTO_DSM, STR_DSM, STR_SUBTYPE_DSM, 7, OPTION_MAXTHR, 0, 1, SW_CYRF, DSM_init, DSM_callback },
#endif
#if defined(DSM_RX_CYRF6936_INO)
{PROTO_DSM_RX, STR_DSM_RX, STR_CPPM, NBR_CPPM, OPTION_NONE, 0, 1, SW_CYRF, DSM_RX_init, DSM_RX_callback },
{PROTO_DSM_RX, STR_DSM_RX, STR_SUB_DSM_RX, DSMCPPM, OPTION_NONE, 0, 1, SW_CYRF, DSM_RX_init, DSM_RX_callback },
#endif
#if defined(E010R5_CYRF6936_INO)
{PROTO_E010R5, STR_E010R5, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CYRF, E010R5_init, E010R5_callback },
@@ -265,6 +280,9 @@ const mm_protocol_definition multi_protocols[] = {
#if defined(E129_CYRF6936_INO)
{PROTO_E129, STR_E129, STR_SUBTYPE_E129, 2, OPTION_NONE, 0, 0, SW_CYRF, E129_init, E129_callback },
#endif
#if defined(EAZYRC_NRF24L01_INO)
{PROTO_EAZYRC, STR_EAZYRC, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, EAZYRC_init, EAZYRC_callback },
#endif
#if defined(ESKY_NRF24L01_INO)
{PROTO_ESKY, STR_ESKY, STR_SUBTYPE_ESKY, 2, OPTION_NONE, 0, 1, SW_NRF, ESKY_init, ESKY_callback },
#endif
@@ -315,7 +333,7 @@ const mm_protocol_definition multi_protocols[] = {
{PROTO_FUTABA, STR_FUTABA, STR_SUBTYPE_FUTABA, 1, OPTION_RFTUNE, 1, 1, SW_CC2500, SFHSS_init, SFHSS_callback },
#endif
#if defined(FX_NRF24L01_INO)
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 3, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 4, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
#endif
#if defined(FY326_NRF24L01_INO)
{PROTO_FY326, STR_FY326, STR_SUBTYPE_FY326, 2, OPTION_NONE, 0, 0, SW_NRF, FY326_init, FY326_callback },
@@ -371,6 +389,9 @@ const mm_protocol_definition multi_protocols[] = {
#if defined(KYOSHO2_NRF24L01_INO)
{PROTO_KYOSHO2, STR_KYOSHO2, STR_SUBTYPE_KYOSHO2, 1, OPTION_NONE, 0, 0, SW_NRF, KYOSHO2_init, KYOSHO2_callback },
#endif
#if defined(KYOSHO3_CYRF6936_INO)
{PROTO_KYOSHO3, STR_KYOSHO3, STR_SUBTYPE_KYOSHO3, 1, OPTION_NONE, 0, 0, SW_CYRF, KYOSHO3_init, KYOSHO3_callback },
#endif
#if defined(LOLI_NRF24L01_INO)
{PROTO_LOLI, STR_LOLI, NO_SUBTYPE, 0, OPTION_NONE, 1, 0, SW_NRF, LOLI_init, LOLI_callback },
#endif
@@ -384,7 +405,7 @@ const mm_protocol_definition multi_protocols[] = {
{PROTO_MLINK, STR_MLINK, NO_SUBTYPE, 0, OPTION_NONE, 1, 0, SW_CYRF, MLINK_init, MLINK_callback },
#endif
#if defined(MOULDKG_NRF24L01_INO)
{PROTO_MOULDKG, STR_MOULDKG, STR_SUBTYPE_MOULKG, 2, OPTION_OPTION, 0, 0, SW_NRF, MOULDKG_init, MOULDKG_callback },
{PROTO_MOULDKG, STR_MOULDKG, STR_SUBTYPE_MOULDKG, 2, OPTION_OPTION, 0, 0, SW_NRF, MOULDKG_init, MOULDKG_callback },
#endif
#if defined(MT99XX_CCNRF_INO)
{PROTO_MT99XX, STR_MT99XX, STR_SUBTYPE_MT99, 8, OPTION_NONE, 0, 0, SW_NRF, MT99XX_init, MT99XX_callback },
@@ -417,10 +438,10 @@ const mm_protocol_definition multi_protocols[] = {
{PROTO_Q90C, STR_Q90C, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, Q90C_init, Q90C_callback },
#endif
#if defined(RLINK_CC2500_INO)
{PROTO_RLINK, STR_RLINK, STR_SUBTYPE_RLINK, 3, OPTION_RFTUNE, 0, 0, SW_CC2500, RLINK_init, RLINK_callback },
{PROTO_RLINK, STR_RLINK, STR_SUBTYPE_RLINK, 4, OPTION_RFTUNE, 0, 0, SW_CC2500, RLINK_init, RLINK_callback },
#endif
#if defined(REALACC_NRF24L01_INO)
{PROTO_REALACC, STR_REALACC, STR_SUBTYPE_REALACC, 1, OPTION_NONE, 0, 0, SW_NRF, REALACC_init, REALACC_callback },
{PROTO_REALACC, STR_REALACC, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, REALACC_init, REALACC_callback },
#endif
#if defined(REDPINE_CC2500_INO)
{PROTO_REDPINE, STR_REDPINE, STR_SUBTYPE_REDPINE, 2, OPTION_RFTUNE, 0, 0, SW_CC2500, REDPINE_init, REDPINE_callback },
@@ -428,6 +449,12 @@ const mm_protocol_definition multi_protocols[] = {
#if defined(SCANNER_CC2500_INO)
{PROTO_SCANNER, STR_SCANNER, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CC2500, SCANNER_init, SCANNER_callback },
#endif
#if defined(SCORPIO_CYRF6936_INO)
{PROTO_SCORPIO, STR_SCORPIO, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CYRF, SCORPIO_init, SCORPIO_callback },
#endif
#if defined(SGF22_NRF24L01_INO)
{PROTO_SGF22, STR_SGF22, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, SGF22_init, SGF22_callback },
#endif
#if defined(SHENQI_NRF24L01_INO)
{PROTO_SHENQI, STR_SHENQI, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, SHENQI_init, SHENQI_callback },
#endif
@@ -435,16 +462,13 @@ const mm_protocol_definition multi_protocols[] = {
{PROTO_SKYARTEC, STR_SKYARTEC, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 1, SW_CC2500, SKYARTEC_init, SKYARTEC_callback },
#endif
#if defined(SLT_CCNRF_INO)
{PROTO_SLT, STR_SLT, STR_SUBTYPE_SLT, 5, OPTION_RFTUNE, 0, 1, SW_NRF, SLT_init, SLT_callback },
{PROTO_SLT, STR_SLT, STR_SUBTYPE_SLT, 6, OPTION_RFTUNE, 0, 1, SW_NRF, SLT_init, SLT_callback },
#endif
#if defined(SYMAX_NRF24L01_INO)
{PROTO_SYMAX, STR_SYMAX, STR_SUBTYPE_SYMAX, 2, OPTION_NONE, 0, 0, SW_NRF, SYMAX_init, SYMAX_callback },
#endif
#if defined(TIGER_NRF24L01_INO)
{PROTO_TIGER, STR_TIGER, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, TIGER_init, TIGER_callback },
#endif
#if defined(TRAXXAS_CYRF6936_INO)
{PROTO_TRAXXAS, STR_TRAXXAS, STR_SUBTYPE_TRAXXAS, 1, OPTION_NONE, 0, 0, SW_CYRF, TRAXXAS_init, TRAXXAS_callback },
{PROTO_TRAXXAS, STR_TRAXXAS, STR_SUBTYPE_TRAXXAS, 2, OPTION_NONE, 0, 0, SW_CYRF, TRAXXAS_init, TRAXXAS_callback },
#endif
#if defined(V2X2_NRF24L01_INO)
{PROTO_V2X2, STR_V2X2, STR_SUBTYPE_V2X2, 3, OPTION_NONE, 0, 0, SW_NRF, V2X2_init, V2X2_callback },
@@ -469,7 +493,7 @@ const mm_protocol_definition multi_protocols[] = {
{PROTO_XERALL, STR_XERALL, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, XERALL_init, XERALL_callback },
#endif
#if defined(XK_CCNRF_INO)
{PROTO_XK, STR_XK, STR_SUBTYPE_XK, 2, OPTION_RFTUNE, 0, 0, SW_NRF, XK_init, XK_callback },
{PROTO_XK, STR_XK, STR_SUBTYPE_XK, 3, OPTION_RFTUNE, 0, 0, SW_NRF, XK_init, XK_callback },
#endif
#if defined(XN297DUMP_NRF24L01_INO)
{PROTO_XN297DUMP, STR_XN297DUMP, STR_SUBTYPE_XN297DUMP, 6, OPTION_RFCHAN, 0, 0, SW_NRF, XN297Dump_init, XN297Dump_callback },

View File

@@ -18,8 +18,8 @@
//******************
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_REVISION 3
#define VERSION_PATCH_LEVEL 25
#define VERSION_REVISION 4
#define VERSION_PATCH_LEVEL 9
#define MODE_SERIAL 0
@@ -89,7 +89,7 @@ enum PROTOCOLS
PROTO_FX = 58, // =>NRF24L01
PROTO_BAYANG_RX = 59, // =>NRF24L01
PROTO_PELIKAN = 60, // =>A7105
PROTO_TIGER = 61, // =>NRF24L01
PROTO_EAZYRC = 61, // =>NRF24L01
PROTO_XK = 62, // =>NRF24L01
PROTO_XN297DUMP = 63, // =>NRF24L01
PROTO_FRSKYX2 = 64, // =>CC2500
@@ -121,7 +121,13 @@ enum PROTOCOLS
PROTO_XERALL = 91, // =>NRF24L01
PROTO_MT99XX2 = 92, // =>NRF24L01, extension of MT99XX protocol
PROTO_KYOSHO2 = 93, // =>NRF24L01
PROTO_SCORPIO = 94, // =>CYRF6936
PROTO_BLUEFLY = 95, // =>CC2500 & NRF24L01
PROTO_BUMBLEB = 96, // =>CC2500 & NRF24L01
PROTO_SGF22 = 97, // =>NRF24L01
PROTO_KYOSHO3 = 98, // =>CYRF6936
PROTO_NANORF = 126, // =>NRF24L01
PROTO_TEST = 127, // =>CC2500
};
@@ -168,6 +174,13 @@ enum DSM
DSMX_2F = 3,
DSM_AUTO = 4,
DSMR = 5,
DSM2_SFC = 6,
};
enum DSM_RX
{
DSM_RX = 0,
DSM_CLONE = 1,
DSM_ERASE = 2,
};
enum YD717
{
@@ -189,11 +202,12 @@ enum SYMAX
};
enum SLT
{
SLT_V1 = 0,
SLT_V2 = 1,
Q100 = 2,
Q200 = 3,
MR100 = 4,
SLT_V1 = 0,
SLT_V2 = 1,
Q100 = 2,
Q200 = 3,
MR100 = 4,
SLT_V1_4 = 5,
};
enum CX10
{
@@ -349,7 +363,8 @@ enum REDPINE
};
enum TRAXXAS
{
RX6519 = 0,
TRAXXAS_TQ2 = 0,
TRAXXAS_TQ1 = 1,
};
enum ESKY150
{
@@ -365,6 +380,7 @@ enum XK
{
X450 = 0,
X420 = 1,
XK_CARS = 2,
};
enum XN297DUMP
{
@@ -440,6 +456,7 @@ enum RLINK
RLINK_SURFACE = 0,
RLINK_AIR = 1,
RLINK_DUMBORC = 2,
RLINK_RC4G = 3,
};
enum MOULDKG
{
@@ -462,6 +479,7 @@ enum FX
FX816 = 0,
FX620 = 1,
FX9630 = 2,
FX_Q560 = 3,
};
#define NONE 0
@@ -822,7 +840,9 @@ enum {
#define FRSKYX2_CLONE_EEPROM_OFFSET 873 // (1) format + (3) TX ID, 4 bytes, end is 877
#define DSM_RX_EEPROM_OFFSET 877 // (4) TX ID + format, 5 bytes, end is 882
#define MOULDKG_EEPROM_OFFSET 882 // RX ID, 3 bytes per model, end is 882+64*3=1074
//#define CONFIG_EEPROM_OFFSET 1074 // Current configuration of the multimodule
#define DSM_CLONE_EEPROM_OFFSET 1074 // (4) TX ID, (1) Initialized, end is 1079
#define TRAXXAS_EEPROM_OFFSET 1079 // RX ID and SOP index, 3 bytes per model id, end is 1079+192=1271
//#define CONFIG_EEPROM_OFFSET 1271 // Current configuration of the multimodule
/* STM32 Flash Size */
#ifndef DISABLE_FLASH_SIZE_CHECK
@@ -911,7 +931,6 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
FX 58
BAYANG_RX 59
PELIKAN 60
TIGER 61
XK 62
XN297DUMP 63
FRSKYX2 64
@@ -961,6 +980,10 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
DSMX_1F 2
DSMX_2F 3
DSM_AUTO 4
sub_protocol==DSM_RX
DSM_RX 0
DSM_CLONE 1
DSM_ERASE 2
sub_protocol==YD717
YD717 0
SKYWLKR 1
@@ -1088,7 +1111,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
RED_FAST 0
RED_SLOW 1
sub_protocol==TRAXXAS
RX6519 0
TQ 0
sub_protocol==ESKY150
ESKY150_4CH 0
ESKY150_7CH 1

View File

@@ -1199,9 +1199,9 @@ static void protocol_init()
modules_reset();
uint8_t index=0;
#if defined(FRSKYX_CC2500_INO) && defined(EU_MODULE)
if( ! ( (protocol == PROTO_FRSKYX || protocol == PROTO_FRSKYX2) && sub_protocol < 2 ) )
#endif
//#if defined(FRSKYX_CC2500_INO) && defined(MULTI_EU)
// if( ! ( (protocol == PROTO_FRSKYX || protocol == PROTO_FRSKYX2) && sub_protocol < 2 ) )
//#endif
while(multi_protocols[index].protocol != 0xFF)
{
if(multi_protocols[index].protocol==protocol)

View File

@@ -22,7 +22,7 @@
//#define PELIKAN_LITE_FORCE_ID
#define PELIKAN_LITE_FORCE_HOP // hop sequence creation is unknown
//#define PELIKAN_SCX24_FORCE_ID
#define PELIKAN_SCX24_FORCE_HOP // hop sequence creation is unknown
//#define PELIKAN_SCX24_FORCE_HOP // hop sequence creation is unknown
#define PELIKAN_BIND_COUNT 400 // 3sec
#define PELIKAN_BIND_RF 0x3C
@@ -30,6 +30,7 @@
#define PELIKAN_PACKET_PERIOD 7980
#define PELIKAN_LITE_PACKET_PERIOD 18000
#define PELIKAN_SCX24_PACKET_PERIOD 15069
#define PELIKAN_SCX_HOP_LIMIT 90
static void __attribute__((unused)) pelikan_build_packet()
{
@@ -37,9 +38,11 @@ static void __attribute__((unused)) pelikan_build_packet()
uint8_t sum;
uint16_t channel;
#ifndef MULTI_AIR
if(sub_protocol == PELIKAN_SCX24)
packet[0] = 0x11;
else //PELIKAN_PRO & PELIKAN_LITE
#endif
packet[0] = 0x15;
if(IS_BIND_IN_PROGRESS)
{
@@ -48,6 +51,7 @@ static void __attribute__((unused)) pelikan_build_packet()
packet[4] = rx_tx_addr[2];
packet[5] = rx_tx_addr[3];
#ifndef MULTI_AIR
if(sub_protocol == PELIKAN_SCX24)
{
packet[1] = 0x65; //??
@@ -55,6 +59,7 @@ static void __attribute__((unused)) pelikan_build_packet()
packet[7] = 0xAA; //??
}
else
#endif
{//PELIKAN_PRO & PELIKAN_LITE
packet[1] = 0x04; //version??
if(sub_protocol==PELIKAN_PRO)
@@ -70,6 +75,7 @@ static void __attribute__((unused)) pelikan_build_packet()
{
//ID
packet[1] = rx_tx_addr[0];
#ifndef MULTI_AIR
if(sub_protocol == PELIKAN_SCX24)
{
//ID
@@ -95,6 +101,7 @@ static void __attribute__((unused)) pelikan_build_packet()
packet_length = 14;
}
else
#endif
{//PELIKAN_PRO & PELIKAN_LITE
//ID
packet[7] = rx_tx_addr[1];
@@ -158,6 +165,13 @@ static void __attribute__((unused)) pelikan_build_packet()
uint16_t PELIKAN_callback()
{
#ifdef MULTI_AIR
if(sub_protocol == PELIKAN_SCX24)
{
SUB_PROTO_INVALID;
return 10000;
}
#endif
if(phase==0)
{
#ifndef FORCE_PELIKAN_TUNING
@@ -172,10 +186,12 @@ uint16_t PELIKAN_callback()
A7105_Strobe(A7105_STANDBY);
if(sub_protocol==PELIKAN_PRO)
A7105_WriteReg(A7105_03_FIFOI,0x28); //????
else if(sub_protocol==PELIKAN_SCX24)
A7105_WriteReg(A7105_03_FIFOI,0x0D);
else//PELIKAN_LITE
else if(sub_protocol==PELIKAN_LITE)
A7105_WriteID(MProtocol_id);
#ifndef MULTI_AIR
else // PELIKAN_SCX24
A7105_WriteReg(A7105_03_FIFOI,0x0D);
#endif
}
}
#ifdef MULTI_SYNC
@@ -216,6 +232,82 @@ static uint8_t pelikan_firstCh(uint8_t u, uint8_t l)
return 0;
}
static uint8_t pelikan_firstCh_scx(uint8_t i, uint8_t j)
{
uint8_t ch;
switch (j) {
case 0:
ch = 30;
break;
case 1:
case 2:
ch = (i * 4) + 42;
break;
case 3:
ch = (i * 2) + 36;
break;
case 4:
ch = (i * 8) + 54;
break;
case 5:
ch = 30;
break;
}
if (ch > PELIKAN_SCX_HOP_LIMIT)
{
do
{
ch -= 62;
} while (ch > PELIKAN_SCX_HOP_LIMIT);
}
switch (ch) {
case 48:
if (j == 3)
ch += 18;
else if (j == 4)
ch += 20;
else
ch += 40;
break;
case 40:
if (j == 4)
ch += 18;
break;
case 52:
if (j < 3)
ch -= 20;
else if (j == 4)
ch -= 10;
break;
case 66:
if (j < 3)
ch += 18;
else if (j == 4)
ch -= 22;
break;
case 72:
if (j < 3)
ch -= 10;
else if (j ==3)
ch -= 20;
else if (j == 4)
ch -= 36;
break;
case 74:
if (j == 4)
ch -= 20;
break;
case 86:
if (j == 4)
ch -= 48;
break;
}
return ch;
}
static uint8_t pelikan_adjust_value(uint8_t value, uint8_t addition, uint8_t limit)
{
uint8_t i;
@@ -234,6 +326,10 @@ static uint8_t pelikan_adjust_value(uint8_t value, uint8_t addition, uint8_t lim
value += addition;
i++;
}
if (value == 72) {
value += addition;
i++;
}
}
while (i > 0);
@@ -278,6 +374,121 @@ static void __attribute__((unused)) pelikan_init_hop()
debugln("");
}
#ifndef MULTI_AIR
const uint8_t PROGMEM scx_ch_map[4][PELIKAN_NUM_RF_CHAN] =
{
{0,1,2,26,27,28,23,24,25,20,21,22,17,18,19,14,15,16,11,12,13,8,9,10,5,6,7,4,3},
{0,1,2,28,25,26,27,24,21,22,23,20,17,18,19,16,13,14,15,12,9,10,11,8,5,6,7,3,4},
{0,1,27,28,25,26,23,24,21,22,19,20,17,18,15,16,13,14,11,12,9,10,7,8,5,6,3,4,2},
{0,1,28,1,4,2,23,26,22,24,27,25,17,20,16,18,21,19,11,14,10,12,15,13,27,8,6,7,9}
};
static void pelikan_shuffle(uint8_t j)
{
uint8_t temp[PELIKAN_NUM_RF_CHAN];
for (uint8_t i = 0; i < PELIKAN_NUM_RF_CHAN; i++)
temp[i] = hopping_frequency[pgm_read_byte_near(&scx_ch_map[j-1][i])];
for (uint8_t i = 0; i < PELIKAN_NUM_RF_CHAN; i++)
hopping_frequency[i] = temp[i];
}
static void __attribute__((unused)) pelikan_init_hop_scx()
{
rx_tx_addr[0] = 0x10;
rx_tx_addr[1] = (rx_tx_addr[1] + RX_num) % 192;
debugln("TX[0]: %02X TX[1]: %02X", rx_tx_addr[0], rx_tx_addr[1]);
uint8_t high = (rx_tx_addr[1]>>4);
uint8_t low = rx_tx_addr[1] & 0x0F;
int16_t i = (high * 10) + low - 23;
uint8_t j = 0;
if (i > 0)
j = 1;
if (i > 24)
{
do
{
i -= 24;
j++;
} while (i > 24);
}
debugln("H: %02X L: %02X I: %02X J: %02X", high, low, i, j);
uint8_t first_channel;
uint8_t last_channel;
uint8_t addition;
first_channel = pelikan_firstCh_scx(i, j);
if (j == 0)
last_channel = 42 - (high * 10) - low;
else
last_channel = 42 - i + 1;
if (last_channel == 24)
last_channel += 9;
if (last_channel == 36)
last_channel -= 10;
if (j == 0)
addition = (2 * i) + 54;
else if (j == 5)
addition = (2 * i) + 6;
else
addition = 56 - (2 * i);
hopping_frequency[0] = first_channel;
for (uint8_t i = 1; i < PELIKAN_NUM_RF_CHAN; i++)
{
hopping_frequency[i] = pelikan_add(hopping_frequency[i-1], addition, PELIKAN_SCX_HOP_LIMIT);
}
if (j > 0 && j < 5)
pelikan_shuffle(j);
if (j == 2)
{
hopping_frequency[PELIKAN_NUM_RF_CHAN - 2] = last_channel;
} else if (j == 4)
{
uint8_t t = (2 * i) + 36;
if (t == 48)
t += 18;
if (t == 72)
t -= 20;
hopping_frequency[1] = t;
hopping_frequency[PELIKAN_NUM_RF_CHAN - 5] = last_channel;
}
else
{
hopping_frequency[PELIKAN_NUM_RF_CHAN - 1] = last_channel;
}
#ifdef DEBUG_SERIAL
for (uint8_t i = 0; i < PELIKAN_NUM_RF_CHAN; i++)
debug("%02X ", hopping_frequency[i]);
debugln("");
#endif
}
#ifdef PELIKAN_SCX24_FORCE_HOP
const uint8_t PROGMEM pelikan_scx24_hopp[][PELIKAN_NUM_RF_CHAN] = {
/*TX1*/ { 0x1E,0x32,0x46,0x5A,0x44,0x58,0x2E,0x42,0x56,0x2C,0x40,0x54,0x2A,0x3E,0x52,0x28,0x3C,0x50,0x26,0x3A,0x4E,0x24,0x38,0x4C,0x22,0x36,0x4A,0x20,0x1A },
/*TX2*/ { 0x2C,0x44,0x1E,0x52,0x56,0x22,0x3A,0x3E,0x34,0x4C,0x26,0x5A,0x50,0x2A,0x42,0x38,0x2E,0x46,0x20,0x54,0x4A,0x24,0x3C,0x32,0x28,0x40,0x58,0x1B,0x4E },
/*TX3*/ { 0x3C,0x4C,0x1E,0x4A,0x5A,0x2C,0x58,0x2A,0x3A,0x56,0x28,0x38,0x26,0x36,0x46,0x34,0x44,0x54,0x42,0x52,0x24,0x50,0x22,0x32,0x4E,0x20,0x40,0x3E,0x17 },
/*TX4*/ { 0x46,0x32,0x1E,0x58,0x44,0x5A,0x56,0x42,0x2E,0x54,0x40,0x2C,0x52,0x3E,0x2A,0x50,0x3C,0x28,0x4E,0x3A,0x26,0x4C,0x38,0x24,0x4A,0x36,0x22,0x20,0x1A }
};
#endif //PELIKAN_SCX24_FORCE_HOP
#endif //MULTI_AIR
#ifdef PELIKAN_FORCE_ID
const uint8_t PROGMEM pelikan_hopp[][PELIKAN_NUM_RF_CHAN] = {
{ 0x5A,0x46,0x32,0x6E,0x6C,0x58,0x44,0x42,0x40,0x6A,0x56,0x54,0x52,0x3E,0x68,0x66,0x64,0x50,0x3C,0x3A,0x38,0x62,0x4E,0x4C,0x5E,0x4A,0x36,0x5C,0x34 }
@@ -289,12 +500,6 @@ const uint8_t PROGMEM pelikan_lite_hopp[][PELIKAN_NUM_RF_CHAN] = {
{ 0x46,0x2A,0x3E,0x5A,0x5C,0x24,0x4E,0x32,0x54,0x26,0x2C,0x34,0x56,0x1E,0x3A,0x3C,0x50,0x4A,0x2E,0x42,0x20,0x52,0x28,0x22,0x44,0x58,0x36,0x38,0x4C }
};
#endif
#ifdef PELIKAN_SCX24_FORCE_HOP
const uint8_t PROGMEM pelikan_scx24_hopp[][PELIKAN_NUM_RF_CHAN] = {
{ 0x1E,0x32,0x46,0x5A,0x44,0x58,0x2E,0x42,0x56,0x2C,0x40,0x54,0x2A,0x3E,0x52,0x28,0x3C,0x50,0x26,0x3A,0x4E,0x24,0x38,0x4C,0x22,0x36,0x4A,0x20,0x1A },
{ 0x2C,0x44,0x1E,0x52,0x56,0x22,0x3A,0x3E,0x34,0x4C,0x26,0x5A,0x50,0x2A,0x42,0x38,0x2E,0x46,0x20,0x54,0x4A,0x24,0x3C,0x32,0x28,0x40,0x58,0x1B,0x4E }
};
#endif
void PELIKAN_init()
{
@@ -341,22 +546,32 @@ void PELIKAN_init()
A7105_WriteID(MProtocol_id);
packet_period = PELIKAN_LITE_PACKET_PERIOD;
}
#ifndef MULTI_AIR
else// if(sub_protocol==PELIKAN_SCX24)
{
pelikan_init_hop_scx();
#if defined(PELIKAN_SCX24_FORCE_HOP)
// Hop frequency table
uint8_t num=rx_tx_addr[3] & 0x01;
if(num)
{//1
rx_tx_addr[0]=0x10; // hopping freq TX2
rx_tx_addr[1]=0x63; // hopping freq TX2
uint8_t num=rx_tx_addr[3] & 0x03;
switch(num)
{
case 1:
rx_tx_addr[0]=0x10; // hopping freq TX2
rx_tx_addr[1]=0x63; // hopping freq TX2
break;
case 2:
rx_tx_addr[0]=0x81; // hopping freq TX3
rx_tx_addr[1]=0x63; // hopping freq TX3
break;
case 3:
rx_tx_addr[0]=0x36; // hopping freq TX4
rx_tx_addr[1]=0x5C; // hopping freq TX4
break;
default:
rx_tx_addr[0]=0x12; // hopping freq TX1
rx_tx_addr[1]=0x46; // hopping freq TX1
break;
}
else
{//0
rx_tx_addr[0]=0x12; // hopping freq TX1
rx_tx_addr[1]=0x46; // hopping freq TX1
}
for(uint8_t i=0;i<PELIKAN_NUM_RF_CHAN;i++)
hopping_frequency[i]=pgm_read_byte_near(&pelikan_scx24_hopp[num][i]);
#endif
@@ -366,12 +581,17 @@ void PELIKAN_init()
rx_tx_addr[3]=0x19; // TX1
rx_tx_addr[2]=0x80; // TX2
rx_tx_addr[3]=0x22; // TX2
rx_tx_addr[2]=0x30; // TX3
rx_tx_addr[3]=0x18; // TX3
rx_tx_addr[2]=0x30; // TX4
rx_tx_addr[3]=0x17; // TX4
#endif
A7105_WriteReg(A7105_0E_DATA_RATE,0x03);
if(IS_BIND_DONE)
A7105_WriteReg(A7105_03_FIFOI,0x0D);
packet_period = PELIKAN_SCX24_PACKET_PERIOD;
}
#endif //MULTI_AIR
}
hopping_frequency_no = PELIKAN_NUM_RF_CHAN;

View File

@@ -18,7 +18,7 @@ Multiprotocol is distributed in the hope that it will be useful,
#include "iface_xn297.h"
#define FORCE_REALACC_ORIGINAL_ID
//#define FORCE_REALACC_ORIGINAL_ID
#define REALACC_INITIAL_WAIT 500
#define REALACC_PACKET_PERIOD 2268
@@ -30,7 +30,7 @@ Multiprotocol is distributed in the hope that it will be useful,
static void __attribute__((unused)) REALACC_send_packet()
{
packet[ 0]= 0xDC;
packet[ 0]= 0xDC; // DC/D6/DE
packet[ 1]= convert_channel_8b(AILERON); // 00..80..FF
packet[ 2]= convert_channel_8b(ELEVATOR); // 00..80..FF
packet[ 3]= convert_channel_8b(THROTTLE); // 00..FF
@@ -39,16 +39,17 @@ static void __attribute__((unused)) REALACC_send_packet()
packet[ 6]= 0x20; // Trim
packet[ 7]= 0x20; // Trim
packet[ 8]= 0x20; // Trim
packet[ 9]= num_ch; // Change at each power up
packet[10]= 0x04 // Flag1
packet[ 9]= 0x88; // Change at each power up: C5 A2 77 F0 84 58, fixed for the E017 = 88
packet[10]= 0x04 // Flag1: R11=04, E017=0C
| 0x02 // Rate1=0, Rate2=1, Rate3=2
| GET_FLAG(CH8_SW, 0x20); // Headless
packet[11]= 0x00 // Flag2
| GET_FLAG(CH7_SW, 0x01) // Calib
| GET_FLAG(CH9_SW, 0x20) // Return
| GET_FLAG(CH10_SW,0x80); // Unknown
| GET_FLAG(CH10_SW,0x80); // Throttle cut
packet[12]= 0x00 // Flag3
| GET_FLAG(CH5_SW, 0x01) // Flip
| GET_FLAG(CH11_SW,0x02) // Rotating
| GET_FLAG(CH6_SW, 0x80); // Light
XN297_Hopping(hopping_frequency_no);
@@ -59,31 +60,50 @@ static void __attribute__((unused)) REALACC_send_packet()
static void __attribute__((unused)) REALACC_send_bind_packet()
{
packet[0] = 0xB1;
memcpy(&packet[1],rx_tx_addr,4);
memcpy(&packet[5],hopping_frequency,5);
packet[0] = 0xB1; // B0/B1
memcpy(&packet[1],rx_tx_addr,4); // Address
memcpy(&packet[5],hopping_frequency,5); // RF frequencies
XN297_WriteEnhancedPayload(packet, REALACC_BIND_PAYLOAD_SIZE,1);
}
static void __attribute__((unused)) REALACC_initialize_txid()
{
rx_tx_addr[3] &= 0x3F;
calc_fh_channels(REALACC_RF_NUM_CHANNELS);
num_ch=random(0xfefefefe); // 00..FF
#ifdef FORCE_REALACC_ORIGINAL_ID
//Dump
rx_tx_addr[0]=0x99;
rx_tx_addr[1]=0x06;
rx_tx_addr[2]=0x00;
rx_tx_addr[3]=0x00;
hopping_frequency[0]=0x55;
hopping_frequency[1]=0x59;
hopping_frequency[2]=0x5A;
hopping_frequency[3]=0x5A;
hopping_frequency[4]=0x62;
num_ch=0xC5; // Value in dumps: C5 A2 77 F0 84 58
if(RX_num==0)
{//TX1
rx_tx_addr[0]=0x99;
rx_tx_addr[1]=0x06;
rx_tx_addr[2]=0x00;
rx_tx_addr[3]=0x00; // 00..3F:OK, 40..:NOK
hopping_frequency[0]=0x55;
hopping_frequency[1]=0x59;
hopping_frequency[2]=0x5A;
hopping_frequency[3]=0x5A;
hopping_frequency[4]=0x62;
}
else
{//TX2
rx_tx_addr[0]=0x4F;
rx_tx_addr[1]=0xB9;
rx_tx_addr[2]=0xA1;
rx_tx_addr[3]=0x17;
hopping_frequency[0]=0x45;
hopping_frequency[1]=0x38;
hopping_frequency[2]=0x3C;
hopping_frequency[3]=0x41;
hopping_frequency[4]=0x3F;
}
#endif
#if 0
debug("ID: %02X %02X %02X %02X, C: ",rx_tx_addr[0],rx_tx_addr[1],rx_tx_addr[2],rx_tx_addr[3]);
for(uint8_t i=0; i<REALACC_RF_NUM_CHANNELS; i++)
debug(" %02X",hopping_frequency[i]);
debugln("");
#endif
}
static void __attribute__((unused)) REALACC_RF_init()
@@ -129,18 +149,39 @@ void REALACC_init()
// Bind
// Address = 4D 41 49 4E = 'MAIN'
// Channel = 80 (most likely from dump)
// P(10) = B1 99 06 00 00 55 59 5A 5A 62
// B1 indicates bind packet
// TX1
// ---
// P(10) = B1 99 06 00 00 55 59 5A 5A 62
// Bx indicates bind packet, why x=1?
// 99 06 00 00 = ID = address of normal packets
// 55 59 5A 5A 62 = 85, 89, 90, 90, 98 = RF channels to be used (kind of match previous dumps)// Normal
// 55 59 5A 5A 62 = 85, 89, 90, 90, 98 = RF channels to be used (kind of match previous dumps)
// TX2
// ---
// P(10) = B0 4F B9 A1 17 45 38 3C 41 3F
// Bx indicates bind packet, why x=0?
// 4F B9 A1 17 = ID = address of normal packets
// 45 38 3C 41 3F = 69, 56, 60, 65, 63 = RF channels to be used
// Normal
// Address = 99 06 00 00
// Channels = 84, 89, 90, 90, 98 (guess from bind)
// P(13)= DC 80 80 32 80 20 20 20 20 58 04 00 00
// DC = normal packet
// 80 80 32 80 : AETR 00..80..FF
// 20 20 20 20 : Trims
// 58 : changing every time the TX restart
// 04 : |0x20=headless, |0x01=rate2, |0x02=rate3
// 00 : |0x01=calib, |0x20=return, |0x80=unknown
// 00 : |0x80=light, |0x01=flip
// TX1
// ---
// Address = 99 06 00 00
// Channels = 84, 89, 90, 90, 98 (guess from bind)
// P(13)= DC 80 80 32 80 20 20 20 20 58 04 00 00
// Dx = normal packet, why C ?
// 80 80 32 80 : AETR 00..80..FF
// 20 20 20 20 : Trims
// 58 : changing every time the TX restart
// 04 : |0x20=headless, |0x01=rate2, |0x02=rate3
// 00 : |0x01=calib, |0x20=return, |0x80=unknown
// 00 : |0x80=light, |0x01=flip
// TX2
// ---
// Address = 4F B9 A1 17
// P(13)= D6/DE 80 80 80 80 20 20 20 20 88 0C 00 00
// Dx = normal packet, why 6/E ?
// 80 80 32 80 : AETR 00..80..FF
// 20 20 20 20 : Trims
// 88 : not changing unknown
// 0C : |0x20=headless, |0x01=rate2, |0x02=rate3
// 00 : |0x01=calib, |0x20=return, |0x80=unknown
// 00 : |0x80=light, |0x01=flip, |0x02=Rotating

View File

@@ -18,7 +18,11 @@
#include "iface_cc2500.h"
//#define RLINK_DEBUG
//#define RLINK_DEBUG_TELEM
//#define RLINK_FORCE_ID
//#define RLINK_RC4G_FORCE_ID
#define RLINK_TX_PACKET_LEN 33
#define RLINK_RX_PACKET_LEN 15
@@ -97,16 +101,70 @@ static void __attribute__((unused)) RLINK_hop()
static void __attribute__((unused)) RLINK_TXID_init()
{
#ifdef RLINK_RC4G_FORCE_ID
//TODO: test any ID
if(sub_protocol==RLINK_RC4G)
{
rx_tx_addr[1]=0x77;
rx_tx_addr[2]=0x00;
rx_tx_addr[3]=0x00;
}
#endif
#ifdef RLINK_FORCE_ID
//surface RC6GS
memcpy(rx_tx_addr,"\x3A\x99\x22\x3A",RLINK_TX_ID_LEN);
//air T8FB
//memcpy(rx_tx_addr,"\xFC\x11\x0D\x20",RLINK_TX_ID_LEN);
if(sub_protocol==RLINK_SURFACE)
memcpy(rx_tx_addr,"\x3A\x99\x22\x3A",RLINK_TX_ID_LEN); //surface RC6GS
else
memcpy(rx_tx_addr,"\xFC\x11\x0D\x20",RLINK_TX_ID_LEN); //air T8FB
#endif
// channels order depend on ID
RLINK_hop();
if(sub_protocol!=RLINK_RC4G)
RLINK_hop();
else
{//RLINK_RC4G
// Find 2 unused channels
// first channel is a multiple of 3 between 00 and 5D
// second channel is a multiple of 3 between 63 and BD
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_17_MCSM1,0x3C);
CC2500_Strobe(CC2500_SFRX);
CC2500_SetTxRxMode(RX_EN);
CC2500_Strobe(CC2500_SRX);
delayMilliseconds(1); //wait for RX mode
uint16_t val;
uint8_t val_low = 0xFF;
hopping_frequency[0] = 0x00;
hopping_frequency[1] = 0x63;
for(uint8_t ch=0; ch<=0xBD; ch+=3)
{
if(ch==0x63)
val_low = 0xFF; //init for second block
if(ch==0x60)
continue; //skip channel
CC2500_WriteReg(CC2500_0A_CHANNR, ch); //switch channel
delayMicroseconds(370); //wait to read
val = 0;
for(uint8_t i=0;i<16;i++)
val += CC2500_ReadReg(CC2500_34_RSSI | CC2500_READ_BURST);
val >>= 4;
debug("C:%02X RSSI:%02X",ch,val);
if(val_low > val)
{
debug(" OK");
val_low = val;
hopping_frequency[ch<0x63?0:1]=ch; //save best channel
}
debugln("");
}
CC2500_WriteReg(CC2500_17_MCSM1,0x30);
CC2500_Strobe(CC2500_SIDLE);
CC2500_SetTxRxMode(TX_EN);
#ifdef RLINK_RC4G_FORCE_ID
hopping_frequency[0] = 0x03;
hopping_frequency[1] = 0x6F;
#endif
}
#if 0
#ifdef RLINK_DEBUG
debug("ID:");
for(uint8_t i=0;i<RLINK_TX_ID_LEN;i++)
debug(" 0x%02X",rx_tx_addr[i]);
@@ -138,7 +196,9 @@ static void __attribute__((unused)) RLINK_rf_init()
CC2500_WriteReg(4, 0xBA);
CC2500_WriteReg(5, 0xDC);
}
else if(sub_protocol==RLINK_RC4G)
CC2500_WriteReg(5, 0xA5);
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
CC2500_SetTxRxMode(TX_EN);
@@ -219,18 +279,79 @@ static void __attribute__((unused)) RLINK_send_packet()
packet_count++;
if(packet_count>5) packet_count=0;
//debugln("C= 0x%02X",hopping_frequency[pseudo & 0x0F]);
//debug("P=");
//for(uint8_t i=1;i<RLINK_TX_PACKET_LEN+1;i++)
// debug(" 0x%02X",packet[i]);
//debugln("");
#ifdef RLINK_DEBUG
debugln("C= 0x%02X",hopping_frequency[pseudo & 0x0F]);
debug("P=");
for(uint8_t i=1;i<RLINK_TX_PACKET_LEN+1;i++)
debug(" 0x%02X",packet[i]);
debugln("");
#endif
}
#ifndef MULTI_AIR
static void __attribute__((unused)) RLINK_RC4G_send_packet()
{
uint32_t val;
//hop
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[packet_count>>1]);
#ifdef RLINK_DEBUG
debug("C= 0x%02X ",hopping_frequency[packet_count>>1]);
#endif
// packet length
packet[0] = 0x0F;
//address
memcpy(&packet[1], &rx_tx_addr[1], 3);
//channels
for(uint8_t i=0;i<2;i++)
{
val = Channel_data[2*i ] +400 -24;
packet[4+i*2] = val;
packet[8+i ] = val>>8;
val = Channel_data[2*i+1] +400 -24;
packet[5+i*2] = val;
packet[8+i ] |= (val>>4) & 0xF0;
}
//special channel which is linked to gyro on the orginal TX but allocating it on CH5 here
packet[10] = convert_channel_16b_limit(CH5,0,100);
//failsafe
for(uint8_t i=0;i<4;i++)
packet[11+i] = convert_channel_16b_limit(CH6+i,0,200);
//next hop
packet_count++;
packet_count &= 0x03;
packet[15] = hopping_frequency[packet_count>>1];
// send packet
CC2500_WriteData(packet, 16);
#ifdef RLINK_DEBUG
debug("P=");
for(uint8_t i=1;i<16;i++)
debug(" 0x%02X",packet[i]);
debugln("");
#endif
}
#endif
#define RLINK_TIMING_PROTO 20000-100 // -100 for compatibility with R8EF
#define RLINK_TIMING_RFSEND 10500
#define RLINK_TIMING_CHECK 2000
#define RLINK_RC4G_TIMING_PROTO 14460
uint16_t RLINK_callback()
{
if(sub_protocol == RLINK_RC4G)
{
#ifndef MULTI_AIR
#ifdef MULTI_SYNC
telemetry_set_input_sync(RLINK_RC4G_TIMING_PROTO);
#endif
CC2500_SetPower();
CC2500_SetFreqOffset();
RLINK_RC4G_send_packet();
#else
SUB_PROTO_INVALID;
#endif
return RLINK_RC4G_TIMING_PROTO;
}
switch(phase)
{
case RLINK_DATA:
@@ -259,13 +380,16 @@ uint16_t RLINK_callback()
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
if (len == RLINK_RX_PACKET_LEN + 1 + 2) //Telemetry frame is 15 bytes + 1 byte for length + 2 bytes for RSSI&LQI&CRC
{
//debug("Telem:");
#ifdef RLINK_DEBUG_TELEM
debug("Telem:");
#endif
CC2500_ReadData(packet_in, len);
if(packet_in[0]==RLINK_RX_PACKET_LEN && (packet_in[len-1] & 0x80) && memcmp(&packet[2],rx_tx_addr,RLINK_TX_ID_LEN)==0 && packet_in[6]==packet[1])
{//Correct telemetry received: length, CRC, ID and type
//Debug
//for(uint8_t i=0;i<len;i++)
// debug(" %02X",packet_in[i]);
#ifdef RLINK_DEBUG_TELEM
for(uint8_t i=0;i<len;i++)
debug(" %02X",packet_in[i]);
#endif
TX_RSSI = packet_in[len-2];
if(TX_RSSI >=128)
TX_RSSI -= 128;
@@ -278,7 +402,9 @@ uint16_t RLINK_callback()
pps_counter++;
packet_count=0;
}
//debugln("");
#ifdef RLINK_DEBUG_TELEM
debugln("");
#endif
}
if (millis() - pps_timer >= 2000)
{//1 telemetry packet every 100ms

View File

@@ -0,0 +1,175 @@
/*
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 SGF22 R11
#if defined(SGF22_NRF24L01_INO)
#include "iface_xn297.h"
//#define FORCE_SGF22_ORIGINAL_ID
#define SGF22_PACKET_PERIOD 11950 //10240
#define SGF22_BIND_RF_CHANNEL 78
#define SGF22_PAYLOAD_SIZE 12
#define SGF22_BIND_COUNT 50
#define SGF22_RF_NUM_CHANNELS 4
//packet[8]
#define SGF22_FLAG_3D 0x00
#define SGF22_FLAG_ROLL 0x08
#define SGF22_FLAG_LIGHT 0x04
#define SGF22_FLAG_VIDEO 0x10
#define SGF22_FLAG_6G 0x40
#define SGF22_FLAG_VERTICAL 0xC0
//packet[9]
#define SGF22_FLAG_PHOTO 0x40
#define SGF22_FLAG_TRIMRESET 0x04
static void __attribute__((unused)) SGF22_send_packet()
{
if(IS_BIND_IN_PROGRESS)
{
packet[ 0] = 0x5B;
packet[ 8] = 0x00; // ??? do they have to be 0 for bind to succeed ?
packet[ 9] = 0x00; // ??? do they have to be 0 for bind to succeed ?
packet[10] = 0xAA;
packet[11] = 0x55;
}
else
{
//hop
XN297_Hopping(packet_sent & 0x03); // ??? from the dumps I can't really say how hop and seq are sync, there could be an offset (0,1,2,3)...
//sequence from 02 to 7A by increments of 4, sometimes with a flag 0x80 from 82 to FA, I can't tell from the dumps when the switch happens
if( (packet_sent & 0x03) == 0x02)
packet_count = packet_sent;
packet_sent++;
if(packet_sent > 0x7B)
packet_sent = 0;
//packet
packet[0] = 0x1B;
packet[8] = SGF22_FLAG_3D // default
| GET_FLAG(CH6_SW, SGF22_FLAG_ROLL) // roll
| GET_FLAG(CH7_SW, SGF22_FLAG_LIGHT) // push up throttle trim for light
| GET_FLAG(CH9_SW, SGF22_FLAG_VIDEO); // push down throttle trim for video
if(Channel_data[CH5] > CHANNEL_MIN_COMMAND)
packet[8] |= SGF22_FLAG_6G; // mode 1 - 6g
if(Channel_data[CH5] > CHANNEL_MAX_COMMAND)
packet[8] |= SGF22_FLAG_VERTICAL; // mode 0 - vertical
packet[9] = GET_FLAG(CH8_SW, SGF22_FLAG_PHOTO) // press in throttle trim for photo
| GET_FLAG(CH10_SW, SGF22_FLAG_TRIMRESET); // Both sticks down inwards
packet[10] = 0x42; // no fine tune
packet[11] = 0x10; // no fine tune
}
packet[1] = packet_count; // sequence
packet[2] = rx_tx_addr[2];
packet[3] = rx_tx_addr[3];
packet[4] = convert_channel_8b(THROTTLE);
packet[5] = convert_channel_8b(RUDDER);
packet[6] = convert_channel_8b(ELEVATOR);
packet[7] = convert_channel_8b(AILERON);
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WriteEnhancedPayload(packet, SGF22_PAYLOAD_SIZE,0);
#if 0
debug_time("");
for(uint8_t i=0; i<SGF22_PAYLOAD_SIZE; i++)
debug(" %02X",packet[i]);
debugln("");
#endif
}
static void __attribute__((unused)) SGF22_initialize_txid()
{
uint16_t val = ( rx_tx_addr[2] << 8 ) | rx_tx_addr[3];
if ( rx_tx_addr[2] > ( 0xFF - rx_tx_addr[3]) )
val--;
val %= 5;
const uint8_t hop[5][4] =
{ { 0x0C, 0x2A, 0x1B, 0x39 },
{ 0x0F, 0x2D, 0x1E, 0x3D },
{ 0x12, 0x31, 0x21, 0x41 },
{ 0x15, 0x34, 0x24, 0x44 },
{ 0x18, 0x37, 0x27, 0x47 } };
memcpy(hopping_frequency, &hop[val], SGF22_RF_NUM_CHANNELS);
/*//Same code sze...
hopping_frequency[0] = 0x0C + 3 * val;
hopping_frequency[1] = hopping_frequency[0] + 0x1E;
if(val > 1) hopping_frequency[1]++;
hopping_frequency[2] = hopping_frequency[0] + 0x0F;
hopping_frequency[3] = hopping_frequency[1] + 0x0F;
if(val ) hopping_frequency[3]++;*/
#ifdef FORCE_SGF22_ORIGINAL_ID
rx_tx_addr[2] = 0x1F; // TX2:27 TX3:2B
rx_tx_addr[3] = 0x61; // TX2:51 TX3:0C
memcpy(hopping_frequency,"\x15\x34\x24\x44", SGF22_RF_NUM_CHANNELS); //Original dump=>21=0x15,52=0x34,36=0x24,68=0x44
#endif
#if 0
debug("ID: %02X %02X, C: ",rx_tx_addr[2],rx_tx_addr[3]);
for(uint8_t i=0; i<SGF22_RF_NUM_CHANNELS; i++)
debug(" %02X",hopping_frequency[i]);
debugln("");
#endif
}
static void __attribute__((unused)) SGF22_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t*)"\xC7\x95\x3C\xBB\xA5", 5);
XN297_RFChannel(SGF22_BIND_RF_CHANNEL); // Set bind channel
}
uint16_t SGF22_callback()
{
if(phase == 0)
{
phase++;
#ifdef MULTI_SYNC
telemetry_set_input_sync(SGF22_PACKET_PERIOD);
#endif
SGF22_send_packet();
if(IS_BIND_IN_PROGRESS)
{
if(--bind_counter==0)
BIND_DONE;
}
}
else
{//send 3 times in total the same packet
NRF24L01_Strobe(REUSE_TX_PL);
phase++;
if(phase > 2)
{
phase = 0;
return SGF22_PACKET_PERIOD - 2*1550;
}
}
return 1550;
}
void SGF22_init()
{
BIND_IN_PROGRESS; // autobind protocol
SGF22_initialize_txid();
SGF22_RF_init();
bind_counter=SGF22_BIND_COUNT;
packet_sent = packet_count = 0x26; // TX2:26 TX3:26
phase = 0;
}
#endif

View File

@@ -21,11 +21,12 @@
//#define SLT_Q200_FORCE_ID
// For code readability
#define SLT_PAYLOADSIZE_V1 7
#define SLT_PAYLOADSIZE_V2 11
#define SLT_NFREQCHANNELS 15
#define SLT_TXID_SIZE 4
#define SLT_BIND_CHANNEL 0x50
#define SLT_PAYLOADSIZE_V1 7
#define SLT_PAYLOADSIZE_V1_4 5
#define SLT_PAYLOADSIZE_V2 11
#define SLT_NFREQCHANNELS 15
#define SLT_TXID_SIZE 4
#define SLT_BIND_CHANNEL 0x50
enum{
// flags going to packet[6] (Q200)
@@ -93,6 +94,12 @@ static void __attribute__((unused)) SLT_set_freq(void)
}
}
}
#if 0
debug("CH:");
for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i)
debug(" %02X", hopping_frequency[i]);
debugln();
#endif
//Bind channel
hopping_frequency[SLT_NFREQCHANNELS]=SLT_BIND_CHANNEL;
@@ -129,44 +136,47 @@ static void __attribute__((unused)) SLT_build_packet()
uint8_t e = 0; // byte where extension 2 bits for every 10-bit channel are packed
for (uint8_t i = 0; i < 4; ++i)
{
uint16_t v = convert_channel_10b(CH_AETR[i], false);
if(sub_protocol>SLT_V2 && (i==CH2 || i==CH3) )
uint16_t v = convert_channel_10b(sub_protocol != SLT_V1_4 ? CH_AETR[i] : i, false);
if(sub_protocol>SLT_V2 && (i==CH2 || i==CH3) && sub_protocol != SLT_V1_4)
v=1023-v; // reverse throttle and elevator channels for Q100/Q200/MR100 protocols
packet[i] = v;
e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0);
}
// Extra bits for AETR
packet[4] = e;
//->V1_4CH stops here
// 8-bit channels
packet[5] = convert_channel_8b(CH5);
packet[6] = convert_channel_8b(CH6);
if(sub_protocol!=SLT_V1)
{
if(sub_protocol==Q200)
packet[6] = GET_FLAG(CH9_SW , FLAG_Q200_FMODE)
|GET_FLAG(CH10_SW, FLAG_Q200_FLIP)
|GET_FLAG(CH11_SW, FLAG_Q200_VIDON)
|GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF);
else if(sub_protocol==MR100 || sub_protocol==Q100)
packet[6] = GET_FLAG(CH9_SW , FLAG_MR100_FMODE)
|GET_FLAG(CH10_SW, FLAG_MR100_FLIP)
|GET_FLAG(CH11_SW, FLAG_MR100_VIDEO) // Does not exist on the Q100 but...
|GET_FLAG(CH12_SW, FLAG_MR100_PICTURE); // Does not exist on the Q100 but...
packet[7]=convert_channel_8b(CH7);
packet[8]=convert_channel_8b(CH8);
packet[9]=0xAA; //normal mode for Q100/Q200, unknown for V2/MR100
packet[10]=0x00; //normal mode for Q100/Q200, unknown for V2/MR100
if((sub_protocol==Q100 || sub_protocol==Q200) && CH13_SW)
{//Calibrate
packet[9]=0x77; //enter calibration
if(calib_counter>=20 && calib_counter<=25) // 7 packets for Q100 / 3 packets for Q200
packet[10]=0x20; //launch calibration
calib_counter++;
if(calib_counter>250) calib_counter=250;
}
else
calib_counter=0;
//->V1 stops here
if(sub_protocol==Q200)
packet[6] = GET_FLAG(CH9_SW , FLAG_Q200_FMODE)
|GET_FLAG(CH10_SW, FLAG_Q200_FLIP)
|GET_FLAG(CH11_SW, FLAG_Q200_VIDON)
|GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF);
else if(sub_protocol==MR100 || sub_protocol==Q100)
packet[6] = GET_FLAG(CH9_SW , FLAG_MR100_FMODE)
|GET_FLAG(CH10_SW, FLAG_MR100_FLIP)
|GET_FLAG(CH11_SW, FLAG_MR100_VIDEO) // Does not exist on the Q100 but...
|GET_FLAG(CH12_SW, FLAG_MR100_PICTURE); // Does not exist on the Q100 but...
packet[7]=convert_channel_8b(CH7);
packet[8]=convert_channel_8b(CH8);
packet[9]=0xAA; //normal mode for Q100/Q200, unknown for V2/MR100
packet[10]=0x00; //normal mode for Q100/Q200, unknown for V2/MR100
if((sub_protocol==Q100 || sub_protocol==Q200) && CH13_SW)
{//Calibrate
packet[9]=0x77; //enter calibration
if(calib_counter>=20 && calib_counter<=25) // 7 packets for Q100 / 3 packets for Q200
packet[10]=0x20; //launch calibration
calib_counter++;
if(calib_counter>250) calib_counter=250;
}
else
calib_counter=0;
}
static void __attribute__((unused)) SLT_send_bind_packet()
@@ -186,6 +196,7 @@ static void __attribute__((unused)) SLT_send_bind_packet()
#define SLT_TIMING_BUILD 1000
#define SLT_V1_TIMING_PACKET 1000
#define SLT_V1_4_TIMING_PACKET 1643
#define SLT_V2_TIMING_PACKET 2042
#define SLT_V1_TIMING_BIND2 1000
#define SLT_V2_TIMING_BIND1 6507
@@ -195,8 +206,9 @@ uint16_t SLT_callback()
switch (phase)
{
case SLT_BUILD:
//debugln_time("b ");
#ifdef MULTI_SYNC
telemetry_set_input_sync(sub_protocol==SLT_V1?20000:13730);
telemetry_set_input_sync(packet_period);
#endif
SLT_build_packet();
NRF250K_SetPower(); //Change power level
@@ -206,42 +218,39 @@ uint16_t SLT_callback()
case SLT_DATA1:
case SLT_DATA2:
phase++;
SLT_send_packet(packet_length);
if(sub_protocol==SLT_V1)
{
SLT_send_packet(SLT_PAYLOADSIZE_V1);
return SLT_V1_TIMING_PACKET;
}
else //V2
if(sub_protocol==SLT_V1_4)
{
SLT_send_packet(SLT_PAYLOADSIZE_V2);
return SLT_V2_TIMING_PACKET;
phase++; //Packets are sent two times only
return SLT_V1_4_TIMING_PACKET;
}
//V2
return SLT_V2_TIMING_PACKET;
case SLT_DATA3:
if(sub_protocol==SLT_V1)
SLT_send_packet(SLT_PAYLOADSIZE_V1);
else //V2
SLT_send_packet(SLT_PAYLOADSIZE_V2);
SLT_send_packet(packet_length);
if (++packet_count >= 100)
{// Send bind packet
packet_count = 0;
if(sub_protocol==SLT_V1)
if(sub_protocol==SLT_V1||sub_protocol==SLT_V1_4)
{
phase=SLT_BIND2;
return SLT_V1_TIMING_BIND2;
}
else //V2
{
phase=SLT_BIND1;
return SLT_V2_TIMING_BIND1;
}
//V2
phase=SLT_BIND1;
return SLT_V2_TIMING_BIND1;
}
else
{// Continue to send normal packets
phase = SLT_BUILD;
if(sub_protocol==SLT_V1)
return 20000-SLT_TIMING_BUILD;
else //V2
return 13730-SLT_TIMING_BUILD;
if(sub_protocol==SLT_V1_4)
return 18000-SLT_TIMING_BUILD-SLT_V1_4_TIMING_PACKET;
//V2
return 13730-SLT_TIMING_BUILD;
}
case SLT_BIND1:
SLT_send_bind_packet();
@@ -252,8 +261,10 @@ uint16_t SLT_callback()
phase = SLT_BUILD;
if(sub_protocol==SLT_V1)
return 20000-SLT_TIMING_BUILD-SLT_V1_TIMING_BIND2;
else //V2
return 13730-SLT_TIMING_BUILD-SLT_V2_TIMING_BIND1-SLT_V2_TIMING_BIND2;
if(sub_protocol==SLT_V1_4)
return 18000-SLT_TIMING_BUILD-SLT_V1_TIMING_BIND2-SLT_V1_4_TIMING_PACKET;
//V2
return 13730-SLT_TIMING_BUILD-SLT_V2_TIMING_BIND1-SLT_V2_TIMING_BIND2;
}
return 19000;
}
@@ -276,6 +287,33 @@ void SLT_init()
SLT_RF_init();
SLT_set_freq();
phase = SLT_BUILD;
if(sub_protocol==SLT_V1)
{
packet_length = SLT_PAYLOADSIZE_V1;
#ifdef MULTI_SYNC
packet_period = 20000+2*SLT_V1_TIMING_PACKET; //22ms
#endif
}
else if(sub_protocol==SLT_V1_4)
{
packet_length = SLT_PAYLOADSIZE_V1_4;
#ifdef MULTI_SYNC
packet_period = 18000; //18ms
#endif
//Test IDs
MProtocol_id = MProtocol_id_master ^ (1<<RX_num);
set_rx_tx_addr(MProtocol_id);
debugln("Try ID: %lx", MProtocol_id);
}
else //V2
{
packet_length = SLT_PAYLOADSIZE_V2;
#ifdef MULTI_SYNC
packet_period = 13730+2*SLT_V2_TIMING_PACKET; //~18ms
#endif
}
}
#endif
//SLT v1_4ch timing
//268363 + 1643 / 15 = 18000

View File

@@ -0,0 +1,123 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(SCORPIO_CYRF6936_INO)
#include "iface_cyrf6936.h"
//#define SCORPIO_FORCE_ID
#define SCORPIO_PACKET_PERIOD 12000
#define SCORPIO_PACKETCH_PERIOD 2580
#define SCORPIO_BINDPAYLOAD_SIZE 8
#define SCORPIO_PAYLOAD_SIZE 10
#define SCORPIO_BIND_COUNT 1000
#define SCORPIO_RF_NUM_CHANNELS 3
static uint16_t __attribute__((unused)) SCORPIO_send_packet()
{
if(IS_BIND_IN_PROGRESS)
{
packet[0] = 0x88; //FIXME: What is this?
packet[1] = 0x55; //FIXME: What is this?
packet[2] = crc; //CRC_low for normal packets
packet[3] = crc >> 8; //CRC_high for normal packets
packet[4] = hopping_frequency[0]; //RF freq 0
packet[5] = hopping_frequency[1]; //RF freq 1
packet[6] = hopping_frequency[2]; //RF freq 2
packet[7] = 0x80; //FIXME: What is this?
//SendPacket
CYRF_WriteDataPacketLen(packet, SCORPIO_BINDPAYLOAD_SIZE);
return SCORPIO_PACKET_PERIOD;
}
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
CYRF_SetPower(0x28); //Update power
delayMicroseconds(180); //Frequency settle time
packet[0] = hopping_frequency[0];
packet[1] = hopping_frequency[1];
packet[2] = hopping_frequency[2];
packet[3] = convert_channel_8b(THROTTLE);
packet[4] = 0xFF - convert_channel_8b(RUDDER);
packet[5] = convert_channel_8b(ELEVATOR);
packet[6] = convert_channel_8b(AILERON);
packet[7] = 0x55; //FIXME: What is this?
packet[8] = 0x00; //FIXME: What is this?
packet[9] = 0x00; //FIXME: What is this?
CYRF_WriteDataPacketLen(packet, SCORPIO_PAYLOAD_SIZE);
hopping_frequency_no++;
if(hopping_frequency_no >= SCORPIO_RF_NUM_CHANNELS)
{
hopping_frequency_no = 0;
return SCORPIO_PACKET_PERIOD - 2*SCORPIO_PACKETCH_PERIOD;
}
return SCORPIO_PACKETCH_PERIOD;
}
static void __attribute__((unused)) SCORPIO_RF_init()
{
/* Initialise CYRF chip */
CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C);
CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xE8);
CYRF_SetPower(0x28);
CYRF_SetTxRxMode(TX_EN);
}
static void __attribute__((unused)) SCORPIO_TX_init()
{
calc_fh_channels(3); // select 3 frequencies between 2 and 77. FIXME: Could they be choosen on the spot finding empty frequencies?
crc = (rx_tx_addr[0] ^ rx_tx_addr[1] ^ RX_num) + ((rx_tx_addr[2] ^ rx_tx_addr[3] ^ RX_num) << 8);
#ifdef SCORPIO_FORCE_ID
crc = 0x689C;
hopping_frequency[0] = 0x26;
hopping_frequency[1] = 0x49;
hopping_frequency[2] = 0x2E;
#endif
//debugln("C0:%02X, C1:%02X, C2:%02X, CRC:%04X", hopping_frequency[0], hopping_frequency[1], hopping_frequency[2], crc);
CYRF_ConfigRFChannel(hopping_frequency[0]); // Use first RF channel for bind
}
uint16_t SCORPIO_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(SCORPIO_PACKET_PERIOD);
#endif
if(bind_counter)
if(--bind_counter==0)
{
CYRF_ConfigCRCSeed(crc);
BIND_DONE;
}
return SCORPIO_send_packet();
}
void SCORPIO_init()
{
SCORPIO_RF_init();
SCORPIO_TX_init();
if(IS_BIND_IN_PROGRESS)
{
bind_counter = SCORPIO_BIND_COUNT;
CYRF_ConfigCRCSeed(0x0001);
}
else
bind_counter = 1;
hopping_frequency_no = 0;
}
#endif

View File

@@ -19,56 +19,72 @@
#include "iface_cyrf6936.h"
//#define TRAXXAS_FORCE_ID
#define TRAXXAS_TQ1_FORCE_ID
//#define TRAXXAS_TQ2_FORCE_ID
#define TRAXXAS_DEBUG
#define TRAXXAS_CHANNEL 0x05
#define TRAXXAS_BIND_CHANNEL 0x2B
#define TRAXXAS_PACKET_SIZE 16
#define TRAXXAS_BIND_CHANNEL 0x2B
#define TRAXXAS_CHECK_CHANNEL 0x22
#define TRAXXAS_PACKET_SIZE 16
#define TRAXXAS_TQ1_BIND_CHANNEL 0x04
#define TRAXXAS_TQ1_CHECK_CHANNEL 0x34
enum {
TRAXXAS_BIND_PREP_RX=0,
TRAXXAS_BIND_RX,
TRAXXAS_BIND_TX1,
TRAXXAS_PREP_RX,
TRAXXAS_RX,
TRAXXAS_PREP_DATA,
TRAXXAS_DATA,
TRAXXAS_TQ1_BIND,
TRAXXAS_TQ1_DATA1,
TRAXXAS_TQ1_DATA2,
};
const uint8_t PROGMEM TRAXXAS_sop_bind[] ={ 0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91 };
const uint8_t PROGMEM TRAXXAS_sop_data[] ={ 0xA1, 0x78, 0xDC, 0x3C, 0x9E, 0x82, 0xDC, 0x3C };
//const uint8_t PROGMEM TRAXXAS_sop_check[]={ 0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72 };
const uint8_t PROGMEM TRAXXAS_init_vals[][2] = {
//Init from dump
{CYRF_0B_PWR_CTRL, 0x00}, // PMU
{CYRF_32_AUTO_CAL_TIME, 0x3C}, // Default init value
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
{CYRF_1B_TX_OFFSET_LSB, 0x55}, // Default init value
{CYRF_1C_TX_OFFSET_MSB, 0x05}, // Default init value
{CYRF_28_CLK_EN, 0x02}, // Force Receive Clock Enable
{CYRF_03_TX_CFG, 0x08 | CYRF_BIND_POWER}, // 8DR Mode, 32 chip codes
{CYRF_0B_PWR_CTRL, 0x00}, // PMU
{CYRF_06_RX_CFG, 0x88 | 0x02}, // AGC enabled, Fast Turn Mode enabled, adding overwrite enable to not lockup RX
{CYRF_1E_RX_OVERRIDE, 0x08}, // Reject packets with 0 seed
{CYRF_03_TX_CFG, 0x08 | CYRF_BIND_POWER}, // 8DR Mode, 32 chip codes
};
static void __attribute__((unused)) TRAXXAS_cyrf_bind_config()
{
CYRF_PROGMEM_ConfigSOPCode(TRAXXAS_sop_bind);
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[0]);
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB, 0x5A);
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB, 0x5A);
CYRF_ConfigRFChannel(TRAXXAS_BIND_CHANNEL);
}
static void __attribute__((unused)) TRAXXAS_cyrf_check_config()
{
CYRF_ConfigRFChannel(TRAXXAS_CHECK_CHANNEL);
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[9]);
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB, 0xA5);
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB, 0xA5);
}
static void __attribute__((unused)) TRAXXAS_cyrf_data_config()
{
CYRF_PROGMEM_ConfigSOPCode(TRAXXAS_sop_data);
CYRF_ConfigRFChannel(hopping_frequency[0]);
#ifdef TRAXXAS_FORCE_ID // data taken from TX dump
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB, 0x1B);
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB, 0x3F);
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[6]);
#else
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB, cyrfmfg_id[0]+0xB6);
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB, cyrfmfg_id[1]+0x5D);
uint16_t addr=TRAXXAS_EEPROM_OFFSET+RX_num*3;
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB, cyrfmfg_id[0] - eeprom_read_byte((EE_ADDR)(addr + 0)));
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB, cyrfmfg_id[1] - eeprom_read_byte((EE_ADDR)(addr + 1)));
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[eeprom_read_byte((EE_ADDR)(addr + 2)) % 20]);
#endif
CYRF_ConfigRFChannel(TRAXXAS_CHANNEL);
CYRF_SetTxRxMode(TX_EN);
}
@@ -76,25 +92,60 @@ static void __attribute__((unused)) TRAXXAS_send_data_packet()
{
packet[0] = 0x01;
memset(&packet[1],0x00,TRAXXAS_PACKET_SIZE-1);
//Steering
uint16_t ch = convert_channel_16b_nolimit(RUDDER,500,1000,false);
packet[2]=ch>>8;
packet[3]=ch;
//Throttle
ch = convert_channel_16b_nolimit(THROTTLE,500,1000,false);
packet[4]=ch>>8;
packet[5]=ch;
//AUX3
ch = convert_channel_16b_nolimit(AILERON,500,1000,false);
packet[6]=ch>>8;
packet[7]=ch;
//AUX4???
ch = convert_channel_16b_nolimit(ELEVATOR,500,1000,false);
packet[12]=ch>>8;
packet[13]=ch;
//Next RF channel ? 0x00 -> keep current, 0x0E change to F=15
//packet[1] = hopping_frequency[0] - 1;
//6 channels
uint16_t ch;
for(uint8_t i=0; i<6; i++)
{
ch = convert_channel_16b_nolimit(i,500,1000,false);
packet[2+i*2]=ch>>8;
packet[3+i*2]=ch;
}
CYRF_SetPower(0x08);
CYRF_WriteDataPacketLen(packet, TRAXXAS_PACKET_SIZE);
CYRF_WriteDataPacket(packet);
}
static void __attribute__((unused)) TRAXXAS_TQ1_send_data_packet()
{
memcpy(&packet[1], cyrfmfg_id, 4);
if(IS_BIND_IN_PROGRESS)
{
packet_length = 8;
packet[0] = 0x2A; // Bind packet
packet[5] = 0xA0; // Bind phase 0
packet[6] = TRAXXAS_TQ1_BIND_CHANNEL-1; // Not sure...
}
else
{
packet_length = 16;
packet[0] = 0x02; // Normal packet
packet[5] = 0xA2; // Bind phase 2 = completed?
//4 channels
uint16_t ch;
for(uint8_t i=0; i<4; i++)
{
ch = convert_channel_ppm(i);
packet[6+i*2]=ch;
packet[7+i*2]=ch>>8;
}
packet[14] = hopping_frequency[0]-1; // Not sure...
}
uint8_t xor_value=0;
for(uint8_t i=0; i<packet_length-1; i++)
xor_value ^= packet[i];
packet[packet_length-1] = xor_value;
CYRF_SetPower(0x08);
CYRF_WriteDataPacketLen(packet, packet_length);
#ifdef TRAXXAS_DEBUG
debug("P:");
for(uint8_t i=0; i<packet_length; i++)
debug(" %02X",packet[i]);
debugln("");
#endif
}
uint16_t TRAXXAS_callback()
@@ -103,133 +154,324 @@ uint16_t TRAXXAS_callback()
switch(phase)
{
//TQ2
case TRAXXAS_BIND_PREP_RX:
TRAXXAS_cyrf_bind_config();
case TRAXXAS_PREP_RX:
//debugln("PREP_RX");
if(phase == TRAXXAS_BIND_PREP_RX)
TRAXXAS_cyrf_bind_config();
else
TRAXXAS_cyrf_check_config();
CYRF_SetTxRxMode(RX_EN); //Receive mode
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive
packet_count=100; //Timeout for RX
phase=TRAXXAS_BIND_RX;
return 700;
phase++; // TRAXXAS_BIND_RX or TRAXXAS_RX
return 7000;
case TRAXXAS_BIND_RX:
case TRAXXAS_RX:
//debugln("RX");
//Read data from RX
status = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
if((status & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
status |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
debugln("s=%02X",status);
#ifdef TRAXXAS_DEBUG
//debugln("s=%02X",status);
#endif
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
if((status & 0x07) == 0x02)
{ // Data received with no errors
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
debugln("L=%02X",len)
#ifdef TRAXXAS_DEBUG
debugln("L=%02X",len)
#endif
if(len==TRAXXAS_PACKET_SIZE)
{
CYRF_ReadDataPacketLen(packet, TRAXXAS_PACKET_SIZE);
debug("RX=");
for(uint8_t i=0;i<TRAXXAS_PACKET_SIZE;i++)
debug(" %02X",packet[i]);
debugln("");
#ifdef TRAXXAS_DEBUG
debug("RX=");
for(uint8_t i=0;i<TRAXXAS_PACKET_SIZE;i++)
debug(" %02X",packet[i]);
debugln("");
#endif
uint16_t addr=TRAXXAS_EEPROM_OFFSET+RX_num*3;
if(phase == TRAXXAS_BIND_RX)
{
// Store RX ID
for(uint8_t i=0;i<2;i++)
eeprom_write_byte((EE_ADDR)(addr+i),packet[i+1]);
//Store SOP index
eeprom_write_byte((EE_ADDR)(addr+2),packet[7]);
}
else
{
//check RX ID and SOP
if(eeprom_read_byte((EE_ADDR)(addr + 0)) != packet[1] || eeprom_read_byte((EE_ADDR)(addr + 1)) != packet[2] || eeprom_read_byte((EE_ADDR)(addr + 2)) != packet[7])
{ // Not our RX
phase++; // TRAXXAS_PREP_DATA
return 10000-7000-500;
}
}
// Replace RX ID by TX ID
for(uint8_t i=0;i<6;i++)
packet[i+1]=cyrfmfg_id[i];
packet[10]=0x01;
//packet[7 ] = 0xEE; // Not needed ??
packet[8 ] = hopping_frequency[0] - 1;
packet[10] = 0x01; // Must change otherwise bind doesn't complete
//packet[13] = 0x05; // Not needed ??
packet_count=12;
CYRF_SetTxRxMode(TX_EN);
phase=TRAXXAS_BIND_TX1;
return 200;
return 10000;
}
}
if( --packet_count == 0 )
{ // Retry RX
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // Force end state
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort
if(--bind_counter != 0)
phase=TRAXXAS_BIND_PREP_RX; // Retry receiving bind packet
else
phase=TRAXXAS_PREP_DATA; // Abort binding
if(phase == TRAXXAS_BIND_RX)
{
if( --packet_count == 0 )
{ // Retry RX
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // Force end state
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort
if(--bind_counter != 0)
phase=TRAXXAS_BIND_PREP_RX; // Retry receiving bind packet
else
phase=TRAXXAS_PREP_DATA; // Abort binding
}
return 700;
}
return 700;
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // Force end state
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort
phase++; // TRAXXAS_PREP_DATA
return 10000-7000-500;
case TRAXXAS_BIND_TX1:
//debugln("BIND_TX1");
CYRF_WriteDataPacketLen(packet, TRAXXAS_PACKET_SIZE);
debug("P=");
for(uint8_t i=0;i<TRAXXAS_PACKET_SIZE;i++)
debug(" %02X",packet[i]);
debugln("");
#ifdef TRAXXAS_DEBUG
debug("P=");
for(uint8_t i=0;i<TRAXXAS_PACKET_SIZE;i++)
debug(" %02X",packet[i]);
debugln("");
#endif
if(--packet_count==0) // Switch to normal mode
phase=TRAXXAS_PREP_DATA;
break;
case TRAXXAS_PREP_DATA:
//debugln("PREP_DATA");
BIND_DONE;
TRAXXAS_cyrf_data_config();
phase++;
return 500;
case TRAXXAS_DATA:
//debugln_time("DATA");
#ifdef MULTI_SYNC
telemetry_set_input_sync(13940);
telemetry_set_input_sync(10000);
#endif
TRAXXAS_send_data_packet();
break;
phase = TRAXXAS_PREP_RX;
return 1000;
//TQ1
case TRAXXAS_TQ1_BIND:
if(bind_counter)
{
CYRF_ConfigRFChannel(TRAXXAS_TQ1_BIND_CHANNEL);
TRAXXAS_TQ1_send_data_packet();
bind_counter--;
if(bind_counter == 0)
{
BIND_DONE;
phase++;
}
}
return 10000;
case TRAXXAS_TQ1_DATA1:
#ifdef MULTI_SYNC
telemetry_set_input_sync(19900);
#endif
CYRF_ConfigRFChannel(TRAXXAS_TQ1_CHECK_CHANNEL);
TRAXXAS_TQ1_send_data_packet();
phase++;
return 7100;
case TRAXXAS_TQ1_DATA2:
CYRF_ConfigRFChannel(hopping_frequency[0]);
TRAXXAS_TQ1_send_data_packet();
phase = TRAXXAS_TQ1_DATA1;
return 12800;
}
return 13940;
return 10000;
}
void TRAXXAS_init()
{
//Config CYRF registers
for(uint8_t i = 0; i < sizeof(TRAXXAS_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&TRAXXAS_init_vals[i][0]), pgm_read_byte_near(&TRAXXAS_init_vals[i][1]));
uint8_t init;
if(sub_protocol == TRAXXAS_TQ1)
{
//CYRF_WriteRegister(CYRF_06_RX_CFG, 0x48 | 0x02);
//CYRF_WriteRegister(CYRF_26_XTAL_CFG, 0x08);
init = 5;
}
else //TQ2
{
init = sizeof(TRAXXAS_init_vals) / 2;
for(uint8_t i = 0; i < init; i++)
CYRF_WriteRegister(pgm_read_byte_near(&TRAXXAS_init_vals[i][0]), pgm_read_byte_near(&TRAXXAS_init_vals[i][1]));
}
//Read CYRF ID
CYRF_GetMfgData(cyrfmfg_id);
cyrfmfg_id[0]+=RX_num;
#ifdef TRAXXAS_FORCE_ID // data taken from TX dump
cyrfmfg_id[0]=0x65; // CYRF MFG ID
cyrfmfg_id[1]=0xE2;
cyrfmfg_id[2]=0x5E;
cyrfmfg_id[3]=0x55;
cyrfmfg_id[4]=0x4D;
cyrfmfg_id[5]=0xFE;
#endif
if(IS_BIND_IN_PROGRESS)
//Find a free channel
if(sub_protocol == TRAXXAS_TQ1)
{
bind_counter=100;
phase = TRAXXAS_BIND_PREP_RX;
cyrfmfg_id[3]+=RX_num; // Not needed for TQ2 since the TX and RX have to match
//CYRF_FindBestChannels(hopping_frequency,1,1,0x0B,0x30, FIND_CHANNEL_ANY); // Complete guess
}
else //TRAXXAS_TQ2
CYRF_FindBestChannels(hopping_frequency,1,1,0x02,0x21, FIND_CHANNEL_ANY);
#ifdef TRAXXAS_TQ1_FORCE_ID // data taken from TX dump
if(sub_protocol == TRAXXAS_TQ1)
{
cyrfmfg_id[0]=0xD8; // CYRF MFG ID
cyrfmfg_id[1]=0xAA;
cyrfmfg_id[2]=0x59;
cyrfmfg_id[3]=0xE6;
//cyrfmfg_id[4]=0x44; // Unused
//cyrfmfg_id[5]=0xFB; // Unused
hopping_frequency[0] = 0x0B;
}
#endif
#ifdef TRAXXAS_TQ2_FORCE_ID // data taken from TX dump
if(sub_protocol == TRAXXAS_TQ2)
{
cyrfmfg_id[0]=0x65; // CYRF MFG ID
cyrfmfg_id[1]=0xE2;
cyrfmfg_id[2]=0x5E;
cyrfmfg_id[3]=0x55;
cyrfmfg_id[4]=0x4D;
cyrfmfg_id[5]=0xFE;
hopping_frequency[0] = 0x05; // seen 05 and 0F
}
#endif
#ifdef TRAXXAS_DEBUG
debugln("ID: %02X %02X %02X %02X %02X %02X",cyrfmfg_id[0],cyrfmfg_id[1],cyrfmfg_id[2],cyrfmfg_id[3],cyrfmfg_id[4],cyrfmfg_id[5]);
debugln("RF CH: %02X",hopping_frequency[0]);
#endif
bind_counter=100;
if(sub_protocol == TRAXXAS_TQ1)
{
CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C);
CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
CYRF_WriteRegister(CYRF_26_XTAL_CFG, 0x08);
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x48);
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x21);
CYRF_WriteRegister(CYRF_03_TX_CFG, 0x0C);
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[0]);
CYRF_SetTxRxMode(TX_EN);
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x21);
if(IS_BIND_IN_PROGRESS)
phase = TRAXXAS_TQ1_BIND;
else
phase = TRAXXAS_TQ1_DATA1;
}
else
phase = TRAXXAS_PREP_DATA;
{//TRAXXAS_TQ2
if(IS_BIND_IN_PROGRESS)
phase = TRAXXAS_BIND_PREP_RX;
else
phase = TRAXXAS_PREP_DATA;
}
//
// phase = TRAXXAS_BIND_TX1;
// TRAXXAS_cyrf_bind_config();
// CYRF_SetTxRxMode(TX_EN);
// memcpy(packet,(uint8_t *)"\x02\x4A\xA3\x2D\x1A\x49\xFE\x06\x00\x00\x02\x01\x06\x06\x00\x00",TRAXXAS_PACKET_SIZE);
// memcpy(packet,(uint8_t *)"\x02\x49\xAC\x4F\x55\x4D\xFE\x05\x00\x00\x02\x01\x06\x06\x00\x00",TRAXXAS_PACKET_SIZE);
}
/*
Bind phase 1
Traxxas TQ 2nd generation
-------------------------
Packets 0x02: Bind learn TX/RX addresses
CHANNEL: 0x2B
SOP_CODE: 0x3C 0x37 0xCC 0x91 0xE2 0xF8 0xCC 0x91
CRC_SEED_LSB: 0x5A
CRC_SEED_MSB: 0x5A
RX1: 0x02 0x4A 0xA3 0x2D 0x1A 0x49 0xFE 0x06 0x00 0x00 0x02 0x01 0x06 0x06 0x00 0x00
TX1: 0x02 0x65 0xE2 0x5E 0x55 0x4D 0xFE 0xEE 0x00 0x00 0x01 0x01 0x06 0x05 0x00 0x00
Note: RX cyrfmfg_id is 0x4A,0xA3,0x2D,0x1A,0x49,0xFE and TX cyrfmfg_id is 0x65,0xE2,0x5E,0x55,0x4D,0xFE
RX: 0x02 0x4A 0xA3 0x2D 0x1A 0x49 0xFE 0x06 0x00 0x00 0x02 0x01 0x06 0x06 0x00 0x00
TX: 0x02 0x65 0xE2 0x5E 0x55 0x4D 0xFE 0xEE 0x00 0x00 0x01 0x01 0x06 0x05 0x00 0x00
Notes:
- RX cyrfmfg_id is 0x4A,0xA3,0x2D,0x1A,0x49,0xFE and TX cyrfmfg_id is 0x65,0xE2,0x5E,0x55,0x4D,0xFE
- P[7] changes from 0x06 to 0xEE but not needed to complete the bind -> doesn't care??
- P[8] RF channel - 1 (on packets type 0x03)
- P[9] 0x00 unchanged??
- P[10] needs to be set to 0x01 to complete the bind -> normal packet P[0]??
- P[11] unchanged ?? -> no bind if set to 0x00 or 0x81
- P[12] unchanged ?? -> no bind if set to 0x05 or 0x86
- P[13] changes from 0x06 to 0x05 but not needed to complete the bind -> doesn't care??
- P[14..15]=0x00 unchanged??
Bind phase 2 (looks like normal mode?)
CHANNEL: 0x05
SOP_CODE: 0xA1 0x78 0xDC 0x3C 0x9E 0x82 0xDC 0x3C
CRC_SEED_LSB: 0x1B
CRC_SEED_MSB: 0x3F
RX2: 0x03 0x4A 0xA3 0x2D 0x1A 0x49 0xFE 0x06 0x00 0x00 0x02 0x01 0x06 0x06 0x00 0x00
TX2: 0x01 0x65 0x01 0xF4 0x03 0xE7 0x02 0x08 0x00 0x00 0x01 0x01 0x02 0xEE 0x00 0x00
Note: TX2 is nearly a normal packet at the exception of the 2nd byte equal to cyrfmfg_id[0]
Bind phase 3 (check?)
Packets 0x03: Which RF channel
CHANNEL: 0x22
SOP_CODE: 0x97 0xE5 0x14 0x72 0x7F 0x1A 0x14 0x72
CRC_SEED_LSB: 0xA5
CRC_SEED_MSB: 0xA5
RX3: 0x04 0x4A 0xA3 0x2D 0x1A 0x49 0xFE 0x06 0x00 0x00 0x02 0x01 0x06 0x06 0x00 0x00
RX: 0x03 0x4A 0xA3 0x2D 0x1A 0x49 0xFE 0x06 0x00 0x00 0x02 0x01 0x06 0x06 0x00 0x00
TX: 0x03 0x65 0xE2 0x5E 0x55 0x4D 0xFE 0xEE 0x0E 0x00 0x01 0x01 0x06 0x05 0x00 0x00
- P[8] RF channel - 1
Switch to normal mode
Packets 0x04: unknown
RX: 0x04 0x4A 0xA3 0x2D 0x1A 0x49 0xFE 0x06 0x00 0x00 0x02 0x01 0x06 0x06 0x00 0x00
Packets 0x01: Normal mode
CHANNEL: 0x05
SOP_CODE: 0xA1 0x78 0xDC 0x3C 0x9E 0x82 0xDC 0x3C
CRC_SEED_LSB: 0x1B
CRC_SEED_MSB: 0x3F
TX3: 0x01 0x00 0x02 0xA8 0x03 0xE7 0x02 0x08 0x00 0x00 0x01 0x01 0x02 0xEE 0x00 0x00
CRC_SEED:
TX ID: \x65\xE2\x5E\x55\x4D\xFE
RX ID: \x4A\xA3\x2D\x1A\x49\xFE CRC 0x1B 0x3F => CRC: 65-4A=1B E2-A3=3F
RX ID: \x4B\xA3\x2D\x1A\x49\xFE CRC 0x1A 0x3F => CRC: 65-4B=1A E2-A3=3F
RX ID: \x00\x00\x2D\x1A\x49\xFE CRC 0x65 0xE2 => CRC: 65-00=65 E2-00=E2
RX ID: \x00\xFF\x2D\x1A\x49\xFE CRC 0x65 0xE3 => CRC: 65-00=65 E2-FF=E3
RX ID: \xFF\x00\x2D\x1A\x49\xFE CRC 0x66 0xE2 => CRC: 65-FF=66 E2-00=E2
SOP Codes:
RX1: 02 4A A3 2D 1A 49 FE 06 00 00 02 01 06 06 00 00
SOP: A1 78 DC 3C 9E 82 DC 3C
RX2: 02 49 AC 4F 55 4D FE 05 00 00 02 01 06 06 00 00
SOP: 5A CC AE 46 B6 31 AE 46
RX3: 02 CA F3 62 55 4D FE 03 00 00 02 01 06 06 00 00
SOP: 66 CD 7C 50 DD 26 7C 50
Dump of SOP Codes:
00: 3C 37 CC 91 E2 F8 CC 91 => bind
01: 9B C5 A1 0F AD 39 A2 0F
02: EF 64 B0 2A D2 8F B1 2A
03: 66 CD 7C 50 DD 26 7C 50
04: 5C E1 F6 44 AD 16 F6 44
05: 5A CC AE 46 B6 31 AE 46
06: A1 78 DC 3C 9E 82 DC 3C
07: B9 8E 19 74 6F 65 18 74
08: DF B1 C0 49 62 DF C1 49
09: 97 E5 14 72 7F 1A 14 72 => check
10: 82 C7 90 36 21 03 FF 17
11: E2 F8 CC 91 3C 37 CC 91 => bind 4 bytes group swapped
12: AD 39 A2 0F 9B C5 A1 0F => 01 4 bytes group swapped
13: D2 8F B1 2A EF 64 B0 2A => 02 4 bytes group swapped
14: DD 26 7C 50 66 CD 7C 50 => 03 4 bytes group swapped
...
19: 62 DF C1 49 DF B1 C0 49 => 08 4 bytes group swapped
20: 00 00 00 33 DE AD BA BE ??over??
*/
/*
Traxxas TQ 1st generation
-------------------------
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/issues/967#issuecomment-2079038576
*/
#endif

View File

@@ -1,163 +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 Tiger Drone 1400782.
#if defined(TIGER_NRF24L01_INO)
#include "iface_xn297.h"
#define TIGER_FORCE_ID
#define TIGER_INITIAL_WAIT 500
#define TIGER_PACKET_PERIOD 3940
#define TIGER_RF_NUM_CHANNELS 4
#define TIGER_BIND_RF_NUM_CHANNELS 8
#define TIGER_PAYLOAD_SIZE 16
#define TIGER_BIND_COUNT 761 //3sec
static uint8_t __attribute__((unused)) TIGER_convert_channel(uint8_t num)
{
uint8_t val=convert_channel_8b(num);
// 7F..01=left, 00=center, 80..FF=right
if(val==0x80)
val=0; // 0
else
if(val>0x80)
val--; // 80..FE
else
{
val=0x80-val; // 80..01
if(val==0x80)
val--; // 7F..01
}
return val;
}
static void __attribute__((unused)) TIGER_send_packet()
{
if(IS_BIND_DONE)
{
//Channels
packet[0]=convert_channel_8b(THROTTLE); // 00..FF
packet[1]=TIGER_convert_channel(RUDDER); // 7F..01=left, 00=center, 80..FF=right
packet[2]=TIGER_convert_channel(ELEVATOR); // 7F..01=down, 00=center, 80..FF=up
packet[3]=TIGER_convert_channel(AILERON); // 7F..01=left, 00=center, 80..FF=right
//Flags
packet[14]= GET_FLAG(CH5_SW, 0x04) //FLIP
| GET_FLAG(CH6_SW, 0x10); //LIGHT
}
//Check
crc8=0;
for(uint8_t i=0;i<TIGER_PAYLOAD_SIZE-1;i++)
crc8+=packet[i];
packet[TIGER_PAYLOAD_SIZE-1]=crc8;
//Hopping frequency
XN297_Hopping(hopping_frequency_no>>1);
hopping_frequency_no++;
if(IS_BIND_IN_PROGRESS)
{
if(hopping_frequency_no>=2*TIGER_BIND_RF_NUM_CHANNELS)
hopping_frequency_no=0;
}
else
{
if(hopping_frequency_no>=2*(TIGER_BIND_RF_NUM_CHANNELS+TIGER_RF_NUM_CHANNELS))
hopping_frequency_no=2*TIGER_BIND_RF_NUM_CHANNELS;
}
//Send
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, TIGER_PAYLOAD_SIZE);
}
static void __attribute__((unused)) TIGER_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t *)"\x68\x94\xA6\xD5\xC3", 5);
}
static void __attribute__((unused)) TIGER_initialize_txid()
{
#ifdef TIGER_FORCE_ID
rx_tx_addr[0]=0x64;
rx_tx_addr[1]=0x39;
rx_tx_addr[2]=0x12;
rx_tx_addr[3]=0x00;
rx_tx_addr[4]=0x00;
memcpy(hopping_frequency,"\x0E\x39\x1C\x07\x24\x3E\x2B\x47",TIGER_BIND_RF_NUM_CHANNELS);
memcpy(&hopping_frequency[TIGER_BIND_RF_NUM_CHANNELS],"\x36\x41\x37\x4E",TIGER_RF_NUM_CHANNELS);
#endif
//prepare bind packet
memset(&packet[0], 0x00, 4);
memset(&packet[4], 0x40, 10);
memcpy(&packet[7], rx_tx_addr, 5);
packet[14]=0xC0;
}
uint16_t TIGER_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(TIGER_PACKET_PERIOD);
#endif
if(bind_counter)
if(--bind_counter==0)
{
BIND_DONE;
XN297_SetTXAddr((uint8_t *)"\x49\xA6\x83\xEB\x4B", 5);
}
TIGER_send_packet();
return TIGER_PACKET_PERIOD;
}
void TIGER_init()
{
BIND_IN_PROGRESS; // autobind protocol
TIGER_initialize_txid();
TIGER_RF_init();
hopping_frequency_no = 0;
bind_counter=TIGER_BIND_COUNT;
}
#endif
/*Bind
- RF setup: 1Mbps, scrambled, CRC
- TX addr: 0x68 0x94 0xA6 0xD5 0xC3
- 8 RF channels: 0x0E 0x39 0x1C 0x07 0x24 0x3E 0x2B 0x47
- 2 packets per RF channel, 3940µs between packets
- payload 16 bytes: 0x00 0x00 0x00 0x00 0x40 0x40 0x40 0x64 0x39 0x12 0x00 0x00 0x40 0x40 0xC0 0xAF
- payload[15]=sum of payload[0..14]
- the only difference with normal packets is the payload[14]=0xC0
- ??? payload[7..11] TX ID ???
Normal
- RF setup: 1Mbps
- TX addr: 0x49 0xA6 0x83 0xEB 0x4B
- 4 RF channels: 0x36 0x41 0x37 0x4E
- 2 packets per RF channel, 3940µs between packets
- payload 16 bytes: 0x00 0x00 0x00 0x00 0x40 0x40 0x40 0x64 0x39 0x12 0x00 0x00 0x40 0x40 0x00 0xEF
- payload[15]=sum of payload[0..14]
- throttle is on payload[0] 00..FF
- rudder is on payload[1] 00=center, 80..FF=right, 01..7F=left
- elevator is on payload[2] 00=center, 80..FF=up, 01..7F=down
- aileron is on payload[3] 00=center, 80..FF=right, 01..7F=left
- trims payload[4..6]
- ??? payload[7..11] TX ID ???
- ??? payload[12..13] ???
- flip is on payload[14] and flag 0x04
- light is on payload[14] and flag 0x10
*/

View File

@@ -22,17 +22,24 @@ Multiprotocol is distributed in the hope that it will be useful,
#define V761_PACKET_PERIOD 7060 // Timeout for callback in uSec
#define V761_INITIAL_WAIT 500
#define V761_PACKET_SIZE 8
#define V761_RXPAYLOAD_SIZE 3
#define V761_BIND_COUNT 200
#define V761_BIND_FREQ 0x28
#define V761_RF_NUM_CHANNELS 3
#define TOPRC_BIND_FREQ 0x2A
#define TOPRC_PACKET_PERIOD 14120 // Timeout for callback in uSec
#define V761_WRITE_TIME 450
#define V761_TELEM_PACKET_PERIOD 14088 // Timeout for callback in uSec
//#define V761_TELEM_DEBUG
enum
{
V761_BIND1 = 0,
V761_BIND2,
V761_DATA
V761_BIND1 = 0,
V761_BIND2,
V761_RX_CHECK,
V761_DATA,
V761_RX
};
static void __attribute__((unused)) V761_set_checksum()
@@ -66,12 +73,16 @@ static void __attribute__((unused)) V761_send_packet()
}
else
{
#ifdef V761_TELEM_DEBUG
debug_time("");
debugln(" Ph:%d",hopping_frequency_no);
#endif
XN297_Hopping(hopping_frequency_no++);
if(hopping_frequency_no >= V761_RF_NUM_CHANNELS)
{
hopping_frequency_no = 0;
packet_count++;
packet_count &= 0x03;
packet_sent++;
packet_sent &= 0x03;
}
packet[0] = convert_channel_8b(THROTTLE); // Throttle
@@ -88,7 +99,7 @@ static void __attribute__((unused)) V761_send_packet()
packet[3] = convert_channel_8b(AILERON)>>1; // Aileron
}
packet[5] = packet_count<<6; // 0X, 4X, 8X, CX
packet[5] = packet_sent<<6; // 0X, 4X, 8X, CX
packet[4] = 0x20; // Trims 00..20..40, 0X->20 4X->TrAil 8X->TrEle CX->TrRud
if(CH5_SW) // Mode Expert Gyro off
@@ -180,46 +191,129 @@ static void __attribute__((unused)) V761_initialize_txid()
uint16_t V761_callback()
{
static bool rx = false;
static uint8_t packet_telem = 0;
switch(phase)
{
case V761_BIND1:
if(bind_counter)
bind_counter--;
packet_count ++;
packet_sent ++;
XN297_RFChannel(sub_protocol == V761_TOPRC ? TOPRC_BIND_FREQ : V761_BIND_FREQ);
XN297_SetTXAddr(rx_id, 4);
V761_send_packet();
if(packet_count >= 20)
if(packet_sent >= 20)
{
packet_count = 0;
packet_sent = 0;
phase = V761_BIND2;
}
return 15730;
case V761_BIND2:
if(bind_counter)
bind_counter--;
packet_count ++;
packet_sent ++;
XN297_Hopping(0);
XN297_SetTXAddr(rx_tx_addr, 4);
V761_send_packet();
if(bind_counter == 0)
{
packet_count = 0;
packet_sent = 0;
BIND_DONE;
phase = V761_DATA;
#ifdef V761_HUB_TELEMETRY
XN297_SetRXAddr(rx_tx_addr, V761_RXPAYLOAD_SIZE);
#endif
}
else if(packet_count >= 20)
else if(packet_sent >= 20)
{
packet_count = 0;
packet_sent = 0;
phase = V761_BIND1;
}
return 15730;
#ifdef V761_HUB_TELEMETRY
case V761_RX_CHECK:
rx = XN297_IsRX(); // Needed for the NRF24L01 since otherwise the bit gets cleared
XN297_SetTxRxMode(TXRX_OFF);
if(packet_count > 4*63) // Around 3.5sec with no telemetry
{
telemetry_lost = 1;
packet_period = V761_PACKET_PERIOD;
}
else
{
packet_count++;
if(!telemetry_lost && !rx && (packet_count%64) == 0)
{// Should have received a telem packet but... Send telem to the radio to keep it alive
telemetry_link = 1;
#ifdef V761_TELEM_DEBUG
debugln("Miss");
#endif
}
}
phase++;
#endif
case V761_DATA:
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
V761_send_packet();
#ifdef V761_HUB_TELEMETRY
if(sub_protocol == V761_TOPRC)
break;
if(rx)
{ // Check if a packet has been received
#ifdef V761_TELEM_DEBUG
debug("RX ");
#endif
if(XN297_ReadPayload(packet_in, V761_RXPAYLOAD_SIZE))
{ // packet with good CRC and length
#ifdef V761_TELEM_DEBUG
debug("OK:");
for(uint8_t i=0;i<V761_RXPAYLOAD_SIZE;i++)
debug(" %02X",packet_in[i]);
debug(" pps:%d", packet_count);
#endif
// packet_in[] = AA 00 55 -> battery ok
// packet_in[] = 55 00 AA -> low battery
crc8 = 0;
for(uint8_t i=0;i<V761_RXPAYLOAD_SIZE;i++)
crc8 ^= packet_in[i];
if(crc8 == 0xFF)
{
v_lipo1 = packet_in[0] >> 1;
telemetry_link = 1;
telemetry_lost = 0;
packet_count = 0;
packet_period = V761_TELEM_PACKET_PERIOD;
}
#ifdef V761_TELEM_DEBUG
else // Bad packet
debug(" NOK");
#endif
}
#ifdef V761_TELEM_DEBUG
else // Bad packet
debug("NOK");
debugln("");
#endif
rx = false;
}
phase++;
return V761_WRITE_TIME;
case V761_RX:
{ // Wait for packet to be sent before switching to receive mode
uint16_t start=(uint16_t)micros();
while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 500)
if(XN297_IsPacketSent())
break;
}
XN297_SetTxRxMode(RX_EN);
phase = V761_RX_CHECK;
return packet_period - V761_WRITE_TIME;
#else
break;
#endif
}
return packet_period;
}
@@ -227,6 +321,7 @@ uint16_t V761_callback()
void V761_init(void)
{
V761_initialize_txid();
V761_RF_init();
if(sub_protocol == V761_TOPRC)
{
memcpy(rx_id,(uint8_t*)"\x20\x21\x05\x0A",4);
@@ -246,12 +341,19 @@ void V761_init(void)
else
{
XN297_SetTXAddr(rx_tx_addr, 4);
#ifdef V761_HUB_TELEMETRY
XN297_SetRXAddr(rx_tx_addr, V761_RXPAYLOAD_SIZE);
#endif
phase = V761_DATA;
}
V761_RF_init();
hopping_frequency_no = 0;
packet_count = 0;
packet_sent = 0;
#ifdef V761_HUB_TELEMETRY
packet_count = 0;
telemetry_lost = 1;
RX_RSSI = 100; // Dummy value
#endif
}
#endif

View File

@@ -35,6 +35,8 @@
// flags going to packet[2]
#define V911S_FLAG_CALIB 0x01
#define A220_FLAG_6G3D 0x04
#define A280_FLAG_6GSENIOR 0x08
#define A280_FLAG_LIGHT 0x20
static void __attribute__((unused)) V911S_send_packet()
{
@@ -74,7 +76,9 @@ static void __attribute__((unused)) V911S_send_packet()
{
packet[ 1]=GET_FLAG(!CH6_SW,E119_FLAG_EXPERT) // short press on left button
|GET_FLAG( CH5_SW,E119_FLAG_CALIB); // short press on right button
packet[ 2]=GET_FLAG( CH7_SW,A220_FLAG_6G3D); // short press on right button
packet[ 2]=GET_FLAG( CH7_SW,A220_FLAG_6G3D) // short press on right button
|GET_FLAG( CH8_SW,A280_FLAG_6GSENIOR) // -100% - 6G, +100% - Senior mode (turn off gyro)
|GET_FLAG( CH9_SW,A280_FLAG_LIGHT); // cycle the light through on-flash-off when the CH9 value is changed from -100% to 100%
}
//packet[3..6]=trims TAER signed

View File

@@ -266,9 +266,11 @@
#undef E01X_CYRF6936_INO
#undef E129_CYRF6936_INO
#undef J6PRO_CYRF6936_INO
#undef KYOSHO3_CYRF6936_INO
#undef LOSI_CYRF6936_INO
#undef MLINK_CYRF6936_INO
#undef TRAXXAS_CYRF6936_INO
#undef SCORPIO_CYRF6936_INO
#undef WFLY_CYRF6936_INO
#undef WK2x01_CYRF6936_INO
#endif
@@ -311,6 +313,7 @@
#undef CX10_NRF24L01_INO
#undef DM002_NRF24L01_INO
#undef E016H_NRF24L01_INO
#undef EAZYRC_NRF24L01_INO
#undef ESKY_NRF24L01_INO
#undef ESKY150_NRF24L01_INO
#undef FQ777_NRF24L01_INO
@@ -329,9 +332,9 @@
#undef POTENSIC_NRF24L01_INO
#undef PROPEL_NRF24L01_INO
#undef REALACC_NRF24L01_INO
#undef SGF22_NRF24L01_INO
#undef SHENQI_NRF24L01_INO
#undef SYMAX_NRF24L01_INO
#undef TIGER_NRF24L01_INO
#undef V2X2_NRF24L01_INO
#undef V761_NRF24L01_INO
#undef XERALL_NRF24L01_INO
@@ -339,6 +342,8 @@
#undef ZSX_NRF24L01_INO
#endif
#if ( not defined(CC2500_INSTALLED) && not defined(NRF24L01_INSTALLED) ) || defined MULTI_EU
#undef BLUEFLY_CCNRF_INO
#undef BUMBLEB_CCNRF_INO
#undef GD00X_CCNRF_INO
#undef KF606_CCNRF_INO
#undef MJXQ_CCNRF_INO
@@ -350,6 +355,9 @@
#undef V911S_CCNRF_INO
#undef XK_CCNRF_INO
#endif
#if not defined(DSM_CYRF6936_INO)
#undef LOSI_CYRF6936_INO
#endif
#if not defined(STM32_BOARD)
//RF2500 emulation does not work on atmega...
#undef E010R5_CYRF6936_INO
@@ -358,10 +366,77 @@
#if not defined(STM32_BOARD)
#undef SX1276_INSTALLED
#endif
#ifndef SX1276_INSTALLED || defined MULTI_EU
#if not defined(SX1276_INSTALLED) || defined MULTI_EU
#undef FRSKYR9_SX1276_INO
#endif
#ifdef MULTI_AIR
#undef JOYSWAY_A7105_INO
//#undef KYOSHO_A7105_INO
//#undef PELIKAN_A7105_INO
#undef LOSI_CYRF6936_INO //Need DSM to be enabled
#undef TRAXXAS_CYRF6936_INO
#undef EAZYRC_NRF24L01_INO
#undef KYOSHO2_NRF24L01_INO
#undef KYOSHO3_CYRF6936_INO
#undef MOULDKG_NRF24L01_INO
#undef SHENQI_NRF24L01_INO
#endif
#ifdef MULTI_SURFACE
#undef BUGS_A7105_INO
#undef HEIGHT_A7105_INO
#undef HUBSAN_A7105_INO
#undef E010R5_CYRF6936_INO
#undef E01X_CYRF6936_INO
#undef E129_CYRF6936_INO
#undef J6PRO_CYRF6936_INO
#undef SCORPIO_CYRF6936_INO
#undef E016HV2_CC2500_INO
#undef ESKY150V2_CC2500_INO
#undef IKEAANSLUTA_CC2500_INO // This is mostly a "for-fun" kind of a thing, not needed for most users
#undef SKYARTEC_CC2500_INO
#undef REDPINE_CC2500_INO
#undef BAYANG_NRF24L01_INO
#undef BAYANG_RX_NRF24L01_INO
#undef BUGSMINI_NRF24L01_INO
#undef CABELL_NRF24L01_INO
#undef CFLIE_NRF24L01_INO
#undef CG023_NRF24L01_INO
#undef CX10_NRF24L01_INO
#undef DM002_NRF24L01_INO
#undef E016H_NRF24L01_INO
#undef ESKY_NRF24L01_INO
#undef ESKY150_NRF24L01_INO
#undef FQ777_NRF24L01_INO
#undef FX_NRF24L01_INO
#undef FY326_NRF24L01_INO
#undef GW008_NRF24L01_INO
#undef HONTAI_NRF24L01_INO
#undef H8_3D_NRF24L01_INO
#undef JJRC345_NRF24L01_INO
#undef KN_NRF24L01_INO
#undef LOLI_NRF24L01_INO
#undef NCC1701_NRF24L01_INO
#undef POTENSIC_NRF24L01_INO
#undef PROPEL_NRF24L01_INO
#undef REALACC_NRF24L01_INO
#undef SGF22_NRF24L01_INO
#undef SYMAX_NRF24L01_INO
#undef V761_NRF24L01_INO
#undef XERALL_NRF24L01_INO
#undef YD717_NRF24L01_INO
#undef ZSX_NRF24L01_INO
#undef GD00X_CCNRF_INO
#undef KF606_CCNRF_INO
#undef MJXQ_CCNRF_INO
#undef MT99XX_CCNRF_INO
#undef OMP_CCNRF_INO
#undef Q303_CCNRF_INO
#undef Q90C_CCNRF_INO
#undef V911S_CCNRF_INO
#endif
//OpenTX 2.3.x issue
#if defined (FRSKYD_CC2500_INO) || defined(FRSKYV_CC2500_INO) || defined(FRSKYX_CC2500_INO)
#define FRSKYX_CC2500_INO
@@ -397,6 +472,7 @@
#undef DEVO_HUB_TELEMETRY
#undef PROPEL_HUB_TELEMETRY
#undef OMP_HUB_TELEMETRY
#undef V761_HUB_TELEMETRY
#undef RLINK_HUB_TELEMETRY
#undef DSM_RX_CYRF6936_INO
#undef DSM_FWD_PGM
@@ -432,6 +508,9 @@
#if not defined(OMP_CCNRF_INO)
#undef OMP_HUB_TELEMETRY
#endif
#if not defined(V761_NRF24L01_INO)
#undef V761_HUB_TELEMETRY
#endif
#if not defined(PROPEL_NRF24L01_INO)
#undef PROPEL_HUB_TELEMETRY
#endif
@@ -489,7 +568,7 @@
//protocols using FRSKYD user frames
#undef HUB_TELEMETRY
#endif
#if not defined(HOTT_FW_TELEMETRY) && not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BUGS_HUB_TELEMETRY) && not defined(NCC1701_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(RLINK_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY) && not defined(SCANNER_TELEMETRY) && not defined(FRSKY_RX_TELEMETRY) && not defined(AFHDS2A_RX_TELEMETRY) && not defined(BAYANG_RX_TELEMETRY) && not defined(DEVO_HUB_TELEMETRY) && not defined(PROPEL_HUB_TELEMETRY) && not defined(OMP_HUB_TELEMETRY) && not defined(WFLY2_HUB_TELEMETRY) && not defined(LOLI_HUB_TELEMETRY) && not defined(MLINK_HUB_TELEMETRY) && not defined(MLINK_FW_TELEMETRY) && not defined(MT99XX_HUB_TELEMETRY) && not defined(MULTI_CONFIG_INO)
#if not defined(HOTT_FW_TELEMETRY) && not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BUGS_HUB_TELEMETRY) && not defined(NCC1701_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(RLINK_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY) && not defined(SCANNER_TELEMETRY) && not defined(FRSKY_RX_TELEMETRY) && not defined(AFHDS2A_RX_TELEMETRY) && not defined(BAYANG_RX_TELEMETRY) && not defined(DEVO_HUB_TELEMETRY) && not defined(PROPEL_HUB_TELEMETRY) && not defined(OMP_HUB_TELEMETRY) && not defined(V761_HUB_TELEMETRY) && not defined(WFLY2_HUB_TELEMETRY) && not defined(LOLI_HUB_TELEMETRY) && not defined(MLINK_HUB_TELEMETRY) && not defined(MLINK_FW_TELEMETRY) && not defined(MT99XX_HUB_TELEMETRY) && not defined(MULTI_CONFIG_INO)
#undef TELEMETRY
#undef INVERT_TELEMETRY
#undef MULTI_TELEMETRY

View File

@@ -487,7 +487,7 @@ void WK_init()
CYRF_SetTxRxMode(TX_EN);
hopping_frequency_no=0;
CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80);
CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80, FIND_CHANNEL_ANY);
CYRF_ConfigRFChannel(hopping_frequency[0]);
packet_count = 0;

View File

@@ -29,11 +29,18 @@ Multiprotocol is distributed in the hope that it will be useful,
static uint16_t __attribute__((unused)) XK_convert_channel(uint8_t num)
{
// Introduce deadband on all channels to prevent twitching
//debug("val:%d",val);
uint16_t val=convert_channel_8b_limit_deadband(num,0x00,0x80, 0xFF, 40)<<2;
//debugln(",%d",val);
uint16_t val;
if(sub_protocol != XK_CARS)
{
// Introduce deadband on all channels to prevent twitching
//debug("val:%d",val);
val=convert_channel_8b_limit_deadband(num,0x00,0x80, 0xFF, 40)<<2;
//debugln(",%d",val);
}
else
val=convert_channel_16b_limit(num,0x00,0x3FF);
// 1FF..01=left, 00=center, 200..3FF=right
if(val==0x200)
val=0; // 0
@@ -89,12 +96,14 @@ static void __attribute__((unused)) XK_send_packet()
packet[10] = 0x04; // 6G-Mode
//0x00 default M-Mode
packet[10] |= GET_FLAG(CH7_SW,0x80); // Emergency stop momentary switch
packet[10] |= GET_FLAG(CH7_SW ,0x80); // Emergency stop momentary switch
packet[11] = GET_FLAG(CH8_SW,0x03) // 3D/6G momentary switch
|GET_FLAG(CH6_SW,0x40); // Take off momentary switch
packet[14] = GET_FLAG(CH9_SW,0x01) // Photo momentary switch
|GET_FLAG(CH10_SW,0x2); // Video momentary switch
packet[11] = GET_FLAG(CH8_SW ,0x03) // 3D/6G momentary switch
|GET_FLAG(CH6_SW ,0x40); // Take off momentary switch
packet[14] = GET_FLAG(CH9_SW ,0x01) // Photo momentary switch
|GET_FLAG(CH10_SW,0x02) // Video momentary switch
|GET_FLAG(CH11_SW,0x04) // Flip
|GET_FLAG(CH12_SW,0x10); // Light
//debugln("P1:%02X,P12:%02X",packet[1],packet[12]);
}
@@ -187,7 +196,7 @@ static void __attribute__((unused)) XK_initialize_txid()
static void __attribute__((unused)) XK_RF_init()
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, sub_protocol==X420 ? XN297_1M : XN297_250K);
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, sub_protocol==X450 ? XN297_250K : XN297_1M );
XN297_SetTXAddr((uint8_t*)"\x68\x94\xA6\xD5\xC3", 5); // Bind address
XN297_HoppingCalib(XK_RF_BIND_NUM_CHANNELS+XK_RF_NUM_CHANNELS); // Calibrate all channels
}
@@ -209,7 +218,8 @@ uint16_t XK_callback()
void XK_init()
{
BIND_IN_PROGRESS; // Autobind protocol
if(sub_protocol != XK_CARS)
BIND_IN_PROGRESS; // Autobind protocol
XK_initialize_txid();
XK_RF_init();
hopping_frequency_no = 0;

View File

@@ -37,6 +37,7 @@ boolean enhanced;
boolean ack;
uint8_t pid;
uint8_t bitrate;
uint8_t old_option;
static void __attribute__((unused)) XN297Dump_RF_init()
{
@@ -609,12 +610,11 @@ static uint16_t XN297Dump_callback()
{
if(phase==0)
{
address_length=3;
memcpy(rx_tx_addr, (uint8_t *)"\xBD\x54\x78", address_length); //"\x62\xE6\xBD\x54\x78"
bitrate=XN297DUMP_1M;
address_length=4;
memcpy(rx_tx_addr, (uint8_t *)"\xF4\x71\x8D\x01", address_length); // bind \x7E\xB8\x63\xA9
bitrate=XN297DUMP_250K;
packet_length=7;
hopping_frequency_no=40; //bind ?, normal 40
hopping_frequency_no=0x50; //bind 0x50, normal ??
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TXRX_OFF);
@@ -623,8 +623,9 @@ static uint16_t XN297Dump_callback()
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, address_length); // set up RX address
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // Enable rx pipe 0
NRF24L01_WriteReg(NRF24L01_05_RF_CH, option); //hopping_frequency_no);
debug("NRF dump, len=%d, rf=%d, address length=%d, bitrate=",packet_length,hopping_frequency_no,address_length);
old_option = option;
debug("NRF dump, len=%d, rf=%d, address length=%d, bitrate=",packet_length,option,address_length); //hopping_frequency_no,address_length);
switch(bitrate)
{
case XN297DUMP_250K:
@@ -643,6 +644,7 @@ static uint16_t XN297Dump_callback()
}
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX)); //_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) |
phase++;
time=0;
}
else
{
@@ -650,13 +652,23 @@ static uint16_t XN297Dump_callback()
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
XN297Dump_overflow();
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
time=(timeH<<16)+timeL-time;
debug("RX: %5luus ", time>>1);
time=(timeH<<16)+timeL;
NRF24L01_ReadPayload(packet, packet_length);
//bool ok=true;
uint8_t buffer[40];
memcpy(buffer,packet,packet_length);
//if(memcmp(&packet_in[0],&packet[0],packet_length))
{
debug("P:");
debug("C: %02X P:", option);
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet[i]);
debugln("");
@@ -718,7 +730,12 @@ static uint16_t XN297Dump_callback()
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX)); // _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) |
}
NRF24L01_WriteReg(NRF24L01_05_RF_CH, option); //hopping_frequency_no);
XN297Dump_overflow();
if(old_option != option)
{
NRF24L01_WriteReg(NRF24L01_05_RF_CH, option); //hopping_frequency_no);
old_option = option;
}
}
}
else if(sub_protocol == XN297DUMP_CC2500)

View File

@@ -133,10 +133,9 @@ static void __attribute__((unused)) XN297_SetRXAddr(const uint8_t* addr, uint8_t
if(xn297_rf == XN297_NRF)
{
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, xn297_rx_addr, xn297_addr_len);
if(rx_packet_len >= 32)
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 32);
else
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, rx_packet_len);
if(rx_packet_len > 32)
rx_packet_len = 32;
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, rx_packet_len);
}
#endif
#ifdef CC2500_INSTALLED

View File

@@ -165,9 +165,14 @@
/*** PROTOCOLS TO INCLUDE ***/
/****************************/
//In this section select the protocols you want to be accessible when using the module.
//All the protocols will not fit in the Atmega328p module so you need to pick and choose.
//All the protocols will not fit in the STM32 or Atmega328p modules so you need to pick and choose.
//Comment the protocols you are not using with "//" to save Flash space.
//Already defined protocols selection
//#define MULTI_AIR //Only Air protocols will be available, all the others are disabled
//#define MULTI_SURFACE //Only Surface protocols will be available, all the others are disabled
//#define MULTI_EU //Only LBT/EU protocols will be available, all the others are disabled
//Protocol for module configuration
#define MULTI_CONFIG_INO
@@ -191,8 +196,10 @@
#define E01X_CYRF6936_INO
#define E129_CYRF6936_INO
#define J6PRO_CYRF6936_INO
#define LOSI_CYRF6936_INO
#define KYOSHO3_CYRF6936_INO
#define LOSI_CYRF6936_INO //Need DSM to be enabled
#define MLINK_CYRF6936_INO
#define SCORPIO_CYRF6936_INO
#define TRAXXAS_CYRF6936_INO
#define WFLY_CYRF6936_INO
#define WK2x01_CYRF6936_INO
@@ -221,11 +228,12 @@
#define BAYANG_RX_NRF24L01_INO
#define BUGSMINI_NRF24L01_INO
#define CABELL_NRF24L01_INO
//#define CFLIE_NRF24L01_INO
#define CFLIE_NRF24L01_INO
#define CG023_NRF24L01_INO
#define CX10_NRF24L01_INO //Include Q2X2 protocol
#define DM002_NRF24L01_INO
#define E016H_NRF24L01_INO
#define EAZYRC_NRF24L01_INO
#define ESKY_NRF24L01_INO
#define ESKY150_NRF24L01_INO
#define FQ777_NRF24L01_INO
@@ -239,14 +247,14 @@
#define KN_NRF24L01_INO
#define KYOSHO2_NRF24L01_INO
#define LOLI_NRF24L01_INO
//#define MOULDKG_NRF24L01_INO
#define MOULDKG_NRF24L01_INO
#define NCC1701_NRF24L01_INO
#define POTENSIC_NRF24L01_INO
#define PROPEL_NRF24L01_INO
#define REALACC_NRF24L01_INO
#define SGF22_NRF24L01_INO
#define SHENQI_NRF24L01_INO
#define SYMAX_NRF24L01_INO
#define TIGER_NRF24L01_INO
#define V2X2_NRF24L01_INO
#define V761_NRF24L01_INO
#define XERALL_NRF24L01_INO
@@ -336,6 +344,7 @@
#define HUBSAN_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define NCC1701_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define OMP_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define V761_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define PROPEL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define CABELL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define RLINK_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
@@ -565,6 +574,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
QX100
PROTO_BAYANG_RX
NONE
PROTO_BLUEFLY
NONE
PROTO_BUGS
NONE
PROTO_BUGSMINI
@@ -601,8 +612,11 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
DSMX_1F
DSMX_2F
DSMR
DSM2_SFC
PROTO_DSM_RX
NONE
DSM_RX
DSM_CLONE
DSM_ERASE
PROTO_E010R5
NONE
PROTO_E016H
@@ -615,6 +629,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
PROTO_E129
E129_E129
E129_C186
PROTO_EAZYRC
NONE
PROTO_ESKY
ESKY_STD
ESKY_ET4
@@ -667,10 +683,13 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
PROTO_FRSKY_RX
FRSKY_RX
FRSKY_CLONE
PROTO_FUTABA
NONE
PROTO_FX
FX816
FX620
FX9630
Q560
PROTO_FY326
FY326
FY319
@@ -727,6 +746,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
KYOSHO_HYPE
PROTO_KYOSHO2
NONE
PROTO_KYOSHO3
NONE
PROTO_LOLI
NONE
PROTO_LOSI
@@ -787,9 +808,12 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
RLINK_SURFACE
RLINK_AIR
RLINK_DUMBORC
RLINK_RC4G
PROTO_SCANNER
NONE
PROTO_FUTABA
PROTO_SCORPIO
NONE
PROTO_SGF22
NONE
PROTO_SHENQI
NONE
@@ -804,10 +828,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
PROTO_SYMAX
SYMAX
SYMAX5C
PROTO_TIGER
NONE
PROTO_TRAXXAS
RX6519
NONE
PROTO_V2X2
V2X2
JXD506
@@ -834,6 +856,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
PROTO_XK
X450
X420
XK_CARS
PROTO_YD717
YD717
SKYWLKR

View File

@@ -71,7 +71,11 @@ enum CYRF_PWR {
CYRF_PWR_DEFAULT,
};
enum FIND_CHANNEL {
FIND_CHANNEL_ANY = 0,
FIND_CHANNEL_EVEN = 1,
FIND_CHANNEL_ODD = 2,
};
/* SPI CYRF6936 */
/*
@@ -85,7 +89,7 @@ void CYRF_SetPower(u8 power);
void CYRF_ConfigCRCSeed(u16 crc);
static void CYRF_StartReceive();
void CYRF_ConfigSOPCode(const u8 *sopcodes);
void CYRF_ConfigDataCode(const u8 *datacodes, u8 len);
void CYRF_ConfigDataCode(const u8 *datacodes);
static u8 CYRF_ReadRSSI(u32 dodummyread);
static void CYRF_ReadDataPacket(u8 dpbuffer[]);
void CYRF_WriteDataPacket(const u8 dpbuffer[]);

View File

@@ -65,6 +65,7 @@ Protocol Name|Protocol Number|Sub_Proto 0|Sub_Proto 1|Sub_Proto 2|Sub_Proto 3|Su
[Assan](Protocols_Details.md#ASSAN---24)|24|||||||||NRF24L01|
[Bayang](Protocols_Details.md#BAYANG---14)|14|Bayang|H8S3D|X16_AH|IRDRONE|DHD_D4|QX100|||NRF24L01|XN297
[Bayang RX](Protocols_Details.md#BAYANG-RX---59)|59|Multi|CPPM|||||||NRF24L01|XN297
[BlueFly](Protocols_Details.md#BLUEFLY---95)|95|||||||||NRF24L01|
[Bugs](Protocols_Details.md#BUGS---41)|41|||||||||A7105|
[BugsMini](Protocols_Details.md#BUGSMINI---42)|42|BUGSMINI|BUGS3H|||||||NRF24L01|XN297
[Cabell](Protocols_Details.md#Cabell---34)|34|Cabell_V3|C_TELEM|-|-|-|-|F_SAFE|UNBIND|NRF24L01|
@@ -74,13 +75,14 @@ CFlie|38|CFlie||||||||NRF24L01|
[CX10](Protocols_Details.md#CX10---12)|12|GREEN|BLUE|DM007|-|J3015_1|J3015_2|MK33041||NRF24L01|XN297
[Devo](Protocols_Details.md#DEVO---7)|7|Devo|8CH|10CH|12CH|6CH|7CH|||CYRF6936|
[DM002](Protocols_Details.md#DM002---33)|33|||||||||NRF24L01|XN297
[DSM](Protocols_Details.md#DSM---6)|6|DSM2_1F|DSM2_2F|DSMX_1F|DSMX_2F|AUTO|DSMR_1F|||CYRF6936|
[DSM](Protocols_Details.md#DSM---6)|6|DSM2_1F|DSM2_2F|DSMX_1F|DSMX_2F|AUTO|DSMR_1F|DSM2SFC||CYRF6936|
[DSM_RX](Protocols_Details.md#DSM_RX---70)|70|Multi|CPPM|||||||CYRF6936|
[E010R5](Protocols_Details.md#E010R5---81)|81|||||||||CYRF6936|RF2500
[E016H](Protocols_Details.md#E016H---85)|85|||||||||NRF24L01|XN297
[E016HV2](Protocols_Details.md#E016HV2---80)|80|||||||||CC2500/NRF24L01|unknown
[E01X](Protocols_Details.md#E01X---45)|45|E012|E015|||||||CYRF6936|HS6200
[E129](Protocols_Details.md#E129---83)|83|E129|C186|||||||CYRF6936|RF2500
[EazyRC](Protocols_Details.md#EazyRC---61)|61|||||||||NRF24L01|XN297L
[ESky](Protocols_Details.md#ESKY---16)|16|ESky|ET4|||||||NRF24L01|
[ESky150](Protocols_Details.md#ESKY150---35)|35|||||||||NRF24L01|
[ESky150V2](Protocols_Details.md#ESKY150V2---69)|69|||||||||CC2500|NRF51822
@@ -96,7 +98,7 @@ CFlie|38|CFlie||||||||NRF24L01|
[FrskyX2](Protocols_Details.md#FRSKYX2---64)|64|CH_16|CH_8|EU_16|EU_8|Cloned|Cloned_8|||CC2500|
[Frsky_RX](Protocols_Details.md#FRSKY_RX---55)|55|Multi|CloneTX|EraseTX|CPPM|||||CC2500|
[Futaba/SFHSS](Protocols_Details.md#Futaba---21)|21|SFHSS||||||||CC2500|
[FX](Protocols_Details.md#FX---58)|28|816|620|||||||NRF24L01|
[FX](Protocols_Details.md#FX---58)|28|816|620|9630||||||NRF24L01|
[FY326](Protocols_Details.md#FY326---20)|20|FY326|FY319|||||||NRF24L01|
[GD00X](Protocols_Details.md#GD00X---47)|47|GD_V1*|GD_V2*|||||||NRF24L01|XN297L
[GW008](Protocols_Details.md#GW008---32)|32|||||||||NRF24L01|XN297
@@ -114,6 +116,7 @@ CFlie|38|CFlie||||||||NRF24L01|
[KN](Protocols_Details.md#KN---9)|9|WLTOYS|FEILUN|||||||NRF24L01|
[Kyosho](Protocols_Details.md#Kyosho---73)|73|FHSS|Hype|||||||A7105|
[Kyosho2](Protocols_Details.md#Kyosho2---93)|93|KT-17||||||||NRF24L01|
[Kyosho3](Protocols_Details.md#Kyosho3---98)|98|ASF||||||||CYRF6936|
[LOLI](Protocols_Details.md#LOLI---82)|82|||||||||NRF24L01|
[Losi](Protocols_Details.md#Losi---89)|89|||||||||CYRF6936|
[MJXq](Protocols_Details.md#MJXQ---18)|18|WLH08|X600|X800|H26D|E010*|H26WH|PHOENIX*||NRF24L01|XN297
@@ -130,16 +133,17 @@ CFlie|38|CFlie||||||||NRF24L01|
[Q2X2](Protocols_Details.md#Q2X2---29)|29|Q222|Q242|Q282||||||NRF24L01|
[Q303](Protocols_Details.md#Q303---31)|31|Q303|CX35|CX10D|CX10WD|||||NRF24L01|XN297
[Q90C](Protocols_Details.md#Q90C---72)|72|Q90C*||||||||NRF24L01|XN297
[RadioLink](Protocols_Details.md#RadioLink---74)|74|Surface|Air|DumboRC||||||CC2500|
[RadioLink](Protocols_Details.md#RadioLink---74)|74|Surface|Air|DumboRC|RC4G|||||CC2500|
[Realacc](Protocols_Details.md#Realacc---76)|76|R11||||||||NRF24L01|
[Redpine](Protocols_Details.md#Redpine---50)|50|FAST|SLOW|||||||NRF24L01|XN297
[Scanner](Protocols_Details.md#Scanner---54)|54|||||||||CC2500|
[Scorpio](Protocols_Details.md#Scorpio---94)|94|||||||||CYRF6936|
[SGF22](Protocols_Details.md#SGF22---97)|97|SGF22||||||||NRF24L01|XN297
[Shenqi](Protocols_Details.md#Shenqi---19)|19|Shenqi||||||||NRF24L01|LT8900
[Skyartec](Protocols_Details.md#Skyartec---68)|68|||||||||CC2500|CC2500
[SLT](Protocols_Details.md#SLT---11)|11|SLT_V1|SLT_V2|Q100|Q200|MR100||||NRF24L01|CC2500
[SLT](Protocols_Details.md#SLT---11)|11|SLT_V1|SLT_V2|Q100|Q200|MR100|V1_4CH|||NRF24L01|CC2500
[SymaX](Protocols_Details.md#Symax---10)|10|SYMAX|SYMAX5C|||||||NRF24L01|
[Tiger](Protocols_Details.md#Tiger---61)|61|||||||||NRF24L01|XN297
[Traxxas](Protocols_Details.md#Traxxas---43)|43|6519 RX||||||||CYRF6936|
[Traxxas](Protocols_Details.md#Traxxas---43)|43|TQ||||||||CYRF6936|
[V2x2](Protocols_Details.md#V2X2---5)|5|V2x2|JXD506|MR101||||||NRF24L01|
[V761](Protocols_Details.md#V761---48)|48|3CH|4CH|TOPRC||||||NRF24L01|XN297
[V911S](Protocols_Details.md#V911S---46)|46|V911S*|E119*|||||||NRF24L01|XN297
@@ -147,7 +151,7 @@ CFlie|38|CFlie||||||||NRF24L01|
[WFLY2](Protocols_Details.md#WFLY2---79)|79|RF20x||||||||A7105|
[WK2x01](Protocols_Details.md#WK2X01---30)|30|WK2801|WK2401|W6_5_1|W6_6_1|W6_HEL|W6_HEL_I|||CYRF6936|
[XERALL](Protocols_Details.md#XERALL---91)|91|Tank||||||||NRF24L01|XN297
[XK](Protocols_Details.md#XK---62)|62|X450|X420|||||||NRF24L01|XN297
[XK](Protocols_Details.md#XK---62)|62|X450|X420|Cars||||||NRF24L01|XN297
[YD717](Protocols_Details.md#YD717---8)|8|YD717|SKYWLKR|SYMAX4|XINXUN|NIHUI||||NRF24L01|
[ZSX](Protocols_Details.md#ZSX---52)|52|280||||||||NRF24L01|XN297
* "*" Sub Protocols designated by * suffix are using a XN297L@250kbps which will be emulated by default with the NRF24L01. If option (freq tune) is diffrent from 0, the CC2500 module (if installed) will be used instead. Each specific sub protocol has a more detailed explanation.
@@ -324,7 +328,11 @@ CH1|CH2|CH3|CH4
## Kyosho - *73*
### Sub_protocol FHSS - *0*
Surface protocol called FHSS introduced in 2017. Transmitters: KT-531P, KT-431PT...
Surface protocol called FHSS introduced in 2017. Transmitter: KT-531P. Models: Mini-Z.
Surface protocol called Syncro. TX: KT-331, RX: KR-331
Extended limits supported
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14
---|---|---|---|---|---|---|---|---|----|----|----|----|----
@@ -357,11 +365,9 @@ Models: TX: CADET 4 LITE
**Only 1 frequency hopping table**
### Sub_protocol SCX24 - *2*
TX: Axial AX-4 2.4GHz transmitter and Panda Hobby 3CH Smart Radio 2.4GHz (MT-305A)
TX: Axial AX-4 2.4GHz transmitter, HPI TF-41 and Panda Hobby 3CH Smart Radio 2.4GHz (MT-305A)
Models: Axial SCX24: Deadbolt, Jeep Wranger Rubicon, Chevrolet 1967 C10, B-17 Betty and Panda Hobby: Tetra K1, X1, X2
**Only 2 frequency hopping tables**
Models: Axial SCX24: Deadbolt, Jeep Wranger Rubicon, Chevrolet 1967 C10, B-17 Betty, HPI RF-50 and Panda Hobby: Tetra K1, X1, X2
Extended limits supported
@@ -520,27 +526,38 @@ Here is a table detailling the different RX output ranges based on the radio set
![Image](/docs/images/DSM_RX_Output.JPG)
### Sub_protocol DSM2_1F - *0*
DSM2, Resolution 1024, servo refresh rate can only be 22ms
Air DSM2, Resolution 1024, servo refresh rate can only be 22ms
### Sub_protocol DSM2_2F - *1*
DSM2, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
Air DSM2, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
### Sub_protocol DSMX_1F - *2*
DSMX, Resolution 2048, servo refresh rate can only be 22ms
Air DSMX, Resolution 2048, servo refresh rate can only be 22ms
### Sub_protocol DSMX_2F - *3*
DSMX, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
Air DSMX, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
### Sub_protocol AUTO - *4*
"AUTO" is recommended to automatically select the best settings for your DSM2 and DSMX RXs.
"AUTO" is recommended to automatically select the best settings for your air DSM2 and DSMX RXs.
### Sub_protocol DSMR_1F - *5*
DSMR receivers
Surface DSMR receivers
**Only 22 IDs available**, use RX num to cycle through them.
Telemetry enabled, extended limits available.
Telemetry enabled, extended limits available and no channel mapping. Do not use DSM/AUTO to bind but DSM/R_1F instead.
CH1|CH2|CH3|CH4|CH5|CH6|CH7
---|---|---|---|---|---|---
STR|THR|AUX1|AUX2|AUX3|AUX4|AUX5
### Sub_protocol DSM2SFC - *6*
Surface DSM2 receivers, tested with a SR3100
Extended limits available and no channel mapping. Do not use DSM/AUTO to bind but DSM/2SFC instead.
Servo refresh rate 22/11ms is repurposed to the frame rates 16.5ms(22) and 11ms(11).
CH1|CH2|CH3
---|---|---
STR|THR|AUX1
## DSM_RX - *70*
The DSM receiver protocol enables master/slave trainning, separate access from 2 different radios to the same model,...
@@ -615,21 +632,38 @@ Calib is the same as the original radio with both sticks down and to the left in
Models: Eachine E129/E130 and Twister Ninja 250
### Sub_protocol C186 - *1*
Models: C186/E120, C127/E110, K127, C159
Models: RC ERA C186/E120, C127/E110, K127, C159, C189, C129v2
The FC of the heli seems to store the trims Trim A/E/R=CH7..9. If you use these trims, make sure to center them after powering off the heli or they will be added to the previous trims and over correct.
CH10|CH11
---|---
Loop|Flip
Loop: circular flight on the C159 (others?)
Flip: flip/aerobatic on the C129v2 (others?)
## J6Pro - *22*
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
---|---|---|---|---|---|---|---|---|----|----|----
A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
## Kyosho3 - *98*
### Sub_protocol ASF - *0*
Surface protocol ASF. Models: Mini-Z.
Extended limits supported
CH1|CH2|CH3|CH4
---|---|---|---
STEERING|THROTTLE|CH3|CH4
## Losi - *89*
TX: LSR-3000
**Only 1 ID available**. More IDs can be added if you dump your original TX.
Extended limits supported
CH1|CH2|CH3
@@ -651,14 +685,23 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|----
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16
## Traxxas - *43*
Receiver 6519
Extended limits supported
## Scorpio - *94*
Model Scorpio Falco 300, TX:Nine Eagles 4CH-TX, RX:Nine Eagles 4CH-RX
CH1|CH2|CH3|CH4
---|---|---|---
AUX3|AUX4|THROTTLE|STEERING
A|E|T|R
## Traxxas - *43*
Transmitter TQ, Receivers: 6519, 2218(X), ECM-2.5
Extended limits supported
CH1|CH2|CH3|CH4|CH5|CH6
---|---|---|---|---|---
CH1|CH2|CH3|CH4|CH5|CH6
Warning from v1.3.4.7 channels order have changed
## WFLY - *40*
Receivers: WFR04S, WFR07S, WFR09S
@@ -981,6 +1024,17 @@ Telemetry: RX_RSSI (for the original value add -256), TX_RSSI, TX_QLY (0..100%)
### Sub_protocol DumboRC - *2*
Compatible RXs: X6/X6F/X6FG
### Sub_protocol RC4G - *3*
Compatible RXs: R4EH-G(/R4EH-H)
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
CH1|CH2|CH3|CH4|CH5|FS_CH1|FS_CH2|FS_CH3|FS_CH4
FS=FailSafe
CH5 is driven by CH3 on the original TX, gyro sensitivity?
## Futaba - *21*
Also called SFHSS depending on radio version.
@@ -1016,6 +1070,17 @@ If a CC2500 is installed it will be used for all the below protocols. Option in
If only a NRF24L01 is installed then these protocols might be problematic because they are using the XN297L emulation with a transmission speed of 250kbps which doesn't work very well with every NRF24L01, this is an hardware issue with the authenticity and accuracy of the components.
## BLUEFLY - *95*
Model: HP100
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
A|E|T|R|CH5|CH6|CH7|CH8
TRIM: either use this channel for trim only or add a mixer with aileron to increase the roll rate.
RATE: -100% high rate, +100% low rate
## GD00X - *47*
Model: GD005 C-17 Transport, GD006 DA62 and ZC-Z50
@@ -1174,6 +1239,14 @@ CH1|CH2|CH3|CH4|CH5|CH6
---|---|---|---|---|---
A|E|T|R|6G3D|Light
Model: KFPLAN Z61 BF109
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
A|E|T|R|-|Rate|Light|Unk1|Unk2
Unk1&2: long press right/left
## MT99XX2 - *92*
### Sub_protocol PA18 - *92*
@@ -1340,6 +1413,12 @@ FLIP: sets model into flip mode for approx 5 seconds at each throw of switch (re
MODE: -100% level, +100% acro
### Sub_protocol V1_4CH - *5*
CH1|CH2|CH3|CH4
---|---|---|---
CH1|CH2|CH3|CH4
## V911S - *46*
CH1|CH2|CH3|CH4|CH5|CH6
@@ -1354,18 +1433,14 @@ Models: WLtoys V911S, XK A110
### Sub_protocol E119 - *1*
Models: Eachine E119, JJRC W01-J3, XK A220 P-40, XK A800 R2, F959S R2, A160 R2, A280
CH1|CH2|CH3|CH4|CH5|CH6|CH7
---|---|---|---|---|---|---
A|E|T|R|CALIB|RATE|6G_3D
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
A|E|T|R|CALIB|RATE|6G_3D|6GSENIOR|LIGHT
A280 -> 6GSENIOR: -100% - 6G, +100% - Senior mode (turn off gyro), LIGHT: cycle the light through on-flash-off when the CH9 value is changed from -100% to 100%
## XK - *62*
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|----
A|E|T|R|Flight_modes|Take_off|Emerg stop|3D/6G|Picture|Video
Flight_modes: -100%=M-Mode, 0%=6G-Mode, +100%=V-Mode. CH6-CH10 are mementary switches.
CC2500: only X450 is supported.
### Sub_protocol X450 - *0*
@@ -1375,9 +1450,31 @@ If a CC2500 is installed it will be used for this sub protocol. Option in this c
If only a NRF24L01 is installed then this sub protocol might be problematic because it is using the xn297L emulation with a transmission speed of 250kbps which doesn't work very well with every NRF24L01, this is an hardware issue with the authenticity and accuracy of the components.
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|----
A|E|T|R|Flight_modes|Take_off|Emerg stop|3D/6G|Picture|Video
Flight_modes: -100%=M-Mode, 0%=6G-Mode, +100%=V-Mode. CH6-CH10 are mementary switches.
### Sub_protocol X420 - *1*
Models: XK X420/X520 (TX=X4)
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|----
A|E|T|R|Flight_modes|Take_off|Emerg stop|3D/6G|Picture|Video
Flight_modes: -100%=M-Mode, 0%=6G-Mode, +100%=V-Mode. CH6-CH10 are mementary switches.
Model: Tiger Drone 1400782
CH1|CH2|CH3|CH4|CH11|CH12
---|---|---|---|---|---
A|E|T|R|FLIP|LIGHT
### Sub_protocol Cars - *2*
Models: WLtoys cars 284131/284161/284010/124016/124017/144010 and Eachine EAT14
***
# NRF24L01 RF Module
@@ -1404,13 +1501,13 @@ Channels 14 and 15 (ANAAUX1 and ANAAUX2) only available with analog aux channel
### Sub_protocol BAYANG - *0*
Models: Eachine H8(C) mini, BayangToys X6/X7/X9, JJRC JJ850, Floureon H101 ...
Option=0 -> normal Bayang protocol
Option=0 or Telemetry = Off -> normal Bayang protocol
Option=1 -> enable telemetry with [Silverxxx firmware](https://github.com/silver13/H101-acro/tree/master). Value returned to the TX using FrSkyD Hub are RX RSSI, TX RSSI, A1=uncompensated battery voltage (set the ratio to 5.0 and adjust with offset), A2=compensated battery voltage (set the ratio to 5.0 and adjust with offset) and if supported AccX=P, AccY=I, ACCZ=D (which you can rename after the sensors discovery)
Option=1 or Telemetry = On -> enable telemetry with [Silverxxx firmware](https://github.com/silver13/H101-acro/tree/master). Value returned to the TX using FrSkyD Hub are RX RSSI, TX RSSI, A1=uncompensated battery voltage (set the ratio to 5.0 and adjust with offset), A2=compensated battery voltage (set the ratio to 5.0 and adjust with offset) and if supported AccX=P, AccY=I, ACCZ=D (which you can rename after the sensors discovery)
Option=2 -> enable analog aux channels with [NFE Silverware firmware](https://github.com/NotFastEnuf/NFE_Silverware). Two otherwise static bytes in the protocol overridden to add two 'analog' (non-binary) auxiliary channels.
Option=2 or Telemetry = Off+AUX -> enable analog aux channels with [NFE Silverware firmware](https://github.com/NotFastEnuf/NFE_Silverware). Two otherwise static bytes in the protocol overridden to add two 'analog' (non-binary) auxiliary channels.
Option=3 -> both Silverware telemetry and analog aux channels enabled.
Option=3 or Telemetry = On+AUX-> both Silverware telemetry and analog aux channels enabled.
### Sub_protocol H8S3D - *1*
Model: H8S 3D
@@ -1586,6 +1683,13 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
A|E|T|R|STOP|FLIP|-|HEADLESS|RTH
## EazyRC - *61*
Autobind protocol
CH1|CH2|CH3|CH4
---|---|---|---
STEERING||THROTTLE|
## ESKY - *16*
CH1|CH2|CH3|CH4|CH5|CH6
@@ -1630,6 +1734,28 @@ Only 8 TX IDs available
### Sub_protocol 620 - *1*
Model: FX620 SU35
### Sub_protocol 9630 - *2*
Model: FX9630, FX9603, QIDI-550
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
A|E|T|R|RATE|GYRO|TrimR|TrimA|TrimE
FX9630 and FX9603 Gyro: -100%=6G small throw, 0%=6G large throw, +100%=3D
QIDI-550 Gyro: -100%=3D, 0%=6G, +100%=Torque
### Sub_protocol Q560 - *2*
Model: QIDI-560
CH1|CH2|CH3|CH4|CH5|CH6|CH7
---|---|---|---|---|---|---
A|E|T|R|FLIP|GYRO|LEDs
FLIP and LEDs are toggle channels meaning that -100% to +100% is a command and +100% to -100% is also a command
Gyro: -100%=6G, 0%=3D+Gyro, +100%=3D
## FY326 - *20*
### Sub_protocol FY326 - *0*
@@ -1704,9 +1830,9 @@ CH1|CH2|CH3|CH4|CH5
| | |T|R|AUX
## KN - *9*
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11
---|---|---|---|---|---|---|---|---|----|----
A|E|T|R|DR|THOLD|IDLEUP|GYRO|Ttrim|Atrim|Etrim
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13
---|---|---|---|---|---|---|---|---|----|----|----|----
A|E|T|R|DR|THOLD|IDLEUP|GYRO|Ttrim|Atrim|Etrim|Rtrim|HoverDebugging
Dual Rate: +100%=full range, Throttle Hold: +100%=hold, Idle Up: +100%=3D, GYRO: -100%=6G, +100%=3G
@@ -1865,17 +1991,13 @@ A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL
Model: JXD 509 is using Q282 with CH12=Start/Stop motors
## Realacc - *76*
Model: Realacc R11
Untested protocol, let me know if it works.
Model: Realacc R11, Eachine E017
Autobind protocol
### Sub_protocol R11 - *0*
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|----
A|E|T|R|FLIP|LIGHT|CALIB|HLESS|RTH|UNK
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11
---|---|---|---|---|---|---|---|---|----|----
A|E|T|R|FLIP|LIGHT|CALIB|HLESS|RTH|THR_CUT|ROTATE
## Redpine - *50*
[Link to the forum](https://www.rcgroups.com/forums/showthread.php?3236043-Redpine-Lowest-latency-RC-protocol)
@@ -1883,6 +2005,15 @@ A|E|T|R|FLIP|LIGHT|CALIB|HLESS|RTH|UNK
### Sub_protocol FAST - *0*
### Sub_protocol SLOW - *1*
## SGF22 - *97*
Autobind protocol
Model: SGF22
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|---
A|E|T|R|MODE|FLIP|LIGHT|PHOTO|VIDEO|TRIMRESET
## Shenqi - *19*
Autobind protocol
@@ -1915,7 +2046,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11
A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS|MAG_CAL_X|MAG_CAL_Y
### Sub_protocol V2x2 - *0*
Models: WLToys V202/252/272, JXD 385/388, JJRC H6C, Yizhan Tarantula X6 ...
Models: WLToys V202/252/272/A959/K969/K979/K989/K999, JXD 385/388, JJRC H6C, Yizhan Tarantula X6 ...
PICTURE: also automatic Missile Launcher and Hoist in one direction
@@ -1945,15 +2076,6 @@ AUTO: Land=-100% Takeoff=+100%
The model can work with a none centered throttle.
## Tiger - *61*
Autobind protocol
**Only 1 ID**
CH1|CH2|CH3|CH4|CH5|CH6
---|---|---|---|---|---
A|E|T|R|FLIP|LIGHT
## V761 - *48*
Gyro: -100%=Beginner mode (Gyro on, yaw and pitch rate limited), 0%=Mid Mode ( Gyro on no rate limits), +100%=Mode Expert Gyro off
@@ -1974,6 +2096,8 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
### Sub_protocol 4CH - *1*
Models: Volantex V761-4+ and Eachine P51-D, F4U, F22 and may be others
If the model (761-11 and above) sends telemetry then the battery status ok/empty is in A1 (4.4V -> 2.2V) and RSSI gets a dummy value of 100.
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
A|E|T|R|GYRO|CALIB|FLIP|RTN_ACT|RTN

View File

@@ -84,22 +84,30 @@ buildEachRFModule() {
}
buildReleaseFiles(){
if [[ "$BOARD" =~ ":avr:multixmega32d4" ]]; then
if [[ "$RELEASE" == "scripts" ]]; then
build_release_scripts;
elif [[ "$RELEASE" == "orangerx" ]]; then
build_release_orx;
elif [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
elif [[ "$RELEASE" == "atmega328p" ]]; then
build_release_avr_noboot;
elif [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=optiboot" ]]; then
elif [[ "$RELEASE" == "atmega328p-optiboot" ]]; then
build_release_avr_optiboot;
elif [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]]; then
build_release_stm32f1_no_debug;
elif [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=native" ]]; then
build_release_stm32f1_native_debug;
elif [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=ftdi" ]]; then
build_release_stm32f1_serial_debug;
elif [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
elif [[ "$RELEASE" == "stm32f103-128k-4in1" ]]; then
build_release_stm32f1_4in1_no_debug;
elif [[ "$RELEASE" == "stm32f103-128k-usb-debug" ]]; then
build_release_stm32f1_4in1_native_debug;
elif [[ "$RELEASE" == "stm32f103-128k-serial-debug" ]]; then
build_release_stm32f1_4in1_serial_debug;
elif [[ "$RELEASE" == "stm32f103-cc2500-64k" ]]; then
build_release_stm32f1_cc2500_64k;
elif [[ "$RELEASE" == "stm32f103-cc2500-128k" ]]; then
build_release_stm32f1_cc2500_128k;
elif [[ "$RELEASE" == "stm32f103-128k-5in1" ]]; then
build_release_stm32f1_5in1;
elif [[ "$RELEASE" == "tlite-5in1" ]]; then
build_release_stm32f1_tlite;
elif [[ "$RELEASE" == "t18-5in1" ]]; then
build_release_stm32f1_t18int;
elif [[ "$BOARD" =~ ":STM32F1:multistm32f103c8:debug_option=none" ]]; then
build_release_stm32f1_64k;
else
printf "No release files for this board.";
fi

View File

@@ -22,6 +22,7 @@ mv build/Multiprotocol.ino.bin ./binaries/mm-avr-usbasp-aetr-CC2500-inv-v$MULTI_
printf "\e[33;1mBuilding mm-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin\e[0m\n";
opt_disable $ALL_PROTOCOLS;
opt_enable $CYRF6936_PROTOCOLS;
opt_disable E01X_CYRF6936_INO LOSI_CYRF6936_INO
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin;

View File

@@ -22,6 +22,7 @@ mv build/Multiprotocol.ino.bin ./binaries/mm-avr-txflash-aetr-CC2500-inv-v$MULTI
printf "\e[33;1mBuilding mm-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin\e[0m\n";
opt_disable $ALL_PROTOCOLS;
opt_enable $CYRF6936_PROTOCOLS;
opt_disable E01X_CYRF6936_INO LOSI_CYRF6936_INO
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin;

View File

@@ -16,11 +16,4 @@ buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-orangerx-aetr-blue-inv-v$MULTI_VERSION.bin;
printf "\e[33;1mPackaging ancilliary files for v$MULTI_VERSION\e[0m\n";
cp Multiprotocol/Multi.txt ./binaries/Multi.txt;
mkdir -p SCRIPTS/TOOLS;
cp Lua_scripts/*.lua SCRIPTS/TOOLS/;
cp Lua_scripts/*.txt SCRIPTS/TOOLS/;
zip -q ./binaries/MultiLuaScripts.zip SCRIPTS/TOOLS/*;
exit $exitcode;

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
source ./buildroot/bin/buildFunctions;
exitcode=0;
printf "\e[33;1mPackaging ancilliary files for v$MULTI_VERSION\e[0m\n";
cp Multiprotocol/Multi.txt ./binaries/Multi.txt;
mkdir -p SCRIPTS/TOOLS;
cp -r Lua_scripts/* SCRIPTS/TOOLS/;
find SCRIPTS/TOOLS -type f -name "*.md" -delete
zip -q -r ./binaries/MultiLuaScripts.zip SCRIPTS/TOOLS/*;
exit $exitcode;

View File

@@ -0,0 +1,97 @@
#!/usr/bin/env bash
source ./buildroot/bin/buildFunctions;
exitcode=0;
# Generic 4-in-1 AIR builds
printf "\e[33;1mBuilding mm-stm-serial-aetr-air-v$MULTI_VERSION.bin\e[0m\n";
opt_add MULTI_AIR
opt_disable ENABLE_PPM;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-aetr-air-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-serial-taer-air-v$MULTI_VERSION.bin\e[0m\n";
opt_replace AETR TAER;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-taer-air-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-serial-reta-air-v$MULTI_VERSION.bin\e[0m\n";
opt_replace TAER RETA;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-reta-air-v$MULTI_VERSION.bin;
# Generic 4-in-1 SURFACE builds
printf "\e[33;1mBuilding mm-stm-serial-aetr-sfc-v$MULTI_VERSION.bin\e[0m\n";
opt_replace RETA AETR;
opt_remove MULTI_AIR;
opt_add MULTI_SURFACE;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-aetr-sfc-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-serial-taer-sfc-v$MULTI_VERSION.bin\e[0m\n";
opt_replace AETR TAER;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-taer-sfc-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-serial-reta-sfc-v$MULTI_VERSION.bin\e[0m\n";
opt_replace TAER RETA;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-reta-sfc-v$MULTI_VERSION.bin;
# Generic 4-in-1 LBT/EU builds
printf "\e[33;1mBuilding mm-stm-serial-aetr-lbt-v$MULTI_VERSION.bin\e[0m\n";
opt_replace RETA AETR;
opt_remove MULTI_SURFACE;
opt_add MULTI_EU;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-aetr-lbt-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-serial-taer-lbt-v$MULTI_VERSION.bin\e[0m\n";
opt_replace AETR TAER;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-taer-lbt-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-serial-reta-lbt-v$MULTI_VERSION.bin\e[0m\n";
opt_replace TAER RETA;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-reta-lbt-v$MULTI_VERSION.bin;
# 4-in-1 PPM builds
printf "\e[33;1mBuilding mm-stm-ppm-aetr-v$MULTI_VERSION.bin\e[0m\n";
opt_add MULTI_AIR;
opt_enable A7105_INSTALLED;
opt_enable CYRF6936_INSTALLED;
opt_enable NRF24L01_INSTALLED;
opt_remove MULTI_EU;
opt_enable ENABLE_PPM;
opt_disable ENABLE_SERIAL;
opt_replace RETA AETR;
opt_disable MULTI_STATUS;
opt_disable MULTI_TELEMETRY;
opt_set NBR_BANKS 5;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-ppm-aetr-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-ppm-taer-v$MULTI_VERSION.bin\e[0m\n";
opt_replace AETR TAER;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-ppm-taer-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-ppm-reta-v$MULTI_VERSION.bin\e[0m\n";
opt_replace TAER RETA;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-ppm-reta-v$MULTI_VERSION.bin;
exit $exitcode;

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bash
source ./buildroot/bin/buildFunctions;
exitcode=0;
# DIY 5-in-1 AIR builds
printf "\e[33;1mBuilding mm-stm-5in1-aetr-air-v$MULTI_VERSION.bin\e[0m\n";
opt_add MULTI_AIR;
opt_disable ENABLE_PPM;
opt_disable CFLIE_NRF24L01_INO
opt_enable SX1276_INSTALLED;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-aetr-air-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-5in1-taer-air-v$MULTI_VERSION.bin\e[0m\n";
opt_replace AETR TAER;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-taer-air-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-5in1-reta-air-v$MULTI_VERSION.bin\e[0m\n";
opt_replace TAER RETA;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-reta-air-v$MULTI_VERSION.bin;
# DIY 5-in-1 SURFACE builds
printf "\e[33;1mBuilding mm-stm-5in1-aetr-sfc-v$MULTI_VERSION.bin\e[0m\n";
opt_add MULTI_SURFACE;
opt_remove MULTI_AIR;
opt_enable CFLIE_NRF24L01_INO
opt_replace RETA AETR;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-aetr-sfc-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-5in1-taer-sfc-v$MULTI_VERSION.bin\e[0m\n";
opt_replace AETR TAER;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-taer-sfc-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-5in1-reta-sfc-v$MULTI_VERSION.bin\e[0m\n";
opt_replace TAER RETA;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-reta-sfc-v$MULTI_VERSION.bin;
# DIY 5-in-1 LBT builds
printf "\e[33;1mBuilding mm-stm-5in1-aetr-lbt-v$MULTI_VERSION.bin\e[0m\n";
opt_remove MULTI_SURFACE;
opt_add MULTI_EU;
opt_replace RETA AETR;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-aetr-lbt-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-5in1-taer-lbt-v$MULTI_VERSION.bin\e[0m\n";
opt_replace AETR TAER;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-taer-lbt-v$MULTI_VERSION.bin;
printf "\e[33;1mBuilding mm-stm-5in1-reta-lbt-v$MULTI_VERSION.bin\e[0m\n";
opt_replace TAER RETA;
buildMulti;
exitcode=$((exitcode+$?));
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-reta-lbt-v$MULTI_VERSION.bin;
exit $exitcode;

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