Compare commits
320 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
dcbc557bf7 | ||
|
e556f5cc40 | ||
|
9ef2415178 | ||
|
bc1a809325 | ||
|
082e96e381 | ||
|
abd26ee113 | ||
|
98518b3c92 | ||
|
d19de99172 | ||
|
13024e3816 | ||
|
90fb2d745f | ||
|
fa13b67f3a | ||
|
10be906bec | ||
|
f538884d48 | ||
|
d3e5acf704 | ||
|
2ac4745c62 | ||
|
889e01c7c6 | ||
|
db5f1f8899 | ||
|
d091c57e10 | ||
|
0fcb4b7f1a | ||
|
432e2e08a4 | ||
|
77efe467ad | ||
|
b9c828c878 | ||
|
99cd4d34d4 | ||
|
a9be2a8644 | ||
|
835facd2c3 | ||
|
9e20e47c5a | ||
|
a916275f0d | ||
|
9beade33de | ||
|
5ba70c3571 | ||
|
168aa89c57 | ||
|
fa055e991c | ||
|
5437d88642 | ||
|
d800f2c333 | ||
|
78f6af6448 | ||
|
b04d4a54f7 | ||
|
ed65c81add | ||
|
9bdc24c42a | ||
|
7107d46d29 | ||
|
825f560cbb | ||
|
ccaec304d5 | ||
|
22d45349cc | ||
|
5f26d624ad | ||
|
496c07943f | ||
|
af87b0f6d1 | ||
|
2918e63fb4 | ||
|
ed63ef7efe | ||
|
36d25c7773 | ||
|
a3ef2b94d4 | ||
|
ad8b45773d | ||
|
b2dec9b331 | ||
|
565aaed0c7 | ||
|
2f520f2e91 | ||
|
f1470a80dd | ||
|
b6f78e93a0 | ||
|
58bfd3b8b0 | ||
|
9e5e907f4a | ||
|
4b68443c8f | ||
|
f092e137c7 | ||
|
7b9941e537 | ||
|
d03a8787d1 | ||
|
75f79095ae | ||
|
b901bedad6 | ||
|
dbbef9181a | ||
|
98a54300e0 | ||
|
56fa7e788b | ||
|
7af23017ff | ||
|
a07c23b25f | ||
|
b5b2dc37d4 | ||
|
756af87ec1 | ||
|
e5810a2978 | ||
|
eaf71c2f49 | ||
|
546a962d96 | ||
|
fd150fa109 | ||
|
9b66711052 | ||
|
550754c7f9 | ||
|
729fdd4719 | ||
|
2713b18099 | ||
|
5b5e95066a | ||
|
b1f8560509 | ||
|
50c18311c9 | ||
|
95746f80a1 | ||
|
bb7685e7a5 | ||
|
a44126583e | ||
|
7fbca99bf3 | ||
|
8db90fb6fc | ||
|
406f5feca5 | ||
|
0e5834a457 | ||
|
75445ee4a7 | ||
|
e724d6970e | ||
|
190ebaefd4 | ||
|
3fdf417ac9 | ||
|
e05bc7c447 | ||
|
e2876c7e8c | ||
|
7acfebc30e | ||
|
af12b21899 | ||
|
68a4285b2a | ||
|
f58f7800d2 | ||
|
10b230d2dd | ||
|
58b19a2130 | ||
|
1b79d7f80f | ||
|
e0299f6c7d | ||
|
64ea7111ac | ||
|
edaee63f16 | ||
|
b449212c34 | ||
|
edaad73290 | ||
|
3d5e43da3b | ||
|
b8c5929521 | ||
|
8685fcae7f | ||
|
6edd2a14a7 | ||
|
600ffe87d7 | ||
|
c6ff0e27d9 | ||
|
7a7b4b2e74 | ||
|
8a30bf1c0a | ||
|
dd82cbec63 | ||
|
be4595fe67 | ||
|
54ae77ed7f | ||
|
2bdbd7088c | ||
|
1d3ed78622 | ||
|
79b1c54007 | ||
|
81eb5dc6bc | ||
|
85a0e4bde8 | ||
|
63dfa316e8 | ||
|
9d383432a5 | ||
|
6b181db629 | ||
|
873279dbe9 | ||
|
f35be2984a | ||
|
7ddeb31e95 | ||
|
7444c44b48 | ||
|
08d1dcbed2 | ||
|
3e4f4e36c1 | ||
|
902419dd3d | ||
|
038b3b9225 | ||
|
45f0154f4b | ||
|
e03864e35f | ||
|
de35ee09f5 | ||
|
c88952c35e | ||
|
ffae7dda1d | ||
|
4f17f76b39 | ||
|
31ef090508 | ||
|
04d4e39b87 | ||
|
b3537ea75a | ||
|
bccc050165 | ||
|
0f0df176de | ||
|
5542e7005d | ||
|
eb35fefd3e | ||
|
5acc3a8d01 | ||
|
9e9c3958c6 | ||
|
7f3a93ca4c | ||
|
debc9de11a | ||
|
f117105124 | ||
|
2e3520acad | ||
|
91af921d98 | ||
|
ab45ec6d1c | ||
|
26b0b6bd20 | ||
|
1b9ce32e89 | ||
|
332e55831c | ||
|
7051438e5d | ||
|
28467fac57 | ||
|
c7513abad8 | ||
|
e6e13c0fdd | ||
|
9579a667fc | ||
|
cbedda2471 | ||
|
f8695befe2 | ||
|
e951e3146b | ||
|
4c0b46549f | ||
|
188f8ff9ce | ||
|
bee6e59582 | ||
|
af47462ba7 | ||
|
d6ccd4af54 | ||
|
0feedc6fa9 | ||
|
b5bc7c04fb | ||
|
a15371d989 | ||
|
3c82f37e2b | ||
|
4f914a18ae | ||
|
1cbce29970 | ||
|
e0c44ed5a8 | ||
|
390e5dd654 | ||
|
968293e599 | ||
|
09ee173e3b | ||
|
babfee0f9e | ||
|
72da3c5bc5 | ||
|
4df1e65a7f | ||
|
1459d690d8 | ||
|
8d96066215 | ||
|
93a5834dd0 | ||
|
5f9ac82ed1 | ||
|
2108912263 | ||
|
72f87cade9 | ||
|
50bd4850fa | ||
|
dc1490b9b0 | ||
|
b18adb0efe | ||
|
53d5684dfd | ||
|
724abbc935 | ||
|
de610b53fc | ||
|
dd7ee7bdce | ||
|
31a9f6860d | ||
|
4a66ae64c6 | ||
|
11ae26a431 | ||
|
cdabde5d67 | ||
|
ce75dd3355 | ||
|
69484b5278 | ||
|
a90e1f2d3a | ||
|
5af246bba0 | ||
|
75a46858da | ||
|
8ac53657ec | ||
|
2888d3e937 | ||
|
3d989a47db | ||
|
a7d6d12679 | ||
|
457703b881 | ||
|
8e663f2531 | ||
|
8c2fe5f65e | ||
|
7549783741 | ||
|
e6bafaabb7 | ||
|
9286ac84f6 | ||
|
ede40ac598 | ||
|
88fad2dc9f | ||
|
549d3ad653 | ||
|
62aa58d32d | ||
|
21a06c2925 | ||
|
9acb3b0e2c | ||
|
785edde659 | ||
|
7da6d52a84 | ||
|
61cbe45ce2 | ||
|
23af33e214 | ||
|
11db967b8a | ||
|
d419e2b344 | ||
|
2b69c1184e | ||
|
1ceed87298 | ||
|
a1737eab46 | ||
|
9cbcafe6cf | ||
|
495706314f | ||
|
595511979b | ||
|
b8d30f47be | ||
|
b7097bdfb7 | ||
|
a682b0e604 | ||
|
7e7b555809 | ||
|
62ecaa8412 | ||
|
5ae052317d | ||
|
f3331ca397 | ||
|
ffcfd44127 | ||
|
5ef944241a | ||
|
ab5f75b1b3 | ||
|
10ec4dd735 | ||
|
a62d1dcd2e | ||
|
2c9e98e341 | ||
|
0bf94e96b5 | ||
|
8d84386c7a | ||
|
cd721e31d8 | ||
|
1294ad21cf | ||
|
01bc08575f | ||
|
ecfe17915f | ||
|
f97aa3597d | ||
|
2e1d763d54 | ||
|
93a2cc8b7f | ||
|
abfebb3da4 | ||
|
ce5f4ec264 | ||
|
a41123deb2 | ||
|
fabb65a2bb | ||
|
eae1329dfe | ||
|
a8ae0a2bd1 | ||
|
c814cc1bd4 | ||
|
4e7c1502ff | ||
|
8ddee12de5 | ||
|
692bcc1fbb | ||
|
0bb345e3fc | ||
|
c193d0b9dd | ||
|
410ce5cc4c | ||
|
cefe69a692 | ||
|
daa4ded390 | ||
|
5949fca990 | ||
|
ed2e2e4f32 | ||
|
b2f8f482bb | ||
|
89023d4b55 | ||
|
66ac007d4c | ||
|
139cd4c583 | ||
|
0fed2486f5 | ||
|
11c01004bf | ||
|
f49f03d7da | ||
|
90bb5f8871 | ||
|
401cc76f20 | ||
|
6297810edc | ||
|
01aef0a822 | ||
|
186730231e | ||
|
770a12ffdf | ||
|
40fa242012 | ||
|
c4e70ab4fd | ||
|
2da8b3c42a | ||
|
38a79c816a | ||
|
1d8f1a0857 | ||
|
5901bac374 | ||
|
2e7b1dc904 | ||
|
7052751261 | ||
|
60047e2c73 | ||
|
40b393ac4a | ||
|
1c6dc01959 | ||
|
5148449066 | ||
|
fcc4d19430 | ||
|
c80f705fa2 | ||
|
c95db35b41 | ||
|
35f3548992 | ||
|
58f6716035 | ||
|
2b15de0f90 | ||
|
be91409df9 | ||
|
4d8e440965 | ||
|
2d469d074e | ||
|
96405d27b5 | ||
|
75c9fb40a7 | ||
|
cd1c15a45a | ||
|
2bd50f4c8c | ||
|
4c2ddcbe48 | ||
|
d7f9ef6967 | ||
|
bfc8c2f9fd | ||
|
ce6243d6e3 | ||
|
80f9ff4163 | ||
|
d9f8a3989a | ||
|
416f7d5c19 | ||
|
eb24dd5549 | ||
|
ba19592973 | ||
|
98d8d7fb5f | ||
|
ad0947b0b7 |
265
.github/workflows/main.yml
vendored
@ -1,6 +1,6 @@
|
||||
# Workflow for testing MULTI-Module firmware builds
|
||||
|
||||
name: CI
|
||||
name: MULTI Test, Build, Deploy, Release
|
||||
|
||||
on:
|
||||
# Trigger the workflow on pushes, except those that are tagged (avoids double-testing releases)
|
||||
@ -32,33 +32,45 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Configure the board matrix
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
board: [
|
||||
"multi4in1:avr:multiatmega328p:bootloader=none",
|
||||
"multi4in1:avr:multiatmega328p:bootloader=optiboot",
|
||||
"multi4in1:avr:multixmega32d4",
|
||||
"multi4in1:STM32F1:multi5in1t18int",
|
||||
"multi4in1:STM32F1:multistm32f103cb:debug_option=none",
|
||||
"multi4in1:STM32F1:multistm32f103cb:debug_option=native",
|
||||
"multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi",
|
||||
"multi4in1:STM32F1:multistm32f103c8:debug_option=none"
|
||||
]
|
||||
include:
|
||||
- board: "multi4in1:avr:multiatmega328p:bootloader=none"
|
||||
name: "ATmega328p"
|
||||
- board: "multi4in1:avr:multiatmega328p:bootloader=optiboot"
|
||||
name: "ATmega328p (Optiboot)"
|
||||
- board: "multi4in1:avr:multixmega32d4"
|
||||
name: "OrangeRX"
|
||||
- board: "multi4in1:STM32F1:multistm32f103c8:debug_option=none"
|
||||
name: "STM32F103 (64KB)"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
|
||||
name: "STM32F103 (128KB)"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=native"
|
||||
name: "STM32F103 (128KB, USB Debug)"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi"
|
||||
name: "STM32F103 (128KB, Serial Debug)"
|
||||
- board: "multi4in1:STM32F1:multi5in1t18int"
|
||||
name: "T18 5-in-1 (128KB)"
|
||||
|
||||
# Set the build name using the friendly board name
|
||||
name: "[Test] ${{ matrix.name }}"
|
||||
|
||||
# Set the environment variables
|
||||
env:
|
||||
BOARD: ${{ matrix.board }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Arduino CLI
|
||||
uses: arduino/setup-arduino-cli@v1.1.1
|
||||
uses: arduino/setup-arduino-cli@v2
|
||||
with:
|
||||
version: "0.32.2"
|
||||
|
||||
- name: Prepare build environment
|
||||
run: |
|
||||
@ -67,15 +79,22 @@ jobs:
|
||||
echo "Event action: ${{ github.event.action }}"
|
||||
echo "Tag name: ${{ github.event.release.tag_name }}"
|
||||
|
||||
arduino-cli config init --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json
|
||||
arduino-cli config init --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json,https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/devel/source/package_multi_4in1_board_devel_index.json
|
||||
arduino-cli core update-index
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1:avr:" ]]; then
|
||||
if [[ "$BOARD" =~ ":avr:" ]]; then
|
||||
arduino-cli core install arduino:avr;
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:avr" ]]; then
|
||||
arduino-cli core install multi4in1-devel:avr
|
||||
elif [[ "$BOARD" =~ "multi4in1:avr" ]]; then
|
||||
arduino-cli core install multi4in1:avr
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1-devel:STM32F1
|
||||
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1:STM32F1
|
||||
fi
|
||||
|
||||
@ -109,18 +128,18 @@ jobs:
|
||||
echo "ALL_RFMODULES=$(echo $ALL_RFMODULES)" >> $GITHUB_ENV
|
||||
|
||||
# Disable CHECK_FOR_BOOTLOADER when not needed
|
||||
if [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=none" ]]; then
|
||||
if [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
fi
|
||||
|
||||
# Trim the build down for the Atmega328p board
|
||||
if [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then
|
||||
if [[ "$BOARD" =~ ":avr:multiatmega328p:" ]]; then
|
||||
opt_disable $ALL_PROTOCOLS
|
||||
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
|
||||
fi
|
||||
|
||||
# Trim the enabled protocols down for the STM32F103CB board with debugging or the STM32F103C8 board in general
|
||||
if [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi" ]] || [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=native" ]] || [[ "$BOARD" =~ "multi4in1:STM32F1:multistm32f103c8" ]]; then
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=ftdi" ]] || [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=native" ]] || [[ "$BOARD" =~ ":STM32F1:multistm32f103c8" ]]; then
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
|
||||
fi
|
||||
@ -133,7 +152,7 @@ jobs:
|
||||
- name: Build default configuration
|
||||
run: |
|
||||
# Skip the default build for boards where it's too large now
|
||||
if [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" == "multi4in1:STM32F1:multi5in1t18int" ]]; then
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
printf "Not testing default build for $BOARD.";
|
||||
else
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
@ -142,23 +161,38 @@ jobs:
|
||||
|
||||
- name: Build serial only
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
opt_disable ENABLE_PPM;
|
||||
buildMulti;
|
||||
# Skip the serial-only build for boards where it's too large now
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
printf "Not testing serial-only build for $BOARD.";
|
||||
else
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
opt_disable ENABLE_PPM;
|
||||
buildMulti;
|
||||
fi
|
||||
|
||||
- name: Build PPM only
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
opt_disable ENABLE_SERIAL;
|
||||
buildMulti;
|
||||
# Skip the PPM-only build for boards where it's too large now
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
printf "Not testing PPM-only build for $BOARD.";
|
||||
else
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||
opt_disable ENABLE_SERIAL;
|
||||
buildMulti;
|
||||
fi
|
||||
|
||||
- name: Build each RF module individually
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
||||
buildEachRFModule;
|
||||
# Skip the per-RF module builds for boards which have fixed modules
|
||||
if [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
printf "Not testing individual RF module builds for $BOARD.";
|
||||
else
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
||||
buildEachRFModule;
|
||||
fi
|
||||
|
||||
- name: Build each protocol individually
|
||||
run: |
|
||||
@ -166,6 +200,128 @@ jobs:
|
||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
||||
buildEachProtocol;
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Configure the board matrix
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- board: "multi4in1:avr:multiatmega328p:bootloader=none"
|
||||
name: "ATmega328p"
|
||||
release: "atmega328p"
|
||||
- board: "multi4in1:avr:multiatmega328p:bootloader=optiboot"
|
||||
name: "ATmega328p (Optiboot)"
|
||||
release: "atmega328p-optiboot"
|
||||
- board: "multi4in1:avr:multixmega32d4"
|
||||
name: "OrangeRX"
|
||||
release: "orangerx"
|
||||
- board: "multi4in1:STM32F1:multistm32f103c8:debug_option=none"
|
||||
name: "STM32F103 CC2500 (64KB)"
|
||||
release: "stm32f103-cc2500-64k"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
|
||||
name: "STM32F103 CC2500 (128KB)"
|
||||
release: "stm32f103-cc2500-128k"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
|
||||
name: "STM32F103 (128KB)"
|
||||
release: "stm32f103-128k-4in1"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=native"
|
||||
name: "STM32F103 (128KB, USB Debug)"
|
||||
release: "stm32f103-128k-usb-debug"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi"
|
||||
name: "STM32F103 (128KB, Serial Debug)"
|
||||
release: "stm32f103-128k-serial-debug"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
|
||||
name: "STM32F103 5-in-1 (128KB)"
|
||||
release: "stm32f103-128k-5in1"
|
||||
- board: "multi4in1:STM32F1:multistm32f103cb:debug_option=none"
|
||||
name: "T-Lite 5-in-1 (128KB)"
|
||||
release: "tlite-5in1"
|
||||
- board: "multi4in1:STM32F1:multi5in1t18int"
|
||||
name: "T18 5-in-1 (128KB)"
|
||||
release: "t18-5in1"
|
||||
- board: "none"
|
||||
name: "Scripts"
|
||||
release: "scripts"
|
||||
|
||||
# Set the build name using the friendly board name
|
||||
name: "[Build] ${{ matrix.name }}"
|
||||
|
||||
# Set the environment variables
|
||||
env:
|
||||
BOARD: ${{ matrix.board }}
|
||||
RELEASE: ${{ matrix.release }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Arduino CLI
|
||||
uses: arduino/setup-arduino-cli@v2
|
||||
with:
|
||||
version: "0.32.2"
|
||||
|
||||
- name: Prepare build environment
|
||||
run: |
|
||||
echo "Github Ref: $GITHUB_REF"
|
||||
echo "Event name: ${{ github.event_name }}"
|
||||
echo "Event action: ${{ github.event.action }}"
|
||||
echo "Tag name: ${{ github.event.release.tag_name }}"
|
||||
|
||||
arduino-cli config init --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json,https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/devel/source/package_multi_4in1_board_devel_index.json
|
||||
arduino-cli core update-index
|
||||
|
||||
if [[ "$BOARD" =~ ":avr:" ]]; then
|
||||
arduino-cli core install arduino:avr;
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:avr" ]]; then
|
||||
arduino-cli core install multi4in1-devel:avr
|
||||
elif [[ "$BOARD" =~ "multi4in1:avr" ]]; then
|
||||
arduino-cli core install multi4in1:avr
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1-devel:STM32F1
|
||||
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1:STM32F1
|
||||
fi
|
||||
|
||||
chmod +x ${GITHUB_WORKSPACE}/buildroot/bin/*
|
||||
echo "${GITHUB_WORKSPACE}/buildroot/bin" >> $GITHUB_PATH
|
||||
|
||||
mkdir ./build
|
||||
mkdir ./binaries
|
||||
|
||||
- name: Configure MULTI-Module firmware options
|
||||
run: |
|
||||
# Load the build functions
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
|
||||
# Get the version
|
||||
getMultiVersion
|
||||
echo "MULTI_VERSION=$(echo $MULTI_VERSION)" >> $GITHUB_ENV
|
||||
|
||||
# Get all the protocols for this board
|
||||
getAllProtocols
|
||||
echo "A7105_PROTOCOLS=$(echo $A7105_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CC2500_PROTOCOLS=$(echo $CC2500_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CYRF6936_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "NRF24L01_PROTOCOLS=$(echo $NRF24L01_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "SX1276_PROTOCOLS=$(echo $SX1276_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "CCNRF_INO_PROTOCOLS=$(echo $CCNRF_INO_PROTOCOLS)" >> $GITHUB_ENV
|
||||
echo "ALL_PROTOCOLS=$(echo $ALL_PROTOCOLS)" >> $GITHUB_ENV
|
||||
|
||||
# Disable CHECK_FOR_BOOTLOADER when not needed
|
||||
if [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
fi
|
||||
|
||||
- name: Save default firmware configuration
|
||||
run: |
|
||||
cat Multiprotocol/_Config.h
|
||||
cp Multiprotocol/_Config.h ./_Config.h.bak
|
||||
|
||||
- name: Build release files
|
||||
run: |
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
@ -180,16 +336,43 @@ jobs:
|
||||
echo "HAVE_FILES=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Deploy files to release
|
||||
if: github.event_name == 'release' && github.event.action == 'created' && env.HAVE_FILES == 'true'
|
||||
uses: AButler/upload-release-assets@v2.0
|
||||
with:
|
||||
files: './binaries/*'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: 'Upload Artifacts'
|
||||
if: env.HAVE_FILES == 'true'
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact/@v4
|
||||
with:
|
||||
name: multi-${{ matrix.release }}
|
||||
path: ./binaries/
|
||||
|
||||
deploy:
|
||||
name: "[Deploy] Attach Build Artifacts"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test, build]
|
||||
steps:
|
||||
- name: Combine and upload build artifacts
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
with:
|
||||
name: multi-test-build
|
||||
path: ./binaries/
|
||||
pattern: multi-*
|
||||
delete-merged: true
|
||||
retention-days: 90
|
||||
|
||||
release:
|
||||
name: "[Release] Publish Files to Release"
|
||||
if: github.event_name == 'release' && github.event.action == 'created'
|
||||
runs-on: ubuntu-latest
|
||||
needs: deploy
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: multi-test-build
|
||||
path: ./artifacts/
|
||||
|
||||
- name: Display downloaded artifacts
|
||||
run: ls -R ./artifacts/
|
||||
|
||||
- name: Deploy artifacts to release
|
||||
uses: AButler/upload-release-assets@v3.0
|
||||
with:
|
||||
files: './artifacts/*'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
@ -1,768 +0,0 @@
|
||||
local toolName = "TNS|DSM Forward Programming v0.2|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for DSM description
|
||||
-- Multi_Buffer[0..2]=="DSM" -> Lua script is running
|
||||
-- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent
|
||||
-- Multi_Buffer[4..9]=6 bytes of TX to RX data
|
||||
-- Multi_Buffer[10..25]=16 bytes of RX to TX data
|
||||
--
|
||||
-- To start operation:
|
||||
-- Write 0x00 at address 3
|
||||
-- Write 0x00 at address 10
|
||||
-- Write "DSM" at address 0..2
|
||||
--###############################################################################
|
||||
|
||||
local RX_VERSION, WAIT_CMD, MENU_TITLE, MENU_LINES, MENU_VALUES, VALUE_CHANGING, VALUE_CHANGING_WAIT, VALUE_CHANGED, EXIT, EXIT_DONE = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
local MENU, LIST_MENU_NOCHANGING, LIST_MENU1, LIST_MENU2, VALUE_NOCHANGING = 0x1C, 0x6C, 0x0C, 0x4C, 0x60
|
||||
local Phase = RX_VERSION
|
||||
local Waiting_RX = 0
|
||||
local Text = {}
|
||||
local RxName = {}
|
||||
local Retry=100
|
||||
local Blink = 0
|
||||
local Value_Changed=0
|
||||
|
||||
local Menu = { Cur=nil, Id=nil, Title="", Prev=nil, PrevId=nil, Next=nil, NextId=nil, Back=nil, BackId=nil, CurLine=nil, SelLine=nil, EditLine=nil }
|
||||
local Line = {}
|
||||
local RX = { Name="", Version="" }
|
||||
|
||||
-- used for debug
|
||||
local rxAnswer = ""
|
||||
local debugLine = 0
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GetDebugInfo(lineNr) -- used for debug
|
||||
local i
|
||||
|
||||
debugLine = lineNr
|
||||
rxAnswer = "RX:"
|
||||
for i=10, 25 do
|
||||
rxAnswer = rxAnswer.." "..string.format("%02X", multiBuffer(i))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function conv_int16(number)
|
||||
if number >= 0x8000 then
|
||||
return number - 0x10000
|
||||
end
|
||||
return number
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function Get_Text(index)
|
||||
out = Text[index]
|
||||
if out == nil then -- unknown...
|
||||
out = "Unknown_"..string.format("%X",index)
|
||||
end
|
||||
return out
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function Get_RxName(index)
|
||||
out = RxName[index]
|
||||
if out == nil then -- unknown...
|
||||
out = "Unknown_"..string.format("%X",index)
|
||||
end
|
||||
return out
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Release()
|
||||
multiBuffer( 0, 0 )
|
||||
Phase = EXIT_DONE
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Send(...)
|
||||
local arg = {...}
|
||||
for i = 1 , #arg do
|
||||
multiBuffer( 3+i, arg[i])
|
||||
end
|
||||
multiBuffer( 3, 0x70+#arg)
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function Value_Add(dir)
|
||||
local line=Line[Menu.SelLine]
|
||||
Speed = getRotEncSpeed()
|
||||
if Speed == ROTENC_MIDSPEED then
|
||||
line.Val = line.Val + (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then
|
||||
line.Val = line.Val + (15 * dir)
|
||||
else
|
||||
line.Val = line.Val + dir
|
||||
end
|
||||
if line.Val > line.Max then
|
||||
line.Val = line.Max
|
||||
elseif line.Val < line.Min then
|
||||
line.Val = line.Min
|
||||
end
|
||||
if Line[Menu.SelLine].Type ~= LIST_MENU_NOCHANGING then
|
||||
Phase = VALUE_CHANGING
|
||||
Waiting_RX = 0
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Menu(event)
|
||||
local Speed = 0
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if Phase == RX_VERSION then
|
||||
DSM_Release()
|
||||
else
|
||||
Phase = EXIT
|
||||
Waiting_RX = 0
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
if Menu.EditLine == nil then
|
||||
-- not changing a value
|
||||
if Menu.SelLine ~= nil then
|
||||
if Menu.SelLine < 7 then
|
||||
local num = Menu.SelLine
|
||||
for i = Menu.SelLine + 1, 6, 1 do
|
||||
if Line[i].Type ~= nil and Line[i].Next ~= nil and Line[i].Type ~= VALUE_NOCHANGING then
|
||||
Menu.SelLine=i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == Menu.SelLine then
|
||||
if Menu.Next ~= 0 then -- Next
|
||||
Menu.SelLine = 7
|
||||
elseif Menu.Prev ~= 0 then -- Prev
|
||||
Menu.SelLine = 8
|
||||
end
|
||||
end
|
||||
elseif Menu.Prev ~= 0 then -- Prev
|
||||
Menu.SelLine = 8
|
||||
end
|
||||
end
|
||||
else -- need to inc the value
|
||||
Value_Add(1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
if Menu.EditLine == nil then
|
||||
if Menu.SelLine ~= nil then
|
||||
if Menu.SelLine == 8 and Menu.Next ~= 0 then
|
||||
Menu.SelLine = 7
|
||||
elseif Menu.SelLine > 0 then
|
||||
if Menu.SelLine > 6 then
|
||||
Menu.SelLine = 7
|
||||
end
|
||||
local num = Menu.SelLine
|
||||
for i = Menu.SelLine-1, 0, -1 do
|
||||
if Line[i].Type ~= nil and Line[i].Next ~= nil and Line[i].Type ~= VALUE_NOCHANGING then
|
||||
Menu.SelLine=i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == Menu.SelLine then -- Back
|
||||
Menu.SelLine = -1
|
||||
end
|
||||
else
|
||||
Menu.SelLine = -1 -- Back
|
||||
end
|
||||
end
|
||||
else -- need to dec the value
|
||||
Value_Add(-1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER_LONG then
|
||||
if Menu.EditLine ~= nil then
|
||||
-- reset the value to default
|
||||
if Line[Menu.SelLine].Type ~= LIST_MENU_NOCHANGING then
|
||||
Line[Menu.SelLine].Val = Line[Menu.SelLine].Def
|
||||
Phase = VALUE_CHANGING
|
||||
Waiting_RX = 0
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
if Menu.SelLine == -1 then -- Back
|
||||
Menu.Cur = Menu.Back
|
||||
Menu.Id = Menu.BackId
|
||||
Menu.SelLine = 0
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
elseif Menu.SelLine == 7 then -- Next
|
||||
Menu.Cur = Menu.Next
|
||||
Menu.Id = Menu.NextId
|
||||
Menu.SelLine = 0
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
elseif Menu.SelLine == 8 then -- Prev
|
||||
Menu.Cur = Menu.Prev
|
||||
Menu.Id = Menu.PrevId
|
||||
Menu.SelLine = 0
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
elseif Menu.SelLine ~= nil and Line[Menu.SelLine].Next ~= nil then
|
||||
if Line[Menu.SelLine].Type == MENU then -- Next menu exist
|
||||
Menu.Cur = Line[Menu.SelLine].Next
|
||||
Menu.Id = Line[Menu.SelLine].NextId
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
else
|
||||
-- value entry
|
||||
if Menu.EditLine == Menu.SelLine then
|
||||
Menu.EditLine = nil
|
||||
Value_Changed = 0
|
||||
Phase = VALUE_CHANGED
|
||||
Waiting_RX = 0
|
||||
else
|
||||
Menu.EditLine = Menu.SelLine
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Send_Receive()
|
||||
if Waiting_RX == 0 then
|
||||
Waiting_RX = 1
|
||||
|
||||
-- Need to send a request
|
||||
if Phase == RX_VERSION then -- request RX version
|
||||
DSM_Send(0x11,0x06,0x00,0x14,0x00,0x00)
|
||||
|
||||
elseif Phase == WAIT_CMD then -- keep connection open
|
||||
DSM_Send(0x00,0x04,0x00,0x00)
|
||||
|
||||
elseif Phase == MENU_TITLE then -- request menu title
|
||||
if Menu.Cur == nil then
|
||||
DSM_Send(0x12,0x06,0x00,0x14,0x00,0x00) -- first menu only
|
||||
Menu.Cur = 0
|
||||
else
|
||||
DSM_Send(0x16,0x06,Menu.Id,Menu.Cur,0x00,Menu.SelLine)
|
||||
end
|
||||
|
||||
elseif Phase == MENU_LINES then -- request menu lines
|
||||
if Menu.CurLine == nil then
|
||||
DSM_Send(0x13,0x04,Menu.Id,Menu.Cur) -- line 0
|
||||
elseif Menu.CurLine >= 0x80 then
|
||||
local last_byte={0x40,0x01,0x02,0x04,0x00,0x00} -- unknown...
|
||||
DSM_Send(0x20,0x06,Menu.CurLine-0x80,Menu.CurLine-0x80,0x00,last_byte[Menu.CurLine-0x80+1]) -- line X
|
||||
else
|
||||
DSM_Send(0x14,0x06,Menu.Id,Menu.Cur,0x00,Menu.CurLine) -- line X
|
||||
end
|
||||
|
||||
elseif Phase == MENU_VALUES then -- request menu values
|
||||
DSM_Send(0x15,0x06,Menu.Id,Menu.Cur,Line[Menu.CurLine].ValId,Line[Menu.CurLine].Next) -- line X
|
||||
|
||||
elseif Phase == VALUE_CHANGING then -- send value
|
||||
local value=Line[Menu.SelLine].Val
|
||||
if value < 0 then
|
||||
value = 0x10000 + value
|
||||
end
|
||||
DSM_Send(0x18,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next,bit32.rshift(value,8),bit32.band(value,0xFF)) -- send current value
|
||||
Phase = VALUE_CHANGING_WAIT
|
||||
|
||||
elseif Phase == VALUE_CHANGED then -- send value
|
||||
if Value_Changed == 0 then
|
||||
local value=Line[Menu.SelLine].Val
|
||||
if value < 0 then
|
||||
value = 0x10000 + value
|
||||
end
|
||||
DSM_Send(0x18,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next,bit32.rshift(value,8),bit32.band(value,0xFF)) -- send current value
|
||||
Value_Changed = Value_Changed + 1
|
||||
Waiting_RX = 0
|
||||
elseif Value_Changed == 1 then
|
||||
DSM_Send(0x19,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next) -- validate
|
||||
-- Value_Changed = Value_Changed + 1
|
||||
-- Waiting_RX = 0
|
||||
--elseif Value_Changed == 2 then
|
||||
-- DSM_Send(0x1B,0x06,0x10,Menu.SelLine) -- validate again?
|
||||
-- Value_Changed = Value_Changed + 1
|
||||
end
|
||||
|
||||
elseif Phase == VALUE_CHANGING_WAIT then
|
||||
DSM_Send(0x1A,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next)
|
||||
|
||||
elseif Phase == EXIT then
|
||||
DSM_Send(0x1F,0x02,0xAA)
|
||||
|
||||
end
|
||||
multiBuffer(10,0x00);
|
||||
Retry = 50
|
||||
-- -- -- -- -- -- -- -- -- -- -- -- receive part -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
elseif multiBuffer(10) == 0x09 then
|
||||
-- Answer received
|
||||
-- GetDebugInfo(292) -- used for debug
|
||||
|
||||
--if multiBuffer(11) == 0x00 then -- waiting for commands?
|
||||
|
||||
if multiBuffer(11) == 0x01 then -- read version
|
||||
--ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
RX.Name = Get_RxName(multiBuffer(13))
|
||||
RX.Version = multiBuffer(14).."."..multiBuffer(15).."."..multiBuffer(16)
|
||||
Phase = MENU_TITLE
|
||||
|
||||
elseif multiBuffer(11) == 0x02 then -- read menu title
|
||||
--ex: 0x09 0x02 0x4F 0x10 0xA5 0x00 0x00 0x00 0x50 0x10 0x10 0x10 0x00 0x00 0x00 0x00
|
||||
Menu.Cur = multiBuffer(12)
|
||||
Menu.Id = multiBuffer(13)
|
||||
Menu.Title = Get_Text(multiBuffer(14)+multiBuffer(15)*256)
|
||||
Menu.Prev = multiBuffer(16)
|
||||
Menu.PrevId = multiBuffer(17)
|
||||
Menu.Next = multiBuffer(18)
|
||||
Menu.NextId = multiBuffer(19)
|
||||
Menu.Back = multiBuffer(20)
|
||||
Menu.BackId = multiBuffer(21)
|
||||
for i = 0, 6 do -- clear menu
|
||||
Line[i] = { Menu = nil, Id = nil, Type = nil, Text="", Next = nil, NextId = nil, ValLine = nil, ValId = nil, Min, Max, Def, Val, Unit, Step }
|
||||
end
|
||||
Menu.CurLine = nil
|
||||
if Menu.Next ~= 0 then
|
||||
Menu.SelLine = 7 -- highlight Next
|
||||
else
|
||||
Menu.SelLine = -1 -- highlight Back
|
||||
end
|
||||
Blink = 0
|
||||
Phase = MENU_LINES
|
||||
|
||||
elseif multiBuffer(11) == 0x03 then -- read menu lines
|
||||
--ex: 0x09 0x03 0x00 0x10 0x00 0x1C 0xF9 0x00 0x10 0x10 0x00 0x00 0x00 0x00 0x03 0x00
|
||||
-- Menu Id line Type Text_idx Next V_Id Val_Min Val_Max Val_Def
|
||||
--ex: 0x09 0x03 0x61 0x10 0x00 0x6C 0x50 0x00 0x00 0x10 0x36 0x00 0x49 0x00 0x36 0x00
|
||||
Menu.CurLine = multiBuffer(14)
|
||||
local line = Line[Menu.CurLine]
|
||||
line.Menu = multiBuffer(12)
|
||||
line.Id = multiBuffer(13) -- not quite sure yet
|
||||
line.Type = multiBuffer(15) -- not quite sure yet: 1C is text menu only, 4C/6C is text followed by text list, C0 is text followed by percentage value, 0C new list type
|
||||
line.Text = Get_Text(multiBuffer(16)+multiBuffer(17)*256)
|
||||
--if multiBuffer(18) == Menu.Cur then
|
||||
-- line.Next = nil
|
||||
--else
|
||||
line.Next = multiBuffer(18) -- not quite sure yet: 1C=text menu=>next menu, others=>identifier of line number of the value
|
||||
--end
|
||||
if Menu.SelLine == -1 and line.Next ~= nil then -- Auto select first line of the menu
|
||||
Menu.SelLine = Menu.CurLine
|
||||
end
|
||||
line.NextId = multiBuffer(19) -- not quite sure yet
|
||||
line.ValLine = multiBuffer(18) -- not quite sure yet
|
||||
line.ValId = multiBuffer(19) -- not quite sure yet
|
||||
line.Min = conv_int16(multiBuffer(20)+multiBuffer(21)*256)
|
||||
line.Max = conv_int16(multiBuffer(22)+multiBuffer(23)*256)
|
||||
line.Def = conv_int16(multiBuffer(24)+multiBuffer(25)*256)
|
||||
if line.Type == MENU then
|
||||
-- nothing to do on menu entries
|
||||
elseif line.Type == LIST_MENU_NOCHANGING or line.Type == LIST_MENU1 or line.Type == LIST_MENU2 then
|
||||
line.Val = nil --line.Def - line.Min -- use default value not sure if needed
|
||||
line.Def = line.Min -- pointer to the start of the list in Text
|
||||
line.Max = line.Max - line.Min -- max index
|
||||
line.Min = 0 -- min index
|
||||
else -- default to numerical value
|
||||
line.Val = nil --line.Def -- use default value not sure if needed
|
||||
end
|
||||
if line.Type ~= MENU and line.Type ~= VALUE_NOCHANGING then -- updatable value to follow
|
||||
line.Text = line.Text..":"
|
||||
end
|
||||
Phase = MENU_LINES
|
||||
|
||||
elseif multiBuffer(11) == 0x04 then -- read menu values
|
||||
--ex: 0x09 0x04 0x53 0x10 0x00 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
-- Menu MeId line VaId Value
|
||||
--ex: 0x09 0x04 0x61 0x10 0x02 0x10 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
-- Identify the line and update the value
|
||||
for i = 0, 6 do
|
||||
if Line[i] ~= nil and Line[i].Type ~= nil then
|
||||
if Line[i].Type ~= MENU and Line[i].Next == multiBuffer(14) then -- identifier of line number stored in .Next
|
||||
Line[i].Val = conv_int16(multiBuffer(16)+multiBuffer(17)*256)
|
||||
Menu.CurLine = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
Phase = MENU_VALUES
|
||||
|
||||
elseif multiBuffer(11) == 0x05 then -- unknown... need to get through the lines...
|
||||
Menu.CurLine = 0x80 + multiBuffer(12)
|
||||
Phase = MENU_LINES
|
||||
|
||||
elseif multiBuffer(11) == 0xA7 then -- answer to EXIT command
|
||||
DSM_Release()
|
||||
|
||||
elseif multiBuffer(11) == 0x00 and Phase == VALUE_CHANGING then
|
||||
Phase = VALUE_CHANGING_WAIT
|
||||
|
||||
end
|
||||
|
||||
-- Data processed
|
||||
Waiting_RX = 0
|
||||
multiBuffer(10,0x00)
|
||||
Retry = 50
|
||||
|
||||
else
|
||||
Retry = Retry - 1
|
||||
if Retry <= 0 then
|
||||
-- Retry the RX request
|
||||
Retry = 50
|
||||
Waiting_RX = 0
|
||||
if Phase == EXIT then
|
||||
DSM_Release()
|
||||
end
|
||||
if Phase ~= RX_VERSION and Phase ~= VALUE_CHANGING_WAIT then
|
||||
Phase = WAIT_CMD
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Display()
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--lcd.drawText(10,55,debugLine.." "..rxAnswer) -- draw debug info
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "DSM Forward Programming", MENU_TITLE_COLOR)
|
||||
--Draw RX Menu
|
||||
if Phase == RX_VERSION then
|
||||
lcd.drawText(10,50,"No compatible DSM RX...", BLINK)
|
||||
else
|
||||
if Menu.Title ~= nil then
|
||||
local attrib=0;
|
||||
lcd.drawText(80,32,Menu.Title,MIDSIZE)
|
||||
for i = 0, 6 do
|
||||
if i == Menu.SelLine then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if Line[i] ~= nil and Line[i].Type ~= nil then
|
||||
if Line[i].Type ~= MENU then -- list/value
|
||||
if Line[i].Val ~= nil then
|
||||
local text=""
|
||||
if Line[i].Type == LIST_MENU_NOCHANGING or Line[i].Type == LIST_MENU1 or Line[i].Type == LIST_MENU2 then
|
||||
text = Get_Text(Line[i].Val+Line[i].Def)
|
||||
elseif ( Line[i].Min == 0 and Line[i].Max == 100) or ( Line[i].Min == -100 and Line[i].Max == 100) or ( Line[i].Min == 0 and Line[i].Max == 150) or ( Line[i].Min == -150 and Line[i].Max == 150) then
|
||||
text = Line[i].Val.." %"
|
||||
else
|
||||
--text = Line[i].Val .." T="..Line[i].Type -- used for debug
|
||||
text = Line[i].Val
|
||||
end
|
||||
if Menu.EditLine == Menu.SelLine then -- blink edited entry
|
||||
Blink = Blink + 1
|
||||
if Blink > 25 then
|
||||
attrib = 0
|
||||
if Blink > 50 then
|
||||
Blink = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
lcd.drawText(240,32+20*(i+2), text, attrib) -- display value
|
||||
end
|
||||
attrib = 0
|
||||
end
|
||||
lcd.drawText(10,32+20*(i+2), Line[i].Text, attrib) -- display text
|
||||
end
|
||||
end
|
||||
if Menu.SelLine == -1 then
|
||||
lcd.drawText(437,32, "Back", INVERS)
|
||||
else
|
||||
lcd.drawText(437,32, "Back", 0)
|
||||
end
|
||||
lcd.drawRectangle(437-5, 32-2, 47, 25)
|
||||
if Menu.Next ~= 0 then
|
||||
if Menu.SelLine == 7 then
|
||||
lcd.drawText(437,220, "Next",INVERS)
|
||||
else
|
||||
lcd.drawText(437,220, "Next")
|
||||
end
|
||||
lcd.drawRectangle(437-5, 220-2, 47, 25)
|
||||
end
|
||||
if Menu.Prev ~= 0 then
|
||||
if Menu.SelLine == 8 then
|
||||
lcd.drawText(5,220, "Prev",INVERS)
|
||||
else
|
||||
lcd.drawText(5,220, "Prev")
|
||||
end
|
||||
lcd.drawRectangle(5-5, 220-2, 47, 25)
|
||||
end
|
||||
end
|
||||
lcd.drawText(170,252, "RX "..RX.Name.." v"..RX.Version) -- display RX info
|
||||
end
|
||||
else
|
||||
-- --Draw RX Menu on LCD_W=128
|
||||
-- if multiBuffer( 4 ) == 0xFF then
|
||||
-- lcd.drawText(2,17,"No compatible DSM RX...",SMLSIZE)
|
||||
-- else
|
||||
-- if Retry_128 ~= 0 then
|
||||
-- --Intro page
|
||||
-- Retry_128 = Retry_128 - 1
|
||||
-- lcd.drawScreenTitle("DSM Forward Programming",0,0)
|
||||
-- lcd.drawText(2,17,"Press Prev Page for previous Menu" ,SMLSIZE)
|
||||
-- else
|
||||
-- --Menu page
|
||||
-- for line = 0, 7, 1 do
|
||||
-- for i = 0, 21-1, 1 do
|
||||
-- value=multiBuffer( line*21+6+i )
|
||||
-- if value > 0x80 then
|
||||
-- value = value - 0x80
|
||||
-- lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS)
|
||||
-- else
|
||||
-- lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE)
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('D') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('D') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Init TX buffer
|
||||
multiBuffer( 3, 0x00 )
|
||||
--Init RX buffer
|
||||
multiBuffer( 10, 0x00 )
|
||||
--Init telemetry
|
||||
multiBuffer( 0, string.byte('D') )
|
||||
multiBuffer( 1, string.byte('S') )
|
||||
multiBuffer( 2, string.byte('M') )
|
||||
|
||||
--RX names--
|
||||
RxName[0x0001]="AR636B"
|
||||
RxName[0x0014]="SPM4651T"
|
||||
RxName[0x0015]="AR637T"
|
||||
RxName[0x0016]="AR637TA"
|
||||
RxName[0x0018]="FC6250HX"
|
||||
RxName[0x001A]="AR8360T"
|
||||
RxName[0x001E]="AR631"
|
||||
|
||||
--Text to be displayed -> need to use a file instead?
|
||||
Text[0x0001]="On"
|
||||
Text[0x0002]="Off"
|
||||
Text[0x0003]="Inh"
|
||||
Text[0x0004]="Act"
|
||||
Text[0x000C]="Inhibit?" --?
|
||||
Text[0x000D]="Gear"
|
||||
|
||||
--Lists--
|
||||
Text[0x002E]="11ms"
|
||||
Text[0x002F]="22ms"
|
||||
Text[0x0032]="1 X"
|
||||
Text[0x0033]="2 X"
|
||||
Text[0x0034]="4 X"
|
||||
Text[0x0035]="Inhibit?" --?
|
||||
Text[0x0036]="Throttle"
|
||||
Text[0x0037]="Aileron"
|
||||
Text[0x0038]="Elevator"
|
||||
Text[0x0039]="Rudder"
|
||||
Text[0x003A]="Gear"
|
||||
|
||||
--******
|
||||
--This part is strange since the AR637T needs
|
||||
for i=1,7 do -- 3B..41
|
||||
Text[0x003A+i]="Aux"..i
|
||||
end
|
||||
for i=1,8 do -- 41..49
|
||||
Text[0x0041+i]="XPlus-"..i
|
||||
end
|
||||
--But FOTO-PETE reports that it should be:
|
||||
Text[0x0040]="Roll"
|
||||
Text[0x0041]="Pitch"
|
||||
Text[0x0042]="Yaw"
|
||||
Text[0x0043]="Gain" -- FC6250HX
|
||||
Text[0x0045]="Differential"
|
||||
Text[0x0046]="Priority"
|
||||
Text[0x0049]="Output Setup" -- FC6250HX
|
||||
--******
|
||||
|
||||
Text[0x004A]="Failsafe"
|
||||
Text[0x004B]="Main Menu"
|
||||
Text[0x004E]="Position"
|
||||
Text[0x0050]="Outputs"
|
||||
Text[0x0051]="Output Channel 1"
|
||||
Text[0x0052]="Output Channel 2"
|
||||
Text[0x0053]="Output Channel 3"
|
||||
Text[0x0054]="Output Channel 4"
|
||||
Text[0x0055]="Output Channel 5"
|
||||
Text[0x0056]="Output Channel 6"
|
||||
--Text[0x005E]="Inhibit"
|
||||
Text[0x005F]="Hold Last"
|
||||
Text[0x0060]="Preset"
|
||||
--Text[0x0061]="Custom"
|
||||
--Messages--
|
||||
Text[0x0071]="Proportional"
|
||||
Text[0x0072]="Integral"
|
||||
Text[0x0073]="Derivate"
|
||||
Text[0x0078]="FM Channel"
|
||||
Text[0x0080]="Orientation"
|
||||
Text[0x0082]="Heading"
|
||||
Text[0x0085]="Frame Rate"
|
||||
Text[0x0086]="System Setup"
|
||||
Text[0x0087]="F-Mode Setup"
|
||||
Text[0x0088]="Enabled F-Modes"
|
||||
Text[0x0089]="Gain Channel"
|
||||
Text[0x008A]="Gain Sensitivity"
|
||||
Text[0x008B]="Panic"
|
||||
Text[0x0090]="Apply"
|
||||
Text[0x0092]="Start"
|
||||
Text[0x0093]="Complete"
|
||||
Text[0x0094]="Done"
|
||||
Text[0x0097]="Factory Reset"
|
||||
Text[0x0099]="Advanced Setup"
|
||||
Text[0x009A]="Capture Failsafe Positions"
|
||||
Text[0x009C]="Custom Failsafe"
|
||||
Text[0x00A5]="First Time Setup"
|
||||
Text[0x00AA]="Capture Gyro Gains"
|
||||
Text[0x00AD]="Gain Channel Select"
|
||||
Text[0x00B0]="Self-Level/Angle Dem"
|
||||
Text[0x00B1]="Envelope"
|
||||
Text[0x00B5]="Inhibit"
|
||||
Text[0x00B6]="FM1"
|
||||
Text[0x00B7]="FM2"
|
||||
Text[0x00B8]="FM3"
|
||||
Text[0x00B9]="FM4"
|
||||
Text[0x00BA]="FM5"
|
||||
Text[0x00BB]="FM6"
|
||||
Text[0x00BC]="FM7"
|
||||
Text[0x00BD]="FM8"
|
||||
Text[0x00BE]="FM9"
|
||||
Text[0x00BF]="FM10"
|
||||
Text[0x00C7]="Calibrate Sensor"
|
||||
Text[0x00CA]="SAFE/Panic Mode Setup"
|
||||
Text[0x00D3]="Swashplate"
|
||||
Text[0x00D5]="Agility"
|
||||
Text[0x00D8]="Stop"
|
||||
Text[0x00DA]="SAFE"
|
||||
Text[0x00DB]="Stability"
|
||||
Text[0x00DC]="@ per sec"
|
||||
Text[0x00DD]="Tail rotor"
|
||||
Text[0x00DE]="Setup"
|
||||
Text[0x00DF]="AFR"
|
||||
Text[0x00E0]="Collective"
|
||||
Text[0x00E1]="Subtrim"
|
||||
Text[0x00E2]="Phasing"
|
||||
Text[0x00E4]="E-Ring"
|
||||
Text[0x00E7]="Left"
|
||||
Text[0x00E8]="Right"
|
||||
Text[0x00F2]="Fixed"
|
||||
Text[0x00F3]="Adjustable"
|
||||
Text[0x00F9]="Gyro settings"
|
||||
Text[0x00FE]="Stick Priority"
|
||||
Text[0x0100]="Make sure the model has been"
|
||||
Text[0x0101]="configured, including wing type,"
|
||||
Text[0x0102]="reversing, travel, trimmed, etc."
|
||||
Text[0x0103]="before continuing setup."
|
||||
Text[0x0106]="Any wing type, channel assignment,"
|
||||
Text[0x0107]="subtrim, or servo reversing changes"
|
||||
Text[0x0108]="require running through initial"
|
||||
Text[0x0109]="setup again."
|
||||
Text[0x0190]="Relearn Servo Settings"
|
||||
Text[0x019C]="Enter Receiver Bind Mode"
|
||||
Text[0x01D7]="SAFE Select Channel"
|
||||
Text[0x01DC]="AS3X"
|
||||
Text[0x01DD]="AS3X Settings"
|
||||
Text[0x01DE]="AS3X Gains"
|
||||
Text[0x01E0]="Rate Gains"
|
||||
Text[0x01E2]="SAFE Settings"
|
||||
Text[0x01E3]="SAFE Gains"
|
||||
Text[0x01E6]="Attitude Trim"
|
||||
Text[0x01E7]="Envelope"
|
||||
Text[0x01E9]="Roll Right"
|
||||
Text[0x01EA]="Roll Left"
|
||||
Text[0x01EB]="Pitch Down"
|
||||
Text[0x01EC]="Pitch Up"
|
||||
Text[0x01EE]="Throttle to Pitch"
|
||||
Text[0x01EF]="Low Thr to Pitch"
|
||||
Text[0x01F0]="High Thr to Pitch"
|
||||
Text[0x01F3]="Threshold"
|
||||
Text[0x01F4]="Angle"
|
||||
Text[0x01F6]="Failsafe Angles"
|
||||
Text[0x01F8]="Safe Mode"
|
||||
Text[0x01F9]="SAFE Select"
|
||||
Text[0x01FD]="SAFE Failsafe FMode"
|
||||
Text[0x0208]="Decay"
|
||||
Text[0x0209]="Save to Backup"
|
||||
Text[0x020A]="Restore from Backup"
|
||||
Text[0x020D]="First Time SAFE Setup"
|
||||
Text[0x021A]="Set the model level,"
|
||||
Text[0x021B]="and press Continue."
|
||||
Text[0x021C]="" -- empty??
|
||||
Text[0x021D]="" -- empty??
|
||||
Text[0x021F]="Set the model on its nose,"
|
||||
Text[0x0220]="and press Continue. If the"
|
||||
Text[0x0221]="orientation on the next"
|
||||
Text[0x0222]="screen is wrong go back"
|
||||
Text[0x0223]="and try again."
|
||||
Text[0x0224]="Continue"
|
||||
Text[0x0226]="Angle Limits"
|
||||
Text[0x0227]="Other settings"
|
||||
Text[0x0229]="Set Orientation Manually"
|
||||
Text[0x022B]="WARNING!"
|
||||
Text[0x022C]="This will reset the"
|
||||
Text[0x022D]="configuration to factory"
|
||||
Text[0x022E]="defaults. This does not"
|
||||
Text[0x022F]="affect the backup config."
|
||||
Text[0x0230]="" -- empty??
|
||||
Text[0x0231]="This will overwrite the"
|
||||
Text[0x0232]="backup memory with your"
|
||||
Text[0x0233]="current configuartion."
|
||||
Text[0x0234]="" -- blank line
|
||||
Text[0x0235]="" -- blank line
|
||||
Text[0x0236]="This will overwrite the"
|
||||
Text[0x0237]="current config with"
|
||||
Text[0x0238]="that which is in"
|
||||
Text[0x0239]="the backup memory."
|
||||
Text[0x023A]="" -- blank line
|
||||
Text[0x023D]="Copy Flight Mode Settings"
|
||||
Text[0x0240]="Utilities"
|
||||
Text[0x024C]="Gains will be captured on"
|
||||
Text[0x024D]="Captured gains will be"
|
||||
Text[0x024E]="Gains on"
|
||||
Text[0x024F]="were captured and changed"
|
||||
Text[0x0250]="from Adjustable to Fixed"
|
||||
Text[0x0254]="Postive = Up, Negative = Down"
|
||||
Text[0x0263]="Fixed/Adjustable Gains"
|
||||
Text[0x0266]="Heading Gain"
|
||||
Text[0x0267]="Positive = Nose Up/Roll Right"
|
||||
Text[0x0268]="Negative = Nose Down/Roll Left"
|
||||
Text[0x0269]="SAFE - Throttle to Pitch"
|
||||
Text[0x026A]="Use CAUTION for Yaw gain!"
|
||||
Text[0x8000]="FLIGHT MODE"
|
||||
Text[0x8001]="Flight Mode 1"
|
||||
Text[0x8002]="Flight Mode 2"
|
||||
Text[0x8003]="Flight Mode 3"
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
local function DSM_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
else
|
||||
DSM_Menu(event)
|
||||
DSM_Send_Receive()
|
||||
DSM_Display()
|
||||
end
|
||||
if Phase == EXIT_DONE then
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=DSM_Init, run=DSM_Run }
|
1046
Lua_scripts/DSM FwdPrg_55_MIN.lua
Normal file
790
Lua_scripts/DSM FwdPrg_56_Color.lua
Normal file
@ -0,0 +1,790 @@
|
||||
local toolName = "TNS|DSM Forward Prog v0.56 (Color) |TNE"
|
||||
local VERSION = "v0.56"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
------------------------------------------------------------------------------
|
||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
||||
-- separate the GUI from the DSM Forward programming engine/logic
|
||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
||||
|
||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
-- Rewrite/Enhancements By: Francisco Arzu
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local SIMULATION_ON = true -- false: dont show simulation menu, TRUE: show simulation menu
|
||||
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
|
||||
local USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX)
|
||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
||||
local IMAGE_PATH = DSMLIB_PATH .. "img/"
|
||||
|
||||
local Log = assert(loadScript(DSMLIB_PATH.."DsmLogLib.lua"), "Not-Found: DSMLIB/DsmLogLib.lua")()
|
||||
local menuLib = assert(loadScript(DSMLIB_PATH.."DsmMenuLib.lua"), "Not-Found: DSMLIB/DsmMenuLib.lua")(Log, DEBUG_ON)
|
||||
local modelLib = assert(loadScript(DSMLIB_PATH.."DsmModelLib.lua"), "Not-Found: DSMLIB/DsmModelLib.lua")(Log, DEBUG_ON)
|
||||
local menuProcessor = assert(loadScript(DSMLIB_PATH.."DsmMainMenuLib.lua"), "Not-Found: DSMLIB/DsmMainMenuLib.lua")(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
|
||||
|
||||
local PHASE = menuLib.PHASE
|
||||
local LINE_TYPE = menuLib.LINE_TYPE
|
||||
local DISP_ATTR = menuLib.DISP_ATTR
|
||||
local DSM_Context = menuLib.DSM_Context
|
||||
|
||||
|
||||
local lastRefresh=0 -- Last time the screen was refreshed
|
||||
local REFRESH_GUI_MS = 300/10 -- 300ms.. Screen Refresh Rate.. to not waste CPU time (in 10ms units to be compatible with getTime())
|
||||
local originalValue = nil
|
||||
|
||||
local touchButtonArea = {}
|
||||
local EDIT_BUTTON = { DEFAULT=1001, DEC_10=1002, DEC_1=1003, INC_1=1004, INC_10=5, OK=1006, ESC=1007 }
|
||||
|
||||
local IS_EDGETX = false -- DEFAULT until Init changed it
|
||||
|
||||
local LCD_Y_MENU_TITLE = 20
|
||||
local LCD_W_MENU_TITLE = LCD_W-100
|
||||
|
||||
local LCD_X_LINE_MENU = 30
|
||||
local LCD_W_LINE_MENU = 350
|
||||
|
||||
local LCD_X_LINE_TITLE = 30
|
||||
local LCD_X_LINE_VALUE = 230
|
||||
local LCD_X_LINE_DEBUG = 390
|
||||
|
||||
|
||||
local LCD_Y_LINE_START = LCD_Y_MENU_TITLE + 30
|
||||
local LCD_Y_LINE_HEIGHT = 27
|
||||
|
||||
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT)
|
||||
|
||||
-- TOOL BG COLOR
|
||||
local LCD_TOOL_BGCOLOR = TEXT_BGCOLOR
|
||||
-- TOOL HEADER
|
||||
local LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR
|
||||
local LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR
|
||||
-- MENU HEADER
|
||||
local LCD_MENU_COLOR = MENU_TITLE_COLOR
|
||||
local LCD_MENU_BGCOLOR = MENU_TITLE_BGCOLOR
|
||||
-- LINE SELECTED
|
||||
local LCD_SELECTED_COLOR = TEXT_INVERTED_COLOR
|
||||
local LCD_SELECTED_BGCOLOR = TEXT_INVERTED_BGCOLOR
|
||||
local LCD_EDIT_BGCOLOR = MENU_TITLE_BGCOLOR -- WARNING_COLOR
|
||||
-- NORMAL TEXT
|
||||
local LCD_NORMAL_COLOR = TEXT_COLOR
|
||||
local LCD_DISABLE_COLOR = TEXT_DISABLE_COLOR
|
||||
local LCD_DEBUG_COLOR = LINE_COLOR
|
||||
-- NORMAL BOX FRAME COLOR
|
||||
local LCD_BOX_COLOR = TEXT_DISABLE_COLOR
|
||||
|
||||
|
||||
local warningScreenON = true
|
||||
|
||||
|
||||
--------------------- lcd.sizeText replacement -------------------------------------------------
|
||||
-- EdgeTx dont have lcd.sizeText, so we do an equivalent one using the string length and 5px per character
|
||||
local function my_lcd_sizeText(s)
|
||||
if (s==nil) then return 20 end
|
||||
-- return: If IS_EDGETX then lcd.sizeText() else string.len()
|
||||
return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10)
|
||||
end
|
||||
|
||||
|
||||
local function GUI_SwitchToRX()
|
||||
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
|
||||
-- local dsmChannelInfo, description = modelLib.CreateDSMPortChannelInfo()
|
||||
|
||||
menuProcessor.done()
|
||||
Log.LOG_close() -- Reset the log
|
||||
Log.LOG_open()
|
||||
|
||||
menuProcessor = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
modelLib.ReadTxModelData()
|
||||
modelLib.ST_LoadFileData()
|
||||
modelLib.CreateDSMPortChannelInfo()
|
||||
|
||||
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")
|
||||
menuProcessor = dsmLib(Log, menuLib, modelLib, DEBUG_ON)
|
||||
|
||||
dsmLib = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
menuProcessor.init(toolName) -- Initialize Library
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function GUI_SwitchToSIM()
|
||||
menuProcessor.done()
|
||||
Log.LOG_close()
|
||||
|
||||
menuProcessor = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
local simLib = assert(loadScript(DSMLIB_PATH.."DsmSimMenuLib.lua"), "Not-Found: DSMLIB/DsmSimMenuLib.lua")
|
||||
menuProcessor = simLib(Log, menuLib, modelLib, DEBUG_ON)
|
||||
|
||||
simLib = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
menuProcessor.init(toolName) -- Initialize Library
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function GUI_SwitchToSetupMenu()
|
||||
menuProcessor.done()
|
||||
|
||||
menuProcessor = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
local setupLib = assert(loadScript(DSMLIB_PATH.."DsmSetupMenuLib.lua"), "Not-Found: DSMLIB/DsmSetupMenuLib.lua")
|
||||
menuProcessor = setupLib(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
|
||||
|
||||
setupLib = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
menuProcessor.init(toolName) -- Initialize Library
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function GUI_SwitchToMainMenu()
|
||||
print("SWITCHING TO MAIN MENU")
|
||||
menuProcessor.done()
|
||||
|
||||
menuProcessor = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
local mainMenuLib = assert(loadScript(DSMLIB_PATH.."DsmMainMenuLib.lua"), "Not-Found: DSMLIB/DsmMainMenuLib.lua")
|
||||
menuProcessor = mainMenuLib(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
|
||||
|
||||
mainMenuLib = nil
|
||||
collectgarbage("collect")
|
||||
|
||||
menuProcessor.init(toolName) -- Initialize Library
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
|
||||
--------------------- Toucch Button Helpers ------------------------------------------------------------
|
||||
local function GUI_addTouchButton(x,y,w,h,line)
|
||||
-- Add new button info to end of the array
|
||||
touchButtonArea[#touchButtonArea+1] = {x=x, y=y, w=w, h=h, line=line}
|
||||
end
|
||||
|
||||
local function GUI_getTouchButton(x,y)
|
||||
for i = 1, #touchButtonArea do
|
||||
local button = touchButtonArea[i]
|
||||
-- is the coordinate inside the button area??
|
||||
if (x >= button.x and x <= (button.x+button.w) and y >= button.y and (y <= button.y+button.h)) then
|
||||
return button.line
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function GUI_clearTouchButtons()
|
||||
touchButtonArea = {}
|
||||
end
|
||||
|
||||
---------- Return Color to display Menu Lines ----------------------------------------------------------------
|
||||
local function GUI_GetTextColor(lineNum)
|
||||
local ctx = DSM_Context
|
||||
local txtColor = LCD_NORMAL_COLOR
|
||||
-- Gray Out any other line except the one been edited
|
||||
if (ctx.isEditing() and ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
|
||||
return txtColor
|
||||
end
|
||||
|
||||
local function GUI_GetFrameColor(lineNum) -- Frame Color for Value/Menu Boxes
|
||||
local ctx = DSM_Context
|
||||
local txtColor = LCD_BOX_COLOR
|
||||
-- Gray Out any other line except the one been edited
|
||||
if (ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
|
||||
return txtColor
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
-- Display Text inside a Rectangle. Inv: true means solid rectangle, false=only perimeter
|
||||
local function GUI_Display_Boxed_Text(lineNum,x,y,w,h,text,inv, isNumber)
|
||||
local ctx = DSM_Context
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local frameColor = GUI_GetFrameColor(lineNum)
|
||||
-- If editing this lineNum, chose EDIT Color, else SELECTED Color
|
||||
local selectedBGColor = (ctx.EditLine==lineNum and LCD_EDIT_BGCOLOR) or LCD_SELECTED_BGCOLOR
|
||||
|
||||
if (inv) then
|
||||
txtColor = LCD_SELECTED_COLOR
|
||||
lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor)
|
||||
else
|
||||
lcd.drawRectangle(x-5, y-2, w, h, frameColor)
|
||||
end
|
||||
if (isNumber) then
|
||||
lcd.drawNumber(x+w-10 , y, text, txtColor + RIGHT)
|
||||
else
|
||||
lcd.drawText(x , y, text, txtColor)
|
||||
end
|
||||
end
|
||||
|
||||
------ Display Pre/Next/Back buttons
|
||||
local function GUI_Diplay_Button(x,y,w,h,text,selected)
|
||||
GUI_Display_Boxed_Text(-1,x,y,w,h,text,selected, false)
|
||||
end
|
||||
|
||||
------ Display MENU type of lines (Navigation, SubHeaders, and plain text comments)
|
||||
local function GUI_Display_Line_Menu(lineNum,line,selected)
|
||||
-- Menu Lines can be navidation to other Menus (if Selectable)
|
||||
-- Or SubHeaders or Messages
|
||||
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||
local x = LCD_X_LINE_MENU
|
||||
|
||||
if menuLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes
|
||||
GUI_Display_Boxed_Text(lineNum,x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT, line.Text,selected, false)
|
||||
GUI_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum)
|
||||
else
|
||||
-- Non Selectable Menu Lines, plain text
|
||||
-- Can be use for sub headers or just regular text lines (like warnings)
|
||||
|
||||
local bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
||||
local tw = my_lcd_sizeText(line.Text)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
||||
local tw = my_lcd_sizeText(line.Text)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
|
||||
lcd.drawText(x, y, line.Text, txtColor + bold)
|
||||
end
|
||||
end
|
||||
|
||||
------ Display NAME : VALUES type of lines
|
||||
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
||||
-- This Displays Name and Value Pairs
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local bold = 0
|
||||
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||
local x = LCD_X_LINE_TITLE
|
||||
|
||||
---------- NAME Part
|
||||
local header = line.Text
|
||||
-- ONLY do this for Flight Mode (Right Align or Centered)
|
||||
if (menuLib.isFlightModeLine(line)) then
|
||||
-- Display Header + Value together
|
||||
header = menuLib.GetFlightModeValue(line)
|
||||
|
||||
-- Bold Text???
|
||||
bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
||||
local tw = my_lcd_sizeText(header)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
||||
local tw = my_lcd_sizeText(header)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
else
|
||||
-- No Flight Mode, no effects here
|
||||
header = header .. ":"
|
||||
end
|
||||
|
||||
lcd.drawText(x, y, header, txtColor + bold) -- display Line Header
|
||||
|
||||
|
||||
--------- VALUE PART, Skip for Flight Mode since already show the value
|
||||
if (value==nil) then return end
|
||||
|
||||
if not menuLib.isFlightModeLine(line) then
|
||||
if menuLib.isSelectableLine(line) then
|
||||
--if (editing) then -- Any Special color/effect when editing??
|
||||
-- value = "["..value .. "]"
|
||||
--end
|
||||
-- Can select/edit value, Box it
|
||||
local tw = math.max(my_lcd_sizeText(value)+10,45) -- Width of the Text in the lcd
|
||||
GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected, not menuLib.isListLine(line))
|
||||
GUI_addTouchButton(LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,lineNum)
|
||||
|
||||
lcd.drawText(LCD_X_LINE_VALUE+tw+5, y, (line.Format or ""), txtColor + bold)
|
||||
else -- Not Editable, Plain Text
|
||||
lcd.drawText(LCD_X_LINE_VALUE, y, value, txtColor)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function GUI_Display_Menu(menu)
|
||||
local ctx = DSM_Context
|
||||
local w= LCD_W_MENU_TITLE
|
||||
|
||||
-- Center Header
|
||||
local tw = my_lcd_sizeText(menu.Text)
|
||||
local x = w/2 - tw/2 -- Center of Screen - Center of Text
|
||||
|
||||
lcd.drawFilledRectangle(0, LCD_Y_MENU_TITLE-2, w, LCD_Y_LINE_HEIGHT-2, LCD_MENU_BGCOLOR)
|
||||
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text, LCD_MENU_COLOR + BOLD)
|
||||
|
||||
-- Back Button
|
||||
if menu.BackId ~= 0 then
|
||||
GUI_Diplay_Button(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,"Back",ctx.SelLine == menuLib.BACK_BUTTON)
|
||||
GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,menuLib.BACK_BUTTON)
|
||||
end
|
||||
-- Next Button
|
||||
if menu.NextId ~= 0 then
|
||||
GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == menuLib.NEXT_BUTTON)
|
||||
GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,menuLib.NEXT_BUTTON)
|
||||
end
|
||||
-- Prev Button
|
||||
if menu.PrevId ~= 0 then
|
||||
GUI_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == menuLib.PREV_BUTTON)
|
||||
GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,menuLib.PREV_BUTTON)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Display the EDIT mode buttons when editing a value
|
||||
|
||||
local function GUI_Display_Edit_Buttons(line)
|
||||
GUI_clearTouchButtons() -- Only this buttons can be touched
|
||||
local x = 15 -- Inittial X position
|
||||
local w = 55 -- Width of the buttons
|
||||
|
||||
local showPrev = line.Val > line.Min
|
||||
local showNext = line.Val < line.Max
|
||||
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,"ESC",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.ESC)
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," Def",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT)
|
||||
|
||||
x=x+w+10
|
||||
if (not menuLib.isListLine(line)) then
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," << ",showPrev)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_10)
|
||||
end
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," <",showPrev)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_1)
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >",showNext)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1)
|
||||
|
||||
x=x+w+10
|
||||
if (not menuLib.isListLine(line)) then
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >>",showNext)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_10)
|
||||
end
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," OK",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.OK)
|
||||
|
||||
end
|
||||
|
||||
local function GUI_ShowBitmap(x,y,imgData)
|
||||
-- imgData format "bitmap.png|alt message"
|
||||
local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|'
|
||||
local imgName, imgMsg = f(), f()
|
||||
|
||||
lcd.drawText(x, y, imgMsg or "") -- Alternate Image MSG
|
||||
|
||||
local imgPath = IMAGE_PATH .. (imgName or "")
|
||||
local bitmap = Bitmap.open(imgPath)
|
||||
if (bitmap~=nil) then
|
||||
lcd.drawBitmap(bitmap, x,y+20)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_Display()
|
||||
local ctx = DSM_Context
|
||||
lcd.clear(LCD_TOOL_BGCOLOR)
|
||||
GUI_clearTouchButtons()
|
||||
|
||||
if LCD_W ~= 480 then
|
||||
-- Different Resolution.. Maybe just adjusting some of the constants will work, adjust it in DSM_Init??
|
||||
-- LCD_X_LINE_TITLE, LCD_Y_LINE_START, etc
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,"Only supported in Color Radios of 480 resolution", BLINK)
|
||||
return
|
||||
end
|
||||
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||
header = header .. ctx.RX.Name.." v"..ctx.RX.Version
|
||||
end
|
||||
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
||||
|
||||
-- Getting RX Version
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
if (ctx.isReset) then
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100, menuLib.Get_Text(0x301), BLINK) -- Resetting...
|
||||
else
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,menuLib.Get_Text(0x300), BLINK) -- Not valid RX
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local menu = ctx.Menu
|
||||
if menu.Text == nil then return end
|
||||
|
||||
----- Draw RX Menu ---------
|
||||
GUI_Display_Menu(menu)
|
||||
|
||||
-- Sending TX Information???
|
||||
if (ctx.Phase==PHASE.MENU_REQ_TX_INFO) then
|
||||
--lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor)
|
||||
--lcd.drawRectangle(x-5, y-2, w, h, frameColor)
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100, "Sending CH"..(ctx.CurLine+1)) -- Channel Info
|
||||
return
|
||||
end
|
||||
|
||||
for i = 0, menuLib.MAX_MENU_LINES do
|
||||
local line = ctx.MenuLines[i]
|
||||
|
||||
if line ~= nil and line.Type ~= 0 then
|
||||
if line.Type == LINE_TYPE.MENU then
|
||||
GUI_Display_Line_Menu(i, line, i == ctx.SelLine)
|
||||
else
|
||||
local value = nil
|
||||
if line.Val ~= nil then
|
||||
value = line.Val
|
||||
if menuLib.isListLine(line) then -- for Lists of Strings, get the text
|
||||
value = menuLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
||||
-- Complentary IMAGE for this value to Display??
|
||||
local offset = 0
|
||||
if (line.Type==LINE_TYPE.LIST_MENU_ORI) then offset = offset + 0x100 end --FH6250 hack
|
||||
|
||||
local imgData = menuLib.Get_List_Text_Img(line.Val + line.TextStart + offset)
|
||||
|
||||
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
||||
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_START, imgData)
|
||||
end
|
||||
end
|
||||
end -- if Line[i]~=nil
|
||||
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
||||
end
|
||||
end -- if ~MENU
|
||||
end -- for
|
||||
|
||||
if IS_EDGETX and ctx.isEditing() then
|
||||
-- Display Touch button for Editing values
|
||||
GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine])
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_RotEncVal(line, dir) -- return encoder speed to inc or dec values
|
||||
|
||||
if menuLib.isListLine(line) then return dir end
|
||||
|
||||
local inc = 0
|
||||
local Speed = getRotEncSpeed()
|
||||
|
||||
if Speed == ROTENC_MIDSPEED then inc = (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then inc = (15 * dir)
|
||||
else inc = dir end
|
||||
|
||||
return inc
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
-- Translate Tap/Touch of EDIT buttons to equivalent Key events
|
||||
local function GUI_Translate_Edit_Buttons(button)
|
||||
local event = EVT_TOUCH_TAP
|
||||
local editInc = nil
|
||||
|
||||
if (button==EDIT_BUTTON.ESC) then -- ESC
|
||||
event = EVT_VIRTUAL_EXIT
|
||||
elseif (button==EDIT_BUTTON.DEFAULT) then -- Default
|
||||
event = EVT_VIRTUAL_ENTER_LONG
|
||||
elseif (button==EDIT_BUTTON.DEC_10) then -- -10
|
||||
event = EVT_VIRTUAL_PREV
|
||||
editInc = -10
|
||||
elseif (button==EDIT_BUTTON.DEC_1) then -- -1
|
||||
event = EVT_VIRTUAL_PREV
|
||||
editInc = -1
|
||||
elseif (button==EDIT_BUTTON.INC_1) then -- +1
|
||||
event = EVT_VIRTUAL_NEXT
|
||||
editInc = 1
|
||||
elseif (button==EDIT_BUTTON.INC_10) then -- + 10
|
||||
event = EVT_VIRTUAL_NEXT
|
||||
editInc = 10
|
||||
elseif (button==EDIT_BUTTON.OK) then -- OK
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
else
|
||||
|
||||
end
|
||||
|
||||
return event, editInc
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Handle Events comming from the GUI
|
||||
local function GUI_HandleEvent(event, touchState)
|
||||
local ctx = DSM_Context
|
||||
local menu = ctx.Menu
|
||||
local menuLines = ctx.MenuLines
|
||||
local editInc = nil
|
||||
|
||||
if (IS_EDGETX) then
|
||||
if (event == EVT_TOUCH_TAP and ctx.isEditing()) then -- Touch and Editing
|
||||
local button = GUI_getTouchButton(touchState.x, touchState.y)
|
||||
if (button) then
|
||||
event, editInc = GUI_Translate_Edit_Buttons(button)
|
||||
end
|
||||
end
|
||||
|
||||
if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",menuLib.phase2String(ctx.Phase),touchState.x, touchState.y) end
|
||||
local button = GUI_getTouchButton(touchState.x, touchState.y)
|
||||
if button then
|
||||
-- Found a valid line
|
||||
ctx.SelLine = button
|
||||
ctx.Refresh_Display=true
|
||||
if event == EVT_TOUCH_TAP then -- EVT_TOUCH_FIRST only move focus
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
end
|
||||
end
|
||||
end
|
||||
end -- IS_EDGETX
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_EXIT\n",menuLib.phase2String(ctx.Phase)) end
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
menuLib.ChangePhase(PHASE.EXIT_DONE) -- Just Exit the Script
|
||||
else
|
||||
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
||||
local line = ctx.MenuLines[ctx.EditLine]
|
||||
line.Val = originalValue
|
||||
menuLib.Value_Write_Validate(line)
|
||||
elseif (menu.BackId > 0 ) then -- Back??
|
||||
ctx.SelLine = menuLib.BACK_BUTTON
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
else
|
||||
menuLib.ChangePhase(PHASE.EXIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if ctx.Phase == PHASE.RX_VERSION then return end
|
||||
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_NEXT\n",menuLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, 1))
|
||||
else -- not editing, move selected line to NEXT
|
||||
menuLib.MoveSelectionLine(1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_PREV\n",menuLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, -1))
|
||||
else -- not editing, move selected line to PREV
|
||||
menuLib.MoveSelectionLine(-1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER_LONG then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",menuLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then
|
||||
-- reset the value to default
|
||||
menuLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",menuLib.phase2String(ctx.Phase), ctx.SelLine) end
|
||||
if ctx.SelLine == menuLib.BACK_BUTTON then -- Back
|
||||
if (menu.BackId==0xFFF9) then
|
||||
-- SPECIAL Main Menu
|
||||
GUI_SwitchToMainMenu()
|
||||
else
|
||||
menuLib.GotoMenu(menu.BackId,0x80)
|
||||
end
|
||||
elseif ctx.SelLine == menuLib.NEXT_BUTTON then -- Next
|
||||
menuLib.GotoMenu(menu.NextId,0x82)
|
||||
elseif ctx.SelLine == menuLib.PREV_BUTTON then -- Prev
|
||||
menuLib.GotoMenu(menu.PrevId,0x81)
|
||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value
|
||||
|
||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Navigate to Menu
|
||||
if (menuLines[ctx.SelLine].ValId==0xFFF1) then
|
||||
-- SPECIAL Simulation menu to Simulator
|
||||
GUI_SwitchToSIM()
|
||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
|
||||
-- SPECIAL Simulation menu to go to RX
|
||||
GUI_SwitchToRX()
|
||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF3) then
|
||||
-- SPECIAL Settup Menu
|
||||
GUI_SwitchToSetupMenu()
|
||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF9) then
|
||||
-- SPECIAL Settup Menu
|
||||
GUI_SwitchToMainMenu()
|
||||
else
|
||||
menuLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
||||
end
|
||||
else -- Enter on a Value
|
||||
if ctx.isEditing() then -- already editing a Line????
|
||||
menuLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
||||
else -- Edit the current value
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = menuLines[ctx.SelLine].Val
|
||||
menuLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_colors()
|
||||
-- osName in OpenTX is nil, otherwise is EDGETX
|
||||
local ver, radio, maj, minor, rev, osname = getVersion()
|
||||
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
|
||||
|
||||
IS_EDGETX = string.sub(osname,1,1) == 'E'
|
||||
|
||||
if (IS_EDGETX and USE_SPECKTRUM_COLORS) then
|
||||
-- SPECKTRUM COLORS (only works on EDGETX)
|
||||
LCD_TOOL_BGCOLOR = LIGHTWHITE
|
||||
-- TOOL HEADER
|
||||
LCD_TOOL_HDR_COLOR = WHITE
|
||||
LCD_TOOL_HDR_BGCOLOR = DARKBLUE
|
||||
-- MENU HEADER
|
||||
LCD_MENU_COLOR = WHITE
|
||||
LCD_MENU_BGCOLOR = DARKGREY
|
||||
-- LINE SELECTED
|
||||
LCD_SELECTED_COLOR = WHITE
|
||||
LCD_SELECTED_BGCOLOR = ORANGE
|
||||
LCD_EDIT_BGCOLOR = RED
|
||||
-- NORMAL TEXT
|
||||
LCD_NORMAL_COLOR = BLACK
|
||||
LCD_DISABLE_COLOR = LIGHTGREY
|
||||
LCD_DEBUG_COLOR = BLUE
|
||||
-- NORMAL BOX FRAME COLOR
|
||||
LCD_BOX_COLOR = LIGHTGREY
|
||||
end
|
||||
end
|
||||
|
||||
local function GUI_Warning(event,touchState)
|
||||
lcd.clear(LCD_TOOL_BGCOLOR)
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
||||
|
||||
lcd.drawText(100,20,"INFO", BOLD)
|
||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", 0)
|
||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", 0)
|
||||
lcd.drawText(5,80,"the TX before your start Fwrd programming your RX.", 0)
|
||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", 0)
|
||||
|
||||
lcd.drawText(5,150,"TX Gyro Servo settings are sent to the RX during 'Initial Setup'", 0)
|
||||
lcd.drawText(5,170,"as well as when using RX 'Relearn Servo Settings'", 0)
|
||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD)
|
||||
|
||||
lcd.drawText(100,250," OK ", INVERS + BOLD)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER or event == EVT_TOUCH_TAP then
|
||||
warningScreenON = false
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
Log.LOG_open()
|
||||
|
||||
init_colors()
|
||||
modelLib.ReadTxModelData()
|
||||
modelLib.ST_LoadFileData()
|
||||
modelLib.CreateDSMPortChannelInfo()
|
||||
|
||||
menuLib.Init()
|
||||
menuProcessor.init()
|
||||
return 0
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
local function DSM_Run(event,touchState)
|
||||
local ctx = DSM_Context
|
||||
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
Log.LOG_close()
|
||||
return 2
|
||||
end
|
||||
|
||||
if (warningScreenON) then
|
||||
return GUI_Warning(event,touchState)
|
||||
end
|
||||
|
||||
GUI_HandleEvent(event,touchState)
|
||||
|
||||
local ret = menuProcessor.run() -- Handle Send and Receive DSM Forward Programming Messages
|
||||
|
||||
if ctx.Phase == PHASE.INIT then return 0 end
|
||||
|
||||
|
||||
local refreshInterval = REFRESH_GUI_MS
|
||||
|
||||
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
|
||||
if (ctx.Phase == PHASE.RX_VERSION or ctx.Phase==PHASE.MENU_REQ_TX_INFO) then -- Requesting RX Message Version usea BLINK?
|
||||
ctx.Refresh_Display=true
|
||||
refreshInterval = 20 -- 200ms
|
||||
end
|
||||
|
||||
if (not IS_EDGETX) then -- OPENTX NEEDS REFRESH ON EVERY CYCLE
|
||||
GUI_Display()
|
||||
-- Refresh display only if needed and no faster than 300ms, utilize more CPU to speedup DSM communications
|
||||
elseif (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
|
||||
GUI_Display()
|
||||
ctx.Refresh_Display=false
|
||||
lastRefresh=getTime()
|
||||
end
|
||||
|
||||
if ctx.Phase == PHASE.EXIT_DONE then
|
||||
Log.LOG_close()
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return { init=DSM_Init, run=DSM_Run }
|
1088
Lua_scripts/DSM FwdPrg_56_MIN.lua
Normal file
951
Lua_scripts/DSM FwdPrg_56_STUP.lua
Normal 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 }
|
813
Lua_scripts/DSMLIB/DsmFwPrgLib.lua
Normal file
@ -0,0 +1,813 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX/EdgeTx #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
||||
-- separate the GUI from the DSM Forward programming engine/logic
|
||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
||||
|
||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
-- Rewrite/Enhancements By: Francisco Arzu
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
--###############################################################################
|
||||
-- Multi buffer for DSM description
|
||||
-- Multi_Buffer[0..2]=="DSM" -> Lua script is running
|
||||
-- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent
|
||||
-- Multi_Buffer[4..9]=6 bytes of TX to RX data
|
||||
-- Multi_Buffer[10..25]=16 bytes of RX to TX data
|
||||
--
|
||||
-- To start operation:
|
||||
-- Write 0x00 at address 3
|
||||
-- Write 0x00 at address 10
|
||||
-- Write "DSM" at address 0..2
|
||||
--###############################################################################
|
||||
|
||||
|
||||
local Log, menuLib, modelLib, DEBUG_ON = ... -- Get Debug_ON from parameters. -- 0=NO DEBUG, 1=HIGH LEVEL 2=MORE DETAILS
|
||||
local LIB_VERSION = "0.55"
|
||||
local MSG_FILE = "/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt"
|
||||
|
||||
local PHASE = menuLib.PHASE
|
||||
local LINE_TYPE = menuLib.LINE_TYPE
|
||||
|
||||
local CH_TYPE = modelLib.CH_TYPE
|
||||
local CH_MIX_TYPE = modelLib.CH_MIX_TYPE
|
||||
|
||||
local DISP_ATTR = menuLib.DISP_ATTR
|
||||
local DSM_Context = menuLib.DSM_Context
|
||||
local MODEL = modelLib.MODEL
|
||||
|
||||
local MAX_MENU_LINES = menuLib.MAX_MENU_LINES
|
||||
local BACK_BUTTON = menuLib.BACK_BUTTON
|
||||
local NEXT_BUTTON = menuLib.NEXT_BUTTON
|
||||
local PREV_BUTTON = menuLib.PREV_BUTTON
|
||||
|
||||
|
||||
local SEND_TIMEOUT = 2000 / 10 -- Home many 10ms intervals to wait on sending data to tx to keep connection open (2s)
|
||||
local TXInactivityTime = 0 -- Next time to do heartbeat after inactivity
|
||||
local RXInactivityTime = 0 -- To check RX disconnection
|
||||
|
||||
|
||||
local TxInfo_Type = 0
|
||||
local TxInfo_Step = 0
|
||||
local Change_Step = 0
|
||||
|
||||
local IS_EDGETX = false
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local function multiBuffer2String() -- used for debug
|
||||
local i
|
||||
local rxAnswer = "RX:"
|
||||
for i = 10, 25 do
|
||||
rxAnswer = rxAnswer .. string.format(" %02X", multiBuffer(i))
|
||||
end
|
||||
return rxAnswer
|
||||
end
|
||||
|
||||
---------------- DSM Values <-> Int16 Manipulation --------------------------------------------------------
|
||||
|
||||
local function int16_LSB(number) -- Less Significat byte
|
||||
local r,x = bit32.band(number, 0xFF)
|
||||
return r
|
||||
end
|
||||
|
||||
local function int16_MSB(number) -- Most signifcant byte
|
||||
return bit32.rshift(number, 8)
|
||||
end
|
||||
|
||||
local function Dsm_to_Int16(lsb, msb) -- Componse an Int16 value
|
||||
return bit32.lshift(msb, 8) + lsb
|
||||
end
|
||||
|
||||
local function Dsm_to_SInt16(lsb,msb) -- Componse a SIGNED Int16 value
|
||||
local value = bit32.lshift(msb, 8) + lsb
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function sInt16ToDsm(value) -- Convent to SIGNED DSM Value
|
||||
if value < 0 then
|
||||
value = 0x10000 + value
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_send(...)
|
||||
local arg = { ... }
|
||||
|
||||
for i = 1, #arg do
|
||||
multiBuffer(3 + i, arg[i])
|
||||
end
|
||||
multiBuffer(3, 0x70 + #arg)
|
||||
|
||||
|
||||
if (DEBUG_ON > 1) then
|
||||
local str = ""
|
||||
for i = 1, #arg do
|
||||
str = str .. string.format("%02X ", arg[i])
|
||||
end
|
||||
LOG_write("DSM_SEND: [%s]\n", str)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
local function DSM_StartConnection()
|
||||
if (DEBUG_ON) then Log.LOG_write("DSM_StartConnection()\n") end
|
||||
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('D') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('D') then
|
||||
if (DEBUG_ON) then Log.LOG_write("Not Enouth memory\n") end
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Init TX buffer
|
||||
multiBuffer( 3, 0x00 )
|
||||
--Init RX buffer
|
||||
multiBuffer( 10, 0x00 )
|
||||
--Init telemetry
|
||||
multiBuffer( 0, string.byte('D') )
|
||||
multiBuffer( 1, string.byte('S') )
|
||||
multiBuffer( 2, string.byte('M') )
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function DSM_ReleaseConnection()
|
||||
if (DEBUG_ON) then Log.LOG_write("DSM_ReleaseConnection()\n") end
|
||||
multiBuffer(0, 0)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
-- REEQUEST Messages to RX
|
||||
|
||||
local function DSM_sendHeartbeat()
|
||||
-- keep connection open
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_sendHeartbeat()\n") end
|
||||
DSM_send(0x00, 0x04, 0x00, 0x00)
|
||||
end
|
||||
|
||||
local function DSM_getRxVerson()
|
||||
local TX_CAP=0x14 -- Capabilities??
|
||||
local TX_MAX_CH = modelLib.TX_CHANNELS - 6 --number of channels after 6 (6Ch=0, 10ch=4, etc)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getRxVersion(Ch:0x%X,Cap:0x%X)\n",TX_MAX_CH,TX_CAP) end
|
||||
DSM_send(0x11, 0x06, TX_MAX_CH, TX_CAP, 0x00, 0x00)
|
||||
end
|
||||
|
||||
local function DSM_getMainMenu()
|
||||
local TX_CAP=0x14 -- Capabilities??
|
||||
local TX_MAX_CH = modelLib.TX_CHANNELS - 6 --number of channels after 6 (6Ch=0, 10ch=4, etc)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getMainMenu(Ch:0x%X,Cap:0x%X) -- TX_Channels=%d\n",TX_MAX_CH,TX_CAP,TX_MAX_CH+6) end
|
||||
DSM_send(0x12, 0x06, TX_MAX_CH, TX_CAP, 0x00, 0x00) -- first menu only
|
||||
end
|
||||
|
||||
local function DSM_getMenu(menuId, latSelLine)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getMenu(MenuId=0x%X LastSelectedLine=%s)\n", menuId, latSelLine) end
|
||||
DSM_send(0x16, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, latSelLine)
|
||||
end
|
||||
|
||||
local function DSM_getFirstMenuLine(menuId)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getFirstMenuLine(MenuId=0x%X)\n", menuId) end
|
||||
DSM_send(0x13, 0x04, int16_MSB(menuId), int16_LSB(menuId)) -- line 0
|
||||
end
|
||||
|
||||
local function DSM_getNextMenuLine(menuId, curLine)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getNextLine(MenuId=0x%X,LastLine=%s)\n", menuId, curLine) end
|
||||
DSM_send(0x14, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, curLine) -- line X
|
||||
end
|
||||
|
||||
local function DSM_getNextMenuValue(menuId, valId, text)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_getNextMenuValue(MenuId=0x%X, LastValueId=0x%X) Extra: Text=\"%s\"\n", menuId, valId,
|
||||
text)
|
||||
end
|
||||
DSM_send(0x15, 0x06, int16_MSB(menuId), int16_LSB(menuId), int16_MSB(valId), int16_LSB(valId)) -- line X
|
||||
end
|
||||
|
||||
local function DSM_updateMenuValue(valId, val, text, line)
|
||||
local value = sInt16ToDsm(val)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_updateValue(ValueId=0x%X,val=%d) Extra: Text=\"%s\" Value=%s\n", valId, val, text, menuLib.lineValue2String(line)) end
|
||||
DSM_send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value)) -- send current value
|
||||
end
|
||||
|
||||
local function DSM_validateMenuValue(valId, text, line)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_validateValue(ValueId=0x%X) Extra: Text=\"%s\" Value=%s\n", valId, text, menuLib.lineValue2String(line)) end
|
||||
DSM_send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId))
|
||||
end
|
||||
|
||||
local function DSM_editingValue(lineNum, text, line)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_editingValue(lineNo=0x%X) Extra: Text=\"%s\" Val=%s\n", lineNum, text, menuLib.lineValue2String(line)) end
|
||||
DSM_send(0x1A, 0x04, int16_MSB(lineNum), int16_LSB(lineNum))
|
||||
end
|
||||
|
||||
local function DSM_editingValueEnd(lineNum, text, line)
|
||||
if (DEBUG_ON) then Log.LOG_write("SEND DSM_editingValueEnd(lineNo=0x%X) Extra: Text=\"%s\" Value=%s\n", lineNum, text, menuLib.lineValue2String(line)) end
|
||||
DSM_send(0x1B, 0x04, int16_MSB(lineNum), int16_LSB(lineNum))
|
||||
end
|
||||
|
||||
-- Send the functionality of the RX channel Port (channel)
|
||||
local function DSM_sendTxChInfo_20(portNo)
|
||||
local b1,b2 = MODEL.DSM_ChannelInfo[portNo][0] or 0, MODEL.DSM_ChannelInfo[portNo][1] or 0
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxChInfo(#%d DATA= %02X %02X %02X %02X) %s\n", portNo,
|
||||
portNo, portNo, b1, b2, modelLib.channelType2String(b1,b2)) -- DATA part
|
||||
end
|
||||
DSM_send(0x20, 0x06, portNo, portNo, b1, b2)
|
||||
end
|
||||
|
||||
local function DSM_sendTxSubtrim_21(portNo)
|
||||
local usage = MODEL.DSM_ChannelInfo[portNo][1] or 0
|
||||
local leftTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].min/10))
|
||||
local rightTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].max/10))
|
||||
local subTrim = math.floor(MODEL.modelOutputChannel[portNo].offset/10)
|
||||
|
||||
-- Center at 100%: 142-1906 (0 8E 07 72)
|
||||
local left = 142
|
||||
local right = 1906
|
||||
|
||||
if (bit32.band(usage,CH_TYPE.THR)>0) then
|
||||
left = 0
|
||||
right = 2047
|
||||
end
|
||||
|
||||
left = math.floor (left - (leftTravel -100) *8.8 + subTrim*2)
|
||||
right = math.floor (right + (rightTravel -100) *8.8 + subTrim*2)
|
||||
|
||||
if (left<0) then left=0 end
|
||||
if (right>2027) then right=2047 end
|
||||
|
||||
local b1,b2,b3,b4 = int16_MSB(left), int16_LSB(left), int16_MSB(right), int16_LSB(right)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxSubtrim(#%d DATA=%02X %02X %02X %02X) Range(%d - %d) ER L/R:(%d - %d)x8 ST:(%d)x2\n", portNo,
|
||||
b1,b2,b3,b4, left, right, leftTravel-100, rightTravel-100, subTrim) -- DATA part
|
||||
end
|
||||
DSM_send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it.
|
||||
end
|
||||
|
||||
local function DSM_sendTxServoTravel_23(portNo)
|
||||
local leftTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].min/10))
|
||||
local rightTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].max/10))
|
||||
local debugInfo = string.format("Travel L/R (%d - %d)",leftTravel,rightTravel)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxServoTravel(#%d DATA= %02X %02X %02X %02X) %s\n", portNo,
|
||||
0x00, leftTravel, 0x00, rightTravel, debugInfo) -- DATA part
|
||||
end
|
||||
DSM_send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel)
|
||||
end
|
||||
|
||||
local function DSM_sentTxInfo(menuId,portNo)
|
||||
-- TxInfo_Type=0 : AR636B Main Menu (Send port/Channel info + SubTrim + Travel)
|
||||
-- TxInfo_Type=1 : AR630-637 Famly Main Menu (Only Send Port/Channel usage Msg 0x20)
|
||||
-- TxInfo_Type=1F : AR630-637 Initial Setup/Relearn Servo Settings (Send port/Channel info + SubTrim + Travel +0x24/Unknown)
|
||||
|
||||
if (TxInfo_Step == 0) then
|
||||
-- AR630 family: Both TxInfo_Type (ManinMenu=0x1, Other First Time Configuration = 0x1F)
|
||||
DSM_sendTxChInfo_20(portNo)
|
||||
|
||||
if (TxInfo_Type == 0x1F) then
|
||||
TxInfo_Step = 1
|
||||
end
|
||||
if (TxInfo_Type == 0x00) then
|
||||
TxInfo_Step = 2
|
||||
end
|
||||
elseif (TxInfo_Step == 1) then
|
||||
DSM_sendTxServoTravel_23(portNo)
|
||||
TxInfo_Step = 2
|
||||
elseif (TxInfo_Step == 2) then
|
||||
DSM_sendTxSubtrim_21(portNo)
|
||||
|
||||
if (TxInfo_Type == 0x00) then
|
||||
TxInfo_Step = 5 -- End Step
|
||||
else
|
||||
TxInfo_Step = 3
|
||||
end
|
||||
elseif (TxInfo_Step == 3) then
|
||||
-- 24,6: 0 83 5A B5
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo,
|
||||
0x00, 0x83, 0x5A, 0xB5) -- DATA part
|
||||
end
|
||||
DSM_send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown
|
||||
TxInfo_Step = 4
|
||||
|
||||
elseif (TxInfo_Step == 4) then
|
||||
-- 24,6: 6 80 25 4B
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo,
|
||||
0x06, 0x80, 0x25, 0x4B) -- DATA part
|
||||
end
|
||||
DSM_send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown
|
||||
TxInfo_Step = 5
|
||||
elseif (TxInfo_Step == 5) then
|
||||
-- 22,4: 0 0
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo_End(#%d)\n", portNo)
|
||||
end
|
||||
DSM_send(0x22, 0x04, 0x00, 0x00)
|
||||
TxInfo_Step = 0
|
||||
end
|
||||
|
||||
if (TxInfo_Step > 0) then
|
||||
DSM_Context.SendDataToRX = 1 -- keep Transmitig
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------
|
||||
|
||||
local function DSM_sendRequest()
|
||||
-- Send the proper Request message depending on the Phase
|
||||
|
||||
local ctx = DSM_Context
|
||||
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||
|
||||
if ctx.Phase == PHASE.RX_VERSION then -- request RX version
|
||||
DSM_getRxVerson()
|
||||
|
||||
elseif ctx.Phase == PHASE.WAIT_CMD then -- keep connection open
|
||||
DSM_sendHeartbeat()
|
||||
|
||||
elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title
|
||||
if ctx.Menu.MenuId == 0 then -- First time loading a menu ?
|
||||
DSM_getMainMenu()
|
||||
else
|
||||
DSM_getMenu(ctx.Menu.MenuId, ctx.SelLine)
|
||||
|
||||
if (ctx.Menu.MenuId == 0x0001) then -- Executed the Reset Menu??
|
||||
if (DEBUG_ON) then Log.LOG_write("RX Reset!!!\n") end
|
||||
-- Start again retriving RX info
|
||||
ctx.Menu.MenuId = 0
|
||||
ctx.isReset = true
|
||||
ctx.Phase = PHASE.RX_VERSION
|
||||
end
|
||||
end
|
||||
|
||||
elseif ctx.Phase == PHASE.MENU_REQ_TX_INFO then
|
||||
DSM_sentTxInfo(ctx.Menu.MenuId, ctx.CurLine)
|
||||
|
||||
elseif ctx.Phase == PHASE.MENU_LINES then -- request next menu lines
|
||||
if ctx.CurLine == -1 then -- No previous menu line loaded ?
|
||||
DSM_getFirstMenuLine(ctx.Menu.MenuId)
|
||||
else
|
||||
DSM_getNextMenuLine(ctx.Menu.MenuId, ctx.CurLine)
|
||||
end
|
||||
|
||||
elseif ctx.Phase == PHASE.MENU_VALUES then -- request menu values
|
||||
local line = ctx.MenuLines[ctx.CurLine]
|
||||
DSM_getNextMenuValue(ctx.Menu.MenuId, line.ValId, line.Text)
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||
|
||||
if (Change_Step==0) then
|
||||
DSM_updateMenuValue(line.ValId, line.Val, line.Text, line)
|
||||
|
||||
if line.Type == menuLib.LINE_TYPE.LIST_MENU then -- Validation on every Step??
|
||||
Change_Step=1; ctx.SendDataToRX=1 -- Send inmediatly after
|
||||
else
|
||||
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
|
||||
end
|
||||
else
|
||||
DSM_validateMenuValue(line.ValId, line.Text, line)
|
||||
Change_Step=0
|
||||
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
|
||||
end
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
|
||||
local line = ctx.MenuLines[ctx.SelLine]
|
||||
DSM_editingValue(line.lineNum, line.Text, line)
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Update Value of SELECTED line
|
||||
|
||||
if (Change_Step==0) then
|
||||
DSM_updateMenuValue(line.ValId, line.Val, line.Text, line)
|
||||
Change_Step=1; ctx.SendDataToRX=1 -- Send inmediatly after
|
||||
elseif (Change_Step==1) then
|
||||
DSM_validateMenuValue(line.ValId, line.Text, line)
|
||||
Change_Step=2; ctx.SendDataToRX=1 -- Send inmediatly after
|
||||
else
|
||||
DSM_editingValueEnd(line.lineNum, line.Text, line)
|
||||
Change_Step=0
|
||||
ctx.Phase = PHASE.WAIT_CMD
|
||||
end
|
||||
elseif ctx.Phase == PHASE.EXIT then
|
||||
if (DEBUG_ON) then Log.LOG_write("CALL DSM_TX_Exit()\n") end
|
||||
DSM_send(0x1F, 0x02, 0xFF, 0xFF) -- 0xAA
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------
|
||||
-- Parsing Responses
|
||||
|
||||
local function DSM_parseRxVersion()
|
||||
--ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 v2.22.1 00 14?? 8ch SAFE
|
||||
-- 0x09 0x01 0x00 0x18 0x05 0x06 0x34 0x00 0x12 v5.6.52 00 12??? 6ch FC6250
|
||||
local rxId = multiBuffer(13)
|
||||
DSM_Context.RX.Id = rxId
|
||||
DSM_Context.RX.Name = menuLib.Get_RxName(rxId)
|
||||
DSM_Context.RX.Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16)
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE Receiver=%s Version %s Cap:0x%02X\n",
|
||||
DSM_Context.RX.Name, DSM_Context.RX.Version, multiBuffer(18)) end
|
||||
end
|
||||
|
||||
local function DSM_parseMenu()
|
||||
--ex: 0x09 0x02 0x4F 0x10 0xA5 0x00 0x00 0x00 0x50 0x10 0x10 0x10 0x00 0x00 0x00 0x00
|
||||
-- MenuID TextID PrevID NextID BackID
|
||||
local ctx = DSM_Context
|
||||
local menu = ctx.Menu
|
||||
menu.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
|
||||
menu.TextId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15))
|
||||
menu.Text = menuLib.Get_Text(menu.TextId)
|
||||
menu.PrevId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17))
|
||||
menu.NextId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19))
|
||||
menu.BackId = Dsm_to_Int16(multiBuffer(20), multiBuffer(21))
|
||||
for i = 0, MAX_MENU_LINES do -- clear menu
|
||||
ctx.MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0, Text = "", TextId = 0, ValId = 0, Min=0, Max=0, Def=0, Val=nil }
|
||||
end
|
||||
ctx.CurLine = -1
|
||||
|
||||
menuLib.MenuPostProcessing(menu)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE Menu: %s\n", menuLib.menu2String(menu)) end
|
||||
return menu
|
||||
end
|
||||
|
||||
|
||||
local function DSM_parseMenuLine()
|
||||
--ex: 0x09 0x03 0x00 0x10 0x00 0x1C 0xF9 0x00 0x10 0x10 0x00 0x00 0x00 0x00 0x03 0x00
|
||||
--ex: 0x09 0x03 0x61 0x10 0x00 0x6C 0x50 0x00 0x00 0x10 0x36 0x00 0x49 0x00 0x36 0x00
|
||||
--ex: 0x09 0x03 0x65 0x10 0x00 0x0C 0x51 0x00 0x00 0x10 0x00 0x00 0xF4 0x00 0x2E 0x00
|
||||
-- MenuLSB MenuMSB line Type TextID NextLSB NextMSB Val_Min Val_Max Val_Def
|
||||
|
||||
local ctx = DSM_Context
|
||||
local i = multiBuffer(14)
|
||||
local type = multiBuffer(15)
|
||||
local line = ctx.MenuLines[i]
|
||||
|
||||
-- are we trying to override existing line
|
||||
if (line.Type > 0 and type == 0) then
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuLine: ERROR. Trying to ZERO Override: %s\n", menuLib.menuLine2String(line)) end
|
||||
return ctx.MenuLines[ctx.CurLine]
|
||||
end
|
||||
|
||||
ctx.CurLine = i
|
||||
|
||||
line.lineNum = i
|
||||
line.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
|
||||
line.Type = type
|
||||
line.TextId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17))
|
||||
line.Text = nil -- Fill at Post processing
|
||||
line.ValId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19))
|
||||
|
||||
-- Singed int values
|
||||
line.Min = Dsm_to_SInt16(multiBuffer(20), multiBuffer(21))
|
||||
line.Max = Dsm_to_SInt16(multiBuffer(22), multiBuffer(23))
|
||||
line.Def = Dsm_to_SInt16(multiBuffer(24), multiBuffer(25))
|
||||
|
||||
line.Val=nil
|
||||
|
||||
menuLib.MenuLinePostProcessing(line)
|
||||
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuLine: %s\n", menuLib.menuLine2String(line)) end
|
||||
|
||||
if (line.MenuId~=ctx.Menu.MenuId) then
|
||||
-- Going Back too fast: Stil receiving lines from previous menu
|
||||
ctx.Menu.MenuId = line.MenuId
|
||||
Log.LOG_write("WARNING: Overriding current Menu from Line\n")
|
||||
end
|
||||
|
||||
return line
|
||||
end
|
||||
|
||||
local function DSM_parseMenuValue()
|
||||
--ex: 0x09 0x04 0x53 0x10 0x00 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
--ex: 0x09 0x04 0x61 0x10 0x02 0x10 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
-- MenuLSB MenuMSB ValLSB ValMSB V_LSB V_MSB
|
||||
|
||||
-- Identify the line and update the value
|
||||
local ctx = DSM_Context
|
||||
local menuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
|
||||
local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15))
|
||||
local value = Dsm_to_SInt16(multiBuffer(16), multiBuffer(17)) --Signed int
|
||||
|
||||
local updatedLine = nil
|
||||
for i = 0, MAX_MENU_LINES do -- Find the menu line for this value
|
||||
local line = ctx.MenuLines[i]
|
||||
if line ~= nil and line.Type ~= 0 then
|
||||
if line.Type ~= LINE_TYPE.MENU and line.ValId == valId then -- identifier of ValueId stored in the line
|
||||
line.Val = value
|
||||
ctx.CurLine = i
|
||||
updatedLine = line
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (updatedLine == nil) then
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuValue: ERROR, Cant find Menu Line with MenuId=%X, ValID=%X to update\n", menuId, valId) end
|
||||
else
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuValue: UPDATED: %s\n", menuLib.menuLine2String(updatedLine))
|
||||
end
|
||||
end
|
||||
return updatedLine ~= nil
|
||||
end
|
||||
|
||||
local function DSM_parseReqTxInfo()
|
||||
local portNo = multiBuffer(12)
|
||||
TxInfo_Type = multiBuffer(13)
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE ReqTXChannelInfo(#%d %s InfoType=0x%0X)\n",
|
||||
portNo, MODEL.PORT_TEXT[portNo], TxInfo_Type) end
|
||||
|
||||
TxInfo_Step = 0
|
||||
|
||||
return portNo
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_processResponse()
|
||||
local ctx = DSM_Context
|
||||
local cmd = multiBuffer(11) -- Response Command
|
||||
|
||||
if (DEBUG_ON > 1) then Log.LOG_write("%s: RESPONSE %s \n", menuLib.phase2String(ctx.Phase), multiBuffer2String()) end
|
||||
if (DEBUG_ON and cmd > 0x00) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||
|
||||
if cmd == 0x01 then -- read version
|
||||
DSM_parseRxVersion()
|
||||
--Lib.Init_Text(DSM_Context.RX.Id)
|
||||
ctx.isReset = false -- no longer resetting
|
||||
ctx.Phase = PHASE.MENU_TITLE
|
||||
ctx.Menu.MenuId = 0
|
||||
|
||||
elseif cmd == 0x02 then -- read menu title
|
||||
local menu = DSM_parseMenu()
|
||||
|
||||
-- Update Selected Line navigation
|
||||
if menu.NextId ~= 0 then
|
||||
ctx.SelLine = NEXT_BUTTON -- highlight Next
|
||||
else
|
||||
ctx.SelLine = BACK_BUTTON -- highlight Back
|
||||
end
|
||||
|
||||
if (ctx.Menu.MenuId == 0x0001) then -- Still in RESETTING MENU???
|
||||
-- Star from Start
|
||||
if (DEBUG_ON) then Log.LOG_write("RX Reset: Still not done, restart again!!!\n") end
|
||||
ctx.Menu.MenuId = 0
|
||||
ctx.Phase = PHASE.RX_VERSION
|
||||
else
|
||||
ctx.Phase = PHASE.MENU_LINES
|
||||
end
|
||||
|
||||
|
||||
elseif cmd == 0x03 then -- menu lines
|
||||
local line = DSM_parseMenuLine()
|
||||
|
||||
-- Update Selected line navigation
|
||||
if (ctx.SelLine == BACK_BUTTON or ctx.SelLine == NEXT_BUTTON or ctx.SelLine == PREV_BUTTON)
|
||||
and menuLib.isSelectableLine(line) then -- Auto select the current line
|
||||
ctx.SelLine = line.lineNum
|
||||
end
|
||||
|
||||
ctx.Phase = PHASE.MENU_LINES
|
||||
|
||||
elseif cmd == 0x04 then -- read menu values
|
||||
if DSM_parseMenuValue() then
|
||||
ctx.Phase = PHASE.MENU_VALUES
|
||||
else
|
||||
ctx.Phase = PHASE.WAIT_CMD
|
||||
end
|
||||
|
||||
elseif cmd == 0x05 then -- Request TX Info
|
||||
local portNo = DSM_parseReqTxInfo()
|
||||
ctx.CurLine = portNo
|
||||
ctx.Phase = PHASE.MENU_REQ_TX_INFO
|
||||
|
||||
elseif cmd == 0xA7 then -- answer to EXIT command
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE RX Exit\n") end
|
||||
if (ctx.Phase==PHASE.EXIT) then -- Expected RX Exit
|
||||
ctx.Phase = PHASE.EXIT_DONE
|
||||
else -- UnExpected RX Exit
|
||||
DSM_ReleaseConnection()
|
||||
error("RX Connection Drop")
|
||||
end
|
||||
|
||||
elseif cmd == 0x00 then -- NULL response (or RX heartbeat)
|
||||
-- 09 00 01 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
-- 09 00 7E 00 20 9E 28 00 20 9E 28 00 20 8D 7E : After TX Heartbeat one of this (FC6250)
|
||||
-- 09 00 18 00 20 08 00 00 00 08 00 00 00 98 AE AR8360T
|
||||
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: RESPONSE RX Heartbeat --Context: 0x%02X\n",
|
||||
menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase), multiBuffer(12)) end
|
||||
else
|
||||
if (DEBUG_ON) then Log.LOG_write("RESPONSE Unknown Command (0x%X) DATA=%s\n", cmd, multiBuffer2String()) end
|
||||
end
|
||||
|
||||
return cmd
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Send_Receive()
|
||||
local ctx = DSM_Context
|
||||
|
||||
-- Receive part: Process incoming messages if there is nothing to send
|
||||
if ctx.SendDataToRX == 0 and multiBuffer(10) == 0x09 then
|
||||
local cmd = DSM_processResponse()
|
||||
|
||||
multiBuffer(10, 0x00) -- Clear Response Buffer to know that we are done with the response
|
||||
RXInactivityTime = getTime() + SEND_TIMEOUT*4 -- Reset RX Inactivity timeout
|
||||
|
||||
if (cmd > 0x00) then -- RX HeartBeat ??
|
||||
-- Only change to SEND mode if we received a valid response (Ignore heartbeat)
|
||||
ctx.SendDataToRX = 1
|
||||
ctx.Refresh_Display = true
|
||||
end
|
||||
else
|
||||
if (getTime() > RXInactivityTime and ctx.Phase ~= PHASE.RX_VERSION and ctx.Phase ~= PHASE.EXIT_DONE) then
|
||||
if (ctx.isEditing()) then -- If Editing, Extend Timeout
|
||||
RXInactivityTime = getTime() + SEND_TIMEOUT*4
|
||||
else
|
||||
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: RX INACTIVITY TIMEOUT\n", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||
DSM_ReleaseConnection()
|
||||
error("RX Disconnected")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----TX Part --------------------------------------
|
||||
if ctx.SendDataToRX == 1 then -- Need to send a request
|
||||
ctx.SendDataToRX = 0
|
||||
DSM_sendRequest()
|
||||
TXInactivityTime = getTime() + SEND_TIMEOUT -- Reset Inactivity timeout
|
||||
else
|
||||
-- Check if enouth time has passed from last transmit/receive activity
|
||||
if getTime() > TXInactivityTime then
|
||||
ctx.SendDataToRX = 1 -- Switch to Send mode to send heartbeat
|
||||
ctx.Refresh_Display = true
|
||||
|
||||
-- Only change to WAIT_CMD if we are NOT wating for RX version
|
||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||
-- Phase = If IsEditing then VALUE_CHANGING_WAIT else WAIT_CMD
|
||||
ctx.Phase = (ctx.isEditing() and PHASE.VALUE_CHANGING_WAIT) or PHASE.WAIT_CMD
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function DSM_Init(toolName)
|
||||
local dateTime = getDateTime()
|
||||
local dateStr = dateTime.year.."-"..dateTime.mon.."-"..dateTime.day.." "..dateTime.hour..":"..dateTime.min
|
||||
|
||||
local ver, radio, maj, minor, rev, osname = getVersion()
|
||||
|
||||
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
|
||||
|
||||
IS_EDGETX = string.sub(osname,1,1) == 'E'
|
||||
|
||||
if (DEBUG_ON) then
|
||||
Log.LOG_write("---------------DSM New Session %s ----------------\n", toolName, dateStr)
|
||||
Log.LOG_write("Radio Info: %s\n", radio .. " " .. (osname or "OpenTx") .. " " .. ver)
|
||||
Log.LOG_write("Date : %s\n", dateStr)
|
||||
Log.LOG_write("DsmLib Version : %s\n", LIB_VERSION)
|
||||
end
|
||||
end
|
||||
|
||||
local function DSM_Init_Text_Exceptions()
|
||||
-- Apply special restrictions to some Values
|
||||
|
||||
local function getTxChText(ch)
|
||||
return " ("..(MODEL.TX_CH_TEXT[ch] or "--")..")"
|
||||
end
|
||||
|
||||
local List_Values = menuLib.List_Values
|
||||
local List_Text = menuLib.List_Text
|
||||
local Text = menuLib.Text
|
||||
|
||||
Log.LOG_write("Initializing TEXT Exception\n")
|
||||
|
||||
-- Channel selection for SAFE MODE and GAINS on FC6250HX
|
||||
--List_Text[0x000C] = "Inhibit?" --?
|
||||
for i = 0, 7 do
|
||||
List_Text[0x000D + i] = "Ch"..(i+5) ..getTxChText(i+4)
|
||||
end -- Aux channels (Ch5 and Greater)
|
||||
|
||||
-- Servo Output values..
|
||||
local servoOutputValues = {0x0003,0x002D,0x002E,0x002F} --Inh (GAP), 5.5ms, 11ms, 22ms. Fixing L_m1 with 0..244 range!
|
||||
--List_Text[0x002D] = "5.5ms"
|
||||
--[0x002E] = "11ms"
|
||||
--List_Text[0x002F] = "22ms"
|
||||
|
||||
-- Gain Values
|
||||
local gainValues = {0x0032,0x0033,0x0034} -- 1X, 2X, 4X -- Fixing L_m1 with 0..244 range!
|
||||
--List_Text[0x0032] = "1 X"
|
||||
--[0x0033] = "2 X"
|
||||
-- List_Text[0x0034] = "4 X"
|
||||
|
||||
-- List of Channels for Safe, Gains, Panic, except FC6250HX that uses other range (0x00C..0x015)
|
||||
-- the valid range Starts with GEAR if enabled (Thr,Ail,Ele,Rud are not valid, the RX reject them )
|
||||
-- Valid Values: Inhibit? (GAP), Gear,Aux1..Aux7,X-Plus-1..XPlus-8
|
||||
local channelValues = {0x0035,0x0036,0x0037,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
|
||||
0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049}
|
||||
|
||||
--List_Text[0x0035] = "Inhibit?"
|
||||
for i = 0, 11 do
|
||||
List_Text[0x0036 + i] = "Ch"..(i+1) .. getTxChText(i)
|
||||
end -- Channels on AR637T
|
||||
|
||||
for i = 1, 8 do -- 41..49
|
||||
List_Text[0x0041 + i] = "Ch"..(i+12)
|
||||
end
|
||||
|
||||
-- Flight mode channel selection
|
||||
--Text[0x0078] = "FM Channel"
|
||||
List_Values[0x0078]=channelValues
|
||||
|
||||
-- Gain channel selection
|
||||
--Text[0x0089] = "Gain Channel"
|
||||
List_Values[0x0089]=channelValues
|
||||
|
||||
-- Gain Sensitivity selection
|
||||
--Text[0x008A] = "Gain Sensitivity/r";
|
||||
List_Values[0x008A]=gainValues -- Right Alight, (L_M1 was wide open range 0->244)
|
||||
|
||||
-- Safe mode options, Ihnibit + this values
|
||||
local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope
|
||||
--List_Text[0x00B0] = "Self-Level/Angle Dem"
|
||||
--List_Text[0x00B1] = "Envelope"
|
||||
|
||||
--Text[0x00D2] = "Panic Channel"
|
||||
List_Values[0x00D2]=channelValues
|
||||
|
||||
--Inh, Self-Level/Angle Dem, Envelope -- (L_M was wide open range 0->244)
|
||||
--Text[0x01F8] = "Safe Mode";
|
||||
List_Values[0x01F8]=safeModeOptions
|
||||
end
|
||||
|
||||
-- Initial Setup
|
||||
local function FP_Init(toolname)
|
||||
DSM_Context.Phase = PHASE.INIT
|
||||
|
||||
DSM_Init(toolname)
|
||||
menuLib.clearAllText()
|
||||
end
|
||||
|
||||
local initStep=0
|
||||
local FileState = {}
|
||||
|
||||
local function Message_Init()
|
||||
lcd.clear()
|
||||
if (initStep == 0) then
|
||||
if (IS_EDGETX) then
|
||||
-- Load all messages at once
|
||||
menuLib.LoadTextFromFile(MSG_FILE,13)
|
||||
initStep=1
|
||||
|
||||
else
|
||||
-- load messages incrementally to avoid "CPU Limit"
|
||||
lcd.drawText(30, 50, "Loading Msg file: "..(FileState.lineNo or 0))
|
||||
if (menuLib.INC_LoadTextFromFile(MSG_FILE, FileState)==1) then
|
||||
initStep=1
|
||||
end
|
||||
end
|
||||
elseif (initStep == 1) then
|
||||
DSM_Init_Text_Exceptions()
|
||||
|
||||
DSM_Context.Phase = PHASE.RX_VERSION
|
||||
DSM_StartConnection()
|
||||
end
|
||||
end
|
||||
|
||||
local function FP_Run()
|
||||
if (DSM_Context.Phase==PHASE.INIT) then
|
||||
Message_Init()
|
||||
return 0
|
||||
end
|
||||
|
||||
return DSM_Send_Receive()
|
||||
end
|
||||
|
||||
local function FP_Done()
|
||||
local ctx = menuLib.DSM_Context
|
||||
ctx.Phase = PHASE.EXIT_DONE
|
||||
DSM_ReleaseConnection()
|
||||
end
|
||||
|
||||
return { init=FP_Init, run=FP_Run, done=FP_Done }
|
33
Lua_scripts/DSMLIB/DsmLogLib.lua
Normal 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
|
167
Lua_scripts/DSMLIB/DsmMIN_P1.lua
Normal 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
|
||||
|
||||
|
282
Lua_scripts/DSMLIB/DsmMIN_P2.lua
Normal 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()
|
||||
|
||||
|
90
Lua_scripts/DSMLIB/DsmMainMenuLib.lua
Normal 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 }
|
788
Lua_scripts/DSMLIB/DsmMenuLib.lua
Normal 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
|
789
Lua_scripts/DSMLIB/DsmModelLib.lua
Normal 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
|
||||
|
467
Lua_scripts/DSMLIB/DsmSetupMenuLib.lua
Normal 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 }
|
1596
Lua_scripts/DSMLIB/DsmSimMenuLib.lua
Normal file
10
Lua_scripts/DSMLIB/MIN_msg_fwdp_en.txt
Normal file
@ -0,0 +1,10 @@
|
||||
-- OVERRIDES Messges for MIN 128x64 screns
|
||||
-- FORMAT <LineType>|<Msg#>|<Text>
|
||||
-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX)
|
||||
-- IMPORTANT: NO EMPTY LINES
|
||||
--
|
||||
T |0x0097|DONT USE: Factory Reset
|
||||
T |0x0098|DONT USE: Factory Reset
|
||||
T |0x00A5|DONT USE: First Time Setup
|
||||
T |0x0190|DONT USE: Relearn Servo Settings
|
||||
T |0x020D|DONT USE: First Time SAFE Setup
|
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_1.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_2.png
Normal file
After Width: | Height: | Size: 862 B |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_3.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_4.png
Normal file
After Width: | Height: | Size: 866 B |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_5.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_6.png
Normal file
After Width: | Height: | Size: 880 B |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_7.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_8.png
Normal file
After Width: | Height: | Size: 863 B |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_120.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_120inv.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_135.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_135inv.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_140.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_140inv.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_90.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_90inv.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_norm.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_1.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_10.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_11.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_12.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_13.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_14.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_15.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_16.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_17.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_18.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_19.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_2.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_20.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_21.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_22.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_23.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_24.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_25.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_3.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_4.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_5.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_6.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_7.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_8.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_9.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_1rud.png
Normal file
After Width: | Height: | Size: 728 B |
BIN
Lua_scripts/DSMLIB/img/tt_1rud_1ele.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_1rud_2ele.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_2rud_1ele.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_2rud_2ele.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_taileron.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_taileron2.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_vtail.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/wt_1ail.png
Normal file
After Width: | Height: | Size: 721 B |
BIN
Lua_scripts/DSMLIB/img/wt_1ail_1flp.png
Normal file
After Width: | Height: | Size: 803 B |
BIN
Lua_scripts/DSMLIB/img/wt_2ail.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
Lua_scripts/DSMLIB/img/wt_2ail_1flp.png
Normal file
After Width: | Height: | Size: 755 B |
BIN
Lua_scripts/DSMLIB/img/wt_2ail_2flp.png
Normal file
After Width: | Height: | Size: 817 B |
BIN
Lua_scripts/DSMLIB/img/wt_elevon.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
Lua_scripts/DSMLIB/img/wt_flaperon.png
Normal file
After Width: | Height: | Size: 679 B |
437
Lua_scripts/DSMLIB/msg_fwdp_en.txt
Normal file
@ -0,0 +1,437 @@
|
||||
-- FORMAT <LineType>|<Msg#>|<Text>
|
||||
-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX)
|
||||
-- NO EMPTY LINES
|
||||
-- Formmatting at end of line: /c=Center, /r=Right, /b=Bold, /m=menu
|
||||
LT|0x0001|Off
|
||||
LT|0x0002|On
|
||||
-- Ihn/Act List Options
|
||||
LT|0x0003|Inh
|
||||
LT|0x0004|Act
|
||||
--
|
||||
-- Channel selection for SAFE MODE and GAINS on FC6250HX
|
||||
LT|0x000C|Inh
|
||||
LT|0x000D|Ch5
|
||||
LT|0x000E|Ch6
|
||||
LT|0x000F|Ch7
|
||||
LT|0x0010|Ch8
|
||||
LT|0x0011|Ch9
|
||||
LT|0x0012|Ch10
|
||||
LT|0x0013|Ch11
|
||||
LT|0x0014|Ch12
|
||||
--
|
||||
-- Servo Output values
|
||||
LT|0x002D|5.5ms
|
||||
LT|0x002E|11ms
|
||||
LT|0x002F|22ms
|
||||
--
|
||||
-- Gain Multiplier Values
|
||||
LT|0x0032|1 X
|
||||
LT|0x0033|2 X
|
||||
LT|0x0034|4 X
|
||||
--
|
||||
LT|0x0035|Inh
|
||||
LT|0x0036|Thr
|
||||
LT|0x0037|Ail
|
||||
LT|0x0038|Ele
|
||||
LT|0x0039|Rud
|
||||
LT|0x003A|Ch5
|
||||
LT|0x003B|Ch6
|
||||
LT|0x003C|Ch7
|
||||
LT|0x003D|Ch8
|
||||
LT|0x003E|Ch9
|
||||
LT|0x003F|Ch10
|
||||
LT|0x0040|Ch11
|
||||
LT|0x0041|Ch12
|
||||
LT|0x0042|Ch13
|
||||
LT|0x0043|Ch14
|
||||
LT|0x0044|Ch15
|
||||
LT|0x0045|Ch16
|
||||
LT|0x0046|Ch17
|
||||
LT|0x0047|Ch18
|
||||
LT|0x0048|Ch19
|
||||
LT|0x0049|Ch20
|
||||
--
|
||||
T |0x0040|Roll
|
||||
T |0x0041|Pitch
|
||||
T |0x0042|Yaw
|
||||
T |0x0043|Gain/c/b
|
||||
T |0x0045|Differential
|
||||
T |0x0046|Priority
|
||||
T |0x0049|Output Setup
|
||||
T |0x004A|Failsafe
|
||||
T |0x004B|Main Menu
|
||||
T |0x004E|Position
|
||||
--
|
||||
T |0x0050|Outputs
|
||||
T |0x0051|Output Channel 1
|
||||
T |0x0052|Output Channel 2
|
||||
T |0x0053|Output Channel 3
|
||||
T |0x0054|Output Channel 4
|
||||
T |0x0055|Output Channel 5
|
||||
T |0x0056|Output Channel 6
|
||||
T |0x0057|Output Channel 7
|
||||
T |0x0058|Output Channel 8
|
||||
T |0x0059|Output Channel 9
|
||||
T |0x005A|Output Channel 10
|
||||
--
|
||||
-- FailSafe Options
|
||||
--LT|0x005E|Inh
|
||||
LT|0x005F|Hold Last
|
||||
LT|0x0060|Preset
|
||||
--LT|0x0061|Custom
|
||||
--
|
||||
T |0x0071|Proportional
|
||||
T |0x0072|Integral
|
||||
T |0x0073|Derivate
|
||||
T |0x0078|FM Channel
|
||||
T |0x007F|Attitude Gain
|
||||
--
|
||||
T |0x0080|Orientation
|
||||
T |0x0082|Heading
|
||||
T |0x0085|Frame Rate
|
||||
T |0x0086|System Setup
|
||||
T |0x0087|F-Mode Setup
|
||||
T |0x0088|Enabled F-Modes
|
||||
T |0x0089|Gain Channel
|
||||
T |0x008A|Gain Sensitivity/r -- Right Align
|
||||
T |0x008B|Panic
|
||||
T |0x008E|Panic Delay
|
||||
--
|
||||
LT|0x0187|No Freq --???? unset Freq
|
||||
LT|0x0088|70hz
|
||||
LT|0x0089|90hz
|
||||
LT|0x008A|200hz
|
||||
LT|0x008B|333hz
|
||||
LT|0x008C|490hz
|
||||
LT|0x008D|560hz
|
||||
LT|0x008E|Normal
|
||||
LT|0x008F|Reversed
|
||||
|
||||
-- FC6250HX: Callibration
|
||||
T |0x0090|Apply
|
||||
T |0x0091|Begin
|
||||
T |0x0092|Start
|
||||
T |0x0093|Complete
|
||||
T |0x0094|Done
|
||||
--
|
||||
-- FC6250HX: Swashplate Type
|
||||
--
|
||||
LT|0x0090|Normal
|
||||
LI|0x0090|h_swp_norm.png|Normal
|
||||
LT|0x0091|3 Servos 120 Y
|
||||
LI|0x0091|h_swp_3_120.png|3 Servos 120 Y
|
||||
LT|0x0092|3 Servos 120 Y-Inv
|
||||
LI|0x0092|h_swp_3_120inv.png|3 Servos 120 Y-Inv
|
||||
LT|0x0093|3 Servos 135 Y
|
||||
LI|0x0093|h_swp_3_135.png|3 Servos 135 Y
|
||||
LT|0x0094|3 Servos 135 Y-Inv
|
||||
LI|0x0094|h_swp_3_135inv.png|3 Servos 135 Y-Inv
|
||||
LT|0x0095|3 Servos 140 Y
|
||||
LI|0x0095|h_swp_3_140.png|3 Servos 140 Y
|
||||
LT|0x0096|3 Servos 140 Y-Inv
|
||||
LI|0x0096|h_swp_3_140inv.png|3 Servos 140 Y-Inv
|
||||
LT|0x0097|3 Servos 90 T
|
||||
LI|0x0097|h_swp_3_90.png|3 Servos 90 T
|
||||
LT|0x0098|3 Servos 90 T-Inv
|
||||
LI|0x0098|h_swp_3_90inv.png|3 Servos 90 T-Inv
|
||||
--
|
||||
T |0x0097|Factory Reset
|
||||
T |0x0098|Factory Reset
|
||||
T |0x0099|Advanced Setup
|
||||
T |0x009A|Capture Failsafe Positions
|
||||
T |0x009C|Custom Failsafe
|
||||
--
|
||||
T |0x009F|Save Settings -- Save & Reboot RX
|
||||
--
|
||||
T |0x00A5|First Time Setup
|
||||
T |0x00AA|Capture Gyro Gains
|
||||
T |0x00AD|Gain Channel Select
|
||||
T |0x00AF|Dynamic
|
||||
LT|0x00B0|Self-Level
|
||||
LT|0x00B1|Envelope
|
||||
--
|
||||
-- Flight Modes List Options
|
||||
LT|0x00B5|Inh
|
||||
LT|0x00B6|FM1
|
||||
LT|0x00B7|FM2
|
||||
LT|0x00B8|FM3
|
||||
LT|0x00B9|FM4
|
||||
LT|0x00BA|FM5
|
||||
LT|0x00BB|FM6
|
||||
LT|0x00BC|FM7
|
||||
LT|0x00BD|FM8
|
||||
LT|0x00BE|FM9
|
||||
LT|0x00BF|FM10
|
||||
--
|
||||
T |0x00BE|Unknown_BE -- Used in Reset menu (0x0001) while the RX is rebooting
|
||||
--
|
||||
T |0x00C7|Calibrate Sensor
|
||||
T |0x00C8|Sensor is Calibrating.. Wait
|
||||
T |0x00CA|SAFE & Panic Mode Setup
|
||||
--
|
||||
T |0x00CD|Level model & capt attitude/m -- SPECIAL MENU to itself who is not a comment
|
||||
T |0x00CE|Error TX Conf
|
||||
T |0x00CF|Invalid TX Ch Conf 1
|
||||
T |0x00D0|Invalid TX Ch Conf 2
|
||||
--
|
||||
-- RX Orientations for AR631/AR637, Optionally attach an Image + Alt Text to display
|
||||
LT|0x00CB|Pos 1
|
||||
LI|0x00CB|rx_pos_1.png|Pilot View: RX Label Up, Pins Back
|
||||
LT|0x00CC|Pos 2
|
||||
LI|0x00CC|rx_pos_2.png|Pilot View: RX Label Left, Pins Back
|
||||
LT|0x00CD|Pos 3
|
||||
LI|0x00CD|rx_pos_3.png|Pilot View: RX Label Down, Pins Back
|
||||
LT|0x00CE|Pos 4
|
||||
LI|0x00CE|rx_pos_4.png|Pilot View: RX Label Right, Pins Back
|
||||
LT|0x00CF|Pos 5
|
||||
LI|0x00CF|rx_pos_5.png|Pilot View: RX Label UP, Pins to Front
|
||||
LT|0x00D0|Pos 6
|
||||
LI|0x00D0|rx_pos_6.png|Pilot View: RX Label Left, Pins Front
|
||||
LT|0x00D1|Pos 7
|
||||
LI|0x00D1|rx_pos_7.png|Pilot View: RX Label Down, Pins Front
|
||||
LT|0x00D2|Pos 8
|
||||
LI|0x00D2|rx_pos_8.png|Pilot View: RX Label Right, Pins Front
|
||||
LT|0x00D3|Pos 9
|
||||
LI|0x00D3|rx_pos_9.png|Pilot View: RX Label Up, Pins Left
|
||||
LT|0x00D4|Pos 10
|
||||
LI|0x00D4|rx_pos_10.png|Pilot View: RX Label Back, Pins Left
|
||||
LT|0x00D5|Pos 11
|
||||
LI|0x00D5|rx_pos_11.png|Pilot View: RX Label Down, Pins Left
|
||||
LT|0x00D6|Pos 12
|
||||
LI|0x00D6|rx_pos_12.png|Pilot View: RX Label Front, Pins Left
|
||||
LT|0x00D7|Pos 13
|
||||
LI|0x00D7|rx_pos_13.png|Pilot View: RX Label Up, Pins Right
|
||||
LT|0x00D8|Pos 14
|
||||
LI|0x00D8|rx_pos_14.png|Pilot View: RX Label Back, Pins Right
|
||||
LT|0x00D9|Pos 15
|
||||
LI|0x00D9|rx_pos_15.png|Pilot View: RX Label Down, Pins Right
|
||||
LT|0x00DA|Pos 16
|
||||
LI|0x00DA|rx_pos_16.png|Pilot View: RX Label Front, Pins Right
|
||||
LT|0x00DB|Pos 17
|
||||
LI|0x00DB|rx_pos_17.png|Pilot View: RX Label Back, Pins Down
|
||||
LT|0x00DC|Pos 18
|
||||
LI|0x00DC|rx_pos_18.png|Pilot View: RX Label Left, Pins Down
|
||||
LT|0x00DD|Pos 19
|
||||
LI|0x00DD|rx_pos_19.png|Pilot View: RX Label Front, Pins Down
|
||||
LT|0x00DE|Pos 20
|
||||
LI|0x00DE|rx_pos_20.png|Pilot View: RX Label Right, Pins Down
|
||||
LT|0x00DF|Pos 21
|
||||
LI|0x00DF|rx_pos_21.png|Pilot View: RX Label Back, Pins Up
|
||||
LT|0x00E0|Pos 22
|
||||
LI|0x00E0|rx_pos_22.png|Pilot View: RX Label Left, Pins Up
|
||||
LT|0x00E1|Pos 23
|
||||
LI|0x00E1|rx_pos_23.png|Pilot View: RX Label Front, Pins Up
|
||||
LT|0x00E2|Pos 24
|
||||
LI|0x00E2|rx_pos_24.png|Pilot View: RX Label Right, Pins Up
|
||||
LT|0x00E3|Pos Invalid
|
||||
LI|0x00E3|rx_pos_25.png|Cannot detect orientation of RX
|
||||
--
|
||||
-- RX Orientations images for FC5250 (HACK add 0x100 internally to differenciate for helis)
|
||||
LI|0x01CB|h_rx_pos_1.png|Pilot View: RX Label Up, Pins Front
|
||||
LI|0x01CC|h_rx_pos_2.png|Pilot View: RX Label Left, Pins Front
|
||||
LI|0x01CD|h_rx_pos_3.png|Pilot View: RX Label Down, Pins Front
|
||||
LI|0x01CE|h_rx_pos_4.png|Pilot View: RX Label Right, Pins Front
|
||||
LI|0x01CF|h_rx_pos_5.png|Pilot View: RX Label UP, Pins to Back
|
||||
LI|0x01D0|h_rx_pos_6.png|Pilot View: RX Label Left, Pins Back
|
||||
LI|0x01D1|h_rx_pos_7.png|Pilot View: RX Label Down, Pins Back
|
||||
LI|0x01D2|h_rx_pos_8.png|Pilot View: RX Label Right, Pins Back
|
||||
--
|
||||
T |0x00D1|Receiver will Reboot/b
|
||||
T |0x00D2|Panic Channel
|
||||
T |0x00D3|Swashplate
|
||||
T |0x00D5|Agility
|
||||
T |0x00D8|Stop
|
||||
T |0x00DA|SAFE/c/b -- Center + Bold
|
||||
T |0x00DB|Stability
|
||||
T |0x00DC|@ per sec
|
||||
T |0x00DD|Tail rotor
|
||||
T |0x00DE|Setup
|
||||
T |0x00DF|AFR
|
||||
T |0x00E0|Collective
|
||||
T |0x00E1|Subtrim
|
||||
T |0x00E2|Phasing
|
||||
T |0x00E3|Pre-Comp
|
||||
T |0x00E4|E-Ring
|
||||
T |0x00E5|Swash Type
|
||||
T |0x00E6|Travel
|
||||
T |0x00E7|Left
|
||||
T |0x00E8|Right
|
||||
T |0x00EA|Low Throttle
|
||||
--
|
||||
T |0x00F2|Governor
|
||||
T |0x00F4|Soft Start
|
||||
--
|
||||
LT|0x00F2|Fixed
|
||||
LT|0x00F3|Adjustable
|
||||
LT|0x00F4|Inh
|
||||
LT|0x00F5|Nitro
|
||||
--
|
||||
T |0x00F6|Direction
|
||||
T |0x00F8|Settings -- ?? validate on a Spektrum radio
|
||||
T |0x00F9|Gyro settings
|
||||
T |0x00FE|Stick Priority/c/b
|
||||
--
|
||||
T |0x0100|Make sure the model has been
|
||||
T |0x0101|configured, including wing type,
|
||||
T |0x0102|reversing, travel, trimmed, etc.
|
||||
T |0x0103|before continuing setup.
|
||||
T |0x0104|
|
||||
T |0x0105| -- Blank
|
||||
--
|
||||
T |0x0106|Any wing type, channel assignment,
|
||||
T |0x0107|subtrim, or servo reversing changes
|
||||
T |0x0108|require running through initial
|
||||
T |0x0109|setup again.
|
||||
T |0x010A|
|
||||
T |0x010B|
|
||||
--
|
||||
T |0x0190|Relearn Servo Settings
|
||||
T |0x019C|Enter Receiver Bind Mode
|
||||
T |0x01AA|Offset
|
||||
T |0x01D7|SAFE Select Channel
|
||||
T |0x01DC|AS3X/c/b -- Center + Bold
|
||||
T |0x01DD|AS3X Settings
|
||||
T |0x01DE|AS3X Gains
|
||||
T |0x01E0|Rate Gains/c/b
|
||||
T |0x01E2|SAFE Settings
|
||||
T |0x01E3|SAFE Gains
|
||||
T |0x01E6|Attitude Trim/c/b
|
||||
T |0x01E7|Envelope
|
||||
T |0x01E9|Roll Right
|
||||
T |0x01EA|Roll Left
|
||||
T |0x01EB|Pitch Down
|
||||
T |0x01EC|Pitch Up
|
||||
T |0x01EE|Thr to Pitch
|
||||
T |0x01EF|Low Thr to Pitch/c/b
|
||||
T |0x01F0|High Thr to Pitch/c/b
|
||||
T |0x01F1|Filter
|
||||
T |0x01F3|Threshold
|
||||
T |0x01F4|Angle
|
||||
T |0x01F6|Failsafe Angles/c/b
|
||||
T |0x01F8|Safe Mode
|
||||
T |0x01F9|SAFE Select
|
||||
T |0x01FC|Panic F-Mode
|
||||
T |0x01FD|FailSafe Flight Mode -- Safe Flight Mode
|
||||
T |0x0201|Throttle
|
||||
T |0x0204|Hover
|
||||
T |0x0208|Decay
|
||||
T |0x0209|Save to Backup
|
||||
T |0x020A|Restore from Backup
|
||||
T |0x020D|First Time SAFE Setup
|
||||
--
|
||||
-- First time safe setup Page 3 :
|
||||
T |0x020E|AS3X gains must be tuned
|
||||
T |0x020F|and active in SAFE Flight Modes
|
||||
T |0x0210|to help reduce wobble.
|
||||
T |0x0211|
|
||||
T |0x0212|
|
||||
T |0x0213| -- Blank
|
||||
--
|
||||
-- AS3X orientation Setting menu (Level)
|
||||
T |0x021A|Set the model level,
|
||||
T |0x021B|and press Continue.
|
||||
T |0x021C|
|
||||
T |0x021D| -- Blank
|
||||
--
|
||||
-- AS3X orientation Setting menu (Nose down)
|
||||
T |0x021F|Set the model on its nose,
|
||||
T |0x0220|and press Continue. If the
|
||||
T |0x0221|orientation on the next
|
||||
T |0x0222|screen is wrong go back
|
||||
T |0x0223|and try again.
|
||||
T |0x0224|Continue
|
||||
--
|
||||
T |0x0226|Angle Limits/c/b
|
||||
T |0x0227|Other settings
|
||||
T |0x0229|Set Orientation Manually
|
||||
--
|
||||
-- Factory Default Warning
|
||||
T |0x022B|WARNING!
|
||||
T |0x022C|This will reset the
|
||||
T |0x022D|configuration to factory
|
||||
T |0x022E|defaults. This does not
|
||||
T |0x022F|affect the backup config.
|
||||
T |0x0230| -- Blank
|
||||
--
|
||||
-- Backup Warning
|
||||
T |0x0231|This will overwrite the
|
||||
T |0x0232|backup memory with your
|
||||
T |0x0233|current configuartion.
|
||||
T |0x0234|
|
||||
T |0x0235| -- Blank
|
||||
--
|
||||
-- Restore from Backup Warning
|
||||
T |0x0236|This will overwrite the
|
||||
T |0x0237|current config with
|
||||
T |0x0238|that which is in
|
||||
T |0x0239|the backup memory.
|
||||
T |0x023A| -- Blank
|
||||
--
|
||||
-- Utilities Copy flight modes
|
||||
T |0x023D|Copy F-Mode Settings
|
||||
T |0x023E|Source F-Mode
|
||||
T |0x023F|Target F-Mode
|
||||
--
|
||||
T |0x0240|Utilities
|
||||
--
|
||||
-- Gain Capture Page
|
||||
T |0x024C|Gains will be captured on
|
||||
T |0x024D|Captured gains will be
|
||||
T |0x024E|Gains on
|
||||
T |0x024F|were captured and changed
|
||||
T |0x0250|from Adjustable to Fixed
|
||||
--
|
||||
-- Utilities, Copy flight mode (Copy Confirmation, oveerriding FM)
|
||||
T |0x0251|Are you sure you want to ovewrite the "Target"
|
||||
T |0x0252|with the "Source" ?
|
||||
T |0x0253| -- Blank
|
||||
--
|
||||
T |0x0254|Pos = Up, Neg = Down
|
||||
--
|
||||
-- First time safe setup Page 1 (maybe ask to select Flight Mode cannel)
|
||||
T |0x0255|Before setting up SAFE
|
||||
T |0x0256|a Flight Mode channel
|
||||
T |0x0257|most be configured.
|
||||
--
|
||||
-- First time safe setup Page 2 (something related for flight mode)
|
||||
T |0x025A|Select the desired flight mode
|
||||
T |0x025B|switch position to adjust settings
|
||||
T |0x025C|for each flight mode
|
||||
T |0x025D|
|
||||
T |0x025E| -- Blank
|
||||
--
|
||||
-- Utilities, Copy flight mode (Confirm)
|
||||
T |0x0259|YES
|
||||
T |0x0260|WARNING: "Target"
|
||||
T |0x0261|F-Mode will be overwritten
|
||||
T |0x0262|by "Source"
|
||||
--
|
||||
T |0x0263|Fixed/Adjustable Gains/c/b
|
||||
T |0x0266|Heading Gain/c/b
|
||||
T |0x0267|Pos = Nose Up/Roll Right
|
||||
T |0x0268|Neg = Nose Down/Roll Left
|
||||
T |0x0269|SAFE - Thr to Pitch
|
||||
T |0x026A|Use CAUTION for Yaw gain!/b
|
||||
--
|
||||
T |0x026B|Head Speed
|
||||
T |0x026C|Pinion
|
||||
T |0x026D|Main Gear
|
||||
T |0x026F|RPM Sensor
|
||||
T |0x0272|Show Advanced Menus
|
||||
--
|
||||
T |0x0300|No compatible DSM RX...
|
||||
T |0x0301|Waiting for RX to Restart
|
||||
--
|
||||
FM|0x8000|Flight Mode/c/b
|
||||
--
|
||||
RX|0x0001|AR636
|
||||
RX|0x0014|SPM4651T
|
||||
RX|0x0015|AR637T
|
||||
RX|0x0016|AR637TA
|
||||
RX|0x0018|FC6250HX
|
||||
RX|0x0019|AR630
|
||||
RX|0x001A|AR8360T
|
||||
RX|0x001B|AR8020T
|
||||
RX|0x001C|AR10360T
|
||||
RX|0x001E|AR631
|
||||
|
22
Lua_scripts/DSMLIB/readme.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Credits
|
||||
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
Rewrite/Enhancements by: Francisco Arzu
|
||||
|
||||
Thanks to all the people volunteered to test it.
|
||||
|
||||
Release Notes for
|
||||
|
||||
## COLOR Radios
|
||||
Read more [Color radios](./readme_color.md)
|
||||
|
||||

|
||||

|
||||
|
||||
## Black & White Radios (Small Screens)
|
||||
Read more [black & whire radios](./readme_bw.md)
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
181
Lua_scripts/DSMLIB/readme_bw.md
Normal 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.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
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
|
||||
|
284
Lua_scripts/DSMLIB/readme_color.md
Normal 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.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
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 doesn’t 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
|
||||
|
683
Lua_scripts/DSM_AR636_Tel.lua
Normal file
@ -0,0 +1,683 @@
|
||||
local toolName = "TNS|DSM AR636 Telemetry|TNE"
|
||||
---- ######################################################################### #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Developer: Francisco Arzu
|
||||
-- Original idea taken from DsmPID.lua.. don't know who is the author
|
||||
--
|
||||
|
||||
local DEBUG_ON = false
|
||||
--
|
||||
|
||||
local TEXT_SIZE = 0 -- NORMAL
|
||||
local X_COL1_HEADER = 6
|
||||
local X_COL1_DATA = 60
|
||||
local X_COL2_HEADER = 170
|
||||
local X_COL2_DATA = 220
|
||||
local Y_LINE_HEIGHT = 20
|
||||
local Y_HEADER = 0
|
||||
local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2
|
||||
local X_DATA_LEN = 80
|
||||
local X_DATA_SPACE = 5
|
||||
|
||||
|
||||
local function getPage(iParam)
|
||||
-- get page from 0-based index
|
||||
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
|
||||
local res = (math.floor(iParam/4)==0) and 0 or 1
|
||||
return res
|
||||
end
|
||||
|
||||
local function round(v)
|
||||
-- round float
|
||||
local factor = 100
|
||||
return math.floor(v * factor + 0.5) / factor
|
||||
end
|
||||
|
||||
|
||||
local function readValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
--v = round(v)
|
||||
return v
|
||||
end
|
||||
|
||||
local function readValueById(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return nil end
|
||||
|
||||
local v = getValue(i.id)
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function readBatValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
if (v==nil) then return "--" end
|
||||
|
||||
return string.format("%2.2f",v)
|
||||
end
|
||||
|
||||
local function readActiveParamValue(sensor)
|
||||
-- read and return a validated active parameter value
|
||||
local v = getValue(sensor)
|
||||
if (v<1 or v>8) then
|
||||
return -1
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
local function drawPIDScreen()
|
||||
-- draw labels and params on screen
|
||||
|
||||
local pageId = getValue("FLss")
|
||||
|
||||
lcd.clear()
|
||||
-- if active gain does not validate then assume
|
||||
-- Gain Adjustment Mode is disabled
|
||||
if not (pageId==4401 or pageId==4402) then
|
||||
lcd.drawText(0,0,"BLADE Gain Adjustment", TEXT_SIZE +INVERS)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Gain Adjustment Mode",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/R + Low/R + Panic (3 sec)",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: Right Stk: Up/Down to select, Left/Right change value",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE)
|
||||
return
|
||||
end
|
||||
|
||||
local activePage = (pageId % 100)-1 --Last 2 digits, make it zero base
|
||||
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Cyclic (0-200)", TEXT_SIZE + INVERS)
|
||||
lcd.drawText (X_COL2_HEADER, Y_HEADER, "Tail (0-200)", TEXT_SIZE + INVERS)
|
||||
|
||||
|
||||
|
||||
local p = readValue("FdeA")
|
||||
local i = readValue("FdeB")
|
||||
local d = readValue("FdeL")
|
||||
local r = readValue("FdeR")
|
||||
|
||||
local titles = {[0]="P:", "I:", "D:", "Resp:", "P:","I:","D:", "Filt:"}
|
||||
local values = {[0]=p,i,d,r,p,i,d,r}
|
||||
|
||||
local activeParam = readActiveParamValue("Hold")-1
|
||||
|
||||
for iParam=0,7 do
|
||||
-- highlight selected parameter
|
||||
local attr = (activeParam==iParam) and INVERS or 0
|
||||
-- circular index (per page)
|
||||
local perPageIndx = (iParam % 4)
|
||||
|
||||
-- set y draw coord
|
||||
local y = (perPageIndx+1)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- check if displaying cyclic params.
|
||||
local isCyclicPage = (getPage(iParam)==0)
|
||||
|
||||
-- labels
|
||||
local x = isCyclicPage and X_COL1_HEADER or X_COL2_HEADER
|
||||
-- labels are P,I,D for both pages except for last param
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- gains
|
||||
-- set all params for non-active page to '--' rather than 'last value'
|
||||
val = (getPage(iParam)==activePage) and values[iParam] or '--'
|
||||
x = isCyclicPage and X_COL1_DATA or X_COL2_DATA
|
||||
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function drawFlightLogScreen()
|
||||
-- draw labels and params on screen
|
||||
local h = getValue("Hold")
|
||||
local activeParam = h-1 -- H
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS)
|
||||
|
||||
-- read and return parameters
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
local r = getValue("FdeR")
|
||||
local f = getValue("FLss")
|
||||
|
||||
local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"}
|
||||
local values = {[0]=a,b,l,r,f,h}
|
||||
|
||||
local y = Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
for iParam=0,3 do -- A,B,L,R
|
||||
-- highlight selected parameter (rund)
|
||||
local attr = ((activeParam%4)==iParam) and INVERS or 0
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA + X_DATA_LEN
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_LINE_HEIGHT+Y_DATA
|
||||
for iParam=4,5 do -- F, H
|
||||
-- labels
|
||||
local x = X_COL2_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + BOLD)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL2_DATA + X_DATA_LEN
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
local bat = readBatValue("A2") or "--"
|
||||
lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE)
|
||||
|
||||
end
|
||||
|
||||
local function servoAdjustScreen()
|
||||
-- draw labels and params on screen
|
||||
local pageId = getValue("FLss") -- FLss
|
||||
local activeParam = getValue("Hold")-1 -- Hold
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0, Y_HEADER, "BLADE Servo SubTrim", TEXT_SIZE + INVERS)
|
||||
|
||||
if pageId~=1234 then
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Servo Adjustment Mode",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/L + Low/R + Panic (3 sec)",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: R Stk: Up/Down to select, Left/Right change value",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE)
|
||||
return
|
||||
end
|
||||
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
|
||||
local titles = {[0]="Servo1:", "Servo2:", "Servo3:"}
|
||||
local values = {[0]=a,b,l}
|
||||
|
||||
for iParam=0,#values do -- S1,S2,S3
|
||||
-- highlight selected parameter
|
||||
local attr = (activeParam==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam+1)*Y_LINE_HEIGHT+Y_HEADER
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Unsigned_to_SInt16(value)
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function getDegreesValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%0.1f o",vs/10)
|
||||
end
|
||||
|
||||
|
||||
local function getDecHexValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%d (0x%04X)",vs,v)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function drawVersionScreen()
|
||||
local paramV = getValue("FdeA")
|
||||
local B = getValue("FdeB")
|
||||
local rxId = getValue("FdeL")
|
||||
local firmware = getValue("FLss")
|
||||
local prodId = getValue("Hold")
|
||||
local bat = readBatValue("A2")
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0, Y_HEADER, "BLADE Version", TEXT_SIZE + INVERS)
|
||||
|
||||
--Product ID
|
||||
local val = "ID_".. prodId
|
||||
|
||||
if (prodId==243) then val = "Blade 230 V1"
|
||||
elseif (prodId==250) then val = "Blade 230 V2 (not Smart)"
|
||||
elseif (prodId==149) then val = "Blade 250 CFX"
|
||||
end
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
lcd.drawText (X_COL1_HEADER, y, "Prod:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- RX
|
||||
val = "ID_"..rxId
|
||||
if (rxId==1) then val = "AR636"
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "RX:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- Firmware
|
||||
val = string.format("%0.2f",firmware/100)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Firmware:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- ParamV
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Params:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, paramV, TEXT_SIZE)
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, bat, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText(X_COL1_HEADER,y,"Press Panic for 3s",TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText(X_COL1_HEADER,y,"Usually Panic is Ch7 on a switch and Revesed",TEXT_SIZE)
|
||||
|
||||
end
|
||||
|
||||
local function parseFlightMode(v)
|
||||
-- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0= off, 1=init, 2=Hold, 3=Running) GG=???
|
||||
if v==nil then return "---" end
|
||||
local fm = bit32.rshift(v, 12)
|
||||
local status = bit32.band(bit32.rshift(v, 8),0xF)
|
||||
|
||||
local res = " "..fm.." "
|
||||
|
||||
if (fm==0) then res = res .. " NORMAL"
|
||||
elseif (fm==1) then res = res .. " INTERMEDIATE"
|
||||
elseif (fm==2) then res = res .. " ADVANCED"
|
||||
elseif (fm==5) then res = res .. " PANIC"
|
||||
end
|
||||
|
||||
if (status==2) then res=res .. " HOLD" end
|
||||
|
||||
if (DEBUG_ON) then
|
||||
res = res .. string.format(" (0x%04X)",v)
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
|
||||
local function drawAlpha6Monitor()
|
||||
lcd.clear()
|
||||
|
||||
local RxStatus = readValueById("2402") -- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0=init, 2=Ready, 3=Sensor Fault) GG=???
|
||||
|
||||
local ARoll = getDegreesValue("2406") --Att Roll
|
||||
local APitch = getDegreesValue("2408") --Att Pitch
|
||||
local AYaw = getDegreesValue("240B") --Att Yaw
|
||||
|
||||
|
||||
lcd.drawText (0,0, "BLADE Alpha6 Monitor", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL1_DATA+X_DATA_LEN*2
|
||||
local x_data3 = X_COL1_DATA+X_DATA_LEN*3
|
||||
|
||||
-- Flight Mode
|
||||
lcd.drawText (0,y, "F-Mode:"..parseFlightMode(RxStatus), TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (x_data1,y, "Attitude", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data2,y, "Gyro", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data3,y, "Gain", TEXT_SIZE+BOLD + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Rol:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, ARoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, APitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, AYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT + Y_LINE_HEIGHT
|
||||
lcd.drawText (0,y, "Bat: "..readBatValue("A2").." v", TEXT_SIZE)
|
||||
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local s2400 = getDecHexValue("2400")
|
||||
local s2402 = getDecHexValue("2402")
|
||||
local s2404 = getDecHexValue("2404")
|
||||
|
||||
local s240D = getDecHexValue("240D")
|
||||
|
||||
local s1G00 = getDecHexValue("1G00")
|
||||
local s1G02 = getDecHexValue("1G02")
|
||||
local s1G04 = getDecHexValue("1G04")
|
||||
local s1G06 = getDecHexValue("1G06")
|
||||
local s1G08 = getDecHexValue("1G08")
|
||||
local s1G0B = getDecHexValue("1G0B")
|
||||
local s1G0D = getDecHexValue("1G0D")
|
||||
|
||||
local titles = {[0]=
|
||||
"2400","2402/FM-S-?",
|
||||
"2404","240D",
|
||||
"1G00","1G02","1G04",
|
||||
"1G06","1G08","1G0B","1G0D"}
|
||||
|
||||
local values = {[0]=
|
||||
s2400,s2402,s2404,s240D,
|
||||
s1G00,s1G02,s1G04,
|
||||
s1G06,s1G08,s1G0B,s1G0D}
|
||||
|
||||
|
||||
-- draw labels and params on screen
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#titles do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+220
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function readAlpha3arameters()
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function drawAS3XMonitor()
|
||||
lcd.clear()
|
||||
local s1G00 = getDecHexValue("1G00")
|
||||
local s1G02 = getDecHexValue("1G02")
|
||||
local s1G04 = getDecHexValue("1G04")
|
||||
local s1G06 = getDecHexValue("1G06")
|
||||
local s1G08 = getDecHexValue("1G08")
|
||||
local s1G0B = getDecHexValue("1G0B")
|
||||
local s1G0D = getDecHexValue("1G0D")
|
||||
|
||||
local s6C00 = getDecHexValue("6C00")
|
||||
local s6C02 = getDecHexValue("6C02")
|
||||
local s6C04 = getDecHexValue("6C04")
|
||||
|
||||
|
||||
|
||||
local RRoll = bit32.rshift(getValue("1G00") or 0,8)
|
||||
local RPitch = bit32.band(getValue("1G00") or 0,0xFF)
|
||||
local RYaw = bit32.rshift(getValue("1G02") or 0,8)
|
||||
|
||||
local HRoll = bit32.band(getValue("1G02") or 0,0xFF)
|
||||
local HPitch = bit32.rshift(getValue("1G04") or 0,8)
|
||||
local HYaw = bit32.band(getValue("1G04") or 0,0xFF)
|
||||
|
||||
local ARoll = bit32.rshift(getValue("1G06") or 0,8)
|
||||
local APitch = bit32.band(getValue("1G06") or 0,0xFF)
|
||||
local AYaw = bit32.rshift(getValue("1G08") or 0,8)
|
||||
|
||||
|
||||
lcd.drawText (0,0, "Plane AR636 AS3X Gains", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL1_DATA+X_DATA_LEN*2
|
||||
local x_data3 = X_COL1_DATA+X_DATA_LEN*3.1
|
||||
|
||||
-- Flight Mode
|
||||
--lcd.drawText (0,y, "F-Mode: "..(nil or "--"), TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (x_data1,y, "Rate", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data2,y, "Head", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data3+X_DATA_SPACE*3,y, "Actual", TEXT_SIZE+BOLD + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RRoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HRoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, ARoll, TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RPitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HPitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, APitch, TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, AYaw, TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local Alpha3Tags = {[0]=
|
||||
"1G00/RA+RE","1G02/RY+HA","1G04R HP+HY","1G06/AR+AP","1G08/AY+?","1G0B","1G0D","6C00","6C02","6C04"}
|
||||
|
||||
local params = {[0]=
|
||||
s1G00,s1G02,s1G04,s1G06,s1G08,s1G0B,s1G0D,s6C00,s6C02,s6C04 }
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#Alpha3Tags do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+220
|
||||
local val = Alpha3Tags[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = params[iParam]
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function openTelemetryRaw(i2cId)
|
||||
--Init telemetry (Spectrun Telemetry Raw STR)
|
||||
multiBuffer( 0, string.byte('S') )
|
||||
multiBuffer( 1, string.byte('T') )
|
||||
multiBuffer( 2, string.byte('R') )
|
||||
multiBuffer( 3, i2cId ) -- Monitor this teemetry data
|
||||
multiBuffer( 4, 0 ) -- Allow to get Data
|
||||
end
|
||||
|
||||
local function closeTelemetryRaw()
|
||||
multiBuffer(0, 0) -- Destroy the STR header
|
||||
multiBuffer(3, 0) -- Not requesting any Telementry ID
|
||||
end
|
||||
|
||||
local lineText = {nil}
|
||||
local I2C_TEXT_GEN = 0x0C
|
||||
|
||||
local function drawTextGen(event)
|
||||
if (multiBuffer(0)~=string.byte('S')) then -- First time run???
|
||||
openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN
|
||||
lineText = {nil}
|
||||
end
|
||||
|
||||
-- Proces TEXT GEN Telementry message
|
||||
if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received
|
||||
local instanceNo = multiBuffer( 5 )
|
||||
local lineNo = multiBuffer( 6 )
|
||||
local line = ""
|
||||
for i=0,13 do
|
||||
line = line .. string.char(multiBuffer( 7 + i ))
|
||||
end
|
||||
|
||||
multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message
|
||||
lineText[lineNo]=line
|
||||
end
|
||||
|
||||
lcd.clear()
|
||||
-- Header
|
||||
if (lineText[0]) then
|
||||
lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS)
|
||||
else
|
||||
lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS)
|
||||
end
|
||||
|
||||
-- Menu lines
|
||||
local y = Y_DATA
|
||||
for i=1,8 do
|
||||
if (lineText[i]) then
|
||||
lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data
|
||||
closeTelemetryRaw()
|
||||
end
|
||||
end
|
||||
|
||||
local telPage = 1
|
||||
local telPageSelected = 0
|
||||
local pageTitle = {[0]="Main", "Blade Version", "Blade Servo Adjust","Blade Gyro Adjust", "Blade Alpha6 Monitor", "Plane AS3X Monitor", "TextGen", "Flight Log"}
|
||||
|
||||
local function drawMainScreen(event)
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (AR636)", TEXT_SIZE + INVERS)
|
||||
|
||||
for iParam=1,#pageTitle do
|
||||
-- highlight selected parameter
|
||||
local attr = (telPage==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam-1)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = pageTitle[iParam]
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
if (telPage>1) then telPage = telPage - 1 end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
if (telPage<#pageTitle) then telPage = telPage + 1 end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
telPageSelected = telPage
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local pageDraw = {[0]=drawMainScreen, drawVersionScreen, servoAdjustScreen,drawPIDScreen, drawAlpha6Monitor, drawAS3XMonitor, drawTextGen, drawFlightLogScreen}
|
||||
|
||||
local function run_func(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
end
|
||||
|
||||
-- draw specific page
|
||||
pageDraw[telPageSelected](event)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if (telPageSelected==0) then return 1 end -- on Main?? Exit Script
|
||||
telPageSelected = 0 -- any page, return to Main
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function init_func()
|
||||
|
||||
if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens
|
||||
TEXT_SIZE = SMLSIZE
|
||||
X_COL1_HEADER = 0
|
||||
X_COL1_DATA = 20
|
||||
|
||||
X_COL2_HEADER = 60
|
||||
X_COL2_DATA = 90
|
||||
|
||||
X_DATA_LEN = 28
|
||||
X_DATA_SPACE = 1
|
||||
|
||||
|
||||
Y_LINE_HEIGHT = 8
|
||||
Y_DATA = Y_HEADER + Y_LINE_HEIGHT
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return { run=run_func, init=init_func }
|
603
Lua_scripts/DSM_SmartRX_Tel.lua
Normal file
@ -0,0 +1,603 @@
|
||||
local toolName = "TNS|DSM Smart RX Telemetry|TNE"
|
||||
---- ######################################################################### #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Developer: Francisco Arzu
|
||||
|
||||
|
||||
local DEBUG_ON = false
|
||||
--
|
||||
|
||||
local TEXT_SIZE = 0 -- NORMAL
|
||||
local X_COL1_HEADER = 6
|
||||
local X_COL1_DATA = 60
|
||||
local X_COL2_HEADER = 170
|
||||
local X_COL2_DATA = 220
|
||||
local Y_LINE_HEIGHT = 20
|
||||
local Y_HEADER = 0
|
||||
local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2
|
||||
local X_DATA_LEN = 80
|
||||
local X_DATA_SPACE = 5
|
||||
|
||||
|
||||
|
||||
|
||||
local function getPage(iParam)
|
||||
-- get page from 0-based index
|
||||
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
|
||||
local res = (math.floor(iParam/4)==0) and 0 or 1
|
||||
return res
|
||||
end
|
||||
|
||||
local function round(v)
|
||||
-- round float
|
||||
local factor = 100
|
||||
return math.floor(v * factor + 0.5) / factor
|
||||
end
|
||||
|
||||
|
||||
local function readValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
--v = round(v)
|
||||
return v
|
||||
end
|
||||
|
||||
local function readValueById(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return nil end
|
||||
|
||||
local v = getValue(i.id)
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function readBatValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
if (v==nil) then return v end
|
||||
|
||||
return string.format("%2.2f",v)
|
||||
end
|
||||
|
||||
local function readActiveParamValue(sensor)
|
||||
-- read and return a validated active parameter value
|
||||
local v = getValue(sensor)
|
||||
if (v<1 or v>8) then
|
||||
return -1
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function drawFlightLogScreen(event)
|
||||
-- draw labels and params on screen
|
||||
local h = getValue("Hold")
|
||||
local activeParam = h-1 -- H
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS)
|
||||
|
||||
-- read and return parameters
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
local r = getValue("FdeR")
|
||||
local f = getValue("FLss")
|
||||
|
||||
local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"}
|
||||
local values = {[0]=a,b,l,r,f,h}
|
||||
|
||||
local y = Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
for iParam=0,3 do -- A,B,L,R
|
||||
-- highlight selected parameter (rund)
|
||||
local attr = ((activeParam%4)==iParam) and INVERS or 0
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA + X_DATA_LEN
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_LINE_HEIGHT+Y_DATA
|
||||
for iParam=4,5 do -- F, H
|
||||
-- labels
|
||||
local x = X_COL2_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + BOLD)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL2_DATA + X_DATA_LEN
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
local bat = readBatValue("A2") or "--"
|
||||
lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE)
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local function Unsigned_to_SInt16(value)
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function getDegreesValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%0.1f o",vs/10)
|
||||
end
|
||||
|
||||
|
||||
local function getDecHexValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%d (0x%04X)",vs,v)
|
||||
end
|
||||
|
||||
local as3xData = {[0]=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
||||
local function drawAS3XSettings(event, page)
|
||||
local s0500 = getDecHexValue("0500")
|
||||
local s0502 = getDecHexValue("0502")
|
||||
local s0504 = getDecHexValue("0504")
|
||||
local s0506 = getDecHexValue("0506")
|
||||
local s0508 = getDecHexValue("0508")
|
||||
local s050B = getDecHexValue("050B")
|
||||
local s050D = getDecHexValue("050D")
|
||||
|
||||
local d0500 = readValueById("0500") or 0
|
||||
local flags = bit32.rshift(d0500,8)
|
||||
local state = bit32.band(d0500,0xFF)
|
||||
|
||||
local flagsMsg=""
|
||||
-- flags bits: Safe Envelop, ?, Angle Demand, Stab
|
||||
if (bit32.band(flags,0x1)~=0) then flagsMsg=flagsMsg.."AS3X Stab" end
|
||||
-- This one, only one should show
|
||||
if (bit32.band(flags,0x2)~=0) then flagsMsg=flagsMsg..", Angle Demand"
|
||||
elseif (bit32.band(flags,0x8)~=0) then flagsMsg=flagsMsg..", Safe Envelope"
|
||||
elseif (bit32.band(flags,0x4)~=0) then flagsMsg=flagsMsg..", AS3X Heading" end
|
||||
|
||||
local d0502 = readValueById("0502") or 0 -- 0x?F?S
|
||||
local fm = bit32.band(bit32.rshift(d0502,8),0xF) -- 0,1,2
|
||||
|
||||
local axis = bit32.band(d0502,0xF) -- 0=Gains,1=Headings,2=Angle Limits (cointinus iterating to provide all values)
|
||||
|
||||
local d0504 = readValueById("0504") or 0
|
||||
local d0506 = readValueById("0506") or 0
|
||||
local d0508 = readValueById("0508") or 0
|
||||
|
||||
local d0 = bit32.rshift(d0504,8)
|
||||
local d1 = bit32.band(d0504,0xFF)
|
||||
local d2 = bit32.rshift(d0506,8)
|
||||
local d3 = bit32.band(d0506,0xFF)
|
||||
local d4 = bit32.rshift(d0508,8)
|
||||
local d5 = bit32.band(d0508,0xFF)
|
||||
|
||||
--axis: 0=Gains+Headings (RG,PG,YG,RH,PH,YH), 1=Safe Gains (R,P,Y),2=Angle Limits(L,R,U,D)
|
||||
--Constantly changing from 0..2 to represent different data, thats why we have to store the values
|
||||
--in a script/global variable, and not local to the function
|
||||
local s = axis*6
|
||||
as3xData[s+0] = d0
|
||||
as3xData[s+1] = d1
|
||||
as3xData[s+2] = d2
|
||||
as3xData[s+3] = d3
|
||||
as3xData[s+4] = d4
|
||||
as3xData[s+5] = d5
|
||||
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0,0, "AS3X/SAFE Settings", TEXT_SIZE + INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
-- Flight Mode
|
||||
lcd.drawText (X_COL1_HEADER,y, "FM: "..(fm+1), TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN*0.3,y, "Flags: "..flags, TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "State: "..state, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, flagsMsg, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
|
||||
if (page==1) then
|
||||
lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "AS3X Gains", TEXT_SIZE+BOLD)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "AS3X Headings", TEXT_SIZE+BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[0], TEXT_SIZE + RIGHT) -- Roll G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[3], TEXT_SIZE + RIGHT) -- Roll H
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y,as3xData[1], TEXT_SIZE + RIGHT) -- Pitch G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[4], TEXT_SIZE + RIGHT) -- Pitch H
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[2], TEXT_SIZE + RIGHT) -- Yaw G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[5], TEXT_SIZE + RIGHT) -- Yaw H
|
||||
end
|
||||
|
||||
|
||||
if (page==2) then
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL2_HEADER+X_DATA_LEN*1.6
|
||||
|
||||
lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "SAFE Gains", TEXT_SIZE+BOLD)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.1,y, "Angle Limits", TEXT_SIZE+BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, as3xData[6], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Roll R:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[12], TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y,as3xData[7], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Roll L:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y,as3xData[13], TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, as3xData[8], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Pitch U:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[14], TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL2_HEADER,y, "Pitch D:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[15], TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local titles = {[0]=
|
||||
"0500","0502","0504","0506","0508","050B","050D"}
|
||||
|
||||
local values = {[0]=
|
||||
s0500,s0502,s0504,s0506,s0508,s050B,s050D }
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#titles do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+250
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam] or "--"
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function drawAS3XSettingsP1(event)
|
||||
drawAS3XSettings(event, 1)
|
||||
end
|
||||
|
||||
local function drawAS3XSettingsP2(event)
|
||||
drawAS3XSettings(event, 2)
|
||||
end
|
||||
|
||||
|
||||
local function doFloat(v)
|
||||
if v==nil then return 0.0 end
|
||||
|
||||
local vs = string.format("%1.2f",v)
|
||||
|
||||
return vs + 0.0
|
||||
end
|
||||
|
||||
|
||||
local ESC_Title={[0]="","RPM:","Volts:","Motor:","Mot Out:","Throttle:","FET Temp:", "BEC V:", "BEC T:", "BEC A:"}
|
||||
local ESC_uom={[0]="","","V","A","%","%","C", "V","C","A"}
|
||||
local ESC_Status={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local ESC_Min={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local ESC_Max={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
|
||||
local function drawESCStatus(event)
|
||||
lcd.clear()
|
||||
ESC_Status[1] = getValue("Erpm") -- RPM
|
||||
ESC_Status[2] = doFloat(getValue("EVIN")) -- Volts
|
||||
ESC_Status[3] = doFloat(getValue("ECUR")) -- Current
|
||||
ESC_Status[4] = doFloat(getValue("EOUT")) -- % Output
|
||||
ESC_Status[5] = doFloat(getValue("ETHR")) -- Throttle % (EOUT)
|
||||
ESC_Status[6] = getValue("TFET") -- Temp FET
|
||||
|
||||
ESC_Status[7] = doFloat(getValue("VBEC")) -- Volts BEC
|
||||
ESC_Status[8] = getValue("TBEC") -- Temp BEC
|
||||
ESC_Status[9] = doFloat(getValue("CBEC")) -- Current BEC
|
||||
|
||||
for i=1,9 do
|
||||
if (ESC_Status~=nil) then
|
||||
if (ESC_Min[i]==0) then
|
||||
ESC_Min[i]=ESC_Status[i]
|
||||
else
|
||||
ESC_Min[i] = math.min(ESC_Min[i],ESC_Status[i])
|
||||
end
|
||||
|
||||
ESC_Max[i] = math.max(ESC_Max[i],ESC_Status[i])
|
||||
end
|
||||
end
|
||||
|
||||
lcd.drawText (0,0, "ESC", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = 0
|
||||
local x_data = X_COL1_DATA+X_DATA_LEN*1.5
|
||||
local x_data2 = X_COL2_DATA+X_DATA_LEN*0.5
|
||||
local x_data3 = x_data2 + X_DATA_LEN*0.8
|
||||
|
||||
|
||||
lcd.drawText (x_data,y , "Status", TEXT_SIZE+BOLD+RIGHT)
|
||||
lcd.drawText (x_data2,y, "Min", TEXT_SIZE+BOLD+RIGHT)
|
||||
lcd.drawText (x_data3,y, "Max", TEXT_SIZE+BOLD+RIGHT)
|
||||
|
||||
y = Y_DATA
|
||||
for i=1,9 do
|
||||
lcd.drawText (X_COL1_HEADER,y, ESC_Title[i], TEXT_SIZE + BOLD)
|
||||
|
||||
lcd.drawText (x_data,y, ESC_Status[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data + X_DATA_SPACE,y, ESC_uom[i], TEXT_SIZE)
|
||||
|
||||
lcd.drawText (x_data2,y, ESC_Min[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, ESC_Max[i] or "--", TEXT_SIZE + RIGHT)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function drawBATStatus(event)
|
||||
local Title={[0]="","Bat:","Temp:","Rem :","Curr:","Used:","Imbal:","Cycles:", "RX:", "BCpT?:"}
|
||||
local uom={[0]="","V","C","%","mAh","mAh","mV","", "V",""}
|
||||
local Values={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local CellValues={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
|
||||
lcd.clear()
|
||||
|
||||
local ESC_Volts = getValue("EVIN") or 0 -- Volts
|
||||
local ESC_Current = getValue("ECUR") or 0 -- Current
|
||||
|
||||
Values[1] = 0 -- compute later
|
||||
Values[2] = getValue("BTmp") -- Current (C)
|
||||
Values[3] = nil -- Remaining???
|
||||
Values[4] = getValue("BCur") -- Current (mAh)
|
||||
Values[5] = getValue("BUse") -- Current Used (mAh)
|
||||
Values[6] = getValue("CLMa") -- 0.0 (mV) Imbalance
|
||||
Values[7] = getValue("Cycl") -- Cycles
|
||||
Values[8] = readBatValue("A2") -- v
|
||||
Values[9] = getValue("BCpT") -- Current (mAh) ????
|
||||
|
||||
|
||||
--- Total Voltange Calculation
|
||||
local VTotal=0
|
||||
for i=1,10 do
|
||||
CellValues[i] = getValue("Cel"..i)
|
||||
VTotal = VTotal + CellValues[i]
|
||||
end
|
||||
|
||||
if (VTotal==0) then -- No Inteligent Battery,use intelligent ESC if any
|
||||
VTotal = ESC_Volts
|
||||
Values[4] = string.format("%d",ESC_Current * 1000)
|
||||
end
|
||||
|
||||
Values[1] = string.format("%2.2f",VTotal)
|
||||
|
||||
--- SCREEN
|
||||
|
||||
lcd.drawText (X_COL1_HEADER,0, "Battery Stats", TEXT_SIZE+INVERS)
|
||||
|
||||
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data = X_COL1_DATA+X_DATA_LEN+X_DATA_SPACE*3
|
||||
for i=2,9 do
|
||||
lcd.drawText (X_COL1_HEADER, y, Title[i], TEXT_SIZE + BOLD)
|
||||
lcd.drawText (x_data, y, Values[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE, y, uom[i], TEXT_SIZE)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_DATA
|
||||
x_data = X_COL2_DATA+X_DATA_LEN+X_DATA_SPACE*5
|
||||
for i=1,8 do
|
||||
if ((CellValues[i] or 0) > 0) then
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,y, "Cel "..i..":", TEXT_SIZE + BOLD)
|
||||
lcd.drawText (x_data,y, string.format("%2.2f",CellValues[i] or 0), TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE,y, "v", TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,0, Title[1], TEXT_SIZE + INVERS + BOLD)
|
||||
lcd.drawText (x_data,0, string.format("%2.2f",Values[1] or 0), TEXT_SIZE + INVERS+ RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE, 0, uom[1], TEXT_SIZE + INVERS)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function openTelemetryRaw(i2cId)
|
||||
--Init telemetry (Spectrun Telemetry Raw STR)
|
||||
multiBuffer( 0, string.byte('S') )
|
||||
multiBuffer( 1, string.byte('T') )
|
||||
multiBuffer( 2, string.byte('R') )
|
||||
multiBuffer( 3, i2cId ) -- Monitor this teemetry data
|
||||
multiBuffer( 4, 0 ) -- Allow to get Data
|
||||
end
|
||||
|
||||
local function closeTelemetryRaw()
|
||||
multiBuffer(0, 0) -- Destroy the STR header
|
||||
multiBuffer(3, 0) -- Not requesting any Telementry ID
|
||||
end
|
||||
|
||||
local lineText = {nil}
|
||||
local I2C_TEXT_GEN = 0x0C
|
||||
local function drawTextGen(event)
|
||||
if (multiBuffer(0)~=string.byte('S')) then -- First time run???
|
||||
openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN
|
||||
lineText = {nil}
|
||||
end
|
||||
|
||||
-- Proces TEXT GEN Telementry message
|
||||
if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received
|
||||
local instanceNo = multiBuffer( 5 )
|
||||
local lineNo = multiBuffer( 6 )
|
||||
|
||||
local line = ""
|
||||
for i=0,13 do
|
||||
line = line .. string.char(multiBuffer( 7 + i ))
|
||||
end
|
||||
|
||||
multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message
|
||||
lineText[lineNo]=line
|
||||
end
|
||||
|
||||
lcd.clear()
|
||||
-- Header
|
||||
if (lineText[0]) then
|
||||
lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS)
|
||||
else
|
||||
lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS)
|
||||
end
|
||||
|
||||
-- Menu lines
|
||||
local y = Y_DATA
|
||||
for i=1,8 do
|
||||
if (lineText[i]) then
|
||||
lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data
|
||||
closeTelemetryRaw()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local telPage = 1
|
||||
local telPageSelected = 0
|
||||
local pageTitle = {[0]="Main", "AS3X Settings", "SAFE Settings", "ESC Status", "Battery Status","TextGen","Flight Log"}
|
||||
|
||||
local function drawMainScreen(event)
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (Smart RXs)", TEXT_SIZE + INVERS)
|
||||
|
||||
for iParam=1,#pageTitle do
|
||||
-- highlight selected parameter
|
||||
local attr = (telPage==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = pageTitle[iParam]
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
if (telPage>1) then telPage = telPage - 1 end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
if (telPage<#pageTitle) then telPage = telPage + 1 end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
telPageSelected = telPage
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local pageDraw = {[0]=drawMainScreen, drawAS3XSettingsP1, drawAS3XSettingsP2, drawESCStatus, drawBATStatus, drawTextGen, drawFlightLogScreen}
|
||||
|
||||
local function run_func(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
end
|
||||
|
||||
-- draw specific page
|
||||
pageDraw[telPageSelected](event)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if (telPageSelected==0) then return 1 end -- on Main?? Exit Script
|
||||
telPageSelected = 0 -- any page, return to Main
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function init_func()
|
||||
|
||||
if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens
|
||||
TEXT_SIZE = SMLSIZE
|
||||
X_COL1_HEADER = 0
|
||||
X_COL1_DATA = 20
|
||||
|
||||
X_COL2_HEADER = 60
|
||||
X_COL2_DATA = 90
|
||||
|
||||
X_DATA_LEN = 28
|
||||
X_DATA_SPACE = 1
|
||||
|
||||
|
||||
Y_LINE_HEIGHT = 8
|
||||
Y_DATA = Y_HEADER + Y_LINE_HEIGHT
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return { run=run_func, init=init_func }
|
@ -35,6 +35,7 @@
|
||||
6,3,DSM,X_2F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,5,DSM,R_1F,0,AUX3,AUX4,AUX5
|
||||
6,6,DSM,2SFC,0
|
||||
70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
70,1,DSM_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
|
||||
@ -53,10 +54,9 @@
|
||||
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,6,Flysky_AFHDS2A,PWM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,7,Flysky_AFHDS2A,PPM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,4,Flysky_AFHDS2A,Gyro_Off,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,ST_Ga,TH_Ga,Prio,Calib
|
||||
28,5,Flysky_AFHDS2A,Gyro_On,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,ST_Ga,TH_Ga,Prio,Calib
|
||||
28,6,Flysky_AFHDS2A,G_On_Rev,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,ST_Ga,TH_Ga,Prio,Calib
|
||||
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
56,1,Flysky2A_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
53,0,Height,5ch,0,Gear
|
||||
@ -86,7 +86,11 @@
|
||||
55,1,FrSkyRX,CloneTX,0
|
||||
55,2,FrSkyRX,EraseTX,0
|
||||
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
58,0,FX816,Std,1
|
||||
58,0,FX,816,1
|
||||
58,1,FX,620,1
|
||||
58,2,FX,9630,1,Rate,Gyro,TrimR,TrimA,TrimE
|
||||
58,3,FX,Q560,1,FLIP,Gyro,LEDs
|
||||
58,4,FX,QF012,1,FLIP,Gyro,Invert,Reset
|
||||
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
||||
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
|
||||
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
|
||||
@ -106,6 +110,7 @@
|
||||
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,4,Hontai,XKK170,1,Rate,Emerg,TakLan,Calib,TrimA,TrimE
|
||||
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
|
||||
@ -116,9 +121,11 @@
|
||||
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
49,0,KF606,KF606,1,Trim
|
||||
49,1,KF606,MIG320,1,Trim,LED
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
49,2,KF606,ZCZ50,1,Trim,UNK
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim,Rtrim,Hover
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim,Rtrim,Hover
|
||||
73,0,Kyosho,FHSS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
73,1,Kyosho,Hype,0,CH5,CH6
|
||||
18,0,MJXQ,WHL08,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
@ -126,14 +133,16 @@
|
||||
18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess
|
||||
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess
|
||||
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
|
||||
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
|
||||
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
|
||||
17,5,MT99XX,A180,0,3D_6G
|
||||
17,6,MT99XX,Dragon,0,Mode,RTH
|
||||
17,7,MT99XX,F949G,0,6G_3D,Light
|
||||
17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess,Atrim,Etrim
|
||||
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess,Atrim,Etrim
|
||||
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess,Atrim,Etrim
|
||||
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess,Atrim,Etrim
|
||||
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess,Atrim,Etrim
|
||||
17,5,MT99XX,A180,0,3D_6G,Rate,3D_6G,n-a,n-a,Atrim,Etrim
|
||||
17,6,MT99XX,Dragon,0,Mode,RTH,n-a,n-a,n-a,Atrim,Etrim
|
||||
17,7,MT99XX,F949G,0,6G_3D,Light,Rates,Unk1,Unk2,Atrim,Etrim
|
||||
92,0,MT99xx2,PA18,0,MODE,FLIP,RTH,n-a,n-a,Atrim,Etrim
|
||||
92,1,MT99xx2,SU35,0,Mode,LED,LED_FH,Invert,Rate,Atrim,Etrim
|
||||
44,0,NCC1701,Std,1,Warp
|
||||
77,0,OMP,M2,0,THold,IdleUp,6G_3D
|
||||
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
||||
@ -152,7 +161,8 @@
|
||||
74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
74,2,RadioLink,DumboRC,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,UNK
|
||||
74,3,RadioLink,RC4G,0,CH5,FS_CH1,FS_CH2,FS_CH3,FS_CH4
|
||||
76,0,Realacc,Std,1,Flip,Light,Calib,HLess,RTH,ThCut,Rotat
|
||||
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
21,0,Futaba,SFHSS,0,CH5,CH6,CH7,CH8
|
||||
@ -163,14 +173,17 @@
|
||||
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
|
||||
11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib
|
||||
11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict
|
||||
11,5,SLT,V1_4CH,0
|
||||
11,6,SLT,RF_SIM,0,CH5,CH6,CH7,CH8,CH9,CH10
|
||||
10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
|
||||
10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess
|
||||
61,0,Tiger,Std,1,Flip,Light
|
||||
43,0,Traxxas,6519,0
|
||||
43,0,Traxxas,TQ2,0
|
||||
43,1,Traxxas,TQ1,0
|
||||
5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY
|
||||
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
|
||||
48,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
48,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn,Beep
|
||||
48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn,Beep
|
||||
48,2,V761,TOPRC,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
46,0,V911s,V911s,1,Calib,Rate
|
||||
46,1,V911s,E119,1,Calib,Rate,6G_3D
|
||||
22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
|
||||
@ -181,7 +194,10 @@
|
||||
30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
|
||||
30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
|
||||
62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
|
||||
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
|
||||
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video,Flip,Light
|
||||
62,2,XK,Cars,0,FMode,TakeOf,Emerg,3D_6G,Pict,Video,Flip,Light
|
||||
99,0,XK2,X4,0,Rate,Mode,Hover,Light
|
||||
99,1,XK2,P10,0,Rate,Mode,Hover,Light
|
||||
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
|
||||
8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess
|
||||
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
|
||||
@ -194,12 +210,28 @@
|
||||
81,0,E010r5,E010r5,1,Flip,LED,CALIB,HLess,RTH,GLIDE
|
||||
82,0,LOLI,Std,0,CH5,CH6,CH7,CH8,1SwSePpPw,2SwSePw,3SwSe,4SwSe,5SwSeSb,6SwSe,7SwSePw,8SwSe
|
||||
83,0,E129,E129,1,TakLan,EmStop,TrimA,TrimE,TrimR
|
||||
83,1,E129,C186,1,TakLan,EmStop,TrimA,TrimE,TrimR
|
||||
83,1,E129,C186,1,TakLan,EmStop,TrimA,TrimE,TrimR,Loop,Flip,Debug
|
||||
84,0,JOYSWAY,Std,0
|
||||
85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH
|
||||
87,0,IKEA
|
||||
89,0,LOSI
|
||||
90,0,MouldKg,Analog,0
|
||||
90,1,MouldKg,Digit,0
|
||||
90,0,MouldKg,A4444,0
|
||||
90,1,MouldKg,D4444,0
|
||||
90,2,MouldKg,A664,0
|
||||
91,0,Xerall,Tank,0,FlTa,TakLan,Rate,HLess,Photo,Video,TrimR,TrimE,TrimA
|
||||
92,0,MT99xx2,PA18,0,MODE,FLIP,RTH
|
||||
93,0,Kyosho2,KT-17,0
|
||||
94,0,Scorpio
|
||||
95,0,Bluefly,HP100,0,CH5,CH6,CH7,CH8
|
||||
96,0,BumbleB
|
||||
97,0,SGF22,F22,1,Mode,Flip,LED,Pict,Video,TrRes,Bal,HiBal
|
||||
97,1,SGF22,F22S,1,Mode,Flip,LED,Pict,Video,TrRes
|
||||
97,2,SGF22,J20,1,Mode,Flip,LED,Pict,Video
|
||||
61,0,EazyRC
|
||||
98,0,Kyosho3,ASF,0
|
||||
100,0,YuXiang,Std,0,Lock,Rate,Land,Manual,Flip,Mode,Pitch
|
||||
102,0,JIABAILE,Std,0,Speed,Light,Flash
|
||||
102,1,JIABAILE,Gyro,0,Speed,Light,Flash,ST_Tr
|
||||
103,0,H36,Std,1,Flip,HLess,RTH
|
||||
104,0,KAMTOM,Std,0,ST_Tr,TH_Tr,TH_DR
|
||||
105,0,Shenqi2,Std,1
|
||||
106,0,WL91x,Std,0
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -58,17 +58,11 @@ This is the Graupner HoTT adapted version of the Model Locator script using RSSI
|
||||
|
||||
The OpenTX sensor "RSSI" is populated by the individual OpenTX telemetry protocol implementations and returns a value from 0..100 (percent) originating from the early FrSky implementation. It turns out that FrSky did not really provide a genuine signal strength indicator in units of dbm but a link quality indicator in 0..100%. With Graupner HoTT the link quality indicator is not a good basis for the model locator as it is very non-linear and doesn't change much with distance. Using the Graupner HoTT telemetry sensor "Rssi" which is a true signal strength indicator serves the purpose of locating a model much better as it varies much more with distance.
|
||||
|
||||
## DSM Forward Programming
|
||||
## DSM Tools for EdgeTX and OpenTx
|
||||
|
||||
Navigation is mainly done using the scroll wheel and ENT. Short press on ENT will edit a value. When editing a value a long ENT press will restore the value to its default. To exit the script and terminate all current operations correctly short press RTN (if you don't do this the RX might not store the changes).
|
||||
Collection of EdgeTx/OpenTX Tools to use with Spektrum Receivers including forward programming. Located on the radio SD card under \SCRIPTS\TOOLS, make sure to copy the DSMLIB folder!
|
||||
|
||||
This is a work in progress. It's only available for color screens (Horus, TX16S, T16, T18...).
|
||||
|
||||
If some text appears as Unknown_xxx, please report xxx and what the exact text display should be.
|
||||
|
||||
Need OpenTX 2.3.10 nightly or above. Located on the radio SD card under \SCRIPTS\TOOLS.
|
||||
|
||||
[](https://www.youtube.com/watch?v=sjIaDw5j9nE)
|
||||
Frank is maintaining these awesome tools, check out his [repository](https://github.com/frankiearzu/DSMTools). Feel free to ask questions or open issues there.
|
||||
|
||||
## DSM PID Flight log gain parameters for Blade micros
|
||||
|
||||
|
@ -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);
|
||||
|
@ -183,8 +183,18 @@ uint16_t AFHDS2A_RX_callback()
|
||||
case AFHDS2A_RX_DATA:
|
||||
if (AFHDS2A_RX_data_ready()) {
|
||||
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
|
||||
if (memcmp(&packet[1], rx_id, 4) == 0 && memcmp(&packet[5], rx_tx_addr, 4) == 0) {
|
||||
if (packet[0] == 0x58 && packet[37] == 0x00 && (telemetry_link&0x7F) == 0) { // standard packet, send channels to TX
|
||||
if (memcmp(&packet[1], rx_id, 4) == 0 && memcmp(&packet[5], rx_tx_addr, 4) == 0)
|
||||
{
|
||||
#if 0
|
||||
//if(packet[0] == 0xAA)
|
||||
{
|
||||
for(uint8_t i=0;i<AFHDS2A_RX_TXPACKET_SIZE;i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");
|
||||
}
|
||||
#endif
|
||||
if (packet[0] == 0x58 && packet[37] == 0x00 && (telemetry_link&0x7F) == 0)
|
||||
{ // standard packet, send channels to TX
|
||||
int rssi = min(A7105_ReadReg(A7105_1D_RSSI_THOLD),160);
|
||||
RX_RSSI = map16b(rssi, 160, 8, 0, 128);
|
||||
AFHDS2A_RX_build_telemetry_packet();
|
||||
|
@ -93,15 +93,16 @@ static void AFHDS2A_update_telemetry()
|
||||
if (option & 0x80)
|
||||
{// forward 0xAA and 0xAC telemetry to TX, skip rx and tx id to save space
|
||||
packet_in[0]= TX_RSSI;
|
||||
debug("T(%02X)=",packet[0]);
|
||||
#if 0
|
||||
debug("T(%02X)=",packet[0]);
|
||||
for(uint8_t i=9;i < AFHDS2A_RXPACKET_SIZE; i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
for(uint8_t i=9;i < AFHDS2A_RXPACKET_SIZE; i++)
|
||||
{
|
||||
packet_in[i-8]=packet[i];
|
||||
debug(" %02X",packet[i]);
|
||||
}
|
||||
packet_in[29]=packet[0]; // 0xAA Normal telemetry, 0xAC Extended telemetry
|
||||
telemetry_link=2;
|
||||
debugln("");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -186,16 +187,40 @@ static void AFHDS2A_build_packet(uint8_t type)
|
||||
case AFHDS2A_PACKET_STICKS:
|
||||
packet[0] = 0x58;
|
||||
//16 channels + RX_LQI on channel 17
|
||||
for(uint8_t ch=0; ch<num_ch; ch++)
|
||||
for(uint8_t ch=0; ch<17; ch++)
|
||||
{
|
||||
if(ch == 16 // CH17=RX_LQI
|
||||
#ifdef AFHDS2A_LQI_CH
|
||||
|| ch == (AFHDS2A_LQI_CH-1) // override channel with LQI
|
||||
#endif
|
||||
)
|
||||
val = 2000 - 10*RX_LQI;
|
||||
val = convert_channel_ppm(sub_protocol<AFHDS2A_GYRO_OFF?CH_AETR[ch]:ch); // No remapping for BS receivers
|
||||
if(ch<14)
|
||||
{
|
||||
packet[9 + ch*2] = val;
|
||||
packet[10 + ch*2] = (val>>8)&0x0F;
|
||||
}
|
||||
else
|
||||
val = convert_channel_ppm(CH_AETR[ch]);
|
||||
{
|
||||
if(ch == 16) //CH17=RX_LQI
|
||||
val = 2000 - 10*RX_LQI;
|
||||
packet[10 + (ch-14)*6] |= (val)<<4;
|
||||
packet[12 + (ch-14)*6] |= (val)&0xF0;
|
||||
packet[14 + (ch-14)*6] |= (val>>4)&0xF0;
|
||||
}
|
||||
}
|
||||
{
|
||||
uint8_t next_hop = (hopping_frequency_no+1)&0x0F;
|
||||
packet[34] |= next_hop<<4;
|
||||
packet[36] |= next_hop?0x80:0x90;
|
||||
}
|
||||
break;
|
||||
case AFHDS2A_PACKET_FAILSAFE:
|
||||
packet[0] = 0x56;
|
||||
for(uint8_t ch=0; ch<16; ch++)
|
||||
{ // Failsafe values
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
val = Failsafe_data[protocol==PROTO_AFHDS2A?CH_AETR[ch]:ch]; // No remapping for BS receivers
|
||||
if(val!=FAILSAFE_CHANNEL_HOLD && val!=FAILSAFE_CHANNEL_NOPULSES)
|
||||
val = (((val<<2)+val)>>3)+860;
|
||||
else
|
||||
#endif
|
||||
val = 0x0FFF;
|
||||
if(ch<14)
|
||||
{
|
||||
packet[9 + ch*2] = val;
|
||||
@ -209,42 +234,6 @@ static void AFHDS2A_build_packet(uint8_t type)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AFHDS2A_PACKET_FAILSAFE:
|
||||
packet[0] = 0x56;
|
||||
for(uint8_t ch=0; ch<num_ch; ch++)
|
||||
{
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(ch<16)
|
||||
val = Failsafe_data[CH_AETR[ch]];
|
||||
else
|
||||
val = FAILSAFE_CHANNEL_NOPULSES;
|
||||
if(val!=FAILSAFE_CHANNEL_HOLD && val!=FAILSAFE_CHANNEL_NOPULSES)
|
||||
{ // Failsafe values
|
||||
val = (((val<<2)+val)>>3)+860;
|
||||
if(ch<14)
|
||||
{
|
||||
packet[9 + ch*2] = val;
|
||||
packet[10 + ch*2] = (val>>8)&0x0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[10 + (ch-14)*6] &= 0x0F;
|
||||
packet[10 + (ch-14)*6] |= (val)<<4;
|
||||
packet[12 + (ch-14)*6] &= 0x0F;
|
||||
packet[12 + (ch-14)*6] |= (val)&0xF0;
|
||||
packet[14 + (ch-14)*6] &= 0x0F;
|
||||
packet[14 + (ch-14)*6] |= (val>>4)&0xF0;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(ch<14)
|
||||
{ // no values
|
||||
packet[9 + ch*2] = 0xff;
|
||||
packet[10+ ch*2] = 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AFHDS2A_PACKET_SETTINGS:
|
||||
packet[0] = 0xaa;
|
||||
packet[9] = 0xfd;
|
||||
@ -253,17 +242,43 @@ static void AFHDS2A_build_packet(uint8_t type)
|
||||
if(val<50 || val>400) val=50; // default is 50Hz
|
||||
packet[11]= val;
|
||||
packet[12]= val >> 8;
|
||||
packet[13] = sub_protocol & 0x01; // 1 -> PPM output enabled
|
||||
packet[14]= 0x00;
|
||||
for(uint8_t i=15; i<37; i++)
|
||||
packet[i] = 0xff;
|
||||
packet[18] = 0x05; // ?
|
||||
packet[19] = 0xdc; // ?
|
||||
packet[20] = 0x05; // ?
|
||||
if(sub_protocol&2)
|
||||
packet[21] = 0xdd; // SBUS output enabled
|
||||
memset(&packet[15],0xFF,22);
|
||||
#ifndef MULTI_AIR
|
||||
if(sub_protocol < AFHDS2A_GYRO_OFF)
|
||||
{
|
||||
#endif
|
||||
packet[13] = sub_protocol & 0x01; // 1 -> PPM output enabled
|
||||
packet[14] = 0x00; // ?
|
||||
packet[18] = 0x05; // ?
|
||||
packet[19] = 0xdc; // ?
|
||||
packet[20] = 0x05; // ?
|
||||
if(sub_protocol&2)
|
||||
packet[21] = 0xdd; // SBUS output enabled
|
||||
else
|
||||
packet[21] = 0xde; // IBUS
|
||||
#ifndef MULTI_AIR
|
||||
}
|
||||
else
|
||||
packet[21] = 0xde; // IBUS
|
||||
{//BS receivers
|
||||
if(sub_protocol == AFHDS2A_GYRO_OFF)
|
||||
{
|
||||
memset(&packet[15],0x00,4);
|
||||
packet[22] = 0xFC; // ?
|
||||
}
|
||||
else
|
||||
{//AFHDS2A_GYRO_ON & AFHDS2A_GYRO_ON_REV
|
||||
packet[15] = convert_channel_16b_limit(CH13,0,100); // ST Gain
|
||||
packet[16] = convert_channel_16b_limit(CH14,0,100); // TH Gain
|
||||
packet[17] = convert_channel_16b_limit(CH15,0,100); // Priority
|
||||
if(sub_protocol == AFHDS2A_GYRO_ON_REV)
|
||||
packet[17] |= 0x80; // Reverse
|
||||
packet[18] = CH16_SW?(0x32|0x80):0x32; // Calib|50?
|
||||
packet[19] = 0x64; // 100?
|
||||
packet[20] = 0x64; // 100?
|
||||
packet[22] = 0xFE; // ?
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
packet[37] = 0x00;
|
||||
@ -283,6 +298,9 @@ uint16_t AFHDS2A_callback()
|
||||
static uint16_t packet_counter;
|
||||
uint8_t data_rx=0;
|
||||
uint16_t start;
|
||||
#ifndef MULTI_AIR
|
||||
static uint16_t Prev_Channel[4] = { 0,0,0,0 };
|
||||
#endif
|
||||
#ifndef FORCE_AFHDS2A_TUNING
|
||||
A7105_AdjustLOBaseFreq(1);
|
||||
#endif
|
||||
@ -292,10 +310,17 @@ uint16_t AFHDS2A_callback()
|
||||
case AFHDS2A_BIND2:
|
||||
case AFHDS2A_BIND3:
|
||||
AFHDS2A_build_bind_packet();
|
||||
data_rx=A7105_ReadReg(A7105_00_MODE); // Check if something has been received...
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, packet_count%2 ? 0x0d : 0x8c);
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5))) // removed FECF check due to issues with fs-x6b -> & (1<<5 | 1<<6)
|
||||
{ // CRCF Ok
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5)) && !(data_rx & 1)) // removed FECF check due to issues with fs-x6b -> & (1<<5 | 1<<6)
|
||||
{ // RX+CRCF Ok
|
||||
A7105_ReadData(AFHDS2A_RXPACKET_SIZE);
|
||||
#if 0
|
||||
debug("RX");
|
||||
for(uint8_t i=0; i<AFHDS2A_RXPACKET_SIZE ; i++)
|
||||
debug(" %02X", packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
if(packet[0] == 0xbc && packet[9] == 0x01)
|
||||
{
|
||||
uint16_t addr;
|
||||
@ -330,7 +355,7 @@ uint16_t AFHDS2A_callback()
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_SetPower();
|
||||
A7105_SetTxRxMode(TXRX_OFF); // Turn LNA off since we are in near range and we want to prevent swamping
|
||||
A7105_SetTxRxMode((packet_count & 0x40) ? TXRX_OFF : RX_EN); // Turn LNA off time to time since we are in near range and we want to prevent swamping
|
||||
A7105_Strobe(A7105_RX);
|
||||
phase &= ~AFHDS2A_WAIT_WRITE;
|
||||
phase++;
|
||||
@ -360,10 +385,39 @@ uint16_t AFHDS2A_callback()
|
||||
AFHDS2A_build_packet(packet_type);
|
||||
data_rx=A7105_ReadReg(A7105_00_MODE); // Check if something has been received...
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, hopping_frequency[hopping_frequency_no++]);
|
||||
if(hopping_frequency_no >= AFHDS2A_NUMFREQ)
|
||||
hopping_frequency_no = 0;
|
||||
hopping_frequency_no &= 0x0F; // AFHDS2A_NUMFREQ
|
||||
#if 0
|
||||
for(uint8_t i=0; i<AFHDS2A_TXPACKET_SIZE; i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
#ifndef MULTI_AIR
|
||||
if(sub_protocol > AFHDS2A_GYRO_OFF)
|
||||
{//Gyro is on
|
||||
//Check if gyro settings have changed
|
||||
uint16_t val;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
{
|
||||
val = Channel_data[CH13+i] - Prev_Channel[i];
|
||||
if(val&0x8000) val ^= 0xFFFF;
|
||||
if(val > 10)
|
||||
{//This setting has significantly changed
|
||||
Prev_Channel[i] = Channel_data[CH13+i];
|
||||
packet_sent = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(packet_sent && (packet_counter%5)==0)
|
||||
{//Inform the RX of the change
|
||||
packet_type = AFHDS2A_PACKET_SETTINGS;
|
||||
packet_sent--;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(!(packet_counter % 1313))
|
||||
{//Send settings every 5s
|
||||
packet_type = AFHDS2A_PACKET_SETTINGS;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
@ -441,9 +495,6 @@ void AFHDS2A_init()
|
||||
rx_id[i]=eeprom_read_byte((EE_ADDR)(addr+i));
|
||||
}
|
||||
hopping_frequency_no = 0;
|
||||
if(sub_protocol&0x04)
|
||||
num_ch=17;
|
||||
else
|
||||
num_ch=14;
|
||||
packet_sent = 0;
|
||||
}
|
||||
#endif
|
||||
|
196
Multiprotocol/BUMBLEB_ccnrf.ino
Normal 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
|
118
Multiprotocol/Bluefly_ccnrf.ino
Normal 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
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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++;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -18,14 +18,21 @@
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
//#define DSM_DEBUG_FWD_PGM
|
||||
//#define DEBUG_BIND 1
|
||||
|
||||
//#define DSM_GR300
|
||||
#define CLONE_BIT_MASK 0x20
|
||||
#define DSM_BIND_CHANNEL 0x0D //13 This can be any odd channel
|
||||
#define DSM2_SFC_PERIOD 16500
|
||||
|
||||
#define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel
|
||||
|
||||
//During binding we will send BIND_COUNT/2 packets
|
||||
//During binding we will send BIND_COUNT packets
|
||||
//One packet each 10msec
|
||||
#define DSM_BIND_COUNT 300
|
||||
//
|
||||
// Most RXs seems to work properly with a long BIND send count (3s): Spektrum, OrangeRX.
|
||||
// Lemon-RX G2s seems to have a timeout waiting for the channel to get quiet after the
|
||||
// first good BIND packet.. If using 3s (300), Lemon-RX will not transmit the BIND-Response packet.
|
||||
|
||||
#define DSM_BIND_COUNT 180 // About 1.8s
|
||||
#define DSM_BIND_COUNT_READ 600 // About 4.2s of waiting for Response
|
||||
|
||||
enum {
|
||||
DSM_BIND_WRITE=0,
|
||||
@ -87,9 +94,12 @@ static void __attribute__((unused)) DSM_build_bind_packet()
|
||||
packet[11] = 12;
|
||||
else
|
||||
packet[11] = num_ch; // DX5 DSMR sends 0x48...
|
||||
//packet[11] = 3; // DX3R
|
||||
|
||||
if (sub_protocol==DSMR)
|
||||
packet[12] = 0xa2;
|
||||
else if (sub_protocol==DSM2_SFC)
|
||||
packet[12] = 0x23; // DX3R
|
||||
else if (sub_protocol==DSM2_1F)
|
||||
packet[12] = num_ch<8?0x01:0x02; // DSM2/1024 1 or 2 packets depending on the number of channels
|
||||
else if(sub_protocol==DSM2_2F)
|
||||
@ -102,7 +112,6 @@ static void __attribute__((unused)) DSM_build_bind_packet()
|
||||
#endif
|
||||
else // DSMX_2F && DSM_AUTO
|
||||
packet[12] = 0xb2; // DSMX/2048 2 packets
|
||||
|
||||
|
||||
packet[13] = 0x00; //???
|
||||
for(i = 8; i < 14; i++)
|
||||
@ -116,8 +125,8 @@ static void __attribute__((unused)) DSM_initialize_bind_phase()
|
||||
CYRF_ConfigRFChannel(DSM_BIND_CHANNEL); //This seems to be random?
|
||||
//64 SDR Mode is configured so only the 8 first values are needed but need to write 16 values...
|
||||
uint8_t code[16];
|
||||
DSM_read_code(code,0,8,8);
|
||||
CYRF_ConfigDataCode(code, 16);
|
||||
DSM_read_code(code,0,8);
|
||||
CYRF_ConfigDataCode(code);
|
||||
DSM_build_bind_packet();
|
||||
}
|
||||
|
||||
@ -129,8 +138,13 @@ static void __attribute__((unused)) DSM_update_channels()
|
||||
if(num_ch<3 || num_ch>12)
|
||||
num_ch=6; // Default to 6 channels if invalid choice...
|
||||
|
||||
if(sub_protocol==DSMR && num_ch>7)
|
||||
num_ch=7; // Max 7 channels in DSMR
|
||||
#ifndef MULTI_AIR
|
||||
if(sub_protocol==DSMR && num_ch>7)
|
||||
num_ch=7; // Max 7 channels in DSMR
|
||||
|
||||
if(sub_protocol==DSM2_SFC && num_ch>5)
|
||||
num_ch=5; // Max 5 channels in DSM2_SFC
|
||||
#endif
|
||||
|
||||
// Create channel map based on number of channels and refresh rate
|
||||
uint8_t idx=num_ch-3;
|
||||
@ -143,7 +157,13 @@ static void __attribute__((unused)) DSM_update_channels()
|
||||
static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
|
||||
{
|
||||
uint8_t bits = 11;
|
||||
|
||||
|
||||
// Check if clone flag has changed
|
||||
if((prev_option&CLONE_BIT_MASK) != (option&CLONE_BIT_MASK))
|
||||
{
|
||||
DSM_init();
|
||||
prev_option^=CLONE_BIT_MASK;
|
||||
}
|
||||
if(prev_option!=option)
|
||||
DSM_update_channels();
|
||||
|
||||
@ -160,19 +180,25 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
|
||||
bits=10; // Only DSM2_1F is using a resolution of 1024
|
||||
}
|
||||
|
||||
if(sub_protocol == DSMR)
|
||||
{
|
||||
for (uint8_t i = 0; i < 7; i++)
|
||||
{
|
||||
uint16_t value = 0x0000;
|
||||
if(i < num_ch)
|
||||
value=Channel_data[i]<<1;
|
||||
packet[i*2+2] = (value >> 8) & 0xff;
|
||||
packet[i*2+3] = (value >> 0) & 0xff;
|
||||
#ifndef MULTI_AIR
|
||||
if(sub_protocol == DSMR || sub_protocol == DSM2_SFC)
|
||||
{ // 12 bits, full range, no reassignment
|
||||
for (uint8_t i = 0; i < 7; i++)
|
||||
{
|
||||
uint16_t value = 0x0000;
|
||||
if(i < num_ch)
|
||||
{
|
||||
value=Channel_data[i]<<1;
|
||||
if(sub_protocol == DSM2_SFC)
|
||||
value |= i<<12;
|
||||
}
|
||||
packet[i*2+2] = (value >> 8) & 0xff;
|
||||
packet[i*2+3] = (value >> 0) & 0xff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DSM_THROTTLE_KILL_CH
|
||||
uint16_t kill_ch=Channel_data[DSM_THROTTLE_KILL_CH-1];
|
||||
#endif
|
||||
@ -249,24 +275,34 @@ static uint8_t __attribute__((unused)) DSM_Check_RX_packet()
|
||||
|
||||
uint16_t DSM_callback()
|
||||
{
|
||||
#if defined MULTI_EU
|
||||
if(sub_protocol == DSM2_1F || sub_protocol == DSM2_2F || sub_protocol == DSM2_SFC)
|
||||
{
|
||||
SUB_PROTO_INVALID;
|
||||
return 11000;
|
||||
}
|
||||
#endif
|
||||
#if defined MULTI_AIR
|
||||
if(sub_protocol == DSMR || sub_protocol == DSM2_SFC)
|
||||
{
|
||||
SUB_PROTO_INVALID;
|
||||
return 11000;
|
||||
}
|
||||
#endif
|
||||
#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
|
||||
#ifdef STM32_BOARD
|
||||
#define DSM_WRITE_DELAY 1600 // Time after write to verify write complete
|
||||
#define DSM_READ_DELAY 300 // Time before write to check read phase, and switch channels.
|
||||
#else
|
||||
#define DSM_WRITE_DELAY 1950 // Time after write to verify write complete
|
||||
#define DSM_READ_DELAY 600 // Time before write to check read phase, and switch channels.
|
||||
#endif
|
||||
#define DSM_READ_DELAY 600 // Time before write to check read phase, and switch channels. Was 400 but 600 seems what the 328p needs to read a packet
|
||||
#if defined DSM_TELEMETRY
|
||||
uint8_t rx_phase;
|
||||
uint8_t len;
|
||||
uint8_t length;
|
||||
#endif
|
||||
uint8_t start;
|
||||
|
||||
#ifdef DSM_GR300
|
||||
uint16_t timing=5000+(convert_channel_8b(CH13)*100);
|
||||
debugln("T=%u",timing);
|
||||
#endif
|
||||
|
||||
//debugln("P=%d",phase);
|
||||
switch(phase)
|
||||
{
|
||||
case DSM_BIND_WRITE:
|
||||
@ -280,11 +316,14 @@ uint16_t DSM_callback()
|
||||
return 10000;
|
||||
#if defined DSM_TELEMETRY
|
||||
case DSM_BIND_CHECK:
|
||||
//64 SDR Mode is configured so only the 8 first values are needed but we need to write 16 values...
|
||||
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84", 16);
|
||||
#if DEBUG_BIND
|
||||
debugln("Bind Check");
|
||||
#endif
|
||||
//64 SDR Mode is configured so only the 8 first values are needed
|
||||
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84");
|
||||
CYRF_SetTxRxMode(RX_EN); //Receive mode
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //Prepare to receive
|
||||
bind_counter=2*DSM_BIND_COUNT; //Timeout of 4.2s if no packet received
|
||||
bind_counter=DSM_BIND_COUNT_READ; //Timeout of 4.2s if no packet received
|
||||
phase++; // change from BIND_CHECK to BIND_READ
|
||||
return 2000;
|
||||
case DSM_BIND_READ:
|
||||
@ -300,10 +339,12 @@ uint16_t DSM_callback()
|
||||
CYRF_ReadDataPacketLen(packet_in+1, 10);
|
||||
if(DSM_Check_RX_packet())
|
||||
{
|
||||
debug("Bind");
|
||||
for(uint8_t i=0;i<10;i++)
|
||||
debug(" %02X",packet_in[i+1]);
|
||||
debugln("");
|
||||
#if DEBUG_BIND
|
||||
debug("Bind");
|
||||
for(uint8_t i=0;i<10;i++)
|
||||
debug(" %02X",packet_in[i+1]);
|
||||
debugln("");
|
||||
#endif
|
||||
packet_in[0]=0x80;
|
||||
packet_in[6]&=0x0F; // It looks like there is a flag 0x40 being added by some receivers
|
||||
if(packet_in[6]>12) packet_in[6]=12;
|
||||
@ -328,6 +369,9 @@ uint16_t DSM_callback()
|
||||
}
|
||||
if( --bind_counter == 0 )
|
||||
{ // Exit if no answer has been received for some time
|
||||
#if DEBUG_BIND
|
||||
debugln("Bind Read TIMEOUT");
|
||||
#endif
|
||||
phase++; // DSM_CHANSEL
|
||||
return 7000 ;
|
||||
}
|
||||
@ -339,25 +383,38 @@ uint16_t DSM_callback()
|
||||
CYRF_SetTxRxMode(TX_EN);
|
||||
hopping_frequency_no = 0;
|
||||
phase = DSM_CH1_WRITE_A; // in fact phase++
|
||||
#ifndef MULTI_AIR
|
||||
if(sub_protocol == DSMR)
|
||||
DSM_set_sop_data_crc(false, true);
|
||||
else
|
||||
#endif
|
||||
DSM_set_sop_data_crc(true, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F); //prep CH1
|
||||
return 10000;
|
||||
case DSM_CH1_WRITE_A:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(11000); // Always request 11ms spacing even if we don't use half of it in 22ms mode
|
||||
if(sub_protocol!=DSM2_SFC || option&0x40) // option&40 in this case is 16.5ms/11ms frame rate for DSM2_SFC
|
||||
telemetry_set_input_sync(11000); // Always request 11ms spacing even if we don't use half of it in 22ms mode
|
||||
else
|
||||
telemetry_set_input_sync(DSM2_SFC_PERIOD);
|
||||
#endif
|
||||
#ifndef MULTI_AIR
|
||||
if(sub_protocol == DSMR)
|
||||
CYRF_SetPower(0x08); //Keep transmit power in sync
|
||||
else
|
||||
#endif
|
||||
CYRF_SetPower(0x28); //Keep transmit power in sync
|
||||
case DSM_CH1_WRITE_B:
|
||||
DSM_build_data_packet(phase == DSM_CH1_WRITE_B); // build lower or upper channels
|
||||
case DSM_CH2_WRITE_A:
|
||||
case DSM_CH2_WRITE_B:
|
||||
CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags
|
||||
CYRF_WriteDataPacket(packet);
|
||||
//debugln_time("");
|
||||
#ifndef MULTI_AIR
|
||||
if(sub_protocol==DSM2_SFC)
|
||||
CYRF_WriteDataPacketLen(packet,2*(num_ch+1));
|
||||
else
|
||||
#endif
|
||||
CYRF_WriteDataPacket(packet);
|
||||
#if 0
|
||||
for(uint8_t i=0;i<16;i++)
|
||||
debug(" %02X", packet[i]);
|
||||
@ -394,41 +451,52 @@ uint16_t DSM_callback()
|
||||
phase++; // change from CH2_CHECK to CH2_READ
|
||||
CYRF_SetTxRxMode(RX_EN); //Receive mode
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
|
||||
if(sub_protocol==DSMR)
|
||||
{
|
||||
phase = DSM_CH2_READ_B;
|
||||
return 11000 - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
||||
}
|
||||
#ifdef DSM_GR300
|
||||
if(num_ch==3)
|
||||
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
||||
#ifndef MULTI_AIR
|
||||
if(sub_protocol==DSMR || sub_protocol == DSM2_SFC)
|
||||
{
|
||||
phase = DSM_CH2_READ_B;
|
||||
if(sub_protocol == DSM2_SFC)
|
||||
{
|
||||
if(option&0x40) // option&40 in this case is 16.5ms/11ms frame rate for DSM2_SFC
|
||||
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
||||
else
|
||||
return DSM2_SFC_PERIOD - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
||||
}
|
||||
return 10900 - DSM_WRITE_DELAY - DSM_READ_DELAY; //Was 11000 but the SR6200A needs 10900 to report telemetry correctly
|
||||
}
|
||||
#endif
|
||||
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
||||
case DSM_CH2_READ_A:
|
||||
case DSM_CH2_READ_B:
|
||||
//Read telemetry
|
||||
rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
//debug("ST1:%02X ",rx_phase);
|
||||
if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
|
||||
rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||
//debug("ST2:%02X ",rx_phase);
|
||||
if((rx_phase & 0x07) == 0x02)
|
||||
{ // good data (complete with no errors)
|
||||
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
|
||||
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
||||
if(len>TELEMETRY_BUFFER_SIZE-2)
|
||||
len=TELEMETRY_BUFFER_SIZE-2;
|
||||
CYRF_ReadDataPacketLen(packet_in+1, len);
|
||||
length=CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
||||
//debug("RX(%d)",length);
|
||||
if(length>TELEMETRY_BUFFER_SIZE-2)
|
||||
length=TELEMETRY_BUFFER_SIZE-2;
|
||||
CYRF_ReadDataPacketLen(packet_in+1, length);
|
||||
#ifdef DSM_DEBUG_FWD_PGM
|
||||
//debug(" %02X", packet_in[1]);
|
||||
if(packet_in[1]==9)
|
||||
{
|
||||
for(uint8_t i=0;i<len;i++)
|
||||
for(uint8_t i=0;i<length;i++)
|
||||
debug(" %02X", packet_in[i+1]);
|
||||
debugln("");
|
||||
}
|
||||
#endif
|
||||
packet_in[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;// store RSSI of the received telemetry signal
|
||||
//for(uint8_t i=0;i<length+1;i++)
|
||||
// debug(" %02X", packet_in[i]);
|
||||
telemetry_link=1;
|
||||
}
|
||||
//debugln("");
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||
if (phase == DSM_CH2_READ_A && (sub_protocol==DSM2_1F || sub_protocol==DSMX_1F) && num_ch < 8) // 22ms mode
|
||||
{
|
||||
@ -436,10 +504,6 @@ uint16_t DSM_callback()
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
|
||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
|
||||
phase = DSM_CH2_READ_B;
|
||||
#ifdef DSM_GR300
|
||||
if(num_ch==3)
|
||||
return timing;
|
||||
#endif
|
||||
return 11000;
|
||||
}
|
||||
if (phase == DSM_CH2_READ_A)
|
||||
@ -460,19 +524,20 @@ uint16_t DSM_callback()
|
||||
else
|
||||
{ //Normal mode 22ms
|
||||
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
|
||||
#ifdef DSM_GR300
|
||||
if(num_ch==3)
|
||||
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
||||
#ifndef MULTI_AIR
|
||||
if(sub_protocol==DSM2_SFC)
|
||||
{
|
||||
if(option&0x40) // option&40 in this case is 16.5ms/11ms frame rate for DSM2_SFC
|
||||
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
||||
else
|
||||
return DSM2_SFC_PERIOD - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
||||
}
|
||||
#endif
|
||||
return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
||||
}
|
||||
}
|
||||
else
|
||||
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower)
|
||||
#ifdef DSM_GR300
|
||||
if(num_ch==3)
|
||||
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
||||
#endif
|
||||
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY;
|
||||
#endif
|
||||
}
|
||||
@ -480,6 +545,7 @@ uint16_t DSM_callback()
|
||||
}
|
||||
|
||||
|
||||
#ifndef MULTI_AIR
|
||||
const uint8_t PROGMEM DSMR_ID_FREQ[][4 + 23] = {
|
||||
{ 0x71, 0x74, 0x1c, 0xe4, 0x11, 0x2f, 0x17, 0x3d, 0x23, 0x3b, 0x0f, 0x21, 0x25, 0x49, 0x1d, 0x13, 0x4d, 0x1f, 0x41, 0x4b, 0x47, 0x05, 0x27, 0x15, 0x19, 0x3f, 0x07 },
|
||||
{ 0xfe, 0xfe, 0xfe, 0xfe, 0x45, 0x31, 0x33, 0x4b, 0x11, 0x29, 0x49, 0x3f, 0x09, 0x13, 0x47, 0x21, 0x1d, 0x43, 0x1f, 0x05, 0x41, 0x19, 0x1b, 0x2d, 0x15, 0x4d, 0x0f },
|
||||
@ -503,32 +569,73 @@ const uint8_t PROGMEM DSMR_ID_FREQ[][4 + 23] = {
|
||||
{ 0xff, 0xff, 0x00, 0x00, 0x2b, 0x35, 0x1b, 0x1d, 0x0f, 0x47, 0x09, 0x0d, 0x45, 0x41, 0x21, 0x11, 0x2f, 0x43, 0x27, 0x33, 0x4b, 0x37, 0x13, 0x19, 0x4d, 0x23, 0x17 },
|
||||
{ 0x00, 0xff, 0x00, 0x00, 0x1b, 0x1d, 0x33, 0x13, 0x2b, 0x27, 0x09, 0x41, 0x25, 0x17, 0x19, 0x2d, 0x4b, 0x37, 0x45, 0x11, 0x21, 0x0d, 0x3d, 0x4d, 0x07, 0x39, 0x43 },
|
||||
{ 0xff, 0x00, 0x00, 0x00, 0x37, 0x27, 0x43, 0x4b, 0x39, 0x13, 0x07, 0x0d, 0x25, 0x17, 0x29, 0x1b, 0x1d, 0x45, 0x19, 0x2d, 0x0b, 0x3d, 0x15, 0x47, 0x1f, 0x21, 0x4d } };
|
||||
#endif
|
||||
|
||||
void DSM_init()
|
||||
{
|
||||
if(sub_protocol == DSMR)
|
||||
{
|
||||
uint8_t row = rx_tx_addr[3]%22;
|
||||
for(uint8_t i=0; i< 4; i++)
|
||||
cyrfmfg_id[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i]);
|
||||
for(uint8_t i=0; i< 23; i++)
|
||||
hopping_frequency[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i+4]);
|
||||
#ifndef MULTI_AIR
|
||||
if(option&CLONE_BIT_MASK)
|
||||
SUB_PROTO_INVALID;
|
||||
else
|
||||
{
|
||||
//SUB_PROTO_VALID;
|
||||
uint8_t row = rx_tx_addr[3]%22;
|
||||
for(uint8_t i=0; i< 4; i++)
|
||||
cyrfmfg_id[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i]);
|
||||
for(uint8_t i=0; i< 23; i++)
|
||||
hopping_frequency[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i+4]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
CYRF_GetMfgData(cyrfmfg_id);
|
||||
//Model match
|
||||
cyrfmfg_id[3]^=RX_num;
|
||||
if(option&CLONE_BIT_MASK)
|
||||
{
|
||||
if(eeprom_read_byte((EE_ADDR)DSM_CLONE_EEPROM_OFFSET+4)==0xF0)
|
||||
{
|
||||
//read cloned ID from EEPROM
|
||||
uint16_t temp = DSM_CLONE_EEPROM_OFFSET;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
cyrfmfg_id[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||
#if DEBUG_BIND
|
||||
debugln("Using cloned ID");
|
||||
debug("Clone ID=")
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
debug("%02x ", cyrfmfg_id[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
SUB_PROTO_INVALID;
|
||||
#if DEBUG_BIND
|
||||
debugln("No valid cloned ID");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//SUB_PROTO_VALID;
|
||||
CYRF_GetMfgData(cyrfmfg_id);
|
||||
//Model match
|
||||
cyrfmfg_id[3]^=RX_num;
|
||||
}
|
||||
}
|
||||
|
||||
//Calc sop_col
|
||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
|
||||
|
||||
//Fix for OrangeRX using wrong DSM_pncodes by preventing access to "Col 8"
|
||||
if(sop_col==0 && sub_protocol != DSMR)
|
||||
{
|
||||
cyrfmfg_id[rx_tx_addr[0]%3]^=0x01; //Change a bit so sop_col will be different from 0
|
||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
|
||||
//We cannot manipulate the ID if we are cloning
|
||||
if(!(option&CLONE_BIT_MASK))
|
||||
{
|
||||
//Fix for OrangeRX using wrong DSM_pncodes by preventing access to "Col 8"
|
||||
if(sop_col==0 && sub_protocol != DSMR)
|
||||
{
|
||||
cyrfmfg_id[rx_tx_addr[0]%3]^=0x01; //Change a bit so sop_col will be different from 0
|
||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
|
||||
}
|
||||
}
|
||||
|
||||
//Calc CRC seed
|
||||
@ -540,7 +647,7 @@ void DSM_init()
|
||||
else if(sub_protocol != DSMR)
|
||||
{
|
||||
uint8_t tmpch[10];
|
||||
CYRF_FindBestChannels(tmpch, 10, 5, 3, 75);
|
||||
CYRF_FindBestChannels(tmpch, 10, 5, 3, 75, FIND_CHANNEL_ANY);
|
||||
//
|
||||
uint8_t idx = random(0xfefefefe) % 10;
|
||||
hopping_frequency[0] = tmpch[idx];
|
||||
@ -564,9 +671,12 @@ void DSM_init()
|
||||
DSM_initialize_bind_phase();
|
||||
phase = DSM_BIND_WRITE;
|
||||
bind_counter=DSM_BIND_COUNT;
|
||||
#if DEBUG_BIND
|
||||
debugln("Bind Started: write count=%d",bind_counter);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
phase = DSM_CHANSEL;//
|
||||
phase = DSM_CHANSEL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -41,7 +41,8 @@ static void __attribute__((unused)) E129_build_data_packet()
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[ 1] = 0xA6;
|
||||
packet[ 1] = 0xA6; // Set to A5 every few packets??
|
||||
|
||||
//Flags
|
||||
if(sub_protocol == E129_E129)
|
||||
packet[ 2] = 0xF7; // High rate 0xF7, low 0xF4
|
||||
@ -53,9 +54,18 @@ static void __attribute__((unused)) E129_build_data_packet()
|
||||
packet[15] = bit_reverse(rx_tx_addr[0]);
|
||||
packet[16] = bit_reverse(rx_tx_addr[1]);
|
||||
}
|
||||
//packet[ 3] = 0x00; // E129 Mode: short press=0x20->0x00->0x20->..., long press=0x10->0x30->0x10->... => C186 throttle trim is doing the same:up=short press and down=long press
|
||||
packet[ 4] = GET_FLAG(CH5_SW, 0x20) // Take off/Land 0x20
|
||||
| GET_FLAG(CH6_SW, 0x04); // Emergency stop 0x04
|
||||
packet[ 3] = GET_FLAG(CH10_SW, 0x40) // C159: loop flight 0x40
|
||||
| GET_FLAG(CH11_SW, 0x08); // C129V2: flip
|
||||
//Other flags seen in packet[3]
|
||||
// Flag 0x04 is set on some helis (C159/C190)
|
||||
// E129 Mode: short press=0x20->0x00->0x20->..., long press=0x10->0x30->0x10->... => C186 throttle trim is doing the same:up=short press and down=long press
|
||||
packet[ 4] = GET_FLAG(CH5_SW, 0x20) // Take off/Land 0x20
|
||||
| GET_FLAG(CH6_SW, 0x04) // Emergency stop 0x04
|
||||
| GET_FLAG(CH12_SW, 0x80); // C190: debug mode->remote THR trim down sets 0x80
|
||||
//Other flags seen in packet[4]
|
||||
// C190 remote LANDING sets 0x10
|
||||
// C190 remote THR trim down sets 0x80
|
||||
|
||||
//Channels and trims
|
||||
uint16_t val = convert_channel_10b(AILERON,false);
|
||||
uint8_t trim = convert_channel_8b(CH7) & 0xFC;
|
||||
@ -80,13 +90,11 @@ static void __attribute__((unused)) E129_build_data_packet()
|
||||
packet[12] = val; // channel (0x000...0x200...0x3FF)
|
||||
}
|
||||
//Check
|
||||
if(sub_protocol == E129_E129)
|
||||
packet[packet_length-2] = packet[0] + packet[1];
|
||||
else
|
||||
packet[packet_length-2] = 0x24 + packet[0] + (packet[1]&0x03); // ??
|
||||
for(uint8_t i=2;i<packet_length-2;i++)
|
||||
for(uint8_t i=0;i<packet_length-2;i++)
|
||||
packet[packet_length-2] += packet[i];
|
||||
|
||||
if(sub_protocol == E129_C186)
|
||||
packet[packet_length-2] -= 0x80;
|
||||
|
||||
RF2500_BuildPayload(packet);
|
||||
}
|
||||
|
||||
|
166
Multiprotocol/EazyRC_nrf24l01.ino
Normal 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
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Compatible with FEI XIONG P38 plane.
|
||||
|
||||
#if defined(FX816_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define FX816_INITIAL_WAIT 500
|
||||
#define FX816_PACKET_PERIOD 10000
|
||||
#define FX816_RF_BIND_CHANNEL 0x28 //40
|
||||
#define FX816_RF_NUM_CHANNELS 4
|
||||
#define FX816_PAYLOAD_SIZE 6
|
||||
#define FX816_BIND_COUNT 300 //3sec
|
||||
|
||||
static void __attribute__((unused)) FX816_send_packet()
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
packet[0] = 0x55;
|
||||
else
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
hopping_frequency_no%=FX816_RF_NUM_CHANNELS;
|
||||
packet[0] = 0xAA;
|
||||
}
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
uint8_t val=convert_channel_8b(AILERON);
|
||||
#define FX816_SWITCH 20
|
||||
if(val>127+FX816_SWITCH)
|
||||
packet[3] = 1;
|
||||
else if(val<127-FX816_SWITCH)
|
||||
packet[3] = 2;
|
||||
else
|
||||
packet[3] = 0;
|
||||
packet[4] = convert_channel_16b_limit(THROTTLE,0,100);
|
||||
val=0;
|
||||
for(uint8_t i=0;i<FX816_PAYLOAD_SIZE-1;i++)
|
||||
val+=packet[i];
|
||||
packet[5]=val;
|
||||
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, FX816_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX816_RF_init()
|
||||
{
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
|
||||
//XN297_HoppingCalib(FX816_RF_NUM_CHANNELS);
|
||||
XN297_RFChannel(FX816_RF_BIND_CHANNEL);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX816_initialize_txid()
|
||||
{
|
||||
//Only 8 IDs: the RX led does not indicate frame loss.
|
||||
//I didn't open the plane to find out if I could connect there so this is the best I came up with with few trial and errors...
|
||||
rx_tx_addr[0]=0x35+(rx_tx_addr[3]&0x07); //Original dump=0x35
|
||||
rx_tx_addr[1]=0x09; //Original dump=0x09
|
||||
memcpy(hopping_frequency,"\x09\x1B\x30\x42",FX816_RF_NUM_CHANNELS); //Original dump=9=0x09,27=0x1B,48=0x30,66=0x42
|
||||
for(uint8_t i=0;i<FX816_RF_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
|
||||
}
|
||||
|
||||
uint16_t FX816_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(FX816_PACKET_PERIOD);
|
||||
#endif
|
||||
if(bind_counter)
|
||||
if(--bind_counter==0)
|
||||
BIND_DONE;
|
||||
FX816_send_packet();
|
||||
return FX816_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
void FX816_init()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
FX816_initialize_txid();
|
||||
FX816_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter=FX816_BIND_COUNT;
|
||||
}
|
||||
|
||||
#endif
|
337
Multiprotocol/FX_nrf24l01.ino
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Compatible with FEI XIONG P38 plane.
|
||||
|
||||
#if defined(FX_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define FX_BIND_COUNT 300 //3sec
|
||||
#define FX_SWITCH 20
|
||||
#define FX_NUM_CHANNELS 4
|
||||
|
||||
#define FX816_PACKET_PERIOD 10000
|
||||
#define FX816_BIND_CHANNEL 40
|
||||
#define FX816_PAYLOAD_SIZE 6
|
||||
#define FX816_CH_OFFSET 3
|
||||
|
||||
#define FX620_PACKET_PERIOD 3250
|
||||
#define FX620_BIND_PACKET_PERIOD 4500
|
||||
#define FX620_BIND_CHANNEL 18
|
||||
#define FX620_PAYLOAD_SIZE 7
|
||||
#define FX620_CH_OFFSET 1
|
||||
|
||||
#define FX9630_PACKET_PERIOD 8124 //8156 on QIDI-560
|
||||
#define FX9630_BIND_CHANNEL 51
|
||||
#define FX9630_PAYLOAD_SIZE 8
|
||||
#define FX9630_NUM_CHANNELS 3
|
||||
#define FX9630_WRITE_TIME 500
|
||||
|
||||
#define FX_QF012_PACKET_PERIOD 12194
|
||||
#define FX_QF012_RX_PAYLOAD_SIZE 3
|
||||
|
||||
//#define FORCE_FX620_ID
|
||||
//#define FORCE_FX9630_ID
|
||||
//#define FORCE_QIDI_ID
|
||||
|
||||
enum
|
||||
{
|
||||
FX_DATA=0,
|
||||
FX_RX,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) FX_send_packet()
|
||||
{
|
||||
static uint8_t trim_ch = 0;
|
||||
|
||||
//Hopp
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
if(sub_protocol >= FX9630)
|
||||
{ // FX9630 & FX_Q560 & FX_QF012
|
||||
if (hopping_frequency_no >= FX9630_NUM_CHANNELS)
|
||||
{
|
||||
hopping_frequency_no = 0;
|
||||
if(sub_protocol == FX9630)
|
||||
{
|
||||
trim_ch++;
|
||||
trim_ch &= 3;
|
||||
}
|
||||
else // FX_Q560 & FX_QF012
|
||||
trim_ch = 0;
|
||||
}
|
||||
}
|
||||
else // FX816 & FX620
|
||||
{
|
||||
hopping_frequency_no &= 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
memset(packet,0x00,packet_length);
|
||||
|
||||
//Channels
|
||||
uint8_t val;
|
||||
if (sub_protocol >= FX9630)
|
||||
{ // FX9630 & FX_Q560 & FX_QF012
|
||||
packet[0] = convert_channel_8b(THROTTLE);
|
||||
packet[1] = convert_channel_8b(AILERON);
|
||||
packet[2] = 0xFF - convert_channel_8b(ELEVATOR);
|
||||
packet[3] = convert_channel_8b(RUDDER);
|
||||
val = trim_ch==0 ? 0x20 : (convert_channel_8b(trim_ch + CH6) >> 2); // no trim on Throttle
|
||||
packet[4] = val; // Trim for channel x 0C..20..34
|
||||
packet[5] = (trim_ch << 4) // channel x << 4
|
||||
| GET_FLAG(CH5_SW, (sub_protocol == FX_QF012 ? 0x08 : 0x01)) // DR toggle swich: 0 small throw, 1 large throw / Q560 acrobatic / QF012 Special effects
|
||||
// FX9630 =>0:6G small throw, 1:6G large throw, 2:3D
|
||||
// QIDI-550=>0:3D, 1:6G, 2:Torque
|
||||
// QF012=>0:beginner(6G), 1:mid(3D), 2:expert(Gyro off)
|
||||
| (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x04 : 0x02));
|
||||
if(sub_protocol == FX_Q560)
|
||||
packet[5] |= GET_FLAG(CH7_SW, 0x18); // Q560 LED flag 0x10 conflicting with trim_ch... Corrected on new boards using 0x08 instead
|
||||
else if (sub_protocol == FX_QF012)
|
||||
packet[5] |= GET_FLAG(CH7_SW, 0x40) // QF012 invert flight
|
||||
| GET_FLAG(CH8_SW, 0x80); // QF012 Restore fine tunning midpoint
|
||||
}
|
||||
else // FX816 & FX620
|
||||
{
|
||||
uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET;
|
||||
val=convert_channel_8b(AILERON);
|
||||
if(val>127+FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 1:0xFF;
|
||||
else if(val<127-FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 2:0x00;
|
||||
else
|
||||
packet[offset] = sub_protocol == FX816 ? 0:0x7F;
|
||||
packet[offset+1] = convert_channel_16b_limit(THROTTLE,0,100); //FX816:0x00..0x63, FX620:0x00..0x5E but that should work
|
||||
}
|
||||
|
||||
//Bind and specifics
|
||||
if(sub_protocol == FX816)
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
packet[0] = 0x55;
|
||||
else
|
||||
packet[0] = 0xAA;
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
}
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
memcpy(packet,rx_tx_addr,3);
|
||||
packet[3] = hopping_frequency[0];
|
||||
if(bind_counter > (FX_BIND_COUNT >> 1))
|
||||
packet[5] = 0x78;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0] = 0x1F; // Is it based on ID??
|
||||
packet[5] = 0xAB; // Is it based on ID??
|
||||
}
|
||||
}
|
||||
else // FX9630 & FX_Q560 & FX_QF012
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
memcpy(packet,rx_tx_addr, 4);
|
||||
packet[4] = hopping_frequency[1];
|
||||
packet[5] = hopping_frequency[2];
|
||||
packet[7] = 0x55;
|
||||
}
|
||||
}
|
||||
|
||||
//Check
|
||||
uint8_t last_packet_idx = packet_length-1;
|
||||
if (sub_protocol >= FX9630 && IS_BIND_IN_PROGRESS)
|
||||
last_packet_idx--;
|
||||
val=0;
|
||||
for(uint8_t i=0;i<last_packet_idx;i++)
|
||||
val+=packet[i];
|
||||
if (sub_protocol >= FX9630)
|
||||
val = val ^ 0xFF;
|
||||
packet[last_packet_idx]=val;
|
||||
|
||||
//Debug
|
||||
#if 0
|
||||
for(uint8_t i=0;i<packet_length;i++)
|
||||
debug("%02X ",packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, packet_length);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX_RF_init()
|
||||
{
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
if(sub_protocol == FX816)
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
|
||||
XN297_RFChannel(FX816_BIND_CHANNEL);
|
||||
packet_period = FX816_PACKET_PERIOD;
|
||||
packet_length = FX816_PAYLOAD_SIZE;
|
||||
}
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\xaa\xbb\xcc", 3);
|
||||
XN297_RFChannel(FX620_BIND_CHANNEL);
|
||||
packet_period = FX620_BIND_PACKET_PERIOD;
|
||||
packet_length = FX620_PAYLOAD_SIZE;
|
||||
}
|
||||
else // FX9630 & FX_Q560 & FX_QF012
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\x56\x78\x90\x12", 4);
|
||||
XN297_RFChannel(FX9630_BIND_CHANNEL);
|
||||
packet_period = sub_protocol == FX_QF012 ? FX_QF012_PACKET_PERIOD : FX9630_PACKET_PERIOD;
|
||||
packet_length = FX9630_PAYLOAD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX_initialize_txid()
|
||||
{
|
||||
if(sub_protocol == FX816)
|
||||
{
|
||||
//Only 8 IDs: the RX led does not indicate frame loss.
|
||||
//I didn't open the plane to find out if I could connect there so this is the best I came up with with few trial and errors...
|
||||
rx_tx_addr[0]=0x35+(rx_tx_addr[3]&0x07); //Original dump=0x35
|
||||
rx_tx_addr[1]=0x09; //Original dump=0x09
|
||||
memcpy(hopping_frequency,"\x09\x1B\x30\x42",FX_NUM_CHANNELS); //Original dump=9=0x09,27=0x1B,48=0x30,66=0x42
|
||||
for(uint8_t i=0;i<FX_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
|
||||
}
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
rx_tx_addr[0] = rx_tx_addr[3];
|
||||
hopping_frequency[0] = 0x18 + rx_tx_addr[3]&0x07; // just to try something
|
||||
#ifdef FORCE_FX620_ID
|
||||
memcpy(rx_tx_addr,(uint8_t*)"\x34\xA9\x32",3);
|
||||
hopping_frequency[0] = 0x18; //on dump: 24 34 44 54
|
||||
#endif
|
||||
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i] = i*10 + hopping_frequency[0];
|
||||
}
|
||||
else // FX9630 & FX_Q560 & FX_QF012
|
||||
{
|
||||
//??? Need to find out how the first RF channel is calculated ???
|
||||
hopping_frequency[0] = 0x13;
|
||||
//Other 2 RF channels are sent during the bind phase so they can be whatever
|
||||
hopping_frequency[1] = RX_num & 0x0F + 0x1A;
|
||||
hopping_frequency[2] = rx_tx_addr[3] & 0x0F + 0x38;
|
||||
#ifdef FORCE_FX9630_ID
|
||||
memcpy(rx_tx_addr,(uint8_t*)"\xCE\x31\x9B\x73", 4);
|
||||
memcpy(hopping_frequency,"\x13\x1A\x38", FX9630_NUM_CHANNELS); //Original dump=>19=0x13,26=0x1A,56=0x38
|
||||
#endif
|
||||
#ifdef FORCE_QIDI_ID
|
||||
memcpy(rx_tx_addr,(uint8_t*)"\x23\xDC\x76\xA2", 4);
|
||||
memcpy(hopping_frequency,"\x08\x25\x33", FX9630_NUM_CHANNELS); //Original dump=>08=0x08,37=0x25,51=0x33
|
||||
|
||||
//QIDI-560 #1
|
||||
//memcpy(rx_tx_addr,(uint8_t*)"\x38\xC7\x6D\x8D", 4);
|
||||
//memcpy(hopping_frequency,"\x0D\x20\x3A", FX9630_NUM_CHANNELS);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t FX_callback()
|
||||
{
|
||||
#ifdef FX_HUB_TELEMETRY
|
||||
bool rx=false;
|
||||
|
||||
switch(phase)
|
||||
{
|
||||
case FX_DATA:
|
||||
rx = XN297_IsRX();
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
#endif
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
if(bind_counter)
|
||||
if(--bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
if(sub_protocol == FX620)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, 3);
|
||||
packet_period = FX620_PACKET_PERIOD;
|
||||
}
|
||||
else if(sub_protocol >= FX9630)
|
||||
{ // FX9630 & FX_Q560 & FX_QF012
|
||||
XN297_SetTXAddr(rx_tx_addr, 4);
|
||||
#ifdef FX_HUB_TELEMETRY
|
||||
XN297_SetRXAddr(rx_tx_addr, FX_QF012_RX_PAYLOAD_SIZE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
FX_send_packet();
|
||||
#ifdef FX_HUB_TELEMETRY
|
||||
if(sub_protocol < FX9630)
|
||||
break;
|
||||
if(rx)
|
||||
{
|
||||
debug("RX");
|
||||
if(XN297_ReadPayload(packet_in, FX_QF012_RX_PAYLOAD_SIZE))
|
||||
{//Good CRC
|
||||
//packets: A5 00 11 -> A5 01 11
|
||||
telemetry_link = 1;
|
||||
v_lipo1 = packet_in[1] ? 60:81; // low voltage 3.7V
|
||||
#if 0
|
||||
for(uint8_t i=0; i < FX_QF012_RX_PAYLOAD_SIZE; i++)
|
||||
debug(" %02X", packet_in[i]);
|
||||
#endif
|
||||
}
|
||||
debugln();
|
||||
}
|
||||
phase++;
|
||||
return FX9630_WRITE_TIME;
|
||||
default: //FX_RX
|
||||
/* { // Wait for packet to be sent before switching to receive mode
|
||||
uint16_t start=(uint16_t)micros(), count=0;
|
||||
while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 500)
|
||||
{
|
||||
if(XN297_IsPacketSent())
|
||||
break;
|
||||
count++;
|
||||
}
|
||||
debug("%d",count);
|
||||
} */
|
||||
//Switch to RX
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
phase = FX_DATA;
|
||||
return packet_period - FX9630_WRITE_TIME;
|
||||
}
|
||||
#endif
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
void FX_init()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
FX_initialize_txid();
|
||||
FX_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter=FX_BIND_COUNT;
|
||||
#ifdef FX_HUB_TELEMETRY
|
||||
RX_RSSI = 100; // Dummy value
|
||||
phase = FX_DATA;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
@ -51,9 +51,9 @@ static void __attribute__((unused)) FrSkyX_build_bind_packet()
|
||||
//packet 1D 03 01 0E 1C 02 00 00 32 0B 00 00 A8 26 28 01 A1 00 00 00 3E F6 87 C7 00 00 00 00 C9 C9
|
||||
//Unknown bytes
|
||||
if(state & 0x01)
|
||||
memcpy(&packet[7],"\x00\x18\x0A\x00\x00\xE0\x02\x0B\x01\xD3\x08\x00\x00\x4C\xFE\x87\xC7",17);
|
||||
memcpy(&packet[7],"\x00\xCC\x00\x00\x00\x70\x14\x15\x00\xD3\x08\x00\x00\xCE\xE2\x85\xC7\x00\x00\x00\x00",21);
|
||||
else
|
||||
memcpy(&packet[7],"\x27\xAD\x02\x00\x00\x64\xC8\x46\x00\x64\x00\x00\x00\xFB\xF6\x87\xC7",17);
|
||||
memcpy(&packet[7],"\x27\xFB\x00\x00\x00\xBC\xEF\x19\x00\x26\x07\x00\x00\xB7\xED\x85\xC7\xA7\xA7\xA7\xA7",21);
|
||||
//ID
|
||||
packet[5] = rx_tx_addr[1]; // ID
|
||||
packet[6] = RX_num;
|
||||
@ -63,8 +63,9 @@ static void __attribute__((unused)) FrSkyX_build_bind_packet()
|
||||
if(binding_idx&0x02)
|
||||
packet[7] |= 0x80; // CH9-16
|
||||
//Replace the ID
|
||||
packet[20] ^= 0x0E ^ rx_tx_addr[3]; // Update the ID
|
||||
packet[21] ^= 0x1C ^ rx_tx_addr[2]; // Update the ID
|
||||
packet[20] ^= rx_tx_addr[3]; // Update the ID
|
||||
packet[21] ^= rx_tx_addr[2]; // Update the ID
|
||||
packet[22] ^= rx_tx_addr[1] & 0x3F; // Update the ID
|
||||
//Xor
|
||||
for(uint8_t i=3; i<packet_length-1; i++)
|
||||
packet[i] ^= 0xA7;
|
||||
@ -100,7 +101,7 @@ static void __attribute__((unused)) FrSkyX_build_packet()
|
||||
FrSkyX_channels(7); // Set packet[7]=failsafe, packet[8]=0?? and packet[9..20]=channels data
|
||||
|
||||
//Sequence and send SPort
|
||||
FrSkyX_seq_sport(21,packet_length-2); //21=RX|TXseq, 22=bytes count, 23..packet_length-2=data
|
||||
FrSkyX_seq_sport(21,packet_length-((protocol==PROTO_FRSKYX && (FrSkyFormat & 2 )) ? 4 : 2)); //21=RX|TXseq, 22=bytes count, 23..packet_length-2=data
|
||||
|
||||
//CRC
|
||||
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_length-4);
|
||||
@ -116,6 +117,10 @@ static void __attribute__((unused)) FrSkyX_build_packet()
|
||||
|
||||
uint16_t FRSKYX_callback()
|
||||
{
|
||||
#if defined MULTI_EU
|
||||
if(sub_protocol == CH_16 || sub_protocol == CH_8)
|
||||
return 9000;
|
||||
#endif
|
||||
switch(state)
|
||||
{
|
||||
default:
|
||||
|
132
Multiprotocol/H36_nrf24l01.ino
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if defined(H36_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297.h"
|
||||
|
||||
//#define FORCE_H36_ORIGINAL_ID
|
||||
|
||||
#define H36_PAYLOAD_SIZE 13
|
||||
#define H36_RF_NUM_CHANNELS 4
|
||||
#define H36_BIND_PACKET_PERIOD 10285
|
||||
#define H36_BIND_COUNT 648 //3sec
|
||||
|
||||
enum {
|
||||
H36_DATA1=0,
|
||||
H36_DATA2,
|
||||
H36_DATA3,
|
||||
H36_DATA4,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) H36_send_packet()
|
||||
{
|
||||
if(IS_BIND_DONE && phase == H36_DATA1)
|
||||
{
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no&=3;
|
||||
XN297_Hopping(hopping_frequency_no);
|
||||
}
|
||||
|
||||
packet[0] = 0x2E; // constant?
|
||||
memcpy(&packet[2],rx_tx_addr,3);
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{//Bind
|
||||
memcpy(&packet[5],hopping_frequency,4);
|
||||
memset(&packet[9], 0x00, 3);
|
||||
packet[12] = 0xED; // constant?
|
||||
bind_counter--;
|
||||
if(bind_counter == 0)
|
||||
BIND_DONE;
|
||||
}
|
||||
else
|
||||
{//Normal
|
||||
packet[5] = convert_channel_8b(THROTTLE);
|
||||
packet[6] = convert_channel_8b(RUDDER);
|
||||
packet[7] = convert_channel_8b(ELEVATOR);
|
||||
packet[8] = convert_channel_8b(AILERON);
|
||||
packet[9] = GET_FLAG(CH6_SW, 0x02) //Headless
|
||||
|GET_FLAG(CH7_SW, 0x04); //RTH(temporary)
|
||||
packet[10] = 0x20; //Trim A centered(0x20)
|
||||
packet[11] = CH5_SW?0x60:0x20; //Flip(0x40)|Trim E centered(0x20)
|
||||
packet[12] = 0xA0; //High(0x80)/Low(0x40) rates|Trim R centered(0x20)?
|
||||
}
|
||||
//crc
|
||||
packet[1]=0xAA;
|
||||
for(uint8_t i=5;i<12;i++)
|
||||
packet[1] ^= packet[i];
|
||||
//Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, H36_PAYLOAD_SIZE);
|
||||
#ifdef DEBUG_SERIAL
|
||||
debug("H%d P",hopping_frequency_no);
|
||||
for(uint8_t i=0; i < H36_PAYLOAD_SIZE; i++)
|
||||
debug(" %02X", packet[i]);
|
||||
debugln();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) H36_initialize_txid()
|
||||
{
|
||||
rx_tx_addr[0] = rx_tx_addr[3];
|
||||
calc_fh_channels(4);
|
||||
#ifdef FORCE_H36_ORIGINAL_ID
|
||||
if(!RX_num)
|
||||
{
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\x00\x11\x00",3);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x36\x3A\x31\x2B",4); //54, 58, 49, 43
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) H36_RF_init()
|
||||
{
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
XN297_SetTXAddr((uint8_t*)"\xCC\x6C\x47\x90\x53", 5);
|
||||
XN297_RFChannel(50); //Bind channel
|
||||
}
|
||||
|
||||
uint16_t H36_callback()
|
||||
{
|
||||
H36_send_packet();
|
||||
switch(phase)
|
||||
{
|
||||
case H36_DATA1:
|
||||
phase++;
|
||||
return 1830;
|
||||
case H36_DATA2:
|
||||
case H36_DATA3:
|
||||
phase++;
|
||||
return 3085;
|
||||
default://DATA4
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(18500);
|
||||
#endif
|
||||
phase = H36_DATA1;
|
||||
break;
|
||||
}
|
||||
return 10500;
|
||||
}
|
||||
|
||||
void H36_init()
|
||||
{
|
||||
BIND_IN_PROGRESS; // Autobind protocol
|
||||
H36_initialize_txid();
|
||||
H36_RF_init();
|
||||
phase = H36_DATA1;
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter = H36_BIND_COUNT;
|
||||
}
|
||||
#endif
|
@ -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()
|
||||
|