mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-12-15 12:23:16 +00:00
Compare commits
101 Commits
v1.3.2.86
...
58f6716035
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58f6716035 | ||
|
|
2b15de0f90 | ||
|
|
be91409df9 | ||
|
|
4d8e440965 | ||
|
|
2d469d074e | ||
|
|
96405d27b5 | ||
|
|
75c9fb40a7 | ||
|
|
cd1c15a45a | ||
|
|
2bd50f4c8c | ||
|
|
4c2ddcbe48 | ||
|
|
d7f9ef6967 | ||
|
|
bfc8c2f9fd | ||
|
|
ce6243d6e3 | ||
|
|
80f9ff4163 | ||
|
|
d9f8a3989a | ||
|
|
416f7d5c19 | ||
|
|
eb24dd5549 | ||
|
|
ba19592973 | ||
|
|
98d8d7fb5f | ||
|
|
ad0947b0b7 | ||
|
|
c093f21b31 | ||
|
|
c5a3e305f9 | ||
|
|
e085602a6c | ||
|
|
dee25215cf | ||
|
|
ef1bb1ead7 | ||
|
|
90170493c0 | ||
|
|
00a9057186 | ||
|
|
05c300e979 | ||
|
|
6730ed6246 | ||
|
|
0a0463652b | ||
|
|
4f580a4286 | ||
|
|
0616cab386 | ||
|
|
175cfa5e93 | ||
|
|
dbfccad568 | ||
|
|
3fe6dc64fa | ||
|
|
49068af59f | ||
|
|
fbd81c6e26 | ||
|
|
9cac96d6a7 | ||
|
|
5987aa40a6 | ||
|
|
30cb812549 | ||
|
|
0fd2e36046 | ||
|
|
8b05e55ebd | ||
|
|
af71a208fd | ||
|
|
7e5cb8e884 | ||
|
|
8c669ea015 | ||
|
|
acd8379077 | ||
|
|
97c6088715 | ||
|
|
db017c73b6 | ||
|
|
24aaa0dd0c | ||
|
|
da33df4346 | ||
|
|
22590ed4f7 | ||
|
|
c0bc64c2aa | ||
|
|
694d968e8c | ||
|
|
fff3b8830e | ||
|
|
b740f4cd24 | ||
|
|
e247b8b9c1 | ||
|
|
4f7af553d1 | ||
|
|
570e6f8c64 | ||
|
|
b6e665b567 | ||
|
|
48e82304a0 | ||
|
|
7b58b9aca0 | ||
|
|
dfcf3f533c | ||
|
|
4c14925b4f | ||
|
|
4c74bc869d | ||
|
|
45edfa1ec0 | ||
|
|
88343b7424 | ||
|
|
13197840c2 | ||
|
|
ffe4ac68fd | ||
|
|
5bab5f03db | ||
|
|
ae748e25f8 | ||
|
|
e9c7959ecb | ||
|
|
bf09855014 | ||
|
|
32bd39f209 | ||
|
|
940f241b9d | ||
|
|
5c00ce6b88 | ||
|
|
016b282246 | ||
|
|
d6ecac1302 | ||
|
|
901f8ca6b0 | ||
|
|
9c3b6ba9f6 | ||
|
|
53ec484028 | ||
|
|
246e808cb4 | ||
|
|
a7b68dc2aa | ||
|
|
08404f9223 | ||
|
|
149554e61c | ||
|
|
7b71425db2 | ||
|
|
f9cfb7f20f | ||
|
|
506ee43d41 | ||
|
|
ebde0915cd | ||
|
|
2501656bf4 | ||
|
|
9356e7654e | ||
|
|
4f1e5d2452 | ||
|
|
64c75414d8 | ||
|
|
5147833487 | ||
|
|
324419241f | ||
|
|
1a921b1cdb | ||
|
|
25c052c0a3 | ||
|
|
a02586cca9 | ||
|
|
226e082c5a | ||
|
|
5afdff8477 | ||
|
|
c52ac2cefc | ||
|
|
09f39ea60f |
37
.github/workflows/main.yml
vendored
37
.github/workflows/main.yml
vendored
@@ -40,14 +40,14 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
board: [
|
||||
"multi4in1:avr:multiatmega328p:bootloader=none",
|
||||
"multi4in1:avr:multiatmega328p:bootloader=optiboot",
|
||||
"multi4in1:avr:multixmega32d4",
|
||||
"multi4in1:STM32F1:multi5in1t18int",
|
||||
"multi4in1:STM32F1:multistm32f103cb:debug_option=none",
|
||||
"multi4in1:STM32F1:multistm32f103cb:debug_option=native",
|
||||
"multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi",
|
||||
"multi4in1:STM32F1:multistm32f103c8:debug_option=none"
|
||||
"multi4in1-devel:avr:multiatmega328p:bootloader=none",
|
||||
"multi4in1-devel:avr:multiatmega328p:bootloader=optiboot",
|
||||
"multi4in1-devel:avr:multixmega32d4",
|
||||
"multi4in1-devel:STM32F1:multi5in1t18int",
|
||||
"multi4in1-devel:STM32F1:multistm32f103cb:debug_option=none",
|
||||
"multi4in1-devel:STM32F1:multistm32f103cb:debug_option=native",
|
||||
"multi4in1-devel:STM32F1:multistm32f103cb:debug_option=ftdi",
|
||||
"multi4in1-devel:STM32F1:multistm32f103c8:debug_option=none"
|
||||
]
|
||||
|
||||
# Set the environment variables
|
||||
@@ -67,15 +67,22 @@ jobs:
|
||||
echo "Event action: ${{ github.event.action }}"
|
||||
echo "Tag name: ${{ github.event.release.tag_name }}"
|
||||
|
||||
arduino-cli config init --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json
|
||||
arduino-cli config init --additional-urls https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json,https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/devel/source/package_multi_4in1_board_devel_index.json
|
||||
arduino-cli core update-index
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1:avr:" ]]; then
|
||||
if [[ "$BOARD" =~ ":avr:" ]]; then
|
||||
arduino-cli core install arduino:avr;
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:avr" ]]; then
|
||||
arduino-cli core install multi4in1-devel:avr
|
||||
elif [[ "$BOARD" =~ "multi4in1:avr" ]]; then
|
||||
arduino-cli core install multi4in1:avr
|
||||
fi
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
if [[ "$BOARD" =~ "multi4in1-devel:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1-devel:STM32F1
|
||||
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
arduino-cli core install multi4in1:STM32F1
|
||||
fi
|
||||
|
||||
@@ -109,18 +116,18 @@ jobs:
|
||||
echo "ALL_RFMODULES=$(echo $ALL_RFMODULES)" >> $GITHUB_ENV
|
||||
|
||||
# Disable CHECK_FOR_BOOTLOADER when not needed
|
||||
if [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=none" ]]; then
|
||||
if [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
fi
|
||||
|
||||
# Trim the build down for the Atmega328p board
|
||||
if [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then
|
||||
if [[ "$BOARD" =~ ":avr:multiatmega328p:" ]]; then
|
||||
opt_disable $ALL_PROTOCOLS
|
||||
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
|
||||
fi
|
||||
|
||||
# Trim the enabled protocols down for the STM32F103CB board with debugging or the STM32F103C8 board in general
|
||||
if [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi" ]] || [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=native" ]] || [[ "$BOARD" =~ "multi4in1:STM32F1:multistm32f103c8" ]]; then
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=ftdi" ]] || [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=native" ]] || [[ "$BOARD" =~ ":STM32F1:multistm32f103c8" ]]; then
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
|
||||
fi
|
||||
@@ -133,7 +140,7 @@ jobs:
|
||||
- name: Build default configuration
|
||||
run: |
|
||||
# Skip the default build for boards where it's too large now
|
||||
if [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" == "multi4in1:STM32F1:multi5in1t18int" ]]; then
|
||||
if [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]] || [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
printf "Not testing default build for $BOARD.";
|
||||
else
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
|
||||
@@ -1,601 +0,0 @@
|
||||
local toolName = "TNS|DSM Forward Programming|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for DSM description
|
||||
-- Multi_Buffer[0..2]=="DSM" -> Lua script is running
|
||||
-- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent
|
||||
-- Multi_Buffer[4..9]=6 bytes of TX to RX data
|
||||
-- Multi_Buffer[10..25]=16 bytes of RX to TX data
|
||||
--
|
||||
-- To start operation:
|
||||
-- Write 0x00 at address 3
|
||||
-- Write 0x00 at address 10
|
||||
-- Write "DSM" at address 0..2
|
||||
--###############################################################################
|
||||
|
||||
local RX_VERSION, WAIT_CMD, MENU_TITLE, MENU_LINES, MENU_VALUES, VALUE_CHANGING, VALUE_CHANGING_WAIT, VALUE_CHANGED = 0, 1, 2, 3, 4, 5, 6, 7
|
||||
local MENU, LIST_MENU_NOCHANGING, LIST_MENU2, PERCENTAGE_VALUE = 0x1C, 0x6C, 0x4C, 0xC0
|
||||
local Phase = RX_VERSION
|
||||
local Waiting_RX = 0
|
||||
local Text = {}
|
||||
local Retry=100
|
||||
local Blink = 0
|
||||
local Value_Changed=0
|
||||
|
||||
local Menu = { Cur=nil, Id=nil, Title="", Prev=nil, PrevId=nil, Next=nil, NextId=nil, Back=nil, BackId=nil, CurLine=nil, SelLine=nil, EditLine=nil }
|
||||
local Line = {}
|
||||
local RX = { Name="", Version="" }
|
||||
|
||||
local function conv_int16(number)
|
||||
if number >= 0x8000 then
|
||||
return number - 0x10000
|
||||
end
|
||||
return number
|
||||
end
|
||||
|
||||
local function Get_Text(index)
|
||||
out = Text[index]
|
||||
if out == nil then -- unknown...
|
||||
out = "Unknown_"..string.format("%X",index)
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
local function DSM_Release()
|
||||
multiBuffer( 0, 0 )
|
||||
end
|
||||
|
||||
local function DSM_Send(...)
|
||||
local arg = {...}
|
||||
for i = 1 , #arg do
|
||||
multiBuffer( 3+i, arg[i])
|
||||
end
|
||||
multiBuffer( 3, 0x70+#arg)
|
||||
end
|
||||
|
||||
local function Value_Add(dir)
|
||||
local line=Line[Menu.SelLine]
|
||||
Speed = getRotEncSpeed()
|
||||
if Speed == ROTENC_MIDSPEED then
|
||||
line.Val = line.Val + (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then
|
||||
line.Val = line.Val + (15 * dir)
|
||||
else
|
||||
line.Val = line.Val + dir
|
||||
end
|
||||
if line.Val > line.Max then
|
||||
line.Val = line.Max
|
||||
elseif line.Val < line.Min then
|
||||
line.Val = line.Min
|
||||
end
|
||||
if Line[Menu.SelLine].Type ~= LIST_MENU_NOCHANGING then
|
||||
Phase = VALUE_CHANGING
|
||||
Waiting_RX = 0
|
||||
end
|
||||
end
|
||||
|
||||
local function DSM_Menu(event)
|
||||
local Speed = 0
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
if Menu.EditLine == nil then
|
||||
-- not changing a value
|
||||
if Menu.SelLine ~= nil then
|
||||
if Menu.SelLine < 7 then
|
||||
local num = Menu.SelLine
|
||||
for i = Menu.SelLine + 1, 6, 1 do
|
||||
if Line[i].Type ~= nil and Line[i].Next ~= nil then
|
||||
Menu.SelLine=i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == Menu.SelLine then
|
||||
if Menu.Next ~= 0 then -- Next
|
||||
Menu.SelLine = 7
|
||||
elseif Menu.Prev ~= 0 then -- Prev
|
||||
Menu.SelLine = 8
|
||||
end
|
||||
end
|
||||
elseif Menu.Prev ~= 0 then -- Prev
|
||||
Menu.SelLine = 8
|
||||
end
|
||||
end
|
||||
else -- need to inc the value
|
||||
Value_Add(1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
if Menu.EditLine == nil then
|
||||
if Menu.SelLine ~= nil then
|
||||
if Menu.SelLine == 8 and Menu.Next ~= 0 then
|
||||
Menu.SelLine = 7
|
||||
elseif Menu.SelLine > 0 then
|
||||
if Menu.SelLine > 6 then
|
||||
Menu.SelLine = 7
|
||||
end
|
||||
local num = Menu.SelLine
|
||||
for i = Menu.SelLine-1, 0, -1 do
|
||||
if Line[i].Type ~= nil and Line[i].Next ~= nil then
|
||||
Menu.SelLine=i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == Menu.SelLine then -- Back
|
||||
Menu.SelLine = -1
|
||||
end
|
||||
else
|
||||
Menu.SelLine = -1 -- Back
|
||||
end
|
||||
end
|
||||
else -- need to dec the value
|
||||
Value_Add(-1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
if Menu.SelLine == -1 then -- Back
|
||||
Menu.Cur = Menu.Back
|
||||
Menu.Id = Menu.BackId
|
||||
Menu.SelLine = 0
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
elseif Menu.SelLine == 7 then -- Next
|
||||
Menu.Cur = Menu.Next
|
||||
Menu.Id = Menu.NextId
|
||||
Menu.SelLine = 0
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
elseif Menu.SelLine == 8 then -- Prev
|
||||
Menu.Cur = Menu.Prev
|
||||
Menu.Id = Menu.PrevId
|
||||
Menu.SelLine = 0
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
elseif Menu.SelLine ~= nil and Line[Menu.SelLine].Next ~= nil then
|
||||
if Line[Menu.SelLine].Type == MENU then -- Next menu exist
|
||||
Menu.Cur = Line[Menu.SelLine].Next
|
||||
Menu.Id = Line[Menu.SelLine].NextId
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
else
|
||||
-- value entry
|
||||
if Menu.EditLine == Menu.SelLine then
|
||||
Menu.EditLine = nil
|
||||
Value_Changed = 0
|
||||
Phase = VALUE_CHANGED
|
||||
Waiting_RX = 0
|
||||
else
|
||||
Menu.EditLine = Menu.SelLine
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function DSM_Send_Receive()
|
||||
if Waiting_RX == 0 then
|
||||
Waiting_RX = 1
|
||||
-- Need to send a request
|
||||
if Phase == RX_VERSION then -- request RX version
|
||||
DSM_Send(0x11,0x06,0x00,0x14,0x00,0x00)
|
||||
elseif Phase == WAIT_CMD then -- keep connection open
|
||||
DSM_Send(0x00,0x04,0x00,0x00)
|
||||
elseif Phase == MENU_TITLE then -- request menu title
|
||||
if Menu.Cur == nil then
|
||||
DSM_Send(0x12,0x06,0x00,0x14,0x00,0x00) -- first menu only
|
||||
Menu.Cur = 0
|
||||
else
|
||||
DSM_Send(0x16,0x06,Menu.Id,Menu.Cur,0x00,Menu.SelLine)
|
||||
end
|
||||
elseif Phase == MENU_LINES then -- request menu lines
|
||||
if Menu.CurLine == nil then
|
||||
DSM_Send(0x13,0x04,Menu.Id,Menu.Cur) -- line 0
|
||||
elseif Menu.CurLine >= 0x80 then
|
||||
local last_byte={0x40,0x01,0x02,0x04,0x00,0x00} -- unknown...
|
||||
DSM_Send(0x20,0x06,Menu.CurLine-0x80,Menu.CurLine-0x80,0x00,last_byte[Menu.CurLine-0x80+1]) -- line X
|
||||
else
|
||||
DSM_Send(0x14,0x06,Menu.Id,Menu.Cur,0x00,Menu.CurLine) -- line X
|
||||
end
|
||||
elseif Phase == MENU_VALUES then -- request menu values
|
||||
DSM_Send(0x15,0x06,Menu.Id,Menu.Cur,Line[Menu.CurLine].ValId,Menu.CurLine) -- line X
|
||||
elseif Phase == VALUE_CHANGING then -- send value
|
||||
local value=Line[Menu.SelLine].Val
|
||||
if value < 0 then
|
||||
value = 0x10000 + value
|
||||
end
|
||||
DSM_Send(0x18,0x06,Line[Menu.SelLine].ValId,Menu.SelLine,bit32.rshift(value,8),bit32.band(value,0xFF)) -- send current value
|
||||
Phase = VALUE_CHANGING_WAIT
|
||||
elseif Phase == VALUE_CHANGED then -- send value
|
||||
if Value_Changed == 0 then
|
||||
local value=Line[Menu.SelLine].Val
|
||||
if value < 0 then
|
||||
value = 0x10000 + value
|
||||
end
|
||||
DSM_Send(0x18,0x06,Line[Menu.SelLine].ValId,Menu.SelLine,bit32.rshift(value,8),bit32.band(value,0xFF)) -- send current value
|
||||
Value_Changed = Value_Changed + 1
|
||||
Waiting_RX = 0
|
||||
elseif Value_Changed == 1 then
|
||||
DSM_Send(0x19,0x06,Line[Menu.SelLine].ValId,Menu.SelLine) -- validate
|
||||
-- Value_Changed = Value_Changed + 1
|
||||
-- Waiting_RX = 0
|
||||
--elseif Value_Changed == 2 then
|
||||
-- DSM_Send(0x1B,0x06,0x10,Menu.SelLine) -- validate again?
|
||||
-- Value_Changed = Value_Changed + 1
|
||||
end
|
||||
elseif Phase == VALUE_CHANGING_WAIT then
|
||||
DSM_Send(0x1A,0x06,Line[Menu.SelLine].ValId,Menu.SelLine)
|
||||
end
|
||||
multiBuffer(10,0x00);
|
||||
Retry = 50
|
||||
elseif multiBuffer(10) == 0x09 then
|
||||
-- Answer received
|
||||
--if multiBuffer(11) == 0x00 then -- waiting for commands?
|
||||
if multiBuffer(11) == 0x01 then -- read version
|
||||
--ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
RX.Name = Get_Text(multiBuffer(13))
|
||||
RX.Version = multiBuffer(14).."."..multiBuffer(15).."."..multiBuffer(16)
|
||||
Phase = MENU_TITLE
|
||||
elseif multiBuffer(11) == 0x02 then -- read menu title
|
||||
--ex: 0x09 0x02 0x4F 0x10 0xA5 0x00 0x00 0x00 0x50 0x10 0x10 0x10 0x00 0x00 0x00 0x00
|
||||
Menu.Cur = multiBuffer(12)
|
||||
Menu.Id = multiBuffer(13)
|
||||
Menu.Title = Get_Text(multiBuffer(14)+multiBuffer(15)*256)
|
||||
Menu.Prev = multiBuffer(16)
|
||||
Menu.PrevId = multiBuffer(17)
|
||||
Menu.Next = multiBuffer(18)
|
||||
Menu.NextId = multiBuffer(19)
|
||||
Menu.Back = multiBuffer(20)
|
||||
Menu.BackId = multiBuffer(21)
|
||||
for i = 0, 6 do -- clear menu
|
||||
Line[i] = { Menu = nil, Id = nil, Type = nil, Text="", Next = nil, NextId = nil, ValLine = nil, ValId = nil, Min, Max, Def, Val, Unit, Step }
|
||||
end
|
||||
Menu.CurLine = nil
|
||||
if Menu.Next ~= 0 then
|
||||
Menu.SelLine = 7 -- highlight Next
|
||||
else
|
||||
Menu.SelLine = -1 -- highlight Back
|
||||
end
|
||||
Blink = 0
|
||||
Phase = MENU_LINES
|
||||
elseif multiBuffer(11) == 0x03 then -- read menu lines
|
||||
--ex: 0x09 0x03 0x00 0x10 0x00 0x1C 0xF9 0x00 0x10 0x10 0x00 0x00 0x00 0x00 0x03 0x00
|
||||
-- Menu Id line Type Text_idx Next V_Id Val_Min Val_Max Val_Def
|
||||
--ex: 0x09 0x03 0x61 0x10 0x00 0x6C 0x50 0x00 0x00 0x10 0x36 0x00 0x49 0x00 0x36 0x00
|
||||
Menu.CurLine = multiBuffer(14)
|
||||
local line = Line[Menu.CurLine]
|
||||
line.Menu = multiBuffer(12)
|
||||
line.Id = multiBuffer(13) -- not quite sure yet
|
||||
line.Type = multiBuffer(15) -- not quite sure yet: 1C is text menu only, 4C/6C is text followed by text list, C0 is text followed by percentage value
|
||||
line.Text = Get_Text(multiBuffer(16)+multiBuffer(17)*256)
|
||||
if multiBuffer(18) == Menu.Cur then
|
||||
line.Next = nil
|
||||
else
|
||||
line.Next = multiBuffer(18) -- not quite sure yet: 1C=text menu=>next menu, others=>line number of the value
|
||||
end
|
||||
if Menu.SelLine == -1 and line.Next ~= nil then -- Auto select first line of the menu
|
||||
Menu.SelLine = Menu.CurLine
|
||||
end
|
||||
line.NextId = multiBuffer(19) -- not quite sure yet
|
||||
line.ValLine = multiBuffer(18) -- not quite sure yet
|
||||
line.ValId = multiBuffer(19) -- not quite sure yet
|
||||
line.Min = conv_int16(multiBuffer(20)+multiBuffer(21)*256)
|
||||
line.Max = conv_int16(multiBuffer(22)+multiBuffer(23)*256)
|
||||
line.Def = conv_int16(multiBuffer(24)+multiBuffer(25)*256)
|
||||
if line.Type == MENU then
|
||||
-- nothing to do on menu entries
|
||||
elseif line.Type == LIST_MENU_NOCHANGING or line.Type == LIST_MENU2 then
|
||||
line.Val = nil --line.Def - line.Min -- use default value not sure if needed
|
||||
line.Def = line.Min -- pointer to the start of the list in Text
|
||||
line.Max = line.Max - line.Min -- max index
|
||||
line.Min = 0 -- min index
|
||||
else -- default to numerical value
|
||||
line.Val = nil --line.Def -- use default value not sure if needed
|
||||
end
|
||||
if line.Type ~= 0x1C then -- value to follow
|
||||
line.Text = line.Text..":"
|
||||
end
|
||||
Phase = MENU_LINES
|
||||
elseif multiBuffer(11) == 0x04 then -- read menu values
|
||||
--ex: 0x09 0x04 0x53 0x10 0x00 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
-- Menu MeId line VaId Value
|
||||
--ex: 0x09 0x04 0x61 0x10 0x02 0x10 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
Menu.CurLine = multiBuffer(14)
|
||||
Line[Menu.CurLine].Val = conv_int16(multiBuffer(16)+multiBuffer(17)*256)
|
||||
Phase = MENU_VALUES
|
||||
elseif multiBuffer(11) == 0x05 then -- unknown... need to get through the lines...
|
||||
Menu.CurLine = 0x80 + multiBuffer(12)
|
||||
Phase = MENU_LINES
|
||||
elseif multiBuffer(11) == 0x00 and Phase == VALUE_CHANGING then
|
||||
Phase = VALUE_CHANGING_WAIT
|
||||
end
|
||||
-- Data processed
|
||||
Waiting_RX = 0
|
||||
multiBuffer(10,0x00)
|
||||
Retry = 50
|
||||
else
|
||||
Retry = Retry - 1
|
||||
if Retry <= 0 then
|
||||
-- Retry the RX request
|
||||
Retry = 50
|
||||
Waiting_RX = 0
|
||||
if Phase ~= RX_VERSION and Phase ~= VALUE_CHANGING_WAIT then
|
||||
Phase = WAIT_CMD
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function DSM_Display()
|
||||
lcd.clear()
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "DSM Forward Programming", MENU_TITLE_COLOR)
|
||||
--Draw RX Menu
|
||||
if Phase == RX_VERSION then
|
||||
lcd.drawText(10,50,"No compatible DSM RX...", BLINK)
|
||||
else
|
||||
if Menu.Title ~= nil then
|
||||
local attrib=0;
|
||||
lcd.drawText(80,32,Menu.Title,MIDSIZE)
|
||||
for i = 0, 6 do
|
||||
if i == Menu.SelLine then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if Line[i] ~= nil and Line[i].Type ~= nil then
|
||||
if Line[i].Type ~= MENU then -- list/value
|
||||
if Line[i].Val ~= nil then
|
||||
local text=""
|
||||
if Line[i].Type == LIST_MENU_NOCHANGING or Line[i].Type == LIST_MENU2 then
|
||||
text = Get_Text(Line[i].Val+Line[i].Def)
|
||||
elseif Line[i].Type == PERCENTAGE_VALUE then
|
||||
text = Line[i].Val.." %"
|
||||
else
|
||||
text = Line[i].Val
|
||||
end
|
||||
if Menu.EditLine == Menu.SelLine then -- blink edited entry
|
||||
Blink = Blink + 1
|
||||
if Blink > 25 then
|
||||
attrib = 0
|
||||
if Blink > 50 then
|
||||
Blink = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
lcd.drawText(240,32+20*(i+2), text, attrib) -- display value
|
||||
end
|
||||
attrib = 0
|
||||
end
|
||||
lcd.drawText(10,32+20*(i+2), Line[i].Text, attrib) -- display text
|
||||
end
|
||||
end
|
||||
if Menu.SelLine == -1 then
|
||||
lcd.drawText(437,32, "Back", INVERS)
|
||||
else
|
||||
lcd.drawText(437,32, "Back", 0)
|
||||
end
|
||||
lcd.drawRectangle(437-5, 32-2, 47, 25)
|
||||
if Menu.Next ~= 0 then
|
||||
if Menu.SelLine == 7 then
|
||||
lcd.drawText(437,220, "Next",INVERS)
|
||||
else
|
||||
lcd.drawText(437,220, "Next")
|
||||
end
|
||||
lcd.drawRectangle(437-5, 220-2, 47, 25)
|
||||
end
|
||||
if Menu.Prev ~= 0 then
|
||||
if Menu.SelLine == 8 then
|
||||
lcd.drawText(5,220, "Prev",INVERS)
|
||||
else
|
||||
lcd.drawText(5,220, "Prev")
|
||||
end
|
||||
lcd.drawRectangle(5-5, 220-2, 47, 25)
|
||||
end
|
||||
end
|
||||
lcd.drawText(170,252, "RX "..RX.Name.." v"..RX.Version) -- display RX info
|
||||
end
|
||||
else
|
||||
-- --Draw RX Menu on LCD_W=128
|
||||
-- if multiBuffer( 4 ) == 0xFF then
|
||||
-- lcd.drawText(2,17,"No compatible DSM RX...",SMLSIZE)
|
||||
-- else
|
||||
-- if Retry_128 ~= 0 then
|
||||
-- --Intro page
|
||||
-- Retry_128 = Retry_128 - 1
|
||||
-- lcd.drawScreenTitle("DSM Forward Programming",0,0)
|
||||
-- lcd.drawText(2,17,"Press Prev Page for previous Menu" ,SMLSIZE)
|
||||
-- else
|
||||
-- --Menu page
|
||||
-- for line = 0, 7, 1 do
|
||||
-- for i = 0, 21-1, 1 do
|
||||
-- value=multiBuffer( line*21+6+i )
|
||||
-- if value > 0x80 then
|
||||
-- value = value - 0x80
|
||||
-- lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS)
|
||||
-- else
|
||||
-- lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE)
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('D') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('D') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Init TX buffer
|
||||
multiBuffer( 3, 0x00 )
|
||||
--Init RX buffer
|
||||
multiBuffer( 10, 0x00 )
|
||||
--Init telemetry
|
||||
multiBuffer( 0, string.byte('D') )
|
||||
multiBuffer( 1, string.byte('S') )
|
||||
multiBuffer( 2, string.byte('M') )
|
||||
|
||||
--Text to be displayed -> need to use a file instead?
|
||||
--RX names--
|
||||
Text[0x0014]="SPM4651T"
|
||||
Text[0x0015]="AR637T"
|
||||
--Lists--
|
||||
Text[0x0036]="Throttle"
|
||||
Text[0x0037]="Aileron"
|
||||
Text[0x0038]="Elevator"
|
||||
Text[0x0039]="Rudder"
|
||||
Text[0x003A]="Gear"
|
||||
|
||||
--******
|
||||
--This part is strange since the AR637T needs
|
||||
for i=1,7 do -- 3B..41
|
||||
Text[0x003A+i]="Aux"..i
|
||||
end
|
||||
for i=1,8 do -- 41..49
|
||||
Text[0x0041+i]="XPlus-"..i
|
||||
end
|
||||
--But FOTO-PETE reports that it should be:
|
||||
Text[0x0040]="Roll"
|
||||
Text[0x0041]="Pitch"
|
||||
Text[0x0042]="Yaw"
|
||||
Text[0x0046]="Priority"
|
||||
--******
|
||||
|
||||
Text[0x004A]="Failsafe"
|
||||
Text[0x004B]="Main Menu"
|
||||
Text[0x004E]="Position"
|
||||
Text[0x0050]="Outputs"
|
||||
Text[0x0051]="Output Channel 1"
|
||||
Text[0x0052]="Output Channel 2"
|
||||
Text[0x0053]="Output Channel 3"
|
||||
Text[0x0054]="Output Channel 4"
|
||||
Text[0x0055]="Output Channel 5"
|
||||
Text[0x0056]="Output Channel 6"
|
||||
--Text[0x005E]="Inhibit"
|
||||
Text[0x005F]="Hold Last"
|
||||
Text[0x0060]="Preset"
|
||||
--Text[0x0061]="Custom"
|
||||
--Messages--
|
||||
Text[0x0078]="FM Channel"
|
||||
Text[0x0080]="Orientation"
|
||||
Text[0x0085]="Frame Rate"
|
||||
Text[0x0086]="System Setup"
|
||||
Text[0x0087]="F-Mode Setup"
|
||||
Text[0x0088]="Enabled F-Modes"
|
||||
Text[0x008A]="Gain Sensitivity"
|
||||
Text[0x0090]="Apply"
|
||||
Text[0x0093]="Complete"
|
||||
Text[0x0094]="Done"
|
||||
Text[0x0097]="Factory Reset"
|
||||
Text[0x009A]="Capture Failsafe Positions"
|
||||
Text[0x009C]="Custom Failsafe"
|
||||
Text[0x00A5]="First Time Setup"
|
||||
Text[0x00AD]="Gain Channel Select"
|
||||
Text[0x00B6]="FM1"
|
||||
Text[0x00B7]="FM2"
|
||||
Text[0x00B8]="FM3"
|
||||
Text[0x00B9]="FM4"
|
||||
Text[0x00BA]="FM5"
|
||||
Text[0x00BB]="FM6"
|
||||
Text[0x00BC]="FM7"
|
||||
Text[0x00BD]="FM8"
|
||||
Text[0x00BE]="FM9"
|
||||
Text[0x00BF]="FM10"
|
||||
Text[0x00F9]="Gyro settings"
|
||||
Text[0x00FE]="Stick Priority"
|
||||
Text[0x0100]="Make sure the model has been"
|
||||
Text[0x0101]="configured, including wing type,"
|
||||
Text[0x0102]="reversing, travel, trimmed, etc."
|
||||
Text[0x0103]="before continuing setup."
|
||||
Text[0x0104]="0104"
|
||||
Text[0x0105]="0105"
|
||||
Text[0x0106]="Any wing type, channel assignment,"
|
||||
Text[0x0107]="subtrim, or servo reversing changes"
|
||||
Text[0x0108]="require running through initial"
|
||||
Text[0x0109]="setup again."
|
||||
Text[0x010A]="010A"
|
||||
Text[0x010B]="010B"
|
||||
Text[0x0190]="Relearn Servo Settings"
|
||||
Text[0x019C]="Enter Receiver Bind Mode"
|
||||
Text[0x01DC]="AS3X"
|
||||
Text[0x01DD]="AS3X Settings"
|
||||
Text[0x01DE]="AS3X Gains"
|
||||
Text[0x01E0]="Rate Gains"
|
||||
Text[0x020A]="Restore from Backup"
|
||||
Text[0x0209]="Save to Backup"
|
||||
Text[0x020D]="First Time SAFE Setup"
|
||||
Text[0x021A]="Set the model level,"
|
||||
Text[0x021B]="and press Continue."
|
||||
Text[0x021C]="021C"
|
||||
Text[0x021D]="021D"
|
||||
|
||||
Text[0x021F]="Set the model on its nose,"
|
||||
Text[0x0220]="and press Continue. If the"
|
||||
Text[0x0221]="orientation on the next"
|
||||
Text[0x0222]="screen is wrong go back"
|
||||
Text[0x0223]="and try again."
|
||||
Text[0x0224]="Continue"
|
||||
Text[0x0229]="Set Orientation Manually"
|
||||
|
||||
Text[0x0227]="Other settings"
|
||||
Text[0x022B]="WARNING!"
|
||||
Text[0x022C]="This will reset the"
|
||||
Text[0x022D]="configuration to factory"
|
||||
Text[0x022E]="defaults. This does not"
|
||||
Text[0x022F]="affect the backup config."
|
||||
Text[0x0230]="0230"
|
||||
Text[0x0231]="This will overwrite the"
|
||||
Text[0x0232]="backup memory with your"
|
||||
Text[0x0233]="current configuartion."
|
||||
Text[0x0234]="0234"
|
||||
Text[0x0235]="0235"
|
||||
Text[0x0236]="This will overwrite the"
|
||||
Text[0x0237]="current config with"
|
||||
Text[0x0238]="that which is in"
|
||||
Text[0x0239]="the backup memory."
|
||||
Text[0x023A]="023A"
|
||||
Text[0x023D]="Copy Flight Mode Settings"
|
||||
Text[0x0240]="Utilities"
|
||||
Text[0x8001]="Flight Mode 1"
|
||||
Text[0x8002]="Flight Mode 2"
|
||||
Text[0x8003]="Flight Mode 3"
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function DSM_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
DSM_Release()
|
||||
return 2
|
||||
else
|
||||
DSM_Menu(event)
|
||||
DSM_Send_Receive()
|
||||
DSM_Display()
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=DSM_Init, run=DSM_Run }
|
||||
439
Lua_scripts/DSM FwdPrg_05_BW.lua
Normal file
439
Lua_scripts/DSM FwdPrg_05_BW.lua
Normal file
@@ -0,0 +1,439 @@
|
||||
local toolName = "TNS|DSM Forward Prog v0.5 (Text B&W) |TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local SIMULATION_ON = true -- FALSE: use real communication to DSM RX (DEFAULT), TRUE: use a simulated version of RX
|
||||
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
|
||||
if (SIMULATION_ON) then
|
||||
-- library with SIMILATION VERSION. Works really well in Companion for GUI development
|
||||
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
|
||||
else
|
||||
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
|
||||
end
|
||||
|
||||
local PHASE = dsmLib.PHASE
|
||||
local LINE_TYPE = dsmLib.LINE_TYPE
|
||||
local DISP_ATTR = dsmLib.DISP_ATTR
|
||||
|
||||
local DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
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 function GUI_SwitchSimulationOFF()
|
||||
dsmLib.ReleaseConnection()
|
||||
dsmLib.LOG_close()
|
||||
|
||||
SIMULATION_ON = false
|
||||
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.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
|
||||
lcd.drawText(x+5,y+2, text, attr + TEXT_SIZE)
|
||||
lcd.drawRectangle(x, y, w, h, LINE_COLOR)
|
||||
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
|
||||
|
||||
local bold = 0
|
||||
if (TEXT_SIZE~=SMLSIZE) then -- Ignore Bold on small size screens
|
||||
bold = BOLD
|
||||
end
|
||||
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 .. " |>" --OPENTX
|
||||
else -- SubHeaders and plain text lines
|
||||
if (TEXT_SIZE~=SMLSIZE) then -- ignore bold on small size screens
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0
|
||||
end
|
||||
|
||||
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
|
||||
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.isFlightModeText(line.TextId)) then
|
||||
-- Display Header + Value together
|
||||
header = header .. " " .. value
|
||||
|
||||
-- Flight mode display attributes
|
||||
if (TEXT_SIZE~=SMLSIZE) then -- ignore bold on small size screens
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0
|
||||
end
|
||||
|
||||
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
|
||||
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.isFlightModeText(line.TextId) then
|
||||
local attrib = 0
|
||||
value = value .. (line.Format or "") -- Append % if needed
|
||||
|
||||
if selected then
|
||||
attrib = INVERS
|
||||
if editing then -- blink editing entry
|
||||
attrib = attrib + BLINK
|
||||
value = "[ " .. value .. " ]"
|
||||
end
|
||||
end
|
||||
|
||||
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_Display()
|
||||
local ctx = DSM_Context
|
||||
lcd.clear()
|
||||
|
||||
local header = "DSM Fwrd Programming "
|
||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||
header = header .. "RX "..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)
|
||||
end
|
||||
--Draw RX Menu
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
lcd.drawText(LCD_X_LINE_TITLE,50,"No compatible DSM RX...", BLINK + TEXT_SIZE)
|
||||
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_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
||||
local imgValue = dsmLib.Get_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
|
||||
|
||||
if (imgValue) then -- Optional Image for a Value
|
||||
--TODO: Pending feature.. create images and put bitmap instead of a message
|
||||
--Display the image/Alternate Text
|
||||
lcd.drawText(LCD_X_LINE_TITLE, LCD_Y_LINE_FIRST+LCD_Y_LINE_HEIGHT, "Img:"..imgValue)
|
||||
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.ChangePhase(PHASE.VALUE_CHANGE_END) -- Update+Validate value in RX
|
||||
ctx.EditLine = nil -- Exit Edit Mode (By clearing the line editing)
|
||||
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, 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)
|
||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
||||
dsmLib.GotoMenu(menu.NextId)
|
||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
||||
dsmLib.GotoMenu(menu.PrevId)
|
||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then
|
||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Next menu exist
|
||||
if (SIMULATION_ON and menuLines[ctx.SelLine].ValId==0xFFFF) then
|
||||
-- SPECIAL Simulation menu to Exit Simulation and
|
||||
-- comunicate with Real RX
|
||||
GUI_SwitchSimulationOFF()
|
||||
else
|
||||
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId) -- ValId is the MenuId to navigate to
|
||||
end
|
||||
else
|
||||
-- Editing a Line????
|
||||
if ctx.isEditing() then
|
||||
-- Change the Value and exit edit
|
||||
ctx.EditLine = nil
|
||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END)
|
||||
else
|
||||
-- enter Edit the current line
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = menuLines[ctx.SelLine].Val
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_screen_pos()
|
||||
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 = 30
|
||||
LCD_H_BUTTONS = 17
|
||||
LCD_X_RIGHT_BUTTONS = 128 - LCD_W_BUTTONS - 5
|
||||
|
||||
LCD_X_LINE_MENU = 0
|
||||
-- X offsets for (Title: [Value] debugInfo) lines
|
||||
LCD_X_LINE_TITLE = 0
|
||||
LCD_X_LINE_VALUE = 90
|
||||
LCD_X_LINE_DEBUG = 110
|
||||
|
||||
LCD_Y_LINE_HEIGHT = 17
|
||||
LCD_Y_MENU_TITLE = 0
|
||||
LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 17
|
||||
LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT
|
||||
end
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
-- Refresh display only if needed and no faster than 500ms, utilize more CPU to speedup DSM communications
|
||||
if (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 }
|
||||
627
Lua_scripts/DSM FwdPrg_05_Color.lua
Normal file
627
Lua_scripts/DSM FwdPrg_05_Color.lua
Normal file
@@ -0,0 +1,627 @@
|
||||
local toolName = "TNS|DSM Forward Prog v0.5 (Color+Touch) |TNE"
|
||||
local VERSION = "v0.5"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local SIMULATION_ON = true -- FALSE: use real communication to DSM RX (DEFAULT), TRUE: use a simulated version of RX
|
||||
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
|
||||
if (SIMULATION_ON) then
|
||||
-- library with SIMILATION VERSION. Works really well in Companion for GUI development
|
||||
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
|
||||
else
|
||||
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
|
||||
end
|
||||
|
||||
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 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 = 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
|
||||
|
||||
|
||||
|
||||
--------------------- 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)
|
||||
print(string.format("EdgeTX=%s",IS_EDGETX))
|
||||
-- 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_SwitchSimulationOFF()
|
||||
dsmLib.ReleaseConnection()
|
||||
dsmLib.LOG_close()
|
||||
|
||||
SIMULATION_ON = false
|
||||
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.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)
|
||||
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
|
||||
lcd.drawText(x , y, text, txtColor)
|
||||
|
||||
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)
|
||||
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)
|
||||
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
|
||||
|
||||
--if (editing) then -- Any Special color/effect when editing??
|
||||
-- value = "["..value .. "]"
|
||||
--end
|
||||
|
||||
---------- NAME Part
|
||||
local header = line.Text
|
||||
-- ONLY do this for Flight Mode (Right Align or Centered)
|
||||
if (dsmLib.isFlightModeText(line.TextId)) then
|
||||
-- Display Header + Value together
|
||||
header = header .. " " .. value
|
||||
|
||||
-- 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.isFlightModeText(line.TextId) then
|
||||
value = value .. (line.Format or "") -- Append % if needed
|
||||
|
||||
if dsmLib.isSelectableLine(line) then
|
||||
-- Can select/edit value, Box it
|
||||
local tw = my_lcd_sizeText(value)+10 -- Width of the Text in the lcd
|
||||
GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected)
|
||||
GUI_addTouchButton(LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,lineNum)
|
||||
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_Display()
|
||||
local ctx = DSM_Context
|
||||
lcd.clear()
|
||||
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
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,"No compatible DSM RX...", BLINK)
|
||||
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
|
||||
-- list/value line
|
||||
local value, imgValue = line.Val, nil
|
||||
|
||||
if line.Val ~= nil then
|
||||
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
|
||||
value = dsmLib.Get_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
||||
imgValue = dsmLib.Get_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
|
||||
|
||||
if (imgValue) then -- Optional Image for a Value
|
||||
--TODO: Pending feature.. create images and put bitmap instead of a message
|
||||
--Display the image/Alternate Text
|
||||
lcd.drawText(LCD_X_LINE_TITLE, LCD_Y_LINE_START+LCD_Y_LINE_HEIGHT, "Img:"..imgValue)
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
ctx.MenuLines[ctx.EditLine].Val = originalValue
|
||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Update + Validate value in RX
|
||||
ctx.EditLine = nil -- Exit Edit Mode (By clearing the line editing)
|
||||
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)
|
||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
||||
dsmLib.GotoMenu(menu.NextId)
|
||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
||||
dsmLib.GotoMenu(menu.PrevId)
|
||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value
|
||||
|
||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Navigate to Menu
|
||||
if (SIMULATION_ON and menuLines[ctx.SelLine].ValId==0xFFFF) then
|
||||
-- SPECIAL Simulation menu to Exit Simulation
|
||||
GUI_SwitchSimulationOFF()
|
||||
else
|
||||
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId) -- ValId is the MenuId to navigate to
|
||||
end
|
||||
else -- Enter on a Value
|
||||
if ctx.isEditing() then -- already editing a Line????
|
||||
ctx.EditLine = nil -- Exit Edit Mode (By clearing the line editing)
|
||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Request change the value on RX
|
||||
else -- Edit the current value
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = menuLines[ctx.SelLine].Val
|
||||
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()
|
||||
IS_EDGETX = osname~=nil
|
||||
|
||||
if (IS_EDGETX and USE_SPECKTRUM_COLORS) then
|
||||
-- SPECKTRUM COLORS (only works on EDGETX)
|
||||
-- TOOL HEADER
|
||||
LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR
|
||||
LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR
|
||||
-- MENU HEADER
|
||||
LCD_MENU_COLOR = WHITE
|
||||
LCD_MENU_BGCOLOR = DARKGREY
|
||||
-- LINE SELECTED
|
||||
LCD_SELECTED_COLOR = WHITE
|
||||
LCD_SELECTED_BGCOLOR = ORANGE
|
||||
LCD_EDIT_BGCOLOR = WARNING_COLOR
|
||||
-- NORMAL TEXT
|
||||
LCD_NORMAL_COLOR = BLACK
|
||||
LCD_DISABLE_COLOR = LIGHTGREY
|
||||
LCD_DEBUG_COLOR = BLUE
|
||||
-- NORMAL BOX FRAME COLOR
|
||||
LCD_BOX_COLOR = LIGHTGREY
|
||||
end
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
-- Refresh display only if needed and no faster than 300ms, utilize more CPU to speedup DSM communications
|
||||
if (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 }
|
||||
1374
Lua_scripts/DSMLIB/DsmFwPrgLib.lua
Normal file
1374
Lua_scripts/DSMLIB/DsmFwPrgLib.lua
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Lua_scripts/DSMLIB/DsmFwPrgLib.luac
Normal file
BIN
Lua_scripts/DSMLIB/DsmFwPrgLib.luac
Normal file
Binary file not shown.
1075
Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua
Normal file
1075
Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Lua_scripts/DSMLIB/DsmFwPrgSIMLib.luac
Normal file
BIN
Lua_scripts/DSMLIB/DsmFwPrgSIMLib.luac
Normal file
Binary file not shown.
44
Lua_scripts/DSMLIB/readme.txt
Normal file
44
Lua_scripts/DSMLIB/readme.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
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, etc.
|
||||
|
||||
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
Rewrite/Enhancements By: Francisco Arzu
|
||||
|
||||
|
||||
|
||||
Deployment:
|
||||
/SCRIPTS/TOOLS/DsmFwdPrg_05_BaW.lua -- OpenTX/EdgeTx version, no touch (black/white radios)
|
||||
/SCRIPTS/TOOLS/DsmFwdPrg_05_Color.lua -- EdgeTX/OpenTx Color version, +touch
|
||||
/SCRIPTS/TOOLS/DSMLIB/ -- Libraries (ALL CAPITALS) to hide them from the Tools menu
|
||||
/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lub -- DSM Protocol Message and Menu engine
|
||||
/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgSIMLib.lub -- Simulation of AR631 for GUI Development in Companion
|
||||
|
||||
/LOGS/dsm_log.txt -- Readable log of the last RX session, usefull for debuging new RX
|
||||
|
||||
|
||||
Version 0.5
|
||||
- Make the code more readable and understadable
|
||||
- Separate the DSM Forwards Programing logic from the GUI
|
||||
- Log the comunnication 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 version with only Key/Roller Inputs (OTX)
|
||||
- Created a nicer GUI for EdgeTX touchscreen color Radios
|
||||
|
||||
Known Problems:
|
||||
1. When trying to Factory Reset an RX, even that navigation to menus seems OK, it did not reset.
|
||||
Maybe another message needs to be sent to RX when reaching that page
|
||||
2. When initially setting a new RX, there is a point where a menu navigates to MenuID=0x0001, this seems like a
|
||||
special Save/Restart type of menu.. but it does not reset the RX. maybe another meesage needs to be send
|
||||
3. Some Menu List line types (LINE_TYPE.LIST_MENU1), the range (min/max) seems to be incorrect, but cannot see in the data how to fix it
|
||||
Some of the valid values are not even sequential, very spread apart. There has to be a list of valid options somewhere (in RX or config for each field).
|
||||
4. The RX return unknow lines when requesting the Lines for a menu. Realy don't understand what they are for.
|
||||
in some menus, seems to stay stuck in the same return line or no response to the request, making the RX reset/close the connection.
|
||||
Did a fix to stop requesting the same menu line if the response is the same. This gives an empty menu, but does not reset the connection.
|
||||
|
||||
|
||||
Version 0.2
|
||||
Original Version from Pascal Langer
|
||||
|
||||
|
||||
167
Lua_scripts/Graupner HoTT Model Locator.lua
Normal file
167
Lua_scripts/Graupner HoTT Model Locator.lua
Normal file
@@ -0,0 +1,167 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Telemetry Widget script for FrSky Horus/Radio Master TX16s #
|
||||
---- # Copyright (C) EdgeTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
-- Model Locator by RSSI
|
||||
-- Offer Shmuely (based on code from Scott Bauer 6/21/2015)
|
||||
-- Date: 2021
|
||||
-- ver: 0.1
|
||||
|
||||
-- MHA (based on code from Offer Shmuely)
|
||||
-- Date: 2022
|
||||
-- ver: 0.11
|
||||
-- changes: made version for Graupner HoTT. Uses real Rssi data scaled -15db to -115db to 100..0
|
||||
|
||||
-- This widget help to find a lost/crashed model based on the RSSI (if still available)
|
||||
-- The widget produce audio representation (variometer style) of the RSSI from the lost model
|
||||
-- The widget also display the RSSI in a visible colorized bar (0-100%)
|
||||
|
||||
-- There are two way to use it
|
||||
-- 1. The simple way:
|
||||
-- walk toward the quad/plane that crashed,
|
||||
-- as you get closer to your model the beeps will become more frequent with higher pitch (and a visual bar graph as well)
|
||||
-- until you get close enough to find it visually
|
||||
|
||||
-- 2. the more accurate way:
|
||||
-- turn the antenna straight away (i.e. to point from you, straight away)
|
||||
-- try to find the weakest signal! (not the highest), i.e. the lowest RSSI you can find, this is the direction to the model.
|
||||
-- now walk to the side (not toward the model), find again the weakest signal, this is also the direction to your model
|
||||
-- triangulate the two lines, and it will be :-)
|
||||
|
||||
local delayMillis = 100
|
||||
local nextPlayTime = getTime()
|
||||
local img = Bitmap.open("/SCRIPTS/TOOLS/Model Locator (by RSSI).png")
|
||||
|
||||
--------------------------------------------------------------
|
||||
local function log(s)
|
||||
--return;
|
||||
print("locator: " .. s)
|
||||
end
|
||||
--------------------------------------------------------------
|
||||
|
||||
|
||||
-- init_func is called once when model is loaded
|
||||
local function init()
|
||||
return 0
|
||||
end
|
||||
|
||||
-- bg_func is called periodically when screen is not visible
|
||||
local function bg()
|
||||
return 0
|
||||
end
|
||||
|
||||
-- This function returns green at gvalue, red at rvalue and graduate in between
|
||||
local function getRangeColor(value, red_value, green_value)
|
||||
local range = math.abs(green_value - red_value)
|
||||
if range == 0 then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
if value == nil then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
|
||||
if green_value > red_value then
|
||||
if value > green_value then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
if value < red_value then
|
||||
return lcd.RGB(0xdf, 0, 0)
|
||||
end
|
||||
g = math.floor(0xdf * (value - red_value) / range)
|
||||
r = 0xdf - g
|
||||
return lcd.RGB(r, g, 0)
|
||||
else
|
||||
if value > green_value then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
if value < red_value then
|
||||
return lcd.RGB(0xdf, 0, 0)
|
||||
end
|
||||
r = math.floor(0xdf * (value - green_value) / range)
|
||||
g = 0xdf - r
|
||||
return lcd.RGB(r, g, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local function main(event)
|
||||
|
||||
lcd.clear()
|
||||
|
||||
-- fetch uplink rssi (HoTT sensor Rssi)
|
||||
local rssi = getValue("Rssi")
|
||||
|
||||
-- calculate a percentage for the color bar (range -115db to -15db)
|
||||
local rssiP = rssi
|
||||
|
||||
if(rssi ~= 0) then -- rssi < 0 -> telemtry data received
|
||||
if(rssi >= -15) then -- -15db to -1db => 100%
|
||||
rssiP = 100
|
||||
else
|
||||
if(rssi >= -115) then -- between -115db and -15db => 0% to 100%
|
||||
rssiP = 100+rssi+15
|
||||
else
|
||||
rssiP = 0 -- less than -115 => 0%
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
lcd.drawBitmap(img, 250, 50, 40)
|
||||
|
||||
-- Title
|
||||
lcd.drawText(3, 3, "Graupner HoTT Rssi Model Locator", 0)
|
||||
myColor = getRangeColor(rssi, 0, 100)
|
||||
lcd.setColor(CUSTOM_COLOR, myColor)
|
||||
|
||||
-- draw current value
|
||||
local dx = 0
|
||||
if rssi < -99 then
|
||||
dx = -33
|
||||
end
|
||||
|
||||
if rssi == 0 then
|
||||
lcd.drawText(115, 73, "no telemetry", DBLSIZE + CUSTOM_COLOR)
|
||||
else
|
||||
lcd.drawNumber(180+dx, 30, rssi, XXLSIZE + CUSTOM_COLOR)
|
||||
lcd.drawText(275, 73, "db", 0 + CUSTOM_COLOR)
|
||||
end
|
||||
|
||||
-- draw main bar
|
||||
lcd.setColor(CUSTOM_COLOR, YELLOW) -- RED / YELLOW
|
||||
local xMin = 0
|
||||
local yMin = 270
|
||||
local xMax = 480
|
||||
local yMax = 200
|
||||
local h = 0
|
||||
local rssiAsX = (rssiP * xMax) / 100
|
||||
|
||||
for xx = xMin, rssiAsX, 20 do
|
||||
lcd.setColor(CUSTOM_COLOR, getRangeColor(xx, xMin, xMax - 40))
|
||||
h = h + 10
|
||||
lcd.drawFilledRectangle(xx, yMin - h, 15, h, CUSTOM_COLOR)
|
||||
end
|
||||
|
||||
-- beep
|
||||
if getTime() >= nextPlayTime then
|
||||
playFile("/SCRIPTS/TOOLS/Model Locator (by RSSI).wav")
|
||||
nextPlayTime = getTime() + delayMillis - rssiP
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
return {init = init,run = main,background = bg}
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,6,Flysky_AFHDS2A,PWM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,7,Flysky_AFHDS2A,PPM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
56,1,Flysky2A_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
53,0,Height,5ch,0,Gear
|
||||
@@ -84,7 +86,8 @@
|
||||
55,1,FrSkyRX,CloneTX,0
|
||||
55,2,FrSkyRX,EraseTX,0
|
||||
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
58,0,FX816,P38,1
|
||||
58,0,FX,816,1
|
||||
58,1,FX,620,1
|
||||
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
||||
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
|
||||
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
|
||||
@@ -112,7 +115,8 @@
|
||||
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
71,0,JJRC345,JJRC345,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
49,0,KF606,Std,1,Trim
|
||||
49,0,KF606,KF606,1,Trim
|
||||
49,1,KF606,MIG320,1,Trim,LED
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
@@ -130,6 +134,7 @@
|
||||
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
|
||||
17,5,MT99XX,A180,0,3D_6G
|
||||
17,6,MT99XX,Dragon,0,Mode,RTH
|
||||
17,7,MT99XX,F949G,0,6G_3D,Light
|
||||
44,0,NCC1701,Std,1,Warp
|
||||
77,0,OMP,M2,0,THold,IdleUp,6G_3D
|
||||
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
||||
@@ -167,8 +172,9 @@
|
||||
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
|
||||
48,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
46,0,V911s,V911s,1,Calib
|
||||
46,1,V911s,E119,1,Calib
|
||||
48,2,V761,TOPRC,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
46,0,V911s,V911s,1,Calib,Rate
|
||||
46,1,V911s,E119,1,Calib,Rate,6G_3D
|
||||
22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
|
||||
30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
|
||||
30,1,WK2x01,WK2401,0
|
||||
@@ -190,9 +196,13 @@
|
||||
81,0,E010r5,E010r5,1,Flip,LED,CALIB,HLess,RTH,GLIDE
|
||||
82,0,LOLI,Std,0,CH5,CH6,CH7,CH8,1SwSePpPw,2SwSePw,3SwSe,4SwSe,5SwSeSb,6SwSe,7SwSePw,8SwSe
|
||||
83,0,E129,E129,1,TakLan,EmStop,TrimA,TrimE,TrimR
|
||||
83,1,E129,C186,1,TakLan,EmStop,TrimA,TrimE,TrimR
|
||||
84,0,JOYSWAY,Std,0
|
||||
85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH
|
||||
87,0,IKEA
|
||||
89,0,LOSI
|
||||
90,0,MouldKg,Analog
|
||||
90,1,MouldKg,Digit,E,F
|
||||
90,0,MouldKg,Analog,0
|
||||
90,1,MouldKg,Digit,0
|
||||
91,0,Xerall,Tank,0,FlTa,TakLan,Rate,HLess,Photo,Video,TrimR,TrimE,TrimA
|
||||
92,0,MT99xx2,PA18,0,MODE,FLIP,RTH
|
||||
93,0,Kyosho2,KT-17,0
|
||||
|
||||
@@ -48,6 +48,7 @@ local ModuleNumber = 0
|
||||
local ModuleType = ""
|
||||
local Module = {}
|
||||
local InitialProtocol = 0
|
||||
local InitialSubProtocol = 0
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
@@ -76,6 +77,7 @@ end
|
||||
local function Config_Release()
|
||||
--Set the protocol back to what it was
|
||||
Module.protocol = InitialProtocol
|
||||
Module.subProtocol = InitialSubProtocol
|
||||
model.setModule(ModuleNumber, Module)
|
||||
|
||||
--Stop requesting updates
|
||||
@@ -422,7 +424,9 @@ local function Config_Init()
|
||||
--Get Module settings and set it to config protocol
|
||||
Module = model.getModule(ModuleNumber)
|
||||
InitialProtocol = Module.protocol
|
||||
InitialSubProtocol = Module.subProtocol
|
||||
Module.protocol = 86
|
||||
Module.subProtocol = 0
|
||||
model.setModule(ModuleNumber, Module)
|
||||
--pause while waiting for the module to switch to config
|
||||
for i = 0, 10, 1 do end
|
||||
|
||||
@@ -17,6 +17,8 @@ If you like this project and want to support further development please consider
|
||||
|
||||
Enables to modify on a Multi module the Global ID, Cyrf ID or format the EEPROM.
|
||||
|
||||
Matching the ID of 2 Multi modules enable them to control the same receivers without rebinding. Be carefull the 2 modules should not be used at the same time unless you know what you are doing.
|
||||
|
||||
Notes:
|
||||
- Supported from Multi v1.3.2.85 or above and OpenTX 2.3.12 or above
|
||||
- The Multi module to be configured must be active, if there is a second Multi module in the radio it must be off
|
||||
@@ -50,16 +52,22 @@ Notes:
|
||||
|
||||
[](https://www.youtube.com/watch?v=81wd8NlF3Qw)
|
||||
|
||||
## Graupner HoTT Model Locator
|
||||
|
||||
This is the Graupner HoTT adapted version of the Model Locator script using RSSI.
|
||||
|
||||
The OpenTX sensor "RSSI" is populated by the individual OpenTX telemetry protocol implementations and returns a value from 0..100 (percent) originating from the early FrSky implementation. It turns out that FrSky did not really provide a genuine signal strength indicator in units of dbm but a link quality indicator in 0..100%. With Graupner HoTT the link quality indicator is not a good basis for the model locator as it is very non-linear and doesn't change much with distance. Using the Graupner HoTT telemetry sensor "Rssi" which is a true signal strength indicator serves the purpose of locating a model much better as it varies much more with distance.
|
||||
|
||||
## DSM Forward Programming
|
||||
|
||||
This is a work in progress. It's only available for color screens (Horus, TX16S, T16, T18...).
|
||||
This is a work in progress. It's available for color(+touch) and B&W screens.
|
||||
|
||||
If some text appears as Unknown_xxx, please report xxx and what the exact text display should be.
|
||||
|
||||
Need OpenTX 2.3.10 nightly or above. Located on the radio SD card under \SCRIPTS\TOOLS.
|
||||
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.
|
||||
|
||||
[](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
|
||||
|
||||
Lua telemetry script from [feathering on RCGroups](https://www.rcgroups.com/forums/showpost.php?p=46033341&postcount=20728) to facilitate setting the Gain Parameters on the Blade 150S FBL. It doesn't use Forward Programming but instead it just reads telemetry data from the Multi-module and displays it on a telemetry display.
|
||||
|
||||
@@ -147,7 +147,7 @@ static void __attribute__((unused)) BUGSMINI_send_packet()
|
||||
hopping_frequency_no++;
|
||||
if(hopping_frequency_no >= BUGSMINI_NUM_RF_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
XN297_Hopping(IS_BIND_IN_PROGRESS ? hopping_frequency[hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS] : hopping_frequency[hopping_frequency_no]);
|
||||
XN297_Hopping(IS_BIND_IN_PROGRESS ? hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS : hopping_frequency_no);
|
||||
}
|
||||
|
||||
// Send
|
||||
|
||||
@@ -247,10 +247,9 @@ uint16_t DSM_RX_callback()
|
||||
eeprom_write_byte((EE_ADDR)temp++, cyrfmfg_id[i]);
|
||||
debug(" %02X", cyrfmfg_id[i]);
|
||||
}
|
||||
// check num_ch
|
||||
// save num_ch
|
||||
num_ch=packet_in[11];
|
||||
if(num_ch>12) num_ch=12;
|
||||
//check DSM_rx_type
|
||||
// store DSM_rx_type
|
||||
/*packet[12] 1 byte -> max DSM type allowed:
|
||||
0x01 => 22ms 1024 DSM2 1 packet => number of channels is <8
|
||||
0x02 => 22ms 1024 DSM2 2 packets => either a number of channel >7
|
||||
@@ -262,22 +261,6 @@ uint16_t DSM_RX_callback()
|
||||
&0xF0 => false=1024, true=2048 */
|
||||
DSM_rx_type=packet_in[12];
|
||||
debugln(", num_ch=%d, type=%02X",num_ch, DSM_rx_type);
|
||||
switch(DSM_rx_type)
|
||||
{
|
||||
case 0x01:
|
||||
if(num_ch>7) DSM_rx_type = 0x02; // Can't be 0x01 with this number of channels
|
||||
break;
|
||||
case 0xA2:
|
||||
if(num_ch>7) DSM_rx_type = 0xB2; // Can't be 0xA2 with this number of channels
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x12:
|
||||
case 0xB2:
|
||||
break;
|
||||
default: // Unknown type, default to DSMX 11ms
|
||||
DSM_rx_type = 0xB2;
|
||||
break;
|
||||
}
|
||||
eeprom_write_byte((EE_ADDR)temp, DSM_rx_type);
|
||||
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Abort RX operation
|
||||
CYRF_SetTxRxMode(TX_EN); // Force end state TX
|
||||
|
||||
@@ -55,14 +55,14 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix()
|
||||
{
|
||||
uint8_t bind_state;
|
||||
#ifdef ENABLE_PPM
|
||||
if(mode_select && option==0 && IS_BIND_DONE) //PPM mode and option not already set and bind is finished
|
||||
if(mode_select && (option&0x01)==0 && IS_BIND_DONE) //PPM mode and option not already set and bind is finished
|
||||
{
|
||||
BIND_SET_INPUT;
|
||||
BIND_SET_PULLUP; // set pullup
|
||||
if(IS_BIND_BUTTON_on)
|
||||
{
|
||||
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num),0x01); // Set fixed id mode for the current model
|
||||
option=1;
|
||||
option |= 0x01;
|
||||
}
|
||||
BIND_SET_OUTPUT;
|
||||
}
|
||||
@@ -72,7 +72,7 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix()
|
||||
MProtocol_id = RX_num + MProtocol_id_master;
|
||||
bind_counter=DEVO_BIND_COUNT;
|
||||
}
|
||||
if (option)
|
||||
if (option&0x01)
|
||||
{
|
||||
if (bind_counter > 0)
|
||||
bind_state = 0xc0;
|
||||
@@ -220,6 +220,7 @@ static void __attribute__((unused)) DEVO_parse_telemetry_packet()
|
||||
#if defined HUB_TELEMETRY
|
||||
//Telemetry https://github.com/DeviationTX/deviation/blob/5efb6a28bea697af9a61b5a0ed2528cc8d203f90/src/protocol/devo_cyrf6936.c#L232
|
||||
uint16_t val, dec;
|
||||
uint32_t val32;
|
||||
switch(packet[0])
|
||||
{
|
||||
case 0x30: // Volt and RPM packet
|
||||
@@ -255,18 +256,30 @@ static void __attribute__((unused)) DEVO_parse_telemetry_packet()
|
||||
break;
|
||||
// GPS Data
|
||||
case 0x32: // Longitude
|
||||
//memcpy(&packet[1],"\x30\x33\x30\x32\x30\x2e\x38\x32\x37\x30\x45\xfb",12); // 030°20.8270E
|
||||
val = DEVO_text_to_int(&packet[1], 3)*100 + DEVO_text_to_int(&packet[4], 2); // dddmm
|
||||
//memcpy(&packet[1],"\x30\x33\x30\x32\x30\x2e\x38\x32\x37\x30\x45\xfb",12); // 030°20.8270E in ddmm.mmmm
|
||||
//memcpy(&packet[1],"\x31\x31\x37\x31\x31\x2e\x35\x39\x34\x37\x57\xfb",12); // RX705 sends 117°11.5947W which should be 11706.95685W in ddmm.mmmm
|
||||
val = DEVO_text_to_int(&packet[1], 3)*100; // dd00
|
||||
val32 = DEVO_text_to_int(&packet[4], 2) * 10000 + DEVO_text_to_int(&packet[7], 4); // mmmmmm
|
||||
if(option&0x02) // if RX705 GPS format
|
||||
val32 = (val32*3)/5; // then * 6/10 correction
|
||||
dec = val32/10000;
|
||||
val = val + dec; // dddmm
|
||||
frsky_send_user_frame(0x12 , val, val>>8);
|
||||
val = DEVO_text_to_int(&packet[7], 4); // .mmmm
|
||||
val = val32 - dec*10000; // .mmmm
|
||||
frsky_send_user_frame(0x12+8, val, val>>8);
|
||||
frsky_send_user_frame(0x1A+8, packet[11], 0x00); // 'E'/'W'
|
||||
break;
|
||||
case 0x33: // Latitude
|
||||
//memcpy(&packet[1],"\x35\x39\x35\x34\x2e\x37\x37\x37\x36\x4e\x07\x00",12); // 59°54.776N
|
||||
val = DEVO_text_to_int(&packet[1], 2)*100 + DEVO_text_to_int(&packet[3], 2); // ddmm
|
||||
//memcpy(&packet[1],"\x35\x39\x35\x34\x2e\x37\x37\x37\x36\x4e\x07\x00",12); // 59°54.776N in ddmm.mmmm
|
||||
//memcpy(&packet[1],"\x31\x37\x31\x31\x2e\x35\x39\x34\x37\x4e\xfb\x00",12); // RX705 sends 17°11.5947N which should be 1706.95685N in ddmm.mmmm
|
||||
val = DEVO_text_to_int(&packet[1], 2)*100; // dd00
|
||||
val32 = DEVO_text_to_int(&packet[3], 2) * 10000 + DEVO_text_to_int(&packet[6], 4); // mmmmmm
|
||||
if(option&0x02) // if RX705 GPS format
|
||||
val32 = (val32*3)/5; // then * 6/10 correction
|
||||
dec = val32/10000;
|
||||
val = val + dec; // dddmm
|
||||
frsky_send_user_frame(0x13 , val, val>>8);
|
||||
val = DEVO_text_to_int(&packet[6], 4); // .mmmm
|
||||
val = val32 - dec*10000; // .mmmm
|
||||
frsky_send_user_frame(0x13+8, val, val>>8);
|
||||
frsky_send_user_frame(0x1B+8, packet[10], 0x00); // 'N'/'S'
|
||||
break;
|
||||
@@ -530,13 +543,13 @@ void DEVO_init()
|
||||
{
|
||||
if(IS_BIND_BUTTON_FLAG_on)
|
||||
{
|
||||
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num),0x00); // reset to autobind mode for the current model
|
||||
option=0;
|
||||
option &= 0xFE;
|
||||
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num),option); // reset to autobind mode for the current model
|
||||
}
|
||||
else
|
||||
{
|
||||
option=eeprom_read_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num)); // load previous mode: autobind or fixed id
|
||||
if(option!=1) option=0; // if not fixed id mode then it should be autobind
|
||||
option=eeprom_read_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+RX_num)); // load previous mode: autobind or fixed id
|
||||
if(option > 3) option = 0; // if invalid then it should be autobind
|
||||
}
|
||||
}
|
||||
#endif //ENABLE_PPM
|
||||
@@ -570,8 +583,13 @@ void DEVO_init()
|
||||
|
||||
packet_count = 0;
|
||||
|
||||
prev_option=option;
|
||||
if(option==0)
|
||||
if(option&0x01)
|
||||
{
|
||||
phase = DEVO_BOUND_1;
|
||||
bind_counter = 0;
|
||||
DEVO_cyrf_set_bound_sop_code();
|
||||
}
|
||||
else
|
||||
{
|
||||
MProtocol_id = ((uint32_t)(hopping_frequency[0] ^ cyrfmfg_id[0] ^ cyrfmfg_id[3]) << 16)
|
||||
| ((uint32_t)(hopping_frequency[1] ^ cyrfmfg_id[1] ^ cyrfmfg_id[4]) << 8)
|
||||
@@ -581,12 +599,6 @@ void DEVO_init()
|
||||
phase = DEVO_BIND;
|
||||
BIND_IN_PROGRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
phase = DEVO_BOUND_1;
|
||||
bind_counter = 0;
|
||||
DEVO_cyrf_set_bound_sop_code();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
*/
|
||||
// compatible with E012 and E015
|
||||
|
||||
#if defined(E01X_NRF24L01_INO)
|
||||
#if defined(E01X_CYRF6936_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
#include "iface_hs6200.h"
|
||||
|
||||
//Protocols constants
|
||||
#define E01X_BIND_COUNT 500
|
||||
@@ -28,7 +28,8 @@
|
||||
#define E012_NUM_RF_CHANNELS 4
|
||||
#define E012_PACKET_SIZE 15
|
||||
|
||||
#define E015_PACKET_PERIOD 4500 // stock Tx=9000, but let's send more packets ...
|
||||
//#define E015_FORCE_ID
|
||||
#define E015_PACKET_PERIOD 9000
|
||||
#define E015_RF_CHANNEL 0x2d // 2445 MHz
|
||||
#define E015_PACKET_SIZE 10
|
||||
#define E015_BIND_PACKET_SIZE 9
|
||||
@@ -87,13 +88,15 @@ static void __attribute__((unused)) E01X_send_packet()
|
||||
packet[0] = rx_tx_addr[1];
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
rf_ch_num = E012_RF_BIND_CHANNEL;
|
||||
packet[1] = 0xaa;
|
||||
memcpy(&packet[2], hopping_frequency, E012_NUM_RF_CHANNELS);
|
||||
memcpy(&packet[6], rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
rf_ch_num=E012_RF_BIND_CHANNEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
rf_ch_num = hopping_frequency[hopping_frequency_no++];
|
||||
hopping_frequency_no %= E012_NUM_RF_CHANNELS;
|
||||
packet[1] = 0x01
|
||||
| GET_FLAG(E01X_RTH_SW, E012_FLAG_RTH)
|
||||
| GET_FLAG(E01X_HEADLESS_SW, E012_FLAG_HEADLESS)
|
||||
@@ -107,8 +110,6 @@ static void __attribute__((unused)) E01X_send_packet()
|
||||
packet[8] = 0x00;
|
||||
packet[9] = 0x00;
|
||||
packet[10]= 0x00;
|
||||
rf_ch_num=hopping_frequency[hopping_frequency_no++];
|
||||
hopping_frequency_no %= E012_NUM_RF_CHANNELS;
|
||||
}
|
||||
packet[11] = 0x00;
|
||||
packet[12] = 0x00;
|
||||
@@ -117,6 +118,7 @@ static void __attribute__((unused)) E01X_send_packet()
|
||||
}
|
||||
else
|
||||
{ // E015
|
||||
rf_ch_num = E015_RF_CHANNEL;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[0] = 0x18;
|
||||
@@ -124,10 +126,11 @@ static void __attribute__((unused)) E01X_send_packet()
|
||||
packet[2] = 0x06;
|
||||
// data phase address
|
||||
memcpy(&packet[3], rx_tx_addr, E01X_ADDRESS_LENGTH);
|
||||
packet[8] = 0x63; // unknown calculation
|
||||
// checksum
|
||||
packet[8] = packet[3];
|
||||
for(uint8_t i=4; i<8; i++)
|
||||
packet[8] += packet[i];
|
||||
//packet[8] = packet[3];
|
||||
//for(uint8_t i=4; i<8; i++)
|
||||
// packet[8] += packet[i];
|
||||
packet_length=E015_BIND_PACKET_SIZE;
|
||||
}
|
||||
else
|
||||
@@ -154,24 +157,15 @@ static void __attribute__((unused)) E01X_send_packet()
|
||||
}
|
||||
}
|
||||
|
||||
HS6200_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num);
|
||||
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
|
||||
NRF24L01_FlushTx();
|
||||
|
||||
HS6200_WritePayload(packet, packet_length);
|
||||
|
||||
// Check and adjust transmission power. We do this after
|
||||
// transmission to not bother with timeout after power
|
||||
// settings change - we have plenty of time until next
|
||||
// packet.
|
||||
NRF24L01_SetPower();
|
||||
HS6200_RFChannel(rf_ch_num);
|
||||
HS6200_SetPower();
|
||||
delayMicroseconds(270); // Wait for RF channel to settle
|
||||
HS6200_SendPayload(packet, packet_length);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) E01X_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
HS6200_Init(true); // CRC enabled
|
||||
|
||||
if(sub_protocol==E012)
|
||||
HS6200_SetTXAddr((uint8_t *)"\x55\x42\x9C\x8F\xC9", E01X_ADDRESS_LENGTH);
|
||||
@@ -218,8 +212,21 @@ void E01X_init()
|
||||
}
|
||||
else //E015
|
||||
{
|
||||
#ifdef E015_FORCE_ID
|
||||
rx_tx_addr[0] = 0x06;
|
||||
rx_tx_addr[1] = 0xC6;
|
||||
rx_tx_addr[2] = 0xB7;
|
||||
rx_tx_addr[3] = 0x56;
|
||||
rx_tx_addr[4] = 0x8A;
|
||||
#endif
|
||||
|
||||
//force the sum to give 0x63 since the id calculation is unknown
|
||||
uint8_t sum=0x63;
|
||||
for(uint8_t i=0; i < 4; i++)
|
||||
sum -= rx_tx_addr[i];
|
||||
rx_tx_addr[4] = sum;
|
||||
|
||||
packet_period=E015_PACKET_PERIOD;
|
||||
rf_ch_num=E015_RF_CHANNEL;
|
||||
armed = 0;
|
||||
arm_flags = 0;
|
||||
arm_channel_previous = E01X_ARM_SW;
|
||||
@@ -18,15 +18,17 @@
|
||||
#include "iface_rf2500.h"
|
||||
|
||||
//#define E129_FORCE_ID
|
||||
//#define C186_FORCE_ID
|
||||
|
||||
#define E129_BIND_CH 0x2D //45
|
||||
#define E129_PAYLOAD_SIZE 16
|
||||
#define C186_PAYLOAD_SIZE 19
|
||||
|
||||
static void __attribute__((unused)) E129_build_data_packet()
|
||||
{
|
||||
//Build the packet
|
||||
memset(packet,0,E129_PAYLOAD_SIZE);
|
||||
packet[ 0] = 0x0F; // Packet length
|
||||
memset(packet,0,packet_length);
|
||||
packet[ 0] = packet_length - 1; // Packet length
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[ 1] = 0xA4;
|
||||
@@ -40,11 +42,21 @@ static void __attribute__((unused)) E129_build_data_packet()
|
||||
else
|
||||
{
|
||||
packet[ 1] = 0xA6;
|
||||
packet[ 2] = 0xF7; // High rate 0xF7, low rate 0xF4
|
||||
//packet[ 3] = 0x00; // Mode: short press=0x20->0x00->0x20->..., long press=0x10->0x30->0x10->...
|
||||
//Flags
|
||||
if(sub_protocol == E129_E129)
|
||||
packet[ 2] = 0xF7; // High rate 0xF7, low 0xF4
|
||||
else //C186
|
||||
{
|
||||
packet[ 2] = 0xFA; // High rate 0xFA, medium 0xF7, low 0xF4
|
||||
packet[13] = bit_reverse(rx_tx_addr[2]);
|
||||
packet[14] = bit_reverse(rx_tx_addr[3]);
|
||||
packet[15] = bit_reverse(rx_tx_addr[0]);
|
||||
packet[16] = bit_reverse(rx_tx_addr[1]);
|
||||
}
|
||||
//packet[ 3] = 0x00; // E129 Mode: short press=0x20->0x00->0x20->..., long press=0x10->0x30->0x10->... => C186 throttle trim is doing the same:up=short press and down=long press
|
||||
packet[ 4] = GET_FLAG(CH5_SW, 0x20) // Take off/Land 0x20
|
||||
| GET_FLAG(CH6_SW, 0x04); // Emergency stop 0x04
|
||||
|
||||
| GET_FLAG(CH6_SW, 0x04); // Emergency stop 0x04
|
||||
//Channels and trims
|
||||
uint16_t val = convert_channel_10b(AILERON,false);
|
||||
uint8_t trim = convert_channel_8b(CH7) & 0xFC;
|
||||
packet[ 5] = trim | (val >>8); // Trim (0x00..0x1F..0x3E) << 2 | channel >> 8
|
||||
@@ -67,10 +79,14 @@ static void __attribute__((unused)) E129_build_data_packet()
|
||||
packet[11] = trim | (val >>8); // Trim (0x00..0x1F..0x3E) << 2 | channel >> 8
|
||||
packet[12] = val; // channel (0x000...0x200...0x3FF)
|
||||
}
|
||||
packet[14] = 0x00; // Check
|
||||
for(uint8_t i=0;i<14;i++)
|
||||
packet[14] += packet[i];
|
||||
|
||||
//Check
|
||||
if(sub_protocol == E129_E129)
|
||||
packet[packet_length-2] = packet[0] + packet[1];
|
||||
else
|
||||
packet[packet_length-2] = 0x24 + packet[0] + (packet[1]&0x03); // ??
|
||||
for(uint8_t i=2;i<packet_length-2;i++)
|
||||
packet[packet_length-2] += packet[i];
|
||||
|
||||
RF2500_BuildPayload(packet);
|
||||
}
|
||||
|
||||
@@ -83,7 +99,7 @@ uint16_t E129_callback()
|
||||
//Send packet
|
||||
RF2500_SendPayload();
|
||||
|
||||
//Send twice on same channel
|
||||
//E129 sends twice on same channel, not the C186 but there is a bug somewhere if I don't send the packets back to back
|
||||
if(phase==0)
|
||||
{
|
||||
phase++;
|
||||
@@ -109,7 +125,9 @@ uint16_t E129_callback()
|
||||
hopping_frequency_no &= 3;
|
||||
|
||||
phase=0;
|
||||
return 5200-1260;
|
||||
if(sub_protocol==E129_E129)
|
||||
return 5200-1260;
|
||||
return 5500-1260; //E129_C186
|
||||
}
|
||||
|
||||
void E129_init()
|
||||
@@ -117,8 +135,9 @@ void E129_init()
|
||||
BIND_IN_PROGRESS; // Autobind protocol
|
||||
bind_counter = 384; // ~2sec
|
||||
|
||||
//RF2500 emu init
|
||||
RF2500_Init(E129_PAYLOAD_SIZE, true); // 16 bytes, Scrambled
|
||||
//RF2500 emu init
|
||||
packet_length = sub_protocol == E129_E129?E129_PAYLOAD_SIZE:C186_PAYLOAD_SIZE;
|
||||
RF2500_Init(packet_length, true); // 16/19 bytes, Scrambled
|
||||
|
||||
//Freq hopping
|
||||
calc_fh_channels(4);
|
||||
@@ -136,6 +155,16 @@ void E129_init()
|
||||
hopping_frequency[2]=0x4B; //75
|
||||
hopping_frequency[3]=0x41; //65
|
||||
#endif
|
||||
#ifdef C186_FORCE_ID
|
||||
rx_tx_addr[0]=0x91;
|
||||
rx_tx_addr[1]=0x02;
|
||||
rx_tx_addr[2]=0x5D;
|
||||
rx_tx_addr[3]=0x33;
|
||||
hopping_frequency[0]=0x44 + 2;
|
||||
hopping_frequency[1]=0x41 + 2;
|
||||
hopping_frequency[2]=0x43 + 2;
|
||||
hopping_frequency[3]=0x49 + 2;
|
||||
#endif
|
||||
|
||||
RF2500_SetTXAddr((uint8_t*)"\xE2\x32\xE0\xC8"); // 4 bytes of bind address
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Compatible with FEI XIONG P38 plane.
|
||||
|
||||
#if defined(FX816_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define FX816_INITIAL_WAIT 500
|
||||
#define FX816_PACKET_PERIOD 10000
|
||||
#define FX816_RF_BIND_CHANNEL 0x28 //40
|
||||
#define FX816_RF_NUM_CHANNELS 4
|
||||
#define FX816_PAYLOAD_SIZE 6
|
||||
#define FX816_BIND_COUNT 300 //3sec
|
||||
|
||||
static void __attribute__((unused)) FX816_send_packet()
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
packet[0] = 0x55;
|
||||
else
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
hopping_frequency_no%=FX816_RF_NUM_CHANNELS;
|
||||
packet[0] = 0xAA;
|
||||
}
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
uint8_t val=convert_channel_8b(AILERON);
|
||||
#define FX816_SWITCH 20
|
||||
if(val>127+FX816_SWITCH)
|
||||
packet[3] = 1;
|
||||
else if(val<127-FX816_SWITCH)
|
||||
packet[3] = 2;
|
||||
else
|
||||
packet[3] = 0;
|
||||
packet[4] = convert_channel_16b_limit(THROTTLE,0,100);
|
||||
val=0;
|
||||
for(uint8_t i=0;i<FX816_PAYLOAD_SIZE-1;i++)
|
||||
val+=packet[i];
|
||||
packet[5]=val;
|
||||
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, FX816_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX816_RF_init()
|
||||
{
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
|
||||
//XN297_HoppingCalib(FX816_RF_NUM_CHANNELS);
|
||||
XN297_RFChannel(FX816_RF_BIND_CHANNEL);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX816_initialize_txid()
|
||||
{
|
||||
//Only 8 IDs: the RX led does not indicate frame loss.
|
||||
//I didn't open the plane to find out if I could connect there so this is the best I came up with with few trial and errors...
|
||||
rx_tx_addr[0]=0x35+(rx_tx_addr[3]&0x07); //Original dump=0x35
|
||||
rx_tx_addr[1]=0x09; //Original dump=0x09
|
||||
memcpy(hopping_frequency,"\x09\x1B\x30\x42",FX816_RF_NUM_CHANNELS); //Original dump=9=0x09,27=0x1B,48=0x30,66=0x42
|
||||
for(uint8_t i=0;i<FX816_RF_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
|
||||
}
|
||||
|
||||
uint16_t FX816_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(FX816_PACKET_PERIOD);
|
||||
#endif
|
||||
if(bind_counter)
|
||||
if(--bind_counter==0)
|
||||
BIND_DONE;
|
||||
FX816_send_packet();
|
||||
return FX816_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
void FX816_init()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
FX816_initialize_txid();
|
||||
FX816_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter=FX816_BIND_COUNT;
|
||||
}
|
||||
|
||||
#endif
|
||||
177
Multiprotocol/FX_nrf24l01.ino
Normal file
177
Multiprotocol/FX_nrf24l01.ino
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Compatible with FEI XIONG P38 plane.
|
||||
|
||||
#if defined(FX_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297.h"
|
||||
|
||||
#define FX_BIND_COUNT 300 //3sec
|
||||
#define FX_SWITCH 20
|
||||
#define FX_NUM_CHANNELS 4
|
||||
|
||||
#define FX816_PACKET_PERIOD 10000
|
||||
#define FX816_BIND_CHANNEL 40
|
||||
#define FX816_PAYLOAD_SIZE 6
|
||||
#define FX816_CH_OFFSET 3
|
||||
|
||||
#define FX620_PACKET_PERIOD 3250
|
||||
#define FX620_BIND_PACKET_PERIOD 4500
|
||||
#define FX620_BIND_CHANNEL 18
|
||||
#define FX620_PAYLOAD_SIZE 7
|
||||
#define FX620_CH_OFFSET 1
|
||||
|
||||
//#define FORCE_FX620_ID
|
||||
|
||||
static void __attribute__((unused)) FX_send_packet()
|
||||
{
|
||||
//Hopp
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
hopping_frequency_no &= 0x03;
|
||||
}
|
||||
|
||||
memset(packet,0x00,packet_length);
|
||||
|
||||
//Channels
|
||||
uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET;
|
||||
uint8_t val=convert_channel_8b(AILERON);
|
||||
if(val>127+FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 1:0xFF;
|
||||
else if(val<127-FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 2:0x00;
|
||||
else
|
||||
packet[offset] = sub_protocol == FX816 ? 0:0x7F;
|
||||
packet[offset+1] = convert_channel_16b_limit(THROTTLE,0,100); //FX816:0x00..0x63, FX620:0x00..0x5E but that should work
|
||||
|
||||
//Bind and specifics
|
||||
if(sub_protocol == FX816)
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
packet[0] = 0x55;
|
||||
else
|
||||
packet[0] = 0xAA;
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
}
|
||||
else //FX620
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
memcpy(packet,rx_tx_addr,3);
|
||||
packet[3] = hopping_frequency[0];
|
||||
if(bind_counter > (FX_BIND_COUNT >> 1))
|
||||
packet[5] = 0x78;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0] = 0x1F; // Is it based on ID??
|
||||
packet[5] = 0xAB; // Is it based on ID??
|
||||
}
|
||||
}
|
||||
|
||||
//Check
|
||||
val=0;
|
||||
for(uint8_t i=0;i<packet_length-1;i++)
|
||||
val+=packet[i];
|
||||
packet[packet_length-1]=val;
|
||||
|
||||
//Debug
|
||||
#if 0
|
||||
for(uint8_t i=0;i<packet_length;i++)
|
||||
debug("%02X ",packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, packet_length);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX_RF_init()
|
||||
{
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
if(sub_protocol == FX816)
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
|
||||
XN297_RFChannel(FX816_BIND_CHANNEL);
|
||||
packet_period = FX816_PACKET_PERIOD;
|
||||
packet_length = FX816_PAYLOAD_SIZE;
|
||||
}
|
||||
else //FX620
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\xaa\xbb\xcc", 3);
|
||||
XN297_RFChannel(FX620_BIND_CHANNEL);
|
||||
packet_period = FX620_BIND_PACKET_PERIOD;
|
||||
packet_length = FX620_PAYLOAD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX_initialize_txid()
|
||||
{
|
||||
if(sub_protocol == FX816)
|
||||
{
|
||||
//Only 8 IDs: the RX led does not indicate frame loss.
|
||||
//I didn't open the plane to find out if I could connect there so this is the best I came up with with few trial and errors...
|
||||
rx_tx_addr[0]=0x35+(rx_tx_addr[3]&0x07); //Original dump=0x35
|
||||
rx_tx_addr[1]=0x09; //Original dump=0x09
|
||||
memcpy(hopping_frequency,"\x09\x1B\x30\x42",FX_NUM_CHANNELS); //Original dump=9=0x09,27=0x1B,48=0x30,66=0x42
|
||||
for(uint8_t i=0;i<FX_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
|
||||
}
|
||||
else//FX620
|
||||
{
|
||||
rx_tx_addr[0] = rx_tx_addr[3];
|
||||
hopping_frequency[0] = 0x18 + rx_tx_addr[3]&0x07; // just to try something
|
||||
#ifdef FORCE_FX620_ID
|
||||
memcpy(rx_tx_addr,(uint8_t*)"\x34\xA9\x32",3);
|
||||
hopping_frequency[0] = 0x18; //on dump: 24 34 44 54
|
||||
#endif
|
||||
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i] = i*10 + hopping_frequency[0];
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t FX_callback()
|
||||
{
|
||||
#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;
|
||||
}
|
||||
}
|
||||
FX_send_packet();
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
void FX_init()
|
||||
{
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
FX_initialize_txid();
|
||||
FX_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
bind_counter=FX_BIND_COUNT;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -169,66 +169,77 @@ static void __attribute__((unused)) HOTT_TXID_init()
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HOTT_prep_data_packet()
|
||||
{
|
||||
static uint8_t upper=0;
|
||||
static void __attribute__((unused)) HOTT_prep_data_packet() {
|
||||
static uint8_t upper = 0; // toggles between sending channels 1..8,9..12 and 1..8,13..16
|
||||
|
||||
packet[2] = hopping_frequency_no; // send next frequency to be used
|
||||
packet[3] = upper; // indicate upper or lower channels (only supporting 16 channels)
|
||||
|
||||
packet[2] = hopping_frequency_no;
|
||||
|
||||
packet[3] = upper; // used for failsafe and upper channels (only supporting 16 channels)
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
static uint8_t failsafe_count=0;
|
||||
if(IS_FAILSAFE_VALUES_on && IS_BIND_DONE)
|
||||
{
|
||||
failsafe_count++;
|
||||
if(failsafe_count>=3)
|
||||
{
|
||||
FAILSAFE_VALUES_off;
|
||||
failsafe_count=0;
|
||||
static uint8_t failsafe_count = 0; // failsafe packet state machine (need to send two packets)
|
||||
|
||||
if(IS_FAILSAFE_VALUES_on && IS_BIND_DONE) { // if TX wants to send failsafe data and RX is connected
|
||||
failsafe_count++; // prepare to send next packet
|
||||
|
||||
if(failsafe_count >= 3) { // done sending two failsafe channel data packets
|
||||
FAILSAFE_VALUES_off;
|
||||
failsafe_count = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
failsafe_count=0;
|
||||
failsafe_count = 0;
|
||||
#endif
|
||||
|
||||
// Channels value are PPM*2, -100%=1100µs, +100%=1900µs, order TAER
|
||||
//
|
||||
// Note: failsafe packets are differnt to normal operation packets
|
||||
// normal operation toggles between sending channels 1..8,9..12 and 1..8,13..16 using bit0 as high/low indicator in packet[3]
|
||||
// while failsafe packets send channels 1..12, 13..24 (and probably 25..32) using bit0 in packet[3] as packet type indicator
|
||||
// packet[3] = 0x40 -> failsafe packet with data for channels 1..12
|
||||
// packet[3] = 0x41 -> failsafe packet with data for channels 13..24
|
||||
//
|
||||
uint16_t val;
|
||||
for(uint8_t i=4;i<28;i+=2)
|
||||
{
|
||||
uint8_t ch=(i-4)>>1;
|
||||
if(upper && ch >= 8)
|
||||
ch+=4; // when upper swap CH9..CH12 by CH13..16
|
||||
val=Channel_data[ch];
|
||||
val=(((val<<2)+val)>>2)+860*2; // value range 860<->2140 *2 <-> -125%<->+125%
|
||||
for(uint8_t i = 0 ; i < 12*2 ; i += 2) { // working 12 channels (using 2 bytes per channel)
|
||||
uint8_t chIndex = i >> 1 ; // normal operation channel number
|
||||
uint8_t fschIndex = chIndex; // linear channel number for failsafe
|
||||
|
||||
if(upper && chIndex >= 8) chIndex += 4; // for normal operation toggle between channels 1..8,9..12 and 1..8,13..16
|
||||
val = Channel_data[chIndex]; // get normal operation channel data
|
||||
val = (((val << 2) + val) >> 2)+ 860*2; // convert channel data 0..2047 to 1720..4278 <-> -125%<->+125%
|
||||
// val = (val*5/4+860*2)
|
||||
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(failsafe_count==1)
|
||||
{ // first failsafe packet
|
||||
packet[3] |= 0x40;
|
||||
uint16_t fs=Failsafe_data[ch];
|
||||
if( fs == FAILSAFE_CHANNEL_HOLD || fs == FAILSAFE_CHANNEL_NOPULSES)
|
||||
val|=0x8000; // channel hold flag
|
||||
else
|
||||
{
|
||||
val=(((fs<<2)+fs)>>2)+860*2; // value range 860<->2140 *2 <-> -125%<->+125%
|
||||
val|=0x4000; // channel specific position flag
|
||||
if(failsafe_count == 1 || failsafe_count == 2) {// failsafe data needs to be sent to RX
|
||||
uint16_t fs = 0x8000; // default failsafe mode is hold
|
||||
|
||||
if(failsafe_count == 1) { // send fail safe packet containing channels 1..12
|
||||
packet[3] = 0x40; // indicate packet has failsafe values for channels 1..12
|
||||
fs = Failsafe_data[fschIndex]; // get failsafe channel data
|
||||
} else { // send fail safe packet containing channels 13..24
|
||||
packet[3] = 0x41; // indicate packet has failsafe values for channels 13..24
|
||||
if(fschIndex < 4) // we only work 16 channels so send channels 13..16, rest default
|
||||
fs = Failsafe_data[fschIndex+12]; // get failsafe channel data 13..16
|
||||
}
|
||||
|
||||
if( fs == FAILSAFE_CHANNEL_HOLD || // treat HOLD and NOPULSES as channel hold
|
||||
fs == FAILSAFE_CHANNEL_NOPULSES)
|
||||
val = 0x8000; // set channel failsafe mode hold flag
|
||||
else {
|
||||
val = (((fs << 2) + fs) >> 2) +860*2; // convert channel data 0..2047 to 1720..4278 <-> -125%<->+125%
|
||||
val |= 0x4000; // set channel failsafe mode position flag
|
||||
}
|
||||
}
|
||||
else if(failsafe_count==2)
|
||||
{ // second failsafe packet=timing?
|
||||
packet[3] |= 0x50;
|
||||
if(i==4)
|
||||
val=2;
|
||||
else
|
||||
val=0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
packet[i] = val;
|
||||
packet[i+1] = val>>8;
|
||||
|
||||
packet[i + 4] = val; // first channel data at packet[4] and packet[5]
|
||||
packet[i + 4+1] = val >> 8;
|
||||
}
|
||||
upper ^= 0x01; // toggle between CH9..CH12 and CH13..16
|
||||
|
||||
packet[28] = 0x80; // no sensor
|
||||
packet[29] = 0x02; // 0x02 when bind starts then when RX replies cycle in sequence 0x1A/22/2A/0A/12, 0x02 during normal packets, 0x01->text config menu, 0x0A->no more RX telemetry
|
||||
|
||||
upper ^= 0x01; // toggle to upper and lower channels
|
||||
|
||||
packet[28] = 0x80; // no sensor
|
||||
packet[29] = 0x02; // 0x02 when bind starts then when RX replies cycle in sequence 0x1A/22/2A/0A/12, 0x02 during normal packets, 0x01->text config menu, 0x0A->no more RX telemetry
|
||||
|
||||
#ifdef HOTT_FW_TELEMETRY
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
@@ -390,7 +401,7 @@ uint16_t HOTT_callback()
|
||||
{ //Telemetry
|
||||
// [0..4] = TXID
|
||||
// [5..9] = RXID
|
||||
// [10] = 0x40 bind, 0x00 normal, 0x80 config menu
|
||||
// [10] = holds warnings issued by hott devices
|
||||
// [11] = telmetry pages. For sensors 0x00 to 0x04, for config mennu 0x00 to 0x12.
|
||||
// Normal telem page 0 = 0x55, 0x32, 0x38, 0x55, 0x64, 0x32, 0xD0, 0x07, 0x00, 0x55
|
||||
// Page 0 [12] = [21] = [15]
|
||||
@@ -400,7 +411,7 @@ uint16_t HOTT_callback()
|
||||
// Page 0 [16] = RX_LQI in %
|
||||
// Page 0 [17] = RX_Voltage Min*10 in V
|
||||
// Page 0 [18,19] = [19]<<8+[18]=max lost packet time in ms, max value seems 2s=0x7D0
|
||||
// Page 0 [20] = 0x00 ??
|
||||
// Page 0 [20] = rx events
|
||||
//
|
||||
// Config menu consists of the different telem pages put all together
|
||||
// Page X [12] = seems like all the telem pages with the same value are going together to make the full config menu text. Seen so far 'a', 'b', 'c', 'd'
|
||||
@@ -412,6 +423,7 @@ uint16_t HOTT_callback()
|
||||
// Reduce telemetry to 14 bytes
|
||||
packet_in[0]= packet_in[HOTT_RX_PACKET_LEN];
|
||||
packet_in[1]= TX_LQI;
|
||||
uint8_t hott_warnings = packet_in[10]; // save warnings from hott devices
|
||||
bool send_telem=true;
|
||||
HOTT_sensor_seq++; // Increment RX sequence counter
|
||||
if(packet[29] & 1)
|
||||
@@ -464,6 +476,7 @@ uint16_t HOTT_callback()
|
||||
packet_in[i-8]=packet_in[i];
|
||||
debug(" %02X",packet_in[i]);
|
||||
}
|
||||
packet_in[14] = hott_warnings; // restore saved warnings from hott devices
|
||||
debugln("");
|
||||
if(send_telem)
|
||||
telemetry_link=2;
|
||||
|
||||
112
Multiprotocol/HS6200_EMU.ino
Normal file
112
Multiprotocol/HS6200_EMU.ino
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef CYRF6936_INSTALLED
|
||||
#include "iface_hs6200.h"
|
||||
|
||||
static bool HS6200_crc;
|
||||
static uint16_t HS6200_crc_init;
|
||||
static uint8_t HS6200_address_length, HS6200_tx_addr[5];
|
||||
|
||||
static void __attribute__((unused)) HS6200_Init(bool crc_en)
|
||||
{
|
||||
CYRF_GFSK1M_Init(32, 1); //Dummy number of bytes for now
|
||||
HS6200_crc = crc_en;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HS6200_SetTXAddr(const uint8_t* addr, uint8_t addr_len)
|
||||
{
|
||||
// precompute address crc
|
||||
crc = 0xffff;
|
||||
for(uint8_t i=0; i<addr_len; i++)
|
||||
crc16_update(addr[addr_len-1-i], 8);
|
||||
HS6200_crc_init=crc;
|
||||
memcpy(HS6200_tx_addr, addr, addr_len);
|
||||
HS6200_address_length = addr_len;
|
||||
}
|
||||
|
||||
static uint16_t __attribute__((unused)) HS6200_calc_crc(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
uint8_t pos;
|
||||
|
||||
crc = HS6200_crc_init;
|
||||
// pcf + payload
|
||||
for(pos=0; pos < len-1; pos++)
|
||||
crc16_update(msg[pos], 8);
|
||||
// last byte (1 bit only)
|
||||
if(len > 0)
|
||||
crc16_update(msg[pos+1], 1);
|
||||
return crc;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) HS6200_SendPayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
static const uint8_t HS6200_scramble[] = { 0x80,0xf5,0x3b,0x0d,0x6d,0x2a,0xf9,0xbc,0x51,0x8e,0x4c,0xfd,0xc1,0x65,0xd0 }; // todo: find all 32 bytes ...
|
||||
uint8_t payload[32];
|
||||
const uint8_t no_ack = 1; // never ask for an ack
|
||||
static uint8_t pid;
|
||||
uint8_t pos = 0;
|
||||
|
||||
if(len > sizeof(HS6200_scramble))
|
||||
len = sizeof(HS6200_scramble);
|
||||
|
||||
// address
|
||||
for(int8_t i=HS6200_address_length-1; i>=0; i--)
|
||||
payload[pos++] = HS6200_tx_addr[i];
|
||||
|
||||
// guard bytes
|
||||
payload[pos++] = HS6200_tx_addr[0];
|
||||
payload[pos++] = HS6200_tx_addr[0];
|
||||
|
||||
// packet control field
|
||||
payload[pos++] = ((len & 0x3f) << 2) | (pid & 0x03);
|
||||
payload[pos] = (no_ack & 0x01) << 7;
|
||||
pid++;
|
||||
|
||||
// scrambled payload
|
||||
if(len > 0)
|
||||
{
|
||||
payload[pos++] |= (msg[0] ^ HS6200_scramble[0]) >> 1;
|
||||
for(uint8_t i=1; i<len; i++)
|
||||
payload[pos++] = ((msg[i-1] ^ HS6200_scramble[i-1]) << 7) | ((msg[i] ^ HS6200_scramble[i]) >> 1);
|
||||
payload[pos] = (msg[len-1] ^ HS6200_scramble[len-1]) << 7;
|
||||
}
|
||||
|
||||
// crc
|
||||
if(HS6200_crc)
|
||||
{
|
||||
uint16_t crc = HS6200_calc_crc(&payload[HS6200_address_length+2], len+2);
|
||||
uint8_t hcrc = crc >> 8;
|
||||
uint8_t lcrc = crc & 0xff;
|
||||
payload[pos++] |= (hcrc >> 1);
|
||||
payload[pos++] = (hcrc << 7) | (lcrc >> 1);
|
||||
payload[pos++] = lcrc << 7;
|
||||
}
|
||||
|
||||
#if 0
|
||||
debug("E:");
|
||||
for(uint8_t i=0; i<pos; i++)
|
||||
debug(" %02X",payload[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
|
||||
//CYRF wants LSB first
|
||||
for(uint8_t i=0; i<pos; i++)
|
||||
payload[i]=bit_reverse(payload[i]);
|
||||
//Send
|
||||
CYRF_WriteRegister(CYRF_01_TX_LENGTH, pos);
|
||||
CYRF_GFSK1M_SendPayload(payload, pos);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -19,6 +19,7 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
#include "iface_xn297.h"
|
||||
|
||||
//#define FORCE_KF606_ORIGINAL_ID
|
||||
//#define FORCE_MIG320_ORIGINAL_ID
|
||||
|
||||
#define KF606_INITIAL_WAIT 500
|
||||
#define KF606_PACKET_PERIOD 3000
|
||||
@@ -35,25 +36,49 @@ static void __attribute__((unused)) KF606_send_packet()
|
||||
memcpy(&packet[1],rx_tx_addr,3);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[0]= 0x55;
|
||||
packet[1]= convert_channel_8b(THROTTLE); // 0..255
|
||||
// Deadband is needed on aileron, 40 gives +-6%
|
||||
packet[2]=convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, Low rates:50..80..AF, High rates:3E..80..C1
|
||||
// Aileron trim must be on a separated channel C1..D0..DF
|
||||
packet[3]= convert_channel_16b_limit(CH5,0xC1,0xDF);
|
||||
}
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no);
|
||||
hopping_frequency_no ^= 1; // 2 RF channels
|
||||
|
||||
packet[0] = 0x55;
|
||||
packet[1] = convert_channel_8b(THROTTLE); // 0..255
|
||||
// Deadband is needed on aileron, 40 gives +-6%
|
||||
if(sub_protocol == KF606_KF606)
|
||||
{
|
||||
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
|
||||
packet[3] = convert_channel_16b_limit(CH5,0xC1,0xDF); // Aileron trim must be on a separated channel C1..D0..DF
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[2] = convert_channel_8b_limit_deadband(AILERON,0x00,0x80,0xFF,40); // Aileron: High rate:2B..80..DA
|
||||
packet[3] = convert_channel_16b_limit(CH5,0x01,0x1F); // Aileron trim must be on a separated channel 01..10..1F
|
||||
packet[3] += (packet[2]-0x80)>>3; // Drive trims for more aileron authority
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t len = KF606_PAYLOAD_SIZE;
|
||||
if(sub_protocol == KF606_MIG320)
|
||||
{
|
||||
len++;
|
||||
packet[4] = 0; // additional channel?
|
||||
}
|
||||
|
||||
#if 0
|
||||
for(uint8_t i=0; i<len; i++)
|
||||
debug("%02X ",packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetFreqOffset();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, KF606_PAYLOAD_SIZE);
|
||||
XN297_WritePayload(packet, len);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) KF606_initialize_txid()
|
||||
@@ -67,13 +92,20 @@ static void __attribute__((unused)) KF606_initialize_txid()
|
||||
rx_tx_addr[1]=0x02;
|
||||
rx_tx_addr[2]=0x00;
|
||||
hopping_frequency[0]=0x20;
|
||||
hopping_frequency[0]=0x23;
|
||||
hopping_frequency[1]=0x23;
|
||||
//TX2
|
||||
rx_tx_addr[0]=0x25;
|
||||
rx_tx_addr[1]=0x04;
|
||||
rx_tx_addr[2]=0x00;
|
||||
hopping_frequency[0]=0x2E;
|
||||
hopping_frequency[0]=0x31;
|
||||
hopping_frequency[1]=0x31;
|
||||
#endif
|
||||
#ifdef FORCE_MIG320_ORIGINAL_ID
|
||||
rx_tx_addr[0]=0xBB;
|
||||
rx_tx_addr[1]=0x13;
|
||||
rx_tx_addr[2]=0x00;
|
||||
hopping_frequency[0]=68;
|
||||
hopping_frequency[1]=71;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -110,3 +142,14 @@ void KF606_init()
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// MIG320 protocol
|
||||
// Bind
|
||||
// 250K C=7 S=Y A= E7 E7 E7 E7 E7 P(5)= AA BB 13 00 00
|
||||
// 3ms on ch7
|
||||
// Normal
|
||||
// 250K C=68 S=Y A= BB 13 00 P(5)= 55 00 80 10 00
|
||||
// P[1] = THR 00..FF
|
||||
// P[2] = AIL 2B..80..DA
|
||||
// P[3] = TRIM 01..10..1F
|
||||
// channels 68=BB&3F+9 and 71
|
||||
|
||||
141
Multiprotocol/Kyosho2_nrf24l01.ino
Normal file
141
Multiprotocol/Kyosho2_nrf24l01.ino
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
This project is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Multiprotocol is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(KYOSHO2_NRF24L01_INO)
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define KYOSHO2_PACKET_PERIOD 1120
|
||||
#define KYOSHO2_BIND_PACKET_PERIOD 1600
|
||||
#define KYOSHO2_BIND_COUNT 6000 // about 9sec
|
||||
#define KYOSHO2_BIND_CHANNEL 0x50
|
||||
#define KYOSHO2_PAYLOAD_SIZE 28
|
||||
#define KYOSHO2_RF_CHANNELS 15
|
||||
#define KYOSHO2_START_RF_CHANNEL 0x13 // No idea where it comes from... ID or unknown bytes during the bind?
|
||||
#define KYOSHO2_NUM_CHANNEL 10 // Only 4 on the dumps but there is space for 10 channels in the payload...
|
||||
|
||||
#define FORCE_KYOSHO2_ID
|
||||
|
||||
bool KYOSHO2_resend;
|
||||
//
|
||||
static void __attribute__((unused)) KYOSHO2_send_packet()
|
||||
{
|
||||
if(KYOSHO2_resend == true)
|
||||
{
|
||||
NRF24L01_Strobe(NRF24L01_E3_REUSE_TX_PL);
|
||||
if(IS_BIND_DONE)
|
||||
KYOSHO2_resend = false;
|
||||
return;
|
||||
}
|
||||
|
||||
memset(packet,0x00,KYOSHO2_PAYLOAD_SIZE);
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
memcpy(packet, (uint8_t*)"\x01\x02\x05\x08\x1A\x2B\x3C\x4D", 8); // unknown bytes, parameters on how to build the rf channels?
|
||||
memcpy(&packet[8], rx_tx_addr, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(packet, rx_tx_addr, 4);
|
||||
//Hopp
|
||||
packet[6] = hopping_frequency_no + KYOSHO2_START_RF_CHANNEL;
|
||||
packet[7] = hopping_frequency[hopping_frequency_no];
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, packet[6+(rf_ch_num&0x01)]);
|
||||
rf_ch_num++;
|
||||
//Channels
|
||||
uint16_t temp;
|
||||
for (uint8_t i = 0; i< KYOSHO2_NUM_CHANNEL; i++)
|
||||
{
|
||||
temp=convert_channel_16b_limit(i,0,0x3FF);
|
||||
packet[8+i*2] = temp >> 8;
|
||||
packet[9+i*2] = temp;
|
||||
}
|
||||
}
|
||||
//Send
|
||||
NRF24L01_WriteReg(NRF24L01_07_STATUS, (_BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT))); // Reset flags
|
||||
NRF24L01_FlushTx();
|
||||
NRF24L01_WritePayload(packet,KYOSHO2_PAYLOAD_SIZE);
|
||||
NRF24L01_SetPower();
|
||||
KYOSHO2_resend = true;
|
||||
|
||||
#if 0
|
||||
for(uint8_t i=0;i<KYOSHO2_PAYLOAD_SIZE;i++)
|
||||
debug("%02X ", packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) KYOSHO2_RF_init()
|
||||
{
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, KYOSHO2_BIND_CHANNEL);
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\x69\x53\x10\xAC\xEF", 5);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) KYOSHO2_initialize_tx_id()
|
||||
{
|
||||
hopping_frequency_no = rx_tx_addr[3]%KYOSHO2_RF_CHANNELS;
|
||||
hopping_frequency[0] = 0x4A;
|
||||
#ifdef FORCE_KYOSHO2_ID
|
||||
memcpy(rx_tx_addr, (uint8_t*)"\x0A\xBD\x31\xDF", 4);
|
||||
hopping_frequency[0] = 0x4A; // No idea where it comes from... ID or unknown bytes during the bind?
|
||||
#endif
|
||||
for(uint8_t i=1;i<KYOSHO2_RF_CHANNELS;i++)
|
||||
{
|
||||
if(hopping_frequency[i-1]+5 < 0x50)
|
||||
hopping_frequency[i] = hopping_frequency[i-1]+5;
|
||||
else
|
||||
hopping_frequency[i] = hopping_frequency[i-1]-0x21;
|
||||
}
|
||||
#if 0
|
||||
for(uint8_t i=0;i<KYOSHO2_RF_CHANNELS;i++)
|
||||
debugln("1:%02X, 2: %02X", i + KYOSHO2_START_RF_CHANNEL, hopping_frequency[i]);
|
||||
debugln("Selected 1:%02X, 2: %02X", hopping_frequency_no + KYOSHO2_START_RF_CHANNEL, hopping_frequency[hopping_frequency_no]);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t KYOSHO2_callback()
|
||||
{
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(KYOSHO2_PACKET_PERIOD);
|
||||
#endif
|
||||
KYOSHO2_send_packet();
|
||||
if(bind_counter)
|
||||
{
|
||||
if(--bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
KYOSHO2_resend = false;
|
||||
}
|
||||
return KYOSHO2_BIND_PACKET_PERIOD;
|
||||
}
|
||||
return KYOSHO2_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
void KYOSHO2_init()
|
||||
{
|
||||
KYOSHO2_initialize_tx_id();
|
||||
KYOSHO2_RF_init();
|
||||
rf_ch_num = 0;
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
bind_counter = KYOSHO2_BIND_COUNT;
|
||||
else
|
||||
bind_counter = 0;
|
||||
KYOSHO2_resend = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -26,11 +26,16 @@
|
||||
#define MT99XX_PACKET_PERIOD_A180 3400 // timing changes between the packets 2 x 27220 then 1x 26080, it seems that it is only on the first RF channel which jitters by 1.14ms but hard to pinpoint with XN297dump
|
||||
#define MT99XX_PACKET_PERIOD_DRAGON 1038 // there is a pause of 2x1038 between two packets, no idea why and how since it is not even stable on a same dump...
|
||||
#define MT99XX_PACKET_PERIOD_DRAGON_TELEM 10265 // long pause to receive the telemetry packets, 3 are sent by the RX one after the other
|
||||
#define MT99XX_PACKET_PERIOD_F949G 3450
|
||||
#define MT99XX_PACKET_PERIOD_PA18 1338
|
||||
#define MT99XX_INITIAL_WAIT 500
|
||||
#define MT99XX_PACKET_SIZE 9
|
||||
|
||||
//#define FORCE_A180_ID
|
||||
//#define FORCE_DRAGON_ID
|
||||
//#define FORCE_F949G_ID
|
||||
#define FORCE_PA18_ID1
|
||||
//#define FORCE_PA18_ID2
|
||||
|
||||
enum {
|
||||
MT99XX_DATA,
|
||||
@@ -75,6 +80,17 @@ enum{
|
||||
FLAG_DRAGON_UNK = 0x04,
|
||||
};
|
||||
|
||||
enum{
|
||||
// flags going to packet[6] (F949G)
|
||||
FLAG_F949G_LIGHT = 0x01,
|
||||
FLAG_F949G_3D6G = 0x20,
|
||||
};
|
||||
enum{
|
||||
// flags going to packet[6] (PA18)
|
||||
FLAG_PA18_RTH = 0x08,
|
||||
FLAG_PA18_FLIP = 0x80,
|
||||
};
|
||||
|
||||
const uint8_t h7_mys_byte[] = {
|
||||
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
|
||||
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
|
||||
@@ -97,6 +113,15 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
{
|
||||
static uint8_t seq_num=0;
|
||||
|
||||
//Set RF freq
|
||||
if(sub_protocol == LS)
|
||||
XN297_RFChannel(0x2D); // LS always transmits on the same channel
|
||||
else
|
||||
if(sub_protocol==FY805)
|
||||
XN297_RFChannel(0x4B); // FY805 always transmits on the same channel
|
||||
else // MT99 & H7 & YZ & A180 & DRAGON & F949G & PA18
|
||||
XN297_Hopping(hopping_frequency_no);
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
//Bind packet
|
||||
@@ -104,7 +129,6 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case YZ:
|
||||
packet_period = MT99XX_PACKET_PERIOD_YZ;
|
||||
packet[1] = 0x15;
|
||||
packet[2] = 0x05;
|
||||
packet[3] = 0x06;
|
||||
@@ -115,14 +139,11 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
packet[3] = 0x11;
|
||||
break;
|
||||
case FY805:
|
||||
packet_period = MT99XX_PACKET_PERIOD_FY805;
|
||||
packet[1] = 0x15;
|
||||
packet[2] = 0x12;
|
||||
packet[3] = 0x17;
|
||||
break;
|
||||
case A180:
|
||||
packet_period = MT99XX_PACKET_PERIOD_A180;
|
||||
default: // MT99 & H7 & A180 & DRAGON
|
||||
default: // MT99 & H7 & A180 & DRAGON & F949G & PA18
|
||||
packet[1] = 0x14;
|
||||
packet[2] = 0x03;
|
||||
packet[3] = 0x25;
|
||||
@@ -131,13 +152,24 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
packet[4] = rx_tx_addr[0];
|
||||
packet[5] = rx_tx_addr[1];
|
||||
packet[6] = rx_tx_addr[2];
|
||||
packet[7] = crc8; // checksum offset
|
||||
packet[8] = 0xAA; // fixed
|
||||
if(sub_protocol == PA18+8)
|
||||
{
|
||||
packet[7] = num_ch; // checksum offset
|
||||
packet[8] = 0x55; // fixed
|
||||
}
|
||||
else
|
||||
{ // all others
|
||||
packet[7] = crc8; // checksum offset
|
||||
if(sub_protocol != F949G)
|
||||
packet[8] = 0xAA; // fixed
|
||||
else
|
||||
packet[8] = 0x00;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sub_protocol != YZ)
|
||||
{ // MT99XX & H7 & LS & FY805 & A180 & DRAGON
|
||||
{ // MT99XX & H7 & LS & FY805 & A180 & DRAGON & F949G & PA18
|
||||
packet[0] = convert_channel_16b_limit(THROTTLE,0xE1,0x00); // throttle
|
||||
packet[1] = convert_channel_16b_limit(RUDDER ,0x00,0xE1); // rudder
|
||||
packet[2] = convert_channel_16b_limit(AILERON ,0xE1,0x00); // aileron
|
||||
@@ -145,8 +177,10 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00)
|
||||
packet[5] = 0x20; // roll trim (0x00-0x20-0x3f)
|
||||
packet[6] = GET_FLAG( CH5_SW, FLAG_MT_FLIP );
|
||||
packet[7] = h7_mys_byte[hopping_frequency_no]; // next rf channel index ?
|
||||
|
||||
if(sub_protocol != PA18+8)
|
||||
packet[7] = h7_mys_byte[hopping_frequency_no]; // next rf channel index ?
|
||||
else
|
||||
packet[7] = (packet[7]&0xBF)|0x20;
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case MT99:
|
||||
@@ -177,15 +211,16 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
crc8=0;
|
||||
break;
|
||||
case A180:
|
||||
packet[6] = FLAG_A180_RATE
|
||||
| GET_FLAG( CH5_SW, FLAG_A180_3D6G );
|
||||
packet[6] = GET_FLAG( !CH6_SW,FLAG_A180_RATE) // 0x02, A180=RATE, F949S=LED
|
||||
|GET_FLAG( CH5_SW, FLAG_A180_3D6G ) // 0x01, A180=3D_6G, F949S=RATE
|
||||
|GET_FLAG( CH7_SW, 0x20 ); // 0x20, F949S=3D_6G
|
||||
packet[7] = 0x00;
|
||||
break;
|
||||
case DRAGON:
|
||||
if(CH5_SW) // Advanced mode
|
||||
if(CH5_SW) // Advanced mode
|
||||
packet[5] |= 0x80;
|
||||
else
|
||||
if(Channel_data[CH5] > CHANNEL_MIN_COMMAND) // Beginner mode
|
||||
if(Channel_data[CH5] > CHANNEL_MIN_COMMAND) // Beginner mode
|
||||
packet[5] |= 0x40;
|
||||
packet[6] = FLAG_DRAGON_RATE
|
||||
| GET_FLAG( CH6_SW, FLAG_DRAGON_RTH );
|
||||
@@ -200,30 +235,49 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
if(packet_count > 11)
|
||||
packet_count = 0;
|
||||
}
|
||||
if(packet_count > 10) // Telemetry packet request every 10 or 11 packets
|
||||
if(packet_count > 10) // Telemetry packet request every 10 or 11 packets
|
||||
{
|
||||
packet[6] |= 0x04; // Request telemetry flag
|
||||
packet[6] |= 0x04; // Request telemetry flag
|
||||
phase = MT99XX_RX;
|
||||
}
|
||||
packet[7] = DRAGON_seq[seq_num]; // seq: 20 80 20 60 20 80 20 60... 80 changes to 80+batt from telem
|
||||
packet[7] = DRAGON_seq[seq_num]; // seq: 20 80 20 60 20 80 20 60... 80 changes to 80+batt from telem
|
||||
if(seq_num==3)
|
||||
packet[7] |= v_lipo1;
|
||||
#else
|
||||
packet[7] = 0x20;
|
||||
#endif
|
||||
break;
|
||||
case F949G:
|
||||
packet[6] = 0x02
|
||||
| GET_FLAG( CH5_SW, FLAG_F949G_3D6G )
|
||||
| GET_FLAG( CH6_SW, FLAG_F949G_LIGHT );
|
||||
packet[7] = 0x00;
|
||||
break;
|
||||
case PA18+8:
|
||||
if(Channel_data[CH5] > CHANNEL_MAX_COMMAND) // Expert mode
|
||||
packet[5] = 0xA0;
|
||||
else
|
||||
if(Channel_data[CH5] > CHANNEL_MIN_COMMAND) // Intermediate mode
|
||||
packet[5] = 0x60;
|
||||
packet[6] = GET_FLAG( CH6_SW, FLAG_PA18_FLIP ) // Flip
|
||||
| GET_FLAG( CH7_SW, FLAG_PA18_RTH ); // RTH
|
||||
if(hopping_frequency_no == 0)
|
||||
packet[7] ^= 0x40;
|
||||
break;
|
||||
}
|
||||
uint8_t result=crc8;
|
||||
for(uint8_t i=0; i<8; i++)
|
||||
result += packet[i];
|
||||
if(sub_protocol == PA18+8)
|
||||
result += num_ch;
|
||||
packet[8] = result;
|
||||
}
|
||||
else
|
||||
{ // YZ
|
||||
packet[0] = convert_channel_16b_limit(THROTTLE,0x00,0x64); // throttle
|
||||
packet[1] = convert_channel_16b_limit(RUDDER ,0x64,0x00); // rudder
|
||||
packet[2] = convert_channel_16b_limit(ELEVATOR,0x00,0x64); // elevator
|
||||
packet[3] = convert_channel_16b_limit(AILERON ,0x64,0x00); // aileron
|
||||
packet[0] = convert_channel_16b_limit(THROTTLE,0x00,0x64); // throttle
|
||||
packet[1] = convert_channel_16b_limit(RUDDER ,0x64,0x00); // rudder
|
||||
packet[2] = convert_channel_16b_limit(ELEVATOR,0x00,0x64); // elevator
|
||||
packet[3] = convert_channel_16b_limit(AILERON ,0x64,0x00); // aileron
|
||||
if(packet_count++ >= 23)
|
||||
{
|
||||
seq_num ++;
|
||||
@@ -233,11 +287,11 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
}
|
||||
packet[4] = yz_p4_seq[seq_num];
|
||||
packet[5] = 0x02 // expert ? (0=unarmed, 1=normal)
|
||||
| GET_FLAG(CH8_SW, 0x10) //VIDEO
|
||||
| GET_FLAG(CH5_SW, 0x80) //FLIP
|
||||
| GET_FLAG(CH9_SW, 0x04) //HEADLESS
|
||||
| GET_FLAG(CH7_SW, 0x20); //SNAPSHOT
|
||||
packet[6] = GET_FLAG(CH6_SW, 0x80); //LED
|
||||
| GET_FLAG(CH8_SW, 0x10) //VIDEO
|
||||
| GET_FLAG(CH5_SW, 0x80) //FLIP
|
||||
| GET_FLAG(CH9_SW, 0x04) //HEADLESS
|
||||
| GET_FLAG(CH7_SW, 0x20); //SNAPSHOT
|
||||
packet[6] = GET_FLAG(CH6_SW, 0x80); //LED
|
||||
packet[7] = packet[0];
|
||||
for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++)
|
||||
packet[7] += packet[idx];
|
||||
@@ -245,17 +299,9 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
}
|
||||
}
|
||||
|
||||
//RF freq
|
||||
if(sub_protocol == LS)
|
||||
XN297_RFChannel(0x2D); // LS always transmits on the same channel
|
||||
else
|
||||
if(sub_protocol==FY805)
|
||||
XN297_RFChannel(0x4B); // FY805 always transmits on the same channel
|
||||
else // MT99 & H7 & YZ & A180 & DRAGON
|
||||
XN297_Hopping(hopping_frequency_no);
|
||||
|
||||
//Hopp
|
||||
hopping_frequency_no++;
|
||||
if(sub_protocol == YZ || sub_protocol == A180 || sub_protocol == DRAGON )
|
||||
if(sub_protocol == YZ || sub_protocol == A180 || sub_protocol == DRAGON || sub_protocol == F949G || sub_protocol == PA18+8)
|
||||
hopping_frequency_no++; // skip every other channel
|
||||
if(hopping_frequency_no > 15)
|
||||
hopping_frequency_no = 0;
|
||||
@@ -265,12 +311,20 @@ static void __attribute__((unused)) MT99XX_send_packet()
|
||||
XN297_SetFreqOffset();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WritePayload(packet, MT99XX_PACKET_SIZE);
|
||||
|
||||
#if 0
|
||||
for(uint8_t i=0; i<MT99XX_PACKET_SIZE; i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) MT99XX_RF_init()
|
||||
{
|
||||
if(sub_protocol == YZ)
|
||||
XN297_Configure(XN297_CRCEN, XN297_UNSCRAMBLED, XN297_250K);
|
||||
else if(sub_protocol == F949G)
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_250K);
|
||||
else
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5);
|
||||
@@ -283,9 +337,9 @@ static void __attribute__((unused)) MT99XX_RF_init()
|
||||
|
||||
static void __attribute__((unused)) MT99XX_initialize_txid()
|
||||
{
|
||||
rx_tx_addr[1] = rx_tx_addr[3]; // RX_Num
|
||||
|
||||
switch(protocol)
|
||||
num_ch = rx_tx_addr[1]; // PA18
|
||||
rx_tx_addr[1] = rx_tx_addr[3]; // RX_Num
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case YZ:
|
||||
rx_tx_addr[0] = 0x53; // test (SB id)
|
||||
@@ -318,8 +372,44 @@ static void __attribute__((unused)) MT99XX_initialize_txid()
|
||||
//channel_offset = 0x06
|
||||
break;
|
||||
#endif
|
||||
default: //MT99 & H7 & A180 & DRAGON
|
||||
#ifdef FORCE_F949G_ID
|
||||
case F949G:
|
||||
rx_tx_addr[0] = 0x7E; // LilTeo14 ID
|
||||
rx_tx_addr[1] = 0x2F;
|
||||
rx_tx_addr[2] = 0x29;
|
||||
//crc8 = 0xD6
|
||||
//channel_offset = 0x03
|
||||
break;
|
||||
#endif
|
||||
#ifdef FORCE_PA18_ID1
|
||||
case PA18+8:
|
||||
rx_tx_addr[0] = 0xC9; // zebble ID
|
||||
rx_tx_addr[1] = 0x02;
|
||||
rx_tx_addr[2] = 0x13;
|
||||
num_ch = 0x89; // additional crc init. How is this calculated? or could it be random?
|
||||
//crc8 = 0xDE
|
||||
//channel_offset = 0x03
|
||||
//1Mb C=5 S=Y A= C9 02 13 CC CC P(9)= E1 70 70 70 20 20 00 20 1A -> 0x91 + 0x89 => 0x1A
|
||||
// S=Y A= C9 02 13 CC CC P(9)= E1 70 70 70 20 A0 00 20 9A -> 0x11 + 0x89 => 0x9A
|
||||
//bind S=Y A= CC CC CC CC CC P(9)= 20 14 03 25 C9 02 13 89 55
|
||||
break;
|
||||
#endif
|
||||
#ifdef FORCE_PA18_ID2
|
||||
case PA18+8:
|
||||
rx_tx_addr[0] = 0x0E;
|
||||
rx_tx_addr[1] = 0x05;
|
||||
rx_tx_addr[2] = 0x13;
|
||||
num_ch = 0xD1; // additional crc init. How is this calculated? or could it be random?
|
||||
//crc8 = 0x28
|
||||
//channel_offset = 0x00
|
||||
//1Mb C=2 S=Y A= 0E 05 13 CC CC P(9)= E1 70 70 70 20 60 00 60 E2 -> 0x11 + 0xD1 => 0xE2
|
||||
//bind S=Y A= CC CC CC CC CC P(9)= 20 14 03 25 0E 05 13 D1 55
|
||||
break;
|
||||
#endif
|
||||
default: //MT99 & H7 & A180 & DRAGON & F949G & PA18
|
||||
rx_tx_addr[2] = 0x00;
|
||||
if(sub_protocol == PA18+8)
|
||||
rx_tx_addr[2] = 0x13;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -409,14 +499,40 @@ uint16_t MT99XX_callback()
|
||||
|
||||
void MT99XX_init(void)
|
||||
{
|
||||
if(sub_protocol != A180 && sub_protocol != DRAGON)
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
if(protocol == PROTO_MT99XX2)
|
||||
sub_protocol|=0x08; // Increase the number of sub_protocols for MT99XX
|
||||
|
||||
bind_counter = MT99XX_BIND_COUNT;
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
if(sub_protocol != A180 && sub_protocol != DRAGON && sub_protocol != F949G && sub_protocol != PA18+8)
|
||||
BIND_IN_PROGRESS; // autobind protocol
|
||||
else
|
||||
bind_counter = 1;
|
||||
}
|
||||
|
||||
MT99XX_initialize_txid();
|
||||
MT99XX_RF_init();
|
||||
|
||||
packet_period = MT99XX_PACKET_PERIOD_MT;
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case YZ:
|
||||
packet_period = MT99XX_PACKET_PERIOD_YZ;
|
||||
break;
|
||||
case FY805:
|
||||
packet_period = MT99XX_PACKET_PERIOD_FY805;
|
||||
break;
|
||||
case F949G:
|
||||
case A180:
|
||||
packet_period = MT99XX_PACKET_PERIOD_A180;
|
||||
break;
|
||||
case PA18+8:
|
||||
packet_period = MT99XX_PACKET_PERIOD_PA18;
|
||||
break;
|
||||
default:
|
||||
packet_period = MT99XX_PACKET_PERIOD_MT;
|
||||
break;
|
||||
}
|
||||
|
||||
packet_count=0;
|
||||
phase=MT99XX_DATA;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE,DHD_D4,QX100
|
||||
15,FrskyX,CH_16,CH_8,EU_16,EU_8,Cloned,Clon_8
|
||||
16,ESky,Std,ET4
|
||||
17,MT99xx,MT,H7,YZ,LS,FY805,A180,Dragon
|
||||
17,MT99xx,MT,H7,YZ,LS,FY805,A180,Dragon,F949G
|
||||
18,MJXq,WLH08,X600,X800,H26D,E010,H26WH,PHOENIX
|
||||
19,Shenqi
|
||||
20,FY326,FY326,FY319
|
||||
@@ -25,7 +25,7 @@
|
||||
25,FrskyV
|
||||
26,HONTAI,HONTAI,JJRCX1,X5C1,FQ777_951
|
||||
27,OpnLrs
|
||||
28,AFHDS2A,PWM_IBUS,PPM_IBUS,PWM_SBUS,PPM_SBUS,PWM_IB16,PPM_IB16
|
||||
28,AFHDS2A,PWM_IBUS,PPM_IBUS,PWM_SBUS,PPM_SBUS,PWM_IB16,PPM_IB16,PWM_SB16,PPM_SB16
|
||||
29,Q2X2,Q222,Q242,Q282
|
||||
30,WK2x01,WK2801,WK2401,W6_5_1,W6_6_1,W6_HEL,W6_HEL_I
|
||||
31,Q303,Q303,CX35,CX10D,CX10WD
|
||||
@@ -45,8 +45,8 @@
|
||||
45,E01X,E012,E015
|
||||
46,V911S,V911S,E119
|
||||
47,GD00x,GD_V1,GD_V2
|
||||
48,V761,3CH,4CH
|
||||
49,KF606
|
||||
48,V761,3CH,4CH,TOPRC
|
||||
49,KF606,KF606,MIG320
|
||||
50,Redpine,Fast,Slow
|
||||
51,Potensic,A20
|
||||
52,ZSX,280
|
||||
@@ -55,7 +55,7 @@
|
||||
55,Frsky_RX,Multi,CloneTX,EraseTX,CPPM
|
||||
56,AFHDS2A_RX,Multi,CPPM
|
||||
57,HoTT,Sync,No_Sync
|
||||
58,FX816,P38
|
||||
58,FX,816,620
|
||||
59,Bayang_RX,Multi,CPPM
|
||||
60,Pelikan,Pro,Lite,SCX24
|
||||
61,Tiger
|
||||
@@ -80,9 +80,13 @@
|
||||
80,E016H,E016Hv2
|
||||
81,E010r5
|
||||
82,LOLI
|
||||
83,E129
|
||||
83,E129,E129,C186
|
||||
84,JOYSWAY
|
||||
85,E016H
|
||||
87,IKEA
|
||||
88,WILLIFM
|
||||
89,Losi
|
||||
90,MouldKg,Analog,Digit
|
||||
90,MouldKg,Analog,Digit
|
||||
91,Xerall
|
||||
92,MT99xx,PA18
|
||||
93,Kyosho2,KT-17
|
||||
|
||||
@@ -33,6 +33,7 @@ const char STR_FRSKYX[] ="FrSky X";
|
||||
const char STR_FRSKYX2[] ="FrSkyX2";
|
||||
const char STR_ESKY[] ="ESky";
|
||||
const char STR_MT99XX[] ="MT99XX";
|
||||
const char STR_MT99XX2[] ="MT99XX2";
|
||||
const char STR_MJXQ[] ="MJXq";
|
||||
const char STR_SHENQI[] ="Shenqi";
|
||||
const char STR_FY326[] ="FY326";
|
||||
@@ -77,7 +78,7 @@ const char STR_SCANNER[] ="Scanner";
|
||||
const char STR_FRSKY_RX[] ="FrSkyRX";
|
||||
const char STR_AFHDS2A_RX[] ="FS2A_RX";
|
||||
const char STR_HOTT[] ="HoTT";
|
||||
const char STR_FX816[] ="FX816";
|
||||
const char STR_FX[] ="FX";
|
||||
const char STR_BAYANG_RX[] ="BayanRX";
|
||||
const char STR_PELIKAN[] ="Pelikan";
|
||||
const char STR_TIGER[] ="Tiger";
|
||||
@@ -87,6 +88,7 @@ const char STR_FRSKYR9[] ="FrSkyR9";
|
||||
const char STR_PROPEL[] ="Propel";
|
||||
const char STR_SKYARTEC[] ="Skyartc";
|
||||
const char STR_KYOSHO[] ="Kyosho";
|
||||
const char STR_KYOSHO2[] ="Kyosho2";
|
||||
const char STR_RLINK[] ="RadLink";
|
||||
const char STR_REALACC[] ="Realacc";
|
||||
const char STR_OMP[] ="OMP";
|
||||
@@ -102,6 +104,7 @@ const char STR_IKEAANSLUTA[]="Ansluta";
|
||||
const char STR_CONFIG[] ="Config";
|
||||
const char STR_LOSI[] ="Losi";
|
||||
const char STR_MOULDKG[] ="MouldKg";
|
||||
const char STR_XERALL[] ="Xerall";
|
||||
|
||||
const char STR_SUBTYPE_FLYSKY[] = "\x04""Std\0""V9x9""V6x6""V912""CX20";
|
||||
const char STR_SUBTYPE_HUBSAN[] = "\x04""H107""H301""H501";
|
||||
@@ -118,7 +121,8 @@ const char STR_SUBTYPE_SLT[] = "\x06""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""M
|
||||
const char STR_SUBTYPE_CX10[] = "\x07""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041";
|
||||
const char STR_SUBTYPE_CG023[] = "\x05""Std\0 ""YD829";
|
||||
const char STR_SUBTYPE_BAYANG[] = "\x07""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4\0""QX100\0 ";
|
||||
const char STR_SUBTYPE_MT99[] = "\x06""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805\0""A180\0 ""Dragon";
|
||||
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_MJXQ[] = "\x07""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix";
|
||||
const char STR_SUBTYPE_FY326[] = "\x05""Std\0 ""FY319";
|
||||
const char STR_SUBTYPE_HONTAI[] = "\x07""Std\0 ""JJRC X1""X5C1\0 ""FQ_951";
|
||||
@@ -137,8 +141,7 @@ const char STR_SUBTYPE_GD00X[] = "\x05""GD_V1""GD_V2";
|
||||
const char STR_SUBTYPE_REDPINE[] = "\x04""Fast""Slow";
|
||||
const char STR_SUBTYPE_POTENSIC[] = "\x03""A20";
|
||||
const char STR_SUBTYPE_ZSX[] = "\x07""280JJRC";
|
||||
const char STR_SUBTYPE_HEIGHT[] = "\x03""5ch""8ch";
|
||||
const char STR_SUBTYPE_FX816[] = "\x03""P38";
|
||||
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_ESKY150[] = "\x03""4ch""7ch";
|
||||
const char STR_SUBTYPE_ESKY150V2[] = "\x05""150V2";
|
||||
@@ -152,14 +155,17 @@ const char STR_SUBTYPE_WFLY[] = "\x05""WFR0x";
|
||||
const char STR_SUBTYPE_WFLY2[] = "\x05""RF20x";
|
||||
const char STR_SUBTYPE_HOTT[] = "\x07""Sync\0 ""No_Sync";
|
||||
const char STR_SUBTYPE_PELIKAN[] = "\x05""Pro\0 ""Lite\0""SCX24";
|
||||
const char STR_SUBTYPE_V761[] = "\x03""3ch""4ch";
|
||||
const char STR_SUBTYPE_V761[] = "\x05""3ch\0 ""4ch\0 ""TOPRC";
|
||||
const char STR_SUBTYPE_RLINK[] = "\x07""Surface""Air\0 ""DumboRC";
|
||||
const char STR_SUBTYPE_REALACC[] = "\x03""R11";
|
||||
const char STR_SUBTYPE_KYOSHO[] = "\x04""FHSS""Hype";
|
||||
const char STR_SUBTYPE_KYOSHO2[] = "\x05""KT-17";
|
||||
const char STR_SUBTYPE_FUTABA[] = "\x05""SFHSS";
|
||||
const char STR_SUBTYPE_JJRC345[] = "\x08""JJRC345\0""SkyTmblr";
|
||||
const char STR_SUBTYPE_MOULKG[] = "\x06""Analog""Digit\0";
|
||||
|
||||
const char STR_SUBTYPE_KF606[] = "\x06""KF606\0""MIG320";
|
||||
const char STR_SUBTYPE_E129[] = "\x04""E129""C186";
|
||||
const char STR_SUBTYPE_FX[] = "\x03""816""620";
|
||||
#define NO_SUBTYPE nullptr
|
||||
|
||||
#ifdef SEND_CPPM
|
||||
@@ -245,11 +251,11 @@ const mm_protocol_definition multi_protocols[] = {
|
||||
#if defined(E016HV2_CC2500_INO)
|
||||
{PROTO_E016HV2, STR_E016HV2, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_CC2500, E016HV2_init, E016HV2_callback },
|
||||
#endif
|
||||
#if defined(E01X_NRF24L01_INO)
|
||||
{PROTO_E01X, STR_E01X, STR_SUBTYPE_E01X, 2, OPTION_OPTION, 0, 0, SW_NRF, E01X_init, E01X_callback },
|
||||
#if defined(E01X_CYRF6936_INO)
|
||||
{PROTO_E01X, STR_E01X, STR_SUBTYPE_E01X, 2, OPTION_NONE, 0, 0, SW_CYRF, E01X_init, E01X_callback },
|
||||
#endif
|
||||
#if defined(E129_CYRF6936_INO)
|
||||
{PROTO_E129, STR_E129, NO_SUBTYPE, 0, 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
|
||||
#if defined(ESKY_NRF24L01_INO)
|
||||
{PROTO_ESKY, STR_ESKY, STR_SUBTYPE_ESKY, 2, OPTION_NONE, 0, 1, SW_NRF, ESKY_init, ESKY_callback },
|
||||
@@ -300,8 +306,8 @@ const mm_protocol_definition multi_protocols[] = {
|
||||
#if defined(FUTABA_CC2500_INO)
|
||||
{PROTO_FUTABA, STR_FUTABA, STR_SUBTYPE_FUTABA, 1, OPTION_RFTUNE, 1, 1, SW_CC2500, SFHSS_init, SFHSS_callback },
|
||||
#endif
|
||||
#if defined(FX816_NRF24L01_INO)
|
||||
{PROTO_FX816, STR_FX816, STR_SUBTYPE_FX816, 1, OPTION_NONE, 0, 0, SW_NRF, FX816_init, FX816_callback },
|
||||
#if defined(FX_NRF24L01_INO)
|
||||
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 2, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
|
||||
#endif
|
||||
#if defined(FY326_NRF24L01_INO)
|
||||
{PROTO_FY326, STR_FY326, STR_SUBTYPE_FY326, 2, OPTION_NONE, 0, 0, SW_NRF, FY326_init, FY326_callback },
|
||||
@@ -346,7 +352,7 @@ const mm_protocol_definition multi_protocols[] = {
|
||||
{PROTO_JOYSWAY, STR_JOYSWAY, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_A7105, JOYSWAY_init, JOYSWAY_callback },
|
||||
#endif
|
||||
#if defined(KF606_CCNRF_INO)
|
||||
{PROTO_KF606, STR_KF606, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback },
|
||||
{PROTO_KF606, STR_KF606, STR_SUBTYPE_KF606, 2, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback },
|
||||
#endif
|
||||
#if defined(KN_NRF24L01_INO)
|
||||
{PROTO_KN, STR_KN, STR_SUBTYPE_KN, 2, OPTION_NONE, 0, 0, SW_NRF, KN_init, KN_callback },
|
||||
@@ -354,6 +360,9 @@ const mm_protocol_definition multi_protocols[] = {
|
||||
#if defined(KYOSHO_A7105_INO)
|
||||
{PROTO_KYOSHO, STR_KYOSHO, STR_SUBTYPE_KYOSHO, 2, OPTION_NONE, 0, 1, SW_A7105, KYOSHO_init, KYOSHO_callback },
|
||||
#endif
|
||||
#if defined(KYOSHO2_NRF24L01_INO)
|
||||
{PROTO_KYOSHO2, STR_KYOSHO2, STR_SUBTYPE_KYOSHO2, 1, OPTION_NONE, 0, 0, SW_NRF, KYOSHO2_init, KYOSHO2_callback },
|
||||
#endif
|
||||
#if defined(LOLI_NRF24L01_INO)
|
||||
{PROTO_LOLI, STR_LOLI, NO_SUBTYPE, 0, OPTION_NONE, 1, 0, SW_NRF, LOLI_init, LOLI_callback },
|
||||
#endif
|
||||
@@ -370,7 +379,10 @@ const mm_protocol_definition multi_protocols[] = {
|
||||
{PROTO_MOULDKG, STR_MOULDKG, STR_SUBTYPE_MOULKG, 2, OPTION_OPTION, 0, 0, SW_NRF, MOULDKG_init, MOULDKG_callback },
|
||||
#endif
|
||||
#if defined(MT99XX_CCNRF_INO)
|
||||
{PROTO_MT99XX, STR_MT99XX, STR_SUBTYPE_MT99, 7, 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
|
||||
#if defined(MT99XX_CCNRF_INO)
|
||||
{PROTO_MT99XX2, STR_MT99XX2, STR_SUBTYPE_MT992, 1, OPTION_NONE, 0, 0, SW_NRF, MT99XX_init, MT99XX_callback },
|
||||
#endif
|
||||
#if defined(NCC1701_NRF24L01_INO)
|
||||
{PROTO_NCC1701, STR_NCC1701, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, NCC_init, NCC_callback },
|
||||
@@ -430,7 +442,7 @@ const mm_protocol_definition multi_protocols[] = {
|
||||
{PROTO_V2X2, STR_V2X2, STR_SUBTYPE_V2X2, 3, OPTION_NONE, 0, 0, SW_NRF, V2X2_init, V2X2_callback },
|
||||
#endif
|
||||
#if defined(V761_NRF24L01_INO)
|
||||
{PROTO_V761, STR_V761, STR_SUBTYPE_V761, 2, OPTION_NONE, 0, 0, SW_NRF, V761_init, V761_callback },
|
||||
{PROTO_V761, STR_V761, STR_SUBTYPE_V761, 3, OPTION_NONE, 0, 0, SW_NRF, V761_init, V761_callback },
|
||||
#endif
|
||||
#if defined(V911S_CCNRF_INO)
|
||||
{PROTO_V911S, STR_V911S, STR_SUBTYPE_V911S, 2, OPTION_RFTUNE, 0, 0, SW_NRF, V911S_init, V911S_callback },
|
||||
@@ -445,6 +457,9 @@ 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_WBUS, 1, 0, SW_A7105, WFLY2_init, WFLY2_callback },// crash OpenTX...
|
||||
#endif
|
||||
#if defined(XERALL_NRF24L01_INO)
|
||||
{PROTO_XERALL, STR_XERALL, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_NRF, XERALL_init, XERALL_callback },
|
||||
#endif
|
||||
#if defined(XK_CCNRF_INO)
|
||||
{PROTO_XK, STR_XK, STR_SUBTYPE_XK, 2, OPTION_RFTUNE, 0, 0, SW_NRF, XK_init, XK_callback },
|
||||
#endif
|
||||
@@ -465,3 +480,69 @@ const mm_protocol_definition multi_protocols[] = {
|
||||
#endif
|
||||
{0xFF, nullptr, nullptr, 0, 0, 0, 0, 0, nullptr, nullptr }
|
||||
};
|
||||
|
||||
#ifdef MULTI_TELEMETRY
|
||||
uint16_t PROTOLIST_callback()
|
||||
{
|
||||
if(option != prev_option)
|
||||
{//Only send once
|
||||
/* Type 0x11 Protocol list export via telemetry. Used by the protocol PROTO_PROTOLIST=0, the list entry is given by the Option field.
|
||||
length: variable
|
||||
data[0] = protocol number, 0xFF is an invalid list entry (Option value too large), Option == 0xFF -> number of protocols in the list
|
||||
data[1..n] = protocol name null terminated
|
||||
data[n+1] = flags
|
||||
flags>>4 Option text number to be displayed (check multi status for description)
|
||||
flags&0x01 failsafe supported
|
||||
flags&0x02 Channel Map Disabled supported
|
||||
data[n+2] = number of sub protocols
|
||||
data[n+3] = sub protocols text length, only sent if nbr_sub != 0
|
||||
data[n+4..] = sub protocol names, only sent if nbr_sub != 0
|
||||
*/
|
||||
prev_option = option;
|
||||
|
||||
if(option >= (sizeof(multi_protocols)/sizeof(mm_protocol_definition)) - 1)
|
||||
{//option is above the end of the list
|
||||
//Header
|
||||
multi_send_header(MULTI_TELEMETRY_PROTO, 1);
|
||||
if(option == 0xFF)
|
||||
Serial_write((sizeof(multi_protocols)/sizeof(mm_protocol_definition)) - 1); //Nbr proto
|
||||
else
|
||||
Serial_write(0xFF); //Error
|
||||
}
|
||||
else
|
||||
{//valid option value
|
||||
uint8_t proto_len = strlen(multi_protocols[option].ProtoString) + 1;
|
||||
uint8_t nbr_sub = multi_protocols[option].nbrSubProto;
|
||||
uint8_t sub_len = 0;
|
||||
if(nbr_sub)
|
||||
sub_len = multi_protocols[option].SubProtoString[0];
|
||||
|
||||
//Header
|
||||
multi_send_header(MULTI_TELEMETRY_PROTO, 1 + proto_len + 1 + 1 + (nbr_sub?1:0) + (nbr_sub * sub_len));
|
||||
//Protocol number
|
||||
Serial_write(multi_protocols[option].protocol);
|
||||
//Protocol name
|
||||
for(uint8_t i=0;i<proto_len;i++)
|
||||
Serial_write(multi_protocols[option].ProtoString[i]);
|
||||
//Flags
|
||||
uint8_t flags=0;
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(multi_protocols[option].failSafe)
|
||||
flags |= 0x01; //Failsafe supported
|
||||
#endif
|
||||
if(multi_protocols[option].chMap)
|
||||
flags |= 0x02; //Disable_ch_mapping supported
|
||||
Serial_write( flags | (multi_protocols[option].optionType<<4)); // flags && option type
|
||||
//Number of sub protocols
|
||||
Serial_write(nbr_sub);
|
||||
|
||||
if(nbr_sub !=0 )
|
||||
{//Sub protocols length and texts
|
||||
for(uint8_t i=0;i<=nbr_sub*sub_len;i++)
|
||||
Serial_write(multi_protocols[option].SubProtoString[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
#endif
|
||||
@@ -18,8 +18,8 @@
|
||||
//******************
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 3
|
||||
#define VERSION_REVISION 2
|
||||
#define VERSION_PATCH_LEVEL 86
|
||||
#define VERSION_REVISION 3
|
||||
#define VERSION_PATCH_LEVEL 21
|
||||
|
||||
#define MODE_SERIAL 0
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
//******************
|
||||
enum PROTOCOLS
|
||||
{
|
||||
PROTO_PROTOLIST = 0, // NO RF
|
||||
PROTO_FLYSKY = 1, // =>A7105
|
||||
PROTO_HUBSAN = 2, // =>A7105
|
||||
PROTO_FRSKYD = 3, // =>CC2500
|
||||
@@ -72,7 +73,7 @@ enum PROTOCOLS
|
||||
PROTO_BUGSMINI = 42, // =>NRF24L01
|
||||
PROTO_TRAXXAS = 43, // =>CYRF6936
|
||||
PROTO_NCC1701 = 44, // =>NRF24L01
|
||||
PROTO_E01X = 45, // =>NRF24L01
|
||||
PROTO_E01X = 45, // =>CYRF6936
|
||||
PROTO_V911S = 46, // =>NRF24L01
|
||||
PROTO_GD00X = 47, // =>NRF24L01
|
||||
PROTO_V761 = 48, // =>NRF24L01
|
||||
@@ -85,7 +86,7 @@ enum PROTOCOLS
|
||||
PROTO_FRSKY_RX = 55, // =>CC2500
|
||||
PROTO_AFHDS2A_RX= 56, // =>A7105
|
||||
PROTO_HOTT = 57, // =>CC2500
|
||||
PROTO_FX816 = 58, // =>NRF24L01
|
||||
PROTO_FX = 58, // =>NRF24L01
|
||||
PROTO_BAYANG_RX = 59, // =>NRF24L01
|
||||
PROTO_PELIKAN = 60, // =>A7105
|
||||
PROTO_TIGER = 61, // =>NRF24L01
|
||||
@@ -117,6 +118,9 @@ enum PROTOCOLS
|
||||
PROTO_WILLIFM = 88, // 27/35ab/40/41/72 MHz module external project
|
||||
PROTO_LOSI = 89, // =>CYRF6936
|
||||
PROTO_MOULDKG = 90, // =>NRF24L01
|
||||
PROTO_XERALL = 91, // =>NRF24L01
|
||||
PROTO_MT99XX2 = 92, // =>NRF24L01, extension of MT99XX protocol
|
||||
PROTO_KYOSHO2 = 93, // =>NRF24L01
|
||||
|
||||
PROTO_NANORF = 126, // =>NRF24L01
|
||||
PROTO_TEST = 127, // =>CC2500
|
||||
@@ -148,6 +152,8 @@ enum AFHDS2A
|
||||
PPM_SBUS = 3,
|
||||
PWM_IB16 = 4,
|
||||
PPM_IB16 = 5,
|
||||
PWM_SB16 = 6,
|
||||
PPM_SB16 = 7,
|
||||
};
|
||||
enum Hisky
|
||||
{
|
||||
@@ -230,6 +236,11 @@ enum MT99XX
|
||||
FY805 = 4,
|
||||
A180 = 5,
|
||||
DRAGON = 6,
|
||||
F949G = 7,
|
||||
};
|
||||
enum MT99XX2
|
||||
{
|
||||
PA18 = 0,
|
||||
};
|
||||
enum MJXQ
|
||||
{
|
||||
@@ -380,7 +391,6 @@ enum ESKY
|
||||
ESKY_STD = 0,
|
||||
ESKY_ET4 = 1,
|
||||
};
|
||||
|
||||
enum FRSKY_RX
|
||||
{
|
||||
FRSKY_RX = 0,
|
||||
@@ -388,62 +398,69 @@ enum FRSKY_RX
|
||||
FRSKY_ERASE = 2,
|
||||
FRSKY_CPPM = 3,
|
||||
};
|
||||
|
||||
enum FRSKYL
|
||||
{
|
||||
LR12 = 0,
|
||||
LR12_6CH = 1,
|
||||
};
|
||||
|
||||
enum HOTT
|
||||
{
|
||||
HOTT_SYNC = 0,
|
||||
HOTT_NO_SYNC= 1,
|
||||
};
|
||||
|
||||
enum PELIKAN
|
||||
{
|
||||
PELIKAN_PRO = 0,
|
||||
PELIKAN_LITE= 1,
|
||||
PELIKAN_SCX24=2,
|
||||
};
|
||||
|
||||
enum V761
|
||||
{
|
||||
V761_3CH = 0,
|
||||
V761_4CH = 1,
|
||||
V761_TOPRC = 2,
|
||||
};
|
||||
|
||||
enum HEIGHT
|
||||
{
|
||||
HEIGHT_5CH = 0,
|
||||
HEIGHT_8CH = 1,
|
||||
};
|
||||
|
||||
enum KYOSHO
|
||||
{
|
||||
KYOSHO_FHSS = 0,
|
||||
KYOSHO_HYPE = 1,
|
||||
};
|
||||
|
||||
enum JJRC345
|
||||
{
|
||||
JJRC345 = 0,
|
||||
SKYTMBLR = 1,
|
||||
};
|
||||
|
||||
enum RLINK
|
||||
{
|
||||
RLINK_SURFACE = 0,
|
||||
RLINK_AIR = 1,
|
||||
RLINK_DUMBORC = 2,
|
||||
};
|
||||
|
||||
enum MOULDKG
|
||||
{
|
||||
MOULDKG_ANALOG = 0,
|
||||
MOULDKG_DIGIT = 1,
|
||||
};
|
||||
enum KF606
|
||||
{
|
||||
KF606_KF606 = 0,
|
||||
KF606_MIG320 = 1,
|
||||
};
|
||||
enum E129
|
||||
{
|
||||
E129_E129 = 0,
|
||||
E129_C186 = 1,
|
||||
};
|
||||
enum FX
|
||||
{
|
||||
FX816 = 0,
|
||||
FX620 = 1,
|
||||
};
|
||||
|
||||
#define NONE 0
|
||||
#define P_HIGH 1
|
||||
@@ -509,6 +526,7 @@ enum MultiPacketTypes
|
||||
MULTI_TELEMETRY_HOTT = 14,
|
||||
MULTI_TELEMETRY_MLINK = 15,
|
||||
MULTI_TELEMETRY_CONFIG = 16,
|
||||
MULTI_TELEMETRY_PROTO = 17,
|
||||
};
|
||||
|
||||
// Macros
|
||||
@@ -888,7 +906,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
||||
FRSKY_RX 55
|
||||
AFHDS2A_RX 56
|
||||
HOTT 57
|
||||
FX816 58
|
||||
FX 58
|
||||
BAYANG_RX 59
|
||||
PELIKAN 60
|
||||
TIGER 61
|
||||
@@ -915,6 +933,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
||||
E129 83
|
||||
JOYSWAY 84
|
||||
E016H 85
|
||||
XERALL 91
|
||||
BindBit=> 0x80 1=Bind/0=No
|
||||
AutoBindBit=> 0x40 1=Yes /0=No
|
||||
RangeCheck=> 0x20 1=Yes /0=No
|
||||
@@ -1263,12 +1282,12 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
||||
data[4-]= packed channels data, 11 bit per channel
|
||||
|
||||
Type 0x0E HoTT telemetry
|
||||
length: 14
|
||||
length: 15
|
||||
data[0] = TX_RSSI
|
||||
data[1] = TX_LQI
|
||||
data[2] = type
|
||||
data[3] = page
|
||||
data[4-13] = data
|
||||
data[4-14] = data
|
||||
|
||||
Type 0x0F M-Link telemetry
|
||||
length: 10
|
||||
@@ -1280,4 +1299,17 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
|
||||
Type 0x10 Config telemetry
|
||||
length: 22
|
||||
data[0..21] = Config data
|
||||
|
||||
Type 0x11 Protocol list export via telemetry. Used by the protocol PROTO_PROTOLIST=0, the list entry is given by the Option field.
|
||||
length: variable
|
||||
data[0] = protocol number, 0xFF is an invalid list entry (Option value too large), Option == 0xFF -> number of protocols in the list
|
||||
data[1..n] = protocol name null terminated
|
||||
data[n+1] = flags
|
||||
flags>>4 Option text number to be displayed (check multi status for description)
|
||||
flags&0x01 failsafe supported
|
||||
flags&0x02 Channel Map Disabled supported
|
||||
data[n+2] = number of sub protocols
|
||||
data[n+3] = sub protocols text length, only sent if nbr_sub != 0
|
||||
data[n+4..] = sub protocol names, only sent if nbr_sub != 0
|
||||
|
||||
*/
|
||||
|
||||
@@ -179,7 +179,7 @@ uint8_t option;
|
||||
uint8_t cur_protocol[3];
|
||||
uint8_t prev_option;
|
||||
uint8_t prev_power=0xFD; // unused power value
|
||||
uint8_t RX_num;
|
||||
uint8_t RX_num;
|
||||
|
||||
//Serial RX variables
|
||||
#define BAUD 100000
|
||||
@@ -765,6 +765,17 @@ void End_Bind()
|
||||
bind_counter=2;
|
||||
}
|
||||
|
||||
void Update_Telem()
|
||||
{
|
||||
#if defined(TELEMETRY)
|
||||
#ifndef MULTI_TELEMETRY
|
||||
if((protocol == PROTO_BAYANG_RX) || (protocol == PROTO_AFHDS2A_RX) || (protocol == PROTO_FRSKY_RX) || (protocol == PROTO_SCANNER) || (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_NCC1701) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_FRSKYX2) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_HOTT) || (protocol==PROTO_PROPEL) || (protocol==PROTO_OMP) || (protocol==PROTO_DEVO) || (protocol==PROTO_DSM_RX) || (protocol==PROTO_FRSKY_R9) || (protocol==PROTO_RLINK) || (protocol==PROTO_WFLY2) || (protocol==PROTO_LOLI) || (protocol==PROTO_MLINK) || (protocol==PROTO_MT99XX))
|
||||
#endif
|
||||
if(IS_DISABLE_TELEM_off)
|
||||
TelemetryUpdate();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Update_All()
|
||||
{
|
||||
#ifdef ENABLE_SERIAL
|
||||
@@ -855,13 +866,9 @@ bool Update_All()
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if defined(TELEMETRY)
|
||||
#ifndef MULTI_TELEMETRY
|
||||
if((protocol == PROTO_BAYANG_RX) || (protocol == PROTO_AFHDS2A_RX) || (protocol == PROTO_FRSKY_RX) || (protocol == PROTO_SCANNER) || (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_NCC1701) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_FRSKYX2) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_HOTT) || (protocol==PROTO_PROPEL) || (protocol==PROTO_OMP) || (protocol==PROTO_DEVO) || (protocol==PROTO_DSM_RX) || (protocol==PROTO_FRSKY_R9) || (protocol==PROTO_RLINK) || (protocol==PROTO_WFLY2) || (protocol==PROTO_LOLI) || (protocol==PROTO_MLINK) || (protocol==PROTO_MT99XX))
|
||||
#endif
|
||||
if(IS_DISABLE_TELEM_off)
|
||||
TelemetryUpdate();
|
||||
#endif
|
||||
|
||||
Update_Telem();
|
||||
|
||||
#ifdef ENABLE_BIND_CH
|
||||
if(IS_AUTOBIND_FLAG_on && IS_BIND_CH_PREV_off && Channel_data[BIND_CH-1]>CHANNEL_MAX_COMMAND)
|
||||
{ // Autobind is on and BIND_CH went up
|
||||
@@ -1128,17 +1135,16 @@ static void protocol_init()
|
||||
{
|
||||
remote_callback = 0; // No protocol
|
||||
LED_off; // Led off during protocol init
|
||||
modules_reset(); // Reset all modules
|
||||
crc16_polynomial = 0x1021; // Default CRC crc16_polynomial
|
||||
crc8_polynomial = 0x31; // Default CRC crc8_polynomial
|
||||
prev_option = option;
|
||||
|
||||
multi_protocols_index = 0xFF;
|
||||
// reset telemetry
|
||||
#ifdef TELEMETRY
|
||||
#ifdef MULTI_SYNC
|
||||
inputRefreshRate = 0; // Don't do it unless the protocol asks for it
|
||||
#endif
|
||||
multi_protocols_index = 0xFF;
|
||||
tx_pause();
|
||||
init_frskyd_link_telemetry();
|
||||
pps_timer=millis();
|
||||
@@ -1160,7 +1166,7 @@ static void protocol_init()
|
||||
TX_RX_PAUSE_off;
|
||||
TX_MAIN_PAUSE_off;
|
||||
tx_resume();
|
||||
#if defined(AFHDS2A_RX_A7105_INO) || defined(FRSKY_RX_CC2500_INO) || defined(BAYANG_RX_NRF24L01_INO)
|
||||
#if defined(AFHDS2A_RX_A7105_INO) || defined(FRSKY_RX_CC2500_INO) || defined(BAYANG_RX_NRF24L01_INO) || defined(DSM_RX_CYRF6936_INO)
|
||||
for(uint8_t ch=0; ch<16; ch++)
|
||||
rx_rc_chan[ch] = 1024;
|
||||
#endif
|
||||
@@ -1181,52 +1187,71 @@ static void protocol_init()
|
||||
#endif
|
||||
DATA_BUFFER_LOW_off;
|
||||
|
||||
SUB_PROTO_VALID;
|
||||
SUB_PROTO_INVALID;
|
||||
option_override = 0xFF;
|
||||
|
||||
blink=millis();
|
||||
|
||||
debugln("Protocol selected: %d, sub proto %d, rxnum %d, option %d", protocol, sub_protocol, RX_num, option);
|
||||
uint8_t index=0;
|
||||
#if defined(FRSKYX_CC2500_INO) && defined(EU_MODULE)
|
||||
if( ! ( (protocol == PROTO_FRSKYX || protocol == PROTO_FRSKYX2) && sub_protocol < 2 ) )
|
||||
#endif
|
||||
while(multi_protocols[index].protocol != 0xFF)
|
||||
if(protocol)
|
||||
{
|
||||
if(multi_protocols[index].protocol==protocol)
|
||||
//Reset all modules
|
||||
modules_reset();
|
||||
|
||||
uint8_t index=0;
|
||||
#if defined(FRSKYX_CC2500_INO) && defined(EU_MODULE)
|
||||
if( ! ( (protocol == PROTO_FRSKYX || protocol == PROTO_FRSKYX2) && sub_protocol < 2 ) )
|
||||
#endif
|
||||
while(multi_protocols[index].protocol != 0xFF)
|
||||
{
|
||||
//Save index
|
||||
multi_protocols_index = index;
|
||||
//Set the RF switch
|
||||
rf_switch(multi_protocols[multi_protocols_index].rfSwitch);
|
||||
//Init protocol
|
||||
multi_protocols[multi_protocols_index].Init();
|
||||
//Save call back function address
|
||||
remote_callback = multi_protocols[multi_protocols_index].CallBack;
|
||||
//Send a telemetry status right now
|
||||
SEND_MULTI_STATUS_on;
|
||||
#ifdef DEBUG_SERIAL
|
||||
debug("Proto=%s",multi_protocols[multi_protocols_index].ProtoString);
|
||||
uint8_t nbr=multi_protocols[multi_protocols_index].nbrSubProto;
|
||||
debug(", nbr_sub=%d, Sub=",nbr);
|
||||
if(nbr && (sub_protocol&0x07)<nbr)
|
||||
{
|
||||
uint8_t len=multi_protocols[multi_protocols_index].SubProtoString[0];
|
||||
uint8_t offset=len*(sub_protocol&0x07)+1;
|
||||
for(uint8_t j=0;j<len;j++)
|
||||
debug("%c",multi_protocols[multi_protocols_index].SubProtoString[j+offset]);
|
||||
if(multi_protocols[index].protocol==protocol)
|
||||
{
|
||||
//Save index
|
||||
multi_protocols_index = index;
|
||||
//Check sub protocol validity
|
||||
if( ((sub_protocol&0x07) == 0) || (sub_protocol&0x07) < multi_protocols[index].nbrSubProto )
|
||||
SUB_PROTO_VALID;
|
||||
if(IS_SUB_PROTO_VALID)
|
||||
{//Start the protocol
|
||||
//Set the RF switch
|
||||
rf_switch(multi_protocols[index].rfSwitch);
|
||||
//Init protocol
|
||||
multi_protocols[index].Init(); // Init could invalidate the sub proto in case it is not suuported
|
||||
if(IS_SUB_PROTO_VALID)
|
||||
remote_callback = multi_protocols[index].CallBack; //Save call back function address
|
||||
}
|
||||
debug(", Opt=%d",multi_protocols[multi_protocols_index].optionType);
|
||||
debug(", FS=%d",multi_protocols[multi_protocols_index].failSafe);
|
||||
debug(", CHMap=%d",multi_protocols[multi_protocols_index].chMap);
|
||||
debugln(", rfSw=%d",multi_protocols[multi_protocols_index].rfSwitch);
|
||||
#endif
|
||||
break;
|
||||
#ifdef DEBUG_SERIAL
|
||||
debug("Proto=%s", multi_protocols[index].ProtoString);
|
||||
debug(", nbr_sub=%d, Sub=", multi_protocols[index].nbrSubProto);
|
||||
if(IS_SUB_PROTO_VALID)
|
||||
{
|
||||
uint8_t len=multi_protocols[index].SubProtoString[0];
|
||||
uint8_t offset=len*(sub_protocol&0x07)+1;
|
||||
for(uint8_t j=0;j<len;j++)
|
||||
debug("%c",multi_protocols[index].SubProtoString[j+offset]);
|
||||
}
|
||||
debug(", Opt=%d",multi_protocols[index].optionType);
|
||||
debug(", FS=%d",multi_protocols[index].failSafe);
|
||||
debug(", CHMap=%d",multi_protocols[index].chMap);
|
||||
debugln(", rfSw=%d",multi_protocols[index].rfSwitch);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
//Send a telemetry status right now
|
||||
SEND_MULTI_STATUS_on;
|
||||
Update_Telem();
|
||||
}
|
||||
#ifdef MULTI_TELEMETRY
|
||||
else
|
||||
{//protocol=PROTO_PROTOLIST=0
|
||||
remote_callback = PROTOLIST_callback;
|
||||
prev_option = option + 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(WAIT_FOR_BIND) && defined(ENABLE_BIND_CH)
|
||||
if( IS_AUTOBIND_FLAG_on && IS_BIND_CH_PREV_off && (cur_protocol[1]&0x80)==0 && mode_select == MODE_SERIAL)
|
||||
{ // Autobind is active but no bind requested by either BIND_CH or BIND. But do not wait if in PPM mode...
|
||||
@@ -1237,16 +1262,19 @@ static void protocol_init()
|
||||
WAIT_BIND_off;
|
||||
CHANGE_PROTOCOL_FLAG_off;
|
||||
|
||||
//Wait 5ms after protocol init
|
||||
cli(); // disable global int
|
||||
OCR1A = TCNT1 + 5000*2; // set compare A for callback
|
||||
#ifndef STM32_BOARD
|
||||
TIFR1 = OCF1A_bm ; // clear compare A flag
|
||||
#else
|
||||
TIMER2_BASE->SR = 0x1E5F & ~TIMER_SR_CC1IF; // Clear Timer2/Comp1 interrupt flag
|
||||
#endif
|
||||
sei(); // enable global int
|
||||
BIND_BUTTON_FLAG_off; // do not bind/reset id anymore even if protocol change
|
||||
if(protocol)
|
||||
{
|
||||
//Wait 5ms after protocol init
|
||||
cli(); // disable global int
|
||||
OCR1A = TCNT1 + 5000*2; // set compare A for callback
|
||||
#ifndef STM32_BOARD
|
||||
TIFR1 = OCF1A_bm ; // clear compare A flag
|
||||
#else
|
||||
TIMER2_BASE->SR = 0x1E5F & ~TIMER_SR_CC1IF; // Clear Timer2/Comp1 interrupt flag
|
||||
#endif
|
||||
sei(); // enable global int
|
||||
BIND_BUTTON_FLAG_off; // do not bind/reset id anymore even if protocol change
|
||||
}
|
||||
}
|
||||
|
||||
void update_serial_data()
|
||||
@@ -1520,7 +1548,9 @@ void update_serial_data()
|
||||
if ( used >= MAX_SPORT_BUFFER-(MAX_SPORT_BUFFER>>2) )
|
||||
{
|
||||
DATA_BUFFER_LOW_on;
|
||||
SEND_MULTI_STATUS_on; //Send Multi Status ASAP to inform the TX
|
||||
//Send Multi Status ASAP to inform the TX
|
||||
SEND_MULTI_STATUS_on;
|
||||
Update_Telem();
|
||||
debugln("Low buf=%d,h=%d,t=%d",used,SportHead,SportTail);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,11 +183,9 @@ void NRF24L01_SetPower()
|
||||
power=NRF_POWER_0;
|
||||
if(prev_power != power)
|
||||
{
|
||||
rf_setup = (rf_setup & 0xF9) | (power << 1);
|
||||
rf_setup = (rf_setup & 0xF8) | (power << 1);
|
||||
if(power==3)
|
||||
rf_setup |=0x01; // Si24r01 full power, unused bit for NRF
|
||||
else
|
||||
rf_setup &=0xFE;
|
||||
rf_setup |= 0x01; // Si24r01 full power, unused bit for NRF
|
||||
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup);
|
||||
prev_power=power;
|
||||
}
|
||||
@@ -246,112 +244,6 @@ uint8_t NRF24L01_packet_ack()
|
||||
return PKT_PENDING;
|
||||
}
|
||||
|
||||
//
|
||||
// HS6200 emulation layer
|
||||
///////////////////////////
|
||||
static uint8_t hs6200_crc;
|
||||
static uint16_t hs6200_crc_init;
|
||||
static uint8_t hs6200_tx_addr[5];
|
||||
static uint8_t hs6200_address_length;
|
||||
|
||||
static const uint8_t hs6200_scramble[] = {
|
||||
0x80,0xf5,0x3b,0x0d,0x6d,0x2a,0xf9,0xbc,
|
||||
0x51,0x8e,0x4c,0xfd,0xc1,0x65,0xd0 }; // todo: find all 32 bytes ...
|
||||
|
||||
void HS6200_SetTXAddr(const uint8_t* addr, uint8_t len)
|
||||
{
|
||||
if(len < 4)
|
||||
len = 4;
|
||||
else if(len > 5)
|
||||
len = 5;
|
||||
|
||||
// use nrf24 address field as a longer preamble
|
||||
if(addr[len-1] & 0x80)
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\x55\x55\x55\x55\x55", 5);
|
||||
else
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xaa\xaa\xaa\xaa\xaa", 5);
|
||||
|
||||
// precompute address crc
|
||||
crc = 0xffff;
|
||||
for(int i=0; i<len; i++)
|
||||
crc16_update(addr[len-1-i], 8);
|
||||
hs6200_crc_init=crc;
|
||||
memcpy(hs6200_tx_addr, addr, len);
|
||||
hs6200_address_length = len;
|
||||
}
|
||||
|
||||
static uint16_t hs6200_calc_crc(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
uint8_t pos;
|
||||
|
||||
crc = hs6200_crc_init;
|
||||
// pcf + payload
|
||||
for(pos=0; pos < len-1; pos++)
|
||||
crc16_update(msg[pos], 8);
|
||||
// last byte (1 bit only)
|
||||
if(len > 0)
|
||||
crc16_update(msg[pos+1], 1);
|
||||
return crc;
|
||||
}
|
||||
|
||||
void HS6200_Configure(uint8_t flags)
|
||||
{
|
||||
hs6200_crc = !!(flags & _BV(NRF24L01_00_EN_CRC));
|
||||
flags &= ~(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xff);
|
||||
}
|
||||
|
||||
void HS6200_WritePayload(uint8_t* msg, uint8_t len)
|
||||
{
|
||||
uint8_t payload[32];
|
||||
const uint8_t no_ack = 1; // never ask for an ack
|
||||
static uint8_t pid;
|
||||
uint8_t pos = 0;
|
||||
|
||||
if(len > sizeof(hs6200_scramble))
|
||||
len = sizeof(hs6200_scramble);
|
||||
|
||||
// address
|
||||
for(int i=hs6200_address_length-1; i>=0; i--)
|
||||
payload[pos++] = hs6200_tx_addr[i];
|
||||
|
||||
// guard bytes
|
||||
payload[pos++] = hs6200_tx_addr[0];
|
||||
payload[pos++] = hs6200_tx_addr[0];
|
||||
|
||||
// packet control field
|
||||
payload[pos++] = ((len & 0x3f) << 2) | (pid & 0x03);
|
||||
payload[pos] = (no_ack & 0x01) << 7;
|
||||
pid++;
|
||||
|
||||
// scrambled payload
|
||||
if(len > 0)
|
||||
{
|
||||
payload[pos++] |= (msg[0] ^ hs6200_scramble[0]) >> 1;
|
||||
for(uint8_t i=1; i<len; i++)
|
||||
payload[pos++] = ((msg[i-1] ^ hs6200_scramble[i-1]) << 7) | ((msg[i] ^ hs6200_scramble[i]) >> 1);
|
||||
payload[pos] = (msg[len-1] ^ hs6200_scramble[len-1]) << 7;
|
||||
}
|
||||
|
||||
// crc
|
||||
if(hs6200_crc)
|
||||
{
|
||||
uint16_t crc = hs6200_calc_crc(&payload[hs6200_address_length+2], len+2);
|
||||
uint8_t hcrc = crc >> 8;
|
||||
uint8_t lcrc = crc & 0xff;
|
||||
payload[pos++] |= (hcrc >> 1);
|
||||
payload[pos++] = (hcrc << 7) | (lcrc >> 1);
|
||||
payload[pos++] = lcrc << 7;
|
||||
}
|
||||
|
||||
NRF24L01_WritePayload(payload, pos);
|
||||
delayMicroseconds(option+20);
|
||||
NRF24L01_WritePayload(payload, pos);
|
||||
}
|
||||
//
|
||||
// End of HS6200 emulation
|
||||
////////////////////////////
|
||||
|
||||
///////////////
|
||||
// LT8900 emulation layer
|
||||
uint8_t LT8900_buffer[64];
|
||||
|
||||
@@ -250,11 +250,16 @@ uint16_t PROPEL_callback()
|
||||
if (_BV(NRF24L01_07_RX_DR) & NRF24L01_ReadReg(NRF24L01_07_STATUS))
|
||||
{// data received from the model
|
||||
NRF24L01_ReadPayload(packet_in, PROPEL_PACKET_SIZE);
|
||||
#if 1
|
||||
for(uint8_t i=0; i<PROPEL_PACKET_SIZE; i++)
|
||||
debug("%02X ",packet_in[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
if (packet_in[0] == 0xa3 && memcmp(&packet_in[1],rx_id,3)==0)
|
||||
{
|
||||
telemetry_counter++; //LQI
|
||||
v_lipo1=packet[5]; //number of life left?
|
||||
v_lipo2=packet[4]; //bit mask: 0x80=flying, 0x08=taking off, 0x04=landing, 0x00=landed/crashed
|
||||
v_lipo1=packet_in[5]; //number of life left?
|
||||
v_lipo2=packet_in[4]; //bit mask: 0x80=flying, 0x08=taking off, 0x04=landing, 0x00=landed/crashed
|
||||
if(telemetry_lost==0)
|
||||
telemetry_link=1;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#define RF2500_ADDR_LENGTH 4
|
||||
|
||||
uint8_t RF2500_payload_length, RF2500_tx_addr[RF2500_ADDR_LENGTH], RF2500_buf[80];
|
||||
uint8_t RF2500_payload_length, RF2500_tx_addr[RF2500_ADDR_LENGTH], RF2500_buf[100];
|
||||
bool RF2500_scramble_enabled;
|
||||
|
||||
static void __attribute__((unused)) RF2500_Init(uint8_t payload_length, bool scramble)
|
||||
@@ -35,9 +35,17 @@ static void __attribute__((unused)) RF2500_SetTXAddr(const uint8_t* addr)
|
||||
|
||||
static void __attribute__((unused)) RF2500_BuildPayload(uint8_t* buffer)
|
||||
{
|
||||
const uint8_t RF2500_scramble[] = { 0xD0, 0x9E, 0x53, 0x33, 0xD8, 0xBA, 0x98, 0x08, 0x24, 0xCB, 0x3B, 0xFC, 0x71, 0xA3, 0xF4, 0x55 };
|
||||
const uint16_t RF2500_crc_xorout_scramble = 0xAEE4;
|
||||
const uint8_t RF2500_scramble[] = { 0xD0, 0x9E, 0x53, 0x33, 0xD8, 0xBA, 0x98, 0x08, 0x24, 0xCB, 0x3B, 0xFC, 0x71, 0xA3, 0xF4, 0x55, 0x68, 0x4F, 0xA9 }; //0x4F: unsure
|
||||
uint16_t RF2500_crc_xorout_scramble;
|
||||
if(RF2500_payload_length == 16)
|
||||
RF2500_crc_xorout_scramble = 0xAEE4;
|
||||
else //19
|
||||
RF2500_crc_xorout_scramble = 0xE7C5;
|
||||
|
||||
#if 0
|
||||
for(uint8_t i=0; i<RF2500_payload_length; i++)
|
||||
debug("%02X ", buffer[i]);
|
||||
#endif
|
||||
//Scramble the incoming buffer
|
||||
if(RF2500_scramble_enabled)
|
||||
for(uint8_t i=0; i<RF2500_payload_length; i++)
|
||||
@@ -50,6 +58,10 @@ static void __attribute__((unused)) RF2500_BuildPayload(uint8_t* buffer)
|
||||
buffer[RF2500_payload_length ] = bit_reverse(crc>>8);
|
||||
buffer[RF2500_payload_length+1] = bit_reverse(crc);
|
||||
|
||||
#if 0
|
||||
debugln("C:%02X %02X",buffer[RF2500_payload_length ], buffer[RF2500_payload_length+1]);
|
||||
#endif
|
||||
|
||||
if(RF2500_scramble_enabled)
|
||||
{
|
||||
buffer[RF2500_payload_length ] ^= RF2500_crc_xorout_scramble>>8;
|
||||
|
||||
@@ -271,7 +271,7 @@ uint16_t RLINK_callback()
|
||||
TX_RSSI -= 128;
|
||||
else
|
||||
TX_RSSI += 128;
|
||||
RX_RSSI=packet_in[7]; //Should be packet_in[7]-256 but since it's an uint8_t...
|
||||
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
|
||||
telemetry_link=1; //Send telemetry out
|
||||
|
||||
@@ -123,45 +123,32 @@ static void telemetry_set_input_sync(uint16_t refreshRate)
|
||||
|
||||
static void multi_send_status()
|
||||
{
|
||||
if(protocol == 0) return;
|
||||
|
||||
multi_send_header(MULTI_TELEMETRY_STATUS, 24);
|
||||
|
||||
// Build flags
|
||||
uint8_t flags=0;
|
||||
if (IS_INPUT_SIGNAL_on)
|
||||
if(IS_INPUT_SIGNAL_on)
|
||||
flags |= 0x01;
|
||||
if (mode_select==MODE_SERIAL)
|
||||
if(mode_select==MODE_SERIAL)
|
||||
flags |= 0x02;
|
||||
if (remote_callback != 0)
|
||||
if(remote_callback != 0)
|
||||
{
|
||||
flags |= 0x04;
|
||||
if(multi_protocols_index == 0xFF)
|
||||
{
|
||||
if(protocol!=PROTO_SCANNER)
|
||||
flags &= ~0x04; //Invalid protocol
|
||||
}
|
||||
else if(IS_SUB_PROTO_INVALID)
|
||||
{
|
||||
flags &= ~0x04; //Invalid sub protocol
|
||||
}
|
||||
else if(sub_protocol&0x07)
|
||||
{
|
||||
uint8_t nbr=multi_protocols[multi_protocols_index].nbrSubProto;
|
||||
//if(protocol==PROTO_DSM) nbr++; //Auto sub_protocol
|
||||
if((sub_protocol&0x07)>=nbr )
|
||||
flags &= ~0x04; //Invalid sub protocol
|
||||
}
|
||||
if (IS_WAIT_BIND_on)
|
||||
if(multi_protocols_index != 0xFF && IS_SUB_PROTO_VALID)
|
||||
flags |= 0x04; //Invalid protocol / sub protocol, can't make the distinction since there is no more flags...
|
||||
if(IS_WAIT_BIND_on)
|
||||
flags |= 0x10;
|
||||
else
|
||||
if (IS_BIND_IN_PROGRESS)
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
flags |= 0x08;
|
||||
if(multi_protocols_index != 0xFF)
|
||||
{
|
||||
if(multi_protocols[multi_protocols_index].chMap)
|
||||
flags |= 0x40; //Disable_ch_mapping supported
|
||||
flags |= 0x40; //Disable_ch_mapping supported
|
||||
#ifdef FAILSAFE_ENABLE
|
||||
if(multi_protocols[multi_protocols_index].failSafe)
|
||||
flags |= 0x20; //Failsafe supported
|
||||
flags |= 0x20; //Failsafe supported
|
||||
#endif
|
||||
}
|
||||
if(IS_DATA_BUFFER_LOW_on)
|
||||
@@ -226,7 +213,7 @@ static void multi_send_status()
|
||||
else
|
||||
Serial_write(nbr | (option_override<<4)); // number of sub protocols && option_override type
|
||||
uint8_t j=0;
|
||||
if(nbr && (sub_protocol&0x07)<nbr)
|
||||
if(IS_SUB_PROTO_VALID)
|
||||
{
|
||||
uint8_t len=multi_protocols[multi_protocols_index].SubProtoString[0];
|
||||
uint8_t offset=len*(sub_protocol&0x07)+1;
|
||||
@@ -322,8 +309,8 @@ static void multi_send_status()
|
||||
#ifdef HOTT_FW_TELEMETRY
|
||||
void HOTT_short_frame()
|
||||
{
|
||||
multi_send_header(MULTI_TELEMETRY_HOTT, 14);
|
||||
for (uint8_t i = 0; i < 14; i++) // TX RSSI and TX LQI values followed by frame number and telemetry data
|
||||
multi_send_header(MULTI_TELEMETRY_HOTT, 15);
|
||||
for (uint8_t i = 0; i < 15; i++) // TX RSSI and TX LQI values followed by frame number and telemetry data
|
||||
Serial_write(packet_in[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,13 +25,15 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
#define V761_BIND_COUNT 200
|
||||
#define V761_BIND_FREQ 0x28
|
||||
#define V761_RF_NUM_CHANNELS 3
|
||||
#define TOPRC_BIND_FREQ 0x2A
|
||||
#define TOPRC_PACKET_PERIOD 14120 // Timeout for callback in uSec
|
||||
|
||||
enum
|
||||
{
|
||||
{
|
||||
V761_BIND1 = 0,
|
||||
V761_BIND2,
|
||||
V761_DATA
|
||||
};
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) V761_set_checksum()
|
||||
{
|
||||
@@ -50,40 +52,44 @@ static void __attribute__((unused)) V761_set_checksum()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((unused)) V761_send_packet()
|
||||
{
|
||||
static bool calib=false, prev_ch6=false;
|
||||
|
||||
|
||||
if(phase != V761_DATA)
|
||||
{
|
||||
packet[0] = rx_tx_addr[0];
|
||||
packet[1] = rx_tx_addr[1];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = rx_tx_addr[3];
|
||||
memcpy(packet, rx_tx_addr, 4);
|
||||
packet[4] = hopping_frequency[1];
|
||||
packet[5] = hopping_frequency[2];
|
||||
if(phase == V761_BIND2)
|
||||
packet[6] = 0xf0; // ?
|
||||
if(phase == V761_BIND2)
|
||||
packet[6] = 0xF0; // ?
|
||||
}
|
||||
else
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
if(hopping_frequency_no >= V761_RF_NUM_CHANNELS)
|
||||
{
|
||||
hopping_frequency_no = 0;
|
||||
packet_count++;
|
||||
packet_count &= 0x03;
|
||||
}
|
||||
|
||||
packet[0] = convert_channel_8b(THROTTLE); // Throttle
|
||||
packet[2] = convert_channel_8b(ELEVATOR)>>1; // Elevator
|
||||
|
||||
if(sub_protocol==V761_3CH)
|
||||
{
|
||||
packet[1] = convert_channel_8b(RUDDER)>>1; // Rudder
|
||||
packet[3] = convert_channel_8b(AILERON)>>1; // Aileron
|
||||
}
|
||||
else
|
||||
if(sub_protocol == V761_4CH || sub_protocol == V761_TOPRC)
|
||||
{
|
||||
packet[1] = convert_channel_8b(AILERON)>>1; // Aileron
|
||||
packet[3] = convert_channel_8b(RUDDER)>>1; // Rudder
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[1] = convert_channel_8b(RUDDER)>>1; // Rudder
|
||||
packet[3] = convert_channel_8b(AILERON)>>1; // Aileron
|
||||
}
|
||||
|
||||
packet[5] = (packet_count++ / 3)<<6;
|
||||
packet[4] = (packet[5] == 0x40) ? 0x1a : 0x20; // ?
|
||||
packet[5] = packet_count<<6; // 0X, 4X, 8X, CX
|
||||
packet[4] = 0x20; // Trims 00..20..40, 0X->20 4X->TrAil 8X->TrEle CX->TrRud
|
||||
|
||||
if(CH5_SW) // Mode Expert Gyro off
|
||||
flags = 0x0c;
|
||||
@@ -104,18 +110,17 @@ static void __attribute__((unused)) V761_send_packet()
|
||||
packet[6] = GET_FLAG(CH7_SW, 0x20) // Flip
|
||||
|GET_FLAG(CH8_SW, 0x08) // RTH activation
|
||||
|GET_FLAG(CH9_SW, 0x10); // RTH on/off
|
||||
if(sub_protocol==V761_3CH)
|
||||
packet[6] |= 0x80; // unknown, set on original V761-1 dump but not on eachine dumps, keeping for compatibility
|
||||
|
||||
//packet counter
|
||||
if(packet_count >= 12)
|
||||
packet_count = 0;
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
|
||||
if(hopping_frequency_no >= V761_RF_NUM_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
if(sub_protocol == V761_3CH)
|
||||
packet[6] |= 0x80; // Unknown, set on original V761-1 dump but not on eachine dumps, keeping for compatibility
|
||||
}
|
||||
V761_set_checksum();
|
||||
|
||||
#if 0
|
||||
debug("H:%02X P:",hopping_frequency_no);
|
||||
for(uint8_t i=0;i<V761_PACKET_SIZE;i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
@@ -130,28 +135,36 @@ static void __attribute__((unused)) V761_RF_init()
|
||||
static void __attribute__((unused)) V761_initialize_txid()
|
||||
{
|
||||
#ifdef V761_FORCE_ID
|
||||
switch(RX_num%5)
|
||||
if(sub_protocol == V761_TOPRC)
|
||||
{ //Dump from air on TopRCHobby TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\xD5\x01\x00\x00",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x2E\x41",2);
|
||||
}
|
||||
else
|
||||
{
|
||||
case 1: //Dump from air on Protonus TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\xE8\xE4\x45\x09",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x0D\x21",2);
|
||||
break;
|
||||
case 2: //Dump from air on mshagg2 TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\xAE\xD1\x45\x09",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x13\x1D",2);
|
||||
break;
|
||||
case 3: //Dump from air on MikeHRC Eachine TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\x08\x03\x00\xA0",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x0D\x21",2);
|
||||
break;
|
||||
case 4: //Dump from air on Crashanium Eachine TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\x58\x08\x00\xA0",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x0D\x31",2);
|
||||
break;
|
||||
default: //Dump from SPI
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\x6f\x2c\xb1\x93",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x14\x1e",2);
|
||||
break;
|
||||
switch(RX_num%5)
|
||||
{
|
||||
case 1: //Dump from air on Protonus TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\xE8\xE4\x45\x09",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x0D\x21",2);
|
||||
break;
|
||||
case 2: //Dump from air on mshagg2 TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\xAE\xD1\x45\x09",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x13\x1D",2);
|
||||
break;
|
||||
case 3: //Dump from air on MikeHRC Eachine TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\x08\x03\x00\xA0",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x0D\x21",2);
|
||||
break;
|
||||
case 4: //Dump from air on Crashanium Eachine TX
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\x58\x08\x00\xA0",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x0D\x31",2);
|
||||
break;
|
||||
default: //Dump from SPI
|
||||
memcpy(rx_tx_addr,(uint8_t *)"\x6f\x2c\xb1\x93",4);
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x14\x1e",2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
//Tested with Eachine RX
|
||||
@@ -173,8 +186,8 @@ uint16_t V761_callback()
|
||||
if(bind_counter)
|
||||
bind_counter--;
|
||||
packet_count ++;
|
||||
XN297_RFChannel(V761_BIND_FREQ);
|
||||
XN297_SetTXAddr((uint8_t*)"\x34\x43\x10\x10", 4);
|
||||
XN297_RFChannel(sub_protocol == V761_TOPRC ? TOPRC_BIND_FREQ : V761_BIND_FREQ);
|
||||
XN297_SetTXAddr(rx_id, 4);
|
||||
V761_send_packet();
|
||||
if(packet_count >= 20)
|
||||
{
|
||||
@@ -191,8 +204,9 @@ uint16_t V761_callback()
|
||||
V761_send_packet();
|
||||
if(bind_counter == 0)
|
||||
{
|
||||
phase = V761_DATA;
|
||||
packet_count = 0;
|
||||
BIND_DONE;
|
||||
phase = V761_DATA;
|
||||
}
|
||||
else if(packet_count >= 20)
|
||||
{
|
||||
@@ -202,17 +216,28 @@ uint16_t V761_callback()
|
||||
return 15730;
|
||||
case V761_DATA:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(V761_PACKET_PERIOD);
|
||||
telemetry_set_input_sync(packet_period);
|
||||
#endif
|
||||
V761_send_packet();
|
||||
break;
|
||||
}
|
||||
return V761_PACKET_PERIOD;
|
||||
return packet_period;
|
||||
}
|
||||
|
||||
void V761_init(void)
|
||||
{
|
||||
V761_initialize_txid();
|
||||
if(sub_protocol == V761_TOPRC)
|
||||
{
|
||||
memcpy(rx_id,(uint8_t*)"\x20\x21\x05\x0A",4);
|
||||
packet_period = TOPRC_PACKET_PERIOD;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(rx_id,(uint8_t*)"\x34\x43\x10\x10",4);
|
||||
packet_period = V761_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
bind_counter = V761_BIND_COUNT;
|
||||
@@ -223,7 +248,7 @@ void V761_init(void)
|
||||
XN297_SetTXAddr(rx_tx_addr, 4);
|
||||
phase = V761_DATA;
|
||||
}
|
||||
|
||||
|
||||
V761_RF_init();
|
||||
hopping_frequency_no = 0;
|
||||
packet_count = 0;
|
||||
|
||||
@@ -26,14 +26,15 @@
|
||||
#define V911S_PACKET_SIZE 16
|
||||
#define V911S_RF_BIND_CHANNEL 35
|
||||
#define V911S_NUM_RF_CHANNELS 8
|
||||
#define V911S_BIND_COUNT 200
|
||||
#define V911S_BIND_COUNT 800
|
||||
|
||||
// flags going to packet[1]
|
||||
#define V911S_FLAG_EXPERT 0x04
|
||||
#define E119_FLAG_EXPERT 0x08
|
||||
#define E119_FLAG_EXPERT 0x08 //0x00 low, 0x08 high
|
||||
#define E119_FLAG_CALIB 0x40
|
||||
// flags going to packet[2]
|
||||
#define V911S_FLAG_CALIB 0x01
|
||||
#define A220_FLAG_6G3D 0x04
|
||||
|
||||
static void __attribute__((unused)) V911S_send_packet()
|
||||
{
|
||||
@@ -66,12 +67,15 @@ static void __attribute__((unused)) V911S_send_packet()
|
||||
memset(packet+1, 0x00, V911S_PACKET_SIZE - 1);
|
||||
if(sub_protocol==V911S_STD)
|
||||
{
|
||||
packet[ 1]=V911S_FLAG_EXPERT; // short press on left button
|
||||
packet[ 1]=GET_FLAG(!CH6_SW,V911S_FLAG_EXPERT); // short press on left button
|
||||
packet[ 2]=GET_FLAG(CH5_SW,V911S_FLAG_CALIB); // long press on right button
|
||||
}
|
||||
else
|
||||
packet[ 1]=E119_FLAG_EXPERT // short press on left button
|
||||
|GET_FLAG(CH5_SW,E119_FLAG_CALIB); // short press on right button
|
||||
else//E119
|
||||
{
|
||||
packet[ 1]=GET_FLAG(!CH6_SW,E119_FLAG_EXPERT) // short press on left button
|
||||
|GET_FLAG( CH5_SW,E119_FLAG_CALIB); // short press on right button
|
||||
packet[ 2]=GET_FLAG( CH7_SW,A220_FLAG_6G3D); // short press on right button
|
||||
}
|
||||
|
||||
//packet[3..6]=trims TAER signed
|
||||
uint16_t ch=convert_channel_16b_limit(THROTTLE ,0,0x7FF);
|
||||
@@ -90,7 +94,7 @@ static void __attribute__((unused)) V911S_send_packet()
|
||||
packet[12] = ch>>5;
|
||||
}
|
||||
else
|
||||
{
|
||||
{//E119
|
||||
ch=0x7FF-ch;
|
||||
packet[ 9]|= ch<<6;
|
||||
packet[10] = ch>>2;
|
||||
@@ -103,7 +107,7 @@ static void __attribute__((unused)) V911S_send_packet()
|
||||
|
||||
if(sub_protocol==V911S_STD)
|
||||
XN297_WritePayload(packet, V911S_PACKET_SIZE);
|
||||
else
|
||||
else//E119
|
||||
XN297_WriteEnhancedPayload(packet, V911S_PACKET_SIZE, IS_BIND_IN_PROGRESS?0:1);
|
||||
|
||||
XN297_SetPower(); // Set tx_power
|
||||
@@ -115,7 +119,7 @@ static void __attribute__((unused)) V911S_RF_init()
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_250K);
|
||||
if(sub_protocol==V911S_STD)
|
||||
XN297_SetTXAddr((uint8_t *)"KNBND",5); // V911S Bind address
|
||||
else
|
||||
else//E119
|
||||
XN297_SetTXAddr((uint8_t *)"XPBND",5); // E119 Bind address
|
||||
XN297_HoppingCalib(V911S_NUM_RF_CHANNELS); // Calibrate all channels
|
||||
XN297_RFChannel(V911S_RF_BIND_CHANNEL); // Set bind channel
|
||||
@@ -171,8 +175,7 @@ void V911S_init(void)
|
||||
rf_ch_num=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//E119
|
||||
{//E119
|
||||
rx_tx_addr[0]=0x30;
|
||||
rx_tx_addr[1]=0xFF;
|
||||
rx_tx_addr[2]=0xD1;
|
||||
|
||||
@@ -236,28 +236,29 @@
|
||||
#define CC2500_INSTALLED
|
||||
#define NRF24L01_INSTALLED
|
||||
#define SX1276_INSTALLED
|
||||
#undef ENABLE_PPM
|
||||
#undef SEND_CPPM
|
||||
#undef ENABLE_PPM
|
||||
#undef SEND_CPPM
|
||||
#endif
|
||||
|
||||
//Make sure protocols are selected correctly
|
||||
#ifndef A7105_INSTALLED
|
||||
#undef AFHDS2A_A7105_INO
|
||||
#undef AFHDS2A_RX_A7105_INO
|
||||
#undef BUGS_A7105_INO
|
||||
#undef FLYSKY_A7105_INO
|
||||
#undef HEIGHT_A7105_INO
|
||||
#undef HUBSAN_A7105_INO
|
||||
#undef JOYSWAY_A7105_INO
|
||||
#undef KYOSHO_A7105_INO
|
||||
#undef PELIKAN_A7105_INO
|
||||
#undef WFLY2_A7105_INO
|
||||
#undef AFHDS2A_A7105_INO
|
||||
#undef AFHDS2A_RX_A7105_INO
|
||||
#undef BUGS_A7105_INO
|
||||
#undef FLYSKY_A7105_INO
|
||||
#undef HEIGHT_A7105_INO
|
||||
#undef HUBSAN_A7105_INO
|
||||
#undef JOYSWAY_A7105_INO
|
||||
#undef KYOSHO_A7105_INO
|
||||
#undef PELIKAN_A7105_INO
|
||||
#undef WFLY2_A7105_INO
|
||||
#endif
|
||||
#ifndef CYRF6936_INSTALLED
|
||||
#undef DEVO_CYRF6936_INO
|
||||
#undef DSM_CYRF6936_INO
|
||||
#undef DSM_RX_CYRF6936_INO
|
||||
#undef E010R5_CYRF6936_INO
|
||||
#undef E01X_CYRF6936_INO
|
||||
#undef E129_CYRF6936_INO
|
||||
#undef J6PRO_CYRF6936_INO
|
||||
#undef LOSI_CYRF6936_INO
|
||||
@@ -295,11 +296,10 @@
|
||||
#undef CX10_NRF24L01_INO
|
||||
#undef DM002_NRF24L01_INO
|
||||
#undef E016H_NRF24L01_INO
|
||||
#undef E01X_NRF24L01_INO
|
||||
#undef ESKY_NRF24L01_INO
|
||||
#undef ESKY150_NRF24L01_INO
|
||||
#undef FQ777_NRF24L01_INO
|
||||
#undef FX816_NRF24L01_INO
|
||||
#undef FX_NRF24L01_INO
|
||||
#undef FY326_NRF24L01_INO
|
||||
#undef GW008_NRF24L01_INO
|
||||
#undef H8_3D_NRF24L01_INO
|
||||
@@ -307,6 +307,7 @@
|
||||
#undef HONTAI_NRF24L01_INO
|
||||
#undef JJRC345_NRF24L01_INO
|
||||
#undef KN_NRF24L01_INO
|
||||
#undef KYOSHO2_NRF24L01_INO
|
||||
#undef LOLI_NRF24L01_INO
|
||||
#undef MOULDKG_NRF24L01_INO
|
||||
#undef NCC1701_NRF24L01_INO
|
||||
@@ -318,6 +319,7 @@
|
||||
#undef TIGER_NRF24L01_INO
|
||||
#undef V2X2_NRF24L01_INO
|
||||
#undef V761_NRF24L01_INO
|
||||
#undef XERALL_NRF24L01_INO
|
||||
#undef YD717_NRF24L01_INO
|
||||
#undef ZSX_NRF24L01_INO
|
||||
#endif
|
||||
@@ -333,6 +335,11 @@
|
||||
#undef V911S_CCNRF_INO
|
||||
#undef XK_CCNRF_INO
|
||||
#endif
|
||||
#if not defined(STM32_BOARD)
|
||||
//RF2500 emulation does not work on atmega...
|
||||
#undef E010R5_CYRF6936_INO
|
||||
#undef E129_CYRF6936_INO
|
||||
#endif
|
||||
#if not defined(STM32_BOARD)
|
||||
#undef SX1276_INSTALLED
|
||||
#endif
|
||||
@@ -383,6 +390,7 @@
|
||||
#undef MT99XX_HUB_TELEMETRY
|
||||
#undef MLINK_HUB_TELEMETRY
|
||||
#undef MLINK_FW_TELEMETRY
|
||||
#undef MULTI_CONFIG_INO
|
||||
#else
|
||||
#if not defined(SCANNER_CC2500_INO) || not defined(SCANNER_TELEMETRY)
|
||||
#undef SCANNER_TELEMETRY
|
||||
@@ -466,7 +474,7 @@
|
||||
//protocols using FRSKYD user frames
|
||||
#undef HUB_TELEMETRY
|
||||
#endif
|
||||
#if not defined(HOTT_FW_TELEMETRY) && not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BUGS_HUB_TELEMETRY) && not defined(NCC1701_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(RLINK_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY) && not defined(SCANNER_TELEMETRY) && not defined(FRSKY_RX_TELEMETRY) && not defined(AFHDS2A_RX_TELEMETRY) && not defined(BAYANG_RX_TELEMETRY) && not defined(DEVO_HUB_TELEMETRY) && not defined(PROPEL_HUB_TELEMETRY) && not defined(OMP_HUB_TELEMETRY) && not defined(WFLY2_HUB_TELEMETRY) && not defined(LOLI_HUB_TELEMETRY) && not defined(MLINK_HUB_TELEMETRY) && not defined(MLINK_FW_TELEMETRY) && not defined(MT99XX_HUB_TELEMETRY)
|
||||
#if not defined(HOTT_FW_TELEMETRY) && not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BUGS_HUB_TELEMETRY) && not defined(NCC1701_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(RLINK_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY) && not defined(SCANNER_TELEMETRY) && not defined(FRSKY_RX_TELEMETRY) && not defined(AFHDS2A_RX_TELEMETRY) && not defined(BAYANG_RX_TELEMETRY) && not defined(DEVO_HUB_TELEMETRY) && not defined(PROPEL_HUB_TELEMETRY) && not defined(OMP_HUB_TELEMETRY) && not defined(WFLY2_HUB_TELEMETRY) && not defined(LOLI_HUB_TELEMETRY) && not defined(MLINK_HUB_TELEMETRY) && not defined(MLINK_FW_TELEMETRY) && not defined(MT99XX_HUB_TELEMETRY) && not defined(MULTI_CONFIG_INO)
|
||||
#undef TELEMETRY
|
||||
#undef INVERT_TELEMETRY
|
||||
#undef MULTI_TELEMETRY
|
||||
|
||||
283
Multiprotocol/XERALL_nrf24l01.ino
Normal file
283
Multiprotocol/XERALL_nrf24l01.ino
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
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 XERALL
|
||||
|
||||
#if defined(XERALL_NRF24L01_INO)
|
||||
|
||||
#include "iface_xn297.h"
|
||||
|
||||
//#define XERALL_ORIGINAL_ID
|
||||
|
||||
#define XERALL_PACKET_PERIOD 2500 //2046
|
||||
#define XERALL_PACKET_SIZE 10
|
||||
#define XERALL_NUM_RF_CHANNELS 4
|
||||
#define XERALL_BIND_COUNT 15000 //about 30sec
|
||||
|
||||
// flags going to packet[6]
|
||||
#define XERALL_FLAG_VIDEO 0x80
|
||||
#define XERALL_FLAG_PHOTO 0x40
|
||||
// flags going to packet[7]
|
||||
#define XERALL_FLAG_RATE 0x80
|
||||
#define XERALL_FLAG_FLIGHT_GROUND 0x20
|
||||
#define XERALL_FLAG_HEADING_HOLD 0x04
|
||||
#define XERALL_FLAG_ONE_BUTTON 0x02
|
||||
|
||||
enum {
|
||||
XERALL_DATA,
|
||||
XERALL_RX,
|
||||
XERALL_CHECK,
|
||||
};
|
||||
|
||||
static void __attribute__((unused)) XERALL_send_packet()
|
||||
{
|
||||
if(bind_phase)
|
||||
bind_phase--;
|
||||
else
|
||||
{ // Hopping frequency
|
||||
if(packet_sent==0)
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no);
|
||||
hopping_frequency_no++;
|
||||
hopping_frequency_no &= (XERALL_NUM_RF_CHANNELS-1);
|
||||
}
|
||||
packet_sent++;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
if(packet_sent > 24)
|
||||
packet_sent=0; // Hopp after 25 packets
|
||||
}
|
||||
else
|
||||
{
|
||||
if(packet_sent > 18)
|
||||
packet_sent = 0; // Hopp after 19 packets
|
||||
}
|
||||
|
||||
// Packet
|
||||
if(IS_BIND_IN_PROGRESS && (bind_counter&0x10)) // Alternate bind and normal packets
|
||||
{ // Bind packet: 01 56 06 23 00 13 20 40 02 00 and 01 F9 58 31 00 13 20 40 05 00
|
||||
if(packet[0] != 0x01)
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\x01\x01\x01\x01\x09", 5); // Bind address
|
||||
XN297_SetRXAddr((uint8_t *)"\x01\x01\x01\x01\x09", XERALL_PACKET_SIZE);
|
||||
}
|
||||
packet[0] = 0x01;
|
||||
for(uint8_t i=0;i<5;i++)
|
||||
packet[i+1] = rx_tx_addr[i];
|
||||
packet[9] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(packet[0] != 0x08)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
XN297_SetRXAddr(rx_tx_addr, XERALL_PACKET_SIZE);
|
||||
}
|
||||
// Normal packet: 08 32 7C 1C 20 20 20 40 0A 00
|
||||
packet[0] = 0x08;
|
||||
//Throttle
|
||||
packet[1] = convert_channel_16b_limit(THROTTLE ,0,0x32)<<1; //00..64 but only even values
|
||||
//Rudder
|
||||
packet[2] = (0xFF-convert_channel_8b(RUDDER))&0xF8; //F8..00 -> 5 bits
|
||||
//Elevator
|
||||
uint8_t ch = convert_channel_8b(ELEVATOR)>>3;
|
||||
packet[2] |= ch>>2; //00..07 -> 3 bits high
|
||||
packet[3] = ch<<6; //00,40,80,C0 -> 2 bits low
|
||||
//Aileron
|
||||
packet[3] |= ((0xFF-convert_channel_8b(AILERON))>>3)<<1; //5 bits
|
||||
|
||||
//Trim Rudder 0x00..0x20..0x3F
|
||||
packet[4] = convert_channel_8b(CH11)>>2;
|
||||
//Trim Elevator 0x00..0x20..0x3F
|
||||
packet[5] = convert_channel_8b(CH12)>>2;
|
||||
}
|
||||
}
|
||||
|
||||
// Flags + Trim Aileron
|
||||
//packet[6]
|
||||
// 0x20 -> 0x60 short press photo/video => |0x40 -> momentary
|
||||
// 0x20 -> 0xA0 long press photo/video => |0x80 -> toggle
|
||||
// 0xA0 -> 0xE0 short press photo/video => |0x40 -> momentary
|
||||
// 0x20 -> 0x00..0x20..0x3F Trim Aileron
|
||||
packet[6] = (convert_channel_8b(CH13)>>2)
|
||||
| GET_FLAG(CH9_SW,XERALL_FLAG_PHOTO)
|
||||
| GET_FLAG(CH10_SW,XERALL_FLAG_VIDEO);
|
||||
|
||||
// Flags
|
||||
// 0x40 -> 0x44 Heading hold mode => |0x04 -> toggle
|
||||
// 0x40 -> 0xC0 High/low speed => |0x80 -> toggle
|
||||
// 0x40 -> 0x42 One button takeoff/landing/emergency => |0x02 -> toggle
|
||||
// 0x40 -> 0x60 Flight/Ground => |0x20 -> toggle
|
||||
packet[7] = 0x40
|
||||
| GET_FLAG(CH5_SW,XERALL_FLAG_FLIGHT_GROUND)
|
||||
| GET_FLAG(CH6_SW,XERALL_FLAG_ONE_BUTTON)
|
||||
| GET_FLAG(CH7_SW,XERALL_FLAG_RATE)
|
||||
| GET_FLAG(CH8_SW,XERALL_FLAG_HEADING_HOLD);
|
||||
|
||||
// CRC
|
||||
uint8_t sum = 0;
|
||||
for(uint8_t i=1;i<8;i++)
|
||||
sum += packet[i];
|
||||
packet[8] = sum & 0x0F;
|
||||
|
||||
//0x00 -> 0x1A on first telemetry packet received
|
||||
//packet[9] = 0x00;
|
||||
|
||||
// Send
|
||||
XN297_SetPower();
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WriteEnhancedPayload(packet, XERALL_PACKET_SIZE, 0);
|
||||
#if 0
|
||||
debug("H:%d,P:",hopping_frequency_no);
|
||||
for(uint8_t i=0; i<XERALL_PACKET_SIZE; i++)
|
||||
debug("%02X ", packet[i]);
|
||||
debugln();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XERALL_RF_init()
|
||||
{
|
||||
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) XERALL_initialize_txid()
|
||||
{
|
||||
rx_tx_addr[0] = rx_tx_addr[3];
|
||||
#ifdef XERALL_ORIGINAL_ID
|
||||
// Pascal
|
||||
if(RX_num)
|
||||
{
|
||||
rx_tx_addr[0]=0x56;
|
||||
rx_tx_addr[1]=0x06;
|
||||
rx_tx_addr[2]=0x23;
|
||||
rx_tx_addr[3]=0x00;
|
||||
rx_tx_addr[4]=0x13;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Alfons
|
||||
rx_tx_addr[0]=0xF9;
|
||||
rx_tx_addr[1]=0x58;
|
||||
rx_tx_addr[2]=0x31;
|
||||
rx_tx_addr[3]=0x00;
|
||||
rx_tx_addr[4]=0x13;
|
||||
}
|
||||
#endif
|
||||
rx_tx_addr[3] = 0x00;
|
||||
rx_tx_addr[4] = 0x13;
|
||||
hopping_frequency[0] = 56; // 0x38
|
||||
hopping_frequency[1] = 46; // 0x2E
|
||||
hopping_frequency[2] = 61; // 0x3D
|
||||
hopping_frequency[3] = 51; // 0x33
|
||||
}
|
||||
|
||||
#define XERALL_WRITE_WAIT 600
|
||||
#define XERALL_CHECK_WAIT 300
|
||||
uint16_t XERALL_callback()
|
||||
{
|
||||
static uint8_t wait = 0;
|
||||
switch(phase)
|
||||
{
|
||||
case XERALL_DATA:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(XERALL_PACKET_PERIOD);
|
||||
#endif
|
||||
if (bind_counter == 0)
|
||||
BIND_DONE;
|
||||
else
|
||||
bind_counter--;
|
||||
XERALL_send_packet();
|
||||
phase++;
|
||||
return XERALL_WRITE_WAIT;
|
||||
case XERALL_RX:
|
||||
// switch to RX mode
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
phase++;
|
||||
return XERALL_PACKET_PERIOD-XERALL_WRITE_WAIT-XERALL_CHECK_WAIT;
|
||||
case XERALL_CHECK:
|
||||
if( XN297_IsRX() )
|
||||
{ // RX fifo data ready
|
||||
uint8_t len = XN297_ReadEnhancedPayload(packet_in, XERALL_PACKET_SIZE);
|
||||
if(len != 255) // CRC OK
|
||||
{
|
||||
#if 0
|
||||
debug("RX(%d):",len);
|
||||
for(uint8_t i=0; i<len; i++)
|
||||
debug("%02X ", packet_in[i]);
|
||||
debugln();
|
||||
#endif
|
||||
if(len == XERALL_PACKET_SIZE && packet_in[0] == 0x11)
|
||||
{ // Request for ack packet
|
||||
// Ack the telem packet
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(TX_EN);
|
||||
XN297_WriteEnhancedPayload(packet, 0, 0);
|
||||
|
||||
packet[9] = packet_in[9];
|
||||
if(packet[0] == 0x01) // Last packet sent was a bind packet
|
||||
{// Build bind response
|
||||
packet[0] = 0x02;
|
||||
for(uint8_t i=1; i<5; i++)
|
||||
packet[i] = packet_in[i]; // Tank ID???
|
||||
bind_phase = 14;
|
||||
XN297_SetTXAddr(rx_tx_addr, 5);
|
||||
}
|
||||
wait = 0;
|
||||
phase = XERALL_DATA;
|
||||
break;
|
||||
}
|
||||
else if(len == XERALL_PACKET_SIZE && packet_in[0] == 0x12)
|
||||
{
|
||||
BIND_DONE;
|
||||
bind_phase = 0;
|
||||
wait = 0;
|
||||
}
|
||||
else if(len == 0)
|
||||
wait = 5; // The quad wants to talk let's pause sending data...
|
||||
}
|
||||
if(wait)
|
||||
{ // switch to RX mode
|
||||
XN297_SetTxRxMode(TXRX_OFF);
|
||||
XN297_SetTxRxMode(RX_EN);
|
||||
}
|
||||
}
|
||||
if(wait)
|
||||
{
|
||||
wait--;
|
||||
break;
|
||||
}
|
||||
phase = XERALL_DATA;
|
||||
return XERALL_CHECK_WAIT;
|
||||
}
|
||||
return XERALL_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
void XERALL_init(void)
|
||||
{
|
||||
XERALL_initialize_txid();
|
||||
|
||||
XERALL_RF_init();
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
bind_counter = XERALL_BIND_COUNT;
|
||||
hopping_frequency_no=0;
|
||||
packet_sent = 0;
|
||||
bind_phase = 0;
|
||||
memset(packet, 0, XERALL_PACKET_SIZE);
|
||||
phase = XERALL_DATA;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -119,29 +119,34 @@ static boolean __attribute__((unused)) XN297Dump_process_packet(void)
|
||||
}
|
||||
|
||||
//Try enhanced payload
|
||||
crc = 0xb5d2;
|
||||
uint16_t crc_save = 0xb5d2;
|
||||
packet_length=0;
|
||||
for (uint8_t i = 0; i < XN297DUMP_MAX_PACKET_LEN-XN297DUMP_CRC_LENGTH; i++)
|
||||
for (uint8_t i = 0; i < XN297DUMP_MAX_PACKET_LEN-XN297DUMP_CRC_LENGTH; i++)
|
||||
{
|
||||
packet_sc[i]=packet[i]^xn297_scramble[i];
|
||||
crc = crc_save;
|
||||
crc16_update( packet[i], 8);
|
||||
crc_save = crc;
|
||||
crc16_update( packet[i+1] & 0xC0, 2);
|
||||
crcxored=(packet[i+1]<<10)|(packet[i+2]<<2)|(packet[i+3]>>6) ;
|
||||
if((crc ^ pgm_read_word(&xn297_crc_xorout_scrambled_enhanced[i - 3])) == crcxored)
|
||||
{ // Found a valid CRC for the enhanced payload mode
|
||||
packet_length=i;
|
||||
scramble=true;
|
||||
i++;
|
||||
packet_sc[i]=packet[i]^xn297_scramble[i];
|
||||
memcpy(packet_un,packet_sc,packet_length+2); // unscramble packet
|
||||
break;
|
||||
}
|
||||
if((crc ^ pgm_read_word(&xn297_crc_xorout_enhanced[i - 3])) == crcxored)
|
||||
{ // Found a valid CRC for the enhanced payload mode
|
||||
packet_length=i;
|
||||
scramble=false;
|
||||
memcpy(packet_un,packet,packet_length+2); // packet is unscrambled
|
||||
break;
|
||||
if(i>=3)
|
||||
{
|
||||
if((crc ^ pgm_read_word(&xn297_crc_xorout_scrambled_enhanced[i - 3])) == crcxored)
|
||||
{ // Found a valid CRC for the enhanced payload mode
|
||||
packet_length=i;
|
||||
scramble=true;
|
||||
i++;
|
||||
packet_sc[i]=packet[i]^xn297_scramble[i];
|
||||
memcpy(packet_un,packet_sc,packet_length+2); // unscramble packet
|
||||
break;
|
||||
}
|
||||
if((crc ^ pgm_read_word(&xn297_crc_xorout_enhanced[i - 3])) == crcxored)
|
||||
{ // Found a valid CRC for the enhanced payload mode
|
||||
packet_length=i;
|
||||
scramble=false;
|
||||
memcpy(packet_un,packet,packet_length+2); // packet is unscrambled
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(packet_length!=0)
|
||||
@@ -324,7 +329,7 @@ static uint16_t XN297Dump_callback()
|
||||
switch(bitrate)
|
||||
{
|
||||
case XN297DUMP_250K:
|
||||
XN297_Configure(XN297_CRCEN, scramble?XN297_SCRAMBLED:XN297_UNSCRAMBLED, XN297_250K);
|
||||
XN297_Configure(XN297_CRCEN, scramble?XN297_SCRAMBLED:XN297_UNSCRAMBLED, XN297_250K, true);
|
||||
debug("250K");
|
||||
break;
|
||||
case XN297DUMP_2M:
|
||||
@@ -426,9 +431,12 @@ static uint16_t XN297Dump_callback()
|
||||
{ // RX fifo data ready
|
||||
// if(NRF24L01_ReadReg(NRF24L01_09_CD))
|
||||
{
|
||||
boolean res;
|
||||
uint8_t res;
|
||||
if(enhanced)
|
||||
{
|
||||
res=XN297_ReadEnhancedPayload(packet, packet_length);
|
||||
res++;
|
||||
}
|
||||
else
|
||||
res=XN297_ReadPayload(packet, packet_length);
|
||||
if(res)
|
||||
@@ -521,9 +529,12 @@ static uint16_t XN297Dump_callback()
|
||||
{ // RX fifo data ready
|
||||
//if(NRF24L01_ReadReg(NRF24L01_09_CD))
|
||||
{
|
||||
boolean res;
|
||||
uint8_t res;
|
||||
if(enhanced)
|
||||
{
|
||||
res=XN297_ReadEnhancedPayload(packet, packet_length);
|
||||
res++;
|
||||
}
|
||||
else
|
||||
res=XN297_ReadPayload(packet, packet_length);
|
||||
if(res)
|
||||
@@ -567,9 +578,12 @@ static uint16_t XN297Dump_callback()
|
||||
{ // RX fifo data ready
|
||||
//if(NRF24L01_ReadReg(NRF24L01_09_CD))
|
||||
{
|
||||
boolean res;
|
||||
uint8_t res;
|
||||
if(enhanced)
|
||||
{
|
||||
res=XN297_ReadEnhancedPayload(packet, packet_length);
|
||||
res++;
|
||||
}
|
||||
else
|
||||
res=XN297_ReadPayload(packet, packet_length);
|
||||
if(res)
|
||||
@@ -595,12 +609,12 @@ static uint16_t XN297Dump_callback()
|
||||
{
|
||||
if(phase==0)
|
||||
{
|
||||
address_length=5;
|
||||
memcpy(rx_tx_addr, (uint8_t *)"\x61\x94\x17\x27\xED", address_length); //"\xA3\x05\x22\xC1""\x5A\x20\x12\xAC"
|
||||
address_length=3;
|
||||
memcpy(rx_tx_addr, (uint8_t *)"\xBD\x54\x78", address_length); //"\x62\xE6\xBD\x54\x78"
|
||||
|
||||
bitrate=XN297DUMP_250K;
|
||||
packet_length=32;
|
||||
hopping_frequency_no=54; //bind ?, normal 60
|
||||
bitrate=XN297DUMP_1M;
|
||||
packet_length=7;
|
||||
hopping_frequency_no=40; //bind ?, normal 40
|
||||
|
||||
NRF24L01_Initialize();
|
||||
NRF24L01_SetTxRxMode(TXRX_OFF);
|
||||
@@ -608,7 +622,7 @@ static uint16_t XN297Dump_callback()
|
||||
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, address_length-2); // RX/TX address length
|
||||
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, address_length); // set up RX address
|
||||
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // Enable rx pipe 0
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency_no);
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, option); //hopping_frequency_no);
|
||||
|
||||
debug("NRF dump, len=%d, rf=%d, address length=%d, bitrate=",packet_length,hopping_frequency_no,address_length);
|
||||
switch(bitrate)
|
||||
@@ -704,6 +718,7 @@ static uint16_t XN297Dump_callback()
|
||||
NRF24L01_FlushRx();
|
||||
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX)); // _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) |
|
||||
}
|
||||
NRF24L01_WriteReg(NRF24L01_05_RF_CH, option); //hopping_frequency_no);
|
||||
}
|
||||
}
|
||||
else if(sub_protocol == XN297DUMP_CC2500)
|
||||
|
||||
@@ -53,7 +53,7 @@ const uint16_t xn297_crc_xorout_enhanced[] = {
|
||||
0xABFC, 0xE68E, 0x0DE7, 0x28A2, 0x1965 };
|
||||
#endif
|
||||
|
||||
static bool __attribute__((unused)) XN297_Configure(bool crc_en, bool scramble_en, bool bitrate)
|
||||
static bool __attribute__((unused)) XN297_Configure(bool crc_en, bool scramble_en, bool bitrate, bool force_nrf)
|
||||
{
|
||||
xn297_crc = crc_en;
|
||||
xn297_scramble_enabled = scramble_en;
|
||||
@@ -61,7 +61,7 @@ static bool __attribute__((unused)) XN297_Configure(bool crc_en, bool scramble_e
|
||||
xn297_rf = XN297_NRF;
|
||||
|
||||
#if defined(NRF24L01_INSTALLED) and defined(CC2500_INSTALLED)
|
||||
if(bitrate == XN297_1M)
|
||||
if(bitrate == XN297_1M || force_nrf)
|
||||
xn297_rf = XN297_NRF; // Use NRF24L01
|
||||
else
|
||||
xn297_rf = XN297_CC2500; // Use CC2500
|
||||
@@ -292,7 +292,7 @@ static void __attribute__((unused)) XN297_WriteEnhancedPayload(uint8_t* msg, uin
|
||||
uint8_t last = 0;
|
||||
static uint8_t pid=0;
|
||||
|
||||
if (xn297_rf == XN297_NRF && xn297_addr_len < 4 && xn297_rf == XN297_NRF)
|
||||
if (xn297_rf == XN297_NRF && xn297_addr_len < 4)
|
||||
{ // If address length (which is defined by receiver address length) is less than 4 the TX address can't fit the preamble, so the last byte goes here
|
||||
buf[last++] = 0x55;
|
||||
}
|
||||
@@ -314,22 +314,25 @@ static void __attribute__((unused)) XN297_WriteEnhancedPayload(uint8_t* msg, uin
|
||||
buf[last] = (pid << 7) | (noack << 6);
|
||||
|
||||
// payload
|
||||
buf[last]|= bit_reverse(msg[0]) >> 2; // first 6 bit of payload
|
||||
if(xn297_scramble_enabled)
|
||||
buf[last] ^= xn297_scramble[scramble_index++];
|
||||
|
||||
for (uint8_t i = 0; i < len-1; ++i)
|
||||
if(len)
|
||||
{
|
||||
last++;
|
||||
buf[last] = (bit_reverse(msg[i]) << 6) | (bit_reverse(msg[i+1]) >> 2);
|
||||
buf[last]|= bit_reverse(msg[0]) >> 2; // first 6 bit of payload
|
||||
if(xn297_scramble_enabled)
|
||||
buf[last] ^= xn297_scramble[scramble_index++];
|
||||
}
|
||||
|
||||
last++;
|
||||
buf[last] = bit_reverse(msg[len-1]) << 6; // last 2 bit of payload
|
||||
if(xn297_scramble_enabled)
|
||||
buf[last] ^= xn297_scramble[scramble_index++] & 0xc0;
|
||||
for (uint8_t i = 0; i < len-1; ++i)
|
||||
{
|
||||
last++;
|
||||
buf[last] = (bit_reverse(msg[i]) << 6) | (bit_reverse(msg[i+1]) >> 2);
|
||||
if(xn297_scramble_enabled)
|
||||
buf[last] ^= xn297_scramble[scramble_index++];
|
||||
}
|
||||
|
||||
last++;
|
||||
buf[last] = bit_reverse(msg[len-1]) << 6; // last 2 bit of payload
|
||||
if(xn297_scramble_enabled)
|
||||
buf[last] ^= xn297_scramble[scramble_index++] & 0xc0;
|
||||
}
|
||||
|
||||
// crc
|
||||
if (xn297_crc)
|
||||
@@ -444,7 +447,9 @@ static uint8_t __attribute__((unused)) XN297_ReadEnhancedPayload(uint8_t* msg, u
|
||||
if(xn297_scramble_enabled)
|
||||
pcf_size ^= xn297_scramble[xn297_addr_len];
|
||||
pcf_size = pcf_size >> 1;
|
||||
for(int i=0; i<len; i++)
|
||||
if(pcf_size>32)
|
||||
return 255; // Error
|
||||
for(uint8_t i=0; i< pcf_size; i++)
|
||||
{
|
||||
msg[i] = bit_reverse((buffer[i+1] << 2) | (buffer[i+2] >> 6));
|
||||
if(xn297_scramble_enabled)
|
||||
@@ -461,20 +466,20 @@ static uint8_t __attribute__((unused)) XN297_ReadEnhancedPayload(uint8_t* msg, u
|
||||
for (uint8_t i = 0; i < xn297_addr_len; ++i)
|
||||
crc16_update( xn297_rx_addr[xn297_addr_len-i-1], 8);
|
||||
//process payload
|
||||
for (uint8_t i = 0; i < len+1; ++i)
|
||||
for (uint8_t i = 0; i < pcf_size+1; ++i)
|
||||
crc16_update( buffer[i], 8);
|
||||
crc16_update( buffer[len+1] & 0xc0, 2);
|
||||
crc16_update( buffer[pcf_size+1] & 0xc0, 2);
|
||||
//xorout
|
||||
if (xn297_scramble_enabled)
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled_enhanced[xn297_addr_len-3+len]);
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled_enhanced[xn297_addr_len-3+pcf_size]);
|
||||
#ifdef XN297DUMP_NRF24L01_INO
|
||||
else
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_enhanced[xn297_addr_len - 3 + len]);
|
||||
crc ^= pgm_read_word(&xn297_crc_xorout_enhanced[xn297_addr_len - 3 + pcf_size]);
|
||||
#endif
|
||||
uint16_t crcxored=(buffer[len+1]<<10)|(buffer[len+2]<<2)|(buffer[len+3]>>6) ;
|
||||
uint16_t crcxored=(buffer[pcf_size+1]<<10)|(buffer[pcf_size+2]<<2)|(buffer[pcf_size+3]>>6) ;
|
||||
if( crc == crcxored)
|
||||
return pcf_size; // CRC OK
|
||||
return 0; // CRC NOK
|
||||
return pcf_size; // CRC OK
|
||||
return 255; // CRC NOK
|
||||
}
|
||||
|
||||
static bool __attribute__((unused)) XN297_IsPacketSent()
|
||||
|
||||
@@ -188,6 +188,7 @@
|
||||
#define DSM_CYRF6936_INO
|
||||
#define DSM_RX_CYRF6936_INO
|
||||
#define E010R5_CYRF6936_INO
|
||||
#define E01X_CYRF6936_INO
|
||||
#define E129_CYRF6936_INO
|
||||
#define J6PRO_CYRF6936_INO
|
||||
#define LOSI_CYRF6936_INO
|
||||
@@ -220,16 +221,15 @@
|
||||
#define BAYANG_RX_NRF24L01_INO
|
||||
#define BUGSMINI_NRF24L01_INO
|
||||
#define CABELL_NRF24L01_INO
|
||||
#define CFLIE_NRF24L01_INO
|
||||
//#define CFLIE_NRF24L01_INO
|
||||
#define CG023_NRF24L01_INO
|
||||
#define CX10_NRF24L01_INO //Include Q2X2 protocol
|
||||
#define DM002_NRF24L01_INO
|
||||
#define E016H_NRF24L01_INO
|
||||
#define E01X_NRF24L01_INO
|
||||
#define ESKY_NRF24L01_INO
|
||||
#define ESKY150_NRF24L01_INO
|
||||
#define FQ777_NRF24L01_INO
|
||||
#define FX816_NRF24L01_INO
|
||||
#define FX_NRF24L01_INO
|
||||
#define FY326_NRF24L01_INO
|
||||
#define GW008_NRF24L01_INO
|
||||
#define HISKY_NRF24L01_INO
|
||||
@@ -237,8 +237,9 @@
|
||||
#define H8_3D_NRF24L01_INO
|
||||
#define JJRC345_NRF24L01_INO
|
||||
#define KN_NRF24L01_INO
|
||||
#define KYOSHO2_NRF24L01_INO
|
||||
#define LOLI_NRF24L01_INO
|
||||
#define MOULDKG_NRF24L01_INO
|
||||
//#define MOULDKG_NRF24L01_INO
|
||||
#define NCC1701_NRF24L01_INO
|
||||
#define POTENSIC_NRF24L01_INO
|
||||
#define PROPEL_NRF24L01_INO
|
||||
@@ -248,6 +249,7 @@
|
||||
#define TIGER_NRF24L01_INO
|
||||
#define V2X2_NRF24L01_INO
|
||||
#define V761_NRF24L01_INO
|
||||
#define XERALL_NRF24L01_INO
|
||||
#define YD717_NRF24L01_INO
|
||||
#define ZSX_NRF24L01_INO
|
||||
|
||||
@@ -255,7 +257,7 @@
|
||||
#define GD00X_CCNRF_INO
|
||||
#define KF606_CCNRF_INO
|
||||
#define MJXQ_CCNRF_INO
|
||||
#define MT99XX_CCNRF_INO
|
||||
#define MT99XX_CCNRF_INO //Include MT99XX2 protocol
|
||||
#define OMP_CCNRF_INO
|
||||
#define Q303_CCNRF_INO
|
||||
#define Q90C_CCNRF_INO
|
||||
@@ -292,9 +294,9 @@
|
||||
/**************************/
|
||||
/*** FAILSAFE SETTINGS ***/
|
||||
/**************************/
|
||||
//The following protocols are supporting failsafe: FrSkyX, Devo, WK2x01, Futaba/SFHSS, HISKY/HK310 and AFHDS2A
|
||||
//The following protocols are supporting failsafe: FrSkyX, FrSkyX2, FRSKYR9, Devo, WK2x01, Futaba/SFHSS, HISKY/HK310, HoTT, LOLI, MLINK, WFLY, WFLY2 and AFHDS2A
|
||||
//In Serial mode failsafe is configured on the radio itself.
|
||||
//In PPM mode and only after the module is up and fully operational, press the bind button for at least 5sec to send the current stick positions as failsafe to the RX.
|
||||
//In PPM mode and only after the module is up and fully operational, press the bind button for at least 5sec to send all the current channels positions as failsafe to the RX.
|
||||
//If you want to disable failsafe globally comment the line below using "//".
|
||||
#define FAILSAFE_ENABLE
|
||||
|
||||
@@ -548,6 +550,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
PPM_SBUS
|
||||
PWM_IB16
|
||||
PPM_IB16
|
||||
PWM_SB16
|
||||
PPM_SB16
|
||||
PROTO_AFHDS2A_RX
|
||||
NONE
|
||||
PROTO_ASSAN
|
||||
@@ -609,7 +613,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
E012
|
||||
E015
|
||||
PROTO_E129
|
||||
NONE
|
||||
E129_E129
|
||||
E129_C186
|
||||
PROTO_ESKY
|
||||
ESKY_STD
|
||||
ESKY_ET4
|
||||
@@ -662,8 +667,9 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
PROTO_FRSKY_RX
|
||||
FRSKY_RX
|
||||
FRSKY_CLONE
|
||||
PROTO_FX816
|
||||
NONE
|
||||
PROTO_FX
|
||||
FX816
|
||||
FX620
|
||||
PROTO_FY326
|
||||
FY326
|
||||
FY319
|
||||
@@ -709,13 +715,16 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
PROTO_JOYSWAY
|
||||
NONE
|
||||
PROTO_KF606
|
||||
NONE
|
||||
KF606_KF606
|
||||
KF606_MIG320
|
||||
PROTO_KN
|
||||
WLTOYS
|
||||
FEILUN
|
||||
PROTO_KYOSHO
|
||||
KYOSHO_FHSS
|
||||
KYOSHO_HYPE
|
||||
PROTO_KYOSHO2
|
||||
NONE
|
||||
PROTO_LOLI
|
||||
NONE
|
||||
PROTO_LOSI
|
||||
@@ -741,6 +750,9 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
FY805
|
||||
A180
|
||||
DRAGON
|
||||
F949G
|
||||
PROTO_MT99XX2
|
||||
PA18
|
||||
PROTO_NCC1701
|
||||
NONE
|
||||
PROTO_OMP
|
||||
@@ -815,6 +827,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
W6_6_1
|
||||
W6_HEL
|
||||
W6_HEL_I
|
||||
PROTO_XERALL
|
||||
NONE
|
||||
PROTO_XK
|
||||
X450
|
||||
X420
|
||||
|
||||
13
Multiprotocol/iface_hs6200.h
Normal file
13
Multiprotocol/iface_hs6200.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef _IFACE_HS6200_H_
|
||||
#define _IFACE_HS6200_H_
|
||||
|
||||
#include "iface_cyrf6936.h"
|
||||
|
||||
//HS6200
|
||||
static void __attribute__((unused)) HS6200_Init(bool);
|
||||
static void __attribute__((unused)) HS6200_SetTXAddr(const uint8_t*, uint8_t);
|
||||
static void __attribute__((unused)) HS6200_SendPayload(uint8_t*, uint8_t);
|
||||
#define HS6200_SetPower() CYRF_GFSK1M_SetPower()
|
||||
#define HS6200_RFChannel(X) CYRF_ConfigRFChannel(X)
|
||||
|
||||
#endif
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
//////////////
|
||||
// Functions
|
||||
static bool __attribute__((unused)) XN297_Configure(bool, bool, bool);
|
||||
static bool __attribute__((unused)) XN297_Configure(bool, bool, bool, bool force_nrf=false);
|
||||
static void __attribute__((unused)) XN297_SetTXAddr(const uint8_t*, uint8_t);
|
||||
static void __attribute__((unused)) XN297_SetRXAddr(const uint8_t*, uint8_t);
|
||||
static void __attribute__((unused)) XN297_SetTxRxMode(enum TXRX_State);
|
||||
|
||||
@@ -76,16 +76,16 @@ CFlie|38|CFlie||||||||NRF24L01|
|
||||
[DM002](Protocols_Details.md#DM002---33)|33|||||||||NRF24L01|XN297
|
||||
[DSM](Protocols_Details.md#DSM---6)|6|DSM2_1F|DSM2_2F|DSMX_1F|DSMX_2F|AUTO|DSMR_1F|||CYRF6936|
|
||||
[DSM_RX](Protocols_Details.md#DSM_RX---70)|70|Multi|CPPM|||||||CYRF6936|
|
||||
[E010R5](Protocols_Details.md#E010R5---81)|81|||||||||CYRF6936/NRF24L01|RF2500
|
||||
[E010R5](Protocols_Details.md#E010R5---81)|81|||||||||CYRF6936|RF2500
|
||||
[E016H](Protocols_Details.md#E016H---85)|85|||||||||NRF24L01|XN297
|
||||
[E016HV2](Protocols_Details.md#E016HV2---80)|80|||||||||CC2500/NRF24L01|unknown
|
||||
[E01X](Protocols_Details.md#E01X---45)|45|E012|E015|||||||NRF24L01|HS6200
|
||||
[E129](Protocols_Details.md#E129---83)|83|||||||||CYRF6936/NRF24L01|RF2500
|
||||
[E01X](Protocols_Details.md#E01X---45)|45|E012|E015|||||||CYRF6936|HS6200
|
||||
[E129](Protocols_Details.md#E129---83)|83|E129|C186|||||||CYRF6936|RF2500
|
||||
[ESky](Protocols_Details.md#ESKY---16)|16|ESky|ET4|||||||NRF24L01|
|
||||
[ESky150](Protocols_Details.md#ESKY150---35)|35|||||||||NRF24L01|
|
||||
[ESky150V2](Protocols_Details.md#ESKY150V2---69)|69|||||||||CC2500|NRF51822
|
||||
[Flysky](Protocols_Details.md#FLYSKY---1)|1|Flysky|V9x9|V6x6|V912|CX20||||A7105|
|
||||
[Flysky AFHDS2A](Protocols_Details.md#FLYSKY-AFHDS2A---28)|28|PWM_IBUS|PPM_IBUS|PWM_SBUS|PPM_SBUS|PWM_IBUS16|PPM_IBUS16|||A7105|
|
||||
[Flysky AFHDS2A](Protocols_Details.md#FLYSKY-AFHDS2A---28)|28|PWM_IBUS|PPM_IBUS|PWM_SBUS|PPM_SBUS|PWM_IBUS16|PPM_IBUS16|PWM_SBUS16|PPM_SBUS16|A7105|
|
||||
[Flysky AFHDS2A RX](Protocols_Details.md#FLYSKY-AFHDS2A-RX---56)|56|Multi|CPPM|||||||A7105|
|
||||
[FQ777](Protocols_Details.md#FQ777---23)|23|||||||||NRF24L01|SSV7241
|
||||
[FrskyD](Protocols_Details.md#FRSKYD---3)|3|D8|Cloned|||||||CC2500|
|
||||
@@ -96,7 +96,7 @@ CFlie|38|CFlie||||||||NRF24L01|
|
||||
[FrskyX2](Protocols_Details.md#FRSKYX2---64)|64|CH_16|CH_8|EU_16|EU_8|Cloned|Cloned_8|||CC2500|
|
||||
[Frsky_RX](Protocols_Details.md#FRSKY_RX---55)|55|Multi|CloneTX|EraseTX|CPPM|||||CC2500|
|
||||
[Futaba/SFHSS](Protocols_Details.md#Futaba---21)|21|SFHSS||||||||CC2500|
|
||||
[FX816](Protocols_Details.md#FX816---58)|28|FX816|P38|||||||NRF24L01|
|
||||
[FX](Protocols_Details.md#FX---58)|28|816|620|||||||NRF24L01|
|
||||
[FY326](Protocols_Details.md#FY326---20)|20|FY326|FY319|||||||NRF24L01|
|
||||
[GD00X](Protocols_Details.md#GD00X---47)|47|GD_V1*|GD_V2*|||||||NRF24L01|XN297L
|
||||
[GW008](Protocols_Details.md#GW008---32)|32|||||||||NRF24L01|XN297
|
||||
@@ -110,15 +110,17 @@ CFlie|38|CFlie||||||||NRF24L01|
|
||||
[J6Pro](Protocols_Details.md#J6Pro---22)|22|||||||||CYRF6936|
|
||||
[JJRC345](Protocols_Details.md#JJRC345---71)|71|JJRC345|SkyTmblr|||||||NRF24L01|XN297
|
||||
[JOYSWAY](Protocols_Details.md#JOYSWAY---84)|84|||||||||NRF24L01|XN297
|
||||
[KF606](Protocols_Details.md#KF606---49)|49|||||||||NRF24L01|XN297
|
||||
[KF606](Protocols_Details.md#KF606---49)|49|KF606|MIG320|||||||NRF24L01|XN297
|
||||
[KN](Protocols_Details.md#KN---9)|9|WLTOYS|FEILUN|||||||NRF24L01|
|
||||
[Kyosho](Protocols_Details.md#Kyosho---73)|73|FHSS|Hype|||||||A7105|
|
||||
[Kyosho2](Protocols_Details.md#Kyosho2---93)|93|KT-17||||||||NRF24L01|
|
||||
[LOLI](Protocols_Details.md#LOLI---82)|82|||||||||NRF24L01|
|
||||
[Losi](Protocols_Details.md#Losi---89)|89|||||||||CYRF6936|
|
||||
[MJXq](Protocols_Details.md#MJXQ---18)|18|WLH08|X600|X800|H26D|E010*|H26WH|PHOENIX*||NRF24L01|XN297
|
||||
[MLINK](Protocols_Details.md#MLINK---78)|78|||||||||CYRF6936|
|
||||
[MouldKg](Protocols_Details.md#mouldkg---90)|90|Analog|Digit|||||||NRF24L01|XN297
|
||||
[MT99xx](Protocols_Details.md#MT99XX---17)|17|MT|H7|YZ|LS|FY805|A180|DRAGON||NRF24L01|XN297
|
||||
[MT99xx](Protocols_Details.md#MT99XX---17)|17|MT|H7|YZ|LS|FY805|A180|DRAGON|F949G|NRF24L01|XN297
|
||||
[MT99xx2](Protocols_Details.md#MT99XX2---92)|92|PA18||||||||NRF24L01|XN297
|
||||
[NCC1701](Protocols_Details.md#NCC1701---44)|44|||||||||NRF24L01|
|
||||
[OMP](Protocols_Details.md#OMP---77)|77|||||||||CC2500&NRF24L01|XN297L
|
||||
[OpenLRS](Protocols_Details.md#OpenLRS---27)|27|||||||||None|
|
||||
@@ -139,11 +141,12 @@ CFlie|38|CFlie||||||||NRF24L01|
|
||||
[Tiger](Protocols_Details.md#Tiger---61)|61|||||||||NRF24L01|XN297
|
||||
[Traxxas](Protocols_Details.md#Traxxas---43)|43|6519 RX||||||||CYRF6936|
|
||||
[V2x2](Protocols_Details.md#V2X2---5)|5|V2x2|JXD506|MR101||||||NRF24L01|
|
||||
[V761](Protocols_Details.md#V761---48)|48|3CH|4CH|||||||NRF24L01|XN297
|
||||
[V761](Protocols_Details.md#V761---48)|48|3CH|4CH|TOPRC||||||NRF24L01|XN297
|
||||
[V911S](Protocols_Details.md#V911S---46)|46|V911S*|E119*|||||||NRF24L01|XN297
|
||||
[WFLY](Protocols_Details.md#WFLY---40)|40|WFR0x||||||||CYRF6936|
|
||||
[WFLY2](Protocols_Details.md#WFLY2---79)|79|RF20x||||||||A7105|
|
||||
[WK2x01](Protocols_Details.md#WK2X01---30)|30|WK2801|WK2401|W6_5_1|W6_6_1|W6_HEL|W6_HEL_I|||CYRF6936|
|
||||
[XERALL](Protocols_Details.md#XERALL---91)|91|Tank||||||||NRF24L01|XN297
|
||||
[XK](Protocols_Details.md#XK---62)|62|X450|X420|||||||NRF24L01|XN297
|
||||
[YD717](Protocols_Details.md#YD717---8)|8|YD717|SKYWLKR|SYMAX4|XINXUN|NIHUI||||NRF24L01|
|
||||
[ZSX](Protocols_Details.md#ZSX---52)|52|280||||||||NRF24L01|XN297
|
||||
@@ -228,17 +231,12 @@ RX output will match the Flysky standard AETR independently of the input configu
|
||||
### Sub_protocol PPM_IBUS - *1*
|
||||
### Sub_protocol PWM_SBUS - *2*
|
||||
### Sub_protocol PPM_SBUS - *3*
|
||||
As stated above.
|
||||
|
||||
### Sub_protocol PWM_IBUS16 - *4*
|
||||
|
||||
3 additional channels. Need recent or updated RXs.
|
||||
|
||||
CH15|CH16|CH17
|
||||
---|---|---
|
||||
CH15|CH16|LQI
|
||||
|
||||
LQI: Link Quality Indicator
|
||||
|
||||
### Sub_protocol PPM_IBUS16 - *5*
|
||||
### Sub_protocol PWM_SBUS16 - *6*
|
||||
### Sub_protocol PPM_SBUS16 - *7*
|
||||
|
||||
3 additional channels. Need recent or updated RXs.
|
||||
|
||||
@@ -400,18 +398,18 @@ A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
|
||||
|
||||
RX output will match the Devo standard EATR independently of the input configuration AETR, RETA... unless on OpenTX 2.3.3+ you use the "Disable channel mapping" feature on the GUI.
|
||||
|
||||
Full telemetry is available if the RX supports it: TX_RSSI, A1 (set the ratio to 12.7) and A2 (set the ratio to 12.7), VFAS, RPM, temperature 1&2, GPS position/speed/altitude/time.
|
||||
Full telemetry is available if the RX supports it: TX_RSSI, A1 (set the ratio to 12.7) and A2 (set the ratio to 12.7), VFAS, RPM, temperature 1&2, GPS position/speed/altitude/time. The GPS coordinates come in two flavors which can't be distinguished programmatically, to switch from one to the other add 2 to the Option/FixedID setting value (0->2, 1->3).
|
||||
|
||||
Bind procedure using serial:
|
||||
- With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode.
|
||||
- Turn on the TX, set protocol = Devo with option=0, turn off the TX (TX is now in autobind mode).
|
||||
- Turn on the TX, set protocol = Devo with Option/FixedID=0, turn off the TX (TX is now in autobind mode).
|
||||
- Turn on RX (RX LED fast blink).
|
||||
- Turn on TX (RX LED solid, TX LED fast blink).
|
||||
- Wait for bind on the TX to complete (TX LED solid).
|
||||
- Make sure to set a uniq RX_Num value for model match.
|
||||
- Change option to 1 to use the global ID.
|
||||
- Do not touch option/RX_Num anymore.
|
||||
- Note: it might be limited to only the RX705 but to get telemetry, the opion fields has to be set back to 0 at then end of the procedure...
|
||||
- Change Option/FixedID to 1 to use the global ID.
|
||||
- Do not touch Option/FixedID and RX_Num anymore.
|
||||
- Note: it might be limited to only the RX705 but to get telemetry, the Option/FixedID field has to be set back to 0 at then end of the procedure...
|
||||
|
||||
Bind procedure using PPM:
|
||||
- With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode.
|
||||
@@ -570,6 +568,8 @@ Once your **setup** is **complete** and before enabling the internal module, you
|
||||
## E010R5 - *81*
|
||||
Models: E010 R5 red boards, JJRC H36, H36F and H36S
|
||||
|
||||
Not supported by Atmega328p modules.
|
||||
|
||||
Autobind protocol.
|
||||
|
||||
**Only 5 IDs are available**. Use RX num to cycle through them. More IDs can be added if you send me your "unused" original TX.
|
||||
@@ -578,8 +578,28 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
|
||||
---|---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R|FLIP|LED|CALIB|HEADLESS|RTH|GLIDE
|
||||
|
||||
## E01X - *45*
|
||||
Autobind protocol
|
||||
|
||||
Not supported by Atmega328p modules.
|
||||
|
||||
### Sub_protocol E012 - *0*
|
||||
Models: Eachine E012
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R||FLIP||HEADLESS|RTH
|
||||
|
||||
### Sub_protocol E015 - *1*
|
||||
Models: Eachine E015
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R|ARM|FLIP|LED|HEADLESS|RTH
|
||||
|
||||
## E129 - *83*
|
||||
Models: Eachine E129/E130 and Twister Ninja 250
|
||||
|
||||
**Not supported by Atmega328p modules.**
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
---|---|---|---|---|---|---|---|---
|
||||
@@ -591,6 +611,14 @@ Take off with a none spring throttle is easier by putting both sticks down outwa
|
||||
|
||||
Calib is the same as the original radio with both sticks down and to the left in Mode 1/2, not sure about other modes.
|
||||
|
||||
### Sub_protocol E129 - *0*
|
||||
Models: Eachine E129/E130 and Twister Ninja 250
|
||||
|
||||
### Sub_protocol C186 - *1*
|
||||
Models: C186/E120, C127/E110, K127
|
||||
|
||||
The FC of the heli seems to store the trims Trim A/E/R=CH7..9. If you use these trims, make sure to center them after powering off the heli or they will be added to the previous trims and over correct.
|
||||
|
||||
## J6Pro - *22*
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
|
||||
@@ -957,15 +985,17 @@ Compatible RXs: X6/X6F/X6FG
|
||||
Also called SFHSS depending on radio version.
|
||||
|
||||
### Sub_protocol SFHSS - *0*
|
||||
Models: Futaba SFHSS RXs and XK models.
|
||||
Models: Futaba SFHSS RXs and some XK models.
|
||||
|
||||
Extended limits and failsafe supported
|
||||
Extended limits and failsafe supported.
|
||||
|
||||
RX output will match the Futaba standard servo throw, mid point and the channel order AETR independently of the input configuration AETR, RETA... unless if on OpenTX 2.3.3+ you use the "Disable channel mapping" feature on the GUI.
|
||||
|
||||
Option for this protocol corresponds to fine frequency tuning. This value is different for each Module and **must** be accurate otherwise the link will not be stable.
|
||||
Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it.
|
||||
|
||||
This protocol does not use bind on the TX side. The RX attaches to the first S-FHHSS TX around it when the bind button is pressed.
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
|
||||
---|---|---|---|---|---|---|---
|
||||
A|E|T|R|CH5|CH6|CH7|CH8
|
||||
@@ -1004,12 +1034,21 @@ First generation of GD models, ZC-Z50
|
||||
New generation of GD models
|
||||
|
||||
## KF606 - *49*
|
||||
|
||||
### Sub_protocol KF606 - *0*
|
||||
Model: KF606
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5
|
||||
---|---|---|---|---
|
||||
A||T||TRIM
|
||||
|
||||
### Sub_protocol MIG320 - *1*
|
||||
Model: Zhiyang MIG-320
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A||T||TRIM|LED
|
||||
|
||||
## MJXQ - *18*
|
||||
Autobind protocol
|
||||
|
||||
@@ -1091,14 +1130,20 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
A|E|T|R|FLIP||||HEADLESS
|
||||
|
||||
### Sub_protocol A180 - *5*
|
||||
Model: XK A180
|
||||
Model: XK A180, F949S, F959
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5
|
||||
---|---|---|---|---
|
||||
A|E|T|R|3D6G
|
||||
A180:
|
||||
CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A|E|T|R|3D6G|RATE
|
||||
|
||||
F949S:
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7
|
||||
---|---|---|---|---|---|---
|
||||
A|E|T|R|RATE|RXLED|3D6G
|
||||
|
||||
### Sub_protocol DRAGON - *6*
|
||||
Model: Eachine Mini Wing Dragon
|
||||
Model: Eachine Mini Wing Dragon, Eachine Mini Cessna
|
||||
|
||||
Telemetry is supported: A1 = battery voltage with a Ratio of 25.5, A2=battery low flag (0=off,>0=on) and RSSI = dummy value of 100
|
||||
|
||||
@@ -1108,6 +1153,24 @@ A|E|T|R|MODE|RTH
|
||||
|
||||
MODE: -100%=Beginner, 0%=Intermediate, +100%=Advanced
|
||||
|
||||
### Sub_protocol F949G - *7*
|
||||
Model: F949G
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A|E|T|R|6G3D|Light
|
||||
|
||||
## MT99XX2 - *92*
|
||||
|
||||
### Sub_protocol PA18 - *92*
|
||||
Model: PA18 mini
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7
|
||||
---|---|---|---|---|---|---
|
||||
A|E|T|R|MODE|FLIP|RTH
|
||||
|
||||
MODE: -100% beginner, 0% intermediate, +100% Expert
|
||||
|
||||
## OMP - *77*
|
||||
Model: OMPHOBBY M1 & M2 Helis, T720 RC Glider
|
||||
|
||||
@@ -1265,15 +1328,21 @@ MODE: -100% level, +100% acro
|
||||
|
||||
## V911S - *46*
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5
|
||||
---|---|---|---|---
|
||||
A|E|T|R|CALIB
|
||||
CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A|E|T|R|CALIB|RATE
|
||||
|
||||
Rate: -100% High, +100% Low
|
||||
|
||||
### Sub_protocol V911S - *0*
|
||||
Models: WLtoys V911S, XK A110
|
||||
|
||||
### Sub_protocol E119 - *1*
|
||||
Models: Eachine E119
|
||||
Models: Eachine E119, JJRC W01-J3, XK A220 P-40, XK A800 R2, F959S R2, A160 R2, A280
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7
|
||||
---|---|---|---|---|---|---
|
||||
A|E|T|R|CALIB|RATE|6G_3D
|
||||
|
||||
## XK - *62*
|
||||
|
||||
@@ -1503,27 +1572,6 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R|STOP|FLIP|-|HEADLESS|RTH
|
||||
|
||||
## E01X - *45*
|
||||
Autobind protocol
|
||||
|
||||
### Sub_protocol E012 - *0*
|
||||
Models: Eachine E012
|
||||
|
||||
This protocol has been reported to not work properly due to the emulation of the HS6200 RF component using the NRF24L01. The option value is used to adjust the timing, try every values between -127 and +127. If it works please report which value you've used.
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R||FLIP||HEADLESS|RTH
|
||||
|
||||
### Sub_protocol E015 - *1*
|
||||
Models: Eachine E015
|
||||
|
||||
This protocol has been reported to not work properly due to the emulation of the HS6200 RF component using the NRF24L01. The option value is used to adjust the timing, try every values between -127 and +127. If it works please report which value you've used.
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R|ARM|FLIP|LED|HEADLESS|RTH
|
||||
|
||||
## ESKY - *16*
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6
|
||||
@@ -1553,15 +1601,21 @@ A|E|T|R|FMODE|AUX6|AUX7
|
||||
|
||||
FMODE and AUX7 have 4 positions: -100%..-50%=>0, -50%..5%=>1, 5%..50%=>2, 50%..100%=>3
|
||||
|
||||
## FX816 - *58*
|
||||
Model: FEI XIONG FX816 P38
|
||||
|
||||
Only 8 TX IDs available
|
||||
## FX - *58*
|
||||
FEI XIONG
|
||||
|
||||
CH1|CH2|CH3|CH4
|
||||
---|---|---|---
|
||||
A|-|T|-
|
||||
|
||||
### Sub_protocol 816 - *0*
|
||||
Model: FX816 P38, B17
|
||||
|
||||
Only 8 TX IDs available
|
||||
|
||||
### Sub_protocol 620 - *1*
|
||||
Model: FX620 SU35
|
||||
|
||||
## FY326 - *20*
|
||||
|
||||
### Sub_protocol FY326 - *0*
|
||||
@@ -1594,7 +1648,7 @@ A|E|T|R|FLIP
|
||||
Autobind protocol
|
||||
|
||||
### Sub_protocol H8_3D - *0*
|
||||
Models: EAchine H8 mini 3D, JJRC H20/H22/H11D
|
||||
Models: Eachine H8 mini 3D,Eachine E10, JJRC H20/H22/H11D
|
||||
|
||||
CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13
|
||||
---|---|---|---|---|---|---|---|---
|
||||
@@ -1643,7 +1697,7 @@ A|E|T|R|DR|THOLD|IDLEUP|GYRO|Ttrim|Atrim|Etrim
|
||||
Dual Rate: +100%=full range, Throttle Hold: +100%=hold, Idle Up: +100%=3D, GYRO: -100%=6G, +100%=3G
|
||||
|
||||
### Sub_protocol WLTOYS - *0*
|
||||
Models: V966/V977/F959S/...
|
||||
Models: V966/V977/F959S/A160 J3/...
|
||||
|
||||
### Sub_protocol FEILUN - *1*
|
||||
|
||||
@@ -1678,6 +1732,13 @@ Model: DF-Models SkyTumbler
|
||||
|
||||
RTH not supported
|
||||
|
||||
## KYOSHO2 - *93*
|
||||
Model: TX KT-17, Minium Edge 540, Minium Citabria
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
|
||||
---|---|---|---|---|---|---|---|---|----
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
|
||||
|
||||
## LOLI - *82*
|
||||
LOLI3 receivers: https://github.com/wooddoor/Loli3
|
||||
|
||||
@@ -1767,7 +1828,7 @@ Model: PROPEL 74-Z Speeder Bike
|
||||
|
||||
Autobind protocol
|
||||
|
||||
Telemetry: RSSI is equal to TX_LQI which indicates how well the TX receives the RX (0-100%). A1 voltage should indicate the numbers of life remaining (not tested). A2 is giving the model status using a bit mask: 0x80=flying, 0x08=taking off, 0x04=landing, 0x00=landed/crashed
|
||||
Telemetry: RSSI is equal to TX_LQI which indicates how well the TX receives the RX (0-100%). A1 (with a ratio of 25.5) voltage should indicate the numbers of life remaining 0.2->0.1->0.0(not tested). A2 (with a ratio of 25.5) is giving the model status: 12.8=flying, 0.8=taking off, 0.4=landing, 0=landed/crashed
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14
|
||||
---|---|---|---|---|---|---|---|---|----|----|----|----|----
|
||||
@@ -1881,25 +1942,58 @@ A|E|T|R|FLIP|LIGHT
|
||||
|
||||
## V761 - *48*
|
||||
|
||||
Gyro: -100%=Beginer mode (Gyro on, yaw and pitch rate limited), 0%=Mid Mode ( Gyro on no rate limits), +100%=Mode Expert Gyro off
|
||||
Gyro: -100%=Beginner mode (Gyro on, yaw and pitch rate limited), 0%=Mid Mode ( Gyro on no rate limits), +100%=Mode Expert Gyro off
|
||||
|
||||
Calib: momentary switch, calib will happen one the channel goes from -100% to +100%
|
||||
|
||||
Flip: momentary switch: hold flip(+100%), indicate flip direction with Ele or Ail, release flip(-100%)
|
||||
|
||||
RTN_ACT and RTN: -100% disable, +100% enable
|
||||
|
||||
### Sub_protocol 3CH - *0*
|
||||
Model: Volantex V761-1, V761-3 and may be others
|
||||
Models: Volantex V761-1, V761-3 and may be others
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
---|---|---|---|---|---|---|---|---
|
||||
-|E|T|R|GYRO|CALIB|FLIP|RTN_ACT|RTN
|
||||
|
||||
### Sub_protocol 4CH - *1*
|
||||
Model: Volantex V761-4+ and Eachine P51-D, F4U, F22 and may be others
|
||||
Models: Volantex V761-4+ and Eachine P51-D, F4U, F22 and may be others
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R|GYRO|CALIB|FLIP|RTN_ACT|RTN
|
||||
|
||||
### Sub_protocol TOPRC - *2*
|
||||
Models: Top RC Hobby Spitfire, P51D, BF-109
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R|GYRO|CALIB|FLIP|RTN_ACT|RTN
|
||||
|
||||
## XERALL - *91*
|
||||
Model: Xerall TankCopter
|
||||
|
||||
To bind/link the model faster put the throttle low before powering up the model.
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13
|
||||
---|---|---|---|---|---|---|---|---|---|---|---|---
|
||||
A|E|T|R|Fly/Tank|Takeoff/Land/Emerg|Rate|HeadLess|Photo|Video|TrimR|TrimE|TrimA
|
||||
|
||||
Fly/Tank: -100%=Fly, +100%=Tank
|
||||
|
||||
Takeoff/Land/Emerg: momentary switch -100%->+100%, same switch for all 3 functions. For Takeoff throttle must be centered before actionning the momentary switch. For Emergency stop hold the momentary switch for a few sec.
|
||||
|
||||
Unlock the motors is achieved like on the original radio by putting sticks in the bottom corners (position depends on your mode 1,2,3,4) and throttle has to be raised to center before recentering the sticks for the motors to keep spinning. Takeoff happens as soon as the throttle goes above center.
|
||||
|
||||
Rate: -100%=Low, +100%=High
|
||||
|
||||
HeadLess: -100%=Off, +100%=On
|
||||
|
||||
Photo: momentary switch -100%->+100% (short press on the original remote)
|
||||
|
||||
Video: -100%=Off, +100%=On (long press on the original remote)
|
||||
|
||||
## YD717 - *8*
|
||||
Autobind protocol
|
||||
|
||||
|
||||
@@ -115,14 +115,14 @@ Most of the older FM radios support the PPM interface.
|
||||
|
||||
If you are the owner of a transmitter that supports the er9X/erSky9X or OpenTX firmwares (Frsky Taranis, Horus or the FlySky TH9X or the Turnigy 9X family) you have the additional option to use a serial protocol to communicate between your Tx and the MULTI-Module. (Owners of Walkera Devo transmitters should look at the [Deviation Tx](http://www.deviationtx.com) project for how to achieve the same end goal). This serial protocol does not require any hardware modifications, but will likely require updating the firmware on your radio. For those willing to do this, there are some nice advantages:
|
||||
- The model protocol selection, associated parameters, failsafe and binding is done from the Model Settings menu on the Tx
|
||||
- For telemetry capable transmitters, the telemetry integration is done seamlessly with the Tx firmware. (Note that FrSky TH9X/Turnigy 9X/R transmitters require a telemetry mod to be done before telemetry can work). Click on the link corressponding to your Tx on the [Transmitters](docs/Transmitters.md) page for more details.
|
||||
- For telemetry capable transmitters, the telemetry integration is done seamlessly with the Tx firmware. (Note that FrSky TH9X/Turnigy 9X/R transmitters require a telemetry mod to be done before telemetry can work). Click on the link corresponding to your Tx on the [Transmitters](docs/Transmitters.md) page for more details.
|
||||
|
||||
# How to get started?
|
||||
1. Browse the [Protocols](Protocols_Details.md) page to see which protocols you would like on your module
|
||||
1. Go to the [Hardware Options](docs/Hardware.md) page to decide which of the MULTI-Module hardware options appeals to you and which RF modules you plan to integrate
|
||||
1. Once you have your module, you should review what jumper settings or modifications are required to the module to support serial communication and possibly telemetry
|
||||
1. Go to [Compiling and Programming](docs/Compiling.md) page to download, compile and program your MULTI-Module
|
||||
1. Finally, you should visit the setup page for your transmitter by clicking on the link corressponding to your Tx on the [Transmitters](docs/Transmitters.md) page to configure the last few settings before you can fly to your heart’s content!!!!!
|
||||
1. Finally, you should visit the setup page for your transmitter by clicking on the link corresponding to your Tx on the [Transmitters](docs/Transmitters.md) page to configure the last few settings before you can fly to your heart’s content!!!!!
|
||||
|
||||
# Troubleshooting
|
||||
Visit the [Troubleshooting](docs/Troubleshooting.md) page. Please bear in mind that the MULTI-Module is a complex system of hardware and software and it may take some patience to get it up and running. Also remember that the developers of the system are actual users of the system. This means that at any moment in time the system is working perfectly for them. A corollary to this is that if you are struggling there are likely two scenarios. First, that the problem is with your hardware or with your configuration, second, and much more unlikely but not impossible scenario, is that you are struggling with a new undiscovered bug. (The author of this documentation speaks from experience ;-) Please check the RC Groups forum and search for keywords relating to your problem before posting a reply. When you do post a reply please so humbly and respectfully – you will find many helpful people there. In your reply please include as much relevant information as possible and attach compilation output and ```_Config.h``` files as text attachments to keep the forum clean.
|
||||
|
||||
@@ -9,11 +9,11 @@ getMultiVersion() {
|
||||
}
|
||||
|
||||
getAllRFModules() {
|
||||
if [[ "$BOARD" =~ "multi4in1:avr:multixmega32d4" ]]; then
|
||||
if [[ "$BOARD" =~ ":avr:multixmega32d4" ]]; then
|
||||
ALL_RFMODULES=$(echo CYRF6936_INSTALLED);
|
||||
elif [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then
|
||||
elif [[ "$BOARD" =~ ":avr:multiatmega328p:" ]]; then
|
||||
ALL_RFMODULES=$(echo A7105_INSTALLED CYRF6936_INSTALLED CC2500_INSTALLED NRF24L01_INSTALLED);
|
||||
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
elif [[ "$BOARD" =~ ":STM32F1:" ]]; then
|
||||
ALL_RFMODULES=$(echo A7105_INSTALLED CYRF6936_INSTALLED CC2500_INSTALLED NRF24L01_INSTALLED SX1276_INSTALLED);
|
||||
fi
|
||||
}
|
||||
@@ -26,11 +26,11 @@ getAllProtocols() {
|
||||
CCNRF_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CCNRF_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
|
||||
SX1276_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_SX1276_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
|
||||
|
||||
if [[ "$BOARD" =~ "multi4in1:avr:multixmega32d4" ]]; then
|
||||
if [[ "$BOARD" =~ ":avr:multixmega32d4" ]]; then
|
||||
ALL_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS);
|
||||
elif [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then
|
||||
elif [[ "$BOARD" =~ ":avr:multiatmega328p:" ]]; then
|
||||
ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS $CCNRF_PROTOCOLS);
|
||||
elif [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
|
||||
elif [[ "$BOARD" =~ ":STM32F1:" ]]; then
|
||||
ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS $CCNRF_PROTOCOLS $SX1276_PROTOCOLS);
|
||||
fi
|
||||
}
|
||||
@@ -84,20 +84,22 @@ buildEachRFModule() {
|
||||
}
|
||||
|
||||
buildReleaseFiles(){
|
||||
if [[ "$BOARD" == "multi4in1:avr:multixmega32d4" ]]; then
|
||||
if [[ "$BOARD" =~ ":avr:multixmega32d4" ]]; then
|
||||
build_release_orx;
|
||||
elif [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=none" ]]; then
|
||||
elif [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=none" ]]; then
|
||||
build_release_avr_noboot;
|
||||
elif [[ "$BOARD" == "multi4in1:avr:multiatmega328p:bootloader=optiboot" ]]; then
|
||||
elif [[ "$BOARD" =~ ":avr:multiatmega328p:bootloader=optiboot" ]]; then
|
||||
build_release_avr_optiboot;
|
||||
elif [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=none" ]]; then
|
||||
elif [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=none" ]]; then
|
||||
build_release_stm32f1_no_debug;
|
||||
elif [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=native" ]]; then
|
||||
elif [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=native" ]]; then
|
||||
build_release_stm32f1_native_debug;
|
||||
elif [[ "$BOARD" == "multi4in1:STM32F1:multistm32f103cb:debug_option=ftdi" ]]; then
|
||||
elif [[ "$BOARD" =~ ":STM32F1:multistm32f103cb:debug_option=ftdi" ]]; then
|
||||
build_release_stm32f1_serial_debug;
|
||||
elif [[ "$BOARD" == "multi4in1:STM32F1:multi5in1t18int" ]]; then
|
||||
elif [[ "$BOARD" =~ ":STM32F1:multi5in1t18int" ]]; then
|
||||
build_release_stm32f1_t18int;
|
||||
elif [[ "$BOARD" =~ ":STM32F1:multistm32f103c8:debug_option=none" ]]; then
|
||||
build_release_stm32f1_64k;
|
||||
else
|
||||
printf "No release files for this board.";
|
||||
fi
|
||||
|
||||
@@ -3,27 +3,27 @@
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
exitcode=0;
|
||||
|
||||
printf "\e[33;1mBuilding multi-avr-usbasp-aetr-A7105-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-avr-usbasp-aetr-A7105-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_disable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $A7105_PROTOCOLS;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-usbasp-aetr-A7105-inv-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-avr-usbasp-aetr-A7105-inv-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-avr-usbasp-aetr-CC2500-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-avr-usbasp-aetr-CC2500-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CC2500_PROTOCOLS;
|
||||
opt_disable HITEC_CC2500_INO REDPINE_CC2500_INO OMP_CC2500_INO SKYARTEC_CC2500_INO SCANNER_CC2500_INO FRSKYL_CC2500_INO;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-usbasp-aetr-CC2500-inv-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-avr-usbasp-aetr-CC2500-inv-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CYRF6936_PROTOCOLS;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-avr-usbasp-aetr-CYRF6936-inv-v$MULTI_VERSION.bin;
|
||||
|
||||
exit $exitcode;
|
||||
|
||||
@@ -3,27 +3,27 @@
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
exitcode=0;
|
||||
|
||||
printf "\e[33;1mBuilding multi-avr-txflash-aetr-A7105-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-avr-txflash-aetr-A7105-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_enable CHECK_FOR_BOOTLOADER;
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $A7105_PROTOCOLS;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-txflash-aetr-A7105-inv-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-avr-txflash-aetr-A7105-inv-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-avr-txflash-aetr-CC2500-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-avr-txflash-aetr-CC2500-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CC2500_PROTOCOLS;
|
||||
opt_disable HITEC_CC2500_INO REDPINE_CC2500_INO OMP_CC2500_INO SKYARTEC_CC2500_INO SCANNER_CC2500_INO FRSKYL_CC2500_INO;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-txflash-aetr-CC2500-inv-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-avr-txflash-aetr-CC2500-inv-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_enable $CYRF6936_PROTOCOLS;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-avr-txflash-aetr-CYRF6936-inv-v$MULTI_VERSION.bin;
|
||||
|
||||
exit $exitcode;
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
exitcode=0;
|
||||
|
||||
printf "\e[33;1mBuilding multi-orangerx-aetr-green-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-orangerx-aetr-green-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
opt_disable ORANGE_TX_BLUE;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-orangerx-aetr-green-inv-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-orangerx-aetr-green-inv-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-orangerx-aetr-blue-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-orangerx-aetr-blue-inv-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_enable ORANGE_TX_BLUE;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-orangerx-aetr-blue-inv-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-orangerx-aetr-blue-inv-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mPackaging ancilliary files for v$MULTI_VERSION\e[0m\n";
|
||||
cp Multiprotocol/Multi.txt ./binaries/Multi.txt;
|
||||
|
||||
31
buildroot/bin/build_release_stm32f1_64k
Normal file
31
buildroot/bin/build_release_stm32f1_64k
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
exitcode=0;
|
||||
|
||||
# CC2500-only 64Kb builds
|
||||
printf "\e[33;1mBuilding mm-stm-cc2500-64-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_enable $ALL_PROTOCOLS;
|
||||
opt_disable IKEAANSLUTA_CC2500_INO;
|
||||
opt_disable ENABLE_PPM;
|
||||
opt_disable A7105_INSTALLED;
|
||||
opt_disable CYRF6936_INSTALLED;
|
||||
opt_disable NRF24L01_INSTALLED;
|
||||
opt_disable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-cc2500-64-aetr-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding mm-stm-cc2500-64-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-cc2500-64-taer-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding mm-stm-cc2500-64-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-cc2500-64-reta-v$MULTI_VERSION.bin;
|
||||
|
||||
exit $exitcode;
|
||||
@@ -3,11 +3,11 @@
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
exitcode=0;
|
||||
|
||||
printf "\e[33;1mBuilding multi-stm-xn297dump-usbdebug-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-xn297dump-usbdebug-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_add XN297DUMP_NRF24L01_INO;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-xn297dump-usbdebug-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-xn297dump-usbdebug-v$MULTI_VERSION.bin;
|
||||
|
||||
exit $exitcode;
|
||||
|
||||
@@ -3,69 +3,75 @@
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
exitcode=0;
|
||||
|
||||
# Builds for the DIY 5-in-1 module exceed the 120KB working capacity of the STM32F103CB
|
||||
# To work around this we have to disable some protocols in the builds for this module
|
||||
#DIY_5IN1_DISABLED="MOULDKG_NRF24L01_INO";
|
||||
|
||||
# Generic 4-in-1 builds
|
||||
printf "\e[33;1mBuilding multi-stm-serial-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-serial-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_disable ENABLE_PPM;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-serial-aetr-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-aetr-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-stm-serial-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-serial-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-serial-taer-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-taer-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-stm-serial-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-serial-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-serial-reta-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-serial-reta-v$MULTI_VERSION.bin;
|
||||
|
||||
# DIY 5-in-1 builds
|
||||
printf "\e[33;1mBuilding multi-stm-5in1-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-5in1-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace RETA AETR;
|
||||
#opt_disable $DIY_5IN1_DISABLED;
|
||||
opt_enable SX1276_INSTALLED;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-5in1-aetr-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-aetr-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-stm-5in1-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-5in1-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-5in1-taer-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-taer-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-stm-5in1-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-5in1-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-5in1-reta-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-5in1-reta-v$MULTI_VERSION.bin;
|
||||
|
||||
# T-Lite 5-in-1 builds
|
||||
printf "\e[33;1mBuilding multi-tlite5in1-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-tlite5in1-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace RETA AETR;
|
||||
opt_disable INVERT_TELEMETRY;
|
||||
opt_disable SX1276_INSTALLED;
|
||||
#opt_enable $DIY_5IN1_DISABLED;
|
||||
opt_enable "MULTI_5IN1_INTERNAL JP_TLite"
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-tlite5in1-aetr-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-tlite5in1-aetr-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-tlite5in1-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-tlite5in1-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-tlite5in1-taer-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-tlite5in1-taer-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-tlite5in1-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-tlite5in1-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-tlite5in1-reta-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-tlite5in1-reta-v$MULTI_VERSION.bin;
|
||||
|
||||
# CC2500-only builds
|
||||
printf "\e[33;1mBuilding multi-stm-cc2500-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-cc2500-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace RETA AETR;
|
||||
opt_disable "MULTI_5IN1_INTERNAL JP_TLite"
|
||||
opt_disable A7105_INSTALLED;
|
||||
@@ -74,22 +80,22 @@ opt_disable NRF24L01_INSTALLED;
|
||||
opt_disable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-cc2500-aetr-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-cc2500-aetr-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-stm-cc2500-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-cc2500-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-cc2500-taer-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-cc2500-taer-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-stm-cc2500-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-cc2500-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-cc2500-reta-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-cc2500-reta-v$MULTI_VERSION.bin;
|
||||
|
||||
# 4-in-1 PPM builds
|
||||
printf "\e[33;1mBuilding multi-stm-ppm-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-ppm-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_enable A7105_INSTALLED;
|
||||
opt_enable CYRF6936_INSTALLED;
|
||||
opt_enable NRF24L01_INSTALLED;
|
||||
@@ -101,18 +107,18 @@ opt_disable MULTI_TELEMETRY;
|
||||
opt_set NBR_BANKS 5;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-ppm-aetr-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-ppm-aetr-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-stm-ppm-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-ppm-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-ppm-taer-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-ppm-taer-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-stm-ppm-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-ppm-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-ppm-reta-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-ppm-reta-v$MULTI_VERSION.bin;
|
||||
|
||||
exit $exitcode;
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
exitcode=0;
|
||||
|
||||
printf "\e[33;1mBuilding multi-stm-xn297dump-ftdidebug-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-stm-xn297dump-ftdidebug-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_disable $ALL_PROTOCOLS;
|
||||
opt_add XN297DUMP_NRF24L01_INO;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-stm-xn297dump-ftdidebug-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-stm-xn297dump-ftdidebug-v$MULTI_VERSION.bin;
|
||||
|
||||
exit $exitcode;
|
||||
|
||||
@@ -3,23 +3,23 @@
|
||||
source ./buildroot/bin/buildFunctions;
|
||||
exitcode=0;
|
||||
|
||||
printf "\e[33;1mBuilding multi-t18int-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-t18int-aetr-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_disable ENABLE_PPM;
|
||||
opt_disable INVERT_TELEMETRY;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-t18int-aetr-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-t18int-aetr-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-t18int-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-t18int-taer-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace AETR TAER;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-t18int-taer-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-t18int-taer-v$MULTI_VERSION.bin;
|
||||
|
||||
printf "\e[33;1mBuilding multi-t18int-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
printf "\e[33;1mBuilding mm-t18int-reta-v$MULTI_VERSION.bin\e[0m\n";
|
||||
opt_replace TAER RETA;
|
||||
buildMulti;
|
||||
exitcode=$((exitcode+$?));
|
||||
mv build/Multiprotocol.ino.bin ./binaries/multi-t18int-reta-v$MULTI_VERSION.bin;
|
||||
mv build/Multiprotocol.ino.bin ./binaries/mm-t18int-reta-v$MULTI_VERSION.bin;
|
||||
|
||||
exit $exitcode;
|
||||
|
||||
@@ -20,6 +20,7 @@ Multiprotocol modules can be flashed with a precompiled firmware file (Option 1
|
||||
1. [USB Port](#usb-port)
|
||||
1. [USB-to-Serial adapter](#usb-to-serial-adapter)
|
||||
1. [Upload the firmware](#upload-the-firmware)
|
||||
1. [Option 4 - Flash via USB, using dfu-util (on Linux)](#option-4---flash-via-usb-using-dfu-util-on-linux)
|
||||
1. [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Tools required
|
||||
@@ -172,6 +173,98 @@ In order to flash the bootloader the **BOOT0** jumper must be installed connecti
|
||||
### Upload the firmware
|
||||
1. In the Arduino IDE click **Sketch -> Upload**, or press **Ctrl+U**
|
||||
|
||||
## Option 4 - Flash via USB, using dfu-util (on Linux)
|
||||
|
||||
This upgrade method is only for modules that have USB connectors and
|
||||
that have the ability to enter DFU mode when plugged into a Linux
|
||||
machine.
|
||||
|
||||
[dfu-util](http://dfu-util.sourceforge.net/) is a command line tool that
|
||||
can be used to write firmware to a processor that is in the DFU
|
||||
state. Pre-built dfu-util packages are available for almost any Linux
|
||||
distribution, so simply install the dfu-util package via your system's
|
||||
package manager.
|
||||
|
||||
You now need to get your multimodule connected to your Linux machine
|
||||
and make sure that it is in DFU mode. Usually the multimodule should
|
||||
enter the DFU mode if you remove it from your radio and simply connect
|
||||
it to your Linux machine via a _proper_ USB cable. Note: Some cheap,
|
||||
loading USB cables sometimes have no data lines connected, and these
|
||||
will no work.
|
||||
|
||||
Once your multimodule is connected, run the following command in order
|
||||
to see if the DFU interface had been discovered:
|
||||
|
||||
```shell
|
||||
|
||||
# dfu-util -l -v
|
||||
dfu-util 0.11
|
||||
|
||||
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
|
||||
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
|
||||
This program is Free Software and has ABSOLUTELY NO WARRANTY
|
||||
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
|
||||
|
||||
libusb version 1.0.26 (11724)
|
||||
Found DFU: [1eaf:0003] ver=0201, devnum=69, cfg=1, intf=0, path="1-4", alt=2, name="STM32duino bootloader v1.0 Upload to Flash 0x8002000", serial="LLM 003"
|
||||
Found DFU: [1eaf:0003] ver=0201, devnum=69, cfg=1, intf=0, path="1-4", alt=1, name="STM32duino bootloader v1.0 Upload to Flash 0x8005000", serial="LLM 003"
|
||||
Found DFU: [1eaf:0003] ver=0201, devnum=69, cfg=1, intf=0, path="1-4", alt=0, name="STM32duino bootloader v1.0 ERROR. Upload to RAM not supported.", serial="LLM 003"
|
||||
```
|
||||
|
||||
If you the above didn't succeed, your module is not in DFU mode and it
|
||||
would not make any sense to continue.
|
||||
|
||||
Now that your Linux machine discovered the device with id, 1eaf:0003,
|
||||
you can can start the update process, which will take around 8 to 10
|
||||
seconds. Once done, your multimodule will be updated and you can
|
||||
simply unplug it and start using it.
|
||||
|
||||
The example below, uses a pre-compiled binary available from
|
||||
[here](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases).
|
||||
|
||||
```shell
|
||||
|
||||
# dfu-util -v -R -a 2 -d 1EAF:0003 -D mm-stm-serial-aetr-v1.3.3.14.bin
|
||||
dfu-util 0.11
|
||||
|
||||
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
|
||||
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
|
||||
This program is Free Software and has ABSOLUTELY NO WARRANTY
|
||||
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
|
||||
|
||||
libusb version 1.0.26 (11724)
|
||||
dfu-util: Warning: Invalid DFU suffix signature
|
||||
dfu-util: A valid DFU suffix will be required in a future dfu-util release
|
||||
Opening DFU capable USB device...
|
||||
Device ID 1eaf:0003
|
||||
Device DFU version 0110
|
||||
DFU attributes: (0x03) bitCanDnload bitCanUpload
|
||||
Detach timeout 255 ms
|
||||
Claiming USB DFU Interface...
|
||||
Setting Alternate Interface #2 ...
|
||||
Determining device status...
|
||||
DFU state(2) = dfuIDLE, status(0) = No error condition is present
|
||||
DFU mode device DFU version 0110
|
||||
Device returned transfer size 1024
|
||||
Copying data from PC to DFU device
|
||||
Download [=========================] 100% 118668 bytes
|
||||
Download done.
|
||||
Sent a total of 118668 bytes
|
||||
DFU state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
|
||||
Resetting USB to switch back to runtime mode
|
||||
Done!
|
||||
```
|
||||
|
||||
NOTE: The above command was taken and adapted from
|
||||
[here](https://github.com/benlye/flash-multi/blob/master/doc/Troubleshooting.md).
|
||||
|
||||
As you can see, the above process is really extremely straight
|
||||
forward. You basically only need to have dfu-util installed and you need to
|
||||
run one single command for updating your multimodule.
|
||||
|
||||
As a bonus, the dfu-util method could also be used under Mac or
|
||||
Windows, as dfu-util binaries also exist for those operating systems.
|
||||
|
||||
# Troubleshooting
|
||||
You can report your problem using the [GitHub issue](https://github.com/midelic/DIY-Multiprotocol-TX-Module/issues) system or go to the [Main thread on RCGROUPS](http://www.rcgroups.com/forums/showthread.php?t=2165676) to ask your question.
|
||||
Please provide the following information:
|
||||
|
||||
@@ -30,7 +30,7 @@ These are examples of the well-known ready-made Multiprotocol modules. Inclusio
|
||||
| **iRangeX IRX4 STM32** | <img src="images/irx4.jpg" width="200"/> | [STM32F103C](Compiling_STM32.md "Firmware compiling and uploading instructions for STM32") | US$39 | <ul><li>Includes case</li><li>Serial mode only</li></ul> | [Banggood](https://www.banggood.com/IRangeX-IRX4-2_4G-CC2500-NRF24L01-A7105-CTRF6936-4-IN-1-Multiprotocol-STM32-TX-Module-With-Case-p-1197130.html) |
|
||||
| **iRangeX IRX4 Plus STM32** | <img src="images/irx4-plus.jpg" width="200"/> | [STM32F103C](Compiling_STM32.md "Firmware compiling and uploading instructions for STM32") | US$37 | <ul><li>Includes case</li><li>Has USB port and LED</li><li>Serial and PPM</li></ul> | [Banggood](https://www.banggood.com/IRangeX-IRX4-Plus-2_4G-CC2500-NRF24L01-A7105-CYRF6936-4-IN-1-Multiprotocol-STM32-TX-Module-With-Case-p-1225080.html) |
|
||||
| **Jumper JP4IN1 Multi Protocol Transmitter Module** | <img src="images/jp4in1.jpg" width="200"/> | [STM32F103](Compiling_STM32.md "Firmware compiling and uploading instructions for STM32") | US$40 | <ul><li>Includes case</li><li>Has USB port and LED</li><li>Serial and PPM</li></ul> | [Hobbyking](https://hobbyking.com/en_us/jumper-jp4in1-multi-protocal-radio-transmitter-module.html) |
|
||||
| **Vantac MPM Lite 2.4G Transmitter Module for X-Lite** | <img src="images/mpm1n.jpg" width="200" /> | [STM32F103C](Compiling_STM32.md "Firmware compiling and uploading instructions for STM32") | $49 | <ul><li>Specially for Frsky X-Lite (not JR bay compatible)</li><li>USB Bootloader preflashed</li><li>Has USB and LED</li></ul> | [Banggood](https://www.banggood.com/Vantac-MPM-Lite-2_4G-Multiple-Protocol-TX-Module-for-Taranis-X-Lite-Radio-Transmitter-p-1307645.html?p=RN27072889497201510A) [HorusRC](https://www.horusrc.com/en/vantac-mpm-lite-2-4g-transmitter-module-for-x-lite.html?acc=9860) |
|
||||
| **Vantac MPM Lite 2.4G Transmitter Module for X-Lite** | <img src="images/mpm1n.jpg" width="200" /> | [STM32F103C](Compiling_STM32.md "Firmware compiling and uploading instructions for STM32") | $49 | <ul><li>**64KB flash only, you need to compile the firmware on your own and select only the protocols you need to fit in the space.**</li><li>Specially for Frsky X-Lite (not JR bay compatible)</li><li>USB Bootloader preflashed</li><li>Has USB and LED</li></ul> | [Banggood](https://www.banggood.com/Vantac-MPM-Lite-2_4G-Multiple-Protocol-TX-Module-for-Taranis-X-Lite-Radio-Transmitter-p-1307645.html?p=RN27072889497201510A) [HorusRC](https://www.horusrc.com/en/vantac-mpm-lite-2-4g-transmitter-module-for-x-lite.html?acc=9860) |
|
||||
|
||||
*Table last updated June 24th, 2018*
|
||||
|
||||
|
||||
Reference in New Issue
Block a user