From 4d8e44096544d6d8b4fef6623cb667e669224d2f Mon Sep 17 00:00:00 2001 From: Frankie Arzu <32604366+frankiearzu@users.noreply.github.com> Date: Thu, 17 Nov 2022 02:42:04 -0600 Subject: [PATCH] Frankie dsm fwrd prg enhancements (#753) DSM Forward Programming Enhancements (New GUI for Color+Touch and BW, etc). Work on EdgeTx and OpenTX. --- Lua_scripts/DSM FwdPrg_05_BW.lua | 439 ++++++++ Lua_scripts/DSM FwdPrg_05_Color.lua | 627 +++++++++++ Lua_scripts/DSMLIB/DsmFwPrgLib.lua | 1374 ++++++++++++++++++++++++ Lua_scripts/DSMLIB/DsmFwPrgLib.luac | Bin 0 -> 29271 bytes Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua | 1075 ++++++++++++++++++ Lua_scripts/DSMLIB/DsmFwPrgSIMLib.luac | Bin 0 -> 20481 bytes Lua_scripts/DSMLIB/readme.txt | 44 + 7 files changed, 3559 insertions(+) create mode 100644 Lua_scripts/DSM FwdPrg_05_BW.lua create mode 100644 Lua_scripts/DSM FwdPrg_05_Color.lua create mode 100644 Lua_scripts/DSMLIB/DsmFwPrgLib.lua create mode 100644 Lua_scripts/DSMLIB/DsmFwPrgLib.luac create mode 100644 Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua create mode 100644 Lua_scripts/DSMLIB/DsmFwPrgSIMLib.luac create mode 100644 Lua_scripts/DSMLIB/readme.txt diff --git a/Lua_scripts/DSM FwdPrg_05_BW.lua b/Lua_scripts/DSM FwdPrg_05_BW.lua new file mode 100644 index 0000000..357ba41 --- /dev/null +++ b/Lua_scripts/DSM FwdPrg_05_BW.lua @@ -0,0 +1,439 @@ +local toolName = "TNS|DSM Forward Prog v0.5 (Text B&W) |TNE" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + +local SIMULATION_ON = true -- FALSE: use real communication to DSM RX (DEFAULT), TRUE: use a simulated version of RX +local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log) +local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX + + +local dsmLib +if (SIMULATION_ON) then + -- library with SIMILATION VERSION. Works really well in Companion for GUI development + dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON) +else + dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON) +end + +local PHASE = dsmLib.PHASE +local LINE_TYPE = dsmLib.LINE_TYPE +local DISP_ATTR = dsmLib.DISP_ATTR + +local DSM_Context = dsmLib.DSM_Context + +local LCD_W_USABLE = LCD_W-10 +-- X for Menu Lines +local LCD_X_LINE_MENU = 10 +-- X offsets for (Title: [Value] debugInfo) lines +local LCD_X_LINE_TITLE = 10 +local LCD_X_LINE_VALUE = 230 +local LCD_X_LINE_DEBUG = 390 + +-- Line Height: make it smaller debugging info tp LCD (some space buttom) +local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27 +-- Y offsets +local LCD_Y_MENU_TITLE = 20 +-- Y offet +local LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 30 +local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT + +local LCD_W_BUTTONS = 47 +local LCD_H_BUTTONS = 25 +local LCD_X_RIGHT_BUTTONS = LCD_W - LCD_W_BUTTONS - 5 + +local TEXT_SIZE = 0 -- NORMAL + +local lastRefresh=0 -- Last time the screen was refreshed +local REFRESH_GUI_MS = 500/10 -- 500ms.. Screen Refresh Rate.. to not use unneded CPU time (in 10ms units to be compatible with getTime()) +local originalValue = nil + +------------------------------------------------------------------------------------------------------------ +local function GUI_SwitchSimulationOFF() + dsmLib.ReleaseConnection() + dsmLib.LOG_close() + + SIMULATION_ON = false + dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON) + DSM_Context = dsmLib.DSM_Context + + dsmLib.Init(toolName) -- Initialize Library + dsmLib.StartConnection() + DSM_Context.Refresh_Display = true +end + +local function openTx_lcd_sizeText(s) + return string.len(s)*5 +end + +local function GUI_Diplay_Button(x,y,w,h,text,selected) + local attr = (selected) and INVERS or 0 -- INVERS if line Selected + lcd.drawText(x+5,y+2, text, attr + TEXT_SIZE) + lcd.drawRectangle(x, y, w, h, LINE_COLOR) +end + +local function GUI_Display_Menu(menu) + local ctx = DSM_Context + local w= LCD_W_USABLE - LCD_W_BUTTONS - 10 -- usable Width for the Menu/Lines + + -- Center Header + local tw = openTx_lcd_sizeText(menu.Text) + local x = w/2 - tw/2 -- Center of Screen - Center of Text + + local bold = 0 + if (TEXT_SIZE~=SMLSIZE) then -- Ignore Bold on small size screens + bold = BOLD + end + lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text,bold + TEXT_SIZE) + + -- Back + if menu.BackId ~= 0 then + GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_MENU_TITLE,LCD_W_BUTTONS,LCD_H_BUTTONS,"Back",ctx.SelLine == dsmLib.BACK_BUTTON) + end + -- Next ? + if menu.NextId ~= 0 then + GUI_Diplay_Button(LCD_X_RIGHT_BUTTONS,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON) + end + -- Prev? + if menu.PrevId ~= 0 then + GUI_Diplay_Button(0,LCD_Y_LOWER_BUTTONS,LCD_W_BUTTONS,LCD_H_BUTTONS,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON) + end + + -- Debug into LCD + if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),TEXT_SIZE + WARNING_COLOR) end -- Phase we are in + if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_MENU,240,dsmLib.menu2String(menu),TEXT_SIZE + WARNING_COLOR) end -- Menu Info +end + +local function GUI_Display_Line_Menu(x,y,w,h,line,selected) + local attr = (selected and INVERS) or 0 -- INVERS if line Selected + local bold = 0 + local text = line.Text + + if dsmLib.isSelectableLine(line) then + -- Menu Line + text = text .. " |>" --OPENTX + else -- SubHeaders and plain text lines + if (TEXT_SIZE~=SMLSIZE) then -- ignore bold on small size screens + bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0 + end + + if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align??? + local tw = openTx_lcd_sizeText(line.Text)+4 + x = LCD_X_LINE_VALUE - tw -- Right + elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Center?? + local tw = openTx_lcd_sizeText(line.Text) + x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text + end + end + + lcd.drawText(x,y, text, attr + bold + TEXT_SIZE) + +end +------------------------------------------------------------------------------------------------------------ +local function GUI_Display_Line_Value(lineNum, line, value, selected, editing) + local bold = 0 + + local y = LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*lineNum) + local x = LCD_X_LINE_TITLE + + ---------- NAME Part + local header = line.Text + -- ONLY do this for Flight Mode (Right Align or Centered) + if (dsmLib.isFlightModeText(line.TextId)) then + -- Display Header + Value together + header = header .. " " .. value + + -- Flight mode display attributes + if (TEXT_SIZE~=SMLSIZE) then -- ignore bold on small size screens + bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0 + end + + if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align + local tw = openTx_lcd_sizeText(header)+4 + x = LCD_X_LINE_VALUE - tw -- Right + elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Centered + local tw = openTx_lcd_sizeText(header) + x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text + end + else + -- No Flight Mode, no effects here + header = header .. ":" + end + + lcd.drawText(x, y, header, bold + TEXT_SIZE) -- display Line Header + + --------- VALUE PART, Skip for Flight Mode since already show the value + if not dsmLib.isFlightModeText(line.TextId) then + local attrib = 0 + value = value .. (line.Format or "") -- Append % if needed + + if selected then + attrib = INVERS + if editing then -- blink editing entry + attrib = attrib + BLINK + value = "[ " .. value .. " ]" + end + end + + lcd.drawText(LCD_X_LINE_VALUE,y, value, attrib + TEXT_SIZE) -- display value + end + + if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG,y, line.MinMaxDebug or "", TEXT_SIZE + WARNING_COLOR) end -- display debug +end +------------------------------------------------------------------------------------------------------------ +local function GUI_Display() + local ctx = DSM_Context + lcd.clear() + + local header = "DSM Fwrd Programming " + if ctx.Phase ~= PHASE.RX_VERSION then + header = header .. "RX "..ctx.RX.Name.." v"..ctx.RX.Version + end + + --Draw title + if (TEXT_SIZE~=SMLSIZE) then -- ignore tool title small size screens + lcd.drawFilledRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR) + lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE) + end + --Draw RX Menu + if ctx.Phase == PHASE.RX_VERSION then + lcd.drawText(LCD_X_LINE_TITLE,50,"No compatible DSM RX...", BLINK + TEXT_SIZE) + else + local menu = ctx.Menu + if menu.Text ~= nil then + + GUI_Display_Menu(menu) + + for i = 0, dsmLib.MAX_MENU_LINES do + local line = ctx.MenuLines[i] + + if i == ctx.SelLine then + -- DEBUG: Display Selected Line info for ON SCREEN Debugging + if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_TITLE,255,dsmLib.menuLine2String(line),TEXT_SIZE + WARNING_COLOR) end + end + + if line ~= nil and line.Type ~= 0 then + if line.Type == LINE_TYPE.MENU then + -- Menu Line + GUI_Display_Line_Menu(LCD_X_LINE_MENU,LCD_Y_LINE_FIRST+(LCD_Y_LINE_HEIGHT*i), 350, LCD_Y_LINE_HEIGHT, line, i == ctx.SelLine) + else + -- list/value line + local value = line.Val + if line.Val ~= nil then + if dsmLib.isListLine(line) then -- for Lists of Strings, get the text + value = dsmLib.Get_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text + local imgValue = dsmLib.Get_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display?? + + if (imgValue) then -- Optional Image for a Value + --TODO: Pending feature.. create images and put bitmap instead of a message + --Display the image/Alternate Text + lcd.drawText(LCD_X_LINE_TITLE, LCD_Y_LINE_FIRST+LCD_Y_LINE_HEIGHT, "Img:"..imgValue) + end + end + + GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine) + end + end -- if ~MENU + end -- if Line[i]~=nil + end -- for + end + end + +end + +------------------------------------------------------------------------------------------------------------- +local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values + local inc = 0 + local Speed = getRotEncSpeed() + + if Speed == ROTENC_MIDSPEED then + inc = (5 * dir) + elseif Speed == ROTENC_HIGHSPEED then + inc = (15 * dir) + else + inc = dir + end + + return inc +end + +------------------------------------------------------------------------------------------------------------ +local function GUI_HandleEvent(event, touchState) + local ctx = DSM_Context + local menu = ctx.Menu + local menuLines = ctx.MenuLines + + if event == EVT_VIRTUAL_EXIT then + ctx.Refresh_Display=true + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end + if ctx.Phase == PHASE.RX_VERSION then + dsmLib.ReleaseConnection() + else + if ctx.isEditing() then -- Editing a Line, need to restore original value + ctx.MenuLines[ctx.EditLine].Val = originalValue + dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Update+Validate value in RX + ctx.EditLine = nil -- Exit Edit Mode (By clearing the line editing) + else + dsmLib.ChangePhase(PHASE.EXIT) + end + end + return + end + + if event == EVT_VIRTUAL_NEXT then + ctx.Refresh_Display=true + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end + if ctx.isEditing() then -- Editing a Line, need to inc the value + local line=ctx.MenuLines[ctx.EditLine] + dsmLib.Value_Add(line, GUI_RotEncVal(1)) + else -- not editing, move selected line to NEXT + dsmLib.MoveSelectionLine(1) + end + return + end + + if event == EVT_VIRTUAL_PREV then + ctx.Refresh_Display=true + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end + if ctx.isEditing() then -- Editiing a line, need to dec the value + local line=ctx.MenuLines[ctx.EditLine] + dsmLib.Value_Add(line, GUI_RotEncVal(-1)) + else -- not editing, move selected line to PREV + dsmLib.MoveSelectionLine(-1) + end + return + end + + if event == EVT_VIRTUAL_ENTER_LONG then + ctx.Refresh_Display=true + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end + if ctx.isEditing() then + -- reset the value to default + dsmLib.Value_Default( menuLines[ctx.EditLine]) -- Update RX value as needed + end + return + end + + if event == EVT_VIRTUAL_ENTER then + ctx.Refresh_Display=true + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER\n",dsmLib.phase2String(ctx.Phase)) end + if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back + dsmLib.GotoMenu(menu.BackId) + elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next + dsmLib.GotoMenu(menu.NextId) + elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev + dsmLib.GotoMenu(menu.PrevId) + elseif menuLines[ctx.SelLine].ValId ~= 0 then + if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Next menu exist + if (SIMULATION_ON and menuLines[ctx.SelLine].ValId==0xFFFF) then + -- SPECIAL Simulation menu to Exit Simulation and + -- comunicate with Real RX + GUI_SwitchSimulationOFF() + else + dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId) -- ValId is the MenuId to navigate to + end + else + -- Editing a Line???? + if ctx.isEditing() then + -- Change the Value and exit edit + ctx.EditLine = nil + dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END) + else + -- enter Edit the current line + ctx.EditLine = ctx.SelLine + originalValue = menuLines[ctx.SelLine].Val + end + end + end + end +end + +local function init_screen_pos() + if LCD_W == 480 then -- TX16 + -- use defaults in the script header + elseif LCD_W == 128 then --TX12 (128x64) -- Still needs some work on the vertical + DEBUG_ON_LCD = false -- no space for this + TEXT_SIZE = SMLSIZE + LCD_W_USABLE = 128 + + LCD_W_BUTTONS = 30 + LCD_H_BUTTONS = 17 + LCD_X_RIGHT_BUTTONS = 128 - LCD_W_BUTTONS - 5 + + LCD_X_LINE_MENU = 0 + -- X offsets for (Title: [Value] debugInfo) lines + LCD_X_LINE_TITLE = 0 + LCD_X_LINE_VALUE = 90 + LCD_X_LINE_DEBUG = 110 + + LCD_Y_LINE_HEIGHT = 17 + LCD_Y_MENU_TITLE = 0 + LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 17 + LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT + end +end + +------------------------------------------------------------------------------------------------------------ +-- Init +local function DSM_Init() + init_screen_pos() + dsmLib.Init(toolName) -- Initialize Library + return dsmLib.StartConnection() +end + + +------------------------------------------------------------------------------------------------------------ +-- Main + + +local function DSM_Run(event) + local ctx = DSM_Context + + if event == nil then + error("Cannot be run as a model script!") + dsmLib.LOG_close() + return 2 + end + + GUI_HandleEvent(event) + + dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages + + local refreshInterval = REFRESH_GUI_MS + -- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD + if (ctx.EditLine or (ctx.Phase == PHASE.RX_VERSION)) then -- Editing or Requesting RX Version? + ctx.Refresh_Display=true + refreshInterval = 20 -- 200ms + end + + -- Refresh display only if needed and no faster than 500ms, utilize more CPU to speedup DSM communications + if (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh + GUI_Display() + ctx.Refresh_Display=false + lastRefresh=getTime() + end + + if ctx.Phase == PHASE.EXIT_DONE then + dsmLib.LOG_close() + return 2 + else + return 0 + end +end + + +return { init=DSM_Init, run=DSM_Run } \ No newline at end of file diff --git a/Lua_scripts/DSM FwdPrg_05_Color.lua b/Lua_scripts/DSM FwdPrg_05_Color.lua new file mode 100644 index 0000000..ff2c824 --- /dev/null +++ b/Lua_scripts/DSM FwdPrg_05_Color.lua @@ -0,0 +1,627 @@ +local toolName = "TNS|DSM Forward Prog v0.5 (Color+Touch) |TNE" +local VERSION = "v0.5" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + +local SIMULATION_ON = true -- FALSE: use real communication to DSM RX (DEFAULT), TRUE: use a simulated version of RX +local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log) +local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX +local USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX) + +local dsmLib +if (SIMULATION_ON) then + -- library with SIMILATION VERSION. Works really well in Companion for GUI development + dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgSIMLib.lua")(DEBUG_ON) +else + dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON) +end + +local PHASE = dsmLib.PHASE +local LINE_TYPE = dsmLib.LINE_TYPE +local DISP_ATTR = dsmLib.DISP_ATTR +local DSM_Context = dsmLib.DSM_Context + + +local lastRefresh=0 -- Last time the screen was refreshed +local REFRESH_GUI_MS = 300/10 -- 300ms.. Screen Refresh Rate.. to not waste CPU time (in 10ms units to be compatible with getTime()) +local originalValue = nil + +local touchButtonArea = {} +local EDIT_BUTTON = { DEFAULT=1001, DEC_10=1002, DEC_1=1003, INC_1=1004, INC_10=5, OK=1006, ESC=1007 } + +local IS_EDGETX = false -- DEFAULT until Init changed it + +local LCD_Y_MENU_TITLE = 20 +local LCD_W_MENU_TITLE = LCD_W-100 + +local LCD_X_LINE_MENU = 30 +local LCD_W_LINE_MENU = 350 + +local LCD_X_LINE_TITLE = 30 +local LCD_X_LINE_VALUE = 230 +local LCD_X_LINE_DEBUG = 390 + + +local LCD_Y_LINE_START = LCD_Y_MENU_TITLE + 30 +local LCD_Y_LINE_HEIGHT = (DEBUG_ON_LCD and 23) or 27 -- if DEBUG 23 else 27 + +local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT) + + +-- TOOL HEADER +local LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR +local LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR +-- MENU HEADER +local LCD_MENU_COLOR = MENU_TITLE_COLOR +local LCD_MENU_BGCOLOR = MENU_TITLE_BGCOLOR +-- LINE SELECTED +local LCD_SELECTED_COLOR = TEXT_INVERTED_COLOR +local LCD_SELECTED_BGCOLOR = TEXT_INVERTED_BGCOLOR +local LCD_EDIT_BGCOLOR = WARNING_COLOR +-- NORMAL TEXT +local LCD_NORMAL_COLOR = TEXT_COLOR +local LCD_DISABLE_COLOR = TEXT_DISABLE_COLOR +local LCD_DEBUG_COLOR = LINE_COLOR +-- NORMAL BOX FRAME COLOR +local LCD_BOX_COLOR = TEXT_DISABLE_COLOR + + + +--------------------- lcd.sizeText replacement ------------------------------------------------- +-- EdgeTx dont have lcd.sizeText, so we do an equivalent one using the string length and 5px per character +local function my_lcd_sizeText(s) + print(string.format("EdgeTX=%s",IS_EDGETX)) + -- return: If IS_EDGETX then lcd.sizeText() else string.len() + return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10) +end + + +local function GUI_SwitchSimulationOFF() + dsmLib.ReleaseConnection() + dsmLib.LOG_close() + + SIMULATION_ON = false + dsmLib = loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua")(DEBUG_ON) + DSM_Context = dsmLib.DSM_Context + + dsmLib.Init(toolName) -- Initialize Library + dsmLib.StartConnection() + DSM_Context.Refresh_Display = true +end + + +--------------------- Toucch Button Helpers ------------------------------------------------------------ +local function GUI_addTouchButton(x,y,w,h,line) + -- Add new button info to end of the array + touchButtonArea[#touchButtonArea+1] = {x=x, y=y, w=w, h=h, line=line} +end + +local function GUI_getTouchButton(x,y) + for i = 1, #touchButtonArea do + local button = touchButtonArea[i] + -- is the coordinate inside the button area?? + if (x >= button.x and x <= (button.x+button.w) and y >= button.y and (y <= button.y+button.h)) then + return button.line + end + end + return nil +end + +local function GUI_clearTouchButtons() + touchButtonArea = {} +end + +---------- Return Color to display Menu Lines ---------------------------------------------------------------- +local function GUI_GetTextColor(lineNum) + local ctx = DSM_Context + local txtColor = LCD_NORMAL_COLOR + -- Gray Out any other line except the one been edited + if (ctx.isEditing() and ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end + return txtColor +end + +local function GUI_GetFrameColor(lineNum) -- Frame Color for Value/Menu Boxes + local ctx = DSM_Context + local txtColor = LCD_BOX_COLOR + -- Gray Out any other line except the one been edited + if (ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end + return txtColor +end + +-------------------------------------------------------------------------------------------------------- +-- Display Text inside a Rectangle. Inv: true means solid rectangle, false=only perimeter +local function GUI_Display_Boxed_Text(lineNum,x,y,w,h,text,inv) + local ctx = DSM_Context + local txtColor = GUI_GetTextColor(lineNum) + local frameColor = GUI_GetFrameColor(lineNum) + -- If editing this lineNum, chose EDIT Color, else SELECTED Color + local selectedBGColor = (ctx.EditLine==lineNum and LCD_EDIT_BGCOLOR) or LCD_SELECTED_BGCOLOR + + if (inv) then + txtColor = LCD_SELECTED_COLOR + lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor) + else + lcd.drawRectangle(x-5, y-2, w, h, frameColor) + end + lcd.drawText(x , y, text, txtColor) + +end + +------ Display Pre/Next/Back buttons +local function GUI_Diplay_Button(x,y,w,h,text,selected) + GUI_Display_Boxed_Text(-1,x,y,w,h,text,selected) +end + +------ Display MENU type of lines (Navigation, SubHeaders, and plain text comments) +local function GUI_Display_Line_Menu(lineNum,line,selected) + -- Menu Lines can be navidation to other Menus (if Selectable) + -- Or SubHeaders or Messages + + local txtColor = GUI_GetTextColor(lineNum) + local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum) + local x = LCD_X_LINE_MENU + + if dsmLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes + GUI_Display_Boxed_Text(lineNum,x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT, line.Text,selected) + GUI_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum) + else + -- Non Selectable Menu Lines, plain text + -- Can be use for sub headers or just regular text lines (like warnings) + + local bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0 + + if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align??? + local tw = my_lcd_sizeText(line.Text)+4 + x = LCD_X_LINE_VALUE - tw -- Right + elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Center?? + local tw = my_lcd_sizeText(line.Text) + x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text + end + + lcd.drawText(x, y, line.Text, txtColor + bold) + end +end + +------ Display NAME : VALUES type of lines +local function GUI_Display_Line_Value(lineNum, line, value, selected, editing) + -- This Displays Name and Value Pairs + local txtColor = GUI_GetTextColor(lineNum) + local bold = 0 + local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum) + local x = LCD_X_LINE_TITLE + + --if (editing) then -- Any Special color/effect when editing?? + -- value = "["..value .. "]" + --end + + ---------- NAME Part + local header = line.Text + -- ONLY do this for Flight Mode (Right Align or Centered) + if (dsmLib.isFlightModeText(line.TextId)) then + -- Display Header + Value together + header = header .. " " .. value + + -- Bold Text??? + bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0 + + if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align + local tw = my_lcd_sizeText(header)+4 + x = LCD_X_LINE_VALUE - tw -- Right + elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Centered + local tw = my_lcd_sizeText(header) + x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text + end + else + -- No Flight Mode, no effects here + header = header .. ":" + end + + lcd.drawText(x, y, header, txtColor + bold) -- display Line Header + + --------- VALUE PART, Skip for Flight Mode since already show the value + if not dsmLib.isFlightModeText(line.TextId) then + value = value .. (line.Format or "") -- Append % if needed + + if dsmLib.isSelectableLine(line) then + -- Can select/edit value, Box it + local tw = my_lcd_sizeText(value)+10 -- Width of the Text in the lcd + GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected) + GUI_addTouchButton(LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,lineNum) + else -- Not Editable, Plain Text + lcd.drawText(LCD_X_LINE_VALUE, y, value, txtColor) + end + end + + -- Debug info for line Value RANGE when Debug on LCD + if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG, y, line.MinMaxDebug or "", SMLSIZE + LCD_DEBUG_COLOR) end -- display debug Min/Max +end + +local function GUI_Display_Menu(menu) + local ctx = DSM_Context + local w= LCD_W_MENU_TITLE + + -- Center Header + local tw = my_lcd_sizeText(menu.Text) + local x = w/2 - tw/2 -- Center of Screen - Center of Text + + lcd.drawFilledRectangle(0, LCD_Y_MENU_TITLE-2, w, LCD_Y_LINE_HEIGHT-2, LCD_MENU_BGCOLOR) + lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text, LCD_MENU_COLOR + BOLD) + + -- Back Button + if menu.BackId ~= 0 then + GUI_Diplay_Button(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,"Back",ctx.SelLine == dsmLib.BACK_BUTTON) + GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,dsmLib.BACK_BUTTON) + end + -- Next Button + if menu.NextId ~= 0 then + GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON) + GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.NEXT_BUTTON) + end + -- Prev Button + if menu.PrevId ~= 0 then + GUI_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == dsmLib.PREV_BUTTON) + GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,dsmLib.PREV_BUTTON) + end + + -- Debug on LCD, Show the menu Indo and Phase we are on + if (DEBUG_ON_LCD) then lcd.drawText(0,LCD_Y_MENU_TITLE,dsmLib.phase2String(ctx.Phase),SMLSIZE+LCD_DEBUG_COLOR) end -- Phase we are in + if (DEBUG_ON_LCD) then lcd.drawText(0,240,dsmLib.menu2String(menu),SMLSIZE+LCD_DEBUG_COLOR) end -- Menu Info +end + +------------------------------------------------------------------------------------------------------------ +-- Display the EDIT mode buttons when editing a value + +local function GUI_Display_Edit_Buttons(line) + GUI_clearTouchButtons() -- Only this buttons can be touched + local x = 15 -- Inittial X position + local w = 55 -- Width of the buttons + + local showPrev = line.Val > line.Min + local showNext = line.Val < line.Max + + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,"ESC",true) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.ESC) + + x=x+w+10 + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," Def",true) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT) + + x=x+w+10 + if (not dsmLib.isListLine(line)) then + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," << ",showPrev) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_10) + end + + x=x+w+10 + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," <",showPrev) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_1) + + x=x+w+10 + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >",showNext) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1) + + x=x+w+10 + if (not dsmLib.isListLine(line)) then + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >>",showNext) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_10) + end + + x=x+w+10 + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," OK",true) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.OK) + +end + +------------------------------------------------------------------------------------------------------------ +local function GUI_Display() + local ctx = DSM_Context + lcd.clear() + GUI_clearTouchButtons() + + if LCD_W == 480 then + local header = "DSM Forward Programming "..VERSION.." " + if ctx.Phase ~= PHASE.RX_VERSION then + header = header .. "RX "..ctx.RX.Name.." v"..ctx.RX.Version + end + + --Draw title + lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR) + lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE) + --Draw RX Menu + if ctx.Phase == PHASE.RX_VERSION then + lcd.drawText(LCD_X_LINE_TITLE,100,"No compatible DSM RX...", BLINK) + else + local menu = ctx.Menu + + + if menu.Text ~= nil then + GUI_Display_Menu(menu) + + for i = 0, dsmLib.MAX_MENU_LINES do + local line = ctx.MenuLines[i] + + if i == ctx.SelLine then + -- DEBUG: Display Selected Line info for ON SCREEN Debugging + if (DEBUG_ON_LCD) then lcd.drawText(0,255,dsmLib.menuLine2String(line),SMLSIZE + LCD_DEBUG_COLOR) end + end + + if line ~= nil and line.Type ~= 0 then + if line.Type == LINE_TYPE.MENU then + GUI_Display_Line_Menu(i, line, i == ctx.SelLine) + else + -- list/value line + local value, imgValue = line.Val, nil + + if line.Val ~= nil then + if dsmLib.isListLine(line) then -- for Lists of Strings, get the text + value = dsmLib.Get_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text + imgValue = dsmLib.Get_Text_Img(line.Val + line.TextStart) -- Complentary IMAGE for this value to Display?? + + if (imgValue) then -- Optional Image for a Value + --TODO: Pending feature.. create images and put bitmap instead of a message + --Display the image/Alternate Text + lcd.drawText(LCD_X_LINE_TITLE, LCD_Y_LINE_START+LCD_Y_LINE_HEIGHT, "Img:"..imgValue) + end + end + + GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine) + end + end -- if ~MENU + end -- if Line[i]~=nil + end -- for + + if IS_EDGETX and ctx.isEditing() then + GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine]) + end + end + end + else + -- Different Resolution.. Maybe just adjusting some of the constants will work, adjust it in DSM_Init?? + -- LCD_X_LINE_TITLE, LCD_Y_LINE_START, etc + end +end + +------------------------------------------------------------------------------------------------------------- +local function GUI_RotEncVal(dir) -- return encoder speed to inc or dec values + local inc = 0 + local Speed = getRotEncSpeed() + + if Speed == ROTENC_MIDSPEED then inc = (5 * dir) + elseif Speed == ROTENC_HIGHSPEED then inc = (15 * dir) + else inc = dir end + + return inc +end + +------------------------------------------------------------------------------------ +-- Translate Tap/Touch of EDIT buttons to equivalent Key events +local function GUI_Translate_Edit_Buttons(button) + local event = EVT_TOUCH_TAP + local editInc = nil + + if (button==EDIT_BUTTON.ESC) then -- ESC + event = EVT_VIRTUAL_EXIT + elseif (button==EDIT_BUTTON.DEFAULT) then -- Default + event = EVT_VIRTUAL_ENTER_LONG + elseif (button==EDIT_BUTTON.DEC_10) then -- -10 + event = EVT_VIRTUAL_PREV + editInc = -10 + elseif (button==EDIT_BUTTON.DEC_1) then -- -1 + event = EVT_VIRTUAL_PREV + editInc = -1 + elseif (button==EDIT_BUTTON.INC_1) then -- +1 + event = EVT_VIRTUAL_NEXT + editInc = 1 + elseif (button==EDIT_BUTTON.INC_10) then -- + 10 + event = EVT_VIRTUAL_NEXT + editInc = 10 + elseif (button==EDIT_BUTTON.OK) then -- OK + event = EVT_VIRTUAL_ENTER + else + + end + + return event, editInc +end + +------------------------------------------------------------------------------------------------------------ +-- Handle Events comming from the GUI +local function GUI_HandleEvent(event, touchState) + local ctx = DSM_Context + local menu = ctx.Menu + local menuLines = ctx.MenuLines + local editInc = nil + + if (IS_EDGETX) then + if (event == EVT_TOUCH_TAP and ctx.isEditing()) then -- Touch and Editing + local button = GUI_getTouchButton(touchState.x, touchState.y) + if (button) then + event, editInc = GUI_Translate_Edit_Buttons(button) + end + end + + if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",dsmLib.phase2String(ctx.Phase),touchState.x, touchState.y) end + local button = GUI_getTouchButton(touchState.x, touchState.y) + if button then + -- Found a valid line + ctx.SelLine = button + ctx.Refresh_Display=true + if event == EVT_TOUCH_TAP then -- EVT_TOUCH_FIRST only move focus + event = EVT_VIRTUAL_ENTER + end + end + end + end + + if event == EVT_VIRTUAL_EXIT then + ctx.Refresh_Display=true + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_EXIT\n",dsmLib.phase2String(ctx.Phase)) end + if ctx.Phase == PHASE.RX_VERSION then + dsmLib.ReleaseConnection() -- Just Exit the Script + else + if ctx.isEditing() then -- Editing a Line, need to restore original value + ctx.MenuLines[ctx.EditLine].Val = originalValue + dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Update + Validate value in RX + ctx.EditLine = nil -- Exit Edit Mode (By clearing the line editing) + else + dsmLib.ChangePhase(PHASE.EXIT) + end + end + return + end + + if event == EVT_VIRTUAL_NEXT then + ctx.Refresh_Display=true + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_NEXT\n",dsmLib.phase2String(ctx.Phase)) end + if ctx.isEditing() then -- Editing a Line, need to inc the value + local line=ctx.MenuLines[ctx.EditLine] + dsmLib.Value_Add(line, editInc or GUI_RotEncVal(1)) + else -- not editing, move selected line to NEXT + dsmLib.MoveSelectionLine(1) + end + return + end + + if event == EVT_VIRTUAL_PREV then + ctx.Refresh_Display=true + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_PREV\n",dsmLib.phase2String(ctx.Phase)) end + if ctx.isEditing() then -- Editiing a line, need to dec the value + local line=ctx.MenuLines[ctx.EditLine] + dsmLib.Value_Add(line, editInc or GUI_RotEncVal(-1)) + else -- not editing, move selected line to PREV + dsmLib.MoveSelectionLine(-1) + end + return + end + + if event == EVT_VIRTUAL_ENTER_LONG then + ctx.Refresh_Display=true + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",dsmLib.phase2String(ctx.Phase)) end + if ctx.isEditing() then + -- reset the value to default + dsmLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed + end + return + end + + if event == EVT_VIRTUAL_ENTER then + ctx.Refresh_Display=true + if (DEBUG_ON) then dsmLib.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",dsmLib.phase2String(ctx.Phase), ctx.SelLine) end + if ctx.SelLine == dsmLib.BACK_BUTTON then -- Back + dsmLib.GotoMenu(menu.BackId) + elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next + dsmLib.GotoMenu(menu.NextId) + elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev + dsmLib.GotoMenu(menu.PrevId) + elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value + + if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Navigate to Menu + if (SIMULATION_ON and menuLines[ctx.SelLine].ValId==0xFFFF) then + -- SPECIAL Simulation menu to Exit Simulation + GUI_SwitchSimulationOFF() + else + dsmLib.GotoMenu(menuLines[ctx.SelLine].ValId) -- ValId is the MenuId to navigate to + end + else -- Enter on a Value + if ctx.isEditing() then -- already editing a Line???? + ctx.EditLine = nil -- Exit Edit Mode (By clearing the line editing) + dsmLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Request change the value on RX + else -- Edit the current value + ctx.EditLine = ctx.SelLine + originalValue = menuLines[ctx.SelLine].Val + end + end + end + end +end + +local function init_colors() + -- osName in OpenTX is nil, otherwise is EDGETX + local ver, radio, maj, minor, rev, osname = getVersion() + IS_EDGETX = osname~=nil + + if (IS_EDGETX and USE_SPECKTRUM_COLORS) then + -- SPECKTRUM COLORS (only works on EDGETX) + -- TOOL HEADER + LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR + LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR + -- MENU HEADER + LCD_MENU_COLOR = WHITE + LCD_MENU_BGCOLOR = DARKGREY + -- LINE SELECTED + LCD_SELECTED_COLOR = WHITE + LCD_SELECTED_BGCOLOR = ORANGE + LCD_EDIT_BGCOLOR = WARNING_COLOR + -- NORMAL TEXT + LCD_NORMAL_COLOR = BLACK + LCD_DISABLE_COLOR = LIGHTGREY + LCD_DEBUG_COLOR = BLUE + -- NORMAL BOX FRAME COLOR + LCD_BOX_COLOR = LIGHTGREY + end +end + +------------------------------------------------------------------------------------------------------------ +-- Init +local function DSM_Init() + init_colors() + dsmLib.Init(toolName) -- Initialize Library + return dsmLib.StartConnection() +end + +------------------------------------------------------------------------------------------------------------ +-- Main +local function DSM_Run(event,touchState) + local ctx = DSM_Context + + if event == nil then + error("Cannot be run as a model script!") + dsmLib.LOG_close() + return 2 + end + + GUI_HandleEvent(event,touchState) + + dsmLib.Send_Receive() -- Handle Send and Receive DSM Forward Programming Messages + + local refreshInterval = REFRESH_GUI_MS + + -- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD + if (ctx.Phase == PHASE.RX_VERSION) then -- Requesting RX Message Version usea BLINK? + ctx.Refresh_Display=true + refreshInterval = 20 -- 200ms + end + + -- Refresh display only if needed and no faster than 300ms, utilize more CPU to speedup DSM communications + if (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh + GUI_Display() + ctx.Refresh_Display=false + lastRefresh=getTime() + end + + if ctx.Phase == PHASE.EXIT_DONE then + dsmLib.LOG_close() + return 2 + else + return 0 + end +end + + +return { init=DSM_Init, run=DSM_Run } \ No newline at end of file diff --git a/Lua_scripts/DSMLIB/DsmFwPrgLib.lua b/Lua_scripts/DSMLIB/DsmFwPrgLib.lua new file mode 100644 index 0000000..7b50a73 --- /dev/null +++ b/Lua_scripts/DSMLIB/DsmFwPrgLib.lua @@ -0,0 +1,1374 @@ +---- ######################################################################### +---- # # +---- # 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 +-- +------------------------------------------------------------------------------ + --############################################################################### + -- 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 DEBUG_ON = ... -- Get Debug_ON from parameters. -- 0=NO DEBUG, 1=HIGH LEVEL 2=MORE DETAILS +local LIB_VERSION = "0.5" + + +local Lib = { Init_Text = function (rxId) end } + +local RX = { + --RX names-- + AR636B = 0x0001, + SPM4651T = 0x0014, + AR637T = 0x0015, + AR637TA = 0x0016, + FC6250HX = 0x0018, + AR8360T = 0x001A, + AR631 = 0x001E +} + +local PHASE = { + RX_VERSION = 0, + WAIT_CMD = 1, + MENU_TITLE = 2, + MENU_UNKNOWN_LINES = 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_MENU0 = 0x6C, -- List: For this, do not send changes as it happends in the screen, only at the END + LIST_MENU1 = 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_MENU2 = 0x4C, -- List: Seems like a bolean menu, just 2 values 0->1 (off/on, ihn/Act) + VALUE_NOCHANGING = 0x60, -- value not change in GUI, change internally at the receiver + VALUE_PERCENT = 0xC0, -- 8 bit number, percent + VALUE_NUM_I8 = 0x40, -- 8 bit number + VALUE_NUM_I16 = 0x41, -- 16 Bit number + VALUE_NUM_SI16 = 0xC1, -- Signed 16 bit number + LT_EMPTY = 0x00 +} + +local DISP_ATTR = { + BOLD = 0x01, RIGHT=0x02, CENTER=0x04, PERCENT = 0x10 +} + +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 +} + +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 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 + +-- Text Arrays for Display Text and Debuging +local PhaseText = {} +local LineTypeText = {} +local Text = {} -- Text for Menu and Menu Lines +local RxName = {} + +local Text_Img = {} -- If the Text has Attached Images +local Menu_List_Values = {} -- Additiona Menu_List valid values when non contiguos + +local LOG_FILE = "/LOGS/dsm_log.txt" +local logFile = nil + +function DSM_Context.isEditing() return DSM_Context.EditLine~=nil end + + +------------------------------------------------------------------------------------------------------------ +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) + + 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 ------------------------------------------------------------------ + +local function isSelectableLine(line) -- is the display line Selectable?? + -- values who are not selectable + if (line.Type == 0 or line.Type == LINE_TYPE.VALUE_NOCHANGING) then return false end -- No Changing Value + if (line.Type == LINE_TYPE.MENU and line.ValId == line.MenuId) 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 + 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.VALUE_NOCHANGING or line.Type == LINE_TYPE.MENU) then return false end + if (line.Min==0 and line.Max==0 and line.Def==0) then return false end -- Values with no Range are only for display + -- any other is Editable + return true +end + +local function isListLine(line) -- is it a List of options?? + if (line.Type == LINE_TYPE.LIST_MENU0 or line.Type == LINE_TYPE.LIST_MENU1 or line.Type == LINE_TYPE.LIST_MENU2) 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 false end +end + +------------------------------------------------------------------------------------------------------------ +local function Get_Text(index) + local out = Text[index] + if out == nil then -- unknown... + out = "Unknown_" .. string.format("%X", index) + end + return out +end + +local function Get_Text_Img(index) + local out = Text_Img[index] + + return out +end + +local function Get_Menu_List_Values(index) + local out = Menu_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)) +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_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 ]", + l.lineNum, lineType2String(l.Type), l.ValId, + l.Text, l.TextId, + value, + range, + l.MenuId + ) + end + return txt +end + +------------------------------------------------------------------------------------------------------------ + +local function multiBuffer2String() -- used for debug + local i + local rxAnswer = "RX:" + for i = 10, 25 do + rxAnswer = rxAnswer .. string.format(" %02X", multiBuffer(i)) + end + return rxAnswer +end + +---------------- DSM Values <-> Int16 Manipulation -------------------------------------------------------- + +local function int16_LSB(number) -- Less Significat byte + local r,x = bit32.band(number, 0xFF) + return r +end + +local function int16_MSB(number) -- Most signifcant byte + return bit32.rshift(number, 8) +end + +local function Dsm_to_Int16(lsb, msb) -- Componse an Int16 value + return bit32.lshift(msb, 8) + lsb +end + +local function Dsm_to_SInt16(lsb,msb) -- Componse a SIGNED Int16 value + local value = bit32.lshift(msb, 8) + lsb + if value >= 0x8000 then -- Negative value?? + return value - 0x10000 + end + return value +end + +local function sInt16ToDsm(value) -- Convent to SIGNED DSM Value + if value < 0 then + value = 0x10000 + value + end + 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, pos = string.gsub(text1, "/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 + + 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) then + -- either explicit Percent or NO-Change value, but range is %Percent + line.Format =" %" + line.TextAttr = bit32.bor(line.TextAttr,DISP_ATTR.PERCENT) + end + end + + line.MinMaxDebug = lineType2String(line.Type).." "..(line.MinMaxOrig or "") +end + +------------------------------------------------------------------------------------------------------------ +local function DSM_send(...) + local arg = { ... } + + for i = 1, #arg do + multiBuffer(3 + i, arg[i]) + end + multiBuffer(3, 0x70 + #arg) + + + if (DEBUG_ON > 1) then + local str = "" + for i = 1, #arg do + str = str .. string.format("%02X ", arg[i]) + end + LOG_write("DSM_SEND: [%s]\n", str) + end +end + +------------------------------------------------------------------------------------------------------------ + +local function DSM_StartConnection() + if (DEBUG_ON) then 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 + error("Not enough memory!") + return 2 + end + --Init TX buffer + multiBuffer( 3, 0x00 ) + --Init RX buffer + multiBuffer( 10, 0x00 ) + --Init telemetry + multiBuffer( 0, string.byte('D') ) + multiBuffer( 1, string.byte('S') ) + multiBuffer( 2, string.byte('M') ) + + return 0 +end + +local function DSM_ReleaseConnection() + if (DEBUG_ON) then 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_Menu_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) then + if line.Type ~= LINE_TYPE.LIST_MENU0 then -- Listof channels only change on the Screen until is Done + -- Update RX value on every change + DSM_ChangePhase(PHASE.VALUE_CHANGING) + end + 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) then + if line.Type ~= LINE_TYPE.LIST_MENU0 then -- Listof channels only change on the Screen until is Done + -- Update RX value on every change + DSM_ChangePhase(PHASE.VALUE_CHANGING) + end + end +end + +local function DSM_GotoMenu(menuId) + if (DEBUG_ON) then LOG_write("%3.3f %s: DSM_GotoMenu(0x%X)\n", getElapsedTime(), phase2String(DSM_Context.Phase), menuId) end + DSM_Context.Menu.MenuId = menuId + DSM_Context.SelLine = 0 + -- 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 + 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) +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 +end + +local function DSM_getMenu(menuId, startLine) + if (DEBUG_ON) then LOG_write("SEND DSM_getMenu(MenuId=0x%X StartLine=%s)\n", menuId, startLine) end + DSM_send(0x16, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, startLine) +end + +local function DSM_getFirstMenuLine(menuId) + if (DEBUG_ON) then 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 + 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, + text) + end + DSM_send(0x15, 0x06, int16_MSB(menuId), int16_LSB(menuId), int16_MSB(valId), int16_LSB(valId)) -- line X +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 + 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 + DSM_send(0x19, 0x06, int16_MSB(valId), int16_LSB(valId)) -- validate +end + +local function DSM_menuValueChangingWait(valId, text, line) + if (DEBUG_ON) then LOG_write("SEND DSM_menuValueChangingWait(ValueId=0x%X) Extra: Text=\"%s\" Value=%s\n", valId, text, lineValue2String(line)) end + DSM_send(0x1A, 0x06, int16_MSB(valId), int16_LSB(valId)) +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 ctx.Phase == PHASE.RX_VERSION then -- request RX version + DSM_getRxVerson() + + elseif ctx.Phase == PHASE.WAIT_CMD then -- keep connection open + DSM_sendHeartbeat() + + elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title + if ctx.Menu.MenuId == 0 then -- First time loading a menu ? + DSM_getMainMenu() + else + -- Start with Line 0 always, otherwise it will be returning weird 0x05 lines if we start in (Menu.SelLine=-1) + -- for internal menu navigation + DSM_getMenu(ctx.Menu.MenuId, 0) + end + + elseif ctx.Phase == PHASE.MENU_UNKNOWN_LINES then -- Still trying to figure out what are this menu lines are for + local curLine = ctx.CurLine + if (DEBUG_ON) then LOG_write("CALL DSM_getNextUknownLine_0x05(LastLine=%s)\n", curLine) end + local last_byte = { 0x40, 0x01, 0x02, 0x04, 0x00, 0x00 } -- unknown... + DSM_send(0x20, 0x06, curLine, curLine, 0x00, last_byte[curLine + 1]) -- line X + + elseif ctx.Phase == PHASE.MENU_LINES then -- request next menu lines + if ctx.CurLine == -1 then -- No previous menu line loaded ? + DSM_getFirstMenuLine(ctx.Menu.MenuId) + else + DSM_getNextMenuLine(ctx.Menu.MenuId, ctx.CurLine) + end + + elseif ctx.Phase == PHASE.MENU_VALUES then -- request menu values + local line = ctx.MenuLines[ctx.CurLine] + 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 + + elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then + local line = ctx.MenuLines[ctx.SelLine] + DSM_menuValueChangingWait(line.ValId, 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] -- Updat 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 + else -- Validate the value + DSM_validateMenuValue(line.ValId, line.Text, line) + Value_Change_Step = 0 + end + + + elseif ctx.Phase == PHASE.EXIT then + if (DEBUG_ON) then LOG_write("CALL DSM_exitRequest()\n") end + DSM_send(0x1F, 0x02, 0xAA) + end +end + +----------------------------------------------------------------------------------------------------------- +-- Parsing Responses + +local function DSM_parseRxVersion() + --ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + local rxId = multiBuffer(13) + DSM_Context.RX.Id = rxId + DSM_Context.RX.Name = 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 +end + +local function DSM_parseMenu() + --ex: 0x09 0x02 0x4F 0x10 0xA5 0x00 0x00 0x00 0x50 0x10 0x10 0x10 0x00 0x00 0x00 0x00 + -- MenuID TextID PrevID NextID BackID + local ctx = DSM_Context + 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.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)) + 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, Val=nil } + end + ctx.CurLine = -1 + + DSM_MenuPostProcessing(menu) + + if (DEBUG_ON) then LOG_write("RESPONSE Menu: %s\n", menu2String(menu)) end + return menu +end + + +local function DSM_parseMenuLine() + --ex: 0x09 0x03 0x00 0x10 0x00 0x1C 0xF9 0x00 0x10 0x10 0x00 0x00 0x00 0x00 0x03 0x00 + --ex: 0x09 0x03 0x61 0x10 0x00 0x6C 0x50 0x00 0x00 0x10 0x36 0x00 0x49 0x00 0x36 0x00 + --ex: 0x09 0x03 0x65 0x10 0x00 0x0C 0x51 0x00 0x00 0x10 0x00 0x00 0xF4 0x00 0x2E 0x00 + -- MenuLSB MenuMSB line Type TextID NextLSB NextMSB Val_Min Val_Max Val_Def + + local ctx = DSM_Context + local i = multiBuffer(14) + local type = multiBuffer(15) + local line = ctx.MenuLines[i] + + -- 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 + end + + ctx.CurLine = i + + line.lineNum = i + line.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) + line.Type = type + line.TextId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17)) + line.Text = nil -- Fill at Post processing + line.ValId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19)) + + -- Singed 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)) + + DSM_MenuLinePostProcessing(line) + + if (DEBUG_ON) then LOG_write("RESPONSE MenuLine: %s\n", menuLine2String(line)) end + return line +end + +local function DSM_parseMenuValue() + --ex: 0x09 0x04 0x53 0x10 0x00 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + --ex: 0x09 0x04 0x61 0x10 0x02 0x10 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + -- MenuLSB MenuMSB ValLSB ValMSB V_LSB V_MSB + + -- Identify the line and update the value + local ctx = DSM_Context + local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) + local value = Dsm_to_SInt16(multiBuffer(16), multiBuffer(17)) --Signed int + + local updatedLine = nil + for i = 0, MAX_MENU_LINES do -- Find the menu line for this value + local line = ctx.MenuLines[i] + if line ~= nil and line.Type ~= 0 then + if line.Type ~= LINE_TYPE.MENU and line.ValId == valId then -- identifier of ValueId stored in the line + line.Val = value + ctx.CurLine = i + updatedLine = line + break + end + end + end + + if (updatedLine == nil) then + if (DEBUG_ON) then LOG_write("ERROR, Cant find Menu Line with ValID=%X to update\n", valId) end + else + if (DEBUG_ON) then LOG_write("RESPONSE MenuValue: UPDATED: %s\n", menuLine2String(updatedLine)) + end + end +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 + line.Format = "" +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 cmd == 0x01 then -- read version + DSM_parseRxVersion() + Lib.Init_Text(DSM_Context.RX.Id) + ctx.Phase = PHASE.MENU_TITLE + + elseif cmd == 0x02 then -- read menu title + local menu = DSM_parseMenu() + + -- Update Selected Line navigation + if menu.NextId ~= 0 then + ctx.SelLine = NEXT_BUTTON -- highlight Next + else + ctx.SelLine = BACK_BUTTON -- highlight Back + end + + ctx.Phase = PHASE.MENU_LINES + + elseif cmd == 0x03 then -- menu lines + local line = DSM_parseMenuLine() + + -- 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 + ctx.SelLine = line.lineNum + end + + ctx.Phase = PHASE.MENU_LINES + + elseif cmd == 0x04 then -- read menu values + DSM_parseMenuValue() + ctx.Phase = PHASE.MENU_VALUES + + elseif cmd == 0x05 then -- unknown... need to get through the lines... + -- 0x09 0x05 0x01 0x01 0x00 0x00 0x00 0x00 0x07 + -- Line MenuId ???? + local curLine = multiBuffer(12) + if (DEBUG_ON) then LOG_write("RESPONSE MenuUknownLine_0x05: LineNum=%s DATA=%s\n", curLine, multiBuffer2String()) end + + if (curLine==ctx.CurLine) then + -- WEIRD BEHAVIOR + -- We got the same line we already got.. Stop requesting the same again and again + -- otherwise we end up in a deadlock loop, and RX will reset the connection + DSM_Add_Error_Menu_Line(0,"\bError: Cannot Load Menu Lines from RX") + ctx.Phase = PHASE.WAIT_CMD + if (DEBUG_ON) then LOG_write("ERROR: Received Same menu line, exiting the loop to prevent disconnect\n") end + else -- Got the next line.. keep requesting more + ctx.CurLine = curLine + ctx.Phase = PHASE.MENU_UNKNOWN_LINES + end + + elseif cmd == 0xA7 then -- answer to EXIT command + if (DEBUG_ON) then LOG_write("RESPONSE Exit Confirm\n") end + DSM_ReleaseConnection() + + 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 + else + if (DEBUG_ON) then LOG_write("RESPONSE Unknown Command (0x%X) DATA=%s\n", cmd, multiBuffer2String()) end + end + + return cmd +end + +------------------------------------------------------------------------------------------------------------ +local function DSM_Send_Receive() + local context = 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 + local cmd = DSM_processResponse() + + multiBuffer(10, 0x00) -- Clear Response Buffer to know that we are done with the response + + 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 + 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 + DSM_ReleaseConnection() + 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 + end + + if context.Phase == PHASE.RX_VERSION then + -- Refresh screen again + context.Refresh_Display = true + end + end + end +end + +-- Init +local function DSM_Init(toolName) + local dateTime = getDateTime() + local dateStr = dateTime.year.."-"..dateTime.mon.."-"..dateTime.day.." "..dateTime.hour..":"..dateTime.min + + local ver, radio, maj, minor, rev, osname = getVersion() + + 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) + 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_UNKNOWN_LINES] = "MENU_UNKNOWN_LINES" + 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_MENU0] = "L_m0" + LineTypeText[LINE_TYPE.LIST_MENU1] = "L_m1" + LineTypeText[LINE_TYPE.LIST_MENU2] = "L_m2" + LineTypeText[LINE_TYPE.VALUE_NOCHANGING] = "V_NC" + LineTypeText[LINE_TYPE.VALUE_PERCENT] = "V_%" + 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" + + --RX names-- + RxName[0x0001] = "AR636B" + RxName[0x0014] = "SPM4651T" + RxName[0x0015] = "AR637T" + RxName[0x0016] = "AR637TA" + RxName[0x0018] = "FC6250HX" + RxName[0x001A] = "AR8360T" + RxName[0x001E] = "AR631" +end + +local function DSM_Init_Text(rxId) + --Text to be displayed + -- For menu lines (no name: value ) who are not navigation to other menus + -- you can use some formatting options: + -- Text allightment: /c = CENTER, /r = RIGHT + -- Text effects: /b = BOLD + -- Text formatting: /p = PERCENT numbers + + -- array Menu_List_Values: + -- For some Menu LIST VALUES, special Lines of type:LIST_MENU1, the valod 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 + + + Text[0x0001] = "On" + Text[0x0002] = "Off" + + Text[0x0003] = "Inh" + Text[0x0004] = "Act" + + -- Channel selection for SAFE MODE and GAINS on FC6250HX + Text[0x000C] = "Inhibit?" --? + Text[0x000D] = "Gear" + for i = 1, 7 do Text[0x000D + i] = "Aux" .. i end -- Aux channels + + -- Servo Output values.. + local servoOutputValues = {0x0003,0x002D,0x002E,0x002F} --Inh (GAP), 5.5ms, 11ms, 22ms + Text[0x002D] = "5.5ms" + Text[0x002E] = "11ms" + Text[0x002F] = "22ms" + + -- Gain Values + local gainValues = {0x0032,0x0033,0x0034} -- 1X, 2X, 4X + Text[0x0032] = "1 X" + Text[0x0033] = "2 X" + Text[0x0034] = "4 X" + + -- List of Channels for most RX, except FC6250HX + local channelValues = {0x0035,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F} -- Inhibit? (GAP), Gear,Aux1..Aux5 + local outputValues = {0x0036,0x0037,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F} -- Thr,Ail,Elv,Rud,Gear,Aux1..Aux5 + Text[0x0035] = "Inhibit?" --? + Text[0x0036] = "Throttle" + Text[0x0037] = "Aileron" + Text[0x0038] = "Elevator" + Text[0x0039] = "Rudder" + Text[0x003A] = "Gear" + for i = 1, 7 do Text[0x003A + i] = "Aux" .. i end -- Aux channels on AR637T + + for i = 1, 8 do -- 41..49 on AR637T -- This don't seem OK + Text[0x0041 + i] = "XPlus-" .. i + end + + --But FOTO-PETE reports that it should be (works with AR631,AR637,FC6250HX) + Text[0x0040] = "Roll" + Text[0x0041] = "Pitch" + Text[0x0042] = "Yaw" + Text[0x0043] = "Gain /c/b" -- FC6250HX, AR631 + Text[0x0045] = "Differential" + Text[0x0046] = "Priority" + Text[0x0049] = "Output Setup" -- FC6250HX + --****** + + Text[0x004A] = "Failsafe" + Text[0x004B] = "Main Menu" + Text[0x004E] = "Position" + + Text[0x0050] = "Outputs"; Menu_List_Values[0x0050]=outputValues + + Text[0x0051] = "Output Channel 1" + Text[0x0052] = "Output Channel 2" + Text[0x0053] = "Output Channel 3" + Text[0x0054] = "Output Channel 4" + Text[0x0055] = "Output Channel 5" + Text[0x0056] = "Output Channel 6" + + if (rxId ~= RX.FC6250HX) then -- Restrictions for non FC6250HX + Menu_List_Values[0x0051]=servoOutputValues + Menu_List_Values[0x0052]=servoOutputValues + Menu_List_Values[0x0053]=servoOutputValues + Menu_List_Values[0x0054]=servoOutputValues + Menu_List_Values[0x0055]=servoOutputValues + Menu_List_Values[0x0056]=servoOutputValues + end + + -- FailSafe Options + --Text[0x005E]="Inhibit" + Text[0x005F] = "Hold Last" + Text[0x0060] = "Preset" + --Text[0x0061]="Custom" + + --FC6250HX + Text[0x0071] = "Proportional" + Text[0x0072] = "Integral" + Text[0x0073] = "Derivate" + + -- Flight mode channel selection + Text[0x0078] = "FM Channel" + if (rxId ~= RX.FC6250HX) then Menu_List_Values[0x0078]=channelValues end --FC6250HX uses other range + + Text[0x0080] = "Orientation" + Text[0x0082] = "Heading" + Text[0x0085] = "Frame Rate" + Text[0x0086] = "System Setup" + Text[0x0087] = "F-Mode Setup" + Text[0x0088] = "Enabled F-Modes" + + -- Gain channel selection + Text[0x0089] = "Gain Channel" + if (rxId ~= RX.FC6250HX) then Menu_List_Values[0x0089]=channelValues end --FC6250HX uses other range + -- Gain Sensitivity + Text[0x008A] = "Gain Sensitivity/r"; Menu_List_Values[0x008A]=gainValues -- (L_M1 was wide open) + + Text[0x008B] = "Panic" + Text[0x008E] = "Panic Delay" + Text[0x0090] = "Apply" + + Text[0x0091] = "Begin" -- FC6250HX: Callibration Menu -> Begin..Start, Complete, Done + Text[0x0092] = "Start" + Text[0x0093] = "Complete" + Text[0x0094] = "Done" + + Text[0x0097] = "Factory Reset" + Text[0x0098] = "Factory Reset" -- FC6250HX: Title + Text[0x0099] = "Advanced Setup" + Text[0x009A] = "Capture Failsafe Positions" + Text[0x009C] = "Custom Failsafe" + + Text[0x009F] = "Save Settings & Reset RX (NOT WORKING YET)" -- FAKE: Menu 0x0001 -- Looks like special Save & Reset Menu + + Text[0x00A5] = "First Time Setup" + Text[0x00AA] = "Capture Gyro Gains" + Text[0x00AD] = "Gain Channel Select" + + -- Safe mode options, Ihnibit + thi values + local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope + Text[0x00B0] = "Self-Level/Angle Dem" + Text[0x00B1] = "Envelope" + + Text[0x00B5] = "Inhibit" + Text[0x00B6] = "FM1" + Text[0x00B7] = "FM2" + Text[0x00B8] = "FM3" + Text[0x00B9] = "FM4" + Text[0x00BA] = "FM5" + Text[0x00BB] = "FM6" + Text[0x00BC] = "FM7" + Text[0x00BD] = "FM8" + Text[0x00BE] = "FM9" + Text[0x00BF] = "FM10" + + Text[0x00C7] = "Calibrate Sensor" + Text[0x00CA] = "SAFE/Panic Mode Setup" + + -- RX Orientations for AR631/AR637 (on the Heli Receiver is different, see below) + -- Optionally attach an Image to display (TODO, not done yet) + Text[0x00CB] = "RX Pos 1"; Text_Img[0x00CB] = "Pilot View: RX Label Up, Pins Back" + Text[0x00CC] = "RX Pos 2"; Text_Img[0x00CC] = "Pilot View: RX Label Left, Pins Back" + Text[0x00CD] = "RX Pos 3"; Text_Img[0x00CD] = "Pilot View: RX Label Down, Pins Back" + Text[0x00CE] = "RX Pos 4"; Text_Img[0x00CE] = "Pilot View: RX Label Right, Pins Back" + Text[0x00CF] = "RX Pos 5"; Text_Img[0x00CF] = "Pilot View: RX Label UP, Pins to Front" + Text[0x00D0] = "RX Pos 6"; Text_Img[0x00D0] = "Pilot View: RX Label Left, Pins Front" + Text[0x00D1] = "RX Pos 7"; Text_Img[0x00D1] = "Pilot View: RX Label Down, Pins Front" + Text[0x00D2] = "RX Pos 8"; Text_Img[0x00D2] = "Pilot View: RX Label Right, Pins Front" + Text[0x00D3] = "RX Pos 9"; Text_Img[0x00D3] = "Pilot View: RX Label Up, Pins Left" + Text[0x00D4] = "RX Pos 10"; Text_Img[0x00D4] = "Pilot View: RX Label Back, Pins Left" + Text[0x00D5] = "RX Pos 11"; Text_Img[0x00D5] = "Pilot View: RX Label Down, Pins Left" + Text[0x00D6] = "RX Pos 12"; Text_Img[0x00D6] = "Pilot View: RX Label Front, Pins Left" + Text[0x00D7] = "RX Pos 13"; Text_Img[0x00D7] = "Pilot View: RX Label Up, Pins Right" + Text[0x00D8] = "RX Pos 14"; Text_Img[0x00D8] = "Pilot View: RX Label Back, Pins Right" + Text[0x00D9] = "RX Pos 15"; Text_Img[0x00D9] = "Pilot View: RX Label Down, Pins Right" + Text[0x00DA] = "RX Pos 16"; Text_Img[0x00DA] = "Pilot View: RX Label Front, Pins Right" + Text[0x00DB] = "RX Pos 17"; Text_Img[0x00DB] = "Pilot View: RX Label Back, Pins Down" + Text[0x00DC] = "RX Pos 18"; Text_Img[0x00DC] = "Pilot View: RX Label Left, Pins Down" + Text[0x00DD] = "RX Pos 19"; Text_Img[0x00DD] = "Pilot View: RX Label Front, Pins Down" + Text[0x00DE] = "RX Pos 20"; Text_Img[0x00DE] = "Pilot View: RX Label Right, Pins Down" + Text[0x00DF] = "RX Pos 21"; Text_Img[0x00DF] = "Pilot View: RX Label Back, Pins Up" + Text[0x00E0] = "RX Pos 22"; Text_Img[0x00E0] = "Pilot View: RX Label Left, Pins Up" + Text[0x00E1] = "RX Pos 23"; Text_Img[0x00E1] = "Pilot View: RX Label Front, Pins Up" + Text[0x00E2] = "RX Pos 24"; Text_Img[0x00E2] = "Pilot View: RX Label Right, Pins Up" + + -- But for FC6250HX, Override this previous values + if (rxId == RX.FC6250HX) then + Text[0x00D2] = "Panic Channel" + Text[0x00D3] = "Swashplate" + Text[0x00D5] = "Agility" + Text[0x00D8] = "Stop" + Text[0x00DA] = "SAFE" + Text[0x00DB] = "Stability" + Text[0x00DC] = "@ per sec" + Text[0x00DD] = "Tail rotor" + Text[0x00DE] = "Setup" + Text[0x00DF] = "AFR" + Text[0x00E0] = "Collective" + Text[0x00E1] = "Subtrim" + Text[0x00E2] = "Phasing" + Text[0x00E4] = "E-Ring" + end + + Text[0x00E7] = "Left" + Text[0x00E8] = "Right" + + Text[0x00F2] = "Fixed" + Text[0x00F3] = "Adjustable" + + Text[0x00F9] = "Gyro settings" + Text[0x00FE] = "Stick Priority/c/b " --SubTitle + + Text[0x0100] = "Make sure the model has been" + Text[0x0101] = "configured, including wing type," + Text[0x0102] = "reversing, travel, trimmed, etc." + Text[0x0103] = "before continuing setup." + Text[0x0104] = "" -- empty?? + Text[0x0105] = "" -- empty?? + + Text[0x0106] = "Any wing type, channel assignment," + Text[0x0107] = "subtrim, or servo reversing changes" + Text[0x0108] = "require running through initial" + Text[0x0109] = "setup again." + Text[0x010A] = "" -- empty?? + Text[0x010B] = "" -- empty?? + + Text[0x0190] = "Relearn Servo Settings" + Text[0x019C] = "Enter Receiver Bind Mode" + Text[0x01D7] = "SAFE Select Channel" + Text[0x01DC] = "AS3X" + Text[0x01DD] = "AS3X Settings" + Text[0x01DE] = "AS3X Gains" + Text[0x01E0] = "Rate Gains/c/b" -- SubTitle + Text[0x01E2] = "SAFE Settings" + Text[0x01E3] = "SAFE Gains" + Text[0x01E6] = "Attitude Trim" + Text[0x01E7] = "Envelope" + Text[0x01E9] = "Roll Right" + Text[0x01EA] = "Roll Left" + Text[0x01EB] = "Pitch Down" + Text[0x01EC] = "Pitch Up" + Text[0x01EE] = "Throttle to Pitch" + Text[0x01EF] = "Low Thr to Pitch" + Text[0x01F0] = "High Thr to Pitch" + Text[0x01F3] = "Threshold" + Text[0x01F4] = "Angle" + Text[0x01F6] = "Failsafe Angles" + + --Inh, Self-Level/Angle Dem, Envelope -- (L_M1 was wide open) + Text[0x01F8] = "Safe Mode"; Menu_List_Values[0x01F8]=safeModeOptions + + Text[0x01F9] = "SAFE Select/c/b " -- SubTitle + Text[0x01FC] = "Panic Flight Mode" + Text[0x01FD] = "SAFE Failsafe FMode" + Text[0x0208] = "Decay" + Text[0x0209] = "Save to Backup" + Text[0x020A] = "Restore from Backup" + Text[0x020D] = "First Time SAFE Setup" + + Text[0x021A] = "Set the model level," + Text[0x021B] = "and press Continue." + Text[0x021C] = "" -- empty?? + Text[0x021D] = "" -- empty?? + + Text[0x021F] = "Set the model on its nose," + Text[0x0220] = "and press Continue. If the" + Text[0x0221] = "orientation on the next" + Text[0x0222] = "screen is wrong go back" + Text[0x0223] = "and try again." + + Text[0x0224] = "Continue" + Text[0x0226] = "Angle Limits/c/b " + Text[0x0227] = "Other settings" + Text[0x0229] = "Set Orientation Manually" + + -- Factory Default Warning + Text[0x022B] = "WARNING!" + Text[0x022C] = "This will reset the" + Text[0x022D] = "configuration to factory" + Text[0x022E] = "defaults. This does not" + Text[0x022F] = "affect the backup config." + Text[0x0230] = "" -- empty?? + + -- Backup Warning + Text[0x0231] = "This will overwrite the" + Text[0x0232] = "backup memory with your" + Text[0x0233] = "current configuartion." + Text[0x0234] = "" -- blank line + Text[0x0235] = "" -- blank line + + -- Restore from Backup Warning + Text[0x0236] = "This will overwrite the" + Text[0x0237] = "current config with" + Text[0x0238] = "that which is in" + Text[0x0239] = "the backup memory." + Text[0x023A] = "" -- blank line + + Text[0x023D] = "Copy Flight Mode Settings" + Text[0x0240] = "Utilities" + + Text[0x024C] = "Gains will be captured on" + Text[0x024D] = "Captured gains will be" + Text[0x024E] = "Gains on" + + Text[0x024F] = "were captured and changed" + Text[0x0250] = "from Adjustable to Fixed" + + Text[0x0254] = "Postive = Up, Negative = Down" + Text[0x0263] = "Fixed/Adjustable Gains /c/b" + Text[0x0266] = "Heading Gain/c/b" + Text[0x0267] = "Positive = Nose Up/Roll Right" + Text[0x0268] = "Negative = Nose Down/Roll Left" + Text[0x0269] = "SAFE - Throttle to Pitch" + Text[0x026A] = "Use CAUTION for Yaw gain!/b" -- SubTitle + + Text[0x8000] = "FLIGHT MODE/c/b" --FC6250HX + Text[0x8001] = "Flight Mode/c/b" -- WAS "Flight Mode 1" Center and Bold + Text[0x8002] = "Flight Mode 2/c/b" + Text[0x8003] = "Flight Mode 3/c/b" +end + +-- Check if the text are Flight modes, who will be treated different for Display +local function isFlightModeText(textId) + return (textId >= 0x8000 and textId <= 0x8003) +end + +------------------------------------------------------------------------------------------------------------ +-- Lib EXPORTS + +-- Export Constants +Lib.PHASE = PHASE +Lib.LINE_TYPE = LINE_TYPE +Lib.RX = RX +Lib.DISP_ATTR = DISP_ATTR + +Lib.BACK_BUTTON = BACK_BUTTON +Lib.NEXT_BUTTON = NEXT_BUTTON +Lib.PREV_BUTTON = PREV_BUTTON +Lib.MAX_MENU_LINES = MAX_MENU_LINES + +-- Export Shared Context Variables +Lib.DSM_Context = DSM_Context + +-- Export Functions +Lib.LOG_write = LOG_write +Lib.LOG_close = LOG_close +Lib.getElapsedTime = getElapsedTime +Lib.Get_Text = Get_Text +Lib.Get_Text_Img = Get_Text_Img + +Lib.phase2String = phase2String +Lib.lineValue2String = lineValue2String +Lib.menu2String = menu2String +Lib.menuLine2String = menuLine2String + +Lib.isSelectableLine = isSelectableLine +Lib.isEditableLine = isEditableLine +Lib.isListLine = isListLine +Lib.isPercentValueLine = isPercentValueLine +Lib.isPercentValueLineByMinMax = isPercentValueLineByMinMax +Lib.isNumberValueLine = isNumberValueLine +Lib.isDisplayAttr = isDisplayAttr +Lib.isFlightModeText = isFlightModeText + +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.GotoMenu = DSM_GotoMenu +Lib.MoveSelectionLine = DSM_MoveSelectionLine +Lib.Send_Receive = DSM_Send_Receive +Lib.Init = DSM_Init +Lib.Init_Text = DSM_Init_Text + +return Lib diff --git a/Lua_scripts/DSMLIB/DsmFwPrgLib.luac b/Lua_scripts/DSMLIB/DsmFwPrgLib.luac new file mode 100644 index 0000000000000000000000000000000000000000..fb0950a313a49368885a71a4c5da8f409fae4a89 GIT binary patch literal 29271 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

mY*cT0tF(9$l8e(zT zJ8d0@5#lYAX1(WW{6OpqDd4e!?&qVCWq*iODCses02&_%dB`IXw1ki)Y<6m>cv05=E9+J5o33`D=v#; z>U7plE$#fzaJd~jn{s77+&EYNLq&RaDCbJfW&4s;q%GzAz02iatMgHaGPuMm#IK69 zU~69Sdp$lg6poJn0R2vQ9F+b7}5U$ D#Q7Jz literal 0 HcmV?d00001 diff --git a/Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua b/Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua new file mode 100644 index 0000000..c96cbb1 --- /dev/null +++ b/Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua @@ -0,0 +1,1075 @@ +---- ######################################################################### +---- # # +---- # 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 simulates the Forward programming menus for AR631 and FC6250HX +-- receivers. +-- The intend is to make easier GUI development in Companion since it cannot +-- talk to the receivers +-- +-- Author: Francisco Arzu +------------------------------------------------------------------------------ + + +local DEBUG_ON = ... -- Get DebugON from parameters + +local dsmLib = 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 SimLib = {} + +local lastGoodMenu=0 +local RX_loadMenu = nil +local RX_Initialized = true + + +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 + 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 + + if (menuId==0x1000) then + --M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"] + --L[#0 T=M VId=0x1010 Text="Gyro settings" MId=0x1000 ] + --L[#1 T=M VId=0x105E Text="Other settings" MId=0x1000 ] + + ctx.Menu = { MenuId = 0x1000, TextId = 0x004B, PrevId = 0, NextId = 0, BackId = 0 } + ctx.MenuLines[0] = { MenuId = 0x1000, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x00F9, ValId = 0x1010 } + ctx.MenuLines[1] = { MenuId = 0x1000, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x0227, ValId = 0x105E } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1010) then + -- M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"] + + -- NEW + -- L[#5 T=M VId=0x104F val=nil [0->0,3] Text="First Time Setup" MId=0x1010 ] -- NEW ONLY + + -- Initialize AR637T + -- L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ] + -- L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ] + -- L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ] + -- L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ] + + + ctx.Menu = { MenuId = 0x1010, TextId = 0x00F9, PrevId = 0, NextId = 0, BackId = 0x1000 } + if not RX_Initialized then + ctx.MenuLines[5] = { MenuId = 0x1010, lineNum = 5, Type = LINE_TYPE.MENU, TextId = 0x00A5, ValId = 0x104F} + ctx.SelLine = 5 + else + ctx.MenuLines[0] = { MenuId = 0x1010, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x1DD, ValId = 0x1011 } + ctx.MenuLines[1] = { MenuId = 0x1010, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x1E2, ValId = 0x1019 } + ctx.MenuLines[2] = { MenuId = 0x1010, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x87, ValId = 0x1021 } + ctx.MenuLines[3] = { MenuId = 0x1010, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x86, ValId = 0x1022 } + ctx.SelLine = 0 + end + lastGoodMenu = menuId + elseif (menuId==0x1011) then + -- M[Id=0x1011 P=0x0 N=0x0 B=0x1010 Text="AS3X Settings"[0x1DD]] + -- L[#0 T=M VId=0x1012 Text="AS3X Gains"[0x1DE] MId=0x1011 ] + -- L[#1 T=M VId=0x1013 Text="Priority"[0x46] MId=0x1011 ] + + -- L[#2 T=M VId=0x1015 Text="Heading"[0x82] MId=0x1011 ] + -- L[#4 T=L_m1 VId=0x1004 val=50 [0->244,50,TS=0] Text="Gain Sensitivity"[0x8A] MId=0x1011] + -- L[#5 T=M VId=0x1016 Text="Fixed/Adjustable Gains"[0x263] MId=0x1011 ] + -- L[#6 T=M VId=0x1017 Text="Capture Gyro Gains"[0xAA] MId=0x1011 ] + + ctx.Menu = { MenuId = 0x1011, TextId = 0x1DD, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { MenuId = 0x1011, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x1DE, ValId = 0x1012} + ctx.MenuLines[1] = { MenuId = 0x1011, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x46, ValId = 0x1013} + ctx.MenuLines[2] = { MenuId = 0x1011, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x82, ValId = 0x1015} + ctx.MenuLines[4] = { MenuId = 0x1011, lineNum = 4, Type = LINE_TYPE.LIST_MENU1, TextId = 0x8A, ValId = 0x1004, Min=0, Max=244, Def=50, Val=50 } + ctx.MenuLines[5] = { MenuId = 0x1011, lineNum = 5, Type = LINE_TYPE.MENU, TextId = 0x263, ValId = 0x1016} + ctx.MenuLines[6] = { MenuId = 0x1011, lineNum = 6, Type = LINE_TYPE.MENU, TextId = 0xAA, ValId = 0x1017 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1012) then + -- M[Id=0x1012 P=0x0 N=0x0 B=0x1011 Text="AS3X Gains"[0x1DE]] + --L[#0 T=V_NC VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x1012 ] + --L[#2 T=M VId=0x1012 Text="Rate Gains"[0x1E0] MId=0x1012 ] + --L[#3 T=V_NC VId=0x1004 Text="Roll"[0x40] val=14 [0->100,40] MId=0x1012 ] + --L[#4 T=V_NC VId=0x1005 Text="Pitch"[0x41] val=29 [0->100,50] MId=0x1012 ] + --L[#5 T=V_NC VId=0x1006 Text="Yaw"[0x42] val=48 [0->100,60] MId=0x1012 ] + + ctx.Menu = { MenuId = 0x1012, TextId = 0x1DE, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { MenuId = 0x1012, lineNum = 0, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { MenuId = 0x1012, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x1E0, ValId = 0x1012 } + ctx.MenuLines[3] = { MenuId = 0x1012, lineNum = 3, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x40, ValId = 0x1004, Min=0, Max=100, Def=40, Val=40 } + ctx.MenuLines[4] = { MenuId = 0x1012, lineNum = 4, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x41, ValId = 0x1005, Min=0, Max=100, Def=50, Val=50 } + ctx.MenuLines[5] = { MenuId = 0x1012, lineNum = 5, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x42, ValId = 0x1006, Min=0, Max=100, Def=60, Val=60 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x1013) then + -- M[Id=0x1013 P=0x0 N=0x0 B=0x1011 Text="Priority"[0x46]] + --L[#0 T=V_NC VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x1012 ] + --L[#1 T=M VId=0x1013 Text="Stick Priority"[0xFE] MId=0x1013 ] + --L[#3 T=V_NC VId=0x1004 Text="Roll"[0x40] val=14 [0->160,160] MId=0x1012 ] + --L[#4 T=V_NC VId=0x1005 Text="Pitch"[0x41] val=29 [0->160,160] MId=0x1012 ] + --L[#5 T=V_NC VId=0x1006 Text="Yaw"[0x42] val=48 [0->160,160] MId=0x1012 ] + + ctx.Menu = { MenuId = 0x1013, TextId = 0x46, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { MenuId = 0x1013, lineNum = 0, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { MenuId = 0x1013, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0xFE, ValId = 0x1013 } + ctx.MenuLines[3] = { MenuId = 0x1013, lineNum = 3, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x40, ValId = 0x1004, Min=0, Max=160, Def=100, Val=160 } + ctx.MenuLines[4] = { MenuId = 0x1013, lineNum = 4, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x41, ValId = 0x1005, Min=0, Max=160, Def=100, Val=160 } + ctx.MenuLines[5] = { MenuId = 0x1013, lineNum = 5, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x42, ValId = 0x1006, Min=0, Max=160, Def=100, Val=160 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x1015) then + -- M[Id=0x1015 P=0x0 N=0x0 B=0x1011 Text="Heading Gain"[0x266]] + -- L[#0 T=V_NC VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x1015 ] + -- L[#1 T=M VId=0x1015 Text="Heading Gain"[0x266] MId=0x1015 ] + -- L[#2 T=V_NC VId=0x1004 Text="Roll"[0x40] val=0 [0->100,0] MId=0x1015 ] + -- L[#3 T=V_NC VId=0x1005 Text="Pitch"[0x41] val=0 [0->100,0] MId=0x1015 ] + -- L[#5 T=M VId=0x1015 Text="Use CAUTION for Yaw gain!"[0x26A] MId=0x1015 ] + -- L[#6 T=V_NC VId=0x1006 Text="Yaw"[0x42] val=0 [0->100,0] MId=0x1015 ] + + ctx.Menu = { MenuId = 0x1015, TextId = 0x266, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { MenuId = 0x1015, lineNum = 0, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { MenuId = 0x1015, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x1F9, ValId = 0x1015 } + ctx.MenuLines[2] = { MenuId = 0x1015, lineNum = 2, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x40, ValId = 0x1004, Min=0, Max=100, Def=0, Val=0 } + ctx.MenuLines[3] = { MenuId = 0x1015, lineNum = 3, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x41, ValId = 0x1005, Min=0, Max=100, Def=0, Val=0 } + ctx.MenuLines[5] = { MenuId = 0x1015, lineNum = 5, Type = LINE_TYPE.MENU, TextId = 0x26A, ValId = 0x1015 } + ctx.MenuLines[6] = { MenuId = 0x1015, lineNum = 6, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x42, ValId = 0x1006, Min=0, Max=100, Def=0, Val=0 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1016) then + -- M[Id=0x1016 P=0x0 N=0x0 B=0x1011 Text="Fixed/Adjustable Gains"[0x263]] + -- L[#0 T=V_NC VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x1016 ] + -- L[#1 T=M VId=0x1016 val=nil [0->0,2] Text="Fixed/Adjustable Gains"[0x263] MId=0x1016 ] + -- L[#2 T=L_m0 VId=0x1002 Text="Roll"[0x40] MId=0x1016 val=1 NL=(0->1,24,S=242) [242->243,243] ] + -- L[#3 T=L_m0 VId=0x1003 Text="Pitch"[0x41] MId=0x1016 val=1 NL=(0->1,1,S=242) [242->243,243] ] + -- L[#4 T=L_m0 VId=0x1004 Text="Yaw"[0x42] MId=0x1016 val=1 NL=(0->1,1,S=242) [242->243,243] ] + + ctx.Menu = { MenuId = 0x1016, TextId = 0x263, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { MenuId = 0x1016, lineNum = 0, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { MenuId = 0x1016, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x1F9, ValId = 0x1016 } + ctx.MenuLines[2] = { MenuId = 0x1016, lineNum = 2, Type = LINE_TYPE.LIST_MENU0, TextId = 0x40, ValId = 0x1002, Min=242, Max=243, Def=243, Val=1 } + ctx.MenuLines[3] = { MenuId = 0x1016, lineNum = 3, Type = LINE_TYPE.LIST_MENU0, TextId = 0x41, ValId = 0x1003, Min=242, Max=243, Def=243, Val=1 } + ctx.MenuLines[4] = { MenuId = 0x1016, lineNum = 4, Type = LINE_TYPE.LIST_MENU0, TextId = 0x42, ValId = 0x1004, Min=242, Max=243, Def=243, Val=1 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1017) then + --M[Id=0x1017 P=0x0 N=0x0 B=0x1011 Text="Capture Gyro Gains"[0xAA]] + --L[#0 T=M VId=0x1017 Text="Gains will be captured on"[0x24C] MId=0x1017 ] + --L[#1 T=V_NC VId=0x1000 Text=" Flight Mode 1"[0x8001] Val=1 [0->10,0] MId=0x1017 ] + --L[#2 T=M VId=0x1017 Text="Captured gains will be"[0x24D] MId=0x1017 ] + --L[#3 T=V_i8 VId=0x1004 Text="Roll"[0x40] Val=40 [0->0,0] MId=0x1017 ] + --L[#4 T=V_i8 VId=0x1005 Text="Pitch"[0x41] Val=50 [0->0,0] MId=0x1017 ] + --L[#5 T=V_i8 VId=0x1006 Text="Yaw"[0x42] Val=60 [0->0,0] MId=0x1017 ] + --L[#6 T=M VId=0x1018 Text="Capture Gyro Gains"[0xAA] MId=0x1017 ] + + ctx.Menu = { MenuId = 0x1017, TextId = 0xAA, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { MenuId = 0x1017, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x24C, ValId = 0x1017 } + ctx.MenuLines[1] = { MenuId = 0x1017, lineNum = 1, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { MenuId = 0x1017, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x24D, ValId = 0x1017 } + ctx.MenuLines[3] = { MenuId = 0x1017, lineNum = 3, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x40, ValId = 0x1004, Min=0, Max=0, Def=0, Val=40 } + ctx.MenuLines[4] = { MenuId = 0x1017, lineNum = 4, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x41, ValId = 0x1005, Min=0, Max=0, Def=0, Val=50 } + ctx.MenuLines[5] = { MenuId = 0x1017, lineNum = 5, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x42, ValId = 0x1006, Min=0, Max=0, Def=0, Val=60 } + ctx.MenuLines[6] = { MenuId = 0x1017, lineNum = 6, Type = LINE_TYPE.MENU, TextId = 0xAA, ValId = 0x1018 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1018) then + --M[Id=0x1018 P=0x0 N=0x0 B=0x1011 Text="Capture Gyro Gains"[0xAA]] + --L[#0 T=M VId=0x1018 Text="Gains on"[0x24E] MId=0x1018 ] + --L[#1 T=V_NC VId=0x1018 Text=" Flight Mode 1"[0x8001] Val=1 [0->10,0] MId=0x1018 ] + --L[#2 T=M VId=0x1018 Text="were captured and changed"[0x24F] MId=0x1018 + --L[#3 T=M VId=0x1018 Text="from Adjustable to Fixed"[0x250] MId=0x1018 ] + --L[#4 T=V_i8 VId=0x1004 Text="Roll"[0x40] Val=40 [0->0,0] MId=0x1018 ] + --L[#5 T=V_i8 VId=0x1005 Text="Pitch"[0x41] Val=50 [0->0,0] MId=0x1018 ] + --L[#6 T=V_i8 VId=0x1006 Text="Yaw"[0x42] Val=60 [0->0,0] MId=0x1018 ] + + ctx.Menu = { MenuId = 0x1018, TextId = 0xAA, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { MenuId = 0x1018, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x24E, ValId = 0x1018 } + ctx.MenuLines[1] = { MenuId = 0x1018, lineNum = 1, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { MenuId = 0x1018, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x24F, ValId = 0x1018 } + ctx.MenuLines[3] = { MenuId = 0x1018, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x250, ValId = 0x1018 } + ctx.MenuLines[4] = { MenuId = 0x1018, lineNum = 4, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x40, ValId = 0x1004, Min=0, Max=0, Def=0, Val=40 } + ctx.MenuLines[5] = { MenuId = 0x1018, lineNum = 5, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x41, ValId = 0x1005, Min=0, Max=0, Def=0, Val=50 } + ctx.MenuLines[6] = { MenuId = 0x1018, lineNum = 6, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x42, ValId = 0x1006, Min=0, Max=0, Def=0, Val=60 } + + ctx.SelLine = -1 + lastGoodMenu = menuId + elseif (menuId==0x1019) then + --M[Id=0x1019 P=0x0 N=0x0 B=0x1010 Text="SAFE Settings"[0x1E2]] + --L[#0 T=M VId=0x101A Text="SAFE Gains"[0x1E3] MId=0x1019 ] + --L[#1 T=M VId=0x101B Text="Angle Limits"[0x226] MId=0x1019 ] + --L[#5 T=M VId=0x101E Text="Fixed/Adjustable Gains"[0x263] MId=0x1019 ] + --L[#6 T=M VId=0x101F Text="Capture Gyro Gains"[0xAA] MId=0x1019 ] + + ctx.Menu = { MenuId = 0x1019, TextId = 0x1E2, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { MenuId = 0x1019, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x1E3, ValId = 0x101A } + ctx.MenuLines[1] = { MenuId = 0x1019, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x226, ValId = 0x101B } + ctx.MenuLines[5] = { MenuId = 0x1019, lineNum = 5, Type = LINE_TYPE.MENU, TextId = 0x263, ValId = 0x101E } + ctx.MenuLines[6] = { MenuId = 0x1019, lineNum = 6, Type = LINE_TYPE.MENU, TextId = 0xAA, ValId = 0x101F } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x101A) then + --M[Id=0x101A P=0x0 N=0x0 B=0x1019 Text="SAFE Gains"[0x1E3]] + --L[#0 T=V_NC VId=0x1000 Text=" Flight Mode 1"[0x8001] Val=nil [0->10,0] MId=0x101A ] + --L[#1 T=M VId=0x101A Text="Gain"[0x43] MId=0x101A ] + --L[#2 T=V_NC VId=0x1002 Text="Roll"[0x40] Val=35 [5->100,35] MId=0x101A ] + --L[#3 T=V_NC VId=0x1003 Text="Pitch"[0x41] Val=35 [5->100,35] MId=0x101A ] + + ctx.Menu = { MenuId = 0x101A, TextId = 0x1E3, PrevId = 0, NextId = 0, BackId = 0x1019 } + ctx.MenuLines[0] = { MenuId = 0x101A, lineNum = 0, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { MenuId = 0x101A, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x43, ValId = 0x101A } + ctx.MenuLines[2] = { MenuId = 0x101A, lineNum = 2, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x40, ValId = 0x1002, Min=5, Max=100, Def=35, Val=35 } + ctx.MenuLines[3] = { MenuId = 0x101A, lineNum = 3, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x41, ValId = 0x1003, Min=5, Max=100, Def=60, Val=35 } + + ctx.SelLine = -1 + lastGoodMenu = menuId + elseif (menuId==0x101B) then + --M[Id=0x101B P=0x0 N=0x0 B=0x1019 Text="Angle Limits"[0x226]] + --L[#0 T=V_NC VId=0x1000 Text=" Flight Mode 1"[0x8001] Val=nil [0->10,0] MId=0x101B ] + --L[#1 T=M VId=0x101B Text="Angle Limits"[0x226] MId=0x101B ] + --L[#2 T=V_NC VId=0x1002 Text="Roll Right"[0x1E9] Val=60 [10->90,60] MId=0x101B ] + --L[#3 T=V_NC VId=0x1003 Text="Roll Left"[0x1EA] Val=60 [10->90,60] MId=0x101B ] + --L[#4 T=V_NC VId=0x1004 Text="Pitch Down"[0x1EB] Val=40 [10->75,40] MId=0x101B ] + --L[#5 T=V_NC VId=0x1005 Text="Pitch Up"[0x1EC] Val=50 [10->75,50] MId=0x101B ] + + ctx.Menu = { MenuId = 0x101B, TextId = 0x226, PrevId = 0, NextId = 0, BackId = 0x1019 } + ctx.MenuLines[0] = { MenuId = 0x101B, lineNum = 0, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { MenuId = 0x101B, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x226, ValId = 0x101B } + ctx.MenuLines[2] = { MenuId = 0x101B, lineNum = 2, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x1E9, ValId = 0x1002, Min=10, Max=90, Def=60, Val=60 } + ctx.MenuLines[3] = { MenuId = 0x101B, lineNum = 3, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x1EA, ValId = 0x1003, Min=10, Max=90, Def=60, Val=60 } + ctx.MenuLines[4] = { MenuId = 0x101B, lineNum = 4, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x1EB, ValId = 0x1004, Min=10, Max=90, Def=40, Val=40 } + ctx.MenuLines[5] = { MenuId = 0x101B, lineNum = 5, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x1EC, ValId = 0x1005, Min=10, Max=90, Def=50, Val=50 } + + ctx.SelLine = -1 + lastGoodMenu = menuId + + elseif (menuId==0x101E) then + --M[Id=0x101E P=0x0 N=0x0 B=0x1019 Text="Fixed/Adjustable Gains"[0x263]] + --L[#0 T=V_NC VId=0x1000 Text=" Flight Mode 1"[0x8001] Val=nil [0->10,0] MId=0x101E ] + --L[#1 T=M VId=0x101E Text="Fixed/Adjustable Gains"[0x263] MId=0x101E ] + --L[#2 T=L_m0 VId=0x1002 Text="Roll"[0x40] Val=0 N=(0->1,1,S=242) [242->243,243] MId=0x101E ] + --L[#3 T=L_m0 VId=0x1003 Text="Pitch"[0x41] Val=0 N=(0->1,1,S=242) [242->243,243] MId=0x101E ] + + ctx.Menu = { MenuId = 0x101E, TextId = 0x263, PrevId = 0, NextId = 0, BackId = 0x1019 } + ctx.MenuLines[0] = { MenuId = 0x101E, lineNum = 0, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { MenuId = 0x101E, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x263, ValId = 0x101E } + ctx.MenuLines[2] = { MenuId = 0x101E, lineNum = 2, Type = LINE_TYPE.LIST_MENU0, TextId = 0x40, ValId = 0x1002, Min=242, Max=243, Def=243, Val=0 } + ctx.MenuLines[3] = { MenuId = 0x101E, lineNum = 3, Type = LINE_TYPE.LIST_MENU0, TextId = 0x41, ValId = 0x1003, Min=242, Max=243, Def=243, Val=0 } + + ctx.SelLine = -1 + lastGoodMenu = menuId + elseif (menuId==0x101F) then + --M[Id=0x101F P=0x0 N=0x0 B=0x1019 Text="Capture Gyro Gains"[0xAA]] + --L[#0 T=M VId=0x101F Text="Gains will be captured on"[0x24C] MId=0x101F ] + --L[#1 T=V_NC VId=0x1000 Text=" Flight Mode 1"[0x8001] Val=1 [0->10,0] MId=0x101F ] + --L[#2 T=M VId=0x101F Text="Captured gains will be"[0x24D] MId=0x101F ] + --L[#3 T=V_i8 VId=0x1004 Text="Roll"[0x40] Val=40 [0->0,0] MId=0x101F ] + --L[#4 T=V_i8 VId=0x1005 Text="Pitch"[0x41] Val=50 [0->0,0] MId=0x101F ] + --L[#6 T=M VId=0x1020 Text="Capture Gyro Gains"[0xAA] MId=0x101F ] + + ctx.Menu = { MenuId = 0x101F, TextId = 0xAA, PrevId = 0, NextId = 0, BackId = 0x1019 } + ctx.MenuLines[0] = { MenuId = 0x101F, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x24C, ValId = 0x101F } + ctx.MenuLines[1] = { MenuId = 0x101F, lineNum = 1, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { MenuId = 0x101F, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x24D, ValId = 0x101F } + ctx.MenuLines[3] = { MenuId = 0x101F, lineNum = 3, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x40, ValId = 0x1004, Min=0, Max=0, Def=0, Val=35 } + ctx.MenuLines[4] = { MenuId = 0x101F, lineNum = 4, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x41, ValId = 0x1005, Min=0, Max=0, Def=0, Val=35 } + ctx.MenuLines[6] = { MenuId = 0x101F, lineNum = 6, Type = LINE_TYPE.MENU, TextId = 0xAA, ValId = 0x1020 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1020) then + --M[Id=0x1020 P=0x0 N=0x0 B=0x101F Text="Capture Gyro Gains"[0xAA]] + --L[#0 T=M VId=0x1020 Text="Gains on"[0x24E] MId=0x1020 ] + --L[#1 T=V_NC VId=0x1018 Text=" Flight Mode 1"[0x8001] Val=1 [0->10,0] MId=0x1020 ] + --L[#2 T=M VId=0x1018 Text="were captured and changed"[0x24F] MId=0x1020 + --L[#3 T=M VId=0x1018 Text="from Adjustable to Fixed"[0x250] MId=0x1020 ] + --L[#4 T=V_i8 VId=0x1004 Text="Roll"[0x40] Val=40 [0->0,0] MId=0x1020 ] + --L[#5 T=V_i8 VId=0x1005 Text="Pitch"[0x41] Val=50 [0->0,0] MId=0x1020 ] + + ctx.Menu = { MenuId = 0x1020, TextId = 0xAA, PrevId = 0, NextId = 0, BackId = 0x1019 } + ctx.MenuLines[0] = { MenuId = 0x1020, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x24E, ValId = 0x1020 } + ctx.MenuLines[1] = { MenuId = 0x1020, lineNum = 1, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { MenuId = 0x1020, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x24F, ValId = 0x1020 } + ctx.MenuLines[3] = { MenuId = 0x1020, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x250, ValId = 0x1020 } + ctx.MenuLines[4] = { MenuId = 0x1020, lineNum = 4, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x40, ValId = 0x1004, Min=0, Max=0, Def=0, Val=35 } + ctx.MenuLines[5] = { MenuId = 0x1020, lineNum = 5, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x41, ValId = 0x1005, Min=0, Max=0, Def=0, Val=35 } + + ctx.SelLine = -1 + lastGoodMenu = menuId + elseif (menuId==0x1021) then + --M[Id=0x1021 P=0x0 N=0x0 B=0x1010 Text="F-Mode Setup"[0x87]] + --L[#0 T=V_NC VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x1021 ] + --L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ] + --L[#2 T=L_m1 VId=0x1002 Text="AS3X"[0x1DC] val=1 (0->1,3,S=3) [3->4|3] MId=0x1021] + + -- Why Jump from Value 3 to 176?? where do we know valid values???? + --L[#3 T=L_m1 VId=0x1003 Text="Safe Mode"[0x1F8] val=3|"Inh" NL=(0->244,0,S=0) [0->244,3] MId=0x1021 ] + --L[#3 T=L_m1 VId=0x1003 Text="Safe Mode"[0x1F8] val=176|"Self-Level/Angle Dem" NL=(0->244,0,S=0) [0->244,3] MId=0x1021 ] + + --L[#4 T=L_m1 VId=0x1004 Text="Panic"[0x8B] val=0 NL=(0->1,3,S=3) [3->4,3] MId=0x1021 ] + --L[#5 T=L_m1 VId=0x1005 Text="High Thr to Pitch"[0x1F0] val=0 NL=(0->1,3,S=3) [3->4,3] MId=0x1021 ] + --L[#6 T=L_m1 VId=0x1006 Text="Low Thr to Pitch"[0x1EF] val=0 NL=(0->1,3,S=3) [3->4,3] MId=0x1021 ] + + ctx.Menu = { MenuId = 0x1021, TextId = 0x87, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { MenuId = 0x1021, lineNum = 0, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { MenuId = 0x1021, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x78, ValId = 0x7CA6 } + ctx.MenuLines[2] = { MenuId = 0x1021, lineNum = 2, Type = LINE_TYPE.LIST_MENU1, TextId = 0x1DC, ValId = 0x1002, Min=3, Max=4, Def=3, Val=1 } + ctx.MenuLines[3] = { MenuId = 0x1021, lineNum = 3, Type = LINE_TYPE.LIST_MENU1, TextId = 0x1F8, ValId = 0x1003, Min=0, Max=244, Def=3, Val=176 } + ctx.MenuLines[4] = { MenuId = 0x1021, lineNum = 4, Type = LINE_TYPE.LIST_MENU1, TextId = 0x8B, ValId = 0x1004, Min=3, Max=4, Def=3, Val=0 } + ctx.MenuLines[5] = { MenuId = 0x1021, lineNum = 5, Type = LINE_TYPE.LIST_MENU1, TextId = 0x1F0, ValId = 0x1005, Min=3, Max=4, Def=3, Val=0 } + ctx.MenuLines[6] = { MenuId = 0x1021, lineNum = 6, Type = LINE_TYPE.LIST_MENU1, TextId = 0x1EF, ValId = 0x1006, Min=3, Max=4, Def=3, Val=0 } + ctx.SelLine = 1 + lastGoodMenu = menuId + elseif (menuId==0x1022) then + --M[Id=0x1022 P=0x0 N=0x0 B=0x1010 Text="System Setup"[0x86]] + --L[#0 T=M VId=0x1023 Text="Relearn Servo Settings"[0x190] MId=0x1022 ] + --L[#1 T=M VId=0x1025 Text="Orientation"[0x80] MId=0x1022 ] + --L[#2 T=M VId=0x1029 [0->0,2] Text="Gain Channel Select"[0xAD] MId=0x1022 ] + --L[#3 T=M VId=0x102A [0->0,2] Text="SAFE/Panic Mode Setup"[0xCA] MId=0x1022 ] + --L[#4 T=M VId=0x1032 [0->0,2] Text="Utilities"[0x240] MId=0x1022 ] + + ctx.Menu = { MenuId = 0x1022, TextId = 0x86, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { MenuId = 0x1022, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x190, ValId = 0x1023 } + ctx.MenuLines[1] = { MenuId = 0x1022, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x80, ValId = 0x1025 } + ctx.MenuLines[2] = { MenuId = 0x1022, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0xAD, ValId = 0x1029 } + ctx.MenuLines[3] = { MenuId = 0x1022, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0xCA, ValId = 0x102A } + ctx.MenuLines[4] = { MenuId = 0x1022, lineNum = 4, Type = LINE_TYPE.MENU, TextId = 0x240, ValId = 0x1032 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x104F) then + --M[Id=0x104F P=0x0 N=0x1050 B=0x1010 Text="First Time Setup"] + --L[#0 T=M VId=0x104F Text="Make sure the model has been" MId=0x104F ] + --L[#1 T=M VId=0x104F Text="configured, including wing type," MId=0x104F ] + --L[#2 T=M VId=0x104F Text="reversing, travel, trimmed, etc." MId=0x104F ] + --L[#3 T=M VId=0x104F [0->0,2] Text="before continuing setup." MId=0x104F ] + --L[#4 T=M VId=0x104F [0->0,2] Text="" MId=0x104F ] + --L[#5 T=M VId=0x104F [0->0,2] Text="" MId=0x104F ] + + ctx.Menu = { MenuId = 0x104F, TextId = 0x00F9, PrevId = 0, NextId = 0x1050, BackId = 0x1010 } + ctx.MenuLines[0] = { MenuId = 0x104F, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x0100, ValId = 0x104F } + ctx.MenuLines[1] = { MenuId = 0x104F, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x0101, ValId = 0x104F } + ctx.MenuLines[2] = { MenuId = 0x104F, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x0102, ValId = 0x104F } + ctx.MenuLines[3] = { MenuId = 0x104F, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x0103, ValId = 0x104F } + ctx.SelLine = dsmLib.NEXT_BUTTON + lastGoodMenu = menuId + elseif (menuId==0x1050) then + + --M[Id=0x1050 P=0x104F N=0x1051 B=0x1010 Text="First Time Setup"] + --L[#0 T=M VId=0x1050 Text="Any wing type, channel assignment," MId=0x1050 ] + --L[#1 T=M VId=0x1050 Text="subtrim, or servo reversing changes" MId=0x1050 + --L[#2 T=M VId=0x1050 Text="require running through initial" MId=0x1050 ] + --L[#3 T=M VId=0x1050 Text="setup again." MId=0x1050 ] + + ctx.Menu = { MenuId = 0x1050, TextId = 0x00F9, PrevId = 0x104F, NextId = 0x1051, BackId = 0x1010 } + ctx.MenuLines[0] = { MenuId = 0x1050, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x0106, ValId = 0x1050 } + ctx.MenuLines[1] = { MenuId = 0x1050, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x0107, ValId = 0x1050 } + ctx.MenuLines[2] = { MenuId = 0x1050, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x0108, ValId = 0x1050 } + ctx.MenuLines[3] = { MenuId = 0x1050, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x0109, ValId = 0x1050 } + ctx.SelLine = dsmLib.NEXT_BUTTON + lastGoodMenu = menuId + elseif (menuId==0x1051) then + --M[Id=0x1051 P=0x0 N=0x0 B=0x1010 Text="First Time Setup"] + --L[#0 T=M VId=0x1051 Text="Set the model level," MId=0x1051 ] + --L[#1 T=M VId=0x1051 Text="and press Continue." MId=0x1051 ] + --L[#2 T=M VId=0x1051 Text="" MId=0x1051 ] + --L[#5 T=M VId=0x1052 Text="Continue" MId=0x1051 ] + --L[#6 T=M VId=0x1053 Text="Set Orientation Manually" MId=0x1051 ] + + ctx.Menu = { MenuId = 0x1051, TextId = 0x00F9, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { MenuId = 0x1051, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x021A, ValId = 0x1051 } + ctx.MenuLines[1] = { MenuId = 0x1051, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x021B, ValId = 0x1051 } + ctx.MenuLines[2] = { MenuId = 0x1051, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x021C, ValId = 0x1051 } + ctx.MenuLines[5] = { MenuId = 0x1051, lineNum = 5, Type = LINE_TYPE.MENU, TextId = 0x0224, ValId = 0x1052 } + ctx.MenuLines[6] = { MenuId = 0x1051, lineNum = 6, Type = LINE_TYPE.MENU, TextId = 0x0229, ValId = 0x1053 } + + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1052) then + --M[Id=0x1052 P=0x1051 N=0x0 B=0x1010 Text="First Time Setup"[0xA5]] + --L[#0 T=M VId=0x1052 Text="Set the model on its nose,"[0x21F] MId=0x1052 ] + --L[#1 T=M VId=0x1052 Text="and press Continue. If the"[0x220] MId=0x1052 ] + --L[#2 T=M VId=0x1052 Text="orientation on the next"[0x221] MId=0x1052 ] + --L[#3 T=M VId=0x1052 Text="screen is wrong go back"[0x222] MId=0x1052 ] + --L[#4 T=M VId=0x1052 Text="and try again."[0x223] MId=0x1052 ] + --L[#6 T=M VId=0x1053 Text="Continue"[0x224] MId=0x1052 ] + + ctx.Menu = { MenuId = 0x1052, TextId = 0x00A5, PrevId = 0x1051, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { MenuId = 0x1052, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x21F, ValId = 0x1052 } + ctx.MenuLines[1] = { MenuId = 0x1052, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x220, ValId = 0x1052 } + ctx.MenuLines[2] = { MenuId = 0x1052, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x221, ValId = 0x1052 } + ctx.MenuLines[3] = { MenuId = 0x1052, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x222, ValId = 0x1052 } + ctx.MenuLines[4] = { MenuId = 0x1052, lineNum = 4, Type = LINE_TYPE.MENU, TextId = 0x223, ValId = 0x1052 } + ctx.MenuLines[6] = { MenuId = 0x1052, lineNum = 6, Type = LINE_TYPE.MENU, TextId = 0x224, ValId = 0x1053 } + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1053) then + --M[Id=0x1053 P=0x1051 N=0x0 B=0x1010 Text="First Time Setup"[0xA5]] + --L[#5 T=L_m0 VId=0x1000 Text="Orientation"[0x80] MId=0x1053 val=0 (0->23,0,S=203) [203->226,203] ] + --L[#6 T=M VId=0x1054 Text="Continue"[0x224] MId=0x1053 ] + + ctx.Menu = { MenuId = 0x1053, TextId = 0x00A5, PrevId = 0x1051, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[5] = { MenuId = 0x1053, lineNum = 0, Type = LINE_TYPE.LIST_MENU0, TextId = 0x80, ValId = 0x1000, Min=203, Max=226, Def=203, Val=0 } + ctx.MenuLines[6] = { MenuId = 0x1053, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x224, ValId = 0x1054 } + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1054) then + --M[Id=0x1054 P=0x1053 N=0x0 B=0x1010 Text="First Time Setup"[0xA5]] + --L[#1 T=M VId=0x7CA5 Text="Gain Channel Select"[0xAD] ] + --L[#6 T=M VId=0x1 Text="Apply"[0x90] MId=0x1054 ] + + ctx.Menu = { MenuId = 0x1054, TextId = 0x00A5, PrevId = 0x1053, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[5] = { MenuId = 0x1054, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0xAD, ValId = 0x7CA5 } + ctx.MenuLines[6] = { MenuId = 0x1054, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x01 } -- Special save&reboot?? + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x105C) then + -- M[Id=0x105C P=0x0 N=0x0 B=0x1010 Text="SAFE Select"[0x1F9]] + --L[#0 T=V_NC VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x105C ] + --L[#1 T=L_m1 VId=0x1001 Text="SAFE Select Channel"[0x1D7] val=5 NL=(0->32,53,S=53) [53->85,53] MId=0x105C] + --L[#2 T=L_m1 VId=0x1002 Text="AS3X"[0x1DC] val=1 NL=(0->1,1,S=1) [1->2,1] MId=0x105C] + --L[#3 T=L_m1 VId=0x1003 Text="SAFE"[0xDA] val=0 NL=(0->0,0,S=1) [1->1,1] MId=0x105C ] + --L[#6 T=L_m1 VId=0x1006 Text="SAFE Select"[0x1F9] val=0 NL=(0->1,1,S=1) [1->2,1] MId=0x105C ] + + ctx.Menu = { MenuId = 0x105C, TextId = 0x1DE, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { MenuId = 0x105C, lineNum = 0, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { MenuId = 0x105C, lineNum = 1, Type = LINE_TYPE.LIST_MENU1, TextId = 0x1D7, ValId = 0x1001, Min=53, Max=85, Def=53, Val=5 } + ctx.MenuLines[2] = { MenuId = 0x105C, lineNum = 2, Type = LINE_TYPE.LIST_MENU1, TextId = 0x1DC, ValId = 0x1002, Min=1, Max=2, Def=1, Val=1 } + ctx.MenuLines[3] = { MenuId = 0x105C, lineNum = 3, Type = LINE_TYPE.LIST_MENU1, TextId = 0xDA, ValId = 0x1003, Min=1, Max=1, Def=1, Val=0 } + ctx.MenuLines[6] = { MenuId = 0x105C, lineNum = 6, Type = LINE_TYPE.LIST_MENU1, TextId = 0x1F9, ValId = 0x1004, Min=1, Max=2, Def=1, Val=0 } + + ctx.SelLine = 1 + lastGoodMenu = menuId + elseif (menuId==0x105E) then + -- M[Id=0x105E P=0x0 N=0x0 B=0x1000 Text="Other settings"] + -- L[#1 T=M VId=0x1060 Text="Failsafe" MId=0x105E ] + -- L[#2 T=M VId=0x1064 Text="Enter Receiver Bind Mode" MId=0x105E ] + -- L[#3 T=M VId=0x1065 Text="Frame Rate" MId=0x105E ] + -- L[#4 T=M VId=0x1067 Text="Factory Reset" MId=0x105E ] + -- L[#5 T=M VId=0x1069 Text="Restore from Backup" MId=0x105E ] + -- L[#6 T=M VId=0x106A Text="Save to Backup" MId=0x105E ] + + ctx.Menu = { MenuId = 0x105E, TextId = 0x0227, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[1] = { MenuId = 0x105E, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x004A, ValId = 0x1060 } + ctx.MenuLines[2] = { MenuId = 0x105E, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x019C, ValId = 0x1064 } + ctx.MenuLines[3] = { MenuId = 0x105E, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x0085, ValId = 0x1065 } + ctx.MenuLines[4] = { MenuId = 0x105E, lineNum = 4, Type = LINE_TYPE.MENU, TextId = 0x0097, ValId = 0x1067 } + ctx.MenuLines[5] = { MenuId = 0x105E, lineNum = 5, Type = LINE_TYPE.MENU, TextId = 0x020A, ValId = 0x1069 } + ctx.MenuLines[6] = { MenuId = 0x105E, lineNum = 6, Type = LINE_TYPE.MENU, TextId = 0x0209, ValId = 0x106A } + + ctx.SelLine = 1 + lastGoodMenu = menuId + elseif (menuId==0x1060) then + --M[Id=0x1060 P=0x0 N=0x0 B=0x105E Text="Failsafe"] + --L[#0 T=M VId=0x1061 Text="Failsafe" MId=0x1060 ] + --L[#1 T=M VId=0x1062 Text="Capture Failsafe Positions" MId=0x1060 ] + + ctx.Menu = { MenuId = 0x1060, TextId = 0x004A, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[0] = { MenuId = 0x1060, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x004A, ValId = 0x1061 } + ctx.MenuLines[1] = { MenuId = 0x1060, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x009A, ValId = 0x1062 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1061) then + --M[Id=0x1061 P=0x0 N=0x0 B=0x1060 Text="Failsafe"] + --L[#0 T=L_m0 VId=0x1000 Text="Outputs:" val=0 NL=(0->19,54,S=54) [54->73,54] MId=0x1061 ] + --L[#2 T=L_m2 VId=0x1002 Text="Custom Failsafe:" val=0 NL=(0->1,95,S=95) [95->96,95] MId=0x1061 ] + --L[#3 T=V_% VId=0x1003 Text="Position:" val=-100 [-150->150,0] MId=0x1061 ] + + ctx.Menu = { MenuId = 0x1061, TextId = 0x004A, PrevId = 0, NextId = 0, BackId = 0x1060 } + ctx.MenuLines[0] = { MenuId = 0x1061, lineNum = 0, Type = LINE_TYPE.LIST_MENU0, TextId = 0x0050, ValId = 0x1000, Min=54, Max=73, Def=54, Val=0 } + ctx.MenuLines[1] = { MenuId = 0x1061, lineNum = 1, Type = LINE_TYPE.LIST_MENU2, TextId = 0x009C, ValId = 0x1002, Min=95, Max=96, Def=95, Val=0 } + ctx.MenuLines[2] = { MenuId = 0x1061, lineNum = 2, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x004E, ValId = 0x1002, Min=-150, Max=150, Def=0, Val=-100 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1064) then + --M[Id=0x1064 P=0x0 N=0x0 B=0x105E Text="Enter Receiver Bind Mode"[0x19C]] + --L[#3 T=M VId=0x1 Text="Apply"[0x90] MId=0x1064 ] + + ctx.Menu = { MenuId = 0x1064, TextId = 0x19C, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[3] = { MenuId = 0x1064, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1 } -- reset RX + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x1065) then + --M[Id=0x1065 P=0x0 N=0x0 B=0x105E Text="Frame Rate"] + --L[#0 T=L_m1 VId=0x1000 Text="Output Channel 1:" val=46 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + --L[#1 T=L_m1 VId=0x1001 Text="Output Channel 2:" val=47 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + --L[#2 T=L_m1 VId=0x1002 Text="Output Channel 3:" val=46 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + --L[#3 T=L_m1 VId=0x1003 Text="Output Channel 4:" val=46 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + --L[#4 T=L_m1 VId=0x1004 Text="Output Channel 5:" val=46 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + --L[#5 T=L_m1 VId=0x1005 Text="Output Channel 6:" val=46 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + + ctx.Menu = { MenuId = 0x1065, TextId = 0x0085, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[0] = { MenuId = 0x1065, lineNum = 0, Type = LINE_TYPE.LIST_MENU1, TextId = 0x0051, ValId = 0x1000, Min=0, Max=244, Def=46, Val=46 } + ctx.MenuLines[1] = { MenuId = 0x1065, lineNum = 1, Type = LINE_TYPE.LIST_MENU1, TextId = 0x0052, ValId = 0x1001, Min=0, Max=244, Def=46, Val=47 } + ctx.MenuLines[2] = { MenuId = 0x1065, lineNum = 2, Type = LINE_TYPE.LIST_MENU1, TextId = 0x0053, ValId = 0x1002, Min=0, Max=244, Def=46, Val=46 } + ctx.MenuLines[3] = { MenuId = 0x1065, lineNum = 3, Type = LINE_TYPE.LIST_MENU1, TextId = 0x0054, ValId = 0x1002, Min=0, Max=244, Def=46, Val=46 } + ctx.MenuLines[4] = { MenuId = 0x1065, lineNum = 4, Type = LINE_TYPE.LIST_MENU1, TextId = 0x0055, ValId = 0x1002, Min=0, Max=244, Def=46, Val=46 } + ctx.MenuLines[5] = { MenuId = 0x1065, lineNum = 5, Type = LINE_TYPE.LIST_MENU1, TextId = 0x0056, ValId = 0x1002, Min=0, Max=244, Def=46, Val=46 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1067) then + --M[Id=0x1067 P=0x0 N=0x0 B=0x105E Text="WARNING!"[0x22B]] + --L[#0 T=M VId=0x1067 Text="This will reset the"[0x22C] MId=0x1067 ] + --L[#1 T=M VId=0x1067 Text="configuration to factory"[0x22D] MId=0x1067 ] + --L[#2 T=M VId=0x1067 Text="defaults. This does not"[0x22E] MId=0x1067 ] + --L[#3 T=M VId=0x1067 Text="affect the backup config."[0x22F] MId=0x1067 ] + --L[#4 T=M VId=0x1067 Text=""[0x230] MId=0x1067 ] + --L[#6 T=M VId=0x1068 Text="Apply"[0x90] MId=0x1067 ] + + ctx.Menu = { MenuId = 0x1067, TextId = 0x22B, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[0] = { MenuId = 0x1067, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x22C, ValId = 0x1067 } + ctx.MenuLines[1] = { MenuId = 0x1067, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x22D, ValId = 0x1067 } + ctx.MenuLines[2] = { MenuId = 0x1067, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x22E, ValId = 0x1067 } + ctx.MenuLines[3] = { MenuId = 0x1067, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x22F, ValId = 0x1067 } + ctx.MenuLines[4] = { MenuId = 0x1067, lineNum = 4, Type = LINE_TYPE.MENU, TextId = 0x230, ValId = 0x1067 } + ctx.MenuLines[6] = { MenuId = 0x1067, lineNum = 6, Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1068 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1068) then + --M[Id=0x1068 P=0x0 N=0x0 B=0x1000 Text="Done"[0x94]] + --L[#3 T=M VId=0x1000 Text="Complete"[0x93] MId=0x1068 ] + + ctx.Menu = { MenuId = 0x1068, TextId = 0x94, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[3] = { MenuId = 0x1068, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x93, ValId = 0x1000 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x1069) then + --M[Id=0x1069 P=0x0 N=0x0 B=0x105E Text="WARNING!"[0x22B]] + --L[#0 T=M VId=0x1069 Text="This will overwrite the"[0x236] MId=0x1069 ] + --L[#1 T=M VId=0x1069 Text="current config with"[0x237] MId=0x1069 ] + --L[#2 T=M VId=0x1069 Text="that which is in"[0x238] MId=0x1069 ] + --L[#3 T=M VId=0x1069 Text="the backup memory."[0x239] MId=0x1069 ] + --L[#4 T=M VId=0x1069 Text=""[0x23A] MId=0x1069 ] + --L[#6 T=M VId=0x1068 Text="Apply"[0x90] MId=0x1069 ] + + ctx.Menu = { MenuId = 0x1069, TextId = 0x22B, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[0] = { MenuId = 0x1069, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x236, ValId = 0x1069 } + ctx.MenuLines[1] = { MenuId = 0x1069, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x237, ValId = 0x1069 } + ctx.MenuLines[2] = { MenuId = 0x1069, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x238, ValId = 0x1069 } + ctx.MenuLines[3] = { MenuId = 0x1069, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x239, ValId = 0x1069 } + ctx.MenuLines[4] = { MenuId = 0x1069, lineNum = 4, Type = LINE_TYPE.MENU, TextId = 0x23A, ValId = 0x1069 } + ctx.MenuLines[6] = { MenuId = 0x1069, lineNum = 6, Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1068 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x106A) then + --M[Id=0x106A P=0x0 N=0x0 B=0x105E Text="WARNING!"[0x22B]] + --L[#0 T=M VId=0x106A Text="This will overwrite the"[0x231] MId=0x106A ] + --L[#1 T=M VId=0x106A Text="backup memory with your"[0x232] MId=0x106A ] + --L[#2 T=M VId=0x106A Text="current configuartion."[0x233] MId=0x106A ] + --L[#3 T=M VId=0x106A Text=""[0x234] MId=0x106A ] + --L[#4 T=M VId=0x106A Text=""[0x235] MId=0x106A ] + --L[#6 T=M VId=0x1068 Text="Apply"[0x90] MId=0x106A ] + + ctx.Menu = { MenuId = 0x106A, TextId = 0x22B, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[0] = { MenuId = 0x106A, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x231, ValId = 0x106A } + ctx.MenuLines[1] = { MenuId = 0x106A, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x232, ValId = 0x106A } + ctx.MenuLines[2] = { MenuId = 0x106A, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x233, ValId = 0x106A } + ctx.MenuLines[3] = { MenuId = 0x106A, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x234, ValId = 0x106A } + ctx.MenuLines[4] = { MenuId = 0x106A, lineNum = 4, Type = LINE_TYPE.MENU, TextId = 0x235, ValId = 0x106A } + ctx.MenuLines[6] = { MenuId = 0x106A, lineNum = 6, Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1068 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x7CA5) then + --M[Id=0x7CA5 P=0x0 N=0x1021 B=0x1021 Text="Gain Channel Select"[0xAD]] + --L[#0 T=L_m1 VId=0x1000 Text="Gain Channel"[0x89] val=7 N=(0->32,53,S=53) [53->85,53] MId=0x7CA5 ] + + ctx.Menu = { MenuId = 0x7CA5, TextId = 0xAD, PrevId = 0, NextId = 0x1054, BackId = 0x1054 } + ctx.MenuLines[0] = { MenuId = 0x7CA5, lineNum = 0, Type = LINE_TYPE.LIST_MENU1, TextId = 0x89, ValId = 0x1000, Min=53, Max=85, Def=53, Val=7 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x7CA6) then + --M[Id=0x7CA6 P=0x0 N=0x1021 B=0x1021 Text="FM Channel"[0x78]] + --L[#0 T=L_m1 VId=0x1000 Text="FM Channel"[0x78] val=7 N=(0->32,53,S=53) [53->85,53] MId=0x7CA6 ] + + ctx.Menu = { MenuId = 0x7CA6, TextId = 0x78, PrevId = 0, NextId = 0x1021, BackId = 0x1021 } + ctx.MenuLines[0] = { MenuId = 0x7CA6, lineNum = 0, Type = LINE_TYPE.LIST_MENU1, TextId = 0x78, ValId = 0x1000, Min=53, Max=85, Def=53, Val=7 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1) then + -- Save Settings and Reboot + ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.SelLine = dsmLib.BACK_BUTTON + + else + print("NOT IMPLEMENTED") + ctx.Menu = { MenuId = 0x0001, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu } + ctx.SelLine = dsmLib.BACK_BUTTON + end + + PostProcessMenu() +end + +local function FC6250HX_loadMenu(menuId) + clearMenuLines() + local ctx = dsmLib.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[#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] = { MenuId = 0x1000, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0xD3, ValId = 0x1100 } + ctx.MenuLines[1] = { MenuId = 0x1000, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0xDD, ValId = 0x1200 } + ctx.MenuLines[2] = { MenuId = 0x1000, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0xDA, ValId = 0x1400 } + ctx.MenuLines[4] = { MenuId = 0x1000, lineNum = 4, Type = LINE_TYPE.MENU, TextId = 0xDE, ValId = 0x1300 } + ctx.MenuLines[6] = { MenuId = 0x1000, lineNum = 5, Type = LINE_TYPE.MENU, TextId = 0x86, ValId = 0x1700 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1100) then + --M[Id=0x1100 P=0x0 N=0x0 B=0x1000 Text="Swashplate"[0xD3]] + --L[#0 T=M VId=0x1110 val=nil [0->0,2] Text="Roll"[0x40] MId=0x1100 ] + --L[#1 T=M VId=0x1120 val=nil [0->0,2] Text="Pitch"[0x41] MId=0x1100 ] + --L[#2 T=V_i8 VId=0x1103 Text="Agility"[0xD5] val=100 [0->200,100] MId=0x1100 ] + + ctx.Menu = { MenuId = 0x1100, TextId = 0xD3, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { MenuId = 0x1100, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x40, ValId = 0x1110, Min=0, Max=0, Def=3, Val=nil } + ctx.MenuLines[1] = { MenuId = 0x1100, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x41, ValId = 0x1120, Min=0, Max=0, Def=2, Val=nil } + ctx.MenuLines[2] = { MenuId = 0x1100, lineNum = 2, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xD5, ValId = 0x1103, Min=0, Max=200, Def=100, Val=100 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1110) then + --M[Id=0x1110 P=0x0 N=0x0 B=0x1100 Text="Roll"[0x40]] + --L[#0 T=V_i16 VId=0x1111 Text="@ per sec"[0xDC] val=270 [0->900,270] MId=0x1110 ] + --L[#1 T=V_NC VId=0x1112 Text="FLIGHT MODE"[0x8000] val=1 [0->5,0] MId=0x1110 ] + --L[#2 T=V_i8 VId=0x1113 Text="Proportional"[0x71] val=100 [0->255,100] MId=0x1110 ] + --L[#3 T=V_i8 VId=0x1114 Text="Integral"[0x72] val=100 [0->255,100] MId=0x1110 ] + --L[#4 T=V_i8 VId=0x1115 Text="Derivate"[0x73] val=7 [0->255,7] MId=0x1110 ] + + ctx.Menu = { MenuId = 0x1110, TextId = 0x40, PrevId = 0, NextId = 0, BackId = 0x1100 } + ctx.MenuLines[0] = { MenuId = 0x1110, lineNum = 0, Type = LINE_TYPE.VALUE_NUM_I16, TextId = 0xDC, ValId = 0x1111, Min=0, Max=900, Def=270, Val=270 } + ctx.MenuLines[1] = { MenuId = 0x1110, lineNum = 1, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8000, ValId = 0x1112, Min=0, Max=5, Def=0, Val=1 } + ctx.MenuLines[2] = { MenuId = 0x1110, lineNum = 2, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x71, ValId = 0x1113, Min=0, Max=255, Def=100, Val=100 } + ctx.MenuLines[3] = { MenuId = 0x1110, lineNum = 3, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x72, ValId = 0x1114, Min=0, Max=255, Def=100, Val=100 } + ctx.MenuLines[4] = { MenuId = 0x1110, lineNum = 4, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x73, ValId = 0x1115, Min=0, Max=255, Def=7, Val=7 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1120) then + --M[Id=0x1120 P=0x0 N=0x0 B=0x1100 Text="Pitch"[0x41]] + --L[#0 T=V_i16 VId=0x1121 Text="@ per sec"[0xDC] Val=270 [0->900,270] MId=0x1120 ] + --L[#1 T=V_i8 VId=0x1212 Text="Start"[0x92] Val=nil [5->200,25] MId=0x1200 ] + --L[#2 T=V_i8 VId=0x1213 Text="Stop"[0xD8] Val=nil [5->200,25] MId=0x1200 ] + --L[#3 T=V_NC VId=0x1122 Text=" FLIGHT MODE"[0x8000] Val=1 [0->5,0] MId=0x1120 ] + --L[#4 T=V_i8 VId=0x1123 Text="Proportional"[0x71] Val=100 [0->255,100] MId=0x1120 ] + --L[#5 T=V_i8 VId=0x1124 Text="Integral"[0x72] Val=100 [0->255,100] MId=0x1120 ] + --L[#6 T=V_i8 VId=0x1125 Text="Derivate"[0x73] Val=14 [0->255,14] MId=0x1120 ] + + ctx.Menu = { MenuId = 0x1120, TextId = 0x41, PrevId = 0, NextId = 0, BackId = 0x1100 } + ctx.MenuLines[0] = { MenuId = 0x1120, lineNum = 0, Type = LINE_TYPE.VALUE_NUM_I16, TextId = 0xDC, ValId = 0x1121, Min=0, Max=900, Def=270, Val=270 } + ctx.MenuLines[1] = { MenuId = 0x1120, lineNum = 1, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x92, ValId = 0x1123, Min=5, Max=200, Def=25, Val=25 } + ctx.MenuLines[2] = { MenuId = 0x1120, lineNum = 2, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xD8, ValId = 0x1123, Min=5, Max=200, Def=26, Val=100 } + + ctx.MenuLines[3] = { MenuId = 0x1120, lineNum = 3, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8000, ValId = 0x1122, Min=0, Max=5, Def=0, Val=1 } + + ctx.MenuLines[4] = { MenuId = 0x1120, lineNum = 4, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x71, ValId = 0x1123, Min=0, Max=255, Def=100, Val=100 } + ctx.MenuLines[5] = { MenuId = 0x1120, lineNum = 5, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x72, ValId = 0x1124, Min=0, Max=255, Def=95, Val=95 } + ctx.MenuLines[6] = { MenuId = 0x1120, lineNum = 6, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x73, ValId = 0x1125, Min=0, Max=255, Def=45, Val=45 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1200) then + --M[Id=0x1200 P=0x0 N=0x0 B=0x1000 Text="Tail rotor"[0xDD]] + --L[#0 T=V_i16 VId=0x1211 Text="@ per sec"[0xDC] Val=550 [0->1280,550] MId=0x1200 ] + --L[#1 T=V_i8 VId=0x1212 Text="Start"[0x92] Val=25 [5->200,25] MId=0x1200 ] + --L[#2 T=V_i8 VId=0x1213 Text="Stop"[0xD8] Val=25 [5->200,25] MId=0x1200 ] + --L[#3 T=V_NC VId=0x1214 Text=" FLIGHT MODE"[0x8000] Val=1 [0->5,0] MId=0x1200 ] + --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[#6 T=V_i8 VId=0x1217 Text="Derivate"[0x73] Val=45 [0->255,45] MId=0x1200 ] + + ctx.Menu = { MenuId = 0x1200, TextId = 0xDD, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { MenuId = 0x1200, lineNum = 0, Type = LINE_TYPE.VALUE_NUM_I16, TextId = 0xDC, ValId = 0x1211, Min=0, Max=1280, Def=550, Val=550 } + ctx.MenuLines[1] = { MenuId = 0x1200, lineNum = 1, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x92, ValId = 0x1212, Min=5, Max=200, Def=25, Val=25 } + ctx.MenuLines[2] = { MenuId = 0x1200, lineNum = 2, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xD8, ValId = 0x1213, Min=5, Max=200, Def=26, Val=100 } + + ctx.MenuLines[3] = { MenuId = 0x1200, lineNum = 3, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8000, ValId = 0x1214, Min=0, Max=5, Def=0, Val=1 } + + ctx.MenuLines[4] = { MenuId = 0x1200, lineNum = 4, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x71, ValId = 0x1215, Min=0, Max=255, Def=100, Val=100 } + ctx.MenuLines[5] = { MenuId = 0x1200, lineNum = 5, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x72, ValId = 0x1216, Min=0, Max=255, Def=95, Val=95 } + ctx.MenuLines[6] = { MenuId = 0x1200, lineNum = 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==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[#4 T=L_m0 VId=0x1701 Text="FM Channel"[0x78] val=1 NL=(0->8,1,S=12) [12->20,13] MId=0x1300 ] + --L[#5 T=L_m0 VId=0x1702 Text="Gain Channel"[0x89] val=0 NL=(0->8,1,S=12)] [12->20,13] MId=0x1300 ] + --L[#6 T=L_m0 VId=0x1703 Text="Output Channel 6"[0x56] val=1 NL=(0->12,0,S=53) [53->65,53] MId=0x1300 ] + + ctx.Menu = { MenuId = 0x1300, TextId = 0xDE, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { MenuId = 0x1300, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0xD3, ValId = 0x1310 } + ctx.MenuLines[1] = { MenuId = 0x1300, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0xDD, ValId = 0x1360 } + ctx.MenuLines[4] = { MenuId = 0x1300, lineNum = 4, Type = LINE_TYPE.LIST_MENU0, TextId = 0x78, ValId = 0x1701, Min=12, Max=20, Def=13, Val=1 } + ctx.MenuLines[5] = { MenuId = 0x1300, lineNum = 5, Type = LINE_TYPE.LIST_MENU0, TextId = 0x89, ValId = 0x1702, Min=12, Max=20, Def=13, Val=0 } + ctx.MenuLines[6] = { MenuId = 0x1300, lineNum = 6, Type = LINE_TYPE.LIST_MENU0, TextId = 0x56, ValId = 0x1702, Min=53, Max=65, Def=53, Val=1 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1310) then + --M[Id=0x1310 P=0x0 N=0x0 B=0x1300 Text="Swashplate"[0xD3]] + --L[#0 T=M VId=0x1330 Text="Output Setup"[0x49] MId=0x1310 ] + --L[#1 T=M VId=0x1320 Text="AFR"[0xDF] MId=0x1310 ] + --L[#2 T=V_% VId=0x1311 Text="E-Ring"[0xE4] Val=100 [50->150,100] MId=0x1310 ] + --L[#3 T=V_% VId=0x1312 Text="Phasing"[0xE2] Val=0 [-45->45,0] MId=0x1310 ] + --L[#4 T=V_% VId=0x1313 Text="Decay"[0x208] Val=50 [0->100,50] MId=0x1310 ] + + ctx.Menu = { MenuId = 0x1310, TextId = 0xD3, PrevId = 0, NextId = 0, BackId = 0x1300 } + ctx.MenuLines[0] = { MenuId = 0x1310, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x49, ValId = 0x1330 } + ctx.MenuLines[1] = { MenuId = 0x1310, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0xDF, ValId = 0x1320 } + ctx.MenuLines[4] = { MenuId = 0x1310, lineNum = 4, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0xE4, ValId = 0x1311, Min=50, Max=150, Def=100, Val=100 } + ctx.MenuLines[5] = { MenuId = 0x1310, lineNum = 5, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0xE2, ValId = 0x1312, Min=-45, Max=45, Def=0, Val=0 } + ctx.MenuLines[6] = { MenuId = 0x1310, lineNum = 6, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x208, ValId = 0x1313, Min=0, Max=100, Def=50, Val=50 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1320) then + --M[Id=0x1320 P=0x0 N=0x0 B=0x1310 Text="AFR"[0xDF]] + --L[#0 T=V_% VId=0x1321 Text="Roll"[0x40] Val=-75 % [-127->127,-75] MId=0x1320 ] + --L[#1 T=V_% VId=0x1322 Text="Pitch"[0x41] Val=-75 % [-127->127,-75] MId=0x1320 ] + --L[#2 T=V_% VId=0x1323 Text="Collective"[0xE0] Val=45 % [5->127,45] MId=0x1320 ] + --L[#3 T=V_% VId=0x1324 Text="Differential"[0x45] Val=0 % [-25->25,0] MId=0x1320 ] + + ctx.Menu = { MenuId = 0x1320, TextId = 0xDF, PrevId = 0, NextId = 0, BackId = 0x1310 } + ctx.MenuLines[0] = { MenuId = 0x1320, lineNum = 0, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x40, ValId = 0x1321, Min=-127, Max=127, Def=-75, Val=-75 } + ctx.MenuLines[1] = { MenuId = 0x1320, lineNum = 1, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x41, ValId = 0x1322, Min=-127, Max=127, Def=-75, Val=-75 } + ctx.MenuLines[2] = { MenuId = 0x1320, lineNum = 2, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0xE0, ValId = 0x1323, Min=5, Max=127, Def=45, Val=45 } + ctx.MenuLines[3] = { MenuId = 0x1320, lineNum = 3, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x45, ValId = 0x1324, Min=-25, Max=25, Def=0, Val=0 } + + ctx.SelLine = 0 + 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 ] + + ctx.Menu = { MenuId = 0x1330, TextId = 0x49, PrevId = 0, NextId = 0, BackId = 0x1310 } + ctx.MenuLines[0] = { MenuId = 0x1330, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0xE1, ValId = 0x1331 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1331) then + --M[Id=0x1331 P=0x0 N=0x0 B=0x1330 Text="Subtrim"[0xE1]] + --L[#0 T=V_s16 VId=0x1332 Text="Output Channel 1"[0x51] Val=57 [-82->82,0] MId=0x1331 ] + --L[#1 T=V_s16 VId=0x1333 Text="Output Channel 2"[0x52] Val=-17 [-82->82,0] MId=0x1331 ] + --L[#2 T=V_s16 VId=0x1334 Text="Output Channel 3"[0x53] Val=-53 [-82->82,0] MId=0x1331 ] + + ctx.Menu = { MenuId = 0x1331, TextId = 0xE1, PrevId = 0, NextId = 0, BackId = 0x1330 } + ctx.MenuLines[0] = { MenuId = 0x1331, lineNum = 0, Type = LINE_TYPE.VALUE_NUM_SI16, TextId = 0x51, ValId = 0x1332, Min=-82, Max=82, Def=0, Val=57 } + ctx.MenuLines[1] = { MenuId = 0x1331, lineNum = 1, Type = LINE_TYPE.VALUE_NUM_SI16, TextId = 0x52, ValId = 0x1333, Min=-82, Max=82, Def=0, Val=-17 } + ctx.MenuLines[2] = { MenuId = 0x1331, lineNum = 2, Type = LINE_TYPE.VALUE_NUM_SI16, TextId = 0x53, ValId = 0x1334, Min=-82, Max=82, Def=0, Val=-53 } + + ctx.SelLine = 0 + 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 ] + + ctx.Menu = { MenuId = 0x1360, TextId = 0xDD, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { MenuId = 0x1360, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0x99, ValId = 0x1390 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1390) then + --M[Id=0x1390 P=0x0 N=0x0 B=0x1360 Text="Phasing"[0xE2]] + --L[#0 T=V_% VId=0x1311 Text="Left"[0xE7] Val=0 % [-45->45,0] MId=0x1390 ] + --L[#1 T=V_% VId=0x1312 Text="Right"[0xE8] Val=0 % [-45->45,0] MId=0x1390 ] + + ctx.Menu = { MenuId = 0x1390, TextId = 0xE2, PrevId = 0, NextId = 0, BackId = 0x1360 } + ctx.MenuLines[0] = { MenuId = 0x1390, lineNum = 0, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0xE2, ValId = 0x1311, Min=-45, Max=45, Def=0, Val=0 } + ctx.MenuLines[1] = { MenuId = 0x1390, lineNum = 1, Type = LINE_TYPE.VALUE_PERCENT, TextId = 0xE8, ValId = 0x1312,Min=-45, Max=45, Def=0, Val=0 } + + + ctx.SelLine = 0 + 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 ] + --L[#1 T=M VId=0x140 Text="Panic"[0x8B] MId=0x1400 ] + --L[#2 T=M VId=0x1420 Text="Attitude Trim"[0x1E6] MId=0x1400 ] + + ctx.Menu = { MenuId = 0x1400, TextId = 0xDA, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { MenuId = 0x1400, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0xDB, ValId = 0x1410 } + ctx.MenuLines[1] = { MenuId = 0x1400, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x8B, ValId = 0x140 } + ctx.MenuLines[2] = { MenuId = 0x1400, lineNum = 2, Type = LINE_TYPE.MENU, TextId = 0x1E6, ValId = 0x1420 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1410) then + -- M[Id=0x1410 P=0x0 N=0x0 B=0x1400 Text="Stability"[0xDB]] + --L[#0 T=V_i8 VId=0x1411 Text="Gain"[0x43] val=50 [5->200,50] MId=0x1410 ] + --L[#1 T=V_i8 VId=0x1412 Text="Envelope"[0x1E7] val=45 [5->90,45] MId=0x1410 ] + --L[#3 T=V_NC VId=0x1413 Text="FLIGHT MODE"[0x8000] val=1 [0->5,0] MId=0x1410 ] + --L[#4 T=L_m2 VId=0x1414 Text="Stability"[0xDB] val=1 NL=(0->1,1,S=1) [1->2,1] MId=0x1410 ] + + ctx.Menu = { MenuId = 0x1410, TextId = 0xDB, PrevId = 0, NextId = 0, BackId = 0x1400 } + ctx.MenuLines[0] = { MenuId = 0x1410, lineNum = 0, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x43, ValId = 0x1411, Min=0, Max=200, Def=50, Val=50 } + ctx.MenuLines[1] = { MenuId = 0x1410, lineNum = 1, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x1E7, ValId = 0x1412, Min=0, Max=90, Def=45, Val=45 } + ctx.MenuLines[3] = { MenuId = 0x1410, lineNum = 3, Type = LINE_TYPE.VALUE_NOCHANGING, TextId = 0x8000, ValId = 0x1413, Min=0, Max=5, Def=0, Val=1 } + ctx.MenuLines[4] = { MenuId = 0x1410, lineNum = 4, Type = LINE_TYPE.LIST_MENU2, TextId = 0xDB, ValId = 0x1414, Min=1, Max=2, Def=1, Val=1 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + + elseif (menuId==0x140) then + --M[Id=0x140 P=0x0 N=0x0 B=0x1400 Text="Panic"[0x8B]] + --L[#0 T=V_i8 VId=0x141 Text="Envelope"[0x1E7] val=30 [5->90,45] MId=0x140 ] + --L[#1 T=V_i8 VId=0x142 Text="Yaw"[0x42] val=30 [25->100,50] MId=0x140 ] + + ctx.Menu = { MenuId = 0x140, TextId = 0x8B, PrevId = 0, NextId = 0, BackId = 0x1400 } + ctx.MenuLines[0] = { MenuId = 0x140, lineNum = 0, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x1E7, ValId = 0x141, Min=5, Max=90, Def=45, Val=30 } + ctx.MenuLines[1] = { MenuId = 0x140, lineNum = 1, Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x1E7, ValId = 0x42, Min=25, Max=100, Def=50, Val=30 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1420) then + --M[Id=0x1420 P=0x0 N=0x0 B=0x1400 Text="Attitude Trim"[0x1E6]] + --L[#0 T=V_s16 VId=0x1421 Text="Roll"[0x40] val=274 [-850->850,450] MId=0x1420 ] + --L[#1 T=V_s16 VId=0x1422 Text="Pitch"[0x41] val=58 [-850->850,0] MId=0x1420 ] + + ctx.Menu = { MenuId = 0x1420, TextId = 0x1E6, PrevId = 0, NextId = 0, BackId = 0x1400 } + ctx.MenuLines[0] = { MenuId = 0x1420, lineNum = 0, Type = LINE_TYPE.VALUE_NUM_SI16, TextId = 0x1E7, ValId = 0x40, Min=-850, Max=850, Def=450, Val=274 } + ctx.MenuLines[1] = { MenuId = 0x1420, lineNum = 1, Type = LINE_TYPE.VALUE_NUM_SI16, TextId = 0x1E7, ValId = 0x41, Min=-850, Max=850, Def=0, Val=58 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1700) then + --M[Id=0x1700 P=0x0 N=0x0 B=0x1000 Text="System Setup"[0x86]] + --L[#0 T=M VId=0x17F0 Text="Calibrate Sensor"[0xC7] MId=0x1700 ] + --L[#1 T=M VId=0x17E0 Text="Factory Reset"[0x97] MId=0x1700 ] + + ctx.Menu = { MenuId = 0x1700, TextId = 0x86, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { MenuId = 0x1700, lineNum = 0, Type = LINE_TYPE.MENU, TextId = 0xC7, ValId = 0x17F0 } + ctx.MenuLines[1] = { MenuId = 0x1700, lineNum = 1, Type = LINE_TYPE.MENU, TextId = 0x97, ValId = 0x17E0 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x17E0) then + --M[Id=0x17E0 P=0x0 N=0x0 B=0x1700 Text="Factory Reset"[0x98]] + --[#3 T=M VId=0x17E1 Text="Apply"[0x90] MId=0x17E0 ] + + ctx.Menu = { MenuId = 0x17E0, TextId = 0x98, PrevId = 0, NextId = 0, BackId = 0x1700 } + ctx.MenuLines[3] = { MenuId = 0x17E0, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x17E1 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x17F0) then + --M[Id=0x17F0 P=0x0 N=0x0 B=0x1700 Text="Calibrate Sensor"[0xC7]] + --L[#3 T=M VId=0x17F1 Text="Begin"[0x91] MId=0x17F0 ] + + ctx.Menu = { MenuId = 0x17F0, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x1700 } + ctx.MenuLines[3] = { MenuId = 0x17F0, lineNum = 3, Type = LINE_TYPE.MENU, TextId = 0x91, ValId = 0x17F1 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + else + ctx.Menu = { MenuId = 0x0001, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu } + ctx.SelLine = dsmLib.BACK_BUTTON + end + + PostProcessMenu() +end + + + +local function loadMenu(menuId) + clearMenuLines() + local ctx = dsmLib.DSM_Context + + if (menuId==0x1000) then + --M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"] + --L[#0 T=M VId=0x1010 val=nil [0->0,3] Text="Gyro settings" MId=0x1000 ] + --L[#1 T=M VId=0x105E val=nil [0->0,2] Text="Other settings" MId=0x1000 ] + + ctx.Menu = { MenuId = 0x1000, Text = "RX SIMULATION", PrevId = 0, NextId = 0, BackId = 0, TextId=0 } + ctx.MenuLines[0] = { MenuId = 0x1000, lineNum = 0, Type = LINE_TYPE.MENU, Text = "AR631/AR637 (NEW)", ValId = 0x1001,TextId=0 } + ctx.MenuLines[1] = { MenuId = 0x1000, lineNum = 1, Type = LINE_TYPE.MENU, Text = "AR631/AR637 (INITIALIZED)", ValId = 0x1002, TextId=0 } + ctx.MenuLines[4] = { MenuId = 0x1000, lineNum = 4, Type = LINE_TYPE.MENU, Text = "FC6250HX", ValId = 0x1005, TextId=0 } + ctx.MenuLines[6] = { MenuId = 0x1000, lineNum = 6, Type = LINE_TYPE.MENU, Text = "EXIT Sim to Real RX", ValId = 0xFFFF, TextId=0 } -- Menu 0xFFFF to Exit Simulator + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1001) then + RX_Initialized = false + ctx.RX.Id = dsmLib.RX.AR631 + ctx.RX.Name = "AR631/AR637 -NEW-SIM" + ctx.RX.Version = "2.38.5" + dsmLib.Init_Text(ctx.RX.Id) + + RX_loadMenu = AR631_loadMenu + RX_loadMenu(0x01000) + elseif (menuId==0x1002) then + ctx.RX.Id = dsmLib.RX.AR631 + ctx.RX.Name = "AR631/AR637 -SIM" + ctx.RX.Version = "2.38.5" + dsmLib.Init_Text(ctx.RX.Id) + + RX_loadMenu = AR631_loadMenu + RX_loadMenu(0x01000) + elseif (menuId==0x1005) then + ctx.RX.Id = dsmLib.RX.FC6250HX + ctx.RX.Name = "FC6250HX-SIM" + ctx.RX.Version = "5.6.255" + dsmLib.Init_Text(ctx.RX.Id) + + RX_loadMenu = FC6250HX_loadMenu + RX_loadMenu(0x01000) + end +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 + + if ctx.Phase == PHASE.RX_VERSION then -- request RX version + ctx.RX.Name = "SIMULATOR" + ctx.RX.Version = "1.0.0" + ctx.Phase = PHASE.MENU_TITLE + + ctx.Refresh_Display = true + RX_loadMenu = loadMenu + + 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 ? + RX_loadMenu(0x01000) + else + RX_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 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 + 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 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 + ctx.Phase = PHASE.WAIT_CMD + + elseif ctx.Phase == PHASE.EXIT then + ctx.Phase=PHASE.EXIT_DONE + end +end + +------------------------------------------------------------------------------------------------------------ +-- Lib EXPORTS + +-- Export Constants +SimLib.PHASE = dsmLib.PHASE +SimLib.LINE_TYPE = dsmLib.LINE_TYPE +SimLib.RX = dsmLib.RX +SimLib.DISP_ATTR = dsmLib.DISP_ATTR + + +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 + +-- 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_Text_Img = dsmLib.Get_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.isFlightModeText = dsmLib.isFlightModeText + +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.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 diff --git a/Lua_scripts/DSMLIB/DsmFwPrgSIMLib.luac b/Lua_scripts/DSMLIB/DsmFwPrgSIMLib.luac new file mode 100644 index 0000000000000000000000000000000000000000..b1908516521868765e2a1f4621020e759740fab5 GIT binary patch literal 20481 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