From 68eab7796a1d7fcfb67a55d5e4cd5d53d83fa148 Mon Sep 17 00:00:00 2001 From: Frankie Arzu <32604366+frankiearzu@users.noreply.github.com> Date: Wed, 16 Nov 2022 00:46:25 -0600 Subject: [PATCH] #751 DSM Enhancements #751 DSM Forward Programming Enhancements (New GUI, etc) --- Lua_scripts/DSM FwdPrg_ETX_05.lua | 560 ++++++++++ Lua_scripts/DSM FwdPrg_OTX_05.lua | 393 +++++++ Lua_scripts/DSMLIB/DsmFwPrgLib.lua | 1374 ++++++++++++++++++++++++ Lua_scripts/DSMLIB/DsmFwPrgLib.luac | Bin 0 -> 32338 bytes Lua_scripts/DSMLIB/DsmFwPrgSIMLib.lua | 1075 ++++++++++++++++++ Lua_scripts/DSMLIB/DsmFwPrgSIMLib.luac | Bin 0 -> 21237 bytes Lua_scripts/DSMLIB/readme.txt | 45 + 7 files changed, 3447 insertions(+) create mode 100644 Lua_scripts/DSM FwdPrg_ETX_05.lua create mode 100644 Lua_scripts/DSM FwdPrg_OTX_05.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_ETX_05.lua b/Lua_scripts/DSM FwdPrg_ETX_05.lua new file mode 100644 index 0000000..5ff3344 --- /dev/null +++ b/Lua_scripts/DSM FwdPrg_ETX_05.lua @@ -0,0 +1,560 @@ +local toolName = "TNS|DSM Forward Prog v0.5 (EdgeTx) |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. # +---- # # +---- ######################################################################### + +-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module) +-- Rewrite/Enhancements By: Francisco Arzu + +local SIMULATION_ON = false -- FALSE: use real communication to DSM RX (DEFAULT), TRUE: use a simulated version of RX +local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log) +local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX + +local dsmLib +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_X_LINE_MENU = 30 +local LCD_X_LINE_TITLE = 30 +local LCD_X_LINE_VALUE = 230 +local LCD_X_LINE_DEBUG = 390 + +local LCD_Y_MENU_TITLE = 20 +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) + +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 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 = BLACK + -- Gray Out any other line except the one been edited + if (ctx.isEditing() and ctx.EditLine~=lineNum) then txtColor=LIGHTGREY end + return txtColor +end + +local function GUI_GetFrameColor(lineNum) -- Frame Color for Value/Menu Boxes + local ctx = DSM_Context + local txtColor = LIGHTGREY --ORANGE + -- Gray Out any other line except the one been edited + if (ctx.isEditing() and ctx.EditLine~=lineNum) then txtColor=LIGHTGREY 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 txtColor = GUI_GetTextColor(lineNum) + local frameColor = GUI_GetFrameColor(lineNum) + + if (inv) then + txtColor = WHITE + lcd.drawFilledRectangle(x-5, y-2, w, h, ORANGE) + 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, 350, LCD_Y_LINE_HEIGHT, line.Text,selected) + GUI_addTouchButton(x, y, 350, 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 = lcd.sizeText(line.Text)+4 + x = LCD_X_LINE_VALUE - tw -- Right + elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Center?? + local tw = 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 = lcd.sizeText(header)+4 + x = LCD_X_LINE_VALUE - tw -- Right + elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Centered + local tw = (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 = 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 + BLUE) end -- display debug Min/Max +end + +local function GUI_Display_Menu(menu) + local ctx = DSM_Context + local w= LCD_W-100 -- usable Width for the Menu/Lines + + -- Center Header + local tw = 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, DARKGREY) + lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text, WHITE + BOLD) -- orig MIDSIZE + + -- 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+BLUE) end -- Phase we are in + if (DEBUG_ON_LCD) then lcd.drawText(0,240,dsmLib.menu2String(menu),SMLSIZE+BLUE) 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, TITLE_BGCOLOR) + lcd.drawText(5, 0, header, MENU_TITLE_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+BLUE) 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 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 (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 + + 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 + +------------------------------------------------------------------------------------------------------------ +-- Init +local function DSM_Init() + 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/DSM FwdPrg_OTX_05.lua b/Lua_scripts/DSM FwdPrg_OTX_05.lua new file mode 100644 index 0000000..a3ce33f --- /dev/null +++ b/Lua_scripts/DSM FwdPrg_OTX_05.lua @@ -0,0 +1,393 @@ +local toolName = "TNS|DSM Forward Prog v0.5 (OTX 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_X_LINE_MENU = 10 +local LCD_X_LINE_TITLE = 10 +local LCD_X_LINE_VALUE = 230 +local LCD_X_LINE_DEBUG = 390 + +local LCD_Y_MENU_TITLE = 20 +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 + 7 * LCD_Y_LINE_HEIGHT + +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) + lcd.drawRectangle(x, y, w, h, LIGHTGREY) +end + +local function GUI_Display_Menu(menu) + local ctx = DSM_Context + local w= LCD_W-100 -- 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 + lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text,BOLD) -- orig MIDSIZE + + -- Back + if menu.BackId ~= 0 then + GUI_Diplay_Button(437-5,LCD_Y_MENU_TITLE,47,25,"Back",ctx.SelLine == dsmLib.BACK_BUTTON) + end + -- Next ? + if menu.NextId ~= 0 then + GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,25,"Next",ctx.SelLine == dsmLib.NEXT_BUTTON) + end + -- Prev? + if menu.PrevId ~= 0 then + GUI_Diplay_Button(0,LCD_Y_LOWER_BUTTONS,47,25,"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),SMLSIZE + BLUE) end -- Phase we are in + if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_MENU,240,dsmLib.menu2String(menu),SMLSIZE + BLUE) 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 + bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0 + if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align??? + local tw = openTx_lcd_sizeText(line.Text)+4 + x = LCD_X_LINE_VALUE - tw -- Right + elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Center?? + local tw = openTx_lcd_sizeText(line.Text) + x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text + end + end + + lcd.drawText(x,y, text, attr + bold) + +end +------------------------------------------------------------------------------------------------------------ +local function GUI_Display_Line_Value(lineNum, line, value, selected, editing) + local bold = 0 + + local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum) + local x = LCD_X_LINE_TITLE + + ---------- NAME Part + local header = line.Text + -- ONLY do this for Flight Mode (Right Align or Centered) + if (dsmLib.isFlightModeText(line.TextId)) then + -- Display Header + Value together + header = header .. " " .. value + + -- Flight mode display attributes + bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0 + + if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align + local tw = openTx_lcd_sizeText(header)+4 + x = LCD_X_LINE_VALUE - tw -- Right + elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Centered + local tw = openTx_lcd_sizeText(header) + x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text + end + else + -- No Flight Mode, no effects here + header = header .. ":" + end + + lcd.drawText(x, y, header, bold) -- 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) -- display value + end + + if (DEBUG_ON_LCD) then lcd.drawText(LCD_X_LINE_DEBUG,y, line.MinMaxDebug or "", SMLSIZE) end -- display debug +end +------------------------------------------------------------------------------------------------------------ +local function GUI_Display() + local ctx = DSM_Context + lcd.clear() + + if LCD_W == 480 then + 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 + lcd.drawFilledRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR) + lcd.drawText(5, 0, header, MENU_TITLE_COLOR) + --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(LCD_X_LINE_TITLE,255,dsmLib.menuLine2String(line),SMLSIZE+BLUE) 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_START+(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_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 + end + end + else + -- Different Resolution + 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 + +------------------------------------------------------------------------------------------------------------ +-- Init +local function DSM_Init() + 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/DSMLIB/DsmFwPrgLib.lua b/Lua_scripts/DSMLIB/DsmFwPrgLib.lua new file mode 100644 index 0000000..59f4a14 --- /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 safeMode = {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..187e740b9d5a6131792c2ad1c38ce249d284c351 GIT binary patch literal 32338 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 nAh?P@%eh@j>;PZj0O+5?kuY_IF}~S0Ma9wCy4x 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..39e257b1ab2fe7f49ed6c2bc6840e19fcae608f4 GIT binary patch literal 21237 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