Version 0.55 (#883)
@ -1,549 +0,0 @@
|
|||||||
local toolName = "TNS|DSM Forward Prog v0.54 (Text B&W) |TNE"
|
|
||||||
local VERSION = "v0.54"
|
|
||||||
|
|
||||||
|
|
||||||
---- #########################################################################
|
|
||||||
---- # #
|
|
||||||
---- # Copyright (C) OpenTX #
|
|
||||||
-----# #
|
|
||||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
|
||||||
---- # #
|
|
||||||
---- # This program is free software; you can redistribute it and/or modify #
|
|
||||||
---- # it under the terms of the GNU General Public License version 2 as #
|
|
||||||
---- # published by the Free Software Foundation. #
|
|
||||||
---- # #
|
|
||||||
---- # This program is distributed in the hope that it will be useful #
|
|
||||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
||||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
||||||
---- # GNU General Public License for more details. #
|
|
||||||
---- # #
|
|
||||||
---- #########################################################################
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
-- This script library is a rewrite of the original DSM forward programming Lua
|
|
||||||
-- Script. The goal is to make it easier to understand, mantain, and to
|
|
||||||
-- separate the GUI from the DSM Forward programming engine/logic
|
|
||||||
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
|
||||||
|
|
||||||
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
|
||||||
-- Rewrite/Enhancements By: Francisco Arzu
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
local SIMULATION_ON = false -- FALSE: don't show simulation menu (DEFAULT), TRUE: show simulation menu
|
|
||||||
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
|
|
||||||
local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
|
|
||||||
|
|
||||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
|
||||||
|
|
||||||
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON)
|
|
||||||
|
|
||||||
local PHASE = dsmLib.PHASE
|
|
||||||
local LINE_TYPE = dsmLib.LINE_TYPE
|
|
||||||
local DISP_ATTR = dsmLib.DISP_ATTR
|
|
||||||
|
|
||||||
local DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
local IS_EDGETX = false -- DEFAULT until Init changed it
|
|
||||||
|
|
||||||
local LCD_W_USABLE = LCD_W-10
|
|
||||||
-- X for Menu Lines
|
|
||||||
local LCD_X_LINE_MENU = 10
|
|
||||||
-- X offsets for (Title: [Value] debugInfo) lines
|
|
||||||
local LCD_X_LINE_TITLE = 10
|
|
||||||
local LCD_X_LINE_VALUE = 230
|
|
||||||
local LCD_X_LINE_DEBUG = 390
|
|
||||||
|
|
||||||
-- Line Height: make it smaller debugging info tp LCD (some space buttom)
|
|
||||||
local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27
|
|
||||||
-- Y offsets
|
|
||||||
local LCD_Y_MENU_TITLE = 20
|
|
||||||
-- Y offet
|
|
||||||
local LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 30
|
|
||||||
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT
|
|
||||||
|
|
||||||
local LCD_W_BUTTONS = 47
|
|
||||||
local LCD_H_BUTTONS = 25
|
|
||||||
local LCD_X_RIGHT_BUTTONS = LCD_W - LCD_W_BUTTONS - 5
|
|
||||||
|
|
||||||
local TEXT_SIZE = 0 -- NORMAL
|
|
||||||
|
|
||||||
local lastRefresh=0 -- Last time the screen was refreshed
|
|
||||||
local REFRESH_GUI_MS = 500/10 -- 500ms.. Screen Refresh Rate.. to not use unneded CPU time (in 10ms units to be compatible with getTime())
|
|
||||||
local originalValue = nil
|
|
||||||
|
|
||||||
local warningScreenON = true
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_SwitchToRX()
|
|
||||||
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
|
|
||||||
local dsmChannelInfo, description = dsmLib.CreateDSMPortChannelInfo()
|
|
||||||
|
|
||||||
dsmLib.ReleaseConnection()
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
|
|
||||||
SIMULATION_ON = false
|
|
||||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
|
|
||||||
DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
|
||||||
dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library
|
|
||||||
dsmLib.StartConnection()
|
|
||||||
DSM_Context.Refresh_Display = true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_SwitchToSIM()
|
|
||||||
dsmLib.ReleaseConnection()
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
|
|
||||||
SIMULATION_ON = true
|
|
||||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
|
|
||||||
DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
|
||||||
dsmLib.StartConnection()
|
|
||||||
DSM_Context.Refresh_Display = true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function openTx_lcd_sizeText(s)
|
|
||||||
return string.len(s)*5
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_Diplay_Button(x,y,w,h,text,selected)
|
|
||||||
local attr = (selected) and INVERS or 0 -- INVERS if line Selected
|
|
||||||
if (TEXT_SIZE~=SMLSIZE) then
|
|
||||||
lcd.drawText(x+5,y+2, text, attr + TEXT_SIZE)
|
|
||||||
lcd.drawRectangle(x, y, w, h, LINE_COLOR)
|
|
||||||
else -- SMALL Screen
|
|
||||||
lcd.drawText(x,y, text, attr + TEXT_SIZE)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_Display_Menu(menu)
|
|
||||||
local ctx = DSM_Context
|
|
||||||
local w= LCD_W_USABLE - LCD_W_BUTTONS - 10 -- usable Width for the Menu/Lines
|
|
||||||
|
|
||||||
-- Center Header
|
|
||||||
local tw = openTx_lcd_sizeText(menu.Text)
|
|
||||||
local x = w/2 - tw/2 -- Center of Screen - Center of Text
|
|
||||||
if (x < 0) then x=0 end -- in case text is too wide
|
|
||||||
|
|
||||||
local bold = BOLD
|
|
||||||
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text,bold + TEXT_SIZE)
|
|
||||||
|
|
||||||
-- Back
|
|
||||||
if menu.BackId ~= 0 then
|
|
||||||
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_MENU_TITLE,LCD_W_BUTTONS,LCD_H_BUTTONS,"Back",ctx.SelLine == dsmLib.BACK_BUTTON)
|
|
||||||
end
|
|
||||||
-- Next ?
|
|
||||||
if menu.NextId ~= 0 then
|
|
||||||
GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON)
|
|
||||||
end
|
|
||||||
-- Prev?
|
|
||||||
if menu.PrevId ~= 0 then
|
|
||||||
GUI_Diplay_Button(0,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug into LCD
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),TEXT_SIZE + WARNING_COLOR) end -- Phase we are in
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_MENU,240,dsmLib.menu2String(menu),TEXT_SIZE + WARNING_COLOR) end -- Menu Info
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_Display_Line_Menu(x,y,w,h,line,selected)
|
|
||||||
local attr = (selected and INVERS) or 0 -- INVERS if line Selected
|
|
||||||
local bold = 0
|
|
||||||
local text = line.Text
|
|
||||||
|
|
||||||
if dsmLib.isSelectableLine(line) then
|
|
||||||
-- Menu Line
|
|
||||||
text = text .. " >"
|
|
||||||
else -- SubHeaders and plain text lines
|
|
||||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
|
||||||
|
|
||||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
|
||||||
local tw = openTx_lcd_sizeText(line.Text)+4
|
|
||||||
x = LCD_X_LINE_VALUE - tw -- Right
|
|
||||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
|
||||||
local tw = openTx_lcd_sizeText(line.Text)
|
|
||||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
|
||||||
end
|
|
||||||
if (x < 0) then x=0 end -- in case text is too wide
|
|
||||||
end
|
|
||||||
|
|
||||||
lcd.drawText(x,y, text, attr + bold + TEXT_SIZE)
|
|
||||||
|
|
||||||
end
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
|
||||||
local bold = 0
|
|
||||||
|
|
||||||
local y = LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*lineNum)
|
|
||||||
local x = LCD_X_LINE_TITLE
|
|
||||||
|
|
||||||
---------- NAME Part
|
|
||||||
local header = line.Text
|
|
||||||
-- ONLY do this for Flight Mode (Right Align or Centered)
|
|
||||||
if (dsmLib.isFlightModeLine(line)) then
|
|
||||||
-- Display Header + Value together
|
|
||||||
header = dsmLib.GetFlightModeValue(line)
|
|
||||||
|
|
||||||
-- Flight mode display attributes
|
|
||||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
|
||||||
|
|
||||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
|
||||||
local tw = openTx_lcd_sizeText(header)+4
|
|
||||||
x = LCD_X_LINE_VALUE - tw -- Right
|
|
||||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
|
||||||
local tw = openTx_lcd_sizeText(header)
|
|
||||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
|
||||||
end
|
|
||||||
if (x < 0) then x=0 end -- in case text is too wide
|
|
||||||
else
|
|
||||||
-- No Flight Mode, no effects here
|
|
||||||
header = header .. ":"
|
|
||||||
end
|
|
||||||
|
|
||||||
lcd.drawText(x, y, header, bold + TEXT_SIZE) -- display Line Header
|
|
||||||
|
|
||||||
--------- VALUE PART, Skip for Flight Mode since already show the value
|
|
||||||
if not dsmLib.isFlightModeLine(line) then
|
|
||||||
local attrib = 0
|
|
||||||
|
|
||||||
if selected then
|
|
||||||
attrib = INVERS
|
|
||||||
if editing then -- blink editing entry
|
|
||||||
attrib = attrib + BLINK
|
|
||||||
value = "[" .. value .. "]"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
value = value .. " " .. (line.Format or "") -- Append % if needed
|
|
||||||
lcd.drawText(LCD_X_LINE_VALUE,y, value, attrib + TEXT_SIZE) -- display value
|
|
||||||
end
|
|
||||||
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG,y, line.MinMaxDebug or "", TEXT_SIZE + WARNING_COLOR) end -- display debug
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_ShowBitmap(x,y,imgData)
|
|
||||||
-- imgData format "bitmap.png|alt message"
|
|
||||||
local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|'
|
|
||||||
local imgName, imgMsg = f(), f()
|
|
||||||
|
|
||||||
if (LCD_W > 128) then
|
|
||||||
lcd.drawText(x, y, imgMsg or "", TEXT_SIZE) -- Alternate Image MSG
|
|
||||||
else
|
|
||||||
local f = string.gmatch(imgMsg, '([^%:]+)') -- Iterator over values split by ':'
|
|
||||||
local msg1,msg2 = f(), f()
|
|
||||||
lcd.drawText(x, y, (msg1 or "")..":", TEXT_SIZE) -- Alternate Image MSG
|
|
||||||
lcd.drawText(x, y+10, msg2 or "", TEXT_SIZE) -- Alternate Image MSG
|
|
||||||
end
|
|
||||||
|
|
||||||
-- NO IMAGES in Text B&W
|
|
||||||
--local imgPath = IMAGE_PATH .. (imgName or "")
|
|
||||||
--local bitmap = Bitmap.open(imgPath)
|
|
||||||
--if (bitmap~=nil) then
|
|
||||||
-- lcd.drawBitmap(bitmap, x,y+20)
|
|
||||||
--end
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_Display()
|
|
||||||
local ctx = DSM_Context
|
|
||||||
lcd.clear()
|
|
||||||
local header = "DSM Fwrd Programming "
|
|
||||||
|
|
||||||
if (TEXT_SIZE==SMLSIZE) then -- Small Screen no title
|
|
||||||
header = ""
|
|
||||||
end
|
|
||||||
|
|
||||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
|
||||||
header = header .. ctx.RX.Name.." v"..ctx.RX.Version
|
|
||||||
end
|
|
||||||
|
|
||||||
--Draw title
|
|
||||||
if (TEXT_SIZE~=SMLSIZE) then -- ignore tool title small size screens
|
|
||||||
lcd.drawFilledRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR)
|
|
||||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
|
||||||
else -- Small Screen
|
|
||||||
lcd.drawText(20, LCD_Y_LOWER_BUTTONS+1, header, TEXT_SIZE)
|
|
||||||
end
|
|
||||||
--Draw RX Menu
|
|
||||||
if ctx.Phase == PHASE.RX_VERSION then
|
|
||||||
if (ctx.isReset) then
|
|
||||||
lcd.drawText(LCD_X_LINE_TITLE,50,dsmLib.Get_Text(0x301), BLINK + TEXT_SIZE) -- Resetting
|
|
||||||
else
|
|
||||||
lcd.drawText(LCD_X_LINE_TITLE,50,dsmLib.Get_Text(0x300), BLINK + TEXT_SIZE) -- Waiting for RX Version
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local menu = ctx.Menu
|
|
||||||
if menu.Text ~= nil then
|
|
||||||
|
|
||||||
GUI_Display_Menu(menu)
|
|
||||||
|
|
||||||
for i = 0, dsmLib.MAX_MENU_LINES do
|
|
||||||
local line = ctx.MenuLines[i]
|
|
||||||
|
|
||||||
if i == ctx.SelLine then
|
|
||||||
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_TITLE,255,dsmLib.menuLine2String(line),TEXT_SIZE + WARNING_COLOR) end
|
|
||||||
end
|
|
||||||
|
|
||||||
if line ~= nil and line.Type ~= 0 then
|
|
||||||
if line.Type == LINE_TYPE.MENU then
|
|
||||||
-- Menu Line
|
|
||||||
GUI_Display_Line_Menu(LCD_X_LINE_MENU,LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*i), 350, LCD_Y_LINE_HEIGHT, line, i == ctx.SelLine)
|
|
||||||
else
|
|
||||||
-- list/value line
|
|
||||||
local value = line.Val
|
|
||||||
if line.Val ~= nil then
|
|
||||||
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
|
|
||||||
value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
|
||||||
local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
|
|
||||||
|
|
||||||
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
|
||||||
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_FIRST+LCD_Y_LINE_HEIGHT, imgData)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
|
||||||
end
|
|
||||||
end -- if ~MENU
|
|
||||||
end -- if Line[i]~=nil
|
|
||||||
end -- for
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
|
|
||||||
local inc = 0
|
|
||||||
local Speed = getRotEncSpeed()
|
|
||||||
|
|
||||||
if Speed == ROTENC_MIDSPEED then
|
|
||||||
inc = (5 * dir)
|
|
||||||
elseif Speed == ROTENC_HIGHSPEED then
|
|
||||||
inc = (15 * dir)
|
|
||||||
else
|
|
||||||
inc = dir
|
|
||||||
end
|
|
||||||
|
|
||||||
return inc
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
local function GUI_HandleEvent(event, touchState)
|
|
||||||
local ctx = DSM_Context
|
|
||||||
local menu = ctx.Menu
|
|
||||||
local menuLines = ctx.MenuLines
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_EXIT then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.Phase == PHASE.RX_VERSION then
|
|
||||||
dsmLib.ReleaseConnection()
|
|
||||||
else
|
|
||||||
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
|
||||||
ctx.MenuLines[ctx.EditLine].Val = originalValue
|
|
||||||
dsmLib.Value_Write_Validate(menuLines[ctx.EditLine])
|
|
||||||
else
|
|
||||||
dsmLib.ChangePhase(PHASE.EXIT) -- Exit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_NEXT then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
|
||||||
local line=ctx.MenuLines[ctx.EditLine]
|
|
||||||
dsmLib.Value_Add(line, GUI_RotEncVal(1))
|
|
||||||
else -- not editing, move selected line to NEXT
|
|
||||||
dsmLib.MoveSelectionLine(1)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_PREV then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
|
||||||
local line=ctx.MenuLines[ctx.EditLine]
|
|
||||||
dsmLib.Value_Add(line, GUI_RotEncVal(-1))
|
|
||||||
else -- not editing, move selected line to PREV
|
|
||||||
dsmLib.MoveSelectionLine(-1)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_ENTER_LONG then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.isEditing() then
|
|
||||||
-- reset the value to default
|
|
||||||
dsmLib.Value_Default( menuLines[ctx.EditLine]) -- Update RX value as needed
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_ENTER then
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER\n",dsmLib.phase2String(ctx.Phase)) end
|
|
||||||
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
|
|
||||||
dsmLib.GotoMenu(menu.BackId,0x80)
|
|
||||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
|
||||||
dsmLib.GotoMenu(menu.NextId,0x82)
|
|
||||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
|
||||||
dsmLib.GotoMenu(menu.PrevId,0x81)
|
|
||||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then
|
|
||||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Next menu exist
|
|
||||||
if (menuLines[ctx.SelLine].ValId==0xFFF1) then
|
|
||||||
-- SPECIAL Simulation menu to Simulator
|
|
||||||
GUI_SwitchToSIM()
|
|
||||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
|
|
||||||
-- SPECIAL Simulation menu to go to RX
|
|
||||||
GUI_SwitchToRX()
|
|
||||||
else
|
|
||||||
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Editing a Line????
|
|
||||||
if ctx.isEditing() then
|
|
||||||
-- Change the Value and exit edit
|
|
||||||
dsmLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
|
||||||
else
|
|
||||||
-- enter Edit the current line
|
|
||||||
ctx.EditLine = ctx.SelLine
|
|
||||||
originalValue = menuLines[ctx.SelLine].Val
|
|
||||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function init_screen_pos()
|
|
||||||
-- osName in OpenTX is nil, otherwise is EDGETX
|
|
||||||
local ver, radio, maj, minor, rev, osname = getVersion()
|
|
||||||
if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil
|
|
||||||
|
|
||||||
IS_EDGETX = string.sub(osname,1,1) =='E'
|
|
||||||
|
|
||||||
if LCD_W == 480 then -- TX16
|
|
||||||
-- use defaults in the script header
|
|
||||||
elseif LCD_W == 128 then --TX12 (128x64) -- Still needs some work on the vertical
|
|
||||||
DEBUG_ON_LCD = false -- no space for this
|
|
||||||
TEXT_SIZE = SMLSIZE
|
|
||||||
LCD_W_USABLE = 128
|
|
||||||
|
|
||||||
LCD_W_BUTTONS = 16
|
|
||||||
LCD_H_BUTTONS = 10
|
|
||||||
LCD_X_RIGHT_BUTTONS = 128 - LCD_W_BUTTONS - 3
|
|
||||||
|
|
||||||
LCD_X_LINE_MENU = 0
|
|
||||||
-- X offsets for (Title: [Value] debugInfo) lines
|
|
||||||
LCD_X_LINE_TITLE = 0
|
|
||||||
LCD_X_LINE_VALUE = 75
|
|
||||||
LCD_X_LINE_DEBUG = 110
|
|
||||||
|
|
||||||
LCD_Y_LINE_HEIGHT = 7
|
|
||||||
LCD_Y_MENU_TITLE = 0
|
|
||||||
LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 8
|
|
||||||
LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + (7 * LCD_Y_LINE_HEIGHT)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GUI_Warning(event)
|
|
||||||
lcd.clear()
|
|
||||||
local header = "DSM Forward Programming "..VERSION.." "
|
|
||||||
--Draw title
|
|
||||||
if (LCD_W > 128) then
|
|
||||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, TITLE_BGCOLOR)
|
|
||||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
|
||||||
|
|
||||||
lcd.drawText(100,20,"INFO", BOLD)
|
|
||||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", TEXT_SIZE)
|
|
||||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", TEXT_SIZE)
|
|
||||||
lcd.drawText(5,80,"the TX before your start programming your RX.", TEXT_SIZE)
|
|
||||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", TEXT_SIZE)
|
|
||||||
|
|
||||||
lcd.drawText(5,150,"TX Servo settings are sent to the RX during 'Initial Setup'", TEXT_SIZE)
|
|
||||||
lcd.drawText(5,170,"as well as when using RX menu 'Relearn Servo Settings'", TEXT_SIZE)
|
|
||||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD+TEXT_SIZE)
|
|
||||||
|
|
||||||
lcd.drawText(100,250," OK ", INVERS + BOLD + TEXT_SIZE)
|
|
||||||
else
|
|
||||||
lcd.drawText(0,15,"Make sure you setup your plane", TEXT_SIZE)
|
|
||||||
lcd.drawText(0,22,"first. Wing and Tail type.", TEXT_SIZE)
|
|
||||||
|
|
||||||
lcd.drawText(0,30,"TX Servo settings are sent to ", TEXT_SIZE)
|
|
||||||
lcd.drawText(0,37,"the RX during 'Initial Setup' and ", TEXT_SIZE)
|
|
||||||
lcd.drawText(0,45,"ALWAYS TEST Gyro reactions", TEXT_SIZE)
|
|
||||||
lcd.drawText(0,52,"before flying!!!", TEXT_SIZE)
|
|
||||||
|
|
||||||
lcd.drawText(10,0," OK ", INVERS + BOLD + TEXT_SIZE)
|
|
||||||
end
|
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER then
|
|
||||||
warningScreenON = false
|
|
||||||
end
|
|
||||||
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Init
|
|
||||||
local function DSM_Init()
|
|
||||||
init_screen_pos()
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
|
||||||
return dsmLib.StartConnection()
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Main
|
|
||||||
|
|
||||||
|
|
||||||
local function DSM_Run(event)
|
|
||||||
local ctx = DSM_Context
|
|
||||||
|
|
||||||
if event == nil then
|
|
||||||
error("Cannot be run as a model script!")
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
return 2
|
|
||||||
end
|
|
||||||
|
|
||||||
if (warningScreenON) then
|
|
||||||
return GUI_Warning(event)
|
|
||||||
end
|
|
||||||
|
|
||||||
GUI_HandleEvent(event)
|
|
||||||
|
|
||||||
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
|
|
||||||
|
|
||||||
local refreshInterval = REFRESH_GUI_MS
|
|
||||||
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
|
|
||||||
if (ctx.EditLine or (ctx.Phase == PHASE.RX_VERSION)) then -- Editing or Requesting RX Version?
|
|
||||||
ctx.Refresh_Display=true
|
|
||||||
refreshInterval = 20 -- 200ms
|
|
||||||
end
|
|
||||||
|
|
||||||
if (not IS_EDGETX) then -- OPENTX NEEDS REFRESH ON EVERY CYCLE
|
|
||||||
GUI_Display()
|
|
||||||
-- Refresh display only if needed and no faster than 500ms, utilize more CPU to speedup DSM communications
|
|
||||||
elseif (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh
|
|
||||||
GUI_Display()
|
|
||||||
ctx.Refresh_Display=false
|
|
||||||
lastRefresh=getTime()
|
|
||||||
end
|
|
||||||
|
|
||||||
if ctx.Phase == PHASE.EXIT_DONE then
|
|
||||||
dsmLib.LOG_close()
|
|
||||||
return 2
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return { init=DSM_Init, run=DSM_Run }
|
|
@ -1,5 +1,5 @@
|
|||||||
local toolName = "TNS|DSM Forward Prog v0.54 (Color+Touch) |TNE"
|
local toolName = "TNS|DSM Forward Prog v0.55a (Color) |TNE"
|
||||||
local VERSION = "v0.54"
|
local VERSION = "v0.55a"
|
||||||
|
|
||||||
---- #########################################################################
|
---- #########################################################################
|
||||||
---- # #
|
---- # #
|
||||||
@ -27,19 +27,21 @@ local VERSION = "v0.54"
|
|||||||
-- Rewrite/Enhancements By: Francisco Arzu
|
-- Rewrite/Enhancements By: Francisco Arzu
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
local SIMULATION_ON = false -- FALSE:don't show simulation memu (DEFAULT), TRUE: show simulation menu
|
local SIMULATION_ON = true -- false: dont show simulation menu, TRUE: show simulation menu
|
||||||
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
|
local 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 USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX)
|
||||||
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/"
|
||||||
local IMAGE_PATH = DSMLIB_PATH .. "img/"
|
local IMAGE_PATH = DSMLIB_PATH .. "img/"
|
||||||
|
|
||||||
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON)
|
local Log = assert(loadScript(DSMLIB_PATH.."DsmLogLib.lua"), "Not-Found: DSMLIB/DsmLogLib.lua")()
|
||||||
|
local menuLib = assert(loadScript(DSMLIB_PATH.."DsmMenuLib.lua"), "Not-Found: DSMLIB/DsmMenuLib.lua")(Log, DEBUG_ON)
|
||||||
|
local modelLib = assert(loadScript(DSMLIB_PATH.."DsmModelLib.lua"), "Not-Found: DSMLIB/DsmModelLib.lua")(Log, DEBUG_ON)
|
||||||
|
local menuProcessor = assert(loadScript(DSMLIB_PATH.."DsmMainMenuLib.lua"), "Not-Found: DSMLIB/DsmMainMenuLib.lua")(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
|
||||||
|
|
||||||
local PHASE = dsmLib.PHASE
|
local PHASE = menuLib.PHASE
|
||||||
local LINE_TYPE = dsmLib.LINE_TYPE
|
local LINE_TYPE = menuLib.LINE_TYPE
|
||||||
local DISP_ATTR = dsmLib.DISP_ATTR
|
local DISP_ATTR = menuLib.DISP_ATTR
|
||||||
local DSM_Context = dsmLib.DSM_Context
|
local DSM_Context = menuLib.DSM_Context
|
||||||
|
|
||||||
|
|
||||||
local lastRefresh=0 -- Last time the screen was refreshed
|
local lastRefresh=0 -- Last time the screen was refreshed
|
||||||
@ -63,7 +65,7 @@ local LCD_X_LINE_DEBUG = 390
|
|||||||
|
|
||||||
|
|
||||||
local LCD_Y_LINE_START = LCD_Y_MENU_TITLE + 30
|
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_LINE_HEIGHT = 27
|
||||||
|
|
||||||
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT)
|
local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT)
|
||||||
|
|
||||||
@ -93,6 +95,7 @@ local warningScreenON = true
|
|||||||
--------------------- lcd.sizeText replacement -------------------------------------------------
|
--------------------- lcd.sizeText replacement -------------------------------------------------
|
||||||
-- EdgeTx dont have lcd.sizeText, so we do an equivalent one using the string length and 5px per character
|
-- 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)
|
local function my_lcd_sizeText(s)
|
||||||
|
if (s==nil) then return 20 end
|
||||||
-- return: If IS_EDGETX then lcd.sizeText() else string.len()
|
-- return: If IS_EDGETX then lcd.sizeText() else string.len()
|
||||||
return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10)
|
return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10)
|
||||||
end
|
end
|
||||||
@ -100,31 +103,76 @@ end
|
|||||||
|
|
||||||
local function GUI_SwitchToRX()
|
local function GUI_SwitchToRX()
|
||||||
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
|
-- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script)
|
||||||
local dsmChannelInfo, description = dsmLib.CreateDSMPortChannelInfo()
|
-- local dsmChannelInfo, description = modelLib.CreateDSMPortChannelInfo()
|
||||||
|
|
||||||
|
menuProcessor.done()
|
||||||
|
Log.LOG_close() -- Reset the log
|
||||||
|
Log.LOG_open()
|
||||||
|
|
||||||
|
menuProcessor = nil
|
||||||
|
collectgarbage("collect")
|
||||||
|
|
||||||
dsmLib.ReleaseConnection()
|
modelLib.ReadTxModelData()
|
||||||
dsmLib.LOG_close()
|
modelLib.ST_LoadFileData()
|
||||||
|
modelLib.CreateDSMPortChannelInfo()
|
||||||
|
|
||||||
SIMULATION_ON = false
|
local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")
|
||||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON)
|
menuProcessor = dsmLib(Log, menuLib, modelLib, DEBUG_ON)
|
||||||
DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
dsmLib = nil
|
||||||
dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library
|
collectgarbage("collect")
|
||||||
dsmLib.StartConnection()
|
|
||||||
|
menuProcessor.init(toolName) -- Initialize Library
|
||||||
DSM_Context.Refresh_Display = true
|
DSM_Context.Refresh_Display = true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function GUI_SwitchToSIM()
|
local function GUI_SwitchToSIM()
|
||||||
dsmLib.ReleaseConnection()
|
menuProcessor.done()
|
||||||
dsmLib.LOG_close()
|
Log.LOG_close()
|
||||||
|
|
||||||
SIMULATION_ON = true
|
menuProcessor = nil
|
||||||
dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON)
|
collectgarbage("collect")
|
||||||
DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
local simLib = assert(loadScript(DSMLIB_PATH.."DsmSimMenuLib.lua"), "Not-Found: DSMLIB/DsmSimMenuLib.lua")
|
||||||
dsmLib.StartConnection()
|
menuProcessor = simLib(Log, menuLib, modelLib, DEBUG_ON)
|
||||||
|
|
||||||
|
simLib = nil
|
||||||
|
collectgarbage("collect")
|
||||||
|
|
||||||
|
menuProcessor.init(toolName) -- Initialize Library
|
||||||
|
DSM_Context.Refresh_Display = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function GUI_SwitchToSetupMenu()
|
||||||
|
menuProcessor.done()
|
||||||
|
|
||||||
|
menuProcessor = nil
|
||||||
|
collectgarbage("collect")
|
||||||
|
|
||||||
|
local setupLib = assert(loadScript(DSMLIB_PATH.."DsmSetupMenuLib.lua"), "Not-Found: DSMLIB/DsmSetupMenuLib.lua")
|
||||||
|
menuProcessor = setupLib(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
|
||||||
|
|
||||||
|
setupLib = nil
|
||||||
|
collectgarbage("collect")
|
||||||
|
|
||||||
|
menuProcessor.init(toolName) -- Initialize Library
|
||||||
|
DSM_Context.Refresh_Display = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function GUI_SwitchToMainMenu()
|
||||||
|
print("SWITCHING TO MAIN MENU")
|
||||||
|
menuProcessor.done()
|
||||||
|
|
||||||
|
menuProcessor = nil
|
||||||
|
collectgarbage("collect")
|
||||||
|
|
||||||
|
local mainMenuLib = assert(loadScript(DSMLIB_PATH.."DsmMainMenuLib.lua"), "Not-Found: DSMLIB/DsmMainMenuLib.lua")
|
||||||
|
menuProcessor = mainMenuLib(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON)
|
||||||
|
|
||||||
|
mainMenuLib = nil
|
||||||
|
collectgarbage("collect")
|
||||||
|
|
||||||
|
menuProcessor.init(toolName) -- Initialize Library
|
||||||
DSM_Context.Refresh_Display = true
|
DSM_Context.Refresh_Display = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -203,19 +251,19 @@ local function GUI_Display_Line_Menu(lineNum,line,selected)
|
|||||||
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
|
local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum)
|
||||||
local x = LCD_X_LINE_MENU
|
local x = LCD_X_LINE_MENU
|
||||||
|
|
||||||
if dsmLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes
|
if menuLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes
|
||||||
GUI_Display_Boxed_Text(lineNum,x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT, line.Text,selected, false)
|
GUI_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)
|
GUI_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum)
|
||||||
else
|
else
|
||||||
-- Non Selectable Menu Lines, plain text
|
-- Non Selectable Menu Lines, plain text
|
||||||
-- Can be use for sub headers or just regular text lines (like warnings)
|
-- 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
|
local bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||||
|
|
||||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
if menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
||||||
local tw = my_lcd_sizeText(line.Text)+4
|
local tw = my_lcd_sizeText(line.Text)+4
|
||||||
x = LCD_X_LINE_VALUE - tw -- Right
|
x = LCD_X_LINE_VALUE - tw -- Right
|
||||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
elseif menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
||||||
local tw = my_lcd_sizeText(line.Text)
|
local tw = my_lcd_sizeText(line.Text)
|
||||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
||||||
end
|
end
|
||||||
@ -235,17 +283,17 @@ local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
|||||||
---------- NAME Part
|
---------- NAME Part
|
||||||
local header = line.Text
|
local header = line.Text
|
||||||
-- ONLY do this for Flight Mode (Right Align or Centered)
|
-- ONLY do this for Flight Mode (Right Align or Centered)
|
||||||
if (dsmLib.isFlightModeLine(line)) then
|
if (menuLib.isFlightModeLine(line)) then
|
||||||
-- Display Header + Value together
|
-- Display Header + Value together
|
||||||
header = dsmLib.GetFlightModeValue(line)
|
header = menuLib.GetFlightModeValue(line)
|
||||||
|
|
||||||
-- Bold Text???
|
-- Bold Text???
|
||||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||||
|
|
||||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
if menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
||||||
local tw = my_lcd_sizeText(header)+4
|
local tw = my_lcd_sizeText(header)+4
|
||||||
x = LCD_X_LINE_VALUE - tw -- Right
|
x = LCD_X_LINE_VALUE - tw -- Right
|
||||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
elseif menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
||||||
local tw = my_lcd_sizeText(header)
|
local tw = my_lcd_sizeText(header)
|
||||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
||||||
end
|
end
|
||||||
@ -256,15 +304,18 @@ local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
|||||||
|
|
||||||
lcd.drawText(x, y, header, txtColor + bold) -- display Line Header
|
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
|
--------- VALUE PART, Skip for Flight Mode since already show the value
|
||||||
if dsmLib.isSelectableLine(line) then
|
if (value==nil) then return end
|
||||||
|
|
||||||
|
if not menuLib.isFlightModeLine(line) then
|
||||||
|
if menuLib.isSelectableLine(line) then
|
||||||
--if (editing) then -- Any Special color/effect when editing??
|
--if (editing) then -- Any Special color/effect when editing??
|
||||||
-- value = "["..value .. "]"
|
-- value = "["..value .. "]"
|
||||||
--end
|
--end
|
||||||
-- Can select/edit value, Box it
|
-- Can select/edit value, Box it
|
||||||
local tw = math.max(my_lcd_sizeText(value)+10,45) -- Width of the Text in the lcd
|
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_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected, not menuLib.isListLine(line))
|
||||||
GUI_addTouchButton(LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,lineNum)
|
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)
|
lcd.drawText(LCD_X_LINE_VALUE+tw+5, y, (line.Format or ""), txtColor + bold)
|
||||||
@ -273,8 +324,6 @@ local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
|||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
local function GUI_Display_Menu(menu)
|
local function GUI_Display_Menu(menu)
|
||||||
@ -290,23 +339,19 @@ local function GUI_Display_Menu(menu)
|
|||||||
|
|
||||||
-- Back Button
|
-- Back Button
|
||||||
if menu.BackId ~= 0 then
|
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_Diplay_Button(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,"Back",ctx.SelLine == menuLib.BACK_BUTTON)
|
||||||
GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,dsmLib.BACK_BUTTON)
|
GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,menuLib.BACK_BUTTON)
|
||||||
end
|
end
|
||||||
-- Next Button
|
-- Next Button
|
||||||
if menu.NextId ~= 0 then
|
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_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == menuLib.NEXT_BUTTON)
|
||||||
GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.NEXT_BUTTON)
|
GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,menuLib.NEXT_BUTTON)
|
||||||
end
|
end
|
||||||
-- Prev Button
|
-- Prev Button
|
||||||
if menu.PrevId ~= 0 then
|
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_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == menuLib.PREV_BUTTON)
|
||||||
GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.PREV_BUTTON)
|
GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,menuLib.PREV_BUTTON)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------
|
||||||
@ -328,7 +373,7 @@ local function GUI_Display_Edit_Buttons(line)
|
|||||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT)
|
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT)
|
||||||
|
|
||||||
x=x+w+10
|
x=x+w+10
|
||||||
if (not dsmLib.isListLine(line)) then
|
if (not menuLib.isListLine(line)) then
|
||||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," << ",showPrev)
|
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)
|
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_10)
|
||||||
end
|
end
|
||||||
@ -342,7 +387,7 @@ local function GUI_Display_Edit_Buttons(line)
|
|||||||
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1)
|
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1)
|
||||||
|
|
||||||
x=x+w+10
|
x=x+w+10
|
||||||
if (not dsmLib.isListLine(line)) then
|
if (not menuLib.isListLine(line)) then
|
||||||
GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >>",showNext)
|
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)
|
GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_10)
|
||||||
end
|
end
|
||||||
@ -373,74 +418,86 @@ local function GUI_Display()
|
|||||||
lcd.clear(LCD_TOOL_BGCOLOR)
|
lcd.clear(LCD_TOOL_BGCOLOR)
|
||||||
GUI_clearTouchButtons()
|
GUI_clearTouchButtons()
|
||||||
|
|
||||||
if LCD_W == 480 then
|
if LCD_W ~= 480 then
|
||||||
local header = "DSM Forward Programming "..VERSION.." "
|
|
||||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
|
||||||
header = header .. "RX "..ctx.RX.Name.." v"..ctx.RX.Version
|
|
||||||
end
|
|
||||||
|
|
||||||
--Draw title
|
|
||||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
|
||||||
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
|
||||||
--Draw RX Menu
|
|
||||||
if ctx.Phase == PHASE.RX_VERSION then
|
|
||||||
if (ctx.isReset) then
|
|
||||||
lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x301), BLINK) -- Waiting for Restart
|
|
||||||
else
|
|
||||||
lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x300), BLINK) -- Waiting for RX
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local menu = ctx.Menu
|
|
||||||
|
|
||||||
|
|
||||||
if menu.Text ~= nil then
|
|
||||||
GUI_Display_Menu(menu)
|
|
||||||
|
|
||||||
for i = 0, dsmLib.MAX_MENU_LINES do
|
|
||||||
local line = ctx.MenuLines[i]
|
|
||||||
|
|
||||||
if i == ctx.SelLine then
|
|
||||||
-- DEBUG: Display Selected Line info for ON SCREEN Debugging
|
|
||||||
if (DEBUG_ON_LCD) then lcd.drawText(0,255,dsmLib.menuLine2String(line),SMLSIZE + LCD_DEBUG_COLOR) end
|
|
||||||
end
|
|
||||||
|
|
||||||
if line ~= nil and line.Type ~= 0 then
|
|
||||||
if line.Type == LINE_TYPE.MENU then
|
|
||||||
GUI_Display_Line_Menu(i, line, i == ctx.SelLine)
|
|
||||||
else
|
|
||||||
if line.Val ~= nil then
|
|
||||||
local value = line.Val
|
|
||||||
|
|
||||||
if dsmLib.isListLine(line) then -- for Lists of Strings, get the text
|
|
||||||
value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
|
||||||
local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display??
|
|
||||||
|
|
||||||
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
|
||||||
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_START, imgData)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
|
||||||
end
|
|
||||||
end -- if ~MENU
|
|
||||||
end -- if Line[i]~=nil
|
|
||||||
end -- for
|
|
||||||
|
|
||||||
if IS_EDGETX and ctx.isEditing() then
|
|
||||||
-- Display Touch button for Editing values
|
|
||||||
GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Different Resolution.. Maybe just adjusting some of the constants will work, adjust it in DSM_Init??
|
-- 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_X_LINE_TITLE, LCD_Y_LINE_START, etc
|
||||||
lcd.drawText(LCD_X_LINE_TITLE,100,"Only supported in Color Radios of 480 resolution", BLINK)
|
lcd.drawText(LCD_X_LINE_TITLE,100,"Only supported in Color Radios of 480 resolution", BLINK)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local header = "DSM Forward Programming "..VERSION.." "
|
||||||
|
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||||
|
header = header .. ctx.RX.Name.." v"..ctx.RX.Version
|
||||||
|
end
|
||||||
|
|
||||||
|
--Draw title
|
||||||
|
lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR)
|
||||||
|
lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE)
|
||||||
|
|
||||||
|
-- Getting RX Version
|
||||||
|
if ctx.Phase == PHASE.RX_VERSION then
|
||||||
|
if (ctx.isReset) then
|
||||||
|
lcd.drawText(LCD_X_LINE_TITLE,100, menuLib.Get_Text(0x301), BLINK) -- Resetting...
|
||||||
|
else
|
||||||
|
lcd.drawText(LCD_X_LINE_TITLE,100,menuLib.Get_Text(0x300), BLINK) -- Not valid RX
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local menu = ctx.Menu
|
||||||
|
if menu.Text == nil then return end
|
||||||
|
|
||||||
|
----- Draw RX Menu ---------
|
||||||
|
GUI_Display_Menu(menu)
|
||||||
|
|
||||||
|
-- Sending TX Information???
|
||||||
|
if (ctx.Phase==PHASE.MENU_REQ_TX_INFO) then
|
||||||
|
--lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor)
|
||||||
|
--lcd.drawRectangle(x-5, y-2, w, h, frameColor)
|
||||||
|
lcd.drawText(LCD_X_LINE_TITLE,100, "Sending CH"..(ctx.CurLine+1)) -- Channel Info
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 0, menuLib.MAX_MENU_LINES do
|
||||||
|
local line = ctx.MenuLines[i]
|
||||||
|
|
||||||
|
if line ~= nil and line.Type ~= 0 then
|
||||||
|
if line.Type == LINE_TYPE.MENU then
|
||||||
|
GUI_Display_Line_Menu(i, line, i == ctx.SelLine)
|
||||||
|
else
|
||||||
|
local value = nil
|
||||||
|
if line.Val ~= nil then
|
||||||
|
value = line.Val
|
||||||
|
if menuLib.isListLine(line) then -- for Lists of Strings, get the text
|
||||||
|
value = menuLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text
|
||||||
|
-- Complentary IMAGE for this value to Display??
|
||||||
|
local offset = 0
|
||||||
|
if (line.Type==LINE_TYPE.LIST_MENU_ORI) then offset = offset + 0x100 end --FH6250 hack
|
||||||
|
|
||||||
|
local imgData = menuLib.Get_List_Text_Img(line.Val + line.TextStart + offset)
|
||||||
|
|
||||||
|
if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
||||||
|
GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_START, imgData)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end -- if Line[i]~=nil
|
||||||
|
GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine)
|
||||||
|
end
|
||||||
|
end -- if ~MENU
|
||||||
|
end -- for
|
||||||
|
|
||||||
|
if IS_EDGETX and ctx.isEditing() then
|
||||||
|
-- Display Touch button for Editing values
|
||||||
|
GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values
|
local function GUI_RotEncVal(line, dir) -- return encoder speed to inc or dec values
|
||||||
|
|
||||||
|
if menuLib.isListLine(line) then return dir end
|
||||||
|
|
||||||
local inc = 0
|
local inc = 0
|
||||||
local Speed = getRotEncSpeed()
|
local Speed = getRotEncSpeed()
|
||||||
|
|
||||||
@ -499,7 +556,7 @@ local function GUI_HandleEvent(event, touchState)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing
|
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
|
if (DEBUG_ON) then Log.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",menuLib.phase2String(ctx.Phase),touchState.x, touchState.y) end
|
||||||
local button = GUI_getTouchButton(touchState.x, touchState.y)
|
local button = GUI_getTouchButton(touchState.x, touchState.y)
|
||||||
if button then
|
if button then
|
||||||
-- Found a valid line
|
-- Found a valid line
|
||||||
@ -514,64 +571,73 @@ local function GUI_HandleEvent(event, touchState)
|
|||||||
|
|
||||||
if event == EVT_VIRTUAL_EXIT then
|
if event == EVT_VIRTUAL_EXIT then
|
||||||
ctx.Refresh_Display=true
|
ctx.Refresh_Display=true
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end
|
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_EXIT\n",menuLib.phase2String(ctx.Phase)) end
|
||||||
if ctx.Phase == PHASE.RX_VERSION then
|
if ctx.Phase == PHASE.RX_VERSION then
|
||||||
dsmLib.ReleaseConnection() -- Just Exit the Script
|
menuLib.ChangePhase(PHASE.EXIT_DONE) -- Just Exit the Script
|
||||||
else
|
else
|
||||||
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
if ctx.isEditing() then -- Editing a Line, need to restore original value
|
||||||
local line = ctx.MenuLines[ctx.EditLine]
|
local line = ctx.MenuLines[ctx.EditLine]
|
||||||
line.Val = originalValue
|
line.Val = originalValue
|
||||||
dsmLib.Value_Write_Validate(line)
|
menuLib.Value_Write_Validate(line)
|
||||||
|
elseif (menu.BackId > 0 ) then -- Back??
|
||||||
|
ctx.SelLine = menuLib.BACK_BUTTON
|
||||||
|
event = EVT_VIRTUAL_ENTER
|
||||||
else
|
else
|
||||||
dsmLib.ChangePhase(PHASE.EXIT)
|
menuLib.ChangePhase(PHASE.EXIT)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if ctx.Phase == PHASE.RX_VERSION then return end
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_NEXT then
|
if event == EVT_VIRTUAL_NEXT then
|
||||||
ctx.Refresh_Display=true
|
ctx.Refresh_Display=true
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end
|
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_NEXT\n",menuLib.phase2String(ctx.Phase)) end
|
||||||
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
if ctx.isEditing() then -- Editing a Line, need to inc the value
|
||||||
local line=ctx.MenuLines[ctx.EditLine]
|
local line=ctx.MenuLines[ctx.EditLine]
|
||||||
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(1))
|
menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, 1))
|
||||||
else -- not editing, move selected line to NEXT
|
else -- not editing, move selected line to NEXT
|
||||||
dsmLib.MoveSelectionLine(1)
|
menuLib.MoveSelectionLine(1)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_PREV then
|
if event == EVT_VIRTUAL_PREV then
|
||||||
ctx.Refresh_Display=true
|
ctx.Refresh_Display=true
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end
|
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_PREV\n",menuLib.phase2String(ctx.Phase)) end
|
||||||
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
if ctx.isEditing() then -- Editiing a line, need to dec the value
|
||||||
local line=ctx.MenuLines[ctx.EditLine]
|
local line=ctx.MenuLines[ctx.EditLine]
|
||||||
dsmLib.Value_Add(line, editInc or GUI_RotEncVal(-1))
|
menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, -1))
|
||||||
else -- not editing, move selected line to PREV
|
else -- not editing, move selected line to PREV
|
||||||
dsmLib.MoveSelectionLine(-1)
|
menuLib.MoveSelectionLine(-1)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_ENTER_LONG then
|
if event == EVT_VIRTUAL_ENTER_LONG then
|
||||||
ctx.Refresh_Display=true
|
ctx.Refresh_Display=true
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end
|
if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",menuLib.phase2String(ctx.Phase)) end
|
||||||
if ctx.isEditing() then
|
if ctx.isEditing() then
|
||||||
-- reset the value to default
|
-- reset the value to default
|
||||||
dsmLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed
|
menuLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if event == EVT_VIRTUAL_ENTER then
|
if event == EVT_VIRTUAL_ENTER then
|
||||||
ctx.Refresh_Display=true
|
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 (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",menuLib.phase2String(ctx.Phase), ctx.SelLine) end
|
||||||
if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back
|
if ctx.SelLine == menuLib.BACK_BUTTON then -- Back
|
||||||
dsmLib.GotoMenu(menu.BackId,0x80)
|
if (menu.BackId==0xFFF9) then
|
||||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
-- SPECIAL Main Menu
|
||||||
dsmLib.GotoMenu(menu.NextId,0x82)
|
GUI_SwitchToMainMenu()
|
||||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
else
|
||||||
dsmLib.GotoMenu(menu.PrevId,0x81)
|
menuLib.GotoMenu(menu.BackId,0x80)
|
||||||
|
end
|
||||||
|
elseif ctx.SelLine == menuLib.NEXT_BUTTON then -- Next
|
||||||
|
menuLib.GotoMenu(menu.NextId,0x82)
|
||||||
|
elseif ctx.SelLine == menuLib.PREV_BUTTON then -- Prev
|
||||||
|
menuLib.GotoMenu(menu.PrevId,0x81)
|
||||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value
|
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].Type == LINE_TYPE.MENU then -- Navigate to Menu
|
||||||
@ -581,16 +647,22 @@ local function GUI_HandleEvent(event, touchState)
|
|||||||
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
|
elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then
|
||||||
-- SPECIAL Simulation menu to go to RX
|
-- SPECIAL Simulation menu to go to RX
|
||||||
GUI_SwitchToRX()
|
GUI_SwitchToRX()
|
||||||
|
elseif (menuLines[ctx.SelLine].ValId==0xFFF3) then
|
||||||
|
-- SPECIAL Settup Menu
|
||||||
|
GUI_SwitchToSetupMenu()
|
||||||
|
elseif (menuLines[ctx.SelLine].ValId==0xFFF9) then
|
||||||
|
-- SPECIAL Settup Menu
|
||||||
|
GUI_SwitchToMainMenu()
|
||||||
else
|
else
|
||||||
dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
menuLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to
|
||||||
end
|
end
|
||||||
else -- Enter on a Value
|
else -- Enter on a Value
|
||||||
if ctx.isEditing() then -- already editing a Line????
|
if ctx.isEditing() then -- already editing a Line????
|
||||||
dsmLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
menuLib.Value_Write_Validate(menuLines[ctx.SelLine])
|
||||||
else -- Edit the current value
|
else -- Edit the current value
|
||||||
ctx.EditLine = ctx.SelLine
|
ctx.EditLine = ctx.SelLine
|
||||||
originalValue = menuLines[ctx.SelLine].Val
|
originalValue = menuLines[ctx.SelLine].Val
|
||||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
menuLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -655,9 +727,16 @@ end
|
|||||||
------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------
|
||||||
-- Init
|
-- Init
|
||||||
local function DSM_Init()
|
local function DSM_Init()
|
||||||
|
Log.LOG_open()
|
||||||
|
|
||||||
init_colors()
|
init_colors()
|
||||||
dsmLib.Init(toolName) -- Initialize Library
|
modelLib.ReadTxModelData()
|
||||||
return dsmLib.StartConnection()
|
modelLib.ST_LoadFileData()
|
||||||
|
modelLib.CreateDSMPortChannelInfo()
|
||||||
|
|
||||||
|
menuLib.Init()
|
||||||
|
menuProcessor.init()
|
||||||
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------
|
||||||
@ -667,7 +746,7 @@ local function DSM_Run(event,touchState)
|
|||||||
|
|
||||||
if event == nil then
|
if event == nil then
|
||||||
error("Cannot be run as a model script!")
|
error("Cannot be run as a model script!")
|
||||||
dsmLib.LOG_close()
|
Log.LOG_close()
|
||||||
return 2
|
return 2
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -677,12 +756,15 @@ local function DSM_Run(event,touchState)
|
|||||||
|
|
||||||
GUI_HandleEvent(event,touchState)
|
GUI_HandleEvent(event,touchState)
|
||||||
|
|
||||||
dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages
|
local ret = menuProcessor.run() -- Handle Send and Receive DSM Forward Programming Messages
|
||||||
|
|
||||||
|
if ctx.Phase == PHASE.INIT then return 0 end
|
||||||
|
|
||||||
|
|
||||||
local refreshInterval = REFRESH_GUI_MS
|
local refreshInterval = REFRESH_GUI_MS
|
||||||
|
|
||||||
-- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD
|
-- 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?
|
if (ctx.Phase == PHASE.RX_VERSION or ctx.Phase==PHASE.MENU_REQ_TX_INFO) then -- Requesting RX Message Version usea BLINK?
|
||||||
ctx.Refresh_Display=true
|
ctx.Refresh_Display=true
|
||||||
refreshInterval = 20 -- 200ms
|
refreshInterval = 20 -- 200ms
|
||||||
end
|
end
|
||||||
@ -697,7 +779,7 @@ local function DSM_Run(event,touchState)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if ctx.Phase == PHASE.EXIT_DONE then
|
if ctx.Phase == PHASE.EXIT_DONE then
|
||||||
dsmLib.LOG_close()
|
Log.LOG_close()
|
||||||
return 2
|
return 2
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
|
@ -1,467 +0,0 @@
|
|||||||
# Forward Programing Protocol
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
DSM, DSMX and DSM Forward Programming are propietary protocol from the **Spektrum** radio brand. Since they don't make this information public, we have to reverse engineer it by analyzing the data exchanged between the RX and TX.
|
|
||||||
|
|
||||||
This document descrives what we know so far.
|
|
||||||
|
|
||||||
Thanks to **Pascal Langer** (Author of the Multi-Module) for the initial reverse engineering of the protocol and first version of the code that has been used for a while (Version 0.2)
|
|
||||||
|
|
||||||
Thanks to **Francisco Arzu** for taking the time to continue the work on reverse engineering, documenting and making the code more understandable.
|
|
||||||
|
|
||||||
New Capabilities in Version 0.5
|
|
||||||
- Log files of the conversation between RX/TX
|
|
||||||
- Improve the GUI (EdgeTX touch screen)
|
|
||||||
- Reversed engineer other things to make it work completly.
|
|
||||||
|
|
||||||
# Menu Title and Lines
|
|
||||||
|
|
||||||
The menu to be displayed is stored at the RX, the GUI only renders the menu title and menu lines received. The tipical conversation with the RX will be to ask for a menu (using the menuId number), and then wait for the data to come. The first thing will be the Menu (header) data, later we request the next 6 lines (one at a time), and optionally the values for each line.
|
|
||||||
|
|
||||||
A typical exchange will look like this in the log:
|
|
||||||
|
|
||||||
SEND DSM_getMenu(MenuId=0x1010 LastSelectedLine=0)
|
|
||||||
RESPONSE Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
|
||||||
SEND DSM_getFirstMenuLine(MenuId=0x1010)
|
|
||||||
RESPONSE MenuLine: L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ]
|
|
||||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=0)
|
|
||||||
RESPONSE MenuLine: L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ]
|
|
||||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=1)
|
|
||||||
RESPONSE MenuLine: L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ]
|
|
||||||
SEND DSM_getNextLine(MenuId=0x1010,LastLine=2)
|
|
||||||
RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
|
|
||||||
|
|
||||||
## Menu
|
|
||||||
|
|
||||||
The menu has the following information:
|
|
||||||
|
|
||||||
Menu: M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"[0xF9]]
|
|
||||||
|
|
||||||
- `MenuId`: The menu ID number of the menu (hex, 16 bit number)
|
|
||||||
- `PrevId`: The menu ID of the previous menu (for navigation), Log show as `"P="`
|
|
||||||
- `NextId`: The menu ID of the next menu (for navigation), Log shows as `"N="`
|
|
||||||
- `BackId`: The menu ID of the back menu (for navigation), Log shows as `"B="`
|
|
||||||
- `TextId`: The message number to display (16 bits, Hex). Log shows as [`0xXX`] after the message.
|
|
||||||
- `Text`: Retrived using the `TextId` from the script message `Text` array.
|
|
||||||
|
|
||||||
## Menu Lines
|
|
||||||
|
|
||||||
The menu lines has the following information:
|
|
||||||
|
|
||||||
L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1021 ]
|
|
||||||
L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ]
|
|
||||||
L[#2 T=LM VId=0x1002 Text="AS3X"[0x1DC] Val=1|"Act" NL=(0->1,0,S=3) [3->4,3] MId=0x1021 ]
|
|
||||||
|
|
||||||
- `MenuId`: of the menu they beling to. Log show as `"MId="` at the end.
|
|
||||||
- `LineNum`: Line number (0..5). The line number in the screen. Log show as # in the beginning
|
|
||||||
- `Type`: Type of Line, Log shows as `"T="` (explanation later)
|
|
||||||
- `TextId`: The message number to display (16 bits, Hex). Log shows as [`0xXXXX`] after the message.
|
|
||||||
- `Text`: Retrived using the `TextId` from the script message `Text` array.
|
|
||||||
- `ValueId`: The value or menu ID of the line. Log shows as `"VId="` (16 bits, Hex).
|
|
||||||
- `Value Range`: Shows as [`Min`->`Max`, `Default`]. This is the RAW data comming from the RX
|
|
||||||
- `NL`: Computed Normalized LIST (0 reference) for List Values. Source is the RAW range. For example, for lines of list of values. `[3->4,3]` is tranlated to `NL=(0->1,0,S=3)` since the value is also normalize to 0. `"S="` means the initial entry in the `List_Text` array
|
|
||||||
- `Val`: Current value for line who hold data. Relative to 0 for List Values. For List Values, the log will show the translation of the value to display text. example: `Val=1|"Act"` that is coming from `List_Value[4]`
|
|
||||||
|
|
||||||
## Type of Menu Lines
|
|
||||||
|
|
||||||
- `LINE_TYPE.MENU (Log: "T=M")`: This could be regular text or a navigation to another menu. if `ValueId` is the same as the current MenuId (`MId=`), is a plain text line (navigation to itself). If the `ValueId` is not the current menuId, then `ValueId` is the MenuId to navigate to.
|
|
||||||
|
|
||||||
We have found only one exception to the plain text rule, a true navigation to itself, in that case, in the text of the menu, you can use the "/M" flag at the end of the text to force it to be a menu button.
|
|
||||||
|
|
||||||
Example, FM_Channel is a navigation to menuId=0x7CA6.
|
|
||||||
|
|
||||||
L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ]
|
|
||||||
|
|
||||||
- `LINE_TYPE.LIST_MENU_NC (Log T=LM_nc)`: This is a line that shows as text in the GUI. The numeric value is translated to the proper text. The range is important, since it descrives the range of posible values. No incremental RX changes, only at the end.
|
|
||||||
|
|
||||||
Example: List of Values, List_Text[] starts at 53, ends at 85, with a default of 85. When normalized to 0, is a range from 0->32 for the numeric value. The Display value `Aux1` is retrive from `List_Text[6+53]`.
|
|
||||||
|
|
||||||
L[#0 T=LM_nc VId=0x1000 Text="FM Channel"[0x78] Val=6|"Aux1" NL=(0->32,0,S=53) [53->85,53] MId=0x7CA6 ]
|
|
||||||
|
|
||||||
- `LINE_TYPE.LIST_MENU_TOG (Log T=L_tog)`: Mostly the same as LIST_MENU_NC, but is just 2 values. (ON/OFF, Ihn/Act, etc). Should be a toggle in the GUI.
|
|
||||||
|
|
||||||
L[#2 T=LM_tog VId=0x1002 Text="AS3X"[0x1DC] Val=1|"Act" NL=(0->1,0,S=3) [3->4,3] MId=0x1021 ]
|
|
||||||
|
|
||||||
- `LINE_TYPE.LIST_MENU (Log T=LM)`: Mostly the same as LIST_MENU_NC, but incremental changes to the RX. Some times, it comes with a strange range `[0->244,Default]`. Usually this means that the values are not contiguos range; usually Ihn + Range. Still haven't found where in the data the correct range comes from.
|
|
||||||
|
|
||||||
Example: Valid Values: 3, 176->177 (Inh, Self-Level/Angle Dem, Envelope)
|
|
||||||
L[#3 T=LM VId=0x1003 Text="Safe Mode"[0x1F8] Val=176|"Self-Level/Angle Dem" NL=(0->244,3,S=0) [0->244,3] MId=0x1021 ]
|
|
||||||
|
|
||||||
- `LINE_TYPE.VALUE_NUM_I8_NC (Log: "T=V_nc")`: This line is editable, but is not updated to the RX incrementally, but only at the end. The Flight Mode line is of this type, so we have to check the TextId to differenciate between Flight mode and an Editable Value.
|
|
||||||
Fligh Mode TextId is between 0x8000 and 0x8003
|
|
||||||
|
|
||||||
Example, Flight mode comes from Variable ValId=0x1000, with current value of 1. Range of the Value is 0..10.
|
|
||||||
|
|
||||||
L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1021 ]
|
|
||||||
|
|
||||||
|
|
||||||
- `LINE_TYPE.VALUE_NUM_I8 (Log T=V_i8)`: 8 bit number (1 byte)
|
|
||||||
- `LINE_TYPE.VALUE_NUM_I16' (Log T=V_i16)`: 16 Bit number (2 bytes)
|
|
||||||
- `LINE_TYPE.VALUE_NUM_SI16 (Log T=V_si16)`: Signed 16 bit number (2 bytes)
|
|
||||||
- `LINE_TYPE.VALUE_PERCENT (Log T=L_%)`: Shows a Percent Value. 1 Byte value.
|
|
||||||
- `LINE_TYPE.VALUE_DEGREES (Log T=L_de)`: Shows a Degrees VAlue. 1 Byte value.
|
|
||||||
|
|
||||||
|
|
||||||
## LIST_TYPE Bitmap
|
|
||||||
TYPE|Sum|Hex|7 Signed|6 Valid Min/Max??|5 No-Inc-Changing|4 Menu|3 List-Menu|2 text / number|1|0 - 16 bits
|
|
||||||
|-|-|-|-|-|-|-|-|-|-|-
|
|
||||||
|MENU|Text|0x1C|0|0|0|1|1|1|0|0
|
|
||||||
|LIST_MENU|Text|0x0C|0|0|0|0|1|1|0|0
|
|
||||||
|LIST_MENU_TOG|Text|0x4C|0|1|0|0|1|1|0|0
|
|
||||||
|LIST_MENU_NC|Text, NC|0x6C|0|1|1|0|1|1|0|0
|
|
||||||
|VALUE_NUM_I8_NC|I8, NC|0x60|0|1|1|0|0|0|0|0
|
|
||||||
|VALUE_PERCENT|S8|0xC0|1|1|0|0|0|0|0|0
|
|
||||||
|VALUE_DEGREES|S8 NC|0xE0|1|1|1|0|0|0|0|0
|
|
||||||
|VALUE_NUM_I8|I8|0x40|0|1|0|0|0|0|0|0
|
|
||||||
|VALUE_NUM_I16|I16|0x41|0|1|0|0|0|0|0|1
|
|
||||||
|VALUE_NUM_SI16|S16|0xC1|1|1|0|0|0|0|0|1
|
|
||||||
|
|
||||||
|
|
||||||
## Important Behavioral differences when updating values
|
|
||||||
|
|
||||||
Values who are editable, are updated to RX as they change. For example, when changing attitude trims, the servo moves as we change the value in real-time.
|
|
||||||
|
|
||||||
LIST_MENU_NC, VALUE_NUM_I8_NC don't update the RX as it changes. It changes only in the GUI, and only update the RX at the end when confirmed the value. (NO-INC-CHANGES Bit)
|
|
||||||
|
|
||||||
After finishing updating a value, a validation command is sent. RX can reject the current value, and will change it to the nearest valid value.
|
|
||||||
|
|
||||||
## Special Menus
|
|
||||||
|
|
||||||
Seems like menuId=0x0001 is special. When you navigate to this menu, the RX reboots.
|
|
||||||
When this happens, we need to start from the beginning as if it was a new connection.
|
|
||||||
|
|
||||||
# Send and Receive messages
|
|
||||||
|
|
||||||
To comunicate with the Multi-Module, Lua scripts in OpenTx/EdgeTx has access to the `Multi_Buffer`. Writting to it will send data to RX, received data will be read from it.
|
|
||||||
|
|
||||||
For our specific case, this is how the Multi_Buffer is used:
|
|
||||||
|
|
||||||
|0..2|3|4..9|10..25
|
|
||||||
|--|--|--|--
|
|
||||||
|DSM|0x70+len|TX->RX data|RX->TX Data
|
|
||||||
|
|
||||||
To write a new DSM Fwd Programing command, write the data to address 4..9, and later set the address 3 with the length.
|
|
||||||
|
|
||||||
When receiving data, address 10 will have the message type we are receiving, or 0 if nothing has been received.
|
|
||||||
|
|
||||||
## Starting a new DSM Forward programming Connection
|
|
||||||
|
|
||||||
- Write 0x00 at address 3
|
|
||||||
- Write 0x00 at address 10
|
|
||||||
- Write "DSM" at address 0..2
|
|
||||||
|
|
||||||
## Disconnect
|
|
||||||
|
|
||||||
- Write 0x00 at address 0
|
|
||||||
|
|
||||||
|
|
||||||
# Request Messages (TX->RX)
|
|
||||||
|
|
||||||
## DSM_sendHeartbeat()
|
|
||||||
keep connection open.. We need to send it every 2-3 seconds, otherwise the RX will force close the connection by sending the TX an Exit_Confirm message.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg| Len? | ?? | ??
|
|
||||||
0x00|0x04|0x00|0x00
|
|
||||||
|
|
||||||
SEND DSM_sendHeartbeat()
|
|
||||||
DSM_SEND: [00 04 00 00 ]
|
|
||||||
|
|
||||||
## DSM_getRxVersion()
|
|
||||||
Request the RX information
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg| Len? | ?? | ?? |??|??
|
|
||||||
0x11|0x06|0x00|0x14|0x00|0x00
|
|
||||||
|
|
||||||
SEND DSM_getRxVersion()
|
|
||||||
DSM_SEND: [11 06 00 14 00 00 ]
|
|
||||||
|
|
||||||
## DSM_getMainMenu()
|
|
||||||
Request data for the main menu of the RX
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg| Len? | ?? | ?? |??|??
|
|
||||||
0x12|0x06|0x00|0x14|0x00|0x00
|
|
||||||
|
|
||||||
SEND DSM_getMainMenu()
|
|
||||||
DSM_SEND: [12 06 00 14 00 00 ]
|
|
||||||
|
|
||||||
|
|
||||||
## DSM_getMenu(menuId, lastSelLine)
|
|
||||||
Request data for Menu with ID=`menuId`. lastSelLine is the line that was selected to navigate to that menu. Most menus works with 0, but for some special "Enter Bind Mode", "Factory Reset", "Save to Backup" they will not work if we send 0, has to be the line who was selected in the confirmation menu line "Apply".
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (line#)??| LSB (line#)
|
|
||||||
0x16|0x06|0x10|0x60|0x00|0x01
|
|
||||||
|
|
||||||
SEND DSM_getMenu(MenuId=0x1060 LastSelectedLine=1)
|
|
||||||
DSM_SEND: [16 06 10 60 00 01 ]
|
|
||||||
|
|
||||||
## DSM_getFirstMenuLine(menuId)
|
|
||||||
Request the first line of a menu identified as `menuId`. The response will be the first line of the menu. Some times, it return lines shown as `'MenuUknownLine_0x05'` that we still are trying to understand what they are for.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (menuId) | LSB (MenuId)
|
|
||||||
0x13|0x04|0x10|0x60
|
|
||||||
|
|
||||||
SEND DSM_getFirstMenuLine(MenuId=0x1000)
|
|
||||||
DSM_SEND: [13 04 10 00 ]
|
|
||||||
|
|
||||||
## DSM_getNextMenuLine(menuId, curLine)
|
|
||||||
Request the retrival of the next line following the current line. Response is either the next line, or the next value, or nothing.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (line#)??| LSB (line#)
|
|
||||||
0x14|0x06|0x10|0x60|0x00|0x01
|
|
||||||
|
|
||||||
SEND DSM_getNextLine(MenuId=0x1000,LastLine=1)
|
|
||||||
DSM_SEND: [14 06 10 00 00 01 ]
|
|
||||||
|
|
||||||
## DSM_getNextMenuValue(menuId, valId, text)
|
|
||||||
Retrive the next value after the last `ValId` of the current `menuId`. text is just for debugging purposes to show the header of the value been retrived.
|
|
||||||
The Response is a Menu Value or nothing if no more data.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (menuId) | LSB (MenuId) | MSB (ValId)| LSB (ValId)
|
|
||||||
0x15|0x06|0x10|0x61|0x10|0x00
|
|
||||||
|
|
||||||
SEND DSM_getNextMenuValue(MenuId=0x1061, LastValueId=0x1000) Extra: Text="Outputs"
|
|
||||||
DSM_SEND: [15 06 10 61 10 00 ]
|
|
||||||
|
|
||||||
## DSM_updateMenuValue(valId, val, text, line)
|
|
||||||
Updates the value identified as `valId` with the numeric value `val`. `text` and `line` are there to add debugging info. No response is expected.
|
|
||||||
|
|
||||||
If the value is negative, it has to be translated to the proper DSM negative representaion.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (ValId) | LSB (ValId) | MSB (Value)| LSB (Value)
|
|
||||||
0x18|0x06|0x??|0x??|0x??|0x??
|
|
||||||
|
|
||||||
DSM_updateMenuValue(valId, val, text, line)
|
|
||||||
-->DSM_send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value))
|
|
||||||
|
|
||||||
## DSM_validateMenuValue(valId, text, line)
|
|
||||||
Validates the value identified as `valId`. `text` and `line` are there to add debugging info. The RX can response an Update value if the value is not valid and needs to be corrected.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | MSB (ValId) | LSB (ValId)
|
|
||||||
0x19|0x06|0x??|0x??
|
|
||||||
|
|
||||||
|
|
||||||
DSM_validateMenuValue(valId, text, line)
|
|
||||||
-> DSM_send(0x19, 0x06, int16_MSB(valId), int16_LSB(valId))
|
|
||||||
|
|
||||||
## DSM_menuValueChangingWait(valId, text, line)
|
|
||||||
Durin editing, this serves as a heartbeat that we are editing the value. The value identified as `valId`. `text` and `line` are there to add debugging info. The RX can response an Update value or a NUL response.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len?? | MSB (ValId) | LSB (ValId)
|
|
||||||
0x1A|0x06|0x??|0x??
|
|
||||||
|
|
||||||
DSM_menuValueChangingWait(valId, text, line)
|
|
||||||
->DSM_send(0x1A, 0x06, int16_MSB(valId), int16_LSB(valId))
|
|
||||||
|
|
||||||
## DSM_exitRequest()
|
|
||||||
Request to end the DSM Frd Prog connection. Will reponse with an exit confirmation.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9|10
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len?? | ??
|
|
||||||
0x1F|0x02|0xAA
|
|
||||||
|
|
||||||
CALL DSM_exitRequest()
|
|
||||||
DSM_SEND: [1F 02 AA ]
|
|
||||||
|
|
||||||
# Response Messages (RX->TX)
|
|
||||||
|
|
||||||
All responses will have the a response byte in Multi_Buffer[10]=0x09, and the type of message in Multi_Buffer[11].
|
|
||||||
|
|
||||||
## RX Version Response
|
|
||||||
|
|
||||||
Returns the information about the current RX.
|
|
||||||
|
|
||||||
The Display text of name name of the RX is retrive from the `RX_Name` array.
|
|
||||||
|
|
||||||
|10|11|12|13|14|15|16
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
|Resp|Msg|?? |RxId|Major|Minor|Patch
|
|
||||||
|0x09|0x01|0x00|0x1E|0x02|0x26|0x05
|
|
||||||
|
|
||||||
RESPONSE RX: 09 01 00 1E 02 26 05
|
|
||||||
RESPONSE Receiver=AR631 Version 2.38.5
|
|
||||||
|
|
||||||
## Menu Response
|
|
||||||
Returns the menu information to display and navigation.
|
|
||||||
The Display text for the menu is retrive from the `Text` array.
|
|
||||||
|
|
||||||
|
|
||||||
|10|11|12|13|14|15|16|17|18|19|20|21
|
|
||||||
|--|--|--|--|--|--|--|--|--|--|--|--
|
|
||||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|LSB (TextId)|MSB (TextId)|LSB (PrevId)|MSB (PrevId)|LSB (NextId)|MSB (NextId)|LSB (BackId)|MSB (BackId)
|
|
||||||
|0x09|0x02|0x5E|0x10|0x27|0x02|0x00|0x00|0x00|0x00|0x00|0x10
|
|
||||||
|
|
||||||
RESPONSE RX: 09 02 5E 10 27 02 00 00 00 00 00 10 00 00 00 00
|
|
||||||
RESPONSE Menu: M[Id=0x105E P=0x0 N=0x0 B=0x1000 Text="Other settings"[0x227]]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Menu Line Response
|
|
||||||
Returns the menu line information.
|
|
||||||
|
|
||||||
The Display text for the menu line is retrive from the `Text` array.
|
|
||||||
`Min`,`Max` and `Default` can be signed numbers.
|
|
||||||
|
|
||||||
|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25
|
|
||||||
|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
|
|
||||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|Line#|Line Type|LSB (TextId)|MSB (TextId)|LSB (ValId)|MSB (ValId)|LSB (Min)|MSB (Min)|LSB (Max)|MSB (Max)|LSB (Def)|MSB (Def)
|
|
||||||
|0x09|0x03|0x61|0x10|0x00|0x6C|0x50|0x00|0x00|0x10|0x36|0x00|0x49|0x00|0x36|0x00
|
|
||||||
|
|
||||||
RESPONSE RX: 09 03 61 10 00 6C 50 00 00 10 36 00 49 00 36 00
|
|
||||||
RESPONSE MenuLine: L[#0 T=LM_nc VId=0x1000 Text="Outputs"[0x50] Val=nil NL=(0->19,0,S=54) [54->73,54] MId=0x1061 ]
|
|
||||||
|
|
||||||
## Menu Line Value Response
|
|
||||||
Returns the Value for a line.
|
|
||||||
|
|
||||||
The response updates the Value in the line identified by `ValId`.
|
|
||||||
The Display text for the Value, when it is a list, is retrive from the `List_Text` array.
|
|
||||||
|
|
||||||
|10|11|12|13|14|15|16|17
|
|
||||||
|--|--|--|--|--|--|--|--
|
|
||||||
|Resp|Msg|LSB (menuId)|MSB (menuId)|LSB (ValId)|MSB (ValId)|LSB (Value)|MSB (Value)
|
|
||||||
|0x09|0x04|0x61|0x10|0x00|0x10|0x00|0x00
|
|
||||||
|
|
||||||
RESPONSE RX: 09 04 61 10 00 10 00 00
|
|
||||||
RESPONSE MenuValue: UPDATED: L[#0 T=L_m0 VId=0x1000 Text="Outputs"[0x50] Val=0|"Throttle" NL=(0->19,0,S=54) [54->73,54] MId=0x1061 ]
|
|
||||||
|
|
||||||
## Exit Response
|
|
||||||
Response from a Exit Request.
|
|
||||||
|
|
||||||
|10|11
|
|
||||||
|--|--
|
|
||||||
|Resp|Msg
|
|
||||||
|0x09|0x07
|
|
||||||
|
|
||||||
RESPONSE RX: 09 A7
|
|
||||||
RESPONSE Exit Confirm
|
|
||||||
|
|
||||||
## NULL Response
|
|
||||||
Can be use as a response, or heartbeat from the RX to keep the connection open.
|
|
||||||
|
|
||||||
|10|11
|
|
||||||
|--|--
|
|
||||||
|Resp|Msg
|
|
||||||
|0x09|0x00
|
|
||||||
|
|
||||||
RESPONSE RX: 09 00
|
|
||||||
RESPONSE NULL
|
|
||||||
|
|
||||||
|
|
||||||
# Unknown Lines
|
|
||||||
TOTALLY UNKNOWN WHAT THIS ARE FOR.. but only works for the Main Menu..
|
|
||||||
Other menus they just loop on line=0 forever.
|
|
||||||
|
|
||||||
## DSM_getNextUknownLine_0x05(menuId, curLine)
|
|
||||||
|
|
||||||
|
|
||||||
Request the retrival of the next Unknown line following the current line. Response is either the next unknow line, next menu line, or the next value, or nothing.
|
|
||||||
|
|
||||||
|4|5|6|7|8|9| Comment
|
|
||||||
|--|--|--|--|--|--|--
|
|
||||||
Msg|Len? | Line# | Line# | 0x00 | Formula(line#)??
|
|
||||||
0x20|0x06|0x00|0x00|0x00|0x40 | LastLineLine=0 retrieval
|
|
||||||
0x20|0x06|0x01|0x01|0x00|0x01| LastLineLine=1 retrieval
|
|
||||||
0x20|0x06|0x02|0x02|0x00|0x02| LastLineLine=2 retrieval
|
|
||||||
0x20|0x06|0x03|0x03|0x00|0x04| LastLineLine=3 retrieval
|
|
||||||
0x20|0x06|0x04|0x04|0x00|0x00| LastLineLine=4 retrieval
|
|
||||||
0x20|0x06|0x05|0x05|0x00|0x00| LastLineLine=5 retrieval
|
|
||||||
|
|
||||||
## Unknown Line Response
|
|
||||||
We still don't know what is this for, but we have to retrive them and skip then. Works for main menu, but when it happens in another menus, usually we stay in an infinite loop retrieving line=0
|
|
||||||
|
|
||||||
|10|11|12|13|14|15|16|17
|
|
||||||
|--|--|--|--|--|--|--|--
|
|
||||||
|Resp|Msg|LSB (line#)
|
|
||||||
|0x09|0x05|0x00|0x01|0x00|0x00|0x00|0x07
|
|
||||||
|0x09|0x05|0x01|0x01|0x00|0x00|0x00|0x07
|
|
||||||
|
|
||||||
## Interaction on Main Menu
|
|
||||||
This is the normal interaction for the main menu. As you can see, it iterates on the 6 Unknow lines (0..5), and afterwards, it starts sending normal menu lines.
|
|
||||||
|
|
||||||
SEND DSM_getFirstMenuLine(MenuId=0x1000)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=1 DATA=RX: 09 05 01 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=1)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=2 DATA=RX: 09 05 02 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=2)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=3 DATA=RX: 09 05 03 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=3)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=4 DATA=RX: 09 05 04 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=4)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=5 DATA=RX: 09 05 05 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=5)
|
|
||||||
RESPONSE MenuLine: L[#0 T=M VId=0x1010 Text="Gyro settings"[0xF9] MId=0x1000 ]
|
|
||||||
|
|
||||||
## Other menus
|
|
||||||
If it hapen on other menus. Usualy stays in an infinite loop until it crash/exits.
|
|
||||||
The screen will show **"Error: Cannot Load Menu Lines from RX"**
|
|
||||||
|
|
||||||
The log will look like:
|
|
||||||
|
|
||||||
DSM_getMenu(MenuId=0x104F LastSelectedLine=1)
|
|
||||||
RESPONSE Menu: M[Id=0x104F P=0x0 N=0x0 B=0x1000 Text="First Time Setup"[0x4A]]
|
|
||||||
SEND DSM_getFirstMenuLine(MenuId=0x104F)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
ERROR: Received Same menu line
|
|
||||||
CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
|
||||||
RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
|
||||||
ERROR: Received Same menu line
|
|
||||||
|
|
||||||
We found that sometimes, Overriding LastSelectedLine to 0 solves the problem for some specific menus. Not for all (for other, is the oposite (0->1)). But at least no unknown lines are returned with this hack for AR631/AR637. Maybe others also needed.
|
|
||||||
|
|
||||||
**Overriding to Zero is not a good solution for every menu. Some menus needs the LastLine to know the behaviour (for example, Factory Reset the RX, Save Backup, Restore Backup, Enter Bind Mode, Some sensor Calibration). Thats why we cannot do it blindly.**
|
|
||||||
|
|
||||||
Here is the current code to fix some of this problems in AR631/AR637.
|
|
||||||
Function `DSM_SelLine_HACK()`
|
|
||||||
|
|
||||||
if (ctx.RX.Id == RX.AR637T or ctx.RX.Id == RX.AR637TA or ctx.RX.Id == RX.AR631) then
|
|
||||||
-- AR631/AR637 Hack for "First time Setup" or
|
|
||||||
-- "First Time AS3X Setup", use 0 instead of the ctx.SelLine=5
|
|
||||||
if (ctx.Menu.MenuId == 0x104F or ctx.Menu.MenuId==0x1055) then
|
|
||||||
LOG_write("First time Setup Menu HACK: Overrideing LastSelectedLine to ZERO\n")
|
|
||||||
ctx.SelLine = 0
|
|
||||||
end
|
|
||||||
-- DID NOT WORK: AR631/AR637 Hack for "Relearn Servo Settings", use 1 instead
|
|
||||||
-- of the ctx.SelLine=0
|
|
||||||
--if (ctx.Menu.MenuId == 0x1023) then
|
|
||||||
-- LOG_write("Relearn Servo Settings HACK: Overrideing LastSelectedLine to 1\n")
|
|
||||||
-- ctx.SelLine = 1
|
|
||||||
--end
|
|
||||||
|
|
||||||
Now it retrives properly the menu:
|
|
||||||
|
|
||||||
Log shows:
|
|
||||||
|
|
||||||
First time Setup Menu HACK: Overrideing LastSelectedLine to ZERO
|
|
||||||
DSM_getMenu(MenuId=0x104F LastSelectedLine=0)
|
|
||||||
RESPONSE Menu: M[Id=0x104F P=0x0 N=0x0 B=0x105E Text="First Time Setup"[0x4A]]
|
|
||||||
SEND DSM_getFirstMenuLine(MenuId=0x104F)
|
|
||||||
.. Good menu data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
33
Lua_scripts/DSMLIB/DsmLogLib.lua
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
local LogLib = { }
|
||||||
|
|
||||||
|
local LOG_FILE = "/LOGS/dsm_log.txt"
|
||||||
|
local logFile = nil
|
||||||
|
local logCount=0
|
||||||
|
|
||||||
|
function LogLib.LOG_open()
|
||||||
|
logFile = io.open(LOG_FILE, "w") -- Truncate Log File
|
||||||
|
end
|
||||||
|
|
||||||
|
function LogLib.LOG_write(...)
|
||||||
|
if (logFile==nil) then LogLib.LOG_open() end
|
||||||
|
local str = string.format(...)
|
||||||
|
|
||||||
|
if (str==nil) then return end
|
||||||
|
|
||||||
|
io.write(logFile, str)
|
||||||
|
|
||||||
|
str = string.gsub(str,"\n"," ") -- Elimitate return from line, since print will do it
|
||||||
|
print(str)
|
||||||
|
|
||||||
|
if (logCount > 10) then -- Close an re-open the file
|
||||||
|
io.close(logFile)
|
||||||
|
logFile = io.open(LOG_FILE, "a")
|
||||||
|
logCount =0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function LogLib.LOG_close()
|
||||||
|
if (logFile~=nil) then io.close(logFile) end
|
||||||
|
end
|
||||||
|
|
||||||
|
return LogLib
|
90
Lua_scripts/DSMLIB/DsmMainMenuLib.lua
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
local Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON = ... -- Get DebugON from parameters
|
||||||
|
local MAIN_MENU_LIB_VERSION = "0.55"
|
||||||
|
local MODEL = modelLib.MODEL
|
||||||
|
|
||||||
|
local PHASE = menuLib.PHASE
|
||||||
|
local LINE_TYPE = menuLib.LINE_TYPE
|
||||||
|
|
||||||
|
local lastGoodMenu=0
|
||||||
|
|
||||||
|
-- Creates the menus to Render with the GUI
|
||||||
|
local function ST_LoadMenu(menuId)
|
||||||
|
local ctx = menuLib.DSM_Context
|
||||||
|
menuLib.clearMenuLines()
|
||||||
|
|
||||||
|
if (menuId==0x1000) then -- MAIN MENU
|
||||||
|
ctx.Menu = { MenuId = 0x1000, Text = "Main Menu ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, Text = "Model Setup", ValId = 0xFFF3,TextId=0 }
|
||||||
|
|
||||||
|
if (SIMULATION_ON) then
|
||||||
|
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, Text = "RX Simulator (GUI dev only)", ValId = 0xFFF1, TextId=0 } -- Menu 0xFFF2 to SIMULATOR
|
||||||
|
end
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text = "Forward Programming RX", ValId = 0xFFF2, TextId=0 } -- Menu 0xFFF2 to Real RX
|
||||||
|
ctx.SelLine = 6
|
||||||
|
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
else
|
||||||
|
--print("NOT IMPLEMENTED")
|
||||||
|
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
|
||||||
|
ctx.SelLine = menuLib.BACK_BUTTON
|
||||||
|
end
|
||||||
|
|
||||||
|
menuLib.PostProcessMenu()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function Main_Send_Receive()
|
||||||
|
local ctx = menuLib.DSM_Context
|
||||||
|
|
||||||
|
if ctx.Phase == PHASE.RX_VERSION then -- Just Init RX Version
|
||||||
|
ctx.RX.Name = "Main Menu"
|
||||||
|
ctx.RX.Version = MAIN_MENU_LIB_VERSION
|
||||||
|
ctx.Phase = PHASE.MENU_TITLE
|
||||||
|
ctx.Menu.MenuId = 0
|
||||||
|
|
||||||
|
ctx.Refresh_Display = true
|
||||||
|
elseif ctx.Phase == PHASE.WAIT_CMD then
|
||||||
|
|
||||||
|
elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title
|
||||||
|
if ctx.Menu.MenuId == 0 then -- First time loading a menu ?
|
||||||
|
ST_LoadMenu(0x01000)
|
||||||
|
else
|
||||||
|
ST_LoadMenu(ctx.Menu.MenuId)
|
||||||
|
end
|
||||||
|
ctx.Phase = PHASE.WAIT_CMD
|
||||||
|
ctx.Refresh_Display = true
|
||||||
|
|
||||||
|
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
|
||||||
|
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||||
|
--if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||||
|
--if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
|
||||||
|
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
|
||||||
|
|
||||||
|
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
|
||||||
|
local line = ctx.MenuLines[ctx.SelLine]
|
||||||
|
|
||||||
|
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
|
||||||
|
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||||
|
--if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||||
|
--if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
|
||||||
|
--if (DEBUG_ON) then Log.LOG_write("SEND SIM_validateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
|
||||||
|
ctx.Phase = PHASE.WAIT_CMD
|
||||||
|
|
||||||
|
elseif ctx.Phase == PHASE.EXIT then
|
||||||
|
ctx.Phase=PHASE.EXIT_DONE
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local function Main_Init()
|
||||||
|
local ctx = menuLib.DSM_Context
|
||||||
|
ctx.Phase = PHASE.RX_VERSION
|
||||||
|
end
|
||||||
|
|
||||||
|
local function Main_Done()
|
||||||
|
local ctx = menuLib.DSM_Context
|
||||||
|
ctx.Phase = PHASE.EXIT_DONE
|
||||||
|
end
|
||||||
|
|
||||||
|
return { init=Main_Init, run=Main_Send_Receive, done=Main_Done }
|
783
Lua_scripts/DSMLIB/DsmMenuLib.lua
Normal file
@ -0,0 +1,783 @@
|
|||||||
|
--- #########################################################################
|
||||||
|
---- # #
|
||||||
|
---- # Copyright (C) OpenTX/EdgeTx #
|
||||||
|
-----# #
|
||||||
|
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||||
|
---- # #
|
||||||
|
---- # This program is free software; you can redistribute it and/or modify #
|
||||||
|
---- # it under the terms of the GNU General Public License version 2 as #
|
||||||
|
---- # published by the Free Software Foundation. #
|
||||||
|
---- # #
|
||||||
|
---- # This program is distributed in the hope that it will be useful #
|
||||||
|
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||||
|
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||||
|
---- # GNU General Public License for more details. #
|
||||||
|
---- # #
|
||||||
|
---- #########################################################################
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
-- This script library is a rewrite of the original DSM forward programming Lua
|
||||||
|
-- Script. The goal is to make it easier to understand, mantain, and to
|
||||||
|
-- separate the GUI from the DSM Forward programming engine/logic
|
||||||
|
-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc.
|
||||||
|
|
||||||
|
-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||||
|
-- Rewrite/Enhancements By: Francisco Arzu
|
||||||
|
|
||||||
|
local Log, DEBUG_ON = ... -- Parameters
|
||||||
|
|
||||||
|
|
||||||
|
local MenuLib = { }
|
||||||
|
|
||||||
|
local PHASE = {
|
||||||
|
INIT = 0,
|
||||||
|
RX_VERSION = 1,
|
||||||
|
WAIT_CMD = 2,
|
||||||
|
MENU_TITLE = 3,
|
||||||
|
MENU_REQ_TX_INFO = 4,
|
||||||
|
MENU_LINES = 5,
|
||||||
|
MENU_VALUES = 6,
|
||||||
|
VALUE_CHANGING = 7,
|
||||||
|
VALUE_CHANGING_WAIT = 8,
|
||||||
|
VALUE_CHANGE_END = 9,
|
||||||
|
EXIT = 10,
|
||||||
|
EXIT_DONE = 11
|
||||||
|
}
|
||||||
|
|
||||||
|
local LINE_TYPE = {
|
||||||
|
MENU = 0x1C,
|
||||||
|
LIST_MENU = 0x0C, -- List: INC Change + Validate
|
||||||
|
LIST_MENU_NC = 0x6C, -- List: No Incremental Change
|
||||||
|
LIST_MENU_NC2 = 0x6D, -- List: No Incremental Change (Frame Rate Herz)
|
||||||
|
LIST_MENU_TOG = 0x4C, -- List: Incremental Change, sometimes bolean/Toggle menu (if only 2 values)
|
||||||
|
LIST_MENU_ORI = 0xCC, -- List: Incremental Change, Orientation Heli
|
||||||
|
|
||||||
|
VALUE_NUM_I8_NC = 0x60, -- 8 bit number, no incremental change
|
||||||
|
VALUE_PERCENT = 0xC0, -- 8 bit number, Signed, percent
|
||||||
|
VALUE_DEGREES = 0xE0, -- 8 bit number, Signed, Degress
|
||||||
|
VALUE_NUM_I8 = 0x40, -- 8 bit number
|
||||||
|
VALUE_NUM_I16 = 0x41, -- 16 Bit number
|
||||||
|
VALUE_NUM_SI16 = 0xC1, -- 16 bit number, Signed
|
||||||
|
|
||||||
|
LT_EMPTY = 0x00
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Bug in Lua compiler, confusing with global BOLD and RIGHT
|
||||||
|
local DISP_ATTR = {
|
||||||
|
_BOLD = 0x01, _RIGHT=0x02, _CENTER=0x04, PERCENT = 0x10, DEGREES=0x20, FORCED_MENU = 0x40
|
||||||
|
}
|
||||||
|
|
||||||
|
--RX IDs--
|
||||||
|
local RX = {
|
||||||
|
AR636B = 0x0001,
|
||||||
|
SPM4651T = 0x0014,
|
||||||
|
AR637T = 0x0015,
|
||||||
|
AR637TA = 0x0016,
|
||||||
|
FC6250HX = 0x0018,
|
||||||
|
AR630 = 0x0019,
|
||||||
|
AR8360T = 0x001A,
|
||||||
|
AR10360T = 0x001C,
|
||||||
|
AR631 = 0x001E
|
||||||
|
}
|
||||||
|
|
||||||
|
local DSM_Context = {
|
||||||
|
Phase = PHASE.INIT,
|
||||||
|
Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 },
|
||||||
|
MenuLines = {},
|
||||||
|
RX = { Id=0, Name = "", Version = "" },
|
||||||
|
Refresh_Display = true,
|
||||||
|
SendDataToRX = 1,
|
||||||
|
|
||||||
|
SelLine = 0, -- Current Selected Line
|
||||||
|
EditLine = nil, -- Current Editing Line
|
||||||
|
CurLine = -1, -- Current Line Requested/Parsed via h message protocol
|
||||||
|
isReset = false -- false when starting from scracts, true when starting from Reset
|
||||||
|
}
|
||||||
|
|
||||||
|
function DSM_Context.isEditing() return DSM_Context.EditLine~=nil end
|
||||||
|
|
||||||
|
local MAX_MENU_LINES = 6
|
||||||
|
local BACK_BUTTON = -1 -- Tread it as a display line #-1
|
||||||
|
local NEXT_BUTTON = MAX_MENU_LINES + 1 -- Tread it as a display line #7
|
||||||
|
local PREV_BUTTON = MAX_MENU_LINES + 2 -- Tread it as a display line #7
|
||||||
|
|
||||||
|
-- Text Arrays for Display Text and Debuging
|
||||||
|
local PhaseText = {}
|
||||||
|
local LineTypeText = {}
|
||||||
|
|
||||||
|
local Text = {} -- Text for Menu and Menu Lines (Headers only)
|
||||||
|
local List_Text = {} -- Messages for List Options (values only)
|
||||||
|
local List_Text_Img = {} -- If the Text has Attached Images
|
||||||
|
local List_Values = {} -- Additiona restrictions on List Values when non contiguos (L_M1 lines has this problem)
|
||||||
|
local Flight_Mode = {[0]="Fligh Mode"}
|
||||||
|
local RxName = {}
|
||||||
|
|
||||||
|
local StartTime = 0
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Get Elapsed Time since we started running the Script. Return a float in format: Seconds.Milliseconds
|
||||||
|
function MenuLib.getElapsedTime()
|
||||||
|
local t = getTime()
|
||||||
|
if (StartTime == 0) then StartTime = t end
|
||||||
|
|
||||||
|
return ((t - StartTime) * 10) / 1000
|
||||||
|
end
|
||||||
|
|
||||||
|
------------- Line Type helper functions ------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Check if the text are Flight modes, who will be treated different for Display
|
||||||
|
function MenuLib.isFlightModeLine(line)
|
||||||
|
return (line.TextId >= 0x8000 and line.TextId <= 0x8003)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.isSelectableLine(line) -- is the display line Selectable??
|
||||||
|
-- values who are not selectable
|
||||||
|
if (line.Type == 0) then return false end -- Empty Line
|
||||||
|
if (line.Type == LINE_TYPE.MENU and line.ValId == line.MenuId and bit32.band(line.TextAttr, DISP_ATTR.FORCED_MENU)==0) then return false end -- Menu that navigates to Itself?
|
||||||
|
if (line.Min==0 and line.Max==0 and line.Def==0) then return false end -- Values with no Range are only for display
|
||||||
|
if (line.Type == LINE_TYPE.VALUE_NUM_I8_NC and MenuLib.isFlightModeLine(line)) then return false end -- Flight mode is not Selectable
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.isEditableLine(line) -- is the display line editable??
|
||||||
|
-- values who are not editable
|
||||||
|
if (line.Type == 0 or line.Type == LINE_TYPE.MENU) then return false end -- Menus are not editable
|
||||||
|
if (line.Min==0 and line.Max==0 and line.Def==0) then return false end -- Values with no Range are only for display
|
||||||
|
if (line.Type == LINE_TYPE.VALUE_NUM_I8_NC and MenuLib.isFlightModeLine(line)) then return false end -- Flight mode is not Editable
|
||||||
|
-- any other is Editable
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.isListLine(line) -- is it a List of options??
|
||||||
|
if (line.Type == LINE_TYPE.LIST_MENU_NC or line.Type == LINE_TYPE.LIST_MENU or
|
||||||
|
line.Type == LINE_TYPE.LIST_MENU_TOG or line.Type == LINE_TYPE.LIST_MENU_NC2 or
|
||||||
|
line.Type == LINE_TYPE.LIST_MENU_ORI) then return true end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.isPercentValueLineByMinMax(line)
|
||||||
|
return
|
||||||
|
(line.Min == 0 and line.Max == 100) or ( line.Min == -100 and line.Max == 100) or
|
||||||
|
( line.Min == 0 and line.Max == 150) or ( line.Min == -150 and line.Max == 150)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.isPercentValueLine(line) -- is it a Percent value??
|
||||||
|
if (line.Type == LINE_TYPE.VALUE_PERCENT) then return true end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.isNumberValueLine(line) -- is it a number ??
|
||||||
|
if (MenuLib.isListLine(line) or line.Type == LINE_TYPE.MENU or line.Type == 0) then return false
|
||||||
|
else return true end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.isIncrementalValueUpdate(line)
|
||||||
|
if (line.Type == LINE_TYPE.LIST_MENU_NC or line.Type == LINE_TYPE.LIST_MENU_NC2 or
|
||||||
|
line.Type == LINE_TYPE.VALUE_NUM_I8_NC or line.Type == LINE_TYPE.VALUE_DEGREES) then return false end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------------------------------------
|
||||||
|
function MenuLib.Get_Text(index)
|
||||||
|
if (index >= 0x8000) then
|
||||||
|
return Flight_Mode[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
local out = Text[index] -- Find in regular header first
|
||||||
|
if out== nil then
|
||||||
|
out = List_Text[index] -- Try list values, don't think is necesary, but just playing Safe
|
||||||
|
end
|
||||||
|
if out == nil then -- unknown...
|
||||||
|
out = "Unknown_" .. string.format("%X", index)
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.Get_List_Text(index)
|
||||||
|
local out = List_Text[index] -- Try to find the message in List_Text
|
||||||
|
if out == nil then
|
||||||
|
out = Text[index] -- Try list headers, don't think is necesary, but just playing Safe
|
||||||
|
end
|
||||||
|
if out == nil then -- unknown...
|
||||||
|
out = "UnknownLT_" .. string.format("%X", index)
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.Get_List_Text_Img(index)
|
||||||
|
local out = List_Text_Img[index]
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.Get_List_Values(index)
|
||||||
|
local out = List_Values[index]
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.Get_RxName(index)
|
||||||
|
local out = RxName[index]
|
||||||
|
return out or ("RX_" .. string.format("%X", index))
|
||||||
|
end
|
||||||
|
|
||||||
|
----------- Debugging 2-String functions -------------------------------------------------------------------
|
||||||
|
|
||||||
|
function MenuLib.phase2String(index)
|
||||||
|
local out = PhaseText[index]
|
||||||
|
return out or ("Phase_" .. string.format("%X", index))
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.lineType2String(index)
|
||||||
|
local out = LineTypeText[index]
|
||||||
|
return out or ("LT_" .. string.format("%X", index or 0xFF))
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.lineValue2String(l)
|
||||||
|
if (DEBUG_ON == 0) then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
if (l ~= nil and l.Val ~= nil) then
|
||||||
|
local value = l.Val
|
||||||
|
if MenuLib.isListLine(l) then
|
||||||
|
value = value .. "|\"" .. MenuLib.Get_List_Text(l.Val + l.TextStart) .. "\""
|
||||||
|
else
|
||||||
|
value = value..(l.Format or "")
|
||||||
|
end
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
return "nil"
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.menu2String(m)
|
||||||
|
local txt = "Menu[]"
|
||||||
|
if (m ~= nil) then
|
||||||
|
txt = string.format("M[Id=0x%X P=0x%X N=0x%X B=0x%X Text=\"%s\"[0x%X]]",
|
||||||
|
m.MenuId, m.PrevId, m.NextId, m.BackId, m.Text, m.TextId)
|
||||||
|
end
|
||||||
|
return txt
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.menuLine2String(l)
|
||||||
|
local txt = "Line[]"
|
||||||
|
if (l ~= nil) then
|
||||||
|
local value = ""
|
||||||
|
local range = ""
|
||||||
|
if l.Type~=LINE_TYPE.MENU then
|
||||||
|
value = "Val="..MenuLib.lineValue2String(l)
|
||||||
|
if MenuLib.isListLine(l) then
|
||||||
|
range = string.format("NL=(%s->%s,%s,S=%s) ",l.Min, l.Max, l.Def, l.TextStart )
|
||||||
|
range = range .. (l.MinMaxOrig or "")
|
||||||
|
else
|
||||||
|
range = string.format("[%s->%s,%s]",l.Min, l.Max, l.Def)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
txt = string.format("L[#%s T=%s VId=0x%X Text=\"%s\"[0x%X] %s %s MId=0x%X A=0x%X]",
|
||||||
|
l.lineNum, MenuLib.lineType2String(l.Type), l.ValId,
|
||||||
|
l.Text, l.TextId,
|
||||||
|
value,
|
||||||
|
range,
|
||||||
|
l.MenuId,
|
||||||
|
l.TextAttr
|
||||||
|
)
|
||||||
|
end
|
||||||
|
return txt
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------------------------------------
|
||||||
|
-- Post Procssing Line from Raw values receive by RX or Simulation
|
||||||
|
|
||||||
|
function MenuLib.isDisplayAttr(attr, bit)
|
||||||
|
return (bit32.band(attr,bit)>0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.ExtractDisplayAttr(text1, attr)
|
||||||
|
local text = text1, pos;
|
||||||
|
|
||||||
|
for i=1,2 do
|
||||||
|
text, pos = string.gsub(text, "/c$", "")
|
||||||
|
if (pos>0) then -- CENTER
|
||||||
|
attr = bit32.bor(attr, DISP_ATTR._CENTER)
|
||||||
|
end
|
||||||
|
|
||||||
|
text, pos = string.gsub(text, "/r$", "")
|
||||||
|
if (pos>0) then -- RIGHT
|
||||||
|
attr = bit32.bor(attr, DISP_ATTR._RIGHT)
|
||||||
|
end
|
||||||
|
|
||||||
|
text, pos = string.gsub(text, "/p$", "")
|
||||||
|
if (pos>0) then -- Percent TEXT
|
||||||
|
attr = bit32.bor(attr, DISP_ATTR.PERCENT)
|
||||||
|
end
|
||||||
|
|
||||||
|
text, pos = string.gsub(text, "/b$", "")
|
||||||
|
if (pos>0) then -- BOLD TEXT
|
||||||
|
attr = bit32.bor(attr, DISP_ATTR._BOLD)
|
||||||
|
end
|
||||||
|
|
||||||
|
text, pos = string.gsub(text, "/m$", "")
|
||||||
|
if (pos>0) then -- FORCED MENU Button
|
||||||
|
attr = bit32.bor(attr, DISP_ATTR.FORCED_MENU)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return text, attr
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.MenuPostProcessing(menu)
|
||||||
|
menu.Text, menu.TextAttr = MenuLib.ExtractDisplayAttr(menu.Text,menu.TextAttr or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.MenuLinePostProcessing(line)
|
||||||
|
if (line.Text==nil) then
|
||||||
|
line.Text = MenuLib.Get_Text(line.TextId) -- Get Textual Line headeing text
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Text formatting options
|
||||||
|
line.Text, line.TextAttr = MenuLib.ExtractDisplayAttr(line.Text,line.TextAttr or 0)
|
||||||
|
|
||||||
|
if line.Type == LINE_TYPE.MENU then
|
||||||
|
-- nothing to do on menu entries
|
||||||
|
line.Val=nil
|
||||||
|
elseif MenuLib.isListLine(line) then
|
||||||
|
-- Original Range for Debugging
|
||||||
|
line.MinMaxOrig = "[" .. line.Min .. "->" .. line.Max .. "," .. line.Def .. "]"
|
||||||
|
|
||||||
|
-- Normalize Min/Max to be relative to Zero
|
||||||
|
line.TextStart = line.Min
|
||||||
|
line.Def = line.Def - line.Min -- normalize default value
|
||||||
|
line.Max = line.Max - line.Min -- normalize max index
|
||||||
|
line.Min = 0 -- min index
|
||||||
|
else -- default to numerical value
|
||||||
|
if MenuLib.isPercentValueLine(line) or MenuLib.isPercentValueLineByMinMax(line) then
|
||||||
|
-- either explicit Percent or NO-Change value, but range is %Percent
|
||||||
|
line.Format ="%"
|
||||||
|
line.TextAttr = bit32.bor(line.TextAttr,DISP_ATTR.PERCENT)
|
||||||
|
elseif (line.Type == LINE_TYPE.VALUE_DEGREES) then
|
||||||
|
line.Format ="o"
|
||||||
|
line.TextAttr = bit32.bor(line.TextAttr,DISP_ATTR.DEGREES)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
line.MinMaxDebug = MenuLib.lineType2String(line.Type).." "..(line.MinMaxOrig or "")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function MenuLib.ChangePhase(newPhase)
|
||||||
|
DSM_Context.Phase = newPhase
|
||||||
|
DSM_Context.SendDataToRX = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.Value_Add(line, inc)
|
||||||
|
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Add(%s,%s)\n",
|
||||||
|
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), inc, MenuLib.menuLine2String(line)) end
|
||||||
|
|
||||||
|
local skipIncrement = false
|
||||||
|
local values = nil
|
||||||
|
local origVal = line.Val
|
||||||
|
|
||||||
|
-- Use local validation for LIST_MENU1 when the range is wide open
|
||||||
|
-- Also use if for some LIST_MENU0 that the Range seems incorrect
|
||||||
|
if (MenuLib.isListLine(line)) then -- and line.Type==LINE_TYPE.LIST_MENU1 and line.Min==0 and line.Max==244) then
|
||||||
|
values = MenuLib.Get_List_Values(line.TextId)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if (values~=nil) then -- Inc/Dec based on a list of predefined Values Local to Script (values not contiguous),
|
||||||
|
-- locate current value in values array
|
||||||
|
-- Values are Zero normalized to the Start of the List (line.TextStart)
|
||||||
|
for i = 1, #values do
|
||||||
|
if ((values[i]-line.TextStart)==origVal) then
|
||||||
|
skipIncrement = true
|
||||||
|
if (inc==-1 and i > 1) then -- PREV
|
||||||
|
line.Val = values[i-1]-line.TextStart
|
||||||
|
elseif (inc==1 and i < #values) then -- NEXT
|
||||||
|
line.Val = values[i+1]-line.TextStart
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not skipIncrement then
|
||||||
|
-- Do it Sequentially
|
||||||
|
line.Val = line.Val + inc
|
||||||
|
|
||||||
|
if line.Val > line.Max then
|
||||||
|
line.Val = line.Max
|
||||||
|
elseif line.Val < line.Min then
|
||||||
|
line.Val = line.Min
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (origVal~=line.Val and MenuLib.isIncrementalValueUpdate(line)) then
|
||||||
|
-- Update RX value on every change
|
||||||
|
MenuLib.ChangePhase(PHASE.VALUE_CHANGING)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.Value_Default(line)
|
||||||
|
local origVal = line.Val
|
||||||
|
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Default(%s)\n",
|
||||||
|
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), MenuLib.menuLine2String(line)) end
|
||||||
|
|
||||||
|
line.Val = line.Def
|
||||||
|
if (origVal~=line.Val and MenuLib.isIncrementalValueUpdate(line)) then
|
||||||
|
-- Update RX value on every change
|
||||||
|
MenuLib.ChangePhase(PHASE.VALUE_CHANGING)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.Value_Write_Validate(line)
|
||||||
|
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Write_Validate(%s)\n",
|
||||||
|
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), MenuLib.menuLine2String(line)) end
|
||||||
|
|
||||||
|
MenuLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Update + Validate value in RX
|
||||||
|
DSM_Context.EditLine = nil -- Exit Edit Mode (By clearing the line editing)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.GotoMenu(menuId, lastSelectedLine)
|
||||||
|
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_GotoMenu(0x%X,LastSelectedLine=%d)\n",
|
||||||
|
MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), menuId, lastSelectedLine) end
|
||||||
|
|
||||||
|
DSM_Context.Menu.MenuId = menuId
|
||||||
|
DSM_Context.SelLine = lastSelectedLine
|
||||||
|
-- Request to load the menu Again
|
||||||
|
MenuLib.ChangePhase(PHASE.MENU_TITLE)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.MoveSelectionLine(dir)
|
||||||
|
local ctx = DSM_Context
|
||||||
|
local menu = ctx.Menu
|
||||||
|
local menuLines = ctx.MenuLines
|
||||||
|
|
||||||
|
if (dir == 1) then -- NEXT
|
||||||
|
if ctx.SelLine <= MAX_MENU_LINES then
|
||||||
|
local num = ctx.SelLine
|
||||||
|
for i = ctx.SelLine + 1, MAX_MENU_LINES, 1 do
|
||||||
|
if MenuLib.isSelectableLine(menuLines[i]) then
|
||||||
|
ctx.SelLine = i
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if num == ctx.SelLine then
|
||||||
|
if menu.NextId ~= 0 then -- Next
|
||||||
|
ctx.SelLine = NEXT_BUTTON
|
||||||
|
elseif menu.PrevId ~= 0 then -- Prev
|
||||||
|
ctx.SelLine = PREV_BUTTON
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif menu.PrevId ~= 0 then -- Prev
|
||||||
|
ctx.SelLine = PREV_BUTTON
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if (dir == -1) then -- PREV
|
||||||
|
if ctx.SelLine == PREV_BUTTON and menu.NextId ~= 0 then
|
||||||
|
ctx.SelLine = NEXT_BUTTON
|
||||||
|
elseif ctx.SelLine > 0 then
|
||||||
|
if ctx.SelLine > MAX_MENU_LINES then
|
||||||
|
ctx.SelLine = NEXT_BUTTON
|
||||||
|
end
|
||||||
|
local num = ctx.SelLine
|
||||||
|
for i = ctx.SelLine - 1, 0, -1 do
|
||||||
|
if MenuLib.isSelectableLine(menuLines[i]) then
|
||||||
|
ctx.SelLine = i
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if num == ctx.SelLine then -- can't find previous selectable line, then SELECT Back
|
||||||
|
if (menu.BackId ~= 0) then ctx.SelLine = BACK_BUTTON end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if (menu.BackId ~= 0) then ctx.SelLine = BACK_BUTTON end -- Back
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Clear each line of the menu
|
||||||
|
function MenuLib.clearMenuLines()
|
||||||
|
local ctx = DSM_Context
|
||||||
|
for i = 0, MAX_MENU_LINES do -- clear menu
|
||||||
|
ctx.MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0, Text = "", TextId = 0, ValId = 0, Min=0, Max=0, Def=0, TextStart=0, Val=nil }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Post processing needed for each menu
|
||||||
|
function MenuLib.PostProcessMenu()
|
||||||
|
local ctx = DSM_Context
|
||||||
|
|
||||||
|
if (ctx.Menu.Text==nil) then
|
||||||
|
ctx.Menu.Text = MenuLib.Get_Text(ctx.Menu.TextId)
|
||||||
|
MenuLib.MenuPostProcessing (ctx.Menu)
|
||||||
|
end
|
||||||
|
|
||||||
|
--if (DEBUG_ON) then Log.LOG_write("SIM RESPONSE Menu: %s\n", MenuLib.menu2String(ctx.Menu)) end
|
||||||
|
|
||||||
|
for i = 0, MenuLib.MAX_MENU_LINES do -- clear menu
|
||||||
|
local line = ctx.MenuLines[i]
|
||||||
|
if (line.Type~=0) then
|
||||||
|
line.MenuId = ctx.Menu.MenuId
|
||||||
|
line.lineNum = i
|
||||||
|
MenuLib.MenuLinePostProcessing(line) -- Do the same post processing as if they come from the RX
|
||||||
|
--if (DEBUG_ON) then Log.LOG_write("SIM RESPONSE MenuLine: %s\n", MenuLib.menuLine2String(line)) end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.GetFlightModeValue(line)
|
||||||
|
local ret = line.Text.." "
|
||||||
|
local val = line.Val
|
||||||
|
|
||||||
|
if (val==nil) then return ret.."--" end
|
||||||
|
|
||||||
|
-- Adjust the displayed value for Flight mode line as needed
|
||||||
|
if (DSM_Context.RX.Id == RX.FC6250HX) then
|
||||||
|
-- Helicopter Flights modes
|
||||||
|
if (val==0) then ret = ret .. "1 / HOLD"
|
||||||
|
elseif (val==1) then ret = ret .. "2 / Normal"
|
||||||
|
elseif (val==2) then ret = ret .. "3 / Stunt 1"
|
||||||
|
elseif (val==3) then ret = ret .. "4 / Stunt 2"
|
||||||
|
elseif (val==4) then ret = ret .. "5 / Panic"
|
||||||
|
else
|
||||||
|
ret = ret .. " " .. (val + 1)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- No adjustment needed
|
||||||
|
ret=ret..(val + 1)
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.Init()
|
||||||
|
print("MenuLib.Init()")
|
||||||
|
-- Phase Names
|
||||||
|
PhaseText[PHASE.INIT] = "INIT"
|
||||||
|
PhaseText[PHASE.RX_VERSION] = "RX_VERSION"
|
||||||
|
PhaseText[PHASE.WAIT_CMD] = "WAIT_CMD"
|
||||||
|
PhaseText[PHASE.MENU_TITLE] = "MENU_TITLE"
|
||||||
|
PhaseText[PHASE.MENU_REQ_TX_INFO] = "MENU_REQ_TX_INFO"
|
||||||
|
PhaseText[PHASE.MENU_LINES] = "MENU_LINES"
|
||||||
|
PhaseText[PHASE.MENU_VALUES] = "MENU_VALUES"
|
||||||
|
PhaseText[PHASE.VALUE_CHANGING] = "VALUE_CHANGING"
|
||||||
|
PhaseText[PHASE.VALUE_CHANGING_WAIT] = "VALUE_EDITING"
|
||||||
|
PhaseText[PHASE.VALUE_CHANGE_END] = "VALUE_CHANGE_END"
|
||||||
|
PhaseText[PHASE.EXIT] = "EXIT"
|
||||||
|
PhaseText[PHASE.EXIT_DONE] = "EXIT_DONE"
|
||||||
|
|
||||||
|
|
||||||
|
-- Line Types
|
||||||
|
LineTypeText[LINE_TYPE.MENU] = "M"
|
||||||
|
LineTypeText[LINE_TYPE.LIST_MENU_NC] = "LM_nc"
|
||||||
|
LineTypeText[LINE_TYPE.LIST_MENU] = "LM"
|
||||||
|
LineTypeText[LINE_TYPE.LIST_MENU_TOG] = "LM_tog"
|
||||||
|
LineTypeText[LINE_TYPE.LIST_MENU_NC2] = "LM_nc2"
|
||||||
|
LineTypeText[LINE_TYPE.LIST_MENU_ORI] = "LM_ori"
|
||||||
|
LineTypeText[LINE_TYPE.VALUE_NUM_I8_NC] = "V_nc"
|
||||||
|
LineTypeText[LINE_TYPE.VALUE_PERCENT] = "V_%"
|
||||||
|
LineTypeText[LINE_TYPE.VALUE_DEGREES] = "V_de"
|
||||||
|
LineTypeText[LINE_TYPE.VALUE_NUM_I8] = "V_i8"
|
||||||
|
LineTypeText[LINE_TYPE.VALUE_NUM_I16] = "V_i16"
|
||||||
|
LineTypeText[LINE_TYPE.VALUE_NUM_SI16] = "V_s16"
|
||||||
|
LineTypeText[LINE_TYPE.LT_EMPTY] = "Z"
|
||||||
|
|
||||||
|
DSM_Context.Phase = PHASE.RX_VERSION
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.clearAllText()
|
||||||
|
local function clearTable(t)
|
||||||
|
for i, v in ipairs(t) do t[i] = nil end
|
||||||
|
end
|
||||||
|
|
||||||
|
clearTable(Text)
|
||||||
|
clearTable(List_Text)
|
||||||
|
clearTable(List_Text_Img)
|
||||||
|
clearTable(List_Values)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.LoadTextFromFile(fileName, mem)
|
||||||
|
local function rtrim(s)
|
||||||
|
local n = string.len(s)
|
||||||
|
while n > 0 and string.find(s, "^%s", n) do n = n - 1 end
|
||||||
|
return string.sub(s, 1, n)
|
||||||
|
end
|
||||||
|
|
||||||
|
--print(string.format("Loading messages from [%s]",fileName))
|
||||||
|
local dataFile = io.open(fileName, "r") -- read File
|
||||||
|
-- cannot read file???
|
||||||
|
assert(dataFile, "Cannot load Message file:" .. fileName)
|
||||||
|
|
||||||
|
local data = io.read(dataFile, mem * 1024) -- read up to 10k characters (newline char also counts!)
|
||||||
|
io.close(dataFile)
|
||||||
|
|
||||||
|
collectgarbage("collect")
|
||||||
|
|
||||||
|
local lineNo = 0
|
||||||
|
for line in string.gmatch(data, "[^\r\n]+") do
|
||||||
|
lineNo = lineNo + 1
|
||||||
|
--print(string.format("Line [%d]: %s",lineNo,line))
|
||||||
|
|
||||||
|
-- Remove Comments
|
||||||
|
local s = string.find(line, "--", 1, true)
|
||||||
|
if (s ~= nil) then
|
||||||
|
line = string.sub(line, 1, s - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
line = rtrim(line)
|
||||||
|
|
||||||
|
if (string.len(line) > 0) then
|
||||||
|
local a, b, c = string.match(line, "%s*(%a*)%s*|%s*(%w*)%s*|(.*)%s*")
|
||||||
|
--print(string.format("[%s] [%s] [%s]",a,b,c))
|
||||||
|
if (a ~= nil) then
|
||||||
|
local index = tonumber(b)
|
||||||
|
|
||||||
|
if (index == nil) then
|
||||||
|
assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, lineNo, b))
|
||||||
|
elseif (a == "T") then
|
||||||
|
Text[index] = c
|
||||||
|
elseif (a == "LT") then
|
||||||
|
List_Text[index] = c
|
||||||
|
elseif (a == "LI") then
|
||||||
|
List_Text_Img[index] = c
|
||||||
|
elseif (a == "FM") then
|
||||||
|
Flight_Mode[0] = c
|
||||||
|
elseif (a == "RX") then
|
||||||
|
RxName[index] = c
|
||||||
|
else
|
||||||
|
assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, lineNo, a))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (lineNo % 50 == 0) then
|
||||||
|
collectgarbage("collect")
|
||||||
|
end
|
||||||
|
end -- For
|
||||||
|
|
||||||
|
--print(string.format("Loaded [%d] messages",lineNo))
|
||||||
|
data = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuLib.INC_LoadTextFromFile(fileName, FileState)
|
||||||
|
-----------------------
|
||||||
|
local function rtrim(s)
|
||||||
|
local n = string.len(s)
|
||||||
|
while n > 0 and string.find(s, "^%s", n) do n = n - 1 end
|
||||||
|
return string.sub(s, 1, n)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function GetTextInfoFromFile(pos)
|
||||||
|
local dataFile = io.open(fileName, "r")
|
||||||
|
io.seek(dataFile,pos)
|
||||||
|
local buff = io.read(dataFile, 100)
|
||||||
|
io.close(dataFile)
|
||||||
|
|
||||||
|
local line=""
|
||||||
|
local index=""
|
||||||
|
local type=""
|
||||||
|
|
||||||
|
local pipe=0
|
||||||
|
local comment=0
|
||||||
|
local newPos = pos
|
||||||
|
|
||||||
|
-- Parse the line:
|
||||||
|
-- Format: TT|0x999|Text -- Comment
|
||||||
|
for i=1,#buff do
|
||||||
|
newPos=newPos+1
|
||||||
|
local ch = string.sub(buff,i,i)
|
||||||
|
|
||||||
|
if (pipe < 2 and ch=="|") then pipe=pipe+1 -- Count pipes pos (Type | Index | .....)
|
||||||
|
elseif (ch=="\r") then -- Ignore CR
|
||||||
|
elseif (ch=="\n") then break -- LF, end of line
|
||||||
|
elseif (ch=="-") then -- March comments
|
||||||
|
comment=comment+1
|
||||||
|
if (comment==2) then pipe=6 end -- Comment part of line
|
||||||
|
else
|
||||||
|
-- regular char
|
||||||
|
comment=0
|
||||||
|
if (pipe==0) then type=type..ch -- in TT (Type)
|
||||||
|
elseif (pipe==1) then index=index..ch -- in Index
|
||||||
|
elseif (pipe<6) then line=line..ch end -- in Text
|
||||||
|
end -- Regular char
|
||||||
|
end -- For
|
||||||
|
|
||||||
|
return type, index, rtrim(line), newPos
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
if (FileState.state==nil) then -- Initial State
|
||||||
|
FileState.state=1
|
||||||
|
FileState.lineNo=0
|
||||||
|
FileState.filePos=0
|
||||||
|
end
|
||||||
|
|
||||||
|
if FileState.state==1 then
|
||||||
|
for l=1,10 do -- do 10 lines at a time
|
||||||
|
local type, sIndex, text
|
||||||
|
local lineStart = FileState.filePos
|
||||||
|
|
||||||
|
type, sIndex, text, FileState.filePos = GetTextInfoFromFile(FileState.filePos)
|
||||||
|
|
||||||
|
--print(string.format("T=%s, I=%s, T=%s LS=%d, FP=%d",type,sIndex,text,lineStart, FileState.filePos))
|
||||||
|
|
||||||
|
if (lineStart==FileState.filePos) then -- EOF
|
||||||
|
FileState.state=2 --EOF State
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
FileState.lineNo = FileState.lineNo + 1
|
||||||
|
|
||||||
|
type = rtrim(type)
|
||||||
|
|
||||||
|
if (string.len(type) > 0 and string.len(sIndex) > 0) then
|
||||||
|
local index = tonumber(sIndex)
|
||||||
|
|
||||||
|
if (index == nil) then
|
||||||
|
assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, FileState.lineNo, sIndex))
|
||||||
|
elseif (type == "T") then
|
||||||
|
Text[index] = text
|
||||||
|
elseif (type == "LT") then
|
||||||
|
List_Text[index] = text
|
||||||
|
elseif (type == "LI") then
|
||||||
|
List_Text_Img[index] = text
|
||||||
|
elseif (type == "FM") then
|
||||||
|
Flight_Mode[0] = text
|
||||||
|
elseif (type == "RX") then
|
||||||
|
RxName[index] = text
|
||||||
|
else
|
||||||
|
assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, FileState.lineNo, type))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end -- for
|
||||||
|
end -- if
|
||||||
|
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Export some Constants and Variables
|
||||||
|
MenuLib.PHASE = PHASE
|
||||||
|
MenuLib.LINE_TYPE = LINE_TYPE
|
||||||
|
MenuLib.DISP_ATTR = DISP_ATTR
|
||||||
|
MenuLib.RX = RX
|
||||||
|
|
||||||
|
MenuLib.MAX_MENU_LINES = MAX_MENU_LINES
|
||||||
|
MenuLib.BACK_BUTTON = BACK_BUTTON
|
||||||
|
MenuLib.NEXT_BUTTON = NEXT_BUTTON
|
||||||
|
MenuLib.PREV_BUTTON = PREV_BUTTON
|
||||||
|
|
||||||
|
MenuLib.DSM_Context = DSM_Context
|
||||||
|
|
||||||
|
MenuLib.Text = Text
|
||||||
|
MenuLib.List_Text = List_Text
|
||||||
|
MenuLib.List_Text_Img = List_Text_Img
|
||||||
|
MenuLib.List_Values = List_Values
|
||||||
|
|
||||||
|
MenuLib.LOG_open = Log.LOG_open
|
||||||
|
MenuLib.LOG_write = Log.LOG_write
|
||||||
|
MenuLib.LOG_Close = Log.LOG_close
|
||||||
|
|
||||||
|
|
||||||
|
return MenuLib
|
810
Lua_scripts/DSMLIB/DsmModelLib.lua
Normal file
@ -0,0 +1,810 @@
|
|||||||
|
|
||||||
|
local Log, DEBUG_ON = ...
|
||||||
|
|
||||||
|
local DATA_PATH = "/MODELS/DSMDATA" -- Path to store model settings files
|
||||||
|
local TX_CHANNELS = 12
|
||||||
|
|
||||||
|
-- MODEL information from ETX/OTX
|
||||||
|
local ModelLib = {}
|
||||||
|
|
||||||
|
local MODEL = {
|
||||||
|
modelName = "", -- The name of the model comming from OTX/ETX
|
||||||
|
modelOutputChannel = {}, -- Output information from OTX/ETX
|
||||||
|
AirWingTailDesc = "",
|
||||||
|
|
||||||
|
TX_CH_TEXT = {},
|
||||||
|
PORT_TEXT = {},
|
||||||
|
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
|
||||||
|
}
|
||||||
|
|
||||||
|
--Channel Types --
|
||||||
|
local CH_TYPE = {
|
||||||
|
NONE = 0x00,
|
||||||
|
AIL = 0x01,
|
||||||
|
ELE = 0x02,
|
||||||
|
RUD = 0x04,
|
||||||
|
|
||||||
|
REVERSE = 0x20,
|
||||||
|
THR = 0x40,
|
||||||
|
SLAVE = 0x80,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Seems like Reverse Mix is complement of the 3 bits
|
||||||
|
local CH_MIX_TYPE = {
|
||||||
|
NORMAL = 0x00, -- 0000
|
||||||
|
MIX_AIL_B = 0x10, -- 0001 Taileron B
|
||||||
|
MIX_ELE_A = 0x20, -- 0010 For VTIAL and Delta-ELEVON A
|
||||||
|
MIX_ELE_B_REV= 0x30, -- 0011 For VTIAL and Delta-ELEVON B
|
||||||
|
MIX_ELE_B = 0x40, -- 0100 For VTIAL and Delta-ELEVON B
|
||||||
|
MIX_ELE_A_REV= 0x50, -- 0101 For VTIAL and Delta-ELEVON A
|
||||||
|
MIX_AIL_B_REV= 0x60, -- 0110 Taileron B Rev
|
||||||
|
NORM_REV = 0x70 -- 0111
|
||||||
|
}
|
||||||
|
|
||||||
|
local AIRCRAFT_TYPE = {
|
||||||
|
PLANE = 0,
|
||||||
|
HELI = 1,
|
||||||
|
GLIDER = 2,
|
||||||
|
DRONE = 3
|
||||||
|
}
|
||||||
|
local aircraft_type_text = {[0]="Plane","Heli","Glider","Drone"}
|
||||||
|
|
||||||
|
local WING_TYPE = {
|
||||||
|
AIL_1 = 0, --1
|
||||||
|
AIL_2 = 1, --2
|
||||||
|
FLAPERON = 2, --2
|
||||||
|
AIL_1_FLP_1 = 3, --2
|
||||||
|
AIL_2_FLP_1 = 4, --3
|
||||||
|
AIL_2_FLP_2 = 5, --4
|
||||||
|
ELEVON_A = 6, --2
|
||||||
|
ELEVON_B = 7 --2
|
||||||
|
}
|
||||||
|
|
||||||
|
local wing_type_text = {[0]="Normal","Dual Ail","Flapperon", "Ail + Flp","Dual Ail + Flp","Dual Ail/Flp","Elevon A","Elevon B"}
|
||||||
|
|
||||||
|
local TAIL_TYPE = {
|
||||||
|
RUD_1 = 0, -- 1
|
||||||
|
RUD_1_ELEV_1 = 1, -- 2
|
||||||
|
RUD_1_ELEV_2 = 2, -- 3
|
||||||
|
RUD_2_ELEV_1 = 3, -- 3
|
||||||
|
RUD_2_ELEV_2 = 4, -- 4
|
||||||
|
VTAIL_A = 5, -- 2
|
||||||
|
VTAIL_B = 6, -- 2
|
||||||
|
TRAILERON_A = 7, -- 3
|
||||||
|
TRAILERON_B = 8, -- 3
|
||||||
|
}
|
||||||
|
local tail_type_text = {[0]="Rud Only","Normal","Rud + Dual Ele","Dual Rud + Elv","Dual Rud/Ele","VTail A","VTail B","Traileron A","Traileron B"}
|
||||||
|
|
||||||
|
local CH_MODE_TYPE = {
|
||||||
|
NORMAL = 0,
|
||||||
|
REVERSE = 1,
|
||||||
|
USE_TX = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
local PORT = {
|
||||||
|
PORT1 = 0,
|
||||||
|
PORT2 = 1,
|
||||||
|
PORT3 = 2,
|
||||||
|
PORT4 = 3,
|
||||||
|
PORT5 = 4,
|
||||||
|
PORT6 = 5,
|
||||||
|
PORT7 = 6,
|
||||||
|
PORT8 = 7,
|
||||||
|
PORT9 = 8,
|
||||||
|
PORT10 = 9,
|
||||||
|
PORT11 = 10,
|
||||||
|
PORT12 = 11
|
||||||
|
}
|
||||||
|
|
||||||
|
local MEMU_VAR = {
|
||||||
|
AIRCRAFT_TYPE = 1001,
|
||||||
|
WING_TYPE = 1002,
|
||||||
|
TAIL_TYPE = 1003,
|
||||||
|
|
||||||
|
CH_BASE = 1010,
|
||||||
|
CH_THR = 1010,
|
||||||
|
|
||||||
|
CH_L_AIL = 1011,
|
||||||
|
CH_R_AIL = 1012,
|
||||||
|
CH_L_FLP = 1013,
|
||||||
|
CH_R_FLP = 1014,
|
||||||
|
|
||||||
|
CH_L_RUD = 1015,
|
||||||
|
CH_R_RUD = 1016,
|
||||||
|
CH_L_ELE = 1017,
|
||||||
|
CH_R_ELE = 1018,
|
||||||
|
|
||||||
|
PORT_BASE = 1020,
|
||||||
|
PORT1_MODE = 1020,
|
||||||
|
PORT2_MODE = 1021,
|
||||||
|
PORT3_MODE = 1022,
|
||||||
|
PORT4_MODE = 1023,
|
||||||
|
PORT5_MODE = 1024,
|
||||||
|
PORT6_MODE = 1025,
|
||||||
|
PORT7_MODE = 1026,
|
||||||
|
PORT8_MODE = 1027,
|
||||||
|
PORT9_MODE = 1028,
|
||||||
|
PORT10_MODE = 1029,
|
||||||
|
PORT11_MODE = 1030,
|
||||||
|
PORT12_MODE = 1031,
|
||||||
|
|
||||||
|
DATA_END = 1040
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- MENU DATA Management
|
||||||
|
local MENU_DATA = {} -- Store the variables used in the Menus.
|
||||||
|
|
||||||
|
|
||||||
|
---- DSM_ChannelInfo ---------------------------------
|
||||||
|
-- First byte describe Special Mixing (Vtail/Elevon = 0x20)
|
||||||
|
--VTAIL
|
||||||
|
--(0x00 0x06) CH_TYPE.ELE+CH_TYPE.RUD (0x02+0x04 = 0x06)
|
||||||
|
--(0x20 0x86) CH_TYPE.ELE+CH_TYPE.RUD+CH_TYPE.SLAVE (0x02+0x04+0x80 = 0x86)
|
||||||
|
|
||||||
|
-- The 2nd byte describes the functionality of the port
|
||||||
|
--
|
||||||
|
-- Single Example: CH_TYPE.AIL (0x01) Aileron
|
||||||
|
-- Reverse Example: CH_TYPE.AIL+CH_TYPE.REVERSE (0x01+0x20=0x21) Reverse Aileron
|
||||||
|
-- Slave Example: CH_TYPE.AIL+CH_TYPE.SLAVE (0x01+0x80) -- 2nd servo Aileron
|
||||||
|
|
||||||
|
-- Elevon Example: CH_TYPE.AIL+CH_TYPE.ELE (0x01+0x02 = 0x03) -- Elevon
|
||||||
|
-- Elevon Example: CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE (0x01+0x02+0x80 = 0x83) -- Slave Elevon
|
||||||
|
|
||||||
|
-- RudElv (VTail) Example: CH_TYPE.ELE+CH_TYPE.RUD (0x02+0x04 = 0x06) -- Rudevator
|
||||||
|
-- RudElv (VTail) Example: CH_TYPE.ELE+CH_TYPE.RUD+CH_TYPE.SLAVE (0x02+0x04+0x80 = 0x86) -- Rudevator Slave
|
||||||
|
|
||||||
|
-- DEFAULT Simple Plane Port configuration (The Configuration tool will overrride this)
|
||||||
|
MODEL.DSM_ChannelInfo= {[0]= -- Start array at position 0
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.THR}, -- Ch1 Thr (0x40)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.AIL}, -- Ch2 Ail (0x01)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.ELE}, -- Ch2 ElE (0x02)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.RUD}, -- Ch4 Rud (0x04)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.NONE}, -- Ch5 Gear (0x00)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.NONE}, -- Ch6 Aux1 (0x00)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.NONE}, -- Ch7 Aux2 (0x00)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.NONE}, -- Ch8 Aux3 (0x00)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.NONE}, -- Ch9 Aux4 (0x00)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.NONE}, -- Ch10 Aux5 (0x00)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.NONE}, -- Ch11 Aux6 (0x00)
|
||||||
|
{[0]= CH_MIX_TYPE.NONE, CH_TYPE.NONE} -- Ch12 Aux7 (0x00)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ModelLib.printChannelSummary(a,w,t)
|
||||||
|
-- Summary
|
||||||
|
print("CHANNEL INFORMATION")
|
||||||
|
print("Aircraft:".. (aircraft_type_text[MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]] or "--"))
|
||||||
|
print("Wing Type:".. (wing_type_text[MENU_DATA[MEMU_VAR.WING_TYPE]] or "--"))
|
||||||
|
print("Tail Type:".. (tail_type_text[MENU_DATA[MEMU_VAR.TAIL_TYPE]] or "--"))
|
||||||
|
print("Thr:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_THR] or 30)] or "--")) -- use fake ch30 for non existing channels
|
||||||
|
print("LAil:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_AIL] or 30)] or "--"))
|
||||||
|
print("RAil:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_AIL] or 30)] or "--"))
|
||||||
|
print("LFlp:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_FLP] or 30)] or "--"))
|
||||||
|
print("RFlp:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_FLP] or 30)] or "--"))
|
||||||
|
print("LEle:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_ELE] or 30)] or "--"))
|
||||||
|
print("REle:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_ELE] or 30)] or "--"))
|
||||||
|
print("LRud:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_RUD] or 30)] or "--"))
|
||||||
|
print("RRud:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_RUD] or 30)] or "--"))
|
||||||
|
end
|
||||||
|
|
||||||
|
function ModelLib.printServoReverseInfo()
|
||||||
|
print("SERVO Normal/Reverse INFORMATION")
|
||||||
|
for i=0, TX_CHANNELS-1 do
|
||||||
|
local s="--"
|
||||||
|
if (MENU_DATA[MEMU_VAR.PORT1_MODE+i] or 0) == 0 then s="NORMAL" else s="REVERSE" end
|
||||||
|
print(string.format("Port%d: %s", i+1, s))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ModelLib.channelType2String(byte1, byte2)
|
||||||
|
local s = ""
|
||||||
|
|
||||||
|
if (byte2==0) then return s end;
|
||||||
|
if (bit32.band(byte2,CH_TYPE.AIL)>0) then s=s.."AIL " end
|
||||||
|
if (bit32.band(byte2,CH_TYPE.ELE)>0) then s=s.."ELE " end
|
||||||
|
if (bit32.band(byte2,CH_TYPE.RUD)>0) then s=s.."RUD " end
|
||||||
|
if (bit32.band(byte2,CH_TYPE.THR)>0) then s=s.."THR " end
|
||||||
|
if (bit32.band(byte2,CH_TYPE.SLAVE)>0) then s=s.."SLAVE " end
|
||||||
|
if (bit32.band(byte2,CH_TYPE.REVERSE)>0) then s=s.."REVERSE " end
|
||||||
|
|
||||||
|
if (byte1==CH_MIX_TYPE.NORMAL) then s=s.." MIX_NOR"
|
||||||
|
elseif (byte1==CH_MIX_TYPE.MIX_AIL_B) then s=s.." MIX_AIL_B"
|
||||||
|
elseif (byte1==CH_MIX_TYPE.MIX_ELE_A) then s=s.." MIX_ELE_A"
|
||||||
|
elseif (byte1==CH_MIX_TYPE.MIX_ELE_B_REV) then s=s.." MIX_ELE_B_Rev"
|
||||||
|
elseif (byte1==CH_MIX_TYPE.MIX_ELE_B) then s=s.." MIX_ELE_B"
|
||||||
|
elseif (byte1==CH_MIX_TYPE.MIX_ELE_A_REV) then s=s.." MIX_ELE_A_Rev"
|
||||||
|
elseif (byte1==CH_MIX_TYPE.MIX_AIL_B_REV) then s=s.." MIX_AIL_B_Rev"
|
||||||
|
elseif (byte1==CH_MIX_TYPE.NORM_REV) then s=s.." MIX_NOR_Rev"
|
||||||
|
end
|
||||||
|
|
||||||
|
return s;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------
|
||||||
|
-- Read the model information from OTX/ETX
|
||||||
|
|
||||||
|
local function getModuleChannelOrder(num)
|
||||||
|
--Determine fist 4 channels order
|
||||||
|
local channel_names={}
|
||||||
|
local stick_names = {[0]= "R", "E", "T", "A" }
|
||||||
|
local ch_order=num
|
||||||
|
if (ch_order == -1) then
|
||||||
|
channel_names[0] = stick_names[3]
|
||||||
|
channel_names[1] = stick_names[1]
|
||||||
|
channel_names[2] = stick_names[2]
|
||||||
|
channel_names[3] = stick_names[0]
|
||||||
|
else
|
||||||
|
channel_names[bit32.band(ch_order,3)] = stick_names[3]
|
||||||
|
ch_order = math.floor(ch_order/4)
|
||||||
|
channel_names[bit32.band(ch_order,3)] = stick_names[1]
|
||||||
|
ch_order = math.floor(ch_order/4)
|
||||||
|
channel_names[bit32.band(ch_order,3)] = stick_names[2]
|
||||||
|
ch_order = math.floor(ch_order/4)
|
||||||
|
channel_names[bit32.band(ch_order,3)] = stick_names[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
local s = ""
|
||||||
|
for i=0,3 do
|
||||||
|
s=s..channel_names[i]
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
function ModelLib.ReadTxModelData()
|
||||||
|
local TRANSLATE_AETR_TO_TAER=false
|
||||||
|
local table = model.getInfo() -- Get the model name
|
||||||
|
MODEL.modelName = table.name
|
||||||
|
|
||||||
|
local module = model.getModule(0) -- Internal
|
||||||
|
if (module==nil) then module = model.getModule(1) end -- External
|
||||||
|
if (module~=nil) then
|
||||||
|
if (module.Type==6 ) then -- MULTI-MODULE
|
||||||
|
local chOrder = module.channelsOrder
|
||||||
|
local s = getModuleChannelOrder(chOrder)
|
||||||
|
Log.LOG_write("MultiChannel Ch Order: [%s] %s\n",chOrder,s)
|
||||||
|
|
||||||
|
if (s=="AETR") then TRANSLATE_AETR_TO_TAER=true
|
||||||
|
else TRANSLATE_AETR_TO_TAER=false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Log.LOG_write("MODEL NAME = %s\n",MODEL.modelName)
|
||||||
|
|
||||||
|
-- Read Ch1 to Ch10
|
||||||
|
local i= 0
|
||||||
|
for i = 0, TX_CHANNELS-1 do
|
||||||
|
local ch = model.getOutput(i) -- Zero base
|
||||||
|
if (ch~=nil) then
|
||||||
|
MODEL.modelOutputChannel[i] = ch
|
||||||
|
if (string.len(ch.name)==0) then
|
||||||
|
ch.formatCh = string.format("TX:Ch%i",i+1)
|
||||||
|
else
|
||||||
|
ch.formatCh = string.format("TX:Ch%i/%s",i+1,ch.name or "--")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Translate AETR to TAER
|
||||||
|
-- TODO: Check if there is a way to know how to the TX is configured, since if it is
|
||||||
|
-- already TAER, is not needed
|
||||||
|
|
||||||
|
if (TRANSLATE_AETR_TO_TAER) then
|
||||||
|
Log.LOG_write("Applying AETR -> TAER translation\n")
|
||||||
|
local ail = MODEL.modelOutputChannel[0]
|
||||||
|
local elv = MODEL.modelOutputChannel[1]
|
||||||
|
local thr = MODEL.modelOutputChannel[2]
|
||||||
|
|
||||||
|
MODEL.modelOutputChannel[0] = thr
|
||||||
|
MODEL.modelOutputChannel[1] = ail
|
||||||
|
MODEL.modelOutputChannel[2] = elv
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create the Port Text to be used
|
||||||
|
Log.LOG_write("Ports/Channels:\n")
|
||||||
|
for i = 0, TX_CHANNELS-1 do
|
||||||
|
local ch = MODEL.modelOutputChannel[i]
|
||||||
|
if (ch~=nil) then
|
||||||
|
MODEL.TX_CH_TEXT[i] = ch.formatCh
|
||||||
|
if LCD_W <= 128 then -- SMALLER SCREENS
|
||||||
|
MODEL.PORT_TEXT[i] = string.format("P%i (%s) ",i+1,MODEL.TX_CH_TEXT[i])
|
||||||
|
else
|
||||||
|
MODEL.PORT_TEXT[i] = string.format("Port%i (%s) ",i+1,MODEL.TX_CH_TEXT[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
Log.LOG_write("Port%d %s [%d,%d] Rev=%d, Off=%d, ppmC=%d, syn=%d\n",i+1,MODEL.TX_CH_TEXT[i],math.floor(ch.min/10),math.floor(ch.max/10), ch.revert, ch.offset, ch.ppmCenter, ch.symetrical)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------- FILE MANAGEMENT ---------------------------------------------
|
||||||
|
-- Create a fairly unique name for a model..combination of name and a hash
|
||||||
|
-- TODO: Check with ETX why we can't get the filename used to store the model info
|
||||||
|
-- Improvement request??
|
||||||
|
|
||||||
|
function ModelLib.hashName(mName)
|
||||||
|
local c=10000;
|
||||||
|
|
||||||
|
local prefix = string.gsub(mName,"%.","_") -- Change any "." to "_"
|
||||||
|
prefix = string.gsub(prefix,"% ","_") -- Change any space to "_"
|
||||||
|
prefix = string.sub(prefix,1,5) -- Take the first 5 characters
|
||||||
|
|
||||||
|
-- Simple Hash of the Model Name adding each character
|
||||||
|
for i = 1, #mName do
|
||||||
|
local ch = string.byte(mName,i,i)
|
||||||
|
c=c+ch
|
||||||
|
end
|
||||||
|
|
||||||
|
return (prefix .. c) -- Return Prefix + Hash
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Load Menu Data from a file
|
||||||
|
function ModelLib.ST_LoadFileData()
|
||||||
|
local fname = ModelLib.hashName(MODEL.modelName)..".txt"
|
||||||
|
|
||||||
|
print("Loading File:"..fname)
|
||||||
|
|
||||||
|
local dataFile = io.open(DATA_PATH .. "/".. fname, "r") -- read File
|
||||||
|
-- cannot read file???
|
||||||
|
if (dataFile==nil) then return 0 end
|
||||||
|
|
||||||
|
local line = io.read(dataFile, 5000)
|
||||||
|
io.close(dataFile)
|
||||||
|
|
||||||
|
if #line == 0 then return 0 end -- No data??
|
||||||
|
|
||||||
|
-- Process the input, each line is "Var_Id : Value" format
|
||||||
|
-- Store it into MANU_DATA
|
||||||
|
local i=0
|
||||||
|
for k, v in string.gmatch(line, "(%d+):(%d+)") do
|
||||||
|
--print(string.format("Read MENU_DATA[%d]:[%d]",k, v))
|
||||||
|
MENU_DATA[k+0]=v+0 -- do aritmentic to convert string to number
|
||||||
|
i=i+1
|
||||||
|
end
|
||||||
|
|
||||||
|
local currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
|
||||||
|
local currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||||
|
local currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||||
|
|
||||||
|
print("Validation")
|
||||||
|
print(string.format("AIRCRAFT_TYPE(%d)=%s", MEMU_VAR.AIRCRAFT_TYPE,aircraft_type_text[currAircraftType]))
|
||||||
|
print(string.format("WING_TYPE(%d)=%s", MEMU_VAR.WING_TYPE, wing_type_text[currWingType]))
|
||||||
|
print(string.format("TAIL_TYPE(%d)=%s", MEMU_VAR.TAIL_TYPE, tail_type_text[currTailType]))
|
||||||
|
|
||||||
|
ModelLib.printChannelSummary()
|
||||||
|
ModelLib.printServoReverseInfo()
|
||||||
|
|
||||||
|
-- Return 0 if no lines processed, 1 otherwise
|
||||||
|
if (i > 0) then return 1 else return 0 end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Saves MENU_DATA to a file
|
||||||
|
function ModelLib.ST_SaveFileData()
|
||||||
|
local fname = ModelLib.hashName(MODEL.modelName)..".txt"
|
||||||
|
|
||||||
|
print("Saving File:"..fname)
|
||||||
|
local dataFile = assert(io.open(DATA_PATH .. "/" .. fname, "w"),"Please create "..DATA_PATH.." folder") -- write File
|
||||||
|
|
||||||
|
-- Foreach MENU_DATA with a value write Var_Id:Value into file
|
||||||
|
for i = 0, MEMU_VAR.DATA_END do
|
||||||
|
if (MENU_DATA[i]~=nil) then
|
||||||
|
--print(string.format("Write MENU_DATA[%s] : %s",i,MENU_DATA[i]))
|
||||||
|
io.write(dataFile,string.format("%s:%s\n",i,MENU_DATA[i]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
io.close(dataFile)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This Creates the Servo Settings that will be used to pass to
|
||||||
|
-- Forward programming
|
||||||
|
function ModelLib.CreateDSMPortChannelInfo()
|
||||||
|
local function ApplyWingMixA(b2)
|
||||||
|
-- ELEVON
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_ELE_A end; -- 0x03
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.MIX_ELE_A_REV end; -- 0x23
|
||||||
|
|
||||||
|
-- Default normal/reverse behaviour
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.NORMAL end; -- 0x83
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.NORM_REV end; -- 0xA3
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ApplyWingMixB(b2)
|
||||||
|
-- ELEVON
|
||||||
|
-- Default normal/reverse behaviour
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.NORMAL end; -- 0x03
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.NORM_REV end; -- 0x23
|
||||||
|
|
||||||
|
-- Difference with B
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_ELE_A end; -- 0x83
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.MIX_ELE_A_REV end; -- 0xA3
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ApplyTailMixA(b2)
|
||||||
|
-- VTAIL
|
||||||
|
-- Default normal/reverse behaviour
|
||||||
|
if (b2==CH_TYPE.RUD+CH_TYPE.ELE) then return CH_MIX_TYPE.NORMAL end; -- 0x06
|
||||||
|
if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.NORM_REV end; -- 0x26
|
||||||
|
|
||||||
|
if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_ELE_A end; -- 0x86
|
||||||
|
if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.MIX_ELE_A_REV end; -- 0xA6
|
||||||
|
|
||||||
|
--TAILERON
|
||||||
|
-- Default normal/reverse behaviour
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.NORMAL end; -- 0x03
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.NORM_REV end; -- 0x23
|
||||||
|
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_AIL_B end; -- 0x83
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.MIX_AIL_B_REV end; -- 0xA3
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ApplyTailMixB(b2)
|
||||||
|
-- VTAIL
|
||||||
|
-- Default normal/reverse behaviour
|
||||||
|
if (b2==CH_TYPE.RUD+CH_TYPE.ELE) then return CH_MIX_TYPE.NORMAL end; -- 0x06
|
||||||
|
if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.NORM_REV end; -- 0x26
|
||||||
|
|
||||||
|
if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_ELE_B end; -- 0x86
|
||||||
|
if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.MIX_ELE_B_REV end; -- 0xA6
|
||||||
|
|
||||||
|
--TAILERON
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_AIL_B end; -- 0x03
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.MIX_AIL_B_REV end; -- 0x23
|
||||||
|
|
||||||
|
-- Default normal/reverse behaviour
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.NORMAL end; -- 0x83
|
||||||
|
if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return CH_MIX_TYPE.NORM_REV end; -- 0xA3
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local DSM_ChannelInfo = MODEL.DSM_ChannelInfo
|
||||||
|
|
||||||
|
for i=0, TX_CHANNELS-1 do
|
||||||
|
DSM_ChannelInfo[i] = {[0]= 0x00, CH_TYPE.NONE} -- Initialize with no special function
|
||||||
|
end
|
||||||
|
|
||||||
|
local aircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
|
||||||
|
local wingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||||
|
local tailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||||
|
|
||||||
|
local thrCh = MENU_DATA[MEMU_VAR.CH_THR]
|
||||||
|
local lAilCh = MENU_DATA[MEMU_VAR.CH_L_AIL]
|
||||||
|
local rAilCh = MENU_DATA[MEMU_VAR.CH_R_AIL]
|
||||||
|
local lflapCh = MENU_DATA[MEMU_VAR.CH_L_FLP]
|
||||||
|
local rflapCh = MENU_DATA[MEMU_VAR.CH_R_FLP]
|
||||||
|
|
||||||
|
local lElevCh = MENU_DATA[MEMU_VAR.CH_L_ELE]
|
||||||
|
local rElevCh = MENU_DATA[MEMU_VAR.CH_R_ELE]
|
||||||
|
|
||||||
|
local lRudCh = MENU_DATA[MEMU_VAR.CH_L_RUD]
|
||||||
|
local rRudCh = MENU_DATA[MEMU_VAR.CH_R_RUD]
|
||||||
|
|
||||||
|
-- Channels in menu vars are Zero base, Channel info is 1 based
|
||||||
|
|
||||||
|
-- THR
|
||||||
|
if (thrCh~=nil) then DSM_ChannelInfo[thrCh][1]= CH_TYPE.THR end
|
||||||
|
|
||||||
|
-- AIL (Left and Right)
|
||||||
|
if (lAilCh~=nil) then DSM_ChannelInfo[lAilCh][1] = CH_TYPE.AIL end
|
||||||
|
if (rAilCh~=nil) then DSM_ChannelInfo[rAilCh][1] = CH_TYPE.AIL+CH_TYPE.SLAVE end
|
||||||
|
-- ELE (Left and Right)
|
||||||
|
if (lElevCh~=nil) then DSM_ChannelInfo[lElevCh][1] = CH_TYPE.ELE end
|
||||||
|
if (rElevCh~=nil) then DSM_ChannelInfo[rElevCh][1] = CH_TYPE.ELE+CH_TYPE.SLAVE end
|
||||||
|
-- RUD (Left and Right)
|
||||||
|
if (lRudCh~=nil) then DSM_ChannelInfo[lRudCh][1] = CH_TYPE.RUD end
|
||||||
|
if (rRudCh~=nil) then DSM_ChannelInfo[rRudCh][1] = CH_TYPE.RUD+CH_TYPE.SLAVE end
|
||||||
|
|
||||||
|
-- VTAIL: RUD + ELE
|
||||||
|
if (tailType==TAIL_TYPE.VTAIL_A) then
|
||||||
|
DSM_ChannelInfo[lElevCh][1] = CH_TYPE.RUD+CH_TYPE.ELE
|
||||||
|
DSM_ChannelInfo[rElevCh][1] = CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE
|
||||||
|
elseif (tailType==TAIL_TYPE.VTAIL_B) then
|
||||||
|
DSM_ChannelInfo[lElevCh][1] = CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE
|
||||||
|
DSM_ChannelInfo[rElevCh][1] = CH_TYPE.RUD+CH_TYPE.ELE
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TRAILERRON: 2-ELE + AIL
|
||||||
|
if (tailType==TAIL_TYPE.TRAILERON_A) then
|
||||||
|
DSM_ChannelInfo[lElevCh][1] = CH_TYPE.AIL+CH_TYPE.ELE
|
||||||
|
DSM_ChannelInfo[rElevCh][1] = CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE
|
||||||
|
elseif (tailType==TAIL_TYPE.TRAILERON_B) then
|
||||||
|
DSM_ChannelInfo[lElevCh][1] = CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE
|
||||||
|
DSM_ChannelInfo[rElevCh][1] = CH_TYPE.AIL+CH_TYPE.ELE
|
||||||
|
end
|
||||||
|
|
||||||
|
---- ELEVON : AIL + ELE
|
||||||
|
if (wingType==WING_TYPE.ELEVON_A) then
|
||||||
|
DSM_ChannelInfo[lAilCh][1] = CH_TYPE.AIL+CH_TYPE.ELE
|
||||||
|
DSM_ChannelInfo[rAilCh][1] = CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE
|
||||||
|
elseif (wingType==WING_TYPE.ELEVON_B) then
|
||||||
|
DSM_ChannelInfo[lAilCh][1] = CH_TYPE.AIL+CH_TYPE.ELE
|
||||||
|
DSM_ChannelInfo[rAilCh][1] = CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply Gyro Reverse as needed for each channel as long as it is used
|
||||||
|
for i=0, TX_CHANNELS-1 do
|
||||||
|
if (MENU_DATA[MEMU_VAR.PORT_BASE+i]==CH_MODE_TYPE.REVERSE and DSM_ChannelInfo[i][1]>0) then
|
||||||
|
DSM_ChannelInfo[i][0]=DSM_ChannelInfo[i][1]+CH_MIX_TYPE.NORM_REV -- ALL REVERSE is 0x70 for normal
|
||||||
|
DSM_ChannelInfo[i][1]=DSM_ChannelInfo[i][1]+CH_TYPE.REVERSE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- VTAIL: RUD + ELE
|
||||||
|
if (tailType==TAIL_TYPE.VTAIL_A) then
|
||||||
|
DSM_ChannelInfo[lElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[lElevCh][1])
|
||||||
|
DSM_ChannelInfo[rElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[rElevCh][1])
|
||||||
|
elseif (tailType==TAIL_TYPE.VTAIL_B) then
|
||||||
|
DSM_ChannelInfo[lElevCh][0] = ApplyTailMixB(DSM_ChannelInfo[lElevCh][1])
|
||||||
|
DSM_ChannelInfo[rElevCh][0] = ApplyTailMixB(DSM_ChannelInfo[rElevCh][1])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TRAILERRON: ELE + AIL
|
||||||
|
if (tailType==TAIL_TYPE.TRAILERON_A) then
|
||||||
|
DSM_ChannelInfo[lElevCh][1] = ApplyTailMixA(DSM_ChannelInfo[lElevCh][1])
|
||||||
|
DSM_ChannelInfo[rElevCh][1] = ApplyTailMixA(DSM_ChannelInfo[rElevCh][1])
|
||||||
|
elseif (tailType==TAIL_TYPE.TRAILERON_B) then
|
||||||
|
DSM_ChannelInfo[lElevCh][1] = ApplyTailMixB(DSM_ChannelInfo[lElevCh][1])
|
||||||
|
DSM_ChannelInfo[rElevCh][1] = ApplyTailMixB(DSM_ChannelInfo[rElevCh][1])
|
||||||
|
end
|
||||||
|
|
||||||
|
---- ELEVON : AIL + ELE
|
||||||
|
if (wingType==WING_TYPE.ELEVON_A) then
|
||||||
|
DSM_ChannelInfo[lAilCh][0] = ApplyWingMixA(DSM_ChannelInfo[lAilCh][1])
|
||||||
|
DSM_ChannelInfo[rAilCh][0] = ApplyWingMixA(DSM_ChannelInfo[rAilCh][1])
|
||||||
|
elseif (wingType==WING_TYPE.ELEVON_B) then
|
||||||
|
DSM_ChannelInfo[lAilCh][0] = ApplyWingMixB(DSM_ChannelInfo[lAilCh][1])
|
||||||
|
DSM_ChannelInfo[rAilCh][0] = ApplyWingMixB(DSM_ChannelInfo[rAilCh][1])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Show how it looks
|
||||||
|
for i=0, 9 do
|
||||||
|
local b1,b2 = DSM_ChannelInfo[i][0], DSM_ChannelInfo[i][1]
|
||||||
|
print(string.format("%s (%02X %02X) %s", MODEL.PORT_TEXT[i],
|
||||||
|
b1, b2, ModelLib.channelType2String(b1,b2)))
|
||||||
|
end
|
||||||
|
|
||||||
|
MODEL.AirWingTailDesc = string.format("Aircraft(%s) Wing(%s) Tail(%s)",aircraft_type_text[aircraftType],wing_type_text[wingType],tail_type_text[tailType])
|
||||||
|
end
|
||||||
|
|
||||||
|
function ModelLib.ST_PlaneWingInit(wingType)
|
||||||
|
print("Change Plane WingType:"..wing_type_text[wingType])
|
||||||
|
|
||||||
|
MENU_DATA[MEMU_VAR.WING_TYPE] = wingType
|
||||||
|
|
||||||
|
-- Clear all Wing Data
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_FLP] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_FLP] = nil
|
||||||
|
|
||||||
|
MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT1
|
||||||
|
|
||||||
|
-- Default Channel Assisgments for each Wing type
|
||||||
|
|
||||||
|
if (wingType==WING_TYPE.AIL_1) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
|
||||||
|
elseif (wingType==WING_TYPE.AIL_2) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||||
|
elseif (wingType==WING_TYPE.FLAPERON) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||||
|
elseif (wingType==WING_TYPE.AIL_1_FLP_1) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT6
|
||||||
|
elseif (wingType==WING_TYPE.AIL_2_FLP_1) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5
|
||||||
|
elseif (wingType==WING_TYPE.AIL_2_FLP_2) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_FLP] = PORT.PORT5
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT7
|
||||||
|
elseif (wingType==WING_TYPE.ELEVON_A) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT3
|
||||||
|
elseif (wingType==WING_TYPE.ELEVON_B) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT3
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||||
|
else -- Assume normal
|
||||||
|
print("ERROR: Invalid Wing Type")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
ModelLib.printChannelSummary()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ModelLib.ST_PlaneTailInit(tailType)
|
||||||
|
if (MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_A) then
|
||||||
|
tailType = TAIL_TYPE.RUD_1 -- Delta only have ruder
|
||||||
|
end
|
||||||
|
|
||||||
|
print("Change Plane Tail Type:"..tail_type_text[tailType])
|
||||||
|
|
||||||
|
-- Clear all data for Tail
|
||||||
|
MENU_DATA[MEMU_VAR.TAIL_TYPE] = tailType
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_ELE] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_RUD] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_RUD] = nil
|
||||||
|
|
||||||
|
-- Setup Channels for different Tail types
|
||||||
|
if (tailType == TAIL_TYPE.RUD_1) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||||
|
elseif (tailType == TAIL_TYPE.RUD_1_ELEV_1) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||||
|
elseif (tailType == TAIL_TYPE.RUD_1_ELEV_2) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||||
|
elseif (tailType == TAIL_TYPE.RUD_2_ELEV_1) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT5
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT4
|
||||||
|
elseif (tailType == TAIL_TYPE.RUD_2_ELEV_2) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT6
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT4
|
||||||
|
elseif (tailType == TAIL_TYPE.VTAIL_A) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT4
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||||
|
elseif (tailType == TAIL_TYPE.VTAIL_B) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT4
|
||||||
|
elseif (tailType == TAIL_TYPE.TRAILERON_A) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||||
|
elseif (tailType == TAIL_TYPE.TRAILERON_B) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||||
|
else -- Assume Normal
|
||||||
|
print("ERROR:invalid Tail Type")
|
||||||
|
end
|
||||||
|
|
||||||
|
ModelLib.printChannelSummary()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ModelLib.ST_GliderWingInit(wingType)
|
||||||
|
print("Change Glider WingType:"..wing_type_text[wingType])
|
||||||
|
|
||||||
|
MENU_DATA[MEMU_VAR.WING_TYPE] = wingType
|
||||||
|
|
||||||
|
-- Clear all Wing Data
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_FLP] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_FLP] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT6
|
||||||
|
|
||||||
|
-- Default Channel Assisgments for each Wing type
|
||||||
|
|
||||||
|
if (wingType==WING_TYPE.AIL_1) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
|
||||||
|
elseif (wingType==WING_TYPE.AIL_2) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||||
|
elseif (wingType==WING_TYPE.AIL_2_FLP_1) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5
|
||||||
|
elseif (wingType==WING_TYPE.AIL_2_FLP_2) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_FLP] = PORT.PORT6
|
||||||
|
MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT7
|
||||||
|
elseif (wingType==WING_TYPE.ELEVON_A) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||||
|
elseif (wingType==WING_TYPE.ELEVON_B) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT1
|
||||||
|
else -- Assume normal
|
||||||
|
print("ERROR: Invalid Wing Type")
|
||||||
|
end
|
||||||
|
|
||||||
|
ModelLib.printChannelSummary()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ModelLib.ST_GliderTailInit(tailType)
|
||||||
|
if (MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_A) then
|
||||||
|
tailType = TAIL_TYPE.RUD_1 -- Delta only have ruder
|
||||||
|
end
|
||||||
|
|
||||||
|
print("Change Glider Tail Type:"..tail_type_text[tailType])
|
||||||
|
|
||||||
|
-- Clear all data for Tail
|
||||||
|
MENU_DATA[MEMU_VAR.TAIL_TYPE] = tailType
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_ELE] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_RUD] = nil
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_RUD] = nil
|
||||||
|
|
||||||
|
-- Setup Channels for different Tail types
|
||||||
|
if (tailType == TAIL_TYPE.RUD_1) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||||
|
elseif (tailType == TAIL_TYPE.RUD_1_ELEV_1) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4
|
||||||
|
elseif (tailType == TAIL_TYPE.VTAIL_A) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT4
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3
|
||||||
|
elseif (tailType == TAIL_TYPE.VTAIL_B) then
|
||||||
|
MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3
|
||||||
|
MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT4
|
||||||
|
else -- Assume Normal
|
||||||
|
print("ERROR: Invalid Tail Type")
|
||||||
|
end
|
||||||
|
|
||||||
|
ModelLib.printChannelSummary()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ModelLib.ST_AircraftInit(aircraftType)
|
||||||
|
MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] = aircraftType
|
||||||
|
|
||||||
|
print("Change Aircraft:".. aircraft_type_text[aircraftType])
|
||||||
|
|
||||||
|
-- Setup Default Aircraft Wing/Tail
|
||||||
|
if (aircraftType==AIRCRAFT_TYPE.PLANE) then
|
||||||
|
ModelLib.ST_PlaneWingInit(WING_TYPE.AIL_1)
|
||||||
|
ModelLib.ST_PlaneTailInit(TAIL_TYPE.RUD_1_ELEV_1)
|
||||||
|
elseif (aircraftType==AIRCRAFT_TYPE.GLIDER) then
|
||||||
|
ModelLib.ST_GliderWingInit(WING_TYPE.AIL_1)
|
||||||
|
ModelLib.ST_GliderTailInit(TAIL_TYPE.RUD_1_ELEV_1)
|
||||||
|
else
|
||||||
|
ModelLib.ST_PlaneWingInit(WING_TYPE.AIL_1)
|
||||||
|
ModelLib.ST_PlaneTailInit(TAIL_TYPE.RUD_1_ELEV_1)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Setup Initial Default Data for the Menus
|
||||||
|
function ModelLib.ST_Default_Data()
|
||||||
|
print("Initializing Menu DATA")
|
||||||
|
ModelLib.ST_AircraftInit(AIRCRAFT_TYPE.PLANE)
|
||||||
|
|
||||||
|
print("Initializing Servo Reverse from TX output settings")
|
||||||
|
|
||||||
|
MENU_DATA[MEMU_VAR.PORT1_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT1].revert
|
||||||
|
MENU_DATA[MEMU_VAR.PORT2_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT2].revert
|
||||||
|
MENU_DATA[MEMU_VAR.PORT3_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT3].revert
|
||||||
|
MENU_DATA[MEMU_VAR.PORT4_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT4].revert
|
||||||
|
MENU_DATA[MEMU_VAR.PORT5_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT5].revert
|
||||||
|
MENU_DATA[MEMU_VAR.PORT6_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT6].revert
|
||||||
|
MENU_DATA[MEMU_VAR.PORT7_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT7].revert
|
||||||
|
MENU_DATA[MEMU_VAR.PORT8_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT8].revert
|
||||||
|
MENU_DATA[MEMU_VAR.PORT9_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT9].revert
|
||||||
|
MENU_DATA[MEMU_VAR.PORT10_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT10].revert
|
||||||
|
|
||||||
|
ModelLib.printServoReverseInfo()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
ModelLib.TX_CHANNELS = TX_CHANNELS
|
||||||
|
ModelLib.MODEL = MODEL
|
||||||
|
ModelLib.CH_TYPE = CH_TYPE
|
||||||
|
ModelLib.CH_MODE_TYPE = CH_MODE_TYPE
|
||||||
|
ModelLib.AIRCRAFT_TYPE = AIRCRAFT_TYPE
|
||||||
|
ModelLib.WING_TYPE = WING_TYPE
|
||||||
|
ModelLib.TAIL_TYPE = TAIL_TYPE
|
||||||
|
ModelLib.MENU_DATA = MENU_DATA
|
||||||
|
ModelLib.MEMU_VAR = MEMU_VAR
|
||||||
|
ModelLib.PORT = PORT
|
||||||
|
ModelLib.DATA_PATH = DATA_PATH
|
||||||
|
|
||||||
|
ModelLib.aircraft_type_text = aircraft_type_text
|
||||||
|
ModelLib.wing_type_text = wing_type_text
|
||||||
|
ModelLib.tail_type_text = tail_type_text
|
||||||
|
|
||||||
|
|
||||||
|
return ModelLib
|
||||||
|
|
421
Lua_scripts/DSMLIB/DsmSetupMenuLib.lua
Normal file
@ -0,0 +1,421 @@
|
|||||||
|
---- #########################################################################
|
||||||
|
---- # #
|
||||||
|
---- # Copyright (C) OpenTX #
|
||||||
|
-----# #
|
||||||
|
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||||
|
---- # #
|
||||||
|
---- # This program is free software; you can redistribute it and/or modify #
|
||||||
|
---- # it under the terms of the GNU General Public License version 2 as #
|
||||||
|
---- # published by the Free Software Foundation. #
|
||||||
|
---- # #
|
||||||
|
---- # This program is distributed in the hope that it will be useful #
|
||||||
|
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||||
|
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||||
|
---- # GNU General Public License for more details. #
|
||||||
|
---- # #
|
||||||
|
---- #########################################################################
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
-- This scrip does the airplane Setup similar to how a a Spektrum radio does
|
||||||
|
-- it. You can select the plane type, the Wing type, etc.
|
||||||
|
-- This settings are needed for ForwardProgramming to send the TX aircraft
|
||||||
|
-- configuration to the RX when in Initial Setup
|
||||||
|
-- Author: Francisco Arzu
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON = ... -- Get DebugON from parameters
|
||||||
|
local SETUP_LIB_VERSION = "0.55"
|
||||||
|
|
||||||
|
local DATA_PATH = modelLib.DATA_PATH
|
||||||
|
|
||||||
|
local PHASE = menuLib.PHASE
|
||||||
|
local LINE_TYPE = menuLib.LINE_TYPE
|
||||||
|
|
||||||
|
local MODEL = modelLib.MODEL
|
||||||
|
|
||||||
|
local AIRCRAFT_TYPE = modelLib.AIRCRAFT_TYPE
|
||||||
|
local WING_TYPE = modelLib.WING_TYPE
|
||||||
|
local TAIL_TYPE = modelLib.TAIL_TYPE
|
||||||
|
local CH_MODE_TYPE = modelLib.CH_MODE_TYPE
|
||||||
|
local PORT = modelLib.PORT
|
||||||
|
local MEMU_VAR = modelLib.MEMU_VAR
|
||||||
|
local MENU_DATA = modelLib.MENU_DATA
|
||||||
|
|
||||||
|
local SetupLib = {}
|
||||||
|
|
||||||
|
local lastGoodMenu=0
|
||||||
|
|
||||||
|
------------------- Model Setup Helper functions ----------------------
|
||||||
|
local currAircraftType = -1 -- Current AircraftType selected, and to detect change
|
||||||
|
local currTailType = -1 -- Current WingType selected, and to detect change
|
||||||
|
local currWingType = -1 -- Current TailType selected, and to detect change
|
||||||
|
|
||||||
|
local menuDataChanged = false -- Flag to notify if any data has changed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Creates the menus to Render with the GUI
|
||||||
|
local function ST_LoadMenu(menuId)
|
||||||
|
local ctx = menuLib.DSM_Context
|
||||||
|
|
||||||
|
local function formatTXRevert(port)
|
||||||
|
if (MODEL.modelOutputChannel[port].revert==0) then
|
||||||
|
return " (Tx:"..menuLib.Get_List_Text(300+CH_MODE_TYPE.NORMAL)..")"
|
||||||
|
else
|
||||||
|
return " (Tx:"..menuLib.Get_List_Text(300+CH_MODE_TYPE.REVERSE)..")"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
menuLib.clearMenuLines()
|
||||||
|
|
||||||
|
|
||||||
|
if (menuId==0x1000) then -- MAIN MENU
|
||||||
|
ctx.Menu = { MenuId = 0x1000, Text = "Save-Exit ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0xFFF9, TextId=0 }
|
||||||
|
|
||||||
|
if (true) then
|
||||||
|
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, Text="Save Changes", TextId = 0, ValId = 0x1005 }
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Discard Changes", TextId = 0, ValId = 0x1006 }
|
||||||
|
ctx.SelLine = 4
|
||||||
|
end
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x1001) then -- MODEL SETUP
|
||||||
|
local backId = 0xFFF9 -- No changes, just exit
|
||||||
|
local title = "Model Setup ("..MODEL.modelName..")"
|
||||||
|
if (menuDataChanged) then
|
||||||
|
backId = 0x1000 -- Go to Save menu
|
||||||
|
title = title.." *"
|
||||||
|
end
|
||||||
|
ctx.Menu = { MenuId = 0x1001, Text = title, PrevId = 0, NextId = 0, BackId = backId, TextId=0 }
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, Text = "Aircraft Type Setup", ValId = 0x1010,TextId=0 }
|
||||||
|
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, Text = "Wing & Tail Channels ", ValId = 0x1020, TextId=0 }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text = "Gyro Channel Reverse", ValId = 0x1030, TextId=0 }
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text = "WARNING: Changing of Aircraft or Wing will", ValId = 0x1001, TextId=0 }
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text = "delete previous Channel/Port assigments.", ValId = 0x1001, TextId=0 }
|
||||||
|
|
||||||
|
ctx.SelLine = 0
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x1005) then
|
||||||
|
modelLib.printChannelSummary()
|
||||||
|
modelLib.ST_SaveFileData()
|
||||||
|
menuDataChanged = false
|
||||||
|
|
||||||
|
|
||||||
|
local msg1 = "Data saved to: "
|
||||||
|
local msg2 = " "..DATA_PATH.."/"..modelLib.hashName(MODEL.modelName)..".txt"
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x1005, Text = "Config Saved", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, Text=msg1, TextId = 0, ValId = 0x1005 }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text=msg2, TextId = 0, ValId = 0x1005 }
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 }
|
||||||
|
ctx.SelLine = 6
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x1006) then
|
||||||
|
modelLib.ST_LoadFileData()
|
||||||
|
menuDataChanged = false
|
||||||
|
currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
|
||||||
|
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||||
|
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||||
|
|
||||||
|
local msg1 = "Data restored from: "
|
||||||
|
local msg2 = " "..DATA_PATH.."/"..modelLib.hashName(MODEL.modelName)..".txt"
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x1006, Text = "Discart Changes", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, Text=msg1, TextId = 0, ValId = 0x1006 }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text=msg2, TextId = 0, ValId = 0x1006 }
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 }
|
||||||
|
ctx.SelLine = 6
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x1010) then
|
||||||
|
ctx.Menu = { MenuId = 0x1010, Text = "Aircraft Type", PrevId = 0, NextId = 0x1011, BackId = 0x1001, TextId=0 }
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Aircraft Type", TextId = 0, ValId = MEMU_VAR.AIRCRAFT_TYPE, Min=50, Max=53, Def=50, Val=MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] }
|
||||||
|
ctx.SelLine = 5
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x1011) then
|
||||||
|
ctx.Menu = { MenuId = 0x1011, Text = "Model Type:"..modelLib.aircraft_type_text[currAircraftType], PrevId = 0, NextId = 0x1020, BackId = 0x1010, TextId=0 }
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Wing Type", TextId = 0, ValId = MEMU_VAR.WING_TYPE, Min=100, Max=107, Def=100, Val=MENU_DATA[MEMU_VAR.WING_TYPE] }
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Tail Type", TextId = 0, ValId = MEMU_VAR.TAIL_TYPE, Min=200, Max=208, Def=200, Val=MENU_DATA[MEMU_VAR.TAIL_TYPE] }
|
||||||
|
ctx.SelLine = 5
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x1020) then
|
||||||
|
------ WING SETUP -------
|
||||||
|
local thr = MENU_DATA[MEMU_VAR.CH_THR]
|
||||||
|
local leftAil = MENU_DATA[MEMU_VAR.CH_L_AIL]
|
||||||
|
local rightAil = MENU_DATA[MEMU_VAR.CH_R_AIL]
|
||||||
|
local leftFlap = MENU_DATA[MEMU_VAR.CH_L_FLP]
|
||||||
|
local rightFlap = MENU_DATA[MEMU_VAR.CH_R_FLP]
|
||||||
|
|
||||||
|
local thrText = "Thr"
|
||||||
|
local leftAilText = "Left Aileron"
|
||||||
|
local rightAilText = "Right Aileron"
|
||||||
|
local leftFlapText = "Left Flap"
|
||||||
|
local rightFlapText = "Right Flap"
|
||||||
|
|
||||||
|
if (rightAil==nil) then leftAilText = "Aileron" end
|
||||||
|
if (rightFlap==nil) then leftFlapText = "Flap" end
|
||||||
|
|
||||||
|
local title = modelLib.aircraft_type_text[currAircraftType].." Wing:"..modelLib.wing_type_text[currWingType]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x1020, Text = title, PrevId = 0, NextId = 0x1021, BackId = 0x1011, TextId=0 }
|
||||||
|
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=thrText, TextId = 0, ValId = MEMU_VAR.CH_THR, Min=0, Max=9, Def=0, Val= thr }
|
||||||
|
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftAilText, TextId = 0, ValId = MEMU_VAR.CH_L_AIL, Min=0, Max=9, Def=0, Val= leftAil }
|
||||||
|
|
||||||
|
if (rightAil~=nil) then
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightAilText, TextId = 0, ValId = MEMU_VAR.CH_R_AIL, Min=0, Max=9, Def=0, Val= rightAil }
|
||||||
|
end
|
||||||
|
|
||||||
|
if (leftFlap~=nil) then
|
||||||
|
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftFlapText, TextId = 0, ValId = MEMU_VAR.CH_L_FLP, Min=0, Max=9, Def=0, Val= leftFlap }
|
||||||
|
end
|
||||||
|
if (rightFlap~=nil) then
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightFlapText, TextId = 0, ValId = MEMU_VAR.CH_R_FLP, Min=0, Max=9, Def=0, Val= rightFlap }
|
||||||
|
end
|
||||||
|
|
||||||
|
ctx.SelLine = 1
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
|
||||||
|
elseif (menuId==0x1021) then
|
||||||
|
------ TAIL SETUP -------
|
||||||
|
local leftRud = MENU_DATA[MEMU_VAR.CH_L_RUD]
|
||||||
|
local rightRud = MENU_DATA[MEMU_VAR.CH_R_RUD]
|
||||||
|
local leftEle = MENU_DATA[MEMU_VAR.CH_L_ELE]
|
||||||
|
local rightEle = MENU_DATA[MEMU_VAR.CH_R_ELE]
|
||||||
|
|
||||||
|
local leftRudText = "Left Rudder"
|
||||||
|
local rightRudText = "Right Rudder"
|
||||||
|
|
||||||
|
local leftElvText = "Left Elevator"
|
||||||
|
local rightElvText = "Right Elevator"
|
||||||
|
|
||||||
|
if (rightRud==nil) then leftRudText = "Rudder" end
|
||||||
|
if (rightEle==nil) then leftElvText = "Elevator" end
|
||||||
|
|
||||||
|
local title = modelLib.aircraft_type_text[currAircraftType].." Tail:"..modelLib.tail_type_text[currTailType]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x1021, Text = title, PrevId = 0, NextId = 0x1001, BackId = 0x1020, TextId=0 }
|
||||||
|
if (leftRud~=nil) then
|
||||||
|
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftRudText, TextId = 0, ValId = MEMU_VAR.CH_L_RUD, Min=0, Max=9, Def=0, Val= leftRud}
|
||||||
|
end
|
||||||
|
|
||||||
|
if (rightRud~=nil) then
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightRudText, TextId = 0, ValId = MEMU_VAR.CH_R_RUD, Min=0, Max=9, Def=0, Val=rightRud }
|
||||||
|
end
|
||||||
|
|
||||||
|
if (leftEle~=nil) then
|
||||||
|
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftElvText, TextId = 0, ValId = MEMU_VAR.CH_L_ELE, Min=0, Max=9, Def=0, Val=leftEle }
|
||||||
|
end
|
||||||
|
|
||||||
|
if (rightEle~=nil) then
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightElvText, TextId = 0, ValId = MEMU_VAR.CH_R_ELE, Min=0, Max=9, Def=0, Val=rightEle }
|
||||||
|
end
|
||||||
|
|
||||||
|
ctx.SelLine = 1
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
|
||||||
|
elseif (menuId==0x1030) then
|
||||||
|
modelLib.printChannelSummary()
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x1030, Text = "Gyro Channel Reverse (Port 1-5)", PrevId = 0, NextId = 0x1031, BackId = 0x1001, TextId=0 }
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT1], TextId = 0, ValId = MEMU_VAR.PORT1_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT1_MODE], Format = formatTXRevert(PORT.PORT1) }
|
||||||
|
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT2], TextId = 0, ValId = MEMU_VAR.PORT2_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT2_MODE], Format = formatTXRevert(PORT.PORT2) }
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT3], TextId = 0, ValId = MEMU_VAR.PORT3_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT3_MODE], Format = formatTXRevert(PORT.PORT3) }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT4], TextId = 0, ValId = MEMU_VAR.PORT4_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT4_MODE], Format = formatTXRevert(PORT.PORT4) }
|
||||||
|
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT5], TextId = 0, ValId = MEMU_VAR.PORT5_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT5_MODE], Format = formatTXRevert(PORT.PORT5) }
|
||||||
|
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Only Thr/Ail/Rud/Ele. This affects AS3X/SAFE reaction dir./b", TextId = 0, ValId = 0x1030 }
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Any changes, use RX 'Relearn Servo Settings'/b", TextId = 0, ValId = 0x1030 }
|
||||||
|
|
||||||
|
ctx.SelLine = 0
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x1031) then
|
||||||
|
modelLib.printChannelSummary()
|
||||||
|
ctx.Menu = { MenuId = 0x1031, Text = "Gyro Channel Reverse (Port 6-10)", PrevId = 0x1030, NextId = 0, BackId = 0x1001, TextId=0 }
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT6], TextId = 0, ValId = MEMU_VAR.PORT6_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT6_MODE], Format = formatTXRevert(PORT.PORT6) }
|
||||||
|
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT7], TextId = 0, ValId = MEMU_VAR.PORT7_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT7_MODE], Format = formatTXRevert(PORT.PORT7) }
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT8], TextId = 0, ValId = MEMU_VAR.PORT8_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT8_MODE], Format = formatTXRevert(PORT.PORT8) }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT9], TextId = 0, ValId = MEMU_VAR.PORT9_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT9_MODE], Format = formatTXRevert(PORT.PORT9) }
|
||||||
|
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT10], TextId = 0, ValId = MEMU_VAR.PORT10_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT10_MODE], Format = formatTXRevert(PORT.PORT10) }
|
||||||
|
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Only Thr/Ail/Rud/Ele. This affects AS3X/SAFE reaction dir./b", TextId = 0, ValId = 0x1031 }
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Any changes, use RX 'Relearn Servo Settings'/b", TextId = 0, ValId = 0x1031 }
|
||||||
|
|
||||||
|
ctx.SelLine = 0
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
else
|
||||||
|
print("NOT IMPLEMENTED")
|
||||||
|
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
|
||||||
|
ctx.SelLine = menuLib.BACK_BUTTON
|
||||||
|
end
|
||||||
|
|
||||||
|
menuLib.PostProcessMenu()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ST_SendReceive
|
||||||
|
-- Main state machine for the Setup menu
|
||||||
|
|
||||||
|
local function ST_SendReceive()
|
||||||
|
local ctx = menuLib.DSM_Context
|
||||||
|
--if (DEBUG_ON>1) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||||
|
|
||||||
|
if ctx.Phase == PHASE.RX_VERSION then -- request RX version
|
||||||
|
ctx.RX.Name = "MODEL SETUP"
|
||||||
|
ctx.RX.Version = SETUP_LIB_VERSION
|
||||||
|
ctx.Phase = PHASE.MENU_TITLE
|
||||||
|
ctx.Menu.MenuId = 0x01001
|
||||||
|
|
||||||
|
ctx.Refresh_Display = true
|
||||||
|
|
||||||
|
|
||||||
|
elseif ctx.Phase == PHASE.WAIT_CMD then
|
||||||
|
|
||||||
|
elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title
|
||||||
|
ST_LoadMenu(ctx.Menu.MenuId)
|
||||||
|
ctx.Phase = PHASE.WAIT_CMD
|
||||||
|
ctx.Refresh_Display = true
|
||||||
|
|
||||||
|
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
|
||||||
|
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||||
|
|
||||||
|
if (MENU_DATA[line.ValId] ~= line.Val ) then
|
||||||
|
MENU_DATA[line.ValId] = line.Val
|
||||||
|
print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val))
|
||||||
|
menuDataChanged=true
|
||||||
|
end
|
||||||
|
|
||||||
|
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
|
||||||
|
|
||||||
|
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
|
||||||
|
local line = ctx.MenuLines[ctx.SelLine]
|
||||||
|
|
||||||
|
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
|
||||||
|
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||||
|
|
||||||
|
-- Update the menu data from the line
|
||||||
|
if (MENU_DATA[line.ValId] ~= line.Val ) then
|
||||||
|
MENU_DATA[line.ValId] = line.Val
|
||||||
|
print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val))
|
||||||
|
menuDataChanged=true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Did the aircraft type change?
|
||||||
|
if (currAircraftType ~= MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]) then
|
||||||
|
currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
|
||||||
|
modelLib.ST_AircraftInit(currAircraftType)
|
||||||
|
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||||
|
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Did the Wing type change?
|
||||||
|
if (currWingType ~= MENU_DATA[MEMU_VAR.WING_TYPE]) then
|
||||||
|
if (currAircraftType==AIRCRAFT_TYPE.GLIDER) then
|
||||||
|
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||||
|
modelLib.ST_GliderWingInit(currWingType)
|
||||||
|
else
|
||||||
|
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||||
|
modelLib.ST_PlaneWingInit(currWingType)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- DELTA has only RUDER
|
||||||
|
if ((currWingType==WING_TYPE.ELEVON_A or currWingType==WING_TYPE.ELEVON_B) and TAIL_TYPE~=TAIL_TYPE.RUD_1) then
|
||||||
|
currTailType = TAIL_TYPE.RUD_1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Did the tail changed?
|
||||||
|
if (currTailType ~= MENU_DATA[MEMU_VAR.TAIL_TYPE]) then
|
||||||
|
if (currAircraftType==AIRCRAFT_TYPE.GLIDER) then
|
||||||
|
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||||
|
modelLib.ST_GliderTailInit(currTailType)
|
||||||
|
else
|
||||||
|
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||||
|
modelLib.ST_PlaneTailInit(currTailType)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ctx.Phase = PHASE.WAIT_CMD
|
||||||
|
elseif ctx.Phase == PHASE.EXIT then
|
||||||
|
ctx.Phase=PHASE.EXIT_DONE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Inital List and Image Text for this menus
|
||||||
|
local function ST_Init_Text(rxId)
|
||||||
|
menuLib.clearAllText()
|
||||||
|
|
||||||
|
local List_Values = menuLib.List_Values
|
||||||
|
local List_Text = menuLib.List_Text
|
||||||
|
local Text = menuLib.Text
|
||||||
|
local List_Text_Img = menuLib.List_Text_Img
|
||||||
|
|
||||||
|
-- Channel Names use the Port Text Retrived from OTX/ETX
|
||||||
|
for i = 0, 9 do List_Text[i] = MODEL.PORT_TEXT[i] end
|
||||||
|
|
||||||
|
-- Aircraft Type
|
||||||
|
List_Text[50+AIRCRAFT_TYPE.PLANE] = "Airplane"; --List_Text_Img[50+AIRCRAFT_TYPE.PLANE] = "at_plane.png|Airplane"
|
||||||
|
List_Text[50+AIRCRAFT_TYPE.GLIDER] = "Glider (Partial work)"; --List_Text_Img[50+AIRCRAFT_TYPE.GLIDER] = "at_glider.png|Glider"
|
||||||
|
List_Text[50+AIRCRAFT_TYPE.HELI] = "Helicopter (Not done)"; --List_Text_Img[50+AIRCRAFT_TYPE.HELI] = "at_heli.png|Helicopter"
|
||||||
|
List_Text[50+AIRCRAFT_TYPE.DRONE] = "Drone (not done)"; --List_Text_Img[50+AIRCRAFT_TYPE.DRONE] = "at_drone.png|Drone"
|
||||||
|
|
||||||
|
-- Wing Types
|
||||||
|
List_Text[100+WING_TYPE.AIL_1] = "Single Ail"; List_Text_Img[100+WING_TYPE.AIL_1] = "wt_1ail.png|Single Aileron"
|
||||||
|
List_Text[100+WING_TYPE.AIL_2] = "Dual Ail"; List_Text_Img[100+WING_TYPE.AIL_2] = "wt_2ail.png|Dual Aileron"
|
||||||
|
List_Text[100+WING_TYPE.FLAPERON] = "Flaperon"; List_Text_Img[100+WING_TYPE.FLAPERON] = "wt_flaperon.png|Flaperon"
|
||||||
|
List_Text[100+WING_TYPE.AIL_1_FLP_1] = "Ail + Flap"; List_Text_Img[100+WING_TYPE.AIL_1_FLP_1] = "wt_1ail_1flp.png|Aileron + Flap"
|
||||||
|
List_Text[100+WING_TYPE.AIL_2_FLP_1] = "Dual Ail + Flap"; List_Text_Img[100+WING_TYPE.AIL_2_FLP_1] = "wt_2ail_1flp.png|Dual Aileron + Flap"
|
||||||
|
List_Text[100+WING_TYPE.AIL_2_FLP_2] = "Dual Ail + Dual Flap"; List_Text_Img[100+WING_TYPE.AIL_2_FLP_2] = "wt_2ail_2flp.png|Dual Aileron + Dual Flap"
|
||||||
|
List_Text[100+WING_TYPE.ELEVON_A] = "Delta/Elevon A"; List_Text_Img[100+WING_TYPE.ELEVON_A] = "wt_elevon.png|Delta/Elevon A"
|
||||||
|
List_Text[100+WING_TYPE.ELEVON_B] = "Delta/Elevon B"; List_Text_Img[100+WING_TYPE.ELEVON_B] = "wt_elevon.png|Delta/Elevon B"
|
||||||
|
|
||||||
|
-- Tail Types
|
||||||
|
List_Text[200+TAIL_TYPE.RUD_1] = "Rudder Only"; List_Text_Img[200+TAIL_TYPE.RUD_1] = "tt_1rud.png|Rudder Only"
|
||||||
|
List_Text[200+TAIL_TYPE.RUD_1_ELEV_1] = "Rud + Ele"; List_Text_Img[200+TAIL_TYPE.RUD_1_ELEV_1] = "tt_1rud_1ele.png|Tail Normal"
|
||||||
|
List_Text[200+TAIL_TYPE.RUD_1_ELEV_2] = "Rud + Dual Ele"; List_Text_Img[200+TAIL_TYPE.RUD_1_ELEV_2] = "tt_1rud_2ele.png|Rud + Dual Elev"
|
||||||
|
List_Text[200+TAIL_TYPE.RUD_2_ELEV_1] = "Dual Rud + Ele"; List_Text_Img[200+TAIL_TYPE.RUD_2_ELEV_1] = "tt_2rud_1ele.png|Dual Rud + Elev"
|
||||||
|
List_Text[200+TAIL_TYPE.RUD_2_ELEV_2] = "Dual Rud + Dual Ele"; List_Text_Img[200+TAIL_TYPE.RUD_2_ELEV_2] = "tt_2rud_2ele.png|Dual Rud + Dual Elev"
|
||||||
|
List_Text[200+TAIL_TYPE.VTAIL_A] = "V-Tail A"; List_Text_Img[200+TAIL_TYPE.VTAIL_A] = "tt_vtail.png|V-Tail A"
|
||||||
|
List_Text[200+TAIL_TYPE.VTAIL_B] = "V-Tail B"; List_Text_Img[200+TAIL_TYPE.VTAIL_B] = "tt_vtail.png|V-Tail B"
|
||||||
|
List_Text[200+TAIL_TYPE.TRAILERON_A] = "Traileron A"; List_Text_Img[200+TAIL_TYPE.TRAILERON_A] = "tt_traileron.png|Traileron A"
|
||||||
|
List_Text[200+TAIL_TYPE.TRAILERON_B] = "Traileron B"; List_Text_Img[200+TAIL_TYPE.TRAILERON_B] = "tt_traileron.png|Traileron B"
|
||||||
|
|
||||||
|
-- Servo Reverse
|
||||||
|
if (LCD_W > 128) then
|
||||||
|
List_Text[300+CH_MODE_TYPE.NORMAL] = "Normal "
|
||||||
|
List_Text[300+CH_MODE_TYPE.REVERSE] = "Reverse"
|
||||||
|
else
|
||||||
|
List_Text[300+CH_MODE_TYPE.NORMAL] = "Nor"
|
||||||
|
List_Text[300+CH_MODE_TYPE.REVERSE] = "Rev"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initial Setup
|
||||||
|
local function ST_Init()
|
||||||
|
-- Initialize text (use RX_ID 0)
|
||||||
|
ST_Init_Text(0)
|
||||||
|
|
||||||
|
-- Setup default Data, and load a file if exist
|
||||||
|
modelLib.ST_Default_Data()
|
||||||
|
if (modelLib.ST_LoadFileData()==0) then -- Did not load a file
|
||||||
|
modelLib.ST_SaveFileData() -- Save Defaults
|
||||||
|
end
|
||||||
|
menuDataChanged = false
|
||||||
|
currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]
|
||||||
|
currWingType = MENU_DATA[MEMU_VAR.WING_TYPE]
|
||||||
|
currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE]
|
||||||
|
|
||||||
|
local ctx = menuLib.DSM_Context
|
||||||
|
ctx.Phase = PHASE.RX_VERSION
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ST_Done()
|
||||||
|
local ctx = menuLib.DSM_Context
|
||||||
|
ctx.Phase = PHASE.EXIT_DONE
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return { init=ST_Init, run=ST_SendReceive, done=ST_Done }
|
@ -25,13 +25,12 @@
|
|||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
local DEBUG_ON = ... -- Get DebugON from parameters
|
local Log, menuLib, modelLib, DEBUG_ON = ... -- Get DebugON from parameters
|
||||||
|
local SIM_LIB_VERSION = "0.55"
|
||||||
|
local MSG_FILE = "/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt"
|
||||||
|
|
||||||
local dsmLib = assert(loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua"))(DEBUG_ON)
|
local PHASE = menuLib.PHASE
|
||||||
|
local LINE_TYPE = menuLib.LINE_TYPE
|
||||||
local PHASE = dsmLib.PHASE
|
|
||||||
local LINE_TYPE = dsmLib.LINE_TYPE
|
|
||||||
local Get_Text = dsmLib.Get_Text
|
|
||||||
|
|
||||||
local SimLib = {}
|
local SimLib = {}
|
||||||
|
|
||||||
@ -39,46 +38,12 @@ local lastGoodMenu=0
|
|||||||
local RX_loadMenu = nil
|
local RX_loadMenu = nil
|
||||||
local RX_Initialized = true
|
local RX_Initialized = true
|
||||||
|
|
||||||
|
local IS_EDGETX = false
|
||||||
|
|
||||||
local function SIM_StartConnection()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local function SIM_ReleaseConnection()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function clearMenuLines()
|
|
||||||
local ctx = dsmLib.DSM_Context
|
|
||||||
for i = 0, dsmLib.MAX_MENU_LINES do -- clear menu
|
|
||||||
ctx.MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0, Text = "", TextId = 0, ValId = 0, Min=0, Max=0, Def=0, TextStart=0, Val=nil }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function PostProcessMenu()
|
|
||||||
local ctx = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
if (ctx.Menu.Text==nil) then
|
|
||||||
ctx.Menu.Text = dsmLib.Get_Text(ctx.Menu.TextId)
|
|
||||||
dsmLib.MenuPostProcessing (ctx.Menu)
|
|
||||||
end
|
|
||||||
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("SIM RESPONSE Menu: %s\n", dsmLib.menu2String(ctx.Menu)) end
|
|
||||||
|
|
||||||
for i = 0, dsmLib.MAX_MENU_LINES do -- clear menu
|
|
||||||
local line = ctx.MenuLines[i]
|
|
||||||
if (line.Type~=0) then
|
|
||||||
line.MenuId = ctx.Menu.MenuId
|
|
||||||
line.lineNum = i
|
|
||||||
dsmLib.MenuLinePostProcessing(line) -- Do the same post processing as if they come from the RX
|
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("SIM RESPONSE MenuLine: %s\n", dsmLib.menuLine2String(line)) end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function AR631_loadMenu(menuId)
|
local function AR631_loadMenu(menuId)
|
||||||
clearMenuLines()
|
menuLib.clearMenuLines()
|
||||||
local ctx = dsmLib.DSM_Context
|
local ctx = menuLib.DSM_Context
|
||||||
|
|
||||||
if (menuId==0x1000) then
|
if (menuId==0x1000) then
|
||||||
--M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"]
|
--M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"]
|
||||||
@ -665,7 +630,7 @@ local function AR631_loadMenu(menuId)
|
|||||||
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0102, ValId = 0x104F }
|
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0102, ValId = 0x104F }
|
||||||
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0103, ValId = 0x104F }
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0103, ValId = 0x104F }
|
||||||
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x0104, ValId = 0x104F }
|
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x0104, ValId = 0x104F }
|
||||||
ctx.SelLine = dsmLib.NEXT_BUTTON
|
ctx.SelLine = menuLib.NEXT_BUTTON
|
||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
elseif (menuId==0x1050) then
|
elseif (menuId==0x1050) then
|
||||||
|
|
||||||
@ -681,7 +646,7 @@ local function AR631_loadMenu(menuId)
|
|||||||
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0108, ValId = 0x1050 }
|
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0108, ValId = 0x1050 }
|
||||||
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0109, ValId = 0x1050 }
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0109, ValId = 0x1050 }
|
||||||
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x010A, ValId = 0x1050 }
|
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x010A, ValId = 0x1050 }
|
||||||
ctx.SelLine = dsmLib.NEXT_BUTTON
|
ctx.SelLine = menuLib.NEXT_BUTTON
|
||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
elseif (menuId==0x1051) then
|
elseif (menuId==0x1051) then
|
||||||
--M[Id=0x1051 P=0x0 N=0x0 B=0x1010 Text="First Time Setup"]
|
--M[Id=0x1051 P=0x0 N=0x0 B=0x1010 Text="First Time Setup"]
|
||||||
@ -1024,34 +989,43 @@ local function AR631_loadMenu(menuId)
|
|||||||
elseif (menuId==0x0001) then
|
elseif (menuId==0x0001) then
|
||||||
-- Save Settings and Reboot
|
-- Save Settings and Reboot
|
||||||
ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 }
|
ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 }
|
||||||
ctx.SelLine = dsmLib.BACK_BUTTON
|
ctx.SelLine = menuLib.BACK_BUTTON
|
||||||
|
|
||||||
else
|
else
|
||||||
print("NOT IMPLEMENTED")
|
print("NOT IMPLEMENTED")
|
||||||
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
|
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
|
||||||
ctx.SelLine = dsmLib.BACK_BUTTON
|
ctx.SelLine = menuLib.BACK_BUTTON
|
||||||
end
|
end
|
||||||
|
|
||||||
PostProcessMenu()
|
menuLib.PostProcessMenu()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function FC6250HX_loadMenu(menuId)
|
local function FC6250HX_loadMenu(menuId)
|
||||||
clearMenuLines()
|
menuLib.clearMenuLines()
|
||||||
local ctx = dsmLib.DSM_Context
|
local ctx = menuLib.DSM_Context
|
||||||
|
|
||||||
if (menuId==0x1000) then
|
if (menuId==0x1000) then
|
||||||
--M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"[0x4B]]
|
--M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"[0x4B]]
|
||||||
--L[#0 T=M VId=0x1100 Text="Swashplate"[0xD3] MId=0x1000 ]
|
--L[#0 T=M VId=0x1100 Text="Swashplate"[0xD3] MId=0x1000 ]
|
||||||
--L[#1 T=M VId=0x1200 [0->0,2] Text="Tail rotor"[0xDD] MId=0x1000 ]
|
--L[#1 T=M VId=0x1200 [0->0,2] Text="Tail rotor"[0xDD] MId=0x1000 ]
|
||||||
--L[#2 T=M VId=0x1400 [0->0,2] Text="SAFE"[0xDA] MId=0x1000 ]
|
|
||||||
--L[#4 T=M VId=0x1300 [0->0,2] Text="Setup"[0xDE] MId=0x1000 ]
|
--L[#2 T=M VId=0x1280 Text="Governor"[0xF2]
|
||||||
|
|
||||||
|
--L[#3 T=M VId=0x1400 [0->0,2] Text="SAFE"[0xDA] MId=0x1000 ]
|
||||||
|
--L[#5 T=M VId=0x1300 [0->0,2] Text="Setup"[0xDE] MId=0x1000 ]
|
||||||
--L[#6 T=M VId=0x1700 [0->0,2] Text="System Setup"[0x86] MId=0x1000 ]
|
--L[#6 T=M VId=0x1700 [0->0,2] Text="System Setup"[0x86] MId=0x1000 ]
|
||||||
|
|
||||||
ctx.Menu = { MenuId = 0x1000, TextId = 0x004B, PrevId = 0, NextId = 0, BackId = 0 }
|
ctx.Menu = { MenuId = 0x1000, TextId = 0x004B, PrevId = 0, NextId = 0, BackId = 0 }
|
||||||
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xD3, ValId = 0x1100 }
|
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xD3, ValId = 0x1100 }
|
||||||
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xDD, ValId = 0x1200 }
|
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xDD, ValId = 0x1200 }
|
||||||
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xDA, ValId = 0x1400 }
|
|
||||||
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0xDE, ValId = 0x1300 }
|
if (not RX_Initialized) then
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xF2, ValId = 0x1280 }
|
||||||
|
end
|
||||||
|
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xDA, ValId = 0x1400 }
|
||||||
|
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0xDE, ValId = 0x1300 }
|
||||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x86, ValId = 0x1700 }
|
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x86, ValId = 0x1700 }
|
||||||
ctx.SelLine = 0
|
ctx.SelLine = 0
|
||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
@ -1129,12 +1103,34 @@ local function FC6250HX_loadMenu(menuId)
|
|||||||
ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x72, ValId = 0x1216, Min=0, Max=255, Def=95, Val=95 }
|
ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x72, ValId = 0x1216, Min=0, Max=255, Def=95, Val=95 }
|
||||||
ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x73, ValId = 0x1217, Min=0, Max=255, Def=45, Val=45 }
|
ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x73, ValId = 0x1217, Min=0, Max=255, Def=45, Val=45 }
|
||||||
|
|
||||||
|
ctx.SelLine = 0
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x1280) then -- TODO
|
||||||
|
--M[Id=0x1200 P=0x0 N=0x0 B=0x1000 Text="Governor"[0xF0]]
|
||||||
|
--L[#4 T=V_i8 VId=0x1215 Text="Proportional"[0x71] Val=100 [0->255,100] MId=0x1200 ]
|
||||||
|
--L[#5 T=V_i8 VId=0x1216 Text="Integral"[0x72] Val=95 [0->255,95] MId=0x1200 ]
|
||||||
|
--L[#3 T=V_nc VId=0x1214 Text=" FLIGHT MODE"[0x8000] Val=1 [0->5,0] MId=0x1200 ]
|
||||||
|
--L[#6 T=V_i8 VId=0x1217 Text="Head Speed"[0x26B] Val=45 [0->255,45] MId=0x1200 ]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x1280, TextId = 0xDD, PrevId = 0, NextId = 0, BackId = 0x1000 }
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x92, ValId = 0x1212, Min=5, Max=200, Def=25, Val=25 }
|
||||||
|
ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xD8, ValId = 0x1213, Min=5, Max=200, Def=26, Val=100 }
|
||||||
|
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8000, ValId = 0x1214, Min=0, Max=5, Def=0, Val=1 }
|
||||||
|
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x71, ValId = 0x1215, Min=0, Max=255, Def=100, Val=100 }
|
||||||
|
|
||||||
|
|
||||||
ctx.SelLine = 0
|
ctx.SelLine = 0
|
||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
elseif (menuId==0x1300) then
|
elseif (menuId==0x1300) then
|
||||||
--M[Id=0x1300 P=0x0 N=0x0 B=0x1000 Text="Setup"[0xDE]]
|
--M[Id=0x1300 P=0x0 N=0x0 B=0x1000 Text="Setup"[0xDE]]
|
||||||
--L[#0 T=M VId=0x1310 Text="Swashplate"[0xD3] MId=0x1300 ]
|
--L[#0 T=M VId=0x1310 Text="Swashplate"[0xD3] MId=0x1300 ]
|
||||||
--L[#1 T=M VId=0x1360 Text="Tail rotor"[0xDD] MId=0x1300 ]
|
--L[#1 T=M VId=0x1360 Text="Tail rotor"[0xDD] MId=0x1300 ]
|
||||||
|
|
||||||
|
-- L[#2 T=M VId=0x13C0 Text="Throttle"[0x201] MId=0x1300 A=0x0]
|
||||||
|
-- L[#3 T=M VId=0x13B0 Text="Gyro settings"[0xF9] MId=0x1300 A=0x0]
|
||||||
|
|
||||||
--L[#4 T=LM_nc VId=0x1701 Text="FM Channel"[0x78] val=1 NL=(0->8,1,S=12) [12->20,13] MId=0x1300 ]
|
--L[#4 T=LM_nc VId=0x1701 Text="FM Channel"[0x78] val=1 NL=(0->8,1,S=12) [12->20,13] MId=0x1300 ]
|
||||||
--L[#5 T=LM_nc VId=0x1702 Text="Gain Channel"[0x89] val=0 NL=(0->8,1,S=12)] [12->20,13] MId=0x1300 ]
|
--L[#5 T=LM_nc VId=0x1702 Text="Gain Channel"[0x89] val=0 NL=(0->8,1,S=12)] [12->20,13] MId=0x1300 ]
|
||||||
--L[#6 T=LM_nc VId=0x1703 Text="Output Channel 6"[0x56] val=1 NL=(0->12,0,S=53) [53->65,53] MId=0x1300 ]
|
--L[#6 T=LM_nc VId=0x1703 Text="Output Channel 6"[0x56] val=1 NL=(0->12,0,S=53) [53->65,53] MId=0x1300 ]
|
||||||
@ -1142,6 +1138,12 @@ local function FC6250HX_loadMenu(menuId)
|
|||||||
ctx.Menu = { MenuId = 0x1300, TextId = 0xDE, PrevId = 0, NextId = 0, BackId = 0x1000 }
|
ctx.Menu = { MenuId = 0x1300, TextId = 0xDE, PrevId = 0, NextId = 0, BackId = 0x1000 }
|
||||||
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xD3, ValId = 0x1310 }
|
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xD3, ValId = 0x1310 }
|
||||||
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xDD, ValId = 0x1360 }
|
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xDD, ValId = 0x1360 }
|
||||||
|
|
||||||
|
if (not RX_Initialized) then
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x201, ValId = 0x13C0 }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xF9, ValId = 0x13B0 }
|
||||||
|
end
|
||||||
|
|
||||||
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x78, ValId = 0x1701, Min=12, Max=20, Def=13, Val=1 }
|
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x78, ValId = 0x1701, Min=12, Max=20, Def=13, Val=1 }
|
||||||
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x89, ValId = 0x1702, Min=12, Max=20, Def=13, Val=0 }
|
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x89, ValId = 0x1702, Min=12, Max=20, Def=13, Val=0 }
|
||||||
ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x56, ValId = 0x1702, Min=53, Max=65, Def=53, Val=1 }
|
ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x56, ValId = 0x1702, Min=53, Max=65, Def=53, Val=1 }
|
||||||
@ -1182,12 +1184,27 @@ local function FC6250HX_loadMenu(menuId)
|
|||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
elseif (menuId==0x1330) then
|
elseif (menuId==0x1330) then
|
||||||
--M[Id=0x1330 P=0x0 N=0x0 B=0x1310 Text="Output Setup"[0x49]]
|
--M[Id=0x1330 P=0x0 N=0x0 B=0x1310 Text="Output Setup"[0x49]]
|
||||||
--L[#0 T=M VId=0x1331 Text="Subtrim"[0xE1] MId=0x1330 ]
|
|
||||||
|
---- Full version
|
||||||
|
--L[#0 T=LM_nc2 VId=0x1331 Text="Frame Rate"[0x85] Val=nil NL=(0->5,0,S=136) [136->141,136] MId=0x1330 A=0x0]
|
||||||
|
--L[#1 T=M VId=0x1334 Text="Swash Type"[0xE5] MId=0x1330 A=0x0]
|
||||||
|
--L[#2 T=M VId=0x1332 Text="Direction"[0xF6] MId=0x1330 A=0x0]
|
||||||
|
|
||||||
|
--L[#3 T=M VId=0x1331 Text="Subtrim"[0xE1] MId=0x1330 ]
|
||||||
|
|
||||||
ctx.Menu = { MenuId = 0x1330, TextId = 0x49, PrevId = 0, NextId = 0, BackId = 0x1310 }
|
ctx.Menu = { MenuId = 0x1330, TextId = 0x49, PrevId = 0, NextId = 0, BackId = 0x1310 }
|
||||||
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xE1, ValId = 0x1331 }
|
|
||||||
|
if (not RX_Initialized) then
|
||||||
ctx.SelLine = 0
|
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x85, ValId = 0x1331, Min=136, Max=141, Def=136, Val=0 }
|
||||||
|
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xE5, ValId = 0x1334 }
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xF6, ValId = 0x1332 }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xE1, ValId = 0x1331 }
|
||||||
|
ctx.SelLine = 0
|
||||||
|
else
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xE1, ValId = 0x1331 }
|
||||||
|
ctx.SelLine = 0
|
||||||
|
end
|
||||||
|
|
||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
elseif (menuId==0x1331) then
|
elseif (menuId==0x1331) then
|
||||||
--M[Id=0x1331 P=0x0 N=0x0 B=0x1330 Text="Subtrim"[0xE1]]
|
--M[Id=0x1331 P=0x0 N=0x0 B=0x1330 Text="Subtrim"[0xE1]]
|
||||||
@ -1202,6 +1219,28 @@ local function FC6250HX_loadMenu(menuId)
|
|||||||
|
|
||||||
ctx.SelLine = 0
|
ctx.SelLine = 0
|
||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x1332) then
|
||||||
|
--M[Id=0x1332 P=0x0 N=0x0 B=0x1330 Text="Direction"[0xF6]]
|
||||||
|
--L[#0 T=LM_tog VId=0x1333 Text="Output Channel 1"[0x51] Val=nil NL=(0->1,0,S=142) [142->143,142] MId=0x1332 A=0x0]
|
||||||
|
--L[#1 T=LM_tog VId=0x1334 Text="Output Channel 2"[0x52] Val=nil NL=(0->1,0,S=142) [142->143,142] MId=0x1332 A=0x0]
|
||||||
|
--L[#2 T=LM_tog VId=0x1335 Text="Output Channel 3"[0x53] Val=nil NL=(0->1,0,S=142) [142->143,142] MId=0x1332 A=0x0]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x1332, TextId = 0xF6, PrevId = 0, NextId = 0, BackId = 0x1330 }
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x51, ValId = 0x1333, Min=142, Max=143, Def=142, Val=0 }
|
||||||
|
ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x52, ValId = 0x1334, Min=142, Max=143, Def=142, Val=0 }
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x53, ValId = 0x1335, Min=142, Max=143, Def=142, Val=0 }
|
||||||
|
|
||||||
|
ctx.SelLine = 0
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x1334) then
|
||||||
|
-- M[Id=0x1334 P=0x0 N=0x0 B=0x1330 Text="Swashplate"[0xD3]]
|
||||||
|
-- L[#6 T=LM_tog VId=0x1335 Text="Swash Type"[0xE5] Val=nil NL=(0->8,0,S=144) [144->152,144] MId=0x1334 A=0x0]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x1334, TextId = 0xD3, PrevId = 0, NextId = 0, BackId = 0x1330 }
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0xE5, ValId = 0x1335, Min=144, Max=152, Def=144, Val=0 }
|
||||||
|
|
||||||
|
ctx.SelLine = 6
|
||||||
|
lastGoodMenu = menuId
|
||||||
elseif (menuId==0x1360) then
|
elseif (menuId==0x1360) then
|
||||||
--M[Id=0x1360 P=0x0 N=0x0 B=0x1300 Text="Tail rotor"[0xDD]]
|
--M[Id=0x1360 P=0x0 N=0x0 B=0x1300 Text="Tail rotor"[0xDD]]
|
||||||
--L[#0 T=M VId=0x1390 Text="Advanced Setup"[0x99] MId=0x1360 ]
|
--L[#0 T=M VId=0x1390 Text="Advanced Setup"[0x99] MId=0x1360 ]
|
||||||
@ -1224,6 +1263,100 @@ local function FC6250HX_loadMenu(menuId)
|
|||||||
ctx.SelLine = 0
|
ctx.SelLine = 0
|
||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
|
|
||||||
|
elseif (menuId==0x13B0) then
|
||||||
|
-- M[Id=0x13B0 P=0x0 N=0x0 B=0x1300 Text="Gyro settings"[0xF9]]
|
||||||
|
-- L[#0 T=M VId=0x13B1 Text="Orientation"[0x80] MId=0x13B0 A=0x0]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x13B0, TextId = 0xF9, PrevId = 0, NextId = 0, BackId = 0x1300 }
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x80, ValId = 0x13B1 }
|
||||||
|
|
||||||
|
ctx.SelLine = 0
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x13B1) then
|
||||||
|
-- M[Id=0x13B1 P=0x0 N=0x0 B=0x13B5 Text="Gyro settings"[0xF9]]
|
||||||
|
--L[#6 T=LM_ori VId=0x13B2 Text="Orientation"[0x80] Val=nil NL=(0->7,0,S=203) [203->210,203] MId=0x13B1 A=0x0]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x13B1, TextId = 0xF9, PrevId = 0, NextId = 0, BackId = 0x13B5 }
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_ORI, TextId = 0x80, ValId = 0x13B2, Min=203, Max=210, Def=203, Val=0 }
|
||||||
|
|
||||||
|
ctx.SelLine = 6
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x13B5) then
|
||||||
|
--M[Id=0x13B5 P=0x0 N=0x0 B=0x13B0 Text="Calibrate Sensor"[0xC7]]
|
||||||
|
--L[#3 T=M VId=0x13B6 Text="Begin"[0x91] MId=0x13B5 A=0x0]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x13B5, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x13B0 }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x91, ValId = 0x13B6 }
|
||||||
|
|
||||||
|
ctx.SelLine = 3
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x13B6) then
|
||||||
|
--M[Id=0x13B6 P=0x0 N=0x0 B=0x13B0 Text="Calibrate Sensor"[0xC7]]
|
||||||
|
--L[#3 T=M VId=0x13B0 Text="Sensor is Calibrating.. Wait"[0xC8] MId=0x13B6 A=0x0]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x13B6, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x13B0 }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xC8, ValId = 0x17F1 }
|
||||||
|
|
||||||
|
ctx.SelLine = 3
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x13C0) then
|
||||||
|
--M[Id=0x13C0 P=0x0 N=0x0 B=0x1300 Text="Throttle"[0x201]]
|
||||||
|
--L[#0 T=M VId=0x13C1 Text="Failsafe"[0x4A] MId=0x13C0 A=0x0]
|
||||||
|
--L[#1 T=V_% VId=0x13C2 Text="Hover"[0x204] Val=nil [0->100,65] MId=0x13C0 A=0x10]
|
||||||
|
--L[#2 T=M VId=0x13D0 Text="Governor"[0xF2] MId=0x13C0 A=0x0]
|
||||||
|
--L[#4 T=V_nc VId=0x13C3 Text="Flight Mode"[0x8000] Val=nil [0->5,0] MId=0x13C0 A=0x5]
|
||||||
|
--L[#5 T=V_% VId=0x13C4 Text="Offset"[0x1AA] Val=nil [-25->25,0] MId=0x13C0 A=0x10]
|
||||||
|
--L[#6 T=V_i8 VId=0x13C5 Text="Soft Start"[0xF4] Val=nil [0->250,0] MId=0x13C0 A=0x0]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x13C0, TextId = 0x201, PrevId = 0, NextId = 0, BackId = 0x1300 }
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x4A, ValId = 0x13C1 }
|
||||||
|
ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x204, ValId = 0x13C2, Min=0, Max=100, Def=65, Val=65 }
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xF2, ValId = 0x13D0 }
|
||||||
|
|
||||||
|
ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8000, ValId = 0x13C3, Min=0, Max=5, Def=0, Val=1 }
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x1AA, ValId = 0x13C4, Min=-25, Max=25, Def=0, Val=0 }
|
||||||
|
ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xF4, ValId = 0x13C5, Min=0, Max=250, Def=0, Val=1 }
|
||||||
|
|
||||||
|
ctx.SelLine = 0
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x13C1) then
|
||||||
|
--M[Id=0x13C1 P=0x0 N=0x0 B=0x13C0 Text="Failsafe"[0x4A]]
|
||||||
|
--L[#2 T=M VId=0x13C3 Text="Capture Failsafe Positions"[0x9A] MId=0x13C1 A=0x0]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x13C1, TextId = 0x4A, PrevId = 0, NextId = 0, BackId = 0x13C0 }
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x9A, ValId = 0x13C3 }
|
||||||
|
|
||||||
|
ctx.SelLine = 2
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x13D0) then
|
||||||
|
--M[Id=0x13D0 P=0x0 N=0x0 B=0x13C0 Text="Governor"[0xF2]]
|
||||||
|
--L[#0 T=LM_ori VId=0x13D1 Text="Governor"[0xF2] Val=nil NL=(0->1,0,S=244) [244->245,244] MId=0x13D0 A=0x0]
|
||||||
|
--L[#1 T=V_i8 VId=0x13D2 Text="Main Gear"[0x26D] Val=nil [1->255,170] MId=0x13D0 A=0x0]
|
||||||
|
--L[#2 T=V_i8 VId=0x13D3 Text="Pinion"[0x26C] Val=nil [1->255,20] MId=0x13D0 A=0x0]
|
||||||
|
--L[#3 T=V_i8 VId=0x13D5 Text="Low Throttle"[0xEA] Val=nil [1->100,75] MId=0x13D0 A=0x0]
|
||||||
|
--L[#4 T=V_i8 VId=0x13D6 Text="Filter"[0x1F1] Val=nil [1->65,35] MId=0x13D0 A=0x0]
|
||||||
|
--L[#5 T=M VId=0x13E0 Text="RPM Sensor"[0x26F] MId=0x13D0 A=0x0]
|
||||||
|
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x13D0, TextId = 0xF2, PrevId = 0, NextId = 0, BackId = 0x13C0 }
|
||||||
|
ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_ORI, TextId = 0x0F2, ValId = 0x13D1, Min=244, Max=245, Def=244, Val=0 }
|
||||||
|
ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x26D, ValId = 0x13D2, Min=1, Max=255, Def=170, Val=170 }
|
||||||
|
ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x26C, ValId = 0x13D3, Min=1, Max=255, Def=20, Val=20 }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x0EA, ValId = 0x13D5, Min=1, Max=100, Def=75, Val=75 }
|
||||||
|
ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x1F1, ValId = 0x13D6, Min=1, Max=65, Def=35, Val=35 }
|
||||||
|
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x26F, ValId = 0x13E0 }
|
||||||
|
|
||||||
|
ctx.SelLine = 0
|
||||||
|
lastGoodMenu = menuId
|
||||||
|
elseif (menuId==0x13E0) then
|
||||||
|
--M[Id=0x13E0 P=0x0 N=0x0 B=0x13D0 Text="Governor"[0xF2]]
|
||||||
|
--L[#0 T=LM_ori VId=0x13D1 Text="RPM Sensor"[0x26F] Val=nil NL=(0->1,0,S=244) [244->245,244] MId=0x13D0 A=0x0]
|
||||||
|
|
||||||
|
ctx.Menu = { MenuId = 0x13E0, TextId = 0xF2, PrevId = 0, NextId = 0, BackId = 0x13D0 }
|
||||||
|
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x26F, ValId = 0x13E3, Min=142, Max=143, Def=142, Val=0 }
|
||||||
|
|
||||||
|
ctx.SelLine = 3
|
||||||
|
lastGoodMenu = menuId
|
||||||
elseif (menuId==0x1400) then
|
elseif (menuId==0x1400) then
|
||||||
--M[Id=0x1400 P=0x0 N=0x0 B=0x1000 Text="SAFE"[0xDA]]
|
--M[Id=0x1400 P=0x0 N=0x0 B=0x1000 Text="SAFE"[0xDA]]
|
||||||
--L[#0 T=M VId=0x1410 Text="Stability"[0xDB] MId=0x1400 ]
|
--L[#0 T=M VId=0x1410 Text="Stability"[0xDB] MId=0x1400 ]
|
||||||
@ -1306,30 +1439,29 @@ local function FC6250HX_loadMenu(menuId)
|
|||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
elseif (menuId==0x17F1) then
|
elseif (menuId==0x17F1) then
|
||||||
--M[Id=0x17F1 P=0x0 N=0x0 B=0x1700 Text="Calibrate Sensor"[0xC7]]
|
--M[Id=0x17F1 P=0x0 N=0x0 B=0x1700 Text="Calibrate Sensor"[0xC7]]
|
||||||
--L[#3 T=M VId=0x17F1 Text="Complete"[0xC8] MId=0x17F0 ]
|
--L[#3 T=M VId=0x17F1 Text="Complete"[0x93] MId=0x17F0 ]
|
||||||
|
|
||||||
ctx.Menu = { MenuId = 0x17F1, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x1700 }
|
ctx.Menu = { MenuId = 0x17F1, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x1700 }
|
||||||
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xC8, ValId = 0x1700 }
|
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x93, ValId = 0x1700 }
|
||||||
|
|
||||||
ctx.SelLine = 3
|
ctx.SelLine = 3
|
||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
elseif (menuId==0x0001) then
|
elseif (menuId==0x0001) then
|
||||||
-- Save Settings and Reboot
|
-- Save Settings and Reboot
|
||||||
ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 }
|
ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 }
|
||||||
ctx.SelLine = dsmLib.BACK_BUTTON
|
ctx.SelLine = menuLib.BACK_BUTTON
|
||||||
else
|
else
|
||||||
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
|
ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu }
|
||||||
ctx.SelLine = dsmLib.BACK_BUTTON
|
ctx.SelLine = menuLib.BACK_BUTTON
|
||||||
end
|
end
|
||||||
|
|
||||||
PostProcessMenu()
|
menuLib.PostProcessMenu()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local function loadMenu(menuId)
|
local function loadMenu(menuId)
|
||||||
clearMenuLines()
|
menuLib.clearMenuLines()
|
||||||
local ctx = dsmLib.DSM_Context
|
local ctx = menuLib.DSM_Context
|
||||||
|
|
||||||
if (menuId==0x1000) then
|
if (menuId==0x1000) then
|
||||||
--M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"]
|
--M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"]
|
||||||
@ -1337,35 +1469,41 @@ local function loadMenu(menuId)
|
|||||||
--L[#1 T=M VId=0x105E val=nil [0->0,2] Text="Other settings" MId=0x1000 ]
|
--L[#1 T=M VId=0x105E val=nil [0->0,2] Text="Other settings" MId=0x1000 ]
|
||||||
|
|
||||||
ctx.Menu = { MenuId = 0x1000, Text = "RX SIMULATION", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
ctx.Menu = { MenuId = 0x1000, Text = "RX SIMULATION", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||||
ctx.MenuLines[0] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR631 (NEW)", ValId = 0x1001,TextId=0 }
|
ctx.MenuLines[0] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR630/631/637 (NEW)", ValId = 0x1001,TextId=0 }
|
||||||
ctx.MenuLines[1] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR631 (INITIALIZED)", ValId = 0x1002, TextId=0 }
|
ctx.MenuLines[1] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR630/631/637 (INITIALIZED)", ValId = 0x1002, TextId=0 }
|
||||||
ctx.MenuLines[4] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "FC6250HX", ValId = 0x1005, TextId=0 }
|
ctx.MenuLines[4] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "FC6250HX", ValId = 0x1005, TextId=0 }
|
||||||
|
ctx.MenuLines[5] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "FC6250HX (UNLOCKED)", ValId = 0x1006, TextId=0 }
|
||||||
|
|
||||||
ctx.SelLine = 0
|
ctx.SelLine = 0
|
||||||
lastGoodMenu = menuId
|
lastGoodMenu = menuId
|
||||||
elseif (menuId==0x1001) then
|
elseif (menuId==0x1001) then
|
||||||
RX_Initialized = false
|
RX_Initialized = false
|
||||||
ctx.RX.Id = dsmLib.RX.AR631
|
ctx.RX.Id = menuLib.RX.AR631
|
||||||
dsmLib.Init_Text(ctx.RX.Id)
|
ctx.RX.Name = "AR630/631/637-SIM"
|
||||||
ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM'
|
ctx.RX.Version = "2.38.5"
|
||||||
ctx.RX.Version = "2.38.5"
|
|
||||||
|
|
||||||
RX_loadMenu = AR631_loadMenu
|
RX_loadMenu = AR631_loadMenu
|
||||||
RX_loadMenu(0x01000)
|
RX_loadMenu(0x01000)
|
||||||
elseif (menuId==0x1002) then
|
elseif (menuId==0x1002) then
|
||||||
ctx.RX.Id = dsmLib.RX.AR631
|
RX_Initialized = true
|
||||||
dsmLib.Init_Text(ctx.RX.Id)
|
ctx.RX.Id = menuLib.RX.AR631
|
||||||
ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM'
|
ctx.RX.Name = "AR630/631/637-SIM"
|
||||||
ctx.RX.Version = "2.38.5"
|
ctx.RX.Version = "2.38.5"
|
||||||
|
|
||||||
RX_loadMenu = AR631_loadMenu
|
RX_loadMenu = AR631_loadMenu
|
||||||
RX_loadMenu(0x01000)
|
RX_loadMenu(0x01000)
|
||||||
elseif (menuId==0x1005) then
|
elseif (menuId==0x1005) then
|
||||||
ctx.RX.Id = dsmLib.RX.FC6250HX
|
RX_Initialized = true
|
||||||
dsmLib.Init_Text(ctx.RX.Id)
|
ctx.RX.Id = menuLib.RX.FC6250HX
|
||||||
ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM'
|
ctx.RX.Name = "FC6250HX-SIM"
|
||||||
ctx.RX.Version = "5.6.255"
|
ctx.RX.Version = "5.6.255"
|
||||||
|
|
||||||
|
RX_loadMenu = FC6250HX_loadMenu
|
||||||
|
RX_loadMenu(0x01000)
|
||||||
|
elseif (menuId==0x1006) then
|
||||||
|
RX_Initialized = false
|
||||||
|
ctx.RX.Id = menuLib.RX.FC6250HX
|
||||||
|
ctx.RX.Name = "FC6250HX-SIM"
|
||||||
|
ctx.RX.Version = "5.6.52"
|
||||||
|
|
||||||
RX_loadMenu = FC6250HX_loadMenu
|
RX_loadMenu = FC6250HX_loadMenu
|
||||||
RX_loadMenu(0x01000)
|
RX_loadMenu(0x01000)
|
||||||
end
|
end
|
||||||
@ -1375,13 +1513,14 @@ end
|
|||||||
|
|
||||||
|
|
||||||
local function SIM_Send_Receive()
|
local function SIM_Send_Receive()
|
||||||
local ctx = dsmLib.DSM_Context
|
local ctx = menuLib.DSM_Context
|
||||||
--if (DEBUG_ON) then dsmLib.LOG_write("%3.3f %s: ", dsmLib.getElapsedTime(), dsmLib.phase2String(ctx.Phase)) end
|
--if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||||
|
|
||||||
if ctx.Phase == PHASE.RX_VERSION then -- request RX version
|
if ctx.Phase == PHASE.RX_VERSION then -- request RX version
|
||||||
ctx.RX.Name = "SIMULATOR"
|
ctx.RX.Name = "SIMULATOR"
|
||||||
ctx.RX.Version = "0.54"
|
ctx.RX.Version = SIM_LIB_VERSION
|
||||||
ctx.Phase = PHASE.MENU_TITLE
|
ctx.Phase = PHASE.MENU_TITLE
|
||||||
|
ctx.Menu.MenuId=0
|
||||||
|
|
||||||
ctx.Refresh_Display = true
|
ctx.Refresh_Display = true
|
||||||
RX_loadMenu = loadMenu
|
RX_loadMenu = loadMenu
|
||||||
@ -1399,8 +1538,8 @@ local function SIM_Send_Receive()
|
|||||||
|
|
||||||
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
|
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
|
||||||
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%3.3f %s: ", dsmLib.getElapsedTime(), dsmLib.phase2String(ctx.Phase)) end
|
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, dsmLib.lineValue2String(line)) end
|
if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
|
||||||
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
|
ctx.Phase = PHASE.VALUE_CHANGING_WAIT
|
||||||
|
|
||||||
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
|
elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then
|
||||||
@ -1408,9 +1547,9 @@ local function SIM_Send_Receive()
|
|||||||
|
|
||||||
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
|
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
|
||||||
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("%3.3f %s: ", dsmLib.getElapsedTime(), dsmLib.phase2String(ctx.Phase)) end
|
if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, dsmLib.lineValue2String(line)) end
|
if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
|
||||||
if (DEBUG_ON) then dsmLib.LOG_write("SEND SIM_validateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, dsmLib.lineValue2String(line)) end
|
if (DEBUG_ON) then Log.LOG_write("SEND SIM_validateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end
|
||||||
ctx.Phase = PHASE.WAIT_CMD
|
ctx.Phase = PHASE.WAIT_CMD
|
||||||
|
|
||||||
elseif ctx.Phase == PHASE.EXIT then
|
elseif ctx.Phase == PHASE.EXIT then
|
||||||
@ -1418,56 +1557,40 @@ local function SIM_Send_Receive()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
local FileState = {}
|
||||||
-- Lib EXPORTS
|
|
||||||
|
|
||||||
-- Export Constants
|
-- Initial Setup
|
||||||
SimLib.PHASE = dsmLib.PHASE
|
local function Sim_Init()
|
||||||
SimLib.LINE_TYPE = dsmLib.LINE_TYPE
|
local ctx = menuLib.DSM_Context
|
||||||
SimLib.RX = dsmLib.RX
|
ctx.Phase = PHASE.INIT
|
||||||
SimLib.DISP_ATTR = dsmLib.DISP_ATTR
|
|
||||||
|
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'
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SIM_Done()
|
||||||
|
local ctx = menuLib.DSM_Context
|
||||||
|
ctx.Phase = PHASE.EXIT_DONE
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
SimLib.BACK_BUTTON = dsmLib.BACK_BUTTON
|
local function SIM_Run()
|
||||||
SimLib.NEXT_BUTTON = dsmLib.NEXT_BUTTON
|
if (menuLib.DSM_Context.Phase == PHASE.INIT) then
|
||||||
SimLib.PREV_BUTTON = dsmLib.PREV_BUTTON
|
if (IS_EDGETX) then
|
||||||
SimLib.MAX_MENU_LINES = dsmLib.MAX_MENU_LINES
|
menuLib.LoadTextFromFile(MSG_FILE,13)
|
||||||
|
menuLib.DSM_Context.Phase = PHASE.RX_VERSION
|
||||||
|
else -- Incremental initialization
|
||||||
|
lcd.clear()
|
||||||
|
lcd.drawText(30, 50, "Loading Msg file: "..(FileState.lineNo or 0))
|
||||||
|
if (menuLib.INC_LoadTextFromFile(MSG_FILE, FileState)==1) then
|
||||||
|
menuLib.DSM_Context.Phase = PHASE.RX_VERSION
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return SIM_Send_Receive()
|
||||||
|
end
|
||||||
|
|
||||||
-- Export Shared Context Variables
|
return { init=Sim_Init, run=SIM_Run, done=SIM_Done }
|
||||||
SimLib.DSM_Context = dsmLib.DSM_Context
|
|
||||||
|
|
||||||
-- Export Functions
|
|
||||||
SimLib.LOG_write = dsmLib.LOG_write
|
|
||||||
SimLib.LOG_close = dsmLib.LOG_close
|
|
||||||
SimLib.getElapsedTime = dsmLib.getElapsedTime
|
|
||||||
|
|
||||||
SimLib.Get_Text = dsmLib.Get_Text
|
|
||||||
SimLib.Get_List_Text = dsmLib.Get_List_Text
|
|
||||||
SimLib.Get_List_Text_Img = dsmLib.Get_List_Text_Img
|
|
||||||
|
|
||||||
SimLib.phase2String = dsmLib.phase2String
|
|
||||||
SimLib.menu2String = dsmLib.menu2String
|
|
||||||
SimLib.menuLine2String = dsmLib.menuLine2String
|
|
||||||
|
|
||||||
SimLib.isSelectableLine = dsmLib.isSelectableLine
|
|
||||||
SimLib.isEditableLine = dsmLib.isEditableLine
|
|
||||||
SimLib.isListLine = dsmLib.isListLine
|
|
||||||
SimLib.isPercentValueLine = dsmLib.isPercentValueLine
|
|
||||||
SimLib.isNumberValueLine = dsmLib.isNumberValueLine
|
|
||||||
SimLib.isDisplayAttr = dsmLib.isDisplayAttr
|
|
||||||
SimLib.isFlightModeLine = dsmLib.isFlightModeLine
|
|
||||||
SimLib.GetFlightModeValue = dsmLib.GetFlightModeValue
|
|
||||||
|
|
||||||
SimLib.StartConnection = SIM_StartConnection -- Override Function
|
|
||||||
SimLib.ReleaseConnection = SIM_ReleaseConnection -- Override Function
|
|
||||||
SimLib.ChangePhase = dsmLib.ChangePhase
|
|
||||||
SimLib.Value_Add = dsmLib.Value_Add
|
|
||||||
SimLib.Value_Default = dsmLib.Value_Default
|
|
||||||
SimLib.Value_Write_Validate = dsmLib.Value_Write_Validate
|
|
||||||
SimLib.GotoMenu = dsmLib.GotoMenu
|
|
||||||
SimLib.MoveSelectionLine = dsmLib.MoveSelectionLine
|
|
||||||
SimLib.Send_Receive = SIM_Send_Receive -- Override Function
|
|
||||||
SimLib.Init = dsmLib.Init
|
|
||||||
SimLib.Init_Text = dsmLib.Init_Text
|
|
||||||
|
|
||||||
return SimLib
|
|
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_1.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_2.png
Normal file
After Width: | Height: | Size: 862 B |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_3.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_4.png
Normal file
After Width: | Height: | Size: 866 B |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_5.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_6.png
Normal file
After Width: | Height: | Size: 880 B |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_7.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/h_rx_pos_8.png
Normal file
After Width: | Height: | Size: 863 B |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_120.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_120inv.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_135.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_135inv.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_140.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_140inv.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_90.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_3_90inv.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/h_swp_norm.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Lua_scripts/DSMLIB/img/tt_taileron.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -9,7 +9,7 @@ LT|0x0003|Inh
|
|||||||
LT|0x0004|Act
|
LT|0x0004|Act
|
||||||
--
|
--
|
||||||
-- Channel selection for SAFE MODE and GAINS on FC6250HX
|
-- Channel selection for SAFE MODE and GAINS on FC6250HX
|
||||||
LT|0x000C|Inhibit?
|
LT|0x000C|Inh
|
||||||
LT|0x000D|Ch5
|
LT|0x000D|Ch5
|
||||||
LT|0x000E|Ch6
|
LT|0x000E|Ch6
|
||||||
LT|0x000F|Ch7
|
LT|0x000F|Ch7
|
||||||
@ -29,7 +29,7 @@ LT|0x0032|1 X
|
|||||||
LT|0x0033|2 X
|
LT|0x0033|2 X
|
||||||
LT|0x0034|4 X
|
LT|0x0034|4 X
|
||||||
--
|
--
|
||||||
LT|0x0035|Inh?
|
LT|0x0035|Inh
|
||||||
LT|0x0036|Thr
|
LT|0x0036|Thr
|
||||||
LT|0x0037|Ail
|
LT|0x0037|Ail
|
||||||
LT|0x0038|Ele
|
LT|0x0038|Ele
|
||||||
@ -71,7 +71,7 @@ T |0x0055|Output Channel 5
|
|||||||
T |0x0056|Output Channel 6
|
T |0x0056|Output Channel 6
|
||||||
--
|
--
|
||||||
-- FailSafe Options
|
-- FailSafe Options
|
||||||
--LT|0x005E|Inhibit
|
--LT|0x005E|Inh
|
||||||
LT|0x005F|Hold Last
|
LT|0x005F|Hold Last
|
||||||
LT|0x0060|Preset
|
LT|0x0060|Preset
|
||||||
--LT|0x0061|Custom
|
--LT|0x0061|Custom
|
||||||
@ -79,8 +79,8 @@ LT|0x0060|Preset
|
|||||||
T |0x0071|Proportional
|
T |0x0071|Proportional
|
||||||
T |0x0072|Integral
|
T |0x0072|Integral
|
||||||
T |0x0073|Derivate
|
T |0x0073|Derivate
|
||||||
--
|
|
||||||
T |0x0078|FM Channel
|
T |0x0078|FM Channel
|
||||||
|
T |0x007F|Attitude Gain
|
||||||
--
|
--
|
||||||
T |0x0080|Orientation
|
T |0x0080|Orientation
|
||||||
T |0x0082|Heading
|
T |0x0082|Heading
|
||||||
@ -93,18 +93,46 @@ T |0x008A|Gain Sensitivity/r -- Right Align
|
|||||||
T |0x008B|Panic
|
T |0x008B|Panic
|
||||||
T |0x008E|Panic Delay
|
T |0x008E|Panic Delay
|
||||||
--
|
--
|
||||||
|
LT|0x0187|No Freq --???? unset Freq
|
||||||
|
LT|0x0088|70hz
|
||||||
|
LT|0x0089|90hz
|
||||||
|
LT|0x008A|200hz
|
||||||
|
LT|0x008B|333hz
|
||||||
|
LT|0x008C|490hz
|
||||||
LT|0x008D|560hz
|
LT|0x008D|560hz
|
||||||
--
|
LT|0x008E|Normal
|
||||||
-- FC6250HX: Callibration Menu -> Begin..Start, Complete, Done
|
LT|0x008F|Reversed
|
||||||
T |0x0091|Begin
|
|
||||||
|
-- FC6250HX: Callibration
|
||||||
T |0x0090|Apply
|
T |0x0090|Apply
|
||||||
|
T |0x0091|Begin
|
||||||
T |0x0092|Start
|
T |0x0092|Start
|
||||||
T |0x0093|Complete
|
T |0x0093|Complete
|
||||||
T |0x0094|Done
|
T |0x0094|Done
|
||||||
--
|
--
|
||||||
|
-- FC6250HX: Swashplate Type
|
||||||
|
--
|
||||||
|
LT|0x0090|Normal
|
||||||
|
LI|0x0090|h_swp_norm.png|Normal
|
||||||
|
LT|0x0091|3 Servos 120 Y
|
||||||
|
LI|0x0091|h_swp_3_120.png|3 Servos 120 Y
|
||||||
|
LT|0x0092|3 Servos 120 Y-Inv
|
||||||
|
LI|0x0092|h_swp_3_120inv.png|3 Servos 120 Y-Inv
|
||||||
|
LT|0x0093|3 Servos 135 Y
|
||||||
|
LI|0x0093|h_swp_3_135.png|3 Servos 135 Y
|
||||||
|
LT|0x0094|3 Servos 135 Y-Inv
|
||||||
|
LI|0x0094|h_swp_3_135inv.png|3 Servos 135 Y-Inv
|
||||||
|
LT|0x0095|3 Servos 140 Y
|
||||||
|
LI|0x0095|h_swp_3_140.png|3 Servos 140 Y
|
||||||
|
LT|0x0096|3 Servos 140 Y-Inv
|
||||||
|
LI|0x0096|h_swp_3_140inv.png|3 Servos 140 Y-Inv
|
||||||
|
LT|0x0097|3 Servos 90 T
|
||||||
|
LI|0x0097|h_swp_3_90.png|3 Servos 90 T
|
||||||
|
LT|0x0098|3 Servos 90 T-Inv
|
||||||
|
LI|0x0098|h_swp_3_90inv.png|3 Servos 90 T-Inv
|
||||||
|
--
|
||||||
T |0x0097|Factory Reset
|
T |0x0097|Factory Reset
|
||||||
T |0x0098|Factory Reset
|
T |0x0098|Factory Reset
|
||||||
--
|
|
||||||
T |0x0099|Advanced Setup
|
T |0x0099|Advanced Setup
|
||||||
T |0x009A|Capture Failsafe Positions
|
T |0x009A|Capture Failsafe Positions
|
||||||
T |0x009C|Custom Failsafe
|
T |0x009C|Custom Failsafe
|
||||||
@ -115,11 +143,11 @@ T |0x00A5|First Time Setup
|
|||||||
T |0x00AA|Capture Gyro Gains
|
T |0x00AA|Capture Gyro Gains
|
||||||
T |0x00AD|Gain Channel Select
|
T |0x00AD|Gain Channel Select
|
||||||
T |0x00AF|Dynamic
|
T |0x00AF|Dynamic
|
||||||
T |0x00B0|Self-Level/Angle Dem
|
LT|0x00B0|Self-Level/Angle Dem
|
||||||
T |0x00B1|Envelope
|
LT|0x00B1|Envelope
|
||||||
--
|
--
|
||||||
-- Flight Modes List Options
|
-- Flight Modes List Options
|
||||||
LT|0x00B5|Inhibit
|
LT|0x00B5|Inh
|
||||||
LT|0x00B6|FM1
|
LT|0x00B6|FM1
|
||||||
LT|0x00B7|FM2
|
LT|0x00B7|FM2
|
||||||
LT|0x00B8|FM3
|
LT|0x00B8|FM3
|
||||||
@ -134,9 +162,13 @@ LT|0x00BF|FM10
|
|||||||
T |0x00BE|Unknown_BE -- Used in Reset menu (0x0001) while the RX is rebooting
|
T |0x00BE|Unknown_BE -- Used in Reset menu (0x0001) while the RX is rebooting
|
||||||
--
|
--
|
||||||
T |0x00C7|Calibrate Sensor
|
T |0x00C7|Calibrate Sensor
|
||||||
|
T |0x00C8|Sensor is Calibrating.. Wait
|
||||||
T |0x00CA|SAFE/Panic Mode Setup
|
T |0x00CA|SAFE/Panic Mode Setup
|
||||||
--
|
--
|
||||||
T |0x00CD|Level model and capture attitude/m -- SPECIAL MENU to itself who is not a comment
|
T |0x00CD|Level model and capture attitude/m -- SPECIAL MENU to itself who is not a comment
|
||||||
|
T |0x00CE|Error TX Conf
|
||||||
|
T |0x00CF|Invalid TX Ch Conf 1
|
||||||
|
T |0x00D0|Invalid TX Ch Conf 2
|
||||||
--
|
--
|
||||||
-- RX Orientations for AR631/AR637, Optionally attach an Image + Alt Text to display
|
-- RX Orientations for AR631/AR637, Optionally attach an Image + Alt Text to display
|
||||||
LT|0x00CB|Pos 1
|
LT|0x00CB|Pos 1
|
||||||
@ -190,6 +222,16 @@ LI|0x00E2|rx_pos_24.png|Pilot View: RX Label Right, Pins Up
|
|||||||
LT|0x00E3|Pos Invalid
|
LT|0x00E3|Pos Invalid
|
||||||
LI|0x00E3|rx_pos_25.png|Cannot detect orientation of RX
|
LI|0x00E3|rx_pos_25.png|Cannot detect orientation of RX
|
||||||
--
|
--
|
||||||
|
-- RX Orientations images for FC5250 (HACK add 0x100 internally to differenciate for helis)
|
||||||
|
LI|0x01CB|h_rx_pos_1.png|Pilot View: RX Label Up, Pins Front
|
||||||
|
LI|0x01CC|h_rx_pos_2.png|Pilot View: RX Label Left, Pins Front
|
||||||
|
LI|0x01CD|h_rx_pos_3.png|Pilot View: RX Label Down, Pins Front
|
||||||
|
LI|0x01CE|h_rx_pos_4.png|Pilot View: RX Label Right, Pins Front
|
||||||
|
LI|0x01CF|h_rx_pos_5.png|Pilot View: RX Label UP, Pins to Back
|
||||||
|
LI|0x01D0|h_rx_pos_6.png|Pilot View: RX Label Left, Pins Back
|
||||||
|
LI|0x01D1|h_rx_pos_7.png|Pilot View: RX Label Down, Pins Back
|
||||||
|
LI|0x01D2|h_rx_pos_8.png|Pilot View: RX Label Right, Pins Back
|
||||||
|
--
|
||||||
T |0x00D1|Receiver will Reboot/b
|
T |0x00D1|Receiver will Reboot/b
|
||||||
T |0x00D2|Panic Channel
|
T |0x00D2|Panic Channel
|
||||||
T |0x00D3|Swashplate
|
T |0x00D3|Swashplate
|
||||||
@ -204,14 +246,21 @@ T |0x00DF|AFR
|
|||||||
T |0x00E0|Collective
|
T |0x00E0|Collective
|
||||||
T |0x00E1|Subtrim
|
T |0x00E1|Subtrim
|
||||||
T |0x00E2|Phasing
|
T |0x00E2|Phasing
|
||||||
|
T |0x00E3|Pre-Comp
|
||||||
T |0x00E4|E-Ring
|
T |0x00E4|E-Ring
|
||||||
T |0x00E5|Swash Type
|
T |0x00E5|Swash Type
|
||||||
T |0x00E6|Travel
|
T |0x00E6|Travel
|
||||||
T |0x00E7|Left
|
T |0x00E7|Left
|
||||||
T |0x00E8|Right
|
T |0x00E8|Right
|
||||||
|
T |0x00EA|Low Throttle
|
||||||
|
--
|
||||||
|
T |0x00F2|Governor
|
||||||
|
T |0x00F4|Soft Start
|
||||||
--
|
--
|
||||||
LT|0x00F2|Fixed
|
LT|0x00F2|Fixed
|
||||||
LT|0x00F3|Adjustable
|
LT|0x00F3|Adjustable
|
||||||
|
LT|0x00F4|Inh
|
||||||
|
LT|0x00F5|Nitro
|
||||||
--
|
--
|
||||||
T |0x00F6|Direction
|
T |0x00F6|Direction
|
||||||
T |0x00F8|Settings -- ?? validate on a Spektrum radio
|
T |0x00F8|Settings -- ?? validate on a Spektrum radio
|
||||||
@ -222,13 +271,15 @@ T |0x0100|Make sure the model has been
|
|||||||
T |0x0101|configured, including wing type,
|
T |0x0101|configured, including wing type,
|
||||||
T |0x0102|reversing, travel, trimmed, etc.
|
T |0x0102|reversing, travel, trimmed, etc.
|
||||||
T |0x0103|before continuing setup.
|
T |0x0103|before continuing setup.
|
||||||
T |0x0104| -- Blank
|
T |0x0104|
|
||||||
|
T |0x0105| -- Blank
|
||||||
--
|
--
|
||||||
T |0x0106|Any wing type, channel assignment,
|
T |0x0106|Any wing type, channel assignment,
|
||||||
T |0x0107|subtrim, or servo reversing changes
|
T |0x0107|subtrim, or servo reversing changes
|
||||||
T |0x0108|require running through initial
|
T |0x0108|require running through initial
|
||||||
T |0x0109|setup again.
|
T |0x0109|setup again.
|
||||||
T |0x010A| -- Blank
|
T |0x010A|
|
||||||
|
T |0x010B|
|
||||||
--
|
--
|
||||||
T |0x0190|Relearn Servo Settings
|
T |0x0190|Relearn Servo Settings
|
||||||
T |0x019C|Enter Receiver Bind Mode
|
T |0x019C|Enter Receiver Bind Mode
|
||||||
@ -249,6 +300,7 @@ T |0x01EC|Pitch Up
|
|||||||
T |0x01EE|Thr to Pitch
|
T |0x01EE|Thr to Pitch
|
||||||
T |0x01EF|Low Thr to Pitch/c/b
|
T |0x01EF|Low Thr to Pitch/c/b
|
||||||
T |0x01F0|High Thr to Pitch/c/b
|
T |0x01F0|High Thr to Pitch/c/b
|
||||||
|
T |0x01F1|Filter
|
||||||
T |0x01F3|Threshold
|
T |0x01F3|Threshold
|
||||||
T |0x01F4|Angle
|
T |0x01F4|Angle
|
||||||
T |0x01F6|Failsafe Angles/c/b
|
T |0x01F6|Failsafe Angles/c/b
|
||||||
@ -267,14 +319,14 @@ T |0x020D|First Time SAFE Setup
|
|||||||
T |0x020E|AS3X gains must be tuned
|
T |0x020E|AS3X gains must be tuned
|
||||||
T |0x020F|and active in SAFE Flight Modes
|
T |0x020F|and active in SAFE Flight Modes
|
||||||
T |0x0210|to help reduce wobble.
|
T |0x0210|to help reduce wobble.
|
||||||
T |0x0211| -- Blank
|
T |0x0211|
|
||||||
T |0x0212| -- Blank
|
T |0x0212|
|
||||||
T |0x0213| -- Blank
|
T |0x0213| -- Blank
|
||||||
--
|
--
|
||||||
-- AS3X orientation Setting menu (Level)
|
-- AS3X orientation Setting menu (Level)
|
||||||
T |0x021A|Set the model level,
|
T |0x021A|Set the model level,
|
||||||
T |0x021B|and press Continue.
|
T |0x021B|and press Continue.
|
||||||
T |0x021C| -- Blank
|
T |0x021C|
|
||||||
T |0x021D| -- Blank
|
T |0x021D| -- Blank
|
||||||
--
|
--
|
||||||
-- AS3X orientation Setting menu (Nose down)
|
-- AS3X orientation Setting menu (Nose down)
|
||||||
@ -283,8 +335,8 @@ T |0x0220|and press Continue. If the
|
|||||||
T |0x0221|orientation on the next
|
T |0x0221|orientation on the next
|
||||||
T |0x0222|screen is wrong go back
|
T |0x0222|screen is wrong go back
|
||||||
T |0x0223|and try again.
|
T |0x0223|and try again.
|
||||||
--
|
|
||||||
T |0x0224|Continue
|
T |0x0224|Continue
|
||||||
|
--
|
||||||
T |0x0226|Angle Limits/c/b
|
T |0x0226|Angle Limits/c/b
|
||||||
T |0x0227|Other settings
|
T |0x0227|Other settings
|
||||||
T |0x0229|Set Orientation Manually
|
T |0x0229|Set Orientation Manually
|
||||||
@ -301,7 +353,7 @@ T |0x0230| -- Blank
|
|||||||
T |0x0231|This will overwrite the
|
T |0x0231|This will overwrite the
|
||||||
T |0x0232|backup memory with your
|
T |0x0232|backup memory with your
|
||||||
T |0x0233|current configuartion.
|
T |0x0233|current configuartion.
|
||||||
T |0x0234| -- Blank
|
T |0x0234|
|
||||||
T |0x0235| -- Blank
|
T |0x0235| -- Blank
|
||||||
--
|
--
|
||||||
-- Restore from Backup Warning
|
-- Restore from Backup Warning
|
||||||
@ -309,7 +361,7 @@ T |0x0236|This will overwrite the
|
|||||||
T |0x0237|current config with
|
T |0x0237|current config with
|
||||||
T |0x0238|that which is in
|
T |0x0238|that which is in
|
||||||
T |0x0239|the backup memory.
|
T |0x0239|the backup memory.
|
||||||
T |0x023A| -- blank line
|
T |0x023A| -- Blank
|
||||||
--
|
--
|
||||||
-- Utilities Copy flight modes
|
-- Utilities Copy flight modes
|
||||||
T |0x023D|Copy F-Mode Settings
|
T |0x023D|Copy F-Mode Settings
|
||||||
@ -341,7 +393,7 @@ T |0x0257|most be configured.
|
|||||||
T |0x025A|Select the desired flight mode
|
T |0x025A|Select the desired flight mode
|
||||||
T |0x025B|switch position to adjust settings
|
T |0x025B|switch position to adjust settings
|
||||||
T |0x025C|for each flight mode
|
T |0x025C|for each flight mode
|
||||||
T |0x025D| -- Blank
|
T |0x025D|
|
||||||
T |0x025E| -- Blank
|
T |0x025E| -- Blank
|
||||||
--
|
--
|
||||||
-- Utilities, Copy flight mode (Confirm)
|
-- Utilities, Copy flight mode (Confirm)
|
||||||
@ -357,6 +409,12 @@ T |0x0268|Negative = Nose Down/Roll Left
|
|||||||
T |0x0269|SAFE - Thr to Pitch
|
T |0x0269|SAFE - Thr to Pitch
|
||||||
T |0x026A|Use CAUTION for Yaw gain!/b
|
T |0x026A|Use CAUTION for Yaw gain!/b
|
||||||
--
|
--
|
||||||
|
T |0x026B|Head Speed
|
||||||
|
T |0x026C|Pinion
|
||||||
|
T |0x026D|Main Gear
|
||||||
|
T |0x026F|RPM Sensor
|
||||||
|
T |0x0272|Show Advanced Menus
|
||||||
|
--
|
||||||
T |0x0300|No compatible DSM RX...
|
T |0x0300|No compatible DSM RX...
|
||||||
T |0x0301|Waiting for RX to Restart
|
T |0x0301|Waiting for RX to Restart
|
||||||
--
|
--
|
||||||
|
@ -4,80 +4,112 @@ Rewrite/Enhancements by: Francisco Arzu
|
|||||||
|
|
||||||
Thanks to all the people volunteered to test it.
|
Thanks to all the people volunteered to test it.
|
||||||
|
|
||||||
# Introduction (v0.54)
|
# NOTE for FC6250HX FC+RX version
|
||||||
|
For the full size FC6250HX, Only use V0.55 or newer.
|
||||||
|
|
||||||
|
DO NOT use previous versions to do the Swashplate -> RX Orientation. The problem was that it did not have the orientation messages.. and you are choosing blind. The calibration will never stop until you place the RX in the right orientation, even after restarting the RX (if flashing red, is not in the right orientation.. if flashshing white is in the right orientation). If you run into this problem, and lights are blinking red, rotate the FC on the longer axis until you get white blinking.. keep it stable, will blink white faster andlet calibration finishes.. after that is back to normal.
|
||||||
|
|
||||||
|
# Introduction (v0.55)
|
||||||
|
|
||||||
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.
|
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).
|
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.
|
During `"Gyro Settings->initial setup"`, the RX asks the TX for model information behind the scenes. After setup, `"Gyro Settings->System Tools-> Relearn Servo Settings"` requests the TX servo configuration and stores it in the RX.
|
||||||
|
|
||||||
# Deployment
|
# Deployment
|
||||||
Make sure to manually create `/MODELS/DSMDATA` . The script will complain at startup if it does not exist. Here the script saves the Spektrun settings for each of your models.
|
|
||||||
|
|
||||||
Uncompress the Zip file (ZIP version) into your local computer.
|
|
||||||
In another window, open your TX SDCard and go to /SCRIPTS/TOOLS.
|
|
||||||
|
|
||||||
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first)
|
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first)
|
||||||
|
|
||||||
Copy the entire DSMLIB folder.
|
Uncompress the Zip file (ZIP version) into your local computer.
|
||||||
Copy the main script you want to use (Color or B&W).
|
In another window, open your TX SDCard.
|
||||||
|
|
||||||
|
1. The zip file has the same structure as your SDCard. If you want to copy all the content of the zip file into your SDCard top level folder, it will create all the directories and files in the right place.
|
||||||
|
2. Make sure to check that `/MODELS/DSMDATA` is there. The script will complain at startup if it does not exist. Here the script saves the Spektrun settings for each of your models.
|
||||||
|
|
||||||
Your TX SDCard should looks like this:
|
Your TX SDCard should looks like this:
|
||||||
|
|
||||||
/SCRIPTS/TOOLS
|
/SCRIPTS/TOOLS/ -- you only need one of the 3 to save some space in your TOOLS screen
|
||||||
DSM FwdPrg_05_BW.lua -- black/white text only
|
DSM FwdPrg_05_BW.lua -- black/white text only
|
||||||
DSM FwdPrg_05_Color.lua -- Color and touch radios
|
DSM FwdPrg_05_Color.lua -- Color and touch radios
|
||||||
DSM FwdPrg_05_MIN.lua -- `NEW!` Minimalistic version for radios with LOW memory (cannot setup new planes)
|
DSM FwdPrg_05_MIN.lua -- `NEW!` Minimalistic version for radios with LOW memory (cannot setup new planes)
|
||||||
|
|
||||||
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
|
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
|
||||||
DsmFwPrgLib.lua -- DSM Protocol Message and Menu engine
|
DsmFwPrgLib.lua -- DSM Protocol Message and Menu engine
|
||||||
DsmFwPrgSIMLib.lua -- Simulation of AR631, FC6250HX (For GUI development)
|
DsmFwPrgSIMLib.lua -- Simulation of AR631, FC6250HX (For GUI development)
|
||||||
SetupLib.lua -- Model Setup Screens
|
SetupLib.lua -- Model Setup Screens
|
||||||
msg_fwdp_en.txt -- `NEW!` Messages for forward programing externalized. To support other langs
|
msg_fwdp_en.txt -- `NEW!` Messages for forward programing externalized. To support other langs (english)
|
||||||
|
... a few other files
|
||||||
|
|
||||||
/SCRIPTS/TOOLS/DSMLIB/img -- Images for RX orientations
|
/SCRIPTS/TOOLS/DSMLIB/img -- Images for RX orientations
|
||||||
|
|
||||||
Other Directories
|
Other Directories
|
||||||
|
|
||||||
/MODELS/DSMDATA --(ALL CAPITALS) Data of model config (Wing Type, Servo Assignments)
|
/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
|
/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
|
# Common Questions
|
||||||
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
|
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
|
||||||
V0.53 and newer: The RX is listening to channel changes for this options. Configure the Switch to the channel, togling once the switch will select the channel on the menu field.
|
- V0.55 and newer: Problem solved.. Should allow you to select up to 12ch with the switch technique or with the scroller.
|
||||||
|
|
||||||
2. `Why Ch1 says Ch1 (TX:Ch3/Thr)?`:
|
- V0.53/0.54: The RX is listening to channel changes for this options. Configure the Switch to the channel, togling once the switch will select the channel on the menu field.
|
||||||
|
|
||||||
|
2. `Only able to switch to Fligh-mode 2 and 3, but not 1:`
|
||||||
|
Check that the module "Enable max throw" is OFF in you Multi-Module settings (where you do BIND), otherwise the TX signals will be out of range.
|
||||||
|
The multi-module is already adjusting the TX/FrSky servo range internally to match Spektrum.
|
||||||
|
|
||||||
|
3. `Why Ch1 says Ch1 (TX:Ch3/Thr)?`:
|
||||||
Radios with Multi-Module are usually configured to work the standard AETR convention. Spektrum uses TAER. The multi-module does the conversion when transmitting the signals. So `Spektrum Ch1 (Throttle)` really comes from the `TX Ch3`. We show both information (+name from the TX output). If your multi-module/radio is setup as TAER, the script will not do the re-arrangement.
|
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. `If i change the model name, the original model settings are lost.` This is correct, the model name is used to generate the file name (inside /MODEL/DSMDATA) who stores the model configuration. Currently EdgeTx and OpenTX has differt features where i could get either the Model Name or the YAML file where the EdgeTX model configuration is stored.. to keep the code compatible, the model name is used.
|
||||||
|
|
||||||
4. `Reversing a channel in my TX do not reverse the AS3X/SAFE reaction.` Correct, the channel stick direction and the Gyro direction are two separate things.
|
5. `Reversing a channel in my TX do not reverse the AS3X/SAFE reaction.` Correct, the chanel stick direction and the Gyro direction are two separate things.
|
||||||
|
|
||||||
4.1: First, you have setup your model so that the sticks and switches moves the surfaces in the right direction.
|
5.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.
|
5.2: Go to the script, `Model Setup` and setup your wing type, tail type, and select the channel assigment for each surface. Leave the servo settings the same as the values in the TX to start.
|
||||||
|
|
||||||
4.3: AR63X family: Go to `Forward programming->Gyro Setting->Initial Setup` (New/factory reset), or `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` (not new RX). This will load your current Gyro servo settings into the plane's RX.
|
5.3: Go to `Forward programming->Gyro Setting->Initial Setup` (New/factory reset), or `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` (not new). This will load your current Gyro servo settings into the plane's RX. This moves the current servo TX settings to the RX, so it is now in a known state.
|
||||||
|
|
||||||
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.
|
5.4: Verify that the AS3X and SAFE reacts in the proper direction. You can use the Flight mode configured as "Safe Mode: Auto-Level" to see if it moves the surfaces in the right direction.
|
||||||
|
|
||||||
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.
|
5.5: If a surface don't move in the right direction, go to the `Model Setup->Gyro Channel Reverse` to reverse the Gyro on the channels needed, and do again the `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` to tranfer the new settings to the RX.
|
||||||
|
|
||||||
|
5.6: Specktrum TX always passes the TX servo reverse as the Gyro Reverse, but on many OpenTX/EdgeTX radios, the Rud/Ail are usually reversed by default compared to Specktrum. So far i don't think that i can use this as a rule, that is why the `Gyro Channel Reverse` page exist.
|
||||||
|
|
||||||
|
|
||||||
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
|
# Changes and fixes
|
||||||
|
V0.55:
|
||||||
|
1. Finally found where the TX reports to the RX how many channels is transmiting. The TX now reports itself as a 12ch radio instead of 6h. (DSM Multi-Module limit). This fixes a few things:
|
||||||
|
|
||||||
|
|
||||||
|
a. Many places where you have to select channels > CH6 for Flight-Mode, Gains, Panic now works properly with the scroller. The radio is still validating that you are not selecting an invalid channel. For example, if you have an additional AIL on CH6, it will not allow you to use CH6 for FM or Gains.. it just move to the next valid one.
|
||||||
|
|
||||||
|
b. When setting up AIL/ELE on channels greater than CH6, on previous versions SAFE/AS3X was not moving them.. now they work up correctly. Set them up in the first in CH1-CH10. Why CH10?? Thats what fits on the reverse screen, otherwise, have to add more screens.
|
||||||
|
|
||||||
|
c. Some individual Gain channels was not allowing to setup on CH greater than CH6. Now is fixed.
|
||||||
|
|
||||||
|
2. User Interface:
|
||||||
|
a. `RTN` Key now works as `Back` when the screen has a `Back`. Makes it easy for navigation.. Presing `RTN` on the main screen exists the tool.
|
||||||
|
b. Much faster refresh of the menus. Optimize the process of send/recive menu data from the RX.
|
||||||
|
|
||||||
|
3. The TX now comunicates the SubTrim positions to the RX during `Relearn Servo Setting`. This changes the center of movement to one side or another. Really not much difference with small amounts of subtrim, previous versions where asuming subtrim of 0. When you have an extreame subtrim to one side, it was not moving simetrically.
|
||||||
|
|
||||||
|
4. Support for FC6250HX (the one with separate RX).. Setup Swashplate type, RX orientation works properly.. This are menu options that the smaller version that comes in the
|
||||||
|
Blade 230S did not have.
|
||||||
|
|
||||||
|
|
||||||
V0.54:
|
V0.54:
|
||||||
1. Fix a problem in the Attitude Trim page (`Gyro Settings->System Setup->SAFE/Panic Setup->Attitude Trim`). It was not saving the values after exiting the menu. This is to change what SAFE considers "Level" flying.
|
1. Fix a problem in the Attitude Trim page (`Gyro Settings->System Setup->SAFE/Panic Setup->Attitude Trim`). It was not saving the values after exiting the menu. This is to change what SAFE considers "Level" flying.
|
||||||
2. Wings 2-Ail 2-Flaps had a bug on the 2nd flap.
|
2. Wings 2-Ail 2-Flaps had a bug on the 2nd flap.
|
||||||
3. New Minimalistic script (`DsmFwdPrg_05_MIN.lua`): For radios with very low memory (FrSky QX7, RM Zorro, others). It can only change existing settings, but does not have the Plane Setup menus to setup a completly new plane. In some radios, the very first time it runs (compile + run), it might give you a `not enouth memory` error.. try to run it again.
|
3. New Minimalistic script (`DsmFwdPrg_05_MIN.lua`): For radios with very low memory (FrSky QX7, RM Zorro, others). It can only change existing settings, but does not have the Plane Setup menus to setup a completly new plane. In some radios, the very first time it runs (compile + run), it might give you a `not enouth memory` error.. try to run it again.
|
||||||
4. External menu message file (DSMLIB/msg_en.txt and msg_MIN_es.txt). Intial work to do localization and different languages.
|
4. External menu message file (DSMLIB/msg_fwdp_en.txt and MIN_msg_fwdp_en.txt). Intial work to do localization and different languages.
|
||||||
|
|
||||||
V0.53:
|
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.
|
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.
|
||||||
@ -91,13 +123,14 @@ V0.52:
|
|||||||
4. Write Log of the conversation between RX/TX. To be used for debugging a problem is reported.
|
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.
|
5. Provide a simulation of RX to do GUI development in Companion, and understand patterns of how the data is organized.
|
||||||
|
|
||||||
|
|
||||||
# Tested Hardware
|
# Tested Hardware
|
||||||
- AR631/AR637xx
|
- AR631/AR637xx
|
||||||
- FC6250HX (Blade 230S V2 Helicopter)
|
- FC6250HX (Blade 230S V2 Helicopter; FC+RX in one, mini version)
|
||||||
|
- FC6250HX (Separate RX.. use only V55 or newer of this tool)
|
||||||
- AR636 (Blade 230S V1 Heli firmware 4.40)
|
- AR636 (Blade 230S V1 Heli firmware 4.40)
|
||||||
|
|
||||||
- Radiomaster TX16S (All versions)
|
- Radiomaster TX16S (All versions)
|
||||||
- FrSky QX7, Radimaster Boxter (Minimalistic version)
|
|
||||||
|
|
||||||
Please report if you have tested it with other receivers to allow us to update the documentation. Code should work up to 10 channels for the main surfaces (Ail/Ele/etc). All Spektrum RX are internally 20 channels, so you can use Ch7 for Flight Mode even if your RX is only 6 channels (See common Questions)
|
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)
|
||||||
|
|
||||||
@ -146,6 +179,7 @@ The menu messages are stored in DSMLIB/msg_fwdp_en.txt (For english). Just add t
|
|||||||
LT|0x00B0|Self-Level/Angle Dem
|
LT|0x00B0|Self-Level/Angle Dem
|
||||||
LT|0x00B1|Envelope
|
LT|0x00B1|Envelope
|
||||||
|
|
||||||
|
|
||||||
# LOG File
|
# 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 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)
|
||||||
@ -203,7 +237,6 @@ The RX validates the data. if you change to an invalid channel or do a invalid n
|
|||||||
- RX simulation for GUI development: turn on `SIMULATION_ON=true` in the beginning of the lua file
|
- RX simulation for GUI development: turn on `SIMULATION_ON=true` in the beginning of the lua file
|
||||||
- Test it on AR631, AR637xx, FC6250HX (Helicopter)
|
- Test it on AR631, AR637xx, FC6250HX (Helicopter)
|
||||||
|
|
||||||
|
|
||||||
### Some settings that can change (top of Lua file):
|
### Some settings that can change (top of Lua file):
|
||||||
SIMULATION_ON = false -- FALSE: hide similation menu (DEFAULT), TRUE: show RX simulation menu
|
SIMULATION_ON = false -- FALSE: hide similation menu (DEFAULT), TRUE: show RX simulation menu
|
||||||
DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm_log.txt)
|
DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm_log.txt)
|
||||||
@ -215,8 +248,6 @@ The RX validates the data. if you change to an invalid channel or do a invalid n
|
|||||||
in the MINimalistic version, the RX is doing all the range validation, and will show invalid options temporarilly. In an Spektrum radio, it happens so fast, that you don't notice it, but in LUA scripts who are slower, you can see it in the screen.
|
in the MINimalistic version, the RX is doing all the range validation, and will show invalid options temporarilly. In an Spektrum radio, it happens so fast, that you don't notice it, but in LUA scripts who are slower, you can see it in the screen.
|
||||||
In the COLOR version, The code has hardcoded the valid ranges to avoid this problem.
|
In the COLOR version, The code has hardcoded the valid ranges to avoid this problem.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2. Glider/Heli/Drone wing types not ready.
|
2. Glider/Heli/Drone wing types not ready.
|
||||||
|
|
||||||
For Helicopter, use airplane normal wing and normal tail
|
For Helicopter, use airplane normal wing and normal tail
|
||||||
|