Compare commits
302 Commits
fix-arduin
...
v1.3.4.63
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79b09468ac | ||
|
|
97fcd0bde0 | ||
|
|
463978939b | ||
|
|
0a7f74dc06 | ||
|
|
3d50a39efb | ||
|
|
9e0efe321c | ||
|
|
3e75c27e95 | ||
|
|
3151a5a5c6 | ||
|
|
2348c3c29d | ||
|
|
968578d59e | ||
|
|
53594ce1a1 | ||
|
|
aaaa5f141d | ||
|
|
1772147e5b | ||
|
|
865f6c1597 | ||
|
|
095acb0975 | ||
|
|
fc8730976c | ||
|
|
699e796a01 | ||
|
|
93bade15d0 | ||
|
|
80d08c25e0 | ||
|
|
debb17a8fc | ||
|
|
174efa332b | ||
|
|
e5f9f8c840 | ||
|
|
a23716269b | ||
|
|
bfef3364fc | ||
|
|
d62f2d0555 | ||
|
|
bb59582271 | ||
|
|
c6c6fa442b | ||
|
|
d95012c30b | ||
|
|
f71768df39 | ||
|
|
7bde06ff50 | ||
|
|
51a01d1393 | ||
|
|
bf38415420 | ||
|
|
5ce6c6f544 | ||
|
|
35f284763a | ||
|
|
e35c4d3ce8 | ||
|
|
ba59605b16 | ||
|
|
b88f4d40f4 | ||
|
|
5ade6bc312 | ||
|
|
9e099bc486 | ||
|
|
48b7430e75 | ||
|
|
6385e822c2 | ||
|
|
66f8906273 | ||
|
|
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 |
244
.github/workflows/main.yml
vendored
@@ -1,6 +1,6 @@
|
|||||||
# Workflow for testing MULTI-Module firmware builds
|
# Workflow for testing MULTI-Module firmware builds
|
||||||
|
|
||||||
name: CI
|
name: MULTI Test, Build, Deploy, Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
# Trigger the workflow on pushes, except those that are tagged (avoids double-testing releases)
|
# Trigger the workflow on pushes, except those that are tagged (avoids double-testing releases)
|
||||||
@@ -32,33 +32,45 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
# Configure the board matrix
|
# Configure the board matrix
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
board: [
|
include:
|
||||||
"multi4in1:avr:multiatmega328p:bootloader=none",
|
- board: "multi4in1:avr:multiatmega328p:bootloader=none"
|
||||||
"multi4in1:avr:multiatmega328p:bootloader=optiboot",
|
name: "ATmega328p"
|
||||||
"multi4in1:avr:multixmega32d4",
|
- board: "multi4in1:avr:multiatmega328p:bootloader=optiboot"
|
||||||
"multi4in1:STM32F1:multi5in1t18int",
|
name: "ATmega328p (Optiboot)"
|
||||||
"multi4in1:STM32F1:multistm32f103cb:debug_option=none",
|
- board: "multi4in1:avr:multixmega32d4"
|
||||||
"multi4in1:STM32F1:multistm32f103cb:debug_option=native",
|
name: "OrangeRX"
|
||||||
"multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi",
|
- board: "multi4in1:STM32F1:multistm32f103c8:debug_option=none"
|
||||||
"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
|
# Set the environment variables
|
||||||
env:
|
env:
|
||||||
BOARD: ${{ matrix.board }}
|
BOARD: ${{ matrix.board }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Arduino CLI
|
- 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
|
- name: Prepare build environment
|
||||||
run: |
|
run: |
|
||||||
@@ -149,23 +161,38 @@ jobs:
|
|||||||
|
|
||||||
- name: Build serial only
|
- name: Build serial only
|
||||||
run: |
|
run: |
|
||||||
source ./buildroot/bin/buildFunctions;
|
# Skip the serial-only build for boards where it's too large now
|
||||||
cp ./_Config.h.bak Multiprotocol/_Config.h
|
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||||
opt_disable ENABLE_PPM;
|
printf "Not testing serial-only build for $BOARD.";
|
||||||
buildMulti;
|
else
|
||||||
|
source ./buildroot/bin/buildFunctions;
|
||||||
|
cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||||
|
opt_disable ENABLE_PPM;
|
||||||
|
buildMulti;
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Build PPM only
|
- name: Build PPM only
|
||||||
run: |
|
run: |
|
||||||
source ./buildroot/bin/buildFunctions;
|
# Skip the PPM-only build for boards where it's too large now
|
||||||
cp ./_Config.h.bak Multiprotocol/_Config.h
|
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||||
opt_disable ENABLE_SERIAL;
|
printf "Not testing PPM-only build for $BOARD.";
|
||||||
buildMulti;
|
else
|
||||||
|
source ./buildroot/bin/buildFunctions;
|
||||||
|
cp ./_Config.h.bak Multiprotocol/_Config.h
|
||||||
|
opt_disable ENABLE_SERIAL;
|
||||||
|
buildMulti;
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Build each RF module individually
|
- name: Build each RF module individually
|
||||||
run: |
|
run: |
|
||||||
source ./buildroot/bin/buildFunctions;
|
# Skip the per-RF module builds for boards which have fixed modules
|
||||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
if [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||||
buildEachRFModule;
|
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
|
- name: Build each protocol individually
|
||||||
run: |
|
run: |
|
||||||
@@ -173,6 +200,128 @@ jobs:
|
|||||||
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
cp ./_Config.h.bak Multiprotocol/_Config.h;
|
||||||
buildEachProtocol;
|
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
|
- name: Build release files
|
||||||
run: |
|
run: |
|
||||||
source ./buildroot/bin/buildFunctions;
|
source ./buildroot/bin/buildFunctions;
|
||||||
@@ -187,16 +336,43 @@ jobs:
|
|||||||
echo "HAVE_FILES=false" >> $GITHUB_ENV
|
echo "HAVE_FILES=false" >> $GITHUB_ENV
|
||||||
fi
|
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'
|
- name: 'Upload Artifacts'
|
||||||
if: env.HAVE_FILES == 'true'
|
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:
|
with:
|
||||||
name: multi-test-build
|
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,549 +0,0 @@
|
|||||||
local toolName = "TNS|DSM Forward Prog v0.54 (Text B&W) |TNE"
|
|
||||||
local VERSION = "v0.54"
|
|
||||||
|
|
||||||
|
|
||||||
---- #########################################################################
|
|
||||||
---- # #
|
|
||||||
---- # Copyright (C) OpenTX #
|
|
||||||
-----# #
|
|
||||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
|
||||||
---- # #
|
|
||||||
---- # This program is free software; you can redistribute it and/or modify #
|
|
||||||
---- # it under the terms of the GNU General Public License version 2 as #
|
|
||||||
---- # published by the Free Software Foundation. #
|
|
||||||
---- # #
|
|
||||||
---- # This program is distributed in the hope that it will be useful #
|
|
||||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
||||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
||||||
---- # GNU General Public License for more details. #
|
|
||||||
---- # #
|
|
||||||
---- #########################################################################
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
|
||||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
|
||||||
-- separate the GUI from the DSM Forward programming engine/logic
|
|
||||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
|
||||||
|
|
||||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
|
||||||
-- Rewrite/Enhancements By: Francisco Arzu
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
local SIMULATION_ON = false -- FALSE: don't show simulation menu (DEFAULT), TRUE: show simulation menu
|
|
||||||
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
|
|
||||||
local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
|
|
||||||
|
|
||||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
|
||||||
|
|
||||||
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON)
|
|
||||||
|
|
||||||
local PHASE = dsmLib.PHASE
|
|
||||||
local LINE_TYPE = dsmLib.LINE_TYPE
|
|
||||||
local DISP_ATTR = dsmLib.DISP_ATTR
|
|
||||||
|
|
||||||
local DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
local IS_EDGETX = false -- DEFAULT until Init changed it
|
|
||||||
|
|
||||||
local LCD_W_USABLE = LCD_W-10
|
|
||||||
-- X for Menu Lines
|
|
||||||
local LCD_X_LINE_MENU = 10
|
|
||||||
-- X offsets for (Title: [Value] debugInfo) lines
|
|
||||||
local LCD_X_LINE_TITLE = 10
|
|
||||||
local LCD_X_LINE_VALUE = 230
|
|
||||||
local LCD_X_LINE_DEBUG = 390
|
|
||||||
|
|
||||||
-- Line Height: make it smaller debugging info tp LCD (some space buttom)
|
|
||||||
local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27
|
|
||||||
-- Y offsets
|
|
||||||
local LCD_Y_MENU_TITLE = 20
|
|
||||||
-- Y offet
|
|
||||||
local LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 30
|
|
||||||
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT
|
|
||||||
|
|
||||||
local LCD_W_BUTTONS = 47
|
|
||||||
local LCD_H_BUTTONS = 25
|
|
||||||
local LCD_X_RIGHT_BUTTONS = LCD_W - LCD_W_BUTTONS - 5
|
|
||||||
|
|
||||||
local TEXT_SIZE = 0 -- NORMAL
|
|
||||||
|
|
||||||
local lastRefresh=0 -- Last time the screen was refreshed
|
|
||||||
local REFRESH_GUI_MS = 500/10 -- 500ms.. Screen Refresh Rate.. to not use unneded CPU time (in 10ms units to be compatible with getTime())
|
|
||||||
local originalValue = nil
|
|
||||||
|
|
||||||
local warningScreenON = true
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_SwitchToRX()
|
|
||||||
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
|
|
||||||
local dsmChannelInfo, description = dsmLib.CreateDSMPortChannelInfo()
|
|
||||||
|
|
||||||
dsmLib.ReleaseConnection()
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
|
|
||||||
SIMULATION_ON = false
|
|
||||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
|
|
||||||
DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
|
||||||
dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library
|
|
||||||
dsmLib.StartConnection()
|
|
||||||
DSM_Context.Refresh_Display = true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_SwitchToSIM()
|
|
||||||
dsmLib.ReleaseConnection()
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
|
|
||||||
SIMULATION_ON = true
|
|
||||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
|
|
||||||
DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
|
||||||
dsmLib.StartConnection()
|
|
||||||
DSM_Context.Refresh_Display = true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function openTx_lcd_sizeText(s)
|
|
||||||
return string.len(s)*5
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_Diplay_Button(x,y,w,h,text,selected)
|
|
||||||
local attr = (selected) and INVERS or 0 -- INVERS if line Selected
|
|
||||||
if (TEXT_SIZE~=SMLSIZE) then
|
|
||||||
lcd.drawText(x+5,y+2, text, attr + TEXT_SIZE)
|
|
||||||
lcd.drawRectangle(x, y, w, h, LINE_COLOR)
|
|
||||||
else -- SMALL Screen
|
|
||||||
lcd.drawText(x,y, text, attr + TEXT_SIZE)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_Display_Menu(menu)
|
|
||||||
local ctx = DSM_Context
|
|
||||||
local w= LCD_W_USABLE - LCD_W_BUTTONS - 10 -- usable Width for the Menu/Lines
|
|
||||||
|
|
||||||
-- Center Header
|
|
||||||
local tw = openTx_lcd_sizeText(menu.Text)
|
|
||||||
local x = w/2 - tw/2 -- Center of Screen - Center of Text
|
|
||||||
if (x < 0) then x=0 end -- in case text is too wide
|
|
||||||
|
|
||||||
local bold = BOLD
|
|
||||||
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text,bold + TEXT_SIZE)
|
|
||||||
|
|
||||||
-- Back
|
|
||||||
if menu.BackId ~= 0 then
|
|
||||||
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_MENU_TITLE,LCD_W_BUTTONS,LCD_H_BUTTONS,"Back",ctx.SelLine == dsmLib.BACK_BUTTON)
|
|
||||||
end
|
|
||||||
-- Next ?
|
|
||||||
if menu.NextId ~= 0 then
|
|
||||||
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON)
|
|
||||||
end
|
|
||||||
-- Prev?
|
|
||||||
if menu.PrevId ~= 0 then
|
|
||||||
GUI_Diplay_Button(0,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug into LCD
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),TEXT_SIZE + WARNING_COLOR) end -- Phase we are in
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_MENU,240,dsmLib.menu2String(menu),TEXT_SIZE + WARNING_COLOR) end -- Menu Info
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_Display_Line_Menu(x,y,w,h,line,selected)
|
|
||||||
local attr = (selected and INVERS) or 0 -- INVERS if line Selected
|
|
||||||
local bold = 0
|
|
||||||
local text = line.Text
|
|
||||||
|
|
||||||
if dsmLib.isSelectableLine(line) then
|
|
||||||
-- Menu Line
|
|
||||||
text = text .. " >"
|
|
||||||
else -- SubHeaders and plain text lines
|
|
||||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
|
||||||
|
|
||||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
|
||||||
local tw = openTx_lcd_sizeText(line.Text)+4
|
|
||||||
x = LCD_X_LINE_VALUE - tw -- Right
|
|
||||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
|
||||||
local tw = openTx_lcd_sizeText(line.Text)
|
|
||||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
|
||||||
end
|
|
||||||
if (x < 0) then x=0 end -- in case text is too wide
|
|
||||||
end
|
|
||||||
|
|
||||||
lcd.drawText(x,y, text, attr + bold + TEXT_SIZE)
|
|
||||||
|
|
||||||
end
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
|
||||||
local bold = 0
|
|
||||||
|
|
||||||
local y = LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*lineNum)
|
|
||||||
local x = LCD_X_LINE_TITLE
|
|
||||||
|
|
||||||
---------- NAME Part
|
|
||||||
local header = line.Text
|
|
||||||
-- ONLY do this for Flight Mode (Right Align or Centered)
|
|
||||||
if (dsmLib.isFlightModeLine(line)) then
|
|
||||||
-- Display Header + Value together
|
|
||||||
header = dsmLib.GetFlightModeValue(line)
|
|
||||||
|
|
||||||
-- Flight mode display attributes
|
|
||||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
|
||||||
|
|
||||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
|
||||||
local tw = openTx_lcd_sizeText(header)+4
|
|
||||||
x = LCD_X_LINE_VALUE - tw -- Right
|
|
||||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
|
||||||
local tw = openTx_lcd_sizeText(header)
|
|
||||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
|
||||||
end
|
|
||||||
if (x < 0) then x=0 end -- in case text is too wide
|
|
||||||
else
|
|
||||||
-- No Flight Mode, no effects here
|
|
||||||
header = header .. ":"
|
|
||||||
end
|
|
||||||
|
|
||||||
lcd.drawText(x, y, header, bold + TEXT_SIZE) -- display Line Header
|
|
||||||
|
|
||||||
--------- VALUE PART, Skip for Flight Mode since already show the value
|
|
||||||
if not dsmLib.isFlightModeLine(line) then
|
|
||||||
local attrib = 0
|
|
||||||
|
|
||||||
if selected then
|
|
||||||
attrib = INVERS
|
|
||||||
if editing then -- blink editing entry
|
|
||||||
attrib = attrib + BLINK
|
|
||||||
value = "[" .. value .. "]"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
value = value .. " " .. (line.Format or "") -- Append % if needed
|
|
||||||
lcd.drawText(LCD_X_LINE_VALUE,y, value, attrib + TEXT_SIZE) -- display value
|
|
||||||
end
|
|
||||||
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG,y, line.MinMaxDebug or "", TEXT_SIZE + WARNING_COLOR) end -- display debug
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_ShowBitmap(x,y,imgData)
|
|
||||||
-- imgData format "bitmap.png|alt message"
|
|
||||||
local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|'
|
|
||||||
local imgName, imgMsg = f(), f()
|
|
||||||
|
|
||||||
if (LCD_W > 128) then
|
|
||||||
lcd.drawText(x, y, imgMsg or "", TEXT_SIZE) -- Alternate Image MSG
|
|
||||||
else
|
|
||||||
local f = string.gmatch(imgMsg, '([^%:]+)') -- Iterator over values split by ':'
|
|
||||||
local msg1,msg2 = f(), f()
|
|
||||||
lcd.drawText(x, y, (msg1 or "")..":", TEXT_SIZE) -- Alternate Image MSG
|
|
||||||
lcd.drawText(x, y+10, msg2 or "", TEXT_SIZE) -- Alternate Image MSG
|
|
||||||
end
|
|
||||||
|
|
||||||
-- NO IMAGES in Text B&W
|
|
||||||
--local imgPath = IMAGE_PATH .. (imgName or "")
|
|
||||||
--local bitmap = Bitmap.open(imgPath)
|
|
||||||
--if (bitmap~=nil) then
|
|
||||||
-- lcd.drawBitmap(bitmap, x,y+20)
|
|
||||||
--end
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_Display()
|
|
||||||
local ctx = DSM_Context
|
|
||||||
lcd.clear()
|
|
||||||
local header = "DSM Fwrd Programming "
|
|
||||||
|
|
||||||
if (TEXT_SIZE==SMLSIZE) then -- Small Screen no title
|
|
||||||
header = ""
|
|
||||||
end
|
|
||||||
|
|
||||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
|
||||||
header = header .. ctx.RX.Name.." v"..ctx.RX.Version
|
|
||||||
end
|
|
||||||
|
|
||||||
--Draw title
|
|
||||||
if (TEXT_SIZE~=SMLSIZE) then -- ignore tool title small size screens
|
|
||||||
lcd.drawFilledRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR)
|
|
||||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
|
||||||
else -- Small Screen
|
|
||||||
lcd.drawText(20, LCD_Y_LOWER_BUTTONS+1, header, TEXT_SIZE)
|
|
||||||
end
|
|
||||||
--Draw RX Menu
|
|
||||||
if ctx.Phase == PHASE.RX_VERSION then
|
|
||||||
if (ctx.isReset) then
|
|
||||||
lcd.drawText(LCD_X_LINE_TITLE,50,dsmLib.Get_Text(0x301), BLINK + TEXT_SIZE) -- Resetting
|
|
||||||
else
|
|
||||||
lcd.drawText(LCD_X_LINE_TITLE,50,dsmLib.Get_Text(0x300), BLINK + TEXT_SIZE) -- Waiting for RX Version
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local menu = ctx.Menu
|
|
||||||
if menu.Text ~= nil then
|
|
||||||
|
|
||||||
GUI_Display_Menu(menu)
|
|
||||||
|
|
||||||
for i = 0, dsmLib.MAX_MENU_LINES do
|
|
||||||
local line = ctx.MenuLines[i]
|
|
||||||
|
|
||||||
if i == ctx.SelLine then
|
|
||||||
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_TITLE,255,dsmLib.menuLine2String(line),TEXT_SIZE + WARNING_COLOR) end
|
|
||||||
end
|
|
||||||
|
|
||||||
if line ~= nil and line.Type ~= 0 then
|
|
||||||
if line.Type == LINE_TYPE.MENU then
|
|
||||||
-- Menu Line
|
|
||||||
GUI_Display_Line_Menu(LCD_X_LINE_MENU,LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*i), 350, LCD_Y_LINE_HEIGHT, line, i == ctx.SelLine)
|
|
||||||
else
|
|
||||||
-- list/value line
|
|
||||||
local value = line.Val
|
|
||||||
if line.Val ~= nil then
|
|
||||||
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
|
|
||||||
value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
|
||||||
local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
|
|
||||||
|
|
||||||
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
|
||||||
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_FIRST+LCD_Y_LINE_HEIGHT, imgData)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
|
||||||
end
|
|
||||||
end -- if ~MENU
|
|
||||||
end -- if Line[i]~=nil
|
|
||||||
end -- for
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
|
|
||||||
local inc = 0
|
|
||||||
local Speed = getRotEncSpeed()
|
|
||||||
|
|
||||||
if Speed == ROTENC_MIDSPEED then
|
|
||||||
inc = (5 * dir)
|
|
||||||
elseif Speed == ROTENC_HIGHSPEED then
|
|
||||||
inc = (15 * dir)
|
|
||||||
else
|
|
||||||
inc = dir
|
|
||||||
end
|
|
||||||
|
|
||||||
return inc
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_HandleEvent(event, touchState)
|
|
||||||
local ctx = DSM_Context
|
|
||||||
local menu = ctx.Menu
|
|
||||||
local menuLines = ctx.MenuLines
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_EXIT then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.Phase == PHASE.RX_VERSION then
|
|
||||||
dsmLib.ReleaseConnection()
|
|
||||||
else
|
|
||||||
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
|
||||||
ctx.MenuLines[ctx.EditLine].Val = originalValue
|
|
||||||
dsmLib.Value_Write_Validate(menuLines[ctx.EditLine])
|
|
||||||
else
|
|
||||||
dsmLib.ChangePhase(PHASE.EXIT) -- Exit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_NEXT then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
|
||||||
local line=ctx.MenuLines[ctx.EditLine]
|
|
||||||
dsmLib.Value_Add(line, GUI_RotEncVal(1))
|
|
||||||
else -- not editing, move selected line to NEXT
|
|
||||||
dsmLib.MoveSelectionLine(1)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_PREV then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
|
||||||
local line=ctx.MenuLines[ctx.EditLine]
|
|
||||||
dsmLib.Value_Add(line, GUI_RotEncVal(-1))
|
|
||||||
else -- not editing, move selected line to PREV
|
|
||||||
dsmLib.MoveSelectionLine(-1)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_ENTER_LONG then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.isEditing() then
|
|
||||||
-- reset the value to default
|
|
||||||
dsmLib.Value_Default( menuLines[ctx.EditLine]) -- Update RX value as needed
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_ENTER then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
|
|
||||||
dsmLib.GotoMenu(menu.BackId,0x80)
|
|
||||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
|
||||||
dsmLib.GotoMenu(menu.NextId,0x82)
|
|
||||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
|
||||||
dsmLib.GotoMenu(menu.PrevId,0x81)
|
|
||||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then
|
|
||||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Next menu exist
|
|
||||||
if (menuLines[ctx.SelLine].ValId==0xFFF1) then
|
|
||||||
-- SPECIAL Simulation menu to Simulator
|
|
||||||
GUI_SwitchToSIM()
|
|
||||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
|
|
||||||
-- SPECIAL Simulation menu to go to RX
|
|
||||||
GUI_SwitchToRX()
|
|
||||||
else
|
|
||||||
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Editing a Line????
|
|
||||||
if ctx.isEditing() then
|
|
||||||
-- Change the Value and exit edit
|
|
||||||
dsmLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
|
||||||
else
|
|
||||||
-- enter Edit the current line
|
|
||||||
ctx.EditLine = ctx.SelLine
|
|
||||||
originalValue = menuLines[ctx.SelLine].Val
|
|
||||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function init_screen_pos()
|
|
||||||
-- osName in OpenTX is nil, otherwise is EDGETX
|
|
||||||
local ver, radio, maj, minor, rev, osname = getVersion()
|
|
||||||
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
|
|
||||||
|
|
||||||
IS_EDGETX = string.sub(osname,1,1) =='E'
|
|
||||||
|
|
||||||
if LCD_W == 480 then -- TX16
|
|
||||||
-- use defaults in the script header
|
|
||||||
elseif LCD_W == 128 then --TX12 (128x64) -- Still needs some work on the vertical
|
|
||||||
DEBUG_ON_LCD = false -- no space for this
|
|
||||||
TEXT_SIZE = SMLSIZE
|
|
||||||
LCD_W_USABLE = 128
|
|
||||||
|
|
||||||
LCD_W_BUTTONS = 16
|
|
||||||
LCD_H_BUTTONS = 10
|
|
||||||
LCD_X_RIGHT_BUTTONS = 128 - LCD_W_BUTTONS - 3
|
|
||||||
|
|
||||||
LCD_X_LINE_MENU = 0
|
|
||||||
-- X offsets for (Title: [Value] debugInfo) lines
|
|
||||||
LCD_X_LINE_TITLE = 0
|
|
||||||
LCD_X_LINE_VALUE = 75
|
|
||||||
LCD_X_LINE_DEBUG = 110
|
|
||||||
|
|
||||||
LCD_Y_LINE_HEIGHT = 7
|
|
||||||
LCD_Y_MENU_TITLE = 0
|
|
||||||
LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 8
|
|
||||||
LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + (7 * LCD_Y_LINE_HEIGHT)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_Warning(event)
|
|
||||||
lcd.clear()
|
|
||||||
local header = "DSM Forward Programming "..VERSION.." "
|
|
||||||
--Draw title
|
|
||||||
if (LCD_W > 128) then
|
|
||||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, TITLE_BGCOLOR)
|
|
||||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
|
||||||
|
|
||||||
lcd.drawText(100,20,"INFO", BOLD)
|
|
||||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", TEXT_SIZE)
|
|
||||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", TEXT_SIZE)
|
|
||||||
lcd.drawText(5,80,"the TX before your start programming your RX.", TEXT_SIZE)
|
|
||||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", TEXT_SIZE)
|
|
||||||
|
|
||||||
lcd.drawText(5,150,"TX Servo settings are sent to the RX during 'Initial Setup'", TEXT_SIZE)
|
|
||||||
lcd.drawText(5,170,"as well as when using RX menu 'Relearn Servo Settings'", TEXT_SIZE)
|
|
||||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD+TEXT_SIZE)
|
|
||||||
|
|
||||||
lcd.drawText(100,250," OK ", INVERS + BOLD + TEXT_SIZE)
|
|
||||||
else
|
|
||||||
lcd.drawText(0,15,"Make sure you setup your plane", TEXT_SIZE)
|
|
||||||
lcd.drawText(0,22,"first. Wing and Tail type.", TEXT_SIZE)
|
|
||||||
|
|
||||||
lcd.drawText(0,30,"TX Servo settings are sent to ", TEXT_SIZE)
|
|
||||||
lcd.drawText(0,37,"the RX during 'Initial Setup' and ", TEXT_SIZE)
|
|
||||||
lcd.drawText(0,45,"ALWAYS TEST Gyro reactions", TEXT_SIZE)
|
|
||||||
lcd.drawText(0,52,"before flying!!!", TEXT_SIZE)
|
|
||||||
|
|
||||||
lcd.drawText(10,0," OK ", INVERS + BOLD + TEXT_SIZE)
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER then
|
|
||||||
warningScreenON = false
|
|
||||||
end
|
|
||||||
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Init
|
|
||||||
local function DSM_Init()
|
|
||||||
init_screen_pos()
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
|
||||||
return dsmLib.StartConnection()
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Main
|
|
||||||
|
|
||||||
|
|
||||||
local function DSM_Run(event)
|
|
||||||
local ctx = DSM_Context
|
|
||||||
|
|
||||||
if event == nil then
|
|
||||||
error("Cannot be run as a model script!")
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
return 2
|
|
||||||
end
|
|
||||||
|
|
||||||
if (warningScreenON) then
|
|
||||||
return GUI_Warning(event)
|
|
||||||
end
|
|
||||||
|
|
||||||
GUI_HandleEvent(event)
|
|
||||||
|
|
||||||
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
|
|
||||||
|
|
||||||
local refreshInterval = REFRESH_GUI_MS
|
|
||||||
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
|
|
||||||
if (ctx.EditLine or (ctx.Phase == PHASE.RX_VERSION)) then -- Editing or Requesting RX Version?
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
refreshInterval = 20 -- 200ms
|
|
||||||
end
|
|
||||||
|
|
||||||
if (not IS_EDGETX) then -- OPENTX NEEDS REFRESH ON EVERY CYCLE
|
|
||||||
GUI_Display()
|
|
||||||
-- Refresh display only if needed and no faster than 500ms, utilize more CPU to speedup DSM communications
|
|
||||||
elseif (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
|
|
||||||
GUI_Display()
|
|
||||||
ctx.Refresh_Display=false
|
|
||||||
lastRefresh=getTime()
|
|
||||||
end
|
|
||||||
|
|
||||||
if ctx.Phase == PHASE.EXIT_DONE then
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
return 2
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return { init=DSM_Init, run=DSM_Run }
|
|
||||||
@@ -1,708 +0,0 @@
|
|||||||
local toolName = "TNS|DSM Forward Prog v0.54 (Color+Touch) |TNE"
|
|
||||||
local VERSION = "v0.54"
|
|
||||||
|
|
||||||
---- #########################################################################
|
|
||||||
---- # #
|
|
||||||
---- # Copyright (C) OpenTX #
|
|
||||||
-----# #
|
|
||||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
|
||||||
---- # #
|
|
||||||
---- # This program is free software; you can redistribute it and/or modify #
|
|
||||||
---- # it under the terms of the GNU General Public License version 2 as #
|
|
||||||
---- # published by the Free Software Foundation. #
|
|
||||||
---- # #
|
|
||||||
---- # This program is distributed in the hope that it will be useful #
|
|
||||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
||||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
||||||
---- # GNU General Public License for more details. #
|
|
||||||
---- # #
|
|
||||||
---- #########################################################################
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
|
||||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
|
||||||
-- separate the GUI from the DSM Forward programming engine/logic
|
|
||||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
|
||||||
|
|
||||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
|
||||||
-- Rewrite/Enhancements By: Francisco Arzu
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
local SIMULATION_ON = false -- FALSE:don't show simulation memu (DEFAULT), TRUE: show simulation menu
|
|
||||||
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
|
|
||||||
local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
|
|
||||||
local USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX)
|
|
||||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
|
||||||
local IMAGE_PATH = DSMLIB_PATH .. "img/"
|
|
||||||
|
|
||||||
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON)
|
|
||||||
|
|
||||||
local PHASE = dsmLib.PHASE
|
|
||||||
local LINE_TYPE = dsmLib.LINE_TYPE
|
|
||||||
local DISP_ATTR = dsmLib.DISP_ATTR
|
|
||||||
local DSM_Context = dsmLib.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 = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 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)
|
|
||||||
-- 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 = dsmLib.CreateDSMPortChannelInfo()
|
|
||||||
|
|
||||||
dsmLib.ReleaseConnection()
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
|
|
||||||
SIMULATION_ON = false
|
|
||||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
|
|
||||||
DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
|
||||||
dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library
|
|
||||||
dsmLib.StartConnection()
|
|
||||||
DSM_Context.Refresh_Display = true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_SwitchToSIM()
|
|
||||||
dsmLib.ReleaseConnection()
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
|
|
||||||
SIMULATION_ON = true
|
|
||||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
|
|
||||||
DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
|
||||||
dsmLib.StartConnection()
|
|
||||||
DSM_Context.Refresh_Display = true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--------------------- 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 dsmLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes
|
|
||||||
GUI_Display_Boxed_Text(lineNum,x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT, line.Text,selected, false)
|
|
||||||
GUI_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum)
|
|
||||||
else
|
|
||||||
-- Non Selectable Menu Lines, plain text
|
|
||||||
-- Can be use for sub headers or just regular text lines (like warnings)
|
|
||||||
|
|
||||||
local bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
|
||||||
|
|
||||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
|
||||||
local tw = my_lcd_sizeText(line.Text)+4
|
|
||||||
x = LCD_X_LINE_VALUE - tw -- Right
|
|
||||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
|
||||||
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 (dsmLib.isFlightModeLine(line)) then
|
|
||||||
-- Display Header + Value together
|
|
||||||
header = dsmLib.GetFlightModeValue(line)
|
|
||||||
|
|
||||||
-- Bold Text???
|
|
||||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
|
||||||
|
|
||||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
|
||||||
local tw = my_lcd_sizeText(header)+4
|
|
||||||
x = LCD_X_LINE_VALUE - tw -- Right
|
|
||||||
elseif dsmLib.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 not dsmLib.isFlightModeLine(line) then
|
|
||||||
if dsmLib.isSelectableLine(line) then
|
|
||||||
--if (editing) then -- Any Special color/effect when editing??
|
|
||||||
-- value = "["..value .. "]"
|
|
||||||
--end
|
|
||||||
-- Can select/edit value, Box it
|
|
||||||
local tw = math.max(my_lcd_sizeText(value)+10,45) -- Width of the Text in the lcd
|
|
||||||
GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected, not dsmLib.isListLine(line))
|
|
||||||
GUI_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
|
|
||||||
|
|
||||||
-- Debug info for line Value RANGE when Debug on LCD
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG, y, line.MinMaxDebug or "", SMLSIZE + LCD_DEBUG_COLOR) end -- display debug Min/Max
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_Display_Menu(menu)
|
|
||||||
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 == dsmLib.BACK_BUTTON)
|
|
||||||
GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,dsmLib.BACK_BUTTON)
|
|
||||||
end
|
|
||||||
-- Next Button
|
|
||||||
if menu.NextId ~= 0 then
|
|
||||||
GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON)
|
|
||||||
GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.NEXT_BUTTON)
|
|
||||||
end
|
|
||||||
-- Prev Button
|
|
||||||
if menu.PrevId ~= 0 then
|
|
||||||
GUI_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON)
|
|
||||||
GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.PREV_BUTTON)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug on LCD, Show the menu Indo and Phase we are on
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),SMLSIZE+LCD_DEBUG_COLOR) end -- Phase we are in
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(0,240,dsmLib.menu2String(menu),SMLSIZE+LCD_DEBUG_COLOR) end -- Menu Info
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
-- 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 dsmLib.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 dsmLib.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
|
|
||||||
local header = "DSM Forward Programming "..VERSION.." "
|
|
||||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
|
||||||
header = header .. "RX "..ctx.RX.Name.." v"..ctx.RX.Version
|
|
||||||
end
|
|
||||||
|
|
||||||
--Draw title
|
|
||||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
|
||||||
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
|
||||||
--Draw RX Menu
|
|
||||||
if ctx.Phase == PHASE.RX_VERSION then
|
|
||||||
if (ctx.isReset) then
|
|
||||||
lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x301), BLINK) -- Waiting for Restart
|
|
||||||
else
|
|
||||||
lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x300), BLINK) -- Waiting for RX
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local menu = ctx.Menu
|
|
||||||
|
|
||||||
|
|
||||||
if menu.Text ~= nil then
|
|
||||||
GUI_Display_Menu(menu)
|
|
||||||
|
|
||||||
for i = 0, dsmLib.MAX_MENU_LINES do
|
|
||||||
local line = ctx.MenuLines[i]
|
|
||||||
|
|
||||||
if i == ctx.SelLine then
|
|
||||||
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(0,255,dsmLib.menuLine2String(line),SMLSIZE + LCD_DEBUG_COLOR) end
|
|
||||||
end
|
|
||||||
|
|
||||||
if line ~= nil and line.Type ~= 0 then
|
|
||||||
if line.Type == LINE_TYPE.MENU then
|
|
||||||
GUI_Display_Line_Menu(i, line, i == ctx.SelLine)
|
|
||||||
else
|
|
||||||
if line.Val ~= nil then
|
|
||||||
local value = line.Val
|
|
||||||
|
|
||||||
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
|
|
||||||
value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
|
||||||
local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
|
|
||||||
|
|
||||||
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
|
||||||
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_START, imgData)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
|
||||||
end
|
|
||||||
end -- if ~MENU
|
|
||||||
end -- if Line[i]~=nil
|
|
||||||
end -- for
|
|
||||||
|
|
||||||
if IS_EDGETX and ctx.isEditing() then
|
|
||||||
-- Display Touch button for Editing values
|
|
||||||
GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- 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)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
|
|
||||||
local inc = 0
|
|
||||||
local Speed = getRotEncSpeed()
|
|
||||||
|
|
||||||
if Speed == ROTENC_MIDSPEED then inc = (5 * dir)
|
|
||||||
elseif Speed == ROTENC_HIGHSPEED then inc = (15 * dir)
|
|
||||||
else inc = dir end
|
|
||||||
|
|
||||||
return inc
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------
|
|
||||||
-- 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 dsmLib.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",dsmLib.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 dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.Phase == PHASE.RX_VERSION then
|
|
||||||
dsmLib.ReleaseConnection() -- Just Exit the Script
|
|
||||||
else
|
|
||||||
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
|
||||||
local line = ctx.MenuLines[ctx.EditLine]
|
|
||||||
line.Val = originalValue
|
|
||||||
dsmLib.Value_Write_Validate(line)
|
|
||||||
else
|
|
||||||
dsmLib.ChangePhase(PHASE.EXIT)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_NEXT then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
|
||||||
local line=ctx.MenuLines[ctx.EditLine]
|
|
||||||
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(1))
|
|
||||||
else -- not editing, move selected line to NEXT
|
|
||||||
dsmLib.MoveSelectionLine(1)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_PREV then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
|
||||||
local line=ctx.MenuLines[ctx.EditLine]
|
|
||||||
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(-1))
|
|
||||||
else -- not editing, move selected line to PREV
|
|
||||||
dsmLib.MoveSelectionLine(-1)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_ENTER_LONG then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.isEditing() then
|
|
||||||
-- reset the value to default
|
|
||||||
dsmLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_ENTER then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",dsmLib.phase2String(ctx.Phase), ctx.SelLine) end
|
|
||||||
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
|
|
||||||
dsmLib.GotoMenu(menu.BackId,0x80)
|
|
||||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
|
||||||
dsmLib.GotoMenu(menu.NextId,0x82)
|
|
||||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
|
||||||
dsmLib.GotoMenu(menu.PrevId,0x81)
|
|
||||||
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()
|
|
||||||
else
|
|
||||||
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
|
||||||
end
|
|
||||||
else -- Enter on a Value
|
|
||||||
if ctx.isEditing() then -- already editing a Line????
|
|
||||||
dsmLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
|
||||||
else -- Edit the current value
|
|
||||||
ctx.EditLine = ctx.SelLine
|
|
||||||
originalValue = menuLines[ctx.SelLine].Val
|
|
||||||
dsmLib.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()
|
|
||||||
init_colors()
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
|
||||||
return dsmLib.StartConnection()
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Main
|
|
||||||
local function DSM_Run(event,touchState)
|
|
||||||
local ctx = DSM_Context
|
|
||||||
|
|
||||||
if event == nil then
|
|
||||||
error("Cannot be run as a model script!")
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
return 2
|
|
||||||
end
|
|
||||||
|
|
||||||
if (warningScreenON) then
|
|
||||||
return GUI_Warning(event,touchState)
|
|
||||||
end
|
|
||||||
|
|
||||||
GUI_HandleEvent(event,touchState)
|
|
||||||
|
|
||||||
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
|
|
||||||
|
|
||||||
local refreshInterval = REFRESH_GUI_MS
|
|
||||||
|
|
||||||
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
|
|
||||||
if (ctx.Phase == PHASE.RX_VERSION) 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
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
return 2
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return { init=DSM_Init, run=DSM_Run }
|
|
||||||
@@ -1,932 +0,0 @@
|
|||||||
local toolName = "TNS|DSM Frwd Prog v0.54-beta (MIN)|TNE"
|
|
||||||
|
|
||||||
--local ModelParam = ...
|
|
||||||
|
|
||||||
---- #########################################################################
|
|
||||||
---- # #
|
|
||||||
---- # 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 VERSION = "v0.54-MIN"
|
|
||||||
local LANGUAGE = "en"
|
|
||||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
|
||||||
|
|
||||||
local LOG_FILE = "/LOGS/dsm_min_log.txt"
|
|
||||||
local MSG_FILE = DSMLIB_PATH.."msg_fwdp_" .. LANGUAGE .. ".txt"
|
|
||||||
local MSG_FILE_MIN = DSMLIB_PATH.."MIN_msg_fwdp_" .. LANGUAGE .. ".txt"
|
|
||||||
|
|
||||||
-- Phase
|
|
||||||
local PH_RX_VER, PH_TITLE, PH_TX_INFO, PH_LINES, PH_VALUES = 1, 2, 3, 4, 5
|
|
||||||
local PH_VAL_CHANGING, PH_VAL_WAIT, PH_VAL_CHNG_END = 6, 7, 8
|
|
||||||
local PH_WAIT_CMD, PH_EXIT_REQ, PH_EXIT_DONE = 9, 10, 11
|
|
||||||
|
|
||||||
-- Line Types
|
|
||||||
local LT_MENU = 0x1C
|
|
||||||
local LT_LIST, LT_LIST_VALIDATE, LT_LIST_TOG = 0x6C, 0x0C, 0x4C
|
|
||||||
local LT_VALUE_NOCHANGING = 0x60
|
|
||||||
local LT_VALUE_PERCENT, LT_VALUE_DEGREES = 0xC0, 0xE0
|
|
||||||
|
|
||||||
local Phase = PH_RX_VER
|
|
||||||
local Waiting_RX = 0
|
|
||||||
|
|
||||||
local Text = {}
|
|
||||||
local List_Text = {}
|
|
||||||
local List_Text_Img = {}
|
|
||||||
local Flight_Mode = { [0] = "Flight Mode" }
|
|
||||||
local RxName = {}
|
|
||||||
|
|
||||||
local InactivityTime = 0
|
|
||||||
local Value_Change_Step = 0
|
|
||||||
local TX_Info_Step = 0
|
|
||||||
local TX_Info_Type = 0
|
|
||||||
local originalValue = 0
|
|
||||||
|
|
||||||
local ctx = {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
local Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 }
|
|
||||||
local MenuLines = {}
|
|
||||||
local RX = { Name = "", Version = "" }
|
|
||||||
|
|
||||||
local logFile = nil
|
|
||||||
local logCount = 0
|
|
||||||
|
|
||||||
local LCD_X_LINE_TITLE = 0
|
|
||||||
local LCD_X_LINE_VALUE = 75
|
|
||||||
|
|
||||||
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 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
|
|
||||||
|
|
||||||
---------------- 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 Get_Text(index)
|
|
||||||
local out = Text[index] or string.format("Unknown_%X", index)
|
|
||||||
if (index >= 0x8000) then
|
|
||||||
out = Flight_Mode[0]
|
|
||||||
end
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Get_Text_Value(index)
|
|
||||||
local out = List_Text[index] or Get_Text(index)
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function Get_RxName(index)
|
|
||||||
local out = RxName[index] or string.format("Unknown_%X", index)
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function DSM_Release()
|
|
||||||
multiBuffer(0, 0)
|
|
||||||
Phase = PH_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
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function ChangePhase(newPhase)
|
|
||||||
Phase = newPhase
|
|
||||||
Waiting_RX = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Value_Add(dir)
|
|
||||||
local line = MenuLines[ctx.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
|
|
||||||
|
|
||||||
ChangePhase(PH_VAL_CHANGING)
|
|
||||||
Value_Change_Step = 0
|
|
||||||
end
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
local function GotoMenu(menuId, lastSelectedLine)
|
|
||||||
Menu.MenuId = menuId
|
|
||||||
ctx.SelLine = lastSelectedLine
|
|
||||||
-- Request to load the menu Again
|
|
||||||
ChangePhase(PH_TITLE)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function isSelectable(line)
|
|
||||||
if (line.TextId == 0x00CD) then return true end -- Exceptiom: Level model and capture attitude
|
|
||||||
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 or line.Type == LT_LIST_VALIDATE or line.Type == LT_LIST_TOG
|
|
||||||
end
|
|
||||||
|
|
||||||
local function DSM_Menu(event)
|
|
||||||
if event == EVT_VIRTUAL_EXIT then
|
|
||||||
if Phase == PH_RX_VER then
|
|
||||||
DSM_Release() -- Exit program
|
|
||||||
else
|
|
||||||
if ctx.EditLine ~= nil then -- Editing a Line, need to restore original value
|
|
||||||
MenuLines[ctx.EditLine].Val = originalValue
|
|
||||||
event = EVT_VIRTUAL_ENTER
|
|
||||||
else
|
|
||||||
ChangePhase(PH_EXIT_REQ)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if Phase == PH_RX_VER then return end -- nothing else to do
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_NEXT then
|
|
||||||
if ctx.EditLine ~= nil then
|
|
||||||
Value_Add(1)
|
|
||||||
else
|
|
||||||
-- not changing a value
|
|
||||||
|
|
||||||
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
|
|
||||||
elseif event == EVT_VIRTUAL_PREV then
|
|
||||||
if ctx.EditLine ~= nil 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
|
|
||||||
elseif event == EVT_VIRTUAL_ENTER_LONG then
|
|
||||||
if ctx.EditLine ~= nil then
|
|
||||||
-- reset the value to default
|
|
||||||
--if MenuLines[ctx.SelLine].Type ~= LIST_MENU_NOCHANGING then
|
|
||||||
MenuLines[ctx.SelLine].Val = MenuLines[ctx.SelLine].Def
|
|
||||||
ChangePhase(PH_VAL_CHANGING)
|
|
||||||
Value_Change_Step = 0
|
|
||||||
--end
|
|
||||||
end
|
|
||||||
elseif 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 ctx.EditLine ~= nil then
|
|
||||||
ctx.EditLine = nil -- Done Editting
|
|
||||||
Value_Change_Step = 0
|
|
||||||
ChangePhase(PH_VAL_CHNG_END)
|
|
||||||
else -- Start Editing
|
|
||||||
ctx.EditLine = ctx.SelLine
|
|
||||||
originalValue = MenuLines[ctx.SelLine].Val
|
|
||||||
ChangePhase(PH_VAL_WAIT)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function SendTxInfo(portNo)
|
|
||||||
-- TxInfo_Type=0 : AR636 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 (TX_Info_Step == 0) then
|
|
||||||
-- AR630 family: Both TxInfo_Type (ManinMenu=0x1, Other First Time Configuration = 0x1F)
|
|
||||||
local info = MODEL.DSM_ChannelInfo[portNo]
|
|
||||||
DSM_Send(0x20, 0x06, portNo, portNo, info[0],info[1])
|
|
||||||
LOG_write("DSM_TxInfo_20(Port=#%d, Port Use)\n", portNo)
|
|
||||||
|
|
||||||
if (TX_Info_Type == 0x1F) then
|
|
||||||
TX_Info_Step = 1
|
|
||||||
elseif (TX_Info_Type == 0x00) then
|
|
||||||
TX_Info_Step = 2
|
|
||||||
end
|
|
||||||
elseif (TX_Info_Step == 1) then
|
|
||||||
local info = MODEL.modelOutputChannel[portNo]
|
|
||||||
local leftTravel = math.abs(math.floor(info.min/10))
|
|
||||||
local rightTravel = math.abs(math.floor(info.max/10))
|
|
||||||
|
|
||||||
DSM_Send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel)
|
|
||||||
LOG_write("DSM_TxInfo_23(Port=#%d,ServoTravel(L=%d - R=%d))\n", portNo,leftTravel,rightTravel)
|
|
||||||
|
|
||||||
TX_Info_Step = 2
|
|
||||||
elseif (TX_Info_Step == 2) then
|
|
||||||
local data = {[0]= -- Start at 0
|
|
||||||
{[0]= 0x0, 0x00, 0x07, 0xFF }, -- Ch1 Thr: 0 00 07 FF Subtrim ??
|
|
||||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch2 Ail: 0 8E 07 72 Subtrim 0
|
|
||||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch3 Elev: 0 8E 07 72 Subtrim 0
|
|
||||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch4 Rud: 0 8E 07 72 Subtrim 0
|
|
||||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch5 Gear: 0 8E 07 72 Subtrim 0
|
|
||||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch6 Aux1: 0 8E 07 72 Subtrim 0
|
|
||||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch7 Aux2: 0 8E 07 72 Subtrim 0
|
|
||||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch8 Aux3: 0 8E 07 72 Subtrim 0
|
|
||||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch9 Aux4: 0 8E 07 72 Subtrim 0
|
|
||||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch10 Aux5: 0 8E 07 72 Subtrim 0
|
|
||||||
}
|
|
||||||
local info = data[portNo]
|
|
||||||
local b1,b2,b3,b4 = info[0], info[1], info[2], info[3]
|
|
||||||
|
|
||||||
DSM_Send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it.
|
|
||||||
LOG_write("DSM_TxInfo_21(Port=#%d, SubTrim)\n", portNo)
|
|
||||||
|
|
||||||
if (TX_Info_Type == 0x00) then
|
|
||||||
TX_Info_Step = 5 -- End Step
|
|
||||||
else
|
|
||||||
TX_Info_Step = 3
|
|
||||||
end
|
|
||||||
elseif (TX_Info_Step == 3) then
|
|
||||||
LOG_write("DSM_TxInfo_24?(Port=#%d)\n", portNo)
|
|
||||||
DSM_Send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown
|
|
||||||
TX_Info_Step = 4
|
|
||||||
elseif (TX_Info_Step == 4) then
|
|
||||||
LOG_write("DSM_TxInfo_24?(Port=#%d)\n", portNo)
|
|
||||||
DSM_Send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown
|
|
||||||
TX_Info_Step = 5
|
|
||||||
elseif (TX_Info_Step == 5) then
|
|
||||||
LOG_write("DSM_TxInfo_22(Port=#%d, END of Data)\n", portNo)
|
|
||||||
DSM_Send(0x22, 0x04, 0x00, 0x00)
|
|
||||||
TX_Info_Step = 0 -- Done!!
|
|
||||||
end
|
|
||||||
|
|
||||||
if (TX_Info_Step > 0) then
|
|
||||||
Waiting_RX = 0 -- keep Transmitig
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function DSM_SendRequest()
|
|
||||||
--LOG_write("DSM_SendRequest Phase=%d\n",Phase)
|
|
||||||
-- Need to send a request
|
|
||||||
if Phase == PH_RX_VER then -- request RX version
|
|
||||||
DSM_Send(0x11, 0x06, 0x00, 0x14, 0x00, 0x00)
|
|
||||||
LOG_write("GetVersion()\n")
|
|
||||||
elseif Phase == PH_WAIT_CMD then -- keep connection open
|
|
||||||
DSM_Send(0x00, 0x04, 0x00, 0x00)
|
|
||||||
elseif Phase == PH_TITLE then -- request menu title
|
|
||||||
local menuId = Menu.MenuId
|
|
||||||
if menuId == 0 then
|
|
||||||
DSM_Send(0x12, 0x06, 0x00, 0x14, 0x00, 0x00) -- first menu only
|
|
||||||
else
|
|
||||||
DSM_Send(0x16, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, ctx.SelLine)
|
|
||||||
if (menuId == 0x0001) then -- Executed Save&Reset menu
|
|
||||||
Phase = PH_RX_VER
|
|
||||||
ctx.isReset = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
LOG_write("GetMenu(M=0x%04X,L=%d)\n", menuId, ctx.SelLine)
|
|
||||||
elseif Phase == PH_TX_INFO then -- TX Info
|
|
||||||
SendTxInfo(ctx.CurLine)
|
|
||||||
elseif Phase == PH_LINES then -- request menu lines
|
|
||||||
local menuId = Menu.MenuId
|
|
||||||
if ctx.CurLine == -1 then
|
|
||||||
DSM_Send(0x13, 0x04, int16_MSB(menuId), int16_LSB(menuId)) -- GetFirstLine
|
|
||||||
else
|
|
||||||
DSM_Send(0x14, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, ctx.CurLine) -- line X
|
|
||||||
end
|
|
||||||
LOG_write("GetLines(LastLine=%d)\n", ctx.CurLine)
|
|
||||||
elseif Phase == PH_VALUES then -- request menu values
|
|
||||||
local menuId = Menu.MenuId
|
|
||||||
local valId = MenuLines[ctx.CurLine].ValId
|
|
||||||
DSM_Send(0x15, 0x06,
|
|
||||||
int16_MSB(menuId), int16_LSB(menuId),
|
|
||||||
int16_MSB(valId), int16_LSB(valId))
|
|
||||||
LOG_write("GetValues(LastVId=0x%04X)\n", valId)
|
|
||||||
elseif Phase == PH_VAL_CHANGING then -- send new value: Two steps, Update & Validate
|
|
||||||
local line = MenuLines[ctx.SelLine]
|
|
||||||
local valId = line.ValId
|
|
||||||
if Value_Change_Step == 0 then
|
|
||||||
local value = sInt16ToDsm(line.Val)
|
|
||||||
DSM_Send(0x18, 0x06,
|
|
||||||
int16_MSB(valId), int16_LSB(valId),
|
|
||||||
int16_MSB(value), int16_LSB(value)) -- send current values
|
|
||||||
LOG_write("ChangeValue(VId=0x%04X,Val=%d)\n", valId, value)
|
|
||||||
|
|
||||||
if line.Type == LT_LIST_VALIDATE then -- Incremental Validation??
|
|
||||||
Value_Change_Step = 1
|
|
||||||
Waiting_RX = 0 -- Do SEND in the next step
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Validate Value
|
|
||||||
DSM_Send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId))
|
|
||||||
Value_Change_Step = 0
|
|
||||||
Phase = PH_VAL_WAIT
|
|
||||||
LOG_write("ValidateValue(VId=0x%04X)\n", valId)
|
|
||||||
end
|
|
||||||
elseif Phase == PH_VAL_CHNG_END then
|
|
||||||
DSM_Send(0x1B, 0x04, 0x00, int16_LSB(ctx.SelLine))
|
|
||||||
Value_Change_Step = 0
|
|
||||||
Phase = PH_WAIT_CMD
|
|
||||||
LOG_write("ValueChangeEnd(L=%d)\n", ctx.SelLine)
|
|
||||||
elseif Phase == PH_VAL_WAIT then
|
|
||||||
-- Value Changing Wait
|
|
||||||
DSM_Send(0x1A, 0x04, 0x00, int16_LSB(ctx.SelLine))
|
|
||||||
LOG_write("ValueChangeWait(L=%d)\n", ctx.SelLine)
|
|
||||||
elseif Phase == PH_EXIT_REQ then -- EXIT Request
|
|
||||||
DSM_Send(0x1F, 0x02, 0xAA)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function DSM_ProcessResponse()
|
|
||||||
local cmd = multiBuffer(11)
|
|
||||||
-- LOG_write("DSM_ProcessResponse BEGIN: Cmd=%x\n",cmd)
|
|
||||||
if cmd == 0x01 then -- read version
|
|
||||||
RX.Name = Get_RxName(multiBuffer(13))
|
|
||||||
RX.Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16)
|
|
||||||
--ctx.isReset = false -- no longer resetting
|
|
||||||
Menu.MenuId = 0
|
|
||||||
Phase = PH_TITLE
|
|
||||||
LOG_write("Version: %s %s\n", RX.Name, RX.Version)
|
|
||||||
elseif cmd == 0x02 then -- read menu title
|
|
||||||
local menu = Menu
|
|
||||||
|
|
||||||
menu.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13))
|
|
||||||
menu.TextId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15))
|
|
||||||
menu.Text = 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, 6 do -- clear menu
|
|
||||||
MenuLines[i] = { MenuId = 0, Type = 0, TextId = 0, ValId = 0, Min = 0, Max = 0, Def = 0, Val = nil, Unit, Step }
|
|
||||||
end
|
|
||||||
ctx.CurLine = -1
|
|
||||||
ctx.SelLine = -1 -- highlight Back
|
|
||||||
|
|
||||||
LOG_write("Menu: Mid=0x%04X \"%s\"\n", menu.MenuId, menu.Text)
|
|
||||||
|
|
||||||
if (menu.MenuId == 0x0001) then -- Still in RESETTING MENU???
|
|
||||||
--menu.MenuId = 0
|
|
||||||
Phase = PH_RX_VER
|
|
||||||
else
|
|
||||||
Phase = PH_LINES
|
|
||||||
end
|
|
||||||
elseif cmd == 0x03 then -- read menu lines
|
|
||||||
local i = multiBuffer(14)
|
|
||||||
local type = multiBuffer(15)
|
|
||||||
local line = MenuLines[i]
|
|
||||||
|
|
||||||
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 = Get_Text(line.TextId)
|
|
||||||
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))
|
|
||||||
|
|
||||||
if line.Type == LT_MENU then
|
|
||||||
-- nothing to do on menu entries
|
|
||||||
elseif isListLine(line) 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
|
|
||||||
if (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) then
|
|
||||||
line.Type = LT_VALUE_PERCENT -- Override to Value Percent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if ctx.SelLine == -1 and isSelectable(line) then -- Auto select first selectable line of the menu
|
|
||||||
ctx.SelLine = ctx.CurLine
|
|
||||||
end
|
|
||||||
|
|
||||||
LOG_write("Line: #%d Vid=0x%04X T=0x%02X \"%s\"\n", i, line.ValId, type, line.Text)
|
|
||||||
Phase = PH_LINES
|
|
||||||
elseif cmd == 0x04 then -- read menu values
|
|
||||||
-- Identify the line and update the value
|
|
||||||
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, 6 do -- Find the menu line for this value
|
|
||||||
local line = MenuLines[i]
|
|
||||||
if line.Type ~= 0 then
|
|
||||||
if line.Type ~= LT_MENU and line.ValId == valId then -- identifier of ValueId stored in the line
|
|
||||||
line.Val = value
|
|
||||||
ctx.CurLine = i
|
|
||||||
updatedLine = line
|
|
||||||
|
|
||||||
local valueTxt = value
|
|
||||||
if isListLine(line) then
|
|
||||||
valueTxt = Get_Text_Value(line.Def + value) .. " [" .. value .. "]"
|
|
||||||
end
|
|
||||||
|
|
||||||
LOG_write("Update Value: #%d VId=0x%04X Value=%s\n", i, valId, valueTxt)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (updatedLine == nil) then
|
|
||||||
LOG_write("Cannot Find Line for ValueId=%x\n", valId)
|
|
||||||
end
|
|
||||||
Phase = PH_VALUES
|
|
||||||
elseif cmd == 0x05 then -- Request TX info
|
|
||||||
ctx.CurLine = multiBuffer(12)
|
|
||||||
TX_Info_Type = multiBuffer(13)
|
|
||||||
TX_Info_Step = 0
|
|
||||||
Phase = PH_TX_INFO
|
|
||||||
LOG_write("TXInfoReq: Port=%d T=0x%02X\n", ctx.CurLine, TX_Info_Type)
|
|
||||||
elseif cmd == 0xA7 then -- answer to EXIT command
|
|
||||||
DSM_Release()
|
|
||||||
elseif cmd == 0x00 and Phase == PH_VAL_CHANGING then
|
|
||||||
Phase = PH_VAL_WAIT
|
|
||||||
end
|
|
||||||
|
|
||||||
--LOG_write("DSM_ProcessResponse END: Cmd=%x\n",cmd)
|
|
||||||
return cmd
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function DSM_Send_Receive()
|
|
||||||
if Waiting_RX == 0 then
|
|
||||||
Waiting_RX = 1
|
|
||||||
DSM_SendRequest()
|
|
||||||
multiBuffer(10, 0x00);
|
|
||||||
InactivityTime = getTime() + 200 -- Reset Inactivity timeout
|
|
||||||
-- -- -- -- -- -- -- -- -- -- -- -- receive part -- -- -- -- -- -- -- -- -- -- -- -- --
|
|
||||||
elseif multiBuffer(10) == 0x09 then
|
|
||||||
local cmd = DSM_ProcessResponse()
|
|
||||||
-- Data processed
|
|
||||||
multiBuffer(10, 0x00)
|
|
||||||
if (cmd > 0x00) then -- Any non NULL response
|
|
||||||
-- Only change to SEND mode if we received a valid response (Ignore NULL Responses, that are really heartbeat i most cases)
|
|
||||||
Waiting_RX = 0
|
|
||||||
InactivityTime = getTime() + 200 -- Reset Inactivity timeout
|
|
||||||
end
|
|
||||||
else -- No Send or Receive,
|
|
||||||
-- Check if enouth time has passed from last transmit/receive activity
|
|
||||||
if getTime() > InactivityTime then
|
|
||||||
InactivityTime = getTime() + 200
|
|
||||||
Waiting_RX = 0 -- Switch to Send mode to send heartbeat
|
|
||||||
|
|
||||||
if Phase == PH_EXIT_REQ then
|
|
||||||
DSM_Release()
|
|
||||||
end
|
|
||||||
|
|
||||||
if Phase ~= PH_RX_VER and Phase ~= PH_VAL_WAIT then
|
|
||||||
Phase = PH_WAIT_CMD
|
|
||||||
end
|
|
||||||
end
|
|
||||||
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
|
|
||||||
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 ver_rx_count = 0
|
|
||||||
|
|
||||||
local function DSM_Display()
|
|
||||||
lcd.clear()
|
|
||||||
--Draw RX Menu
|
|
||||||
if Phase == PH_RX_VER then
|
|
||||||
lcd.drawText(1, 0, "DSM Frwd Prog "..VERSION, INVERS)
|
|
||||||
|
|
||||||
local msgId = 0x300 -- Waiting for RX
|
|
||||||
if (ctx.isReset) then msgId=0x301 end -- Waiting for Reset
|
|
||||||
lcd.drawText(0, 3 * LCD_Y_LINE_HEIGHT, Get_Text(msgId), BLINK)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- display Program version or RX version
|
|
||||||
local msg = RX.Name .. " v" .. RX.Version
|
|
||||||
if (ver_rx_count < 100) then
|
|
||||||
msg = RX.Name .. " v" .. RX.Version
|
|
||||||
ver_rx_count = ver_rx_count + 1
|
|
||||||
else
|
|
||||||
msg = "Frwd Prog "..VERSION
|
|
||||||
ver_rx_count = ver_rx_count + 1
|
|
||||||
if (ver_rx_count > 200) then ver_rx_count=0 end
|
|
||||||
end
|
|
||||||
lcd.drawText(30, 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 = Get_Text(line.TextId)
|
|
||||||
|
|
||||||
if (line.TextId >= 0x8000) then -- Flight mode
|
|
||||||
heading = " " .. Flight_Mode[0] .. " "
|
|
||||||
if (line.Val==nil) then heading = heading .. "--" else heading = heading .. ((line.Val or 0) + 1) end
|
|
||||||
else
|
|
||||||
local text = "-"
|
|
||||||
if line.Type ~= LT_MENU then -- list/value
|
|
||||||
if line.Val ~= nil then
|
|
||||||
if isListLine(line) then
|
|
||||||
local textId = line.Val + line.Def
|
|
||||||
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(0, 20, imgDesc)
|
|
||||||
end
|
|
||||||
elseif (line.Type == LT_VALUE_PERCENT) then
|
|
||||||
text = line.Val .. " %"
|
|
||||||
elseif (line.Type == LT_VALUE_DEGREES) then
|
|
||||||
text = line.Val .. " @"
|
|
||||||
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, attrib + RIGHT) -- display value
|
|
||||||
attrib = TEXT_ATTR
|
|
||||||
end
|
|
||||||
end -- Flight mode
|
|
||||||
lcd.drawText(0, 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(0, LCD_Y_LOWER_BUTTONS, "Prev", ctx.SelLine == 8)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function load_msg_from_file(fileName, mem, Text, List_Text, List_Text_Img, RxName, Flight_Mode)
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
local function clean_msg(Text, Flight_Mode)
|
|
||||||
local function clean_line(c)
|
|
||||||
if (c==nil) then return c end
|
|
||||||
local pos
|
|
||||||
c, pos = string.gsub(c, "/b$", "")
|
|
||||||
c, pos = string.gsub(c, "/c$", "")
|
|
||||||
c, pos = string.gsub(c, "/r$", "")
|
|
||||||
c, pos = string.gsub(c, "/p$", "")
|
|
||||||
c, pos = string.gsub(c, "/m$", "")
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Clean the line of special markers that are only used in color vesion
|
|
||||||
for i = 0, 0x0300 do
|
|
||||||
Text[i] = clean_line(Text[i])
|
|
||||||
collectgarbage("collect")
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 0, #Flight_Mode do
|
|
||||||
-- Clean the line of special markers that are only used in color vesion
|
|
||||||
Flight_Mode[i] = clean_line(Flight_Mode[i])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function DSM_Init_Model()
|
|
||||||
MODEL.DSM_ChannelInfo= {[0]= -- Start array at position 0
|
|
||||||
{[0]= 0x00, 0x40}, -- Ch1 Thr (0x40)
|
|
||||||
{[0]= 0x00, 0x01}, -- Ch2 Ail (0x01)
|
|
||||||
{[0]= 0x00, 0x02}, -- Ch2 ElE (0x02)
|
|
||||||
{[0]= 0x00, 0x04}, -- Ch4 Rud (0x04)
|
|
||||||
{[0]= 0x00, 0x00}, -- Ch5 Gear (0x00)
|
|
||||||
{[0]= 0x00, 0x00}, -- Ch6 Aux1 (0x00)
|
|
||||||
{[0]= 0x00, 0x00}, -- Ch7 Aux2 (0x00)
|
|
||||||
{[0]= 0x00, 0x00}, -- Ch8 Aux3 (0x00)
|
|
||||||
{[0]= 0x00, 0x00}, -- Ch9 Aux4 (0x00)
|
|
||||||
{[0]= 0x00, 0x00} -- Ch10 Aux5 (0x00)
|
|
||||||
}
|
|
||||||
|
|
||||||
MODEL.modelOutputChannel = {[0]=
|
|
||||||
{min=1000, max=1000}, -- Ch1
|
|
||||||
{min=1000, max=1000}, -- Ch2
|
|
||||||
{min=1000, max=1000}, -- Ch3
|
|
||||||
{min=1000, max=1000}, -- Ch4
|
|
||||||
{min=1000, max=1000}, -- Ch5
|
|
||||||
{min=1000, max=1000}, -- Ch6
|
|
||||||
{min=1000, max=1000}, -- Ch7
|
|
||||||
{min=1000, max=1000}, -- Ch8
|
|
||||||
{min=1000, max=1000}, -- Ch9
|
|
||||||
{min=1000, max=1000} -- Ch10
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Init
|
|
||||||
local function DSM_Init()
|
|
||||||
LOG_open()
|
|
||||||
LOG_write("-------- NEW SESSION --------------------\n")
|
|
||||||
|
|
||||||
DSM_Init_Model()
|
|
||||||
|
|
||||||
--[[
|
|
||||||
if (ModelParam~=nil) then
|
|
||||||
LOG_write("Got MODEL PARAMETER... copying\n")
|
|
||||||
MODEL.DSM_ChannelInfo = ModelParam.DSM_ChannelInfo
|
|
||||||
else
|
|
||||||
LOG_write("NO-PARMETER --- Create DEFAULT")
|
|
||||||
end
|
|
||||||
--]]
|
|
||||||
|
|
||||||
collectgarbage("collect")
|
|
||||||
LOG_write("Mem before msg =%d\n",collectgarbage("count"))
|
|
||||||
load_msg_from_file(MSG_FILE, 10, Text, List_Text, List_Text_Img, RxName, Flight_Mode)
|
|
||||||
collectgarbage("collect")
|
|
||||||
LOG_write("Mem after msg =%d\n",collectgarbage("count"))
|
|
||||||
load_msg_from_file(MSG_FILE_MIN, 4, Text, List_Text, List_Text_Img, RxName, Flight_Mode)
|
|
||||||
collectgarbage("collect")
|
|
||||||
LOG_write("Mem after msg2 =%d\n",collectgarbage("count"))
|
|
||||||
clean_msg(Text,Flight_Mode)
|
|
||||||
collectgarbage("collect")
|
|
||||||
|
|
||||||
--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'))
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Main
|
|
||||||
local function DSM_Run(event)
|
|
||||||
if event == nil then
|
|
||||||
error("Cannot be run as a model script!")
|
|
||||||
return 2
|
|
||||||
else
|
|
||||||
DSM_Display()
|
|
||||||
DSM_Menu(event)
|
|
||||||
DSM_Send_Receive()
|
|
||||||
end
|
|
||||||
if Phase == PH_EXIT_DONE then
|
|
||||||
LOG_close()
|
|
||||||
return 2
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return { init = DSM_Init, run = DSM_Run }
|
|
||||||
@@ -1,467 +0,0 @@
|
|||||||
# Forward Programing Protocol
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
DSM, DSMX and DSM Forward Programming are propietary protocol from the **Spektrum** radio brand. Since they don't make this information public, we have to reverse engineer it by analyzing the data exchanged between the RX and TX.
|
|
||||||
|
|
||||||
This document descrives what we know so far.
|
|
||||||
|
|
||||||
Thanks to **Pascal Langer** (Author of the Multi-Module) for the initial reverse engineering of the protocol and first version of the code that has been used for a while (Version 0.2)
|
|
||||||
|
|
||||||
Thanks to **Francisco Arzu** for taking the time to continue the work on reverse engineering, documenting and making the code more understandable.
|
|
||||||
|
|
||||||
New Capabilities in Version 0.5
|
|
||||||
- Log files of the conversation between RX/TX
|
|
||||||
- Improve the GUI (EdgeTX touch screen)
|
|
||||||
- Reversed engineer other things to make it work completly.
|
|
||||||
|
|
||||||
# Menu Title and Lines
|
|
||||||
|
|
||||||
The menu to be displayed is stored at the RX, the GUI only renders the menu title and menu lines received. The tipical conversation with the RX will be to ask for a menu (using the menuId number), and then wait for the data to come. The first thing will be the Menu (header) data, later we request the next 6 lines (one at a time), and optionally the values for each line.
|
|
||||||
|
|
||||||
A typical exchange will look like this in the log:
|
|
||||||
|
|
||||||
SEND DSM_getMenu(MenuId=0x1010 LastSelectedLine=0)
|
|
||||||
RESPONSE Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
|
||||||
SEND DSM_getFirstMenuLine(MenuId=0x1010)
|
|
||||||
RESPONSE MenuLine: L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ]
|
|
||||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=0)
|
|
||||||
RESPONSE MenuLine: L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ]
|
|
||||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=1)
|
|
||||||
RESPONSE MenuLine: L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ]
|
|
||||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=2)
|
|
||||||
RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
|
|
||||||
|
|
||||||
## Menu
|
|
||||||
|
|
||||||
The menu has the following information:
|
|
||||||
|
|
||||||
Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
|
||||||
|
|
||||||
- `MenuId`: The menu ID number of the menu (hex, 16 bit number)
|
|
||||||
- `PrevId`: The menu ID of the previous menu (for navigation), Log show as `"P="`
|
|
||||||
- `NextId`: The menu ID of the next menu (for navigation), Log shows as `"N="`
|
|
||||||
- `BackId`: The menu ID of the back menu (for navigation), Log shows as `"B="`
|
|
||||||
- `TextId`: The message number to display (16 bits, Hex). Log shows as [`0xXX`] after the message.
|
|
||||||
- `Text`: Retrived using the `TextId` from the script message `Text` array.
|
|
||||||
|
|
||||||
## Menu Lines
|
|
||||||
|
|
||||||
The menu lines has the following information:
|
|
||||||
|
|
||||||
L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1021 ]
|
|
||||||
L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ]
|
|
||||||
L[#2 T=LM VId=0x1002 Text="AS3X"[0x1DC] Val=1|"Act" NL=(0->1,0,S=3) [3->4,3] MId=0x1021 ]
|
|
||||||
|
|
||||||
- `MenuId`: of the menu they beling to. Log show as `"MId="` at the end.
|
|
||||||
- `LineNum`: Line number (0..5). The line number in the screen. Log show as # in the beginning
|
|
||||||
- `Type`: Type of Line, Log shows as `"T="` (explanation later)
|
|
||||||
- `TextId`: The message number to display (16 bits, Hex). Log shows as [`0xXXXX`] after the message.
|
|
||||||
- `Text`: Retrived using the `TextId` from the script message `Text` array.
|
|
||||||
- `ValueId`: The value or menu ID of the line. Log shows as `"VId="` (16 bits, Hex).
|
|
||||||
- `Value Range`: Shows as [`Min`->`Max`, `Default`]. This is the RAW data comming from the RX
|
|
||||||
- `NL`: Computed Normalized LIST (0 reference) for List Values. Source is the RAW range. For example, for lines of list of values. `[3->4,3]` is tranlated to `NL=(0->1,0,S=3)` since the value is also normalize to 0. `"S="` means the initial entry in the `List_Text` array
|
|
||||||
- `Val`: Current value for line who hold data. Relative to 0 for List Values. For List Values, the log will show the translation of the value to display text. example: `Val=1|"Act"` that is coming from `List_Value[4]`
|
|
||||||
|
|
||||||
## Type of Menu Lines
|
|
||||||
|
|
||||||
- `LINE_TYPE.MENU (Log: "T=M")`: This could be regular text or a navigation to another menu. if `ValueId` is the same as the current MenuId (`MId=`), is a plain text line (navigation to itself). If the `ValueId` is not the current menuId, then `ValueId` is the MenuId to navigate to.
|
|
||||||
|
|
||||||
We have found only one exception to the plain text rule, a true navigation to itself, in that case, in the text of the menu, you can use the "/M" flag at the end of the text to force it to be a menu button.
|
|
||||||
|
|
||||||
Example, FM_Channel is a navigation to menuId=0x7CA6.
|
|
||||||
|
|
||||||
L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ]
|
|
||||||
|
|
||||||
- `LINE_TYPE.LIST_MENU_NC (Log T=LM_nc)`: This is a line that shows as text in the GUI. The numeric value is translated to the proper text. The range is important, since it descrives the range of posible values. No incremental RX changes, only at the end.
|
|
||||||
|
|
||||||
Example: List of Values, List_Text[] starts at 53, ends at 85, with a default of 85. When normalized to 0, is a range from 0->32 for the numeric value. The Display value `Aux1` is retrive from `List_Text[6+53]`.
|
|
||||||
|
|
||||||
L[#0 T=LM_nc VId=0x1000 Text="FM Channel"[0x78] Val=6|"Aux1" NL=(0->32,0,S=53) [53->85,53] MId=0x7CA6 ]
|
|
||||||
|
|
||||||
- `LINE_TYPE.LIST_MENU_TOG (Log T=L_tog)`: Mostly the same as LIST_MENU_NC, but is just 2 values. (ON/OFF, Ihn/Act, etc). Should be a toggle in the GUI.
|
|
||||||
|
|
||||||
L[#2 T=LM_tog VId=0x1002 Text="AS3X"[0x1DC] Val=1|"Act" NL=(0->1,0,S=3) [3->4,3] MId=0x1021 ]
|
|
||||||
|
|
||||||
- `LINE_TYPE.LIST_MENU (Log T=LM)`: Mostly the same as LIST_MENU_NC, but incremental changes to the RX. Some times, it comes with a strange range `[0->244,Default]`. Usually this means that the values are not contiguos range; usually Ihn + Range. Still haven't found where in the data the correct range comes from.
|
|
||||||
|
|
||||||
Example: Valid Values: 3, 176->177 (Inh, Self-Level/Angle Dem, Envelope)
|
|
||||||
L[#3 T=LM VId=0x1003 Text="Safe Mode"[0x1F8] Val=176|"Self-Level/Angle Dem" NL=(0->244,3,S=0) [0->244,3] MId=0x1021 ]
|
|
||||||
|
|
||||||
- `LINE_TYPE.VALUE_NUM_I8_NC (Log: "T=V_nc")`: This line is editable, but is not updated to the RX incrementally, but only at the end. The Flight Mode line is of this type, so we have to check the TextId to differenciate between Flight mode and an Editable Value.
|
|
||||||
Fligh Mode TextId is between 0x8000 and 0x8003
|
|
||||||
|
|
||||||
Example, Flight mode comes from Variable ValId=0x1000, with current value of 1. Range of the Value is 0..10.
|
|
||||||
|
|
||||||
L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1021 ]
|
|
||||||
|
|
||||||
|
|
||||||
- `LINE_TYPE.VALUE_NUM_I8 (Log T=V_i8)`: 8 bit number (1 byte)
|
|
||||||
- `LINE_TYPE.VALUE_NUM_I16' (Log T=V_i16)`: 16 Bit number (2 bytes)
|
|
||||||
- `LINE_TYPE.VALUE_NUM_SI16 (Log T=V_si16)`: Signed 16 bit number (2 bytes)
|
|
||||||
- `LINE_TYPE.VALUE_PERCENT (Log T=L_%)`: Shows a Percent Value. 1 Byte value.
|
|
||||||
- `LINE_TYPE.VALUE_DEGREES (Log T=L_de)`: Shows a Degrees VAlue. 1 Byte value.
|
|
||||||
|
|
||||||
|
|
||||||
## LIST_TYPE Bitmap
|
|
||||||
TYPE|Sum|Hex|7 Signed|6 Valid Min/Max??|5 No-Inc-Changing|4 Menu|3 List-Menu|2 text / number|1|0 - 16 bits
|
|
||||||
|-|-|-|-|-|-|-|-|-|-|-
|
|
||||||
|MENU|Text|0x1C|0|0|0|1|1|1|0|0
|
|
||||||
|LIST_MENU|Text|0x0C|0|0|0|0|1|1|0|0
|
|
||||||
|LIST_MENU_TOG|Text|0x4C|0|1|0|0|1|1|0|0
|
|
||||||
|LIST_MENU_NC|Text, NC|0x6C|0|1|1|0|1|1|0|0
|
|
||||||
|VALUE_NUM_I8_NC|I8, NC|0x60|0|1|1|0|0|0|0|0
|
|
||||||
|VALUE_PERCENT|S8|0xC0|1|1|0|0|0|0|0|0
|
|
||||||
|VALUE_DEGREES|S8 NC|0xE0|1|1|1|0|0|0|0|0
|
|
||||||
|VALUE_NUM_I8|I8|0x40|0|1|0|0|0|0|0|0
|
|
||||||
|VALUE_NUM_I16|I16|0x41|0|1|0|0|0|0|0|1
|
|
||||||
|VALUE_NUM_SI16|S16|0xC1|1|1|0|0|0|0|0|1
|
|
||||||
|
|
||||||
|
|
||||||
## Important Behavioral differences when updating values
|
|
||||||
|
|
||||||
Values who are editable, are updated to RX as they change. For example, when changing attitude trims, the servo moves as we change the value in real-time.
|
|
||||||
|
|
||||||
LIST_MENU_NC, VALUE_NUM_I8_NC don't update the RX as it changes. It changes only in the GUI, and only update the RX at the end when confirmed the value. (NO-INC-CHANGES Bit)
|
|
||||||
|
|
||||||
After finishing updating a value, a validation command is sent. RX can reject the current value, and will change it to the nearest valid value.
|
|
||||||
|
|
||||||
## Special Menus
|
|
||||||
|
|
||||||
Seems like menuId=0x0001 is special. When you navigate to this menu, the RX reboots.
|
|
||||||
When this happens, we need to start from the beginning as if it was a new connection.
|
|
||||||
|
|
||||||
# Send and Receive messages
|
|
||||||
|
|
||||||
To comunicate with the Multi-Module, Lua scripts in OpenTx/EdgeTx has access to the `Multi_Buffer`. Writting to it will send data to RX, received data will be read from it.
|
|
||||||
|
|
||||||
For our specific case, this is how the Multi_Buffer is used:
|
|
||||||
|
|
||||||
|0..2|3|4..9|10..25
|
|
||||||
|--|--|--|--
|
|
||||||
|DSM|0x70+len|TX->RX data|RX->TX Data
|
|
||||||
|
|
||||||
To write a new DSM Fwd Programing command, write the data to address 4..9, and later set the address 3 with the length.
|
|
||||||
|
|
||||||
When receiving data, address 10 will have the message type we are receiving, or 0 if nothing has been received.
|
|
||||||
|
|
||||||
## Starting a new DSM Forward programming Connection
|
|
||||||
|
|
||||||
- Write 0x00 at address 3
|
|
||||||
- Write 0x00 at address 10
|
|
||||||
- Write "DSM" at address 0..2
|
|
||||||
|
|
||||||
## Disconnect
|
|
||||||
|
|
||||||
- Write 0x00 at address 0
|
|
||||||
|
|
||||||
|
|
||||||
# Request Messages (TX->RX)
|
|
||||||
|
|
||||||
## DSM_sendHeartbeat()
|
|
||||||
keep connection open.. We need to send it every 2-3 seconds, otherwise the RX will force close the connection by sending the TX an Exit_Confirm message.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg| Len? | ?? | ??
|
|
||||||
0x00|0x04|0x00|0x00
|
|
||||||
|
|
||||||
SEND DSM_sendHeartbeat()
|
|
||||||
DSM_SEND: [00 04 00 00 ]
|
|
||||||
|
|
||||||
## DSM_getRxVersion()
|
|
||||||
Request the RX information
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg| Len? | ?? | ?? |??|??
|
|
||||||
0x11|0x06|0x00|0x14|0x00|0x00
|
|
||||||
|
|
||||||
SEND DSM_getRxVersion()
|
|
||||||
DSM_SEND: [11 06 00 14 00 00 ]
|
|
||||||
|
|
||||||
## DSM_getMainMenu()
|
|
||||||
Request data for the main menu of the RX
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg| Len? | ?? | ?? |??|??
|
|
||||||
0x12|0x06|0x00|0x14|0x00|0x00
|
|
||||||
|
|
||||||
SEND DSM_getMainMenu()
|
|
||||||
DSM_SEND: [12 06 00 14 00 00 ]
|
|
||||||
|
|
||||||
|
|
||||||
## DSM_getMenu(menuId, lastSelLine)
|
|
||||||
Request data for Menu with ID=`menuId`. lastSelLine is the line that was selected to navigate to that menu. Most menus works with 0, but for some special "Enter Bind Mode", "Factory Reset", "Save to Backup" they will not work if we send 0, has to be the line who was selected in the confirmation menu line "Apply".
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (line#)??| LSB (line#)
|
|
||||||
0x16|0x06|0x10|0x60|0x00|0x01
|
|
||||||
|
|
||||||
SEND DSM_getMenu(MenuId=0x1060 LastSelectedLine=1)
|
|
||||||
DSM_SEND: [16 06 10 60 00 01 ]
|
|
||||||
|
|
||||||
## DSM_getFirstMenuLine(menuId)
|
|
||||||
Request the first line of a menu identified as `menuId`. The response will be the first line of the menu. Some times, it return lines shown as `'MenuUknownLine_0x05'` that we still are trying to understand what they are for.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (menuId) | LSB (MenuId)
|
|
||||||
0x13|0x04|0x10|0x60
|
|
||||||
|
|
||||||
SEND DSM_getFirstMenuLine(MenuId=0x1000)
|
|
||||||
DSM_SEND: [13 04 10 00 ]
|
|
||||||
|
|
||||||
## DSM_getNextMenuLine(menuId, curLine)
|
|
||||||
Request the retrival of the next line following the current line. Response is either the next line, or the next value, or nothing.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (line#)??| LSB (line#)
|
|
||||||
0x14|0x06|0x10|0x60|0x00|0x01
|
|
||||||
|
|
||||||
SEND DSM_getNextLine(MenuId=0x1000,LastLine=1)
|
|
||||||
DSM_SEND: [14 06 10 00 00 01 ]
|
|
||||||
|
|
||||||
## DSM_getNextMenuValue(menuId, valId, text)
|
|
||||||
Retrive the next value after the last `ValId` of the current `menuId`. text is just for debugging purposes to show the header of the value been retrived.
|
|
||||||
The Response is a Menu Value or nothing if no more data.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (ValId)| LSB (ValId)
|
|
||||||
0x15|0x06|0x10|0x61|0x10|0x00
|
|
||||||
|
|
||||||
SEND DSM_getNextMenuValue(MenuId=0x1061, LastValueId=0x1000) Extra: Text="Outputs"
|
|
||||||
DSM_SEND: [15 06 10 61 10 00 ]
|
|
||||||
|
|
||||||
## DSM_updateMenuValue(valId, val, text, line)
|
|
||||||
Updates the value identified as `valId` with the numeric value `val`. `text` and `line` are there to add debugging info. No response is expected.
|
|
||||||
|
|
||||||
If the value is negative, it has to be translated to the proper DSM negative representaion.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (ValId) | LSB (ValId) | MSB (Value)| LSB (Value)
|
|
||||||
0x18|0x06|0x??|0x??|0x??|0x??
|
|
||||||
|
|
||||||
DSM_updateMenuValue(valId, val, text, line)
|
|
||||||
-->DSM_send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value))
|
|
||||||
|
|
||||||
## DSM_validateMenuValue(valId, text, line)
|
|
||||||
Validates the value identified as `valId`. `text` and `line` are there to add debugging info. The RX can response an Update value if the value is not valid and needs to be corrected.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (ValId) | LSB (ValId)
|
|
||||||
0x19|0x06|0x??|0x??
|
|
||||||
|
|
||||||
|
|
||||||
DSM_validateMenuValue(valId, text, line)
|
|
||||||
-> DSM_send(0x19, 0x06, int16_MSB(valId), int16_LSB(valId))
|
|
||||||
|
|
||||||
## DSM_menuValueChangingWait(valId, text, line)
|
|
||||||
Durin editing, this serves as a heartbeat that we are editing the value. The value identified as `valId`. `text` and `line` are there to add debugging info. The RX can response an Update value or a NUL response.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len?? | MSB (ValId) | LSB (ValId)
|
|
||||||
0x1A|0x06|0x??|0x??
|
|
||||||
|
|
||||||
DSM_menuValueChangingWait(valId, text, line)
|
|
||||||
->DSM_send(0x1A, 0x06, int16_MSB(valId), int16_LSB(valId))
|
|
||||||
|
|
||||||
## DSM_exitRequest()
|
|
||||||
Request to end the DSM Frd Prog connection. Will reponse with an exit confirmation.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len?? | ??
|
|
||||||
0x1F|0x02|0xAA
|
|
||||||
|
|
||||||
CALL DSM_exitRequest()
|
|
||||||
DSM_SEND: [1F 02 AA ]
|
|
||||||
|
|
||||||
# Response Messages (RX->TX)
|
|
||||||
|
|
||||||
All responses will have the a response byte in Multi_Buffer[10]=0x09, and the type of message in Multi_Buffer[11].
|
|
||||||
|
|
||||||
## RX Version Response
|
|
||||||
|
|
||||||
Returns the information about the current RX.
|
|
||||||
|
|
||||||
The Display text of name name of the RX is retrive from the `RX_Name` array.
|
|
||||||
|
|
||||||
|10|11|12|13|14|15|16
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
|Resp|Msg|?? |RxId|Major|Minor|Patch
|
|
||||||
|0x09|0x01|0x00|0x1E|0x02|0x26|0x05
|
|
||||||
|
|
||||||
RESPONSE RX: 09 01 00 1E 02 26 05
|
|
||||||
RESPONSE Receiver=AR631 Version 2.38.5
|
|
||||||
|
|
||||||
## Menu Response
|
|
||||||
Returns the menu information to display and navigation.
|
|
||||||
The Display text for the menu is retrive from the `Text` array.
|
|
||||||
|
|
||||||
|
|
||||||
|10|11|12|13|14|15|16|17|18|19|20|21
|
|
||||||
|--|--|--|--|--|--|--|--|--|--|--|--
|
|
||||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|LSB (TextId)|MSB (TextId)|LSB (PrevId)|MSB (PrevId)|LSB (NextId)|MSB (NextId)|LSB (BackId)|MSB (BackId)
|
|
||||||
|0x09|0x02|0x5E|0x10|0x27|0x02|0x00|0x00|0x00|0x00|0x00|0x10
|
|
||||||
|
|
||||||
RESPONSE RX: 09 02 5E 10 27 02 00 00 00 00 00 10 00 00 00 00
|
|
||||||
RESPONSE Menu: M[Id=0x105E P=0x0 N=0x0 B=0x1000 Text="Other settings"[0x227]]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Menu Line Response
|
|
||||||
Returns the menu line information.
|
|
||||||
|
|
||||||
The Display text for the menu line is retrive from the `Text` array.
|
|
||||||
`Min`,`Max` and `Default` can be signed numbers.
|
|
||||||
|
|
||||||
|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25
|
|
||||||
|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
|
|
||||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|Line#|Line Type|LSB (TextId)|MSB (TextId)|LSB (ValId)|MSB (ValId)|LSB (Min)|MSB (Min)|LSB (Max)|MSB (Max)|LSB (Def)|MSB (Def)
|
|
||||||
|0x09|0x03|0x61|0x10|0x00|0x6C|0x50|0x00|0x00|0x10|0x36|0x00|0x49|0x00|0x36|0x00
|
|
||||||
|
|
||||||
RESPONSE RX: 09 03 61 10 00 6C 50 00 00 10 36 00 49 00 36 00
|
|
||||||
RESPONSE MenuLine: L[#0 T=LM_nc VId=0x1000 Text="Outputs"[0x50] Val=nil NL=(0->19,0,S=54) [54->73,54] MId=0x1061 ]
|
|
||||||
|
|
||||||
## Menu Line Value Response
|
|
||||||
Returns the Value for a line.
|
|
||||||
|
|
||||||
The response updates the Value in the line identified by `ValId`.
|
|
||||||
The Display text for the Value, when it is a list, is retrive from the `List_Text` array.
|
|
||||||
|
|
||||||
|10|11|12|13|14|15|16|17
|
|
||||||
|--|--|--|--|--|--|--|--
|
|
||||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|LSB (ValId)|MSB (ValId)|LSB (Value)|MSB (Value)
|
|
||||||
|0x09|0x04|0x61|0x10|0x00|0x10|0x00|0x00
|
|
||||||
|
|
||||||
RESPONSE RX: 09 04 61 10 00 10 00 00
|
|
||||||
RESPONSE MenuValue: UPDATED: L[#0 T=L_m0 VId=0x1000 Text="Outputs"[0x50] Val=0|"Throttle" NL=(0->19,0,S=54) [54->73,54] MId=0x1061 ]
|
|
||||||
|
|
||||||
## Exit Response
|
|
||||||
Response from a Exit Request.
|
|
||||||
|
|
||||||
|10|11
|
|
||||||
|--|--
|
|
||||||
|Resp|Msg
|
|
||||||
|0x09|0x07
|
|
||||||
|
|
||||||
RESPONSE RX: 09 A7
|
|
||||||
RESPONSE Exit Confirm
|
|
||||||
|
|
||||||
## NULL Response
|
|
||||||
Can be use as a response, or heartbeat from the RX to keep the connection open.
|
|
||||||
|
|
||||||
|10|11
|
|
||||||
|--|--
|
|
||||||
|Resp|Msg
|
|
||||||
|0x09|0x00
|
|
||||||
|
|
||||||
RESPONSE RX: 09 00
|
|
||||||
RESPONSE NULL
|
|
||||||
|
|
||||||
|
|
||||||
# Unknown Lines
|
|
||||||
TOTALLY UNKNOWN WHAT THIS ARE FOR.. but only works for the Main Menu..
|
|
||||||
Other menus they just loop on line=0 forever.
|
|
||||||
|
|
||||||
## DSM_getNextUknownLine_0x05(menuId, curLine)
|
|
||||||
|
|
||||||
|
|
||||||
Request the retrival of the next Unknown line following the current line. Response is either the next unknow line, next menu line, or the next value, or nothing.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9| Comment
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | Line# | Line# | 0x00 | Formula(line#)??
|
|
||||||
0x20|0x06|0x00|0x00|0x00|0x40 | LastLineLine=0 retrieval
|
|
||||||
0x20|0x06|0x01|0x01|0x00|0x01| LastLineLine=1 retrieval
|
|
||||||
0x20|0x06|0x02|0x02|0x00|0x02| LastLineLine=2 retrieval
|
|
||||||
0x20|0x06|0x03|0x03|0x00|0x04| LastLineLine=3 retrieval
|
|
||||||
0x20|0x06|0x04|0x04|0x00|0x00| LastLineLine=4 retrieval
|
|
||||||
0x20|0x06|0x05|0x05|0x00|0x00| LastLineLine=5 retrieval
|
|
||||||
|
|
||||||
## Unknown Line Response
|
|
||||||
We still don't know what is this for, but we have to retrive them and skip then. Works for main menu, but when it happens in another menus, usually we stay in an infinite loop retrieving line=0
|
|
||||||
|
|
||||||
|10|11|12|13|14|15|16|17
|
|
||||||
|--|--|--|--|--|--|--|--
|
|
||||||
|Resp|Msg|LSB (line#)
|
|
||||||
|0x09|0x05|0x00|0x01|0x00|0x00|0x00|0x07
|
|
||||||
|0x09|0x05|0x01|0x01|0x00|0x00|0x00|0x07
|
|
||||||
|
|
||||||
## Interaction on Main Menu
|
|
||||||
This is the normal interaction for the main menu. As you can see, it iterates on the 6 Unknow lines (0..5), and afterwards, it starts sending normal menu lines.
|
|
||||||
|
|
||||||
SEND DSM_getFirstMenuLine(MenuId=0x1000)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=1 DATA=RX: 09 05 01 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=1)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=2 DATA=RX: 09 05 02 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=2)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=3 DATA=RX: 09 05 03 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=3)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=4 DATA=RX: 09 05 04 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=4)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=5 DATA=RX: 09 05 05 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=5)
|
|
||||||
RESPONSE MenuLine: L[#0 T=M VId=0x1010 Text="Gyro settings"[0xF9] MId=0x1000 ]
|
|
||||||
|
|
||||||
## Other menus
|
|
||||||
If it hapen on other menus. Usualy stays in an infinite loop until it crash/exits.
|
|
||||||
The screen will show **"Error: Cannot Load Menu Lines from RX"**
|
|
||||||
|
|
||||||
The log will look like:
|
|
||||||
|
|
||||||
DSM_getMenu(MenuId=0x104F LastSelectedLine=1)
|
|
||||||
RESPONSE Menu: M[Id=0x104F P=0x0 N=0x0 B=0x1000 Text="First Time Setup"[0x4A]]
|
|
||||||
SEND DSM_getFirstMenuLine(MenuId=0x104F)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
ERROR: Received Same menu line
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
ERROR: Received Same menu line
|
|
||||||
|
|
||||||
We found that sometimes, Overriding LastSelectedLine to 0 solves the problem for some specific menus. Not for all (for other, is the oposite (0->1)). But at least no unknown lines are returned with this hack for AR631/AR637. Maybe others also needed.
|
|
||||||
|
|
||||||
**Overriding to Zero is not a good solution for every menu. Some menus needs the LastLine to know the behaviour (for example, Factory Reset the RX, Save Backup, Restore Backup, Enter Bind Mode, Some sensor Calibration). Thats why we cannot do it blindly.**
|
|
||||||
|
|
||||||
Here is the current code to fix some of this problems in AR631/AR637.
|
|
||||||
Function `DSM_SelLine_HACK()`
|
|
||||||
|
|
||||||
if (ctx.RX.Id == RX.AR637T or ctx.RX.Id == RX.AR637TA or ctx.RX.Id == RX.AR631) then
|
|
||||||
-- AR631/AR637 Hack for "First time Setup" or
|
|
||||||
-- "First Time AS3X Setup", use 0 instead of the ctx.SelLine=5
|
|
||||||
if (ctx.Menu.MenuId == 0x104F or ctx.Menu.MenuId==0x1055) then
|
|
||||||
LOG_write("First time Setup Menu HACK: Overrideing LastSelectedLine to ZERO\n")
|
|
||||||
ctx.SelLine = 0
|
|
||||||
end
|
|
||||||
-- DID NOT WORK: AR631/AR637 Hack for "Relearn Servo Settings", use 1 instead
|
|
||||||
-- of the ctx.SelLine=0
|
|
||||||
--if (ctx.Menu.MenuId == 0x1023) then
|
|
||||||
-- LOG_write("Relearn Servo Settings HACK: Overrideing LastSelectedLine to 1\n")
|
|
||||||
-- ctx.SelLine = 1
|
|
||||||
--end
|
|
||||||
|
|
||||||
Now it retrives properly the menu:
|
|
||||||
|
|
||||||
Log shows:
|
|
||||||
|
|
||||||
First time Setup Menu HACK: Overrideing LastSelectedLine to ZERO
|
|
||||||
DSM_getMenu(MenuId=0x104F LastSelectedLine=0)
|
|
||||||
RESPONSE Menu: M[Id=0x104F P=0x0 N=0x0 B=0x105E Text="First Time Setup"[0x4A]]
|
|
||||||
SEND DSM_getFirstMenuLine(MenuId=0x104F)
|
|
||||||
.. Good menu data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
-- 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 |0x00B0|Self-Lev/Ang Dem
|
|
||||||
T |0x00CD|Level model & capt attitude
|
|
||||||
T |0x0190|DONT USE: Relearn Servo Settings
|
|
||||||
T |0x020D|DONT USE: First Time SAFE Setup
|
|
||||||
T |0x0254|Pos = Up, Neg = Down
|
|
||||||
T |0x0267|Pos = Nose Up/Roll Right
|
|
||||||
T |0x0268|Neg = Nose Down/Roll Left
|
|
||||||
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 728 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 721 B |
|
Before Width: | Height: | Size: 803 B |
|
Before Width: | Height: | Size: 679 B |
|
Before Width: | Height: | Size: 755 B |
|
Before Width: | Height: | Size: 817 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 679 B |
@@ -1,375 +0,0 @@
|
|||||||
-- 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|Inhibit?
|
|
||||||
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
|
|
||||||
--
|
|
||||||
-- FailSafe Options
|
|
||||||
--LT|0x005E|Inhibit
|
|
||||||
LT|0x005F|Hold Last
|
|
||||||
LT|0x0060|Preset
|
|
||||||
--LT|0x0061|Custom
|
|
||||||
--
|
|
||||||
T |0x0071|Proportional
|
|
||||||
T |0x0072|Integral
|
|
||||||
T |0x0073|Derivate
|
|
||||||
--
|
|
||||||
T |0x0078|FM Channel
|
|
||||||
--
|
|
||||||
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|0x008D|560hz
|
|
||||||
--
|
|
||||||
-- FC6250HX: Callibration Menu -> Begin..Start, Complete, Done
|
|
||||||
T |0x0091|Begin
|
|
||||||
T |0x0090|Apply
|
|
||||||
T |0x0092|Start
|
|
||||||
T |0x0093|Complete
|
|
||||||
T |0x0094|Done
|
|
||||||
--
|
|
||||||
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
|
|
||||||
T |0x00B0|Self-Level/Angle Dem
|
|
||||||
T |0x00B1|Envelope
|
|
||||||
--
|
|
||||||
-- Flight Modes List Options
|
|
||||||
LT|0x00B5|Inhibit
|
|
||||||
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 |0x00CA|SAFE/Panic Mode Setup
|
|
||||||
--
|
|
||||||
T |0x00CD|Level model and capture attitude/m -- SPECIAL MENU to itself who is not a comment
|
|
||||||
--
|
|
||||||
-- 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
|
|
||||||
--
|
|
||||||
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 |0x00E4|E-Ring
|
|
||||||
T |0x00E5|Swash Type
|
|
||||||
T |0x00E6|Travel
|
|
||||||
T |0x00E7|Left
|
|
||||||
T |0x00E8|Right
|
|
||||||
--
|
|
||||||
LT|0x00F2|Fixed
|
|
||||||
LT|0x00F3|Adjustable
|
|
||||||
--
|
|
||||||
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| -- Blank
|
|
||||||
--
|
|
||||||
T |0x0106|Any wing type, channel assignment,
|
|
||||||
T |0x0107|subtrim, or servo reversing changes
|
|
||||||
T |0x0108|require running through initial
|
|
||||||
T |0x0109|setup again.
|
|
||||||
T |0x010A| -- Blank
|
|
||||||
--
|
|
||||||
T |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 |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| -- Blank
|
|
||||||
T |0x0212| -- Blank
|
|
||||||
T |0x0213| -- Blank
|
|
||||||
--
|
|
||||||
-- AS3X orientation Setting menu (Level)
|
|
||||||
T |0x021A|Set the model level,
|
|
||||||
T |0x021B|and press Continue.
|
|
||||||
T |0x021C| -- Blank
|
|
||||||
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| -- Blank
|
|
||||||
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 line
|
|
||||||
--
|
|
||||||
-- 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|Postive = Up, Negative = 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| -- Blank
|
|
||||||
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|Positive = Nose Up/Roll Right
|
|
||||||
T |0x0268|Negative = Nose Down/Roll Left
|
|
||||||
T |0x0269|SAFE - Thr to Pitch
|
|
||||||
T |0x026A|Use CAUTION for Yaw gain!/b
|
|
||||||
--
|
|
||||||
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
|
|
||||||
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
# 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.54)
|
|
||||||
|
|
||||||
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 configuration and stores it in the RX.
|
|
||||||
|
|
||||||
# Deployment
|
|
||||||
Make sure to manually create `/MODELS/DSMDATA` . The script will complain at startup if it does not exist. Here the script saves the Spektrun settings for each of your models.
|
|
||||||
|
|
||||||
Uncompress the Zip file (ZIP version) into your local computer.
|
|
||||||
In another window, open your TX SDCard and go to /SCRIPTS/TOOLS.
|
|
||||||
|
|
||||||
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first)
|
|
||||||
|
|
||||||
Copy the entire DSMLIB folder.
|
|
||||||
Copy the main script you want to use (Color or B&W).
|
|
||||||
|
|
||||||
|
|
||||||
Your TX SDCard should looks like this:
|
|
||||||
|
|
||||||
/SCRIPTS/TOOLS
|
|
||||||
DSM FwdPrg_05_BW.lua -- black/white text only
|
|
||||||
DSM FwdPrg_05_Color.lua -- Color and touch radios
|
|
||||||
DSM FwdPrg_05_MIN.lua -- `NEW!` Minimalistic version for radios with LOW memory (cannot setup new planes)
|
|
||||||
|
|
||||||
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
|
|
||||||
DsmFwPrgLib.lua -- DSM Protocol Message and Menu engine
|
|
||||||
DsmFwPrgSIMLib.lua -- Simulation of AR631, FC6250HX (For GUI development)
|
|
||||||
SetupLib.lua -- Model Setup Screens
|
|
||||||
msg_fwdp_en.txt -- `NEW!` Messages for forward programing externalized. To support other langs
|
|
||||||
|
|
||||||
/SCRIPTS/TOOLS/DSMLIB/img -- Images for RX orientations
|
|
||||||
|
|
||||||
Other Directories
|
|
||||||
|
|
||||||
/MODELS/DSMDATA --(ALL CAPITALS) Data of model config (Wing Type, Servo Assignments)
|
|
||||||
/LOGS/dsm_log.txt --Readable log of the last RX/TX session, usefull for debugging problems
|
|
||||||
|
|
||||||
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first)
|
|
||||||
|
|
||||||
# Common Questions
|
|
||||||
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
|
|
||||||
V0.53 and newer: The RX is listening to channel changes for this options. Configure the Switch to the channel, togling once the switch will select the channel on the menu field.
|
|
||||||
|
|
||||||
2. `Why Ch1 says Ch1 (TX:Ch3/Thr)?`:
|
|
||||||
Radios with Multi-Module are usually configured to work the standard AETR convention. Spektrum uses TAER. The multi-module does the conversion when transmitting the signals. So `Spektrum Ch1 (Throttle)` really comes from the `TX Ch3`. We show both information (+name from the TX output). If your multi-module/radio is setup as TAER, the script will not do the re-arrangement.
|
|
||||||
|
|
||||||
3. `If i change the model name, the original model settings are lost.` This is correct, the model name is used to generate the file name (inside /MODEL/DSMDATA) who stores the model configuration. Currently EdgeTx and OpenTX has differt features where i could get either the Model Name or the YAML file where the EdgeTX model configuration is stored.. to keep the code compatible, the model name is used.
|
|
||||||
|
|
||||||
4. `Reversing a channel in my TX do not reverse the AS3X/SAFE reaction.` Correct, the channel stick direction and the Gyro direction are two separate things.
|
|
||||||
|
|
||||||
4.1: First, you have setup your model so that the sticks and switches moves the surfaces in the right direction.
|
|
||||||
|
|
||||||
4.2: Go to the script, `Model Setup` and setup your wing type, tail type, and select the channel assigment for each surface. Leave the servo settings the same as the values in the TX to start.
|
|
||||||
|
|
||||||
4.3: AR63X family: Go to `Forward programming->Gyro Setting->Initial Setup` (New/factory reset), or `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` (not new RX). This will load your current Gyro servo settings into the plane's RX.
|
|
||||||
|
|
||||||
4.4: Verify that the AS3X and SAFE reacts in the proper direction. You can use the Flight mode confugured as "Safe Mode: Auto-Level" to see if it moves the surfaces in the right direction.
|
|
||||||
|
|
||||||
4.5: If a surface don't move in the right direction, go to the `Model Setup->Gyro Channel Reverse` to reverse the Gyro on the channels needed, and do again the `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` to tranfer the new settings to the RX.
|
|
||||||
|
|
||||||
4.6: Specktrum TX always passes the TX servo reverse as the Gyro Reverse, but on many OpenTX/EdgeTX radios, the Rud/Ail are usually reversed by default compared to Specktrum. So far i don't think that i can use this as a rule, that is why the `Gyro Channel Reverse` page exist.
|
|
||||||
|
|
||||||
---
|
|
||||||
---
|
|
||||||
|
|
||||||
# Changes and fixes
|
|
||||||
V0.54:
|
|
||||||
1. Fix a problem in the Attitude Trim page (`Gyro Settings->System Setup->SAFE/Panic Setup->Attitude Trim`). It was not saving the values after exiting the menu. This is to change what SAFE considers "Level" flying.
|
|
||||||
2. Wings 2-Ail 2-Flaps had a bug on the 2nd flap.
|
|
||||||
3. New Minimalistic script (`DsmFwdPrg_05_MIN.lua`): For radios with very low memory (FrSky QX7, RM Zorro, others). It can only change existing settings, but does not have the Plane Setup menus to setup a completly new plane. In some radios, the very first time it runs (compile + run), it might give you a `not enouth memory` error.. try to run it again.
|
|
||||||
4. External menu message file (DSMLIB/msg_en.txt and msg_MIN_es.txt). Intial work to do localization and different languages.
|
|
||||||
|
|
||||||
V0.53:
|
|
||||||
1. Improved channel selection (Flight mode, Panic Channel, Gains Channel). Now during editing a channel, you can select any channel (>Ch4). Also, of you toggle the switch/channel it will populate the screen.
|
|
||||||
2. Support for smaller screens (128x64) in B&W. The problem with this older radios is memory. In some, it does not have enouth memory to load the additional DSMLIB libraries.
|
|
||||||
3. Fix formatting problem with some TX channel names who could affect the screen.. for example, rud channel should show "Ch4/rud", but shows "Ch4ud" because /r is for right justify formatting on messages. Now the formatting is only if it appears at the end of the message.
|
|
||||||
|
|
||||||
V0.52:
|
|
||||||
1. Menus to be able to configure Plane in a similar way as Spektrum Radio (v0.52)
|
|
||||||
2. Make "Gyro Settings"->"Initial Setup" works (Tested on AR631,AR637xx with PLANE type of aircraft)
|
|
||||||
3. Properly reset and restart after initial configuration and SAFE changes.
|
|
||||||
4. Write Log of the conversation between RX/TX. To be used for debugging a problem is reported.
|
|
||||||
5. Provide a simulation of RX to do GUI development in Companion, and understand patterns of how the data is organized.
|
|
||||||
|
|
||||||
# Tested Hardware
|
|
||||||
- AR631/AR637xx
|
|
||||||
- FC6250HX (Blade 230S V2 Helicopter)
|
|
||||||
- AR636 (Blade 230S V1 Heli firmware 4.40)
|
|
||||||
|
|
||||||
- Radiomaster TX16S (All versions)
|
|
||||||
- FrSky QX7, Radimaster Boxter (Minimalistic version)
|
|
||||||
|
|
||||||
Please report if you have tested it with other receivers to allow us to update the documentation. Code should work up to 10 channels for the main surfaces (Ail/Ele/etc). All Spektrum RX are internally 20 channels, so you can use Ch7 for Flight Mode even if your RX is only 6 channels (See common Questions)
|
|
||||||
|
|
||||||
|
|
||||||
# Messages Displayed in the GUI
|
|
||||||
|
|
||||||
If in a screen you get text that looks like `Unknown_XX` (ex: Unknown_D3), that message has not been setup in the script in english. If you can determine what the proper message is, you can send us a message to be added to the library.
|
|
||||||
The `XX` represents a Hex Number (0..9,A..F) message ID.
|
|
||||||
|
|
||||||
|
|
||||||
### Version 0.53 and older:
|
|
||||||
If you want to fix it in your local copy, all messages are towards the end in the file `SCRIPT\TOOS\DSMLIB\DsmFwPrgLib.lua`. Messages for Headers are stored in `Text` and messages for Options are stored in `List_Text`. Lua scripts are text files, and can be edited with Notepad or equivalent.
|
|
||||||
|
|
||||||
Portion of DsmFwPrgLib.lua:
|
|
||||||
|
|
||||||
Text[0x0097] = "Factory Reset"
|
|
||||||
Text[0x0098] = "Factory Reset" -- FC6250HX: Title
|
|
||||||
Text[0x0099] = "Advanced Setup"
|
|
||||||
Text[0x009A] = "Capture Failsafe Positions"
|
|
||||||
Text[0x009C] = "Custom Failsafe"
|
|
||||||
|
|
||||||
Text[0x009F] = "Save & Reset RX" -- TODO: Find the Proper Spektrum Value ??
|
|
||||||
|
|
||||||
Text[0x00A5] = "First Time Setup"
|
|
||||||
Text[0x00AA] = "Capture Gyro Gains"
|
|
||||||
Text[0x00AD] = "Gain Channel Select"
|
|
||||||
|
|
||||||
-- Safe mode options, Inhibit + the values
|
|
||||||
local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope
|
|
||||||
List_Text[0x00B0] = "Self-Level/Angle Dem"
|
|
||||||
List_Text[0x00B1] = "Envelope"
|
|
||||||
|
|
||||||
For example, if you get `Unknown_9D` in the GUI and your now that it should say **NEW Text**, you can edit the lua script to look like this:
|
|
||||||
|
|
||||||
Text[0x009A] = "Capture Failsafe Positions"
|
|
||||||
Text[0x009C] = "Custom Failsafe"
|
|
||||||
|
|
||||||
Text[0x009D] = "NEW Text" -- NEW Text added for AR98xx
|
|
||||||
|
|
||||||
Text[0x009F] = "Save & Reset RX" -- TODO: Find the proper Spektrum text
|
|
||||||
|
|
||||||
### Version 0.54 and newer:
|
|
||||||
The menu messages are stored in DSMLIB/msg_fwdp_en.txt (For english). Just add the message there. MIN_msg_fwdp_en.txt has shorter messages overrides for screens who are smaller (for minimalistic 128x64 version). The reference to the message file is at the file `/DSMLIB/DsmFwPrgLib.lua` if you want to change to use another language.
|
|
||||||
|
|
||||||
T |0x0097|Factory Reset
|
|
||||||
LT|0x00B0|Self-Level/Angle Dem
|
|
||||||
LT|0x00B1|Envelope
|
|
||||||
|
|
||||||
# LOG File
|
|
||||||
|
|
||||||
The log file of the last use of the script is located at `/LOGS/dsm_log.txt`. **It is overridden on every start to avoid filling up the SD card**. So if you want to keep it, copy or rename it before starting the script again. (it can be renamed in the TX by browsing the SD card)
|
|
||||||
|
|
||||||
The log is human readable. The first number is the number of seconds since the start, and then what is the current state of the Library, and what has been sent and received. The info in the log can be easily used to create a new simulation for that RX in the future.
|
|
||||||
|
|
||||||
Example Log:
|
|
||||||
|
|
||||||
5.340 WAIT_CMD: DSM_GotoMenu(0x1010,LastSelectedLine=0)
|
|
||||||
5.350 MENU_TITLE: SEND DSM_getMenu(MenuId=0x1010 LastSelectedLine=0)
|
|
||||||
5.440 MENU_TITLE: RESPONSE Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
|
||||||
5.490 MENU_LINES: SEND DSM_getFirstMenuLine(MenuId=0x1010)
|
|
||||||
5.590 MENU_LINES: RESPONSE MenuLine: L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ]
|
|
||||||
5.640 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=0)
|
|
||||||
5.740 MENU_LINES: RESPONSE MenuLine: L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ]
|
|
||||||
5.790 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=1)
|
|
||||||
5.850 MENU_LINES: RESPONSE MenuLine: L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ]
|
|
||||||
5.910 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=2)
|
|
||||||
5.970 MENU_LINES: RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
|
|
||||||
6.020 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=3
|
|
||||||
|
|
||||||
# Validation of data by the RX
|
|
||||||
|
|
||||||
The RX validates the data. if you change to an invalid channel or do a invalid number range, the RX will change it at the end of editing the field.
|
|
||||||
|
|
||||||
---
|
|
||||||
# Version 0.53
|
|
||||||
- Improve Channel selection in menus
|
|
||||||
- Support smaller screens 128x64 in the black/white mode.
|
|
||||||
|
|
||||||
# Version 0.52
|
|
||||||
- Fix Reversing of Servos
|
|
||||||
- Properly detect Multimodule Ch settings AETR
|
|
||||||
---
|
|
||||||
|
|
||||||
# Version 0.51 (volunteer testing version, not for production)
|
|
||||||
- New Screens to Configure Model (Wing Type/Tail Tail, etc)
|
|
||||||
- Finally got understanding that the previous unknown 0x05 lines are to send Model/Servo data to RX.
|
|
||||||
- Fix use of AR636B (Firmware version 4.40.0 for Blade 230 heli, is the only one with Forward Programming)
|
|
||||||
- Aircraft types: Tested With Plane type only.. Glider and other in progress
|
|
||||||
|
|
||||||
### Known Problems:
|
|
||||||
- 4-Servo Wing type (Dual Ail/Tail) in planes give conflicting servo assignments by defaults.. Solution choose your own Ch.
|
|
||||||
- Glider, Heli, Drone: Still in development. In glider, only a few wing type works.. needs to restrict menu options for the only valid one.
|
|
||||||
|
|
||||||
|
|
||||||
# Version 0.5
|
|
||||||
|
|
||||||
- Make the code more readable and understandable
|
|
||||||
- Separate the DSM Forwards Programming logic from the GUI
|
|
||||||
- Log the communication with the RX on a /LOGS/dsm_log.txt to allow to debug it easier
|
|
||||||
and see the exchange of data between the RX/TX
|
|
||||||
- Created a black/white Text only version with only Key/Roller Inputs
|
|
||||||
- Created a nicer GUI for EdgeTX touch screen color Radios
|
|
||||||
- RX simulation for GUI development: turn on `SIMULATION_ON=true` in the beginning of the lua file
|
|
||||||
- Test it on AR631, AR637xx, FC6250HX (Helicopter)
|
|
||||||
|
|
||||||
|
|
||||||
### Some settings that can change (top of Lua file):
|
|
||||||
SIMULATION_ON = false -- FALSE: hide similation menu (DEFAULT), TRUE: show RX simulation menu
|
|
||||||
DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm_log.txt)
|
|
||||||
USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX, OpenTX handle colors different)
|
|
||||||
|
|
||||||
|
|
||||||
### Known Problems:
|
|
||||||
1. **Incorrect List Value Options:** Some Menu List line (`LINE_TYPE.LIST_MENU1` or `L_m1` in logs), the range (min/max) of valid values seems to be incorrect, but the RX corrects the values.
|
|
||||||
in the MINimalistic version, the RX is doing all the range validation, and will show invalid options temporarilly. In an Spektrum radio, it happens so fast, that you don't notice it, but in LUA scripts who are slower, you can see it in the screen.
|
|
||||||
In the COLOR version, The code has hardcoded the valid ranges to avoid this problem.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2. Glider/Heli/Drone wing types not ready.
|
|
||||||
|
|
||||||
For Helicopter, use airplane normal wing and normal tail
|
|
||||||
|
|
||||||
|
|
||||||
# Version 0.2
|
|
||||||
Original Version from Pascal Langer
|
|
||||||
|
|
||||||
@@ -1,683 +0,0 @@
|
|||||||
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 }
|
|
||||||
@@ -1,603 +0,0 @@
|
|||||||
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 }
|
|
||||||
305
Lua_scripts/DumboRC P Series.lua
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
local toolName = "TNS|DumboRC P series|TNE"
|
||||||
|
|
||||||
|
-- EdgeTX/Multi bridge:
|
||||||
|
-- Multi_Buffer[4] is RF payload length, [5..12] is RF payload.
|
||||||
|
-- Multi rewrites the 00 00 token and checksum from its hop state.
|
||||||
|
-- Special1 payload: 18 00 00 arg_l arg_h 00. Args: 1 poll, 2 Set GY EPA, 3 Set FS.
|
||||||
|
-- Special2 payload: 28 00 00 gyro0 gyro1 gyro2 gyro3 00.
|
||||||
|
-- Gyro word: bit0 enable, bit1 phase, bits2..5 SEN channel selector
|
||||||
|
-- (0=NULL, 1..7=CH2..CH8), bits6..13 SEN, bits14..21 PCA,
|
||||||
|
-- bits22..29 AGS, bits30..31 servo frequency (67HZ,250HZ,50HZ,300HZ).
|
||||||
|
|
||||||
|
local PROTO_RLINK = 74
|
||||||
|
local SUB_DUMBORC_P = 4
|
||||||
|
|
||||||
|
local TX_READY = 4
|
||||||
|
local TX_PAYLOAD = 5
|
||||||
|
local TX_MAX_PAYLOAD = 8
|
||||||
|
local RX_READY = 14
|
||||||
|
local RX_PAYLOAD = 15
|
||||||
|
local RX_MAX_PAYLOAD = 32
|
||||||
|
local colorLcd = type(lcd.RGB) == "function"
|
||||||
|
|
||||||
|
local servoHz = { "67HZ", "250HZ", "50HZ", "300HZ" }
|
||||||
|
|
||||||
|
local gyro = { enable = 0, phase = 0, senCh = 0, sen = 0, pca = 0, ags = 0, flags = 0 }
|
||||||
|
local lines = {}
|
||||||
|
local sel = 1
|
||||||
|
local top = 1
|
||||||
|
local edit = false
|
||||||
|
local blink = 0
|
||||||
|
local moduleOk = false
|
||||||
|
local haveValues = false
|
||||||
|
|
||||||
|
local function limit(v, mn, mx)
|
||||||
|
if v < mn then return mn end
|
||||||
|
if v > mx then return mx end
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
local function byte(v)
|
||||||
|
return limit(math.floor(tonumber(v) or 0), 0, 255)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function gyroRaw(v)
|
||||||
|
return limit(math.floor(tonumber(v) or 0), 0, 200)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function gyroText(v)
|
||||||
|
local raw = gyroRaw(v)
|
||||||
|
return tostring(math.floor(raw / 2)) .. (raw % 2 == 0 and ".0" or ".5")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function screenLines()
|
||||||
|
if colorLcd then return limit(math.floor(((LCD_H or 272) - 46) / 20), 8, 12) end
|
||||||
|
return 6
|
||||||
|
end
|
||||||
|
|
||||||
|
local function drawTitle(title)
|
||||||
|
if colorLcd and lcd.drawFilledRectangle then
|
||||||
|
lcd.drawFilledRectangle(0, 0, LCD_W, 30, COLOR_THEME_SECONDARY1)
|
||||||
|
lcd.drawText(3, 5, title, COLOR_THEME_PRIMARY2)
|
||||||
|
elseif lcd.drawScreenTitle then
|
||||||
|
lcd.drawScreenTitle(title, 0, 0)
|
||||||
|
else
|
||||||
|
lcd.drawText(0, 0, title, INVERS)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function findModule()
|
||||||
|
for i = 0, 1 do
|
||||||
|
local m = model.getModule(i)
|
||||||
|
if m and m["Type"] == 6 and m["protocol"] == PROTO_RLINK and m["subProtocol"] == SUB_DUMBORC_P then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function initBuffer()
|
||||||
|
multiBuffer(0, string.byte("R"))
|
||||||
|
if multiBuffer(0) ~= string.byte("R") then
|
||||||
|
error("Not enough memory!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
multiBuffer(1, string.byte("L"))
|
||||||
|
multiBuffer(2, string.byte("n"))
|
||||||
|
multiBuffer(3, string.byte("k"))
|
||||||
|
multiBuffer(TX_READY, 0)
|
||||||
|
multiBuffer(RX_READY, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function release()
|
||||||
|
for i = 0, RX_PAYLOAD + RX_MAX_PAYLOAD - 1 do
|
||||||
|
multiBuffer(i, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sendPayload(payload)
|
||||||
|
local len = #payload
|
||||||
|
if len < 1 or len > TX_MAX_PAYLOAD or multiBuffer(TX_READY) ~= 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for i = 1, TX_MAX_PAYLOAD do
|
||||||
|
multiBuffer(TX_PAYLOAD + i - 1, 0)
|
||||||
|
end
|
||||||
|
for i = 1, #payload do
|
||||||
|
multiBuffer(TX_PAYLOAD + i - 1, byte(payload[i]))
|
||||||
|
end
|
||||||
|
multiBuffer(TX_READY, len)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sendSpecial1(arg)
|
||||||
|
return sendPayload({ 0x18, 0, 0, arg % 256, math.floor(arg / 256), 0 })
|
||||||
|
end
|
||||||
|
|
||||||
|
local function gyroSelector()
|
||||||
|
if gyro.senCh < 2 or gyro.senCh > 8 then return 0 end
|
||||||
|
return gyro.senCh - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sendGyro()
|
||||||
|
local sen = gyroRaw(gyro.sen)
|
||||||
|
local pca = gyroRaw(gyro.pca)
|
||||||
|
local ags = gyroRaw(gyro.ags)
|
||||||
|
local b0 = gyro.enable + gyro.phase * 2 + gyroSelector() * 4 + (sen % 4) * 64
|
||||||
|
local b1 = math.floor(sen / 4) + (pca % 4) * 64
|
||||||
|
local b2 = math.floor(pca / 4) + (ags % 4) * 64
|
||||||
|
local b3 = math.floor(ags / 4) + limit(gyro.flags, 0, 3) * 64
|
||||||
|
sendPayload({ 0x28, 0, 0, b0, b1, b2, b3, 0 })
|
||||||
|
end
|
||||||
|
|
||||||
|
local function decodeGyroBytes(b0, b1, b2, b3)
|
||||||
|
b0 = byte(b0); b1 = byte(b1); b2 = byte(b2); b3 = byte(b3)
|
||||||
|
gyro.enable = b0 % 2
|
||||||
|
gyro.phase = math.floor(b0 / 2) % 2
|
||||||
|
local selector = math.floor(b0 / 4) % 16
|
||||||
|
gyro.senCh = selector == 0 and 0 or limit(selector + 1, 2, 8)
|
||||||
|
gyro.sen = gyroRaw(math.floor(b0 / 64) + (b1 % 64) * 4)
|
||||||
|
gyro.pca = gyroRaw(math.floor(b1 / 64) + (b2 % 64) * 4)
|
||||||
|
gyro.ags = gyroRaw(math.floor(b2 / 64) + (b3 % 64) * 4)
|
||||||
|
gyro.flags = math.floor(b3 / 64) % 4
|
||||||
|
haveValues = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pollRx()
|
||||||
|
local len = multiBuffer(RX_READY)
|
||||||
|
if not len or len == 0 then return end
|
||||||
|
if len > RX_MAX_PAYLOAD then
|
||||||
|
multiBuffer(RX_READY, 0)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local p = {}
|
||||||
|
for i = 1, len do
|
||||||
|
p[i] = multiBuffer(RX_PAYLOAD + i - 1)
|
||||||
|
end
|
||||||
|
multiBuffer(RX_READY, 0)
|
||||||
|
|
||||||
|
if len == 7 and p[1] == 0x01 then
|
||||||
|
decodeGyroBytes(p[3], p[4], p[5], p[6])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function chText()
|
||||||
|
if gyro.senCh == 0 then return "NULL" end
|
||||||
|
return "CH" .. gyro.senCh
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rebuildLines()
|
||||||
|
lines = {
|
||||||
|
{ "Poll RX", "action", function() sendSpecial1(1) end },
|
||||||
|
{ "Gyro", "toggle", "enable" },
|
||||||
|
{ "Phase", "toggle", "phase" },
|
||||||
|
{ "SEN Ch", "channel", "senCh" },
|
||||||
|
{ "SEN", "percent", "sen" },
|
||||||
|
{ "PCA", "percent", "pca" },
|
||||||
|
{ "AGS", "percent", "ags" },
|
||||||
|
{ "Servo Hz", "flags", "flags" },
|
||||||
|
{ "Send Gyro", "action", sendGyro },
|
||||||
|
{ "Set GY EPA", "action", function() sendSpecial1(2) end },
|
||||||
|
{ "Set FS", "action", function() sendSpecial1(3) end },
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function lineValue(line)
|
||||||
|
if line[2] == "action" then return ">" end
|
||||||
|
if not haveValues then return "--" end
|
||||||
|
if line[2] == "toggle" then return gyro[line[3]] == 0 and "Off" or "On" end
|
||||||
|
if line[2] == "channel" then return chText() end
|
||||||
|
if line[2] == "percent" then return gyroText(gyro[line[3]]) end
|
||||||
|
if line[2] == "flags" then return servoHz[gyro.flags + 1] or tostring(gyro.flags) end
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
local function changeValue(dir, fast)
|
||||||
|
local line = lines[sel]
|
||||||
|
if not line then return end
|
||||||
|
local step = fast and 20 or 1
|
||||||
|
haveValues = true
|
||||||
|
|
||||||
|
if line[2] == "toggle" then
|
||||||
|
gyro[line[3]] = dir > 0 and 1 or 0
|
||||||
|
elseif line[2] == "channel" then
|
||||||
|
local vals = { 0, 2, 3, 4, 5, 6, 7, 8 }
|
||||||
|
local pos = 1
|
||||||
|
for i = 1, #vals do
|
||||||
|
if vals[i] == gyro.senCh then pos = i end
|
||||||
|
end
|
||||||
|
gyro.senCh = vals[limit(pos + dir, 1, #vals)]
|
||||||
|
elseif line[2] == "percent" then
|
||||||
|
gyro[line[3]] = gyroRaw(gyro[line[3]] + dir * step)
|
||||||
|
elseif line[2] == "flags" then
|
||||||
|
gyro.flags = limit(gyro.flags + dir, 0, 3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fastRotary()
|
||||||
|
return getRotEncSpeed() > 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function handleEvent(event)
|
||||||
|
local nextEvent = edit and EVT_VIRTUAL_INC or EVT_VIRTUAL_NEXT
|
||||||
|
local prevEvent = edit and EVT_VIRTUAL_DEC or EVT_VIRTUAL_PREV
|
||||||
|
if event == nextEvent then
|
||||||
|
if edit then changeValue(1, fastRotary()) else sel = limit(sel + 1, 1, #lines) end
|
||||||
|
elseif event == prevEvent then
|
||||||
|
if edit then changeValue(-1, fastRotary()) else sel = limit(sel - 1, 1, #lines) end
|
||||||
|
elseif event == EVT_VIRTUAL_NEXT_PAGE then
|
||||||
|
if edit then changeValue(1, true) else sel = limit(sel + screenLines(), 1, #lines) end
|
||||||
|
elseif event == EVT_VIRTUAL_PREV_PAGE then
|
||||||
|
if edit then changeValue(-1, true) else sel = limit(sel - screenLines(), 1, #lines) end
|
||||||
|
killEvents(event)
|
||||||
|
elseif event == EVT_VIRTUAL_ENTER then
|
||||||
|
local line = lines[sel]
|
||||||
|
if line and line[2] == "action" then
|
||||||
|
line[3]()
|
||||||
|
elseif line then
|
||||||
|
edit = not edit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local count = screenLines()
|
||||||
|
if sel < top then top = sel end
|
||||||
|
if sel >= top + count then top = sel - count + 1 end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw()
|
||||||
|
lcd.clear()
|
||||||
|
drawTitle("DumboRC P series")
|
||||||
|
|
||||||
|
local font = colorLcd and 0 or SMLSIZE
|
||||||
|
local x = 2
|
||||||
|
local y = colorLcd and 34 or 9
|
||||||
|
local dy = colorLcd and 20 or 8
|
||||||
|
local valueX = colorLcd and 150 or 82
|
||||||
|
|
||||||
|
if not moduleOk then
|
||||||
|
if colorLcd then
|
||||||
|
lcd.drawText(x, y + dy, "Select Multi RadLink/Dumbo_P", font + BLINK)
|
||||||
|
else
|
||||||
|
lcd.drawText(x, y + dy, "Select RadLink", font + BLINK)
|
||||||
|
lcd.drawText(x, y + dy * 2, "Dumbo_P", font + BLINK)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = top, math.min(#lines, top + screenLines() - 1) do
|
||||||
|
local attr = font
|
||||||
|
if i == sel then
|
||||||
|
attr = attr + INVERS
|
||||||
|
if edit then
|
||||||
|
blink = (blink + 1) % 30
|
||||||
|
if blink > 15 then attr = font end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local yy = y + (i - top) * dy
|
||||||
|
lcd.drawText(x, yy, lines[i][1], attr)
|
||||||
|
lcd.drawText(valueX, yy, lineValue(lines[i]), attr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function init()
|
||||||
|
moduleOk = type(multiBuffer) == "function" and findModule()
|
||||||
|
rebuildLines()
|
||||||
|
if moduleOk then initBuffer() end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function run(event)
|
||||||
|
if event == nil then
|
||||||
|
error("Cannot be run as a model script!")
|
||||||
|
return 2
|
||||||
|
elseif event == EVT_VIRTUAL_EXIT then
|
||||||
|
if moduleOk then release() end
|
||||||
|
return 2
|
||||||
|
end
|
||||||
|
if moduleOk then
|
||||||
|
pollRx()
|
||||||
|
handleEvent(event)
|
||||||
|
end
|
||||||
|
draw()
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return { init = init, run = run }
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
6,3,DSM,X_2F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
6,3,DSM,X_2F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||||
6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
6,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,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,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
|
70,1,DSM_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||||
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
|
45,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,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,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,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,4,Flysky_AFHDS2A,Gyro_Off,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,ST_Ga,TH_Ga,Prio,Calib
|
||||||
28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
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,PWM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
28,6,Flysky_AFHDS2A,G_On_Rev,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,ST_Ga,TH_Ga,Prio,Calib
|
||||||
28,7,Flysky_AFHDS2A,PPM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
|
||||||
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
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
|
56,1,Flysky2A_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||||
53,0,Height,5ch,0,Gear
|
53,0,Height,5ch,0,Gear
|
||||||
@@ -86,11 +86,17 @@
|
|||||||
55,1,FrSkyRX,CloneTX,0
|
55,1,FrSkyRX,CloneTX,0
|
||||||
55,2,FrSkyRX,EraseTX,0
|
55,2,FrSkyRX,EraseTX,0
|
||||||
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||||
58,0,FX,816,1
|
58,0,FX,FX816,1
|
||||||
58,1,FX,620,1
|
58,1,FX,FX620,1
|
||||||
|
58,2,FX,9630,1,Rate,Gyro,TrimR,TrimA,TrimE
|
||||||
|
58,3,FX,Q560,1,FLIP,Gyro,LEDs
|
||||||
|
58,4,FX,QF012,1,FLIP,Gyro,Invert,Reset
|
||||||
|
58,5,FX,BM26,1,FLIP,Gyro,LEDs,LED,CALIB
|
||||||
|
58,6,FX,A570,1,STOP,Rate,Color,LED,TrimR,TrimA,TrimE
|
||||||
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
||||||
20,1,FY326,FY319,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
|
23,0,FQ777,124,1,Flip,RTH,HLess,Expert
|
||||||
|
23,1,FQ777,XBM37,1,Rate,Flip,HLess,LED,Pict,Video,RTH,OK,ETrim,Atrim
|
||||||
47,0,GD00x,V1,1,Trim,LED,Rate
|
47,0,GD00x,V1,1,Trim,LED,Rate
|
||||||
47,1,GD00x,V2,1,Trim,LED,Rate
|
47,1,GD00x,V2,1,Trim,LED,Rate
|
||||||
32,0,GW008,FY326,1,Flip
|
32,0,GW008,FY326,1,Flip
|
||||||
@@ -107,6 +113,7 @@
|
|||||||
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||||
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
26,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,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||||
|
26,4,Hontai,XKK170,1,Rate,Emerg,TakLan,Calib,TrimA,TrimE,Optic
|
||||||
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
57,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
|
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||||
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
|
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
|
||||||
@@ -115,12 +122,13 @@
|
|||||||
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||||
71,0,JJRC345,JJRC345,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
71,0,JJRC345,JJRC345,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||||
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||||
49,0,KF606,KF606,1,Trim
|
49,0,KF606,KF606,1,Trim,LED
|
||||||
49,1,KF606,MIG320,1,Trim,LED
|
49,1,KF606,MIG320,1,Trim,LED
|
||||||
49,2,KF606,ZCZ50,1,Trim,UNK
|
49,2,KF606,ZCZ50,1,Trim,UNK
|
||||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
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
|
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim,Rtrim,Hover
|
||||||
73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
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,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,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||||
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||||
@@ -128,14 +136,16 @@
|
|||||||
18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||||
18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
18,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
|
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,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess,Atrim,Etrim
|
||||||
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess
|
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess,Atrim,Etrim
|
||||||
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
|
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess,Atrim,Etrim
|
||||||
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
|
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
|
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess,Atrim,Etrim
|
||||||
17,5,MT99XX,A180,0,3D_6G
|
17,5,MT99XX,A180,0,3D_6G,Rate,3D_6G,n-a,n-a,Atrim,Etrim
|
||||||
17,6,MT99XX,Dragon,0,Mode,RTH
|
17,6,MT99XX,Dragon,0,Mode,RTH,n-a,n-a,n-a,Atrim,Etrim
|
||||||
17,7,MT99XX,F949G,0,6G_3D,Light
|
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
|
44,0,NCC1701,Std,1,Warp
|
||||||
77,0,OMP,M2,0,THold,IdleUp,6G_3D
|
77,0,OMP,M2,0,THold,IdleUp,6G_3D
|
||||||
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
||||||
@@ -153,8 +163,11 @@
|
|||||||
72,0,Q90C,Std,0,FMode,VTX+
|
72,0,Q90C,Std,0,FMode,VTX+
|
||||||
74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
74,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,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
|
74,2,RadioLink,DumboRC,0,CH5,CH6,CH7,CH8GY,CH9,CH10,n-a,n-a,n-a,n-a,n-a,n-a
|
||||||
76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,UNK
|
74,3,RadioLink,RC4G,0,CH5,FS_CH1,FS_CH2,FS_CH3,FS_CH4
|
||||||
|
74,4,RadioLink,Dumbo_P,0,CH5,CH6,CH7,CH8GY,CH9,CH10,n-a,n-a,n-a,n-a,n-a,n-a
|
||||||
|
76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,ThCut,Rotat
|
||||||
|
76,1,Realacc,WLV8TX,0,ST_Tr
|
||||||
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
50,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
|
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
|
21,0,Futaba,SFHSS,0,CH5,CH6,CH7,CH8
|
||||||
@@ -165,14 +178,16 @@
|
|||||||
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
|
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,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,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,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
|
||||||
10,1,Symax,X5C,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,TQ2,0
|
||||||
43,0,Traxxas,6519,0
|
43,1,Traxxas,TQ1,0
|
||||||
5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY
|
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
|
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,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn,Beep
|
||||||
48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn
|
48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn,Beep
|
||||||
48,2,V761,TOPRC,0,Gyro,Calib,Flip,RtnAct,Rtn
|
48,2,V761,TOPRC,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||||
46,0,V911s,V911s,1,Calib,Rate
|
46,0,V911s,V911s,1,Calib,Rate
|
||||||
46,1,V911s,E119,1,Calib,Rate,6G_3D
|
46,1,V911s,E119,1,Calib,Rate,6G_3D
|
||||||
@@ -184,7 +199,10 @@
|
|||||||
30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
|
30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
|
||||||
30,5,WK2x01,W6HEL_I,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,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,Stunt
|
||||||
|
99,1,XK2,P10,0,Rate,Mode,Hover,Light,Stunt
|
||||||
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
|
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
|
||||||
8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess
|
8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess
|
||||||
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
|
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
|
||||||
@@ -197,14 +215,30 @@
|
|||||||
81,0,E010r5,E010r5,1,Flip,LED,CALIB,HLess,RTH,GLIDE
|
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
|
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,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
|
84,0,JOYSWAY,Std,0
|
||||||
85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH
|
85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH
|
||||||
87,0,IKEA
|
87,0,IKEA
|
||||||
89,0,LOSI
|
89,0,LOSI
|
||||||
90,0,MouldKg,Analog,0
|
90,0,MouldKg,A4444,0
|
||||||
90,1,MouldKg,Digit,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
|
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
|
93,0,Kyosho2,KT-17,0
|
||||||
94,0,Scorpio
|
94,0,Scorpio
|
||||||
|
95,0,Bluefly,HP100,0,CH5,CH6,CH7,CH8
|
||||||
|
96,0,BumbleB
|
||||||
|
97,0,SGF22,F22,1,Mode,Flip,LED,Pict,Video,TrRes,Bal,HiBal
|
||||||
|
97,1,SGF22,F22S,1,Mode,Flip,LED,Pict,Video,TrRes
|
||||||
|
97,2,SGF22,J20,1,Mode,Flip,LED,Pict,Video
|
||||||
|
61,0,EazyRC
|
||||||
|
98,0,Kyosho3,ASF,0
|
||||||
|
100,0,YuXiang,Std,0,Lock,Rate,Land,Manual,Flip,Mode,Pitch
|
||||||
|
102,0,JIABAILE,Std,0,Speed,Light,Flash
|
||||||
|
102,1,JIABAILE,Gyro,0,Speed,Light,Flash,ST_Tr
|
||||||
|
103,0,H36,Std,1,Flip,HLess,RTH
|
||||||
|
104,0,KAMTOM,Std,0,ST_Tr,TH_Tr,TH_DR
|
||||||
|
105,0,Shenqi2,Std,1
|
||||||
|
106,0,WL91x,Std,0
|
||||||
|
107,0,WPL,Std,0,Light,TH_DR,ST_DR
|
||||||
|
108,0,Ares,6HPA_Tx,0,CH5,CH6
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ local function Multi_Init()
|
|||||||
stick_names[4] = "Aux3"
|
stick_names[4] = "Aux3"
|
||||||
elseif ( protocol == 48 and sub_protocol == 0 ) then -- V761 3CH
|
elseif ( protocol == 48 and sub_protocol == 0 ) then -- V761 3CH
|
||||||
stick_names[4] = "n-a"
|
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[1] = "n-a"
|
||||||
stick_names[2] = "n-a"
|
stick_names[2] = "n-a"
|
||||||
end
|
end
|
||||||
@@ -280,7 +280,7 @@ local function Multi_Init()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--Exceptions on first 4 channels...
|
--Exceptions on first 4 channels...
|
||||||
if ( protocol == 73 or (protocol == 74 and sub_protocol == 0) or (protocol == 60 and sub_protocol == 2) or protocol == 89) then -- Kyosho or RadioLink Surface or Pelikan/SCX24 or Losi
|
if ( protocol == 73 or (protocol == 74 and (sub_protocol == 0 or sub_protocol == 2 or sub_protocol == 4)) or (protocol == 60 and sub_protocol == 2) or protocol == 89) then -- Kyosho or RadioLink (Surface or DumboRC/P) or Pelikan/SCX24 or Losi
|
||||||
channel_names[1] = "ST"
|
channel_names[1] = "ST"
|
||||||
channel_names[2] = "THR"
|
channel_names[2] = "THR"
|
||||||
channel_names[3] = "CH3"
|
channel_names[3] = "CH3"
|
||||||
|
|||||||
@@ -135,10 +135,14 @@ local function Config_Draw_Edit( event )
|
|||||||
Edit = 0
|
Edit = 0
|
||||||
elseif event == EVT_VIRTUAL_PREV then
|
elseif event == EVT_VIRTUAL_PREV then
|
||||||
-- Change value
|
-- 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
|
elseif event == EVT_VIRTUAL_NEXT then
|
||||||
-- Change value
|
-- 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
|
end
|
||||||
--Blink
|
--Blink
|
||||||
Blink = Blink + 1
|
Blink = Blink + 1
|
||||||
@@ -319,9 +323,6 @@ local function Config_Draw_Menu()
|
|||||||
--Read line from buffer
|
--Read line from buffer
|
||||||
for i = 0, 20-1, 1 do
|
for i = 0, 20-1, 1 do
|
||||||
value=multiBuffer( line*20+13+i )
|
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
|
if value > 0x80 and Menu[line].field_type == 0 then
|
||||||
-- Read field type
|
-- Read field type
|
||||||
Menu[line].field_type = bitand(value, 0xF0)
|
Menu[line].field_type = bitand(value, 0xF0)
|
||||||
@@ -334,6 +335,9 @@ local function Config_Draw_Menu()
|
|||||||
else
|
else
|
||||||
if Menu[line].field_type == 0 then
|
if Menu[line].field_type == 0 then
|
||||||
-- Text
|
-- Text
|
||||||
|
if value == 0 then
|
||||||
|
break -- end of line
|
||||||
|
end
|
||||||
Menu[line].text = Menu[line].text .. string.char(value)
|
Menu[line].text = Menu[line].text .. string.char(value)
|
||||||
else
|
else
|
||||||
-- Menu specific fields
|
-- Menu specific fields
|
||||||
|
|||||||
@@ -58,15 +58,11 @@ This is the Graupner HoTT adapted version of the Model Locator script using RSSI
|
|||||||
|
|
||||||
The OpenTX sensor "RSSI" is populated by the individual OpenTX telemetry protocol implementations and returns a value from 0..100 (percent) originating from the early FrSky implementation. It turns out that FrSky did not really provide a genuine signal strength indicator in units of dbm but a link quality indicator in 0..100%. With Graupner HoTT the link quality indicator is not a good basis for the model locator as it is very non-linear and doesn't change much with distance. Using the Graupner HoTT telemetry sensor "Rssi" which is a true signal strength indicator serves the purpose of locating a model much better as it varies much more with distance.
|
The OpenTX sensor "RSSI" is populated by the individual OpenTX telemetry protocol implementations and returns a value from 0..100 (percent) originating from the early FrSky implementation. It turns out that FrSky did not really provide a genuine signal strength indicator in units of dbm but a link quality indicator in 0..100%. With Graupner HoTT the link quality indicator is not a good basis for the model locator as it is very non-linear and doesn't change much with distance. Using the Graupner HoTT telemetry sensor "Rssi" which is a true signal strength indicator serves the purpose of locating a model much better as it varies much more with distance.
|
||||||
|
|
||||||
## DSM Forward Programming
|
## DSM Tools for EdgeTX and OpenTx
|
||||||
|
|
||||||
This is a work in progress. It's available for color(+touch) and B&W screens.
|
Collection of EdgeTx/OpenTX Tools to use with Spektrum Receivers including forward programming. Extract the color or black&white zip version at the root of your SD card.
|
||||||
|
|
||||||
Work on OpenTX and EdgeTX. Located on the radio SD card under \SCRIPTS\TOOLS, make sure to copy the DSMLIB folder along with DSM FwdPrg_05_Color.lua or DSM FwdPrg_05_BW.lua.
|
Frank is maintaining these awesome tools, check out his [repository](https://github.com/frankiearzu/DSMTools). Feel free to ask questions or open issues there.
|
||||||
|
|
||||||
[](https://www.youtube.com/watch?v=sjIaDw5j9nE)
|
|
||||||
|
|
||||||
If some text appears as Unknown_xxx, please report xxx and what the exact text display should be.
|
|
||||||
|
|
||||||
## DSM PID Flight log gain parameters for Blade micros
|
## DSM PID Flight log gain parameters for Blade micros
|
||||||
|
|
||||||
|
|||||||
BIN
Lua_scripts/dsmtools-ETX-BW-2.4.zip
Normal file
BIN
Lua_scripts/dsmtools-ETX-color-2.6.zip
Normal file
@@ -418,10 +418,10 @@ void A7105_Init(void)
|
|||||||
#ifdef KYOSHO_A7105_INO
|
#ifdef KYOSHO_A7105_INO
|
||||||
if(protocol==PROTO_KYOSHO)
|
if(protocol==PROTO_KYOSHO)
|
||||||
{
|
{
|
||||||
if(sub_protocol==KYOSHO_FHSS)
|
if(sub_protocol==KYOSHO_HYPE)
|
||||||
A7105_Regs=(uint8_t*)KYOSHO_A7105_regs;
|
|
||||||
else
|
|
||||||
A7105_Regs=(uint8_t*)KYOSHO_HYPE_A7105_regs;
|
A7105_Regs=(uint8_t*)KYOSHO_HYPE_A7105_regs;
|
||||||
|
else //FHSS && SYNCRO
|
||||||
|
A7105_Regs=(uint8_t*)KYOSHO_A7105_regs;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -446,7 +446,7 @@ void A7105_Init(void)
|
|||||||
}
|
}
|
||||||
A7105_Strobe(A7105_STANDBY);
|
A7105_Strobe(A7105_STANDBY);
|
||||||
|
|
||||||
if(protocol==PROTO_KYOSHO && sub_protocol==KYOSHO_FHSS)
|
if(protocol==PROTO_KYOSHO && sub_protocol!=KYOSHO_HYPE)
|
||||||
{//strange calibration...
|
{//strange calibration...
|
||||||
//IF Filter Bank Calibration
|
//IF Filter Bank Calibration
|
||||||
A7105_WriteReg(A7105_02_CALC,0x0F);
|
A7105_WriteReg(A7105_02_CALC,0x0F);
|
||||||
|
|||||||
@@ -183,8 +183,18 @@ uint16_t AFHDS2A_RX_callback()
|
|||||||
case AFHDS2A_RX_DATA:
|
case AFHDS2A_RX_DATA:
|
||||||
if (AFHDS2A_RX_data_ready()) {
|
if (AFHDS2A_RX_data_ready()) {
|
||||||
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
|
A7105_ReadData(AFHDS2A_RX_TXPACKET_SIZE);
|
||||||
if (memcmp(&packet[1], rx_id, 4) == 0 && memcmp(&packet[5], rx_tx_addr, 4) == 0) {
|
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 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);
|
int rssi = min(A7105_ReadReg(A7105_1D_RSSI_THOLD),160);
|
||||||
RX_RSSI = map16b(rssi, 160, 8, 0, 128);
|
RX_RSSI = map16b(rssi, 160, 8, 0, 128);
|
||||||
AFHDS2A_RX_build_telemetry_packet();
|
AFHDS2A_RX_build_telemetry_packet();
|
||||||
|
|||||||
@@ -93,15 +93,19 @@ static void AFHDS2A_update_telemetry()
|
|||||||
if (option & 0x80)
|
if (option & 0x80)
|
||||||
{// forward 0xAA and 0xAC telemetry to TX, skip rx and tx id to save space
|
{// forward 0xAA and 0xAC telemetry to TX, skip rx and tx id to save space
|
||||||
packet_in[0]= TX_RSSI;
|
packet_in[0]= TX_RSSI;
|
||||||
debug("T(%02X)=",packet[0]);
|
//Fix for CROSSOVER-RX,
|
||||||
|
if(packet[17+8]==0xFF && packet[21+8]==0xFC && packet[25+8]==0xFF)
|
||||||
|
packet[17+8]=0xFE; // RX_ERR_RATE needed for TX to validate the telem
|
||||||
|
#if 0
|
||||||
|
debug("T(%02X)=",packet[0]);
|
||||||
|
for(uint8_t i=9;i < AFHDS2A_RXPACKET_SIZE; i++)
|
||||||
|
debug(" %02X",packet[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
for(uint8_t i=9;i < AFHDS2A_RXPACKET_SIZE; i++)
|
for(uint8_t i=9;i < AFHDS2A_RXPACKET_SIZE; i++)
|
||||||
{
|
|
||||||
packet_in[i-8]=packet[i];
|
packet_in[i-8]=packet[i];
|
||||||
debug(" %02X",packet[i]);
|
|
||||||
}
|
|
||||||
packet_in[29]=packet[0]; // 0xAA Normal telemetry, 0xAC Extended telemetry
|
packet_in[29]=packet[0]; // 0xAA Normal telemetry, 0xAC Extended telemetry
|
||||||
telemetry_link=2;
|
telemetry_link=2;
|
||||||
debugln("");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -186,16 +190,40 @@ static void AFHDS2A_build_packet(uint8_t type)
|
|||||||
case AFHDS2A_PACKET_STICKS:
|
case AFHDS2A_PACKET_STICKS:
|
||||||
packet[0] = 0x58;
|
packet[0] = 0x58;
|
||||||
//16 channels + RX_LQI on channel 17
|
//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
|
val = convert_channel_ppm(sub_protocol<AFHDS2A_GYRO_OFF?CH_AETR[ch]:ch); // No remapping for BS receivers
|
||||||
#ifdef AFHDS2A_LQI_CH
|
if(ch<14)
|
||||||
|| ch == (AFHDS2A_LQI_CH-1) // override channel with LQI
|
{
|
||||||
#endif
|
packet[9 + ch*2] = val;
|
||||||
)
|
packet[10 + ch*2] = (val>>8)&0x0F;
|
||||||
val = 2000 - 10*RX_LQI;
|
}
|
||||||
else
|
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)
|
if(ch<14)
|
||||||
{
|
{
|
||||||
packet[9 + ch*2] = val;
|
packet[9 + ch*2] = val;
|
||||||
@@ -209,42 +237,6 @@ static void AFHDS2A_build_packet(uint8_t type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case AFHDS2A_PACKET_SETTINGS:
|
||||||
packet[0] = 0xaa;
|
packet[0] = 0xaa;
|
||||||
packet[9] = 0xfd;
|
packet[9] = 0xfd;
|
||||||
@@ -253,17 +245,43 @@ static void AFHDS2A_build_packet(uint8_t type)
|
|||||||
if(val<50 || val>400) val=50; // default is 50Hz
|
if(val<50 || val>400) val=50; // default is 50Hz
|
||||||
packet[11]= val;
|
packet[11]= val;
|
||||||
packet[12]= val >> 8;
|
packet[12]= val >> 8;
|
||||||
packet[13] = sub_protocol & 0x01; // 1 -> PPM output enabled
|
memset(&packet[15],0xFF,22);
|
||||||
packet[14]= 0x00;
|
#ifndef MULTI_AIR
|
||||||
for(uint8_t i=15; i<37; i++)
|
if(sub_protocol < AFHDS2A_GYRO_OFF)
|
||||||
packet[i] = 0xff;
|
{
|
||||||
packet[18] = 0x05; // ?
|
#endif
|
||||||
packet[19] = 0xdc; // ?
|
packet[13] = sub_protocol & 0x01; // 1 -> PPM output enabled
|
||||||
packet[20] = 0x05; // ?
|
packet[14] = 0x00; // ?
|
||||||
if(sub_protocol&2)
|
packet[18] = 0x05; // ?
|
||||||
packet[21] = 0xdd; // SBUS output enabled
|
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
|
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;
|
break;
|
||||||
}
|
}
|
||||||
packet[37] = 0x00;
|
packet[37] = 0x00;
|
||||||
@@ -283,6 +301,9 @@ uint16_t AFHDS2A_callback()
|
|||||||
static uint16_t packet_counter;
|
static uint16_t packet_counter;
|
||||||
uint8_t data_rx=0;
|
uint8_t data_rx=0;
|
||||||
uint16_t start;
|
uint16_t start;
|
||||||
|
#ifndef MULTI_AIR
|
||||||
|
static uint16_t Prev_Channel[4] = { 0,0,0,0 };
|
||||||
|
#endif
|
||||||
#ifndef FORCE_AFHDS2A_TUNING
|
#ifndef FORCE_AFHDS2A_TUNING
|
||||||
A7105_AdjustLOBaseFreq(1);
|
A7105_AdjustLOBaseFreq(1);
|
||||||
#endif
|
#endif
|
||||||
@@ -367,10 +388,39 @@ uint16_t AFHDS2A_callback()
|
|||||||
AFHDS2A_build_packet(packet_type);
|
AFHDS2A_build_packet(packet_type);
|
||||||
data_rx=A7105_ReadReg(A7105_00_MODE); // Check if something has been received...
|
data_rx=A7105_ReadReg(A7105_00_MODE); // Check if something has been received...
|
||||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, hopping_frequency[hopping_frequency_no++]);
|
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, hopping_frequency[hopping_frequency_no++]);
|
||||||
if(hopping_frequency_no >= AFHDS2A_NUMFREQ)
|
hopping_frequency_no &= 0x0F; // AFHDS2A_NUMFREQ
|
||||||
hopping_frequency_no = 0;
|
#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))
|
if(!(packet_counter % 1313))
|
||||||
|
{//Send settings every 5s
|
||||||
packet_type = AFHDS2A_PACKET_SETTINGS;
|
packet_type = AFHDS2A_PACKET_SETTINGS;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef FAILSAFE_ENABLE
|
#ifdef FAILSAFE_ENABLE
|
||||||
@@ -448,9 +498,6 @@ void AFHDS2A_init()
|
|||||||
rx_id[i]=eeprom_read_byte((EE_ADDR)(addr+i));
|
rx_id[i]=eeprom_read_byte((EE_ADDR)(addr+i));
|
||||||
}
|
}
|
||||||
hopping_frequency_no = 0;
|
hopping_frequency_no = 0;
|
||||||
if(sub_protocol&0x04)
|
packet_sent = 0;
|
||||||
num_ch=17;
|
|
||||||
else
|
|
||||||
num_ch=14;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
254
Multiprotocol/Ares_cc2500.ino
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
This project is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Multiprotocol is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// Compatible with ARES 6HPA transmitter
|
||||||
|
|
||||||
|
#if defined(ARES_CC2500_INO)
|
||||||
|
|
||||||
|
#include "iface_cc2500.h"
|
||||||
|
|
||||||
|
//#define ARES_FORCE_ID
|
||||||
|
|
||||||
|
#define ARES_COARSE 0
|
||||||
|
|
||||||
|
#define ARES_PACKET_LEN 17
|
||||||
|
#define ARES_NUM_FREQUENCIES 60
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARES_START = 0x00,
|
||||||
|
ARES_CALIB = 0x01,
|
||||||
|
ARES_PREP = 0x02,
|
||||||
|
ARES_DATA = 0x03,
|
||||||
|
};
|
||||||
|
|
||||||
|
// CC2500 register init values captured from the ARES 6HPA transmitter
|
||||||
|
const PROGMEM uint8_t ARES_init_values[] = {
|
||||||
|
/* 00 */ 0x06, 0x2E, 0x2E, 0x07, 0x5A, 0x60, 0x30, 0x04,
|
||||||
|
/* 08 */ 0x05, 0x00, 0x00, 0x06, 0x00, 0x5C, 0xB1, 0x3B + ARES_COARSE,
|
||||||
|
/* 10 */ 0x6A, 0xF8, 0x03, 0x23, 0x7A, 0x44, 0x07, 0x30,
|
||||||
|
/* 18 */ 0x18, 0x16, 0x6C, 0x43, 0x40, 0x91, 0x87, 0x6B,
|
||||||
|
/* 20 */ 0xF8, 0x56, 0x10, 0xA9, 0x0A, 0x00, 0x11
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fixed hopping sequence captured from the ARES 6HPA transmitter.
|
||||||
|
// This is a permutation of 60 channel values spread across the band.
|
||||||
|
static const PROGMEM uint8_t ARES_hop[] = {
|
||||||
|
0xB0, 0x6F, 0x1D, 0xB4, 0x74, 0x20, 0xB8, 0xD8,
|
||||||
|
0x24, 0xBC, 0xDC, 0x28, 0x48, 0xE0, 0x2C, 0x4C,
|
||||||
|
0xE4, 0x90, 0x50, 0xE8, 0x94, 0x54, 0xEC, 0x00,
|
||||||
|
0x98, 0x58, 0x04, 0x9B, 0x5C, 0x08, 0xA0, 0xC0,
|
||||||
|
0x0C, 0xA4, 0xC3, 0x10, 0x30, 0xC6, 0x14, 0x34,
|
||||||
|
0xCC, 0x78, 0x38, 0xD0, 0x7C, 0x3C, 0xD4, 0x80,
|
||||||
|
0x40, 0x60, 0x84, 0x44, 0x64, 0x88, 0xA8, 0x68,
|
||||||
|
0x8C, 0xAC, 0x6C, 0x18
|
||||||
|
};
|
||||||
|
|
||||||
|
static void __attribute__((unused)) ARES_CC2500_init()
|
||||||
|
{
|
||||||
|
CC2500_Strobe(CC2500_SRES);
|
||||||
|
delayMilliseconds(1);
|
||||||
|
CC2500_Strobe(CC2500_SIDLE);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 39; ++i)
|
||||||
|
CC2500_WriteReg(i, pgm_read_byte_near(&ARES_init_values[i]));
|
||||||
|
|
||||||
|
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||||
|
prev_option = option;
|
||||||
|
|
||||||
|
// Write PATABLE to max power (0xFF for all 8 entries) as captured
|
||||||
|
for (uint8_t i = 0; i < 8; i++)
|
||||||
|
CC2500_WriteReg(CC2500_3E_PATABLE, 0xFF);
|
||||||
|
|
||||||
|
CC2500_SetTxRxMode(TX_EN);
|
||||||
|
CC2500_SetPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load hopping table
|
||||||
|
static void __attribute__((unused)) ARES_RF_channels()
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < ARES_NUM_FREQUENCIES; i++)
|
||||||
|
hopping_frequency[i] = pgm_read_byte_near(&ARES_hop[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) ARES_tune_chan()
|
||||||
|
{
|
||||||
|
CC2500_Strobe(CC2500_SIDLE);
|
||||||
|
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[hopping_frequency_no]);
|
||||||
|
CC2500_Strobe(CC2500_SFTX);
|
||||||
|
CC2500_Strobe(CC2500_SCAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) ARES_change_chan_fast()
|
||||||
|
{
|
||||||
|
CC2500_Strobe(CC2500_SIDLE);
|
||||||
|
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[hopping_frequency_no]);
|
||||||
|
CC2500_WriteReg(CC2500_25_FSCAL1, calData[hopping_frequency_no]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance the hop counter: cycles through 0-58 with step, inserting 59 when wrapping through 0
|
||||||
|
static uint8_t __attribute__((unused)) ARES_next_counter(uint8_t current, uint8_t step)
|
||||||
|
{
|
||||||
|
if (current == 59)
|
||||||
|
return 0;
|
||||||
|
uint8_t next = (current + step) % 59;
|
||||||
|
if (next == 0)
|
||||||
|
return 59;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) ARES_build_packet()
|
||||||
|
{
|
||||||
|
// Length byte: 16 data bytes follow
|
||||||
|
packet[0] = 0x10;
|
||||||
|
|
||||||
|
// TX ID
|
||||||
|
packet[1] = rx_tx_addr[1];
|
||||||
|
packet[2] = rx_tx_addr[2];
|
||||||
|
packet[3] = rx_tx_addr[3];
|
||||||
|
|
||||||
|
// 6 channels encoded as interleaved 12-bit values in bytes 4-12
|
||||||
|
uint16_t ch[6];
|
||||||
|
for (uint8_t i = 0; i < 6; i++)
|
||||||
|
ch[i] = convert_channel_16b_nolimit(i, 1820, 3300, false);
|
||||||
|
|
||||||
|
packet[4] = ch[0] >> 4;
|
||||||
|
packet[5] = ((ch[0] & 0x0F) << 4) | (ch[1] & 0x0F);
|
||||||
|
packet[6] = ch[1] >> 4;
|
||||||
|
packet[7] = ch[2] >> 4;
|
||||||
|
packet[8] = ((ch[2] & 0x0F) << 4) | (ch[3] & 0x0F);
|
||||||
|
packet[9] = ch[3] >> 4;
|
||||||
|
packet[10] = ch[4] >> 4;
|
||||||
|
packet[11] = ((ch[4] & 0x0F) << 4) | (ch[5] & 0x0F);
|
||||||
|
packet[12] = ch[5] >> 4;
|
||||||
|
|
||||||
|
// Byte 16: counter step size (stored in crc, set to 1-58 in ARES_init)
|
||||||
|
uint8_t step = crc;
|
||||||
|
|
||||||
|
// Bytes 13-15: running counter with rotating bit 7 frame indicator
|
||||||
|
// The counter cycles 0-58 with a step, inserting 59 before wrapping to 0
|
||||||
|
// Each group of 3 packets has 3 consecutive counter values
|
||||||
|
// packet_count holds the current counter value
|
||||||
|
uint8_t c0 = packet_count;
|
||||||
|
uint8_t c1 = ARES_next_counter(c0, step);
|
||||||
|
uint8_t c2 = ARES_next_counter(c1, step);
|
||||||
|
|
||||||
|
// Frame indicator: each data frame is sent 3 times
|
||||||
|
// bind_phase tracks position 0/1/2 within the group of 3
|
||||||
|
packet[13] = c0;
|
||||||
|
packet[14] = c1;
|
||||||
|
packet[15] = c2;
|
||||||
|
packet[16] = step;
|
||||||
|
|
||||||
|
// Set the rotating frame bit (bit 7) on one of bytes 13-15
|
||||||
|
switch (bind_phase)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
packet[13] |= 0x80;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
packet[14] |= 0x80;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
packet[15] |= 0x80;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) ARES_send_packet()
|
||||||
|
{
|
||||||
|
ARES_change_chan_fast();
|
||||||
|
CC2500_SetPower();
|
||||||
|
CC2500_WriteData(packet, ARES_PACKET_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ARES_PACKET_PERIOD 6670 // 6.67ms between packets
|
||||||
|
#define ARES_PREP_TIMING 2000
|
||||||
|
|
||||||
|
uint16_t ARES_callback()
|
||||||
|
{
|
||||||
|
switch(phase)
|
||||||
|
{
|
||||||
|
case ARES_START:
|
||||||
|
ARES_CC2500_init();
|
||||||
|
hopping_frequency_no = 0;
|
||||||
|
bind_phase = 0;
|
||||||
|
ARES_tune_chan();
|
||||||
|
phase = ARES_CALIB;
|
||||||
|
return ARES_PREP_TIMING;
|
||||||
|
case ARES_CALIB:
|
||||||
|
calData[hopping_frequency_no] = CC2500_ReadReg(CC2500_25_FSCAL1);
|
||||||
|
hopping_frequency_no++;
|
||||||
|
if (hopping_frequency_no < ARES_NUM_FREQUENCIES)
|
||||||
|
ARES_tune_chan();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hopping_frequency_no = 0;
|
||||||
|
phase = ARES_PREP;
|
||||||
|
}
|
||||||
|
return ARES_PREP_TIMING;
|
||||||
|
case ARES_PREP:
|
||||||
|
if (prev_option != option)
|
||||||
|
{
|
||||||
|
phase = ARES_START;
|
||||||
|
return ARES_PREP_TIMING;
|
||||||
|
}
|
||||||
|
#ifdef MULTI_SYNC
|
||||||
|
telemetry_set_input_sync(ARES_PACKET_PERIOD);
|
||||||
|
#endif
|
||||||
|
ARES_build_packet();
|
||||||
|
phase = ARES_DATA;
|
||||||
|
// Fall through
|
||||||
|
case ARES_DATA:
|
||||||
|
ARES_send_packet();
|
||||||
|
hopping_frequency_no++;
|
||||||
|
if (hopping_frequency_no >= ARES_NUM_FREQUENCIES)
|
||||||
|
hopping_frequency_no = 0;
|
||||||
|
bind_phase++;
|
||||||
|
if (bind_phase >= 3)
|
||||||
|
{
|
||||||
|
bind_phase = 0;
|
||||||
|
// Advance counter to start of next group
|
||||||
|
uint8_t step = crc;
|
||||||
|
packet_count = ARES_next_counter(packet_count, step);
|
||||||
|
packet_count = ARES_next_counter(packet_count, step);
|
||||||
|
packet_count = ARES_next_counter(packet_count, step);
|
||||||
|
}
|
||||||
|
phase = ARES_PREP;
|
||||||
|
return ARES_PACKET_PERIOD;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ARES_init()
|
||||||
|
{
|
||||||
|
BIND_DONE; // Autobind protocol - no TX-initiated bind phase
|
||||||
|
ARES_RF_channels();
|
||||||
|
|
||||||
|
// rx_tx_addr[1] and [2] are already set from MProtocol_id by the framework
|
||||||
|
// RX_num (0-63) in byte 3 provides model match
|
||||||
|
rx_tx_addr[3] = RX_num;
|
||||||
|
|
||||||
|
// Counter step and start from capture
|
||||||
|
crc = 23;
|
||||||
|
packet_count = 35;
|
||||||
|
|
||||||
|
#ifdef ARES_FORCE_ID
|
||||||
|
rx_tx_addr[1] = 0xDC;
|
||||||
|
rx_tx_addr[2] = 0xCC;
|
||||||
|
rx_tx_addr[3] = 0x00;
|
||||||
|
#endif
|
||||||
|
phase = ARES_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
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);
|
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:
|
//NOTE: This can also be implemented as:
|
||||||
//for(i = 0; i < len; i++) WriteRegister)0x23, datacodes[i];
|
//for(i = 0; i < 16; i++) WriteRegister)0x23, datacodes[i];
|
||||||
CYRF_WriteRegisterMulti(CYRF_23_DATA_CODE, datacodes, len);
|
CYRF_WriteRegisterMulti(CYRF_23_DATA_CODE, datacodes, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CYRF_WritePreamble(uint32_t preamble)
|
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
|
//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 NUM_FREQ 80
|
||||||
#define FREQ_OFFSET 4
|
#define FREQ_OFFSET 4
|
||||||
@@ -269,7 +269,12 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin
|
|||||||
delayMilliseconds(1);
|
delayMilliseconds(1);
|
||||||
for(i = 0; i < NUM_FREQ; i++)
|
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
|
delayMicroseconds(270); //slow channel require 270usec for synthesizer to settle
|
||||||
if( !(CYRF_ReadRegister(CYRF_05_RX_CTRL) & 0x80)) {
|
if( !(CYRF_ReadRegister(CYRF_05_RX_CTRL) & 0x80)) {
|
||||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80); //Prepare to receive
|
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
|
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] = {
|
const uint8_t PROGMEM DEVO_j6pro_sopcodes[][8] = {
|
||||||
/* Note these are in order transmitted (LSB 1st) */
|
/* Note these are in order transmitted (LSB 1st) */
|
||||||
{0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91},
|
{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},
|
{0xB9, 0x8E, 0x19, 0x74, 0x6F, 0x65, 0x18, 0x74},
|
||||||
{0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49},
|
{0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49},
|
||||||
{0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72},
|
{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},
|
{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
|
{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,
|
{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},
|
{0xB6, 0x31, 0xAE, 0x46, 0x5A, 0xCC, 0xAE, 0x46},
|
||||||
{0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C},
|
{0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C},
|
||||||
{0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74},
|
{0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74},
|
||||||
|
{0x62, 0xDF, 0xC1, 0x49, 0xDF, 0xB1, 0xC0, 0x49}, //j6pro bind
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
#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)
|
static void __attribute__((unused)) CYRF_PROGMEM_ConfigSOPCode(const uint8_t *data)
|
||||||
{
|
{
|
||||||
uint8_t code[8];
|
uint8_t code[8];
|
||||||
|
//debug("SOP:");
|
||||||
for(uint8_t i=0;i<8;i++)
|
for(uint8_t i=0;i<8;i++)
|
||||||
|
{
|
||||||
code[i]=pgm_read_byte_near(&data[i]);
|
code[i]=pgm_read_byte_near(&data[i]);
|
||||||
|
//debug(" %02X",code[i]);
|
||||||
|
}
|
||||||
|
//debugln("");
|
||||||
CYRF_ConfigSOPCode(code);
|
CYRF_ConfigSOPCode(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,45 @@
|
|||||||
|
|
||||||
uint8_t sop_col;
|
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) */
|
/* 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 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8},
|
||||||
/* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6},
|
/* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6},
|
||||||
/* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9},
|
/* 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 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D},
|
||||||
/* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1},
|
/* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1},
|
||||||
/* Col 8 */ {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86}
|
/* 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++)
|
row--;
|
||||||
buf[i]=pgm_read_byte_near( &DSM_pncodes[row][col][i] );
|
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] = {
|
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_time();
|
||||||
debug(" crc:%04X,row:%d,col:%d,rf:%02X",(~seed)&0xffff,pn_row,sop_col,hopping_frequency[hopping_frequency_no]);
|
debug(" crc:%04X,row:%d,col:%d,rf:%02X",(~seed)&0xffff,pn_row,sop_col,hopping_frequency[hopping_frequency_no]);
|
||||||
#endif
|
#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);
|
CYRF_ConfigSOPCode(code);
|
||||||
DSM_read_code(code,pn_row,7 - sop_col,8); // 7-sop_col between 0 and 6
|
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,8); // 7-sop_col+1 between 1 and 7
|
DSM_read_code(code+8,pn_row,7 - sop_col + 1); // 7-sop_col+1 between 1 and 8
|
||||||
CYRF_ConfigDataCode(code, 16);
|
CYRF_ConfigDataCode(code);
|
||||||
|
|
||||||
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
|
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
|
||||||
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...
|
//64 SDR Mode is configured so only the 8 first values are needed but need to write 16 values...
|
||||||
uint8_t code[16];
|
uint8_t code[16];
|
||||||
DSM_read_code(code,0,8,8);
|
DSM_read_code(code,0,8);
|
||||||
CYRF_ConfigDataCode(code, 16);
|
CYRF_ConfigDataCode(code);
|
||||||
CYRF_ConfigRFChannel(1);
|
CYRF_ConfigRFChannel(1);
|
||||||
CYRF_SetTxRxMode(RX_EN); // Force end state read
|
CYRF_SetTxRxMode(RX_EN); // Force end state read
|
||||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive
|
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive
|
||||||
@@ -214,6 +214,15 @@ uint16_t DSM_RX_callback()
|
|||||||
uint8_t rx_status;
|
uint8_t rx_status;
|
||||||
static uint8_t read_retry=0;
|
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)
|
switch (phase)
|
||||||
{
|
{
|
||||||
case DSM_RX_BIND1:
|
case DSM_RX_BIND1:
|
||||||
@@ -240,10 +249,14 @@ uint16_t DSM_RX_callback()
|
|||||||
{
|
{
|
||||||
// store tx info into eeprom
|
// store tx info into eeprom
|
||||||
uint16_t temp = DSM_RX_EEPROM_OFFSET;
|
uint16_t temp = DSM_RX_EEPROM_OFFSET;
|
||||||
|
|
||||||
debug("ID=");
|
debug("ID=");
|
||||||
for(uint8_t i=0;i<4;i++)
|
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]);
|
eeprom_write_byte((EE_ADDR)temp++, cyrfmfg_id[i]);
|
||||||
debug(" %02X", 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
|
0x01 => 22ms 1024 DSM2 1 packet => number of channels is <8
|
||||||
0x02 => 22ms 1024 DSM2 2 packets => either a number of channel >7
|
0x02 => 22ms 1024 DSM2 2 packets => either a number of channel >7
|
||||||
0x12 => 11ms 2048 DSM2 2 packets => can be any number of channels
|
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
|
0xA2 => 22ms 2048 DSMX 1 packet => number of channels is <8
|
||||||
0xB2 => 11ms 2048 DSMX => can be any number of channels
|
0xB2 => 11ms 2048 DSMX => can be any number of channels
|
||||||
(0x01 or 0xA2) and num_ch < 7 => 22ms else 11ms
|
(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);
|
eeprom_write_byte((EE_ADDR)temp, DSM_rx_type);
|
||||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||||
CYRF_SetTxRxMode(TX_EN); // Force end state TX
|
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
|
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX
|
||||||
DSM_RX_build_bind_packet();
|
DSM_RX_build_bind_packet();
|
||||||
bind_counter=500;
|
bind_counter=500;
|
||||||
@@ -303,6 +317,14 @@ uint16_t DSM_RX_callback()
|
|||||||
{
|
{
|
||||||
BIND_DONE;
|
BIND_DONE;
|
||||||
phase++; // DSM_RX_DATA_PREP
|
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;
|
break;
|
||||||
case DSM_RX_DATA_PREP:
|
case DSM_RX_DATA_PREP:
|
||||||
@@ -470,20 +492,34 @@ void DSM_RX_init()
|
|||||||
|
|
||||||
if (IS_BIND_IN_PROGRESS)
|
if (IS_BIND_IN_PROGRESS)
|
||||||
{
|
{
|
||||||
packet_count=0;
|
if(sub_protocol == DSM_ERASE)
|
||||||
phase = DSM_RX_BIND1;
|
{
|
||||||
|
// 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
|
else
|
||||||
{
|
{
|
||||||
uint16_t temp = DSM_RX_EEPROM_OFFSET;
|
uint16_t temp = DSM_RX_EEPROM_OFFSET;
|
||||||
|
if (sub_protocol == DSM_CLONE || sub_protocol == DSM_ERASE )
|
||||||
|
temp = DSM_CLONE_EEPROM_OFFSET;
|
||||||
debug("ID=");
|
debug("ID=");
|
||||||
for(uint8_t i=0;i<4;i++)
|
for(uint8_t i=0;i<4;i++)
|
||||||
{
|
{
|
||||||
cyrfmfg_id[i]=eeprom_read_byte((EE_ADDR)temp++);
|
cyrfmfg_id[i]=eeprom_read_byte((EE_ADDR)temp++);
|
||||||
debug(" %02X", cyrfmfg_id[i]);
|
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);
|
debugln(", type=%02X", DSM_rx_type);
|
||||||
|
|
||||||
phase = DSM_RX_DATA_PREP;
|
phase = DSM_RX_DATA_PREP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,23 @@
|
|||||||
#include "iface_cyrf6936.h"
|
#include "iface_cyrf6936.h"
|
||||||
|
|
||||||
//#define DSM_DEBUG_FWD_PGM
|
//#define DSM_DEBUG_FWD_PGM
|
||||||
|
//#define DEBUG_BIND 1
|
||||||
|
|
||||||
//#define DSM_GR300
|
#define CLONE_BIT_MASK 0x20
|
||||||
|
#define MODE_11MS_BIT_MASK 0x40
|
||||||
|
#define MAX_THROW_BIT_MASK 0x80
|
||||||
|
#define DSM_BIND_CHANNEL 0x0D //13 This can be any odd channel
|
||||||
|
#define DSM2_SFC_PERIOD 16500
|
||||||
|
|
||||||
#define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel
|
//During binding we will send BIND_COUNT packets
|
||||||
|
|
||||||
//During binding we will send BIND_COUNT/2 packets
|
|
||||||
//One packet each 10msec
|
//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 {
|
enum {
|
||||||
DSM_BIND_WRITE=0,
|
DSM_BIND_WRITE=0,
|
||||||
@@ -44,6 +53,13 @@ enum {
|
|||||||
DSM_CH2_READ_B,
|
DSM_CH2_READ_B,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(DSM_X_PLUS)
|
||||||
|
#define XP_CH CH13 // X-Plus channel placeholder in frame
|
||||||
|
uint8_t x_plus_ch = 0; // X-Plus channel currently multiplexing
|
||||||
|
#else
|
||||||
|
#define XP_CH 0xff // No Channel
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
uint8_t ch_map[14];
|
uint8_t ch_map[14];
|
||||||
const uint8_t PROGMEM DSM_ch_map_progmem[][14] = {
|
const uint8_t PROGMEM DSM_ch_map_progmem[][14] = {
|
||||||
@@ -58,7 +74,7 @@ const uint8_t PROGMEM DSM_ch_map_progmem[][14] = {
|
|||||||
{1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 8, 0xff, 0xff, 0xff}, //9ch - Guess
|
{1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 8, 0xff, 0xff, 0xff}, //9ch - Guess
|
||||||
{1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 8, 9, 0xff, 0xff}, //10ch - Guess
|
{1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 8, 9, 0xff, 0xff}, //10ch - Guess
|
||||||
{1, 5, 2, 3, 6, 10, 0xff, 4, 0, 7, 8, 9, 0xff, 0xff}, //11ch - Guess
|
{1, 5, 2, 3, 6, 10, 0xff, 4, 0, 7, 8, 9, 0xff, 0xff}, //11ch - Guess
|
||||||
{1, 5, 2, 4, 6, 10, 0xff, 0, 7, 3, 8, 9 , 11 , 0xff}, //12ch - DX18/DX8G2
|
{1, 5, 2, 4, 6, 10, XP_CH, 0, 7, 3, 8, 9 , 11 , 0xff}, //12ch - DX18/DX8G2
|
||||||
//11ms for 8..11 channels
|
//11ms for 8..11 channels
|
||||||
{1, 5, 2, 3, 6, 7, 0xff, 1, 5, 2, 4, 0, 0xff, 0xff}, //8ch - DX7
|
{1, 5, 2, 3, 6, 7, 0xff, 1, 5, 2, 4, 0, 0xff, 0xff}, //8ch - DX7
|
||||||
{1, 5, 2, 3, 6, 7, 0xff, 1, 5, 2, 4, 0, 8, 0xff}, //9ch - Guess
|
{1, 5, 2, 3, 6, 7, 0xff, 1, 5, 2, 4, 0, 8, 0xff}, //9ch - Guess
|
||||||
@@ -87,9 +103,12 @@ static void __attribute__((unused)) DSM_build_bind_packet()
|
|||||||
packet[11] = 12;
|
packet[11] = 12;
|
||||||
else
|
else
|
||||||
packet[11] = num_ch; // DX5 DSMR sends 0x48...
|
packet[11] = num_ch; // DX5 DSMR sends 0x48...
|
||||||
|
//packet[11] = 3; // DX3R
|
||||||
|
|
||||||
if (sub_protocol==DSMR)
|
if (sub_protocol==DSMR)
|
||||||
packet[12] = 0xa2;
|
packet[12] = 0xa2;
|
||||||
|
else if (sub_protocol==DSM2_SFC)
|
||||||
|
packet[12] = 0x23; // DX3R
|
||||||
else if (sub_protocol==DSM2_1F)
|
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
|
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)
|
else if(sub_protocol==DSM2_2F)
|
||||||
@@ -102,7 +121,6 @@ static void __attribute__((unused)) DSM_build_bind_packet()
|
|||||||
#endif
|
#endif
|
||||||
else // DSMX_2F && DSM_AUTO
|
else // DSMX_2F && DSM_AUTO
|
||||||
packet[12] = 0xb2; // DSMX/2048 2 packets
|
packet[12] = 0xb2; // DSMX/2048 2 packets
|
||||||
|
|
||||||
|
|
||||||
packet[13] = 0x00; //???
|
packet[13] = 0x00; //???
|
||||||
for(i = 8; i < 14; i++)
|
for(i = 8; i < 14; i++)
|
||||||
@@ -116,8 +134,8 @@ static void __attribute__((unused)) DSM_initialize_bind_phase()
|
|||||||
CYRF_ConfigRFChannel(DSM_BIND_CHANNEL); //This seems to be random?
|
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...
|
//64 SDR Mode is configured so only the 8 first values are needed but need to write 16 values...
|
||||||
uint8_t code[16];
|
uint8_t code[16];
|
||||||
DSM_read_code(code,0,8,8);
|
DSM_read_code(code,0,8);
|
||||||
CYRF_ConfigDataCode(code, 16);
|
CYRF_ConfigDataCode(code);
|
||||||
DSM_build_bind_packet();
|
DSM_build_bind_packet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,16 +144,23 @@ static void __attribute__((unused)) DSM_update_channels()
|
|||||||
prev_option=option;
|
prev_option=option;
|
||||||
num_ch=option & 0x0F; // Remove flags 0x80=max_throw, 0x40=11ms
|
num_ch=option & 0x0F; // Remove flags 0x80=max_throw, 0x40=11ms
|
||||||
|
|
||||||
if(num_ch<3 || num_ch>12)
|
if(num_ch<3)
|
||||||
num_ch=6; // Default to 6 channels if invalid choice...
|
num_ch=6; // Default to 6 channels if invalid choice...
|
||||||
|
|
||||||
if(sub_protocol==DSMR && num_ch>7)
|
#ifndef MULTI_AIR
|
||||||
num_ch=7; // Max 7 channels in DSMR
|
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
|
// Create channel map based on number of channels and refresh rate
|
||||||
uint8_t idx=num_ch-3;
|
uint8_t idx=num_ch-3;
|
||||||
if((option & 0x40) && num_ch>7 && num_ch<12)
|
if(idx > 9)
|
||||||
idx+=5; // In 11ms mode change index only for channels 8..11
|
idx = 9;
|
||||||
|
if((option & MODE_11MS_BIT_MASK) && num_ch>7 && num_ch<12)
|
||||||
|
idx += 5; // In 11ms mode change index only for channels 8..11
|
||||||
for(uint8_t i=0;i<14;i++)
|
for(uint8_t i=0;i<14;i++)
|
||||||
ch_map[i]=pgm_read_byte_near(&DSM_ch_map_progmem[idx][i]);
|
ch_map[i]=pgm_read_byte_near(&DSM_ch_map_progmem[idx][i]);
|
||||||
}
|
}
|
||||||
@@ -143,7 +168,13 @@ static void __attribute__((unused)) DSM_update_channels()
|
|||||||
static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
|
static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
|
||||||
{
|
{
|
||||||
uint8_t bits = 11;
|
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)
|
if(prev_option!=option)
|
||||||
DSM_update_channels();
|
DSM_update_channels();
|
||||||
|
|
||||||
@@ -160,34 +191,41 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
|
|||||||
bits=10; // Only DSM2_1F is using a resolution of 1024
|
bits=10; // Only DSM2_1F is using a resolution of 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sub_protocol == DSMR)
|
#ifndef MULTI_AIR
|
||||||
{
|
if(sub_protocol == DSMR || sub_protocol == DSM2_SFC)
|
||||||
for (uint8_t i = 0; i < 7; i++)
|
{ // 12 bits, full range, no reassignment
|
||||||
{
|
for (uint8_t i = 0; i < 7; i++)
|
||||||
uint16_t value = 0x0000;
|
{
|
||||||
if(i < num_ch)
|
uint16_t value = 0x0000;
|
||||||
value=Channel_data[i]<<1;
|
if(i < num_ch)
|
||||||
packet[i*2+2] = (value >> 8) & 0xff;
|
{
|
||||||
packet[i*2+3] = (value >> 0) & 0xff;
|
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
|
||||||
}
|
|
||||||
|
#if defined(DSM_THROTTLE_KILL_CH)
|
||||||
#ifdef DSM_THROTTLE_KILL_CH
|
|
||||||
uint16_t kill_ch=Channel_data[DSM_THROTTLE_KILL_CH-1];
|
uint16_t kill_ch=Channel_data[DSM_THROTTLE_KILL_CH-1];
|
||||||
#endif
|
#endif
|
||||||
for (uint8_t i = 0; i < 7; i++)
|
for (uint8_t i = 0; i < 7; i++)
|
||||||
{
|
{
|
||||||
uint8_t idx = ch_map[(upper?7:0) + i]; // 1,5,2,3,0,4
|
uint8_t idx = ch_map[(upper?7:0) + i]; // 1,5,2,3,0,4
|
||||||
uint16_t value = 0xffff;
|
uint16_t value = 0xffff;
|
||||||
if((option&0x40) == 0 && num_ch < 8 && upper)
|
|
||||||
|
if((option & MODE_11MS_BIT_MASK) == 0 && num_ch < 8 && upper)
|
||||||
idx=0xff; // in 22ms do not transmit upper channels if <8, is it the right method???
|
idx=0xff; // in 22ms do not transmit upper channels if <8, is it the right method???
|
||||||
if (idx != 0xff)
|
else if (idx != 0xff)
|
||||||
{
|
{
|
||||||
/* Spektrum own remotes transmit normal values during bind and actually use this (e.g. Nano CP X) to
|
/* Spektrum own remotes transmit normal values during bind and actually use this (e.g. Nano CP X) to
|
||||||
select the transmitter mode (e.g. computer vs non-computer radio), so always send normal output */
|
select the transmitter mode (e.g. computer vs non-computer radio), so always send normal output */
|
||||||
#ifdef DSM_THROTTLE_KILL_CH
|
#if defined(DSM_THROTTLE_KILL_CH)
|
||||||
if(idx==CH1 && kill_ch<=604)
|
if(idx==CH1 && kill_ch<=604 && num_ch<=12)
|
||||||
{//Activate throttle kill only if channel is throttle and DSM_THROTTLE_KILL_CH below -50%
|
{//Activate throttle kill only if channel is throttle and DSM_THROTTLE_KILL_CH below -50%
|
||||||
if(kill_ch<CHANNEL_MIN_100) // restrict val to 0...400
|
if(kill_ch<CHANNEL_MIN_100) // restrict val to 0...400
|
||||||
kill_ch=0;
|
kill_ch=0;
|
||||||
@@ -197,16 +235,41 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
#ifdef DSM_MAX_THROW
|
{
|
||||||
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
|
#if defined(DSM_X_PLUS)
|
||||||
#else
|
if (idx==XP_CH) { // X-Plus special channel placeholder
|
||||||
if(option & 0x80)
|
idx = XP_CH + x_plus_ch; // Encode CH13-CH16 instead
|
||||||
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef DSM_MAX_THROW
|
||||||
|
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
|
||||||
|
#else
|
||||||
|
if(option & MAX_THROW_BIT_MASK)
|
||||||
|
value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
|
||||||
|
else
|
||||||
|
value=convert_channel_16b_nolimit(CH_TAER[idx],0x156,0x6AA,false); // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on a DX8 G2 dump
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if defined(DSM_X_PLUS)
|
||||||
|
if (idx >= XP_CH) { // X-Plus Channel
|
||||||
|
// Multiplexing 4 chanels on the same frame channel placeholder for channel 13 (ID=12) over time (Refresh cycle 88ms)
|
||||||
|
// CH13-16 lower frame, and Ch17-20 upper. We only do lower right now, since MM cannot handle more than 16ch
|
||||||
|
// Channel value is 9 bits, and upper 2 bits is the X-Plus channel (CH13..CH16).
|
||||||
|
if(num_ch>12)
|
||||||
|
{
|
||||||
|
value >>= 2; // Convert to 9 bits
|
||||||
|
value |= (XP_CH << 11) | (x_plus_ch << 9); // constant 12 (4 bits), XPlus Ch (2 bits), Value (9 bits)
|
||||||
|
x_plus_ch = (x_plus_ch + 1) % 4; // only 0..3
|
||||||
|
}
|
||||||
else
|
else
|
||||||
value=convert_channel_16b_nolimit(CH_TAER[idx],0x156,0x6AA,false); // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on a DX8 G2 dump
|
value = 0xffff;
|
||||||
#endif
|
}
|
||||||
if(bits==10) value>>=1;
|
else
|
||||||
value |= (upper && i==0 ? 0x8000 : 0) | (idx << bits);
|
#endif
|
||||||
|
{ // Regular channel
|
||||||
|
if(bits==10) value>>=1;
|
||||||
|
value |= (upper && i==0 ? 0x8000 : 0) | (idx << bits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
packet[i*2+2] = value >> 8;
|
packet[i*2+2] = value >> 8;
|
||||||
packet[i*2+3] = value;
|
packet[i*2+3] = value;
|
||||||
@@ -250,27 +313,33 @@ static uint8_t __attribute__((unused)) DSM_Check_RX_packet()
|
|||||||
uint16_t DSM_callback()
|
uint16_t DSM_callback()
|
||||||
{
|
{
|
||||||
#if defined MULTI_EU
|
#if defined MULTI_EU
|
||||||
if(sub_protocol == DSM2_1F || sub_protocol == DSM2_2F)
|
if(sub_protocol == DSM2_1F || sub_protocol == DSM2_2F || sub_protocol == DSM2_SFC)
|
||||||
|
{
|
||||||
|
SUB_PROTO_INVALID;
|
||||||
return 11000;
|
return 11000;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined MULTI_AIR
|
||||||
|
if(sub_protocol == DSMR || sub_protocol == DSM2_SFC)
|
||||||
|
{
|
||||||
|
SUB_PROTO_INVALID;
|
||||||
|
return 11000;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
|
#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
|
||||||
#ifdef STM32_BOARD
|
#ifdef STM32_BOARD
|
||||||
#define DSM_WRITE_DELAY 1600 // Time after write to verify write complete
|
#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
|
#else
|
||||||
#define DSM_WRITE_DELAY 1950 // Time after write to verify write complete
|
#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
|
#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
|
#if defined DSM_TELEMETRY
|
||||||
uint8_t rx_phase;
|
uint8_t rx_phase;
|
||||||
uint8_t len;
|
uint8_t length;
|
||||||
#endif
|
#endif
|
||||||
uint8_t start;
|
uint8_t start;
|
||||||
|
//debugln("P=%d",phase);
|
||||||
#ifdef DSM_GR300
|
|
||||||
uint16_t timing=5000+(convert_channel_8b(CH13)*100);
|
|
||||||
debugln("T=%u",timing);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch(phase)
|
switch(phase)
|
||||||
{
|
{
|
||||||
case DSM_BIND_WRITE:
|
case DSM_BIND_WRITE:
|
||||||
@@ -284,11 +353,14 @@ uint16_t DSM_callback()
|
|||||||
return 10000;
|
return 10000;
|
||||||
#if defined DSM_TELEMETRY
|
#if defined DSM_TELEMETRY
|
||||||
case DSM_BIND_CHECK:
|
case DSM_BIND_CHECK:
|
||||||
//64 SDR Mode is configured so only the 8 first values are needed but we need to write 16 values...
|
#if DEBUG_BIND
|
||||||
CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84", 16);
|
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_SetTxRxMode(RX_EN); //Receive mode
|
||||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //Prepare to receive
|
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
|
phase++; // change from BIND_CHECK to BIND_READ
|
||||||
return 2000;
|
return 2000;
|
||||||
case DSM_BIND_READ:
|
case DSM_BIND_READ:
|
||||||
@@ -304,10 +376,12 @@ uint16_t DSM_callback()
|
|||||||
CYRF_ReadDataPacketLen(packet_in+1, 10);
|
CYRF_ReadDataPacketLen(packet_in+1, 10);
|
||||||
if(DSM_Check_RX_packet())
|
if(DSM_Check_RX_packet())
|
||||||
{
|
{
|
||||||
debug("Bind");
|
#if DEBUG_BIND
|
||||||
for(uint8_t i=0;i<10;i++)
|
debug("Bind");
|
||||||
debug(" %02X",packet_in[i+1]);
|
for(uint8_t i=0;i<10;i++)
|
||||||
debugln("");
|
debug(" %02X",packet_in[i+1]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
packet_in[0]=0x80;
|
packet_in[0]=0x80;
|
||||||
packet_in[6]&=0x0F; // It looks like there is a flag 0x40 being added by some receivers
|
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;
|
if(packet_in[6]>12) packet_in[6]=12;
|
||||||
@@ -332,6 +406,9 @@ uint16_t DSM_callback()
|
|||||||
}
|
}
|
||||||
if( --bind_counter == 0 )
|
if( --bind_counter == 0 )
|
||||||
{ // Exit if no answer has been received for some time
|
{ // Exit if no answer has been received for some time
|
||||||
|
#if DEBUG_BIND
|
||||||
|
debugln("Bind Read TIMEOUT");
|
||||||
|
#endif
|
||||||
phase++; // DSM_CHANSEL
|
phase++; // DSM_CHANSEL
|
||||||
return 7000 ;
|
return 7000 ;
|
||||||
}
|
}
|
||||||
@@ -343,25 +420,38 @@ uint16_t DSM_callback()
|
|||||||
CYRF_SetTxRxMode(TX_EN);
|
CYRF_SetTxRxMode(TX_EN);
|
||||||
hopping_frequency_no = 0;
|
hopping_frequency_no = 0;
|
||||||
phase = DSM_CH1_WRITE_A; // in fact phase++
|
phase = DSM_CH1_WRITE_A; // in fact phase++
|
||||||
|
#ifndef MULTI_AIR
|
||||||
if(sub_protocol == DSMR)
|
if(sub_protocol == DSMR)
|
||||||
DSM_set_sop_data_crc(false, true);
|
DSM_set_sop_data_crc(false, true);
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
DSM_set_sop_data_crc(true, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F); //prep CH1
|
DSM_set_sop_data_crc(true, sub_protocol==DSMX_2F||sub_protocol==DSMX_1F); //prep CH1
|
||||||
return 10000;
|
return 10000;
|
||||||
case DSM_CH1_WRITE_A:
|
case DSM_CH1_WRITE_A:
|
||||||
#ifdef MULTI_SYNC
|
#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
|
#endif
|
||||||
|
#ifndef MULTI_AIR
|
||||||
if(sub_protocol == DSMR)
|
if(sub_protocol == DSMR)
|
||||||
CYRF_SetPower(0x08); //Keep transmit power in sync
|
CYRF_SetPower(0x08); //Keep transmit power in sync
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
CYRF_SetPower(0x28); //Keep transmit power in sync
|
CYRF_SetPower(0x28); //Keep transmit power in sync
|
||||||
case DSM_CH1_WRITE_B:
|
case DSM_CH1_WRITE_B:
|
||||||
DSM_build_data_packet(phase == DSM_CH1_WRITE_B); // build lower or upper channels
|
DSM_build_data_packet(phase == DSM_CH1_WRITE_B); // build lower or upper channels
|
||||||
case DSM_CH2_WRITE_A:
|
case DSM_CH2_WRITE_A:
|
||||||
case DSM_CH2_WRITE_B:
|
case DSM_CH2_WRITE_B:
|
||||||
CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags
|
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
|
#if 0
|
||||||
for(uint8_t i=0;i<16;i++)
|
for(uint8_t i=0;i<16;i++)
|
||||||
debug(" %02X", packet[i]);
|
debug(" %02X", packet[i]);
|
||||||
@@ -398,41 +488,52 @@ uint16_t DSM_callback()
|
|||||||
phase++; // change from CH2_CHECK to CH2_READ
|
phase++; // change from CH2_CHECK to CH2_READ
|
||||||
CYRF_SetTxRxMode(RX_EN); //Receive mode
|
CYRF_SetTxRxMode(RX_EN); //Receive mode
|
||||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
|
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
|
||||||
if(sub_protocol==DSMR)
|
#ifndef MULTI_AIR
|
||||||
{
|
if(sub_protocol==DSMR || sub_protocol == DSM2_SFC)
|
||||||
phase = DSM_CH2_READ_B;
|
{
|
||||||
return 11000 - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
phase = DSM_CH2_READ_B;
|
||||||
}
|
if(sub_protocol == DSM2_SFC)
|
||||||
#ifdef DSM_GR300
|
{
|
||||||
if(num_ch==3)
|
if(option&0x40) // option&40 in this case is 16.5ms/11ms frame rate for DSM2_SFC
|
||||||
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
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
|
#endif
|
||||||
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY;
|
||||||
case DSM_CH2_READ_A:
|
case DSM_CH2_READ_A:
|
||||||
case DSM_CH2_READ_B:
|
case DSM_CH2_READ_B:
|
||||||
//Read telemetry
|
//Read telemetry
|
||||||
rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
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)
|
if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing)
|
||||||
rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
|
||||||
|
//debug("ST2:%02X ",rx_phase);
|
||||||
if((rx_phase & 0x07) == 0x02)
|
if((rx_phase & 0x07) == 0x02)
|
||||||
{ // good data (complete with no errors)
|
{ // good data (complete with no errors)
|
||||||
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
|
CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read
|
||||||
len=CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
length=CYRF_ReadRegister(CYRF_09_RX_COUNT);
|
||||||
if(len>TELEMETRY_BUFFER_SIZE-2)
|
//debug("RX(%d)",length);
|
||||||
len=TELEMETRY_BUFFER_SIZE-2;
|
if(length>TELEMETRY_BUFFER_SIZE-2)
|
||||||
CYRF_ReadDataPacketLen(packet_in+1, len);
|
length=TELEMETRY_BUFFER_SIZE-2;
|
||||||
|
CYRF_ReadDataPacketLen(packet_in+1, length);
|
||||||
#ifdef DSM_DEBUG_FWD_PGM
|
#ifdef DSM_DEBUG_FWD_PGM
|
||||||
//debug(" %02X", packet_in[1]);
|
//debug(" %02X", packet_in[1]);
|
||||||
if(packet_in[1]==9)
|
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]);
|
debug(" %02X", packet_in[i+1]);
|
||||||
debugln("");
|
debugln("");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
packet_in[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;// store RSSI of the received telemetry signal
|
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;
|
telemetry_link=1;
|
||||||
}
|
}
|
||||||
|
//debugln("");
|
||||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
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
|
if (phase == DSM_CH2_READ_A && (sub_protocol==DSM2_1F || sub_protocol==DSMX_1F) && num_ch < 8) // 22ms mode
|
||||||
{
|
{
|
||||||
@@ -440,10 +541,6 @@ uint16_t DSM_callback()
|
|||||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
|
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Clear abort RX operation
|
||||||
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
|
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive
|
||||||
phase = DSM_CH2_READ_B;
|
phase = DSM_CH2_READ_B;
|
||||||
#ifdef DSM_GR300
|
|
||||||
if(num_ch==3)
|
|
||||||
return timing;
|
|
||||||
#endif
|
|
||||||
return 11000;
|
return 11000;
|
||||||
}
|
}
|
||||||
if (phase == DSM_CH2_READ_A)
|
if (phase == DSM_CH2_READ_A)
|
||||||
@@ -464,19 +561,20 @@ uint16_t DSM_callback()
|
|||||||
else
|
else
|
||||||
{ //Normal mode 22ms
|
{ //Normal mode 22ms
|
||||||
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
|
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
|
||||||
#ifdef DSM_GR300
|
#ifndef MULTI_AIR
|
||||||
if(num_ch==3)
|
if(sub_protocol==DSM2_SFC)
|
||||||
return timing - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
{
|
||||||
|
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
|
#endif
|
||||||
return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower)
|
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;
|
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -484,6 +582,7 @@ uint16_t DSM_callback()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MULTI_AIR
|
||||||
const uint8_t PROGMEM DSMR_ID_FREQ[][4 + 23] = {
|
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 },
|
{ 0x71, 0x74, 0x1c, 0xe4, 0x11, 0x2f, 0x17, 0x3d, 0x23, 0x3b, 0x0f, 0x21, 0x25, 0x49, 0x1d, 0x13, 0x4d, 0x1f, 0x41, 0x4b, 0x47, 0x05, 0x27, 0x15, 0x19, 0x3f, 0x07 },
|
||||||
{ 0xfe, 0xfe, 0xfe, 0xfe, 0x45, 0x31, 0x33, 0x4b, 0x11, 0x29, 0x49, 0x3f, 0x09, 0x13, 0x47, 0x21, 0x1d, 0x43, 0x1f, 0x05, 0x41, 0x19, 0x1b, 0x2d, 0x15, 0x4d, 0x0f },
|
{ 0xfe, 0xfe, 0xfe, 0xfe, 0x45, 0x31, 0x33, 0x4b, 0x11, 0x29, 0x49, 0x3f, 0x09, 0x13, 0x47, 0x21, 0x1d, 0x43, 0x1f, 0x05, 0x41, 0x19, 0x1b, 0x2d, 0x15, 0x4d, 0x0f },
|
||||||
@@ -507,32 +606,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 },
|
{ 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 },
|
{ 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 } };
|
{ 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()
|
void DSM_init()
|
||||||
{
|
{
|
||||||
if(sub_protocol == DSMR)
|
if(sub_protocol == DSMR)
|
||||||
{
|
{
|
||||||
uint8_t row = rx_tx_addr[3]%22;
|
#ifndef MULTI_AIR
|
||||||
for(uint8_t i=0; i< 4; i++)
|
if(option&CLONE_BIT_MASK)
|
||||||
cyrfmfg_id[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i]);
|
SUB_PROTO_INVALID;
|
||||||
for(uint8_t i=0; i< 23; i++)
|
else
|
||||||
hopping_frequency[i] = pgm_read_byte_near(&DSMR_ID_FREQ[row][i+4]);
|
{
|
||||||
|
//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
|
else
|
||||||
{
|
{
|
||||||
CYRF_GetMfgData(cyrfmfg_id);
|
if(option&CLONE_BIT_MASK)
|
||||||
//Model match
|
{
|
||||||
cyrfmfg_id[3]^=RX_num;
|
if(eeprom_read_byte((EE_ADDR)DSM_CLONE_EEPROM_OFFSET+4)==0xF0)
|
||||||
|
{
|
||||||
|
//read cloned ID from EEPROM
|
||||||
|
uint16_t temp = DSM_CLONE_EEPROM_OFFSET;
|
||||||
|
for(uint8_t i=0;i<4;i++)
|
||||||
|
cyrfmfg_id[i] = eeprom_read_byte((EE_ADDR)temp++);
|
||||||
|
cyrfmfg_id[3]^=RX_num; //Model match
|
||||||
|
#if DEBUG_BIND
|
||||||
|
debugln("Using cloned ID");
|
||||||
|
debug("Clone ID=")
|
||||||
|
for(uint8_t i=0;i<4;i++)
|
||||||
|
debug("%02x ", cyrfmfg_id[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SUB_PROTO_INVALID;
|
||||||
|
#if DEBUG_BIND
|
||||||
|
debugln("No valid cloned ID");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//SUB_PROTO_VALID;
|
||||||
|
CYRF_GetMfgData(cyrfmfg_id);
|
||||||
|
cyrfmfg_id[3]^=RX_num; //Model match
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Calc sop_col
|
//Calc sop_col
|
||||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
|
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"
|
//We cannot manipulate the ID if we are cloning
|
||||||
if(sop_col==0 && sub_protocol != DSMR)
|
if(!(option&CLONE_BIT_MASK))
|
||||||
{
|
{
|
||||||
cyrfmfg_id[rx_tx_addr[0]%3]^=0x01; //Change a bit so sop_col will be different from 0
|
//Fix for OrangeRX using wrong DSM_pncodes by preventing access to "Col 8"
|
||||||
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
|
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
|
//Calc CRC seed
|
||||||
@@ -544,7 +684,7 @@ void DSM_init()
|
|||||||
else if(sub_protocol != DSMR)
|
else if(sub_protocol != DSMR)
|
||||||
{
|
{
|
||||||
uint8_t tmpch[10];
|
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;
|
uint8_t idx = random(0xfefefefe) % 10;
|
||||||
hopping_frequency[0] = tmpch[idx];
|
hopping_frequency[0] = tmpch[idx];
|
||||||
@@ -568,9 +708,12 @@ void DSM_init()
|
|||||||
DSM_initialize_bind_phase();
|
DSM_initialize_bind_phase();
|
||||||
phase = DSM_BIND_WRITE;
|
phase = DSM_BIND_WRITE;
|
||||||
bind_counter=DSM_BIND_COUNT;
|
bind_counter=DSM_BIND_COUNT;
|
||||||
|
#if DEBUG_BIND
|
||||||
|
debugln("Bind Started: write count=%d",bind_counter);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
phase = DSM_CHANSEL;//
|
phase = DSM_CHANSEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ static void __attribute__((unused)) DEVO_cyrf_init()
|
|||||||
|
|
||||||
static void __attribute__((unused)) DEVO_set_radio_channels()
|
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[3] = hopping_frequency[0];
|
||||||
hopping_frequency[4] = hopping_frequency[1];
|
hopping_frequency[4] = hopping_frequency[1];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,11 @@ static void __attribute__((unused)) E129_build_data_packet()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
packet[ 1] = 0xA6;
|
packet[ 1] = 0xA6; // Set to A5 every few packets??
|
||||||
|
|
||||||
//Flags
|
//Flags
|
||||||
if(sub_protocol == E129_E129)
|
packet[ 2] = 0xF7; // E129 High rate 0xF7, low 0xF4
|
||||||
packet[ 2] = 0xF7; // High rate 0xF7, low 0xF4
|
if(sub_protocol == E129_C186)
|
||||||
else //C186
|
|
||||||
{
|
{
|
||||||
packet[ 2] = 0xFA; // High rate 0xFA, medium 0xF7, low 0xF4
|
packet[ 2] = 0xFA; // High rate 0xFA, medium 0xF7, low 0xF4
|
||||||
packet[13] = bit_reverse(rx_tx_addr[2]);
|
packet[13] = bit_reverse(rx_tx_addr[2]);
|
||||||
@@ -53,9 +53,18 @@ static void __attribute__((unused)) E129_build_data_packet()
|
|||||||
packet[15] = bit_reverse(rx_tx_addr[0]);
|
packet[15] = bit_reverse(rx_tx_addr[0]);
|
||||||
packet[16] = bit_reverse(rx_tx_addr[1]);
|
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[ 3] = GET_FLAG(CH10_SW, 0x40) // C159: loop flight 0x40
|
||||||
packet[ 4] = GET_FLAG(CH5_SW, 0x20) // Take off/Land 0x20
|
| GET_FLAG(CH11_SW, 0x08); // C129V2: flip
|
||||||
| GET_FLAG(CH6_SW, 0x04); // Emergency stop 0x04
|
//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
|
//Channels and trims
|
||||||
uint16_t val = convert_channel_10b(AILERON,false);
|
uint16_t val = convert_channel_10b(AILERON,false);
|
||||||
uint8_t trim = convert_channel_8b(CH7) & 0xFC;
|
uint8_t trim = convert_channel_8b(CH7) & 0xFC;
|
||||||
@@ -80,13 +89,11 @@ static void __attribute__((unused)) E129_build_data_packet()
|
|||||||
packet[12] = val; // channel (0x000...0x200...0x3FF)
|
packet[12] = val; // channel (0x000...0x200...0x3FF)
|
||||||
}
|
}
|
||||||
//Check
|
//Check
|
||||||
if(sub_protocol == E129_E129)
|
for(uint8_t i=0;i<packet_length-2;i++)
|
||||||
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++)
|
|
||||||
packet[packet_length-2] += packet[i];
|
packet[packet_length-2] += packet[i];
|
||||||
|
if(sub_protocol == E129_C186)
|
||||||
|
packet[packet_length-2] -= 0x80;
|
||||||
|
|
||||||
RF2500_BuildPayload(packet);
|
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
|
||||||
@@ -31,6 +31,19 @@ enum {
|
|||||||
FQ777_FLAG_FLIP = 0x80,
|
FQ777_FLAG_FLIP = 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
XBM37_B5_OK = 0x80,
|
||||||
|
XBM37_B6_RATE_LOW = 0x00,
|
||||||
|
XBM37_B6_RATE_MID = 0x01,
|
||||||
|
XBM37_B6_RATE_HIGH = 0x02,
|
||||||
|
XBM37_B6_LED_OFF = 0x04,
|
||||||
|
XBM37_B6_RTH = 0x08,
|
||||||
|
XBM37_B6_HEADLESS = 0x10,
|
||||||
|
XBM37_B6_VIDEO = 0x20,
|
||||||
|
XBM37_B6_PICTURE = 0x40,
|
||||||
|
XBM37_B6_FLIP = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
const uint8_t ssv_xor[] = {0x80,0x44,0x64,0x75,0x6C,0x71,0x2A,0x36,0x7C,0xF1,0x6E,0x52,0x9,0x9D,0x1F,0x78,0x3F,0xE1,0xEE,0x16,0x6D,0xE8,0x73,0x9,0x15,0xD7,0x92,0xE7,0x3,0xBA};
|
const uint8_t ssv_xor[] = {0x80,0x44,0x64,0x75,0x6C,0x71,0x2A,0x36,0x7C,0xF1,0x6E,0x52,0x9,0x9D,0x1F,0x78,0x3F,0xE1,0xEE,0x16,0x6D,0xE8,0x73,0x9,0x15,0xD7,0x92,0xE7,0x3,0xBA};
|
||||||
uint8_t FQ777_bind_addr [] = {0xe7,0xe7,0xe7,0xe7,0x67};
|
uint8_t FQ777_bind_addr [] = {0xe7,0xe7,0xe7,0xe7,0x67};
|
||||||
|
|
||||||
@@ -87,12 +100,21 @@ static void __attribute__((unused)) FQ777_send_packet()
|
|||||||
uint8_t packet_ori[8];
|
uint8_t packet_ori[8];
|
||||||
if (IS_BIND_IN_PROGRESS)
|
if (IS_BIND_IN_PROGRESS)
|
||||||
{
|
{
|
||||||
// 4,5,6 = address fields
|
// Byte 0 is always 0x20; bytes 1-3 are sub-protocol specific
|
||||||
// last field is checksum of address fields
|
|
||||||
packet_ori[0] = 0x20;
|
packet_ori[0] = 0x20;
|
||||||
packet_ori[1] = 0x15;
|
if (sub_protocol == XBM37)
|
||||||
packet_ori[2] = 0x05;
|
{
|
||||||
packet_ori[3] = 0x06;
|
packet_ori[1] = 0x14;
|
||||||
|
packet_ori[2] = 0x07;
|
||||||
|
packet_ori[3] = 0x03;
|
||||||
|
}
|
||||||
|
else // FQ777
|
||||||
|
{
|
||||||
|
packet_ori[1] = 0x15;
|
||||||
|
packet_ori[2] = 0x05;
|
||||||
|
packet_ori[3] = 0x06;
|
||||||
|
}
|
||||||
|
// Bytes 4-6: address fields, byte 7: checksum of address fields (shared by both protocols)
|
||||||
packet_ori[4] = rx_tx_addr[0];
|
packet_ori[4] = rx_tx_addr[0];
|
||||||
packet_ori[5] = rx_tx_addr[1];
|
packet_ori[5] = rx_tx_addr[1];
|
||||||
packet_ori[6] = rx_tx_addr[2];
|
packet_ori[6] = rx_tx_addr[2];
|
||||||
@@ -100,36 +122,64 @@ static void __attribute__((unused)) FQ777_send_packet()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// throt, yaw, pitch, roll, trims, flags/left button,00,right button
|
if (sub_protocol == XBM37)
|
||||||
//0-3 0x00-0x64
|
{
|
||||||
//4 roll/pitch/yaw trims. cycles through one trim at a time - 0-40 trim1, 40-80 trim2, 80-C0 trim3 (center: A0 20 60)
|
packet_ori[0] = convert_channel_16b_limit(THROTTLE,0xE1,0); // reverse channel
|
||||||
//5 flags for throttle button, two buttons above throttle - def: 0x40
|
packet_ori[1] = convert_channel_16b_limit(RUDDER,0,0xE1);
|
||||||
//6 00 ??
|
packet_ori[2] = convert_channel_16b_limit(AILERON,0xE1,0); // reverse channel
|
||||||
//7 checksum - add values in other fields
|
packet_ori[3] = convert_channel_16b_limit(ELEVATOR,0xE1,0); // reverse channel
|
||||||
|
packet_ori[4] = (convert_channel_8b(CH13) >> 2) + 1; // ele trim (01..20..40) front ^ plus 0x01, back - minus 0x01 per click
|
||||||
|
packet_ori[5] = 0x3F - (convert_channel_8b(CH14) >> 2) // ail trim (40..20..01) left <- plus 0x01, right -> minus 0x01 per click
|
||||||
|
| GET_FLAG(CH12_SW, XBM37_B5_OK); // bit7 = OK button ...unknown use for this model?
|
||||||
|
|
||||||
|
uint8_t rate_bits;
|
||||||
// Trims are usually done through the radio configuration but leaving the code here just in case...
|
if (CH5_SW)
|
||||||
uint8_t trim_mod = packet_count % 144;
|
rate_bits = XBM37_B6_RATE_HIGH; // high rate
|
||||||
uint8_t trim_val = 0;
|
else if (Channel_data[CH5] < CHANNEL_MIN_COMMAND)
|
||||||
if (36 <= trim_mod && trim_mod < 72) // yaw
|
rate_bits = XBM37_B6_RATE_LOW; // low rate
|
||||||
trim_val = 0x20; // don't modify yaw trim
|
else
|
||||||
else
|
rate_bits = XBM37_B6_RATE_MID; // medium rate
|
||||||
if (108 < trim_mod && trim_mod) // pitch
|
|
||||||
trim_val = 0xA0;
|
|
||||||
else // roll
|
|
||||||
trim_val = 0x60;
|
|
||||||
|
|
||||||
packet_ori[0] = convert_channel_16b_limit(THROTTLE,0,0x64);
|
packet_ori[6] = rate_bits // bits[1:0] = rate
|
||||||
packet_ori[1] = convert_channel_16b_limit(RUDDER,0,0x64);
|
| GET_FLAG(CH8_SW, XBM37_B6_LED_OFF) // bit2 = LED off
|
||||||
packet_ori[2] = convert_channel_16b_limit(ELEVATOR,0,0x64);
|
| GET_FLAG(CH11_SW, XBM37_B6_RTH) // bit3 = RTH
|
||||||
packet_ori[3] = convert_channel_16b_limit(AILERON,0,0x64);
|
| GET_FLAG(CH7_SW, XBM37_B6_HEADLESS) // bit4 = headless
|
||||||
packet_ori[4] = trim_val; // calculated above
|
| GET_FLAG(CH10_SW, XBM37_B6_VIDEO) // bit5 = video
|
||||||
packet_ori[5] = GET_FLAG(CH5_SW, FQ777_FLAG_FLIP)
|
| GET_FLAG(CH9_SW, XBM37_B6_PICTURE) // bit6 = picture
|
||||||
| GET_FLAG(CH7_SW, FQ777_FLAG_HEADLESS)
|
| GET_FLAG(CH6_SW, XBM37_B6_FLIP); // bit7 = flip
|
||||||
| GET_FLAG(!CH6_SW, FQ777_FLAG_RETURN)
|
}
|
||||||
| GET_FLAG(CH8_SW,FQ777_FLAG_EXPERT);
|
else // FQ777
|
||||||
packet_ori[6] = 0x00;
|
{
|
||||||
// calculate checksum
|
// throt, yaw, pitch, roll, trims, flags/left button,00,right button
|
||||||
|
//0-3 0x00-0x64
|
||||||
|
//4 roll/pitch/yaw trims. cycles through one trim at a time - 0-40 trim1, 40-80 trim2, 80-C0 trim3 (center: A0 20 60)
|
||||||
|
//5 flags for throttle button, two buttons above throttle - def: 0x40
|
||||||
|
//6 00 ??
|
||||||
|
//7 checksum - add values in other fields
|
||||||
|
|
||||||
|
// Trims are usually done through the radio configuration but leaving the code here just in case...
|
||||||
|
uint8_t trim_mod = packet_count % 144;
|
||||||
|
uint8_t trim_val = 0;
|
||||||
|
if (36 <= trim_mod && trim_mod < 72) // yaw
|
||||||
|
trim_val = 0x20; // don't modify yaw trim
|
||||||
|
else
|
||||||
|
if (108 < trim_mod && trim_mod) // pitch
|
||||||
|
trim_val = 0xA0;
|
||||||
|
else // roll
|
||||||
|
trim_val = 0x60;
|
||||||
|
|
||||||
|
packet_ori[0] = convert_channel_16b_limit(THROTTLE,0,0x64);
|
||||||
|
packet_ori[1] = convert_channel_16b_limit(RUDDER,0,0x64);
|
||||||
|
packet_ori[2] = convert_channel_16b_limit(ELEVATOR,0,0x64);
|
||||||
|
packet_ori[3] = convert_channel_16b_limit(AILERON,0,0x64);
|
||||||
|
packet_ori[4] = trim_val; // calculated above
|
||||||
|
packet_ori[5] = GET_FLAG(CH5_SW, FQ777_FLAG_FLIP)
|
||||||
|
| GET_FLAG(CH7_SW, FQ777_FLAG_HEADLESS)
|
||||||
|
| GET_FLAG(!CH6_SW, FQ777_FLAG_RETURN)
|
||||||
|
| GET_FLAG(CH8_SW,FQ777_FLAG_EXPERT);
|
||||||
|
packet_ori[6] = 0x00;
|
||||||
|
}
|
||||||
|
// Data packet checksum: sum of bytes 0-6 (not applied to bind packets)
|
||||||
uint8_t checksum = 0;
|
uint8_t checksum = 0;
|
||||||
for (int i = 0; i < 7; ++i)
|
for (int i = 0; i < 7; ++i)
|
||||||
checksum += packet_ori[i];
|
checksum += packet_ori[i];
|
||||||
@@ -181,12 +231,17 @@ void FQ777_init(void)
|
|||||||
BIND_IN_PROGRESS; // autobind protocol
|
BIND_IN_PROGRESS; // autobind protocol
|
||||||
bind_counter = FQ777_BIND_COUNT;
|
bind_counter = FQ777_BIND_COUNT;
|
||||||
packet_count=0;
|
packet_count=0;
|
||||||
hopping_frequency[0] = 0x4D;
|
// Sub-protocol hop channel table: first 3 channels differ; channel[3]=0x07 is shared
|
||||||
hopping_frequency[1] = 0x43;
|
static const uint8_t hop_ch[2][3] = {
|
||||||
hopping_frequency[2] = 0x27;
|
{0x4D, 0x43, 0x27}, // FQ777
|
||||||
|
{0x49, 0x34, 0x26}, // XBM-37
|
||||||
|
};
|
||||||
|
hopping_frequency[0] = hop_ch[sub_protocol][0];
|
||||||
|
hopping_frequency[1] = hop_ch[sub_protocol][1];
|
||||||
|
hopping_frequency[2] = hop_ch[sub_protocol][2];
|
||||||
hopping_frequency[3] = 0x07;
|
hopping_frequency[3] = 0x07;
|
||||||
hopping_frequency_no=0;
|
hopping_frequency_no=0;
|
||||||
rx_tx_addr[2] = 0x00;
|
rx_tx_addr[2] = (sub_protocol == XBM37) ? (RX_num & 0x3F) : 0x00; // XBM-37 uses receiver number (0-63) for model match capability
|
||||||
rx_tx_addr[3] = 0xe7;
|
rx_tx_addr[3] = 0xe7;
|
||||||
rx_tx_addr[4] = 0x67;
|
rx_tx_addr[4] = 0x67;
|
||||||
FQ777_RF_init();
|
FQ777_RF_init();
|
||||||
|
|||||||
@@ -33,28 +33,54 @@ Multiprotocol is distributed in the hope that it will be useful,
|
|||||||
#define FX620_PAYLOAD_SIZE 7
|
#define FX620_PAYLOAD_SIZE 7
|
||||||
#define FX620_CH_OFFSET 1
|
#define FX620_CH_OFFSET 1
|
||||||
|
|
||||||
#define FX9630_PACKET_PERIOD 8124
|
#define FX9630_PACKET_PERIOD 8124 //8156 on QIDI-560
|
||||||
#define FX9630_BIND_PACKET_PERIOD 8124
|
|
||||||
#define FX9630_BIND_CHANNEL 51
|
#define FX9630_BIND_CHANNEL 51
|
||||||
#define FX9630_PAYLOAD_SIZE 8
|
#define FX9630_PAYLOAD_SIZE 8
|
||||||
#define FX9630_NUM_CHANNELS 3
|
#define FX9630_NUM_CHANNELS 3
|
||||||
|
#define FX9630_WRITE_TIME 500
|
||||||
|
|
||||||
|
#define FX_QF012_PACKET_PERIOD 12194
|
||||||
|
#define FX_QF012_RX_PAYLOAD_SIZE 3
|
||||||
|
|
||||||
|
#define FX_BM26_BIND_CHANNEL 40
|
||||||
|
#define FX_BM26_PACKET_PERIOD 14066
|
||||||
|
|
||||||
|
#define FX_A570_PACKET_PERIOD 10270
|
||||||
|
|
||||||
//#define FORCE_FX620_ID
|
//#define FORCE_FX620_ID
|
||||||
//#define FORCE_FX9630_ID
|
//#define FORCE_FX9630_ID
|
||||||
|
//#define FORCE_QIDI_ID
|
||||||
|
//#define FORCE_FX_A570_ID
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
FX_DATA=0,
|
||||||
|
FX_RX,
|
||||||
|
};
|
||||||
|
|
||||||
static void __attribute__((unused)) FX_send_packet()
|
static void __attribute__((unused)) FX_send_packet()
|
||||||
{
|
{
|
||||||
|
static uint8_t trim_ch = 0;
|
||||||
|
|
||||||
//Hopp
|
//Hopp
|
||||||
if(IS_BIND_DONE)
|
if(IS_BIND_DONE)
|
||||||
{
|
{
|
||||||
XN297_Hopping(hopping_frequency_no++);
|
XN297_Hopping(hopping_frequency_no++);
|
||||||
if(sub_protocol == FX9630)
|
if(sub_protocol >= FX9630)
|
||||||
{
|
{ // FX9630 & FX_Q560 & FX_QF012 & FX_A570
|
||||||
XN297_SetTXAddr(rx_tx_addr, 4);
|
if (hopping_frequency_no >= FX9630_NUM_CHANNELS)
|
||||||
if (hopping_frequency_no > FX9630_NUM_CHANNELS)
|
{
|
||||||
hopping_frequency_no = 0;
|
hopping_frequency_no = 0;
|
||||||
|
if(sub_protocol == FX9630)
|
||||||
|
{
|
||||||
|
trim_ch++;
|
||||||
|
trim_ch &= 3;
|
||||||
|
}
|
||||||
|
else // FX_Q560 & FX_QF012 & FX_A570
|
||||||
|
trim_ch = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else // FX816 and FX620
|
else // FX816 & FX620
|
||||||
{
|
{
|
||||||
hopping_frequency_no &= 0x03;
|
hopping_frequency_no &= 0x03;
|
||||||
}
|
}
|
||||||
@@ -64,17 +90,7 @@ static void __attribute__((unused)) FX_send_packet()
|
|||||||
|
|
||||||
//Channels
|
//Channels
|
||||||
uint8_t val;
|
uint8_t val;
|
||||||
if (sub_protocol == FX9630)
|
if (sub_protocol == FX816 || sub_protocol == FX620)
|
||||||
{
|
|
||||||
packet[0] = convert_channel_8b(THROTTLE);
|
|
||||||
packet[1] = convert_channel_8b(AILERON);
|
|
||||||
packet[2] = 0xFF - convert_channel_8b(ELEVATOR);
|
|
||||||
packet[3] = convert_channel_8b(RUDDER);
|
|
||||||
packet[4] = 0x20;
|
|
||||||
packet[5] = GET_FLAG(CH5_SW, 0x01); // DR toggle swich: 0 small throw, 1 large throw
|
|
||||||
packet[5] |= (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x02 : 0x01)) << 1; // Mode A(0) : 6D small throw, B(1) : 6D large throw, C(2) : 3D
|
|
||||||
}
|
|
||||||
else // FX816 and FX620
|
|
||||||
{
|
{
|
||||||
uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET;
|
uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET;
|
||||||
val=convert_channel_8b(AILERON);
|
val=convert_channel_8b(AILERON);
|
||||||
@@ -86,6 +102,60 @@ static void __attribute__((unused)) FX_send_packet()
|
|||||||
packet[offset] = sub_protocol == FX816 ? 0:0x7F;
|
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
|
packet[offset+1] = convert_channel_16b_limit(THROTTLE,0,100); //FX816:0x00..0x63, FX620:0x00..0x5E but that should work
|
||||||
}
|
}
|
||||||
|
else if (sub_protocol == FX_A570)
|
||||||
|
{
|
||||||
|
packet[0] = convert_channel_16b_limit(THROTTLE,0x1C,0xE4);
|
||||||
|
packet[1] = convert_channel_16b_limit(AILERON,0xE4,0x1C);
|
||||||
|
packet[2] = convert_channel_16b_limit(ELEVATOR,0xE4,0x1C);
|
||||||
|
packet[3] = convert_channel_16b_limit(RUDDER,0x1C,0xE4);
|
||||||
|
// Trims - Ruddder L:01 R:02, Aileron L:03 R:04, Elevator Fwd:05 Back:06
|
||||||
|
packet[4] = (Channel_data[CH10] < CHANNEL_MIN_COMMAND ? 0x01 : GET_FLAG(CH10_SW, 0x02)) // Rudder trim
|
||||||
|
| (Channel_data[CH11] < CHANNEL_MIN_COMMAND ? 0x03 : GET_FLAG(CH11_SW, 0x04)) // Aileron trim
|
||||||
|
| (Channel_data[CH12] < CHANNEL_MIN_COMMAND ? 0x06 : GET_FLAG(CH12_SW, 0x05)); // Elevator trim
|
||||||
|
packet[5] = GET_FLAG(CH5_SW, 0x40) // motors stop
|
||||||
|
// A570 flight modes = 0>vertical flight(3 axis mode):00, 1>flat flight(6G):02, 2>vertical flight(2 axis mode):04
|
||||||
|
| (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x04 : 0x02))
|
||||||
|
| GET_FLAG(CH7_SW, 0x01) // 0:low rate, 1:high rate
|
||||||
|
| GET_FLAG(CH8_SW, 0x08) // LED color change
|
||||||
|
| GET_FLAG(CH9_SW, 0x10); // LED off
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // FX9630 & FX_Q560 & FX_QF012 & FX_BM26
|
||||||
|
packet[0] = convert_channel_8b(THROTTLE);
|
||||||
|
packet[1] = convert_channel_8b(AILERON);
|
||||||
|
packet[2] = 0xFF - convert_channel_8b(ELEVATOR);
|
||||||
|
packet[3] = convert_channel_8b(RUDDER);
|
||||||
|
if ( sub_protocol == FX_BM26 ) // BM26 Ail, Elev, Rud range between 0x00-0x3F-0x7F
|
||||||
|
{
|
||||||
|
packet[1] >>= 1;
|
||||||
|
packet[2] >>= 1;
|
||||||
|
packet[3] >>= 1;
|
||||||
|
}
|
||||||
|
val = trim_ch==0 ? 0x20 : (convert_channel_8b(trim_ch + CH6) >> 2); // no trim on Throttle
|
||||||
|
packet[4] = val; // Trim for channel x 0C..20..34
|
||||||
|
packet[5] = (trim_ch << 4) // channel x << 4
|
||||||
|
| GET_FLAG(CH5_SW, (sub_protocol == FX_QF012 ? 0x08 : 0x01)) // DR toggle swich: 0 small throw, 1 large throw / Q560 acrobatic / QF012 Special effects
|
||||||
|
// FX9630 =>0:6G small throw, 1:6G large throw, 2:3D
|
||||||
|
// QIDI-550=>0:3D, 1:6G, 2:Torque
|
||||||
|
// QF012=>0:beginner(6G), 1:mid(3D), 2:expert(Gyro off)
|
||||||
|
| (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x04 : 0x02));
|
||||||
|
if(sub_protocol == FX_Q560)
|
||||||
|
packet[5] |= GET_FLAG(CH7_SW, 0x18); // Q560 LED flag 0x10 conflicting with trim_ch... Corrected on new boards using 0x08 instead
|
||||||
|
else if (sub_protocol == FX_QF012)
|
||||||
|
packet[5] |= GET_FLAG(CH7_SW, 0x40) // QF012 invert flight
|
||||||
|
| GET_FLAG(CH8_SW, 0x80); // QF012 Restore fine tunning midpoint
|
||||||
|
else if ( sub_protocol == FX_BM26 )
|
||||||
|
{
|
||||||
|
packet[5] &= 0xC0;
|
||||||
|
packet[5] += 0x40;
|
||||||
|
// BM26 P51=>0:beginner(6G), 1:mid(3D), 2:expert(Gyro off)
|
||||||
|
packet[5] |= (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x08 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x0C : 0x0A));
|
||||||
|
packet[6] = GET_FLAG( CH5_SW, 0x20) // 6G Roll
|
||||||
|
| GET_FLAG(!CH7_SW, 0x08) // Light control switch, default on
|
||||||
|
| GET_FLAG(!CH8_SW, 0x10) // Turn signal switch, default on
|
||||||
|
| GET_FLAG( CH9_SW, 0x01); // Gyro Calibration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Bind and specifics
|
//Bind and specifics
|
||||||
if(sub_protocol == FX816)
|
if(sub_protocol == FX816)
|
||||||
@@ -112,7 +182,7 @@ static void __attribute__((unused)) FX_send_packet()
|
|||||||
packet[5] = 0xAB; // Is it based on ID??
|
packet[5] = 0xAB; // Is it based on ID??
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // FX9630
|
else // FX9630 & FX_Q560 & FX_QF012 & FX_BM26 & FX_A570
|
||||||
{
|
{
|
||||||
if(IS_BIND_IN_PROGRESS)
|
if(IS_BIND_IN_PROGRESS)
|
||||||
{
|
{
|
||||||
@@ -125,15 +195,17 @@ static void __attribute__((unused)) FX_send_packet()
|
|||||||
|
|
||||||
//Check
|
//Check
|
||||||
uint8_t last_packet_idx = packet_length-1;
|
uint8_t last_packet_idx = packet_length-1;
|
||||||
if (sub_protocol == FX9630 && IS_BIND_IN_PROGRESS)
|
if (sub_protocol >= FX9630 && IS_BIND_IN_PROGRESS)
|
||||||
last_packet_idx--;
|
last_packet_idx--;
|
||||||
val=0;
|
val=0;
|
||||||
for(uint8_t i=0;i<last_packet_idx;i++)
|
for(uint8_t i=0;i<last_packet_idx;i++)
|
||||||
val+=packet[i];
|
val+=packet[i];
|
||||||
if (sub_protocol == FX9630)
|
if (sub_protocol >= FX9630)
|
||||||
val = val ^ 0xFF;
|
val = val ^ 0xFF;
|
||||||
packet[last_packet_idx]=val;
|
packet[last_packet_idx]=val;
|
||||||
|
|
||||||
|
if ( IS_BIND_IN_PROGRESS && sub_protocol == FX_BM26 ) packet[7] = packet[6];
|
||||||
|
|
||||||
//Debug
|
//Debug
|
||||||
#if 0
|
#if 0
|
||||||
for(uint8_t i=0;i<packet_length;i++)
|
for(uint8_t i=0;i<packet_length;i++)
|
||||||
@@ -150,6 +222,7 @@ static void __attribute__((unused)) FX_send_packet()
|
|||||||
static void __attribute__((unused)) FX_RF_init()
|
static void __attribute__((unused)) FX_RF_init()
|
||||||
{
|
{
|
||||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||||
|
packet_length = FX9630_PAYLOAD_SIZE; // default
|
||||||
if(sub_protocol == FX816)
|
if(sub_protocol == FX816)
|
||||||
{
|
{
|
||||||
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
|
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
|
||||||
@@ -164,12 +237,23 @@ static void __attribute__((unused)) FX_RF_init()
|
|||||||
packet_period = FX620_BIND_PACKET_PERIOD;
|
packet_period = FX620_BIND_PACKET_PERIOD;
|
||||||
packet_length = FX620_PAYLOAD_SIZE;
|
packet_length = FX620_PAYLOAD_SIZE;
|
||||||
}
|
}
|
||||||
else // FX9630
|
else if (sub_protocol == FX_BM26)
|
||||||
|
{
|
||||||
|
XN297_SetTXAddr((uint8_t *)"\x12\x34\x10\x10", 4);
|
||||||
|
XN297_RFChannel(FX_BM26_BIND_CHANNEL);
|
||||||
|
packet_period = FX_BM26_PACKET_PERIOD;
|
||||||
|
}
|
||||||
|
else if(sub_protocol == FX_A570)
|
||||||
|
{
|
||||||
|
XN297_SetTXAddr((uint8_t *)"\x56\x78\x92\x13", 4);
|
||||||
|
XN297_RFChannel(FX9630_BIND_CHANNEL);
|
||||||
|
packet_period = FX_A570_PACKET_PERIOD;
|
||||||
|
}
|
||||||
|
else // FX9630 & FX_Q560 & FX_QF012
|
||||||
{
|
{
|
||||||
XN297_SetTXAddr((uint8_t *)"\x56\x78\x90\x12", 4);
|
XN297_SetTXAddr((uint8_t *)"\x56\x78\x90\x12", 4);
|
||||||
XN297_RFChannel(FX9630_BIND_CHANNEL);
|
XN297_RFChannel(FX9630_BIND_CHANNEL);
|
||||||
packet_period = FX9630_BIND_PACKET_PERIOD;
|
packet_period = sub_protocol == FX_QF012 ? FX_QF012_PACKET_PERIOD : FX9630_PACKET_PERIOD;
|
||||||
packet_length = FX9630_PAYLOAD_SIZE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,35 +280,121 @@ static void __attribute__((unused)) FX_initialize_txid()
|
|||||||
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
|
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
|
||||||
hopping_frequency[i] = i*10 + hopping_frequency[0];
|
hopping_frequency[i] = i*10 + hopping_frequency[0];
|
||||||
}
|
}
|
||||||
else // FX9630
|
else // FX9630 & FX_Q560 & FX_QF012 & FX_BM26 & FX_A570
|
||||||
{
|
{
|
||||||
|
//??? Need to find out how the first RF channel is calculated ???
|
||||||
|
hopping_frequency[0] = sub_protocol == FX_BM26? 0x0C : 0x13;
|
||||||
|
if (sub_protocol == FX_A570) hopping_frequency[0] = 0x0E;
|
||||||
|
//Other 2 RF channels are sent during the bind phase so they can be whatever
|
||||||
|
hopping_frequency[1] = RX_num & 0x0F + 0x1A;
|
||||||
|
hopping_frequency[2] = rx_tx_addr[3] & 0x0F + 0x38;
|
||||||
#ifdef FORCE_FX9630_ID
|
#ifdef FORCE_FX9630_ID
|
||||||
memcpy(rx_tx_addr,(uint8_t*)"\xCE\x31\x9B\x73", 4);
|
memcpy(rx_tx_addr,(uint8_t*)"\xCE\x31\x9B\x73", 4);
|
||||||
memcpy(hopping_frequency,"\x13\x1A\x38", FX9630_NUM_CHANNELS); //Original dump=19=0x13,26=0x1A,56=0x38
|
memcpy(hopping_frequency,"\x13\x1A\x38", FX9630_NUM_CHANNELS); //Original dump=>19=0x13,26=0x1A,56=0x38
|
||||||
#else
|
|
||||||
hopping_frequency[0] = 0x13; // constant
|
|
||||||
hopping_frequency[1] = RX_num & 0x0F + 0x1A;
|
|
||||||
hopping_frequency[2] = rx_tx_addr[3] & 0x0F + 0x38;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
#ifdef FORCE_QIDI_ID
|
||||||
|
memcpy(rx_tx_addr,(uint8_t*)"\x23\xDC\x76\xA2", 4);
|
||||||
|
memcpy(hopping_frequency,"\x08\x25\x33", FX9630_NUM_CHANNELS); //Original dump=>08=0x08,37=0x25,51=0x33
|
||||||
|
|
||||||
|
//QIDI-560 #1
|
||||||
|
//memcpy(rx_tx_addr,(uint8_t*)"\x38\xC7\x6D\x8D", 4);
|
||||||
|
//memcpy(hopping_frequency,"\x0D\x20\x3A", FX9630_NUM_CHANNELS);
|
||||||
|
#endif
|
||||||
|
// BM26 rx_tx_addr: "\x17\x03\x00\x00", hopping_frequency: 0x0C,0x30,0x43(12,48,67)
|
||||||
|
#ifdef FORCE_FX_A570_ID
|
||||||
|
memcpy(rx_tx_addr,(uint8_t*)"\xA9\x56\xFC\x1C", 4);
|
||||||
|
memcpy(hopping_frequency,"\x0E\x1F\x39", FX9630_NUM_CHANNELS); //Original dump=>14=0x0E,31=0x1F,57=0x39
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t FX_callback()
|
uint16_t FX_callback()
|
||||||
{
|
{
|
||||||
#ifdef MULTI_SYNC
|
#ifdef FX_HUB_TELEMETRY
|
||||||
telemetry_set_input_sync(packet_period);
|
bool rx=false;
|
||||||
#endif
|
static uint8_t telem_count = 0;
|
||||||
if(bind_counter)
|
switch(phase)
|
||||||
if(--bind_counter==0)
|
|
||||||
{
|
{
|
||||||
BIND_DONE;
|
case FX_DATA:
|
||||||
if(sub_protocol == FX620)
|
rx = XN297_IsRX();
|
||||||
{
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
XN297_SetTXAddr(rx_tx_addr, 3);
|
#endif
|
||||||
packet_period = FX620_PACKET_PERIOD;
|
#ifdef MULTI_SYNC
|
||||||
}
|
telemetry_set_input_sync(packet_period);
|
||||||
|
#endif
|
||||||
|
if(bind_counter)
|
||||||
|
if(--bind_counter==0)
|
||||||
|
{
|
||||||
|
BIND_DONE;
|
||||||
|
if(sub_protocol == FX620)
|
||||||
|
{
|
||||||
|
XN297_SetTXAddr(rx_tx_addr, 3);
|
||||||
|
packet_period = FX620_PACKET_PERIOD;
|
||||||
|
}
|
||||||
|
else if(sub_protocol >= FX9630)
|
||||||
|
{ // FX9630 & FX_Q560 & FX_QF012
|
||||||
|
XN297_SetTXAddr(rx_tx_addr, 4);
|
||||||
|
#ifdef FX_HUB_TELEMETRY
|
||||||
|
XN297_SetRXAddr(rx_tx_addr, FX_QF012_RX_PAYLOAD_SIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FX_send_packet();
|
||||||
|
#ifdef FX_HUB_TELEMETRY
|
||||||
|
if (sub_protocol == FX816 || sub_protocol == FX620 || sub_protocol == FX_A570)
|
||||||
|
break;
|
||||||
|
if(rx)
|
||||||
|
{
|
||||||
|
debug("RX");
|
||||||
|
if(XN297_ReadPayload(packet_in, FX_QF012_RX_PAYLOAD_SIZE))
|
||||||
|
{//Good CRC
|
||||||
|
telemetry_link = 1;
|
||||||
|
telemetry_lost = 0;
|
||||||
|
telem_count = 0;
|
||||||
|
if ( sub_protocol == FX_BM26 )
|
||||||
|
v_lipo1 = packet_in[0] < packet_in[2] ? 60:81; // packets: AA 00 55 -> 55 00 AA = low voltage 3.7V
|
||||||
|
else
|
||||||
|
v_lipo1 = packet_in[1] ? 60:81; // packets: A5 00 11 -> A5 01 11 = low voltage 3.7V
|
||||||
|
#if 0
|
||||||
|
for(uint8_t i=0; i < FX_QF012_RX_PAYLOAD_SIZE; i++)
|
||||||
|
debug(" %02X", packet_in[i]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
debugln();
|
||||||
|
}
|
||||||
|
if(telem_count > 4*63) // Around 3.5 sec with no telemetry
|
||||||
|
telemetry_lost = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
telem_count++;
|
||||||
|
if(!telemetry_lost && (telem_count & 0x3F) == 0)
|
||||||
|
{// Should have received a telem packet but... Send telem to the radio to keep it alive
|
||||||
|
telemetry_link = 1;
|
||||||
|
#if 0
|
||||||
|
debugln("Miss");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
phase++;
|
||||||
|
return FX9630_WRITE_TIME;
|
||||||
|
default: //FX_RX
|
||||||
|
/* { // Wait for packet to be sent before switching to receive mode
|
||||||
|
uint16_t start=(uint16_t)micros(), count=0;
|
||||||
|
while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 500)
|
||||||
|
{
|
||||||
|
if(XN297_IsPacketSent())
|
||||||
|
break;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
debug("%d",count);
|
||||||
|
} */
|
||||||
|
//Switch to RX
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
XN297_SetTxRxMode(RX_EN);
|
||||||
|
phase = FX_DATA;
|
||||||
|
return packet_period - FX9630_WRITE_TIME;
|
||||||
}
|
}
|
||||||
FX_send_packet();
|
#endif
|
||||||
return packet_period;
|
return packet_period;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,6 +405,11 @@ void FX_init()
|
|||||||
FX_RF_init();
|
FX_RF_init();
|
||||||
hopping_frequency_no = 0;
|
hopping_frequency_no = 0;
|
||||||
bind_counter=FX_BIND_COUNT;
|
bind_counter=FX_BIND_COUNT;
|
||||||
|
#ifdef FX_HUB_TELEMETRY
|
||||||
|
RX_RSSI = 100; // Dummy value
|
||||||
|
telemetry_lost = 1;
|
||||||
|
phase = FX_DATA;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
//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
|
//Unknown bytes
|
||||||
if(state & 0x01)
|
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
|
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
|
//ID
|
||||||
packet[5] = rx_tx_addr[1]; // ID
|
packet[5] = rx_tx_addr[1]; // ID
|
||||||
packet[6] = RX_num;
|
packet[6] = RX_num;
|
||||||
@@ -63,8 +63,9 @@ static void __attribute__((unused)) FrSkyX_build_bind_packet()
|
|||||||
if(binding_idx&0x02)
|
if(binding_idx&0x02)
|
||||||
packet[7] |= 0x80; // CH9-16
|
packet[7] |= 0x80; // CH9-16
|
||||||
//Replace the ID
|
//Replace the ID
|
||||||
packet[20] ^= 0x0E ^ rx_tx_addr[3]; // Update the ID
|
packet[20] ^= rx_tx_addr[3]; // Update the ID
|
||||||
packet[21] ^= 0x1C ^ rx_tx_addr[2]; // Update the ID
|
packet[21] ^= rx_tx_addr[2]; // Update the ID
|
||||||
|
packet[22] ^= rx_tx_addr[1] & 0x3F; // Update the ID
|
||||||
//Xor
|
//Xor
|
||||||
for(uint8_t i=3; i<packet_length-1; i++)
|
for(uint8_t i=3; i<packet_length-1; i++)
|
||||||
packet[i] ^= 0xA7;
|
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
|
FrSkyX_channels(7); // Set packet[7]=failsafe, packet[8]=0?? and packet[9..20]=channels data
|
||||||
|
|
||||||
//Sequence and send SPort
|
//Sequence and send SPort
|
||||||
FrSkyX_seq_sport(21,packet_length-(protocol==PROTO_FRSKYX && (FrSkyFormat & 2 )) ? 4 : 2); //21=RX|TXseq, 22=bytes count, 23..packet_length-2=data
|
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
|
//CRC
|
||||||
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_length-4);
|
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_length-4);
|
||||||
|
|||||||
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_0A_RX_ADDR_P0, rx_tx_addr, 5);
|
||||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, 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
|
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 10); // payload size = 10
|
||||||
|
#ifndef MULTI_AIR
|
||||||
if(sub_protocol==HK310)
|
if(sub_protocol==HK310)
|
||||||
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
|
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// HiSky channel sequence: AILE ELEV THRO RUDD GEAR PITCH, channel data value is from 0 to 1000
|
// 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()
|
uint16_t HISKY_callback()
|
||||||
{
|
{
|
||||||
phase++;
|
phase++;
|
||||||
|
#ifdef MULTI_AIR
|
||||||
|
if(sub_protocol==HK310)
|
||||||
|
{
|
||||||
|
SUB_PROTO_INVALID;
|
||||||
|
return 10000;
|
||||||
|
}
|
||||||
|
#else
|
||||||
if(sub_protocol==HK310)
|
if(sub_protocol==HK310)
|
||||||
switch(phase)
|
switch(phase)
|
||||||
{
|
{
|
||||||
@@ -132,6 +141,7 @@ uint16_t HISKY_callback()
|
|||||||
phase=8;
|
phase=8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
switch(phase)
|
switch(phase)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
@@ -195,6 +205,7 @@ uint16_t HISKY_callback()
|
|||||||
static void __attribute__((unused)) HISKY_initialize_tx_id()
|
static void __attribute__((unused)) HISKY_initialize_tx_id()
|
||||||
{
|
{
|
||||||
//Generate frequency hopping table
|
//Generate frequency hopping table
|
||||||
|
#ifndef MULTI_AIR
|
||||||
if(sub_protocol==HK310)
|
if(sub_protocol==HK310)
|
||||||
{
|
{
|
||||||
// for HiSky surface protocol, the transmitter always generates hop channels in sequential order.
|
// 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...
|
hopping_frequency[i]=hopping_frequency_no++; // Sequential order hop channels...
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
calc_fh_channels(HISKY_FREQUENCE_NUM);
|
#endif
|
||||||
// HiSky air protocol uses TX id as an address for nRF24L01, and uses frequency hopping sequence
|
// 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
|
// 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]
|
// to generate this sequence as we wish. It should be in the range [02..77]
|
||||||
|
calc_fh_channels(HISKY_FREQUENCE_NUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HISKY_init()
|
void HISKY_init()
|
||||||
|
|||||||
@@ -17,21 +17,25 @@
|
|||||||
|
|
||||||
#include "iface_xn297.h" // mix of nrf and xn297 at 1Mb...
|
#include "iface_xn297.h" // mix of nrf and xn297 at 1Mb...
|
||||||
|
|
||||||
#define HONTAI_BIND_COUNT 80
|
#define HONTAI_BIND_COUNT 80
|
||||||
#define HONTAI_PACKET_PERIOD 13500
|
#define HONTAI_PACKET_PERIOD 13500
|
||||||
#define FQ777_951_PACKET_PERIOD 10000
|
#define FQ777_951_PACKET_PERIOD 10000
|
||||||
#define HONTAI_INITIAL_WAIT 500
|
#define HONTAI_INITIAL_WAIT 500
|
||||||
#define HONTAI_BIND_PACKET_SIZE 10
|
#define HONTAI_BIND_PACKET_SIZE 10
|
||||||
#define HONTAI_PACKET_SIZE 12
|
#define HONTAI_PACKET_SIZE 12
|
||||||
#define HONTAI_RF_BIND_CHANNEL 0
|
#define HONTAI_RF_BIND_CHANNEL 0
|
||||||
|
#define HONTAI_XKK170_RF_BIND_CHANNEL 20
|
||||||
|
#define HONTAI_XKK170_PACKET_PERIOD 8085
|
||||||
|
|
||||||
|
//#define FORCE_HONTAI_XKK170_ORIGINAL_ID
|
||||||
|
|
||||||
enum{
|
enum{
|
||||||
HONTAI_FLAG_FLIP = 0x01,
|
HONTAI_FLAG_FLIP = 0x01,
|
||||||
HONTAI_FLAG_PICTURE = 0x02,
|
HONTAI_FLAG_PICTURE = 0x02,
|
||||||
HONTAI_FLAG_VIDEO = 0x04,
|
HONTAI_FLAG_VIDEO = 0x04,
|
||||||
HONTAI_FLAG_HEADLESS = 0x08,
|
HONTAI_FLAG_HEADLESS = 0x08,
|
||||||
HONTAI_FLAG_RTH = 0x10,
|
HONTAI_FLAG_RTH = 0x10,
|
||||||
HONTAI_FLAG_CALIBRATE = 0x20,
|
HONTAI_FLAG_CALIBRATE = 0x20,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __attribute__((unused)) HONTAI_send_packet()
|
static void __attribute__((unused)) HONTAI_send_packet()
|
||||||
@@ -40,6 +44,8 @@ static void __attribute__((unused)) HONTAI_send_packet()
|
|||||||
{
|
{
|
||||||
memcpy(packet, rx_tx_addr, 5);
|
memcpy(packet, rx_tx_addr, 5);
|
||||||
memset(&packet[5], 0, 3);
|
memset(&packet[5], 0, 3);
|
||||||
|
//if(sub_protocol == HONTAI_XKK170)
|
||||||
|
// packet[6] = 0xD2;
|
||||||
packet_length = HONTAI_BIND_PACKET_SIZE;
|
packet_length = HONTAI_BIND_PACKET_SIZE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -50,58 +56,88 @@ static void __attribute__((unused)) HONTAI_send_packet()
|
|||||||
XN297_Hopping(hopping_frequency_no++);
|
XN297_Hopping(hopping_frequency_no++);
|
||||||
hopping_frequency_no %= 3;
|
hopping_frequency_no %= 3;
|
||||||
memset(packet,0,HONTAI_PACKET_SIZE);
|
memset(packet,0,HONTAI_PACKET_SIZE);
|
||||||
packet[3] = convert_channel_16b_limit(THROTTLE, 0, 127) << 1; // Throttle
|
for(uint8_t i=0; i<4; i++)
|
||||||
packet[4] = convert_channel_16b_limit(AILERON, 63, 0); // Aileron
|
packet[i+3] = convert_channel_8b(CH_TAER[i]);
|
||||||
packet[5] = convert_channel_16b_limit(ELEVATOR, 0, 63); // Elevator
|
if(sub_protocol != HONTAI_XKK170)
|
||||||
packet[6] = convert_channel_16b_limit(RUDDER, 0, 63); // Rudder
|
{
|
||||||
if(sub_protocol == X5C1)
|
//Drive trims
|
||||||
packet[7] = convert_channel_16b_limit(AILERON, 0, 63)-31; // Aileron trim
|
packet[7] = (packet[4]>>3)-16;
|
||||||
|
packet[8] = (packet[6]>>3)-16;
|
||||||
|
packet[9] = (packet[5]>>3)-16;
|
||||||
|
//Reverse aileron
|
||||||
|
packet[4] ^= 0xFF;
|
||||||
|
//Limit range
|
||||||
|
for(uint8_t i=3; i<7; i++)
|
||||||
|
packet[i] >>= 2; //00..63
|
||||||
|
}
|
||||||
else
|
else
|
||||||
packet[7] = convert_channel_16b_limit(AILERON, 0, 32)-16; // Aileron trim
|
{//K170
|
||||||
packet[8] = convert_channel_16b_limit(RUDDER, 0, 32)-16; // Rudder trim
|
//packet[2] = 0xAB; //This value keeps changing when touching any button... Left over from debug?
|
||||||
if (sub_protocol == X5C1)
|
//Sticks
|
||||||
packet[9] = convert_channel_16b_limit(ELEVATOR, 0, 63)-31; // Elevator trim
|
for(uint8_t i=1; i<4; i++)
|
||||||
else
|
packet[i+3] = convert_channel_16b_limit(CH_TAER[i],0x28,0xD8);
|
||||||
packet[9] = convert_channel_16b_limit(ELEVATOR, 0, 32)-16; // Elevator trim
|
packet[6] ^= 0xFF; //Reverse rudder
|
||||||
|
//flags
|
||||||
|
packet[1] = GET_FLAG(CH8_SW, 0x04) //Gyro calibration (momentary)
|
||||||
|
|GET_FLAG(CH11_SW, 0x10); //XK K270 optical flow switch
|
||||||
|
// |GET_FLAG(CH_SW, 0x08) //Unk long press second top right button (momentary)
|
||||||
|
// |GET_FLAG(CH_SW, 0x10) //Unk short press second top right button (toggle)
|
||||||
|
// |GET_FLAG(CH_SW, 0x40) //Unk short press second top left button (momentary)
|
||||||
|
// |GET_FLAG(CH_SW, 0x80); //Unk long press second top left button (momentary)
|
||||||
|
uint8_t rate = 0x80; //Mid rate
|
||||||
|
if(CH5_SW)
|
||||||
|
rate = 0xC0; //High rate
|
||||||
|
else if(Channel_data[CH5] < CHANNEL_MIN_COMMAND)
|
||||||
|
rate = 0x40; //Low rate
|
||||||
|
packet[8] = rate
|
||||||
|
|GET_FLAG(CH7_SW, 0x04) //Take-off/Landing (momentary)
|
||||||
|
|GET_FLAG(CH6_SW, 0x10); //Emergency (momentary)
|
||||||
|
//Trims
|
||||||
|
packet[7] = ((convert_channel_8b(CH9)^0xFF)>>2)-31; // Trim Aileron
|
||||||
|
packet[9] = ( convert_channel_8b(CH10) >>2)-32; // Trim Elevator
|
||||||
|
}
|
||||||
|
|
||||||
switch(sub_protocol)
|
switch(sub_protocol)
|
||||||
{
|
{
|
||||||
case HONTAI:
|
case HONTAI:
|
||||||
packet[0] = 0x0B;
|
packet[0] = 0x0B;
|
||||||
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
|
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
|
||||||
packet[4] |= GET_FLAG(CH10_SW, 0x80) // RTH
|
packet[4] |= GET_FLAG(CH10_SW, 0x80) // RTH
|
||||||
| GET_FLAG(CH9_SW, 0x40); // Headless
|
| GET_FLAG(CH9_SW, 0x40); // Headless
|
||||||
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
|
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
|
||||||
| GET_FLAG(CH5_SW, 0x40); // Flip
|
| GET_FLAG(CH5_SW, 0x40); // Flip
|
||||||
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
|
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
|
||||||
break;
|
break;
|
||||||
case JJRCX1:
|
case JJRCX1:
|
||||||
packet[0] = GET_FLAG(CH6_SW, 0x02); // Arm
|
packet[0] = GET_FLAG(CH6_SW, 0x02); // Arm
|
||||||
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
|
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
|
||||||
packet[4] |= 0x80; // unknown
|
packet[4] |= 0x80; // unknown
|
||||||
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
|
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
|
||||||
| GET_FLAG(CH5_SW, 0x40); // Flip
|
| GET_FLAG(CH5_SW, 0x40); // Flip
|
||||||
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
|
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
|
||||||
packet[8] = 0xC0 // high rate, no rudder trim
|
packet[8] = 0xC0 // high rate, no rudder trim
|
||||||
| GET_FLAG(CH10_SW, 0x02) // RTH
|
| GET_FLAG(CH10_SW, 0x02) // RTH
|
||||||
| GET_FLAG(CH9_SW, 0x01); // Headless
|
| GET_FLAG(CH9_SW, 0x01); // Headless
|
||||||
break;
|
break;
|
||||||
case X5C1:
|
case X5C1:
|
||||||
packet[0] = 0x0B;
|
packet[0] = 0x0B;
|
||||||
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
|
packet[3] |= GET_FLAG(CH7_SW, 0x01); // Picture
|
||||||
packet[4] = 0x80 // unknown
|
packet[4] = 0x80 // unknown
|
||||||
| GET_FLAG(CH6_SW, 0x40); // Lights
|
| GET_FLAG(CH6_SW, 0x40); // Lights
|
||||||
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
|
packet[5] |= GET_FLAG(CH11_SW, 0x80) // Calibrate
|
||||||
| GET_FLAG(CH5_SW, 0x40); // Flip
|
| GET_FLAG(CH5_SW, 0x40); // Flip
|
||||||
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
|
packet[6] |= GET_FLAG(CH8_SW, 0x80); // Video
|
||||||
packet[8] = 0xC0 // high rate, no rudder trim
|
packet[7] <<= 1; // Aileron trim
|
||||||
| GET_FLAG(CH10_SW, 0x02) // RTH
|
packet[8] = 0xC0 // high rate, no rudder trim
|
||||||
|
| GET_FLAG(CH10_SW, 0x02) // RTH
|
||||||
| GET_FLAG(CH9_SW, 0x01); // Headless
|
| GET_FLAG(CH9_SW, 0x01); // Headless
|
||||||
|
packet[9] <<= 1; // Elevator trim
|
||||||
break;
|
break;
|
||||||
case FQ777_951:
|
case FQ777_951:
|
||||||
packet[0] = GET_FLAG(CH7_SW, 0x01) // Picture
|
packet[0] = GET_FLAG(CH7_SW, 0x01) // Picture
|
||||||
| GET_FLAG(CH8_SW, 0x02); // Video
|
| GET_FLAG(CH8_SW, 0x02); // Video
|
||||||
packet[3] |= GET_FLAG(CH5_SW, 0x01); // Flip
|
packet[3] |= GET_FLAG(CH5_SW, 0x01); // Flip
|
||||||
packet[4] |= 0xC0; // High rate (mid=0xa0, low=0x60)
|
packet[4] |= 0xC0; // High rate (mid=0xa0, low=0x60)
|
||||||
packet[5] |= GET_FLAG(CH11_SW, 0x80); // Calibrate
|
packet[5] |= GET_FLAG(CH11_SW, 0x80); // Calibrate
|
||||||
packet[6] |= GET_FLAG(CH9_SW, 0x40); // Headless
|
packet[6] |= GET_FLAG(CH9_SW, 0x40); // Headless
|
||||||
break;
|
break;
|
||||||
@@ -109,13 +145,18 @@ static void __attribute__((unused)) HONTAI_send_packet()
|
|||||||
packet_length = HONTAI_PACKET_SIZE;
|
packet_length = HONTAI_PACKET_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CRC 16 bits reflected in and out
|
if(sub_protocol != HONTAI_XKK170)
|
||||||
crc=0xFFFF;
|
{
|
||||||
for(uint8_t i=0; i< packet_length-2; i++)
|
// CRC 16 bits reflected in and out
|
||||||
crc16_update(bit_reverse(packet[i]),8);
|
crc=0xFFFF;
|
||||||
crc ^= 0xFFFF;
|
for(uint8_t i=0; i< packet_length-2; i++)
|
||||||
packet[packet_length-2]=bit_reverse(crc>>8);
|
crc16_update(bit_reverse(packet[i]),8);
|
||||||
packet[packet_length-1]=bit_reverse(crc);
|
crc ^= 0xFFFF;
|
||||||
|
packet[packet_length-2]=bit_reverse(crc>>8);
|
||||||
|
packet[packet_length-1]=bit_reverse(crc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memset(&packet[packet_length-2], 0xAA, 2);
|
||||||
|
|
||||||
// Power on, TX mode, 2byte CRC
|
// Power on, TX mode, 2byte CRC
|
||||||
/*if(sub_protocol == JJRCX1)
|
/*if(sub_protocol == JJRCX1)
|
||||||
@@ -135,6 +176,11 @@ static void __attribute__((unused)) HONTAI_send_packet()
|
|||||||
NRF24L01_WritePayload(packet, packet_length);
|
NRF24L01_WritePayload(packet, packet_length);
|
||||||
else
|
else
|
||||||
XN297_WritePayload(packet, packet_length);
|
XN297_WritePayload(packet, packet_length);
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
for(uint8_t i=0; i < packet_length; i++)
|
||||||
|
debug("%02X ", packet[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((unused)) HONTAI_RF_init()
|
static void __attribute__((unused)) HONTAI_RF_init()
|
||||||
@@ -152,15 +198,16 @@ static void __attribute__((unused)) HONTAI_RF_init()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
XN297_SetTXAddr((const uint8_t*)"\xd2\xb5\x99\xb3\x4a", 5);
|
memcpy(rx_id,(const uint8_t*)"\xD2\xB5\x99\xB3\x41",5);
|
||||||
|
if(sub_protocol == HONTAI_XKK170)
|
||||||
|
rx_id[4] = 0x4A;
|
||||||
|
XN297_SetTXAddr(rx_id, 5);
|
||||||
//XN297_HoppingCalib(3);
|
//XN297_HoppingCalib(3);
|
||||||
}
|
}
|
||||||
XN297_RFChannel(HONTAI_RF_BIND_CHANNEL);
|
XN297_RFChannel(sub_protocol==HONTAI_XKK170?HONTAI_XKK170_RF_BIND_CHANNEL:HONTAI_RF_BIND_CHANNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t PROGMEM HONTAI_hopping_frequency_nonels[][3] = {
|
const uint8_t PROGMEM HONTAI_hopping_frequency[3] = { 0x05, 0x19, 0x28 };
|
||||||
{0x05, 0x19, 0x28}, // Hontai
|
|
||||||
{0x0a, 0x1e, 0x2d}}; // JJRC X1
|
|
||||||
|
|
||||||
const uint8_t PROGMEM HONTAI_addr_vals[4][16] = {
|
const uint8_t PROGMEM HONTAI_addr_vals[4][16] = {
|
||||||
{0x24, 0x26, 0x2a, 0x2c, 0x32, 0x34, 0x36, 0x4a, 0x4c, 0x4e, 0x54, 0x56, 0x5a, 0x64, 0x66, 0x6a},
|
{0x24, 0x26, 0x2a, 0x2c, 0x32, 0x34, 0x36, 0x4a, 0x4c, 0x4e, 0x54, 0x56, 0x5a, 0x64, 0x66, 0x6a},
|
||||||
@@ -178,32 +225,69 @@ static void __attribute__((unused)) HONTAI_init2()
|
|||||||
data_tx_addr[2] = pgm_read_byte_near( &HONTAI_addr_vals[2][ rx_tx_addr[4] & 0x0f]);
|
data_tx_addr[2] = pgm_read_byte_near( &HONTAI_addr_vals[2][ rx_tx_addr[4] & 0x0f]);
|
||||||
data_tx_addr[3] = pgm_read_byte_near( &HONTAI_addr_vals[3][(rx_tx_addr[4] >> 4) & 0x0f]);
|
data_tx_addr[3] = pgm_read_byte_near( &HONTAI_addr_vals[3][(rx_tx_addr[4] >> 4) & 0x0f]);
|
||||||
data_tx_addr[4] = 0x24;
|
data_tx_addr[4] = 0x24;
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug("A N");
|
||||||
|
for(uint8_t i=0; i < 5; i++)
|
||||||
|
debug(" %02X", data_tx_addr[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
if(sub_protocol == JJRCX1)
|
if(sub_protocol == JJRCX1)
|
||||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, data_tx_addr, 5);
|
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, data_tx_addr, 5);
|
||||||
else
|
else
|
||||||
XN297_SetTXAddr(data_tx_addr, 5);
|
XN297_SetTXAddr(data_tx_addr, 5);
|
||||||
|
|
||||||
//Hopping frequency table
|
//Hopping frequency table
|
||||||
|
uint8_t val;
|
||||||
for(uint8_t i=0;i<3;i++)
|
for(uint8_t i=0;i<3;i++)
|
||||||
hopping_frequency[i]=pgm_read_byte_near( &HONTAI_hopping_frequency_nonels[sub_protocol == JJRCX1?1:0][i] );
|
{
|
||||||
|
if(sub_protocol==HONTAI_XKK170)
|
||||||
|
val = 60+10*i;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val = pgm_read_byte_near( &HONTAI_hopping_frequency[i] );
|
||||||
|
if(sub_protocol == JJRCX1)
|
||||||
|
val += 5;
|
||||||
|
}
|
||||||
|
hopping_frequency[i] = val;
|
||||||
|
}
|
||||||
hopping_frequency_no=0;
|
hopping_frequency_no=0;
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug("H");
|
||||||
|
for(uint8_t i=0; i < 3; i++)
|
||||||
|
debug(" %d(%02X)", hopping_frequency[i], hopping_frequency[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((unused)) HONTAI_initialize_txid()
|
static void __attribute__((unused)) HONTAI_initialize_txid()
|
||||||
{
|
{
|
||||||
rx_tx_addr[4] = rx_tx_addr[2];
|
rx_tx_addr[4] = rx_tx_addr[2];
|
||||||
if(sub_protocol == HONTAI || sub_protocol == FQ777_951)
|
// First three bytes some kind of model id? - set same as stock tx
|
||||||
{
|
if(sub_protocol == JJRCX1 || sub_protocol == X5C1)
|
||||||
rx_tx_addr[0] = 0x4c; // first three bytes some kind of model id? - set same as stock tx
|
{//JJRCX1 & X5C1
|
||||||
rx_tx_addr[1] = 0x4b;
|
rx_tx_addr[0] = 0x4B;
|
||||||
rx_tx_addr[2] = 0x3a;
|
rx_tx_addr[1] = 0x59;
|
||||||
|
rx_tx_addr[2] = 0x3A;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{//HONTAI, FQ777_951, HONTAI_XKK170
|
||||||
rx_tx_addr[0] = 0x4b; // JJRC X1
|
rx_tx_addr[0] = 0x4C;
|
||||||
rx_tx_addr[1] = 0x59;
|
rx_tx_addr[1] = 0x4B;
|
||||||
rx_tx_addr[2] = 0x3a;
|
rx_tx_addr[2] = 0x3A;
|
||||||
|
#ifdef FORCE_HONTAI_XKK170_ORIGINAL_ID
|
||||||
|
if(sub_protocol == HONTAI_XKK170)
|
||||||
|
{
|
||||||
|
rx_tx_addr[3] = 0x5A;
|
||||||
|
rx_tx_addr[4] = 0x06;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug("A B");
|
||||||
|
for(uint8_t i=0; i < 5; i++)
|
||||||
|
debug(" %02X", rx_tx_addr[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t HONTAI_callback()
|
uint16_t HONTAI_callback()
|
||||||
@@ -228,8 +312,14 @@ void HONTAI_init()
|
|||||||
{
|
{
|
||||||
BIND_IN_PROGRESS; // autobind protocol
|
BIND_IN_PROGRESS; // autobind protocol
|
||||||
bind_counter = HONTAI_BIND_COUNT;
|
bind_counter = HONTAI_BIND_COUNT;
|
||||||
HONTAI_initialize_txid();
|
|
||||||
HONTAI_RF_init();
|
HONTAI_RF_init();
|
||||||
packet_period = sub_protocol == FQ777_951 ? FQ777_951_PACKET_PERIOD : HONTAI_PACKET_PERIOD;
|
HONTAI_initialize_txid();
|
||||||
|
if(sub_protocol == FQ777_951)
|
||||||
|
packet_period = FQ777_951_PACKET_PERIOD;
|
||||||
|
else if(sub_protocol == HONTAI_XKK170)
|
||||||
|
packet_period = HONTAI_XKK170_PACKET_PERIOD;
|
||||||
|
else
|
||||||
|
packet_period = HONTAI_PACKET_PERIOD;
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ enum PktState {
|
|||||||
J6PRO_CHAN_4,
|
J6PRO_CHAN_4,
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t PROGMEM j6pro_bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49};
|
const uint8_t j6pro_data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f}; // unneeded since this is the default table after a reset
|
||||||
//const uint8_t j6pro_data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f}; // unneeded since this is the default table after a reset
|
|
||||||
|
|
||||||
static void __attribute__((unused)) j6pro_build_bind_packet()
|
static void __attribute__((unused)) j6pro_build_bind_packet()
|
||||||
{
|
{
|
||||||
@@ -84,7 +83,9 @@ static void __attribute__((unused)) j6pro_cyrf_init()
|
|||||||
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xee);
|
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xee);
|
||||||
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
|
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
|
||||||
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x00);
|
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x00);
|
||||||
//CYRF_ConfigDataCode(j6pro_data_code, 16);
|
|
||||||
|
//Same as default reset but issues if not configured...
|
||||||
|
CYRF_ConfigDataCode(j6pro_data_code);
|
||||||
CYRF_WritePreamble(0x333302);
|
CYRF_WritePreamble(0x333302);
|
||||||
|
|
||||||
CYRF_GetMfgData(cyrfmfg_id);
|
CYRF_GetMfgData(cyrfmfg_id);
|
||||||
@@ -97,7 +98,7 @@ static void __attribute__((unused)) cyrf_bindinit()
|
|||||||
/* Use when binding */
|
/* Use when binding */
|
||||||
CYRF_SetPower(0x28); //Deviation using max power, replaced by bind power...
|
CYRF_SetPower(0x28); //Deviation using max power, replaced by bind power...
|
||||||
//CYRF_ConfigRFChannel(0x52);
|
//CYRF_ConfigRFChannel(0x52);
|
||||||
CYRF_PROGMEM_ConfigSOPCode(j6pro_bind_sop_code);
|
CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[19]);
|
||||||
CYRF_ConfigCRCSeed(0x0000);
|
CYRF_ConfigCRCSeed(0x0000);
|
||||||
//CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
|
//CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
|
||||||
//CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80);
|
//CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80);
|
||||||
@@ -122,7 +123,7 @@ static void __attribute__((unused)) j6pro_set_radio_channels()
|
|||||||
{
|
{
|
||||||
//FIXME: Query free channels
|
//FIXME: Query free channels
|
||||||
//lowest channel is 0x08, upper channel is 0x4d?
|
//lowest channel is 0x08, upper channel is 0x4d?
|
||||||
CYRF_FindBestChannels(hopping_frequency, 3, 5, 8, 77);
|
CYRF_FindBestChannels(hopping_frequency, 3, 5, 8, 77, FIND_CHANNEL_ANY);
|
||||||
hopping_frequency[3] = hopping_frequency[0];
|
hopping_frequency[3] = hopping_frequency[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
450
Multiprotocol/JIABAILE_nrf24l01.ino
Normal file
@@ -0,0 +1,450 @@
|
|||||||
|
/*
|
||||||
|
This project is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Multiprotocol is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#if defined(JIABAILE_NRF24L01_INO)
|
||||||
|
|
||||||
|
#include "iface_xn297.h"
|
||||||
|
|
||||||
|
//#define FORCE_JIABAILE_ORIGINAL_ID
|
||||||
|
//#define FORCE_JIABAILE_GYRO_ORIGINAL_ID
|
||||||
|
|
||||||
|
#define JIABAILE_PAYLOAD_SIZE 8
|
||||||
|
#define JIABAILE_RX_PAYLOAD_SIZE 7
|
||||||
|
#define JIABAILE_RF_NUM_CHANNELS 3
|
||||||
|
#define JIABAILE_BIND_PACKET_PERIOD 12700
|
||||||
|
#define JIABAILE_PACKET_PERIOD 2408
|
||||||
|
#define JIABAILE_GYRO_PACKET_PERIOD 8205
|
||||||
|
#define JIABAILE_BIND_COUNT 160 //2 sec
|
||||||
|
#define JIABAILE_WRITE_TIME 1000
|
||||||
|
|
||||||
|
enum {
|
||||||
|
JIABAILE_BIND=0,
|
||||||
|
JIABAILE_RX,
|
||||||
|
JIABAILE_PREP_DATA,
|
||||||
|
JIABAILE_DATA,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t __attribute__((unused)) JIABAILE_channel(uint8_t num)
|
||||||
|
{
|
||||||
|
uint8_t val=convert_channel_16b_limit(num,0,100);
|
||||||
|
if(val > 50+num)
|
||||||
|
{
|
||||||
|
packet[3] |= 0x01;
|
||||||
|
return val-50;
|
||||||
|
}
|
||||||
|
if(val < 50-num)
|
||||||
|
{
|
||||||
|
packet[3] |= 0x02;
|
||||||
|
return 50-val;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) JIABAILE_send_packet()
|
||||||
|
{
|
||||||
|
if(!(sub_protocol == JIABAILE_GYRO && IS_BIND_IN_PROGRESS))
|
||||||
|
{
|
||||||
|
hopping_frequency_no++;
|
||||||
|
if(hopping_frequency_no > 2)
|
||||||
|
hopping_frequency_no = 0;
|
||||||
|
XN297_Hopping(hopping_frequency_no);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sub_protocol == JIABAILE_STD)
|
||||||
|
{//Std
|
||||||
|
memcpy(packet,rx_tx_addr,3);
|
||||||
|
memset(&packet[3], 0x00, 4);
|
||||||
|
if(IS_BIND_DONE)
|
||||||
|
{//Normal
|
||||||
|
packet[4] = convert_channel_16b_limit(RUDDER,0,50)-25; //ST Trim
|
||||||
|
packet[6] = JIABAILE_channel(AILERON); //ST
|
||||||
|
packet[3] ^= 0x03; //Reverse ST channel
|
||||||
|
packet[3] <<= 2; //Move ST channel where it should be
|
||||||
|
packet[5] = JIABAILE_channel(ELEVATOR); //TH
|
||||||
|
packet[3] |= GET_FLAG(CH5_SW, 0x20) //Low speed
|
||||||
|
|GET_FLAG(CH7_SW, 0x40) //Flash light
|
||||||
|
|GET_FLAG(!CH6_SW, 0x80); //Light
|
||||||
|
if(!CH5_SW && Channel_data[CH5] > CHANNEL_MIN_COMMAND)
|
||||||
|
packet[3] |= 0x10; //Mid speed
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bind_counter--;
|
||||||
|
if(!bind_counter)
|
||||||
|
{
|
||||||
|
BIND_DONE;
|
||||||
|
phase = JIABAILE_PREP_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
packet[7] = 0x55 + hopping_frequency[hopping_frequency_no];
|
||||||
|
for(uint8_t i=0;i<JIABAILE_PAYLOAD_SIZE-1;i++)
|
||||||
|
packet[7] += packet[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{//Gyro
|
||||||
|
if(bind_counter)
|
||||||
|
{
|
||||||
|
bind_counter--;
|
||||||
|
if(!bind_counter)
|
||||||
|
{
|
||||||
|
BIND_DONE;
|
||||||
|
XN297_SetTXAddr(rx_tx_addr, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t crc_pos;
|
||||||
|
if(IS_BIND_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
memcpy(packet,rx_tx_addr,4);
|
||||||
|
packet[4] = hopping_frequency[1];
|
||||||
|
packet[5] = hopping_frequency[2];
|
||||||
|
crc_pos = 6;
|
||||||
|
packet[7] = 0x55;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
packet[0] = convert_channel_16b_limit(CH2,0x60,0xA0); //Throttle
|
||||||
|
packet[1] = convert_channel_16b_limit(CH1,0x40,0xC0); //Steering
|
||||||
|
if(Channel_data[CH5] < CHANNEL_MIN_COMMAND)
|
||||||
|
packet[2] = 0x02; //High speed
|
||||||
|
else if(CH5_SW)
|
||||||
|
packet[2] = 0x00; //Low speed
|
||||||
|
else
|
||||||
|
packet[2] = 0x01; //Mid speed
|
||||||
|
packet[3] = convert_channel_8b(CH3) ^0xFF; //Gyro
|
||||||
|
uint8_t val = GET_FLAG(CH6_SW, 0x04) //Light
|
||||||
|
|GET_FLAG(CH7_SW, 0x08); //Flash
|
||||||
|
if(Channel_data[CH4] > CHANNEL_MAX_COMMAND)
|
||||||
|
val |= 0x01; //Trim right
|
||||||
|
else if(Channel_data[CH4] < CHANNEL_MIN_COMMAND)
|
||||||
|
val |= 0x02; //Trim left
|
||||||
|
packet[4] = val;
|
||||||
|
packet[5] = packet[6] = 0x00; //?
|
||||||
|
crc_pos = 7;
|
||||||
|
}
|
||||||
|
uint8_t sum=0;
|
||||||
|
for(uint8_t i=0; i<crc_pos; i++)
|
||||||
|
sum += packet[i];
|
||||||
|
sum ^= 0xFF;
|
||||||
|
packet[crc_pos] = sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send
|
||||||
|
XN297_SetPower();
|
||||||
|
XN297_SetTxRxMode(TX_EN);
|
||||||
|
XN297_WritePayload(packet, JIABAILE_PAYLOAD_SIZE);
|
||||||
|
#if 0
|
||||||
|
debug("B%d ",bind_counter);
|
||||||
|
debug("H%d RF%d",hopping_frequency_no,hopping_frequency[hopping_frequency_no]);
|
||||||
|
for(uint8_t i=0; i < JIABAILE_PAYLOAD_SIZE; i++)
|
||||||
|
debug(" %02X", packet[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) JIABAILE_initialize_txid()
|
||||||
|
{
|
||||||
|
if(sub_protocol == JIABAILE_STD)
|
||||||
|
{//Std
|
||||||
|
rx_tx_addr[0] = rx_tx_addr[3];
|
||||||
|
#ifdef FORCE_JIABAILE_ORIGINAL_ID
|
||||||
|
memcpy(rx_tx_addr,(uint8_t *)"\xCB\x03\xA5",3);
|
||||||
|
//memcpy(rx_tx_addr,(uint8_t *)"\x3D\x08\xA2",3);
|
||||||
|
//Normal frequencies are calculated from the car ID...
|
||||||
|
//memcpy(&hopping_frequency[3],(uint8_t *)"\x23\x2D\x4B",3); //35,45,75
|
||||||
|
memcpy(&hopping_frequency[3],(uint8_t *)"\x24\x43\x4C",3); //36,67,76
|
||||||
|
#endif
|
||||||
|
//Bind frequencies
|
||||||
|
memcpy(hopping_frequency,(uint8_t *)"\x07\x27\x45",3); //7,39,69
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{//Gyro
|
||||||
|
rx_tx_addr[0] += RX_num;
|
||||||
|
uint8_t val = (rx_tx_addr[0] & 0x0F) + 5; //5..20
|
||||||
|
for(uint8_t i=0; i<3; i++)
|
||||||
|
hopping_frequency[i] = val+ 20*i; //hopping_frequency[1,2] could be whatever but...
|
||||||
|
#ifdef FORCE_JIABAILE_GYRO_ORIGINAL_ID
|
||||||
|
if(RX_num)
|
||||||
|
{
|
||||||
|
memcpy(rx_tx_addr,(uint8_t *)"\x7D\x82\x28\xC2",4);
|
||||||
|
memcpy(hopping_frequency,(uint8_t *)"\x12\x1B\x35",3); //18,27,53
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(rx_tx_addr,(uint8_t *)"\x0C\xF3\x59\xB3",4);
|
||||||
|
memcpy(hopping_frequency,(uint8_t *)"\x11\x1C\x36",3); //17,28,54
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
debugln("ID: %02X %02X %02X %02X, HOP: %2d %2d %2d",rx_tx_addr[0],rx_tx_addr[1],rx_tx_addr[2],rx_tx_addr[3],hopping_frequency[0],hopping_frequency[1],hopping_frequency[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) JIABAILE_RF_init()
|
||||||
|
{
|
||||||
|
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||||
|
//Bind address
|
||||||
|
if(sub_protocol == JIABAILE_STD)
|
||||||
|
{//Std
|
||||||
|
memcpy(rx_id,(uint8_t*)"\xA7\x07\x57\xA7\x26", 5);
|
||||||
|
XN297_SetTXAddr(rx_id, 5);
|
||||||
|
XN297_SetRXAddr(rx_id, JIABAILE_RX_PAYLOAD_SIZE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{//Gyro
|
||||||
|
XN297_SetTXAddr((uint8_t*)"\x14\x41\x11\x13", 4);
|
||||||
|
XN297_RFChannel(0x29); //41
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t JIABAILE_callback()
|
||||||
|
{
|
||||||
|
uint8_t sum;
|
||||||
|
uint16_t addr;
|
||||||
|
|
||||||
|
switch(phase)
|
||||||
|
{
|
||||||
|
case JIABAILE_BIND:
|
||||||
|
phase++; // JIABAILE_RX but is overwritten if RX or bind timeout
|
||||||
|
if(XN297_IsRX())
|
||||||
|
{
|
||||||
|
if(XN297_ReadPayload(packet_in, JIABAILE_RX_PAYLOAD_SIZE))
|
||||||
|
{//CRC OK
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug("RX");
|
||||||
|
for(uint8_t i=0; i < JIABAILE_RX_PAYLOAD_SIZE; i++)
|
||||||
|
debug(" %02X", packet_in[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
//RX: CB 03 A5 9D 05 A2 68
|
||||||
|
if(memcmp(packet_in,rx_tx_addr,3)==0)
|
||||||
|
{//TX ID match
|
||||||
|
//Check packet
|
||||||
|
sum=0xAA + hopping_frequency[hopping_frequency_no];
|
||||||
|
for(uint8_t i=0; i < JIABAILE_RX_PAYLOAD_SIZE-1; i++)
|
||||||
|
sum+=packet_in[i];
|
||||||
|
if(sum==packet_in[6])
|
||||||
|
{
|
||||||
|
//Write the RXID
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug("RXID ");
|
||||||
|
for(uint8_t i=0; i < 3; i++)
|
||||||
|
debug(" %02X", packet_in[3+i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
addr=JIABAILE_EEPROM_OFFSET+RX_num*3;
|
||||||
|
for(uint8_t i=0;i<3;i++)
|
||||||
|
eeprom_write_byte((EE_ADDR)(addr+i),packet_in[3+i]);
|
||||||
|
//Switch to normal mode
|
||||||
|
BIND_DONE;
|
||||||
|
phase = JIABAILE_PREP_DATA;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
else
|
||||||
|
debug("Wrong Sum");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug("Wrong TX ID");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug("Bad CRC");
|
||||||
|
debugln("");
|
||||||
|
#else
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
JIABAILE_send_packet();
|
||||||
|
return JIABAILE_WRITE_TIME;
|
||||||
|
case JIABAILE_RX:
|
||||||
|
//Wait for the packet transmission to finish
|
||||||
|
while(XN297_IsPacketSent()==false);
|
||||||
|
//Switch to RX
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
XN297_SetTxRxMode(RX_EN);
|
||||||
|
phase = JIABAILE_BIND;
|
||||||
|
return JIABAILE_BIND_PACKET_PERIOD - JIABAILE_WRITE_TIME;
|
||||||
|
case JIABAILE_PREP_DATA:
|
||||||
|
//Read the RXID
|
||||||
|
addr=JIABAILE_EEPROM_OFFSET+RX_num*3;
|
||||||
|
for(uint8_t i=0;i<3;i++)
|
||||||
|
rx_id[i+1] = eeprom_read_byte((EE_ADDR)(addr+i));
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug("RXID ");
|
||||||
|
for(uint8_t i=0; i < 3; i++)
|
||||||
|
debug(" %02X", rx_id[i+1]);
|
||||||
|
#endif
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
XN297_SetTXAddr(rx_id, 5);
|
||||||
|
//Set the normal frequencies
|
||||||
|
sum=rx_id[1]&0x07;
|
||||||
|
hopping_frequency[0] = (sum>4?30:8) + sum;
|
||||||
|
if(sum==4 || sum ==7)
|
||||||
|
hopping_frequency[0]++;
|
||||||
|
hopping_frequency[1] = 40 + sum;
|
||||||
|
if((sum & 0x06) == 0x06)
|
||||||
|
hopping_frequency[1] += 21;
|
||||||
|
hopping_frequency[2] = 70 + sum;
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug(" RF");
|
||||||
|
for(uint8_t i=0; i < 3; i++)
|
||||||
|
debug(" %d", hopping_frequency[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
phase++;
|
||||||
|
default: //JIABAILE_DATA
|
||||||
|
#ifdef MULTI_SYNC
|
||||||
|
telemetry_set_input_sync(packet_period);
|
||||||
|
#endif
|
||||||
|
JIABAILE_send_packet();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return packet_period;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JIABAILE_init()
|
||||||
|
{
|
||||||
|
JIABAILE_initialize_txid();
|
||||||
|
JIABAILE_RF_init();
|
||||||
|
if(sub_protocol == JIABAILE_STD)
|
||||||
|
{//Std
|
||||||
|
if(IS_BIND_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
phase = JIABAILE_BIND;
|
||||||
|
bind_counter = JIABAILE_BIND_COUNT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
phase = JIABAILE_PREP_DATA;
|
||||||
|
packet_period = JIABAILE_PACKET_PERIOD;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{//Gyro
|
||||||
|
phase = JIABAILE_DATA;
|
||||||
|
bind_counter = IS_BIND_IN_PROGRESS?JIABAILE_BIND_COUNT>>2:1;
|
||||||
|
packet_period = JIABAILE_GYRO_PACKET_PERIOD;
|
||||||
|
}
|
||||||
|
hopping_frequency_no = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
// CAR RX debug code
|
||||||
|
|
||||||
|
static void __attribute__((unused)) JIABAILE_RF_init()
|
||||||
|
{
|
||||||
|
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||||
|
//Bind address
|
||||||
|
memcpy(rx_id,(uint8_t*)"\xA7\x07\x57\xA7\x26", 5);
|
||||||
|
XN297_SetTXAddr(rx_id, 5);
|
||||||
|
XN297_SetRXAddr(rx_id, JIABAILE_PAYLOAD_SIZE);
|
||||||
|
XN297_RFChannel(7);
|
||||||
|
rx_tx_addr[0] = 0x00;
|
||||||
|
rx_tx_addr[1] = RX_num;
|
||||||
|
rx_tx_addr[2] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t JIABAILE_callback()
|
||||||
|
{
|
||||||
|
switch(phase)
|
||||||
|
{
|
||||||
|
case JIABAILE_BIND:
|
||||||
|
if(XN297_IsRX())
|
||||||
|
{
|
||||||
|
if(XN297_ReadPayload(packet_in, JIABAILE_PAYLOAD_SIZE))
|
||||||
|
{//CRC OK
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug("RX Bind");
|
||||||
|
for(uint8_t i=0; i < JIABAILE_PAYLOAD_SIZE; i++)
|
||||||
|
debug(" %02X", packet_in[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
memcpy(packet,packet_in,3);
|
||||||
|
memcpy(&packet[3],rx_tx_addr,3);
|
||||||
|
packet[6]=0xAA + 7;
|
||||||
|
for(uint8_t i=0; i < JIABAILE_RX_PAYLOAD_SIZE-1; i++)
|
||||||
|
packet[6]+=packet[i];
|
||||||
|
XN297_SetTxRxMode(TX_EN);
|
||||||
|
memcpy(&rx_id[1],rx_tx_addr,3);
|
||||||
|
bind_counter = 10;
|
||||||
|
phase = JIABAILE_RX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JIABAILE_WRITE_TIME;
|
||||||
|
case JIABAILE_RX:
|
||||||
|
if(bind_counter)
|
||||||
|
{
|
||||||
|
bind_counter--;
|
||||||
|
XN297_WritePayload(packet, JIABAILE_RX_PAYLOAD_SIZE);
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug("TX Bind");
|
||||||
|
for(uint8_t i=0; i < JIABAILE_RX_PAYLOAD_SIZE; i++)
|
||||||
|
debug(" %02X", packet[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
return JIABAILE_PACKET_PERIOD;
|
||||||
|
}
|
||||||
|
//Wait for the packet transmission to finish
|
||||||
|
//while(XN297_IsPacketSent()==false);
|
||||||
|
//Switch to RX
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
XN297_SetRXAddr(rx_id, JIABAILE_PAYLOAD_SIZE);
|
||||||
|
hopping_frequency_no++;
|
||||||
|
if(hopping_frequency_no>84)
|
||||||
|
hopping_frequency_no = 0;
|
||||||
|
debug(".");
|
||||||
|
XN297_RFChannel(hopping_frequency_no);
|
||||||
|
XN297_SetTxRxMode(RX_EN);
|
||||||
|
phase = JIABAILE_DATA;
|
||||||
|
return JIABAILE_BIND_PACKET_PERIOD;
|
||||||
|
case JIABAILE_DATA:
|
||||||
|
if(XN297_IsRX())
|
||||||
|
{
|
||||||
|
debugln("");
|
||||||
|
if(XN297_ReadPayload(packet_in, JIABAILE_PAYLOAD_SIZE))
|
||||||
|
{//CRC OK
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug("CH=%d=%02X P:",hopping_frequency_no,hopping_frequency_no);
|
||||||
|
for(uint8_t i=0; i < JIABAILE_PAYLOAD_SIZE; i++)
|
||||||
|
debug(" %02X", packet_in[i]);
|
||||||
|
#endif
|
||||||
|
//Check packet
|
||||||
|
uint8_t sum=0x55 + hopping_frequency_no;
|
||||||
|
for(uint8_t i=0; i < JIABAILE_PAYLOAD_SIZE-1; i++)
|
||||||
|
sum+=packet_in[i];
|
||||||
|
if(sum==packet_in[7])
|
||||||
|
{
|
||||||
|
debug("Good channel");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug("Wrong Sum");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug("Bad CRC");
|
||||||
|
debugln("");
|
||||||
|
}
|
||||||
|
phase = JIABAILE_RX;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return JIABAILE_PACKET_PERIOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JIABAILE_init()
|
||||||
|
{
|
||||||
|
JIABAILE_RF_init();
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
XN297_SetTxRxMode(RX_EN);
|
||||||
|
phase = JIABAILE_BIND;
|
||||||
|
hopping_frequency_no = 7;
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -48,32 +48,19 @@ static void __attribute__((unused)) KF606_send_packet()
|
|||||||
hopping_frequency_no ^= 1; // 2 RF channels
|
hopping_frequency_no ^= 1; // 2 RF channels
|
||||||
|
|
||||||
packet[0] = 0x55;
|
packet[0] = 0x55;
|
||||||
packet[1] = convert_channel_8b(THROTTLE); // 0..255
|
if(sub_protocol == KF606_ZCZ50) len--;
|
||||||
|
packet[len-3] = convert_channel_8b(THROTTLE); // 0..255
|
||||||
// Deadband is needed on aileron, 40 gives +-6%
|
// Deadband is needed on aileron, 40 gives +-6%
|
||||||
switch(sub_protocol)
|
packet[len-2] = convert_channel_8b_limit_deadband(AILERON,0x00,0x80,0xFF,40); // Aileron: High rate:2B..80..DA
|
||||||
{
|
uint8_t p3;
|
||||||
case KF606_KF606:
|
p3 = convert_channel_8b(CH5)>>3; // Aileron trim must be on a separated channel 01..10..1F
|
||||||
packet[2] = convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, Low rates:50..80..AF, High rates:3E..80..C1
|
p3 += (packet[2]-0x80)>>3; // Drive trims for more aileron authority
|
||||||
packet[3] = convert_channel_16b_limit(CH5,0xC1,0xDF); // Aileron trim must be on a separated channel C1..D0..DF
|
if(p3 > 0x80)
|
||||||
break;
|
p3 = 0x01;
|
||||||
case KF606_MIG320:
|
else if(p3 > 0x1F)
|
||||||
packet[2] = convert_channel_8b_limit_deadband(AILERON,0x00,0x80,0xFF,40); // Aileron: High rate:2B..80..DA
|
p3 = 0x1F;
|
||||||
packet[3] = convert_channel_16b_limit(CH5,0x01,0x1F); // Aileron trim must be on a separated channel 01..10..1F
|
p3 |= GET_FLAG(CH6_SW, 0xC0); // 0xC0 and 0xE0 are both turning the LED off, not sure if there is another hidden feature
|
||||||
packet[3] += (packet[2]-0x80)>>3; // Drive trims for more aileron authority
|
packet[len-1] = p3;
|
||||||
if(packet[3] > 0x80)
|
|
||||||
packet[3] = 0x01;
|
|
||||||
else if(packet[3] > 0x1F)
|
|
||||||
packet[3] = 0x1F;
|
|
||||||
packet[3] |= GET_FLAG(CH6_SW, 0xC0); // 0xC0 and 0xE0 are both turning the LED off, not sure if there is another hidden feature
|
|
||||||
break;
|
|
||||||
case KF606_ZCZ50:
|
|
||||||
len--; // uses only 3 bytes of payload
|
|
||||||
packet[0] = packet[1]; // Throttle: 0x00..0xFF
|
|
||||||
packet[1] = convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, low rate 0x52..0x80..0xB1, high rate: 0x41..0x80..0xC3.
|
|
||||||
packet[2] = convert_channel_16b_limit(CH5,0x01,0x1F); // Trim: 0x01..0x10..0x1F
|
|
||||||
packet[2] |= GET_FLAG(CH6_SW, 0xC0); // Unknown: 0x00 or 0xC0. Left top switch on original TX changes nothing on my plane. Maybe ON/OFF for main motor?
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sub_protocol == KF606_MIG320)
|
if(sub_protocol == KF606_MIG320)
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ enum {
|
|||||||
KN_FLAG_DR = 0x01, // Dual Rate: 1 - full range
|
KN_FLAG_DR = 0x01, // Dual Rate: 1 - full range
|
||||||
KN_FLAG_TH = 0x02, // Throttle Hold: 1 - hold
|
KN_FLAG_TH = 0x02, // Throttle Hold: 1 - hold
|
||||||
KN_FLAG_IDLEUP = 0x04, // Idle up: 1 - 3D
|
KN_FLAG_IDLEUP = 0x04, // Idle up: 1 - 3D
|
||||||
KN_FLAG_RES1 = 0x08,
|
KN_FLAG_RES1 = 0x08, // HoverDebugging
|
||||||
KN_FLAG_RES2 = 0x10,
|
KN_FLAG_RES2 = 0x10,
|
||||||
KN_FLAG_RES3 = 0x20,
|
KN_FLAG_RES3 = 0x20,
|
||||||
KN_FLAG_GYRO3 = 0x40, // 0 - 6G mode, 1 - 3G mode
|
KN_FLAG_GYRO3 = 0x40, // 0 - 6G mode, 1 - 3G mode
|
||||||
@@ -141,19 +141,13 @@ static void __attribute__((unused)) kn_update_packet_control_data()
|
|||||||
packet[8] = convert_channel_16b_limit(CH9,0,200); // 0x64; // T
|
packet[8] = convert_channel_16b_limit(CH9,0,200); // 0x64; // T
|
||||||
packet[9] = convert_channel_16b_limit(CH10,0,200); // 0x64; // A
|
packet[9] = convert_channel_16b_limit(CH10,0,200); // 0x64; // A
|
||||||
packet[10] = convert_channel_16b_limit(CH11,0,200); // 0x64; // E
|
packet[10] = convert_channel_16b_limit(CH11,0,200); // 0x64; // E
|
||||||
packet[11] = 0x64; // R
|
packet[11] = convert_channel_16b_limit(CH12,0,200); // 0x64; // R
|
||||||
|
|
||||||
flags=0;
|
packet[12] = GET_FLAG(CH5_SW, KN_FLAG_DR)
|
||||||
if (CH5_SW)
|
|GET_FLAG(CH6_SW, KN_FLAG_TH)
|
||||||
flags = KN_FLAG_DR;
|
|GET_FLAG(CH7_SW, KN_FLAG_IDLEUP)
|
||||||
if (CH6_SW)
|
|GET_FLAG(CH8_SW, KN_FLAG_GYRO3)
|
||||||
flags |= KN_FLAG_TH;
|
|GET_FLAG(CH13_SW, KN_FLAG_RES1); //Hover debugging
|
||||||
if (CH7_SW)
|
|
||||||
flags |= KN_FLAG_IDLEUP;
|
|
||||||
if (CH8_SW)
|
|
||||||
flags |= KN_FLAG_GYRO3;
|
|
||||||
|
|
||||||
packet[12] = flags;
|
|
||||||
|
|
||||||
packet[13] = 0x00;
|
packet[13] = 0x00;
|
||||||
if(sub_protocol==WLTOYS)
|
if(sub_protocol==WLTOYS)
|
||||||
|
|||||||
185
Multiprotocol/Kamtom_nrf24l01.ino
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
This project is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Multiprotocol is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#if defined(KAMTOM_NRF24L01_INO)
|
||||||
|
|
||||||
|
#include "iface_xn297.h"
|
||||||
|
|
||||||
|
//#define FORCE_KAMTOM_ORIGINAL_ID
|
||||||
|
|
||||||
|
#define KAMTOM_PAYLOAD_SIZE 16
|
||||||
|
#define KAMTOM_RF_NUM_CHANNELS 4
|
||||||
|
#define KAMTOM_BIND_COUNT 2000
|
||||||
|
#define KAMTOM_WRITE_TIME 650
|
||||||
|
#define KAMTOM_BIND_CHANNEL 0x28 //40
|
||||||
|
#define KAMTOM_PACKET_PERIOD 3585
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
KAMTOM_DATA,
|
||||||
|
KAMTOM_RX,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void __attribute__((unused)) KAMTOM_send_packet()
|
||||||
|
{
|
||||||
|
if(bind_counter)
|
||||||
|
{
|
||||||
|
bind_counter--;
|
||||||
|
if(!bind_counter)
|
||||||
|
BIND_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(packet, 0x00, 16);
|
||||||
|
|
||||||
|
if(IS_BIND_DONE)
|
||||||
|
{//Normal
|
||||||
|
XN297_Hopping(hopping_frequency_no);
|
||||||
|
hopping_frequency_no++;
|
||||||
|
hopping_frequency_no &= 3;
|
||||||
|
|
||||||
|
//RXID
|
||||||
|
packet[0] = rx_tx_addr[0];
|
||||||
|
packet[2] = rx_tx_addr[1];
|
||||||
|
//Next RF channel
|
||||||
|
packet[1] = hopping_frequency[hopping_frequency_no];
|
||||||
|
//Channels and trims
|
||||||
|
for(uint8_t i=0; i<6; i++)
|
||||||
|
{
|
||||||
|
packet[4+i] = convert_channel_s8b(CH_TAER[i]);
|
||||||
|
if(i>3) //ST_TR and TH_TR
|
||||||
|
packet[4+i] >>= 2;
|
||||||
|
}
|
||||||
|
//packet[11] = 0x00; //??
|
||||||
|
//TH_DR
|
||||||
|
packet[12] = convert_channel_16b_limit(CH7,0x25,0x64);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
packet[1] = KAMTOM_BIND_CHANNEL;
|
||||||
|
memcpy(&packet[4],hopping_frequency,4);
|
||||||
|
packet[12] = 0xA5;
|
||||||
|
}
|
||||||
|
packet[10] = 0x40; //??
|
||||||
|
//Checksum
|
||||||
|
uint16_t sum = packet[1];
|
||||||
|
for(uint8_t i=4;i<13;i++)
|
||||||
|
sum += packet[i];
|
||||||
|
packet[13] = sum;
|
||||||
|
packet[3] = (sum>>6) & 0xFC;
|
||||||
|
//TXID
|
||||||
|
packet[14] = rx_tx_addr[2];
|
||||||
|
packet[15] = rx_tx_addr[3];
|
||||||
|
// Send
|
||||||
|
XN297_SetPower();
|
||||||
|
XN297_SetTxRxMode(TX_EN);
|
||||||
|
XN297_WriteEnhancedPayload(packet, KAMTOM_PAYLOAD_SIZE,false);
|
||||||
|
#if 0
|
||||||
|
//def DEBUG_SERIAL
|
||||||
|
for(uint8_t i=0; i < KAMTOM_PAYLOAD_SIZE; i++)
|
||||||
|
debug("%02X ", packet[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) KAMTOM_initialize_txid()
|
||||||
|
{
|
||||||
|
calc_fh_channels(4);
|
||||||
|
#ifdef FORCE_KAMTOM_ORIGINAL_ID
|
||||||
|
rx_tx_addr[0] = 0xC7;
|
||||||
|
rx_tx_addr[1] = 0x78;
|
||||||
|
rx_tx_addr[2] = 0x2C;
|
||||||
|
rx_tx_addr[3] = 0x25;
|
||||||
|
hopping_frequency[0] = 59;
|
||||||
|
hopping_frequency[1] = 59;
|
||||||
|
hopping_frequency[2] = 71;
|
||||||
|
hopping_frequency[3] = 65;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) KAMTOM_RF_init()
|
||||||
|
{
|
||||||
|
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||||
|
//Address
|
||||||
|
XN297_SetTXAddr((uint8_t*)"\xCC\xDD\xEE\xDD", 4);
|
||||||
|
XN297_SetRXAddr((uint8_t*)"\xCC\xDD\xEE\xDD", KAMTOM_PAYLOAD_SIZE);
|
||||||
|
XN297_RFChannel(KAMTOM_BIND_CHANNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t KAMTOM_callback()
|
||||||
|
{
|
||||||
|
static bool rx=false;
|
||||||
|
|
||||||
|
switch(phase)
|
||||||
|
{
|
||||||
|
case KAMTOM_DATA:
|
||||||
|
rx = XN297_IsRX();
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
#ifdef MULTI_SYNC
|
||||||
|
telemetry_set_input_sync(KAMTOM_PACKET_PERIOD);
|
||||||
|
#endif
|
||||||
|
KAMTOM_send_packet();
|
||||||
|
if(rx)
|
||||||
|
{
|
||||||
|
uint8_t val=XN297_ReadEnhancedPayload(packet_in, KAMTOM_PAYLOAD_SIZE);
|
||||||
|
if(val==KAMTOM_PAYLOAD_SIZE)
|
||||||
|
{
|
||||||
|
BIND_DONE;
|
||||||
|
if(packet_in[0] == 0xA0 && packet_in[14] == rx_tx_addr[2] && packet_in[15] == rx_tx_addr[3])
|
||||||
|
{//Good packet with our TXID
|
||||||
|
rx_tx_addr[0] = packet_in[9];
|
||||||
|
rx_tx_addr[1] = packet_in[10];
|
||||||
|
#ifdef KAMTOM_HUB_TELEMETRY
|
||||||
|
v_lipo1 = packet_in[1] == 0x03 ? 0x00:0xFF; // low voltage
|
||||||
|
telemetry_link = 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
for(uint8_t i=0; i < KAMTOM_PAYLOAD_SIZE; i++)
|
||||||
|
debug(" %02X", packet_in[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
phase++;
|
||||||
|
return KAMTOM_WRITE_TIME;
|
||||||
|
default: //KAMTOM_RX
|
||||||
|
//{ // Wait for packet to be sent before switching to receive mode
|
||||||
|
// uint16_t start=(uint16_t)micros();
|
||||||
|
// while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 500)
|
||||||
|
// if(XN297_IsPacketSent())
|
||||||
|
// break;
|
||||||
|
//}
|
||||||
|
//Switch to RX
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
XN297_SetTxRxMode(RX_EN);
|
||||||
|
phase = KAMTOM_DATA;
|
||||||
|
return KAMTOM_PACKET_PERIOD - KAMTOM_WRITE_TIME;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KAMTOM_init()
|
||||||
|
{
|
||||||
|
KAMTOM_initialize_txid();
|
||||||
|
KAMTOM_RF_init();
|
||||||
|
|
||||||
|
bind_counter = KAMTOM_BIND_COUNT;
|
||||||
|
phase = KAMTOM_DATA;
|
||||||
|
hopping_frequency_no = 0;
|
||||||
|
#ifdef KAMTOM_HUB_TELEMETRY
|
||||||
|
RX_RSSI = 100; // Dummy value
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
124
Multiprotocol/Kyosho3_cyrf6936.ino
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
This project is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Multiprotocol is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(KYOSHO3_CYRF6936_INO)
|
||||||
|
|
||||||
|
#include "iface_cyrf6936.h"
|
||||||
|
|
||||||
|
//#define KYOSHO3_FORCE_ID
|
||||||
|
//#define KYOSHO3_DEBUG
|
||||||
|
|
||||||
|
#define KYOSHO3_BIND_PACKET_SIZE 4
|
||||||
|
#define KYOSHO3_PACKET_SIZE 9
|
||||||
|
|
||||||
|
const uint8_t PROGMEM KYOSHO3_init_vals[][2] = {
|
||||||
|
//Init from dump
|
||||||
|
{CYRF_0B_PWR_CTRL, 0x00}, // PMU
|
||||||
|
{CYRF_32_AUTO_CAL_TIME, 0x3C}, // Default init value
|
||||||
|
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
|
||||||
|
{CYRF_03_TX_CFG, 0x28 | CYRF_BIND_POWER}, // 8DR Mode, 64 chip codes
|
||||||
|
{CYRF_10_FRAMING_CFG, 0xA4}, // SOP and LEN enable
|
||||||
|
{CYRF_1F_TX_OVERRIDE, 0x05}, // Disable CRC, Data invert
|
||||||
|
{CYRF_1E_RX_OVERRIDE, 0x04}, // CRC check disabled
|
||||||
|
//{CYRF_11_DATA32_THOLD, 0x04}, // ???Using 64 chip...
|
||||||
|
{CYRF_12_DATA64_THOLD, 0x0E}, // Default
|
||||||
|
{CYRF_06_RX_CFG, 0x52}, // AGC disabled, LNA enabled, override enabled
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint16_t __attribute__((unused)) KYOSHO3_send_packet()
|
||||||
|
{
|
||||||
|
CYRF_SetPower(0x28);
|
||||||
|
if(IS_BIND_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
if(--bind_counter==0)
|
||||||
|
BIND_DONE;
|
||||||
|
packet[0] = 0xAA;
|
||||||
|
//ID
|
||||||
|
memcpy(&packet[1],&rx_tx_addr[1],3);
|
||||||
|
CYRF_WriteDataPacketLen(packet, KYOSHO3_BIND_PACKET_SIZE);
|
||||||
|
#ifdef KYOSHO3_DEBUG
|
||||||
|
debug("P:");
|
||||||
|
for(uint8_t i=0;i<KYOSHO3_BIND_PACKET_SIZE;i++)
|
||||||
|
debug(" %02X",packet[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
|
return 2434;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//ID
|
||||||
|
memcpy(packet,&rx_tx_addr[1],3);
|
||||||
|
//Channels
|
||||||
|
for(uint8_t i=0;i<4;i++)
|
||||||
|
{
|
||||||
|
packet[3] >>= 2;
|
||||||
|
packet[3] |= Channel_data[i]<<6;
|
||||||
|
packet[4+i] = Channel_data[i]>>3;
|
||||||
|
}
|
||||||
|
//Checksum
|
||||||
|
packet[8] = packet[3];
|
||||||
|
for(uint8_t i=4;i<8;i++)
|
||||||
|
packet[8] += packet[i];
|
||||||
|
//Timing
|
||||||
|
phase ^= 0x01;
|
||||||
|
CYRF_WriteDataPacketLen(packet, KYOSHO3_PACKET_SIZE);
|
||||||
|
#ifdef KYOSHO3_DEBUG
|
||||||
|
debug("P:");
|
||||||
|
for(uint8_t i=0;i<KYOSHO3_PACKET_SIZE;i++)
|
||||||
|
debug(" %02X",packet[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
|
if(phase)
|
||||||
|
return 9047;
|
||||||
|
}
|
||||||
|
return 6957;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t KYOSHO3_callback()
|
||||||
|
{
|
||||||
|
return KYOSHO3_send_packet();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KYOSHO3_init()
|
||||||
|
{
|
||||||
|
//Config CYRF registers
|
||||||
|
for(uint8_t i = 0; i < sizeof(KYOSHO3_init_vals) / 2; i++)
|
||||||
|
CYRF_WriteRegister(pgm_read_byte_near(&KYOSHO3_init_vals[i][0]), pgm_read_byte_near(&KYOSHO3_init_vals[i][1]));
|
||||||
|
CYRF_WritePreamble(0x333304);
|
||||||
|
|
||||||
|
//Find a free even channel
|
||||||
|
CYRF_FindBestChannels(hopping_frequency,1,1,0x04,0x50, FIND_CHANNEL_EVEN);
|
||||||
|
|
||||||
|
#ifdef KYOSHO3_FORCE_ID // data taken from TX dump
|
||||||
|
rx_tx_addr[1] = 0x01;
|
||||||
|
rx_tx_addr[2] = 0xAB;
|
||||||
|
rx_tx_addr[3] = 0x31;
|
||||||
|
hopping_frequency[0] = 0x04;
|
||||||
|
#endif
|
||||||
|
#ifdef KYOSHO3_DEBUG
|
||||||
|
debugln("ID: %02X %02X %02X",rx_tx_addr[1],rx_tx_addr[2],rx_tx_addr[3]);
|
||||||
|
debugln("RF CH: %02X",hopping_frequency[0]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(IS_BIND_IN_PROGRESS)
|
||||||
|
CYRF_ConfigRFChannel(0x04);
|
||||||
|
else
|
||||||
|
CYRF_ConfigRFChannel(hopping_frequency[0]);
|
||||||
|
|
||||||
|
bind_counter = 8217;
|
||||||
|
phase = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -19,10 +19,12 @@
|
|||||||
|
|
||||||
//#define KYOSHO_FORCE_ID_FHSS
|
//#define KYOSHO_FORCE_ID_FHSS
|
||||||
//#define KYOSHO_FORCE_ID_HYPE
|
//#define KYOSHO_FORCE_ID_HYPE
|
||||||
|
//#define KYOSHO_FORCE_ID_SYNCRO
|
||||||
|
|
||||||
//Kyosho constants & variables
|
//Kyosho constants & variables
|
||||||
#define KYOSHO_BIND_COUNT 2500
|
#define KYOSHO_BIND_COUNT 2500
|
||||||
|
|
||||||
|
#ifndef MULTI_AIR
|
||||||
static void __attribute__((unused)) KYOSHO_send_packet()
|
static void __attribute__((unused)) KYOSHO_send_packet()
|
||||||
{
|
{
|
||||||
//ID
|
//ID
|
||||||
@@ -32,7 +34,7 @@ static void __attribute__((unused)) KYOSHO_send_packet()
|
|||||||
packet[4] = rx_tx_addr[3];
|
packet[4] = rx_tx_addr[3];
|
||||||
//unknown may be RX ID on some other remotes
|
//unknown may be RX ID on some other remotes
|
||||||
memset(packet+5,0xFF,4);
|
memset(packet+5,0xFF,4);
|
||||||
|
|
||||||
if(IS_BIND_IN_PROGRESS)
|
if(IS_BIND_IN_PROGRESS)
|
||||||
{
|
{
|
||||||
packet[ 0] = 0xBC; // bind indicator
|
packet[ 0] = 0xBC; // bind indicator
|
||||||
@@ -42,8 +44,9 @@ static void __attribute__((unused)) KYOSHO_send_packet()
|
|||||||
//RF table
|
//RF table
|
||||||
for(uint8_t i=0; i<16;i++)
|
for(uint8_t i=0; i<16;i++)
|
||||||
packet[i+11]=hopping_frequency[i+(packet[9]<<4)];
|
packet[i+11]=hopping_frequency[i+(packet[9]<<4)];
|
||||||
//unknwon
|
//TX type
|
||||||
packet[27] = 0x05;
|
packet[27] = (bind_counter & 0x40) ? 0x05:0x07; // FHSS is 5 and Syncro is 7
|
||||||
|
//Unknown
|
||||||
packet[28] = 0x00;
|
packet[28] = 0x00;
|
||||||
memset(packet+29,0xFF,8);
|
memset(packet+29,0xFF,8);
|
||||||
//frequency hop during bind
|
//frequency hop during bind
|
||||||
@@ -55,13 +58,23 @@ static void __attribute__((unused)) KYOSHO_send_packet()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
packet[ 0] = 0x58; // normal packet
|
packet[ 0] = 0x58; // normal packet
|
||||||
//14 channels: steering, throttle, ...
|
//FHSS 14 channels: steering, throttle, ...
|
||||||
for(uint8_t i = 0; i < 14; i++)
|
//Syncro 6 channels: steering, throttle, ...
|
||||||
|
for(uint8_t i = 0; i < 14; i++) //needed? i < (sub_protocol==KYOSHO_FHSS?14:6); i++)
|
||||||
{
|
{
|
||||||
uint16_t temp=convert_channel_ppm(i);
|
uint16_t temp = convert_channel_ppm(i);
|
||||||
packet[9 + i*2]=temp&0xFF; // low byte of servo timing(1000-2000us)
|
packet[ 9 + i*2] = temp&0xFF; // low byte of servo timing(1000-2000us)
|
||||||
packet[10 + i*2]=(temp>>8)&0xFF; // high byte of servo timing(1000-2000us)
|
packet[10 + i*2] = (temp>>8)&0xFF; // high byte of servo timing(1000-2000us)
|
||||||
}
|
}
|
||||||
|
// if(sub_protocol==KYOSHO_SYNCRO) // needed?
|
||||||
|
// {
|
||||||
|
// memcpy(&packet[21],&hopping_frequency[11],6);
|
||||||
|
// packet[27] = 0x07;
|
||||||
|
// packet[28] = 0x00;
|
||||||
|
// memset(packet+29,0xFF,8);
|
||||||
|
// packet[34] = 0x0F;
|
||||||
|
// packet[36] = 0x0F;
|
||||||
|
// }
|
||||||
rf_ch_num=hopping_frequency[hopping_frequency_no];
|
rf_ch_num=hopping_frequency[hopping_frequency_no];
|
||||||
hopping_frequency_no++;
|
hopping_frequency_no++;
|
||||||
packet[34] |= (hopping_frequency_no&0x0F)<<4;
|
packet[34] |= (hopping_frequency_no&0x0F)<<4;
|
||||||
@@ -76,6 +89,7 @@ static void __attribute__((unused)) KYOSHO_send_packet()
|
|||||||
#endif
|
#endif
|
||||||
A7105_WriteData(37, rf_ch_num);
|
A7105_WriteData(37, rf_ch_num);
|
||||||
}
|
}
|
||||||
|
#endif //MULTI_AIR
|
||||||
|
|
||||||
static void __attribute__((unused)) KYOSHO_hype_send_packet()
|
static void __attribute__((unused)) KYOSHO_hype_send_packet()
|
||||||
{
|
{
|
||||||
@@ -150,10 +164,14 @@ uint16_t KYOSHO_callback()
|
|||||||
telemetry_set_input_sync(packet_period);
|
telemetry_set_input_sync(packet_period);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if(sub_protocol==KYOSHO_FHSS)
|
if(sub_protocol==KYOSHO_HYPE)
|
||||||
KYOSHO_send_packet();
|
|
||||||
else//HYPE
|
|
||||||
KYOSHO_hype_send_packet();
|
KYOSHO_hype_send_packet();
|
||||||
|
else //FHSS && SYNCRO
|
||||||
|
#ifndef MULTI_AIR
|
||||||
|
KYOSHO_send_packet();
|
||||||
|
#else
|
||||||
|
SUB_PROTO_INVALID;
|
||||||
|
#endif
|
||||||
return packet_period;
|
return packet_period;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +180,7 @@ void KYOSHO_init()
|
|||||||
A7105_Init();
|
A7105_Init();
|
||||||
|
|
||||||
// compute channels from ID
|
// compute channels from ID
|
||||||
calc_fh_channels(sub_protocol==KYOSHO_FHSS?32:15);
|
calc_fh_channels(sub_protocol==KYOSHO_HYPE?15:32);
|
||||||
hopping_frequency_no=0;
|
hopping_frequency_no=0;
|
||||||
|
|
||||||
#ifdef KYOSHO_FORCE_ID_FHSS
|
#ifdef KYOSHO_FORCE_ID_FHSS
|
||||||
@@ -172,6 +190,13 @@ void KYOSHO_init()
|
|||||||
memcpy(hopping_frequency,"\x29\x4C\x67\x92\x31\x1C\x77\x18\x23\x6E\x81\x5C\x8F\x5A\x51\x94\x7A\x12\x45\x6C\x7F\x1E\x0D\x88\x63\x8C\x4F\x37\x26\x61\x2C\x8A",32);
|
memcpy(hopping_frequency,"\x29\x4C\x67\x92\x31\x1C\x77\x18\x23\x6E\x81\x5C\x8F\x5A\x51\x94\x7A\x12\x45\x6C\x7F\x1E\x0D\x88\x63\x8C\x4F\x37\x26\x61\x2C\x8A",32);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef KYOSHO_FORCE_ID_SYNCRO
|
||||||
|
if(sub_protocol==KYOSHO_FHSS)
|
||||||
|
{
|
||||||
|
memcpy(rx_tx_addr,"\x00\xC2\x24\x00",4);
|
||||||
|
memcpy(hopping_frequency,"\x73\x12\x7D\x88\x63\x4A\x8D\x60\x57\x16\x5D\x8B\x25\x53\x6E\x3C\x41\x70\x20\x83\x2A\x19\x94\x2F\x91\x4C\x47\x36\x78\x10\x5A\x31",32);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if(sub_protocol==KYOSHO_HYPE)
|
if(sub_protocol==KYOSHO_HYPE)
|
||||||
{
|
{
|
||||||
MProtocol_id &= 0x00FF00FF;
|
MProtocol_id &= 0x00FF00FF;
|
||||||
|
|||||||
@@ -17,26 +17,64 @@
|
|||||||
|
|
||||||
#include "iface_cyrf6936.h"
|
#include "iface_cyrf6936.h"
|
||||||
|
|
||||||
#define LOSI_FORCE_ID
|
//#define LOSI_FORCE_ID
|
||||||
|
|
||||||
const uint8_t PROGMEM LOSI_bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49};
|
/* Using DSM.ino data codes since they are the same
|
||||||
const uint8_t LOSI_data_code[][16] = {
|
const uint8_t LOSI_data_code[][8] = {
|
||||||
{ 0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86, 0xC9, 0x2C, 0x06, 0x93, 0x86, 0xB9, 0x9E, 0xD7 }, //bind
|
//(Freq-1)%5=0
|
||||||
/* { 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93, 0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C },
|
{ 0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3 },
|
||||||
{ 0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C, 0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA },
|
{ 0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9 },
|
||||||
{ 0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA, 0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC },
|
{ 0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82 },
|
||||||
{ 0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC, 0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84 },
|
{ 0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB },
|
||||||
{ 0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84, 0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7 },
|
{ 0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7 },
|
||||||
{ 0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7, 0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0 },
|
{ 0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95 },
|
||||||
{ 0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0, 0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1 },*/
|
{ 0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4 },
|
||||||
{ 0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1, 0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8 } //normal
|
{ 0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF },
|
||||||
};
|
//(Freq-1)%5=1
|
||||||
|
{ 0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97 },
|
||||||
|
{ 0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA },
|
||||||
|
{ 0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE },
|
||||||
|
{ 0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD },
|
||||||
|
{ 0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD },
|
||||||
|
{ 0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9 },
|
||||||
|
{ 0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3 },
|
||||||
|
{ 0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0 },
|
||||||
|
//(Freq-1)%5=2
|
||||||
|
{ 0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E },
|
||||||
|
{ 0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7 },
|
||||||
|
{ 0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1 },
|
||||||
|
{ 0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4 },
|
||||||
|
{ 0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6 },
|
||||||
|
{ 0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80 },
|
||||||
|
{ 0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88 },
|
||||||
|
{ 0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88 },
|
||||||
|
//(Freq-1)%5=3
|
||||||
|
{ 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93 },
|
||||||
|
{ 0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C },
|
||||||
|
{ 0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA },
|
||||||
|
{ 0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC },
|
||||||
|
{ 0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84 },
|
||||||
|
{ 0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7 },
|
||||||
|
{ 0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0 },
|
||||||
|
{ 0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1 },
|
||||||
|
//(Freq-1)%5=4
|
||||||
|
{ 0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8 },
|
||||||
|
{ 0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6 },
|
||||||
|
{ 0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9 },
|
||||||
|
{ 0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4 },
|
||||||
|
{ 0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0 },
|
||||||
|
{ 0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8 },
|
||||||
|
{ 0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D },
|
||||||
|
{ 0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1 },
|
||||||
|
//Bind
|
||||||
|
{ 0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86 }
|
||||||
|
};*/
|
||||||
|
|
||||||
static uint16_t __attribute__((unused)) LOSI_check(uint16_t val)
|
static uint16_t __attribute__((unused)) LOSI_check(uint16_t val)
|
||||||
{
|
{
|
||||||
const uint8_t PROGMEM tab[] = { 0xF1, 0xDA, 0xB6, 0xC8 };
|
const uint8_t PROGMEM tab[] = { 0xF1, 0xDA, 0xB6, 0xC8 };
|
||||||
uint8_t res = 0x0B, tmp;
|
uint8_t res = crc8, tmp;
|
||||||
uint16_t calc = val>>2; // don't care about the 2 first bits
|
uint16_t calc = val>>2; // don't care about the 2 first bits
|
||||||
for(uint8_t i=0; i<5; i++)
|
for(uint8_t i=0; i<5; i++)
|
||||||
{
|
{
|
||||||
tmp=pgm_read_byte_near(&tab[i&0x03]);
|
tmp=pgm_read_byte_near(&tab[i&0x03]);
|
||||||
@@ -56,8 +94,11 @@ static void __attribute__((unused)) LOSI_send_packet()
|
|||||||
if(IS_BIND_IN_PROGRESS)
|
if(IS_BIND_IN_PROGRESS)
|
||||||
{
|
{
|
||||||
memcpy(&packet[4], rx_tx_addr, 4);
|
memcpy(&packet[4], rx_tx_addr, 4);
|
||||||
packet[8] = 0x05; // CRC?
|
crc = 0x0170;
|
||||||
packet[9] = 0x52; // CRC?
|
for(uint8_t i=0; i < 8; i++)
|
||||||
|
crc += packet[i];
|
||||||
|
packet[8] = crc >> 8;
|
||||||
|
packet[9] = crc;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -88,60 +129,88 @@ static void __attribute__((unused)) LOSI_cyrf_init()
|
|||||||
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
|
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
|
||||||
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
|
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
|
||||||
//CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24);
|
//CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24);
|
||||||
CYRF_SetPower(0x38);
|
CYRF_SetPower(0x38); // 64 SDR mode -> 8 bytes data code
|
||||||
CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0A);
|
CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0A);
|
||||||
CYRF_WriteRegister(CYRF_39_ANALOG_CTRL, 0x01);
|
CYRF_WriteRegister(CYRF_39_ANALOG_CTRL, 0x01);
|
||||||
CYRF_WritePreamble(0x333304);
|
CYRF_WritePreamble(0x333304);
|
||||||
//CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x00);
|
//CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x00);
|
||||||
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0x4A);
|
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0x4A);
|
||||||
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x04); // No CRC
|
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x04); // No CRC
|
||||||
//CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x14);
|
//CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x14);
|
||||||
//CYRF_WriteRegister(CYRF_14_EOP_CTRL, 0x02);
|
//CYRF_WriteRegister(CYRF_14_EOP_CTRL, 0x02);
|
||||||
|
uint8_t code[16];
|
||||||
|
DSM_read_code(code,0,8); // Load bind data code by default
|
||||||
|
CYRF_ConfigDataCode(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t LOSI_callback()
|
uint16_t LOSI_callback()
|
||||||
{
|
{
|
||||||
#ifdef MULTI_SYNC
|
#ifdef MULTI_SYNC
|
||||||
telemetry_set_input_sync(19738);
|
telemetry_set_input_sync(packet_period);
|
||||||
#endif
|
#endif
|
||||||
LOSI_send_packet();
|
|
||||||
if(bind_counter)
|
if(bind_counter)
|
||||||
{
|
{
|
||||||
bind_counter--;
|
bind_counter--;
|
||||||
if(bind_counter==0)
|
if(bind_counter==0)
|
||||||
{
|
{
|
||||||
BIND_DONE;
|
BIND_DONE;
|
||||||
CYRF_ConfigDataCode(LOSI_data_code[1], 16); // Load normal data code
|
// Load normal data code
|
||||||
|
uint8_t code[16];
|
||||||
|
DSM_read_code(code,hopping_frequency[0] % 5,(rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2]) % 8);
|
||||||
|
CYRF_ConfigDataCode(code);
|
||||||
|
packet_period = 19738;
|
||||||
}
|
}
|
||||||
return 8763;
|
|
||||||
}
|
}
|
||||||
return 19738;
|
LOSI_send_packet();
|
||||||
|
return packet_period;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LOSI_init()
|
void LOSI_init()
|
||||||
{
|
{
|
||||||
LOSI_cyrf_init();
|
LOSI_cyrf_init();
|
||||||
//CYRF_FindBestChannels(hopping_frequency, 1, 0, 0x13, 75); // 75 is unknown since dump stops at 0x27, this routine resets the CRC Seed to 0
|
|
||||||
//CYRF_ConfigRFChannel(hopping_frequency[0] | 1); // Only odd channels
|
CYRF_FindBestChannels(hopping_frequency, 1, 0, 0x07, 0x4F, FIND_CHANNEL_ODD); // 0x07 and 0x4F are unknown limits, this routine resets the CRC Seed to 0
|
||||||
|
|
||||||
|
crc8 = 0;
|
||||||
|
crc8 = (uint16_t)LOSI_check(((rx_tx_addr[2]&0x0F) << 8) + rx_tx_addr[3]) >> 12;
|
||||||
|
|
||||||
#ifdef LOSI_FORCE_ID
|
#ifdef LOSI_FORCE_ID
|
||||||
|
/*
|
||||||
rx_tx_addr[0] = 0x47;
|
rx_tx_addr[0] = 0x47;
|
||||||
rx_tx_addr[1] = 0x52;
|
rx_tx_addr[1] = 0x52;
|
||||||
rx_tx_addr[2] = 0xAE;
|
rx_tx_addr[2] = 0xAE;
|
||||||
rx_tx_addr[3] = 0xAA;
|
rx_tx_addr[3] = 0xAA;
|
||||||
CYRF_ConfigRFChannel(0x27);
|
crc8 = 0x0B;
|
||||||
|
num_ch = 0x07;
|
||||||
|
//Data codes for hopping_frequency[0] % 5
|
||||||
|
//{ 0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1, 0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86 },
|
||||||
|
//{ 0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF, 0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97 },
|
||||||
|
//{ 0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0, 0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E },
|
||||||
|
//{ 0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93 },
|
||||||
|
//{ 0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1, 0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8 }
|
||||||
|
*/
|
||||||
|
rx_tx_addr[0] = 0x56;
|
||||||
|
rx_tx_addr[1] = 0x52;
|
||||||
|
rx_tx_addr[2] = 0x22;
|
||||||
|
rx_tx_addr[3] = 0x8A;
|
||||||
|
crc8 = 0x0F;
|
||||||
|
num_ch = 0x02;
|
||||||
|
//Data codes for hopping_frequency[0] % 5
|
||||||
|
//{ 0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9, 0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4 },
|
||||||
|
//{ 0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82, 0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB },
|
||||||
|
//{ 0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE, 0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD },
|
||||||
|
//{ 0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1, 0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4 },
|
||||||
|
//{ 0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA, 0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC }
|
||||||
|
|
||||||
|
// Note: crc8=00..0F and num_ch=00..07
|
||||||
|
// num_ch = (rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2]) % 8;
|
||||||
|
// crc8 = (uint16_t)LOSI_check(((rx_tx_addr[2]&0x0F) << 8) + rx_tx_addr[3]) >> 12;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(IS_BIND_IN_PROGRESS)
|
CYRF_ConfigRFChannel(hopping_frequency[0]);
|
||||||
{
|
|
||||||
bind_counter = 300;
|
bind_counter = IS_BIND_IN_PROGRESS?300:1;
|
||||||
CYRF_ConfigDataCode(LOSI_data_code[0], 16); // Load bind data code
|
packet_period = 8763;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CYRF_ConfigDataCode(LOSI_data_code[1], 16); // Load normal data code
|
|
||||||
bind_counter = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ uint16_t MLINK_callback()
|
|||||||
|
|
||||||
|
|
||||||
case MLINK_PREP_DATA:
|
case MLINK_PREP_DATA:
|
||||||
CYRF_ConfigDataCode(MLINK_Data_Code,16);
|
CYRF_ConfigDataCode(MLINK_Data_Code);
|
||||||
MLINK_CRC_Init += 0xED;
|
MLINK_CRC_Init += 0xED;
|
||||||
hopping_frequency_no = 0x00;
|
hopping_frequency_no = 0x00;
|
||||||
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
|
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
|
||||||
@@ -597,7 +597,7 @@ void MLINK_init()
|
|||||||
{
|
{
|
||||||
packet_count = 0;
|
packet_count = 0;
|
||||||
bind_counter = MLINK_BIND_COUNT;
|
bind_counter = MLINK_BIND_COUNT;
|
||||||
CYRF_ConfigDataCode((uint8_t*)"\x6F\xBE\x32\x01\xDB\xF1\x2B\x01\xE3\x5C\xFA\x02\x97\x93\xF9\x02",16); //Bind data code
|
CYRF_ConfigDataCode((uint8_t*)"\x6F\xBE\x32\x01\xDB\xF1\x2B\x01\xE3\x5C\xFA\x02\x97\x93\xF9\x02"); //Bind data code
|
||||||
CYRF_ConfigRFChannel(MLINK_BIND_CHANNEL);
|
CYRF_ConfigRFChannel(MLINK_BIND_CHANNEL);
|
||||||
phase = MLINK_BIND_TX;
|
phase = MLINK_BIND_TX;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
// compatible with MT99xx, Eachine H7, Yi Zhan i6S and LS114/124
|
// compatible with MT99xx, Eachine H7, Yi Zhan i6S, LS114/124, QF009 Su35
|
||||||
// Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29
|
// Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29
|
||||||
|
|
||||||
#if defined(MT99XX_CCNRF_INO)
|
#if defined(MT99XX_CCNRF_INO)
|
||||||
@@ -83,7 +83,12 @@ enum{
|
|||||||
enum{
|
enum{
|
||||||
// flags going to packet[6] (F949G)
|
// flags going to packet[6] (F949G)
|
||||||
FLAG_F949G_LIGHT = 0x01,
|
FLAG_F949G_LIGHT = 0x01,
|
||||||
|
FLAG_F949G_RATES = 0x02,
|
||||||
FLAG_F949G_3D6G = 0x20,
|
FLAG_F949G_3D6G = 0x20,
|
||||||
|
FLAG_BF109_RATES = 0x01, // short press right
|
||||||
|
FLAG_BF109_LIGHT = 0x02, // short press left
|
||||||
|
FLAG_BF109_UNK1 = 0x08, // long press right
|
||||||
|
FLAG_BF109_UNK2 = 0x10, // long press left
|
||||||
};
|
};
|
||||||
enum{
|
enum{
|
||||||
// flags going to packet[6] (PA18)
|
// flags going to packet[6] (PA18)
|
||||||
@@ -91,6 +96,16 @@ enum{
|
|||||||
FLAG_PA18_FLIP = 0x80,
|
FLAG_PA18_FLIP = 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum{
|
||||||
|
// flags going to packet[6] (QF009 Su35)
|
||||||
|
FLAG_SU35_6G = 0x00,
|
||||||
|
FLAG_SU35_3D = 0x40,
|
||||||
|
FLAG_SU35_HIRATE = 0x01,
|
||||||
|
FLAG_SU35_LED = 0x02,
|
||||||
|
FLAG_SU35_FLASH = 0x04,
|
||||||
|
FLAG_SU35_INVERT = 0x08,
|
||||||
|
};
|
||||||
|
|
||||||
const uint8_t h7_mys_byte[] = {
|
const uint8_t h7_mys_byte[] = {
|
||||||
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
|
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
|
||||||
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
|
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
|
||||||
@@ -174,8 +189,8 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
|||||||
packet[1] = convert_channel_16b_limit(RUDDER ,0x00,0xE1); // rudder
|
packet[1] = convert_channel_16b_limit(RUDDER ,0x00,0xE1); // rudder
|
||||||
packet[2] = convert_channel_16b_limit(AILERON ,0xE1,0x00); // aileron
|
packet[2] = convert_channel_16b_limit(AILERON ,0xE1,0x00); // aileron
|
||||||
packet[3] = convert_channel_16b_limit(ELEVATOR,0x00,0xE1); // elevator
|
packet[3] = convert_channel_16b_limit(ELEVATOR,0x00,0xE1); // elevator
|
||||||
packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00)
|
packet[4] = (convert_channel_8b(CH10) ^ 0xFF) >> 2; // aileron trim (3F..20..00)
|
||||||
packet[5] = 0x20; // roll trim (0x00-0x20-0x3f)
|
packet[5] = convert_channel_8b(CH11) >> 2; // elevator trim (00..20..3F)
|
||||||
packet[6] = GET_FLAG( CH5_SW, FLAG_MT_FLIP );
|
packet[6] = GET_FLAG( CH5_SW, FLAG_MT_FLIP );
|
||||||
if(sub_protocol != PA18+8)
|
if(sub_protocol != PA18+8)
|
||||||
packet[7] = h7_mys_byte[hopping_frequency_no]; // next rf channel index ?
|
packet[7] = h7_mys_byte[hopping_frequency_no]; // next rf channel index ?
|
||||||
@@ -248,9 +263,11 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
|||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case F949G:
|
case F949G:
|
||||||
packet[6] = 0x02
|
packet[6] = GET_FLAG( CH5_SW, FLAG_F949G_3D6G )
|
||||||
| GET_FLAG( CH5_SW, FLAG_F949G_3D6G )
|
| GET_FLAG( CH6_SW, FLAG_F949G_LIGHT ) //FLAG_BF109_RATES
|
||||||
| GET_FLAG( CH6_SW, FLAG_F949G_LIGHT );
|
| GET_FLAG(!CH7_SW, FLAG_F949G_RATES ) //FLAG_BF109_LIGHT
|
||||||
|
| GET_FLAG( CH8_SW, FLAG_BF109_UNK1 ) //BF109 long press right, temporary flag
|
||||||
|
| GET_FLAG( CH9_SW, FLAG_BF109_UNK2 ); //BF109 long press left, temporary flag
|
||||||
packet[7] = 0x00;
|
packet[7] = 0x00;
|
||||||
break;
|
break;
|
||||||
case PA18+8:
|
case PA18+8:
|
||||||
@@ -264,6 +281,14 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
|||||||
if(hopping_frequency_no == 0)
|
if(hopping_frequency_no == 0)
|
||||||
packet[7] ^= 0x40;
|
packet[7] ^= 0x40;
|
||||||
break;
|
break;
|
||||||
|
case SU35+8:
|
||||||
|
packet[6] = FLAG_SU35_6G
|
||||||
|
| GET_FLAG( CH5_SW, FLAG_SU35_3D )
|
||||||
|
| GET_FLAG( !CH6_SW, FLAG_SU35_LED )
|
||||||
|
| GET_FLAG( CH7_SW, FLAG_SU35_FLASH )
|
||||||
|
| GET_FLAG( CH8_SW, FLAG_SU35_INVERT )
|
||||||
|
| GET_FLAG( CH9_SW, FLAG_SU35_HIRATE );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
uint8_t result=crc8;
|
uint8_t result=crc8;
|
||||||
for(uint8_t i=0; i<8; i++)
|
for(uint8_t i=0; i<8; i++)
|
||||||
@@ -312,7 +337,7 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
|||||||
XN297_SetTxRxMode(TX_EN);
|
XN297_SetTxRxMode(TX_EN);
|
||||||
XN297_WritePayload(packet, MT99XX_PACKET_SIZE);
|
XN297_WritePayload(packet, MT99XX_PACKET_SIZE);
|
||||||
|
|
||||||
#if 0
|
#if 1
|
||||||
for(uint8_t i=0; i<MT99XX_PACKET_SIZE; i++)
|
for(uint8_t i=0; i<MT99XX_PACKET_SIZE; i++)
|
||||||
debug(" %02X",packet[i]);
|
debug(" %02X",packet[i]);
|
||||||
debugln();
|
debugln();
|
||||||
@@ -505,7 +530,7 @@ void MT99XX_init(void)
|
|||||||
bind_counter = MT99XX_BIND_COUNT;
|
bind_counter = MT99XX_BIND_COUNT;
|
||||||
if(IS_BIND_DONE)
|
if(IS_BIND_DONE)
|
||||||
{
|
{
|
||||||
if(sub_protocol != A180 && sub_protocol != DRAGON && sub_protocol != F949G && sub_protocol != PA18+8)
|
if(sub_protocol != A180 && sub_protocol != DRAGON && sub_protocol != F949G && sub_protocol != PA18+8 && sub_protocol != SU35+8)
|
||||||
BIND_IN_PROGRESS; // autobind protocol
|
BIND_IN_PROGRESS; // autobind protocol
|
||||||
else
|
else
|
||||||
bind_counter = 1;
|
bind_counter = 1;
|
||||||
|
|||||||
@@ -50,12 +50,19 @@ static void __attribute__((unused)) MOULDKG_send_packet()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint8_t n = num_ch<<2;
|
uint8_t n = num_ch<<2;
|
||||||
if(sub_protocol == MOULDKG_ANALOG)
|
if(sub_protocol == MOULDKG_ANALOG4 || sub_protocol == MOULDKG_ANALOG6 )
|
||||||
{
|
{
|
||||||
packet[0] = 0x36;
|
packet[0] = 0x36;
|
||||||
uint8_t ch[]={ 1,0,2,3 };
|
const uint8_t ch[]={ 1,0,2,3,5,4 };
|
||||||
for(uint8_t i=0;i<4;i++)
|
if(sub_protocol == MOULDKG_ANALOG6)
|
||||||
packet[i+4] = convert_channel_8b(ch[i]+n);
|
n += num_ch<<1;
|
||||||
|
for(uint8_t i=0;i<6;i++)
|
||||||
|
{
|
||||||
|
if( (i > 3 && sub_protocol == MOULDKG_ANALOG4) || i + n > 15)
|
||||||
|
packet[i+4] = 0x80; //Centered channel
|
||||||
|
else
|
||||||
|
packet[i+4] = convert_channel_8b(ch[i]+n);
|
||||||
|
}
|
||||||
len = MOULDKG_PAYLOAD_SIZE_ANALOG;
|
len = MOULDKG_PAYLOAD_SIZE_ANALOG;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
3,FrskyD,D8,Cloned
|
3,FrskyD,D8,Cloned
|
||||||
4,Hisky,Hisky,HK310
|
4,Hisky,Hisky,HK310
|
||||||
5,V2x2,V2x2,JXD506,MR101
|
5,V2x2,V2x2,JXD506,MR101
|
||||||
6,DSM,DSM2_1F,DSM2_2F,DSMX_1F,DSMX_2F,AUTO,DSMR_1F
|
6,DSM,DSM2_1F,DSM2_2F,DSMX_1F,DSMX_2F,AUTO,DSMR_1F,DSMR,DSM2_SFC
|
||||||
7,Devo,8CH,10CH,12CH,6CH,7CH
|
7,Devo,8CH,10CH,12CH,6CH,7CH
|
||||||
8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI
|
8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI
|
||||||
9,KN,WLTOYS,FEILUN
|
9,KN,WLTOYS,FEILUN
|
||||||
10,SymaX,SYMAX,SYMAX5C
|
10,SymaX,SYMAX,SYMAX5C
|
||||||
11,SLT,SLT_V1,SLT_V2,Q100,Q200,MR100
|
11,SLT,SLT_V1,SLT_V2,Q100,Q200,MR100,V1_4CH,RF_SIM,SLT6TX
|
||||||
12,CX10,GREEN,BLUE,DM007,---,J3015_1,J3015_2,MK33041
|
12,CX10,GREEN,BLUE,DM007,---,J3015_1,J3015_2,MK33041
|
||||||
13,CG023,CG023,YD829
|
13,CG023,CG023,YD829
|
||||||
14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE,DHD_D4,QX100
|
14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE,DHD_D4,QX100
|
||||||
@@ -20,12 +20,12 @@
|
|||||||
20,FY326,FY326,FY319
|
20,FY326,FY326,FY319
|
||||||
21,Futaba,SFHSS
|
21,Futaba,SFHSS
|
||||||
22,J6PRO
|
22,J6PRO
|
||||||
23,FQ777
|
23,FQ777,124,XBM37
|
||||||
24,ASSAN
|
24,ASSAN
|
||||||
25,FrskyV
|
25,FrskyV
|
||||||
26,HONTAI,HONTAI,JJRCX1,X5C1,FQ777_951
|
26,HONTAI,HONTAI,JJRCX1,X5C1,FQ777_951,XKK170
|
||||||
27,OpnLrs
|
27,OpnLrs
|
||||||
28,AFHDS2A,PWM_IBUS,PPM_IBUS,PWM_SBUS,PPM_SBUS,PWM_IB16,PPM_IB16,PWM_SB16,PPM_SB16
|
28,AFHDS2A,PWM_IBUS,PPM_IBUS,PWM_SBUS,PPM_SBUS,Gyro_Off,Gyro_On,G_On_Rev
|
||||||
29,Q2X2,Q222,Q242,Q282
|
29,Q2X2,Q222,Q242,Q282
|
||||||
30,WK2x01,WK2801,WK2401,W6_5_1,W6_6_1,W6_HEL,W6_HEL_I
|
30,WK2x01,WK2801,WK2401,W6_5_1,W6_6_1,W6_HEL,W6_HEL_I
|
||||||
31,Q303,Q303,CX35,CX10D,CX10WD
|
31,Q303,Q303,CX35,CX10D,CX10WD
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
40,WFLY,WFR0x
|
40,WFLY,WFR0x
|
||||||
41,BUGS
|
41,BUGS
|
||||||
42,BUGSMINI,BUGSMINI,BUGS3H
|
42,BUGSMINI,BUGSMINI,BUGS3H
|
||||||
43,Traxxas,RX6519
|
43,Traxxas,TQ
|
||||||
44,NCC1701
|
44,NCC1701
|
||||||
45,E01X,E012,E015
|
45,E01X,E012,E015
|
||||||
46,V911S,V911S,E119
|
46,V911S,V911S,E119
|
||||||
@@ -55,11 +55,11 @@
|
|||||||
55,Frsky_RX,Multi,CloneTX,EraseTX,CPPM
|
55,Frsky_RX,Multi,CloneTX,EraseTX,CPPM
|
||||||
56,AFHDS2A_RX,Multi,CPPM
|
56,AFHDS2A_RX,Multi,CPPM
|
||||||
57,HoTT,Sync,No_Sync
|
57,HoTT,Sync,No_Sync
|
||||||
58,FX,816,620,9630
|
58,FX,FX816,FX620,9630,Q560,QF012,BM26,A570
|
||||||
59,Bayang_RX,Multi,CPPM
|
59,Bayang_RX,Multi,CPPM
|
||||||
60,Pelikan,Pro,Lite,SCX24
|
60,Pelikan,Pro,Lite,SCX24
|
||||||
61,Tiger
|
61,EazyRC
|
||||||
62,XK,X450,X420
|
62,XK,X450,X420,Cars
|
||||||
63,XN_DUMP,250K,1M,2M,AUTO
|
63,XN_DUMP,250K,1M,2M,AUTO
|
||||||
64,FrskyX2,CH_16,CH_8,EU_16,EU_8,Cloned
|
64,FrskyX2,CH_16,CH_8,EU_16,EU_8,Cloned
|
||||||
65,FrSkyR9,915MHz,868MHz,915_8ch,868_8ch,FCC,--,FCC_8ch,--_8ch
|
65,FrSkyR9,915MHz,868MHz,915_8ch,868_8ch,FCC,--,FCC_8ch,--_8ch
|
||||||
@@ -67,13 +67,13 @@
|
|||||||
67,LR12,LR12,LR12_6ch
|
67,LR12,LR12,LR12_6ch
|
||||||
68,Skyartec
|
68,Skyartec
|
||||||
69,ESKYv2,150V2
|
69,ESKYv2,150V2
|
||||||
70,DSM_RX,Multi,CPPM
|
70,DSM_RX,Multi,CloneTX,EraseTX,CPPM
|
||||||
71,JJRC345,JJRC345,SkyTmblr
|
71,JJRC345,JJRC345,SkyTmblr
|
||||||
72,Q90C
|
72,Q90C
|
||||||
73,Kyosho,FHSS,Hype
|
73,Kyosho,FHSS,Hype
|
||||||
74,RadioLink,Surface,Air,DumboRC
|
74,RadioLink,Surface,Air,DumboRC,RC4G,Dumbo_P
|
||||||
75,---
|
75,---
|
||||||
76,Realacc,R11
|
76,Realacc,R11,WLV8TX
|
||||||
77,OMP
|
77,OMP
|
||||||
78,M-Link
|
78,M-Link
|
||||||
79,WFLY,RF20x
|
79,WFLY,RF20x
|
||||||
@@ -86,8 +86,21 @@
|
|||||||
87,IKEA
|
87,IKEA
|
||||||
88,WILLIFM
|
88,WILLIFM
|
||||||
89,Losi
|
89,Losi
|
||||||
90,MouldKg,Analog,Digit
|
90,MouldKg,A4444,D4444,A664
|
||||||
91,Xerall
|
91,Xerall
|
||||||
92,MT99xx,PA18
|
92,MT99xx,PA18,SU35
|
||||||
93,Kyosho2,KT-17
|
93,Kyosho2,KT-17
|
||||||
94,Scorpio
|
94,Scorpio
|
||||||
|
95,BlueFly
|
||||||
|
96,BumbleB
|
||||||
|
97,SGF22,F22,F22S,J20
|
||||||
|
98,Kyosho3
|
||||||
|
99,XK2,X4,P10
|
||||||
|
100,YuXiang
|
||||||
|
102,JIABAILE,STD,GYRO
|
||||||
|
103,H36
|
||||||
|
104,KAMTOM
|
||||||
|
105,Shenqi2
|
||||||
|
106,WL91x
|
||||||
|
107,WPL
|
||||||
|
108,0,Ares
|
||||||
@@ -36,6 +36,7 @@ const char STR_MT99XX[] ="MT99XX";
|
|||||||
const char STR_MT99XX2[] ="MT99XX2";
|
const char STR_MT99XX2[] ="MT99XX2";
|
||||||
const char STR_MJXQ[] ="MJXq";
|
const char STR_MJXQ[] ="MJXq";
|
||||||
const char STR_SHENQI[] ="Shenqi";
|
const char STR_SHENQI[] ="Shenqi";
|
||||||
|
const char STR_SHENQI2[] ="Shenqi2";
|
||||||
const char STR_FY326[] ="FY326";
|
const char STR_FY326[] ="FY326";
|
||||||
const char STR_FUTABA[] ="Futaba";
|
const char STR_FUTABA[] ="Futaba";
|
||||||
const char STR_J6PRO[] ="J6 Pro";
|
const char STR_J6PRO[] ="J6 Pro";
|
||||||
@@ -55,6 +56,7 @@ const char STR_DM002[] ="DM002";
|
|||||||
const char STR_CABELL[] ="Cabell";
|
const char STR_CABELL[] ="Cabell";
|
||||||
const char STR_ESKY150[] ="Esky150";
|
const char STR_ESKY150[] ="Esky150";
|
||||||
const char STR_ESKY150V2[] ="EskyV2";
|
const char STR_ESKY150V2[] ="EskyV2";
|
||||||
|
const char STR_H36[] ="H36";
|
||||||
const char STR_H8_3D[] ="H8 3D";
|
const char STR_H8_3D[] ="H8 3D";
|
||||||
const char STR_CORONA[] ="Corona";
|
const char STR_CORONA[] ="Corona";
|
||||||
const char STR_CFLIE[] ="CFlie";
|
const char STR_CFLIE[] ="CFlie";
|
||||||
@@ -78,11 +80,11 @@ const char STR_SCANNER[] ="Scanner";
|
|||||||
const char STR_FRSKY_RX[] ="FrSkyRX";
|
const char STR_FRSKY_RX[] ="FrSkyRX";
|
||||||
const char STR_AFHDS2A_RX[] ="FS2A_RX";
|
const char STR_AFHDS2A_RX[] ="FS2A_RX";
|
||||||
const char STR_HOTT[] ="HoTT";
|
const char STR_HOTT[] ="HoTT";
|
||||||
const char STR_FX[] ="FX";
|
const char STR_FX[] ="FX";
|
||||||
const char STR_BAYANG_RX[] ="BayanRX";
|
const char STR_BAYANG_RX[] ="BayanRX";
|
||||||
const char STR_PELIKAN[] ="Pelikan";
|
const char STR_PELIKAN[] ="Pelikan";
|
||||||
const char STR_TIGER[] ="Tiger";
|
|
||||||
const char STR_XK[] ="XK";
|
const char STR_XK[] ="XK";
|
||||||
|
const char STR_XK2[] ="XK2";
|
||||||
const char STR_XN297DUMP[] ="XN297DP";
|
const char STR_XN297DUMP[] ="XN297DP";
|
||||||
const char STR_FRSKYR9[] ="FrSkyR9";
|
const char STR_FRSKYR9[] ="FrSkyR9";
|
||||||
const char STR_PROPEL[] ="Propel";
|
const char STR_PROPEL[] ="Propel";
|
||||||
@@ -106,6 +108,18 @@ const char STR_LOSI[] ="Losi";
|
|||||||
const char STR_MOULDKG[] ="MouldKg";
|
const char STR_MOULDKG[] ="MouldKg";
|
||||||
const char STR_XERALL[] ="Xerall";
|
const char STR_XERALL[] ="Xerall";
|
||||||
const char STR_SCORPIO[] ="Scorpio";
|
const char STR_SCORPIO[] ="Scorpio";
|
||||||
|
const char STR_BLUEFLY[] ="BlueFly";
|
||||||
|
const char STR_BUMBLEB[] ="BumbleB";
|
||||||
|
const char STR_SGF22[] ="SGF22";
|
||||||
|
const char STR_EAZYRC[] ="EazyRC";
|
||||||
|
const char STR_KYOSHO3[] ="Kyosho3";
|
||||||
|
const char STR_YUXIANG[] ="YuXiang";
|
||||||
|
const char STR_UDIRC[] ="UDIRC";
|
||||||
|
const char STR_JIABAILE[] ="JIABAILE";
|
||||||
|
const char STR_KAMTOM[] ="KAMTOM";
|
||||||
|
const char STR_WL91X[] ="WL91x";
|
||||||
|
const char STR_WPL[] ="WPL";
|
||||||
|
const char STR_ARES[] ="ARES";
|
||||||
|
|
||||||
const char STR_SUBTYPE_FLYSKY[] = "\x04""Std\0""V9x9""V6x6""V912""CX20";
|
const char STR_SUBTYPE_FLYSKY[] = "\x04""Std\0""V9x9""V6x6""V912""CX20";
|
||||||
const char STR_SUBTYPE_HUBSAN[] = "\x04""H107""H301""H501";
|
const char STR_SUBTYPE_HUBSAN[] = "\x04""H107""H301""H501";
|
||||||
@@ -118,24 +132,25 @@ const char STR_SUBTYPE_FRSKYD[] = "\x06""D8\0 ""Cloned";
|
|||||||
const char STR_SUBTYPE_HISKY[] = "\x05""Std\0 ""HK310";
|
const char STR_SUBTYPE_HISKY[] = "\x05""Std\0 ""HK310";
|
||||||
const char STR_SUBTYPE_V2X2[] = "\x06""Std\0 ""JXD506""MR101\0";
|
const char STR_SUBTYPE_V2X2[] = "\x06""Std\0 ""JXD506""MR101\0";
|
||||||
#ifndef MULTI_EU
|
#ifndef MULTI_EU
|
||||||
const char STR_SUBTYPE_DSM[] = "\x04""2 1F""2 2F""X 1F""X 2F""Auto""R 1F";
|
const char STR_SUBTYPE_DSM[] = "\x04""2 1F""2 2F""X 1F""X 2F""Auto""R 1F""2SFC";
|
||||||
#else
|
#else
|
||||||
const char STR_SUBTYPE_DSM[] = "\x04""--->""--->""X 1F""X 2F""Auto""R 1F";
|
const char STR_SUBTYPE_DSM[] = "\x04""--->""--->""X 1F""X 2F""Auto""R 1F""----";
|
||||||
#endif
|
#endif
|
||||||
const char STR_SUBTYPE_DEVO[] = "\x04""8ch\0""10ch""12ch""6ch\0""7ch\0";
|
const char STR_SUBTYPE_DEVO[] = "\x04""8ch\0""10ch""12ch""6ch\0""7ch\0";
|
||||||
const char STR_SUBTYPE_YD717[] = "\x07""Std\0 ""SkyWlkr""Syma X4""XINXUN\0""NIHUI\0 ";
|
const char STR_SUBTYPE_YD717[] = "\x07""Std\0 ""SkyWlkr""Syma X4""XINXUN\0""NIHUI\0 ";
|
||||||
const char STR_SUBTYPE_KN[] = "\x06""WLtoys""FeiLun";
|
const char STR_SUBTYPE_KN[] = "\x06""WLtoys""FeiLun";
|
||||||
const char STR_SUBTYPE_SYMAX[] = "\x03""Std""X5C";
|
const char STR_SUBTYPE_SYMAX[] = "\x03""Std""X5C";
|
||||||
const char STR_SUBTYPE_SLT[] = "\x06""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0";
|
const char STR_SUBTYPE_SLT[] = "\x06""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0""V1_4ch""RF_SIM""SLT6TX";
|
||||||
const char STR_SUBTYPE_CX10[] = "\x07""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041";
|
const char STR_SUBTYPE_CX10[] = "\x07""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041";
|
||||||
const char STR_SUBTYPE_CG023[] = "\x05""Std\0 ""YD829";
|
const char STR_SUBTYPE_CG023[] = "\x05""Std\0 ""YD829";
|
||||||
const char STR_SUBTYPE_BAYANG[] = "\x07""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4\0""QX100\0 ";
|
const char STR_SUBTYPE_BAYANG[] = "\x07""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4\0""QX100\0 ";
|
||||||
const char STR_SUBTYPE_MT99[] = "\x06""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805\0""A180\0 ""Dragon""F949G\0";
|
const char STR_SUBTYPE_MT99[] = "\x06""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805\0""A180\0 ""Dragon""F949G\0";
|
||||||
const char STR_SUBTYPE_MT992[] = "\x04""PA18";
|
const char STR_SUBTYPE_MT992[] = "\x04""PA18""SU35";
|
||||||
const char STR_SUBTYPE_MJXQ[] = "\x07""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix";
|
const char STR_SUBTYPE_MJXQ[] = "\x07""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix";
|
||||||
const char STR_SUBTYPE_FY326[] = "\x05""Std\0 ""FY319";
|
const char STR_SUBTYPE_FY326[] = "\x05""Std\0 ""FY319";
|
||||||
const char STR_SUBTYPE_HONTAI[] = "\x07""Std\0 ""JJRC X1""X5C1\0 ""FQ_951";
|
const char STR_SUBTYPE_FQ777[] = "\x05""124\0 ""XBM37";
|
||||||
const char STR_SUBTYPE_AFHDS2A[] = "\x08""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS""PWM,IB16""PPM,IB16""PWM,SB16""PPM,SB16";
|
const char STR_SUBTYPE_HONTAI[] = "\x06""Std\0 ""JJRCX1""X5C1\0 ""FQ_951""XKK170";
|
||||||
|
const char STR_SUBTYPE_AFHDS2A[] = "\x08""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS""Gyro_Off""Gyro_On\0""G_On_Rev";
|
||||||
const char STR_SUBTYPE_Q2X2[] = "\x04""Q222""Q242""Q282";
|
const char STR_SUBTYPE_Q2X2[] = "\x04""Q222""Q242""Q282";
|
||||||
const char STR_SUBTYPE_WK2x01[] = "\x06""WK2801""WK2401""W6_5_1""W6_6_1""W6_HeL""W6_HeI";
|
const char STR_SUBTYPE_WK2x01[] = "\x06""WK2801""WK2401""W6_5_1""W6_6_1""W6_HeL""W6_HeI";
|
||||||
const char STR_SUBTYPE_Q303[] = "\x06""Std\0 ""CX35\0 ""CX10D\0""CX10WD";
|
const char STR_SUBTYPE_Q303[] = "\x06""Std\0 ""CX35\0 ""CX10D\0""CX10WD";
|
||||||
@@ -144,18 +159,19 @@ const char STR_SUBTYPE_H83D[] = "\x07""Std\0 ""H20H\0 ""H20Mini""H30Min
|
|||||||
const char STR_SUBTYPE_CORONA[] = "\x05""V1\0 ""V2\0 ""FD V3";
|
const char STR_SUBTYPE_CORONA[] = "\x05""V1\0 ""V2\0 ""FD V3";
|
||||||
const char STR_SUBTYPE_HITEC[] = "\x07""Optima\0""Opt Hub""Minima\0";
|
const char STR_SUBTYPE_HITEC[] = "\x07""Optima\0""Opt Hub""Minima\0";
|
||||||
const char STR_SUBTYPE_BUGS_MINI[] = "\x06""Std\0 ""Bugs3H";
|
const char STR_SUBTYPE_BUGS_MINI[] = "\x06""Std\0 ""Bugs3H";
|
||||||
const char STR_SUBTYPE_TRAXXAS[] = "\x04""6519";
|
const char STR_SUBTYPE_TRAXXAS[] = "\x03""TQ2""TQ1";
|
||||||
const char STR_SUBTYPE_E01X[] = "\x05""E012\0""E015\0";
|
const char STR_SUBTYPE_E01X[] = "\x05""E012\0""E015\0";
|
||||||
const char STR_SUBTYPE_GD00X[] = "\x05""GD_V1""GD_V2";
|
const char STR_SUBTYPE_GD00X[] = "\x05""GD_V1""GD_V2";
|
||||||
const char STR_SUBTYPE_REDPINE[] = "\x04""Fast""Slow";
|
const char STR_SUBTYPE_REDPINE[] = "\x04""Fast""Slow";
|
||||||
const char STR_SUBTYPE_POTENSIC[] = "\x03""A20";
|
const char STR_SUBTYPE_POTENSIC[] = "\x03""A20";
|
||||||
const char STR_SUBTYPE_ZSX[] = "\x07""280JJRC";
|
const char STR_SUBTYPE_ZSX[] = "\x07""280JJRC";
|
||||||
const char STR_SUBTYPE_HEIGHT[] = "\x03""5ch""8ch";
|
const char STR_SUBTYPE_HEIGHT[] = "\x03""5ch""8ch";
|
||||||
const char STR_SUBTYPE_XN297DUMP[] = "\x07""250Kbps""1Mbps\0 ""2Mbps\0 ""Auto\0 ""NRF\0 ""CC2500\0";
|
const char STR_SUBTYPE_XN297DUMP[] = "\x07""250Kbps""1Mbps\0 ""2Mbps\0 ""Auto\0 ""NRF\0 ""CC2500\0""XN297\0 ";
|
||||||
const char STR_SUBTYPE_ESKY150[] = "\x03""4ch""7ch";
|
const char STR_SUBTYPE_ESKY150[] = "\x03""4ch""7ch";
|
||||||
const char STR_SUBTYPE_ESKY150V2[] = "\x05""150V2";
|
const char STR_SUBTYPE_ESKY150V2[] = "\x05""150V2";
|
||||||
const char STR_SUBTYPE_V911S[] = "\x05""V911S""E119\0";
|
const char STR_SUBTYPE_V911S[] = "\x05""V911S""E119\0";
|
||||||
const char STR_SUBTYPE_XK[] = "\x04""X450""X420";
|
const char STR_SUBTYPE_XK[] = "\x04""X450""X420""Cars";
|
||||||
|
const char STR_SUBTYPE_XK2[] = "\x03""X4\0""P10";
|
||||||
const char STR_SUBTYPE_FRSKYR9[] = "\x07""915MHz\0""868MHz\0""915 8ch""868 8ch""FCC\0 ""--\0 ""FCC 8ch""-- 8ch\0";
|
const char STR_SUBTYPE_FRSKYR9[] = "\x07""915MHz\0""868MHz\0""915 8ch""868 8ch""FCC\0 ""--\0 ""FCC 8ch""-- 8ch\0";
|
||||||
const char STR_SUBTYPE_ESKY[] = "\x03""Std""ET4";
|
const char STR_SUBTYPE_ESKY[] = "\x03""Std""ET4";
|
||||||
const char STR_SUBTYPE_PROPEL[] = "\x04""74-Z";
|
const char STR_SUBTYPE_PROPEL[] = "\x04""74-Z";
|
||||||
@@ -165,26 +181,33 @@ const char STR_SUBTYPE_WFLY2[] = "\x05""RF20x";
|
|||||||
const char STR_SUBTYPE_HOTT[] = "\x07""Sync\0 ""No_Sync";
|
const char STR_SUBTYPE_HOTT[] = "\x07""Sync\0 ""No_Sync";
|
||||||
const char STR_SUBTYPE_PELIKAN[] = "\x05""Pro\0 ""Lite\0""SCX24";
|
const char STR_SUBTYPE_PELIKAN[] = "\x05""Pro\0 ""Lite\0""SCX24";
|
||||||
const char STR_SUBTYPE_V761[] = "\x05""3ch\0 ""4ch\0 ""TOPRC";
|
const char STR_SUBTYPE_V761[] = "\x05""3ch\0 ""4ch\0 ""TOPRC";
|
||||||
const char STR_SUBTYPE_RLINK[] = "\x07""Surface""Air\0 ""DumboRC";
|
const char STR_SUBTYPE_RLINK[] = "\x07""Surface""Air\0 ""DumboRC""RC4G\0 ""Dumbo_P";
|
||||||
const char STR_SUBTYPE_REALACC[] = "\x03""R11";
|
const char STR_SUBTYPE_REALACC[] = "\x06""R11\0 ""WLV8TX";
|
||||||
const char STR_SUBTYPE_KYOSHO[] = "\x04""FHSS""Hype";
|
const char STR_SUBTYPE_KYOSHO[] = "\x04""FHSS""Hype";
|
||||||
const char STR_SUBTYPE_KYOSHO2[] = "\x05""KT-17";
|
const char STR_SUBTYPE_KYOSHO2[] = "\x05""KT-17";
|
||||||
|
const char STR_SUBTYPE_KYOSHO3[] = "\x03""ASF";
|
||||||
const char STR_SUBTYPE_FUTABA[] = "\x05""SFHSS";
|
const char STR_SUBTYPE_FUTABA[] = "\x05""SFHSS";
|
||||||
const char STR_SUBTYPE_JJRC345[] = "\x08""JJRC345\0""SkyTmblr";
|
const char STR_SUBTYPE_JJRC345[] = "\x08""JJRC345\0""SkyTmblr";
|
||||||
const char STR_SUBTYPE_MOULKG[] = "\x06""Analog""Digit\0";
|
const char STR_SUBTYPE_MOULDKG[] = "\x05""A4444""D4444""A664\0";
|
||||||
const char STR_SUBTYPE_KF606[] = "\x06""KF606\0""MIG320""ZCZ50\0";
|
const char STR_SUBTYPE_KF606[] = "\x06""KF606\0""MIG320""ZCZ50\0";
|
||||||
const char STR_SUBTYPE_E129[] = "\x04""E129""C186";
|
const char STR_SUBTYPE_E129[] = "\x04""E129""C186";
|
||||||
const char STR_SUBTYPE_FX[] = "\x04""816\0""620\0""9630";
|
const char STR_SUBTYPE_FX[] = "\x05""FX816""FX620""9630\0""Q560\0""QF012""BM26\0""A570\0";
|
||||||
|
const char STR_SUBTYPE_SGF22[] = "\x04""F22\0""F22S""J20\0""CX10";
|
||||||
|
const char STR_SUBTYPE_JIABAILE[] = "\x04""Std\0""Gyro";
|
||||||
#define NO_SUBTYPE nullptr
|
#define NO_SUBTYPE nullptr
|
||||||
|
|
||||||
#ifdef SEND_CPPM
|
#ifdef SEND_CPPM
|
||||||
const char STR_SUB_FRSKY_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX""CPPM\0 ";
|
const char STR_SUB_FRSKY_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX""CPPM\0 ";
|
||||||
|
const char STR_SUB_DSM_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX""CPPM\0 ";
|
||||||
#define FRCPPM 4
|
#define FRCPPM 4
|
||||||
|
#define DSMCPPM 4
|
||||||
const char STR_CPPM[] = "\x05""Multi""CPPM\0";
|
const char STR_CPPM[] = "\x05""Multi""CPPM\0";
|
||||||
#define NBR_CPPM 2
|
#define NBR_CPPM 2
|
||||||
#else
|
#else
|
||||||
const char STR_SUB_FRSKY_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX";
|
const char STR_SUB_FRSKY_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX";
|
||||||
|
const char STR_SUB_DSM_RX[] = "\x07""Multi\0 ""CloneTX""EraseTX";
|
||||||
#define FRCPPM 3
|
#define FRCPPM 3
|
||||||
|
#define DSMCPPM 3
|
||||||
#define STR_CPPM NO_SUBTYPE
|
#define STR_CPPM NO_SUBTYPE
|
||||||
#define NBR_CPPM 0
|
#define NBR_CPPM 0
|
||||||
#endif
|
#endif
|
||||||
@@ -209,6 +232,9 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
#if defined(MULTI_CONFIG_INO)
|
#if defined(MULTI_CONFIG_INO)
|
||||||
{PROTO_CONFIG, STR_CONFIG, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, 0, CONFIG_init, CONFIG_callback },
|
{PROTO_CONFIG, STR_CONFIG, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, 0, CONFIG_init, CONFIG_callback },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(ARES_CC2500_INO)
|
||||||
|
{PROTO_ARES, STR_ARES, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_CC2500, ARES_init, ARES_callback },
|
||||||
|
#endif
|
||||||
#if defined(ASSAN_NRF24L01_INO)
|
#if defined(ASSAN_NRF24L01_INO)
|
||||||
{PROTO_ASSAN, STR_ASSAN, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, ASSAN_init, ASSAN_callback },
|
{PROTO_ASSAN, STR_ASSAN, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, ASSAN_init, ASSAN_callback },
|
||||||
#endif
|
#endif
|
||||||
@@ -218,6 +244,12 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
#if defined(BAYANG_RX_NRF24L01_INO)
|
#if defined(BAYANG_RX_NRF24L01_INO)
|
||||||
{PROTO_BAYANG_RX, STR_BAYANG_RX, STR_CPPM, NBR_CPPM, OPTION_NONE, 0, 0, SW_NRF, BAYANG_RX_init, BAYANG_RX_callback },
|
{PROTO_BAYANG_RX, STR_BAYANG_RX, STR_CPPM, NBR_CPPM, OPTION_NONE, 0, 0, SW_NRF, BAYANG_RX_init, BAYANG_RX_callback },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(BLUEFLY_CCNRF_INO)
|
||||||
|
{PROTO_BLUEFLY, STR_BLUEFLY, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, BLUEFLY_init, BLUEFLY_callback },
|
||||||
|
#endif
|
||||||
|
#if defined(BUMBLEB_CCNRF_INO)
|
||||||
|
{PROTO_BUMBLEB, STR_BUMBLEB, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, BUMBLEB_init, BUMBLEB_callback },
|
||||||
|
#endif
|
||||||
#if defined(BUGS_A7105_INO)
|
#if defined(BUGS_A7105_INO)
|
||||||
{PROTO_BUGS, STR_BUGS, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_A7105, BUGS_init, BUGS_callback },
|
{PROTO_BUGS, STR_BUGS, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_A7105, BUGS_init, BUGS_callback },
|
||||||
#endif
|
#endif
|
||||||
@@ -246,10 +278,10 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
{PROTO_DM002, STR_DM002, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, DM002_init, DM002_callback },
|
{PROTO_DM002, STR_DM002, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, DM002_init, DM002_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(DSM_CYRF6936_INO)
|
#if defined(DSM_CYRF6936_INO)
|
||||||
{PROTO_DSM, STR_DSM, STR_SUBTYPE_DSM, 6, OPTION_MAXTHR, 0, 1, SW_CYRF, DSM_init, DSM_callback },
|
{PROTO_DSM, STR_DSM, STR_SUBTYPE_DSM, 7, OPTION_MAXTHR, 0, 1, SW_CYRF, DSM_init, DSM_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(DSM_RX_CYRF6936_INO)
|
#if defined(DSM_RX_CYRF6936_INO)
|
||||||
{PROTO_DSM_RX, STR_DSM_RX, STR_CPPM, NBR_CPPM, OPTION_NONE, 0, 1, SW_CYRF, DSM_RX_init, DSM_RX_callback },
|
{PROTO_DSM_RX, STR_DSM_RX, STR_SUB_DSM_RX, DSMCPPM, OPTION_NONE, 0, 1, SW_CYRF, DSM_RX_init, DSM_RX_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(E010R5_CYRF6936_INO)
|
#if defined(E010R5_CYRF6936_INO)
|
||||||
{PROTO_E010R5, STR_E010R5, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CYRF, E010R5_init, E010R5_callback },
|
{PROTO_E010R5, STR_E010R5, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CYRF, E010R5_init, E010R5_callback },
|
||||||
@@ -266,6 +298,9 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
#if defined(E129_CYRF6936_INO)
|
#if defined(E129_CYRF6936_INO)
|
||||||
{PROTO_E129, STR_E129, STR_SUBTYPE_E129, 2, OPTION_NONE, 0, 0, SW_CYRF, E129_init, E129_callback },
|
{PROTO_E129, STR_E129, STR_SUBTYPE_E129, 2, OPTION_NONE, 0, 0, SW_CYRF, E129_init, E129_callback },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(EAZYRC_NRF24L01_INO)
|
||||||
|
{PROTO_EAZYRC, STR_EAZYRC, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, EAZYRC_init, EAZYRC_callback },
|
||||||
|
#endif
|
||||||
#if defined(ESKY_NRF24L01_INO)
|
#if defined(ESKY_NRF24L01_INO)
|
||||||
{PROTO_ESKY, STR_ESKY, STR_SUBTYPE_ESKY, 2, OPTION_NONE, 0, 1, SW_NRF, ESKY_init, ESKY_callback },
|
{PROTO_ESKY, STR_ESKY, STR_SUBTYPE_ESKY, 2, OPTION_NONE, 0, 1, SW_NRF, ESKY_init, ESKY_callback },
|
||||||
#endif
|
#endif
|
||||||
@@ -279,13 +314,13 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
{PROTO_FLYSKY, STR_FLYSKY, STR_SUBTYPE_FLYSKY, 5, OPTION_NONE, 0, 1, SW_A7105, FLYSKY_init, FLYSKY_callback },
|
{PROTO_FLYSKY, STR_FLYSKY, STR_SUBTYPE_FLYSKY, 5, OPTION_NONE, 0, 1, SW_A7105, FLYSKY_init, FLYSKY_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(AFHDS2A_A7105_INO)
|
#if defined(AFHDS2A_A7105_INO)
|
||||||
{PROTO_AFHDS2A, STR_AFHDS2A, STR_SUBTYPE_AFHDS2A, 8, OPTION_SRVFREQ, 1, 1, SW_A7105, AFHDS2A_init, AFHDS2A_callback },
|
{PROTO_AFHDS2A, STR_AFHDS2A, STR_SUBTYPE_AFHDS2A, 7, OPTION_SRVFREQ, 1, 1, SW_A7105, AFHDS2A_init, AFHDS2A_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(AFHDS2A_RX_A7105_INO)
|
#if defined(AFHDS2A_RX_A7105_INO)
|
||||||
{PROTO_AFHDS2A_RX, STR_AFHDS2A_RX,STR_CPPM, NBR_CPPM, OPTION_NONE, 0, 0, SW_A7105, AFHDS2A_RX_init, AFHDS2A_RX_callback },
|
{PROTO_AFHDS2A_RX, STR_AFHDS2A_RX,STR_CPPM, NBR_CPPM, OPTION_NONE, 0, 0, SW_A7105, AFHDS2A_RX_init, AFHDS2A_RX_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(FQ777_NRF24L01_INO)
|
#if defined(FQ777_NRF24L01_INO)
|
||||||
{PROTO_FQ777, STR_FQ777, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, FQ777_init, FQ777_callback },
|
{PROTO_FQ777, STR_FQ777, STR_SUBTYPE_FQ777, 2, OPTION_NONE, 0, 0, SW_NRF, FQ777_init, FQ777_callback },
|
||||||
#endif
|
#endif
|
||||||
//OpenTX 2.3.x issue: DO NOT CHANGE ORDER below
|
//OpenTX 2.3.x issue: DO NOT CHANGE ORDER below
|
||||||
#if defined(FRSKY_RX_CC2500_INO)
|
#if defined(FRSKY_RX_CC2500_INO)
|
||||||
@@ -316,7 +351,7 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
{PROTO_FUTABA, STR_FUTABA, STR_SUBTYPE_FUTABA, 1, OPTION_RFTUNE, 1, 1, SW_CC2500, SFHSS_init, SFHSS_callback },
|
{PROTO_FUTABA, STR_FUTABA, STR_SUBTYPE_FUTABA, 1, OPTION_RFTUNE, 1, 1, SW_CC2500, SFHSS_init, SFHSS_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(FX_NRF24L01_INO)
|
#if defined(FX_NRF24L01_INO)
|
||||||
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 3, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
|
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 7, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(FY326_NRF24L01_INO)
|
#if defined(FY326_NRF24L01_INO)
|
||||||
{PROTO_FY326, STR_FY326, STR_SUBTYPE_FY326, 2, OPTION_NONE, 0, 0, SW_NRF, FY326_init, FY326_callback },
|
{PROTO_FY326, STR_FY326, STR_SUBTYPE_FY326, 2, OPTION_NONE, 0, 0, SW_NRF, FY326_init, FY326_callback },
|
||||||
@@ -327,6 +362,9 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
#if defined(GW008_NRF24L01_INO)
|
#if defined(GW008_NRF24L01_INO)
|
||||||
{PROTO_GW008, STR_GW008, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, GW008_init, GW008_callback },
|
{PROTO_GW008, STR_GW008, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, GW008_init, GW008_callback },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(H36_NRF24L01_INO)
|
||||||
|
{PROTO_H36, STR_H36, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, H36_init, H36_callback },
|
||||||
|
#endif
|
||||||
#if defined(H8_3D_NRF24L01_INO)
|
#if defined(H8_3D_NRF24L01_INO)
|
||||||
{PROTO_H8_3D, STR_H8_3D, STR_SUBTYPE_H83D, 4, OPTION_NONE, 0, 0, SW_NRF, H8_3D_init, H8_3D_callback },
|
{PROTO_H8_3D, STR_H8_3D, STR_SUBTYPE_H83D, 4, OPTION_NONE, 0, 0, SW_NRF, H8_3D_init, H8_3D_callback },
|
||||||
#endif
|
#endif
|
||||||
@@ -340,7 +378,7 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
{PROTO_HITEC, STR_HITEC, STR_SUBTYPE_HITEC, 3, OPTION_RFTUNE, 0, 0, SW_CC2500, HITEC_init, HITEC_callback },
|
{PROTO_HITEC, STR_HITEC, STR_SUBTYPE_HITEC, 3, OPTION_RFTUNE, 0, 0, SW_CC2500, HITEC_init, HITEC_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(HONTAI_NRF24L01_INO)
|
#if defined(HONTAI_NRF24L01_INO)
|
||||||
{PROTO_HONTAI, STR_HONTAI, STR_SUBTYPE_HONTAI, 4, OPTION_NONE, 0, 0, SW_NRF, HONTAI_init, HONTAI_callback },
|
{PROTO_HONTAI, STR_HONTAI, STR_SUBTYPE_HONTAI, 5, OPTION_NONE, 0, 0, SW_NRF, HONTAI_init, HONTAI_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(HOTT_CC2500_INO)
|
#if defined(HOTT_CC2500_INO)
|
||||||
{PROTO_HOTT, STR_HOTT, STR_SUBTYPE_HOTT, 2, OPTION_RFTUNE, 1, 0, SW_CC2500, HOTT_init, HOTT_callback },
|
{PROTO_HOTT, STR_HOTT, STR_SUBTYPE_HOTT, 2, OPTION_RFTUNE, 1, 0, SW_CC2500, HOTT_init, HOTT_callback },
|
||||||
@@ -354,12 +392,18 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
#if defined(J6PRO_CYRF6936_INO)
|
#if defined(J6PRO_CYRF6936_INO)
|
||||||
{PROTO_J6PRO, STR_J6PRO, NO_SUBTYPE, 0, OPTION_NONE, 0, 1, SW_CYRF, J6PRO_init, J6PRO_callback },
|
{PROTO_J6PRO, STR_J6PRO, NO_SUBTYPE, 0, OPTION_NONE, 0, 1, SW_CYRF, J6PRO_init, J6PRO_callback },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(JIABAILE_NRF24L01_INO)
|
||||||
|
{PROTO_JIABAILE, STR_JIABAILE, STR_SUBTYPE_JIABAILE, 2, OPTION_NONE, 0, 0, SW_NRF, JIABAILE_init, JIABAILE_callback },
|
||||||
|
#endif
|
||||||
#if defined(JJRC345_NRF24L01_INO)
|
#if defined(JJRC345_NRF24L01_INO)
|
||||||
{PROTO_JJRC345, STR_JJRC345, STR_SUBTYPE_JJRC345, 2, OPTION_NONE, 0, 0, SW_NRF, JJRC345_init, JJRC345_callback },
|
{PROTO_JJRC345, STR_JJRC345, STR_SUBTYPE_JJRC345, 2, OPTION_NONE, 0, 0, SW_NRF, JJRC345_init, JJRC345_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(JOYSWAY_A7105_INO)
|
#if defined(JOYSWAY_A7105_INO)
|
||||||
{PROTO_JOYSWAY, STR_JOYSWAY, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_A7105, JOYSWAY_init, JOYSWAY_callback },
|
{PROTO_JOYSWAY, STR_JOYSWAY, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_A7105, JOYSWAY_init, JOYSWAY_callback },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(KAMTOM_NRF24L01_INO)
|
||||||
|
{PROTO_KAMTOM, STR_KAMTOM, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, KAMTOM_init, KAMTOM_callback },
|
||||||
|
#endif
|
||||||
#if defined(KF606_CCNRF_INO)
|
#if defined(KF606_CCNRF_INO)
|
||||||
{PROTO_KF606, STR_KF606, STR_SUBTYPE_KF606, 3, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback },
|
{PROTO_KF606, STR_KF606, STR_SUBTYPE_KF606, 3, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback },
|
||||||
#endif
|
#endif
|
||||||
@@ -372,6 +416,9 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
#if defined(KYOSHO2_NRF24L01_INO)
|
#if defined(KYOSHO2_NRF24L01_INO)
|
||||||
{PROTO_KYOSHO2, STR_KYOSHO2, STR_SUBTYPE_KYOSHO2, 1, OPTION_NONE, 0, 0, SW_NRF, KYOSHO2_init, KYOSHO2_callback },
|
{PROTO_KYOSHO2, STR_KYOSHO2, STR_SUBTYPE_KYOSHO2, 1, OPTION_NONE, 0, 0, SW_NRF, KYOSHO2_init, KYOSHO2_callback },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(KYOSHO3_CYRF6936_INO)
|
||||||
|
{PROTO_KYOSHO3, STR_KYOSHO3, STR_SUBTYPE_KYOSHO3, 1, OPTION_NONE, 0, 0, SW_CYRF, KYOSHO3_init, KYOSHO3_callback },
|
||||||
|
#endif
|
||||||
#if defined(LOLI_NRF24L01_INO)
|
#if defined(LOLI_NRF24L01_INO)
|
||||||
{PROTO_LOLI, STR_LOLI, NO_SUBTYPE, 0, OPTION_NONE, 1, 0, SW_NRF, LOLI_init, LOLI_callback },
|
{PROTO_LOLI, STR_LOLI, NO_SUBTYPE, 0, OPTION_NONE, 1, 0, SW_NRF, LOLI_init, LOLI_callback },
|
||||||
#endif
|
#endif
|
||||||
@@ -385,13 +432,13 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
{PROTO_MLINK, STR_MLINK, NO_SUBTYPE, 0, OPTION_NONE, 1, 0, SW_CYRF, MLINK_init, MLINK_callback },
|
{PROTO_MLINK, STR_MLINK, NO_SUBTYPE, 0, OPTION_NONE, 1, 0, SW_CYRF, MLINK_init, MLINK_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(MOULDKG_NRF24L01_INO)
|
#if defined(MOULDKG_NRF24L01_INO)
|
||||||
{PROTO_MOULDKG, STR_MOULDKG, STR_SUBTYPE_MOULKG, 2, OPTION_OPTION, 0, 0, SW_NRF, MOULDKG_init, MOULDKG_callback },
|
{PROTO_MOULDKG, STR_MOULDKG, STR_SUBTYPE_MOULDKG, 3, OPTION_OPTION, 0, 0, SW_NRF, MOULDKG_init, MOULDKG_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(MT99XX_CCNRF_INO)
|
#if defined(MT99XX_CCNRF_INO)
|
||||||
{PROTO_MT99XX, STR_MT99XX, STR_SUBTYPE_MT99, 8, OPTION_NONE, 0, 0, SW_NRF, MT99XX_init, MT99XX_callback },
|
{PROTO_MT99XX, STR_MT99XX, STR_SUBTYPE_MT99, 8, OPTION_NONE, 0, 0, SW_NRF, MT99XX_init, MT99XX_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(MT99XX_CCNRF_INO)
|
#if defined(MT99XX_CCNRF_INO)
|
||||||
{PROTO_MT99XX2, STR_MT99XX2, STR_SUBTYPE_MT992, 1, OPTION_NONE, 0, 0, SW_NRF, MT99XX_init, MT99XX_callback },
|
{PROTO_MT99XX2, STR_MT99XX2, STR_SUBTYPE_MT992, 2, OPTION_NONE, 0, 0, SW_NRF, MT99XX_init, MT99XX_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(NCC1701_NRF24L01_INO)
|
#if defined(NCC1701_NRF24L01_INO)
|
||||||
{PROTO_NCC1701, STR_NCC1701, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, NCC_init, NCC_callback },
|
{PROTO_NCC1701, STR_NCC1701, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, NCC_init, NCC_callback },
|
||||||
@@ -418,10 +465,10 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
{PROTO_Q90C, STR_Q90C, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, Q90C_init, Q90C_callback },
|
{PROTO_Q90C, STR_Q90C, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, Q90C_init, Q90C_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(RLINK_CC2500_INO)
|
#if defined(RLINK_CC2500_INO)
|
||||||
{PROTO_RLINK, STR_RLINK, STR_SUBTYPE_RLINK, 3, OPTION_RFTUNE, 0, 0, SW_CC2500, RLINK_init, RLINK_callback },
|
{PROTO_RLINK, STR_RLINK, STR_SUBTYPE_RLINK, 5, OPTION_RFTUNE, 0, 0, SW_CC2500, RLINK_init, RLINK_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(REALACC_NRF24L01_INO)
|
#if defined(REALACC_NRF24L01_INO)
|
||||||
{PROTO_REALACC, STR_REALACC, STR_SUBTYPE_REALACC, 1, OPTION_NONE, 0, 0, SW_NRF, REALACC_init, REALACC_callback },
|
{PROTO_REALACC, STR_REALACC, STR_SUBTYPE_REALACC, 2, OPTION_NONE, 0, 0, SW_NRF, REALACC_init, REALACC_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(REDPINE_CC2500_INO)
|
#if defined(REDPINE_CC2500_INO)
|
||||||
{PROTO_REDPINE, STR_REDPINE, STR_SUBTYPE_REDPINE, 2, OPTION_RFTUNE, 0, 0, SW_CC2500, REDPINE_init, REDPINE_callback },
|
{PROTO_REDPINE, STR_REDPINE, STR_SUBTYPE_REDPINE, 2, OPTION_RFTUNE, 0, 0, SW_CC2500, REDPINE_init, REDPINE_callback },
|
||||||
@@ -432,23 +479,29 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
#if defined(SCORPIO_CYRF6936_INO)
|
#if defined(SCORPIO_CYRF6936_INO)
|
||||||
{PROTO_SCORPIO, STR_SCORPIO, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CYRF, SCORPIO_init, SCORPIO_callback },
|
{PROTO_SCORPIO, STR_SCORPIO, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CYRF, SCORPIO_init, SCORPIO_callback },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(SGF22_NRF24L01_INO)
|
||||||
|
{PROTO_SGF22, STR_SGF22, STR_SUBTYPE_SGF22, 4, OPTION_NONE, 0, 0, SW_NRF, SGF22_init, SGF22_callback },
|
||||||
|
#endif
|
||||||
#if defined(SHENQI_NRF24L01_INO)
|
#if defined(SHENQI_NRF24L01_INO)
|
||||||
{PROTO_SHENQI, STR_SHENQI, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, SHENQI_init, SHENQI_callback },
|
{PROTO_SHENQI, STR_SHENQI, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, SHENQI_init, SHENQI_callback },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(SHENQI2_NRF24L01_INO)
|
||||||
|
{PROTO_SHENQI2, STR_SHENQI2, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, SHENQI2_init, SHENQI2_callback },
|
||||||
|
#endif
|
||||||
#if defined(SKYARTEC_CC2500_INO)
|
#if defined(SKYARTEC_CC2500_INO)
|
||||||
{PROTO_SKYARTEC, STR_SKYARTEC, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 1, SW_CC2500, SKYARTEC_init, SKYARTEC_callback },
|
{PROTO_SKYARTEC, STR_SKYARTEC, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 1, SW_CC2500, SKYARTEC_init, SKYARTEC_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(SLT_CCNRF_INO)
|
#if defined(SLT_CCNRF_INO)
|
||||||
{PROTO_SLT, STR_SLT, STR_SUBTYPE_SLT, 5, OPTION_RFTUNE, 0, 1, SW_NRF, SLT_init, SLT_callback },
|
{PROTO_SLT, STR_SLT, STR_SUBTYPE_SLT, 8, OPTION_RFTUNE, 0, 1, SW_NRF, SLT_init, SLT_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(SYMAX_NRF24L01_INO)
|
#if defined(SYMAX_NRF24L01_INO)
|
||||||
{PROTO_SYMAX, STR_SYMAX, STR_SUBTYPE_SYMAX, 2, OPTION_NONE, 0, 0, SW_NRF, SYMAX_init, SYMAX_callback },
|
{PROTO_SYMAX, STR_SYMAX, STR_SUBTYPE_SYMAX, 2, OPTION_NONE, 0, 0, SW_NRF, SYMAX_init, SYMAX_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(TIGER_NRF24L01_INO)
|
|
||||||
{PROTO_TIGER, STR_TIGER, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, TIGER_init, TIGER_callback },
|
|
||||||
#endif
|
|
||||||
#if defined(TRAXXAS_CYRF6936_INO)
|
#if defined(TRAXXAS_CYRF6936_INO)
|
||||||
{PROTO_TRAXXAS, STR_TRAXXAS, STR_SUBTYPE_TRAXXAS, 1, OPTION_NONE, 0, 0, SW_CYRF, TRAXXAS_init, TRAXXAS_callback },
|
{PROTO_TRAXXAS, STR_TRAXXAS, STR_SUBTYPE_TRAXXAS, 2, OPTION_NONE, 0, 0, SW_CYRF, TRAXXAS_init, TRAXXAS_callback },
|
||||||
|
#endif
|
||||||
|
#if defined(UDIRC_CCNRF_INO)
|
||||||
|
{PROTO_UDIRC, STR_UDIRC, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, UDIRC_init, UDIRC_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(V2X2_NRF24L01_INO)
|
#if defined(V2X2_NRF24L01_INO)
|
||||||
{PROTO_V2X2, STR_V2X2, STR_SUBTYPE_V2X2, 3, OPTION_NONE, 0, 0, SW_NRF, V2X2_init, V2X2_callback },
|
{PROTO_V2X2, STR_V2X2, STR_SUBTYPE_V2X2, 3, OPTION_NONE, 0, 0, SW_NRF, V2X2_init, V2X2_callback },
|
||||||
@@ -459,9 +512,6 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
#if defined(V911S_CCNRF_INO)
|
#if defined(V911S_CCNRF_INO)
|
||||||
{PROTO_V911S, STR_V911S, STR_SUBTYPE_V911S, 2, OPTION_RFTUNE, 0, 0, SW_NRF, V911S_init, V911S_callback },
|
{PROTO_V911S, STR_V911S, STR_SUBTYPE_V911S, 2, OPTION_RFTUNE, 0, 0, SW_NRF, V911S_init, V911S_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(WK2x01_CYRF6936_INO)
|
|
||||||
{PROTO_WK2x01, STR_WK2x01, STR_SUBTYPE_WK2x01, 6, OPTION_NONE, 1, 1, SW_CYRF, WK_init, WK_callback },
|
|
||||||
#endif
|
|
||||||
#if defined(WFLY_CYRF6936_INO)
|
#if defined(WFLY_CYRF6936_INO)
|
||||||
{PROTO_WFLY, STR_WFLY, STR_SUBTYPE_WFLY, 1, OPTION_NONE, 1, 0, SW_CYRF, WFLY_init, WFLY_callback },
|
{PROTO_WFLY, STR_WFLY, STR_SUBTYPE_WFLY, 1, OPTION_NONE, 1, 0, SW_CYRF, WFLY_init, WFLY_callback },
|
||||||
#endif
|
#endif
|
||||||
@@ -469,18 +519,33 @@ const mm_protocol_definition multi_protocols[] = {
|
|||||||
{PROTO_WFLY2, STR_WFLY2, STR_SUBTYPE_WFLY2, 1, OPTION_OPTION, 1, 0, SW_A7105, WFLY2_init, WFLY2_callback },
|
{PROTO_WFLY2, STR_WFLY2, STR_SUBTYPE_WFLY2, 1, OPTION_OPTION, 1, 0, SW_A7105, WFLY2_init, WFLY2_callback },
|
||||||
// {PROTO_WFLY2, STR_WFLY2, STR_SUBTYPE_WFLY2, 1, OPTION_WBUS, 1, 0, SW_A7105, WFLY2_init, WFLY2_callback },// crash OpenTX...
|
// {PROTO_WFLY2, STR_WFLY2, STR_SUBTYPE_WFLY2, 1, OPTION_WBUS, 1, 0, SW_A7105, WFLY2_init, WFLY2_callback },// crash OpenTX...
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(WK2x01_CYRF6936_INO)
|
||||||
|
{PROTO_WK2x01, STR_WK2x01, STR_SUBTYPE_WK2x01, 6, OPTION_NONE, 1, 1, SW_CYRF, WK_init, WK_callback },
|
||||||
|
#endif
|
||||||
|
#if defined(WL91X_CCNRF_INO)
|
||||||
|
{PROTO_WL91X, STR_WL91X, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, WL91X_init, WL91X_callback },
|
||||||
|
#endif
|
||||||
|
#if defined(WPL_NRF24L01_INO)
|
||||||
|
{PROTO_WPL, STR_WPL, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, WPL_init, WPL_callback },
|
||||||
|
#endif
|
||||||
#if defined(XERALL_NRF24L01_INO)
|
#if defined(XERALL_NRF24L01_INO)
|
||||||
{PROTO_XERALL, STR_XERALL, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, XERALL_init, XERALL_callback },
|
{PROTO_XERALL, STR_XERALL, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, XERALL_init, XERALL_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(XK_CCNRF_INO)
|
#if defined(XK_CCNRF_INO)
|
||||||
{PROTO_XK, STR_XK, STR_SUBTYPE_XK, 2, OPTION_RFTUNE, 0, 0, SW_NRF, XK_init, XK_callback },
|
{PROTO_XK, STR_XK, STR_SUBTYPE_XK, 3, OPTION_RFTUNE, 0, 0, SW_NRF, XK_init, XK_callback },
|
||||||
|
#endif
|
||||||
|
#if defined(XK2_CCNRF_INO)
|
||||||
|
{PROTO_XK2, STR_XK2, STR_SUBTYPE_XK2, 2, OPTION_RFTUNE, 0, 0, SW_NRF, XK2_init, XK2_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(XN297DUMP_NRF24L01_INO)
|
#if defined(XN297DUMP_NRF24L01_INO)
|
||||||
{PROTO_XN297DUMP, STR_XN297DUMP, STR_SUBTYPE_XN297DUMP, 6, OPTION_RFCHAN, 0, 0, SW_NRF, XN297Dump_init, XN297Dump_callback },
|
{PROTO_XN297DUMP, STR_XN297DUMP, STR_SUBTYPE_XN297DUMP, 7, OPTION_RFCHAN, 0, 0, SW_NRF, XN297Dump_init, XN297Dump_callback },
|
||||||
#endif
|
#endif
|
||||||
#if defined(YD717_NRF24L01_INO)
|
#if defined(YD717_NRF24L01_INO)
|
||||||
{PROTO_YD717, STR_YD717, STR_SUBTYPE_YD717, 5, OPTION_NONE, 0, 0, SW_NRF, YD717_init, YD717_callback },
|
{PROTO_YD717, STR_YD717, STR_SUBTYPE_YD717, 5, OPTION_NONE, 0, 0, SW_NRF, YD717_init, YD717_callback },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(YUXIANG_NRF24L01_INO)
|
||||||
|
{PROTO_YUXIANG, STR_YUXIANG, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, YUXIANG_init, YUXIANG_callback },
|
||||||
|
#endif
|
||||||
#if defined(ZSX_NRF24L01_INO)
|
#if defined(ZSX_NRF24L01_INO)
|
||||||
{PROTO_ZSX, STR_ZSX, STR_SUBTYPE_ZSX, 1, OPTION_NONE, 0, 0, SW_NRF, ZSX_init, ZSX_callback },
|
{PROTO_ZSX, STR_ZSX, STR_SUBTYPE_ZSX, 1, OPTION_NONE, 0, 0, SW_NRF, ZSX_init, ZSX_callback },
|
||||||
#endif
|
#endif
|
||||||
@@ -535,7 +600,10 @@ uint16_t PROTOLIST_callback()
|
|||||||
Serial_write(multi_protocols[option].protocol);
|
Serial_write(multi_protocols[option].protocol);
|
||||||
//Protocol name
|
//Protocol name
|
||||||
for(uint8_t i=0;i<proto_len;i++)
|
for(uint8_t i=0;i<proto_len;i++)
|
||||||
|
{
|
||||||
Serial_write(multi_protocols[option].ProtoString[i]);
|
Serial_write(multi_protocols[option].ProtoString[i]);
|
||||||
|
//debug("%c",multi_protocols[option].ProtoString[i]);
|
||||||
|
}
|
||||||
//Flags
|
//Flags
|
||||||
uint8_t flags=0;
|
uint8_t flags=0;
|
||||||
#ifdef FAILSAFE_ENABLE
|
#ifdef FAILSAFE_ENABLE
|
||||||
@@ -545,16 +613,21 @@ uint16_t PROTOLIST_callback()
|
|||||||
if(multi_protocols[option].chMap)
|
if(multi_protocols[option].chMap)
|
||||||
flags |= 0x02; //Disable_ch_mapping supported
|
flags |= 0x02; //Disable_ch_mapping supported
|
||||||
Serial_write( flags | (multi_protocols[option].optionType<<4)); // flags && option type
|
Serial_write( flags | (multi_protocols[option].optionType<<4)); // flags && option type
|
||||||
|
//debug(" Flag=%02X",flags | (multi_protocols[option].optionType<<4));
|
||||||
//Number of sub protocols
|
//Number of sub protocols
|
||||||
Serial_write(nbr_sub);
|
Serial_write(nbr_sub);
|
||||||
|
//debug(" NSub=%02X ",nbr_sub);
|
||||||
if(nbr_sub !=0 )
|
if(nbr_sub !=0 )
|
||||||
{//Sub protocols length and texts
|
{//Sub protocols length and texts
|
||||||
for(uint8_t i=0;i<=nbr_sub*sub_len;i++)
|
for(uint8_t i=0;i<=nbr_sub*sub_len;i++)
|
||||||
|
{
|
||||||
Serial_write(multi_protocols[option].SubProtoString[i]);
|
Serial_write(multi_protocols[option].SubProtoString[i]);
|
||||||
|
//debug("%c",multi_protocols[option].SubProtoString[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//debugln("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1000;
|
return 1000;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
//******************
|
//******************
|
||||||
#define VERSION_MAJOR 1
|
#define VERSION_MAJOR 1
|
||||||
#define VERSION_MINOR 3
|
#define VERSION_MINOR 3
|
||||||
#define VERSION_REVISION 3
|
#define VERSION_REVISION 4
|
||||||
#define VERSION_PATCH_LEVEL 27
|
#define VERSION_PATCH_LEVEL 63
|
||||||
|
|
||||||
#define MODE_SERIAL 0
|
#define MODE_SERIAL 0
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ enum PROTOCOLS
|
|||||||
PROTO_NCC1701 = 44, // =>NRF24L01
|
PROTO_NCC1701 = 44, // =>NRF24L01
|
||||||
PROTO_E01X = 45, // =>CYRF6936
|
PROTO_E01X = 45, // =>CYRF6936
|
||||||
PROTO_V911S = 46, // =>NRF24L01
|
PROTO_V911S = 46, // =>NRF24L01
|
||||||
PROTO_GD00X = 47, // =>NRF24L01
|
PROTO_GD00X = 47, // =>CC2500 & NRF24L01
|
||||||
PROTO_V761 = 48, // =>NRF24L01
|
PROTO_V761 = 48, // =>NRF24L01
|
||||||
PROTO_KF606 = 49, // =>NRF24L01
|
PROTO_KF606 = 49, // =>NRF24L01
|
||||||
PROTO_REDPINE = 50, // =>CC2500
|
PROTO_REDPINE = 50, // =>CC2500
|
||||||
@@ -89,7 +89,7 @@ enum PROTOCOLS
|
|||||||
PROTO_FX = 58, // =>NRF24L01
|
PROTO_FX = 58, // =>NRF24L01
|
||||||
PROTO_BAYANG_RX = 59, // =>NRF24L01
|
PROTO_BAYANG_RX = 59, // =>NRF24L01
|
||||||
PROTO_PELIKAN = 60, // =>A7105
|
PROTO_PELIKAN = 60, // =>A7105
|
||||||
PROTO_TIGER = 61, // =>NRF24L01
|
PROTO_EAZYRC = 61, // =>NRF24L01
|
||||||
PROTO_XK = 62, // =>NRF24L01
|
PROTO_XK = 62, // =>NRF24L01
|
||||||
PROTO_XN297DUMP = 63, // =>NRF24L01
|
PROTO_XN297DUMP = 63, // =>NRF24L01
|
||||||
PROTO_FRSKYX2 = 64, // =>CC2500
|
PROTO_FRSKYX2 = 64, // =>CC2500
|
||||||
@@ -122,6 +122,20 @@ enum PROTOCOLS
|
|||||||
PROTO_MT99XX2 = 92, // =>NRF24L01, extension of MT99XX protocol
|
PROTO_MT99XX2 = 92, // =>NRF24L01, extension of MT99XX protocol
|
||||||
PROTO_KYOSHO2 = 93, // =>NRF24L01
|
PROTO_KYOSHO2 = 93, // =>NRF24L01
|
||||||
PROTO_SCORPIO = 94, // =>CYRF6936
|
PROTO_SCORPIO = 94, // =>CYRF6936
|
||||||
|
PROTO_BLUEFLY = 95, // =>CC2500 & NRF24L01
|
||||||
|
PROTO_BUMBLEB = 96, // =>CC2500 & NRF24L01
|
||||||
|
PROTO_SGF22 = 97, // =>NRF24L01
|
||||||
|
PROTO_KYOSHO3 = 98, // =>CYRF6936
|
||||||
|
PROTO_XK2 = 99, // =>CC2500 & NRF24L01
|
||||||
|
PROTO_YUXIANG = 100, // =>NRF24L01
|
||||||
|
PROTO_UDIRC = 101, // =>CC2500 & NRF24L01
|
||||||
|
PROTO_JIABAILE = 102, // =>NRF24L01
|
||||||
|
PROTO_H36 = 103, // =>NRF24L01
|
||||||
|
PROTO_KAMTOM = 104, // =>NRF24L01
|
||||||
|
PROTO_SHENQI2 = 105, // =>NRF24L01
|
||||||
|
PROTO_WL91X = 106, // =>CC2500 & NRF24L01
|
||||||
|
PROTO_WPL = 107, // =>NRF24L01
|
||||||
|
PROTO_ARES = 108, // =>CC2500
|
||||||
|
|
||||||
PROTO_NANORF = 126, // =>NRF24L01
|
PROTO_NANORF = 126, // =>NRF24L01
|
||||||
PROTO_TEST = 127, // =>CC2500
|
PROTO_TEST = 127, // =>CC2500
|
||||||
@@ -147,14 +161,13 @@ enum Hubsan
|
|||||||
};
|
};
|
||||||
enum AFHDS2A
|
enum AFHDS2A
|
||||||
{
|
{
|
||||||
PWM_IBUS = 0,
|
PWM_IBUS = 0,
|
||||||
PPM_IBUS = 1,
|
PPM_IBUS = 1,
|
||||||
PWM_SBUS = 2,
|
PWM_SBUS = 2,
|
||||||
PPM_SBUS = 3,
|
PPM_SBUS = 3,
|
||||||
PWM_IB16 = 4,
|
AFHDS2A_GYRO_OFF = 4,
|
||||||
PPM_IB16 = 5,
|
AFHDS2A_GYRO_ON = 5,
|
||||||
PWM_SB16 = 6,
|
AFHDS2A_GYRO_ON_REV = 6,
|
||||||
PPM_SB16 = 7,
|
|
||||||
};
|
};
|
||||||
enum Hisky
|
enum Hisky
|
||||||
{
|
{
|
||||||
@@ -169,6 +182,13 @@ enum DSM
|
|||||||
DSMX_2F = 3,
|
DSMX_2F = 3,
|
||||||
DSM_AUTO = 4,
|
DSM_AUTO = 4,
|
||||||
DSMR = 5,
|
DSMR = 5,
|
||||||
|
DSM2_SFC = 6,
|
||||||
|
};
|
||||||
|
enum DSM_RX
|
||||||
|
{
|
||||||
|
DSM_RX = 0,
|
||||||
|
DSM_CLONE = 1,
|
||||||
|
DSM_ERASE = 2,
|
||||||
};
|
};
|
||||||
enum YD717
|
enum YD717
|
||||||
{
|
{
|
||||||
@@ -190,11 +210,14 @@ enum SYMAX
|
|||||||
};
|
};
|
||||||
enum SLT
|
enum SLT
|
||||||
{
|
{
|
||||||
SLT_V1 = 0,
|
SLT_V1 = 0,
|
||||||
SLT_V2 = 1,
|
SLT_V2 = 1,
|
||||||
Q100 = 2,
|
Q100 = 2,
|
||||||
Q200 = 3,
|
Q200 = 3,
|
||||||
MR100 = 4,
|
MR100 = 4,
|
||||||
|
SLT_V1_4 = 5,
|
||||||
|
RF_SIM = 6,
|
||||||
|
SLT6TX = 7,
|
||||||
};
|
};
|
||||||
enum CX10
|
enum CX10
|
||||||
{
|
{
|
||||||
@@ -241,7 +264,8 @@ enum MT99XX
|
|||||||
};
|
};
|
||||||
enum MT99XX2
|
enum MT99XX2
|
||||||
{
|
{
|
||||||
PA18 = 0,
|
PA18 = 0,
|
||||||
|
SU35 = 1,
|
||||||
};
|
};
|
||||||
enum MJXQ
|
enum MJXQ
|
||||||
{
|
{
|
||||||
@@ -269,10 +293,11 @@ enum FRSKYX
|
|||||||
};
|
};
|
||||||
enum HONTAI
|
enum HONTAI
|
||||||
{
|
{
|
||||||
HONTAI = 0,
|
HONTAI = 0,
|
||||||
JJRCX1 = 1,
|
JJRCX1 = 1,
|
||||||
X5C1 = 2,
|
X5C1 = 2,
|
||||||
FQ777_951 =3,
|
FQ777_951 = 3,
|
||||||
|
HONTAI_XKK170 = 4,
|
||||||
};
|
};
|
||||||
enum V2X2
|
enum V2X2
|
||||||
{
|
{
|
||||||
@@ -350,7 +375,8 @@ enum REDPINE
|
|||||||
};
|
};
|
||||||
enum TRAXXAS
|
enum TRAXXAS
|
||||||
{
|
{
|
||||||
RX6519 = 0,
|
TRAXXAS_TQ2 = 0,
|
||||||
|
TRAXXAS_TQ1 = 1,
|
||||||
};
|
};
|
||||||
enum ESKY150
|
enum ESKY150
|
||||||
{
|
{
|
||||||
@@ -366,6 +392,7 @@ enum XK
|
|||||||
{
|
{
|
||||||
X450 = 0,
|
X450 = 0,
|
||||||
X420 = 1,
|
X420 = 1,
|
||||||
|
XK_CARS = 2,
|
||||||
};
|
};
|
||||||
enum XN297DUMP
|
enum XN297DUMP
|
||||||
{
|
{
|
||||||
@@ -375,6 +402,7 @@ enum XN297DUMP
|
|||||||
XN297DUMP_AUTO = 3,
|
XN297DUMP_AUTO = 3,
|
||||||
XN297DUMP_NRF = 4,
|
XN297DUMP_NRF = 4,
|
||||||
XN297DUMP_CC2500 = 5,
|
XN297DUMP_CC2500 = 5,
|
||||||
|
XN297DUMP_XN297 = 6,
|
||||||
};
|
};
|
||||||
enum FRSKY_R9
|
enum FRSKY_R9
|
||||||
{
|
{
|
||||||
@@ -392,6 +420,11 @@ enum ESKY
|
|||||||
ESKY_STD = 0,
|
ESKY_STD = 0,
|
||||||
ESKY_ET4 = 1,
|
ESKY_ET4 = 1,
|
||||||
};
|
};
|
||||||
|
enum FQ777
|
||||||
|
{
|
||||||
|
FQ777 = 0,
|
||||||
|
XBM37 = 1,
|
||||||
|
};
|
||||||
enum FRSKY_RX
|
enum FRSKY_RX
|
||||||
{
|
{
|
||||||
FRSKY_RX = 0,
|
FRSKY_RX = 0,
|
||||||
@@ -441,11 +474,19 @@ enum RLINK
|
|||||||
RLINK_SURFACE = 0,
|
RLINK_SURFACE = 0,
|
||||||
RLINK_AIR = 1,
|
RLINK_AIR = 1,
|
||||||
RLINK_DUMBORC = 2,
|
RLINK_DUMBORC = 2,
|
||||||
|
RLINK_RC4G = 3,
|
||||||
|
RLINK_DUMBORC_P = 4,
|
||||||
|
};
|
||||||
|
enum REALACC
|
||||||
|
{
|
||||||
|
REALACC_R11 = 0,
|
||||||
|
REALACC_WLV8TX = 1,
|
||||||
};
|
};
|
||||||
enum MOULDKG
|
enum MOULDKG
|
||||||
{
|
{
|
||||||
MOULDKG_ANALOG = 0,
|
MOULDKG_ANALOG4 = 0,
|
||||||
MOULDKG_DIGIT = 1,
|
MOULDKG_DIGIT4 = 1,
|
||||||
|
MOULDKG_ANALOG6 = 2,
|
||||||
};
|
};
|
||||||
enum KF606
|
enum KF606
|
||||||
{
|
{
|
||||||
@@ -463,6 +504,27 @@ enum FX
|
|||||||
FX816 = 0,
|
FX816 = 0,
|
||||||
FX620 = 1,
|
FX620 = 1,
|
||||||
FX9630 = 2,
|
FX9630 = 2,
|
||||||
|
FX_Q560 = 3,
|
||||||
|
FX_QF012 = 4,
|
||||||
|
FX_BM26 = 5,
|
||||||
|
FX_A570 = 6,
|
||||||
|
};
|
||||||
|
enum SGF22
|
||||||
|
{
|
||||||
|
SGF22_F22 = 0,
|
||||||
|
SGF22_F22S = 1,
|
||||||
|
SGF22_J20 = 2,
|
||||||
|
SGF22_CX10 = 3,
|
||||||
|
};
|
||||||
|
enum JIABAILE
|
||||||
|
{
|
||||||
|
JIABAILE_STD = 0,
|
||||||
|
JIABAILE_GYRO = 1,
|
||||||
|
};
|
||||||
|
enum XK2
|
||||||
|
{
|
||||||
|
XK2_X4 = 0,
|
||||||
|
XK2_P10 = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NONE 0
|
#define NONE 0
|
||||||
@@ -530,6 +592,7 @@ enum MultiPacketTypes
|
|||||||
MULTI_TELEMETRY_MLINK = 15,
|
MULTI_TELEMETRY_MLINK = 15,
|
||||||
MULTI_TELEMETRY_CONFIG = 16,
|
MULTI_TELEMETRY_CONFIG = 16,
|
||||||
MULTI_TELEMETRY_PROTO = 17,
|
MULTI_TELEMETRY_PROTO = 17,
|
||||||
|
MULTI_TELEMETRY_RLINK = 18,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Macros
|
// Macros
|
||||||
@@ -823,7 +886,11 @@ enum {
|
|||||||
#define FRSKYX2_CLONE_EEPROM_OFFSET 873 // (1) format + (3) TX ID, 4 bytes, end is 877
|
#define FRSKYX2_CLONE_EEPROM_OFFSET 873 // (1) format + (3) TX ID, 4 bytes, end is 877
|
||||||
#define DSM_RX_EEPROM_OFFSET 877 // (4) TX ID + format, 5 bytes, end is 882
|
#define DSM_RX_EEPROM_OFFSET 877 // (4) TX ID + format, 5 bytes, end is 882
|
||||||
#define MOULDKG_EEPROM_OFFSET 882 // RX ID, 3 bytes per model, end is 882+64*3=1074
|
#define MOULDKG_EEPROM_OFFSET 882 // RX ID, 3 bytes per model, end is 882+64*3=1074
|
||||||
//#define CONFIG_EEPROM_OFFSET 1074 // Current configuration of the multimodule
|
#define DSM_CLONE_EEPROM_OFFSET 1074 // (4) TX ID, (1) Initialized, end is 1079
|
||||||
|
#define TRAXXAS_EEPROM_OFFSET 1079 // RX ID and SOP index, 3 bytes per model id, end is 1079+192=1271
|
||||||
|
#define XK2_EEPROM_OFFSET 1271 // RX ID checksum, 1 byte per model, end is 1271+64=1335
|
||||||
|
#define JIABAILE_EEPROM_OFFSET 1335 // RX ID, 3 bytes per model, end is 1335+64*3=1527
|
||||||
|
//#define CONFIG_EEPROM_OFFSET 1527 // Current configuration of the multimodule
|
||||||
|
|
||||||
/* STM32 Flash Size */
|
/* STM32 Flash Size */
|
||||||
#ifndef DISABLE_FLASH_SIZE_CHECK
|
#ifndef DISABLE_FLASH_SIZE_CHECK
|
||||||
@@ -912,7 +979,6 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
|||||||
FX 58
|
FX 58
|
||||||
BAYANG_RX 59
|
BAYANG_RX 59
|
||||||
PELIKAN 60
|
PELIKAN 60
|
||||||
TIGER 61
|
|
||||||
XK 62
|
XK 62
|
||||||
XN297DUMP 63
|
XN297DUMP 63
|
||||||
FRSKYX2 64
|
FRSKYX2 64
|
||||||
@@ -962,6 +1028,10 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
|||||||
DSMX_1F 2
|
DSMX_1F 2
|
||||||
DSMX_2F 3
|
DSMX_2F 3
|
||||||
DSM_AUTO 4
|
DSM_AUTO 4
|
||||||
|
sub_protocol==DSM_RX
|
||||||
|
DSM_RX 0
|
||||||
|
DSM_CLONE 1
|
||||||
|
DSM_ERASE 2
|
||||||
sub_protocol==YD717
|
sub_protocol==YD717
|
||||||
YD717 0
|
YD717 0
|
||||||
SKYWLKR 1
|
SKYWLKR 1
|
||||||
@@ -1079,6 +1149,9 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
|||||||
Q100 2
|
Q100 2
|
||||||
Q200 3
|
Q200 3
|
||||||
MR100 4
|
MR100 4
|
||||||
|
SLT_V1_4CH 5
|
||||||
|
RF_SIM 6
|
||||||
|
SLT6TX 7
|
||||||
sub_protocol==E01X
|
sub_protocol==E01X
|
||||||
E012 0
|
E012 0
|
||||||
E015 1
|
E015 1
|
||||||
@@ -1089,7 +1162,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
|||||||
RED_FAST 0
|
RED_FAST 0
|
||||||
RED_SLOW 1
|
RED_SLOW 1
|
||||||
sub_protocol==TRAXXAS
|
sub_protocol==TRAXXAS
|
||||||
RX6519 0
|
TQ 0
|
||||||
sub_protocol==ESKY150
|
sub_protocol==ESKY150
|
||||||
ESKY150_4CH 0
|
ESKY150_4CH 0
|
||||||
ESKY150_7CH 1
|
ESKY150_7CH 1
|
||||||
@@ -1137,6 +1210,8 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
|||||||
RLINK_SURFACE 0
|
RLINK_SURFACE 0
|
||||||
RLINK_AIR 1
|
RLINK_AIR 1
|
||||||
RLINK_DUMBORC 2
|
RLINK_DUMBORC 2
|
||||||
|
RLINK_RC4G 3
|
||||||
|
RLINK_DUMBORC_P 4
|
||||||
|
|
||||||
Power value => 0x80 0=High/1=Low
|
Power value => 0x80 0=High/1=Low
|
||||||
Stream[3] = option_protocol;
|
Stream[3] = option_protocol;
|
||||||
@@ -1164,6 +1239,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
|||||||
FrSkyX and FrSkyX2: Stream[27..34] during normal operation unstuffed SPort data to be sent
|
FrSkyX and FrSkyX2: Stream[27..34] during normal operation unstuffed SPort data to be sent
|
||||||
HoTT: Stream[27] 1 byte for telemetry type
|
HoTT: Stream[27] 1 byte for telemetry type
|
||||||
DSM: Stream[27..33] Forward Programming
|
DSM: Stream[27..33] Forward Programming
|
||||||
|
RadioLink/DumboRC P: Stream[27..35] raw command payload, used to send failsafe and gyro settings
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
Multiprotocol telemetry/command definition for OpenTX and erskyTX
|
Multiprotocol telemetry/command definition for OpenTX and erskyTX
|
||||||
@@ -1314,5 +1390,9 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
|||||||
data[n+2] = number of sub protocols
|
data[n+2] = number of sub protocols
|
||||||
data[n+3] = sub protocols text length, only sent if nbr_sub != 0
|
data[n+3] = sub protocols text length, only sent if nbr_sub != 0
|
||||||
data[n+4..] = sub protocol names, only sent if nbr_sub != 0
|
data[n+4..] = sub protocol names, only sent if nbr_sub != 0
|
||||||
|
|
||||||
|
Type 0x12 RadioLink/DumboRC P raw command payload
|
||||||
|
length: variable
|
||||||
|
data[0..] = raw command payload, used to send failsafe and gyro settings
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ uint16_t packet_period;
|
|||||||
uint8_t packet_count;
|
uint8_t packet_count;
|
||||||
uint8_t packet_sent;
|
uint8_t packet_sent;
|
||||||
uint8_t packet_length;
|
uint8_t packet_length;
|
||||||
#if defined(HOTT_CC2500_INO) || defined(ESKY150V2_CC2500_INO) || defined(MLINK_CYRF6936_INO)
|
#if defined(HOTT_CC2500_INO) || defined(ESKY150V2_CC2500_INO) || defined(MLINK_CYRF6936_INO) || defined(ARES_CC2500_INO)
|
||||||
uint8_t hopping_frequency[78];
|
uint8_t hopping_frequency[78];
|
||||||
#else
|
#else
|
||||||
uint8_t hopping_frequency[50];
|
uint8_t hopping_frequency[50];
|
||||||
@@ -130,7 +130,7 @@ uint16_t pps_counter;
|
|||||||
#ifdef CC2500_INSTALLED
|
#ifdef CC2500_INSTALLED
|
||||||
#ifdef SCANNER_CC2500_INO
|
#ifdef SCANNER_CC2500_INO
|
||||||
uint8_t calData[255];
|
uint8_t calData[255];
|
||||||
#elif defined(HOTT_CC2500_INO) || defined(ESKY150V2_CC2500_INO)
|
#elif defined(HOTT_CC2500_INO) || defined(ESKY150V2_CC2500_INO) || defined(ARES_CC2500_INO)
|
||||||
uint8_t calData[75];
|
uint8_t calData[75];
|
||||||
#else
|
#else
|
||||||
uint8_t calData[50];
|
uint8_t calData[50];
|
||||||
@@ -265,6 +265,11 @@ uint8_t packet_in[TELEMETRY_BUFFER_SIZE];//telemetry receiving packets
|
|||||||
uint8_t CONFIG_SerialRX_val[7];
|
uint8_t CONFIG_SerialRX_val[7];
|
||||||
bool CONFIG_SerialRX=false;
|
bool CONFIG_SerialRX=false;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RLINK_HUB_TELEMETRY
|
||||||
|
uint8_t RLINK_SerialRX_val[8];
|
||||||
|
uint8_t RLINK_SerialRX_len=0;
|
||||||
|
bool RLINK_SerialRX=false;
|
||||||
|
#endif
|
||||||
#endif // TELEMETRY
|
#endif // TELEMETRY
|
||||||
|
|
||||||
uint8_t multi_protocols_index=0xFF;
|
uint8_t multi_protocols_index=0xFF;
|
||||||
@@ -630,7 +635,11 @@ void setup()
|
|||||||
option = FORCE_HOTT_TUNING; // Use config-defined tuning value for HOTT
|
option = FORCE_HOTT_TUNING; // Use config-defined tuning value for HOTT
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
option = (uint8_t)PPM_prot_line->option; // Use radio-defined option value
|
#if defined(FORCE_ARES_TUNING) && defined(ARES_CC2500_INO)
|
||||||
|
if (protocol==PROTO_ARES)
|
||||||
|
option = FORCE_ARES_TUNING; // Use config-defined tuning value for ARES
|
||||||
|
else
|
||||||
|
#endif option = (uint8_t)PPM_prot_line->option; // Use radio-defined option value
|
||||||
|
|
||||||
if(PPM_prot_line->power) POWER_FLAG_on;
|
if(PPM_prot_line->power) POWER_FLAG_on;
|
||||||
if(PPM_prot_line->autobind)
|
if(PPM_prot_line->autobind)
|
||||||
@@ -1371,6 +1380,11 @@ void update_serial_data()
|
|||||||
if (protocol==PROTO_HOTT)
|
if (protocol==PROTO_HOTT)
|
||||||
option=FORCE_HOTT_TUNING; // Use config-defined tuning value for HOTT
|
option=FORCE_HOTT_TUNING; // Use config-defined tuning value for HOTT
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
|
#if defined(FORCE_ARES_TUNING) && defined(ARES_CC2500_INO)
|
||||||
|
if (protocol==PROTO_ARES)
|
||||||
|
option=FORCE_ARES_TUNING; // Use config-defined tuning value for ARES
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
option=rx_ok_buff[3]; // Use radio-defined option value
|
option=rx_ok_buff[3]; // Use radio-defined option value
|
||||||
|
|
||||||
@@ -1577,6 +1591,15 @@ void update_serial_data()
|
|||||||
CONFIG_SerialRX=true;
|
CONFIG_SerialRX=true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RLINK_HUB_TELEMETRY
|
||||||
|
if(protocol==PROTO_RLINK && sub_protocol==RLINK_DUMBORC_P
|
||||||
|
&& rx_len>27 && rx_len<=27+sizeof(RLINK_SerialRX_val))
|
||||||
|
{//DumboRC P raw command payload from Lua/multiBuffer bridge
|
||||||
|
RLINK_SerialRX_len=rx_len-27;
|
||||||
|
memcpy(RLINK_SerialRX_val, (const void *)&rx_ok_buff[27], RLINK_SerialRX_len);
|
||||||
|
RLINK_SerialRX=true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
RX_DONOTUPDATE_off;
|
RX_DONOTUPDATE_off;
|
||||||
|
|||||||
@@ -16,13 +16,25 @@
|
|||||||
|
|
||||||
#include "iface_nrf250k.h"
|
#include "iface_nrf250k.h"
|
||||||
|
|
||||||
|
#if defined(CC2500_INSTALLED) && defined(NRF24L01_INSTALLED)
|
||||||
|
extern bool xn297_rf;
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8_t cc2500_nrf_tx_addr[5], cc2500_nrf_addr_len;
|
uint8_t cc2500_nrf_tx_addr[5], cc2500_nrf_addr_len;
|
||||||
|
|
||||||
static void __attribute__((unused)) NRF250K_SetTXAddr(uint8_t* addr, uint8_t len)
|
static void __attribute__((unused)) NRF250K_SetTXAddr(uint8_t* addr, uint8_t len)
|
||||||
{
|
{
|
||||||
if (len > 5) len = 5;
|
if (len > 5) len = 5;
|
||||||
if (len < 3) len = 3;
|
if (len < 3) len = 3;
|
||||||
#if defined(CC2500_INSTALLED)
|
#if defined(CC2500_INSTALLED) && defined(NRF24L01_INSTALLED)
|
||||||
|
cc2500_nrf_addr_len = len;
|
||||||
|
memcpy(cc2500_nrf_tx_addr, addr, len);
|
||||||
|
if(xn297_rf == XN297_NRF)
|
||||||
|
{
|
||||||
|
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, len-2);
|
||||||
|
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, addr, len);
|
||||||
|
}
|
||||||
|
#elif defined(CC2500_INSTALLED)
|
||||||
cc2500_nrf_addr_len = len;
|
cc2500_nrf_addr_len = len;
|
||||||
memcpy(cc2500_nrf_tx_addr, addr, len);
|
memcpy(cc2500_nrf_tx_addr, addr, len);
|
||||||
#elif defined(NRF24L01_INSTALLED)
|
#elif defined(NRF24L01_INSTALLED)
|
||||||
@@ -33,6 +45,22 @@ static void __attribute__((unused)) NRF250K_SetTXAddr(uint8_t* addr, uint8_t len
|
|||||||
|
|
||||||
static void __attribute__((unused)) NRF250K_WritePayload(uint8_t* msg, uint8_t len)
|
static void __attribute__((unused)) NRF250K_WritePayload(uint8_t* msg, uint8_t len)
|
||||||
{
|
{
|
||||||
|
#if defined(NRF24L01_INSTALLED)
|
||||||
|
#if defined(CC2500_INSTALLED)
|
||||||
|
if(xn297_rf == XN297_NRF)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if(len<=32)
|
||||||
|
{
|
||||||
|
NRF24L01_FlushTx();
|
||||||
|
NRF24L01_WriteReg(NRF24L01_07_STATUS, _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_MAX_RT));
|
||||||
|
NRF24L01_WritePayload(msg, len);
|
||||||
|
}
|
||||||
|
#if defined(CC2500_INSTALLED)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if defined(CC2500_INSTALLED)
|
#if defined(CC2500_INSTALLED)
|
||||||
#if defined(ESKY150V2_CC2500_INO)
|
#if defined(ESKY150V2_CC2500_INO)
|
||||||
uint8_t buf[158];
|
uint8_t buf[158];
|
||||||
@@ -106,13 +134,6 @@ static void __attribute__((unused)) NRF250K_WritePayload(uint8_t* msg, uint8_t l
|
|||||||
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buff, last);
|
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buff, last);
|
||||||
CC2500_Strobe(CC2500_STX);
|
CC2500_Strobe(CC2500_STX);
|
||||||
}
|
}
|
||||||
#elif defined(NRF24L01_INSTALLED)
|
|
||||||
if(len<=32)
|
|
||||||
{
|
|
||||||
NRF24L01_FlushTx();
|
|
||||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_MAX_RT));
|
|
||||||
NRF24L01_WritePayload(msg, len);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
//#define PELIKAN_LITE_FORCE_ID
|
//#define PELIKAN_LITE_FORCE_ID
|
||||||
#define PELIKAN_LITE_FORCE_HOP // hop sequence creation is unknown
|
#define PELIKAN_LITE_FORCE_HOP // hop sequence creation is unknown
|
||||||
//#define PELIKAN_SCX24_FORCE_ID
|
//#define PELIKAN_SCX24_FORCE_ID
|
||||||
#define PELIKAN_SCX24_FORCE_HOP // hop sequence creation is unknown
|
//#define PELIKAN_SCX24_FORCE_HOP // hop sequence creation is unknown
|
||||||
|
|
||||||
#define PELIKAN_BIND_COUNT 400 // 3sec
|
#define PELIKAN_BIND_COUNT 400 // 3sec
|
||||||
#define PELIKAN_BIND_RF 0x3C
|
#define PELIKAN_BIND_RF 0x3C
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
#define PELIKAN_PACKET_PERIOD 7980
|
#define PELIKAN_PACKET_PERIOD 7980
|
||||||
#define PELIKAN_LITE_PACKET_PERIOD 18000
|
#define PELIKAN_LITE_PACKET_PERIOD 18000
|
||||||
#define PELIKAN_SCX24_PACKET_PERIOD 15069
|
#define PELIKAN_SCX24_PACKET_PERIOD 15069
|
||||||
|
#define PELIKAN_SCX_HOP_LIMIT 90
|
||||||
|
|
||||||
static void __attribute__((unused)) pelikan_build_packet()
|
static void __attribute__((unused)) pelikan_build_packet()
|
||||||
{
|
{
|
||||||
@@ -37,9 +38,11 @@ static void __attribute__((unused)) pelikan_build_packet()
|
|||||||
uint8_t sum;
|
uint8_t sum;
|
||||||
uint16_t channel;
|
uint16_t channel;
|
||||||
|
|
||||||
|
#ifndef MULTI_AIR
|
||||||
if(sub_protocol == PELIKAN_SCX24)
|
if(sub_protocol == PELIKAN_SCX24)
|
||||||
packet[0] = 0x11;
|
packet[0] = 0x11;
|
||||||
else //PELIKAN_PRO & PELIKAN_LITE
|
else //PELIKAN_PRO & PELIKAN_LITE
|
||||||
|
#endif
|
||||||
packet[0] = 0x15;
|
packet[0] = 0x15;
|
||||||
if(IS_BIND_IN_PROGRESS)
|
if(IS_BIND_IN_PROGRESS)
|
||||||
{
|
{
|
||||||
@@ -48,6 +51,7 @@ static void __attribute__((unused)) pelikan_build_packet()
|
|||||||
packet[4] = rx_tx_addr[2];
|
packet[4] = rx_tx_addr[2];
|
||||||
packet[5] = rx_tx_addr[3];
|
packet[5] = rx_tx_addr[3];
|
||||||
|
|
||||||
|
#ifndef MULTI_AIR
|
||||||
if(sub_protocol == PELIKAN_SCX24)
|
if(sub_protocol == PELIKAN_SCX24)
|
||||||
{
|
{
|
||||||
packet[1] = 0x65; //??
|
packet[1] = 0x65; //??
|
||||||
@@ -55,6 +59,7 @@ static void __attribute__((unused)) pelikan_build_packet()
|
|||||||
packet[7] = 0xAA; //??
|
packet[7] = 0xAA; //??
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
{//PELIKAN_PRO & PELIKAN_LITE
|
{//PELIKAN_PRO & PELIKAN_LITE
|
||||||
packet[1] = 0x04; //version??
|
packet[1] = 0x04; //version??
|
||||||
if(sub_protocol==PELIKAN_PRO)
|
if(sub_protocol==PELIKAN_PRO)
|
||||||
@@ -70,6 +75,7 @@ static void __attribute__((unused)) pelikan_build_packet()
|
|||||||
{
|
{
|
||||||
//ID
|
//ID
|
||||||
packet[1] = rx_tx_addr[0];
|
packet[1] = rx_tx_addr[0];
|
||||||
|
#ifndef MULTI_AIR
|
||||||
if(sub_protocol == PELIKAN_SCX24)
|
if(sub_protocol == PELIKAN_SCX24)
|
||||||
{
|
{
|
||||||
//ID
|
//ID
|
||||||
@@ -95,6 +101,7 @@ static void __attribute__((unused)) pelikan_build_packet()
|
|||||||
packet_length = 14;
|
packet_length = 14;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
{//PELIKAN_PRO & PELIKAN_LITE
|
{//PELIKAN_PRO & PELIKAN_LITE
|
||||||
//ID
|
//ID
|
||||||
packet[7] = rx_tx_addr[1];
|
packet[7] = rx_tx_addr[1];
|
||||||
@@ -158,6 +165,13 @@ static void __attribute__((unused)) pelikan_build_packet()
|
|||||||
|
|
||||||
uint16_t PELIKAN_callback()
|
uint16_t PELIKAN_callback()
|
||||||
{
|
{
|
||||||
|
#ifdef MULTI_AIR
|
||||||
|
if(sub_protocol == PELIKAN_SCX24)
|
||||||
|
{
|
||||||
|
SUB_PROTO_INVALID;
|
||||||
|
return 10000;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if(phase==0)
|
if(phase==0)
|
||||||
{
|
{
|
||||||
#ifndef FORCE_PELIKAN_TUNING
|
#ifndef FORCE_PELIKAN_TUNING
|
||||||
@@ -172,10 +186,12 @@ uint16_t PELIKAN_callback()
|
|||||||
A7105_Strobe(A7105_STANDBY);
|
A7105_Strobe(A7105_STANDBY);
|
||||||
if(sub_protocol==PELIKAN_PRO)
|
if(sub_protocol==PELIKAN_PRO)
|
||||||
A7105_WriteReg(A7105_03_FIFOI,0x28); //????
|
A7105_WriteReg(A7105_03_FIFOI,0x28); //????
|
||||||
else if(sub_protocol==PELIKAN_SCX24)
|
else if(sub_protocol==PELIKAN_LITE)
|
||||||
A7105_WriteReg(A7105_03_FIFOI,0x0D);
|
|
||||||
else//PELIKAN_LITE
|
|
||||||
A7105_WriteID(MProtocol_id);
|
A7105_WriteID(MProtocol_id);
|
||||||
|
#ifndef MULTI_AIR
|
||||||
|
else // PELIKAN_SCX24
|
||||||
|
A7105_WriteReg(A7105_03_FIFOI,0x0D);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef MULTI_SYNC
|
#ifdef MULTI_SYNC
|
||||||
@@ -216,6 +232,82 @@ static uint8_t pelikan_firstCh(uint8_t u, uint8_t l)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t pelikan_firstCh_scx(uint8_t i, uint8_t j)
|
||||||
|
{
|
||||||
|
uint8_t ch;
|
||||||
|
switch (j) {
|
||||||
|
case 0:
|
||||||
|
ch = 30;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
ch = (i * 4) + 42;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ch = (i * 2) + 36;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
ch = (i * 8) + 54;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
ch = 30;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch > PELIKAN_SCX_HOP_LIMIT)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ch -= 62;
|
||||||
|
} while (ch > PELIKAN_SCX_HOP_LIMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ch) {
|
||||||
|
case 48:
|
||||||
|
if (j == 3)
|
||||||
|
ch += 18;
|
||||||
|
else if (j == 4)
|
||||||
|
ch += 20;
|
||||||
|
else
|
||||||
|
ch += 40;
|
||||||
|
break;
|
||||||
|
case 40:
|
||||||
|
if (j == 4)
|
||||||
|
ch += 18;
|
||||||
|
break;
|
||||||
|
case 52:
|
||||||
|
if (j < 3)
|
||||||
|
ch -= 20;
|
||||||
|
else if (j == 4)
|
||||||
|
ch -= 10;
|
||||||
|
break;
|
||||||
|
case 66:
|
||||||
|
if (j < 3)
|
||||||
|
ch += 18;
|
||||||
|
else if (j == 4)
|
||||||
|
ch -= 22;
|
||||||
|
break;
|
||||||
|
case 72:
|
||||||
|
if (j < 3)
|
||||||
|
ch -= 10;
|
||||||
|
else if (j ==3)
|
||||||
|
ch -= 20;
|
||||||
|
else if (j == 4)
|
||||||
|
ch -= 36;
|
||||||
|
break;
|
||||||
|
case 74:
|
||||||
|
if (j == 4)
|
||||||
|
ch -= 20;
|
||||||
|
break;
|
||||||
|
case 86:
|
||||||
|
if (j == 4)
|
||||||
|
ch -= 48;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t pelikan_adjust_value(uint8_t value, uint8_t addition, uint8_t limit)
|
static uint8_t pelikan_adjust_value(uint8_t value, uint8_t addition, uint8_t limit)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
@@ -234,6 +326,10 @@ static uint8_t pelikan_adjust_value(uint8_t value, uint8_t addition, uint8_t lim
|
|||||||
value += addition;
|
value += addition;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
if (value == 72) {
|
||||||
|
value += addition;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (i > 0);
|
while (i > 0);
|
||||||
|
|
||||||
@@ -278,6 +374,121 @@ static void __attribute__((unused)) pelikan_init_hop()
|
|||||||
debugln("");
|
debugln("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MULTI_AIR
|
||||||
|
|
||||||
|
const uint8_t PROGMEM scx_ch_map[4][PELIKAN_NUM_RF_CHAN] =
|
||||||
|
{
|
||||||
|
{0,1,2,26,27,28,23,24,25,20,21,22,17,18,19,14,15,16,11,12,13,8,9,10,5,6,7,4,3},
|
||||||
|
{0,1,2,28,25,26,27,24,21,22,23,20,17,18,19,16,13,14,15,12,9,10,11,8,5,6,7,3,4},
|
||||||
|
{0,1,27,28,25,26,23,24,21,22,19,20,17,18,15,16,13,14,11,12,9,10,7,8,5,6,3,4,2},
|
||||||
|
{0,1,28,1,4,2,23,26,22,24,27,25,17,20,16,18,21,19,11,14,10,12,15,13,27,8,6,7,9}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pelikan_shuffle(uint8_t j)
|
||||||
|
{
|
||||||
|
uint8_t temp[PELIKAN_NUM_RF_CHAN];
|
||||||
|
for (uint8_t i = 0; i < PELIKAN_NUM_RF_CHAN; i++)
|
||||||
|
temp[i] = hopping_frequency[pgm_read_byte_near(&scx_ch_map[j-1][i])];
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < PELIKAN_NUM_RF_CHAN; i++)
|
||||||
|
hopping_frequency[i] = temp[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) pelikan_init_hop_scx()
|
||||||
|
{
|
||||||
|
rx_tx_addr[0] = 0x10;
|
||||||
|
rx_tx_addr[1] = (rx_tx_addr[1] + RX_num) % 192;
|
||||||
|
debugln("TX[0]: %02X TX[1]: %02X", rx_tx_addr[0], rx_tx_addr[1]);
|
||||||
|
|
||||||
|
uint8_t high = (rx_tx_addr[1]>>4);
|
||||||
|
uint8_t low = rx_tx_addr[1] & 0x0F;
|
||||||
|
int16_t i = (high * 10) + low - 23;
|
||||||
|
uint8_t j = 0;
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
j = 1;
|
||||||
|
|
||||||
|
if (i > 24)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
i -= 24;
|
||||||
|
j++;
|
||||||
|
} while (i > 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
debugln("H: %02X L: %02X I: %02X J: %02X", high, low, i, j);
|
||||||
|
|
||||||
|
uint8_t first_channel;
|
||||||
|
uint8_t last_channel;
|
||||||
|
uint8_t addition;
|
||||||
|
|
||||||
|
first_channel = pelikan_firstCh_scx(i, j);
|
||||||
|
|
||||||
|
if (j == 0)
|
||||||
|
last_channel = 42 - (high * 10) - low;
|
||||||
|
else
|
||||||
|
last_channel = 42 - i + 1;
|
||||||
|
|
||||||
|
if (last_channel == 24)
|
||||||
|
last_channel += 9;
|
||||||
|
|
||||||
|
if (last_channel == 36)
|
||||||
|
last_channel -= 10;
|
||||||
|
|
||||||
|
if (j == 0)
|
||||||
|
addition = (2 * i) + 54;
|
||||||
|
else if (j == 5)
|
||||||
|
addition = (2 * i) + 6;
|
||||||
|
else
|
||||||
|
addition = 56 - (2 * i);
|
||||||
|
|
||||||
|
hopping_frequency[0] = first_channel;
|
||||||
|
for (uint8_t i = 1; i < PELIKAN_NUM_RF_CHAN; i++)
|
||||||
|
{
|
||||||
|
hopping_frequency[i] = pelikan_add(hopping_frequency[i-1], addition, PELIKAN_SCX_HOP_LIMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j > 0 && j < 5)
|
||||||
|
pelikan_shuffle(j);
|
||||||
|
|
||||||
|
if (j == 2)
|
||||||
|
{
|
||||||
|
hopping_frequency[PELIKAN_NUM_RF_CHAN - 2] = last_channel;
|
||||||
|
} else if (j == 4)
|
||||||
|
{
|
||||||
|
uint8_t t = (2 * i) + 36;
|
||||||
|
if (t == 48)
|
||||||
|
t += 18;
|
||||||
|
if (t == 72)
|
||||||
|
t -= 20;
|
||||||
|
|
||||||
|
hopping_frequency[1] = t;
|
||||||
|
hopping_frequency[PELIKAN_NUM_RF_CHAN - 5] = last_channel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hopping_frequency[PELIKAN_NUM_RF_CHAN - 1] = last_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
for (uint8_t i = 0; i < PELIKAN_NUM_RF_CHAN; i++)
|
||||||
|
debug("%02X ", hopping_frequency[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PELIKAN_SCX24_FORCE_HOP
|
||||||
|
const uint8_t PROGMEM pelikan_scx24_hopp[][PELIKAN_NUM_RF_CHAN] = {
|
||||||
|
/*TX1*/ { 0x1E,0x32,0x46,0x5A,0x44,0x58,0x2E,0x42,0x56,0x2C,0x40,0x54,0x2A,0x3E,0x52,0x28,0x3C,0x50,0x26,0x3A,0x4E,0x24,0x38,0x4C,0x22,0x36,0x4A,0x20,0x1A },
|
||||||
|
/*TX2*/ { 0x2C,0x44,0x1E,0x52,0x56,0x22,0x3A,0x3E,0x34,0x4C,0x26,0x5A,0x50,0x2A,0x42,0x38,0x2E,0x46,0x20,0x54,0x4A,0x24,0x3C,0x32,0x28,0x40,0x58,0x1B,0x4E },
|
||||||
|
/*TX3*/ { 0x3C,0x4C,0x1E,0x4A,0x5A,0x2C,0x58,0x2A,0x3A,0x56,0x28,0x38,0x26,0x36,0x46,0x34,0x44,0x54,0x42,0x52,0x24,0x50,0x22,0x32,0x4E,0x20,0x40,0x3E,0x17 },
|
||||||
|
/*TX4*/ { 0x46,0x32,0x1E,0x58,0x44,0x5A,0x56,0x42,0x2E,0x54,0x40,0x2C,0x52,0x3E,0x2A,0x50,0x3C,0x28,0x4E,0x3A,0x26,0x4C,0x38,0x24,0x4A,0x36,0x22,0x20,0x1A }
|
||||||
|
};
|
||||||
|
#endif //PELIKAN_SCX24_FORCE_HOP
|
||||||
|
|
||||||
|
#endif //MULTI_AIR
|
||||||
|
|
||||||
#ifdef PELIKAN_FORCE_ID
|
#ifdef PELIKAN_FORCE_ID
|
||||||
const uint8_t PROGMEM pelikan_hopp[][PELIKAN_NUM_RF_CHAN] = {
|
const uint8_t PROGMEM pelikan_hopp[][PELIKAN_NUM_RF_CHAN] = {
|
||||||
{ 0x5A,0x46,0x32,0x6E,0x6C,0x58,0x44,0x42,0x40,0x6A,0x56,0x54,0x52,0x3E,0x68,0x66,0x64,0x50,0x3C,0x3A,0x38,0x62,0x4E,0x4C,0x5E,0x4A,0x36,0x5C,0x34 }
|
{ 0x5A,0x46,0x32,0x6E,0x6C,0x58,0x44,0x42,0x40,0x6A,0x56,0x54,0x52,0x3E,0x68,0x66,0x64,0x50,0x3C,0x3A,0x38,0x62,0x4E,0x4C,0x5E,0x4A,0x36,0x5C,0x34 }
|
||||||
@@ -289,12 +500,6 @@ const uint8_t PROGMEM pelikan_lite_hopp[][PELIKAN_NUM_RF_CHAN] = {
|
|||||||
{ 0x46,0x2A,0x3E,0x5A,0x5C,0x24,0x4E,0x32,0x54,0x26,0x2C,0x34,0x56,0x1E,0x3A,0x3C,0x50,0x4A,0x2E,0x42,0x20,0x52,0x28,0x22,0x44,0x58,0x36,0x38,0x4C }
|
{ 0x46,0x2A,0x3E,0x5A,0x5C,0x24,0x4E,0x32,0x54,0x26,0x2C,0x34,0x56,0x1E,0x3A,0x3C,0x50,0x4A,0x2E,0x42,0x20,0x52,0x28,0x22,0x44,0x58,0x36,0x38,0x4C }
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#ifdef PELIKAN_SCX24_FORCE_HOP
|
|
||||||
const uint8_t PROGMEM pelikan_scx24_hopp[][PELIKAN_NUM_RF_CHAN] = {
|
|
||||||
{ 0x1E,0x32,0x46,0x5A,0x44,0x58,0x2E,0x42,0x56,0x2C,0x40,0x54,0x2A,0x3E,0x52,0x28,0x3C,0x50,0x26,0x3A,0x4E,0x24,0x38,0x4C,0x22,0x36,0x4A,0x20,0x1A },
|
|
||||||
{ 0x2C,0x44,0x1E,0x52,0x56,0x22,0x3A,0x3E,0x34,0x4C,0x26,0x5A,0x50,0x2A,0x42,0x38,0x2E,0x46,0x20,0x54,0x4A,0x24,0x3C,0x32,0x28,0x40,0x58,0x1B,0x4E }
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void PELIKAN_init()
|
void PELIKAN_init()
|
||||||
{
|
{
|
||||||
@@ -341,22 +546,32 @@ void PELIKAN_init()
|
|||||||
A7105_WriteID(MProtocol_id);
|
A7105_WriteID(MProtocol_id);
|
||||||
packet_period = PELIKAN_LITE_PACKET_PERIOD;
|
packet_period = PELIKAN_LITE_PACKET_PERIOD;
|
||||||
}
|
}
|
||||||
|
#ifndef MULTI_AIR
|
||||||
else// if(sub_protocol==PELIKAN_SCX24)
|
else// if(sub_protocol==PELIKAN_SCX24)
|
||||||
{
|
{
|
||||||
|
pelikan_init_hop_scx();
|
||||||
#if defined(PELIKAN_SCX24_FORCE_HOP)
|
#if defined(PELIKAN_SCX24_FORCE_HOP)
|
||||||
// Hop frequency table
|
// Hop frequency table
|
||||||
uint8_t num=rx_tx_addr[3] & 0x01;
|
uint8_t num=rx_tx_addr[3] & 0x03;
|
||||||
if(num)
|
switch(num)
|
||||||
{//1
|
{
|
||||||
rx_tx_addr[0]=0x10; // hopping freq TX2
|
case 1:
|
||||||
rx_tx_addr[1]=0x63; // hopping freq TX2
|
rx_tx_addr[0]=0x10; // hopping freq TX2
|
||||||
|
rx_tx_addr[1]=0x63; // hopping freq TX2
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rx_tx_addr[0]=0x81; // hopping freq TX3
|
||||||
|
rx_tx_addr[1]=0x63; // hopping freq TX3
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rx_tx_addr[0]=0x36; // hopping freq TX4
|
||||||
|
rx_tx_addr[1]=0x5C; // hopping freq TX4
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rx_tx_addr[0]=0x12; // hopping freq TX1
|
||||||
|
rx_tx_addr[1]=0x46; // hopping freq TX1
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{//0
|
|
||||||
rx_tx_addr[0]=0x12; // hopping freq TX1
|
|
||||||
rx_tx_addr[1]=0x46; // hopping freq TX1
|
|
||||||
}
|
|
||||||
|
|
||||||
for(uint8_t i=0;i<PELIKAN_NUM_RF_CHAN;i++)
|
for(uint8_t i=0;i<PELIKAN_NUM_RF_CHAN;i++)
|
||||||
hopping_frequency[i]=pgm_read_byte_near(&pelikan_scx24_hopp[num][i]);
|
hopping_frequency[i]=pgm_read_byte_near(&pelikan_scx24_hopp[num][i]);
|
||||||
#endif
|
#endif
|
||||||
@@ -366,12 +581,17 @@ void PELIKAN_init()
|
|||||||
rx_tx_addr[3]=0x19; // TX1
|
rx_tx_addr[3]=0x19; // TX1
|
||||||
rx_tx_addr[2]=0x80; // TX2
|
rx_tx_addr[2]=0x80; // TX2
|
||||||
rx_tx_addr[3]=0x22; // TX2
|
rx_tx_addr[3]=0x22; // TX2
|
||||||
|
rx_tx_addr[2]=0x30; // TX3
|
||||||
|
rx_tx_addr[3]=0x18; // TX3
|
||||||
|
rx_tx_addr[2]=0x30; // TX4
|
||||||
|
rx_tx_addr[3]=0x17; // TX4
|
||||||
#endif
|
#endif
|
||||||
A7105_WriteReg(A7105_0E_DATA_RATE,0x03);
|
A7105_WriteReg(A7105_0E_DATA_RATE,0x03);
|
||||||
if(IS_BIND_DONE)
|
if(IS_BIND_DONE)
|
||||||
A7105_WriteReg(A7105_03_FIFOI,0x0D);
|
A7105_WriteReg(A7105_03_FIFOI,0x0D);
|
||||||
packet_period = PELIKAN_SCX24_PACKET_PERIOD;
|
packet_period = PELIKAN_SCX24_PACKET_PERIOD;
|
||||||
}
|
}
|
||||||
|
#endif //MULTI_AIR
|
||||||
}
|
}
|
||||||
|
|
||||||
hopping_frequency_no = PELIKAN_NUM_RF_CHAN;
|
hopping_frequency_no = PELIKAN_NUM_RF_CHAN;
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ Multiprotocol is distributed in the hope that it will be useful,
|
|||||||
|
|
||||||
#include "iface_xn297.h"
|
#include "iface_xn297.h"
|
||||||
|
|
||||||
#define FORCE_REALACC_ORIGINAL_ID
|
//#define FORCE_REALACC_ORIGINAL_ID
|
||||||
|
//#define FORCE_REALACC_WLV8TX_ID
|
||||||
|
|
||||||
#define REALACC_INITIAL_WAIT 500
|
#define REALACC_INITIAL_WAIT 500
|
||||||
#define REALACC_PACKET_PERIOD 2268
|
#define REALACC_PACKET_PERIOD 2268
|
||||||
@@ -28,29 +29,66 @@ Multiprotocol is distributed in the hope that it will be useful,
|
|||||||
#define REALACC_BIND_COUNT 50
|
#define REALACC_BIND_COUNT 50
|
||||||
#define REALACC_RF_NUM_CHANNELS 5
|
#define REALACC_RF_NUM_CHANNELS 5
|
||||||
|
|
||||||
|
#ifndef MULTI_AIR
|
||||||
|
#define WLV8TX_PACKET_PERIOD 16279
|
||||||
|
#define WLV8TX_BIND2_PAYLOAD_SIZE 12
|
||||||
|
#define WLV8TX_RX_PAYLOAD_SIZE 6
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
REALACC_WLV8TX_BIND_TX = 0,
|
||||||
|
REALACC_WLV8TX_BIND_RX_SETUP,
|
||||||
|
REALACC_WLV8TX_BIND_RX_CHECK,
|
||||||
|
REALACC_WLV8TX_DATA
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
static uint8_t realacc_bind_packet[REALACC_BIND_PAYLOAD_SIZE];
|
||||||
|
|
||||||
static void __attribute__((unused)) REALACC_send_packet()
|
static void __attribute__((unused)) REALACC_send_packet()
|
||||||
{
|
{
|
||||||
packet[ 0]= 0xDC;
|
#ifndef MULTI_AIR
|
||||||
packet[ 1]= convert_channel_8b(AILERON); // 00..80..FF
|
if(sub_protocol == REALACC_WLV8TX)
|
||||||
packet[ 2]= convert_channel_8b(ELEVATOR); // 00..80..FF
|
{
|
||||||
packet[ 3]= convert_channel_8b(THROTTLE); // 00..FF
|
packet[ 0]= 0xDC; // DC
|
||||||
packet[ 4]= convert_channel_8b(RUDDER); // 00..80..FF
|
packet[ 1]= 0x80; // not used
|
||||||
packet[ 5]= 0x20; // Trim
|
packet[ 2]= 0x80; // not used
|
||||||
packet[ 6]= 0x20; // Trim
|
packet[ 3]= convert_channel_16b_limit(CH2,0x0F,0xF1); // Throttle 0F..80..F7 (spring center)
|
||||||
packet[ 7]= 0x20; // Trim
|
packet[ 4]= convert_channel_16b_limit(CH1,0xE7,0x19); // Steering E7..80..1F (reversed)
|
||||||
packet[ 8]= 0x20; // Trim
|
packet[ 5]=(convert_channel_8b(CH3) >> 2); // GY Trim (Rate) 02..20..3D
|
||||||
packet[ 9]= num_ch; // Change at each power up
|
packet[ 6]= 0x20; // Constant?
|
||||||
packet[10]= 0x04 // Flag1
|
packet[ 7]= (convert_channel_8b(CH4) >> 2); // TH Trim (Rate) 02..20..3D
|
||||||
| 0x02 // Rate1=0, Rate2=1, Rate3=2
|
packet[ 8]=((convert_channel_8b(CH5) >> 2) ^ 0x3F); // ST Trim (R..C..L) 3F..20..01 (reversed)
|
||||||
| GET_FLAG(CH8_SW, 0x20); // Headless
|
packet[ 9]= 0x77; // Change at each power up? 07 0D 25 50 77 82 89 A5 E4
|
||||||
packet[11]= 0x00 // Flag2
|
packet[10]= 0x0C; // WL-V8Tx: fixed value = 0C
|
||||||
| GET_FLAG(CH7_SW, 0x01) // Calib
|
packet[11]= 0x00; // Constant?
|
||||||
| GET_FLAG(CH9_SW, 0x20) // Return
|
packet[12]= 0x00; // Constant?
|
||||||
| GET_FLAG(CH10_SW,0x80); // Unknown
|
}
|
||||||
packet[12]= 0x00 // Flag3
|
else
|
||||||
| GET_FLAG(CH5_SW, 0x01) // Flip
|
#endif
|
||||||
| GET_FLAG(CH6_SW, 0x80); // Light
|
{
|
||||||
|
packet[ 0]= 0xDC; // DC/D6/DE
|
||||||
|
packet[ 1]= convert_channel_8b(AILERON); // 00..80..FF
|
||||||
|
packet[ 2]= convert_channel_8b(ELEVATOR); // 00..80..FF
|
||||||
|
packet[ 3]= convert_channel_8b(THROTTLE); // 00..FF
|
||||||
|
packet[ 4]= convert_channel_8b(RUDDER); // 00..80..FF
|
||||||
|
packet[ 5]= 0x20; // Trim
|
||||||
|
packet[ 6]= 0x20; // Trim
|
||||||
|
packet[ 7]= 0x20; // Trim
|
||||||
|
packet[ 8]= 0x20; // Trim
|
||||||
|
packet[ 9]= 0x88; // Change at each power up: C5 A2 77 F0 84 58, fixed for the E017 = 88
|
||||||
|
packet[10]= 0x04 // Flag1: R11=04, E017=0C
|
||||||
|
| 0x02 // Rate1=0, Rate2=1, Rate3=2
|
||||||
|
| GET_FLAG(CH8_SW, 0x20); // Headless
|
||||||
|
packet[11]= 0x00 // Flag2
|
||||||
|
| GET_FLAG(CH7_SW, 0x01) // Calib
|
||||||
|
| GET_FLAG(CH9_SW, 0x20) // Return
|
||||||
|
| GET_FLAG(CH10_SW,0x80); // Throttle cut
|
||||||
|
packet[12]= 0x00 // Flag3
|
||||||
|
| GET_FLAG(CH5_SW, 0x01) // Flip
|
||||||
|
| GET_FLAG(CH11_SW,0x02) // Rotating
|
||||||
|
| GET_FLAG(CH6_SW, 0x80); // Light
|
||||||
|
}
|
||||||
XN297_Hopping(hopping_frequency_no);
|
XN297_Hopping(hopping_frequency_no);
|
||||||
hopping_frequency_no++;
|
hopping_frequency_no++;
|
||||||
hopping_frequency_no %= REALACC_RF_NUM_CHANNELS;
|
hopping_frequency_no %= REALACC_RF_NUM_CHANNELS;
|
||||||
@@ -59,30 +97,75 @@ static void __attribute__((unused)) REALACC_send_packet()
|
|||||||
|
|
||||||
static void __attribute__((unused)) REALACC_send_bind_packet()
|
static void __attribute__((unused)) REALACC_send_bind_packet()
|
||||||
{
|
{
|
||||||
packet[0] = 0xB1;
|
#ifndef MULTI_AIR
|
||||||
memcpy(&packet[1],rx_tx_addr,4);
|
if(sub_protocol == REALACC_WLV8TX && rx_id[0])
|
||||||
memcpy(&packet[5],hopping_frequency,5);
|
{ // WLV8TX bind sent after RX packet B3 acknowledged
|
||||||
|
packet[0] = 0xB4;
|
||||||
XN297_WriteEnhancedPayload(packet, REALACC_BIND_PAYLOAD_SIZE,1);
|
packet[1] = rx_id[1];
|
||||||
|
packet[2] = rx_id[2];
|
||||||
|
memcpy(&packet[3], realacc_bind_packet, 4); // Original TX ID before XOR
|
||||||
|
memcpy(&packet[7], hopping_frequency, 5); // RF frequencies
|
||||||
|
XN297_WriteEnhancedPayload(packet, WLV8TX_BIND2_PAYLOAD_SIZE,1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{ // initial bind sent for all models
|
||||||
|
packet[0] = 0xB1; // B0/B1
|
||||||
|
memcpy(&packet[1],realacc_bind_packet,4); // Address
|
||||||
|
memcpy(&packet[5],hopping_frequency,5); // RF frequencies
|
||||||
|
XN297_WriteEnhancedPayload(packet, REALACC_BIND_PAYLOAD_SIZE,1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((unused)) REALACC_initialize_txid()
|
static void __attribute__((unused)) REALACC_initialize_txid()
|
||||||
{
|
{
|
||||||
|
rx_tx_addr[3] &= 0x3F;
|
||||||
calc_fh_channels(REALACC_RF_NUM_CHANNELS);
|
calc_fh_channels(REALACC_RF_NUM_CHANNELS);
|
||||||
num_ch=random(0xfefefefe); // 00..FF
|
|
||||||
|
|
||||||
#ifdef FORCE_REALACC_ORIGINAL_ID
|
#ifdef FORCE_REALACC_ORIGINAL_ID
|
||||||
//Dump
|
if(RX_num==0)
|
||||||
rx_tx_addr[0]=0x99;
|
{//TX1
|
||||||
rx_tx_addr[1]=0x06;
|
rx_tx_addr[0]=0x99;
|
||||||
rx_tx_addr[2]=0x00;
|
rx_tx_addr[1]=0x06;
|
||||||
rx_tx_addr[3]=0x00;
|
rx_tx_addr[2]=0x00;
|
||||||
hopping_frequency[0]=0x55;
|
rx_tx_addr[3]=0x00; // 00..3F:OK, 40..:NOK
|
||||||
hopping_frequency[1]=0x59;
|
hopping_frequency[0]=0x55;
|
||||||
hopping_frequency[2]=0x5A;
|
hopping_frequency[1]=0x59;
|
||||||
hopping_frequency[3]=0x5A;
|
hopping_frequency[2]=0x5A;
|
||||||
hopping_frequency[4]=0x62;
|
hopping_frequency[3]=0x5A;
|
||||||
num_ch=0xC5; // Value in dumps: C5 A2 77 F0 84 58
|
hopping_frequency[4]=0x62;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{//TX2
|
||||||
|
rx_tx_addr[0]=0x4F;
|
||||||
|
rx_tx_addr[1]=0xB9;
|
||||||
|
rx_tx_addr[2]=0xA1;
|
||||||
|
rx_tx_addr[3]=0x17;
|
||||||
|
hopping_frequency[0]=0x45;
|
||||||
|
hopping_frequency[1]=0x38;
|
||||||
|
hopping_frequency[2]=0x3C;
|
||||||
|
hopping_frequency[3]=0x41;
|
||||||
|
hopping_frequency[4]=0x3F;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef FORCE_REALACC_WLV8TX_ID
|
||||||
|
{
|
||||||
|
rx_tx_addr[0]=0x32;
|
||||||
|
rx_tx_addr[1]=0xE9;
|
||||||
|
rx_tx_addr[2]=0xDE;
|
||||||
|
rx_tx_addr[3]=0x0A;
|
||||||
|
hopping_frequency[0]=0x45;
|
||||||
|
hopping_frequency[1]=0x42;
|
||||||
|
hopping_frequency[2]=0x38;
|
||||||
|
hopping_frequency[3]=0x3C;
|
||||||
|
hopping_frequency[4]=0x4A;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
memcpy(realacc_bind_packet, rx_tx_addr, 4);
|
||||||
|
#if 0
|
||||||
|
debug("ID: %02X %02X %02X %02X, C: ",rx_tx_addr[0],rx_tx_addr[1],rx_tx_addr[2],rx_tx_addr[3]);
|
||||||
|
for(uint8_t i=0; i<REALACC_RF_NUM_CHANNELS; i++)
|
||||||
|
debug(" %02X",hopping_frequency[i]);
|
||||||
|
debugln("");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,12 +176,82 @@ static void __attribute__((unused)) REALACC_RF_init()
|
|||||||
XN297_RFChannel(REALACC_BIND_RF_CHANNEL); // Set bind channel
|
XN297_RFChannel(REALACC_BIND_RF_CHANNEL); // Set bind channel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MULTI_AIR
|
||||||
|
static void __attribute__((unused)) REALACC_wlv8tx_process_rx()
|
||||||
|
{
|
||||||
|
if(!XN297_IsRX())
|
||||||
|
return;
|
||||||
|
uint8_t len = XN297_ReadEnhancedPayload(packet_in, WLV8TX_RX_PAYLOAD_SIZE);
|
||||||
|
if(len != 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(packet_in[0] == 0xB3 && !rx_id[0])
|
||||||
|
{
|
||||||
|
rx_id[0] = 0x01;
|
||||||
|
rx_id[1] = packet_in[1];
|
||||||
|
rx_id[2] = packet_in[2];
|
||||||
|
rx_tx_addr[2] ^= packet_in[1];
|
||||||
|
rx_tx_addr[3] ^= packet_in[2];
|
||||||
|
rx_tx_addr[3] |= 0x80;
|
||||||
|
}
|
||||||
|
else if(packet_in[0] == 0xB5 && rx_id[0])
|
||||||
|
{
|
||||||
|
BIND_DONE;
|
||||||
|
XN297_SetTXAddr(rx_tx_addr, 4);
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
bind_phase = REALACC_WLV8TX_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint16_t REALACC_callback()
|
uint16_t REALACC_callback()
|
||||||
{
|
{
|
||||||
#ifdef MULTI_SYNC
|
#ifdef MULTI_SYNC
|
||||||
telemetry_set_input_sync(REALACC_PACKET_PERIOD);
|
telemetry_set_input_sync(REALACC_PACKET_PERIOD);
|
||||||
#endif
|
#endif
|
||||||
XN297_SetPower();
|
XN297_SetPower();
|
||||||
|
|
||||||
|
#ifdef MULTI_AIR
|
||||||
|
if(sub_protocol == REALACC_WLV8TX)
|
||||||
|
{
|
||||||
|
SUB_PROTO_INVALID;
|
||||||
|
return 10000;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if(sub_protocol == REALACC_WLV8TX)
|
||||||
|
{
|
||||||
|
if(bind_phase == REALACC_WLV8TX_DATA)
|
||||||
|
{
|
||||||
|
XN297_SetTxRxMode(TX_EN);
|
||||||
|
REALACC_send_packet();
|
||||||
|
return WLV8TX_PACKET_PERIOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bind_phase == REALACC_WLV8TX_BIND_RX_SETUP)
|
||||||
|
{
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
XN297_SetTxRxMode(RX_EN);
|
||||||
|
bind_phase = REALACC_WLV8TX_BIND_RX_CHECK;
|
||||||
|
return WLV8TX_PACKET_PERIOD/3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bind_phase == REALACC_WLV8TX_BIND_RX_CHECK)
|
||||||
|
{
|
||||||
|
REALACC_wlv8tx_process_rx();
|
||||||
|
if(bind_phase == REALACC_WLV8TX_DATA)
|
||||||
|
return WLV8TX_PACKET_PERIOD;
|
||||||
|
bind_phase = REALACC_WLV8TX_BIND_TX;
|
||||||
|
return WLV8TX_PACKET_PERIOD/3;
|
||||||
|
}
|
||||||
|
//Bind Phase
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
XN297_SetTxRxMode(TX_EN);
|
||||||
|
REALACC_send_bind_packet();
|
||||||
|
bind_phase = REALACC_WLV8TX_BIND_RX_SETUP;
|
||||||
|
return WLV8TX_PACKET_PERIOD/3;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
XN297_SetTxRxMode(TX_EN);
|
XN297_SetTxRxMode(TX_EN);
|
||||||
if(IS_BIND_IN_PROGRESS)
|
if(IS_BIND_IN_PROGRESS)
|
||||||
{
|
{
|
||||||
@@ -119,7 +272,20 @@ void REALACC_init()
|
|||||||
BIND_IN_PROGRESS; // autobind protocol
|
BIND_IN_PROGRESS; // autobind protocol
|
||||||
REALACC_initialize_txid();
|
REALACC_initialize_txid();
|
||||||
REALACC_RF_init();
|
REALACC_RF_init();
|
||||||
bind_counter=REALACC_BIND_COUNT;
|
#ifndef MULTI_AIR
|
||||||
|
if(sub_protocol == REALACC_WLV8TX)
|
||||||
|
{
|
||||||
|
rx_id[0] = 0; // realacc_wlv8tx_rx_b3
|
||||||
|
rx_id[1] = 0;
|
||||||
|
rx_id[2] = 0;
|
||||||
|
bind_phase = REALACC_WLV8TX_BIND_TX;
|
||||||
|
memcpy(packet, realacc_bind_packet, 4);
|
||||||
|
packet[3] |= 0x80;
|
||||||
|
XN297_SetRXAddr(packet, 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
bind_counter=REALACC_BIND_COUNT;
|
||||||
hopping_frequency_no=0;
|
hopping_frequency_no=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,18 +295,63 @@ void REALACC_init()
|
|||||||
// Bind
|
// Bind
|
||||||
// Address = 4D 41 49 4E = 'MAIN'
|
// Address = 4D 41 49 4E = 'MAIN'
|
||||||
// Channel = 80 (most likely from dump)
|
// Channel = 80 (most likely from dump)
|
||||||
// P(10) = B1 99 06 00 00 55 59 5A 5A 62
|
// TX1
|
||||||
// B1 indicates bind packet
|
// ---
|
||||||
|
// P(10) = B1 99 06 00 00 55 59 5A 5A 62
|
||||||
|
// Bx indicates bind packet, why x=1?
|
||||||
// 99 06 00 00 = ID = address of normal packets
|
// 99 06 00 00 = ID = address of normal packets
|
||||||
// 55 59 5A 5A 62 = 85, 89, 90, 90, 98 = RF channels to be used (kind of match previous dumps)// Normal
|
// 55 59 5A 5A 62 = 85, 89, 90, 90, 98 = RF channels to be used (kind of match previous dumps)
|
||||||
|
// TX2
|
||||||
|
// ---
|
||||||
|
// P(10) = B0 4F B9 A1 17 45 38 3C 41 3F
|
||||||
|
// Bx indicates bind packet, why x=0?
|
||||||
|
// 4F B9 A1 17 = ID = address of normal packets
|
||||||
|
// 45 38 3C 41 3F = 69, 56, 60, 65, 63 = RF channels to be used
|
||||||
|
// WLtoys Car 284019A V8-Tx
|
||||||
|
// ------> TX sends
|
||||||
|
// P(10)= B1 32 E9 DE 0A 45 42 38 3C 4A
|
||||||
|
// B1 indicates bind packet
|
||||||
|
// 32 E9 DE 0A = ID -> address of normal TX packets before bind
|
||||||
|
// 45 42 38 3C 4A = 69, 66, 56, 60, 74 -> RF channels to be used
|
||||||
|
// P(12)= B4 D4 E9 32 E9 DE 0A 45 42 38 3C 4A -> B4 designates TX found RX?, P(10) to P(12), TX inserts packet[1] and [2] from RX
|
||||||
|
// 32 E9 0A E3 = ID -> address of normal TX packets after bind (XOR rx_tx_addr[2],[3] with values from RX)
|
||||||
|
// ------> RX returns
|
||||||
|
// 32 E9 DE 8A = -> RX ID address returning bind info, same as TX address except (packet[3]|0x80)
|
||||||
|
// P(3)= B3 D4 E9 = B3=bind initiates Tx found, D4=XOR with rx_tx_addr[2], E9=XOR with rx_tx_addr[3]
|
||||||
|
// P(3)= B5 D4 E9 = B5=bind completed
|
||||||
|
// P(6)= 40 83 00 00 00 00 = RX returns on some hopping channels - unknown? telemetry? not used on this model?
|
||||||
// Normal
|
// Normal
|
||||||
// Address = 99 06 00 00
|
// TX1
|
||||||
// Channels = 84, 89, 90, 90, 98 (guess from bind)
|
// ---
|
||||||
// P(13)= DC 80 80 32 80 20 20 20 20 58 04 00 00
|
// Address = 99 06 00 00
|
||||||
// DC = normal packet
|
// Channels = 84, 89, 90, 90, 98 (guess from bind)
|
||||||
// 80 80 32 80 : AETR 00..80..FF
|
// P(13)= DC 80 80 32 80 20 20 20 20 58 04 00 00
|
||||||
// 20 20 20 20 : Trims
|
// Dx = normal packet, why C ?
|
||||||
// 58 : changing every time the TX restart
|
// 80 80 32 80 : AETR 00..80..FF
|
||||||
// 04 : |0x20=headless, |0x01=rate2, |0x02=rate3
|
// 20 20 20 20 : Trims
|
||||||
// 00 : |0x01=calib, |0x20=return, |0x80=unknown
|
// 58 : changing every time the TX restart
|
||||||
// 00 : |0x80=light, |0x01=flip
|
// 04 : |0x20=headless, |0x01=rate2, |0x02=rate3
|
||||||
|
// 00 : |0x01=calib, |0x20=return, |0x80=unknown
|
||||||
|
// 00 : |0x80=light, |0x01=flip
|
||||||
|
// TX2
|
||||||
|
// ---
|
||||||
|
// Address = 4F B9 A1 17
|
||||||
|
// P(13)= D6/DE 80 80 80 80 20 20 20 20 88 0C 00 00
|
||||||
|
// Dx = normal packet, why 6/E ?
|
||||||
|
// 80 80 32 80 : AETR 00..80..FF
|
||||||
|
// 20 20 20 20 : Trims
|
||||||
|
// 88 : not changing unknown
|
||||||
|
// 0C : |0x20=headless, |0x01=rate2, |0x02=rate3
|
||||||
|
// 00 : |0x01=calib, |0x20=return, |0x80=unknown
|
||||||
|
// 00 : |0x80=light, |0x01=flip, |0x02=Rotating
|
||||||
|
// WLtoys Car 284019A V8-Tx
|
||||||
|
// ---
|
||||||
|
// Address = 32 E9 DE 0A (before bind), 32 E9 0A E3 (after bind and XOR)
|
||||||
|
// P(13)= DC 80 80 80 80 20 20 20 20 77 0C 00 00
|
||||||
|
// Dx = normal packet, why C ?
|
||||||
|
// 80 80 80 80 : AE=80 TR 00..80..FF
|
||||||
|
// 20 20 20 20 : Gyro Rate, Constant?, Throttle Rate, Steer Trim
|
||||||
|
// 77 : changing every time the TX restart
|
||||||
|
// 0C : Constant?
|
||||||
|
// 00 : Constant?
|
||||||
|
// 00 : Constant?
|
||||||
|
|||||||
@@ -12,13 +12,17 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
// Radiolink surface protocol. TXs: RC4GS,RC6GS. Compatible RXs:R7FG(Std),R6FG,R6F,R8EF,R8FM,R8F,R4FGM
|
// Radiolink surface protocol. TXs: RC4GS,RC6GS. Compatible RXs:R7FG(Std),R6FG,R6F,R8EF,R8FM,R8F,R4FGM
|
||||||
|
|
||||||
#if defined(RLINK_CC2500_INO)
|
#if defined(RLINK_CC2500_INO)
|
||||||
|
|
||||||
#include "iface_cc2500.h"
|
#include "iface_cc2500.h"
|
||||||
|
|
||||||
|
//#define RLINK_DEBUG
|
||||||
|
//#define RLINK_DEBUG_TELEM
|
||||||
|
|
||||||
//#define RLINK_FORCE_ID
|
//#define RLINK_FORCE_ID
|
||||||
|
//#define RLINK_RC4G_FORCE_ID
|
||||||
|
|
||||||
#define RLINK_TX_PACKET_LEN 33
|
#define RLINK_TX_PACKET_LEN 33
|
||||||
#define RLINK_RX_PACKET_LEN 15
|
#define RLINK_RX_PACKET_LEN 15
|
||||||
@@ -33,6 +37,7 @@ enum {
|
|||||||
|
|
||||||
uint32_t RLINK_rand1;
|
uint32_t RLINK_rand1;
|
||||||
uint32_t RLINK_rand2;
|
uint32_t RLINK_rand2;
|
||||||
|
uint32_t RLINK_pseudo;
|
||||||
|
|
||||||
static uint32_t __attribute__((unused)) RLINK_prng_next(uint32_t r)
|
static uint32_t __attribute__((unused)) RLINK_prng_next(uint32_t r)
|
||||||
{
|
{
|
||||||
@@ -80,7 +85,7 @@ static void __attribute__((unused)) RLINK_shuffle_freqs(uint32_t seed)
|
|||||||
static void __attribute__((unused)) RLINK_hop()
|
static void __attribute__((unused)) RLINK_hop()
|
||||||
{
|
{
|
||||||
uint8_t inc=3*(rx_tx_addr[0]&3);
|
uint8_t inc=3*(rx_tx_addr[0]&3);
|
||||||
|
|
||||||
// init hop table
|
// init hop table
|
||||||
for(uint8_t i=0; i<RLINK_HOP; i++)
|
for(uint8_t i=0; i<RLINK_HOP; i++)
|
||||||
hopping_frequency[i] = (12*i) + inc;
|
hopping_frequency[i] = (12*i) + inc;
|
||||||
@@ -89,24 +94,103 @@ static void __attribute__((unused)) RLINK_hop()
|
|||||||
RLINK_shuffle_freqs(RLINK_compute_start_id(rx_tx_addr[0] + (rx_tx_addr[1] << 8)));
|
RLINK_shuffle_freqs(RLINK_compute_start_id(rx_tx_addr[0] + (rx_tx_addr[1] << 8)));
|
||||||
RLINK_shuffle_freqs(RLINK_compute_start_id(rx_tx_addr[2] + (rx_tx_addr[3] << 8)));
|
RLINK_shuffle_freqs(RLINK_compute_start_id(rx_tx_addr[2] + (rx_tx_addr[3] << 8)));
|
||||||
|
|
||||||
// replace one of the channel randomely
|
// replace one of the channel randomly
|
||||||
rf_ch_num=random(0xfefefefe)%0x11; // 0x00..0x10
|
rf_ch_num=random(0xfefefefe)%0x11; // 0x00..0x10
|
||||||
if(inc==9) inc=6; // frequency exception
|
if(inc==9) inc=6; // frequency exception
|
||||||
hopping_frequency[rf_ch_num]=12*16+inc;
|
hopping_frequency[rf_ch_num]=12*16+inc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) RLINK_hop_RC4G()
|
||||||
|
{
|
||||||
|
// Find 2 unused channels
|
||||||
|
// first channel is a multiple of 3 between 00 and 5D
|
||||||
|
// second channel is a multiple of 3 between 63 and BD
|
||||||
|
CC2500_Strobe(CC2500_SIDLE);
|
||||||
|
CC2500_WriteReg(CC2500_17_MCSM1,0x3C);
|
||||||
|
CC2500_Strobe(CC2500_SFRX);
|
||||||
|
CC2500_SetTxRxMode(RX_EN);
|
||||||
|
CC2500_Strobe(CC2500_SRX);
|
||||||
|
delayMilliseconds(1); //wait for RX mode
|
||||||
|
uint16_t val;
|
||||||
|
uint8_t val_low = 0xFF;
|
||||||
|
hopping_frequency[0] = 0x00;
|
||||||
|
hopping_frequency[1] = 0x63;
|
||||||
|
for(uint8_t ch=0; ch<=0xBD; ch+=3)
|
||||||
|
{
|
||||||
|
if(ch==0x63)
|
||||||
|
val_low = 0xFF; //init for second block
|
||||||
|
if(ch==0x60)
|
||||||
|
continue; //skip channel
|
||||||
|
CC2500_WriteReg(CC2500_0A_CHANNR, ch); //switch channel
|
||||||
|
delayMicroseconds(370); //wait to read
|
||||||
|
val = 0;
|
||||||
|
for(uint8_t i=0;i<16;i++)
|
||||||
|
val += CC2500_ReadReg(CC2500_34_RSSI | CC2500_READ_BURST);
|
||||||
|
val >>= 4;
|
||||||
|
debug("C:%02X RSSI:%02X",ch,val);
|
||||||
|
if(val_low > val)
|
||||||
|
{
|
||||||
|
debug(" OK");
|
||||||
|
val_low = val;
|
||||||
|
hopping_frequency[ch<0x63?0:1]=ch; //save best channel
|
||||||
|
}
|
||||||
|
debugln("");
|
||||||
|
}
|
||||||
|
CC2500_WriteReg(CC2500_17_MCSM1,0x30);
|
||||||
|
CC2500_Strobe(CC2500_SIDLE);
|
||||||
|
CC2500_SetTxRxMode(TX_EN);
|
||||||
|
#ifdef RLINK_RC4G_FORCE_ID
|
||||||
|
hopping_frequency[0] = 0x03;
|
||||||
|
hopping_frequency[1] = 0x6F;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// calc next pseudo random value
|
||||||
|
static void __attribute__((unused)) RLINK_next_pseudo()
|
||||||
|
{
|
||||||
|
RLINK_pseudo = ((RLINK_pseudo * 0xAA) + 0x03) % 0x7673;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) RLINK_set_next_channel()
|
||||||
|
{
|
||||||
|
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[RLINK_pseudo & 0x0F]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t __attribute__((unused)) RLINK_checksum(const uint8_t *data, uint8_t payload_len, bool include_id=false)
|
||||||
|
{
|
||||||
|
uint8_t sum=0;
|
||||||
|
for(uint8_t i=0;i<payload_len;i++)
|
||||||
|
sum+=data[i];
|
||||||
|
if(include_id)
|
||||||
|
for(uint8_t i=0;i<RLINK_TX_ID_LEN;i++)
|
||||||
|
sum+=rx_tx_addr[i];
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
static void __attribute__((unused)) RLINK_TXID_init()
|
static void __attribute__((unused)) RLINK_TXID_init()
|
||||||
{
|
{
|
||||||
|
#ifdef RLINK_RC4G_FORCE_ID
|
||||||
|
//TODO: test any ID
|
||||||
|
if(sub_protocol==RLINK_RC4G)
|
||||||
|
{
|
||||||
|
rx_tx_addr[1]=0x77;
|
||||||
|
rx_tx_addr[2]=0x00;
|
||||||
|
rx_tx_addr[3]=0x00;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef RLINK_FORCE_ID
|
#ifdef RLINK_FORCE_ID
|
||||||
//surface RC6GS
|
if(sub_protocol==RLINK_SURFACE)
|
||||||
memcpy(rx_tx_addr,"\x3A\x99\x22\x3A",RLINK_TX_ID_LEN);
|
memcpy(rx_tx_addr,"\x3A\x99\x22\x3A",RLINK_TX_ID_LEN); //surface RC6GS
|
||||||
//air T8FB
|
else
|
||||||
//memcpy(rx_tx_addr,"\xFC\x11\x0D\x20",RLINK_TX_ID_LEN);
|
memcpy(rx_tx_addr,"\xFC\x11\x0D\x20",RLINK_TX_ID_LEN); //air T8FB
|
||||||
#endif
|
#endif
|
||||||
// channels order depend on ID
|
// channels order depend on ID
|
||||||
RLINK_hop();
|
if(sub_protocol==RLINK_RC4G)
|
||||||
|
RLINK_hop_RC4G();
|
||||||
|
else
|
||||||
|
RLINK_hop();
|
||||||
|
|
||||||
#if 0
|
#ifdef RLINK_DEBUG
|
||||||
debug("ID:");
|
debug("ID:");
|
||||||
for(uint8_t i=0;i<RLINK_TX_ID_LEN;i++)
|
for(uint8_t i=0;i<RLINK_TX_ID_LEN;i++)
|
||||||
debug(" 0x%02X",rx_tx_addr[i]);
|
debug(" 0x%02X",rx_tx_addr[i]);
|
||||||
@@ -133,20 +217,21 @@ static void __attribute__((unused)) RLINK_rf_init()
|
|||||||
for (uint8_t i = 0; i < 39; ++i)
|
for (uint8_t i = 0; i < 39; ++i)
|
||||||
CC2500_WriteReg(i, pgm_read_byte_near(&RLINK_init_values[i]));
|
CC2500_WriteReg(i, pgm_read_byte_near(&RLINK_init_values[i]));
|
||||||
|
|
||||||
if(sub_protocol==RLINK_DUMBORC)
|
if(sub_protocol == RLINK_DUMBORC || sub_protocol == RLINK_DUMBORC_P)
|
||||||
{
|
{
|
||||||
CC2500_WriteReg(4, 0xBA);
|
CC2500_WriteReg(4, 0xBA);
|
||||||
CC2500_WriteReg(5, 0xDC);
|
CC2500_WriteReg(5, 0xDC);
|
||||||
}
|
}
|
||||||
|
else if(sub_protocol==RLINK_RC4G)
|
||||||
|
CC2500_WriteReg(5, 0xA5);
|
||||||
|
|
||||||
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
|
||||||
|
|
||||||
CC2500_SetTxRxMode(TX_EN);
|
CC2500_SetTxRxMode(TX_EN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((unused)) RLINK_send_packet()
|
static void __attribute__((unused)) RLINK_send_packet()
|
||||||
{
|
{
|
||||||
static uint32_t pseudo=0;
|
|
||||||
uint32_t bits = 0;
|
uint32_t bits = 0;
|
||||||
uint8_t bitsavailable = 0;
|
uint8_t bitsavailable = 0;
|
||||||
uint8_t idx = 6;
|
uint8_t idx = 6;
|
||||||
@@ -165,17 +250,18 @@ static void __attribute__((unused)) RLINK_send_packet()
|
|||||||
{
|
{
|
||||||
case RLINK_SURFACE:
|
case RLINK_SURFACE:
|
||||||
packet[1] |= 0x01;
|
packet[1] |= 0x01;
|
||||||
//radiolink additionnal ID which is working only on a small set of RXs
|
//radiolink additional ID which is working only on a small set of RXs
|
||||||
//if(RX_num) packet[1] |= ((RX_num+2)<<4)+4; // RX number limited to 10 values, 0 is a wildcard
|
//if(RX_num) packet[1] |= ((RX_num+2)<<4)+4; // RX number limited to 10 values, 0 is a wildcard
|
||||||
break;
|
break;
|
||||||
case RLINK_AIR:
|
case RLINK_AIR:
|
||||||
packet[1] |= 0x21; //air 0x21 on dump but it looks to support telemetry at least RSSI
|
packet[1] |= 0x21; //air 0x21 on dump but it looks to support telemetry at least RSSI
|
||||||
break;
|
break;
|
||||||
case RLINK_DUMBORC:
|
case RLINK_DUMBORC:
|
||||||
packet[1] = 0x00; //always 0x00 on dump
|
case RLINK_DUMBORC_P:
|
||||||
|
packet[1] |= 0x01; //always 0x00 on dump but does appear to support telemtry on newer transmitters
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID
|
// ID
|
||||||
memcpy(&packet[2],rx_tx_addr,RLINK_TX_ID_LEN);
|
memcpy(&packet[2],rx_tx_addr,RLINK_TX_ID_LEN);
|
||||||
|
|
||||||
@@ -196,41 +282,176 @@ static void __attribute__((unused)) RLINK_send_packet()
|
|||||||
bitsavailable -= 8;
|
bitsavailable -= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hop
|
// hop
|
||||||
pseudo=((pseudo * 0xAA) + 0x03) % 0x7673; // calc next pseudo random value
|
RLINK_next_pseudo();
|
||||||
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[pseudo & 0x0F]);
|
RLINK_set_next_channel();
|
||||||
packet[28]= pseudo;
|
packet[28]= RLINK_pseudo;
|
||||||
packet[29]= pseudo >> 8;
|
packet[29]= RLINK_pseudo >> 8;
|
||||||
packet[30]= 0x00; // unknown
|
packet[30]= 0x00; // unknown
|
||||||
packet[31]= 0x00; // unknown
|
packet[31]= 0x00; // unknown
|
||||||
packet[32]= rf_ch_num; // index of value changed in the RF table
|
packet[32]= rf_ch_num; // index of value changed in the RF table
|
||||||
|
|
||||||
// check
|
// check
|
||||||
uint8_t sum=0;
|
packet[33]=RLINK_checksum(&packet[1], RLINK_TX_PACKET_LEN-1);
|
||||||
for(uint8_t i=1;i<33;i++)
|
|
||||||
sum+=packet[i];
|
|
||||||
packet[33]=sum;
|
|
||||||
|
|
||||||
// send packet
|
// send packet
|
||||||
CC2500_WriteData(packet, RLINK_TX_PACKET_LEN+1);
|
CC2500_WriteData(packet, RLINK_TX_PACKET_LEN+1);
|
||||||
|
|
||||||
// packets type
|
// packets type
|
||||||
packet_count++;
|
packet_count++;
|
||||||
if(packet_count>5) packet_count=0;
|
if(packet_count>5) packet_count=0;
|
||||||
|
|
||||||
//debugln("C= 0x%02X",hopping_frequency[pseudo & 0x0F]);
|
#ifdef RLINK_DEBUG
|
||||||
//debug("P=");
|
debugln("C= 0x%02X",hopping_frequency[RLINK_pseudo & 0x0F]);
|
||||||
//for(uint8_t i=1;i<RLINK_TX_PACKET_LEN+1;i++)
|
debug("P=");
|
||||||
// debug(" 0x%02X",packet[i]);
|
for(uint8_t i=1;i<RLINK_TX_PACKET_LEN+1;i++)
|
||||||
//debugln("");
|
debug(" 0x%02X",packet[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RLINK_HUB_TELEMETRY
|
||||||
|
|
||||||
|
static bool __attribute__((unused)) RLINK_DUMBORC_send_command()
|
||||||
|
{
|
||||||
|
if(!RLINK_SerialRX || sub_protocol != RLINK_DUMBORC_P)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RLINK_SerialRX=false;
|
||||||
|
|
||||||
|
if(RLINK_SerialRX_len > sizeof(RLINK_SerialRX_val))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CC2500_Strobe(CC2500_SIDLE);
|
||||||
|
|
||||||
|
RLINK_next_pseudo();
|
||||||
|
RLINK_set_next_channel();
|
||||||
|
|
||||||
|
packet[0] = RLINK_SerialRX_len;
|
||||||
|
memcpy(&packet[1], RLINK_SerialRX_val, RLINK_SerialRX_len);
|
||||||
|
packet[2] = RLINK_pseudo;
|
||||||
|
packet[3] = RLINK_pseudo >> 8;
|
||||||
|
// special packages have id check embedded in checksum
|
||||||
|
packet[RLINK_SerialRX_len] = RLINK_checksum(&packet[1], RLINK_SerialRX_len - 1, true);
|
||||||
|
|
||||||
|
CC2500_WriteData(packet, RLINK_SerialRX_len + 1);
|
||||||
|
|
||||||
|
packet_count++;
|
||||||
|
if(packet_count>5) packet_count=0;
|
||||||
|
|
||||||
|
#ifdef RLINK_DEBUG
|
||||||
|
debugln("C= 0x%02X",hopping_frequency[RLINK_pseudo & 0x0F]);
|
||||||
|
debug("DumboRC P command=");
|
||||||
|
for(uint8_t i=1;i<packet[0]+1;i++)
|
||||||
|
debug(" 0x%02X",packet[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// logic is rougly copied from ddf-350, which in itself seems to be based on cc2500 docs
|
||||||
|
static uint8_t __attribute__((unused)) RLINK_DUMBORC_tele_rssi_as_percent(uint8_t rssi)
|
||||||
|
{
|
||||||
|
if(rssi < 15)
|
||||||
|
rssi=15;
|
||||||
|
else if(rssi > 90)
|
||||||
|
rssi=90;
|
||||||
|
return ((90 - rssi) * 100) / 75;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __attribute__((unused)) RLINK_DUMBORC_validate_telemetry_packet(const uint8_t *data)
|
||||||
|
{
|
||||||
|
const uint8_t declaredLen = data[0];
|
||||||
|
|
||||||
|
if(data[1] == 0x00)
|
||||||
|
{
|
||||||
|
// telemetry package follows base radiolink procotol with slightly less rules
|
||||||
|
if(declaredLen != RLINK_RX_PACKET_LEN || memcmp(&data[2], rx_tx_addr, RLINK_TX_ID_LEN) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// telemetry packages do not have id check embeeded in checksum, just like base RadioLink
|
||||||
|
return data[RLINK_RX_PACKET_LEN] == RLINK_checksum(&data[1], RLINK_RX_PACKET_LEN - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sub_protocol != RLINK_DUMBORC_P)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// special packages have id check embedded in checksum
|
||||||
|
return data[declaredLen] == RLINK_checksum(&data[1], declaredLen - 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef MULTI_AIR
|
||||||
|
static void __attribute__((unused)) RLINK_RC4G_send_packet()
|
||||||
|
{
|
||||||
|
uint32_t val;
|
||||||
|
//hop
|
||||||
|
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[packet_count>>1]);
|
||||||
|
#ifdef RLINK_DEBUG
|
||||||
|
debug("C= 0x%02X ",hopping_frequency[packet_count>>1]);
|
||||||
|
#endif
|
||||||
|
// packet length
|
||||||
|
packet[0] = 0x0F;
|
||||||
|
//address
|
||||||
|
memcpy(&packet[1], &rx_tx_addr[1], 3);
|
||||||
|
//channels
|
||||||
|
for(uint8_t i=0;i<2;i++)
|
||||||
|
{
|
||||||
|
val = Channel_data[2*i ] +400 -24;
|
||||||
|
packet[4+i*2] = val;
|
||||||
|
packet[8+i ] = val>>8;
|
||||||
|
val = Channel_data[2*i+1] +400 -24;
|
||||||
|
packet[5+i*2] = val;
|
||||||
|
packet[8+i ] |= (val>>4) & 0xF0;
|
||||||
|
}
|
||||||
|
//special channel which is linked to gyro on the original TX but allocating it on CH5 here
|
||||||
|
packet[10] = convert_channel_16b_limit(CH5,0,100);
|
||||||
|
//failsafe
|
||||||
|
for(uint8_t i=0;i<4;i++)
|
||||||
|
packet[11+i] = convert_channel_16b_limit(CH6+i,0,200);
|
||||||
|
//next hop
|
||||||
|
packet_count++;
|
||||||
|
packet_count &= 0x03;
|
||||||
|
packet[15] = hopping_frequency[packet_count>>1];
|
||||||
|
// send packet
|
||||||
|
CC2500_WriteData(packet, 16);
|
||||||
|
|
||||||
|
#ifdef RLINK_DEBUG
|
||||||
|
debug("P=");
|
||||||
|
for(uint8_t i=1;i<16;i++)
|
||||||
|
debug(" 0x%02X",packet[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined RLINK_HUB_TELEMETRY
|
||||||
|
uint16_t RLINK_timing_last_rfsend = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define RLINK_TIMING_PROTO 20000-100 // -100 for compatibility with R8EF
|
#define RLINK_TIMING_PROTO 20000-100 // -100 for compatibility with R8EF
|
||||||
#define RLINK_TIMING_RFSEND 10500
|
#define RLINK_TIMING_RFSEND 10500
|
||||||
#define RLINK_TIMING_CHECK 2000
|
#define RLINK_TIMING_CHECK 2000
|
||||||
|
#define RLINK_RC4G_TIMING_PROTO 14460
|
||||||
|
#define RLINK_DUMBORC_COMMAND_RFSEND 5000
|
||||||
uint16_t RLINK_callback()
|
uint16_t RLINK_callback()
|
||||||
{
|
{
|
||||||
|
if(sub_protocol == RLINK_RC4G)
|
||||||
|
{
|
||||||
|
#ifndef MULTI_AIR
|
||||||
|
#ifdef MULTI_SYNC
|
||||||
|
telemetry_set_input_sync(RLINK_RC4G_TIMING_PROTO);
|
||||||
|
#endif
|
||||||
|
CC2500_SetPower();
|
||||||
|
CC2500_SetFreqOffset();
|
||||||
|
RLINK_RC4G_send_packet();
|
||||||
|
#else
|
||||||
|
SUB_PROTO_INVALID;
|
||||||
|
#endif
|
||||||
|
return RLINK_RC4G_TIMING_PROTO;
|
||||||
|
}
|
||||||
switch(phase)
|
switch(phase)
|
||||||
{
|
{
|
||||||
case RLINK_DATA:
|
case RLINK_DATA:
|
||||||
@@ -239,46 +460,96 @@ uint16_t RLINK_callback()
|
|||||||
#endif
|
#endif
|
||||||
CC2500_SetPower();
|
CC2500_SetPower();
|
||||||
CC2500_SetFreqOffset();
|
CC2500_SetFreqOffset();
|
||||||
RLINK_send_packet();
|
|
||||||
#if not defined RLINK_HUB_TELEMETRY
|
#if not defined RLINK_HUB_TELEMETRY
|
||||||
return RLINK_TIMING_PROTO;
|
RLINK_send_packet();
|
||||||
|
return RLINK_TIMING_PROTO; // RLINK_DATA
|
||||||
#else
|
#else
|
||||||
|
if(RLINK_DUMBORC_send_command())
|
||||||
|
{
|
||||||
|
phase++; // RX1
|
||||||
|
RLINK_timing_last_rfsend = RLINK_DUMBORC_COMMAND_RFSEND;
|
||||||
|
return RLINK_timing_last_rfsend;
|
||||||
|
}
|
||||||
|
|
||||||
|
RLINK_send_packet();
|
||||||
|
|
||||||
if(!(packet[1]&0x02))
|
if(!(packet[1]&0x02))
|
||||||
return RLINK_TIMING_PROTO; //Normal packet
|
return RLINK_TIMING_PROTO; // Normal packet -> RLINK_DATA
|
||||||
//Telemetry packet
|
// Telemetry packet
|
||||||
phase++; // RX1
|
phase++; // RX1
|
||||||
return RLINK_TIMING_RFSEND;
|
RLINK_timing_last_rfsend = RLINK_TIMING_RFSEND;
|
||||||
|
return RLINK_timing_last_rfsend;
|
||||||
case RLINK_RX1:
|
case RLINK_RX1:
|
||||||
CC2500_Strobe(CC2500_SIDLE);
|
CC2500_Strobe(CC2500_SIDLE);
|
||||||
CC2500_Strobe(CC2500_SFRX);
|
CC2500_Strobe(CC2500_SFRX);
|
||||||
CC2500_SetTxRxMode(RX_EN);
|
CC2500_SetTxRxMode(RX_EN);
|
||||||
CC2500_Strobe(CC2500_SRX);
|
CC2500_Strobe(CC2500_SRX);
|
||||||
phase++; // RX2
|
phase++; // RX2
|
||||||
return RLINK_TIMING_PROTO-RLINK_TIMING_RFSEND-RLINK_TIMING_CHECK;
|
return RLINK_TIMING_PROTO-RLINK_timing_last_rfsend-RLINK_TIMING_CHECK;
|
||||||
case RLINK_RX2:
|
case RLINK_RX2:
|
||||||
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||||
if (len == RLINK_RX_PACKET_LEN + 1 + 2) //Telemetry frame is 15 bytes + 1 byte for length + 2 bytes for RSSI&LQI&CRC
|
const bool dumborc_family = sub_protocol == RLINK_DUMBORC || sub_protocol == RLINK_DUMBORC_P;
|
||||||
|
//Telemetry frame is 15 bytes + 1 byte for length + 2 bytes for RSSI&LQI&CRC
|
||||||
|
const bool rlink_telem_len = !dumborc_family && len == RLINK_RX_PACKET_LEN + 1 + 2;
|
||||||
|
// length byte + type byte + checksum byte + RSSI/LQI/CRC
|
||||||
|
const bool dumborc_len = dumborc_family && len >= 5 && len <= sizeof(packet_in);
|
||||||
|
if (rlink_telem_len || dumborc_len)
|
||||||
{
|
{
|
||||||
//debug("Telem:");
|
#ifdef RLINK_DEBUG_TELEM
|
||||||
|
debug("Telem:");
|
||||||
|
#endif
|
||||||
CC2500_ReadData(packet_in, len);
|
CC2500_ReadData(packet_in, len);
|
||||||
if(packet_in[0]==RLINK_RX_PACKET_LEN && (packet_in[len-1] & 0x80) && memcmp(&packet[2],rx_tx_addr,RLINK_TX_ID_LEN)==0 && packet_in[6]==packet[1])
|
if(len >= 3 && packet_in[0] == len - 3 && (packet_in[len-1] & 0x80))
|
||||||
{//Correct telemetry received: length, CRC, ID and type
|
{//Telemetry received with correct length and CC2500 CRC
|
||||||
//Debug
|
#ifdef RLINK_DEBUG_TELEM
|
||||||
//for(uint8_t i=0;i<len;i++)
|
for(uint8_t i=0;i<len;i++)
|
||||||
// debug(" %02X",packet_in[i]);
|
debug(" %02X",packet_in[i]);
|
||||||
TX_RSSI = packet_in[len-2];
|
#endif
|
||||||
if(TX_RSSI >=128)
|
bool valid_telem=false;
|
||||||
TX_RSSI -= 128;
|
if(dumborc_family)
|
||||||
else
|
{
|
||||||
TX_RSSI += 128;
|
if(RLINK_DUMBORC_validate_telemetry_packet(packet_in))
|
||||||
RX_RSSI=packet_in[7]&0x7F; //Should be packet_in[7]-256 but since it's an uint8_t...
|
{
|
||||||
v_lipo1=packet_in[8]<<1; //RX Batt
|
if(packet_in[1] == 0x00)
|
||||||
v_lipo2=packet_in[9]; //Batt
|
{
|
||||||
telemetry_link=1; //Send telemetry out
|
uint8_t tele_rssi = RLINK_DUMBORC_tele_rssi_as_percent(packet_in[7]);
|
||||||
pps_counter++;
|
uint16_t ext_v = packet_in[9] | (((uint16_t)packet_in[10]) << 8);
|
||||||
packet_count=0;
|
uint16_t direct_rssi = packet_in[11] | (((uint16_t)packet_in[12]) << 8);
|
||||||
|
direct_rssi = direct_rssi > 100 ? 100 : direct_rssi;
|
||||||
|
RX_RSSI = direct_rssi ? direct_rssi : tele_rssi;
|
||||||
|
v_lipo1 = 0; //Has no RX batt
|
||||||
|
v_lipo2 = ext_v > 255 ? 255 : ext_v; //Batt in same position as base radiolink
|
||||||
|
valid_telem=true;
|
||||||
|
}
|
||||||
|
else if(sub_protocol == RLINK_DUMBORC_P)
|
||||||
|
{
|
||||||
|
telemetry_link=2; // Raw DumboRC P packet to Lua/multiBuffer handling.
|
||||||
|
pps_counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(packet_in[0] == RLINK_RX_PACKET_LEN && memcmp(&packet[2],rx_tx_addr,RLINK_TX_ID_LEN)==0 && packet_in[6]==packet[1])
|
||||||
|
{
|
||||||
|
RX_RSSI=packet_in[7]&0x7F; //Should be packet_in[7]-256 but since it's an uint8_t...
|
||||||
|
v_lipo1=packet_in[8]<<1; //RX Batt
|
||||||
|
v_lipo2=packet_in[9]; //Batt
|
||||||
|
valid_telem=true;
|
||||||
|
}
|
||||||
|
if(valid_telem)
|
||||||
|
{
|
||||||
|
TX_RSSI = packet_in[len-2];
|
||||||
|
if(TX_RSSI >=128)
|
||||||
|
TX_RSSI -= 128;
|
||||||
|
else
|
||||||
|
TX_RSSI += 128;
|
||||||
|
telemetry_link=1; //Send telemetry out
|
||||||
|
pps_counter++;
|
||||||
|
packet_count=0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//debugln("");
|
#ifdef RLINK_DEBUG_TELEM
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (millis() - pps_timer >= 2000)
|
if (millis() - pps_timer >= 2000)
|
||||||
{//1 telemetry packet every 100ms
|
{//1 telemetry packet every 100ms
|
||||||
@@ -308,4 +579,4 @@ void RLINK_init()
|
|||||||
phase = RLINK_DATA;
|
phase = RLINK_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
308
Multiprotocol/SGF22_nrf24l01.ino
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
This project is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Multiprotocol is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// Compatible with SGF22, ParkTen F22S, KF700 J20
|
||||||
|
|
||||||
|
#if defined(SGF22_NRF24L01_INO)
|
||||||
|
|
||||||
|
#include "iface_xn297.h"
|
||||||
|
|
||||||
|
//#define FORCE_SGF22_ORIGINAL_ID
|
||||||
|
#define FORCE_SGF22_CX10_ORIGINAL_ID
|
||||||
|
|
||||||
|
#define SGF22_PACKET_PERIOD 11950 //10240
|
||||||
|
#define SGF22_PAYLOAD_SIZE 12
|
||||||
|
#define SGF22_BIND_COUNT 50
|
||||||
|
#define SGF22_RF_NUM_CHANNELS 4
|
||||||
|
#define SGF22_BIND_RF_CHANNEL 78
|
||||||
|
#define SGF22_F22S_BIND_RF_CHANNEL 10
|
||||||
|
#define SGF22_J20_BIND_RF_CHANNEL 28
|
||||||
|
#define SGF22_CX10_BIND_RF_CHANNEL 48
|
||||||
|
|
||||||
|
//packet[8]
|
||||||
|
#define SGF22_FLAG_3D 0x00
|
||||||
|
#define SGF22_FLAG_LIGHT 0x04
|
||||||
|
#define SGF22_FLAG_ROLL 0x08
|
||||||
|
#define SGF22_FLAG_VIDEO 0x10
|
||||||
|
#define SGF22_FLAG_6G 0x40
|
||||||
|
#define SGF22_FLAG_VERTICAL 0xC0
|
||||||
|
|
||||||
|
#define SGF22_J20_FLAG_HORIZONTAL 0x80
|
||||||
|
//#define SGF22_J20_FLAG_SPEED 0x01 // Up/Down trim, not implemented
|
||||||
|
|
||||||
|
#define SGF22_FX922_FLAG_BALANCEHIGH 0x01
|
||||||
|
#define SGF22_FX922_FLAG_BALANCE 0x02
|
||||||
|
|
||||||
|
|
||||||
|
//packet[9]
|
||||||
|
#define SGF22_FLAG_TRIMRESET 0x04
|
||||||
|
#define SGF22_FLAG_PHOTO 0x40 // #define SGF22_J20_FLAG_INVERT 0x40
|
||||||
|
#define SGF22_J20_FLAG_FIXHEIGHT 0x80
|
||||||
|
|
||||||
|
#define SGF22_WRITE_TIME 1000
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SGF22_DATA1,
|
||||||
|
SGF22_DATA2,
|
||||||
|
SGF22_DATA3,
|
||||||
|
SGF22_RX,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void __attribute__((unused)) SGF22_send_packet()
|
||||||
|
{
|
||||||
|
if(IS_BIND_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
packet[ 0] = 0x5B;
|
||||||
|
packet[ 8] = 0x00; // ??? do they have to be 0 for bind to succeed ?
|
||||||
|
packet[ 9] = 0x00; // ??? do they have to be 0 for bind to succeed ?
|
||||||
|
packet[10] = 0xAA;
|
||||||
|
packet[11] = 0x55;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//hop
|
||||||
|
XN297_Hopping(packet_sent & 0x03); // ??? from the dumps I can't really say how hop and seq are sync, there could be an offset (0,1,2,3)...
|
||||||
|
//sequence from 02 to 7A by increments of 4, sometimes with a flag 0x80 from 82 to FA, I can't tell from the dumps when the switch happens
|
||||||
|
if( (packet_sent & 0x03) == 0x02)
|
||||||
|
packet_count = packet_sent;
|
||||||
|
packet_sent++;
|
||||||
|
if(packet_sent > 0x7B)
|
||||||
|
packet_sent = 0;
|
||||||
|
//packet
|
||||||
|
packet[0] = 0x1B;
|
||||||
|
if (sub_protocol != SGF22_CX10)
|
||||||
|
{//SGF22_F22,SGF22_F22S,SGF22_J20
|
||||||
|
packet[8] = SGF22_FLAG_3D // CH5 -100%, F22 & F22S - 3D mode, J20 - Gyro off
|
||||||
|
| GET_FLAG(CH6_SW, SGF22_FLAG_ROLL) // roll
|
||||||
|
| GET_FLAG(CH7_SW, SGF22_FLAG_LIGHT) // push up throttle trim for light in the stock TX
|
||||||
|
| GET_FLAG(CH9_SW, SGF22_FLAG_VIDEO) // push down throttle trim for video in the stock TX
|
||||||
|
| GET_FLAG(CH11_SW, SGF22_FX922_FLAG_BALANCE)
|
||||||
|
| GET_FLAG(CH12_SW, SGF22_FX922_FLAG_BALANCEHIGH);
|
||||||
|
if(Channel_data[CH5] > CHANNEL_MAX_COMMAND)
|
||||||
|
packet[8] |= SGF22_FLAG_VERTICAL; // CH5 100%, vertical mode (torque)
|
||||||
|
else if(Channel_data[CH5] > CHANNEL_MIN_COMMAND )
|
||||||
|
packet[8] |= ( sub_protocol == SGF22_J20 ? SGF22_J20_FLAG_HORIZONTAL : SGF22_FLAG_6G ); // CH5 0%, F22 & F22S - 6G mode, J20 - Horizontal mode
|
||||||
|
}
|
||||||
|
else //SGF22_CX10 114548
|
||||||
|
{
|
||||||
|
if(CH6_SW)
|
||||||
|
flags = 0x06; // high rate
|
||||||
|
else
|
||||||
|
if(Channel_data[CH6] < CHANNEL_MIN_COMMAND)
|
||||||
|
flags = 0x04; // low rate
|
||||||
|
else
|
||||||
|
flags = 0x05; // mid rate
|
||||||
|
packet[8] = flags
|
||||||
|
| GET_FLAG(CH5_SW, 0x08); // flip
|
||||||
|
}
|
||||||
|
packet[9] = GET_FLAG(CH8_SW, SGF22_FLAG_PHOTO) // F22: photo, press in throttle trim in the stock TX, J20: invert flight
|
||||||
|
| GET_FLAG(CH10_SW, ( sub_protocol == SGF22_J20 ? SGF22_J20_FLAG_FIXHEIGHT : SGF22_FLAG_TRIMRESET )) ; // F22: Both sticks down inwards in the stock TX, J20: Altitude hold
|
||||||
|
packet[10] = 0x42; // no fine tune
|
||||||
|
packet[11] = 0x10; // no fine tune
|
||||||
|
}
|
||||||
|
if(sub_protocol == SGF22_F22S)
|
||||||
|
packet[0] += 6;
|
||||||
|
else if (sub_protocol == SGF22_J20)
|
||||||
|
packet[0] += 3;
|
||||||
|
else if (sub_protocol == SGF22_CX10)
|
||||||
|
packet[0] += 0x6A;
|
||||||
|
packet[1] = packet_count; // sequence
|
||||||
|
packet[2] = rx_tx_addr[2];
|
||||||
|
packet[3] = rx_tx_addr[3];
|
||||||
|
packet[4] = convert_channel_8b(THROTTLE);
|
||||||
|
packet[5] = convert_channel_8b(RUDDER);
|
||||||
|
packet[6] = convert_channel_8b(ELEVATOR);
|
||||||
|
packet[7] = convert_channel_8b(AILERON);
|
||||||
|
|
||||||
|
XN297_SetPower();
|
||||||
|
XN297_SetTxRxMode(TX_EN);
|
||||||
|
if (sub_protocol != SGF22_CX10)
|
||||||
|
XN297_WriteEnhancedPayload(packet, SGF22_PAYLOAD_SIZE,0);
|
||||||
|
else
|
||||||
|
XN297_WritePayload(packet, SGF22_PAYLOAD_SIZE);
|
||||||
|
#if 0
|
||||||
|
debug_time("");
|
||||||
|
for(uint8_t i=0; i<SGF22_PAYLOAD_SIZE; i++)
|
||||||
|
debug(" %02X",packet[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) SGF22_initialize_txid()
|
||||||
|
{
|
||||||
|
uint16_t val = ( rx_tx_addr[2] << 8 ) | rx_tx_addr[3];
|
||||||
|
if ( rx_tx_addr[2] > ( 0xFF - rx_tx_addr[3]) )
|
||||||
|
val--;
|
||||||
|
val %= 5;
|
||||||
|
|
||||||
|
const uint8_t hop[5][4] =
|
||||||
|
{ { 0x0C, 0x2A, 0x1B, 0x39 },
|
||||||
|
{ 0x0F, 0x2D, 0x1E, 0x3D },
|
||||||
|
{ 0x12, 0x31, 0x21, 0x41 },
|
||||||
|
{ 0x15, 0x34, 0x24, 0x44 },
|
||||||
|
{ 0x18, 0x37, 0x27, 0x47 } };
|
||||||
|
memcpy(hopping_frequency, &hop[val], SGF22_RF_NUM_CHANNELS);
|
||||||
|
|
||||||
|
/*//Same code size...
|
||||||
|
hopping_frequency[0] = 0x0C + 3 * val;
|
||||||
|
hopping_frequency[1] = hopping_frequency[0] + 0x1E;
|
||||||
|
if(val > 1) hopping_frequency[1]++;
|
||||||
|
hopping_frequency[2] = hopping_frequency[0] + 0x0F;
|
||||||
|
hopping_frequency[3] = hopping_frequency[1] + 0x0F;
|
||||||
|
if(val ) hopping_frequency[3]++;*/
|
||||||
|
|
||||||
|
#ifdef FORCE_SGF22_ORIGINAL_ID
|
||||||
|
rx_tx_addr[2] = 0x1F; // TX2:27 TX3:2B
|
||||||
|
rx_tx_addr[3] = 0x61; // TX2:51 TX3:0C
|
||||||
|
memcpy(hopping_frequency,"\x15\x34\x24\x44", SGF22_RF_NUM_CHANNELS); //Original dump=>21=0x15,52=0x34,36=0x24,68=0x44
|
||||||
|
#endif
|
||||||
|
#ifdef FORCE_SGF22_CX10_ORIGINAL_ID
|
||||||
|
if(sub_protocol == SGF22_CX10)
|
||||||
|
{
|
||||||
|
if(rx_tx_addr[3] & 1)
|
||||||
|
{
|
||||||
|
rx_tx_addr[2] = 0x4C;
|
||||||
|
rx_tx_addr[3] = 0xD7;
|
||||||
|
memcpy(hopping_frequency, "\x37\x42\x47\x3c", SGF22_RF_NUM_CHANNELS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx_tx_addr[2] = 0x50;
|
||||||
|
rx_tx_addr[3] = 0xE1;
|
||||||
|
memcpy(hopping_frequency, "\x3b\x4b\x46\x41", SGF22_RF_NUM_CHANNELS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
|
debug("ID: %02X %02X, C: ",rx_tx_addr[2],rx_tx_addr[3]);
|
||||||
|
for(uint8_t i=0; i<SGF22_RF_NUM_CHANNELS; i++)
|
||||||
|
debug(" %02X",hopping_frequency[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) SGF22_RF_init()
|
||||||
|
{
|
||||||
|
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||||
|
XN297_SetTXAddr((uint8_t*)"\xC7\x95\x3C\xBB\xA5", 5);
|
||||||
|
#ifdef SGF22_HUB_TELEMETRY
|
||||||
|
XN297_SetRXAddr((uint8_t*)"\xC7\x95\x3C\xBB\xA5", SGF22_PAYLOAD_SIZE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const uint8_t bind_chan[] = {SGF22_BIND_RF_CHANNEL, SGF22_F22S_BIND_RF_CHANNEL, SGF22_J20_BIND_RF_CHANNEL, SGF22_CX10_BIND_RF_CHANNEL};
|
||||||
|
XN297_RFChannel(bind_chan[sub_protocol]); // Set bind channel
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SGF22_callback()
|
||||||
|
{
|
||||||
|
#ifdef SGF22_HUB_TELEMETRY
|
||||||
|
bool rx = false;
|
||||||
|
static uint8_t telem_count = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch(phase)
|
||||||
|
{
|
||||||
|
case SGF22_DATA1:
|
||||||
|
#ifdef MULTI_SYNC
|
||||||
|
telemetry_set_input_sync(SGF22_PACKET_PERIOD);
|
||||||
|
#endif
|
||||||
|
#ifdef SGF22_HUB_TELEMETRY
|
||||||
|
rx = XN297_IsRX();
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
#endif
|
||||||
|
SGF22_send_packet();
|
||||||
|
if(IS_BIND_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
if(--bind_counter==0)
|
||||||
|
BIND_DONE;
|
||||||
|
}
|
||||||
|
#ifdef SGF22_HUB_TELEMETRY
|
||||||
|
if(rx)
|
||||||
|
{
|
||||||
|
uint8_t p_len = XN297_ReadEnhancedPayload(packet_in, SGF22_PAYLOAD_SIZE);
|
||||||
|
if(p_len == 3 && packet_in[0] == rx_tx_addr[2] && packet_in[1] == rx_tx_addr[3])
|
||||||
|
{//packets: 00 0B 00 -> 00 0B 01
|
||||||
|
telemetry_link = 1;
|
||||||
|
v_lipo1 = packet_in[2] ? 0 : 255; //2.9V for 1S, 7.0V for 2S
|
||||||
|
telemetry_lost = 0;
|
||||||
|
telem_count = 0;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
debug("L %d ",p_len);
|
||||||
|
debug("RX");
|
||||||
|
for(uint8_t i=0; i<SGF22_PAYLOAD_SIZE; i++)
|
||||||
|
debug(" %02X",packet_in[i]);
|
||||||
|
debugln("");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if(telem_count > 4*63) // Around 3.5sec with no telemetry
|
||||||
|
telemetry_lost = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
telem_count++;
|
||||||
|
if(!telemetry_lost && (telem_count & 0x3F) == 0)
|
||||||
|
{// Should have received a telem packet but... Send telem to the radio to keep it alive
|
||||||
|
telemetry_link = 1;
|
||||||
|
#if 0
|
||||||
|
debugln("Miss");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
phase++;
|
||||||
|
break;
|
||||||
|
case SGF22_DATA2:
|
||||||
|
case SGF22_DATA3:
|
||||||
|
//send 3 times in total the same packet
|
||||||
|
XN297_ReSendPayload();
|
||||||
|
phase++;
|
||||||
|
break;
|
||||||
|
default: //SGF22_RX
|
||||||
|
#ifdef SGF22_HUB_TELEMETRY
|
||||||
|
/*{ // 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++;
|
||||||
|
}
|
||||||
|
debugln("%d",count);
|
||||||
|
}*/
|
||||||
|
//Switch to RX
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
XN297_SetTxRxMode(RX_EN);
|
||||||
|
#endif
|
||||||
|
phase = SGF22_DATA1;
|
||||||
|
return SGF22_PACKET_PERIOD - 3*1550;
|
||||||
|
}
|
||||||
|
return 1550;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SGF22_init()
|
||||||
|
{
|
||||||
|
BIND_IN_PROGRESS; // autobind protocol
|
||||||
|
SGF22_initialize_txid();
|
||||||
|
SGF22_RF_init();
|
||||||
|
bind_counter=SGF22_BIND_COUNT;
|
||||||
|
packet_sent = packet_count = 0x26; // TX2:26 TX3:26
|
||||||
|
phase = SGF22_DATA1;
|
||||||
|
#ifdef SGF22_HUB_TELEMETRY
|
||||||
|
RX_RSSI = 100; // Dummy value
|
||||||
|
telemetry_lost = 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
232
Multiprotocol/SHENQI2_nrf24l01.ino
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
/*
|
||||||
|
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(SHENQI2_NRF24L01_INO)
|
||||||
|
|
||||||
|
#include "iface_xn297.h"
|
||||||
|
|
||||||
|
//#define FORCE_SHENQI2_ORIGINAL_ID
|
||||||
|
|
||||||
|
#define SHENQI2_PAYLOAD_SIZE 8
|
||||||
|
#define SHENQI2_RF_NUM_CHANNELS 16
|
||||||
|
#define SHENQI2_BIND_COUNT 2000
|
||||||
|
#define SHENQI2_WRITE_TIME 650
|
||||||
|
#define SHENQI2_BIND_CHANNEL 44
|
||||||
|
#define SHENQI2_PACKET_PERIOD 8210
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SHENQI2_BIND = 0,
|
||||||
|
SHENQI2_BIND_RX,
|
||||||
|
SHENQI2_DATA,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void __attribute__((unused)) SHENQI2_send_packet()
|
||||||
|
{
|
||||||
|
if(bind_counter)
|
||||||
|
{
|
||||||
|
bind_counter--;
|
||||||
|
if(!bind_counter)
|
||||||
|
BIND_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(packet, 0x00, SHENQI2_PAYLOAD_SIZE);
|
||||||
|
|
||||||
|
packet_count &= 0x0F;
|
||||||
|
packet[0] = packet_count;
|
||||||
|
|
||||||
|
memcpy(&packet[1],rx_tx_addr,5);
|
||||||
|
|
||||||
|
if(IS_BIND_DONE)
|
||||||
|
{//Normal
|
||||||
|
uint8_t val = convert_channel_8b(CH2);
|
||||||
|
if(val < 0x70)
|
||||||
|
val = 0x30;
|
||||||
|
else if(val < 0x80)
|
||||||
|
val = 0x00;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val &= 0x7F;
|
||||||
|
val >>= 2;
|
||||||
|
}
|
||||||
|
if(Channel_data[CH1] > 1024+50)
|
||||||
|
val |= 0x40;
|
||||||
|
else if(Channel_data[CH1] < 1024-50)
|
||||||
|
val |= 0x80;
|
||||||
|
packet[6] = val;
|
||||||
|
//packet[7] = 0x00; // ??
|
||||||
|
}
|
||||||
|
else
|
||||||
|
packet[0] |= 0x30;
|
||||||
|
|
||||||
|
// Send
|
||||||
|
XN297_SetPower();
|
||||||
|
XN297_SetTxRxMode(TX_EN);
|
||||||
|
XN297_WriteEnhancedPayload(packet, SHENQI2_PAYLOAD_SIZE, false);
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
for(uint8_t i=0; i < SHENQI2_PAYLOAD_SIZE; i++)
|
||||||
|
debug("%02X ", packet[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) SHENQI2_initialize_txid()
|
||||||
|
{
|
||||||
|
#ifdef FORCE_SHENQI2_ORIGINAL_ID
|
||||||
|
//TXID
|
||||||
|
rx_tx_addr[0] = 0x51;
|
||||||
|
rx_tx_addr[1] = 0x70;
|
||||||
|
rx_tx_addr[2] = 0x02;
|
||||||
|
//RXID
|
||||||
|
rx_tx_addr[3] = 0x46;
|
||||||
|
rx_tx_addr[4] = 0xBE;
|
||||||
|
#endif
|
||||||
|
rx_tx_addr[3] = 0x00;
|
||||||
|
rx_tx_addr[4] = 0x00;
|
||||||
|
//Freq
|
||||||
|
memcpy(hopping_frequency,(uint8_t*)"\x05\x09\x0E\x0F\x17\x1C\x21\x27\x2A\x2C\x33\x39\x3D\x42\x48\x4C",16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused)) SHENQI2_RF_init()
|
||||||
|
{
|
||||||
|
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||||
|
//Address
|
||||||
|
XN297_SetTXAddr((uint8_t*)"\x74\xD1\x3A\xF5\x6C", 5);
|
||||||
|
XN297_SetRXAddr((uint8_t*)"\x74\xD1\x3A\xF5\x6C", SHENQI2_PAYLOAD_SIZE);
|
||||||
|
XN297_RFChannel(SHENQI2_BIND_CHANNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SHENQI2_callback()
|
||||||
|
{
|
||||||
|
static bool rx=false;
|
||||||
|
|
||||||
|
switch(phase)
|
||||||
|
{
|
||||||
|
case SHENQI2_BIND:
|
||||||
|
rx = XN297_IsRX();
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
SHENQI2_send_packet();
|
||||||
|
packet_count++;
|
||||||
|
if(rx)
|
||||||
|
{
|
||||||
|
uint8_t val=XN297_ReadEnhancedPayload(packet_in, SHENQI2_PAYLOAD_SIZE);
|
||||||
|
if(val == SHENQI2_PAYLOAD_SIZE)
|
||||||
|
{
|
||||||
|
if(memcmp(rx_tx_addr, packet_in, 3) == 0)
|
||||||
|
{//Good packet with our TXID
|
||||||
|
BIND_DONE;
|
||||||
|
rx_tx_addr[3] = packet_in[3];
|
||||||
|
rx_tx_addr[4] = packet_in[4];
|
||||||
|
packet_count = 0;
|
||||||
|
phase = SHENQI2_DATA;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
for(uint8_t i=0; i < SHENQI2_PAYLOAD_SIZE; i++)
|
||||||
|
debug(" %02X", packet_in[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
phase++;
|
||||||
|
return SHENQI2_WRITE_TIME;
|
||||||
|
case SHENQI2_BIND_RX:
|
||||||
|
XN297_SetTxRxMode(TXRX_OFF);
|
||||||
|
XN297_SetTxRxMode(RX_EN);
|
||||||
|
phase = SHENQI2_BIND;
|
||||||
|
return SHENQI2_PACKET_PERIOD - SHENQI2_WRITE_TIME;
|
||||||
|
default: //SHENQI2_DATA
|
||||||
|
//Since I don't know the order of the channels, I'm hopping on all the channels quickly
|
||||||
|
//Refresh rate from the motorcycle perspective is 32ms instead of 8ms...
|
||||||
|
XN297_Hopping(hopping_frequency_no);
|
||||||
|
hopping_frequency_no++;
|
||||||
|
hopping_frequency_no &= 0x0F;
|
||||||
|
SHENQI2_send_packet();
|
||||||
|
if(hopping_frequency_no%4 == 0)
|
||||||
|
packet_count++;
|
||||||
|
return SHENQI2_PACKET_PERIOD/4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHENQI2_init()
|
||||||
|
{
|
||||||
|
BIND_IN_PROGRESS;
|
||||||
|
SHENQI2_initialize_txid();
|
||||||
|
SHENQI2_RF_init();
|
||||||
|
|
||||||
|
bind_counter = SHENQI2_BIND_COUNT;
|
||||||
|
phase = SHENQI2_BIND;
|
||||||
|
hopping_frequency_no = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
XN297 1Mb Enhanced,Acked,Scrambled
|
||||||
|
|
||||||
|
Bind
|
||||||
|
---
|
||||||
|
RX on channel: 44, Time: 2890us P: 34 51 70 02 00 00 00 00
|
||||||
|
RX on channel: 44, Time: 1780us P: 34 51 70 02 00 00 00 00
|
||||||
|
RX on channel: 44, Time: 1773us P: 34 51 70 02 00 00 00 00
|
||||||
|
RX on channel: 44, Time: 1772us P: 34 51 70 02 00 00 00 00
|
||||||
|
RX on channel: 44, Time: 2889us P: 35 51 70 02 00 00 00 00
|
||||||
|
RX on channel: 44, Time: 1769us P: 35 51 70 02 00 00 00 00
|
||||||
|
RX on channel: 44, Time: 1774us P: 35 51 70 02 00 00 00 00
|
||||||
|
RX on channel: 44, Time: 1771us P: 35 51 70 02 00 00 00 00
|
||||||
|
RX on channel: 44, Time: 2894us P: 36 51 70 02 00 00 00 00
|
||||||
|
|
||||||
|
A= 74 D1 3A F5 6C
|
||||||
|
RF:44
|
||||||
|
Timing: 1772µs between the same 4 packets, 2892µs to the next packet, 8208µs between 2 packets
|
||||||
|
Request ack, if no ack repeat the packet 4 times
|
||||||
|
|
||||||
|
P[0] = counter 00..0F | 30 bind
|
||||||
|
P[1] = TXID[0]
|
||||||
|
P[2] = TXID[1]
|
||||||
|
P[3] = TXID[2]
|
||||||
|
P[4] = RXID[0]
|
||||||
|
P[5] = RXID[1]
|
||||||
|
P[6] = TH 00..1F, Break 30, 40 ST_right, 80 ST_left
|
||||||
|
P[7] = 00?
|
||||||
|
|
||||||
|
Answer from motorcycle:
|
||||||
|
P: 51 70 02 46 BE 00 00 00
|
||||||
|
P[0] = TXID[0]
|
||||||
|
P[1] = TXID[1]
|
||||||
|
P[2] = TXID[2]
|
||||||
|
P[3] = RXID[0]
|
||||||
|
P[4] = RXID[1]
|
||||||
|
P[5] = 00
|
||||||
|
P[6] = 00
|
||||||
|
P[7] = 00
|
||||||
|
|
||||||
|
Normal packets
|
||||||
|
---
|
||||||
|
A= 74 D1 3A F5 6C
|
||||||
|
RF:5,9,14,15,23,28,33,39,42,44,51,57,61,66,72,76
|
||||||
|
RF:\x05\x09\x0E\x0F\x17\x1C\x21\x27\x2A\x2C\x33\x39\x3D\x42\x48\x4C
|
||||||
|
- order of the channels is unknown and vary over time
|
||||||
|
- send 16 times on each channel and switch (counter 00..0F)
|
||||||
|
Timing:1772µs between the same 4 packets, 2892µs to the next packet, 8208µs between 2 packets
|
||||||
|
Timing:8208 between packets if acked
|
||||||
|
P: 00 51 70 02 46 BE 00 00
|
||||||
|
P[0] = counter 00..0F
|
||||||
|
P[1] = TXID[0]
|
||||||
|
P[2] = TXID[1]
|
||||||
|
P[3] = TXID[2]
|
||||||
|
P[4] = RXID[0]
|
||||||
|
P[5] = RXID[1]
|
||||||
|
P[6] = TH 00..1F, Break 30, 40 ST_right, 80 ST_left
|
||||||
|
P[7] = 00?
|
||||||
|
*/
|
||||||
@@ -19,13 +19,18 @@
|
|||||||
#include "iface_nrf250k.h"
|
#include "iface_nrf250k.h"
|
||||||
|
|
||||||
//#define SLT_Q200_FORCE_ID
|
//#define SLT_Q200_FORCE_ID
|
||||||
|
//#define SLT_V1_4_FORCE_ID
|
||||||
|
|
||||||
// For code readability
|
// For code readability
|
||||||
#define SLT_PAYLOADSIZE_V1 7
|
#define SLT_PAYLOADSIZE_V1 7
|
||||||
#define SLT_PAYLOADSIZE_V2 11
|
#define SLT_PAYLOADSIZE_V1_4 5
|
||||||
#define SLT_NFREQCHANNELS 15
|
#define SLT_PAYLOADSIZE_V2 11
|
||||||
#define SLT_TXID_SIZE 4
|
#define SLT_NFREQCHANNELS 15
|
||||||
#define SLT_BIND_CHANNEL 0x50
|
#define SLT_TXID_SIZE 4
|
||||||
|
#define SLT_BIND_CHANNEL 0x50
|
||||||
|
#define SLT6_CH_MIN 182 // 10-bit AETR minimum (captures: 180-185, symmetric around 512)
|
||||||
|
#define SLT6_CH_MAX 842 // 10-bit AETR maximum (captures: 829-843, symmetric around 512)
|
||||||
|
#define SLT6_SW_THRESHOLD 273 // ~33% of half-range (820/3) for 3-position switch zones
|
||||||
|
|
||||||
enum{
|
enum{
|
||||||
// flags going to packet[6] (Q200)
|
// flags going to packet[6] (Q200)
|
||||||
@@ -52,9 +57,32 @@ enum {
|
|||||||
SLT_BIND2,
|
SLT_BIND2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SLT6 sub-cycle states: 3 sub-cycles per triple, each with 2 copies
|
||||||
|
enum {
|
||||||
|
SLT6_BUILD_A=0, // Build packet, configure for 7B sub-cycle
|
||||||
|
SLT6_DATA_A1, // Send 7B copy 1
|
||||||
|
SLT6_DATA_A2, // Send 7B copy 2, configure for 6B sub-cycle
|
||||||
|
SLT6_DATA_B1, // Send 6B copy 1
|
||||||
|
SLT6_DATA_B2, // Send 6B copy 2, configure for 5B sub-cycle
|
||||||
|
SLT6_DATA_C1, // Send 5B copy 1
|
||||||
|
SLT6_DATA_C2, // Send 5B copy 2
|
||||||
|
SLT6_BIND, // Send bind packet
|
||||||
|
};
|
||||||
|
|
||||||
|
// SLT6 address XOR values for the 3 sub-cycles
|
||||||
|
#define SLT6_ADDR_XOR_A 0x00 // 7B sub-cycle: base address
|
||||||
|
#define SLT6_ADDR_XOR_B 0x06 // 6B sub-cycle: byte[0] XOR 0x06
|
||||||
|
#define SLT6_ADDR_XOR_C 0x09 // 5B sub-cycle: byte[0] XOR 0x09
|
||||||
|
|
||||||
|
// SLT6 timing (from capture 12b, in microseconds)
|
||||||
|
#define SLT6_TIMING_SUBCYCLE 5994 // ~6000us between sub-cycle starts
|
||||||
|
#define SLT6_TIMING_PAIR 1633 // ~1633us between the two copies within a sub-cycle
|
||||||
|
#define SLT6_TIMING_BUILD 1000 // Build+config time at start of each triple
|
||||||
|
#define SLT6_TIMING_TRIPLE (3 * SLT6_TIMING_SUBCYCLE) // ~18ms triple period
|
||||||
|
|
||||||
static void __attribute__((unused)) SLT_RF_init()
|
static void __attribute__((unused)) SLT_RF_init()
|
||||||
{
|
{
|
||||||
NRF250K_Init();
|
NRF250K_Init(option == 0); // SLT: option==0 uses NRF24L01, option!=0 uses CC2500 with freq tuning
|
||||||
NRF250K_SetTXAddr(rx_tx_addr, SLT_TXID_SIZE);
|
NRF250K_SetTXAddr(rx_tx_addr, SLT_TXID_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,12 +100,12 @@ static void __attribute__((unused)) SLT_set_freq(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unique freq
|
// Unique freq
|
||||||
uint8_t max_freq=0x50; //V1 and V2
|
uint8_t max_freq = 0x50; //V1 and V2
|
||||||
if(sub_protocol==Q200)
|
if(sub_protocol == Q200)
|
||||||
max_freq=45;
|
max_freq=45;
|
||||||
for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i)
|
for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i)
|
||||||
{
|
{
|
||||||
if(sub_protocol==Q200 && hopping_frequency[i] >= max_freq)
|
if(sub_protocol == Q200 && hopping_frequency[i] >= max_freq)
|
||||||
hopping_frequency[i] = hopping_frequency[i] - max_freq + 0x03;
|
hopping_frequency[i] = hopping_frequency[i] - max_freq + 0x03;
|
||||||
uint8_t done = 0;
|
uint8_t done = 0;
|
||||||
while (!done)
|
while (!done)
|
||||||
@@ -93,9 +121,15 @@ static void __attribute__((unused)) SLT_set_freq(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
debug("CH:");
|
||||||
|
for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i)
|
||||||
|
debug(" %02X(%d)", hopping_frequency[i], hopping_frequency[i]);
|
||||||
|
debugln();
|
||||||
|
#endif
|
||||||
|
|
||||||
//Bind channel
|
//Bind channel
|
||||||
hopping_frequency[SLT_NFREQCHANNELS]=SLT_BIND_CHANNEL;
|
hopping_frequency[SLT_NFREQCHANNELS] = SLT_BIND_CHANNEL;
|
||||||
|
|
||||||
//Calib all channels
|
//Calib all channels
|
||||||
NRF250K_HoppingCalib(SLT_NFREQCHANNELS+1);
|
NRF250K_HoppingCalib(SLT_NFREQCHANNELS+1);
|
||||||
@@ -129,44 +163,94 @@ static void __attribute__((unused)) SLT_build_packet()
|
|||||||
uint8_t e = 0; // byte where extension 2 bits for every 10-bit channel are packed
|
uint8_t e = 0; // byte where extension 2 bits for every 10-bit channel are packed
|
||||||
for (uint8_t i = 0; i < 4; ++i)
|
for (uint8_t i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
uint16_t v = convert_channel_10b(CH_AETR[i], false);
|
uint16_t v = convert_channel_10b(sub_protocol != SLT_V1_4 ? CH_AETR[i] : i, false);
|
||||||
if(sub_protocol>SLT_V2 && (i==CH2 || i==CH3) )
|
if(sub_protocol>SLT_V2 && (i==CH2 || i==CH3) && sub_protocol != SLT_V1_4 && sub_protocol != RF_SIM)
|
||||||
v=1023-v; // reverse throttle and elevator channels for Q100/Q200/MR100 protocols
|
v=1023-v; // reverse throttle and elevator channels for Q100/Q200/MR100 protocols
|
||||||
packet[i] = v;
|
packet[i] = v;
|
||||||
e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0);
|
e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0);
|
||||||
}
|
}
|
||||||
// Extra bits for AETR
|
// Extra bits for AETR
|
||||||
packet[4] = e;
|
packet[4] = e;
|
||||||
|
|
||||||
|
//->V1_4CH stops here
|
||||||
|
|
||||||
// 8-bit channels
|
// 8-bit channels
|
||||||
packet[5] = convert_channel_8b(CH5);
|
packet[5] = convert_channel_8b(CH5);
|
||||||
packet[6] = convert_channel_8b(CH6);
|
packet[6] = convert_channel_8b(CH6);
|
||||||
if(sub_protocol!=SLT_V1)
|
|
||||||
|
if(sub_protocol == Q200)
|
||||||
|
packet[6] = GET_FLAG(CH9_SW , FLAG_Q200_FMODE)
|
||||||
|
|GET_FLAG(CH10_SW, FLAG_Q200_FLIP)
|
||||||
|
|GET_FLAG(CH11_SW, FLAG_Q200_VIDON)
|
||||||
|
|GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF);
|
||||||
|
else if(sub_protocol == MR100 || sub_protocol == Q100)
|
||||||
|
packet[6] = GET_FLAG(CH9_SW , FLAG_MR100_FMODE)
|
||||||
|
|GET_FLAG(CH10_SW, FLAG_MR100_FLIP)
|
||||||
|
|GET_FLAG(CH11_SW, FLAG_MR100_VIDEO) // Does not exist on the Q100 but...
|
||||||
|
|GET_FLAG(CH12_SW, FLAG_MR100_PICTURE); // Does not exist on the Q100 but...
|
||||||
|
packet[7] = convert_channel_8b(CH7);
|
||||||
|
packet[8] = convert_channel_8b(CH8);
|
||||||
|
if(sub_protocol == RF_SIM)
|
||||||
{
|
{
|
||||||
if(sub_protocol==Q200)
|
packet[9] = convert_channel_8b(CH9);
|
||||||
packet[6] = GET_FLAG(CH9_SW , FLAG_Q200_FMODE)
|
packet[10] = convert_channel_8b(CH10);
|
||||||
|GET_FLAG(CH10_SW, FLAG_Q200_FLIP)
|
|
||||||
|GET_FLAG(CH11_SW, FLAG_Q200_VIDON)
|
|
||||||
|GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF);
|
|
||||||
else if(sub_protocol==MR100 || sub_protocol==Q100)
|
|
||||||
packet[6] = GET_FLAG(CH9_SW , FLAG_MR100_FMODE)
|
|
||||||
|GET_FLAG(CH10_SW, FLAG_MR100_FLIP)
|
|
||||||
|GET_FLAG(CH11_SW, FLAG_MR100_VIDEO) // Does not exist on the Q100 but...
|
|
||||||
|GET_FLAG(CH12_SW, FLAG_MR100_PICTURE); // Does not exist on the Q100 but...
|
|
||||||
packet[7]=convert_channel_8b(CH7);
|
|
||||||
packet[8]=convert_channel_8b(CH8);
|
|
||||||
packet[9]=0xAA; //normal mode for Q100/Q200, unknown for V2/MR100
|
|
||||||
packet[10]=0x00; //normal mode for Q100/Q200, unknown for V2/MR100
|
|
||||||
if((sub_protocol==Q100 || sub_protocol==Q200) && CH13_SW)
|
|
||||||
{//Calibrate
|
|
||||||
packet[9]=0x77; //enter calibration
|
|
||||||
if(calib_counter>=20 && calib_counter<=25) // 7 packets for Q100 / 3 packets for Q200
|
|
||||||
packet[10]=0x20; //launch calibration
|
|
||||||
calib_counter++;
|
|
||||||
if(calib_counter>250) calib_counter=250;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
calib_counter=0;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
packet[9] = 0xAA; //normal mode for Q100/Q200, unknown for V2/MR100
|
||||||
|
packet[10] = 0x00; //normal mode for Q100/Q200, unknown for V2/MR100
|
||||||
|
}
|
||||||
|
if((sub_protocol == Q100 || sub_protocol == Q200) && CH13_SW)
|
||||||
|
{//Calibrate
|
||||||
|
packet[9] = 0x77; //enter calibration
|
||||||
|
if(calib_counter >= 20 && calib_counter <= 25) // 7 packets for Q100 / 3 packets for Q200
|
||||||
|
packet[10] = 0x20; //launch calibration
|
||||||
|
calib_counter++;
|
||||||
|
if(calib_counter > 250) calib_counter = 250;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
calib_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SLT6: build 7-byte data packet from current channel values
|
||||||
|
static void __attribute__((unused)) SLT6_build_packet()
|
||||||
|
{
|
||||||
|
// aileron, elevator, throttle, rudder (10-bit, limited range)
|
||||||
|
uint8_t e = 0;
|
||||||
|
for (uint8_t i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
uint16_t v = convert_channel_16b_limit(CH_AETR[i], SLT6_CH_MIN, SLT6_CH_MAX);
|
||||||
|
packet[i] = v;
|
||||||
|
e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0);
|
||||||
|
}
|
||||||
|
packet[4] = e;
|
||||||
|
|
||||||
|
// Flight mode: 3 positions at ~33% each
|
||||||
|
if(Channel_data[CH5] > CHANNEL_MID + SLT6_SW_THRESHOLD)
|
||||||
|
packet[5] = 0xD0;
|
||||||
|
else if(Channel_data[CH5] < CHANNEL_MID - SLT6_SW_THRESHOLD)
|
||||||
|
packet[5] = 0x30;
|
||||||
|
else
|
||||||
|
packet[5] = 0x80;
|
||||||
|
|
||||||
|
// Panic: only active when CH6 is below -33%, center and up = no panic
|
||||||
|
if(Channel_data[CH6] < CHANNEL_MID - SLT6_SW_THRESHOLD)
|
||||||
|
packet[6] = 0x30;
|
||||||
|
else
|
||||||
|
packet[6] = 0xD0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SLT6: configure radio for a sub-cycle (set address and channel)
|
||||||
|
static void __attribute__((unused)) SLT6_configure_radio(uint8_t addr_xor, uint8_t hop_offset)
|
||||||
|
{
|
||||||
|
SLT_wait_radio();
|
||||||
|
// Set TX address with XOR on byte[0]
|
||||||
|
uint8_t addr[SLT_TXID_SIZE];
|
||||||
|
memcpy(addr, rx_tx_addr, SLT_TXID_SIZE);
|
||||||
|
addr[0] ^= addr_xor;
|
||||||
|
NRF250K_SetTXAddr(addr, SLT_TXID_SIZE);
|
||||||
|
// Set RF channel
|
||||||
|
NRF250K_Hopping((hopping_frequency_no + hop_offset) % SLT_NFREQCHANNELS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((unused)) SLT_send_bind_packet()
|
static void __attribute__((unused)) SLT_send_bind_packet()
|
||||||
@@ -177,8 +261,8 @@ static void __attribute__((unused)) SLT_send_bind_packet()
|
|||||||
NRF250K_SetPower();
|
NRF250K_SetPower();
|
||||||
BIND_DONE;
|
BIND_DONE;
|
||||||
NRF250K_SetTXAddr((uint8_t *)"\x7E\xB8\x63\xA9", SLT_TXID_SIZE);
|
NRF250K_SetTXAddr((uint8_t *)"\x7E\xB8\x63\xA9", SLT_TXID_SIZE);
|
||||||
memcpy((void*)packet,(void*)rx_tx_addr,SLT_TXID_SIZE);
|
memcpy((void*)packet, (void*)rx_tx_addr, SLT_TXID_SIZE);
|
||||||
if(phase==SLT_BIND2)
|
if(phase == SLT_BIND2 || phase == SLT6_BIND)
|
||||||
SLT_send_packet(SLT_TXID_SIZE);
|
SLT_send_packet(SLT_TXID_SIZE);
|
||||||
else // SLT_BIND1
|
else // SLT_BIND1
|
||||||
SLT_send_packet(SLT_PAYLOADSIZE_V2);
|
SLT_send_packet(SLT_PAYLOADSIZE_V2);
|
||||||
@@ -186,17 +270,82 @@ static void __attribute__((unused)) SLT_send_bind_packet()
|
|||||||
|
|
||||||
#define SLT_TIMING_BUILD 1000
|
#define SLT_TIMING_BUILD 1000
|
||||||
#define SLT_V1_TIMING_PACKET 1000
|
#define SLT_V1_TIMING_PACKET 1000
|
||||||
|
#define SLT_V1_4_TIMING_PACKET 1643
|
||||||
#define SLT_V2_TIMING_PACKET 2042
|
#define SLT_V2_TIMING_PACKET 2042
|
||||||
#define SLT_V1_TIMING_BIND2 1000
|
#define SLT_V1_TIMING_BIND2 1000
|
||||||
#define SLT_V2_TIMING_BIND1 6507
|
#define SLT_V2_TIMING_BIND1 6507
|
||||||
#define SLT_V2_TIMING_BIND2 2112
|
#define SLT_V2_TIMING_BIND2 2112
|
||||||
uint16_t SLT_callback()
|
|
||||||
|
// SLT6 callback: triple-address state machine
|
||||||
|
// Each triple: 3 sub-cycles (7B, 6B, 5B), each sent twice, with different addresses and channels
|
||||||
|
static uint16_t __attribute__((unused)) SLT6_callback()
|
||||||
{
|
{
|
||||||
switch (phase)
|
switch (phase)
|
||||||
{
|
{
|
||||||
case SLT_BUILD:
|
case SLT6_BUILD_A:
|
||||||
#ifdef MULTI_SYNC
|
#ifdef MULTI_SYNC
|
||||||
telemetry_set_input_sync(sub_protocol==SLT_V1?20000:13730);
|
telemetry_set_input_sync(SLT6_TIMING_TRIPLE);
|
||||||
|
#endif
|
||||||
|
SLT6_build_packet();
|
||||||
|
NRF250K_SetPower();
|
||||||
|
SLT6_configure_radio(SLT6_ADDR_XOR_A, 0); // 7B sub-cycle: base address, hop+0
|
||||||
|
phase = SLT6_DATA_A1;
|
||||||
|
return SLT6_TIMING_BUILD;
|
||||||
|
case SLT6_DATA_A1:
|
||||||
|
SLT_send_packet(7);
|
||||||
|
phase = SLT6_DATA_A2;
|
||||||
|
return SLT6_TIMING_PAIR; // 1633us between copies
|
||||||
|
case SLT6_DATA_A2:
|
||||||
|
SLT_send_packet(7);
|
||||||
|
SLT6_configure_radio(SLT6_ADDR_XOR_B, 3); // 6B sub-cycle: XOR 0x06 address, hop+3
|
||||||
|
phase = SLT6_DATA_B1;
|
||||||
|
return SLT6_TIMING_SUBCYCLE - SLT6_TIMING_PAIR; // 4361us to next sub-cycle TX
|
||||||
|
case SLT6_DATA_B1:
|
||||||
|
SLT_send_packet(6);
|
||||||
|
phase = SLT6_DATA_B2;
|
||||||
|
return SLT6_TIMING_PAIR;
|
||||||
|
case SLT6_DATA_B2:
|
||||||
|
SLT_send_packet(6);
|
||||||
|
SLT6_configure_radio(SLT6_ADDR_XOR_C, 6); // 5B sub-cycle: XOR 0x09 address, hop+6
|
||||||
|
phase = SLT6_DATA_C1;
|
||||||
|
return SLT6_TIMING_SUBCYCLE - SLT6_TIMING_PAIR; // 4361us
|
||||||
|
case SLT6_DATA_C1:
|
||||||
|
SLT_send_packet(5);
|
||||||
|
phase = SLT6_DATA_C2;
|
||||||
|
return SLT6_TIMING_PAIR;
|
||||||
|
case SLT6_DATA_C2:
|
||||||
|
SLT_send_packet(5);
|
||||||
|
// Advance hopping for next triple
|
||||||
|
if (++hopping_frequency_no >= SLT_NFREQCHANNELS)
|
||||||
|
hopping_frequency_no = 0;
|
||||||
|
if (++packet_count >= 100)
|
||||||
|
{// Send bind packet periodically
|
||||||
|
packet_count = 0;
|
||||||
|
phase = SLT6_BIND;
|
||||||
|
return SLT_V1_TIMING_BIND2;
|
||||||
|
}
|
||||||
|
phase = SLT6_BUILD_A;
|
||||||
|
return SLT6_TIMING_SUBCYCLE - SLT6_TIMING_PAIR - SLT6_TIMING_BUILD; // Gap before next build
|
||||||
|
case SLT6_BIND:
|
||||||
|
SLT_send_bind_packet();
|
||||||
|
phase = SLT6_BUILD_A;
|
||||||
|
return SLT6_TIMING_SUBCYCLE - SLT6_TIMING_PAIR - SLT6_TIMING_BUILD;
|
||||||
|
}
|
||||||
|
return SLT6_TIMING_TRIPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SLT_callback()
|
||||||
|
{
|
||||||
|
// SLT6 has its own state machine
|
||||||
|
if(sub_protocol == SLT6TX)
|
||||||
|
return SLT6_callback();
|
||||||
|
|
||||||
|
switch (phase)
|
||||||
|
{
|
||||||
|
case SLT_BUILD:
|
||||||
|
//debugln_time("b ");
|
||||||
|
#ifdef MULTI_SYNC
|
||||||
|
telemetry_set_input_sync(packet_period);
|
||||||
#endif
|
#endif
|
||||||
SLT_build_packet();
|
SLT_build_packet();
|
||||||
NRF250K_SetPower(); //Change power level
|
NRF250K_SetPower(); //Change power level
|
||||||
@@ -206,42 +355,39 @@ uint16_t SLT_callback()
|
|||||||
case SLT_DATA1:
|
case SLT_DATA1:
|
||||||
case SLT_DATA2:
|
case SLT_DATA2:
|
||||||
phase++;
|
phase++;
|
||||||
if(sub_protocol==SLT_V1)
|
SLT_send_packet(packet_length);
|
||||||
{
|
if(sub_protocol == SLT_V1)
|
||||||
SLT_send_packet(SLT_PAYLOADSIZE_V1);
|
|
||||||
return SLT_V1_TIMING_PACKET;
|
return SLT_V1_TIMING_PACKET;
|
||||||
}
|
if(sub_protocol == SLT_V1_4)
|
||||||
else //V2
|
|
||||||
{
|
{
|
||||||
SLT_send_packet(SLT_PAYLOADSIZE_V2);
|
phase++; //Packets are sent two times only
|
||||||
return SLT_V2_TIMING_PACKET;
|
return SLT_V1_4_TIMING_PACKET;
|
||||||
}
|
}
|
||||||
|
//V2
|
||||||
|
return SLT_V2_TIMING_PACKET;
|
||||||
case SLT_DATA3:
|
case SLT_DATA3:
|
||||||
if(sub_protocol==SLT_V1)
|
SLT_send_packet(packet_length);
|
||||||
SLT_send_packet(SLT_PAYLOADSIZE_V1);
|
|
||||||
else //V2
|
|
||||||
SLT_send_packet(SLT_PAYLOADSIZE_V2);
|
|
||||||
if (++packet_count >= 100)
|
if (++packet_count >= 100)
|
||||||
{// Send bind packet
|
{// Send bind packet
|
||||||
packet_count = 0;
|
packet_count = 0;
|
||||||
if(sub_protocol==SLT_V1)
|
if(sub_protocol == SLT_V1 || sub_protocol == SLT_V1_4)
|
||||||
{
|
{
|
||||||
phase=SLT_BIND2;
|
phase = SLT_BIND2;
|
||||||
return SLT_V1_TIMING_BIND2;
|
return SLT_V1_TIMING_BIND2;
|
||||||
}
|
}
|
||||||
else //V2
|
//V2
|
||||||
{
|
phase = SLT_BIND1;
|
||||||
phase=SLT_BIND1;
|
return SLT_V2_TIMING_BIND1;
|
||||||
return SLT_V2_TIMING_BIND1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{// Continue to send normal packets
|
{// Continue to send normal packets
|
||||||
phase = SLT_BUILD;
|
phase = SLT_BUILD;
|
||||||
if(sub_protocol==SLT_V1)
|
if(sub_protocol == SLT_V1)
|
||||||
return 20000-SLT_TIMING_BUILD;
|
return 20000 - SLT_TIMING_BUILD;
|
||||||
else //V2
|
if(sub_protocol==SLT_V1_4)
|
||||||
return 13730-SLT_TIMING_BUILD;
|
return 18000 - SLT_TIMING_BUILD - SLT_V1_4_TIMING_PACKET;
|
||||||
|
//V2
|
||||||
|
return 13730 - SLT_TIMING_BUILD;
|
||||||
}
|
}
|
||||||
case SLT_BIND1:
|
case SLT_BIND1:
|
||||||
SLT_send_bind_packet();
|
SLT_send_bind_packet();
|
||||||
@@ -250,10 +396,12 @@ uint16_t SLT_callback()
|
|||||||
case SLT_BIND2:
|
case SLT_BIND2:
|
||||||
SLT_send_bind_packet();
|
SLT_send_bind_packet();
|
||||||
phase = SLT_BUILD;
|
phase = SLT_BUILD;
|
||||||
if(sub_protocol==SLT_V1)
|
if(sub_protocol == SLT_V1)
|
||||||
return 20000-SLT_TIMING_BUILD-SLT_V1_TIMING_BIND2;
|
return 20000 - SLT_TIMING_BUILD - SLT_V1_TIMING_BIND2;
|
||||||
else //V2
|
if(sub_protocol == SLT_V1_4)
|
||||||
return 13730-SLT_TIMING_BUILD-SLT_V2_TIMING_BIND1-SLT_V2_TIMING_BIND2;
|
return 18000 - SLT_TIMING_BUILD - SLT_V1_TIMING_BIND2 - SLT_V1_4_TIMING_PACKET;
|
||||||
|
//V2
|
||||||
|
return 13730 - SLT_TIMING_BUILD - SLT_V2_TIMING_BIND1 - SLT_V2_TIMING_BIND2;
|
||||||
}
|
}
|
||||||
return 19000;
|
return 19000;
|
||||||
}
|
}
|
||||||
@@ -264,7 +412,44 @@ void SLT_init()
|
|||||||
packet_count = 0;
|
packet_count = 0;
|
||||||
packet_sent = 0;
|
packet_sent = 0;
|
||||||
hopping_frequency_no = 0;
|
hopping_frequency_no = 0;
|
||||||
if(sub_protocol==Q200)
|
|
||||||
|
if(sub_protocol == SLT6TX)
|
||||||
|
{
|
||||||
|
hopping_frequency_no = 1; // SLT6 starts hopping at index 1 (verified from captures)
|
||||||
|
// packet_length not used for SLT6 (lengths vary per sub-cycle)
|
||||||
|
#ifdef MULTI_SYNC
|
||||||
|
packet_period = SLT6_TIMING_TRIPLE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(sub_protocol == SLT_V1)
|
||||||
|
{
|
||||||
|
packet_length = SLT_PAYLOADSIZE_V1;
|
||||||
|
#ifdef MULTI_SYNC
|
||||||
|
packet_period = 20000+2*SLT_V1_TIMING_PACKET; //22ms
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(sub_protocol == SLT_V1_4)
|
||||||
|
{
|
||||||
|
packet_length = SLT_PAYLOADSIZE_V1_4;
|
||||||
|
#ifdef MULTI_SYNC
|
||||||
|
packet_period = 18000; //18ms
|
||||||
|
#endif
|
||||||
|
//Force high part of the ID otherwise the RF frequencies do not match, only tested the 2 last bytes...
|
||||||
|
rx_tx_addr[0]=0xF4;
|
||||||
|
rx_tx_addr[1]=0x71;
|
||||||
|
#ifdef SLT_V1_4_FORCE_ID // ID taken from TX dumps
|
||||||
|
memcpy(rx_tx_addr,"\xF4\x71\x8D\x01",SLT_TXID_SIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else //V2
|
||||||
|
{
|
||||||
|
packet_length = SLT_PAYLOADSIZE_V2;
|
||||||
|
#ifdef MULTI_SYNC
|
||||||
|
packet_period = 13730+2*SLT_V2_TIMING_PACKET; //~18ms
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sub_protocol == Q200)
|
||||||
{ //Q200: Force high part of the ID otherwise it won't bind
|
{ //Q200: Force high part of the ID otherwise it won't bind
|
||||||
rx_tx_addr[0]=0x01;
|
rx_tx_addr[0]=0x01;
|
||||||
rx_tx_addr[1]=0x02;
|
rx_tx_addr[1]=0x02;
|
||||||
@@ -273,9 +458,16 @@ void SLT_init()
|
|||||||
/* rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x0B;rx_tx_addr[3]=0x57;*/
|
/* rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x0B;rx_tx_addr[3]=0x57;*/
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SLT_RF_init();
|
SLT_RF_init();
|
||||||
SLT_set_freq();
|
SLT_set_freq();
|
||||||
phase = SLT_BUILD;
|
|
||||||
|
if(sub_protocol == SLT6TX)
|
||||||
|
phase = SLT6_BUILD_A;
|
||||||
|
else
|
||||||
|
phase = SLT_BUILD;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
//SLT v1_4ch timing
|
||||||
|
//268363 + 1643 / 15 = 18000
|
||||||
|
|||||||