Merge branch 'master' into CFlie_improved
@ -1,768 +0,0 @@
|
||||
local toolName = "TNS|DSM Forward Programming v0.2|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for DSM description
|
||||
-- Multi_Buffer[0..2]=="DSM" -> Lua script is running
|
||||
-- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent
|
||||
-- Multi_Buffer[4..9]=6 bytes of TX to RX data
|
||||
-- Multi_Buffer[10..25]=16 bytes of RX to TX data
|
||||
--
|
||||
-- To start operation:
|
||||
-- Write 0x00 at address 3
|
||||
-- Write 0x00 at address 10
|
||||
-- Write "DSM" at address 0..2
|
||||
--###############################################################################
|
||||
|
||||
local RX_VERSION, WAIT_CMD, MENU_TITLE, MENU_LINES, MENU_VALUES, VALUE_CHANGING, VALUE_CHANGING_WAIT, VALUE_CHANGED, EXIT, EXIT_DONE = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
local MENU, LIST_MENU_NOCHANGING, LIST_MENU1, LIST_MENU2, VALUE_NOCHANGING = 0x1C, 0x6C, 0x0C, 0x4C, 0x60
|
||||
local Phase = RX_VERSION
|
||||
local Waiting_RX = 0
|
||||
local Text = {}
|
||||
local RxName = {}
|
||||
local Retry=100
|
||||
local Blink = 0
|
||||
local Value_Changed=0
|
||||
|
||||
local Menu = { Cur=nil, Id=nil, Title="", Prev=nil, PrevId=nil, Next=nil, NextId=nil, Back=nil, BackId=nil, CurLine=nil, SelLine=nil, EditLine=nil }
|
||||
local Line = {}
|
||||
local RX = { Name="", Version="" }
|
||||
|
||||
-- used for debug
|
||||
local rxAnswer = ""
|
||||
local debugLine = 0
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GetDebugInfo(lineNr) -- used for debug
|
||||
local i
|
||||
|
||||
debugLine = lineNr
|
||||
rxAnswer = "RX:"
|
||||
for i=10, 25 do
|
||||
rxAnswer = rxAnswer.." "..string.format("%02X", multiBuffer(i))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function conv_int16(number)
|
||||
if number >= 0x8000 then
|
||||
return number - 0x10000
|
||||
end
|
||||
return number
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function Get_Text(index)
|
||||
out = Text[index]
|
||||
if out == nil then -- unknown...
|
||||
out = "Unknown_"..string.format("%X",index)
|
||||
end
|
||||
return out
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function Get_RxName(index)
|
||||
out = RxName[index]
|
||||
if out == nil then -- unknown...
|
||||
out = "Unknown_"..string.format("%X",index)
|
||||
end
|
||||
return out
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Release()
|
||||
multiBuffer( 0, 0 )
|
||||
Phase = EXIT_DONE
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Send(...)
|
||||
local arg = {...}
|
||||
for i = 1 , #arg do
|
||||
multiBuffer( 3+i, arg[i])
|
||||
end
|
||||
multiBuffer( 3, 0x70+#arg)
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function Value_Add(dir)
|
||||
local line=Line[Menu.SelLine]
|
||||
Speed = getRotEncSpeed()
|
||||
if Speed == ROTENC_MIDSPEED then
|
||||
line.Val = line.Val + (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then
|
||||
line.Val = line.Val + (15 * dir)
|
||||
else
|
||||
line.Val = line.Val + dir
|
||||
end
|
||||
if line.Val > line.Max then
|
||||
line.Val = line.Max
|
||||
elseif line.Val < line.Min then
|
||||
line.Val = line.Min
|
||||
end
|
||||
if Line[Menu.SelLine].Type ~= LIST_MENU_NOCHANGING then
|
||||
Phase = VALUE_CHANGING
|
||||
Waiting_RX = 0
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Menu(event)
|
||||
local Speed = 0
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if Phase == RX_VERSION then
|
||||
DSM_Release()
|
||||
else
|
||||
Phase = EXIT
|
||||
Waiting_RX = 0
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
if Menu.EditLine == nil then
|
||||
-- not changing a value
|
||||
if Menu.SelLine ~= nil then
|
||||
if Menu.SelLine < 7 then
|
||||
local num = Menu.SelLine
|
||||
for i = Menu.SelLine + 1, 6, 1 do
|
||||
if Line[i].Type ~= nil and Line[i].Next ~= nil and Line[i].Type ~= VALUE_NOCHANGING then
|
||||
Menu.SelLine=i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == Menu.SelLine then
|
||||
if Menu.Next ~= 0 then -- Next
|
||||
Menu.SelLine = 7
|
||||
elseif Menu.Prev ~= 0 then -- Prev
|
||||
Menu.SelLine = 8
|
||||
end
|
||||
end
|
||||
elseif Menu.Prev ~= 0 then -- Prev
|
||||
Menu.SelLine = 8
|
||||
end
|
||||
end
|
||||
else -- need to inc the value
|
||||
Value_Add(1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
if Menu.EditLine == nil then
|
||||
if Menu.SelLine ~= nil then
|
||||
if Menu.SelLine == 8 and Menu.Next ~= 0 then
|
||||
Menu.SelLine = 7
|
||||
elseif Menu.SelLine > 0 then
|
||||
if Menu.SelLine > 6 then
|
||||
Menu.SelLine = 7
|
||||
end
|
||||
local num = Menu.SelLine
|
||||
for i = Menu.SelLine-1, 0, -1 do
|
||||
if Line[i].Type ~= nil and Line[i].Next ~= nil and Line[i].Type ~= VALUE_NOCHANGING then
|
||||
Menu.SelLine=i
|
||||
break
|
||||
end
|
||||
end
|
||||
if num == Menu.SelLine then -- Back
|
||||
Menu.SelLine = -1
|
||||
end
|
||||
else
|
||||
Menu.SelLine = -1 -- Back
|
||||
end
|
||||
end
|
||||
else -- need to dec the value
|
||||
Value_Add(-1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER_LONG then
|
||||
if Menu.EditLine ~= nil then
|
||||
-- reset the value to default
|
||||
if Line[Menu.SelLine].Type ~= LIST_MENU_NOCHANGING then
|
||||
Line[Menu.SelLine].Val = Line[Menu.SelLine].Def
|
||||
Phase = VALUE_CHANGING
|
||||
Waiting_RX = 0
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
if Menu.SelLine == -1 then -- Back
|
||||
Menu.Cur = Menu.Back
|
||||
Menu.Id = Menu.BackId
|
||||
Menu.SelLine = 0
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
elseif Menu.SelLine == 7 then -- Next
|
||||
Menu.Cur = Menu.Next
|
||||
Menu.Id = Menu.NextId
|
||||
Menu.SelLine = 0
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
elseif Menu.SelLine == 8 then -- Prev
|
||||
Menu.Cur = Menu.Prev
|
||||
Menu.Id = Menu.PrevId
|
||||
Menu.SelLine = 0
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
elseif Menu.SelLine ~= nil and Line[Menu.SelLine].Next ~= nil then
|
||||
if Line[Menu.SelLine].Type == MENU then -- Next menu exist
|
||||
Menu.Cur = Line[Menu.SelLine].Next
|
||||
Menu.Id = Line[Menu.SelLine].NextId
|
||||
Phase = MENU_TITLE
|
||||
Waiting_RX = 0
|
||||
else
|
||||
-- value entry
|
||||
if Menu.EditLine == Menu.SelLine then
|
||||
Menu.EditLine = nil
|
||||
Value_Changed = 0
|
||||
Phase = VALUE_CHANGED
|
||||
Waiting_RX = 0
|
||||
else
|
||||
Menu.EditLine = Menu.SelLine
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Send_Receive()
|
||||
if Waiting_RX == 0 then
|
||||
Waiting_RX = 1
|
||||
|
||||
-- Need to send a request
|
||||
if Phase == RX_VERSION then -- request RX version
|
||||
DSM_Send(0x11,0x06,0x00,0x14,0x00,0x00)
|
||||
|
||||
elseif Phase == WAIT_CMD then -- keep connection open
|
||||
DSM_Send(0x00,0x04,0x00,0x00)
|
||||
|
||||
elseif Phase == MENU_TITLE then -- request menu title
|
||||
if Menu.Cur == nil then
|
||||
DSM_Send(0x12,0x06,0x00,0x14,0x00,0x00) -- first menu only
|
||||
Menu.Cur = 0
|
||||
else
|
||||
DSM_Send(0x16,0x06,Menu.Id,Menu.Cur,0x00,Menu.SelLine)
|
||||
end
|
||||
|
||||
elseif Phase == MENU_LINES then -- request menu lines
|
||||
if Menu.CurLine == nil then
|
||||
DSM_Send(0x13,0x04,Menu.Id,Menu.Cur) -- line 0
|
||||
elseif Menu.CurLine >= 0x80 then
|
||||
local last_byte={0x40,0x01,0x02,0x04,0x00,0x00} -- unknown...
|
||||
DSM_Send(0x20,0x06,Menu.CurLine-0x80,Menu.CurLine-0x80,0x00,last_byte[Menu.CurLine-0x80+1]) -- line X
|
||||
else
|
||||
DSM_Send(0x14,0x06,Menu.Id,Menu.Cur,0x00,Menu.CurLine) -- line X
|
||||
end
|
||||
|
||||
elseif Phase == MENU_VALUES then -- request menu values
|
||||
DSM_Send(0x15,0x06,Menu.Id,Menu.Cur,Line[Menu.CurLine].ValId,Line[Menu.CurLine].Next) -- line X
|
||||
|
||||
elseif Phase == VALUE_CHANGING then -- send value
|
||||
local value=Line[Menu.SelLine].Val
|
||||
if value < 0 then
|
||||
value = 0x10000 + value
|
||||
end
|
||||
DSM_Send(0x18,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next,bit32.rshift(value,8),bit32.band(value,0xFF)) -- send current value
|
||||
Phase = VALUE_CHANGING_WAIT
|
||||
|
||||
elseif Phase == VALUE_CHANGED then -- send value
|
||||
if Value_Changed == 0 then
|
||||
local value=Line[Menu.SelLine].Val
|
||||
if value < 0 then
|
||||
value = 0x10000 + value
|
||||
end
|
||||
DSM_Send(0x18,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next,bit32.rshift(value,8),bit32.band(value,0xFF)) -- send current value
|
||||
Value_Changed = Value_Changed + 1
|
||||
Waiting_RX = 0
|
||||
elseif Value_Changed == 1 then
|
||||
DSM_Send(0x19,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next) -- validate
|
||||
-- Value_Changed = Value_Changed + 1
|
||||
-- Waiting_RX = 0
|
||||
--elseif Value_Changed == 2 then
|
||||
-- DSM_Send(0x1B,0x06,0x10,Menu.SelLine) -- validate again?
|
||||
-- Value_Changed = Value_Changed + 1
|
||||
end
|
||||
|
||||
elseif Phase == VALUE_CHANGING_WAIT then
|
||||
DSM_Send(0x1A,0x06,Line[Menu.SelLine].ValId,Line[Menu.SelLine].Next)
|
||||
|
||||
elseif Phase == EXIT then
|
||||
DSM_Send(0x1F,0x02,0xAA)
|
||||
|
||||
end
|
||||
multiBuffer(10,0x00);
|
||||
Retry = 50
|
||||
-- -- -- -- -- -- -- -- -- -- -- -- receive part -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
elseif multiBuffer(10) == 0x09 then
|
||||
-- Answer received
|
||||
-- GetDebugInfo(292) -- used for debug
|
||||
|
||||
--if multiBuffer(11) == 0x00 then -- waiting for commands?
|
||||
|
||||
if multiBuffer(11) == 0x01 then -- read version
|
||||
--ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
RX.Name = Get_RxName(multiBuffer(13))
|
||||
RX.Version = multiBuffer(14).."."..multiBuffer(15).."."..multiBuffer(16)
|
||||
Phase = MENU_TITLE
|
||||
|
||||
elseif multiBuffer(11) == 0x02 then -- read menu title
|
||||
--ex: 0x09 0x02 0x4F 0x10 0xA5 0x00 0x00 0x00 0x50 0x10 0x10 0x10 0x00 0x00 0x00 0x00
|
||||
Menu.Cur = multiBuffer(12)
|
||||
Menu.Id = multiBuffer(13)
|
||||
Menu.Title = Get_Text(multiBuffer(14)+multiBuffer(15)*256)
|
||||
Menu.Prev = multiBuffer(16)
|
||||
Menu.PrevId = multiBuffer(17)
|
||||
Menu.Next = multiBuffer(18)
|
||||
Menu.NextId = multiBuffer(19)
|
||||
Menu.Back = multiBuffer(20)
|
||||
Menu.BackId = multiBuffer(21)
|
||||
for i = 0, 6 do -- clear menu
|
||||
Line[i] = { Menu = nil, Id = nil, Type = nil, Text="", Next = nil, NextId = nil, ValLine = nil, ValId = nil, Min, Max, Def, Val, Unit, Step }
|
||||
end
|
||||
Menu.CurLine = nil
|
||||
if Menu.Next ~= 0 then
|
||||
Menu.SelLine = 7 -- highlight Next
|
||||
else
|
||||
Menu.SelLine = -1 -- highlight Back
|
||||
end
|
||||
Blink = 0
|
||||
Phase = MENU_LINES
|
||||
|
||||
elseif multiBuffer(11) == 0x03 then -- read menu lines
|
||||
--ex: 0x09 0x03 0x00 0x10 0x00 0x1C 0xF9 0x00 0x10 0x10 0x00 0x00 0x00 0x00 0x03 0x00
|
||||
-- Menu Id line Type Text_idx Next V_Id Val_Min Val_Max Val_Def
|
||||
--ex: 0x09 0x03 0x61 0x10 0x00 0x6C 0x50 0x00 0x00 0x10 0x36 0x00 0x49 0x00 0x36 0x00
|
||||
Menu.CurLine = multiBuffer(14)
|
||||
local line = Line[Menu.CurLine]
|
||||
line.Menu = multiBuffer(12)
|
||||
line.Id = multiBuffer(13) -- not quite sure yet
|
||||
line.Type = multiBuffer(15) -- not quite sure yet: 1C is text menu only, 4C/6C is text followed by text list, C0 is text followed by percentage value, 0C new list type
|
||||
line.Text = Get_Text(multiBuffer(16)+multiBuffer(17)*256)
|
||||
--if multiBuffer(18) == Menu.Cur then
|
||||
-- line.Next = nil
|
||||
--else
|
||||
line.Next = multiBuffer(18) -- not quite sure yet: 1C=text menu=>next menu, others=>identifier of line number of the value
|
||||
--end
|
||||
if Menu.SelLine == -1 and line.Next ~= nil then -- Auto select first line of the menu
|
||||
Menu.SelLine = Menu.CurLine
|
||||
end
|
||||
line.NextId = multiBuffer(19) -- not quite sure yet
|
||||
line.ValLine = multiBuffer(18) -- not quite sure yet
|
||||
line.ValId = multiBuffer(19) -- not quite sure yet
|
||||
line.Min = conv_int16(multiBuffer(20)+multiBuffer(21)*256)
|
||||
line.Max = conv_int16(multiBuffer(22)+multiBuffer(23)*256)
|
||||
line.Def = conv_int16(multiBuffer(24)+multiBuffer(25)*256)
|
||||
if line.Type == MENU then
|
||||
-- nothing to do on menu entries
|
||||
elseif line.Type == LIST_MENU_NOCHANGING or line.Type == LIST_MENU1 or line.Type == LIST_MENU2 then
|
||||
line.Val = nil --line.Def - line.Min -- use default value not sure if needed
|
||||
line.Def = line.Min -- pointer to the start of the list in Text
|
||||
line.Max = line.Max - line.Min -- max index
|
||||
line.Min = 0 -- min index
|
||||
else -- default to numerical value
|
||||
line.Val = nil --line.Def -- use default value not sure if needed
|
||||
end
|
||||
if line.Type ~= MENU and line.Type ~= VALUE_NOCHANGING then -- updatable value to follow
|
||||
line.Text = line.Text..":"
|
||||
end
|
||||
Phase = MENU_LINES
|
||||
|
||||
elseif multiBuffer(11) == 0x04 then -- read menu values
|
||||
--ex: 0x09 0x04 0x53 0x10 0x00 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
-- Menu MeId line VaId Value
|
||||
--ex: 0x09 0x04 0x61 0x10 0x02 0x10 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
-- Identify the line and update the value
|
||||
for i = 0, 6 do
|
||||
if Line[i] ~= nil and Line[i].Type ~= nil then
|
||||
if Line[i].Type ~= MENU and Line[i].Next == multiBuffer(14) then -- identifier of line number stored in .Next
|
||||
Line[i].Val = conv_int16(multiBuffer(16)+multiBuffer(17)*256)
|
||||
Menu.CurLine = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
Phase = MENU_VALUES
|
||||
|
||||
elseif multiBuffer(11) == 0x05 then -- unknown... need to get through the lines...
|
||||
Menu.CurLine = 0x80 + multiBuffer(12)
|
||||
Phase = MENU_LINES
|
||||
|
||||
elseif multiBuffer(11) == 0xA7 then -- answer to EXIT command
|
||||
DSM_Release()
|
||||
|
||||
elseif multiBuffer(11) == 0x00 and Phase == VALUE_CHANGING then
|
||||
Phase = VALUE_CHANGING_WAIT
|
||||
|
||||
end
|
||||
|
||||
-- Data processed
|
||||
Waiting_RX = 0
|
||||
multiBuffer(10,0x00)
|
||||
Retry = 50
|
||||
|
||||
else
|
||||
Retry = Retry - 1
|
||||
if Retry <= 0 then
|
||||
-- Retry the RX request
|
||||
Retry = 50
|
||||
Waiting_RX = 0
|
||||
if Phase == EXIT then
|
||||
DSM_Release()
|
||||
end
|
||||
if Phase ~= RX_VERSION and Phase ~= VALUE_CHANGING_WAIT then
|
||||
Phase = WAIT_CMD
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Display()
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--lcd.drawText(10,55,debugLine.." "..rxAnswer) -- draw debug info
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "DSM Forward Programming", MENU_TITLE_COLOR)
|
||||
--Draw RX Menu
|
||||
if Phase == RX_VERSION then
|
||||
lcd.drawText(10,50,"No compatible DSM RX...", BLINK)
|
||||
else
|
||||
if Menu.Title ~= nil then
|
||||
local attrib=0;
|
||||
lcd.drawText(80,32,Menu.Title,MIDSIZE)
|
||||
for i = 0, 6 do
|
||||
if i == Menu.SelLine then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if Line[i] ~= nil and Line[i].Type ~= nil then
|
||||
if Line[i].Type ~= MENU then -- list/value
|
||||
if Line[i].Val ~= nil then
|
||||
local text=""
|
||||
if Line[i].Type == LIST_MENU_NOCHANGING or Line[i].Type == LIST_MENU1 or Line[i].Type == LIST_MENU2 then
|
||||
text = Get_Text(Line[i].Val+Line[i].Def)
|
||||
elseif ( Line[i].Min == 0 and Line[i].Max == 100) or ( Line[i].Min == -100 and Line[i].Max == 100) or ( Line[i].Min == 0 and Line[i].Max == 150) or ( Line[i].Min == -150 and Line[i].Max == 150) then
|
||||
text = Line[i].Val.." %"
|
||||
else
|
||||
--text = Line[i].Val .." T="..Line[i].Type -- used for debug
|
||||
text = Line[i].Val
|
||||
end
|
||||
if Menu.EditLine == Menu.SelLine then -- blink edited entry
|
||||
Blink = Blink + 1
|
||||
if Blink > 25 then
|
||||
attrib = 0
|
||||
if Blink > 50 then
|
||||
Blink = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
lcd.drawText(240,32+20*(i+2), text, attrib) -- display value
|
||||
end
|
||||
attrib = 0
|
||||
end
|
||||
lcd.drawText(10,32+20*(i+2), Line[i].Text, attrib) -- display text
|
||||
end
|
||||
end
|
||||
if Menu.SelLine == -1 then
|
||||
lcd.drawText(437,32, "Back", INVERS)
|
||||
else
|
||||
lcd.drawText(437,32, "Back", 0)
|
||||
end
|
||||
lcd.drawRectangle(437-5, 32-2, 47, 25)
|
||||
if Menu.Next ~= 0 then
|
||||
if Menu.SelLine == 7 then
|
||||
lcd.drawText(437,220, "Next",INVERS)
|
||||
else
|
||||
lcd.drawText(437,220, "Next")
|
||||
end
|
||||
lcd.drawRectangle(437-5, 220-2, 47, 25)
|
||||
end
|
||||
if Menu.Prev ~= 0 then
|
||||
if Menu.SelLine == 8 then
|
||||
lcd.drawText(5,220, "Prev",INVERS)
|
||||
else
|
||||
lcd.drawText(5,220, "Prev")
|
||||
end
|
||||
lcd.drawRectangle(5-5, 220-2, 47, 25)
|
||||
end
|
||||
end
|
||||
lcd.drawText(170,252, "RX "..RX.Name.." v"..RX.Version) -- display RX info
|
||||
end
|
||||
else
|
||||
-- --Draw RX Menu on LCD_W=128
|
||||
-- if multiBuffer( 4 ) == 0xFF then
|
||||
-- lcd.drawText(2,17,"No compatible DSM RX...",SMLSIZE)
|
||||
-- else
|
||||
-- if Retry_128 ~= 0 then
|
||||
-- --Intro page
|
||||
-- Retry_128 = Retry_128 - 1
|
||||
-- lcd.drawScreenTitle("DSM Forward Programming",0,0)
|
||||
-- lcd.drawText(2,17,"Press Prev Page for previous Menu" ,SMLSIZE)
|
||||
-- else
|
||||
-- --Menu page
|
||||
-- for line = 0, 7, 1 do
|
||||
-- for i = 0, 21-1, 1 do
|
||||
-- value=multiBuffer( line*21+6+i )
|
||||
-- if value > 0x80 then
|
||||
-- value = value - 0x80
|
||||
-- lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS)
|
||||
-- else
|
||||
-- lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE)
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('D') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('D') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Init TX buffer
|
||||
multiBuffer( 3, 0x00 )
|
||||
--Init RX buffer
|
||||
multiBuffer( 10, 0x00 )
|
||||
--Init telemetry
|
||||
multiBuffer( 0, string.byte('D') )
|
||||
multiBuffer( 1, string.byte('S') )
|
||||
multiBuffer( 2, string.byte('M') )
|
||||
|
||||
--RX names--
|
||||
RxName[0x0001]="AR636B"
|
||||
RxName[0x0014]="SPM4651T"
|
||||
RxName[0x0015]="AR637T"
|
||||
RxName[0x0016]="AR637TA"
|
||||
RxName[0x0018]="FC6250HX"
|
||||
RxName[0x001A]="AR8360T"
|
||||
RxName[0x001E]="AR631"
|
||||
|
||||
--Text to be displayed -> need to use a file instead?
|
||||
Text[0x0001]="On"
|
||||
Text[0x0002]="Off"
|
||||
Text[0x0003]="Inh"
|
||||
Text[0x0004]="Act"
|
||||
Text[0x000C]="Inhibit?" --?
|
||||
Text[0x000D]="Gear"
|
||||
|
||||
--Lists--
|
||||
Text[0x002E]="11ms"
|
||||
Text[0x002F]="22ms"
|
||||
Text[0x0032]="1 X"
|
||||
Text[0x0033]="2 X"
|
||||
Text[0x0034]="4 X"
|
||||
Text[0x0035]="Inhibit?" --?
|
||||
Text[0x0036]="Throttle"
|
||||
Text[0x0037]="Aileron"
|
||||
Text[0x0038]="Elevator"
|
||||
Text[0x0039]="Rudder"
|
||||
Text[0x003A]="Gear"
|
||||
|
||||
--******
|
||||
--This part is strange since the AR637T needs
|
||||
for i=1,7 do -- 3B..41
|
||||
Text[0x003A+i]="Aux"..i
|
||||
end
|
||||
for i=1,8 do -- 41..49
|
||||
Text[0x0041+i]="XPlus-"..i
|
||||
end
|
||||
--But FOTO-PETE reports that it should be:
|
||||
Text[0x0040]="Roll"
|
||||
Text[0x0041]="Pitch"
|
||||
Text[0x0042]="Yaw"
|
||||
Text[0x0043]="Gain" -- FC6250HX
|
||||
Text[0x0045]="Differential"
|
||||
Text[0x0046]="Priority"
|
||||
Text[0x0049]="Output Setup" -- FC6250HX
|
||||
--******
|
||||
|
||||
Text[0x004A]="Failsafe"
|
||||
Text[0x004B]="Main Menu"
|
||||
Text[0x004E]="Position"
|
||||
Text[0x0050]="Outputs"
|
||||
Text[0x0051]="Output Channel 1"
|
||||
Text[0x0052]="Output Channel 2"
|
||||
Text[0x0053]="Output Channel 3"
|
||||
Text[0x0054]="Output Channel 4"
|
||||
Text[0x0055]="Output Channel 5"
|
||||
Text[0x0056]="Output Channel 6"
|
||||
--Text[0x005E]="Inhibit"
|
||||
Text[0x005F]="Hold Last"
|
||||
Text[0x0060]="Preset"
|
||||
--Text[0x0061]="Custom"
|
||||
--Messages--
|
||||
Text[0x0071]="Proportional"
|
||||
Text[0x0072]="Integral"
|
||||
Text[0x0073]="Derivate"
|
||||
Text[0x0078]="FM Channel"
|
||||
Text[0x0080]="Orientation"
|
||||
Text[0x0082]="Heading"
|
||||
Text[0x0085]="Frame Rate"
|
||||
Text[0x0086]="System Setup"
|
||||
Text[0x0087]="F-Mode Setup"
|
||||
Text[0x0088]="Enabled F-Modes"
|
||||
Text[0x0089]="Gain Channel"
|
||||
Text[0x008A]="Gain Sensitivity"
|
||||
Text[0x008B]="Panic"
|
||||
Text[0x0090]="Apply"
|
||||
Text[0x0092]="Start"
|
||||
Text[0x0093]="Complete"
|
||||
Text[0x0094]="Done"
|
||||
Text[0x0097]="Factory Reset"
|
||||
Text[0x0099]="Advanced Setup"
|
||||
Text[0x009A]="Capture Failsafe Positions"
|
||||
Text[0x009C]="Custom Failsafe"
|
||||
Text[0x00A5]="First Time Setup"
|
||||
Text[0x00AA]="Capture Gyro Gains"
|
||||
Text[0x00AD]="Gain Channel Select"
|
||||
Text[0x00B0]="Self-Level/Angle Dem"
|
||||
Text[0x00B1]="Envelope"
|
||||
Text[0x00B5]="Inhibit"
|
||||
Text[0x00B6]="FM1"
|
||||
Text[0x00B7]="FM2"
|
||||
Text[0x00B8]="FM3"
|
||||
Text[0x00B9]="FM4"
|
||||
Text[0x00BA]="FM5"
|
||||
Text[0x00BB]="FM6"
|
||||
Text[0x00BC]="FM7"
|
||||
Text[0x00BD]="FM8"
|
||||
Text[0x00BE]="FM9"
|
||||
Text[0x00BF]="FM10"
|
||||
Text[0x00C7]="Calibrate Sensor"
|
||||
Text[0x00CA]="SAFE/Panic Mode Setup"
|
||||
Text[0x00D3]="Swashplate"
|
||||
Text[0x00D5]="Agility"
|
||||
Text[0x00D8]="Stop"
|
||||
Text[0x00DA]="SAFE"
|
||||
Text[0x00DB]="Stability"
|
||||
Text[0x00DC]="@ per sec"
|
||||
Text[0x00DD]="Tail rotor"
|
||||
Text[0x00DE]="Setup"
|
||||
Text[0x00DF]="AFR"
|
||||
Text[0x00E0]="Collective"
|
||||
Text[0x00E1]="Subtrim"
|
||||
Text[0x00E2]="Phasing"
|
||||
Text[0x00E4]="E-Ring"
|
||||
Text[0x00E7]="Left"
|
||||
Text[0x00E8]="Right"
|
||||
Text[0x00F2]="Fixed"
|
||||
Text[0x00F3]="Adjustable"
|
||||
Text[0x00F9]="Gyro settings"
|
||||
Text[0x00FE]="Stick Priority"
|
||||
Text[0x0100]="Make sure the model has been"
|
||||
Text[0x0101]="configured, including wing type,"
|
||||
Text[0x0102]="reversing, travel, trimmed, etc."
|
||||
Text[0x0103]="before continuing setup."
|
||||
Text[0x0106]="Any wing type, channel assignment,"
|
||||
Text[0x0107]="subtrim, or servo reversing changes"
|
||||
Text[0x0108]="require running through initial"
|
||||
Text[0x0109]="setup again."
|
||||
Text[0x0190]="Relearn Servo Settings"
|
||||
Text[0x019C]="Enter Receiver Bind Mode"
|
||||
Text[0x01D7]="SAFE Select Channel"
|
||||
Text[0x01DC]="AS3X"
|
||||
Text[0x01DD]="AS3X Settings"
|
||||
Text[0x01DE]="AS3X Gains"
|
||||
Text[0x01E0]="Rate Gains"
|
||||
Text[0x01E2]="SAFE Settings"
|
||||
Text[0x01E3]="SAFE Gains"
|
||||
Text[0x01E6]="Attitude Trim"
|
||||
Text[0x01E7]="Envelope"
|
||||
Text[0x01E9]="Roll Right"
|
||||
Text[0x01EA]="Roll Left"
|
||||
Text[0x01EB]="Pitch Down"
|
||||
Text[0x01EC]="Pitch Up"
|
||||
Text[0x01EE]="Throttle to Pitch"
|
||||
Text[0x01EF]="Low Thr to Pitch"
|
||||
Text[0x01F0]="High Thr to Pitch"
|
||||
Text[0x01F3]="Threshold"
|
||||
Text[0x01F4]="Angle"
|
||||
Text[0x01F6]="Failsafe Angles"
|
||||
Text[0x01F8]="Safe Mode"
|
||||
Text[0x01F9]="SAFE Select"
|
||||
Text[0x01FD]="SAFE Failsafe FMode"
|
||||
Text[0x0208]="Decay"
|
||||
Text[0x0209]="Save to Backup"
|
||||
Text[0x020A]="Restore from Backup"
|
||||
Text[0x020D]="First Time SAFE Setup"
|
||||
Text[0x021A]="Set the model level,"
|
||||
Text[0x021B]="and press Continue."
|
||||
Text[0x021C]="" -- empty??
|
||||
Text[0x021D]="" -- empty??
|
||||
Text[0x021F]="Set the model on its nose,"
|
||||
Text[0x0220]="and press Continue. If the"
|
||||
Text[0x0221]="orientation on the next"
|
||||
Text[0x0222]="screen is wrong go back"
|
||||
Text[0x0223]="and try again."
|
||||
Text[0x0224]="Continue"
|
||||
Text[0x0226]="Angle Limits"
|
||||
Text[0x0227]="Other settings"
|
||||
Text[0x0229]="Set Orientation Manually"
|
||||
Text[0x022B]="WARNING!"
|
||||
Text[0x022C]="This will reset the"
|
||||
Text[0x022D]="configuration to factory"
|
||||
Text[0x022E]="defaults. This does not"
|
||||
Text[0x022F]="affect the backup config."
|
||||
Text[0x0230]="" -- empty??
|
||||
Text[0x0231]="This will overwrite the"
|
||||
Text[0x0232]="backup memory with your"
|
||||
Text[0x0233]="current configuartion."
|
||||
Text[0x0234]="" -- blank line
|
||||
Text[0x0235]="" -- blank line
|
||||
Text[0x0236]="This will overwrite the"
|
||||
Text[0x0237]="current config with"
|
||||
Text[0x0238]="that which is in"
|
||||
Text[0x0239]="the backup memory."
|
||||
Text[0x023A]="" -- blank line
|
||||
Text[0x023D]="Copy Flight Mode Settings"
|
||||
Text[0x0240]="Utilities"
|
||||
Text[0x024C]="Gains will be captured on"
|
||||
Text[0x024D]="Captured gains will be"
|
||||
Text[0x024E]="Gains on"
|
||||
Text[0x024F]="were captured and changed"
|
||||
Text[0x0250]="from Adjustable to Fixed"
|
||||
Text[0x0254]="Postive = Up, Negative = Down"
|
||||
Text[0x0263]="Fixed/Adjustable Gains"
|
||||
Text[0x0266]="Heading Gain"
|
||||
Text[0x0267]="Positive = Nose Up/Roll Right"
|
||||
Text[0x0268]="Negative = Nose Down/Roll Left"
|
||||
Text[0x0269]="SAFE - Throttle to Pitch"
|
||||
Text[0x026A]="Use CAUTION for Yaw gain!"
|
||||
Text[0x8000]="FLIGHT MODE"
|
||||
Text[0x8001]="Flight Mode 1"
|
||||
Text[0x8002]="Flight Mode 2"
|
||||
Text[0x8003]="Flight Mode 3"
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
local function DSM_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
else
|
||||
DSM_Menu(event)
|
||||
DSM_Send_Receive()
|
||||
DSM_Display()
|
||||
end
|
||||
if Phase == EXIT_DONE then
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=DSM_Init, run=DSM_Run }
|
549
Lua_scripts/DSM FwdPrg_05_BW.lua
Normal file
@ -0,0 +1,549 @@
|
||||
local toolName = "TNS|DSM Forward Prog v0.53 (Text B&W) |TNE"
|
||||
local VERSION = "v0.53"
|
||||
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
------------------------------------------------------------------------------
|
||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
||||
-- separate the GUI from the DSM Forward programming engine/logic
|
||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
||||
|
||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
-- Rewrite/Enhancements By: Francisco Arzu
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local SIMULATION_ON = false -- FALSE: 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_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
||||
|
||||
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON)
|
||||
|
||||
local PHASE = dsmLib.PHASE
|
||||
local LINE_TYPE = dsmLib.LINE_TYPE
|
||||
local DISP_ATTR = dsmLib.DISP_ATTR
|
||||
|
||||
local DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
local IS_EDGETX = false -- DEFAULT until Init changed it
|
||||
|
||||
local LCD_W_USABLE = LCD_W-10
|
||||
-- X for Menu Lines
|
||||
local LCD_X_LINE_MENU = 10
|
||||
-- X offsets for (Title: [Value] debugInfo) lines
|
||||
local LCD_X_LINE_TITLE = 10
|
||||
local LCD_X_LINE_VALUE = 230
|
||||
local LCD_X_LINE_DEBUG = 390
|
||||
|
||||
-- Line Height: make it smaller debugging info tp LCD (some space buttom)
|
||||
local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27
|
||||
-- Y offsets
|
||||
local LCD_Y_MENU_TITLE = 20
|
||||
-- Y offet
|
||||
local LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 30
|
||||
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT
|
||||
|
||||
local LCD_W_BUTTONS = 47
|
||||
local LCD_H_BUTTONS = 25
|
||||
local LCD_X_RIGHT_BUTTONS = LCD_W - LCD_W_BUTTONS - 5
|
||||
|
||||
local TEXT_SIZE = 0 -- NORMAL
|
||||
|
||||
local lastRefresh=0 -- Last time the screen was refreshed
|
||||
local REFRESH_GUI_MS = 500/10 -- 500ms.. Screen Refresh Rate.. to not use unneded CPU time (in 10ms units to be compatible with getTime())
|
||||
local originalValue = nil
|
||||
|
||||
local warningScreenON = true
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_SwitchToRX()
|
||||
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
|
||||
local dsmChannelInfo, description = dsmLib.CreateDSMPortChannelInfo()
|
||||
|
||||
dsmLib.ReleaseConnection()
|
||||
dsmLib.LOG_close()
|
||||
|
||||
SIMULATION_ON = false
|
||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
|
||||
DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library
|
||||
dsmLib.StartConnection()
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function GUI_SwitchToSIM()
|
||||
dsmLib.ReleaseConnection()
|
||||
dsmLib.LOG_close()
|
||||
|
||||
SIMULATION_ON = true
|
||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
|
||||
DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
dsmLib.StartConnection()
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function openTx_lcd_sizeText(s)
|
||||
return string.len(s)*5
|
||||
end
|
||||
|
||||
local function GUI_Diplay_Button(x,y,w,h,text,selected)
|
||||
local attr = (selected) and INVERS or 0 -- INVERS if line Selected
|
||||
if (TEXT_SIZE~=SMLSIZE) then
|
||||
lcd.drawText(x+5,y+2, text, attr + TEXT_SIZE)
|
||||
lcd.drawRectangle(x, y, w, h, LINE_COLOR)
|
||||
else -- SMALL Screen
|
||||
lcd.drawText(x,y, text, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
|
||||
local function GUI_Display_Menu(menu)
|
||||
local ctx = DSM_Context
|
||||
local w= LCD_W_USABLE - LCD_W_BUTTONS - 10 -- usable Width for the Menu/Lines
|
||||
|
||||
-- Center Header
|
||||
local tw = openTx_lcd_sizeText(menu.Text)
|
||||
local x = w/2 - tw/2 -- Center of Screen - Center of Text
|
||||
if (x < 0) then x=0 end -- in case text is too wide
|
||||
|
||||
local bold = BOLD
|
||||
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text,bold + TEXT_SIZE)
|
||||
|
||||
-- Back
|
||||
if menu.BackId ~= 0 then
|
||||
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_MENU_TITLE,LCD_W_BUTTONS,LCD_H_BUTTONS,"Back",ctx.SelLine == dsmLib.BACK_BUTTON)
|
||||
end
|
||||
-- Next ?
|
||||
if menu.NextId ~= 0 then
|
||||
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON)
|
||||
end
|
||||
-- Prev?
|
||||
if menu.PrevId ~= 0 then
|
||||
GUI_Diplay_Button(0,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON)
|
||||
end
|
||||
|
||||
-- Debug into LCD
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),TEXT_SIZE + WARNING_COLOR) end -- Phase we are in
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_MENU,240,dsmLib.menu2String(menu),TEXT_SIZE + WARNING_COLOR) end -- Menu Info
|
||||
end
|
||||
|
||||
local function GUI_Display_Line_Menu(x,y,w,h,line,selected)
|
||||
local attr = (selected and INVERS) or 0 -- INVERS if line Selected
|
||||
local bold = 0
|
||||
local text = line.Text
|
||||
|
||||
if dsmLib.isSelectableLine(line) then
|
||||
-- Menu Line
|
||||
text = text .. " >"
|
||||
else -- SubHeaders and plain text lines
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
||||
local tw = openTx_lcd_sizeText(line.Text)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
||||
local tw = openTx_lcd_sizeText(line.Text)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
if (x < 0) then x=0 end -- in case text is too wide
|
||||
end
|
||||
|
||||
lcd.drawText(x,y, text, attr + bold + TEXT_SIZE)
|
||||
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
||||
local bold = 0
|
||||
|
||||
local y = LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||
local x = LCD_X_LINE_TITLE
|
||||
|
||||
---------- NAME Part
|
||||
local header = line.Text
|
||||
-- ONLY do this for Flight Mode (Right Align or Centered)
|
||||
if (dsmLib.isFlightModeLine(line)) then
|
||||
-- Display Header + Value together
|
||||
header = dsmLib.GetFlightModeValue(line)
|
||||
|
||||
-- Flight mode display attributes
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
||||
local tw = openTx_lcd_sizeText(header)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
||||
local tw = openTx_lcd_sizeText(header)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
if (x < 0) then x=0 end -- in case text is too wide
|
||||
else
|
||||
-- No Flight Mode, no effects here
|
||||
header = header .. ":"
|
||||
end
|
||||
|
||||
lcd.drawText(x, y, header, bold + TEXT_SIZE) -- display Line Header
|
||||
|
||||
--------- VALUE PART, Skip for Flight Mode since already show the value
|
||||
if not dsmLib.isFlightModeLine(line) then
|
||||
local attrib = 0
|
||||
|
||||
if selected then
|
||||
attrib = INVERS
|
||||
if editing then -- blink editing entry
|
||||
attrib = attrib + BLINK
|
||||
value = "[" .. value .. "]"
|
||||
end
|
||||
end
|
||||
|
||||
value = value .. " " .. (line.Format or "") -- Append % if needed
|
||||
lcd.drawText(LCD_X_LINE_VALUE,y, value, attrib + TEXT_SIZE) -- display value
|
||||
end
|
||||
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG,y, line.MinMaxDebug or "", TEXT_SIZE + WARNING_COLOR) end -- display debug
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_ShowBitmap(x,y,imgData)
|
||||
-- imgData format "bitmap.png|alt message"
|
||||
local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|'
|
||||
local imgName, imgMsg = f(), f()
|
||||
|
||||
if (LCD_W > 128) then
|
||||
lcd.drawText(x, y, imgMsg or "", TEXT_SIZE) -- Alternate Image MSG
|
||||
else
|
||||
local f = string.gmatch(imgMsg, '([^%:]+)') -- Iterator over values split by ':'
|
||||
local msg1,msg2 = f(), f()
|
||||
lcd.drawText(x, y, (msg1 or "")..":", TEXT_SIZE) -- Alternate Image MSG
|
||||
lcd.drawText(x, y+10, msg2 or "", TEXT_SIZE) -- Alternate Image MSG
|
||||
end
|
||||
|
||||
-- NO IMAGES in Text B&W
|
||||
--local imgPath = IMAGE_PATH .. (imgName or "")
|
||||
--local bitmap = Bitmap.open(imgPath)
|
||||
--if (bitmap~=nil) then
|
||||
-- lcd.drawBitmap(bitmap, x,y+20)
|
||||
--end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_Display()
|
||||
local ctx = DSM_Context
|
||||
lcd.clear()
|
||||
local header = "DSM Fwrd Programming "
|
||||
|
||||
if (TEXT_SIZE==SMLSIZE) then -- Small Screen no title
|
||||
header = ""
|
||||
end
|
||||
|
||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||
header = header .. ctx.RX.Name.." v"..ctx.RX.Version
|
||||
end
|
||||
|
||||
--Draw title
|
||||
if (TEXT_SIZE~=SMLSIZE) then -- ignore tool title small size screens
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
||||
else -- Small Screen
|
||||
lcd.drawText(20, LCD_Y_LOWER_BUTTONS+1, header, TEXT_SIZE)
|
||||
end
|
||||
--Draw RX Menu
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
if (ctx.isReset) then
|
||||
lcd.drawText(LCD_X_LINE_TITLE,50,"Waiting for RX to Restart", BLINK + TEXT_SIZE)
|
||||
else
|
||||
lcd.drawText(LCD_X_LINE_TITLE,50,"No compatible DSM RX...", BLINK + TEXT_SIZE)
|
||||
end
|
||||
else
|
||||
local menu = ctx.Menu
|
||||
if menu.Text ~= nil then
|
||||
|
||||
GUI_Display_Menu(menu)
|
||||
|
||||
for i = 0, dsmLib.MAX_MENU_LINES do
|
||||
local line = ctx.MenuLines[i]
|
||||
|
||||
if i == ctx.SelLine then
|
||||
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_TITLE,255,dsmLib.menuLine2String(line),TEXT_SIZE + WARNING_COLOR) end
|
||||
end
|
||||
|
||||
if line ~= nil and line.Type ~= 0 then
|
||||
if line.Type == LINE_TYPE.MENU then
|
||||
-- Menu Line
|
||||
GUI_Display_Line_Menu(LCD_X_LINE_MENU,LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*i), 350, LCD_Y_LINE_HEIGHT, line, i == ctx.SelLine)
|
||||
else
|
||||
-- list/value line
|
||||
local value = line.Val
|
||||
if line.Val ~= nil then
|
||||
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
|
||||
value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
||||
local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
|
||||
|
||||
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
||||
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_FIRST+LCD_Y_LINE_HEIGHT, imgData)
|
||||
end
|
||||
end
|
||||
|
||||
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
||||
end
|
||||
end -- if ~MENU
|
||||
end -- if Line[i]~=nil
|
||||
end -- for
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
|
||||
local inc = 0
|
||||
local Speed = getRotEncSpeed()
|
||||
|
||||
if Speed == ROTENC_MIDSPEED then
|
||||
inc = (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then
|
||||
inc = (15 * dir)
|
||||
else
|
||||
inc = dir
|
||||
end
|
||||
|
||||
return inc
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_HandleEvent(event, touchState)
|
||||
local ctx = DSM_Context
|
||||
local menu = ctx.Menu
|
||||
local menuLines = ctx.MenuLines
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
dsmLib.ReleaseConnection()
|
||||
else
|
||||
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
||||
ctx.MenuLines[ctx.EditLine].Val = originalValue
|
||||
dsmLib.Value_Write_Validate(menuLines[ctx.EditLine])
|
||||
else
|
||||
dsmLib.ChangePhase(PHASE.EXIT) -- Exit
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
dsmLib.Value_Add(line, GUI_RotEncVal(1))
|
||||
else -- not editing, move selected line to NEXT
|
||||
dsmLib.MoveSelectionLine(1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
dsmLib.Value_Add(line, GUI_RotEncVal(-1))
|
||||
else -- not editing, move selected line to PREV
|
||||
dsmLib.MoveSelectionLine(-1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER_LONG then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then
|
||||
-- reset the value to default
|
||||
dsmLib.Value_Default( menuLines[ctx.EditLine]) -- Update RX value as needed
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
|
||||
dsmLib.GotoMenu(menu.BackId,0)
|
||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
||||
dsmLib.GotoMenu(menu.NextId,0)
|
||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
||||
dsmLib.GotoMenu(menu.PrevId,0)
|
||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then
|
||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Next menu exist
|
||||
if (menuLines[ctx.SelLine].ValId==0xFFF1) then
|
||||
-- SPECIAL Simulation menu to Simulator
|
||||
GUI_SwitchToSIM()
|
||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
|
||||
-- SPECIAL Simulation menu to go to RX
|
||||
GUI_SwitchToRX()
|
||||
else
|
||||
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
||||
end
|
||||
else
|
||||
-- Editing a Line????
|
||||
if ctx.isEditing() then
|
||||
-- Change the Value and exit edit
|
||||
dsmLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
||||
else
|
||||
-- enter Edit the current line
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = menuLines[ctx.SelLine].Val
|
||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_screen_pos()
|
||||
-- osName in OpenTX is nil, otherwise is EDGETX
|
||||
local ver, radio, maj, minor, rev, osname = getVersion()
|
||||
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
|
||||
|
||||
IS_EDGETX = string.sub(osname,1,1) =='E'
|
||||
|
||||
if LCD_W == 480 then -- TX16
|
||||
-- use defaults in the script header
|
||||
elseif LCD_W == 128 then --TX12 (128x64) -- Still needs some work on the vertical
|
||||
DEBUG_ON_LCD = false -- no space for this
|
||||
TEXT_SIZE = SMLSIZE
|
||||
LCD_W_USABLE = 128
|
||||
|
||||
LCD_W_BUTTONS = 16
|
||||
LCD_H_BUTTONS = 10
|
||||
LCD_X_RIGHT_BUTTONS = 128 - LCD_W_BUTTONS - 3
|
||||
|
||||
LCD_X_LINE_MENU = 0
|
||||
-- X offsets for (Title: [Value] debugInfo) lines
|
||||
LCD_X_LINE_TITLE = 0
|
||||
LCD_X_LINE_VALUE = 75
|
||||
LCD_X_LINE_DEBUG = 110
|
||||
|
||||
LCD_Y_LINE_HEIGHT = 7
|
||||
LCD_Y_MENU_TITLE = 0
|
||||
LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 8
|
||||
LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + (7 * LCD_Y_LINE_HEIGHT)
|
||||
end
|
||||
end
|
||||
|
||||
local function GUI_Warning(event)
|
||||
lcd.clear()
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
--Draw title
|
||||
if (LCD_W > 128) then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, TITLE_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
||||
|
||||
lcd.drawText(100,20,"INFO", BOLD)
|
||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", TEXT_SIZE)
|
||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", TEXT_SIZE)
|
||||
lcd.drawText(5,80,"the TX before your start programming your RX.", TEXT_SIZE)
|
||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", TEXT_SIZE)
|
||||
|
||||
lcd.drawText(5,150,"TX Servo settings are sent to the RX during 'Initial Setup'", TEXT_SIZE)
|
||||
lcd.drawText(5,170,"as well as when using RX menu 'Relearn Servo Settings'", TEXT_SIZE)
|
||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD+TEXT_SIZE)
|
||||
|
||||
lcd.drawText(100,250," OK ", INVERS + BOLD + TEXT_SIZE)
|
||||
else
|
||||
lcd.drawText(0,15,"Make sure you setup your plane", TEXT_SIZE)
|
||||
lcd.drawText(0,22,"first. Wing and Tail type.", TEXT_SIZE)
|
||||
|
||||
lcd.drawText(0,30,"TX Servo settings are sent to ", TEXT_SIZE)
|
||||
lcd.drawText(0,37,"the RX during 'Initial Setup' and ", TEXT_SIZE)
|
||||
lcd.drawText(0,45,"ALWAYS TEST Gyro reactions", TEXT_SIZE)
|
||||
lcd.drawText(0,52,"before flying!!!", TEXT_SIZE)
|
||||
|
||||
lcd.drawText(10,0," OK ", INVERS + BOLD + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER then
|
||||
warningScreenON = false
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
init_screen_pos()
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
return dsmLib.StartConnection()
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
|
||||
|
||||
local function DSM_Run(event)
|
||||
local ctx = DSM_Context
|
||||
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
dsmLib.LOG_close()
|
||||
return 2
|
||||
end
|
||||
|
||||
if (warningScreenON) then
|
||||
return GUI_Warning(event)
|
||||
end
|
||||
|
||||
GUI_HandleEvent(event)
|
||||
|
||||
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
|
||||
|
||||
local refreshInterval = REFRESH_GUI_MS
|
||||
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
|
||||
if (ctx.EditLine or (ctx.Phase == PHASE.RX_VERSION)) then -- Editing or Requesting RX Version?
|
||||
ctx.Refresh_Display=true
|
||||
refreshInterval = 20 -- 200ms
|
||||
end
|
||||
|
||||
if (not IS_EDGETX) then -- OPENTX NEEDS REFRESH ON EVERY CYCLE
|
||||
GUI_Display()
|
||||
-- Refresh display only if needed and no faster than 500ms, utilize more CPU to speedup DSM communications
|
||||
elseif (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
|
||||
GUI_Display()
|
||||
ctx.Refresh_Display=false
|
||||
lastRefresh=getTime()
|
||||
end
|
||||
|
||||
if ctx.Phase == PHASE.EXIT_DONE then
|
||||
dsmLib.LOG_close()
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return { init=DSM_Init, run=DSM_Run }
|
708
Lua_scripts/DSM FwdPrg_05_Color.lua
Normal file
@ -0,0 +1,708 @@
|
||||
local toolName = "TNS|DSM Forward Prog v0.53 (Color+Touch) |TNE"
|
||||
local VERSION = "v0.53"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
------------------------------------------------------------------------------
|
||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
||||
-- separate the GUI from the DSM Forward programming engine/logic
|
||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
||||
|
||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
-- Rewrite/Enhancements By: Francisco Arzu
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local SIMULATION_ON = false -- FALSE: 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_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
||||
local IMAGE_PATH = DSMLIB_PATH .. "img/"
|
||||
|
||||
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON)
|
||||
|
||||
local PHASE = dsmLib.PHASE
|
||||
local LINE_TYPE = dsmLib.LINE_TYPE
|
||||
local DISP_ATTR = dsmLib.DISP_ATTR
|
||||
local DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
|
||||
local lastRefresh=0 -- Last time the screen was refreshed
|
||||
local REFRESH_GUI_MS = 300/10 -- 300ms.. Screen Refresh Rate.. to not waste CPU time (in 10ms units to be compatible with getTime())
|
||||
local originalValue = nil
|
||||
|
||||
local touchButtonArea = {}
|
||||
local EDIT_BUTTON = { DEFAULT=1001, DEC_10=1002, DEC_1=1003, INC_1=1004, INC_10=5, OK=1006, ESC=1007 }
|
||||
|
||||
local IS_EDGETX = false -- DEFAULT until Init changed it
|
||||
|
||||
local LCD_Y_MENU_TITLE = 20
|
||||
local LCD_W_MENU_TITLE = LCD_W-100
|
||||
|
||||
local LCD_X_LINE_MENU = 30
|
||||
local LCD_W_LINE_MENU = 350
|
||||
|
||||
local LCD_X_LINE_TITLE = 30
|
||||
local LCD_X_LINE_VALUE = 230
|
||||
local LCD_X_LINE_DEBUG = 390
|
||||
|
||||
|
||||
local LCD_Y_LINE_START = LCD_Y_MENU_TITLE + 30
|
||||
local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27
|
||||
|
||||
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT)
|
||||
|
||||
-- TOOL BG COLOR
|
||||
local LCD_TOOL_BGCOLOR = TEXT_BGCOLOR
|
||||
-- TOOL HEADER
|
||||
local LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR
|
||||
local LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR
|
||||
-- MENU HEADER
|
||||
local LCD_MENU_COLOR = MENU_TITLE_COLOR
|
||||
local LCD_MENU_BGCOLOR = MENU_TITLE_BGCOLOR
|
||||
-- LINE SELECTED
|
||||
local LCD_SELECTED_COLOR = TEXT_INVERTED_COLOR
|
||||
local LCD_SELECTED_BGCOLOR = TEXT_INVERTED_BGCOLOR
|
||||
local LCD_EDIT_BGCOLOR = MENU_TITLE_BGCOLOR -- WARNING_COLOR
|
||||
-- NORMAL TEXT
|
||||
local LCD_NORMAL_COLOR = TEXT_COLOR
|
||||
local LCD_DISABLE_COLOR = TEXT_DISABLE_COLOR
|
||||
local LCD_DEBUG_COLOR = LINE_COLOR
|
||||
-- NORMAL BOX FRAME COLOR
|
||||
local LCD_BOX_COLOR = TEXT_DISABLE_COLOR
|
||||
|
||||
|
||||
local warningScreenON = true
|
||||
|
||||
|
||||
--------------------- lcd.sizeText replacement -------------------------------------------------
|
||||
-- EdgeTx dont have lcd.sizeText, so we do an equivalent one using the string length and 5px per character
|
||||
local function my_lcd_sizeText(s)
|
||||
-- return: If IS_EDGETX then lcd.sizeText() else string.len()
|
||||
return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10)
|
||||
end
|
||||
|
||||
|
||||
local function GUI_SwitchToRX()
|
||||
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
|
||||
local dsmChannelInfo, description = dsmLib.CreateDSMPortChannelInfo()
|
||||
|
||||
dsmLib.ReleaseConnection()
|
||||
dsmLib.LOG_close()
|
||||
|
||||
SIMULATION_ON = false
|
||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
|
||||
DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library
|
||||
dsmLib.StartConnection()
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
local function GUI_SwitchToSIM()
|
||||
dsmLib.ReleaseConnection()
|
||||
dsmLib.LOG_close()
|
||||
|
||||
SIMULATION_ON = true
|
||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
|
||||
DSM_Context = dsmLib.DSM_Context
|
||||
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
dsmLib.StartConnection()
|
||||
DSM_Context.Refresh_Display = true
|
||||
end
|
||||
|
||||
|
||||
--------------------- Toucch Button Helpers ------------------------------------------------------------
|
||||
local function GUI_addTouchButton(x,y,w,h,line)
|
||||
-- Add new button info to end of the array
|
||||
touchButtonArea[#touchButtonArea+1] = {x=x, y=y, w=w, h=h, line=line}
|
||||
end
|
||||
|
||||
local function GUI_getTouchButton(x,y)
|
||||
for i = 1, #touchButtonArea do
|
||||
local button = touchButtonArea[i]
|
||||
-- is the coordinate inside the button area??
|
||||
if (x >= button.x and x <= (button.x+button.w) and y >= button.y and (y <= button.y+button.h)) then
|
||||
return button.line
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function GUI_clearTouchButtons()
|
||||
touchButtonArea = {}
|
||||
end
|
||||
|
||||
---------- Return Color to display Menu Lines ----------------------------------------------------------------
|
||||
local function GUI_GetTextColor(lineNum)
|
||||
local ctx = DSM_Context
|
||||
local txtColor = LCD_NORMAL_COLOR
|
||||
-- Gray Out any other line except the one been edited
|
||||
if (ctx.isEditing() and ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
|
||||
return txtColor
|
||||
end
|
||||
|
||||
local function GUI_GetFrameColor(lineNum) -- Frame Color for Value/Menu Boxes
|
||||
local ctx = DSM_Context
|
||||
local txtColor = LCD_BOX_COLOR
|
||||
-- Gray Out any other line except the one been edited
|
||||
if (ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
|
||||
return txtColor
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
-- Display Text inside a Rectangle. Inv: true means solid rectangle, false=only perimeter
|
||||
local function GUI_Display_Boxed_Text(lineNum,x,y,w,h,text,inv, isNumber)
|
||||
local ctx = DSM_Context
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local frameColor = GUI_GetFrameColor(lineNum)
|
||||
-- If editing this lineNum, chose EDIT Color, else SELECTED Color
|
||||
local selectedBGColor = (ctx.EditLine==lineNum and LCD_EDIT_BGCOLOR) or LCD_SELECTED_BGCOLOR
|
||||
|
||||
if (inv) then
|
||||
txtColor = LCD_SELECTED_COLOR
|
||||
lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor)
|
||||
else
|
||||
lcd.drawRectangle(x-5, y-2, w, h, frameColor)
|
||||
end
|
||||
if (isNumber) then
|
||||
lcd.drawNumber(x+w-10 , y, text, txtColor + RIGHT)
|
||||
else
|
||||
lcd.drawText(x , y, text, txtColor)
|
||||
end
|
||||
end
|
||||
|
||||
------ Display Pre/Next/Back buttons
|
||||
local function GUI_Diplay_Button(x,y,w,h,text,selected)
|
||||
GUI_Display_Boxed_Text(-1,x,y,w,h,text,selected, false)
|
||||
end
|
||||
|
||||
------ Display MENU type of lines (Navigation, SubHeaders, and plain text comments)
|
||||
local function GUI_Display_Line_Menu(lineNum,line,selected)
|
||||
-- Menu Lines can be navidation to other Menus (if Selectable)
|
||||
-- Or SubHeaders or Messages
|
||||
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||
local x = LCD_X_LINE_MENU
|
||||
|
||||
if dsmLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes
|
||||
GUI_Display_Boxed_Text(lineNum,x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT, line.Text,selected, false)
|
||||
GUI_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum)
|
||||
else
|
||||
-- Non Selectable Menu Lines, plain text
|
||||
-- Can be use for sub headers or just regular text lines (like warnings)
|
||||
|
||||
local bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
||||
local tw = my_lcd_sizeText(line.Text)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
||||
local tw = my_lcd_sizeText(line.Text)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
|
||||
lcd.drawText(x, y, line.Text, txtColor + bold)
|
||||
end
|
||||
end
|
||||
|
||||
------ Display NAME : VALUES type of lines
|
||||
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
||||
-- This Displays Name and Value Pairs
|
||||
local txtColor = GUI_GetTextColor(lineNum)
|
||||
local bold = 0
|
||||
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||
local x = LCD_X_LINE_TITLE
|
||||
|
||||
---------- NAME Part
|
||||
local header = line.Text
|
||||
-- ONLY do this for Flight Mode (Right Align or Centered)
|
||||
if (dsmLib.isFlightModeLine(line)) then
|
||||
-- Display Header + Value together
|
||||
header = dsmLib.GetFlightModeValue(line)
|
||||
|
||||
-- Bold Text???
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
||||
local tw = my_lcd_sizeText(header)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
||||
local tw = my_lcd_sizeText(header)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
else
|
||||
-- No Flight Mode, no effects here
|
||||
header = header .. ":"
|
||||
end
|
||||
|
||||
lcd.drawText(x, y, header, txtColor + bold) -- display Line Header
|
||||
|
||||
--------- VALUE PART, Skip for Flight Mode since already show the value
|
||||
if not dsmLib.isFlightModeLine(line) then
|
||||
if dsmLib.isSelectableLine(line) then
|
||||
--if (editing) then -- Any Special color/effect when editing??
|
||||
-- value = "["..value .. "]"
|
||||
--end
|
||||
-- Can select/edit value, Box it
|
||||
local tw = math.max(my_lcd_sizeText(value)+10,45) -- Width of the Text in the lcd
|
||||
GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected, not dsmLib.isListLine(line))
|
||||
GUI_addTouchButton(LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,lineNum)
|
||||
|
||||
lcd.drawText(LCD_X_LINE_VALUE+tw+5, y, (line.Format or ""), txtColor + bold)
|
||||
else -- Not Editable, Plain Text
|
||||
lcd.drawText(LCD_X_LINE_VALUE, y, value, txtColor)
|
||||
end
|
||||
end
|
||||
|
||||
-- Debug info for line Value RANGE when Debug on LCD
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG, y, line.MinMaxDebug or "", SMLSIZE + LCD_DEBUG_COLOR) end -- display debug Min/Max
|
||||
end
|
||||
|
||||
local function GUI_Display_Menu(menu)
|
||||
local ctx = DSM_Context
|
||||
local w= LCD_W_MENU_TITLE
|
||||
|
||||
-- Center Header
|
||||
local tw = my_lcd_sizeText(menu.Text)
|
||||
local x = w/2 - tw/2 -- Center of Screen - Center of Text
|
||||
|
||||
lcd.drawFilledRectangle(0, LCD_Y_MENU_TITLE-2, w, LCD_Y_LINE_HEIGHT-2, LCD_MENU_BGCOLOR)
|
||||
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text, LCD_MENU_COLOR + BOLD)
|
||||
|
||||
-- Back Button
|
||||
if menu.BackId ~= 0 then
|
||||
GUI_Diplay_Button(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,"Back",ctx.SelLine == dsmLib.BACK_BUTTON)
|
||||
GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,dsmLib.BACK_BUTTON)
|
||||
end
|
||||
-- Next Button
|
||||
if menu.NextId ~= 0 then
|
||||
GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON)
|
||||
GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.NEXT_BUTTON)
|
||||
end
|
||||
-- Prev Button
|
||||
if menu.PrevId ~= 0 then
|
||||
GUI_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON)
|
||||
GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.PREV_BUTTON)
|
||||
end
|
||||
|
||||
-- Debug on LCD, Show the menu Indo and Phase we are on
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),SMLSIZE+LCD_DEBUG_COLOR) end -- Phase we are in
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(0,240,dsmLib.menu2String(menu),SMLSIZE+LCD_DEBUG_COLOR) end -- Menu Info
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Display the EDIT mode buttons when editing a value
|
||||
|
||||
local function GUI_Display_Edit_Buttons(line)
|
||||
GUI_clearTouchButtons() -- Only this buttons can be touched
|
||||
local x = 15 -- Inittial X position
|
||||
local w = 55 -- Width of the buttons
|
||||
|
||||
local showPrev = line.Val > line.Min
|
||||
local showNext = line.Val < line.Max
|
||||
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,"ESC",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.ESC)
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," Def",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT)
|
||||
|
||||
x=x+w+10
|
||||
if (not dsmLib.isListLine(line)) then
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," << ",showPrev)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_10)
|
||||
end
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," <",showPrev)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_1)
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >",showNext)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1)
|
||||
|
||||
x=x+w+10
|
||||
if (not dsmLib.isListLine(line)) then
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >>",showNext)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_10)
|
||||
end
|
||||
|
||||
x=x+w+10
|
||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," OK",true)
|
||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.OK)
|
||||
|
||||
end
|
||||
|
||||
local function GUI_ShowBitmap(x,y,imgData)
|
||||
-- imgData format "bitmap.png|alt message"
|
||||
local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|'
|
||||
local imgName, imgMsg = f(), f()
|
||||
|
||||
lcd.drawText(x, y, imgMsg or "") -- Alternate Image MSG
|
||||
|
||||
local imgPath = IMAGE_PATH .. (imgName or "")
|
||||
local bitmap = Bitmap.open(imgPath)
|
||||
if (bitmap~=nil) then
|
||||
lcd.drawBitmap(bitmap, x,y+20)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_Display()
|
||||
local ctx = DSM_Context
|
||||
lcd.clear(LCD_TOOL_BGCOLOR)
|
||||
GUI_clearTouchButtons()
|
||||
|
||||
if LCD_W == 480 then
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||
header = header .. "RX "..ctx.RX.Name.." v"..ctx.RX.Version
|
||||
end
|
||||
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
||||
--Draw RX Menu
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
if (ctx.isReset) then
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,"Waiting for RX to Restart", BLINK)
|
||||
else
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,"No compatible DSM RX...", BLINK)
|
||||
end
|
||||
else
|
||||
local menu = ctx.Menu
|
||||
|
||||
|
||||
if menu.Text ~= nil then
|
||||
GUI_Display_Menu(menu)
|
||||
|
||||
for i = 0, dsmLib.MAX_MENU_LINES do
|
||||
local line = ctx.MenuLines[i]
|
||||
|
||||
if i == ctx.SelLine then
|
||||
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
|
||||
if (DEBUG_ON_LCD) then lcd.drawText(0,255,dsmLib.menuLine2String(line),SMLSIZE + LCD_DEBUG_COLOR) end
|
||||
end
|
||||
|
||||
if line ~= nil and line.Type ~= 0 then
|
||||
if line.Type == LINE_TYPE.MENU then
|
||||
GUI_Display_Line_Menu(i, line, i == ctx.SelLine)
|
||||
else
|
||||
if line.Val ~= nil then
|
||||
local value = line.Val
|
||||
|
||||
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
|
||||
value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
||||
local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
|
||||
|
||||
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
||||
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_START, imgData)
|
||||
end
|
||||
end
|
||||
|
||||
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
||||
end
|
||||
end -- if ~MENU
|
||||
end -- if Line[i]~=nil
|
||||
end -- for
|
||||
|
||||
if IS_EDGETX and ctx.isEditing() then
|
||||
-- Display Touch button for Editing values
|
||||
GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine])
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Different Resolution.. Maybe just adjusting some of the constants will work, adjust it in DSM_Init??
|
||||
-- LCD_X_LINE_TITLE, LCD_Y_LINE_START, etc
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,"Only supported in Color Radios of 480 resolution", BLINK)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
|
||||
local inc = 0
|
||||
local Speed = getRotEncSpeed()
|
||||
|
||||
if Speed == ROTENC_MIDSPEED then inc = (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then inc = (15 * dir)
|
||||
else inc = dir end
|
||||
|
||||
return inc
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
-- Translate Tap/Touch of EDIT buttons to equivalent Key events
|
||||
local function GUI_Translate_Edit_Buttons(button)
|
||||
local event = EVT_TOUCH_TAP
|
||||
local editInc = nil
|
||||
|
||||
if (button==EDIT_BUTTON.ESC) then -- ESC
|
||||
event = EVT_VIRTUAL_EXIT
|
||||
elseif (button==EDIT_BUTTON.DEFAULT) then -- Default
|
||||
event = EVT_VIRTUAL_ENTER_LONG
|
||||
elseif (button==EDIT_BUTTON.DEC_10) then -- -10
|
||||
event = EVT_VIRTUAL_PREV
|
||||
editInc = -10
|
||||
elseif (button==EDIT_BUTTON.DEC_1) then -- -1
|
||||
event = EVT_VIRTUAL_PREV
|
||||
editInc = -1
|
||||
elseif (button==EDIT_BUTTON.INC_1) then -- +1
|
||||
event = EVT_VIRTUAL_NEXT
|
||||
editInc = 1
|
||||
elseif (button==EDIT_BUTTON.INC_10) then -- + 10
|
||||
event = EVT_VIRTUAL_NEXT
|
||||
editInc = 10
|
||||
elseif (button==EDIT_BUTTON.OK) then -- OK
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
else
|
||||
|
||||
end
|
||||
|
||||
return event, editInc
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Handle Events comming from the GUI
|
||||
local function GUI_HandleEvent(event, touchState)
|
||||
local ctx = DSM_Context
|
||||
local menu = ctx.Menu
|
||||
local menuLines = ctx.MenuLines
|
||||
local editInc = nil
|
||||
|
||||
if (IS_EDGETX) then
|
||||
if (event == EVT_TOUCH_TAP and ctx.isEditing()) then -- Touch and Editing
|
||||
local button = GUI_getTouchButton(touchState.x, touchState.y)
|
||||
if (button) then
|
||||
event, editInc = GUI_Translate_Edit_Buttons(button)
|
||||
end
|
||||
end
|
||||
|
||||
if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",dsmLib.phase2String(ctx.Phase),touchState.x, touchState.y) end
|
||||
local button = GUI_getTouchButton(touchState.x, touchState.y)
|
||||
if button then
|
||||
-- Found a valid line
|
||||
ctx.SelLine = button
|
||||
ctx.Refresh_Display=true
|
||||
if event == EVT_TOUCH_TAP then -- EVT_TOUCH_FIRST only move focus
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
end
|
||||
end
|
||||
end
|
||||
end -- IS_EDGETX
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
dsmLib.ReleaseConnection() -- Just Exit the Script
|
||||
else
|
||||
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
||||
local line = ctx.MenuLines[ctx.EditLine]
|
||||
line.Val = originalValue
|
||||
dsmLib.Value_Write_Validate(line)
|
||||
else
|
||||
dsmLib.ChangePhase(PHASE.EXIT)
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(1))
|
||||
else -- not editing, move selected line to NEXT
|
||||
dsmLib.MoveSelectionLine(1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
||||
local line=ctx.MenuLines[ctx.EditLine]
|
||||
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(-1))
|
||||
else -- not editing, move selected line to PREV
|
||||
dsmLib.MoveSelectionLine(-1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER_LONG then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
|
||||
if ctx.isEditing() then
|
||||
-- reset the value to default
|
||||
dsmLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
ctx.Refresh_Display=true
|
||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",dsmLib.phase2String(ctx.Phase), ctx.SelLine) end
|
||||
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
|
||||
dsmLib.GotoMenu(menu.BackId,0)
|
||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
||||
dsmLib.GotoMenu(menu.NextId,0)
|
||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
||||
dsmLib.GotoMenu(menu.PrevId,0)
|
||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value
|
||||
|
||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Navigate to Menu
|
||||
if (menuLines[ctx.SelLine].ValId==0xFFF1) then
|
||||
-- SPECIAL Simulation menu to Simulator
|
||||
GUI_SwitchToSIM()
|
||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
|
||||
-- SPECIAL Simulation menu to go to RX
|
||||
GUI_SwitchToRX()
|
||||
else
|
||||
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
||||
end
|
||||
else -- Enter on a Value
|
||||
if ctx.isEditing() then -- already editing a Line????
|
||||
dsmLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
||||
else -- Edit the current value
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = menuLines[ctx.SelLine].Val
|
||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_colors()
|
||||
-- osName in OpenTX is nil, otherwise is EDGETX
|
||||
local ver, radio, maj, minor, rev, osname = getVersion()
|
||||
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
|
||||
|
||||
IS_EDGETX = string.sub(osname,1,1) == 'E'
|
||||
|
||||
if (IS_EDGETX and USE_SPECKTRUM_COLORS) then
|
||||
-- SPECKTRUM COLORS (only works on EDGETX)
|
||||
LCD_TOOL_BGCOLOR = LIGHTWHITE
|
||||
-- TOOL HEADER
|
||||
LCD_TOOL_HDR_COLOR = WHITE
|
||||
LCD_TOOL_HDR_BGCOLOR = DARKBLUE
|
||||
-- MENU HEADER
|
||||
LCD_MENU_COLOR = WHITE
|
||||
LCD_MENU_BGCOLOR = DARKGREY
|
||||
-- LINE SELECTED
|
||||
LCD_SELECTED_COLOR = WHITE
|
||||
LCD_SELECTED_BGCOLOR = ORANGE
|
||||
LCD_EDIT_BGCOLOR = RED
|
||||
-- NORMAL TEXT
|
||||
LCD_NORMAL_COLOR = BLACK
|
||||
LCD_DISABLE_COLOR = LIGHTGREY
|
||||
LCD_DEBUG_COLOR = BLUE
|
||||
-- NORMAL BOX FRAME COLOR
|
||||
LCD_BOX_COLOR = LIGHTGREY
|
||||
end
|
||||
end
|
||||
|
||||
local function GUI_Warning(event,touchState)
|
||||
lcd.clear(LCD_TOOL_BGCOLOR)
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
||||
|
||||
lcd.drawText(100,20,"INFO", BOLD)
|
||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", 0)
|
||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", 0)
|
||||
lcd.drawText(5,80,"the TX before your start Fwrd programming your RX.", 0)
|
||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", 0)
|
||||
|
||||
lcd.drawText(5,150,"TX Gyro Servo settings are sent to the RX during 'Initial Setup'", 0)
|
||||
lcd.drawText(5,170,"as well as when using RX 'Relearn Servo Settings'", 0)
|
||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD)
|
||||
|
||||
lcd.drawText(100,250," OK ", INVERS + BOLD)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER or event == EVT_TOUCH_TAP then
|
||||
warningScreenON = false
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
init_colors()
|
||||
dsmLib.Init(toolName) -- Initialize Library
|
||||
return dsmLib.StartConnection()
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
local function DSM_Run(event,touchState)
|
||||
local ctx = DSM_Context
|
||||
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
dsmLib.LOG_close()
|
||||
return 2
|
||||
end
|
||||
|
||||
if (warningScreenON) then
|
||||
return GUI_Warning(event,touchState)
|
||||
end
|
||||
|
||||
GUI_HandleEvent(event,touchState)
|
||||
|
||||
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
|
||||
|
||||
local refreshInterval = REFRESH_GUI_MS
|
||||
|
||||
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
|
||||
if (ctx.Phase == PHASE.RX_VERSION) then -- Requesting RX Message Version usea BLINK?
|
||||
ctx.Refresh_Display=true
|
||||
refreshInterval = 20 -- 200ms
|
||||
end
|
||||
|
||||
if (not IS_EDGETX) then -- OPENTX NEEDS REFRESH ON EVERY CYCLE
|
||||
GUI_Display()
|
||||
-- Refresh display only if needed and no faster than 300ms, utilize more CPU to speedup DSM communications
|
||||
elseif (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
|
||||
GUI_Display()
|
||||
ctx.Refresh_Display=false
|
||||
lastRefresh=getTime()
|
||||
end
|
||||
|
||||
if ctx.Phase == PHASE.EXIT_DONE then
|
||||
dsmLib.LOG_close()
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return { init=DSM_Init, run=DSM_Run }
|
467
Lua_scripts/DSMLIB/DSM Fwd Prog Protocol.md
Normal file
@ -0,0 +1,467 @@
|
||||
# Forward Programing Protocol
|
||||
|
||||
## Introduction
|
||||
DSM, DSMX and DSM Forward Programming are propietary protocol from the **Spektrum** radio brand. Since they don't make this information public, we have to reverse engineer it by analyzing the data exchanged between the RX and TX.
|
||||
|
||||
This document descrives what we know so far.
|
||||
|
||||
Thanks to **Pascal Langer** (Author of the Multi-Module) for the initial reverse engineering of the protocol and first version of the code that has been used for a while (Version 0.2)
|
||||
|
||||
Thanks to **Francisco Arzu** for taking the time to continue the work on reverse engineering, documenting and making the code more understandable.
|
||||
|
||||
New Capabilities in Version 0.5
|
||||
- Log files of the conversation between RX/TX
|
||||
- Improve the GUI (EdgeTX touch screen)
|
||||
- Reversed engineer other things to make it work completly.
|
||||
|
||||
# Menu Title and Lines
|
||||
|
||||
The menu to be displayed is stored at the RX, the GUI only renders the menu title and menu lines received. The tipical conversation with the RX will be to ask for a menu (using the menuId number), and then wait for the data to come. The first thing will be the Menu (header) data, later we request the next 6 lines (one at a time), and optionally the values for each line.
|
||||
|
||||
A typical exchange will look like this in the log:
|
||||
|
||||
SEND DSM_getMenu(MenuId=0x1010 LastSelectedLine=0)
|
||||
RESPONSE Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
||||
SEND DSM_getFirstMenuLine(MenuId=0x1010)
|
||||
RESPONSE MenuLine: L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ]
|
||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=0)
|
||||
RESPONSE MenuLine: L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ]
|
||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=1)
|
||||
RESPONSE MenuLine: L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ]
|
||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=2)
|
||||
RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
|
||||
|
||||
## Menu
|
||||
|
||||
The menu has the following information:
|
||||
|
||||
Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
||||
|
||||
- `MenuId`: The menu ID number of the menu (hex, 16 bit number)
|
||||
- `PrevId`: The menu ID of the previous menu (for navigation), Log show as `"P="`
|
||||
- `NextId`: The menu ID of the next menu (for navigation), Log shows as `"N="`
|
||||
- `BackId`: The menu ID of the back menu (for navigation), Log shows as `"B="`
|
||||
- `TextId`: The message number to display (16 bits, Hex). Log shows as [`0xXX`] after the message.
|
||||
- `Text`: Retrived using the `TextId` from the script message `Text` array.
|
||||
|
||||
## Menu Lines
|
||||
|
||||
The menu lines has the following information:
|
||||
|
||||
L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1021 ]
|
||||
L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ]
|
||||
L[#2 T=LM VId=0x1002 Text="AS3X"[0x1DC] Val=1|"Act" NL=(0->1,0,S=3) [3->4,3] MId=0x1021 ]
|
||||
|
||||
- `MenuId`: of the menu they beling to. Log show as `"MId="` at the end.
|
||||
- `LineNum`: Line number (0..5). The line number in the screen. Log show as # in the beginning
|
||||
- `Type`: Type of Line, Log shows as `"T="` (explanation later)
|
||||
- `TextId`: The message number to display (16 bits, Hex). Log shows as [`0xXXXX`] after the message.
|
||||
- `Text`: Retrived using the `TextId` from the script message `Text` array.
|
||||
- `ValueId`: The value or menu ID of the line. Log shows as `"VId="` (16 bits, Hex).
|
||||
- `Value Range`: Shows as [`Min`->`Max`, `Default`]. This is the RAW data comming from the RX
|
||||
- `NL`: Computed Normalized LIST (0 reference) for List Values. Source is the RAW range. For example, for lines of list of values. `[3->4,3]` is tranlated to `NL=(0->1,0,S=3)` since the value is also normalize to 0. `"S="` means the initial entry in the `List_Text` array
|
||||
- `Val`: Current value for line who hold data. Relative to 0 for List Values. For List Values, the log will show the translation of the value to display text. example: `Val=1|"Act"` that is coming from `List_Value[4]`
|
||||
|
||||
## Type of Menu Lines
|
||||
|
||||
- `LINE_TYPE.MENU (Log: "T=M")`: This could be regular text or a navigation to another menu. if `ValueId` is the same as the current MenuId (`MId=`), is a plain text line (navigation to itself). If the `ValueId` is not the current menuId, then `ValueId` is the MenuId to navigate to.
|
||||
|
||||
We have found only one exception to the plain text rule, a true navigation to itself, in that case, in the text of the menu, you can use the "/M" flag at the end of the text to force it to be a menu button.
|
||||
|
||||
Example, FM_Channel is a navigation to menuId=0x7CA6.
|
||||
|
||||
L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ]
|
||||
|
||||
- `LINE_TYPE.LIST_MENU_NC (Log T=LM_nc)`: This is a line that shows as text in the GUI. The numeric value is translated to the proper text. The range is important, since it descrives the range of posible values. No incremental RX changes, only at the end.
|
||||
|
||||
Example: List of Values, List_Text[] starts at 53, ends at 85, with a default of 85. When normalized to 0, is a range from 0->32 for the numeric value. The Display value `Aux1` is retrive from `List_Text[6+53]`.
|
||||
|
||||
L[#0 T=LM_nc VId=0x1000 Text="FM Channel"[0x78] Val=6|"Aux1" NL=(0->32,0,S=53) [53->85,53] MId=0x7CA6 ]
|
||||
|
||||
- `LINE_TYPE.LIST_MENU_TOG (Log T=L_tog)`: Mostly the same as LIST_MENU_NC, but is just 2 values. (ON/OFF, Ihn/Act, etc). Should be a toggle in the GUI.
|
||||
|
||||
L[#2 T=LM_tog VId=0x1002 Text="AS3X"[0x1DC] Val=1|"Act" NL=(0->1,0,S=3) [3->4,3] MId=0x1021 ]
|
||||
|
||||
- `LINE_TYPE.LIST_MENU (Log T=LM)`: Mostly the same as LIST_MENU_NC, but incremental changes to the RX. Some times, it comes with a strange range `[0->244,Default]`. Usually this means that the values are not contiguos range; usually Ihn + Range. Still haven't found where in the data the correct range comes from.
|
||||
|
||||
Example: Valid Values: 3, 176->177 (Inh, Self-Level/Angle Dem, Envelope)
|
||||
L[#3 T=LM VId=0x1003 Text="Safe Mode"[0x1F8] Val=176|"Self-Level/Angle Dem" NL=(0->244,3,S=0) [0->244,3] MId=0x1021 ]
|
||||
|
||||
- `LINE_TYPE.VALUE_NUM_I8_NC (Log: "T=V_nc")`: This line is editable, but is not updated to the RX incrementally, but only at the end. The Flight Mode line is of this type, so we have to check the TextId to differenciate between Flight mode and an Editable Value.
|
||||
Fligh Mode TextId is between 0x8000 and 0x8003
|
||||
|
||||
Example, Flight mode comes from Variable ValId=0x1000, with current value of 1. Range of the Value is 0..10.
|
||||
|
||||
L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1021 ]
|
||||
|
||||
|
||||
- `LINE_TYPE.VALUE_NUM_I8 (Log T=V_i8)`: 8 bit number (1 byte)
|
||||
- `LINE_TYPE.VALUE_NUM_I16' (Log T=V_i16)`: 16 Bit number (2 bytes)
|
||||
- `LINE_TYPE.VALUE_NUM_SI16 (Log T=V_si16)`: Signed 16 bit number (2 bytes)
|
||||
- `LINE_TYPE.VALUE_PERCENT (Log T=L_%)`: Shows a Percent Value. 1 Byte value.
|
||||
- `LINE_TYPE.VALUE_DEGREES (Log T=L_de)`: Shows a Degrees VAlue. 1 Byte value.
|
||||
|
||||
|
||||
## LIST_TYPE Bitmap
|
||||
TYPE|Sum|Hex|7 Signed|6 Valid Min/Max??|5 No-Inc-Changing|4 Menu|3 List-Menu|2 text / number|1|0 - 16 bits
|
||||
|-|-|-|-|-|-|-|-|-|-|-
|
||||
|MENU|Text|0x1C|0|0|0|1|1|1|0|0
|
||||
|LIST_MENU|Text|0x0C|0|0|0|0|1|1|0|0
|
||||
|LIST_MENU_TOG|Text|0x4C|0|1|0|0|1|1|0|0
|
||||
|LIST_MENU_NC|Text, NC|0x6C|0|1|1|0|1|1|0|0
|
||||
|VALUE_NUM_I8_NC|I8, NC|0x60|0|1|1|0|0|0|0|0
|
||||
|VALUE_PERCENT|S8|0xC0|1|1|0|0|0|0|0|0
|
||||
|VALUE_DEGREES|S8 NC|0xE0|1|1|1|0|0|0|0|0
|
||||
|VALUE_NUM_I8|I8|0x40|0|1|0|0|0|0|0|0
|
||||
|VALUE_NUM_I16|I16|0x41|0|1|0|0|0|0|0|1
|
||||
|VALUE_NUM_SI16|S16|0xC1|1|1|0|0|0|0|0|1
|
||||
|
||||
|
||||
## Important Behavioral differences when updating values
|
||||
|
||||
Values who are editable, are updated to RX as they change. For example, when changing attitude trims, the servo moves as we change the value in real-time.
|
||||
|
||||
LIST_MENU_NC, VALUE_NUM_I8_NC don't update the RX as it changes. It changes only in the GUI, and only update the RX at the end when confirmed the value. (NO-INC-CHANGES Bit)
|
||||
|
||||
After finishing updating a value, a validation command is sent. RX can reject the current value, and will change it to the nearest valid value.
|
||||
|
||||
## Special Menus
|
||||
|
||||
Seems like menuId=0x0001 is special. When you navigate to this menu, the RX reboots.
|
||||
When this happens, we need to start from the beginning as if it was a new connection.
|
||||
|
||||
# Send and Receive messages
|
||||
|
||||
To comunicate with the Multi-Module, Lua scripts in OpenTx/EdgeTx has access to the `Multi_Buffer`. Writting to it will send data to RX, received data will be read from it.
|
||||
|
||||
For our specific case, this is how the Multi_Buffer is used:
|
||||
|
||||
|0..2|3|4..9|10..25
|
||||
|--|--|--|--
|
||||
|DSM|0x70+len|TX->RX data|RX->TX Data
|
||||
|
||||
To write a new DSM Fwd Programing command, write the data to address 4..9, and later set the address 3 with the length.
|
||||
|
||||
When receiving data, address 10 will have the message type we are receiving, or 0 if nothing has been received.
|
||||
|
||||
## Starting a new DSM Forward programming Connection
|
||||
|
||||
- Write 0x00 at address 3
|
||||
- Write 0x00 at address 10
|
||||
- Write "DSM" at address 0..2
|
||||
|
||||
## Disconnect
|
||||
|
||||
- Write 0x00 at address 0
|
||||
|
||||
|
||||
# Request Messages (TX->RX)
|
||||
|
||||
## DSM_sendHeartbeat()
|
||||
keep connection open.. We need to send it every 2-3 seconds, otherwise the RX will force close the connection by sending the TX an Exit_Confirm message.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg| Len? | ?? | ??
|
||||
0x00|0x04|0x00|0x00
|
||||
|
||||
SEND DSM_sendHeartbeat()
|
||||
DSM_SEND: [00 04 00 00 ]
|
||||
|
||||
## DSM_getRxVersion()
|
||||
Request the RX information
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg| Len? | ?? | ?? |??|??
|
||||
0x11|0x06|0x00|0x14|0x00|0x00
|
||||
|
||||
SEND DSM_getRxVersion()
|
||||
DSM_SEND: [11 06 00 14 00 00 ]
|
||||
|
||||
## DSM_getMainMenu()
|
||||
Request data for the main menu of the RX
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg| Len? | ?? | ?? |??|??
|
||||
0x12|0x06|0x00|0x14|0x00|0x00
|
||||
|
||||
SEND DSM_getMainMenu()
|
||||
DSM_SEND: [12 06 00 14 00 00 ]
|
||||
|
||||
|
||||
## DSM_getMenu(menuId, lastSelLine)
|
||||
Request data for Menu with ID=`menuId`. lastSelLine is the line that was selected to navigate to that menu. Most menus works with 0, but for some special "Enter Bind Mode", "Factory Reset", "Save to Backup" they will not work if we send 0, has to be the line who was selected in the confirmation menu line "Apply".
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (line#)??| LSB (line#)
|
||||
0x16|0x06|0x10|0x60|0x00|0x01
|
||||
|
||||
SEND DSM_getMenu(MenuId=0x1060 LastSelectedLine=1)
|
||||
DSM_SEND: [16 06 10 60 00 01 ]
|
||||
|
||||
## DSM_getFirstMenuLine(menuId)
|
||||
Request the first line of a menu identified as `menuId`. The response will be the first line of the menu. Some times, it return lines shown as `'MenuUknownLine_0x05'` that we still are trying to understand what they are for.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (menuId) | LSB (MenuId)
|
||||
0x13|0x04|0x10|0x60
|
||||
|
||||
SEND DSM_getFirstMenuLine(MenuId=0x1000)
|
||||
DSM_SEND: [13 04 10 00 ]
|
||||
|
||||
## DSM_getNextMenuLine(menuId, curLine)
|
||||
Request the retrival of the next line following the current line. Response is either the next line, or the next value, or nothing.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (line#)??| LSB (line#)
|
||||
0x14|0x06|0x10|0x60|0x00|0x01
|
||||
|
||||
SEND DSM_getNextLine(MenuId=0x1000,LastLine=1)
|
||||
DSM_SEND: [14 06 10 00 00 01 ]
|
||||
|
||||
## DSM_getNextMenuValue(menuId, valId, text)
|
||||
Retrive the next value after the last `ValId` of the current `menuId`. text is just for debugging purposes to show the header of the value been retrived.
|
||||
The Response is a Menu Value or nothing if no more data.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (ValId)| LSB (ValId)
|
||||
0x15|0x06|0x10|0x61|0x10|0x00
|
||||
|
||||
SEND DSM_getNextMenuValue(MenuId=0x1061, LastValueId=0x1000) Extra: Text="Outputs"
|
||||
DSM_SEND: [15 06 10 61 10 00 ]
|
||||
|
||||
## DSM_updateMenuValue(valId, val, text, line)
|
||||
Updates the value identified as `valId` with the numeric value `val`. `text` and `line` are there to add debugging info. No response is expected.
|
||||
|
||||
If the value is negative, it has to be translated to the proper DSM negative representaion.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (ValId) | LSB (ValId) | MSB (Value)| LSB (Value)
|
||||
0x18|0x06|0x??|0x??|0x??|0x??
|
||||
|
||||
DSM_updateMenuValue(valId, val, text, line)
|
||||
-->DSM_send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value))
|
||||
|
||||
## DSM_validateMenuValue(valId, text, line)
|
||||
Validates the value identified as `valId`. `text` and `line` are there to add debugging info. The RX can response an Update value if the value is not valid and needs to be corrected.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | MSB (ValId) | LSB (ValId)
|
||||
0x19|0x06|0x??|0x??
|
||||
|
||||
|
||||
DSM_validateMenuValue(valId, text, line)
|
||||
-> DSM_send(0x19, 0x06, int16_MSB(valId), int16_LSB(valId))
|
||||
|
||||
## DSM_menuValueChangingWait(valId, text, line)
|
||||
Durin editing, this serves as a heartbeat that we are editing the value. The value identified as `valId`. `text` and `line` are there to add debugging info. The RX can response an Update value or a NUL response.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len?? | MSB (ValId) | LSB (ValId)
|
||||
0x1A|0x06|0x??|0x??
|
||||
|
||||
DSM_menuValueChangingWait(valId, text, line)
|
||||
->DSM_send(0x1A, 0x06, int16_MSB(valId), int16_LSB(valId))
|
||||
|
||||
## DSM_exitRequest()
|
||||
Request to end the DSM Frd Prog connection. Will reponse with an exit confirmation.
|
||||
|
||||
|4|5|6|7|8|9|10
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len?? | ??
|
||||
0x1F|0x02|0xAA
|
||||
|
||||
CALL DSM_exitRequest()
|
||||
DSM_SEND: [1F 02 AA ]
|
||||
|
||||
# Response Messages (RX->TX)
|
||||
|
||||
All responses will have the a response byte in Multi_Buffer[10]=0x09, and the type of message in Multi_Buffer[11].
|
||||
|
||||
## RX Version Response
|
||||
|
||||
Returns the information about the current RX.
|
||||
|
||||
The Display text of name name of the RX is retrive from the `RX_Name` array.
|
||||
|
||||
|10|11|12|13|14|15|16
|
||||
|--|--|--|--|--|--|--
|
||||
|Resp|Msg|?? |RxId|Major|Minor|Patch
|
||||
|0x09|0x01|0x00|0x1E|0x02|0x26|0x05
|
||||
|
||||
RESPONSE RX: 09 01 00 1E 02 26 05
|
||||
RESPONSE Receiver=AR631 Version 2.38.5
|
||||
|
||||
## Menu Response
|
||||
Returns the menu information to display and navigation.
|
||||
The Display text for the menu is retrive from the `Text` array.
|
||||
|
||||
|
||||
|10|11|12|13|14|15|16|17|18|19|20|21
|
||||
|--|--|--|--|--|--|--|--|--|--|--|--
|
||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|LSB (TextId)|MSB (TextId)|LSB (PrevId)|MSB (PrevId)|LSB (NextId)|MSB (NextId)|LSB (BackId)|MSB (BackId)
|
||||
|0x09|0x02|0x5E|0x10|0x27|0x02|0x00|0x00|0x00|0x00|0x00|0x10
|
||||
|
||||
RESPONSE RX: 09 02 5E 10 27 02 00 00 00 00 00 10 00 00 00 00
|
||||
RESPONSE Menu: M[Id=0x105E P=0x0 N=0x0 B=0x1000 Text="Other settings"[0x227]]
|
||||
|
||||
|
||||
|
||||
## Menu Line Response
|
||||
Returns the menu line information.
|
||||
|
||||
The Display text for the menu line is retrive from the `Text` array.
|
||||
`Min`,`Max` and `Default` can be signed numbers.
|
||||
|
||||
|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25
|
||||
|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
|
||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|Line#|Line Type|LSB (TextId)|MSB (TextId)|LSB (ValId)|MSB (ValId)|LSB (Min)|MSB (Min)|LSB (Max)|MSB (Max)|LSB (Def)|MSB (Def)
|
||||
|0x09|0x03|0x61|0x10|0x00|0x6C|0x50|0x00|0x00|0x10|0x36|0x00|0x49|0x00|0x36|0x00
|
||||
|
||||
RESPONSE RX: 09 03 61 10 00 6C 50 00 00 10 36 00 49 00 36 00
|
||||
RESPONSE MenuLine: L[#0 T=LM_nc VId=0x1000 Text="Outputs"[0x50] Val=nil NL=(0->19,0,S=54) [54->73,54] MId=0x1061 ]
|
||||
|
||||
## Menu Line Value Response
|
||||
Returns the Value for a line.
|
||||
|
||||
The response updates the Value in the line identified by `ValId`.
|
||||
The Display text for the Value, when it is a list, is retrive from the `List_Text` array.
|
||||
|
||||
|10|11|12|13|14|15|16|17
|
||||
|--|--|--|--|--|--|--|--
|
||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|LSB (ValId)|MSB (ValId)|LSB (Value)|MSB (Value)
|
||||
|0x09|0x04|0x61|0x10|0x00|0x10|0x00|0x00
|
||||
|
||||
RESPONSE RX: 09 04 61 10 00 10 00 00
|
||||
RESPONSE MenuValue: UPDATED: L[#0 T=L_m0 VId=0x1000 Text="Outputs"[0x50] Val=0|"Throttle" NL=(0->19,0,S=54) [54->73,54] MId=0x1061 ]
|
||||
|
||||
## Exit Response
|
||||
Response from a Exit Request.
|
||||
|
||||
|10|11
|
||||
|--|--
|
||||
|Resp|Msg
|
||||
|0x09|0x07
|
||||
|
||||
RESPONSE RX: 09 A7
|
||||
RESPONSE Exit Confirm
|
||||
|
||||
## NULL Response
|
||||
Can be use as a response, or heartbeat from the RX to keep the connection open.
|
||||
|
||||
|10|11
|
||||
|--|--
|
||||
|Resp|Msg
|
||||
|0x09|0x00
|
||||
|
||||
RESPONSE RX: 09 00
|
||||
RESPONSE NULL
|
||||
|
||||
|
||||
# Unknown Lines
|
||||
TOTALLY UNKNOWN WHAT THIS ARE FOR.. but only works for the Main Menu..
|
||||
Other menus they just loop on line=0 forever.
|
||||
|
||||
## DSM_getNextUknownLine_0x05(menuId, curLine)
|
||||
|
||||
|
||||
Request the retrival of the next Unknown line following the current line. Response is either the next unknow line, next menu line, or the next value, or nothing.
|
||||
|
||||
|4|5|6|7|8|9| Comment
|
||||
|--|--|--|--|--|--|--
|
||||
Msg|Len? | Line# | Line# | 0x00 | Formula(line#)??
|
||||
0x20|0x06|0x00|0x00|0x00|0x40 | LastLineLine=0 retrieval
|
||||
0x20|0x06|0x01|0x01|0x00|0x01| LastLineLine=1 retrieval
|
||||
0x20|0x06|0x02|0x02|0x00|0x02| LastLineLine=2 retrieval
|
||||
0x20|0x06|0x03|0x03|0x00|0x04| LastLineLine=3 retrieval
|
||||
0x20|0x06|0x04|0x04|0x00|0x00| LastLineLine=4 retrieval
|
||||
0x20|0x06|0x05|0x05|0x00|0x00| LastLineLine=5 retrieval
|
||||
|
||||
## Unknown Line Response
|
||||
We still don't know what is this for, but we have to retrive them and skip then. Works for main menu, but when it happens in another menus, usually we stay in an infinite loop retrieving line=0
|
||||
|
||||
|10|11|12|13|14|15|16|17
|
||||
|--|--|--|--|--|--|--|--
|
||||
|Resp|Msg|LSB (line#)
|
||||
|0x09|0x05|0x00|0x01|0x00|0x00|0x00|0x07
|
||||
|0x09|0x05|0x01|0x01|0x00|0x00|0x00|0x07
|
||||
|
||||
## Interaction on Main Menu
|
||||
This is the normal interaction for the main menu. As you can see, it iterates on the 6 Unknow lines (0..5), and afterwards, it starts sending normal menu lines.
|
||||
|
||||
SEND DSM_getFirstMenuLine(MenuId=0x1000)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=1 DATA=RX: 09 05 01 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=1)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=2 DATA=RX: 09 05 02 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=2)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=3 DATA=RX: 09 05 03 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=3)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=4 DATA=RX: 09 05 04 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=4)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=5 DATA=RX: 09 05 05 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=5)
|
||||
RESPONSE MenuLine: L[#0 T=M VId=0x1010 Text="Gyro settings"[0xF9] MId=0x1000 ]
|
||||
|
||||
## Other menus
|
||||
If it hapen on other menus. Usualy stays in an infinite loop until it crash/exits.
|
||||
The screen will show **"Error: Cannot Load Menu Lines from RX"**
|
||||
|
||||
The log will look like:
|
||||
|
||||
DSM_getMenu(MenuId=0x104F LastSelectedLine=1)
|
||||
RESPONSE Menu: M[Id=0x104F P=0x0 N=0x0 B=0x1000 Text="First Time Setup"[0x4A]]
|
||||
SEND DSM_getFirstMenuLine(MenuId=0x104F)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
ERROR: Received Same menu line
|
||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
ERROR: Received Same menu line
|
||||
|
||||
We found that sometimes, Overriding LastSelectedLine to 0 solves the problem for some specific menus. Not for all (for other, is the oposite (0->1)). But at least no unknown lines are returned with this hack for AR631/AR637. Maybe others also needed.
|
||||
|
||||
**Overriding to Zero is not a good solution for every menu. Some menus needs the LastLine to know the behaviour (for example, Factory Reset the RX, Save Backup, Restore Backup, Enter Bind Mode, Some sensor Calibration). Thats why we cannot do it blindly.**
|
||||
|
||||
Here is the current code to fix some of this problems in AR631/AR637.
|
||||
Function `DSM_SelLine_HACK()`
|
||||
|
||||
if (ctx.RX.Id == RX.AR637T or ctx.RX.Id == RX.AR637TA or ctx.RX.Id == RX.AR631) then
|
||||
-- AR631/AR637 Hack for "First time Setup" or
|
||||
-- "First Time AS3X Setup", use 0 instead of the ctx.SelLine=5
|
||||
if (ctx.Menu.MenuId == 0x104F or ctx.Menu.MenuId==0x1055) then
|
||||
LOG_write("First time Setup Menu HACK: Overrideing LastSelectedLine to ZERO\n")
|
||||
ctx.SelLine = 0
|
||||
end
|
||||
-- DID NOT WORK: AR631/AR637 Hack for "Relearn Servo Settings", use 1 instead
|
||||
-- of the ctx.SelLine=0
|
||||
--if (ctx.Menu.MenuId == 0x1023) then
|
||||
-- LOG_write("Relearn Servo Settings HACK: Overrideing LastSelectedLine to 1\n")
|
||||
-- ctx.SelLine = 1
|
||||
--end
|
||||
|
||||
Now it retrives properly the menu:
|
||||
|
||||
Log shows:
|
||||
|
||||
First time Setup Menu HACK: Overrideing LastSelectedLine to ZERO
|
||||
DSM_getMenu(MenuId=0x104F LastSelectedLine=0)
|
||||
RESPONSE Menu: M[Id=0x104F P=0x0 N=0x0 B=0x105E Text="First Time Setup"[0x4A]]
|
||||
SEND DSM_getFirstMenuLine(MenuId=0x104F)
|
||||
.. Good menu data
|
||||
|
||||
|
||||
|
||||
|
||||
|
1859
Lua_scripts/DSMLIB/DsmFwPrgLib.lua
Normal file
1473
Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua
Normal file
1107
Lua_scripts/DSMLIB/DsmSetupLib.lua
Normal file
BIN
Lua_scripts/DSMLIB/img/rx_pos_1.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_10.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_11.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_12.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_13.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_14.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_15.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_16.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_17.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_18.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_19.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_2.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_20.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_21.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_22.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_23.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_24.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_25.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_3.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_4.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_5.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_6.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_7.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_8.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Lua_scripts/DSMLIB/img/rx_pos_9.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_1rud.png
Normal file
After Width: | Height: | Size: 728 B |
BIN
Lua_scripts/DSMLIB/img/tt_1rud_1ele.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_1rud_2ele.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_2rud_1ele.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_2rud_2ele.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_traileron.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_vtail.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/wt_1ail.png
Normal file
After Width: | Height: | Size: 721 B |
BIN
Lua_scripts/DSMLIB/img/wt_1ail_1flp.png
Normal file
After Width: | Height: | Size: 803 B |
BIN
Lua_scripts/DSMLIB/img/wt_2ail.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
Lua_scripts/DSMLIB/img/wt_2ail_1flp.png
Normal file
After Width: | Height: | Size: 755 B |
BIN
Lua_scripts/DSMLIB/img/wt_2ail_2flp.png
Normal file
After Width: | Height: | Size: 817 B |
BIN
Lua_scripts/DSMLIB/img/wt_elevon.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
Lua_scripts/DSMLIB/img/wt_flaperon.png
Normal file
After Width: | Height: | Size: 679 B |
222
Lua_scripts/DSMLIB/readme.md
Normal file
@ -0,0 +1,222 @@
|
||||
# Credits
|
||||
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
Rewrite/Enhancements by: Francisco Arzu
|
||||
|
||||
Thanks to all the people volunteered to test it.
|
||||
|
||||
# Introduction (v0.53)
|
||||
|
||||
This script library enhances the original DSM Forward Programming tool. DSM Forward Programming is needed to setup many of the new Spektrum Receivers with Gyro AS3X/SAFE features. For the Gyro (/Safe) to correct the plane in flight, it needs to move the right surfaces therefore the RX needs to know the configuration of the plane (Wing Type, Tail Type, Mixers, Servo Assignments, Servo Reverse). That info tells the RX where the aileron(s) are (one or two), where the elevator(s) are (one or two), V-Tail, Delta Wing, etc.
|
||||
|
||||
Since EdgeTx/OpenTx doesn’t have an equivalent setup that is stored in the radio, we have to create our own version. This info is stored inside the `/MODELS/DSMDATA` directory/folder (which needs to be created by manually).
|
||||
|
||||
During `"Gyro Settings->initial setup"`, the RX asks the TX for model information behind the scenes. After setup, `"Gyro Settings->System Tools-> Relearn Servo Settings"` requests the TX configuration and stores it in the RX.
|
||||
|
||||
# Deployment
|
||||
Make sure to manually create `/MODELS/DSMDATA` . The script will complain at startup.
|
||||
|
||||
/SCRIPTS/TOOLS/DsmFwdPrg_05_BW.lua -- black/white text only radios
|
||||
/SCRIPTS/TOOLS/DsmFwdPrg_05_Color.lua -- Color and touch radios
|
||||
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
|
||||
/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua -- DSM Protocol Message and Menu engine
|
||||
/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgSIMLib.lua -- Simulation of AR631, FC6250HX
|
||||
/SCRIPTS/TOOLS/DSMLIB/SetupLib.lua -- Model Setup Screens
|
||||
/SCRIPTS/TOOLS/DSMLIB/img --Images for RX orientations
|
||||
|
||||
Other Directories
|
||||
|
||||
/MODELS/DSMDATA --(ALL CAPITALS) Data of model config (Wing Type, Servo Assignments)
|
||||
/LOGS/dsm_log.txt --Readable log of the last RX/TX session, usefull for debugging problems
|
||||
|
||||
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first)
|
||||
|
||||
# Common Questions
|
||||
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
|
||||
V0.53 improve this.. you can select any channel now. Additionally, if you already mapped the Switch to the channel, togling once the switch will select the channel on the menu field.
|
||||
<s>V0.52 and prior: The RX corrects your channel to ch5 or ch6. This means that the RX is not
|
||||
detecting the upper channels from the TX. You need to exercise (move the switch) so that the RX detects it. Put the Channel Field on edit (changing) mode, change it to Ch7 (or any other), flip the switch for Ch7 3 times, now confirm the edit. The RX now will not reject it. All Spektrum RX are 20 channels internally, even if it only has 6 external Ch/Ports to connect servos. </s>
|
||||
|
||||
2. `Why Ch1 says Ch1 (TX:Ch3/Thr)?`:
|
||||
Radios with Multi-Module are usually configured to work the standard AETR convention. Spektrum uses TAER. The multi-module does the conversion when transmitting the signals. So `Spektrum Ch1 (Throttle)` really comes from the `TX Ch3`. We show both information (+name from the TX output). If your multi-module/radio is setup as TAER, the script will not do the re-arrangement.
|
||||
|
||||
3. `If i change the model name, the original model settings are lost.` This is correct, the model name is used to generate the file name (inside /MODEL/DSMDATA) who stores the model configuration. Currently EdgeTx and OpenTX has differt features where i could get either the Model Name or the YAML file where the EdgeTX model configuration is stored.. to keep the code compatible, the model name is used.
|
||||
|
||||
4. `Reversing a channel in my TX do not reverse the AS3X/SAFE reaction.` Correct, the chanel stick direction and the Gyro direction are two separate things.
|
||||
|
||||
4.1: First, you have setup your model so that the sticks and switches moves the surfaces in the right direction.
|
||||
|
||||
4.2: Go to the script, `Model Setup` and setup your wing type, tail type, and select the channel assigment for each surface. Leave the servo settings the same as the values in the TX to start.
|
||||
|
||||
4.3: AR63X family: Go to `Forward programming->Gyro Setting->Initial Setup` (New/factory reset), or `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` (not new). This will load your urrent Gyro servo settings into the plane's RX.
|
||||
|
||||
4.4: Verify that the AS3X and SAFE reacts in the proper direction. You can use the Flight mode confugured as "Safe Mode: Auto-Level" to see if it moves the surfaces in the right direction.
|
||||
|
||||
4.5: If a surface don't move in the right direction, go to the `Model Setup->Gyro Channel Reverse` to reverse the Gyro on the channels needed, and do again the `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` to tranfer the new settings to the RX.
|
||||
|
||||
4.6: Specktrum TX always passes the TX servo reverse as the Gyro Reverse, but on many OpenTX/EdgeTX radios, the Rud/Ail are usually reversed by default compared to Specktrum. So far i don't think that i can use this as a rule, that is why the `Gyro Channel Reverse` page exist.
|
||||
|
||||
|
||||
|
||||
---
|
||||
---
|
||||
|
||||
# Changes and fixes
|
||||
V0.53:
|
||||
1. Improved channel selection (Flight mode, Panic Channel, Gains Channel). Now during editing a channel, you can select any channel (>Ch4). Also, of you toggle the switch/channel it will populate the screen.
|
||||
2. Support for smaller screens (128x64) in B&W. The problem with this older radios is memory. In some, it does not have enouth memory to load the additional DSMLIB libraries.
|
||||
3. Fix formatting problem with some TX channel names who could affect the screen.. for example, rud channel should show "Ch4/rud", but shows "Ch4ud" because /r is for right justify formatting on messages. Now the formatting is only if it appears at the end of the message.
|
||||
|
||||
V0.52:
|
||||
1. Menus to be able to configure Plane in a similar way as Spektrum Radio (v0.52)
|
||||
2. Make "Gyro Settings"->"Initial Setup" works (Tested on AR631,AR637xx with PLANE type of aircraft)
|
||||
3. Properly reset and restart after initial configuration and SAFE changes.
|
||||
4. Write Log of the conversation between RX/TX. To be used for debugging a problem is reported.
|
||||
5. Provide a simulation of RX to do GUI development in Companion, and understand patterns of how the data is organized.
|
||||
|
||||
# Tested RXs
|
||||
- AR631/AR637xx
|
||||
- FC6250HX (Blade 230S V2 Helicopter)
|
||||
- AR636 (Blade 230S V1 Heli firmware 4.40)
|
||||
|
||||
Please report if you have tested it with other receivers to allow us to update the documentation. Code should work up to 10 channels for the main surfaces (Ail/Ele/etc). All Spektrum RX are internally 20 channels, so you can use Ch7 for Flight Mode even if your RX is only 6 channels (See common Questions)
|
||||
|
||||
# Flight mode/Gain channels
|
||||
Fixed in version 0.53. no longer a tick to select it.
|
||||
<s>I ran into a case where trying to set Aux2 or Aux3 for flight mode, but the RX was correcting it to Aux1.. the RX only was allowing Gear or Aux1 (AR631/AR637).
|
||||
This is because the RX doesn’t know that we are using more than 6 channels. To make the RX aware that there are other channels, while editing the channel, you have to toggle the switch to exercise the channel (3 times), and now the RX will recognize it.</s>
|
||||
|
||||
|
||||
# Messages Displayed in the GUI
|
||||
|
||||
If in a screen you get text that looks like `Unknown_XX` (ex: Unknown_D3), that message has not been setup in the script in english. If you can determine what the proper message is, you can send us a message to be added to the library.
|
||||
The `XX` represents a Hex Number (0..9,A..F) message ID.
|
||||
|
||||
If you want to fix it in your local copy, all messages are towards the end in the file `SCRIPT\TOOS\DSMLIB\DsmFwPrgLib.lua`. Messages for Headers are stored in `Text` and messages for Options are stored in `List_Text`. Lua scripts are text files, and can be edited with Notepad or equivalent.
|
||||
|
||||
Portion of DsmFwPrgLib.lua:
|
||||
|
||||
Text[0x0097] = "Factory Reset"
|
||||
Text[0x0098] = "Factory Reset" -- FC6250HX: Title
|
||||
Text[0x0099] = "Advanced Setup"
|
||||
Text[0x009A] = "Capture Failsafe Positions"
|
||||
Text[0x009C] = "Custom Failsafe"
|
||||
|
||||
Text[0x009F] = "Save & Reset RX" -- TODO: Find the Proper Spektrum Value ??
|
||||
|
||||
Text[0x00A5] = "First Time Setup"
|
||||
Text[0x00AA] = "Capture Gyro Gains"
|
||||
Text[0x00AD] = "Gain Channel Select"
|
||||
|
||||
-- Safe mode options, Inhibit + the values
|
||||
local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope
|
||||
List_Text[0x00B0] = "Self-Level/Angle Dem"
|
||||
List_Text[0x00B1] = "Envelope"
|
||||
|
||||
For example, if you get `Unknown_9D` in the GUI and your now that it should say **NEW Text**, you can edit the lua script to look like this:
|
||||
|
||||
Text[0x009A] = "Capture Failsafe Positions"
|
||||
Text[0x009C] = "Custom Failsafe"
|
||||
|
||||
Text[0x009D] = "NEW Text" -- NEW Text added for AR98xx
|
||||
|
||||
Text[0x009F] = "Save & Reset RX" -- TODO: Find the proper Spektrum text
|
||||
|
||||
|
||||
# LOG File
|
||||
|
||||
The log file of the last use of the script is located at `/LOGS/dsm_log.txt`. **It is overridden on every start to avoid filling up the SD card**. So if you want to keep it, copy or rename it before starting the script again. (it can be renamed in the TX by browsing the SD card)
|
||||
|
||||
The log is human readable. The first number is the number of seconds since the start, and then what is the current state of the Library, and what has been sent and received. The info in the log can be easily used to create a new simulation for that RX in the future.
|
||||
|
||||
Example Log:
|
||||
|
||||
5.340 WAIT_CMD: DSM_GotoMenu(0x1010,LastSelectedLine=0)
|
||||
5.350 MENU_TITLE: SEND DSM_getMenu(MenuId=0x1010 LastSelectedLine=0)
|
||||
5.440 MENU_TITLE: RESPONSE Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
||||
5.490 MENU_LINES: SEND DSM_getFirstMenuLine(MenuId=0x1010)
|
||||
5.590 MENU_LINES: RESPONSE MenuLine: L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ]
|
||||
5.640 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=0)
|
||||
5.740 MENU_LINES: RESPONSE MenuLine: L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ]
|
||||
5.790 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=1)
|
||||
5.850 MENU_LINES: RESPONSE MenuLine: L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ]
|
||||
5.910 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=2)
|
||||
5.970 MENU_LINES: RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
|
||||
6.020 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=3
|
||||
|
||||
Example of the Unknown_0x05 Lines correctly processed (receiving lines 0..5):
|
||||
|
||||
0.130 MENU_TITLE: SEND DSM_getMainMenu()
|
||||
0.230 MENU_TITLE: RESPONSE Menu: M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"[0x4B]]
|
||||
0.280 MENU_LINES: SEND DSM_getFirstMenuLine(MenuId=0x1000)
|
||||
0.400 MENU_LINES: RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
0.460 MENU_UNKNOWN_LINES: CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
||||
0.550 MENU_UNKNOWN_LINES: RESPONSE MenuUknownLine_0x05: LineNum=1 DATA=RX: 09 05 01 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
0.600 MENU_UNKNOWN_LINES: CALL DSM_getNextUknownLine_0x05(LastLine=1)
|
||||
0.700 MENU_UNKNOWN_LINES: RESPONSE MenuUknownLine_0x05: LineNum=2 DATA=RX: 09 05 02 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
0.760 MENU_UNKNOWN_LINES: CALL DSM_getNextUknownLine_0x05(LastLine=2)
|
||||
|
||||
|
||||
# Validation of data by the RX
|
||||
|
||||
<s>When you change a value in the GUI, the RX validates that the value is valid.
|
||||
For example, I ran into a case where trying to set Aux2 or Aux3 for flight mode, but the RX was correcting it back to Aux1.. the RX only was allowing Gear or Aux1 (AR631/AR637).. in this case, toggle the Switch while editing it on the screen.
|
||||
|
||||
If you go to the logs, you can see that the RX was correcting the value:
|
||||
|
||||
20.520 VALUE_CHANGE_END: SEND DSM_updateMenuValue(ValueId=0x1000,val=7) Extra: Text="FM Channel" Value=7|"Aux2"
|
||||
20.570 VALUE_CHANGE_END: SEND DSM_validateMenuValue(ValueId=0x1000) Extra: Text="FM Channel" Value=7|"Aux2"
|
||||
20.680 VALUE_CHANGE_END: RESPONSE MenuValue: UPDATED: L[#0 T=L_m1 VId=0x1000 Text="FM Channel"[0x78] Val=6|"Aux1" NL=(0->32,0,S=53) [53->85,53] MId=0x7CA6 ]
|
||||
</s>
|
||||
|
||||
---
|
||||
# Version 0.53
|
||||
- Improve Channel selection in menus
|
||||
- Support smaller screens 128x64 in the black/white mode.
|
||||
|
||||
# Version 0.52
|
||||
- Fix Reversing of Servos
|
||||
- Properly detect Multimodule Ch settings AETR
|
||||
---
|
||||
|
||||
# Version 0.51 (volunteer testing version, not for production)
|
||||
- New Screens to Configure Model (Wing Type/Tail Tail, etc)
|
||||
- Finally got understanding that the previous unknown 0x05 lines are to send Model/Servo data to RX.
|
||||
- Fix use of AR636B (Firmware version 4.40.0 for Blade 230 heli, is the only one with Forward Programming)
|
||||
- Aircraft types: Tested With Plane type only.. Glider and other in progress
|
||||
|
||||
### Known Problems:
|
||||
- 4-Servo Wing type (Dual Ail/Tail) in planes give conflicting servo assignments by defaults.. Solution choose your own Ch.
|
||||
- Glider, Heli, Drone: Still in development. In glider, only a few wing type works.. needs to restrict menu options for the only valid one.
|
||||
|
||||
|
||||
# Version 0.5
|
||||
|
||||
- Make the code more readable and understandable
|
||||
- Separate the DSM Forwards Programming logic from the GUI
|
||||
- Log the communication with the RX on a /LOGS/dsm_log.txt to allow to debug it easier
|
||||
and see the exchange of data between the RX/TX
|
||||
- Created a black/white Text only version with only Key/Roller Inputs
|
||||
- Created a nicer GUI for EdgeTX touch screen color Radios
|
||||
- RX simulation for GUI development: turn on `SIMULATION_ON=true` in the beginning of the lua file
|
||||
- Test it on AR631, AR637xx, FC6250HX (Helicopter)
|
||||
|
||||
|
||||
### Some settings that can change (top of Lua file):
|
||||
SIMULATION_ON = false -- FALSE: use real communication to DSM RX (DEFAULT), TRUE: use a simulated version of RX
|
||||
DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm_log.txt)
|
||||
DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
|
||||
USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX, OpenTX handle colors different)
|
||||
|
||||
|
||||
### Known Problems:
|
||||
1. **Incorrect List Value Options:** Some Menu List line (`LINE_TYPE.LIST_MENU1` or `L_m1` in logs), the range (min/max) of valid values seems to be incorrect, but 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. Currently fixed some by overriding the valid values in the script code (config for each field).
|
||||
|
||||
2. Glider/Heli/Drone wing types not ready.
|
||||
|
||||
For Helicopter, use airplane normal wing and normal tail
|
||||
|
||||
|
||||
# Version 0.2
|
||||
Original Version from Pascal Langer
|
||||
|
@ -117,6 +117,7 @@
|
||||
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
49,0,KF606,KF606,1,Trim
|
||||
49,1,KF606,MIG320,1,Trim,LED
|
||||
49,2,KF606,ZCZ50,1,Trim,UNK
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
@ -172,6 +173,7 @@
|
||||
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
|
||||
48,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn
|
||||
48,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
|
||||
|
@ -60,16 +60,14 @@ The OpenTX sensor "RSSI" is populated by the individual OpenTX telemetry protoco
|
||||
|
||||
## DSM Forward Programming
|
||||
|
||||
Navigation is mainly done using the scroll wheel and ENT. Short press on ENT will edit a value. When editing a value a long ENT press will restore the value to its default. To exit the script and terminate all current operations correctly short press RTN (if you don't do this the RX might not store the changes).
|
||||
This is a work in progress. It's available for color(+touch) and B&W screens.
|
||||
|
||||
This is a work in progress. It's only available for color screens (Horus, TX16S, T16, T18...).
|
||||
|
||||
If some text appears as Unknown_xxx, please report xxx and what the exact text display should be.
|
||||
|
||||
Need OpenTX 2.3.10 nightly or above. Located on the radio SD card under \SCRIPTS\TOOLS.
|
||||
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.
|
||||
|
@ -292,10 +292,17 @@ uint16_t AFHDS2A_callback()
|
||||
case AFHDS2A_BIND2:
|
||||
case AFHDS2A_BIND3:
|
||||
AFHDS2A_build_bind_packet();
|
||||
data_rx=A7105_ReadReg(A7105_00_MODE); // Check if something has been received...
|
||||
A7105_WriteData(AFHDS2A_TXPACKET_SIZE, packet_count%2 ? 0x0d : 0x8c);
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5))) // removed FECF check due to issues with fs-x6b -> & (1<<5 | 1<<6)
|
||||
{ // CRCF Ok
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & (1<<5)) && !(data_rx & 1)) // removed FECF check due to issues with fs-x6b -> & (1<<5 | 1<<6)
|
||||
{ // RX+CRCF Ok
|
||||
A7105_ReadData(AFHDS2A_RXPACKET_SIZE);
|
||||
#if 0
|
||||
debug("RX");
|
||||
for(uint8_t i=0; i<AFHDS2A_RXPACKET_SIZE ; i++)
|
||||
debug(" %02X", packet[i]);
|
||||
debugln("");
|
||||
#endif
|
||||
if(packet[0] == 0xbc && packet[9] == 0x01)
|
||||
{
|
||||
uint16_t addr;
|
||||
@ -330,7 +337,7 @@ uint16_t AFHDS2A_callback()
|
||||
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
|
||||
break;
|
||||
A7105_SetPower();
|
||||
A7105_SetTxRxMode(TXRX_OFF); // Turn LNA off since we are in near range and we want to prevent swamping
|
||||
A7105_SetTxRxMode((packet_count & 0x40) ? TXRX_OFF : RX_EN); // Turn LNA off time to time since we are in near range and we want to prevent swamping
|
||||
A7105_Strobe(A7105_RX);
|
||||
phase &= ~AFHDS2A_WAIT_WRITE;
|
||||
phase++;
|
||||
|
@ -249,6 +249,10 @@ static uint8_t __attribute__((unused)) DSM_Check_RX_packet()
|
||||
|
||||
uint16_t DSM_callback()
|
||||
{
|
||||
#if defined MULTI_EU
|
||||
if(sub_protocol == DSM2_1F || sub_protocol == DSM2_2F)
|
||||
return 11000;
|
||||
#endif
|
||||
#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
|
||||
#ifdef STM32_BOARD
|
||||
#define DSM_WRITE_DELAY 1600 // Time after write to verify write complete
|
||||
|
@ -33,7 +33,14 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
#define FX620_PAYLOAD_SIZE 7
|
||||
#define FX620_CH_OFFSET 1
|
||||
|
||||
#define FX9630_PACKET_PERIOD 8124
|
||||
#define FX9630_BIND_PACKET_PERIOD 8124
|
||||
#define FX9630_BIND_CHANNEL 51
|
||||
#define FX9630_PAYLOAD_SIZE 8
|
||||
#define FX9630_NUM_CHANNELS 3
|
||||
|
||||
//#define FORCE_FX620_ID
|
||||
//#define FORCE_FX9630_ID
|
||||
|
||||
static void __attribute__((unused)) FX_send_packet()
|
||||
{
|
||||
@ -41,14 +48,36 @@ static void __attribute__((unused)) FX_send_packet()
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
if(sub_protocol == FX9630)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, 4);
|
||||
if (hopping_frequency_no > FX9630_NUM_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
}
|
||||
else // FX816 and FX620
|
||||
{
|
||||
hopping_frequency_no &= 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
memset(packet,0x00,packet_length);
|
||||
|
||||
//Channels
|
||||
uint8_t val;
|
||||
if (sub_protocol == FX9630)
|
||||
{
|
||||
packet[0] = convert_channel_8b(THROTTLE);
|
||||
packet[1] = convert_channel_8b(AILERON);
|
||||
packet[2] = 0xFF - convert_channel_8b(ELEVATOR);
|
||||
packet[3] = convert_channel_8b(RUDDER);
|
||||
packet[4] = 0x20;
|
||||
packet[5] = GET_FLAG(CH5_SW, 0x01); // DR toggle swich: 0 small throw, 1 large throw
|
||||
packet[5] |= (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x02 : 0x01)) << 1; // Mode A(0) : 6D small throw, B(1) : 6D large throw, C(2) : 3D
|
||||
}
|
||||
else // FX816 and FX620
|
||||
{
|
||||
uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET;
|
||||
uint8_t val=convert_channel_8b(AILERON);
|
||||
val=convert_channel_8b(AILERON);
|
||||
if(val>127+FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 1:0xFF;
|
||||
else if(val<127-FX_SWITCH)
|
||||
@ -56,6 +85,7 @@ static void __attribute__((unused)) FX_send_packet()
|
||||
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)
|
||||
@ -67,7 +97,7 @@ static void __attribute__((unused)) FX_send_packet()
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
}
|
||||
else //FX620
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
@ -82,12 +112,27 @@ static void __attribute__((unused)) FX_send_packet()
|
||||
packet[5] = 0xAB; // Is it based on ID??
|
||||
}
|
||||
}
|
||||
else // FX9630
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
memcpy(packet,rx_tx_addr, 4);
|
||||
packet[4] = hopping_frequency[1];
|
||||
packet[5] = hopping_frequency[2];
|
||||
packet[7] = 0x55;
|
||||
}
|
||||
}
|
||||
|
||||
//Check
|
||||
uint8_t last_packet_idx = packet_length-1;
|
||||
if (sub_protocol == FX9630 && IS_BIND_IN_PROGRESS)
|
||||
last_packet_idx--;
|
||||
val=0;
|
||||
for(uint8_t i=0;i<packet_length-1;i++)
|
||||
for(uint8_t i=0;i<last_packet_idx;i++)
|
||||
val+=packet[i];
|
||||
packet[packet_length-1]=val;
|
||||
if (sub_protocol == FX9630)
|
||||
val = val ^ 0xFF;
|
||||
packet[last_packet_idx]=val;
|
||||
|
||||
//Debug
|
||||
#if 0
|
||||
@ -112,13 +157,20 @@ static void __attribute__((unused)) FX_RF_init()
|
||||
packet_period = FX816_PACKET_PERIOD;
|
||||
packet_length = FX816_PAYLOAD_SIZE;
|
||||
}
|
||||
else //FX620
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\xaa\xbb\xcc", 3);
|
||||
XN297_RFChannel(FX620_BIND_CHANNEL);
|
||||
packet_period = FX620_BIND_PACKET_PERIOD;
|
||||
packet_length = FX620_PAYLOAD_SIZE;
|
||||
}
|
||||
else // FX9630
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\x56\x78\x90\x12", 4);
|
||||
XN297_RFChannel(FX9630_BIND_CHANNEL);
|
||||
packet_period = FX9630_BIND_PACKET_PERIOD;
|
||||
packet_length = FX9630_PAYLOAD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX_initialize_txid()
|
||||
@ -133,7 +185,7 @@ static void __attribute__((unused)) FX_initialize_txid()
|
||||
for(uint8_t i=0;i<FX_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
|
||||
}
|
||||
else//FX620
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
rx_tx_addr[0] = rx_tx_addr[3];
|
||||
hopping_frequency[0] = 0x18 + rx_tx_addr[3]&0x07; // just to try something
|
||||
@ -144,6 +196,17 @@ static void __attribute__((unused)) FX_initialize_txid()
|
||||
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i] = i*10 + hopping_frequency[0];
|
||||
}
|
||||
else // FX9630
|
||||
{
|
||||
#ifdef FORCE_FX9630_ID
|
||||
memcpy(rx_tx_addr,(uint8_t*)"\xCE\x31\x9B\x73", 4);
|
||||
memcpy(hopping_frequency,"\x13\x1A\x38", FX9630_NUM_CHANNELS); //Original dump=19=0x13,26=0x1A,56=0x38
|
||||
#else
|
||||
hopping_frequency[0] = 0x13; // constant
|
||||
hopping_frequency[1] = RX_num & 0x0F + 0x1A;
|
||||
hopping_frequency[2] = rx_tx_addr[3] & 0x0F + 0x38;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t FX_callback()
|
||||
|
@ -116,6 +116,10 @@ static void __attribute__((unused)) FrSkyX_build_packet()
|
||||
|
||||
uint16_t FRSKYX_callback()
|
||||
{
|
||||
#if defined MULTI_EU
|
||||
if(sub_protocol == CH_16 || sub_protocol == CH_8)
|
||||
return 9000;
|
||||
#endif
|
||||
switch(state)
|
||||
{
|
||||
default:
|
||||
|
@ -20,6 +20,7 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
|
||||
//#define FORCE_KF606_ORIGINAL_ID
|
||||
//#define FORCE_MIG320_ORIGINAL_ID
|
||||
//#define FORCE_ZCZ50_ORIGINAL_ID
|
||||
|
||||
#define KF606_INITIAL_WAIT 500
|
||||
#define KF606_PACKET_PERIOD 3000
|
||||
@ -30,11 +31,17 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
|
||||
static void __attribute__((unused)) KF606_send_packet()
|
||||
{
|
||||
uint8_t len = KF606_PAYLOAD_SIZE;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
if(sub_protocol != KF606_ZCZ50)
|
||||
{
|
||||
packet[0] = 0xAA;
|
||||
memcpy(&packet[1],rx_tx_addr,3);
|
||||
}
|
||||
else
|
||||
memcpy(packet,rx_tx_addr,4);
|
||||
}
|
||||
else
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no);
|
||||
@ -43,13 +50,13 @@ static void __attribute__((unused)) KF606_send_packet()
|
||||
packet[0] = 0x55;
|
||||
packet[1] = convert_channel_8b(THROTTLE); // 0..255
|
||||
// Deadband is needed on aileron, 40 gives +-6%
|
||||
if(sub_protocol == KF606_KF606)
|
||||
switch(sub_protocol)
|
||||
{
|
||||
case 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
|
||||
{
|
||||
break;
|
||||
case KF606_MIG320:
|
||||
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
|
||||
@ -58,10 +65,17 @@ static void __attribute__((unused)) KF606_send_packet()
|
||||
else if(packet[3] > 0x1F)
|
||||
packet[3] = 0x1F;
|
||||
packet[3] |= GET_FLAG(CH6_SW, 0xC0); // 0xC0 and 0xE0 are both turning the LED off, not sure if there is another hidden feature
|
||||
break;
|
||||
case KF606_ZCZ50:
|
||||
len--; // uses only 3 bytes of payload
|
||||
packet[0] = packet[1]; // Throttle: 0x00..0xFF
|
||||
packet[1] = convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, low rate 0x52..0x80..0xB1, high rate: 0x41..0x80..0xC3.
|
||||
packet[2] = convert_channel_16b_limit(CH5,0x01,0x1F); // Trim: 0x01..0x10..0x1F
|
||||
packet[2] |= GET_FLAG(CH6_SW, 0xC0); // Unknown: 0x00 or 0xC0. Left top switch on original TX changes nothing on my plane. Maybe ON/OFF for main motor?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t len = KF606_PAYLOAD_SIZE;
|
||||
if(sub_protocol == KF606_MIG320)
|
||||
{
|
||||
len++;
|
||||
@ -107,6 +121,19 @@ static void __attribute__((unused)) KF606_initialize_txid()
|
||||
hopping_frequency[0]=68;
|
||||
hopping_frequency[1]=71;
|
||||
#endif
|
||||
if(sub_protocol == KF606_ZCZ50)
|
||||
{
|
||||
rx_tx_addr[1] = rx_tx_addr[0];
|
||||
rx_tx_addr[0]=0xAA;
|
||||
}
|
||||
#ifdef FORCE_ZCZ50_ORIGINAL_ID
|
||||
rx_tx_addr[0]=0xAA;
|
||||
rx_tx_addr[1]=0x67;
|
||||
rx_tx_addr[2]=0x64;
|
||||
rx_tx_addr[3]=0x01;
|
||||
hopping_frequency[0]=48;
|
||||
hopping_frequency[1]=51;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) KF606_RF_init()
|
||||
@ -126,7 +153,7 @@ uint16_t KF606_callback()
|
||||
if(--bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
XN297_SetTXAddr(rx_tx_addr, 3);
|
||||
XN297_SetTXAddr(rx_tx_addr, sub_protocol != KF606_ZCZ50 ? 3 : 4);
|
||||
}
|
||||
KF606_send_packet();
|
||||
return KF606_PACKET_PERIOD;
|
||||
@ -153,3 +180,14 @@ void KF606_init()
|
||||
// P[2] = AIL 2B..80..DA
|
||||
// P[3] = TRIM 01..10..1F
|
||||
// channels 68=BB&3F+9 and 71
|
||||
|
||||
|
||||
// ZCZ50v2 protocol (with fake front propeller)
|
||||
// Bind
|
||||
// 250K C=7 S=Y A= E7 E7 E7 E7 E7 P(4)= AA 67 64 01
|
||||
// 3ms on ch7
|
||||
// Normal
|
||||
// 250K C=48 S=Y A= AA 67 64 01 P(3)= 00 80 10
|
||||
// P[0] = THR 0x00..0xFF
|
||||
// P[1] = AIL low rate 0x52..0x80..0xB1, high rate: 0x41..0x80..0xC3
|
||||
// P[2] = TRIM 0x01..0x10..0x1F + UNKNOWN 0x00 or 0xC0
|
||||
|
@ -17,8 +17,9 @@
|
||||
|
||||
#include "iface_nrf24l01.h"
|
||||
|
||||
#define KYOSHO2_PACKET_PERIOD 1120 // 1600 for bind, let's see
|
||||
#define KYOSHO2_BIND_COUNT 2000 // about 3sec
|
||||
#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
|
||||
@ -111,13 +112,16 @@ 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;
|
||||
}
|
||||
KYOSHO2_send_packet();
|
||||
return KYOSHO2_BIND_PACKET_PERIOD;
|
||||
}
|
||||
return KYOSHO2_PACKET_PERIOD;
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,8 @@
|
||||
45,E01X,E012,E015
|
||||
46,V911S,V911S,E119
|
||||
47,GD00x,GD_V1,GD_V2
|
||||
48,V761,3CH,4CH
|
||||
49,KF606,KF606,MIG320
|
||||
48,V761,3CH,4CH,TOPRC
|
||||
49,KF606,KF606,MIG320,ZCZ50
|
||||
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,FX,816,620
|
||||
58,FX,816,620,9630
|
||||
59,Bayang_RX,Multi,CPPM
|
||||
60,Pelikan,Pro,Lite,SCX24
|
||||
61,Tiger
|
||||
|
@ -109,10 +109,18 @@ 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";
|
||||
const char STR_SUBTYPE_FRSKYD[] = "\x06""D8\0 ""Cloned";
|
||||
const char STR_SUBTYPE_FRSKYX[] = "\x07""D16\0 ""D16 8ch""LBT(EU)""LBT 8ch""Cloned\0""Clo 8ch";
|
||||
#ifndef MULTI_EU
|
||||
const char STR_SUBTYPE_FRSKYX[] = "\x07""D16\0 ""D16 8ch""LBT(EU)""LBT 8ch""Cloned\0""Clo 8ch";
|
||||
#else
|
||||
const char STR_SUBTYPE_FRSKYX[] = "\x07""--->\0 ""--->\0 ""LBT(EU)""LBT 8ch""Cloned\0""Clo 8ch";
|
||||
#endif
|
||||
const char STR_SUBTYPE_HISKY[] = "\x05""Std\0 ""HK310";
|
||||
const char STR_SUBTYPE_V2X2[] = "\x06""Std\0 ""JXD506""MR101\0";
|
||||
const char STR_SUBTYPE_DSM[] = "\x04""2 1F""2 2F""X 1F""X 2F""Auto""R 1F";
|
||||
#ifndef MULTI_EU
|
||||
const char STR_SUBTYPE_DSM[] = "\x04""2 1F""2 2F""X 1F""X 2F""Auto""R 1F";
|
||||
#else
|
||||
const char STR_SUBTYPE_DSM[] = "\x04""--->""--->""X 1F""X 2F""Auto""R 1F";
|
||||
#endif
|
||||
const char STR_SUBTYPE_DEVO[] = "\x04""8ch\0""10ch""12ch""6ch\0""7ch\0";
|
||||
const char STR_SUBTYPE_YD717[] = "\x07""Std\0 ""SkyWlkr""Syma X4""XINXUN\0""NIHUI\0 ";
|
||||
const char STR_SUBTYPE_KN[] = "\x06""WLtoys""FeiLun";
|
||||
@ -155,7 +163,7 @@ 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";
|
||||
@ -163,9 +171,9 @@ 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_KF606[] = "\x06""KF606\0""MIG320""ZCZ50\0";
|
||||
const char STR_SUBTYPE_E129[] = "\x04""E129""C186";
|
||||
const char STR_SUBTYPE_FX[] = "\x03""816""620";
|
||||
const char STR_SUBTYPE_FX[] = "\x04""816\0""620\0""9630";
|
||||
const char STR_SUBTYPE_CFLIE[] = "\x07""Auto\0 ""2Mbps\0 ""1Mbps\0 ""250kbps";
|
||||
#define NO_SUBTYPE nullptr
|
||||
|
||||
@ -308,7 +316,7 @@ const mm_protocol_definition multi_protocols[] = {
|
||||
{PROTO_FUTABA, STR_FUTABA, STR_SUBTYPE_FUTABA, 1, OPTION_RFTUNE, 1, 1, SW_CC2500, SFHSS_init, SFHSS_callback },
|
||||
#endif
|
||||
#if defined(FX_NRF24L01_INO)
|
||||
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 2, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
|
||||
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 3, 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 },
|
||||
@ -353,7 +361,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, STR_SUBTYPE_KF606, 2, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback },
|
||||
{PROTO_KF606, STR_KF606, STR_SUBTYPE_KF606, 3, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback },
|
||||
#endif
|
||||
#if defined(KN_NRF24L01_INO)
|
||||
{PROTO_KN, STR_KN, STR_SUBTYPE_KN, 2, OPTION_NONE, 0, 0, SW_NRF, KN_init, KN_callback },
|
||||
@ -443,7 +451,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 },
|
||||
|
@ -19,7 +19,7 @@
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 3
|
||||
#define VERSION_REVISION 3
|
||||
#define VERSION_PATCH_LEVEL 19
|
||||
#define VERSION_PATCH_LEVEL 25
|
||||
|
||||
#define MODE_SERIAL 0
|
||||
|
||||
@ -418,6 +418,7 @@ enum V761
|
||||
{
|
||||
V761_3CH = 0,
|
||||
V761_4CH = 1,
|
||||
V761_TOPRC = 2,
|
||||
};
|
||||
enum HEIGHT
|
||||
{
|
||||
@ -449,6 +450,7 @@ enum KF606
|
||||
{
|
||||
KF606_KF606 = 0,
|
||||
KF606_MIG320 = 1,
|
||||
KF606_ZCZ50 = 2,
|
||||
};
|
||||
enum E129
|
||||
{
|
||||
@ -459,6 +461,7 @@ enum FX
|
||||
{
|
||||
FX816 = 0,
|
||||
FX620 = 1,
|
||||
FX9630 = 2,
|
||||
};
|
||||
enum CFLIE
|
||||
{
|
||||
|
@ -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()
|
||||
{
|
||||
@ -56,14 +58,11 @@ static void __attribute__((unused)) V761_send_packet()
|
||||
|
||||
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; // ?
|
||||
packet[6] = 0xF0; // ?
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -72,23 +71,22 @@ static void __attribute__((unused)) V761_send_packet()
|
||||
{
|
||||
hopping_frequency_no = 0;
|
||||
packet_count++;
|
||||
if(packet_count >= 4)
|
||||
packet_count = 0;
|
||||
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<<6; // 0X, 4X, 8X, CX
|
||||
packet[4] = 0x20; // Trims 00..20..40, 0X->20 4X->TrAil 8X->TrEle CX->TrRud
|
||||
@ -112,7 +110,7 @@ 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)
|
||||
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();
|
||||
@ -137,6 +135,13 @@ static void __attribute__((unused)) V761_RF_init()
|
||||
static void __attribute__((unused)) V761_initialize_txid()
|
||||
{
|
||||
#ifdef V761_FORCE_ID
|
||||
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
|
||||
{
|
||||
switch(RX_num%5)
|
||||
{
|
||||
case 1: //Dump from air on Protonus TX
|
||||
@ -160,6 +165,7 @@ static void __attribute__((unused)) V761_initialize_txid()
|
||||
memcpy(hopping_frequency,(uint8_t *)"\x14\x1e",2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
//Tested with Eachine RX
|
||||
rx_tx_addr[0]+=RX_num;
|
||||
@ -180,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)
|
||||
{
|
||||
@ -210,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;
|
||||
|
@ -241,9 +241,11 @@
|
||||
#endif
|
||||
|
||||
//Make sure protocols are selected correctly
|
||||
#ifndef A7105_INSTALLED
|
||||
#if not defined(A7105_INSTALLED) || defined MULTI_EU
|
||||
#undef AFHDS2A_A7105_INO
|
||||
#if not defined(A7105_INSTALLED)
|
||||
#undef AFHDS2A_RX_A7105_INO
|
||||
#endif
|
||||
#undef BUGS_A7105_INO
|
||||
#undef FLYSKY_A7105_INO
|
||||
#undef HEIGHT_A7105_INO
|
||||
@ -253,10 +255,13 @@
|
||||
#undef PELIKAN_A7105_INO
|
||||
#undef WFLY2_A7105_INO
|
||||
#endif
|
||||
#ifndef CYRF6936_INSTALLED
|
||||
|
||||
#if not defined(CYRF6936_INSTALLED) || defined MULTI_EU
|
||||
#undef DEVO_CYRF6936_INO
|
||||
#if not defined(CYRF6936_INSTALLED)
|
||||
#undef DSM_CYRF6936_INO
|
||||
#undef DSM_RX_CYRF6936_INO
|
||||
#endif
|
||||
#undef E010R5_CYRF6936_INO
|
||||
#undef E01X_CYRF6936_INO
|
||||
#undef E129_CYRF6936_INO
|
||||
@ -267,28 +272,38 @@
|
||||
#undef WFLY_CYRF6936_INO
|
||||
#undef WK2x01_CYRF6936_INO
|
||||
#endif
|
||||
#ifndef CC2500_INSTALLED
|
||||
|
||||
#if not defined(CC2500_INSTALLED) || defined MULTI_EU
|
||||
#undef CORONA_CC2500_INO
|
||||
#undef E016HV2_CC2500_INO
|
||||
#undef ESKY150V2_CC2500_INO
|
||||
#undef FRSKYD_CC2500_INO
|
||||
#undef FRSKYL_CC2500_INO
|
||||
#undef FRSKYV_CC2500_INO
|
||||
#if not defined(CC2500_INSTALLED)
|
||||
#undef FRSKYX_CC2500_INO
|
||||
#undef FRSKY_RX_CC2500_INO
|
||||
#endif
|
||||
#undef HITEC_CC2500_INO
|
||||
#if not defined(CC2500_INSTALLED)
|
||||
#undef HOTT_CC2500_INO
|
||||
#endif
|
||||
#undef IKEAANSLUTA_CC2500_INO
|
||||
#undef REDPINE_CC2500_INO
|
||||
#undef RLINK_CC2500_INO
|
||||
#if not defined(CC2500_INSTALLED)
|
||||
#undef SCANNER_CC2500_INO
|
||||
#endif
|
||||
#undef FUTABA_CC2500_INO
|
||||
#undef SKYARTEC_CC2500_INO
|
||||
#endif
|
||||
#ifndef NRF24L01_INSTALLED
|
||||
|
||||
#if not defined(NRF24L01_INSTALLED) || defined MULTI_EU
|
||||
#undef ASSAN_NRF24L01_INO
|
||||
#undef BAYANG_NRF24L01_INO
|
||||
#if not defined(NRF24L01_INSTALLED)
|
||||
#undef BAYANG_RX_NRF24L01_INO
|
||||
#endif
|
||||
#undef BUGSMINI_NRF24L01_INO
|
||||
#undef CABELL_NRF24L01_INO
|
||||
#undef CFLIE_NRF24L01_INO
|
||||
@ -323,7 +338,7 @@
|
||||
#undef YD717_NRF24L01_INO
|
||||
#undef ZSX_NRF24L01_INO
|
||||
#endif
|
||||
#if not defined(CC2500_INSTALLED) && not defined(NRF24L01_INSTALLED)
|
||||
#if ( not defined(CC2500_INSTALLED) && not defined(NRF24L01_INSTALLED) ) || defined MULTI_EU
|
||||
#undef GD00X_CCNRF_INO
|
||||
#undef KF606_CCNRF_INO
|
||||
#undef MJXQ_CCNRF_INO
|
||||
@ -343,7 +358,7 @@
|
||||
#if not defined(STM32_BOARD)
|
||||
#undef SX1276_INSTALLED
|
||||
#endif
|
||||
#ifndef SX1276_INSTALLED
|
||||
#ifndef SX1276_INSTALLED || defined MULTI_EU
|
||||
#undef FRSKYR9_SX1276_INO
|
||||
#endif
|
||||
|
||||
|
@ -673,6 +673,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
PROTO_FX
|
||||
FX816
|
||||
FX620
|
||||
FX9630
|
||||
PROTO_FY326
|
||||
FY326
|
||||
FY319
|
||||
@ -720,6 +721,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
PROTO_KF606
|
||||
KF606_KF606
|
||||
KF606_MIG320
|
||||
KF606_ZCZ50
|
||||
PROTO_KN
|
||||
WLTOYS
|
||||
FEILUN
|
||||
|
@ -110,7 +110,7 @@ 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|KF606|MIG320|||||||NRF24L01|XN297
|
||||
[KF606](Protocols_Details.md#KF606---49)|49|KF606|MIG320|ZCZ50||||||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|
|
||||
@ -141,7 +141,7 @@ 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|
|
||||
@ -528,7 +528,7 @@ DSMX, Resolution 2048, servo refresh rate can only be 22ms
|
||||
### Sub_protocol DSMX_2F - *3*
|
||||
DSMX, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
|
||||
### Sub_protocol AUTO - *4*
|
||||
"AUTO" is recommended to automatically select the best settings for your DSM RX.
|
||||
"AUTO" is recommended to automatically select the best settings for your DSM2 and DSMX RXs.
|
||||
|
||||
### Sub_protocol DSMR_1F - *5*
|
||||
DSMR receivers
|
||||
@ -1049,6 +1049,15 @@ CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A||T||TRIM|LED
|
||||
|
||||
### Sub_protocol ZCZ50v2 - *2*
|
||||
Model: ZC-Z50 Cessna
|
||||
|
||||
This might be newer version of the model. My plane does not have front propeller, but its just fake anyway (no motor in the front).
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A||T||TRIM|UNKNOWN
|
||||
|
||||
## MJXQ - *18*
|
||||
Autobind protocol
|
||||
|
||||
@ -1130,13 +1139,18 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
|
||||
A|E|T|R|FLIP||||HEADLESS
|
||||
|
||||
### Sub_protocol A180 - *5*
|
||||
Model: XK A180, F949S, F959
|
||||
Model: XK A180, A120, F949S, F959
|
||||
|
||||
A180:
|
||||
CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A|E|T|R|3D6G|RATE
|
||||
|
||||
A120:
|
||||
CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A|E|T|R|RATE|LED
|
||||
|
||||
F949S:
|
||||
CH1|CH2|CH3|CH4|CH5|CH6|CH7
|
||||
---|---|---|---|---|---|---
|
||||
@ -1778,7 +1792,7 @@ Option field | Value
|
||||
3|The module will control the brick number RX_num, RX_num+1 and RX_num+2
|
||||
4|The module will control the brick number RX_num, RX_num+1, RX_num+2 and RX_num+3
|
||||
|
||||
To associate a brick to a RX number (RX_num above), set this RX number under the protocol, set option to 1, launch a bind and power on the brick you want to control. Repeat this for every brick using a different RX number each time and then indicate the number of bricks to be comtrolled using the Option field.
|
||||
To associate a brick to a RX number (RX_num above), set this RX number under the protocol, set option to 1, launch a bind and power on the brick you want to control. Repeat this for every brick using a different RX number each time and then indicate the number of bricks to be controlled using the Option field.
|
||||
|
||||
Example: I want to control 2 bricks. I select RX number 1, set option to 1 and launch a bind on the first brick. I select RX number 2, set option to 1 and launch a bind on the second brick. Now to control both bricks I set RX number to 1 and option to 2. Therefore brick1 will react to channels CH1 to CH4 and brick2 to channel CH5 to CH8.
|
||||
On another model I can control 4 other bricks, bind each brick to RX number 3 to 6 and then finaly set RX number to 3 and option to 4 to contol the 4 bricks with CH1 to CH16.
|
||||
@ -1951,14 +1965,21 @@ Flip: momentary switch: hold flip(+100%), indicate flip direction with Ele or Ai
|
||||
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
|
||||
---|---|---|---|---|---|---|---|---
|
||||
|
BIN
STM32 PCB/Flysky PL18/Casing/MPM-BF.stl
Normal file
BIN
STM32 PCB/Flysky PL18/Casing/MPM-TF.stl
Normal file
BIN
STM32 PCB/Flysky PL18/Casing/MPM.blend
Normal file
130
STM32 PCB/Flysky PL18/PL18_multiprotocol/Multi.kicad_sym
Normal file
@ -0,0 +1,130 @@
|
||||
(kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor)
|
||||
(symbol "MULTIRF4IN1SMT" (in_bom yes) (on_board yes)
|
||||
(property "Reference" "M" (id 0) (at -12.7 21.59 0)
|
||||
(effects (font (size 1.27 1.0795)) (justify left bottom))
|
||||
)
|
||||
(property "Value" "MULTIRF4IN1SMT" (id 1) (at -12.7 -16.51 0)
|
||||
(effects (font (size 1.778 1.5113)) (justify left top))
|
||||
)
|
||||
(property "Footprint" "Multi:MULTIRF4IN1-SMT" (id 2) (at 0 0 0)
|
||||
(effects (font (size 1.27 1.27)) hide)
|
||||
)
|
||||
(property "Datasheet" "" (id 3) (at 0 0 0)
|
||||
(effects (font (size 1.27 1.27)) hide)
|
||||
)
|
||||
(symbol "MULTIRF4IN1SMT_1_0"
|
||||
(polyline
|
||||
(pts
|
||||
(xy -12.7 -15.24)
|
||||
(xy 12.7 -15.24)
|
||||
)
|
||||
(stroke (width 0.254) (type default) (color 0 0 0 0))
|
||||
(fill (type none))
|
||||
)
|
||||
(polyline
|
||||
(pts
|
||||
(xy -12.7 20.32)
|
||||
(xy -12.7 -15.24)
|
||||
)
|
||||
(stroke (width 0.254) (type default) (color 0 0 0 0))
|
||||
(fill (type none))
|
||||
)
|
||||
(polyline
|
||||
(pts
|
||||
(xy 12.7 -15.24)
|
||||
(xy 12.7 20.32)
|
||||
)
|
||||
(stroke (width 0.254) (type default) (color 0 0 0 0))
|
||||
(fill (type none))
|
||||
)
|
||||
(polyline
|
||||
(pts
|
||||
(xy 12.7 20.32)
|
||||
(xy -12.7 20.32)
|
||||
)
|
||||
(stroke (width 0.254) (type default) (color 0 0 0 0))
|
||||
(fill (type none))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 17.78 180) (length 2.54)
|
||||
(name "CE_2401" (effects (font (size 1.27 1.27))))
|
||||
(number "CE_2401" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 2.54 180) (length 2.54)
|
||||
(name "CS_2401" (effects (font (size 1.27 1.27))))
|
||||
(number "CS_2401" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 0 180) (length 2.54)
|
||||
(name "CS_2500" (effects (font (size 1.27 1.27))))
|
||||
(number "CS_2500" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 5.08 180) (length 2.54)
|
||||
(name "CS_6936" (effects (font (size 1.27 1.27))))
|
||||
(number "CS_6936" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 -2.54 180) (length 2.54)
|
||||
(name "CS_7105" (effects (font (size 1.27 1.27))))
|
||||
(number "CS_7105" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin power_in line (at 15.24 -10.16 180) (length 2.54)
|
||||
(name "GND" (effects (font (size 1.27 1.27))))
|
||||
(number "GND" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin power_in line (at -15.24 17.78 0) (length 2.54)
|
||||
(name "GND@1" (effects (font (size 1.27 1.27))))
|
||||
(number "GND@1" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin power_in line (at -15.24 15.24 0) (length 2.54)
|
||||
(name "GND@2" (effects (font (size 1.27 1.27))))
|
||||
(number "GND@2" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin power_in line (at -15.24 5.08 0) (length 2.54)
|
||||
(name "GND@3" (effects (font (size 1.27 1.27))))
|
||||
(number "GND@3" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin power_in line (at -15.24 0 0) (length 2.54)
|
||||
(name "GND@4" (effects (font (size 1.27 1.27))))
|
||||
(number "GND@4" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin power_in line (at -15.24 -10.16 0) (length 2.54)
|
||||
(name "GND@5" (effects (font (size 1.27 1.27))))
|
||||
(number "GND@5" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin power_in line (at -15.24 -12.7 0) (length 2.54)
|
||||
(name "GND@6" (effects (font (size 1.27 1.27))))
|
||||
(number "GND@6" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 12.7 180) (length 2.54)
|
||||
(name "MISO" (effects (font (size 1.27 1.27))))
|
||||
(number "MISO" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 10.16 180) (length 2.54)
|
||||
(name "MOSI" (effects (font (size 1.27 1.27))))
|
||||
(number "MOSI" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 -7.62 180) (length 2.54)
|
||||
(name "PE1" (effects (font (size 1.27 1.27))))
|
||||
(number "PE1" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 -5.08 180) (length 2.54)
|
||||
(name "PE2" (effects (font (size 1.27 1.27))))
|
||||
(number "PE2" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin output line (at -15.24 2.54 0) (length 2.54)
|
||||
(name "RF" (effects (font (size 1.27 1.27))))
|
||||
(number "RF" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 15.24 180) (length 2.54)
|
||||
(name "RST_CYFR" (effects (font (size 1.27 1.27))))
|
||||
(number "RST_CYFR" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin bidirectional line (at 15.24 7.62 180) (length 2.54)
|
||||
(name "SCK" (effects (font (size 1.27 1.27))))
|
||||
(number "SCK" (effects (font (size 0 0))))
|
||||
)
|
||||
(pin power_in line (at 15.24 -12.7 180) (length 2.54)
|
||||
(name "VCC" (effects (font (size 1.27 1.27))))
|
||||
(number "VCC" (effects (font (size 0 0))))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
@ -0,0 +1,42 @@
|
||||
(footprint "DS-B01F-A-S2" (version 20211014) (generator pcbnew)
|
||||
(layer "F.Cu")
|
||||
(tedit 59FED5CC)
|
||||
(descr "Through hole straight pin header, 1x05, 2.54mm pitch, single row")
|
||||
(tags "Through hole pin header THT 1x05 2.54mm single row")
|
||||
(attr through_hole)
|
||||
(fp_text reference "REF**" (at -0.25 -4.75) (layer "F.SilkS")
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
(tstamp d518c7db-9a4d-4905-902c-7b6d95f659cb)
|
||||
)
|
||||
(fp_text value "DS-B01F-A-S2" (at 0 12.49) (layer "F.Fab")
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
(tstamp 614f538e-5f2b-401d-b0ab-3346d3ff44e4)
|
||||
)
|
||||
(fp_text user "${REFERENCE}" (at 0 5.08 90) (layer "F.Fab")
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
(tstamp 9586cda1-48da-45c7-86f7-751657e7c25a)
|
||||
)
|
||||
(fp_line (start -4.5 13.5) (end 1.25 13.5) (layer "F.SilkS") (width 0.12) (tstamp 05393a00-de07-40a8-8064-67c0a8a1e9ef))
|
||||
(fp_line (start 1.25 -3.5) (end 1.25 13.5) (layer "F.SilkS") (width 0.12) (tstamp 09bf1fa9-9ec6-4d5c-bed9-fcd1fe76bd8e))
|
||||
(fp_line (start -4.5 -3.5) (end 1.25 -3.5) (layer "F.SilkS") (width 0.12) (tstamp 2f1dd441-3cdc-4eed-9839-dc1fa6a931ba))
|
||||
(fp_line (start -4.5 -3.5) (end -4.5 13.5) (layer "F.SilkS") (width 0.12) (tstamp 35bb1bb5-998b-4ce9-a139-e009425d4e40))
|
||||
(fp_line (start -4.5 -3.5) (end -4.5 13.5) (layer "F.CrtYd") (width 0.05) (tstamp 346ee0d3-e13a-49f6-8f6c-eb860777d6c4))
|
||||
(fp_line (start 1.25 13.5) (end 1.25 -3.5) (layer "F.CrtYd") (width 0.05) (tstamp 93808e54-10fb-4c6c-984b-3a91c36dbafa))
|
||||
(fp_line (start 1.25 -3.5) (end -4.5 -3.5) (layer "F.CrtYd") (width 0.05) (tstamp d7a0888c-6be2-4a97-ac01-de345dcd2919))
|
||||
(fp_line (start -4.5 13.5) (end 1.25 13.5) (layer "F.CrtYd") (width 0.05) (tstamp ee85719d-9f71-411e-a024-43105a50c262))
|
||||
(fp_line (start -1.27 11.43) (end -1.27 -0.635) (layer "F.Fab") (width 0.1) (tstamp 085f4818-84f1-415f-823e-e6076d0e732d))
|
||||
(fp_line (start -1.27 -0.635) (end -0.635 -1.27) (layer "F.Fab") (width 0.1) (tstamp 602c4495-9f5f-4ae3-9800-df18526e3c50))
|
||||
(fp_line (start 1.27 -1.27) (end 1.27 11.43) (layer "F.Fab") (width 0.1) (tstamp 73eb4832-b804-463c-ae2b-563755d89978))
|
||||
(fp_line (start -0.635 -1.27) (end 1.27 -1.27) (layer "F.Fab") (width 0.1) (tstamp aed66e63-a453-441e-94eb-3442ef294c72))
|
||||
(fp_line (start 1.27 11.43) (end -1.27 11.43) (layer "F.Fab") (width 0.1) (tstamp dde86203-069d-47dc-8693-34fe614da099))
|
||||
(pad "1" thru_hole rect (at 0 0) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask) (tstamp 174ecd2f-6484-485c-a83d-71d6a1dc733a))
|
||||
(pad "2" thru_hole oval (at 0 2.5) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask) (tstamp 997a59d1-7e2b-4400-b74b-3cb21ad33038))
|
||||
(pad "3" thru_hole oval (at 0 5) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask) (tstamp 7aa5c04b-5bd3-4c72-bbaf-9ec87c5447e0))
|
||||
(pad "4" thru_hole oval (at 0 7.5) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask) (tstamp 8a6c42bd-bf44-40be-9e58-41dc76d10644))
|
||||
(pad "5" thru_hole oval (at 0 10) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask) (tstamp c1741286-ba0e-4f33-8f37-5fd51504bac5))
|
||||
(model "${KICAD6_3DMODEL_DIR}/Connector_PinHeader_2.54mm.3dshapes/PinHeader_1x05_P2.54mm_Vertical.wrl"
|
||||
(offset (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
)
|
@ -0,0 +1,60 @@
|
||||
(footprint "MULTIRF4IN1-SMT" (version 20211014) (generator pcbnew)
|
||||
(layer "F.Cu")
|
||||
(tedit 0)
|
||||
(fp_text reference "REF**" (at 0 -0.75) (layer "F.SilkS")
|
||||
(effects (font (size 1.27 1.27) (thickness 0.15)))
|
||||
(tstamp c70c9e03-6ffa-4ea8-9291-15d2673122a0)
|
||||
)
|
||||
(fp_text value "Val**" (at 0 1) (layer "F.Fab")
|
||||
(effects (font (size 1.27 1.27) (thickness 0.15)))
|
||||
(tstamp c3246ecf-81bc-4b14-94a2-7b86227cabaf)
|
||||
)
|
||||
(fp_line (start -13 11.9) (end -13 17) (layer "F.SilkS") (width 0.12) (tstamp 21d8aff3-5b17-43c7-9d08-4e33edbcbeb9))
|
||||
(fp_line (start -13 3.4) (end -13 8.1) (layer "F.SilkS") (width 0.12) (tstamp 4a2c9e01-3f0b-4116-a39b-baa7e7b94b8a))
|
||||
(fp_line (start -13 -8.1) (end -13 -2.4) (layer "F.SilkS") (width 0.12) (tstamp 960baeae-d7ca-4f76-ac15-6cd68f041702))
|
||||
(fp_line (start 13 -17) (end 13 -13.9) (layer "F.SilkS") (width 0.12) (tstamp a22c44ee-0c9a-42e0-81e0-94f90a0da388))
|
||||
(fp_line (start 13 11.9) (end 13 17) (layer "F.SilkS") (width 0.12) (tstamp a8050edb-a9eb-479e-abea-105077de87b8))
|
||||
(fp_line (start -13 -17) (end -13 -11.9) (layer "F.SilkS") (width 0.12) (tstamp dbeb96d9-bbc7-4dae-ba00-6746209bdc43))
|
||||
(fp_line (start 13 -17) (end -13 -17) (layer "F.SilkS") (width 0.12) (tstamp de173627-aedf-48e0-8674-66cfe17b969a))
|
||||
(fp_line (start 13 17) (end -13 17) (layer "F.SilkS") (width 0.12) (tstamp edb180b5-b35e-4fa4-8440-d021574908ae))
|
||||
(pad "CE_2401" smd rect (at 12.49 -13) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 177c8408-9b8a-453c-871a-7a335239833a))
|
||||
(pad "CS_2401" smd rect (at 12.49 -1) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp deb3cbb7-c404-4161-b154-3014395e2a30))
|
||||
(pad "CS_2500" smd rect (at 12.49 1) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp e8ecba2d-0746-43bc-b641-9cc180ff9253))
|
||||
(pad "CS_6936" smd rect (at 12.49 -3) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 90314976-271d-4f34-b2f0-dff6de6b86e7))
|
||||
(pad "CS_7105" smd rect (at 12.49 3) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 1f154bf6-42ea-456f-89ac-fed01ff7208b))
|
||||
(pad "GND" smd rect (at 12.49 9) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 14373cb3-8424-453e-b0d3-1a6022ea35b1))
|
||||
(pad "GND@1" smd rect (at -12.49 -11) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp b15a1378-3e57-41cb-96b2-030f4848402c))
|
||||
(pad "GND@2" smd rect (at -12.49 -9) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 71e83330-d2fe-4680-bbc4-fbbb511ecf3d))
|
||||
(pad "GND@3" smd rect (at -12.49 -1.5) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 27f29ad7-d4f7-416a-bc00-7c36c9ffbaca))
|
||||
(pad "GND@4" smd rect (at -12.49 2.5) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 6b446947-9739-4960-abfc-ef89034a0437))
|
||||
(pad "GND@5" smd rect (at -12.49 9) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 589b3137-9b71-4e00-93fe-63222c56ecc3))
|
||||
(pad "GND@6" smd rect (at -12.49 11) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 371c3d69-e48f-46fb-a1b6-b681b17bacb1))
|
||||
(pad "MISO" smd rect (at 12.49 -9) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp a1ef8d67-bdf4-443e-88f7-406670c2aef9))
|
||||
(pad "MOSI" smd rect (at 12.49 -7) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp d9f5d5e2-2571-4cc2-800c-f5758bd5695f))
|
||||
(pad "PE1" smd rect (at 12.49 7) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 06684ce2-c9de-48bf-9621-ada44ca8a12c))
|
||||
(pad "PE2" smd rect (at 12.49 5) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp bd470244-7da3-4d59-894b-19e4071da146))
|
||||
(pad "RF" smd rect (at -12.49 0.5) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp e91e6b83-902b-42be-92fa-6ac19487af54))
|
||||
(pad "RST_CYFR" smd rect (at 12.49 -11) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp dc86e8ca-1f6b-4f0d-9576-5c57346768bf))
|
||||
(pad "SCK" smd rect (at 12.49 -5) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 483e384c-d6af-490d-b4f9-371490f0e46f))
|
||||
(pad "VCC" smd rect (at 12.49 11) (size 1.52 1.27) (layers "F.Cu" "F.Paste" "F.Mask")
|
||||
(solder_mask_margin 0.1) (tstamp 8796d68c-81fa-42ef-ace9-9d8c76827e59))
|
||||
)
|
11745
STM32 PCB/Flysky PL18/PL18_multiprotocol/PL18_multiprotocol.kicad_pcb
Normal file
@ -0,0 +1,75 @@
|
||||
{
|
||||
"board": {
|
||||
"active_layer": 0,
|
||||
"active_layer_preset": "All Layers",
|
||||
"auto_track_width": false,
|
||||
"hidden_nets": [],
|
||||
"high_contrast_mode": 0,
|
||||
"net_color_mode": 1,
|
||||
"opacity": {
|
||||
"pads": 1.0,
|
||||
"tracks": 1.0,
|
||||
"vias": 1.0,
|
||||
"zones": 0.6
|
||||
},
|
||||
"ratsnest_display_mode": 0,
|
||||
"selection_filter": {
|
||||
"dimensions": true,
|
||||
"footprints": true,
|
||||
"graphics": true,
|
||||
"keepouts": true,
|
||||
"lockedItems": true,
|
||||
"otherItems": true,
|
||||
"pads": true,
|
||||
"text": true,
|
||||
"tracks": true,
|
||||
"vias": true,
|
||||
"zones": true
|
||||
},
|
||||
"visible_items": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36
|
||||
],
|
||||
"visible_layers": "fffffff_ffffffff",
|
||||
"zone_display_mode": 0
|
||||
},
|
||||
"meta": {
|
||||
"filename": "PL18_multiprotocol.kicad_prl",
|
||||
"version": 3
|
||||
},
|
||||
"project": {
|
||||
"files": []
|
||||
}
|
||||
}
|
@ -0,0 +1,462 @@
|
||||
{
|
||||
"board": {
|
||||
"design_settings": {
|
||||
"defaults": {
|
||||
"board_outline_line_width": 0.09999999999999999,
|
||||
"copper_line_width": 0.19999999999999998,
|
||||
"copper_text_italic": false,
|
||||
"copper_text_size_h": 1.5,
|
||||
"copper_text_size_v": 1.5,
|
||||
"copper_text_thickness": 0.3,
|
||||
"copper_text_upright": false,
|
||||
"courtyard_line_width": 0.049999999999999996,
|
||||
"dimension_precision": 4,
|
||||
"dimension_units": 3,
|
||||
"dimensions": {
|
||||
"arrow_length": 1270000,
|
||||
"extension_offset": 500000,
|
||||
"keep_text_aligned": true,
|
||||
"suppress_zeroes": false,
|
||||
"text_position": 0,
|
||||
"units_format": 1
|
||||
},
|
||||
"fab_line_width": 0.09999999999999999,
|
||||
"fab_text_italic": false,
|
||||
"fab_text_size_h": 1.0,
|
||||
"fab_text_size_v": 1.0,
|
||||
"fab_text_thickness": 0.15,
|
||||
"fab_text_upright": false,
|
||||
"other_line_width": 0.15,
|
||||
"other_text_italic": false,
|
||||
"other_text_size_h": 1.0,
|
||||
"other_text_size_v": 1.0,
|
||||
"other_text_thickness": 0.15,
|
||||
"other_text_upright": false,
|
||||
"pads": {
|
||||
"drill": 0.762,
|
||||
"height": 1.524,
|
||||
"width": 1.524
|
||||
},
|
||||
"silk_line_width": 0.15,
|
||||
"silk_text_italic": false,
|
||||
"silk_text_size_h": 1.0,
|
||||
"silk_text_size_v": 1.0,
|
||||
"silk_text_thickness": 0.15,
|
||||
"silk_text_upright": false,
|
||||
"zones": {
|
||||
"45_degree_only": false,
|
||||
"min_clearance": 0.19999999999999998
|
||||
}
|
||||
},
|
||||
"diff_pair_dimensions": [
|
||||
{
|
||||
"gap": 0.0,
|
||||
"via_gap": 0.0,
|
||||
"width": 0.0
|
||||
}
|
||||
],
|
||||
"drc_exclusions": [
|
||||
"copper_edge_clearance|34900000|34735000|785ef911-e457-413e-ac63-cf1535b242cb|be0d3c71-0f5b-45b9-9c9b-72866af0f7a2",
|
||||
"copper_edge_clearance|34900000|36735000|785ef911-e457-413e-ac63-cf1535b242cb|e7b16a25-ec09-4bb5-aa09-fe00038c1f1f",
|
||||
"copper_edge_clearance|34900000|38735000|785ef911-e457-413e-ac63-cf1535b242cb|e65ad8dc-91cb-4c5d-b0fe-169b84ac0b55",
|
||||
"copper_edge_clearance|34900000|40735000|785ef911-e457-413e-ac63-cf1535b242cb|95287391-9e27-4475-a375-0f63337ce67a",
|
||||
"copper_edge_clearance|34900000|42735000|785ef911-e457-413e-ac63-cf1535b242cb|c29c966c-91b2-4b36-b1bc-6673192d38fe",
|
||||
"copper_edge_clearance|34900000|44735000|785ef911-e457-413e-ac63-cf1535b242cb|4f24c66e-64cb-408b-9295-97d993d96225",
|
||||
"copper_edge_clearance|34900000|46735000|785ef911-e457-413e-ac63-cf1535b242cb|0ddbf31e-bbeb-43d6-ae3b-cab85e65b36d",
|
||||
"copper_edge_clearance|34900000|48735000|785ef911-e457-413e-ac63-cf1535b242cb|4dcf731f-2949-4865-b539-ff1e637244c5",
|
||||
"copper_edge_clearance|34900000|50735000|785ef911-e457-413e-ac63-cf1535b242cb|34e18046-0932-48eb-854b-3707688a2215",
|
||||
"copper_edge_clearance|34900000|52735000|785ef911-e457-413e-ac63-cf1535b242cb|5c40c44b-70c5-4c30-aafc-a4724555cbb1",
|
||||
"copper_edge_clearance|34900000|54735000|785ef911-e457-413e-ac63-cf1535b242cb|bb59f967-af06-40a4-adc7-d38dcc40fc54",
|
||||
"copper_edge_clearance|34900000|56735000|785ef911-e457-413e-ac63-cf1535b242cb|27057d15-87f3-4a5e-bab7-6c1fa0d1954f",
|
||||
"copper_edge_clearance|34900000|58735000|785ef911-e457-413e-ac63-cf1535b242cb|13a669d2-833b-4c54-a87d-44fb38d91e82",
|
||||
"copper_edge_clearance|61100000|36735000|b1556ea3-f1cc-4201-b942-480142bd0c54|5bd3edee-4a1d-4d5f-8aae-d7afd4bced8c",
|
||||
"copper_edge_clearance|61100000|38735000|b1556ea3-f1cc-4201-b942-480142bd0c54|2bcfc76b-5219-4cb8-b24e-4fb83ce73dfb",
|
||||
"copper_edge_clearance|61100000|46235000|b1556ea3-f1cc-4201-b942-480142bd0c54|ad1d31a9-5733-4b73-be03-a80ca4f16773",
|
||||
"copper_edge_clearance|61100000|48235000|b1556ea3-f1cc-4201-b942-480142bd0c54|0967fce8-8cdb-4026-bedd-d620a9cd0bad",
|
||||
"copper_edge_clearance|61100000|50235000|b1556ea3-f1cc-4201-b942-480142bd0c54|7aa764ba-7abe-485a-b859-ce8f0595e5cd",
|
||||
"copper_edge_clearance|61100000|56735000|b1556ea3-f1cc-4201-b942-480142bd0c54|7dbb4403-9304-4fc0-8912-17af08ce6248",
|
||||
"copper_edge_clearance|61100000|58735000|b1556ea3-f1cc-4201-b942-480142bd0c54|425646f1-4301-496a-bd77-d52b64168923"
|
||||
],
|
||||
"meta": {
|
||||
"version": 2
|
||||
},
|
||||
"rule_severities": {
|
||||
"annular_width": "error",
|
||||
"clearance": "error",
|
||||
"copper_edge_clearance": "error",
|
||||
"courtyards_overlap": "error",
|
||||
"diff_pair_gap_out_of_range": "error",
|
||||
"diff_pair_uncoupled_length_too_long": "error",
|
||||
"drill_out_of_range": "error",
|
||||
"duplicate_footprints": "warning",
|
||||
"extra_footprint": "warning",
|
||||
"footprint_type_mismatch": "error",
|
||||
"hole_clearance": "error",
|
||||
"hole_near_hole": "error",
|
||||
"invalid_outline": "error",
|
||||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
"missing_footprint": "warning",
|
||||
"net_conflict": "warning",
|
||||
"npth_inside_courtyard": "ignore",
|
||||
"padstack": "error",
|
||||
"pth_inside_courtyard": "ignore",
|
||||
"shorting_items": "error",
|
||||
"silk_over_copper": "warning",
|
||||
"silk_overlap": "warning",
|
||||
"skew_out_of_range": "error",
|
||||
"through_hole_pad_without_hole": "error",
|
||||
"too_many_vias": "error",
|
||||
"track_dangling": "warning",
|
||||
"track_width": "error",
|
||||
"tracks_crossing": "error",
|
||||
"unconnected_items": "error",
|
||||
"unresolved_variable": "error",
|
||||
"via_dangling": "warning",
|
||||
"zone_has_empty_net": "error",
|
||||
"zones_intersect": "error"
|
||||
},
|
||||
"rules": {
|
||||
"allow_blind_buried_vias": false,
|
||||
"allow_microvias": false,
|
||||
"max_error": 0.005,
|
||||
"min_clearance": 0.0,
|
||||
"min_copper_edge_clearance": 0.0,
|
||||
"min_hole_clearance": 0.25,
|
||||
"min_hole_to_hole": 0.25,
|
||||
"min_microvia_diameter": 0.19999999999999998,
|
||||
"min_microvia_drill": 0.09999999999999999,
|
||||
"min_silk_clearance": 0.0,
|
||||
"min_through_hole_diameter": 0.3,
|
||||
"min_track_width": 0.19999999999999998,
|
||||
"min_via_annular_width": 0.049999999999999996,
|
||||
"min_via_diameter": 0.39999999999999997,
|
||||
"solder_mask_clearance": 0.0,
|
||||
"solder_mask_min_width": 0.0,
|
||||
"use_height_for_length_calcs": true
|
||||
},
|
||||
"track_widths": [
|
||||
0.0,
|
||||
0.4,
|
||||
0.6,
|
||||
0.603595,
|
||||
1.0
|
||||
],
|
||||
"via_dimensions": [
|
||||
{
|
||||
"diameter": 0.0,
|
||||
"drill": 0.0
|
||||
},
|
||||
{
|
||||
"diameter": 1.2,
|
||||
"drill": 0.6
|
||||
}
|
||||
],
|
||||
"zones_allow_external_fillets": false,
|
||||
"zones_use_no_outline": true
|
||||
},
|
||||
"layer_presets": []
|
||||
},
|
||||
"boards": [],
|
||||
"cvpcb": {
|
||||
"equivalence_files": []
|
||||
},
|
||||
"erc": {
|
||||
"erc_exclusions": [],
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"pin_map": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
]
|
||||
],
|
||||
"rule_severities": {
|
||||
"bus_definition_conflict": "error",
|
||||
"bus_entry_needed": "error",
|
||||
"bus_label_syntax": "error",
|
||||
"bus_to_bus_conflict": "error",
|
||||
"bus_to_net_conflict": "error",
|
||||
"different_unit_footprint": "error",
|
||||
"different_unit_net": "error",
|
||||
"duplicate_reference": "error",
|
||||
"duplicate_sheet_names": "error",
|
||||
"extra_units": "error",
|
||||
"global_label_dangling": "warning",
|
||||
"hier_label_mismatch": "error",
|
||||
"label_dangling": "error",
|
||||
"lib_symbol_issues": "warning",
|
||||
"multiple_net_names": "warning",
|
||||
"net_not_bus_member": "warning",
|
||||
"no_connect_connected": "warning",
|
||||
"no_connect_dangling": "warning",
|
||||
"pin_not_connected": "error",
|
||||
"pin_not_driven": "error",
|
||||
"pin_to_pin": "warning",
|
||||
"power_pin_not_driven": "error",
|
||||
"similar_labels": "warning",
|
||||
"unannotated": "error",
|
||||
"unit_value_mismatch": "error",
|
||||
"unresolved_variable": "error",
|
||||
"wire_dangling": "error"
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"pinned_footprint_libs": [],
|
||||
"pinned_symbol_libs": []
|
||||
},
|
||||
"meta": {
|
||||
"filename": "PL18_multiprotocol.kicad_pro",
|
||||
"version": 1
|
||||
},
|
||||
"net_settings": {
|
||||
"classes": [
|
||||
{
|
||||
"bus_width": 12.0,
|
||||
"clearance": 0.2,
|
||||
"diff_pair_gap": 0.25,
|
||||
"diff_pair_via_gap": 0.25,
|
||||
"diff_pair_width": 0.2,
|
||||
"line_style": 0,
|
||||
"microvia_diameter": 0.3,
|
||||
"microvia_drill": 0.1,
|
||||
"name": "Default",
|
||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||
"track_width": 0.25,
|
||||
"via_diameter": 0.8,
|
||||
"via_drill": 0.4,
|
||||
"wire_width": 6.0
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"version": 2
|
||||
},
|
||||
"net_colors": null
|
||||
},
|
||||
"pcbnew": {
|
||||
"last_paths": {
|
||||
"gencad": "",
|
||||
"idf": "",
|
||||
"netlist": "",
|
||||
"specctra_dsn": "",
|
||||
"step": "",
|
||||
"vrml": ""
|
||||
},
|
||||
"page_layout_descr_file": ""
|
||||
},
|
||||
"schematic": {
|
||||
"annotate_start_num": 0,
|
||||
"drawing": {
|
||||
"default_line_thickness": 6.0,
|
||||
"default_text_size": 50.0,
|
||||
"field_names": [],
|
||||
"intersheets_ref_own_page": false,
|
||||
"intersheets_ref_prefix": "",
|
||||
"intersheets_ref_short": false,
|
||||
"intersheets_ref_show": false,
|
||||
"intersheets_ref_suffix": "",
|
||||
"junction_size_choice": 3,
|
||||
"label_size_ratio": 0.375,
|
||||
"pin_symbol_size": 25.0,
|
||||
"text_offset_ratio": 0.15
|
||||
},
|
||||
"legacy_lib_dir": "",
|
||||
"legacy_lib_list": [],
|
||||
"meta": {
|
||||
"version": 1
|
||||
},
|
||||
"net_format_name": "",
|
||||
"ngspice": {
|
||||
"fix_include_paths": true,
|
||||
"fix_passive_vals": false,
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"model_mode": 0,
|
||||
"workbook_filename": ""
|
||||
},
|
||||
"page_layout_descr_file": "",
|
||||
"plot_directory": "",
|
||||
"spice_adjust_passive_values": false,
|
||||
"spice_external_command": "spice \"%I\"",
|
||||
"subpart_first_id": 65,
|
||||
"subpart_id_separator": 0
|
||||
},
|
||||
"sheets": [
|
||||
[
|
||||
"e6b36db3-d652-4d66-bbfe-8c61f998d4b2",
|
||||
""
|
||||
]
|
||||
],
|
||||
"text_variables": {}
|
||||
}
|
86052
STM32 PCB/Flysky PL18/PL18_multiprotocol/fp-info-cache
Normal file
3
STM32 PCB/Flysky PL18/PL18_multiprotocol/fp-lib-table
Normal file
@ -0,0 +1,3 @@
|
||||
(fp_lib_table
|
||||
(lib (name "Multi")(type "KiCad")(uri "${KIPRJMOD}/Multi.pretty")(options "")(descr ""))
|
||||
)
|
3
STM32 PCB/Flysky PL18/PL18_multiprotocol/sym-lib-table
Normal file
@ -0,0 +1,3 @@
|
||||
(sym_lib_table
|
||||
(lib (name "Multi")(type "KiCad")(uri "${KIPRJMOD}/Multi.kicad_sym")(options "")(descr ""))
|
||||
)
|
5
STM32 PCB/Flysky PL18/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# MPM for Flysky PL18
|
||||
|
||||
The PCB design is located in PL18_multiprotocol folder and is designed using KiCad 6.0.
|
||||
|
||||
The casing is located in Casing folder and is designed using Blender 3.3.1. The model included 2 pieces, T is the top piece and B is the bottom pieces. These 2 pieces is cloned into TF and BF respectively to apply all modifiers and make manifold for 3D printing. I have included the stl files generated for simplity.
|
@ -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:
|
||||
|