Compare commits

..

4 Commits

Author SHA1 Message Date
pascallanger
58f6716035
Update README.md 2022-11-17 09:49:30 +01:00
pascallanger
2b15de0f90
Update README.md 2022-11-17 09:47:22 +01:00
pascallanger
be91409df9
Delete DSM FwdPrg.lua 2022-11-17 09:44:18 +01:00
Frankie Arzu
4d8e440965
Frankie dsm fwrd prg enhancements (#753)
DSM Forward Programming Enhancements (New GUI for Color+Touch and BW, etc). Work on EdgeTx and OpenTX.
2022-11-17 09:42:04 +01:00
9 changed files with 3563 additions and 777 deletions

View File

@ -1,771 +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]="Off"
Text[0x0002]="On"
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[0x008E]="Panic Delay"
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[0x00D2]="Panic Channel"
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[0x01FC]="Panic Flight Mode"
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 }

View File

@ -0,0 +1,439 @@
local toolName = "TNS|DSM Forward Prog v0.5 (Text B&W) |TNE"
---- #########################################################################
---- # #
---- # Copyright (C) OpenTX #
-----# #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
local SIMULATION_ON = true -- FALSE: use real communication to DSM RX (DEFAULT), TRUE: use a simulated version of RX
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
local dsmLib
if (SIMULATION_ON) then
-- library with SIMILATION VERSION. Works really well in Companion for GUI development
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
else
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
end
local PHASE = dsmLib.PHASE
local LINE_TYPE = dsmLib.LINE_TYPE
local DISP_ATTR = dsmLib.DISP_ATTR
local DSM_Context = dsmLib.DSM_Context
local LCD_W_USABLE = LCD_W-10
-- X for Menu Lines
local LCD_X_LINE_MENU = 10
-- X offsets for (Title: [Value] debugInfo) lines
local LCD_X_LINE_TITLE = 10
local LCD_X_LINE_VALUE = 230
local LCD_X_LINE_DEBUG = 390
-- Line Height: make it smaller debugging info tp LCD (some space buttom)
local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27
-- Y offsets
local LCD_Y_MENU_TITLE = 20
-- Y offet
local LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 30
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT
local LCD_W_BUTTONS = 47
local LCD_H_BUTTONS = 25
local LCD_X_RIGHT_BUTTONS = LCD_W - LCD_W_BUTTONS - 5
local TEXT_SIZE = 0 -- NORMAL
local lastRefresh=0 -- Last time the screen was refreshed
local REFRESH_GUI_MS = 500/10 -- 500ms.. Screen Refresh Rate.. to not use unneded CPU time (in 10ms units to be compatible with getTime())
local originalValue = nil
------------------------------------------------------------------------------------------------------------
local function GUI_SwitchSimulationOFF()
dsmLib.ReleaseConnection()
dsmLib.LOG_close()
SIMULATION_ON = false
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
DSM_Context = dsmLib.DSM_Context
dsmLib.Init(toolName) -- Initialize Library
dsmLib.StartConnection()
DSM_Context.Refresh_Display = true
end
local function openTx_lcd_sizeText(s)
return string.len(s)*5
end
local function GUI_Diplay_Button(x,y,w,h,text,selected)
local attr = (selected) and INVERS or 0 -- INVERS if line Selected
lcd.drawText(x+5,y+2, text, attr + TEXT_SIZE)
lcd.drawRectangle(x, y, w, h, LINE_COLOR)
end
local function GUI_Display_Menu(menu)
local ctx = DSM_Context
local w= LCD_W_USABLE - LCD_W_BUTTONS - 10 -- usable Width for the Menu/Lines
-- Center Header
local tw = openTx_lcd_sizeText(menu.Text)
local x = w/2 - tw/2 -- Center of Screen - Center of Text
local bold = 0
if (TEXT_SIZE~=SMLSIZE) then -- Ignore Bold on small size screens
bold = BOLD
end
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text,bold + TEXT_SIZE)
-- Back
if menu.BackId ~= 0 then
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_MENU_TITLE,LCD_W_BUTTONS,LCD_H_BUTTONS,"Back",ctx.SelLine == dsmLib.BACK_BUTTON)
end
-- Next ?
if menu.NextId ~= 0 then
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON)
end
-- Prev?
if menu.PrevId ~= 0 then
GUI_Diplay_Button(0,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON)
end
-- Debug into LCD
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),TEXT_SIZE + WARNING_COLOR) end -- Phase we are in
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_MENU,240,dsmLib.menu2String(menu),TEXT_SIZE + WARNING_COLOR) end -- Menu Info
end
local function GUI_Display_Line_Menu(x,y,w,h,line,selected)
local attr = (selected and INVERS) or 0 -- INVERS if line Selected
local bold = 0
local text = line.Text
if dsmLib.isSelectableLine(line) then
-- Menu Line
text = text .. " |>" --OPENTX
else -- SubHeaders and plain text lines
if (TEXT_SIZE~=SMLSIZE) then -- ignore bold on small size screens
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0
end
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align???
local tw = openTx_lcd_sizeText(line.Text)+4
x = LCD_X_LINE_VALUE - tw -- Right
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Center??
local tw = openTx_lcd_sizeText(line.Text)
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
end
end
lcd.drawText(x,y, text, attr + bold + TEXT_SIZE)
end
------------------------------------------------------------------------------------------------------------
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
local bold = 0
local y = LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*lineNum)
local x = LCD_X_LINE_TITLE
---------- NAME Part
local header = line.Text
-- ONLY do this for Flight Mode (Right Align or Centered)
if (dsmLib.isFlightModeText(line.TextId)) then
-- Display Header + Value together
header = header .. " " .. value
-- Flight mode display attributes
if (TEXT_SIZE~=SMLSIZE) then -- ignore bold on small size screens
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0
end
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align
local tw = openTx_lcd_sizeText(header)+4
x = LCD_X_LINE_VALUE - tw -- Right
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Centered
local tw = openTx_lcd_sizeText(header)
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
end
else
-- No Flight Mode, no effects here
header = header .. ":"
end
lcd.drawText(x, y, header, bold + TEXT_SIZE) -- display Line Header
--------- VALUE PART, Skip for Flight Mode since already show the value
if not dsmLib.isFlightModeText(line.TextId) then
local attrib = 0
value = value .. (line.Format or "") -- Append % if needed
if selected then
attrib = INVERS
if editing then -- blink editing entry
attrib = attrib + BLINK
value = "[ " .. value .. " ]"
end
end
lcd.drawText(LCD_X_LINE_VALUE,y, value, attrib + TEXT_SIZE) -- display value
end
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG,y, line.MinMaxDebug or "", TEXT_SIZE + WARNING_COLOR) end -- display debug
end
------------------------------------------------------------------------------------------------------------
local function GUI_Display()
local ctx = DSM_Context
lcd.clear()
local header = "DSM Fwrd Programming "
if ctx.Phase ~= PHASE.RX_VERSION then
header = header .. "RX "..ctx.RX.Name.." v"..ctx.RX.Version
end
--Draw title
if (TEXT_SIZE~=SMLSIZE) then -- ignore tool title small size screens
lcd.drawFilledRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR)
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
end
--Draw RX Menu
if ctx.Phase == PHASE.RX_VERSION then
lcd.drawText(LCD_X_LINE_TITLE,50,"No compatible DSM RX...", BLINK + TEXT_SIZE)
else
local menu = ctx.Menu
if menu.Text ~= nil then
GUI_Display_Menu(menu)
for i = 0, dsmLib.MAX_MENU_LINES do
local line = ctx.MenuLines[i]
if i == ctx.SelLine then
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_TITLE,255,dsmLib.menuLine2String(line),TEXT_SIZE + WARNING_COLOR) end
end
if line ~= nil and line.Type ~= 0 then
if line.Type == LINE_TYPE.MENU then
-- Menu Line
GUI_Display_Line_Menu(LCD_X_LINE_MENU,LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*i), 350, LCD_Y_LINE_HEIGHT, line, i == ctx.SelLine)
else
-- list/value line
local value = line.Val
if line.Val ~= nil then
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
value = dsmLib.Get_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
local imgValue = dsmLib.Get_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
if (imgValue) then -- Optional Image for a Value
--TODO: Pending feature.. create images and put bitmap instead of a message
--Display the image/Alternate Text
lcd.drawText(LCD_X_LINE_TITLE, LCD_Y_LINE_FIRST+LCD_Y_LINE_HEIGHT, "Img:"..imgValue)
end
end
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
end
end -- if ~MENU
end -- if Line[i]~=nil
end -- for
end
end
end
-------------------------------------------------------------------------------------------------------------
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
local inc = 0
local Speed = getRotEncSpeed()
if Speed == ROTENC_MIDSPEED then
inc = (5 * dir)
elseif Speed == ROTENC_HIGHSPEED then
inc = (15 * dir)
else
inc = dir
end
return inc
end
------------------------------------------------------------------------------------------------------------
local function GUI_HandleEvent(event, touchState)
local ctx = DSM_Context
local menu = ctx.Menu
local menuLines = ctx.MenuLines
if event == EVT_VIRTUAL_EXIT then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.Phase == PHASE.RX_VERSION then
dsmLib.ReleaseConnection()
else
if ctx.isEditing() then -- Editing a Line, need to restore original value
ctx.MenuLines[ctx.EditLine].Val = originalValue
dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Update+Validate value in RX
ctx.EditLine = nil -- Exit Edit Mode (By clearing the line editing)
else
dsmLib.ChangePhase(PHASE.EXIT)
end
end
return
end
if event == EVT_VIRTUAL_NEXT then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then -- Editing a Line, need to inc the value
local line=ctx.MenuLines[ctx.EditLine]
dsmLib.Value_Add(line, GUI_RotEncVal(1))
else -- not editing, move selected line to NEXT
dsmLib.MoveSelectionLine(1)
end
return
end
if event == EVT_VIRTUAL_PREV then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then -- Editiing a line, need to dec the value
local line=ctx.MenuLines[ctx.EditLine]
dsmLib.Value_Add(line, GUI_RotEncVal(-1))
else -- not editing, move selected line to PREV
dsmLib.MoveSelectionLine(-1)
end
return
end
if event == EVT_VIRTUAL_ENTER_LONG then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then
-- reset the value to default
dsmLib.Value_Default( menuLines[ctx.EditLine]) -- Update RX value as needed
end
return
end
if event == EVT_VIRTUAL_ENTER then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
dsmLib.GotoMenu(menu.BackId)
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
dsmLib.GotoMenu(menu.NextId)
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
dsmLib.GotoMenu(menu.PrevId)
elseif menuLines[ctx.SelLine].ValId ~= 0 then
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Next menu exist
if (SIMULATION_ON and menuLines[ctx.SelLine].ValId==0xFFFF) then
-- SPECIAL Simulation menu to Exit Simulation and
-- comunicate with Real RX
GUI_SwitchSimulationOFF()
else
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId) -- ValId is the MenuId to navigate to
end
else
-- Editing a Line????
if ctx.isEditing() then
-- Change the Value and exit edit
ctx.EditLine = nil
dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END)
else
-- enter Edit the current line
ctx.EditLine = ctx.SelLine
originalValue = menuLines[ctx.SelLine].Val
end
end
end
end
end
local function init_screen_pos()
if LCD_W == 480 then -- TX16
-- use defaults in the script header
elseif LCD_W == 128 then --TX12 (128x64) -- Still needs some work on the vertical
DEBUG_ON_LCD = false -- no space for this
TEXT_SIZE = SMLSIZE
LCD_W_USABLE = 128
LCD_W_BUTTONS = 30
LCD_H_BUTTONS = 17
LCD_X_RIGHT_BUTTONS = 128 - LCD_W_BUTTONS - 5
LCD_X_LINE_MENU = 0
-- X offsets for (Title: [Value] debugInfo) lines
LCD_X_LINE_TITLE = 0
LCD_X_LINE_VALUE = 90
LCD_X_LINE_DEBUG = 110
LCD_Y_LINE_HEIGHT = 17
LCD_Y_MENU_TITLE = 0
LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 17
LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT
end
end
------------------------------------------------------------------------------------------------------------
-- Init
local function DSM_Init()
init_screen_pos()
dsmLib.Init(toolName) -- Initialize Library
return dsmLib.StartConnection()
end
------------------------------------------------------------------------------------------------------------
-- Main
local function DSM_Run(event)
local ctx = DSM_Context
if event == nil then
error("Cannot be run as a model script!")
dsmLib.LOG_close()
return 2
end
GUI_HandleEvent(event)
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
local refreshInterval = REFRESH_GUI_MS
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
if (ctx.EditLine or (ctx.Phase == PHASE.RX_VERSION)) then -- Editing or Requesting RX Version?
ctx.Refresh_Display=true
refreshInterval = 20 -- 200ms
end
-- Refresh display only if needed and no faster than 500ms, utilize more CPU to speedup DSM communications
if (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
GUI_Display()
ctx.Refresh_Display=false
lastRefresh=getTime()
end
if ctx.Phase == PHASE.EXIT_DONE then
dsmLib.LOG_close()
return 2
else
return 0
end
end
return { init=DSM_Init, run=DSM_Run }

View File

@ -0,0 +1,627 @@
local toolName = "TNS|DSM Forward Prog v0.5 (Color+Touch) |TNE"
local VERSION = "v0.5"
---- #########################################################################
---- # #
---- # Copyright (C) OpenTX #
-----# #
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 2 as #
---- # published by the Free Software Foundation. #
---- # #
---- # This program is distributed in the hope that it will be useful #
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
---- # GNU General Public License for more details. #
---- # #
---- #########################################################################
local SIMULATION_ON = true -- FALSE: use real communication to DSM RX (DEFAULT), TRUE: use a simulated version of RX
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
local USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX)
local dsmLib
if (SIMULATION_ON) then
-- library with SIMILATION VERSION. Works really well in Companion for GUI development
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
else
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
end
local PHASE = dsmLib.PHASE
local LINE_TYPE = dsmLib.LINE_TYPE
local DISP_ATTR = dsmLib.DISP_ATTR
local DSM_Context = dsmLib.DSM_Context
local lastRefresh=0 -- Last time the screen was refreshed
local REFRESH_GUI_MS = 300/10 -- 300ms.. Screen Refresh Rate.. to not waste CPU time (in 10ms units to be compatible with getTime())
local originalValue = nil
local touchButtonArea = {}
local EDIT_BUTTON = { DEFAULT=1001, DEC_10=1002, DEC_1=1003, INC_1=1004, INC_10=5, OK=1006, ESC=1007 }
local IS_EDGETX = false -- DEFAULT until Init changed it
local LCD_Y_MENU_TITLE = 20
local LCD_W_MENU_TITLE = LCD_W-100
local LCD_X_LINE_MENU = 30
local LCD_W_LINE_MENU = 350
local LCD_X_LINE_TITLE = 30
local LCD_X_LINE_VALUE = 230
local LCD_X_LINE_DEBUG = 390
local LCD_Y_LINE_START = LCD_Y_MENU_TITLE + 30
local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT)
-- TOOL HEADER
local LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR
local LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR
-- MENU HEADER
local LCD_MENU_COLOR = MENU_TITLE_COLOR
local LCD_MENU_BGCOLOR = MENU_TITLE_BGCOLOR
-- LINE SELECTED
local LCD_SELECTED_COLOR = TEXT_INVERTED_COLOR
local LCD_SELECTED_BGCOLOR = TEXT_INVERTED_BGCOLOR
local LCD_EDIT_BGCOLOR = WARNING_COLOR
-- NORMAL TEXT
local LCD_NORMAL_COLOR = TEXT_COLOR
local LCD_DISABLE_COLOR = TEXT_DISABLE_COLOR
local LCD_DEBUG_COLOR = LINE_COLOR
-- NORMAL BOX FRAME COLOR
local LCD_BOX_COLOR = TEXT_DISABLE_COLOR
--------------------- lcd.sizeText replacement -------------------------------------------------
-- EdgeTx dont have lcd.sizeText, so we do an equivalent one using the string length and 5px per character
local function my_lcd_sizeText(s)
print(string.format("EdgeTX=%s",IS_EDGETX))
-- return: If IS_EDGETX then lcd.sizeText() else string.len()
return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10)
end
local function GUI_SwitchSimulationOFF()
dsmLib.ReleaseConnection()
dsmLib.LOG_close()
SIMULATION_ON = false
dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
DSM_Context = dsmLib.DSM_Context
dsmLib.Init(toolName) -- Initialize Library
dsmLib.StartConnection()
DSM_Context.Refresh_Display = true
end
--------------------- Toucch Button Helpers ------------------------------------------------------------
local function GUI_addTouchButton(x,y,w,h,line)
-- Add new button info to end of the array
touchButtonArea[#touchButtonArea+1] = {x=x, y=y, w=w, h=h, line=line}
end
local function GUI_getTouchButton(x,y)
for i = 1, #touchButtonArea do
local button = touchButtonArea[i]
-- is the coordinate inside the button area??
if (x >= button.x and x <= (button.x+button.w) and y >= button.y and (y <= button.y+button.h)) then
return button.line
end
end
return nil
end
local function GUI_clearTouchButtons()
touchButtonArea = {}
end
---------- Return Color to display Menu Lines ----------------------------------------------------------------
local function GUI_GetTextColor(lineNum)
local ctx = DSM_Context
local txtColor = LCD_NORMAL_COLOR
-- Gray Out any other line except the one been edited
if (ctx.isEditing() and ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
return txtColor
end
local function GUI_GetFrameColor(lineNum) -- Frame Color for Value/Menu Boxes
local ctx = DSM_Context
local txtColor = LCD_BOX_COLOR
-- Gray Out any other line except the one been edited
if (ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end
return txtColor
end
--------------------------------------------------------------------------------------------------------
-- Display Text inside a Rectangle. Inv: true means solid rectangle, false=only perimeter
local function GUI_Display_Boxed_Text(lineNum,x,y,w,h,text,inv)
local ctx = DSM_Context
local txtColor = GUI_GetTextColor(lineNum)
local frameColor = GUI_GetFrameColor(lineNum)
-- If editing this lineNum, chose EDIT Color, else SELECTED Color
local selectedBGColor = (ctx.EditLine==lineNum and LCD_EDIT_BGCOLOR) or LCD_SELECTED_BGCOLOR
if (inv) then
txtColor = LCD_SELECTED_COLOR
lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor)
else
lcd.drawRectangle(x-5, y-2, w, h, frameColor)
end
lcd.drawText(x , y, text, txtColor)
end
------ Display Pre/Next/Back buttons
local function GUI_Diplay_Button(x,y,w,h,text,selected)
GUI_Display_Boxed_Text(-1,x,y,w,h,text,selected)
end
------ Display MENU type of lines (Navigation, SubHeaders, and plain text comments)
local function GUI_Display_Line_Menu(lineNum,line,selected)
-- Menu Lines can be navidation to other Menus (if Selectable)
-- Or SubHeaders or Messages
local txtColor = GUI_GetTextColor(lineNum)
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
local x = LCD_X_LINE_MENU
if dsmLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes
GUI_Display_Boxed_Text(lineNum,x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT, line.Text,selected)
GUI_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum)
else
-- Non Selectable Menu Lines, plain text
-- Can be use for sub headers or just regular text lines (like warnings)
local bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align???
local tw = my_lcd_sizeText(line.Text)+4
x = LCD_X_LINE_VALUE - tw -- Right
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Center??
local tw = my_lcd_sizeText(line.Text)
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
end
lcd.drawText(x, y, line.Text, txtColor + bold)
end
end
------ Display NAME : VALUES type of lines
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
-- This Displays Name and Value Pairs
local txtColor = GUI_GetTextColor(lineNum)
local bold = 0
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
local x = LCD_X_LINE_TITLE
--if (editing) then -- Any Special color/effect when editing??
-- value = "["..value .. "]"
--end
---------- NAME Part
local header = line.Text
-- ONLY do this for Flight Mode (Right Align or Centered)
if (dsmLib.isFlightModeText(line.TextId)) then
-- Display Header + Value together
header = header .. " " .. value
-- Bold Text???
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align
local tw = my_lcd_sizeText(header)+4
x = LCD_X_LINE_VALUE - tw -- Right
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Centered
local tw = my_lcd_sizeText(header)
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
end
else
-- No Flight Mode, no effects here
header = header .. ":"
end
lcd.drawText(x, y, header, txtColor + bold) -- display Line Header
--------- VALUE PART, Skip for Flight Mode since already show the value
if not dsmLib.isFlightModeText(line.TextId) then
value = value .. (line.Format or "") -- Append % if needed
if dsmLib.isSelectableLine(line) then
-- Can select/edit value, Box it
local tw = my_lcd_sizeText(value)+10 -- Width of the Text in the lcd
GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected)
GUI_addTouchButton(LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,lineNum)
else -- Not Editable, Plain Text
lcd.drawText(LCD_X_LINE_VALUE, y, value, txtColor)
end
end
-- Debug info for line Value RANGE when Debug on LCD
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG, y, line.MinMaxDebug or "", SMLSIZE + LCD_DEBUG_COLOR) end -- display debug Min/Max
end
local function GUI_Display_Menu(menu)
local ctx = DSM_Context
local w= LCD_W_MENU_TITLE
-- Center Header
local tw = my_lcd_sizeText(menu.Text)
local x = w/2 - tw/2 -- Center of Screen - Center of Text
lcd.drawFilledRectangle(0, LCD_Y_MENU_TITLE-2, w, LCD_Y_LINE_HEIGHT-2, LCD_MENU_BGCOLOR)
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text, LCD_MENU_COLOR + BOLD)
-- Back Button
if menu.BackId ~= 0 then
GUI_Diplay_Button(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,"Back",ctx.SelLine == dsmLib.BACK_BUTTON)
GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,dsmLib.BACK_BUTTON)
end
-- Next Button
if menu.NextId ~= 0 then
GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON)
GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.NEXT_BUTTON)
end
-- Prev Button
if menu.PrevId ~= 0 then
GUI_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON)
GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.PREV_BUTTON)
end
-- Debug on LCD, Show the menu Indo and Phase we are on
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),SMLSIZE+LCD_DEBUG_COLOR) end -- Phase we are in
if (DEBUG_ON_LCD) then lcd.drawText(0,240,dsmLib.menu2String(menu),SMLSIZE+LCD_DEBUG_COLOR) end -- Menu Info
end
------------------------------------------------------------------------------------------------------------
-- Display the EDIT mode buttons when editing a value
local function GUI_Display_Edit_Buttons(line)
GUI_clearTouchButtons() -- Only this buttons can be touched
local x = 15 -- Inittial X position
local w = 55 -- Width of the buttons
local showPrev = line.Val > line.Min
local showNext = line.Val < line.Max
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,"ESC",true)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.ESC)
x=x+w+10
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," Def",true)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT)
x=x+w+10
if (not dsmLib.isListLine(line)) then
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," << ",showPrev)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_10)
end
x=x+w+10
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," <",showPrev)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_1)
x=x+w+10
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >",showNext)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1)
x=x+w+10
if (not dsmLib.isListLine(line)) then
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >>",showNext)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_10)
end
x=x+w+10
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," OK",true)
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.OK)
end
------------------------------------------------------------------------------------------------------------
local function GUI_Display()
local ctx = DSM_Context
lcd.clear()
GUI_clearTouchButtons()
if LCD_W == 480 then
local header = "DSM Forward Programming "..VERSION.." "
if ctx.Phase ~= PHASE.RX_VERSION then
header = header .. "RX "..ctx.RX.Name.." v"..ctx.RX.Version
end
--Draw title
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
--Draw RX Menu
if ctx.Phase == PHASE.RX_VERSION then
lcd.drawText(LCD_X_LINE_TITLE,100,"No compatible DSM RX...", BLINK)
else
local menu = ctx.Menu
if menu.Text ~= nil then
GUI_Display_Menu(menu)
for i = 0, dsmLib.MAX_MENU_LINES do
local line = ctx.MenuLines[i]
if i == ctx.SelLine then
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
if (DEBUG_ON_LCD) then lcd.drawText(0,255,dsmLib.menuLine2String(line),SMLSIZE + LCD_DEBUG_COLOR) end
end
if line ~= nil and line.Type ~= 0 then
if line.Type == LINE_TYPE.MENU then
GUI_Display_Line_Menu(i, line, i == ctx.SelLine)
else
-- list/value line
local value, imgValue = line.Val, nil
if line.Val ~= nil then
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
value = dsmLib.Get_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
imgValue = dsmLib.Get_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
if (imgValue) then -- Optional Image for a Value
--TODO: Pending feature.. create images and put bitmap instead of a message
--Display the image/Alternate Text
lcd.drawText(LCD_X_LINE_TITLE, LCD_Y_LINE_START+LCD_Y_LINE_HEIGHT, "Img:"..imgValue)
end
end
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
end
end -- if ~MENU
end -- if Line[i]~=nil
end -- for
if IS_EDGETX and ctx.isEditing() then
GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine])
end
end
end
else
-- Different Resolution.. Maybe just adjusting some of the constants will work, adjust it in DSM_Init??
-- LCD_X_LINE_TITLE, LCD_Y_LINE_START, etc
end
end
-------------------------------------------------------------------------------------------------------------
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
local inc = 0
local Speed = getRotEncSpeed()
if Speed == ROTENC_MIDSPEED then inc = (5 * dir)
elseif Speed == ROTENC_HIGHSPEED then inc = (15 * dir)
else inc = dir end
return inc
end
------------------------------------------------------------------------------------
-- Translate Tap/Touch of EDIT buttons to equivalent Key events
local function GUI_Translate_Edit_Buttons(button)
local event = EVT_TOUCH_TAP
local editInc = nil
if (button==EDIT_BUTTON.ESC) then -- ESC
event = EVT_VIRTUAL_EXIT
elseif (button==EDIT_BUTTON.DEFAULT) then -- Default
event = EVT_VIRTUAL_ENTER_LONG
elseif (button==EDIT_BUTTON.DEC_10) then -- -10
event = EVT_VIRTUAL_PREV
editInc = -10
elseif (button==EDIT_BUTTON.DEC_1) then -- -1
event = EVT_VIRTUAL_PREV
editInc = -1
elseif (button==EDIT_BUTTON.INC_1) then -- +1
event = EVT_VIRTUAL_NEXT
editInc = 1
elseif (button==EDIT_BUTTON.INC_10) then -- + 10
event = EVT_VIRTUAL_NEXT
editInc = 10
elseif (button==EDIT_BUTTON.OK) then -- OK
event = EVT_VIRTUAL_ENTER
else
end
return event, editInc
end
------------------------------------------------------------------------------------------------------------
-- Handle Events comming from the GUI
local function GUI_HandleEvent(event, touchState)
local ctx = DSM_Context
local menu = ctx.Menu
local menuLines = ctx.MenuLines
local editInc = nil
if (IS_EDGETX) then
if (event == EVT_TOUCH_TAP and ctx.isEditing()) then -- Touch and Editing
local button = GUI_getTouchButton(touchState.x, touchState.y)
if (button) then
event, editInc = GUI_Translate_Edit_Buttons(button)
end
end
if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",dsmLib.phase2String(ctx.Phase),touchState.x, touchState.y) end
local button = GUI_getTouchButton(touchState.x, touchState.y)
if button then
-- Found a valid line
ctx.SelLine = button
ctx.Refresh_Display=true
if event == EVT_TOUCH_TAP then -- EVT_TOUCH_FIRST only move focus
event = EVT_VIRTUAL_ENTER
end
end
end
end
if event == EVT_VIRTUAL_EXIT then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.Phase == PHASE.RX_VERSION then
dsmLib.ReleaseConnection() -- Just Exit the Script
else
if ctx.isEditing() then -- Editing a Line, need to restore original value
ctx.MenuLines[ctx.EditLine].Val = originalValue
dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Update + Validate value in RX
ctx.EditLine = nil -- Exit Edit Mode (By clearing the line editing)
else
dsmLib.ChangePhase(PHASE.EXIT)
end
end
return
end
if event == EVT_VIRTUAL_NEXT then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then -- Editing a Line, need to inc the value
local line=ctx.MenuLines[ctx.EditLine]
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(1))
else -- not editing, move selected line to NEXT
dsmLib.MoveSelectionLine(1)
end
return
end
if event == EVT_VIRTUAL_PREV then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then -- Editiing a line, need to dec the value
local line=ctx.MenuLines[ctx.EditLine]
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(-1))
else -- not editing, move selected line to PREV
dsmLib.MoveSelectionLine(-1)
end
return
end
if event == EVT_VIRTUAL_ENTER_LONG then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
if ctx.isEditing() then
-- reset the value to default
dsmLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed
end
return
end
if event == EVT_VIRTUAL_ENTER then
ctx.Refresh_Display=true
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",dsmLib.phase2String(ctx.Phase), ctx.SelLine) end
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
dsmLib.GotoMenu(menu.BackId)
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
dsmLib.GotoMenu(menu.NextId)
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
dsmLib.GotoMenu(menu.PrevId)
elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Navigate to Menu
if (SIMULATION_ON and menuLines[ctx.SelLine].ValId==0xFFFF) then
-- SPECIAL Simulation menu to Exit Simulation
GUI_SwitchSimulationOFF()
else
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId) -- ValId is the MenuId to navigate to
end
else -- Enter on a Value
if ctx.isEditing() then -- already editing a Line????
ctx.EditLine = nil -- Exit Edit Mode (By clearing the line editing)
dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Request change the value on RX
else -- Edit the current value
ctx.EditLine = ctx.SelLine
originalValue = menuLines[ctx.SelLine].Val
end
end
end
end
end
local function init_colors()
-- osName in OpenTX is nil, otherwise is EDGETX
local ver, radio, maj, minor, rev, osname = getVersion()
IS_EDGETX = osname~=nil
if (IS_EDGETX and USE_SPECKTRUM_COLORS) then
-- SPECKTRUM COLORS (only works on EDGETX)
-- TOOL HEADER
LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR
LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR
-- MENU HEADER
LCD_MENU_COLOR = WHITE
LCD_MENU_BGCOLOR = DARKGREY
-- LINE SELECTED
LCD_SELECTED_COLOR = WHITE
LCD_SELECTED_BGCOLOR = ORANGE
LCD_EDIT_BGCOLOR = WARNING_COLOR
-- NORMAL TEXT
LCD_NORMAL_COLOR = BLACK
LCD_DISABLE_COLOR = LIGHTGREY
LCD_DEBUG_COLOR = BLUE
-- NORMAL BOX FRAME COLOR
LCD_BOX_COLOR = LIGHTGREY
end
end
------------------------------------------------------------------------------------------------------------
-- Init
local function DSM_Init()
init_colors()
dsmLib.Init(toolName) -- Initialize Library
return dsmLib.StartConnection()
end
------------------------------------------------------------------------------------------------------------
-- Main
local function DSM_Run(event,touchState)
local ctx = DSM_Context
if event == nil then
error("Cannot be run as a model script!")
dsmLib.LOG_close()
return 2
end
GUI_HandleEvent(event,touchState)
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
local refreshInterval = REFRESH_GUI_MS
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
if (ctx.Phase == PHASE.RX_VERSION) then -- Requesting RX Message Version usea BLINK?
ctx.Refresh_Display=true
refreshInterval = 20 -- 200ms
end
-- Refresh display only if needed and no faster than 300ms, utilize more CPU to speedup DSM communications
if (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
GUI_Display()
ctx.Refresh_Display=false
lastRefresh=getTime()
end
if ctx.Phase == PHASE.EXIT_DONE then
dsmLib.LOG_close()
return 2
else
return 0
end
end
return { init=DSM_Init, run=DSM_Run }

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,44 @@
This script library is a rewrite of the original DSM forward programming Lua
Script. The goal is to make it easier to understand, mantain, and to
separate the GUI from the DSM Forward programming engine/logic
in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, etc.
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
Rewrite/Enhancements By: Francisco Arzu
Deployment:
/SCRIPTS/TOOLS/DsmFwdPrg_05_BaW.lua -- OpenTX/EdgeTx version, no touch (black/white radios)
/SCRIPTS/TOOLS/DsmFwdPrg_05_Color.lua -- EdgeTX/OpenTx Color version, +touch
/SCRIPTS/TOOLS/DSMLIB/ -- Libraries (ALL CAPITALS) to hide them from the Tools menu
/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lub -- DSM Protocol Message and Menu engine
/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgSIMLib.lub -- Simulation of AR631 for GUI Development in Companion
/LOGS/dsm_log.txt -- Readable log of the last RX session, usefull for debuging new RX
Version 0.5
- Make the code more readable and understadable
- Separate the DSM Forwards Programing logic from the GUI
- Log the comunnication with the RX on a /LOGS/dsm_log.txt to allow to debug it easier
and see the exchange of data between the RX/TX
- Created a black/white version with only Key/Roller Inputs (OTX)
- Created a nicer GUI for EdgeTX touchscreen color Radios
Known Problems:
1. When trying to Factory Reset an RX, even that navigation to menus seems OK, it did not reset.
Maybe another message needs to be sent to RX when reaching that page
2. When initially setting a new RX, there is a point where a menu navigates to MenuID=0x0001, this seems like a
special Save/Restart type of menu.. but it does not reset the RX. maybe another meesage needs to be send
3. Some Menu List line types (LINE_TYPE.LIST_MENU1), the range (min/max) seems to be incorrect, but cannot see in the data how to fix it
Some of the valid values are not even sequential, very spread apart. There has to be a list of valid options somewhere (in RX or config for each field).
4. The RX return unknow lines when requesting the Lines for a menu. Realy don't understand what they are for.
in some menus, seems to stay stuck in the same return line or no response to the request, making the RX reset/close the connection.
Did a fix to stop requesting the same menu line if the response is the same. This gives an empty menu, but does not reset the connection.
Version 0.2
Original Version from Pascal Langer

View File

@ -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.
[![DSM Forward Programming](https://img.youtube.com/vi/sjIaDw5j9nE/0.jpg)](https://www.youtube.com/watch?v=sjIaDw5j9nE)
If some text appears as Unknown_xxx, please report xxx and what the exact text display should be.
## 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.