diff --git a/Lua_scripts/DSM FwdPrg_05_BW.lua b/Lua_scripts/DSM FwdPrg_05_BW.lua deleted file mode 100644 index b81ffaf..0000000 --- a/Lua_scripts/DSM FwdPrg_05_BW.lua +++ /dev/null @@ -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 } \ No newline at end of file diff --git a/Lua_scripts/DSM FwdPrg_05_Color.lua b/Lua_scripts/DSM FwdPrg_05_Color.lua index c7bd7d2..c177b45 100644 --- a/Lua_scripts/DSM FwdPrg_05_Color.lua +++ b/Lua_scripts/DSM FwdPrg_05_Color.lua @@ -1,5 +1,5 @@ -local toolName = "TNS|DSM Forward Prog v0.54 (Color+Touch) |TNE" -local VERSION = "v0.54" +local toolName = "TNS|DSM Forward Prog v0.55a (Color) |TNE" +local VERSION = "v0.55a" ---- ######################################################################### ---- # # @@ -27,19 +27,21 @@ local VERSION = "v0.54" -- 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_LCD = false -- Interactive Information on LCD of Menu data from RX local USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX) local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/" local IMAGE_PATH = DSMLIB_PATH .. "img/" -local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmSetupLib.lua"), "Not-Found: DSMLIB/DsmSetupLib.lua")(DEBUG_ON,SIMULATION_ON) +local 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 LINE_TYPE = dsmLib.LINE_TYPE -local DISP_ATTR = dsmLib.DISP_ATTR -local DSM_Context = dsmLib.DSM_Context +local PHASE = menuLib.PHASE +local LINE_TYPE = menuLib.LINE_TYPE +local DISP_ATTR = menuLib.DISP_ATTR +local DSM_Context = menuLib.DSM_Context 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_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) @@ -93,6 +95,7 @@ local warningScreenON = true --------------------- lcd.sizeText replacement ------------------------------------------------- -- EdgeTx dont have lcd.sizeText, so we do an equivalent one using the string length and 5px per character local function my_lcd_sizeText(s) + if (s==nil) then return 20 end -- return: If IS_EDGETX then lcd.sizeText() else string.len() return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10) end @@ -100,31 +103,76 @@ end local function GUI_SwitchToRX() -- 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() - dsmLib.LOG_close() + modelLib.ReadTxModelData() + modelLib.ST_LoadFileData() + modelLib.CreateDSMPortChannelInfo() - SIMULATION_ON = false - dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON) - DSM_Context = dsmLib.DSM_Context + local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua") + menuProcessor = dsmLib(Log, menuLib, modelLib, DEBUG_ON) - dsmLib.Init(toolName) -- Initialize Library - dsmLib.SetDSMChannelInfo(dsmChannelInfo, description) -- send the dsmChannelInfo to new instance library - dsmLib.StartConnection() + dsmLib = nil + collectgarbage("collect") + + menuProcessor.init(toolName) -- Initialize Library DSM_Context.Refresh_Display = true end local function GUI_SwitchToSIM() - dsmLib.ReleaseConnection() - dsmLib.LOG_close() + menuProcessor.done() + Log.LOG_close() - SIMULATION_ON = true - dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgSIMLib.lua"), "Not-Found: DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON) - DSM_Context = dsmLib.DSM_Context + menuProcessor = nil + collectgarbage("collect") - dsmLib.Init(toolName) -- Initialize Library - dsmLib.StartConnection() + local simLib = assert(loadScript(DSMLIB_PATH.."DsmSimMenuLib.lua"), "Not-Found: DSMLIB/DsmSimMenuLib.lua") + 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 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 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_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum) else -- Non Selectable Menu Lines, plain text -- Can be use for sub headers or just regular text lines (like warnings) - local bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0 + 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 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) x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text end @@ -235,17 +283,17 @@ local function GUI_Display_Line_Value(lineNum, line, value, selected, editing) ---------- NAME Part local header = line.Text -- ONLY do this for Flight Mode (Right Align or Centered) - if (dsmLib.isFlightModeLine(line)) then + if (menuLib.isFlightModeLine(line)) then -- Display Header + Value together - header = dsmLib.GetFlightModeValue(line) + header = menuLib.GetFlightModeValue(line) -- 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 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) x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text 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 - --------- VALUE PART, Skip for Flight Mode since already show the value - if not dsmLib.isFlightModeLine(line) then - if dsmLib.isSelectableLine(line) then + + --------- VALUE PART, Skip for Flight Mode since already show the value + 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?? -- value = "["..value .. "]" --end -- Can select/edit value, Box it local tw = math.max(my_lcd_sizeText(value)+10,45) -- Width of the Text in the lcd - GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected, not dsmLib.isListLine(line)) + GUI_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) 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 - -- Debug info for line Value RANGE when Debug on LCD - if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG, y, line.MinMaxDebug or "", SMLSIZE + LCD_DEBUG_COLOR) end -- display debug Min/Max end local function GUI_Display_Menu(menu) @@ -290,23 +339,19 @@ local function GUI_Display_Menu(menu) -- Back Button if menu.BackId ~= 0 then - GUI_Diplay_Button(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,"Back",ctx.SelLine == dsmLib.BACK_BUTTON) - GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,dsmLib.BACK_BUTTON) + 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,menuLib.BACK_BUTTON) end -- Next Button if menu.NextId ~= 0 then - GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON) - GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.NEXT_BUTTON) + 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,menuLib.NEXT_BUTTON) end -- Prev Button if menu.PrevId ~= 0 then - GUI_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON) - GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.PREV_BUTTON) + 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,menuLib.PREV_BUTTON) end - - -- Debug on LCD, Show the menu Indo and Phase we are on - if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),SMLSIZE+LCD_DEBUG_COLOR) end -- Phase we are in - if (DEBUG_ON_LCD) then lcd.drawText(0,240,dsmLib.menu2String(menu),SMLSIZE+LCD_DEBUG_COLOR) end -- Menu Info end ------------------------------------------------------------------------------------------------------------ @@ -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) 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_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_10) 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) 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_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_10) end @@ -373,74 +418,86 @@ local function GUI_Display() lcd.clear(LCD_TOOL_BGCOLOR) GUI_clearTouchButtons() - if LCD_W == 480 then - local header = "DSM Forward Programming "..VERSION.." " - if ctx.Phase ~= PHASE.RX_VERSION then - header = header .. "RX "..ctx.RX.Name.." v"..ctx.RX.Version - end - - --Draw title - lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR) - lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE) - --Draw RX Menu - if ctx.Phase == PHASE.RX_VERSION then - if (ctx.isReset) then - lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x301), BLINK) -- Waiting for Restart - else - lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x300), BLINK) -- Waiting for RX - end - else - local menu = ctx.Menu - - - if menu.Text ~= nil then - GUI_Display_Menu(menu) - - for i = 0, dsmLib.MAX_MENU_LINES do - local line = ctx.MenuLines[i] - - if i == ctx.SelLine then - -- DEBUG: Display Selected Line info for ON SCREEN Debugging - if (DEBUG_ON_LCD) then lcd.drawText(0,255,dsmLib.menuLine2String(line),SMLSIZE + LCD_DEBUG_COLOR) end - end - - if line ~= nil and line.Type ~= 0 then - if line.Type == LINE_TYPE.MENU then - GUI_Display_Line_Menu(i, line, i == ctx.SelLine) - else - if line.Val ~= nil then - local value = line.Val - - if dsmLib.isListLine(line) then -- for Lists of Strings, get the text - value = dsmLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text - local imgData = dsmLib.Get_List_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display?? - - if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value - GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_START, imgData) - end - end - - GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine) - end - end -- if ~MENU - end -- if Line[i]~=nil - end -- for - - if IS_EDGETX and ctx.isEditing() then - -- Display Touch button for Editing values - GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine]) - end - end - end - else + if LCD_W ~= 480 then -- Different Resolution.. Maybe just adjusting some of the constants will work, adjust it in DSM_Init?? -- LCD_X_LINE_TITLE, LCD_Y_LINE_START, etc lcd.drawText(LCD_X_LINE_TITLE,100,"Only supported in Color Radios of 480 resolution", BLINK) + 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 ------------------------------------------------------------------------------------------------------------- -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 Speed = getRotEncSpeed() @@ -499,7 +556,7 @@ local function GUI_HandleEvent(event, touchState) end if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing - if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",dsmLib.phase2String(ctx.Phase),touchState.x, touchState.y) end + 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) if button then -- Found a valid line @@ -514,64 +571,73 @@ local function GUI_HandleEvent(event, touchState) 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 (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_EXIT\n",menuLib.phase2String(ctx.Phase)) end if ctx.Phase == PHASE.RX_VERSION then - dsmLib.ReleaseConnection() -- Just Exit the Script + menuLib.ChangePhase(PHASE.EXIT_DONE) -- Just Exit the Script else if ctx.isEditing() then -- Editing a Line, need to restore original value local line = ctx.MenuLines[ctx.EditLine] line.Val = originalValue - dsmLib.Value_Write_Validate(line) + menuLib.Value_Write_Validate(line) + elseif (menu.BackId > 0 ) then -- Back?? + ctx.SelLine = menuLib.BACK_BUTTON + event = EVT_VIRTUAL_ENTER else - dsmLib.ChangePhase(PHASE.EXIT) + menuLib.ChangePhase(PHASE.EXIT) end end - return end + + if ctx.Phase == PHASE.RX_VERSION then 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 (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 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 - dsmLib.MoveSelectionLine(1) + menuLib.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 (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 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 - dsmLib.MoveSelectionLine(-1) + menuLib.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 (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",menuLib.phase2String(ctx.Phase)) end if ctx.isEditing() then -- reset the value to default - dsmLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed + menuLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed end return end if event == EVT_VIRTUAL_ENTER then ctx.Refresh_Display=true - if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",dsmLib.phase2String(ctx.Phase), ctx.SelLine) end - if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back - dsmLib.GotoMenu(menu.BackId,0x80) - elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next - dsmLib.GotoMenu(menu.NextId,0x82) - elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev - dsmLib.GotoMenu(menu.PrevId,0x81) + if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",menuLib.phase2String(ctx.Phase), ctx.SelLine) end + if ctx.SelLine == menuLib.BACK_BUTTON then -- Back + if (menu.BackId==0xFFF9) then + -- SPECIAL Main Menu + GUI_SwitchToMainMenu() + else + 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 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 -- SPECIAL Simulation menu to go to RX 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 - 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 else -- Enter on a Value 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 ctx.EditLine = ctx.SelLine originalValue = menuLines[ctx.SelLine].Val - dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT) + menuLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT) end end end @@ -655,9 +727,16 @@ end ------------------------------------------------------------------------------------------------------------ -- Init local function DSM_Init() + Log.LOG_open() + init_colors() - dsmLib.Init(toolName) -- Initialize Library - return dsmLib.StartConnection() + modelLib.ReadTxModelData() + modelLib.ST_LoadFileData() + modelLib.CreateDSMPortChannelInfo() + + menuLib.Init() + menuProcessor.init() + return 0 end ------------------------------------------------------------------------------------------------------------ @@ -667,7 +746,7 @@ local function DSM_Run(event,touchState) if event == nil then error("Cannot be run as a model script!") - dsmLib.LOG_close() + Log.LOG_close() return 2 end @@ -677,12 +756,15 @@ local function DSM_Run(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 -- 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 refreshInterval = 20 -- 200ms end @@ -697,7 +779,7 @@ local function DSM_Run(event,touchState) end if ctx.Phase == PHASE.EXIT_DONE then - dsmLib.LOG_close() + Log.LOG_close() return 2 else return 0 diff --git a/Lua_scripts/DSM FwdPrg_05_MIN.lua b/Lua_scripts/DSM FwdPrg_05_MIN.lua index a046ed4..62aa215 100644 --- a/Lua_scripts/DSM FwdPrg_05_MIN.lua +++ b/Lua_scripts/DSM FwdPrg_05_MIN.lua @@ -1,6 +1,4 @@ -local toolName = "TNS|DSM Frwd Prog v0.54-beta (MIN)|TNE" - ---local ModelParam = ... +local toolName = "TNS|DSM Frwd Prog v0.55a (MIN)|TNE" ---- ######################################################################### ---- # # @@ -20,67 +18,57 @@ local toolName = "TNS|DSM Frwd Prog v0.54-beta (MIN)|TNE" ---- ######################################################################### ---############################################################################### --- Multi buffer for DSM description --- Multi_Buffer[0..2]=="DSM" -> Lua script is running --- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent --- Multi_Buffer[4..9]=6 bytes of TX to RX data --- Multi_Buffer[10..25]=16 bytes of RX to TX data --- --- To start operation: --- Write 0x00 at address 3 --- Write 0x00 at address 10 --- Write "DSM" at address 0..2 ---############################################################################### - -local VERSION = "v0.54-MIN" +local VERSION = "v0.55a-MIN" local LANGUAGE = "en" local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/" local LOG_FILE = "/LOGS/dsm_min_log.txt" local MSG_FILE = DSMLIB_PATH.."msg_fwdp_" .. LANGUAGE .. ".txt" local MSG_FILE_MIN = DSMLIB_PATH.."MIN_msg_fwdp_" .. LANGUAGE .. ".txt" +local MSG_MIN_FILE_OFFSET = 20000 -- Phase +local PH_INIT = 0 local PH_RX_VER, PH_TITLE, PH_TX_INFO, PH_LINES, PH_VALUES = 1, 2, 3, 4, 5 -local PH_VAL_CHANGING, PH_VAL_WAIT, PH_VAL_CHNG_END = 6, 7, 8 +local PH_VAL_CHANGING, PH_VAL_EDITING, PH_VAL_EDIT_END = 6, 7, 8 local PH_WAIT_CMD, PH_EXIT_REQ, PH_EXIT_DONE = 9, 10, 11 -- Line Types local LT_MENU = 0x1C -local LT_LIST, LT_LIST_VALIDATE, LT_LIST_TOG = 0x6C, 0x0C, 0x4C -local LT_VALUE_NOCHANGING = 0x60 +local LT_LIST_NC, LT_LIST_NC2, LT_LIST, LT_LIST_ORI, LT_LIST_TOG = 0x6C, 0x6D, 0x0C, 0xCC, 0x4C +local LT_VALUE_NC = 0x60 local LT_VALUE_PERCENT, LT_VALUE_DEGREES = 0xC0, 0xE0 -local Phase = PH_RX_VER -local Waiting_RX = 0 +local Phase = PH_INIT +local SendDataToRX = 1 -- Initiate Sending Data local Text = {} local List_Text = {} local List_Text_Img = {} -local Flight_Mode = { [0] = "Flight Mode" } +local Flight_Mode = "Flight Mode" local RxName = {} -local InactivityTime = 0 -local Value_Change_Step = 0 +local TXInactivityTime = 0 +local RXInactivityTime = 0 local TX_Info_Step = 0 local TX_Info_Type = 0 +local Change_Step = 0 local originalValue = 0 -local ctx = { - SelLine = 0, -- Current Selected Line - EditLine = nil, -- Current Editing Line - CurLine = -1, -- Current Line Requested/Parsed via h message protocol - isReset = false -- false when starting from scracts, true when starting from Reset -} +local TX_MAX_CH = 12 - 6 -- Number of Channels after Ch6 + +--local ctx = { +local ctx_SelLine = 0 -- Current Selected Line +local ctx_EditLine = nil -- Current Editing Line +local ctx_CurLine = -1 -- Current Line Requested/Parsed via h message protocol +local ctx_isReset = false -- false when starting from scracts, true when starting from Reset +--} local MODEL = { modelName = "", -- The name of the model comming from OTX/ETX modelOutputChannel = {}, -- Output information from OTX/ETX AirWingTailDesc = "", - --TX_CH_TEXT = {}, - --PORT_TEXT = {}, DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script } @@ -89,10 +77,9 @@ local MenuLines = {} local RX = { Name = "", Version = "" } local logFile = nil -local logCount = 0 -local LCD_X_LINE_TITLE = 0 -local LCD_X_LINE_VALUE = 75 +--local LCD_X_LINE_TITLE = 0 +--local LCD_X_LINE_VALUE = 75 local LCD_W_BUTTONS = 19 local LCD_H_BUTTONS = 10 @@ -119,6 +106,31 @@ local function LOG_close() if (logFile ~= nil) then io.close(logFile) end end +----- Line Type +local function isIncrementalValueUpdate(line) + if (line.Type == LT_LIST_NC or line.Type == LT_LIST_NC2 or + line.Type == LT_VALUE_NC or line.Type == LT_VALUE_DEGREES) then return false end + return true +end + +local function isSelectable(line) + if (line.TextId == 0x00CD) then return true end -- Exceptiom: Level model and capture attitude + if (line.Type == LT_MENU and line.ValId == line.MenuId) then return false end -- Menu to same page + if (line.Type ~= LT_MENU and line.Max == 0) then return false end -- Read only data line + if (line.Type ~= 0 and line.TextId < 0x8000) then return true end -- Not Flight Mode + return false; +end + +local function isListLine(line) + return line.Type==LT_LIST_NC or line.Type==LT_LIST_NC2 or + line.Type == LT_LIST or line.Type == LT_LIST_ORI or line.Type == LT_LIST_TOG +end + +local function isEditing() + return ctx_EditLine ~= nil +end + + ---------------- DSM Values <-> Int16 Manipulation -------------------------------------------------------- local function int16_LSB(number) -- Less Significat byte @@ -149,30 +161,118 @@ local function sInt16ToDsm(value) -- Convent to SIGNED DSM Value return value end ------------------------------------------------------------------------------------------------------------- +----------------------- +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 f=MSG_FILE + if (pos >= MSG_MIN_FILE_OFFSET) then -- Depending on offset, use the main, or MIN version + f = MSG_FILE_MIN + pos = pos - MSG_MIN_FILE_OFFSET + end + + -- open and read File + local dataFile = io.open(f, "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=="/") then pipe=6 -- far right end, like comment + 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 -- Fpr + + return type, index, rtrim(line), newPos +end + +local function GetTextFromFile(pos) + if (pos==nil) then return nil end + local t,i,l, p = GetTextInfoFromFile(pos) + return l +end + +----------------------- local function Get_Text(index) - local out = Text[index] or string.format("Unknown_%X", index) + local pos = Text[index] + local out = "" + + if (pos == nil) then + out = string.format("Unknown_%X", index) + else + out = GetTextFromFile(pos) + end + + --local out = Text[index] or string.format("Unknown_%X", index) if (index >= 0x8000) then - out = Flight_Mode[0] + out = Flight_Mode end return out end local function Get_Text_Value(index) - local out = List_Text[index] or Get_Text(index) + local pos = List_Text[index] + local out = "" + + if (pos == nil) then + out = Get_Text(index) + else + out = GetTextFromFile(pos) + end + + --local out = List_Text[index] or Get_Text(index) return out end ------------------------------------------------------------------------------------------------------------- +--------------------- local function Get_RxName(index) local out = RxName[index] or string.format("Unknown_%X", index) return out end ------------------------------------------------------------------------------------------------------------- +-------------------- + +local function DSM_Connect() + --Init TX buffer + multiBuffer(3, 0x00) + --Init RX buffer + multiBuffer(10, 0x00) + --Init telemetry + multiBuffer(0, string.byte('D')) + multiBuffer(1, string.byte('S')) + multiBuffer(2, string.byte('M')) +end + local function DSM_Release() multiBuffer(0, 0) - Phase = PH_EXIT_DONE end ------------------------------------------------------------------------------------------------------------- +-------------------- local function DSM_Send(...) local arg = { ... } for i = 1, #arg do @@ -180,157 +280,156 @@ local function DSM_Send(...) end multiBuffer(3, 0x70 + #arg) end ------------------------------------------------------------------------------------------------------------- +--------------------- function ChangePhase(newPhase) Phase = newPhase - Waiting_RX = 0 + SendDataToRX = 1 end local function Value_Add(dir) - local line = MenuLines[ctx.SelLine] + local line = MenuLines[ctx_SelLine] + local origVal = line.Val + local inc = dir - Speed = getRotEncSpeed() - if Speed == ROTENC_MIDSPEED then - line.Val = line.Val + (5 * dir) - elseif Speed == ROTENC_HIGHSPEED then - line.Val = line.Val + (15 * dir) - else - line.Val = line.Val + dir + if (not isListLine(line)) then -- List do slow inc + local Speed = getRotEncSpeed() + if Speed == ROTENC_MIDSPEED then + inc = (5 * dir) + elseif Speed == ROTENC_HIGHSPEED then + inc = (15 * dir) + end end + 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 - ChangePhase(PH_VAL_CHANGING) - Value_Change_Step = 0 + if (origVal~=line.Val and isIncrementalValueUpdate(line)) then + -- Update RX value on every change, otherwise, just at the end + ChangePhase(PH_VAL_CHANGING) + end end ------------------------------------------------------------------------------------------------------------- +-------------- local function GotoMenu(menuId, lastSelectedLine) Menu.MenuId = menuId - ctx.SelLine = lastSelectedLine + ctx_SelLine = lastSelectedLine -- Request to load the menu Again ChangePhase(PH_TITLE) end -local function isSelectable(line) - if (line.TextId == 0x00CD) then return true end -- Exceptiom: Level model and capture attitude - if (line.Type == LT_MENU and line.ValId == line.MenuId) then return false end -- Menu to same page - if (line.Type ~= LT_MENU and line.Max == 0) then return false end -- Read only data line - if (line.Type ~= 0 and line.TextId < 0x8000) then return true end -- Not Flight Mode - return false; -end - -local function isListLine(line) - return line.Type==LT_LIST or line.Type == LT_LIST_VALIDATE or line.Type == LT_LIST_TOG -end - -local function DSM_Menu(event) +local function DSM_HandleEvent(event) if event == EVT_VIRTUAL_EXIT then if Phase == PH_RX_VER then - DSM_Release() -- Exit program + Phase = PH_EXIT_DONE -- Exit program else - if ctx.EditLine ~= nil then -- Editing a Line, need to restore original value - MenuLines[ctx.EditLine].Val = originalValue + if isEditing() then -- Editing a Line, need to restore original value + MenuLines[ctx_EditLine].Val = originalValue event = EVT_VIRTUAL_ENTER else - ChangePhase(PH_EXIT_REQ) + if (Menu.BackId > 0 ) then -- Back?? + ctx_SelLine = -1 --Back Button + event = EVT_VIRTUAL_ENTER + else + ChangePhase(PH_EXIT_REQ) + end end end - end + end -- Exit if Phase == PH_RX_VER then return end -- nothing else to do if event == EVT_VIRTUAL_NEXT then - if ctx.EditLine ~= nil then + if isEditing() then -- Editting? Value_Add(1) else - -- not changing a value - - if ctx.SelLine < 7 then -- On a regular line - local num = ctx.SelLine -- Find the prev selectable - for i = ctx.SelLine + 1, 6, 1 do + if ctx_SelLine < 7 then -- On a regular line + local num = ctx_SelLine -- Find the prev selectable + for i = ctx_SelLine + 1, 6, 1 do local line = MenuLines[i] if isSelectable(line) then - ctx.SelLine = i + ctx_SelLine = i break end end - if num == ctx.SelLine then -- No Selectable Line + if num == ctx_SelLine then -- No Selectable Line if Menu.NextId ~= 0 then - ctx.SelLine = 7 -- Next + ctx_SelLine = 7 -- Next elseif Menu.PrevId ~= 0 then - ctx.SelLine = 8 -- Prev + ctx_SelLine = 8 -- Prev end end elseif Menu.PrevId ~= 0 then - ctx.SelLine = 8 -- Prev + ctx_SelLine = 8 -- Prev end end - elseif event == EVT_VIRTUAL_PREV then - if ctx.EditLine ~= nil then -- In Edit Mode + return + end + + if event == EVT_VIRTUAL_PREV then + if isEditing() then -- In Edit Mode Value_Add(-1) else - if ctx.SelLine == 8 and Menu.NextId ~= 0 then - ctx.SelLine = 7 -- Next - elseif ctx.SelLine > 0 then - if ctx.SelLine > 6 then - ctx.SelLine = 7 --NEXT + if ctx_SelLine == 8 and Menu.NextId ~= 0 then + ctx_SelLine = 7 -- Next + elseif ctx_SelLine > 0 then + if ctx_SelLine > 6 then + ctx_SelLine = 7 --NEXT end - local num = ctx.SelLine -- Find Prev Selectable line - for i = ctx.SelLine - 1, 0, -1 do + local num = ctx_SelLine -- Find Prev Selectable line + for i = ctx_SelLine - 1, 0, -1 do local line = MenuLines[i] if isSelectable(line) then - ctx.SelLine = i + ctx_SelLine = i break end end - if num == ctx.SelLine then -- No Selectable Line + if num == ctx_SelLine then -- No Selectable Line if (Menu.BackId > 0) then - ctx.SelLine = -1 -- Back + ctx_SelLine = -1 -- Back end end else - ctx.SelLine = -1 -- Back + ctx_SelLine = -1 -- Back end end - elseif event == EVT_VIRTUAL_ENTER_LONG then - if ctx.EditLine ~= nil then - -- reset the value to default - --if MenuLines[ctx.SelLine].Type ~= LIST_MENU_NOCHANGING then - MenuLines[ctx.SelLine].Val = MenuLines[ctx.SelLine].Def + return + end + + if event == EVT_VIRTUAL_ENTER_LONG then + if isEditing() then + MenuLines[ctx_SelLine].Val = MenuLines[ctx_SelLine].Def ChangePhase(PH_VAL_CHANGING) - Value_Change_Step = 0 - --end end elseif event == EVT_VIRTUAL_ENTER then - if ctx.SelLine == -1 then -- Back + if ctx_SelLine == -1 then -- Back GotoMenu(Menu.BackId, 0x80) - elseif ctx.SelLine == 7 then -- Next + elseif ctx_SelLine == 7 then -- Next GotoMenu(Menu.NextId, 0x82) - elseif ctx.SelLine == 8 then -- Prev + elseif ctx_SelLine == 8 then -- Prev GotoMenu(Menu.PrevId, 0x81) - elseif ctx.SelLine >= 0 and MenuLines[ctx.SelLine].Type == LT_MENU then - GotoMenu(MenuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the next menu + elseif ctx_SelLine >= 0 and MenuLines[ctx_SelLine].Type == LT_MENU then + GotoMenu(MenuLines[ctx_SelLine].ValId, ctx_SelLine) -- ValId is the next menu else -- value entry - if ctx.EditLine ~= nil then - ctx.EditLine = nil -- Done Editting - Value_Change_Step = 0 - ChangePhase(PH_VAL_CHNG_END) + if isEditing() then + ctx_EditLine = nil -- Done Editting + ChangePhase(PH_VAL_EDIT_END) else -- Start Editing - ctx.EditLine = ctx.SelLine - originalValue = MenuLines[ctx.SelLine].Val - ChangePhase(PH_VAL_WAIT) + ctx_EditLine = ctx_SelLine + originalValue = MenuLines[ctx_SelLine].Val + ChangePhase(PH_VAL_EDITING) end end end end ------------------------------------------------------------------------------------------------------------ + local function SendTxInfo(portNo) -- TxInfo_Type=0 : AR636 Main Menu (Send port/Channel info + SubTrim + Travel) -- TxInfo_Type=1 : AR630-637 Famly Main Menu (Only Send Port/Channel usage Msg 0x20) @@ -341,11 +440,11 @@ local function SendTxInfo(portNo) -- AR630 family: Both TxInfo_Type (ManinMenu=0x1, Other First Time Configuration = 0x1F) local info = MODEL.DSM_ChannelInfo[portNo] DSM_Send(0x20, 0x06, portNo, portNo, info[0],info[1]) - LOG_write("DSM_TxInfo_20(Port=#%d, Port Use)\n", portNo) + LOG_write("TX:DSM_TxInfo_20(Port=#%d, Port Use)\n", portNo) - if (TX_Info_Type == 0x1F) then + if (TX_Info_Type == 0x1F) then -- SmartRx TX_Info_Step = 1 - elseif (TX_Info_Type == 0x00) then + elseif (TX_Info_Type == 0x00) then -- AR636 TX_Info_Step = 2 end elseif (TX_Info_Step == 1) then @@ -354,134 +453,156 @@ local function SendTxInfo(portNo) local rightTravel = math.abs(math.floor(info.max/10)) DSM_Send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel) - LOG_write("DSM_TxInfo_23(Port=#%d,ServoTravel(L=%d - R=%d))\n", portNo,leftTravel,rightTravel) + LOG_write("TX:DSM_TxInfo_Travel(Port=#%d,(L=%d - R=%d))\n", portNo,leftTravel,rightTravel) TX_Info_Step = 2 elseif (TX_Info_Step == 2) then - local data = {[0]= -- Start at 0 - {[0]= 0x0, 0x00, 0x07, 0xFF }, -- Ch1 Thr: 0 00 07 FF Subtrim ?? - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch2 Ail: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch3 Elev: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch4 Rud: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch5 Gear: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch6 Aux1: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch7 Aux2: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch8 Aux3: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch9 Aux4: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch10 Aux5: 0 8E 07 72 Subtrim 0 - } - local info = data[portNo] - local b1,b2,b3,b4 = info[0], info[1], info[2], info[3] + -- Subtrim + local b1,b2,b3,b4 = 0x00, 0x8E, 0x07, 0x72 -- (192-1904) + if (portNo==0) then -- Thr + b1,b2,b3,b4 = 0x00, 0x00, 0x07, 0xFF -- (0-2047) + end DSM_Send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it. - LOG_write("DSM_TxInfo_21(Port=#%d, SubTrim)\n", portNo) + LOG_write("TX:DSM_TxInfo_SubTrim(Port=#%d)\n", portNo) - if (TX_Info_Type == 0x00) then + if (TX_Info_Type == 0x00) then -- AR636 TX_Info_Step = 5 -- End Step else TX_Info_Step = 3 end elseif (TX_Info_Step == 3) then - LOG_write("DSM_TxInfo_24?(Port=#%d)\n", portNo) + LOG_write("TX:DSM_TxInfo_24?(Port=#%d)\n", portNo) DSM_Send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown TX_Info_Step = 4 elseif (TX_Info_Step == 4) then - LOG_write("DSM_TxInfo_24?(Port=#%d)\n", portNo) + LOG_write("TX:DSM_TxInfo_24?(Port=#%d)\n", portNo) DSM_Send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown TX_Info_Step = 5 elseif (TX_Info_Step == 5) then - LOG_write("DSM_TxInfo_22(Port=#%d, END of Data)\n", portNo) + LOG_write("TX:DSM_TxInfo_END(Port=#%d)\n", portNo) DSM_Send(0x22, 0x04, 0x00, 0x00) TX_Info_Step = 0 -- Done!! end if (TX_Info_Step > 0) then - Waiting_RX = 0 -- keep Transmitig + SendDataToRX = 1 -- keep Transmitig end end +local function DSM_SendUpdate(line) + local valId = line.ValId + local value = sInt16ToDsm(line.Val) + + LOG_write("TX:ChangeValue(VId=0x%04X,Val=%d)\n", valId, line.Val) + DSM_Send(0x18, 0x06, + int16_MSB(valId), int16_LSB(valId), + int16_MSB(value), int16_LSB(value)) -- send current values +end + +local function DSM_SendValidate(line) + local valId = line.ValId + LOG_write("TX:ValidateValue(VId=0x%04X)\n", valId) + DSM_Send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId)) +end + local function DSM_SendRequest() --LOG_write("DSM_SendRequest Phase=%d\n",Phase) -- Need to send a request + local menuId = Menu.MenuId + local menuLSB = int16_LSB(menuId) + local menuMSB = int16_MSB(menuId) + if Phase == PH_RX_VER then -- request RX version - DSM_Send(0x11, 0x06, 0x00, 0x14, 0x00, 0x00) - LOG_write("GetVersion()\n") + DSM_Send(0x11, 0x06, TX_MAX_CH, 0x14, 0x00, 0x00) + LOG_write("TX:GetVersion(TX_MAX_CH=%d)\n",TX_MAX_CH+6) + elseif Phase == PH_WAIT_CMD then -- keep connection open DSM_Send(0x00, 0x04, 0x00, 0x00) + LOG_write("TX:TxHb\n") + elseif Phase == PH_TITLE then -- request menu title - local menuId = Menu.MenuId if menuId == 0 then - DSM_Send(0x12, 0x06, 0x00, 0x14, 0x00, 0x00) -- first menu only + -- very first menu only + DSM_Send(0x12, 0x06, TX_MAX_CH, 0x14, 0x00, 0x00) else - DSM_Send(0x16, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, ctx.SelLine) + -- Any other menu + DSM_Send(0x16, 0x06, menuMSB, menuLSB, 0x00, ctx_SelLine) if (menuId == 0x0001) then -- Executed Save&Reset menu Phase = PH_RX_VER - ctx.isReset = true + ctx_isReset = true end end - LOG_write("GetMenu(M=0x%04X,L=%d)\n", menuId, ctx.SelLine) - elseif Phase == PH_TX_INFO then -- TX Info - SendTxInfo(ctx.CurLine) - elseif Phase == PH_LINES then -- request menu lines - local menuId = Menu.MenuId - if ctx.CurLine == -1 then - DSM_Send(0x13, 0x04, int16_MSB(menuId), int16_LSB(menuId)) -- GetFirstLine - else - DSM_Send(0x14, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, ctx.CurLine) -- line X - end - LOG_write("GetLines(LastLine=%d)\n", ctx.CurLine) - elseif Phase == PH_VALUES then -- request menu values - local menuId = Menu.MenuId - local valId = MenuLines[ctx.CurLine].ValId - DSM_Send(0x15, 0x06, - int16_MSB(menuId), int16_LSB(menuId), - int16_MSB(valId), int16_LSB(valId)) - LOG_write("GetValues(LastVId=0x%04X)\n", valId) - elseif Phase == PH_VAL_CHANGING then -- send new value: Two steps, Update & Validate - local line = MenuLines[ctx.SelLine] - local valId = line.ValId - if Value_Change_Step == 0 then - local value = sInt16ToDsm(line.Val) - DSM_Send(0x18, 0x06, - int16_MSB(valId), int16_LSB(valId), - int16_MSB(value), int16_LSB(value)) -- send current values - LOG_write("ChangeValue(VId=0x%04X,Val=%d)\n", valId, value) + LOG_write("TX:GetMenu(M=0x%04X,L=%d)\n", menuId, ctx_SelLine) - if line.Type == LT_LIST_VALIDATE then -- Incremental Validation?? - Value_Change_Step = 1 - Waiting_RX = 0 -- Do SEND in the next step - end + elseif Phase == PH_TX_INFO then -- TX Info + SendTxInfo(ctx_CurLine) + + elseif Phase == PH_LINES then -- request menu lines + if ctx_CurLine == -1 then + DSM_Send(0x13, 0x04, menuMSB, menuLSB) -- GetFirstLine else - -- Validate Value - DSM_Send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId)) - Value_Change_Step = 0 - Phase = PH_VAL_WAIT - LOG_write("ValidateValue(VId=0x%04X)\n", valId) + DSM_Send(0x14, 0x06, menuMSB, menuLSB, 0x00, ctx_CurLine) -- line X end - elseif Phase == PH_VAL_CHNG_END then - DSM_Send(0x1B, 0x04, 0x00, int16_LSB(ctx.SelLine)) - Value_Change_Step = 0 - Phase = PH_WAIT_CMD - LOG_write("ValueChangeEnd(L=%d)\n", ctx.SelLine) - elseif Phase == PH_VAL_WAIT then - -- Value Changing Wait - DSM_Send(0x1A, 0x04, 0x00, int16_LSB(ctx.SelLine)) - LOG_write("ValueChangeWait(L=%d)\n", ctx.SelLine) + LOG_write("TX:GetNextLine(LastLine=%d)\n", ctx_CurLine) + + elseif Phase == PH_VALUES then -- request menu values + local valId = MenuLines[ctx_CurLine].ValId + DSM_Send(0x15, 0x06, + menuMSB, menuLSB, + int16_MSB(valId), int16_LSB(valId)) + LOG_write("TX:GetNextValue(LastVId=0x%04X)\n", valId) + + elseif Phase == PH_VAL_EDITING then -- Editing a line (like a HB) + local line = MenuLines[ctx_SelLine] + DSM_Send(0x1A, 0x04, 0x00, ctx_SelLine) + LOG_write("TX:EditingValueLine(L=%d)\n", ctx_SelLine) + + elseif Phase == PH_VAL_CHANGING then -- change value during editing + local line = MenuLines[ctx_SelLine] + if (Change_Step==0) then + DSM_SendUpdate(line) + if line.Type == LT_LIST then -- Incremental Validation?? + Change_Step=1 + end + else -- Change_Step==1 + DSM_SendValidate(line) + Change_Step=0 + end + if (Change_Step==0) then Phase=PH_VAL_EDITING else SendDataToRX=1 end -- Done with change? + + elseif Phase == PH_VAL_EDIT_END then -- Done Editing line + local line = MenuLines[ctx_SelLine] + + if (Change_Step==0) then + DSM_SendUpdate(line) + Change_Step=1 + elseif (Change_Step==1) then + DSM_SendValidate(line) + Change_Step=2 + else -- Change_Step==3 + LOG_write("TX:EditValueEnd(L=%d)\n", ctx_SelLine) + DSM_Send(0x1B, 0x04, 0x00, ctx_SelLine) + Change_Step=0 + end + if (Change_Step==0) then Phase = PH_WAIT_CMD else SendDataToRX=1 end -- Done with change? + elseif Phase == PH_EXIT_REQ then -- EXIT Request - DSM_Send(0x1F, 0x02, 0xAA) + DSM_Send(0x1F, 0x02, 0xAA) + LOG_write("TX:TX Exit Request\n") end end local function DSM_ProcessResponse() local cmd = multiBuffer(11) - -- LOG_write("DSM_ProcessResponse BEGIN: Cmd=%x\n",cmd) if cmd == 0x01 then -- read version RX.Name = Get_RxName(multiBuffer(13)) RX.Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) - --ctx.isReset = false -- no longer resetting + Menu.MenuId = 0 Phase = PH_TITLE - LOG_write("Version: %s %s\n", RX.Name, RX.Version) + LOG_write("RX:Version: %s %s\n", RX.Name, RX.Version) + elseif cmd == 0x02 then -- read menu title local menu = Menu @@ -493,25 +614,25 @@ local function DSM_ProcessResponse() menu.BackId = Dsm_to_Int16(multiBuffer(20), multiBuffer(21)) for i = 0, 6 do -- clear menu - MenuLines[i] = { MenuId = 0, Type = 0, TextId = 0, ValId = 0, Min = 0, Max = 0, Def = 0, Val = nil, Unit, Step } + MenuLines[i] = { MenuId = 0, Type = 0, TextId = 0, ValId = 0, Min = 0, Max = 0, Def = 0, Val = nil } end - ctx.CurLine = -1 - ctx.SelLine = -1 -- highlight Back + ctx_CurLine = -1 + ctx_SelLine = -1 -- highlight Back - LOG_write("Menu: Mid=0x%04X \"%s\"\n", menu.MenuId, menu.Text) + LOG_write("RX:Menu: Mid=0x%04X \"%s\"\n", menu.MenuId, menu.Text) if (menu.MenuId == 0x0001) then -- Still in RESETTING MENU??? - --menu.MenuId = 0 Phase = PH_RX_VER else Phase = PH_LINES end + elseif cmd == 0x03 then -- read menu lines local i = multiBuffer(14) local type = multiBuffer(15) local line = MenuLines[i] - ctx.CurLine = i + ctx_CurLine = i line.lineNum = i line.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) @@ -520,7 +641,7 @@ local function DSM_ProcessResponse() line.Text = Get_Text(line.TextId) line.ValId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19)) - -- Singed int values + -- Signed int values line.Min = Dsm_to_SInt16(multiBuffer(20), multiBuffer(21)) line.Max = Dsm_to_SInt16(multiBuffer(22), multiBuffer(23)) line.Def = Dsm_to_SInt16(multiBuffer(24), multiBuffer(25)) @@ -540,12 +661,18 @@ local function DSM_ProcessResponse() end end - if ctx.SelLine == -1 and isSelectable(line) then -- Auto select first selectable line of the menu - ctx.SelLine = ctx.CurLine + if ctx_SelLine == -1 and isSelectable(line) then -- Auto select first selectable line of the menu + ctx_SelLine = ctx_CurLine + end + + LOG_write("RX:Line: #%d Vid=0x%04X T=0x%02X \"%s\"\n", i, line.ValId, type, line.Text) + + if (line.MenuId~=Menu.MenuId) then -- Going Back too fast: Stil receiving lines from previous menu + Menu.MenuId = line.MenuId end - LOG_write("Line: #%d Vid=0x%04X T=0x%02X \"%s\"\n", i, line.ValId, type, line.Text) Phase = PH_LINES + elseif cmd == 0x04 then -- read menu values -- Identify the line and update the value local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) @@ -557,7 +684,7 @@ local function DSM_ProcessResponse() if line.Type ~= 0 then if line.Type ~= LT_MENU and line.ValId == valId then -- identifier of ValueId stored in the line line.Val = value - ctx.CurLine = i + ctx_CurLine = i updatedLine = line local valueTxt = value @@ -565,66 +692,85 @@ local function DSM_ProcessResponse() valueTxt = Get_Text_Value(line.Def + value) .. " [" .. value .. "]" end - LOG_write("Update Value: #%d VId=0x%04X Value=%s\n", i, valId, valueTxt) + LOG_write("RX: Value Updated: #%d VId=0x%04X Value=%s\n", i, valId, valueTxt) break end end end - if (updatedLine == nil) then - LOG_write("Cannot Find Line for ValueId=%x\n", valId) - end + --if (updatedLine == nil) then + -- LOG_write("Cannot Find Line for ValueId=%x\n", valId) + --end Phase = PH_VALUES + elseif cmd == 0x05 then -- Request TX info - ctx.CurLine = multiBuffer(12) + ctx_CurLine = multiBuffer(12) TX_Info_Type = multiBuffer(13) TX_Info_Step = 0 Phase = PH_TX_INFO - LOG_write("TXInfoReq: Port=%d T=0x%02X\n", ctx.CurLine, TX_Info_Type) - elseif cmd == 0xA7 then -- answer to EXIT command - DSM_Release() - elseif cmd == 0x00 and Phase == PH_VAL_CHANGING then - Phase = PH_VAL_WAIT + LOG_write("RX:TXInfoReq: Port=%d T=0x%02X\n", ctx_CurLine, TX_Info_Type) + + elseif cmd == 0xA7 then -- RX EXIT Request + if Phase == PH_EXIT_REQ then -- Response to our EXIT req + Phase = PH_EXIT_DONE + else -- Unexpected RX Exit + DSM_Release() + error("RX Connection Drop") + end + + elseif cmd == 0x00 then -- RX Heartbeat + LOG_write("RX:RxHb\n") end - --LOG_write("DSM_ProcessResponse END: Cmd=%x\n",cmd) return cmd end local function DSM_Send_Receive() - if Waiting_RX == 0 then - Waiting_RX = 1 - DSM_SendRequest() - multiBuffer(10, 0x00); - InactivityTime = getTime() + 200 -- Reset Inactivity timeout - -- -- -- -- -- -- -- -- -- -- -- -- receive part -- -- -- -- -- -- -- -- -- -- -- -- -- - elseif multiBuffer(10) == 0x09 then + + -- Receive part: Process incoming messages if there is nothing to send + if SendDataToRX==0 and multiBuffer(10) == 0x09 then local cmd = DSM_ProcessResponse() -- Data processed multiBuffer(10, 0x00) - if (cmd > 0x00) then -- Any non NULL response - -- Only change to SEND mode if we received a valid response (Ignore NULL Responses, that are really heartbeat i most cases) - Waiting_RX = 0 - InactivityTime = getTime() + 200 -- Reset Inactivity timeout + RXInactivityTime = getTime() + 800 -- Reset Inactivity timeout (8s) + + if (cmd > 0x00) then -- RX-HeartBeat?? + -- Only change to SEND mode if we received a valid response (Ignore heartbeat) + SendDataToRX = 1 end - else -- No Send or Receive, - -- Check if enouth time has passed from last transmit/receive activity - if getTime() > InactivityTime then - InactivityTime = getTime() + 200 - Waiting_RX = 0 -- Switch to Send mode to send heartbeat - - if Phase == PH_EXIT_REQ then + else + -- Check if enouth time has passed from last Received activity + if (getTime() > RXInactivityTime and Phase~=PH_RX_VER and Phase~= PH_EXIT_DONE) then + if (isEditing()) then -- If Editing, extend time + RXInactivityTime = getTime() + 400 + else DSM_Release() + error("RX Disconnected") end + end + end - if Phase ~= PH_RX_VER and Phase ~= PH_VAL_WAIT then - Phase = PH_WAIT_CMD + -- Sending part -- + if SendDataToRX == 1 then + SendDataToRX = 0 + DSM_SendRequest() + TXInactivityTime = getTime() + 200 -- Reset Inactivity timeout (2s) + else + -- Check if enouth time has passed from last transmit activity + if getTime() > TXInactivityTime then + SendDataToRX = 1 -- Switch to Send mode to send heartbeat + + -- Change to Idle/HB mode if we are wating for RX version + if Phase ~= PH_RX_VER then + -- Phase = If IsEditing then PH_VAL_EDITING else PH_WAIT_CMD + Phase = (isEditing() and PH_VAL_EDITING) or PH_WAIT_CMD end end end end ------------------------------------------------------------------------------------------------------------- + +----- local function showBitmap(x, y, imgDesc) local f = string.gmatch(imgDesc, '([^%|]+)') -- Iterator over values split by '|' @@ -653,32 +799,36 @@ local function DSM_Display() lcd.drawText(1, 0, "DSM Frwd Prog "..VERSION, INVERS) local msgId = 0x300 -- Waiting for RX - if (ctx.isReset) then msgId=0x301 end -- Waiting for Reset - lcd.drawText(0, 3 * LCD_Y_LINE_HEIGHT, Get_Text(msgId), BLINK) + if (ctx_isReset) then msgId=0x301 end -- Waiting for Reset + lcd.drawText(1, 3 * LCD_Y_LINE_HEIGHT, Get_Text(msgId), BLINK) return end -- display Program version or RX version local msg = RX.Name .. " v" .. RX.Version - if (ver_rx_count < 100) then + if (ver_rx_count < 70) then msg = RX.Name .. " v" .. RX.Version ver_rx_count = ver_rx_count + 1 else - msg = "Frwd Prog "..VERSION + msg = "FProg "..VERSION ver_rx_count = ver_rx_count + 1 - if (ver_rx_count > 200) then ver_rx_count=0 end + if (ver_rx_count > 140) then ver_rx_count=0 end end - lcd.drawText(30, LCD_Y_LOWER_BUTTONS, msg, TEXT_ATTR) + lcd.drawText(40, LCD_Y_LOWER_BUTTONS, msg, TEXT_ATTR) if Menu.MenuId == 0 then return end; -- No Title yet -- Got a Menu lcd.drawText(1, 0, Menu.Text, TEXT_ATTR + INVERS) + if (Phase == PH_TX_INFO) then + lcd.drawText(1, 3 * LCD_Y_LINE_HEIGHT, "Sending CH"..(ctx_CurLine+1), TEXT_ATTR) + end + local y = LCD_Y_LINE_HEIGHT + 2 for i = 0, 6 do local attrib = TEXT_ATTR - if (i == ctx.SelLine) then attrib = attrib + INVERS end -- Selected Line + if (i == ctx_SelLine) then attrib = attrib + INVERS end -- Selected Line local line = MenuLines[i] @@ -686,199 +836,132 @@ local function DSM_Display() local heading = Get_Text(line.TextId) if (line.TextId >= 0x8000) then -- Flight mode - heading = " " .. Flight_Mode[0] .. " " + heading = " " .. Flight_Mode .. " " if (line.Val==nil) then heading = heading .. "--" else heading = heading .. ((line.Val or 0) + 1) end else - local text = "-" + local text = nil if line.Type ~= LT_MENU then -- list/value if line.Val ~= nil then if isListLine(line) then local textId = line.Val + line.Def text = Get_Text_Value(textId) - local imgDesc = List_Text_Img[textId] - - if (imgDesc and i == ctx.SelLine) then -- Optional Image and Msg for selected value - showBitmap(0, 20, imgDesc) + local offset = 0 + if (line.Type==LT_LIST_ORI) then offset = offset + 0x100 end --FH6250 hack + local imgDesc = GetTextFromFile(List_Text_Img[textId+offset]) + + if (imgDesc and i == ctx_SelLine) then -- Optional Image and Msg for selected value + showBitmap(1, 20, imgDesc) end - elseif (line.Type == LT_VALUE_PERCENT) then - text = line.Val .. " %" - elseif (line.Type == LT_VALUE_DEGREES) then - text = line.Val .. " @" else text = line.Val end end -- if is Value - if (ctx.EditLine == i) then -- Editing a Line + if (ctx_EditLine == i) then -- Editing a Line attrib = BLINK + INVERS + TEXT_ATTR end - lcd.drawText(LCD_X_MAX, y, text, attrib + RIGHT) -- display value + lcd.drawText(LCD_X_MAX, y, text or "--", attrib + RIGHT) -- display value attrib = TEXT_ATTR end - end -- Flight mode - lcd.drawText(0, y, heading, attrib) -- display text + end -- not Flight mode + lcd.drawText(1, y, heading, attrib) -- display text end y = y + LCD_Y_LINE_HEIGHT end -- for if Menu.BackId ~= 0 then - drawButton(LCD_X_RIGHT_BUTTONS, 0, "Back", ctx.SelLine == -1) + drawButton(LCD_X_RIGHT_BUTTONS, 0, "Back", ctx_SelLine == -1) end if Menu.NextId ~= 0 then - drawButton(LCD_X_RIGHT_BUTTONS, LCD_Y_LOWER_BUTTONS, "Next", ctx.SelLine == 7) + drawButton(LCD_X_RIGHT_BUTTONS, LCD_Y_LOWER_BUTTONS, "Next", ctx_SelLine == 7) end if Menu.PrevId ~= 0 then - drawButton(0, LCD_Y_LOWER_BUTTONS, "Prev", ctx.SelLine == 8) + drawButton(1, LCD_Y_LOWER_BUTTONS, "Prev", ctx_SelLine == 8) end - end +----------------------------------------------------------------------------------------- -local function load_msg_from_file(fileName, mem, Text, List_Text, List_Text_Img, RxName, Flight_Mode) - local function rtrim(s) - local n = string.len(s) - while n > 0 and string.find(s, "^%s", n) do n = n - 1 end - return string.sub(s, 1, n) +local function load_msg_from_file(fileName, offset, FileState) + + if (FileState.state==nil) then -- Initial State + FileState.state=1 + FileState.lineNo=0 + FileState.filePos=0 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) + if FileState.state==1 then + for l=1,10 do -- do 10 lines at a time + local type, sIndex, text + local lineStart = FileState.filePos - local data = io.read(dataFile, mem * 1024) -- read up to 10k characters (newline char also counts!) - io.close(dataFile) + type, sIndex, text, FileState.filePos = GetTextInfoFromFile(FileState.filePos+offset) + + --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) + local filePos = lineStart + offset + + if (index == nil) then + assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, FileState.lineNo, sIndex)) + elseif (type == "T") then + Text[index] = filePos + elseif (type == "LT") then + List_Text[index] = filePos + elseif (type == "LI") then + List_Text_Img[index] = filePos + elseif (type == "FM") then + Flight_Mode = 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 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 + return 0 end - -local function clean_msg(Text, Flight_Mode) - local function clean_line(c) - if (c==nil) then return c end - local pos - c, pos = string.gsub(c, "/b$", "") - c, pos = string.gsub(c, "/c$", "") - c, pos = string.gsub(c, "/r$", "") - c, pos = string.gsub(c, "/p$", "") - c, pos = string.gsub(c, "/m$", "") - return c - end - - -- Clean the line of special markers that are only used in color vesion - for i = 0, 0x0300 do - Text[i] = clean_line(Text[i]) - collectgarbage("collect") - end - - for i = 0, #Flight_Mode do - -- Clean the line of special markers that are only used in color vesion - Flight_Mode[i] = clean_line(Flight_Mode[i]) - end -end - - local function DSM_Init_Model() - MODEL.DSM_ChannelInfo= {[0]= -- Start array at position 0 - {[0]= 0x00, 0x40}, -- Ch1 Thr (0x40) - {[0]= 0x00, 0x01}, -- Ch2 Ail (0x01) - {[0]= 0x00, 0x02}, -- Ch2 ElE (0x02) - {[0]= 0x00, 0x04}, -- Ch4 Rud (0x04) - {[0]= 0x00, 0x00}, -- Ch5 Gear (0x00) - {[0]= 0x00, 0x00}, -- Ch6 Aux1 (0x00) - {[0]= 0x00, 0x00}, -- Ch7 Aux2 (0x00) - {[0]= 0x00, 0x00}, -- Ch8 Aux3 (0x00) - {[0]= 0x00, 0x00}, -- Ch9 Aux4 (0x00) - {[0]= 0x00, 0x00} -- Ch10 Aux5 (0x00) - } + MODEL.DSM_ChannelInfo={} + MODEL.modelOutputChannel={} - MODEL.modelOutputChannel = {[0]= - {min=1000, max=1000}, -- Ch1 - {min=1000, max=1000}, -- Ch2 - {min=1000, max=1000}, -- Ch3 - {min=1000, max=1000}, -- Ch4 - {min=1000, max=1000}, -- Ch5 - {min=1000, max=1000}, -- Ch6 - {min=1000, max=1000}, -- Ch7 - {min=1000, max=1000}, -- Ch8 - {min=1000, max=1000}, -- Ch9 - {min=1000, max=1000} -- Ch10 - } + local ChInfo = MODEL.DSM_ChannelInfo + local OutCh = MODEL.modelOutputChannel + + for i=0, 11 do + ChInfo[i] = {[0]= 0x00, 0x00} + OutCh[i] = {min=1000, max=1000} + end + + ChInfo[0][1] = 0x40 -- Ch1 Thr (0x40) + ChInfo[1][1] = 0x01 -- Ch2 Ail (0x01) + ChInfo[2][1] = 0x02 -- Ch2 ElE (0x02) + ChInfo[3][1] = 0x04 -- Ch4 Rud (0x04) end ------------------------------------------------------------------------------------------------------------ -- Init local function DSM_Init() LOG_open() - LOG_write("-------- NEW SESSION --------------------\n") + LOG_write("--- NEW SESSION\n") DSM_Init_Model() - - --[[ - if (ModelParam~=nil) then - LOG_write("Got MODEL PARAMETER... copying\n") - MODEL.DSM_ChannelInfo = ModelParam.DSM_ChannelInfo - else - LOG_write("NO-PARMETER --- Create DEFAULT") - end - --]] - - collectgarbage("collect") - LOG_write("Mem before msg =%d\n",collectgarbage("count")) - load_msg_from_file(MSG_FILE, 10, Text, List_Text, List_Text_Img, RxName, Flight_Mode) - collectgarbage("collect") - LOG_write("Mem after msg =%d\n",collectgarbage("count")) - load_msg_from_file(MSG_FILE_MIN, 4, Text, List_Text, List_Text_Img, RxName, Flight_Mode) - collectgarbage("collect") - LOG_write("Mem after msg2 =%d\n",collectgarbage("count")) - clean_msg(Text,Flight_Mode) collectgarbage("collect") --Set protocol to talk to @@ -889,16 +972,6 @@ local function DSM_Init() return 2 end - --Init TX buffer - multiBuffer(3, 0x00) - --Init RX buffer - multiBuffer(10, 0x00) - --Init telemetry - multiBuffer(0, string.byte('D')) - multiBuffer(1, string.byte('S')) - multiBuffer(2, string.byte('M')) - - if (LCD_W > 128) then TEXT_ATTR = 0 LCD_Y_LINE_HEIGHT = 25 @@ -908,20 +981,61 @@ local function DSM_Init() LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2 end - + Phase = PH_INIT end + + +----------------------------------------------------------------------------------------------------------- +local initStep=0 +local FileState = { lineNo=0} + +local function Inc_Init() + lcd.clear() + + if (initStep == 0) then + lcd.drawText(1, 0, "Loading Msg file: "..(FileState.lineNo or 0)) + if (load_msg_from_file(MSG_FILE, 0, FileState)==1) then + initStep=1 + FileState = {} + collectgarbage("collect") + end + return 0 + elseif (initStep == 1) then + lcd.drawText(1, 0, "Loading Msg file: "..(FileState.lineNo or 0)) + if (load_msg_from_file(MSG_FILE_MIN, MSG_MIN_FILE_OFFSET, FileState)==1) then + initStep=2 + FileState ={} + collectgarbage("collect") + end + return 0 + else -- initStep==2 + --initStep=3 + Phase = PH_RX_VER -- Done Init + DSM_Connect() + end +end + ------------------------------------------------------------------------------------------------------------ -- Main + local function DSM_Run(event) if event == nil then error("Cannot be run as a model script!") return 2 - else - DSM_Display() - DSM_Menu(event) - DSM_Send_Receive() end + + if (Phase == PH_INIT) then + Inc_Init() -- Incremental initialization + return 0 + end + + DSM_Display() + DSM_HandleEvent(event) + DSM_Send_Receive() + collectgarbage("collect") + if Phase == PH_EXIT_DONE then + DSM_Release() LOG_close() return 2 else diff --git a/Lua_scripts/DSMLIB/DSM Fwd Prog Protocol.md b/Lua_scripts/DSMLIB/DSM Fwd Prog Protocol.md deleted file mode 100644 index 0fc9127..0000000 --- a/Lua_scripts/DSMLIB/DSM Fwd Prog Protocol.md +++ /dev/null @@ -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 - - - - - diff --git a/Lua_scripts/DSMLIB/DsmFwPrgLib.lua b/Lua_scripts/DSMLIB/DsmFwPrgLib.lua index a688030..e81759f 100644 --- a/Lua_scripts/DSMLIB/DsmFwPrgLib.lua +++ b/Lua_scripts/DSMLIB/DsmFwPrgLib.lua @@ -1,6 +1,6 @@ ---- ######################################################################### ---- # # ----- # Copyright (C) OpenTX # +---- # Copyright (C) OpenTX/EdgeTx # -----# # ---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # ---- # # @@ -39,386 +39,36 @@ --############################################################################### -local DEBUG_ON = ... -- Get Debug_ON from parameters. -- 0=NO DEBUG, 1=HIGH LEVEL 2=MORE DETAILS +local Log, menuLib, modelLib, DEBUG_ON = ... -- Get Debug_ON from parameters. -- 0=NO DEBUG, 1=HIGH LEVEL 2=MORE DETAILS +local LIB_VERSION = "0.55" +local MSG_FILE = "/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt" -local LIB_VERSION = "0.54" -local LANGUAGE = "en" +local PHASE = menuLib.PHASE +local LINE_TYPE = menuLib.LINE_TYPE -local LOG_FILE = "/LOGS/dsm_log.txt" -local MSG_FILE = "/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_"..LANGUAGE..".txt" +local CH_TYPE = modelLib.CH_TYPE +local CH_MIX_TYPE = modelLib.CH_MIX_TYPE +local DISP_ATTR = menuLib.DISP_ATTR +local DSM_Context = menuLib.DSM_Context +local MODEL = modelLib.MODEL -local Lib = { Init_Text = function (rxId) end } +local MAX_MENU_LINES = menuLib.MAX_MENU_LINES +local BACK_BUTTON = menuLib.BACK_BUTTON +local NEXT_BUTTON = menuLib.NEXT_BUTTON +local PREV_BUTTON = menuLib.PREV_BUTTON ---RX IDs-- -local RX = { - AR636B = 0x0001, - SPM4651T = 0x0014, - AR637T = 0x0015, - AR637TA = 0x0016, - FC6250HX = 0x0018, - AR630 = 0x0019, - AR8360T = 0x001A, - AR10360T = 0x001C, - AR631 = 0x001E -} - -local PHASE = { - RX_VERSION = 0, - WAIT_CMD = 1, - MENU_TITLE = 2, - MENU_REQ_TX_INFO = 3, - MENU_LINES = 4, MENU_VALUES = 5, - VALUE_CHANGING = 6, VALUE_CHANGING_WAIT = 7, VALUE_CHANGE_END = 8, - EXIT = 9, EXIT_DONE = 10 -} - -local LINE_TYPE = { - MENU = 0x1C, - LIST_MENU = 0x0C, -- List: TODO: Investigate why the Min/Max on some lines comes with a wide range (0..244) when non-contiguos values. example Valid (3,176,177) - LIST_MENU_NC = 0x6C, -- List: No Incremental Change - LIST_MENU_TOG = 0x4C, -- List: Seems like a bolean/Toggle menu, just 2 values 0->1 (off/on, ihn/Act) - - 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 -} - ---Channel Types -- -local CH_TYPE = { - NONE = 0x00, - AIL = 0x01, - ELE = 0x02, - RUD = 0x04, - - REVERSE = 0x20, - THR = 0x40, - SLAVE = 0x80, -} - -local CH_MIX_TYPE = { - NORMAL = 0x00, - MIX_AIL_B = 0x10, -- Traileron B - MIX_ELE_A = 0x20, -- For VTIAL and Delta-ELEVON A - MIX_ELE_B_REV= 0x30, -- For VTIAL and Delta-ELEVON B - MIX_ELE_B = 0x40, -- For VTIAL and Delta-ELEVON B - MIX_ELE_A_REV= 0x50, -- For VTIAL and Delta-ELEVON A - MIX_AIL_B_REV= 0x60, -- Traileron B Rev - NORM_REV = 0x70 -} - --- 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 -} - -local DSM_Context = { - Phase = PHASE.RX_VERSION, - Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 }, - MenuLines = {}, - RX = { Id=0, Name = "", Version = "" }, - Refresh_Display = true, - - 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 -} - --- MODEL information from ETX/OTX -local MODEL = { - modelName = "", -- The name of the model comming from OTX/ETX - modelOutputChannel = {}, -- Output information from OTX/ETX - - TX_CH_TEXT = {}, - PORT_TEXT = {}, - DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script -} - - -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 local SEND_TIMEOUT = 2000 / 10 -- Home many 10ms intervals to wait on sending data to tx to keep connection open (2s) -local InactivityTime = 0 -- Next time to do heartbeat after inactivity -local StartTime = 0 -- Start time since the start of the script +local TXInactivityTime = 0 -- Next time to do heartbeat after inactivity +local RXInactivityTime = 0 -- To check RX disconnection -local Waiting_RX = 0 -- 1 if Waiting for an RX response, 0 if transmiting -local Value_Change_Step = 0 -- 2 Steps to update. 0=Send update value, 1=Send Verificatin request local TxInfo_Type = 0 local TxInfo_Step = 0 +local Change_Step = 0 --- 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 RxName = {} -local Flight_Mode = {[0]="Flight Mode"} - -local logFile = nil - - -function DSM_Context.isEditing() return DSM_Context.EditLine~=nil end - - ----- 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) - } - - ------------------------------------------------------------------------------------------------------------- -local logCount=0 -local function LOG_open() - logFile = io.open(LOG_FILE, "w") -- Truncate Log File -end - -local function LOG_write(...) - if (logFile==nil) then LOG_open() end - local str = string.format(...) - io.write(logFile, str) - - 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 - -local function LOG_close() - if (logFile~=nil) then io.close(logFile) end -end - ------------------------------------------------------------------------------------------------------------- --- Get Elapsed Time since we started running the Script. Return a float in format: Seconds.Milliseconds -local function 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 -local function isFlightModeLine(line) - return (line.TextId >= 0x8000 and line.TextId <= 0x8003) -end - -local function 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 isFlightModeLine(line)) then return false end -- Flight mode is not Selectable - return true -end - -local function 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 isFlightModeLine(line)) then return false end -- Flight mode is not Editable - -- any other is Editable - return true -end - -local function 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) then return true end - return false -end - -local function 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 - -local function isPercentValueLine(line) -- is it a Percent value?? - if (line.Type == LINE_TYPE.VALUE_PERCENT) then return true end - return false -end - -local function isNumberValueLine(line) -- is it a number ?? - if (isListLine(line) or line.Type == LINE_TYPE.MENU or line.Type == 0) then return false - else return true end -end - -local function isIncrementalValueUpdate(line) - if (line.Type == LINE_TYPE.LIST_MENU_NC or line.Type == LINE_TYPE.VALUE_NUM_I8_NC or line.Type == LINE_TYPE.VALUE_DEGREES) then return false end - return true -end - ------------------------------------------------------------------------------------------------------------- -local function Get_Text(index) - local out = Text[index] -- Find in regular header first - if (index >= 0x8000) then - out = Flight_Mode[0] - end - 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 - -local function 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 - -local function Get_List_Text_Img(index) - local out = List_Text_Img[index] - return out -end - -local function Get_List_Values(index) - local out = List_Values[index] - return out -end - ------------------------------------------------------------------------------------------------------------- -local function Get_RxName(index) - local out = RxName[index] - return out or ("Unknown_" .. string.format("%X", index)) -end - ------------ Debugging 2-String functions ------------------------------------------------------------------- - -local function phase2String(index) - local out = PhaseText[index] - return out or ("Phase_" .. string.format("%X", index)) -end - -local function lineType2String(index) - local out = LineTypeText[index] - return out or ("LT_" .. string.format("%X", index or 0xFF)) -end - -local function lineValue2String(l) - if (DEBUG_ON == 0) then - return "" - end - if (l ~= nil and l.Val ~= nil) then - local value = l.Val - if isListLine(l) then - value = value .. "|\"" .. Get_List_Text(l.Val + l.TextStart) .. "\"" - else - value = value..(l.Format or "") - end - return value - end - return "nil" -end - -local function 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 - -local function menuLine2String(l) - local txt = "Line[]" - if (l ~= nil) then - local value = "" - local range = "" - if l.Type~=LINE_TYPE.MENU then - value = "Val="..lineValue2String(l) - if 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, lineType2String(l.Type), l.ValId, - l.Text, l.TextId, - value, - range, - l.MenuId, - l.TextAttr - ) - end - return txt -end - -local function 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 +local IS_EDGETX = false ------------------------------------------------------------------------------------------------------------ @@ -461,85 +111,6 @@ local function sInt16ToDsm(value) -- Convent to SIGNED DSM Value return value end - ------------------------------------------------------------------------------------------------------------ --- Post Procssing Line from Raw values receive by RX or Simulation - -local function isDisplayAttr(attr, bit) - return (bit32.band(attr,bit)>0) -end - -local function 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 - -local function DSM_MenuPostProcessing(menu) - menu.Text, menu.TextAttr = ExtractDisplayAttr(menu.Text,menu.TextAttr or 0) -end - -local function DSM_MenuLinePostProcessing(line) - if (line.Text==nil) then - line.Text = Get_Text(line.TextId) -- Get Textual Line headeing text - end - - -- Text formatting options - line.Text, line.TextAttr = ExtractDisplayAttr(line.Text,line.TextAttr or 0) - - if line.Type == LINE_TYPE.MENU then - -- nothing to do on menu entries - line.Val=nil - elseif 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 isPercentValueLine(line) or 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 = lineType2String(line.Type).." "..(line.MinMaxOrig or "") -end - ------------------------------------------------------------------------------------------------------------ local function DSM_send(...) local arg = { ... } @@ -559,123 +130,17 @@ local function DSM_send(...) end 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 - -local function DSM_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_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_write("MODEL NAME = %s\n",MODEL.modelName) - - -- Read Ch1 to Ch10 - local i= 0 - for i = 0, 12 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_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_write("Ports/Channels:\n") - for i = 0, 9 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_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 - -local function DSM_SetDSMChannelInfo(channelInfo, description) - MODEL.DSM_ChannelInfo = channelInfo - - LOG_write("Current Model Generated Port Configuration\n") - LOG_write("Description:%s\n",description) - for i = 0, 9 do - local b1, b2 = channelInfo[i][0], channelInfo[i][1] - LOG_write("%s (0x%02X, 0x%02X) = %s \n",MODEL.PORT_TEXT[i],b1,b2, channelType2String(b1,b2)) - end -end ------------------------------------------------------------------------------------------------- local function DSM_StartConnection() - if (DEBUG_ON) then LOG_write("DSM_StartConnection()\n") end + if (DEBUG_ON) then Log.LOG_write("DSM_StartConnection()\n") end --Set protocol to talk to multiBuffer( 0, string.byte('D') ) --test if value has been written if multiBuffer( 0 ) ~= string.byte('D') then - if (DEBUG_ON) then LOG_write("Not Enouth memory\n") end + if (DEBUG_ON) then Log.LOG_write("Not Enouth memory\n") end error("Not enough memory!") return 2 end @@ -692,173 +157,52 @@ local function DSM_StartConnection() end local function DSM_ReleaseConnection() - if (DEBUG_ON) then LOG_write("DSM_ReleaseConnection()\n") end + if (DEBUG_ON) then Log.LOG_write("DSM_ReleaseConnection()\n") end multiBuffer(0, 0) - DSM_Context.Phase = PHASE.EXIT_DONE end -local function DSM_ChangePhase(newPhase) - DSM_Context.Phase = newPhase - Waiting_RX = 0 -end - -local function DSM_Value_Add(line, inc) - if (DEBUG_ON) then LOG_write("%3.3f %s: DSM_Value_Add(%s,%s)\n", getElapsedTime(), phase2String(DSM_Context.Phase), inc, 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 (isListLine(line)) then -- and line.Type==LINE_TYPE.LIST_MENU1 and line.Min==0 and line.Max==244) then - values = 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 isIncrementalValueUpdate(line)) then - -- Update RX value on every change - DSM_ChangePhase(PHASE.VALUE_CHANGING) - end -end - -local function DSM_Value_Default(line) - local origVal = line.Val - if (DEBUG_ON) then LOG_write("%3.3f %s: DSM_Value_Default(%s)\n", getElapsedTime(), phase2String(DSM_Context.Phase), menuLine2String(line)) end - - line.Val = line.Def - if (origVal~=line.Val and isIncrementalValueUpdate(line)) then - -- Update RX value on every change - DSM_ChangePhase(PHASE.VALUE_CHANGING) - end -end - -local function DSM_Value_Write_Validate(line) - if (DEBUG_ON) then LOG_write("%3.3f %s: DSM_Value_Write_Validate(%s)\n", getElapsedTime(), phase2String(DSM_Context.Phase), menuLine2String(line)) end - DSM_ChangePhase(PHASE.VALUE_CHANGE_END) -- Update + Validate value in RX - DSM_Context.EditLine = nil -- Exit Edit Mode (By clearing the line editing) -end - -local function DSM_GotoMenu(menuId, lastSelectedLine) - if (DEBUG_ON) then LOG_write("%3.3f %s: DSM_GotoMenu(0x%X,LastSelectedLine=%d)\n", getElapsedTime(), phase2String(DSM_Context.Phase), menuId, lastSelectedLine) end - DSM_Context.Menu.MenuId = menuId - DSM_Context.SelLine = lastSelectedLine - -- Request to load the menu Again - DSM_ChangePhase(PHASE.MENU_TITLE) -end - -local function DSM_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 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 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 -------------------------------------------------------------------------------------------------------- -- REEQUEST Messages to RX local function DSM_sendHeartbeat() -- keep connection open - if (DEBUG_ON) then LOG_write("SEND DSM_sendHeartbeat()\n") end + if (DEBUG_ON) then Log.LOG_write("SEND DSM_sendHeartbeat()\n") end DSM_send(0x00, 0x04, 0x00, 0x00) end local function DSM_getRxVerson() - if (DEBUG_ON) then LOG_write("SEND DSM_getRxVersion()\n") end - DSM_send(0x11, 0x06, 0x00, 0x14, 0x00, 0x00) + local TX_CAP=0x14 -- Capabilities?? + local TX_MAX_CH = modelLib.TX_CHANNELS - 6 --number of channels after 6 (6Ch=0, 10ch=4, etc) + + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getRxVersion(Ch:0x%X,Cap:0x%X)\n",TX_MAX_CH,TX_CAP) end + DSM_send(0x11, 0x06, TX_MAX_CH, TX_CAP, 0x00, 0x00) end local function DSM_getMainMenu() - if (DEBUG_ON) then LOG_write("SEND DSM_getMainMenu()\n") end - DSM_send(0x12, 0x06, 0x00, 0x14, 0x00, 0x00) -- first menu only + local TX_CAP=0x14 -- Capabilities?? + local TX_MAX_CH = modelLib.TX_CHANNELS - 6 --number of channels after 6 (6Ch=0, 10ch=4, etc) + + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getMainMenu(Ch:0x%X,Cap:0x%X) -- TX_Channels=%d\n",TX_MAX_CH,TX_CAP,TX_MAX_CH+6) end + DSM_send(0x12, 0x06, TX_MAX_CH, TX_CAP, 0x00, 0x00) -- first menu only end local function DSM_getMenu(menuId, latSelLine) - if (DEBUG_ON) then LOG_write("SEND DSM_getMenu(MenuId=0x%X LastSelectedLine=%s)\n", menuId, latSelLine) end + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getMenu(MenuId=0x%X LastSelectedLine=%s)\n", menuId, latSelLine) end DSM_send(0x16, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, latSelLine) end local function DSM_getFirstMenuLine(menuId) - if (DEBUG_ON) then LOG_write("SEND DSM_getFirstMenuLine(MenuId=0x%X)\n", menuId) end + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getFirstMenuLine(MenuId=0x%X)\n", menuId) end DSM_send(0x13, 0x04, int16_MSB(menuId), int16_LSB(menuId)) -- line 0 end local function DSM_getNextMenuLine(menuId, curLine) - if (DEBUG_ON) then LOG_write("SEND DSM_getNextLine(MenuId=0x%X,LastLine=%s)\n", menuId, curLine) end + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getNextLine(MenuId=0x%X,LastLine=%s)\n", menuId, curLine) end DSM_send(0x14, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, curLine) -- line X end local function DSM_getNextMenuValue(menuId, valId, text) - if (DEBUG_ON) then LOG_write("SEND DSM_getNextMenuValue(MenuId=0x%X, LastValueId=0x%X) Extra: Text=\"%s\"\n", menuId, valId, + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getNextMenuValue(MenuId=0x%X, LastValueId=0x%X) Extra: Text=\"%s\"\n", menuId, valId, text) end DSM_send(0x15, 0x06, int16_MSB(menuId), int16_LSB(menuId), int16_MSB(valId), int16_LSB(valId)) -- line X @@ -866,55 +210,60 @@ end local function DSM_updateMenuValue(valId, val, text, line) local value = sInt16ToDsm(val) - if (DEBUG_ON) then LOG_write("SEND DSM_updateMenuValue(ValueId=0x%X,val=%d) Extra: Text=\"%s\" Value=%s\n", valId, val, text, lineValue2String(line)) end + if (DEBUG_ON) then Log.LOG_write("SEND DSM_updateValue(ValueId=0x%X,val=%d) Extra: Text=\"%s\" Value=%s\n", valId, val, text, menuLib.lineValue2String(line)) end DSM_send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value)) -- send current value end local function DSM_validateMenuValue(valId, text, line) - if (DEBUG_ON) then LOG_write("SEND DSM_validateMenuValue(ValueId=0x%X) Extra: Text=\"%s\" Value=%s\n", valId, text, lineValue2String(line)) end + if (DEBUG_ON) then Log.LOG_write("SEND DSM_validateValue(ValueId=0x%X) Extra: Text=\"%s\" Value=%s\n", valId, text, menuLib.lineValue2String(line)) end DSM_send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId)) end -local function DSM_menuValueChangingWait(lineNum, text, line) - if (DEBUG_ON) then LOG_write("SEND DSM_menuValueChangingWait(lineNo=0x%X) Extra: Text=\"%s\" Val=%s\n", lineNum, text, lineValue2String(line)) end +local function DSM_editingValue(lineNum, text, line) + if (DEBUG_ON) then Log.LOG_write("SEND DSM_editingValue(lineNo=0x%X) Extra: Text=\"%s\" Val=%s\n", lineNum, text, menuLib.lineValue2String(line)) end DSM_send(0x1A, 0x04, int16_MSB(lineNum), int16_LSB(lineNum)) end -local function DSM_menuValueChangingWaitEnd(lineNum, text, line) - if (DEBUG_ON) then LOG_write("SEND DSM_menuValueChangingEnd(lineNo=0x%X) Extra: Text=\"%s\" Value=%s\n", lineNum, text, lineValue2String(line)) end +local function DSM_editingValueEnd(lineNum, text, line) + if (DEBUG_ON) then Log.LOG_write("SEND DSM_editingValueEnd(lineNo=0x%X) Extra: Text=\"%s\" Value=%s\n", lineNum, text, menuLib.lineValue2String(line)) end DSM_send(0x1B, 0x04, int16_MSB(lineNum), int16_LSB(lineNum)) end -- Send the functionality of the RX channel Port (channel) local function DSM_sendTxChInfo_20(portNo) - local b1,b2 = MODEL.DSM_ChannelInfo[portNo][0], MODEL.DSM_ChannelInfo[portNo][1] + local b1,b2 = MODEL.DSM_ChannelInfo[portNo][0] or 0, MODEL.DSM_ChannelInfo[portNo][1] or 0 - if (DEBUG_ON) then LOG_write("CALL DSM_TxChInfo_20(#%d %s DATA= %02X %02X %02X %02X) CONTEXT: %s\n", portNo, MODEL.PORT_TEXT[portNo], - portNo, portNo, b1, b2, channelType2String(b1,b2)) -- DATA part + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxChInfo(#%d DATA= %02X %02X %02X %02X) %s\n", portNo, + portNo, portNo, b1, b2, modelLib.channelType2String(b1,b2)) -- DATA part end DSM_send(0x20, 0x06, portNo, portNo, b1, b2) end local function DSM_sendTxSubtrim_21(portNo) - --SubTrim is encoded as an offset of the pulse width. + local usage = MODEL.DSM_ChannelInfo[portNo][1] or 0 + local leftTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].min/10)) + local rightTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].max/10)) + local subTrim = math.floor(MODEL.modelOutputChannel[portNo].offset/10) + + -- Center at 100%: 142-1906 (0 8E 07 72) + local left = 142 + local right = 1906 - local data = {[0]= -- Start at 0 - {[0]= 0x0, 0x00, 0x07, 0xFF }, -- Ch1 Thr: 0 00 07 FF Subtrim ?? - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch2 Ail: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch3 Elev: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch4 Rud: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch5 Gear: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch6 Aux1: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch7 Aux2: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch8 Aux3: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch9 Aux4: 0 8E 07 72 Subtrim 0 - {[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch10 Aux5: 0 8E 07 72 Subtrim 0 - } + if (bit32.band(usage,CH_TYPE.THR)>0) then + left = 0 + right = 2047 + end - local b1,b2,b3,b4 = data[portNo][0], data[portNo][1], data[portNo][2], data[portNo][3] + left = math.floor (left - (leftTravel -100) *8.8 + subTrim*2) + right = math.floor (right + (rightTravel -100) *8.8 + subTrim*2) - if (DEBUG_ON) then LOG_write("CALL DSM_TxSubtrim_21(#%d %s DATA=%02X %02X %02X %02X)\n", portNo, MODEL.PORT_TEXT[portNo], - b1,b2,b3,b4) -- DATA part + if (left<0) then left=0 end + if (right>2027) then right=2047 end + + local b1,b2,b3,b4 = int16_MSB(left), int16_LSB(left), int16_MSB(right), int16_LSB(right) + + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxSubtrim(#%d DATA=%02X %02X %02X %02X) Range(%d - %d) ER L/R:(%d - %d)x8 ST:(%d)x2\n", portNo, + b1,b2,b3,b4, left, right, leftTravel-100, rightTravel-100, subTrim) -- DATA part end DSM_send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it. end @@ -924,7 +273,7 @@ local function DSM_sendTxServoTravel_23(portNo) local rightTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].max/10)) local debugInfo = string.format("Travel L/R (%d - %d)",leftTravel,rightTravel) - if (DEBUG_ON) then LOG_write("CALL DSM_TxServoTravel_23(#%d %s DATA= %02X %02X %02X %02X) CONTEXT: %s\n", portNo, MODEL.PORT_TEXT[portNo], + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxServoTravel(#%d DATA= %02X %02X %02X %02X) %s\n", portNo, 0x00, leftTravel, 0x00, rightTravel, debugInfo) -- DATA part end DSM_send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel) @@ -940,59 +289,57 @@ local function DSM_sentTxInfo(menuId,portNo) DSM_sendTxChInfo_20(portNo) if (TxInfo_Type == 0x1F) then - Waiting_RX = 0 -- keep Transmitig TxInfo_Step = 1 end if (TxInfo_Type == 0x00) then - Waiting_RX = 0 -- keep Transmitig TxInfo_Step = 2 end elseif (TxInfo_Step == 1) then DSM_sendTxServoTravel_23(portNo) - TxInfo_Step = 2 - Waiting_RX = 0 -- keep Transmitig + TxInfo_Step = 2 elseif (TxInfo_Step == 2) then DSM_sendTxSubtrim_21(portNo) - Waiting_RX = 0 -- keep Transmitig if (TxInfo_Type == 0x00) then TxInfo_Step = 5 -- End Step else TxInfo_Step = 3 - end + end elseif (TxInfo_Step == 3) then -- 24,6: 0 83 5A B5 - if (DEBUG_ON) then LOG_write("CALL DSM_TxInfo_24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo, + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo, 0x00, 0x83, 0x5A, 0xB5) -- DATA part - end - DSM_send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown - TxInfo_Step = 4 - Waiting_RX = 0 -- keep Transmitig + end + DSM_send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown + TxInfo_Step = 4 + elseif (TxInfo_Step == 4) then -- 24,6: 6 80 25 4B - if (DEBUG_ON) then LOG_write("CALL DSM_TxInfo_24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo, + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo, 0x06, 0x80, 0x25, 0x4B) -- DATA part - end - DSM_send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown - TxInfo_Step = 5 - Waiting_RX = 0 -- keep Transmitig + end + DSM_send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown + TxInfo_Step = 5 elseif (TxInfo_Step == 5) then -- 22,4: 0 0 - if (DEBUG_ON) then LOG_write("CALL DSM_TxInfo_End_22(#%d DATA=%02X %02X)\n", portNo, - 0x00, 0x00) -- DATA part - end - DSM_send(0x22, 0x04, 0x00, 0x00) - TxInfo_Step = 6 + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo_End(#%d)\n", portNo) + end + DSM_send(0x22, 0x04, 0x00, 0x00) + TxInfo_Step = 0 + end + + if (TxInfo_Step > 0) then + DSM_Context.SendDataToRX = 1 -- keep Transmitig end end ----------------------------------------------------------------------------------------------------------- - + local function DSM_sendRequest() -- Send the proper Request message depending on the Phase local ctx = DSM_Context - if (DEBUG_ON) then LOG_write("%3.3f %s: ", getElapsedTime(), 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 DSM_getRxVerson() @@ -1007,7 +354,7 @@ local function DSM_sendRequest() DSM_getMenu(ctx.Menu.MenuId, ctx.SelLine) if (ctx.Menu.MenuId == 0x0001) then -- Executed the Reset Menu?? - if (DEBUG_ON) then LOG_write("RX Reset!!!\n") end + if (DEBUG_ON) then Log.LOG_write("RX Reset!!!\n") end -- Start again retriving RX info ctx.Menu.MenuId = 0 ctx.isReset = true @@ -1030,36 +377,42 @@ local function DSM_sendRequest() DSM_getNextMenuValue(ctx.Menu.MenuId, line.ValId, line.Text) elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value - local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line - DSM_updateMenuValue(line.ValId, line.Val, line.Text, line) - ctx.Phase = PHASE.VALUE_CHANGING_WAIT + local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line + + if (Change_Step==0) then + DSM_updateMenuValue(line.ValId, line.Val, line.Text, line) + + if line.Type == menuLib.LINE_TYPE.LIST_MENU then -- Validation on every Step?? + Change_Step=1; ctx.SendDataToRX=1 -- Send inmediatly after + else + ctx.Phase = PHASE.VALUE_CHANGING_WAIT + end + else + DSM_validateMenuValue(line.ValId, line.Text, line) + Change_Step=0 + ctx.Phase = PHASE.VALUE_CHANGING_WAIT + end elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then local line = ctx.MenuLines[ctx.SelLine] - DSM_menuValueChangingWait(line.lineNum, line.Text, line) - + DSM_editingValue(line.lineNum, line.Text, line) elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value - -- This is a 2 step operation.. Send the value first, then send the Verification.. Value_Changed_Step used for that - -- on the validation, the RX will set a valid value if the value is invalid. A Menu_Value Message will come from the RX - local line = ctx.MenuLines[ctx.SelLine] -- Update Value of SELECTED line - if Value_Change_Step == 0 then - DSM_updateMenuValue(line.ValId, line.Val, line.Text, line) - Value_Change_Step = 1 - Waiting_RX = 0 -- Keep on Transmitin State, since we want to send a ValidateMenuValue inmediatly after - elseif Value_Change_Step == 1 then -- Validate the value - DSM_validateMenuValue(line.ValId, line.Text, line) - Value_Change_Step = 2 - Waiting_RX = 0 -- Keep on Transmitin State, since we want to send a ValidateMenuValue inmediatly after - else -- No more waiting for changes - DSM_menuValueChangingWaitEnd(line.lineNum, line.Text, line) - Value_Change_Step = 0 - end - + if (Change_Step==0) then + DSM_updateMenuValue(line.ValId, line.Val, line.Text, line) + Change_Step=1; ctx.SendDataToRX=1 -- Send inmediatly after + elseif (Change_Step==1) then + DSM_validateMenuValue(line.ValId, line.Text, line) + Change_Step=2; ctx.SendDataToRX=1 -- Send inmediatly after + else + DSM_editingValueEnd(line.lineNum, line.Text, line) + Change_Step=0 + ctx.Phase = PHASE.WAIT_CMD + end elseif ctx.Phase == PHASE.EXIT then - if (DEBUG_ON) then LOG_write("CALL DSM_exitRequest()\n") end - DSM_send(0x1F, 0x02, 0xAA) + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TX_Exit()\n") end + DSM_send(0x1F, 0x02, 0xFF, 0xFF) -- 0xAA end end @@ -1067,12 +420,14 @@ end -- Parsing Responses local function DSM_parseRxVersion() - --ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + --ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 v2.22.1 00 14?? 8ch SAFE + -- 0x09 0x01 0x00 0x18 0x05 0x06 0x34 0x00 0x12 v5.6.52 00 12??? 6ch FC6250 local rxId = multiBuffer(13) DSM_Context.RX.Id = rxId - DSM_Context.RX.Name = Get_RxName(rxId) + DSM_Context.RX.Name = menuLib.Get_RxName(rxId) DSM_Context.RX.Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) - if (DEBUG_ON) then LOG_write("RESPONSE Receiver=%s Version %s\n", DSM_Context.RX.Name, DSM_Context.RX.Version) end + if (DEBUG_ON) then Log.LOG_write("RESPONSE Receiver=%s Version %s Cap:0x%02X\n", + DSM_Context.RX.Name, DSM_Context.RX.Version, multiBuffer(18)) end end local function DSM_parseMenu() @@ -1082,7 +437,7 @@ local function DSM_parseMenu() local menu = ctx.Menu menu.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) menu.TextId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) - menu.Text = Get_Text(menu.TextId) + menu.Text = menuLib.Get_Text(menu.TextId) menu.PrevId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17)) menu.NextId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19)) menu.BackId = Dsm_to_Int16(multiBuffer(20), multiBuffer(21)) @@ -1091,9 +446,9 @@ local function DSM_parseMenu() end ctx.CurLine = -1 - DSM_MenuPostProcessing(menu) + menuLib.MenuPostProcessing(menu) - if (DEBUG_ON) then LOG_write("RESPONSE Menu: %s\n", menu2String(menu)) end + if (DEBUG_ON) then Log.LOG_write("RESPONSE Menu: %s\n", menuLib.menu2String(menu)) end return menu end @@ -1111,8 +466,8 @@ local function DSM_parseMenuLine() -- are we trying to override existing line if (line.Type > 0 and type == 0) then - if (DEBUG_ON) then LOG_write("RESPONSE MenuLine: ERROR. Trying to Override: %s\n", menuLine2String(line)) end - return line + if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuLine: ERROR. Trying to ZERO Override: %s\n", menuLib.menuLine2String(line)) end + return ctx.MenuLines[ctx.CurLine] end ctx.CurLine = i @@ -1129,9 +484,18 @@ local function DSM_parseMenuLine() line.Max = Dsm_to_SInt16(multiBuffer(22), multiBuffer(23)) line.Def = Dsm_to_SInt16(multiBuffer(24), multiBuffer(25)) - DSM_MenuLinePostProcessing(line) + line.Val=nil + + menuLib.MenuLinePostProcessing(line) + + if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuLine: %s\n", menuLib.menuLine2String(line)) end + + if (line.MenuId~=ctx.Menu.MenuId) then + -- Going Back too fast: Stil receiving lines from previous menu + ctx.Menu.MenuId = line.MenuId + Log.LOG_write("WARNING: Overriding current Menu from Line\n") + end - if (DEBUG_ON) then LOG_write("RESPONSE MenuLine: %s\n", menuLine2String(line)) end return line end @@ -1142,6 +506,7 @@ local function DSM_parseMenuValue() -- Identify the line and update the value local ctx = DSM_Context + local menuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) local value = Dsm_to_SInt16(multiBuffer(16), multiBuffer(17)) --Signed int @@ -1159,65 +524,39 @@ local function DSM_parseMenuValue() end if (updatedLine == nil) then - if (DEBUG_ON) then LOG_write("ERROR, Cant find Menu Line with ValID=%X to update\n", valId) end + if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuValue: ERROR, Cant find Menu Line with MenuId=%X, ValID=%X to update\n", menuId, valId) end else - if (DEBUG_ON) then LOG_write("RESPONSE MenuValue: UPDATED: %s\n", menuLine2String(updatedLine)) + if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuValue: UPDATED: %s\n", menuLib.menuLine2String(updatedLine)) end end + return updatedLine ~= nil end local function DSM_parseReqTxInfo() - -- unknown... I think is trying to request info about TX (Wing type, etc) - -- 0x09 0x05 0x01 0x01 0x00 0x00 0x00 0x00 0x07 Menu: MAIN MENU - -- 0x09 0x05 0x01 0x1F 0x00 0x00 0x00 0x00 0x07 Menu: First Time Setup - -- Line ?? ???? - local portNo = multiBuffer(12) + local portNo = multiBuffer(12) TxInfo_Type = multiBuffer(13) - if (DEBUG_ON) then LOG_write("RESPONSE ReqTXChannelInfo(#%d DataType=0x%0X DATA=%s)\n", portNo, TxInfo_Type, multiBuffer2String()) end + if (DEBUG_ON) then Log.LOG_write("RESPONSE ReqTXChannelInfo(#%d %s InfoType=0x%0X)\n", + portNo, MODEL.PORT_TEXT[portNo], TxInfo_Type) end TxInfo_Step = 0 return portNo end - --- Creates a fake line do display an error in the GUI -local function DSM_Add_Error_Menu_Line(i, text) - local ctx = DSM_Context - local line = ctx.MenuLines[i] - ctx.CurLine = i - - line.lineNum = i - line.MenuId = ctx.Menu.MenuId - line.Type = LINE_TYPE.MENU - line.TextId = 0 - line.Text = text - line.ValId = ctx.Menu.MenuId - - -- Singed int values - line.Min =0 - line.Max = 0 - line.Def = 0 - - line.MinMaxOrig = "" - line.Val = nil - - DSM_MenuLinePostProcessing(line) -end - ------------------------------------------------------------------------------------------------------------ local function DSM_processResponse() local ctx = DSM_Context local cmd = multiBuffer(11) -- Response Command - if (DEBUG_ON > 1) then LOG_write("%s: RESPONSE %s \n", phase2String(ctx.Phase), multiBuffer2String()) end - if (DEBUG_ON and cmd > 0x00) then LOG_write("%3.3f %s: ", getElapsedTime(), phase2String(ctx.Phase)) end + if (DEBUG_ON > 1) then Log.LOG_write("%s: RESPONSE %s \n", menuLib.phase2String(ctx.Phase), multiBuffer2String()) end + if (DEBUG_ON and cmd > 0x00) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end if cmd == 0x01 then -- read version DSM_parseRxVersion() - Lib.Init_Text(DSM_Context.RX.Id) + --Lib.Init_Text(DSM_Context.RX.Id) ctx.isReset = false -- no longer resetting ctx.Phase = PHASE.MENU_TITLE + ctx.Menu.MenuId = 0 elseif cmd == 0x02 then -- read menu title local menu = DSM_parseMenu() @@ -1231,7 +570,7 @@ local function DSM_processResponse() if (ctx.Menu.MenuId == 0x0001) then -- Still in RESETTING MENU??? -- Star from Start - if (DEBUG_ON) then LOG_write("RX Reset: Still not done, restart again!!!\n") end + if (DEBUG_ON) then Log.LOG_write("RX Reset: Still not done, restart again!!!\n") end ctx.Menu.MenuId = 0 ctx.Phase = PHASE.RX_VERSION else @@ -1244,46 +583,41 @@ local function DSM_processResponse() -- Update Selected line navigation if (ctx.SelLine == BACK_BUTTON or ctx.SelLine == NEXT_BUTTON or ctx.SelLine == PREV_BUTTON) - and isSelectableLine(line) then -- Auto select the current line + and menuLib.isSelectableLine(line) then -- Auto select the current line ctx.SelLine = line.lineNum end ctx.Phase = PHASE.MENU_LINES elseif cmd == 0x04 then -- read menu values - DSM_parseMenuValue() - ctx.Phase = PHASE.MENU_VALUES + if DSM_parseMenuValue() then + ctx.Phase = PHASE.MENU_VALUES + else + ctx.Phase = PHASE.WAIT_CMD + end elseif cmd == 0x05 then -- Request TX Info - local portNo = DSM_parseReqTxInfo() - - if (portNo==ctx.CurLine) then - -- WEIRD BEHAVIOR - -- We got the same line we already got. thi will continue - -- on a loop and disconnect RX - DSM_Add_Error_Menu_Line(0,"\bError: Cannot Load Menu Lines from RX") - if (DEBUG_ON) then LOG_write("ERROR: Received Same menu line\n") end - end -- Got the next line.. keep requesting more - + local portNo = DSM_parseReqTxInfo() ctx.CurLine = portNo ctx.Phase = PHASE.MENU_REQ_TX_INFO elseif cmd == 0xA7 then -- answer to EXIT command - if (DEBUG_ON) then LOG_write("RESPONSE Exit Confirm\n") end - DSM_ReleaseConnection() + if (DEBUG_ON) then Log.LOG_write("RESPONSE RX Exit\n") end + if (ctx.Phase==PHASE.EXIT) then -- Expected RX Exit + ctx.Phase = PHASE.EXIT_DONE + else -- UnExpected RX Exit + DSM_ReleaseConnection() + error("RX Connection Drop") + end elseif cmd == 0x00 then -- NULL response (or RX heartbeat) - if (ctx.Phase == PHASE.WAIT_CMD) then -- Dont show null while waiting for command to no fill the logs - if (DEBUG_ON > 1) then LOG_write("%3.3f %s: RESPONSE NULL\n", getElapsedTime(), phase2String(ctx.Phase)) end - else - if (DEBUG_ON) then LOG_write("%3.3f %s: RESPONSE NULL\n", getElapsedTime(), phase2String(ctx.Phase)) end - end - - if (ctx.Phase == PHASE.VALUE_CHANGING) then - ctx.Phase = PHASE.VALUE_CHANGING_WAIT - end + -- 09 00 01 00 00 00 00 00 00 00 00 00 00 00 00 + -- 09 00 7E 00 20 9E 28 00 20 9E 28 00 20 8D 7E : After TX Heartbeat one of this (FC6250) + -- 09 00 18 00 20 08 00 00 00 08 00 00 00 98 AE AR8360T + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: RESPONSE RX Heartbeat --Context: 0x%02X\n", + menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase), multiBuffer(12)) end else - if (DEBUG_ON) then LOG_write("RESPONSE Unknown Command (0x%X) DATA=%s\n", cmd, multiBuffer2String()) end + if (DEBUG_ON) then Log.LOG_write("RESPONSE Unknown Command (0x%X) DATA=%s\n", cmd, multiBuffer2String()) end end return cmd @@ -1291,117 +625,52 @@ end ------------------------------------------------------------------------------------------------------------ local function DSM_Send_Receive() - local context = DSM_Context + local ctx = DSM_Context - if Waiting_RX == 0 then -- Need to send a request - Waiting_RX = 1 - DSM_sendRequest() - - multiBuffer(10, 0x00) -- Clear Response Buffer - InactivityTime = getTime() + SEND_TIMEOUT -- Reset Inactivity timeout - elseif multiBuffer(10) == 0x09 then -- RX data available + -- Receive part: Process incoming messages if there is nothing to send + if ctx.SendDataToRX == 0 and multiBuffer(10) == 0x09 then local cmd = DSM_processResponse() multiBuffer(10, 0x00) -- Clear Response Buffer to know that we are done with the response + RXInactivityTime = getTime() + SEND_TIMEOUT*4 -- Reset RX Inactivity timeout - if (cmd > 0x00) then -- Any non NULL response - -- Only change to SEND mode if we received a valid response (Ignore NULL Responses, that are really heartbeat i most cases) - Waiting_RX = 0 - InactivityTime = getTime() + SEND_TIMEOUT -- Reset Inactivity timeout - context.Refresh_Display = true + if (cmd > 0x00) then -- RX HeartBeat ?? + -- Only change to SEND mode if we received a valid response (Ignore heartbeat) + ctx.SendDataToRX = 1 + ctx.Refresh_Display = true end else - -- Check if enouth time has passed from last transmit/receive activity - if getTime() > InactivityTime then - if (DEBUG_ON) then LOG_write("%3.3f %s: INACTIVITY TIMEOUT\n", getElapsedTime(), phase2String(context.Phase)) end - - InactivityTime = getTime() + SEND_TIMEOUT - Waiting_RX = 0 -- Switch to Send mode to send heartbeat - - if context.Phase == PHASE.EXIT then -- Did not receive response to Exit_Request + if (getTime() > RXInactivityTime and ctx.Phase ~= PHASE.RX_VERSION and ctx.Phase ~= PHASE.EXIT_DONE) then + if (ctx.isEditing()) then -- If Editing, Extend Timeout + RXInactivityTime = getTime() + SEND_TIMEOUT*4 + else + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: RX INACTIVITY TIMEOUT\n", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end DSM_ReleaseConnection() + error("RX Disconnected") end + end + end - if context.Phase ~= PHASE.RX_VERSION and context.Phase ~= PHASE.VALUE_CHANGING_WAIT and - context.Phase ~= PHASE.WAIT_CMD then - -- Only change to WAIT_CMD if we are NOT already waiting for Data - context.Phase = PHASE.WAIT_CMD - context.Refresh_Display = true + -----TX Part -------------------------------------- + if ctx.SendDataToRX == 1 then -- Need to send a request + ctx.SendDataToRX = 0 + DSM_sendRequest() + TXInactivityTime = getTime() + SEND_TIMEOUT -- Reset Inactivity timeout + else + -- Check if enouth time has passed from last transmit/receive activity + if getTime() > TXInactivityTime then + ctx.SendDataToRX = 1 -- Switch to Send mode to send heartbeat + ctx.Refresh_Display = true + + -- Only change to WAIT_CMD if we are NOT wating for RX version + if ctx.Phase ~= PHASE.RX_VERSION then + -- Phase = If IsEditing then VALUE_CHANGING_WAIT else WAIT_CMD + ctx.Phase = (ctx.isEditing() and PHASE.VALUE_CHANGING_WAIT) or PHASE.WAIT_CMD end - - if context.Phase == PHASE.RX_VERSION then - -- Refresh screen again - context.Refresh_Display = true - end - - end end end -local function load_msg_from_file(fileName, mem, Text, List_Text, List_Text_Img, RxName, Flight_Mode) - local function rtrim(s) - local n = string.len(s) - while n > 0 and string.find(s, "^%s", n) do n = n - 1 end - return string.sub(s, 1, n) - end - - --print(string.format("Loading messages from [%s]",fileName)) - local dataFile = io.open(fileName, "r") -- read File - -- cannot read file??? - assert(dataFile, "Cannot load Message file:" .. fileName) - - local data = io.read(dataFile, mem * 1024) -- read up to 10k characters (newline char also counts!) - io.close(dataFile) - - collectgarbage("collect") - - local lineNo = 0 - for line in string.gmatch(data, "[^\r\n]+") do - lineNo = lineNo + 1 - --print(string.format("Line [%d]: %s",lineNo,line)) - - -- Remove Comments - local s = string.find(line, "--", 1, true) - if (s ~= nil) then - line = string.sub(line, 1, s - 1) - end - - line = rtrim(line) - - if (string.len(line) > 0) then - local a, b, c = string.match(line, "%s*(%a*)%s*|%s*(%w*)%s*|(.*)%s*") - --print(string.format("[%s] [%s] [%s]",a,b,c)) - if (a ~= nil) then - local index = tonumber(b) - - if (index == nil) then - assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, lineNo, b)) - elseif (a == "T") then - Text[index] = c - elseif (a == "LT") then - List_Text[index] = c - elseif (a == "LI") then - List_Text_Img[index] = c - elseif (a == "FM") then - Flight_Mode[0] = c - elseif (a == "RX") then - RxName[index] = c - else - assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, lineNo, a)) - end - end - end - if (lineNo % 50 == 0) then - collectgarbage("collect") - end - end -- For - - --print(string.format("Loaded [%d] messages",lineNo)) - data = nil - end - - -- Init local function DSM_Init(toolName) local dateTime = getDateTime() @@ -1409,121 +678,71 @@ local function DSM_Init(toolName) 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 (DEBUG_ON) then - LOG_write("---------------DSM New Session %s ----------------\n", toolName, dateStr) - LOG_write("Radio Info: %s\n", radio .. " " .. (osname or "OpenTx") .. " " .. ver) - LOG_write("Date : %s\n", dateStr) - LOG_write("DsmLib Version : %s\n", LIB_VERSION) + Log.LOG_write("---------------DSM New Session %s ----------------\n", toolName, dateStr) + Log.LOG_write("Radio Info: %s\n", radio .. " " .. (osname or "OpenTx") .. " " .. ver) + Log.LOG_write("Date : %s\n", dateStr) + Log.LOG_write("DsmLib Version : %s\n", LIB_VERSION) end - - DSM_Context.Phase = PHASE.RX_VERSION - - -- Phase Names - 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_CHANGING_WAIT" - 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.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_ReadTxModelData() - - -- Load messages from external file (/DSMLIB/msg_en.txt) - load_msg_from_file(MSG_FILE,10,Text,List_Text,List_Text_Img,RxName,Flight_Mode) end - -local function DSM_Init_Text(rxId) - --Text to be displayed - -- For menu lines who are not navigation to other menus (SubHeders or Plain text) - -- you can use some formatting options AT THE END OF THE STRING : - - -- Text allightment: /c = CENTER, /r = RIGHT - -- Text effects: /b = BOLD - -- Text formatting: /p = PERCENT numbers (forced if not in Line Type=PERCENT) - -- Navigaton: /m = Force to be a Menu button, when a menu navigates to itself, - -- is usually a message line.. but sometimes, we want to navigate to the same page to refresh values - - -- array List_Values: - -- For some Menu LIST VALUES, special Lines of type:LIST_MENU1, the valur options seems not - -- to be contiguos, the array "Menu_List_Values" can help narrow down the - -- valid menu options. I think this should come from the RX, but cant find where. - -- Most of the times, Limes of type LIST_MENU1 comes with a 0->244 value range that is not correct - -- usually is Ihnibit + range of contiguos values, but cant seems to find in the RX data receive the values - -- to do it automatically +local function DSM_Init_Text_Exceptions() + -- Apply special restrictions to some Values local function getTxChText(ch) return " ("..(MODEL.TX_CH_TEXT[ch] or "--")..")" end - -- OVERRIDES for list of valid VALUES and channel names + local List_Values = menuLib.List_Values + local List_Text = menuLib.List_Text + local Text = menuLib.Text + + Log.LOG_write("Initializing TEXT Exception\n") -- Channel selection for SAFE MODE and GAINS on FC6250HX - -- List_Text[0x000C] = "Inhibit?" --? - for i = 0, 7 do List_Text[0x000D + i] = "Ch"..(i+5) ..getTxChText(i+4) end -- Aux channels (Ch5 and Greater) + --List_Text[0x000C] = "Inhibit?" --? + for i = 0, 7 do + List_Text[0x000D + i] = "Ch"..(i+5) ..getTxChText(i+4) + end -- Aux channels (Ch5 and Greater) -- Servo Output values.. local servoOutputValues = {0x0003,0x002D,0x002E,0x002F} --Inh (GAP), 5.5ms, 11ms, 22ms. Fixing L_m1 with 0..244 range! --List_Text[0x002D] = "5.5ms" - --List_Text[0x002E] = "11ms" + --[0x002E] = "11ms" --List_Text[0x002F] = "22ms" -- Gain Values local gainValues = {0x0032,0x0033,0x0034} -- 1X, 2X, 4X -- Fixing L_m1 with 0..244 range! --List_Text[0x0032] = "1 X" - --List_Text[0x0033] = "2 X" - --List_Text[0x0034] = "4 X" + --[0x0033] = "2 X" + -- List_Text[0x0034] = "4 X" -- List of Channels for Safe, Gains, Panic, except FC6250HX that uses other range (0x00C..0x015) -- the valid range Starts with GEAR if enabled (Thr,Ail,Ele,Rud are not valid, the RX reject them ) -- Valid Values: Inhibit? (GAP), Gear,Aux1..Aux7,X-Plus-1..XPlus-8 - local channelValues = {0x0035,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049} + local channelValues = {0x0035,0x0036,0x0037,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049} --List_Text[0x0035] = "Inhibit?" - for i = 0, 11 do List_Text[0x0036 + i] = "Ch"..(i+1) .. getTxChText(i) end -- Channels on AR637T + for i = 0, 11 do + List_Text[0x0036 + i] = "Ch"..(i+1) .. getTxChText(i) + end -- Channels on AR637T for i = 1, 8 do -- 41..49 - List_Text[0x0041 + i] = "Ch"..(i+13) - end - - -- ****No longer overrides of previous XPlus values, since using different array - -- for List_Text values - - if (rxId ~= RX.FC6250HX) then -- Restrictions for non FC6250HX - List_Values[0x0051]=servoOutputValues - List_Values[0x0052]=servoOutputValues - List_Values[0x0053]=servoOutputValues - List_Values[0x0054]=servoOutputValues - List_Values[0x0055]=servoOutputValues - List_Values[0x0056]=servoOutputValues + List_Text[0x0041 + i] = "Ch"..(i+12) end -- Flight mode channel selection --Text[0x0078] = "FM Channel" - if (rxId ~= RX.FC6250HX) then List_Values[0x0078]=channelValues end --FC6250HX uses other range + List_Values[0x0078]=channelValues -- Gain channel selection --Text[0x0089] = "Gain Channel" - if (rxId ~= RX.FC6250HX) then List_Values[0x0089]=channelValues end --FC6250HX uses other range + List_Values[0x0089]=channelValues -- Gain Sensitivity selection --Text[0x008A] = "Gain Sensitivity/r"; @@ -1534,105 +753,61 @@ local function DSM_Init_Text(rxId) --List_Text[0x00B0] = "Self-Level/Angle Dem" --List_Text[0x00B1] = "Envelope" - --FC6250HX --Text[0x00D2] = "Panic Channel" - if (rxId ~= RX.FC6250HX) then List_Values[0x00D2]=channelValues end --FC6250HX uses other range - + List_Values[0x00D2]=channelValues + --Inh, Self-Level/Angle Dem, Envelope -- (L_M was wide open range 0->244) --Text[0x01F8] = "Safe Mode"; List_Values[0x01F8]=safeModeOptions end --- Adjust the displayed value for Flight mode line as needed -local function GetFlightModeValue(line) - local value = line.Val or 0 -- protect when in the middle of changing FM can be nil - local textId = line.TextId - local header = line.Text - local out = value .. "" - - if (textId == 0x8000) then -- FC6250HX - if (DSM_Context.RX.Id == RX.FC6250HX) then - -- Helicopter Flights modes - if (value==0) then out = header .. " 1 / Normal 1" - elseif (value==1) then out = header .. " 2 / Normal 2" - elseif (value==2) then out = header .. " 3 / Stunt 1" - elseif (value==3) then out = header .. " 4 / Stunt 2" - elseif (value==4) then out = header .. " 5 / Hold" - else - out = header .. " " .. value - end - else - -- No adjustment needed - out = header .. " " .. (value + 1) - end - elseif (textId == 0x8001) then -- AR630-637, AR8360T, AR10360T - -- Seems that we really have to add +1 to the value, so Flight Mode 0 is Really Flight Mode 1 - out = header .. " " .. (value + 1) - else - -- Default, return the value as we Have it - out = header .. " " .. (value + 1) - end - return out +-- Initial Setup +local function FP_Init(toolname) + DSM_Context.Phase = PHASE.INIT + + DSM_Init(toolname) + menuLib.clearAllText() end ------------------------------------------------------------------------------------------------------------- --- Lib EXPORTS +local initStep=0 +local FileState = {} --- Export Constants -Lib.PHASE = PHASE -Lib.LINE_TYPE = LINE_TYPE -Lib.RX = RX -Lib.DISP_ATTR = DISP_ATTR -Lib.CH_TYPE = CH_TYPE +local function Message_Init() + lcd.clear() + if (initStep == 0) then + if (IS_EDGETX) then + -- Load all messages at once + menuLib.LoadTextFromFile(MSG_FILE,13) + initStep=1 -Lib.BACK_BUTTON = BACK_BUTTON -Lib.NEXT_BUTTON = NEXT_BUTTON -Lib.PREV_BUTTON = PREV_BUTTON -Lib.MAX_MENU_LINES = MAX_MENU_LINES + else + -- load messages incrementally to avoid "CPU Limit" + lcd.drawText(30, 50, "Loading Msg file: "..(FileState.lineNo or 0)) + if (menuLib.INC_LoadTextFromFile(MSG_FILE, FileState)==1) then + initStep=1 + end + end + elseif (initStep == 1) then + DSM_Init_Text_Exceptions() --- Export Shared Context Variables -Lib.DSM_Context = DSM_Context -Lib.MODEL = MODEL + DSM_Context.Phase = PHASE.RX_VERSION + DSM_StartConnection() + end +end --- Export Functions -Lib.LOG_write = LOG_write -Lib.LOG_close = LOG_close -Lib.getElapsedTime = getElapsedTime -Lib.Get_Text = Get_Text -Lib.Get_List_Text = Get_List_Text -Lib.Get_List_Text_Img = Get_List_Text_Img +local function FP_Run() + if (DSM_Context.Phase==PHASE.INIT) then + Message_Init() + return 0 + end + + return DSM_Send_Receive() +end -Lib.phase2String = phase2String -Lib.lineValue2String = lineValue2String -Lib.menu2String = menu2String -Lib.menuLine2String = menuLine2String -Lib.channelType2String = channelType2String +local function FP_Done() + local ctx = menuLib.DSM_Context + ctx.Phase = PHASE.EXIT_DONE + DSM_ReleaseConnection() +end -Lib.isSelectableLine = isSelectableLine -Lib.isEditableLine = isEditableLine -Lib.isListLine = isListLine -Lib.isPercentValueLine = isPercentValueLine -Lib.isPercentValueLineByMinMax = isPercentValueLineByMinMax -Lib.isNumberValueLine = isNumberValueLine -Lib.isDisplayAttr = isDisplayAttr -Lib.isFlightModeLine = isFlightModeLine -Lib.GetFlightModeValue = GetFlightModeValue - -Lib.StartConnection = DSM_StartConnection -Lib.ReleaseConnection = DSM_ReleaseConnection -Lib.ChangePhase = DSM_ChangePhase -Lib.MenuPostProcessing = DSM_MenuPostProcessing -Lib.MenuLinePostProcessing = DSM_MenuLinePostProcessing -Lib.Value_Add = DSM_Value_Add -Lib.Value_Default = DSM_Value_Default -Lib.Value_Write_Validate = DSM_Value_Write_Validate -Lib.GotoMenu = DSM_GotoMenu -Lib.MoveSelectionLine = DSM_MoveSelectionLine -Lib.Send_Receive = DSM_Send_Receive -Lib.Init = DSM_Init -Lib.Init_Text = DSM_Init_Text - -Lib.SetDSMChannelInfo = DSM_SetDSMChannelInfo -Lib.Get_RxName = Get_RxName - -return Lib +return { init=FP_Init, run=FP_Run, done=FP_Done } diff --git a/Lua_scripts/DSMLIB/DsmLogLib.lua b/Lua_scripts/DSMLIB/DsmLogLib.lua new file mode 100644 index 0000000..4d13be2 --- /dev/null +++ b/Lua_scripts/DSMLIB/DsmLogLib.lua @@ -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 diff --git a/Lua_scripts/DSMLIB/DsmMainMenuLib.lua b/Lua_scripts/DSMLIB/DsmMainMenuLib.lua new file mode 100644 index 0000000..4c3d3ad --- /dev/null +++ b/Lua_scripts/DSMLIB/DsmMainMenuLib.lua @@ -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 } \ No newline at end of file diff --git a/Lua_scripts/DSMLIB/DsmMenuLib.lua b/Lua_scripts/DSMLIB/DsmMenuLib.lua new file mode 100644 index 0000000..02951f5 --- /dev/null +++ b/Lua_scripts/DSMLIB/DsmMenuLib.lua @@ -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 \ No newline at end of file diff --git a/Lua_scripts/DSMLIB/DsmModelLib.lua b/Lua_scripts/DSMLIB/DsmModelLib.lua new file mode 100644 index 0000000..a3e65da --- /dev/null +++ b/Lua_scripts/DSMLIB/DsmModelLib.lua @@ -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 + diff --git a/Lua_scripts/DSMLIB/DsmSetupLib.lua b/Lua_scripts/DSMLIB/DsmSetupLib.lua deleted file mode 100644 index 0b1d298..0000000 --- a/Lua_scripts/DSMLIB/DsmSetupLib.lua +++ /dev/null @@ -1,1107 +0,0 @@ ----- ######################################################################### ----- # # ----- # 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 DEBUG_ON, SIMULATION_ON = ... -- Get DebugON from parameters -local SETUP_LIB_VERSION = "0.54" - -local DATA_PATH = "/MODELS/DSMDATA" -- Path to store model settings files -local dsmLib = assert(loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua"))(DEBUG_ON) - -local PHASE = dsmLib.PHASE -local LINE_TYPE = dsmLib.LINE_TYPE -local CH_TYPE = dsmLib.CH_TYPE -local MODEL = dsmLib.MODEL - -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, -} - -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, - - DATA_END = 1040 -} - -local SetupLib = {} - --- MENU DATA Management -local MENU_DATA = {} -- Store the variables used in the Menus. -local menuDataChanged = false -- Flag to notify if any data has changed -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 lastGoodMenu=0 - -------------------- Model Setup Helper functions ---------------------- - -local function printChannelSummary() - -- Summary - print("CHANNEL INFORMATION") - print("Aircraft:".. (aircraft_type_text[currAircraftType] or "--")) - print("Wing Type:".. (wing_type_text[currWingType] or "--")) - print("Tail Type:".. (tail_type_text[currTailType] 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 - -local function printServoReverseInfo() - print("SERVO Normal/Reverse INFORMATION") - for i=0,10 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 - -local function ST_PlaneWingInit(wingType) - print("Change Plane WingType:"..wing_type_text[wingType]) - - currWingType = 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 - - - printChannelSummary() -end - -local function 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]) - - currTailType = 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 - - printChannelSummary() -end - -local function ST_GliderWingInit(wingType) - print("Change Glider WingType:"..wing_type_text[wingType]) - - currWingType = 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 - - printChannelSummary() -end - -local function 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]) - - currTailType = 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 - - printChannelSummary() -end - - -local function ST_AircraftInit(aircraftType) - MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] = aircraftType - currAircraftType = aircraftType - - print("Change Aircraft:".. aircraft_type_text[aircraftType]) - - -- Setup Default Aircraft Wing/Tail - if (aircraftType==AIRCRAFT_TYPE.PLANE) then - ST_PlaneWingInit(WING_TYPE.AIL_1) - ST_PlaneTailInit(TAIL_TYPE.RUD_1_ELEV_1) - elseif (aircraftType==AIRCRAFT_TYPE.GLIDER) then - ST_GliderWingInit(WING_TYPE.AIL_1) - ST_GliderTailInit(TAIL_TYPE.RUD_1_ELEV_1) - else - ST_PlaneWingInit(WING_TYPE.AIL_1) - ST_PlaneTailInit(TAIL_TYPE.RUD_1_ELEV_1) - end - - -end - - --- Setup Initial Default Data for the Menus -local function ST_Default_Data() - print("Initializing Menu DATA") - 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 - - printServoReverseInfo() - -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?? - -local function 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 ST_LoadFileData() - local fname = 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 - - -- Get the basic info - currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] - currWingType = MENU_DATA[MEMU_VAR.WING_TYPE] - 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])) - - printChannelSummary() - printServoReverseInfo() - - - -- No need to save right now - menuDataChanged = false - - -- 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 ST_SaveFileData() - local fname = 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) - menuDataChanged = false -end - --- This Creates the Servo Settings that will be used to pass to --- Forward programming -local function CreateDSMPortChannelInfo() - local function ApplyWingMixA(b2) - -- ELEVON - if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return 0x20 end; -- 0x03 - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.REVERSE) then return 0x50 end; -- 0x23 - - -- Default normal/reverse behaviour - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return 0x00 end; -- 0x83 - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return 0x70 end; -- 0xA3 - end - - local function ApplyWingMixB(b2) - -- ELEVON - -- Default normal/reverse behaviour - if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return 0x00 end; -- 0x03 - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.REVERSE) then return 0x70 end; -- 0x23 - - -- Difference with B - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return 0x20 end; -- 0x83 - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return 0x50 end; -- 0xA3 - end - - local function ApplyTailMixA(b2) - -- VTAIL - -- Default normal/reverse behaviour - if (b2==CH_TYPE.RUD+CH_TYPE.ELE) then return 0x00 end; -- 0x06 - if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.REVERSE) then return 0x70 end; -- 0x26 - - if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE) then return 0x20 end; -- 0x86 - if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return 0x50 end; -- 0xA6 - - --TRAILERON - -- Default normal/reverse behaviour - if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return 0x00 end; -- 0x03 - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.REVERSE) then return 0x70 end; -- 0x23 - - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return 0x10 end; -- 0x83 - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return 0x60 end; -- 0xA3 - - end - - local function ApplyTailMixB(b2) - -- VTAIL - -- Default normal/reverse behaviour - if (b2==CH_TYPE.RUD+CH_TYPE.ELE) then return 0x00 end; -- 0x06 - if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.REVERSE) then return 0x70 end; -- 0x26 - - if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE) then return 0x40 end; -- 0x86 - if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return 0x30 end; -- 0xA6 - - --TAILERON - if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return 0x10 end; -- 0x03 - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.REVERSE) then return 0x60 end; -- 0x23 - - -- Default normal/reverse behaviour - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return 0x00 end; -- 0x83 - if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE+CH_TYPE.REVERSE) then return 0x70 end; -- 0xA3 - end - - - - local DSM_ChannelInfo = {} - - for i=0, 9 do - DSM_ChannelInfo[i] = {[0]= 0x00, CH_TYPE.NONE} -- Initialize with no special function - end - - 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, 9 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]+0x70 -- 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, dsmLib.channelType2String(b1,b2))) - end - - return DSM_ChannelInfo, string.format("Aircraft(%s) Wing(%s) Tail(%s)",aircraft_type_text[currAircraftType],wing_type_text[wingType],tail_type_text[tailType]) -end - ----- Memu Processing Helpers to Mimic the DSM RX menu behaviour - -local function ST_StartConnection() - return 0 -end - -local function ST_ReleaseConnection() -end - --- Clear each line of the menu -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 - --- Post processing needed for each menu -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 - --- Creates the menus to Render with the GUI -local function ST_LoadMenu(menuId) - local ctx = dsmLib.DSM_Context - - local function formatTXRevert(port) - return ((MODEL.modelOutputChannel[port].revert==0 and " (Tx:Normal)") or " (Tx:Reverse)") - end - - 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 = 0x1001,TextId=0 } - - if (menuDataChanged) 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 - else - 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 - end - lastGoodMenu = menuId - elseif (menuId==0x1001) then -- MODEL SETUP - ctx.Menu = { MenuId = 0x1001, Text = "Model Setup ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0x1000, 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 - printChannelSummary() - ST_SaveFileData() - - - local msg1 = "Data saved to: " - local msg2 = " "..DATA_PATH.."/"..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 = 0x1000 } - ctx.SelLine = 6 - lastGoodMenu = menuId - elseif (menuId==0x1006) then - ST_LoadFileData() - local msg1 = "Data restored from: " - local msg2 = " "..DATA_PATH.."/"..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 = 0x1000 } - ctx.SelLine = 6 - lastGoodMenu = menuId - elseif (menuId==0x1010) then - ctx.Menu = { MenuId = 0x1010, Text = "Aircraft Type", PrevId = 0x1001, NextId = 0x1011, BackId = 0, 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:"..aircraft_type_text[currAircraftType], PrevId = 0x1010, NextId = 0x1020, BackId = 0, 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 = aircraft_type_text[currAircraftType].." Wing:"..wing_type_text[currWingType] - - ctx.Menu = { MenuId = 0x1020, Text = title, PrevId = 0x1011, NextId = 0x1021, BackId = 0, 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 = aircraft_type_text[currAircraftType].." Tail:"..tail_type_text[currTailType] - - ctx.Menu = { MenuId = 0x1021, Text = title, PrevId = 0x1020, NextId = 0x1001, BackId = 0, 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 - 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 - 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 = dsmLib.BACK_BUTTON - end - - PostProcessMenu() -end - --- ST_SendReceive --- Main state machine for the Setup menu - -local function ST_SendReceive() - local ctx = dsmLib.DSM_Context - --if (DEBUG_ON) then dsmLib.LOG_write("%3.3f %s: ", dsmLib.getElapsedTime(), dsmLib.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.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 (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 - ST_AircraftInit(MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]) - end - - -- Did the Wing type change? - if (currWingType ~= MENU_DATA[MEMU_VAR.WING_TYPE]) then - if (currAircraftType==AIRCRAFT_TYPE.GLIDER) then - ST_GliderWingInit(MENU_DATA[MEMU_VAR.WING_TYPE]) - else - ST_PlaneWingInit(MENU_DATA[MEMU_VAR.WING_TYPE]) - 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 - ST_GliderTailInit(MENU_DATA[MEMU_VAR.TAIL_TYPE]) - else - ST_PlaneTailInit(MENU_DATA[MEMU_VAR.TAIL_TYPE]) - end - end - - ctx.Phase = PHASE.WAIT_CMD - elseif ctx.Phase == PHASE.EXIT then - ctx.Phase=PHASE.EXIT_DONE - end -end - ------------------------------------------------------------------------------------------------------------- --- TEXT Management - -local List_Text = {} -local Text = {} -local List_Text_Img = {} -local List_Values = {} - --- Get the text for this menus -local function ST_Get_Text(index) - 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 - --- Get the List text for this menus -local function ST_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 - --- Get the List_Text Images -local function ST_Get_List_Text_Img(index) - local out = List_Text_Img[index] - return out -end - -local function ST_Get_List_Values(index) - local out = List_Values[index] - return out -end - --- Inital List and Image Text for this menus -local function ST_Init_Text(rxId) - dsmLib.Init_Text(rxId) - - -- 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 - List_Text[300+CH_MODE_TYPE.NORMAL] = "Normal " - List_Text[300+CH_MODE_TYPE.REVERSE] = "Reverse" - -end - --- Initial Setup -local function ST_Init() - -- Initialize dsmLib background - dsmLib.Init() - -- Initialize text (use RX_ID 0) - ST_Init_Text(0) - - -- Setup default Data, and load a file if exist - ST_Default_Data() - if (ST_LoadFileData()==0) then -- Did not load a file - ST_SaveFileData() -- Save Defaults - end -end - - ------------------------------------------------------------------------------------------------------------- --- Lib EXPORTS - --- Export Constants -SetupLib.PHASE = dsmLib.PHASE -SetupLib.LINE_TYPE = dsmLib.LINE_TYPE -SetupLib.RX = dsmLib.RX -SetupLib.DISP_ATTR = dsmLib.DISP_ATTR - -SetupLib.BACK_BUTTON = dsmLib.BACK_BUTTON -SetupLib.NEXT_BUTTON = dsmLib.NEXT_BUTTON -SetupLib.PREV_BUTTON = dsmLib.PREV_BUTTON -SetupLib.MAX_MENU_LINES = dsmLib.MAX_MENU_LINES - --- Export Shared Context Variables -SetupLib.DSM_Context = dsmLib.DSM_Context - --- Export Functions -SetupLib.LOG_write = dsmLib.LOG_write -SetupLib.LOG_close = dsmLib.LOG_close -SetupLib.getElapsedTime = dsmLib.getElapsedTime - -SetupLib.Get_Text = ST_Get_Text -SetupLib.Get_List_Text = ST_Get_List_Text -SetupLib.Get_List_Text_Img = ST_Get_List_Text_Img - -SetupLib.phase2String = dsmLib.phase2String -SetupLib.menu2String = dsmLib.menu2String -SetupLib.menuLine2String = dsmLib.menuLine2String - -SetupLib.isSelectableLine = dsmLib.isSelectableLine -SetupLib.isEditableLine = dsmLib.isEditableLine -SetupLib.isListLine = dsmLib.isListLine -SetupLib.isPercentValueLine = dsmLib.isPercentValueLine -SetupLib.isNumberValueLine = dsmLib.isNumberValueLine -SetupLib.isDisplayAttr = dsmLib.isDisplayAttr -SetupLib.isFlightModeLine = dsmLib.isFlightModeLine -SetupLib.GetFlightModeValue = dsmLib.GetFlightModeValue - -SetupLib.StartConnection = ST_StartConnection -- Override Function -SetupLib.ReleaseConnection = ST_ReleaseConnection -- Override Function -SetupLib.ChangePhase = dsmLib.ChangePhase -SetupLib.Value_Add = dsmLib.Value_Add -SetupLib.Value_Default = dsmLib.Value_Default -SetupLib.Value_Write_Validate = dsmLib.Value_Write_Validate -SetupLib.GotoMenu = dsmLib.GotoMenu -SetupLib.MoveSelectionLine = dsmLib.MoveSelectionLine -SetupLib.Send_Receive = ST_SendReceive -- Override Function -SetupLib.Init = ST_Init -SetupLib.Init_Text = ST_Init_Text - -SetupLib.CreateDSMPortChannelInfo = CreateDSMPortChannelInfo - -return SetupLib diff --git a/Lua_scripts/DSMLIB/DsmSetupMenuLib.lua b/Lua_scripts/DSMLIB/DsmSetupMenuLib.lua new file mode 100644 index 0000000..2aca668 --- /dev/null +++ b/Lua_scripts/DSMLIB/DsmSetupMenuLib.lua @@ -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 } \ No newline at end of file diff --git a/Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua b/Lua_scripts/DSMLIB/DsmSimMenuLib.lua similarity index 86% rename from Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua rename to Lua_scripts/DSMLIB/DsmSimMenuLib.lua index 004edfb..888208d 100644 --- a/Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua +++ b/Lua_scripts/DSMLIB/DsmSimMenuLib.lua @@ -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 = dsmLib.PHASE -local LINE_TYPE = dsmLib.LINE_TYPE -local Get_Text = dsmLib.Get_Text +local PHASE = menuLib.PHASE +local LINE_TYPE = menuLib.LINE_TYPE local SimLib = {} @@ -39,46 +38,12 @@ local lastGoodMenu=0 local RX_loadMenu = nil 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) - clearMenuLines() - local ctx = dsmLib.DSM_Context + menuLib.clearMenuLines() + local ctx = menuLib.DSM_Context if (menuId==0x1000) then --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[3] = { Type = LINE_TYPE.MENU, TextId = 0x0103, 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 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[3] = { Type = LINE_TYPE.MENU, TextId = 0x0109, 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 elseif (menuId==0x1051) then --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 -- Save Settings and Reboot ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 } - ctx.SelLine = dsmLib.BACK_BUTTON + ctx.SelLine = menuLib.BACK_BUTTON else print("NOT IMPLEMENTED") 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 - PostProcessMenu() + menuLib.PostProcessMenu() end local function FC6250HX_loadMenu(menuId) - clearMenuLines() - local ctx = dsmLib.DSM_Context + menuLib.clearMenuLines() + local ctx = menuLib.DSM_Context if (menuId==0x1000) then --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[#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 ] 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[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.SelLine = 0 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[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 lastGoodMenu = menuId elseif (menuId==0x1300) then --M[Id=0x1300 P=0x0 N=0x0 B=0x1000 Text="Setup"[0xDE]] --L[#0 T=M VId=0x1310 Text="Swashplate"[0xD3] 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[#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 ] @@ -1142,6 +1138,12 @@ local function FC6250HX_loadMenu(menuId) 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[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[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 } @@ -1182,12 +1184,27 @@ local function FC6250HX_loadMenu(menuId) lastGoodMenu = menuId elseif (menuId==0x1330) then --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.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xE1, ValId = 0x1331 } - - ctx.SelLine = 0 + + if (not RX_Initialized) then + 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 elseif (menuId==0x1331) then --M[Id=0x1331 P=0x0 N=0x0 B=0x1330 Text="Subtrim"[0xE1]] @@ -1202,6 +1219,28 @@ local function FC6250HX_loadMenu(menuId) ctx.SelLine = 0 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 --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 ] @@ -1224,6 +1263,100 @@ local function FC6250HX_loadMenu(menuId) ctx.SelLine = 0 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 --M[Id=0x1400 P=0x0 N=0x0 B=0x1000 Text="SAFE"[0xDA]] --L[#0 T=M VId=0x1410 Text="Stability"[0xDB] MId=0x1400 ] @@ -1306,30 +1439,29 @@ local function FC6250HX_loadMenu(menuId) lastGoodMenu = menuId elseif (menuId==0x17F1) then --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.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xC8, ValId = 0x1700 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x93, ValId = 0x1700 } ctx.SelLine = 3 lastGoodMenu = menuId elseif (menuId==0x0001) then -- Save Settings and Reboot ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 } - ctx.SelLine = dsmLib.BACK_BUTTON + ctx.SelLine = menuLib.BACK_BUTTON else 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 - PostProcessMenu() + menuLib.PostProcessMenu() end - local function loadMenu(menuId) - clearMenuLines() - local ctx = dsmLib.DSM_Context + menuLib.clearMenuLines() + local ctx = menuLib.DSM_Context if (menuId==0x1000) then --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 ] 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[1] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR631 (INITIALIZED)", ValId = 0x1002, 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 = "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[5] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "FC6250HX (UNLOCKED)", ValId = 0x1006, TextId=0 } ctx.SelLine = 0 lastGoodMenu = menuId elseif (menuId==0x1001) then RX_Initialized = false - ctx.RX.Id = dsmLib.RX.AR631 - dsmLib.Init_Text(ctx.RX.Id) - ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM' - ctx.RX.Version = "2.38.5" - + ctx.RX.Id = menuLib.RX.AR631 + ctx.RX.Name = "AR630/631/637-SIM" + ctx.RX.Version = "2.38.5" RX_loadMenu = AR631_loadMenu RX_loadMenu(0x01000) elseif (menuId==0x1002) then - ctx.RX.Id = dsmLib.RX.AR631 - dsmLib.Init_Text(ctx.RX.Id) - ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM' + RX_Initialized = true + ctx.RX.Id = menuLib.RX.AR631 + ctx.RX.Name = "AR630/631/637-SIM" ctx.RX.Version = "2.38.5" - RX_loadMenu = AR631_loadMenu RX_loadMenu(0x01000) elseif (menuId==0x1005) then - ctx.RX.Id = dsmLib.RX.FC6250HX - dsmLib.Init_Text(ctx.RX.Id) - ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM' + RX_Initialized = true + ctx.RX.Id = menuLib.RX.FC6250HX + ctx.RX.Name = "FC6250HX-SIM" 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(0x01000) end @@ -1375,13 +1513,14 @@ end local function SIM_Send_Receive() - local ctx = dsmLib.DSM_Context - --if (DEBUG_ON) then dsmLib.LOG_write("%3.3f %s: ", dsmLib.getElapsedTime(), dsmLib.phase2String(ctx.Phase)) end + local ctx = menuLib.DSM_Context + --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 ctx.RX.Name = "SIMULATOR" - ctx.RX.Version = "0.54" + ctx.RX.Version = SIM_LIB_VERSION ctx.Phase = PHASE.MENU_TITLE + ctx.Menu.MenuId=0 ctx.Refresh_Display = true RX_loadMenu = loadMenu @@ -1399,8 +1538,8 @@ local function SIM_Send_Receive() elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value 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 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("%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 @@ -1408,9 +1547,9 @@ local function SIM_Send_Receive() 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 dsmLib.LOG_write("%3.3f %s: ", dsmLib.getElapsedTime(), dsmLib.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 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("%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 @@ -1418,56 +1557,40 @@ local function SIM_Send_Receive() end end ------------------------------------------------------------------------------------------------------------- --- Lib EXPORTS +local FileState = {} --- Export Constants -SimLib.PHASE = dsmLib.PHASE -SimLib.LINE_TYPE = dsmLib.LINE_TYPE -SimLib.RX = dsmLib.RX -SimLib.DISP_ATTR = dsmLib.DISP_ATTR +-- Initial Setup +local function Sim_Init() + local ctx = menuLib.DSM_Context + ctx.Phase = PHASE.INIT + + 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 -SimLib.NEXT_BUTTON = dsmLib.NEXT_BUTTON -SimLib.PREV_BUTTON = dsmLib.PREV_BUTTON -SimLib.MAX_MENU_LINES = dsmLib.MAX_MENU_LINES +local function SIM_Run() + if (menuLib.DSM_Context.Phase == PHASE.INIT) then + if (IS_EDGETX) then + 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 -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 +return { init=Sim_Init, run=SIM_Run, done=SIM_Done } diff --git a/Lua_scripts/DSMLIB/img/h_rx_pos_1.png b/Lua_scripts/DSMLIB/img/h_rx_pos_1.png new file mode 100644 index 0000000..2fbc84d Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_rx_pos_1.png differ diff --git a/Lua_scripts/DSMLIB/img/h_rx_pos_2.png b/Lua_scripts/DSMLIB/img/h_rx_pos_2.png new file mode 100644 index 0000000..c458f03 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_rx_pos_2.png differ diff --git a/Lua_scripts/DSMLIB/img/h_rx_pos_3.png b/Lua_scripts/DSMLIB/img/h_rx_pos_3.png new file mode 100644 index 0000000..b9aef9a Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_rx_pos_3.png differ diff --git a/Lua_scripts/DSMLIB/img/h_rx_pos_4.png b/Lua_scripts/DSMLIB/img/h_rx_pos_4.png new file mode 100644 index 0000000..9427670 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_rx_pos_4.png differ diff --git a/Lua_scripts/DSMLIB/img/h_rx_pos_5.png b/Lua_scripts/DSMLIB/img/h_rx_pos_5.png new file mode 100644 index 0000000..2a526c3 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_rx_pos_5.png differ diff --git a/Lua_scripts/DSMLIB/img/h_rx_pos_6.png b/Lua_scripts/DSMLIB/img/h_rx_pos_6.png new file mode 100644 index 0000000..0d6e3d6 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_rx_pos_6.png differ diff --git a/Lua_scripts/DSMLIB/img/h_rx_pos_7.png b/Lua_scripts/DSMLIB/img/h_rx_pos_7.png new file mode 100644 index 0000000..f905abf Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_rx_pos_7.png differ diff --git a/Lua_scripts/DSMLIB/img/h_rx_pos_8.png b/Lua_scripts/DSMLIB/img/h_rx_pos_8.png new file mode 100644 index 0000000..38ca245 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_rx_pos_8.png differ diff --git a/Lua_scripts/DSMLIB/img/h_swp_3_120.png b/Lua_scripts/DSMLIB/img/h_swp_3_120.png new file mode 100644 index 0000000..0858fb8 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_swp_3_120.png differ diff --git a/Lua_scripts/DSMLIB/img/h_swp_3_120inv.png b/Lua_scripts/DSMLIB/img/h_swp_3_120inv.png new file mode 100644 index 0000000..7e7173e Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_swp_3_120inv.png differ diff --git a/Lua_scripts/DSMLIB/img/h_swp_3_135.png b/Lua_scripts/DSMLIB/img/h_swp_3_135.png new file mode 100644 index 0000000..8b06374 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_swp_3_135.png differ diff --git a/Lua_scripts/DSMLIB/img/h_swp_3_135inv.png b/Lua_scripts/DSMLIB/img/h_swp_3_135inv.png new file mode 100644 index 0000000..656ec64 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_swp_3_135inv.png differ diff --git a/Lua_scripts/DSMLIB/img/h_swp_3_140.png b/Lua_scripts/DSMLIB/img/h_swp_3_140.png new file mode 100644 index 0000000..5058d97 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_swp_3_140.png differ diff --git a/Lua_scripts/DSMLIB/img/h_swp_3_140inv.png b/Lua_scripts/DSMLIB/img/h_swp_3_140inv.png new file mode 100644 index 0000000..71faf52 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_swp_3_140inv.png differ diff --git a/Lua_scripts/DSMLIB/img/h_swp_3_90.png b/Lua_scripts/DSMLIB/img/h_swp_3_90.png new file mode 100644 index 0000000..88e8d2c Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_swp_3_90.png differ diff --git a/Lua_scripts/DSMLIB/img/h_swp_3_90inv.png b/Lua_scripts/DSMLIB/img/h_swp_3_90inv.png new file mode 100644 index 0000000..b104f08 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_swp_3_90inv.png differ diff --git a/Lua_scripts/DSMLIB/img/h_swp_norm.png b/Lua_scripts/DSMLIB/img/h_swp_norm.png new file mode 100644 index 0000000..17e38cc Binary files /dev/null and b/Lua_scripts/DSMLIB/img/h_swp_norm.png differ diff --git a/Lua_scripts/DSMLIB/img/tt_taileron.png b/Lua_scripts/DSMLIB/img/tt_taileron.png new file mode 100644 index 0000000..cbf22a3 Binary files /dev/null and b/Lua_scripts/DSMLIB/img/tt_taileron.png differ diff --git a/Lua_scripts/DSMLIB/msg_fwdp_en.txt b/Lua_scripts/DSMLIB/msg_fwdp_en.txt index 820cfad..c59d6e3 100644 --- a/Lua_scripts/DSMLIB/msg_fwdp_en.txt +++ b/Lua_scripts/DSMLIB/msg_fwdp_en.txt @@ -9,7 +9,7 @@ LT|0x0003|Inh LT|0x0004|Act -- -- Channel selection for SAFE MODE and GAINS on FC6250HX -LT|0x000C|Inhibit? +LT|0x000C|Inh LT|0x000D|Ch5 LT|0x000E|Ch6 LT|0x000F|Ch7 @@ -29,7 +29,7 @@ LT|0x0032|1 X LT|0x0033|2 X LT|0x0034|4 X -- -LT|0x0035|Inh? +LT|0x0035|Inh LT|0x0036|Thr LT|0x0037|Ail LT|0x0038|Ele @@ -71,7 +71,7 @@ T |0x0055|Output Channel 5 T |0x0056|Output Channel 6 -- -- FailSafe Options ---LT|0x005E|Inhibit +--LT|0x005E|Inh LT|0x005F|Hold Last LT|0x0060|Preset --LT|0x0061|Custom @@ -79,8 +79,8 @@ LT|0x0060|Preset T |0x0071|Proportional T |0x0072|Integral T |0x0073|Derivate --- T |0x0078|FM Channel +T |0x007F|Attitude Gain -- T |0x0080|Orientation T |0x0082|Heading @@ -93,18 +93,46 @@ T |0x008A|Gain Sensitivity/r -- Right Align T |0x008B|Panic 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 --- --- FC6250HX: Callibration Menu -> Begin..Start, Complete, Done -T |0x0091|Begin +LT|0x008E|Normal +LT|0x008F|Reversed + +-- FC6250HX: Callibration T |0x0090|Apply +T |0x0091|Begin T |0x0092|Start T |0x0093|Complete 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 |0x0098|Factory Reset --- T |0x0099|Advanced Setup T |0x009A|Capture Failsafe Positions T |0x009C|Custom Failsafe @@ -115,11 +143,11 @@ T |0x00A5|First Time Setup T |0x00AA|Capture Gyro Gains T |0x00AD|Gain Channel Select T |0x00AF|Dynamic -T |0x00B0|Self-Level/Angle Dem -T |0x00B1|Envelope +LT|0x00B0|Self-Level/Angle Dem +LT|0x00B1|Envelope -- -- Flight Modes List Options -LT|0x00B5|Inhibit +LT|0x00B5|Inh LT|0x00B6|FM1 LT|0x00B7|FM2 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 |0x00C7|Calibrate Sensor +T |0x00C8|Sensor is Calibrating.. Wait T |0x00CA|SAFE/Panic Mode Setup -- 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 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 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 |0x00D2|Panic Channel T |0x00D3|Swashplate @@ -204,14 +246,21 @@ T |0x00DF|AFR T |0x00E0|Collective T |0x00E1|Subtrim T |0x00E2|Phasing +T |0x00E3|Pre-Comp T |0x00E4|E-Ring T |0x00E5|Swash Type T |0x00E6|Travel T |0x00E7|Left T |0x00E8|Right +T |0x00EA|Low Throttle +-- +T |0x00F2|Governor +T |0x00F4|Soft Start -- LT|0x00F2|Fixed LT|0x00F3|Adjustable +LT|0x00F4|Inh +LT|0x00F5|Nitro -- T |0x00F6|Direction 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 |0x0102|reversing, travel, trimmed, etc. T |0x0103|before continuing setup. -T |0x0104| -- Blank +T |0x0104| +T |0x0105| -- Blank -- T |0x0106|Any wing type, channel assignment, T |0x0107|subtrim, or servo reversing changes T |0x0108|require running through initial T |0x0109|setup again. -T |0x010A| -- Blank +T |0x010A| +T |0x010B| -- T |0x0190|Relearn Servo Settings T |0x019C|Enter Receiver Bind Mode @@ -249,6 +300,7 @@ T |0x01EC|Pitch Up T |0x01EE|Thr to Pitch T |0x01EF|Low Thr to Pitch/c/b T |0x01F0|High Thr to Pitch/c/b +T |0x01F1|Filter T |0x01F3|Threshold T |0x01F4|Angle T |0x01F6|Failsafe Angles/c/b @@ -267,14 +319,14 @@ T |0x020D|First Time SAFE Setup T |0x020E|AS3X gains must be tuned T |0x020F|and active in SAFE Flight Modes T |0x0210|to help reduce wobble. -T |0x0211| -- Blank -T |0x0212| -- Blank +T |0x0211| +T |0x0212| T |0x0213| -- Blank -- -- AS3X orientation Setting menu (Level) T |0x021A|Set the model level, T |0x021B|and press Continue. -T |0x021C| -- Blank +T |0x021C| T |0x021D| -- Blank -- -- AS3X orientation Setting menu (Nose down) @@ -283,8 +335,8 @@ T |0x0220|and press Continue. If the T |0x0221|orientation on the next T |0x0222|screen is wrong go back T |0x0223|and try again. --- T |0x0224|Continue +-- T |0x0226|Angle Limits/c/b T |0x0227|Other settings T |0x0229|Set Orientation Manually @@ -301,7 +353,7 @@ T |0x0230| -- Blank T |0x0231|This will overwrite the T |0x0232|backup memory with your T |0x0233|current configuartion. -T |0x0234| -- Blank +T |0x0234| T |0x0235| -- Blank -- -- Restore from Backup Warning @@ -309,7 +361,7 @@ T |0x0236|This will overwrite the T |0x0237|current config with T |0x0238|that which is in T |0x0239|the backup memory. -T |0x023A| -- blank line +T |0x023A| -- Blank -- -- Utilities Copy flight modes T |0x023D|Copy F-Mode Settings @@ -341,7 +393,7 @@ T |0x0257|most be configured. T |0x025A|Select the desired flight mode T |0x025B|switch position to adjust settings T |0x025C|for each flight mode -T |0x025D| -- Blank +T |0x025D| T |0x025E| -- Blank -- -- Utilities, Copy flight mode (Confirm) @@ -357,6 +409,12 @@ T |0x0268|Negative = Nose Down/Roll Left T |0x0269|SAFE - Thr to Pitch 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 |0x0301|Waiting for RX to Restart -- diff --git a/Lua_scripts/DSMLIB/readme.md b/Lua_scripts/DSMLIB/readme.md index c438323..c9d48b4 100644 --- a/Lua_scripts/DSMLIB/readme.md +++ b/Lua_scripts/DSMLIB/readme.md @@ -4,80 +4,112 @@ Rewrite/Enhancements by: Francisco Arzu 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. 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 -Make sure to manually create `/MODELS/DSMDATA` . The script will complain at startup if it does not exist. Here the script saves the Spektrun settings for each of your models. - -Uncompress the Zip file (ZIP version) into your local computer. -In another window, open your TX SDCard and go to /SCRIPTS/TOOLS. When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first) -Copy the entire DSMLIB folder. -Copy the main script you want to use (Color or B&W). +Uncompress the Zip file (ZIP version) into your local computer. +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: -/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_Color.lua -- Color and touch radios DSM FwdPrg_05_MIN.lua -- `NEW!` Minimalistic version for radios with LOW memory (cannot setup new planes) - + /SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files DsmFwPrgLib.lua -- DSM Protocol Message and Menu engine DsmFwPrgSIMLib.lua -- Simulation of AR631, FC6250HX (For GUI development) SetupLib.lua -- Model Setup Screens - msg_fwdp_en.txt -- `NEW!` Messages for forward programing externalized. To support other langs + 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 -/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 + /MODELS/DSMDATA --(ALL CAPITALS) Data of model config (Wing Type, Servo Assignments) + /LOGS/dsm_log.txt --Readable log of the last RX/TX session, usefull for debugging problems + -When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first) # Common Questions 1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:` -V0.53 and newer: The RX is listening to channel changes for this options. Configure the Switch to the channel, togling once the switch will select the channel on the menu field. +- 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. - 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 +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: 1. Fix a problem in the Attitude Trim page (`Gyro Settings->System Setup->SAFE/Panic Setup->Attitude Trim`). It was not saving the values after exiting the menu. This is to change what SAFE considers "Level" flying. 2. Wings 2-Ail 2-Flaps had a bug on the 2nd flap. 3. New Minimalistic script (`DsmFwdPrg_05_MIN.lua`): For radios with very low memory (FrSky QX7, RM Zorro, others). It can only change existing settings, but does not have the Plane Setup menus to setup a completly new plane. In some radios, the very first time it runs (compile + run), it might give you a `not enouth memory` error.. try to run it again. -4. External menu message file (DSMLIB/msg_en.txt and msg_MIN_es.txt). Intial work to do localization and different languages. +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: 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. 5. Provide a simulation of RX to do GUI development in Companion, and understand patterns of how the data is organized. + # Tested Hardware - AR631/AR637xx -- FC6250HX (Blade 230S V2 Helicopter) +- 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) - 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) @@ -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|0x00B1|Envelope + # LOG File The log file of the last use of the script is located at `/LOGS/dsm_log.txt`. **It is overridden on every start to avoid filling up the SD card**. So if you want to keep it, copy or rename it before starting the script again. (it can be renamed in the TX by browsing the SD card) @@ -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 - Test it on AR631, AR637xx, FC6250HX (Helicopter) - ### Some settings that can change (top of Lua file): SIMULATION_ON = false -- FALSE: hide similation menu (DEFAULT), TRUE: show RX simulation menu DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm_log.txt) @@ -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 COLOR version, The code has hardcoded the valid ranges to avoid this problem. - - 2. Glider/Heli/Drone wing types not ready. For Helicopter, use airplane normal wing and normal tail