local toolName = "TNS|DSM Frwd Prog v0.56 (MIN)|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 VERSION = "v0.56" local LANGUAGE = "en" local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/" local LOG_FILE = "/LOGS/dsm_min_log.txt" local MSG_FILE = DSMLIB_PATH.."msg_fwdp_" .. LANGUAGE .. ".txt" local MSG_FILE_MIN = DSMLIB_PATH.."MIN_msg_fwdp_" .. LANGUAGE .. ".txt" local MSG_MIN_FILE_OFFSET = 20000 -- Phase local PH_INIT = 0 local PH_RX_VER, PH_TITLE, PH_TX_INFO, PH_LINES, PH_VALUES = 1, 2, 3, 4, 5 local PH_VAL_CHANGING, PH_VAL_EDITING, PH_VAL_EDIT_END = 6, 7, 8 local PH_WAIT_CMD, PH_EXIT_REQ, PH_EXIT_DONE = 9, 10, 11 -- Line Types local LT_MENU = 0x1C local LT_LIST_NC, LT_LIST_NC2, LT_LIST, LT_LIST_ORI, LT_LIST_TOG = 0x6C, 0x6D, 0x0C, 0xCC, 0x4C local LT_VALUE_NC = 0x60 local LT_VALUE_PERCENT, LT_VALUE_DEGREES = 0xC0, 0xE0 local Phase = PH_INIT local SendDataToRX = 1 -- Initiate Sending Data local Text = {} local List_Text = {} local List_Text_Img = {} local Flight_Mode = "Flight Mode" local RxName = {} local TXInactivityTime = 0 local RXInactivityTime = 0 local TX_Info_Step = 0 local TX_Info_Type = 0 local Change_Step = 0 local originalValue = 0 local TX_MAX_CH = 12 - 6 -- Number of Channels after Ch6 --local ctx = { local ctx_SelLine = 0 -- Current Selected Line local ctx_EditLine = nil -- Current Editing Line local ctx_CurLine = -1 -- Current Line Requested/Parsed via h message protocol local ctx_isReset = false -- false when starting from scracts, true when starting from Reset --} local MODEL = { modelName = "", -- The name of the model comming from OTX/ETX modelOutputChannel = {}, -- Output information from OTX/ETX TX_CH_TEXT= { }, PORT_TEXT = { }, DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script } local Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 } local MenuLines = {} local RX_Name = "" local RX_Version = "" local logFile = nil --local LCD_X_LINE_TITLE = 0 --local LCD_X_LINE_VALUE = 75 local LCD_W_BUTTONS = 19 local LCD_H_BUTTONS = 10 local LCD_X_MAX = 128 local LCD_X_RIGHT_BUTTONS = LCD_X_MAX - LCD_W_BUTTONS - 1 local LCD_Y_LINE_HEIGHT = 7 local LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2 local TEXT_ATTR = SMLSIZE local function gc() collectgarbage("collect") end --[[ local function gcTable(t) if type(t)=="table" then for i,v in pairs(t) do if type(v) == "table" then gcTable(v) end t[i] = nil end end gc() return t end --]] 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) end local function LOG_close() if (logFile ~= nil) then io.close(logFile) end end ----- Line Type local function isIncrementalValueUpdate(line) if (line.Type == LT_LIST_NC or line.Type == LT_LIST_NC2 or line.Type == LT_VALUE_NC or line.Type == LT_VALUE_DEGREES) then return false end return true end local function isSelectable(line) if (line.TextId == 0x00CD) then return true end -- Exceptiom: Level model and capture attitude if (line.Type == LT_MENU and line.ValId == line.MenuId) then return false end -- Menu to same page if (line.Type ~= LT_MENU and line.Max == 0) then return false end -- Read only data line if (line.Type ~= 0 and line.TextId < 0x8000) then return true end -- Not Flight Mode return false; end local function isListLine(line) return line.Type==LT_LIST_NC or line.Type==LT_LIST_NC2 or line.Type == LT_LIST or line.Type == LT_LIST_ORI or line.Type == LT_LIST_TOG end local function isEditing() return ctx_EditLine ~= nil end ---------------- DSM Values <-> Int16 Manipulation -------------------------------------------------------- local function int16_LSB(number) -- Less Significat byte 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 ----------------------- local function rtrim(s) local n = string.len(s) while n > 0 and string.find(s, "^%s", n) do n = n - 1 end return string.sub(s, 1, n) end local function GetTextInfoFromFile(pos) local f=MSG_FILE if (pos >= MSG_MIN_FILE_OFFSET) then -- Depending on offset, use the main, or MIN version f = MSG_FILE_MIN pos = pos - MSG_MIN_FILE_OFFSET end -- open and read File local dataFile = io.open(f, "r") io.seek(dataFile,pos) local buff = io.read(dataFile, 100) io.close(dataFile) local line="" local index="" local type="" local pipe=0 local comment=0 local newPos = pos -- Parse the line: -- Format: TT|0x999|Text -- Comment for i=1,#buff do newPos=newPos+1 local ch = string.sub(buff,i,i) if (pipe < 2 and ch=="|") then pipe=pipe+1 -- Count pipes pos (Type | Index | .....) elseif (ch=="/") then pipe=6 -- far right end, like comment elseif (ch=="\r") then -- Ignore CR elseif (ch=="\n") then break -- LF, end of line elseif (ch=="-") then -- March comments comment=comment+1 if (comment==2) then pipe=6 end -- Comment part of line else -- regular char comment=0 if (pipe==0) then type=type..ch -- in TT (Type) elseif (pipe==1) then index=index..ch -- in Index elseif (pipe<6) then line=line..ch end -- in Text end -- Regular char end -- Fpr gc() return type, index, rtrim(line), newPos end local function GetTextFromFile(pos) if (pos==nil) then return nil end local t,i,l, p = GetTextInfoFromFile(pos) return l end local function getTxChText(index) local ch = nil local out = nil if (index >= 0x000D and index <= 0x000D+7) then ch = index - 0x000D + 5 -- ch5 elseif (index >= 0x0036 and index <= 0x0036+11) then ch = index - 0x0036 end if (ch ~= nil) then out = "Ch"..(ch+1) .. " ("..(MODEL.TX_CH_TEXT[ch] or "--")..")" --out = MODEL.PORT_TEXT[ch] or "--" end return out end ----------------------- local function Get_Text(index) local pos = Text[index] local out = nil if (pos == nil) then out = string.format("Unknown_%X", index) else out = GetTextFromFile(pos) end if (index >= 0x8000) then out = Flight_Mode end return out end local function Get_Text_Value(index) local out = getTxChText(index) if (out) then return out end local pos = List_Text[index] if (pos == nil) then out = Get_Text(index) else out = GetTextFromFile(pos) end return out end --------------------- local function Get_RxName(index) local out = RxName[index] or string.format("Unknown_%X", index) return out end -------------------- local function updateValText(line) line.ValText = line.Val if (isListLine(line)) then line.ValText = Get_Text_Value(line.TextStart + line.Val) end end local function DSM_Connect() --Init TX buffer multiBuffer(3, 0x00) --Init RX buffer multiBuffer(10, 0x00) --Init telemetry multiBuffer(0, string.byte('D')) multiBuffer(1, string.byte('S')) multiBuffer(2, string.byte('M')) end local function DSM_Release() multiBuffer(0, 0) end -------------------- local function DSM_Send(...) local arg = { ... } for i = 1, #arg do multiBuffer(3 + i, arg[i]) end multiBuffer(3, 0x70 + #arg) end --------------------- function ChangePhase(newPhase) Phase = newPhase SendDataToRX = 1 end local function Value_Add(dir) local line = MenuLines[ctx_SelLine] local origVal = line.Val local inc = dir if (not isListLine(line)) then -- List do slow inc local Speed = getRotEncSpeed() if Speed == ROTENC_MIDSPEED then inc = (5 * dir) elseif Speed == ROTENC_HIGHSPEED then inc = (15 * dir) end end line.Val = line.Val + inc if line.Val > line.Max then line.Val = line.Max elseif line.Val < line.Min then line.Val = line.Min end if (origVal~=line.Val) then -- Any changes? if (isIncrementalValueUpdate(line)) then -- Update RX value on every change, otherwise, just at the end ChangePhase(PH_VAL_CHANGING) end updateValText(line) end end -------------- local function GotoMenu(menuId, lastSelectedLine) Menu.MenuId = menuId ctx_SelLine = lastSelectedLine -- Request to load the menu Again ChangePhase(PH_TITLE) end local function DSM_HandleEvent(event) if event == EVT_VIRTUAL_EXIT then if Phase == PH_RX_VER then Phase = PH_EXIT_DONE -- Exit program else if isEditing() then -- Editing a Line, need to restore original value MenuLines[ctx_EditLine].Val = originalValue event = EVT_VIRTUAL_ENTER else if (Menu.BackId > 0 ) then -- Back?? ctx_SelLine = -1 --Back Button event = EVT_VIRTUAL_ENTER else ChangePhase(PH_EXIT_REQ) end end end end -- Exit if Phase == PH_RX_VER then return end -- nothing else to do if event == EVT_VIRTUAL_NEXT then if isEditing() then -- Editting? Value_Add(1) else if ctx_SelLine < 7 then -- On a regular line local num = ctx_SelLine -- Find the prev selectable for i = ctx_SelLine + 1, 6, 1 do local line = MenuLines[i] if isSelectable(line) then ctx_SelLine = i break end end if num == ctx_SelLine then -- No Selectable Line if Menu.NextId ~= 0 then ctx_SelLine = 7 -- Next elseif Menu.PrevId ~= 0 then ctx_SelLine = 8 -- Prev end end elseif Menu.PrevId ~= 0 then ctx_SelLine = 8 -- Prev end end return end if event == EVT_VIRTUAL_PREV then if isEditing() then -- In Edit Mode Value_Add(-1) else if ctx_SelLine == 8 and Menu.NextId ~= 0 then ctx_SelLine = 7 -- Next elseif ctx_SelLine > 0 then if ctx_SelLine > 6 then ctx_SelLine = 7 --NEXT end local num = ctx_SelLine -- Find Prev Selectable line for i = ctx_SelLine - 1, 0, -1 do local line = MenuLines[i] if isSelectable(line) then ctx_SelLine = i break end end if num == ctx_SelLine then -- No Selectable Line if (Menu.BackId > 0) then ctx_SelLine = -1 -- Back end end else ctx_SelLine = -1 -- Back end end return end if event == EVT_VIRTUAL_ENTER_LONG then if isEditing() then MenuLines[ctx_SelLine].Val = MenuLines[ctx_SelLine].Def ChangePhase(PH_VAL_CHANGING) end elseif event == EVT_VIRTUAL_ENTER then if ctx_SelLine == -1 then -- Back GotoMenu(Menu.BackId, 0x80) elseif ctx_SelLine == 7 then -- Next GotoMenu(Menu.NextId, 0x82) elseif ctx_SelLine == 8 then -- Prev GotoMenu(Menu.PrevId, 0x81) elseif ctx_SelLine >= 0 and MenuLines[ctx_SelLine].Type == LT_MENU then GotoMenu(MenuLines[ctx_SelLine].ValId, ctx_SelLine) -- ValId is the next menu else -- value entry if isEditing() then ctx_EditLine = nil -- Done Editting ChangePhase(PH_VAL_EDIT_END) else -- Start Editing ctx_EditLine = ctx_SelLine originalValue = MenuLines[ctx_SelLine].Val ChangePhase(PH_VAL_EDITING) end end end end ------------------------------------------------------------------------------------------------------------ local function SendTxInfo(portNo) -- TxInfo_Type=0 : AR636 Main Menu (Send port/Channel info + SubTrim + Travel) -- TxInfo_Type=1 : AR630-637 Famly Main Menu (Only Send Port/Channel usage Msg 0x20) -- TxInfo_Type=1F : AR630-637 Initial Setup/Relearn Servo Settings (Send port/Channel info + SubTrim + Travel +0x24/Unknown) if (TX_Info_Step == 0) then -- AR630 family: Both TxInfo_Type (ManinMenu=0x1, Other First Time Configuration = 0x1F) local info = MODEL.DSM_ChannelInfo[portNo] local b0, b1, b2 = info[0], info[1], info[2] DSM_Send(0x20, 0x06, portNo, portNo, b0,b1) LOG_write("TX:DSM_TxInfo_20(Port=#%d, (%02x, %02x) %s)\n", portNo, b0,b1,b2 or "") if (TX_Info_Type == 0x1F) then -- SmartRx TX_Info_Step = 1 elseif (TX_Info_Type == 0x00) then -- AR636 TX_Info_Step = 2 end elseif (TX_Info_Step == 1) then local info = MODEL.modelOutputChannel[portNo] local leftTravel = math.abs(math.floor(info.min/10)) local rightTravel = math.abs(math.floor(info.max/10)) DSM_Send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel) LOG_write("TX:DSM_TxInfo_Travel(Port=#%d,(L=%d - R=%d))\n", portNo,leftTravel,rightTravel) TX_Info_Step = 2 elseif (TX_Info_Step == 2) then -- Subtrim local b1,b2,b3,b4 = 0x00, 0x8E, 0x07, 0x72 -- (192-1904) if (portNo==0) then -- Thr b1,b2,b3,b4 = 0x00, 0x00, 0x07, 0xFF -- (0-2047) end DSM_Send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it. LOG_write("TX:DSM_TxInfo_SubTrim(Port=#%d)\n", portNo) if (TX_Info_Type == 0x00) then -- AR636 TX_Info_Step = 5 -- End Step else TX_Info_Step = 3 end elseif (TX_Info_Step == 3) then LOG_write("TX:DSM_TxInfo_24?(Port=#%d)\n", portNo) DSM_Send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown TX_Info_Step = 4 elseif (TX_Info_Step == 4) then LOG_write("TX:DSM_TxInfo_24?(Port=#%d)\n", portNo) DSM_Send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown TX_Info_Step = 5 elseif (TX_Info_Step == 5) then LOG_write("TX:DSM_TxInfo_END(Port=#%d)\n", portNo) DSM_Send(0x22, 0x04, 0x00, 0x00) TX_Info_Step = 0 -- Done!! end if (TX_Info_Step > 0) then SendDataToRX = 1 -- keep Transmitig end end local function DSM_SendUpdate(line) local valId = line.ValId local value = sInt16ToDsm(line.Val) LOG_write("TX:ChangeValue(VId=0x%04X,Val=%d)\n", valId, line.Val) DSM_Send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value)) -- send current values end local function DSM_SendValidate(line) local valId = line.ValId LOG_write("TX:ValidateValue(VId=0x%04X)\n", valId) DSM_Send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId)) end local function DSM_SendRequest() --LOG_write("DSM_SendRequest Phase=%d\n",Phase) -- Need to send a request local menuId = Menu.MenuId local menuLSB = int16_LSB(menuId) local menuMSB = int16_MSB(menuId) if Phase == PH_RX_VER then -- request RX version DSM_Send(0x11, 0x06, TX_MAX_CH, 0x14, 0x00, 0x00) LOG_write("TX:GetVersion(TX_MAX_CH=%d)\n",TX_MAX_CH+6) elseif Phase == PH_WAIT_CMD then -- keep connection open DSM_Send(0x00, 0x04, 0x00, 0x00) --LOG_write("TX:TxHb\n") elseif Phase == PH_TITLE then -- request menu title if menuId == 0 then -- very first menu only DSM_Send(0x12, 0x06, TX_MAX_CH, 0x14, 0x00, 0x00) else -- Any other menu DSM_Send(0x16, 0x06, menuMSB, menuLSB, 0x00, ctx_SelLine) if (menuId == 0x0001) then -- Executed Save&Reset menu Phase = PH_RX_VER ctx_isReset = true end end LOG_write("TX:GetMenu(M=0x%04X,L=%d)\n", menuId, ctx_SelLine) elseif Phase == PH_TX_INFO then -- TX Info SendTxInfo(ctx_CurLine) elseif Phase == PH_LINES then -- request menu lines if ctx_CurLine == -1 then DSM_Send(0x13, 0x04, menuMSB, menuLSB) -- GetFirstLine else DSM_Send(0x14, 0x06, menuMSB, menuLSB, 0x00, ctx_CurLine) -- line X end LOG_write("TX:GetNextLine(LastLine=%d)\n", ctx_CurLine) elseif Phase == PH_VALUES then -- request menu values local valId = MenuLines[ctx_CurLine].ValId DSM_Send(0x15, 0x06, menuMSB, menuLSB, int16_MSB(valId), int16_LSB(valId)) LOG_write("TX:GetNextValue(LastVId=0x%04X)\n", valId) elseif Phase == PH_VAL_EDITING then -- Editing a line (like a HB) local line = MenuLines[ctx_SelLine] DSM_Send(0x1A, 0x04, 0x00, ctx_SelLine) LOG_write("TX:EditingValueLine(L=%d)\n", ctx_SelLine) elseif Phase == PH_VAL_CHANGING then -- change value during editing local line = MenuLines[ctx_SelLine] if (Change_Step==0) then DSM_SendUpdate(line) if line.Type == LT_LIST then -- Incremental Validation?? Change_Step=1 end else -- Change_Step==1 DSM_SendValidate(line) Change_Step=0 end if (Change_Step==0) then Phase=PH_VAL_EDITING else SendDataToRX=1 end -- Done with change? elseif Phase == PH_VAL_EDIT_END then -- Done Editing line local line = MenuLines[ctx_SelLine] if (Change_Step==0) then DSM_SendUpdate(line) Change_Step=1 elseif (Change_Step==1) then DSM_SendValidate(line) Change_Step=2 else -- Change_Step==3 LOG_write("TX:EditValueEnd(L=%d)\n", ctx_SelLine) DSM_Send(0x1B, 0x04, 0x00, ctx_SelLine) Change_Step=0 end if (Change_Step==0) then Phase = PH_WAIT_CMD else SendDataToRX=1 end -- Done with change? elseif Phase == PH_EXIT_REQ then -- EXIT Request DSM_Send(0x1F, 0x02, 0xAA) LOG_write("TX:TX Exit Request\n") end end local function DSM_ProcessResponse() local cmd = multiBuffer(11) if cmd == 0x01 then -- read version RX_Name = Get_RxName(multiBuffer(13)) RX_Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) Menu.MenuId = 0 Phase = PH_TITLE LOG_write("RX:Version: %s %s\n", RX_Name, RX_Version) elseif cmd == 0x02 then -- read menu title local menu = 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, 6 do -- clear menu MenuLines[i] = { Type = 0 } end ctx_CurLine = -1 ctx_SelLine = -1 -- highlight Back LOG_write("RX:Menu: Mid=0x%04X \"%s\"\n", menu.MenuId, menu.Text) if (menu.MenuId == 0x0001) then -- Still in RESETTING MENU??? Phase = PH_RX_VER else Phase = PH_LINES end elseif cmd == 0x03 then -- read menu lines local i = multiBuffer(14) local type = multiBuffer(15) local line = MenuLines[i] ctx_CurLine = i 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 = Get_Text(line.TextId) line.ValId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19)) -- Signed int values line.Min = Dsm_to_SInt16(multiBuffer(20), multiBuffer(21)) line.Max = Dsm_to_SInt16(multiBuffer(22), multiBuffer(23)) line.Def = Dsm_to_SInt16(multiBuffer(24), multiBuffer(25)) if line.Type == LT_MENU then -- nothing to do on menu entries elseif isListLine(line) then line.Val = nil 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 line.Val = nil --line.Def -- use default value not sure if needed if (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) then line.Type = LT_VALUE_PERCENT -- Override to Value Percent end end if ctx_SelLine == -1 and isSelectable(line) then -- Auto select first selectable line of the menu ctx_SelLine = ctx_CurLine end LOG_write("RX:Line: #%d Vid=0x%04X T=0x%02X \"%s\"\n", i, line.ValId, type, line.Text) if (line.MenuId~=Menu.MenuId) then -- Going Back too fast: Stil receiving lines from previous menu Menu.MenuId = line.MenuId end Phase = PH_LINES elseif cmd == 0x04 then -- read menu values -- Identify the line and update the value local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) local value = Dsm_to_SInt16(multiBuffer(16), multiBuffer(17)) --Signed int --local updatedLine = nil for i = 0, 6 do -- Find the menu line for this value local line = MenuLines[i] if line.Type ~= 0 then if line.Type ~= LT_MENU and line.ValId == valId then -- identifier of ValueId stored in the line line.Val = value ctx_CurLine = i --updatedLine = line updateValText(line) local debugTxt = line.Val if isListLine(line) then debugTxt = line.ValText .. " [" .. value .. "]" end LOG_write("RX: Value Updated: #%d VId=0x%04X Value=%s\n", i, valId, debugTxt) break end end end --if (updatedLine == nil) then -- LOG_write("Cannot Find Line for ValueId=%x\n", valId) --end Phase = PH_VALUES elseif cmd == 0x05 then -- Request TX info ctx_CurLine = multiBuffer(12) TX_Info_Type = multiBuffer(13) TX_Info_Step = 0 Phase = PH_TX_INFO LOG_write("RX:TXInfoReq: Port=%d T=0x%02X\n", ctx_CurLine, TX_Info_Type) elseif cmd == 0xA7 then -- RX EXIT Request if Phase == PH_EXIT_REQ then -- Response to our EXIT req Phase = PH_EXIT_DONE else -- Unexpected RX Exit DSM_Release() error("RX Connection Drop") end elseif cmd == 0x00 then -- RX Heartbeat LOG_write("RX:RxHb\n") end return cmd end local function DSM_Send_Receive() -- Receive part: Process incoming messages if there is nothing to send if SendDataToRX==0 and multiBuffer(10) == 0x09 then local cmd = DSM_ProcessResponse() -- Data processed multiBuffer(10, 0x00) RXInactivityTime = getTime() + 800 -- Reset Inactivity timeout (8s) if (cmd > 0x00) then -- RX-HeartBeat?? -- Only change to SEND mode if we received a valid response (Ignore heartbeat) SendDataToRX = 1 end else -- Check if enouth time has passed from last Received activity if (getTime() > RXInactivityTime and Phase~=PH_RX_VER and Phase~= PH_EXIT_DONE) then if (isEditing()) then -- If Editing, extend time RXInactivityTime = getTime() + 400 else DSM_Release() error("RX Disconnected") end end end -- Sending part -- if SendDataToRX == 1 then SendDataToRX = 0 DSM_SendRequest() TXInactivityTime = getTime() + 200 -- Reset Inactivity timeout (2s) else -- Check if enouth time has passed from last transmit activity if getTime() > TXInactivityTime then SendDataToRX = 1 -- Switch to Send mode to send heartbeat -- Change to Idle/HB mode if we are wating for RX version if Phase ~= PH_RX_VER then -- Phase = If IsEditing then PH_VAL_EDITING else PH_WAIT_CMD Phase = (isEditing() and PH_VAL_EDITING) or PH_WAIT_CMD end end end end ----- local function showBitmap(x, y, imgDesc) local f = string.gmatch(imgDesc, '([^%|]+)') -- Iterator over values split by '|' local imgName, imgMsg = f(), f() f = string.gmatch(imgMsg or "", '([^%:]+)') -- Iterator over values split by ':' local p1, p2 = f(), f() lcd.drawText(x, y, p1 or "", TEXT_ATTR) -- Alternate Image MSG lcd.drawText(x, y + LCD_Y_LINE_HEIGHT, p2 or "", TEXT_ATTR) -- Alternate Image MSG end local function drawButton(x, y, text, active) local attr = TEXT_ATTR if (active) then attr = attr + INVERS end lcd.drawText(x, y, text, attr) end local ver_rx_count = 0 local function DSM_Display() lcd.clear() --Draw RX Menu if Phase == PH_RX_VER then lcd.drawText(1, 0, "DSM Frwd Prog "..VERSION, INVERS) local msgId = 0x300 -- Waiting for RX if (ctx_isReset) then msgId=0x301 end -- Waiting for Reset lcd.drawText(1, 3 * LCD_Y_LINE_HEIGHT, Get_Text(msgId), BLINK) return end -- display Program version or RX version local msg = RX_Name .. " v" .. RX_Version ver_rx_count = ver_rx_count + 1 if (ver_rx_count > 50) then msg = "FProg "..VERSION if (ver_rx_count > 100) then ver_rx_count=0 end end lcd.drawText(40, LCD_Y_LOWER_BUTTONS, msg, TEXT_ATTR) if Menu.MenuId == 0 then return end; -- No Title yet -- Got a Menu lcd.drawText(1, 0, Menu.Text, TEXT_ATTR + INVERS) if (Phase == PH_TX_INFO) then lcd.drawText(1, 3 * LCD_Y_LINE_HEIGHT, "Sending CH"..(ctx_CurLine+1), TEXT_ATTR) end local y = LCD_Y_LINE_HEIGHT + 2 for i = 0, 6 do local attrib = TEXT_ATTR if (i == ctx_SelLine) then attrib = attrib + INVERS end -- Selected Line local line = MenuLines[i] if line.Type ~= 0 then local heading = line.Text if (line.TextId >= 0x8000) then -- Flight mode heading = " " .. Flight_Mode .. " " if (line.Val==nil) then heading = heading .. "--" else heading = heading .. ((line.Val or 0) + 1) end else local text = nil if line.Type ~= LT_MENU then -- list/value if line.Val ~= nil then -- Value to display?? -- text = line.Val text = line.ValText if isListLine(line) then local textId = line.Val + line.TextStart --text = Get_Text_Value(textId) -- image?? local offset = 0 if (line.Type==LT_LIST_ORI) then offset = offset + 0x100 end --FH6250 hack local imgDesc = GetTextFromFile(List_Text_Img[textId+offset]) if (imgDesc and i == ctx_SelLine) then -- Optional Image and Msg for selected value showBitmap(1, 20, imgDesc) end end end -- Value if (ctx_EditLine == i) then -- Editing a Line attrib = BLINK + INVERS + TEXT_ATTR end lcd.drawText(LCD_X_MAX, y, text or "--", attrib + RIGHT) -- display value attrib = TEXT_ATTR end -- Line with value/list end -- not Flight mode lcd.drawText(1, y, heading, attrib) -- display text end y = y + LCD_Y_LINE_HEIGHT end -- for if Menu.BackId~=0 then drawButton(LCD_X_RIGHT_BUTTONS, 0, "Back", ctx_SelLine == -1) end if Menu.NextId~=0 then drawButton(LCD_X_RIGHT_BUTTONS, LCD_Y_LOWER_BUTTONS, "Next", ctx_SelLine == 7) end if Menu.PrevId~=0 then drawButton(1, LCD_Y_LOWER_BUTTONS, "Prev", ctx_SelLine == 8) end end ----------------------------------------------------------------------------------------- local function load_msg_from_file(fileName, offset, FileState) if (FileState.state==nil) then -- Initial State FileState.state=1 FileState.lineNo=0 FileState.filePos=0 end if FileState.state==1 then for l=1,10 do -- do 10 lines at a time local type, sIndex, text local lineStart = FileState.filePos type, sIndex, text, FileState.filePos = GetTextInfoFromFile(FileState.filePos+offset) --print(string.format("T=%s, I=%s, T=%s LS=%d, FP=%d",type,sIndex,text,lineStart, FileState.filePos)) if (lineStart==FileState.filePos) then -- EOF FileState.state=2 --EOF State return 1 end FileState.lineNo = FileState.lineNo + 1 type = rtrim(type) if (string.len(type) > 0 and string.len(sIndex) > 0) then local index = tonumber(sIndex) local filePos = lineStart + offset if (index == nil) then assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, FileState.lineNo, sIndex)) elseif (type == "T") then Text[index] = filePos elseif (type == "LT") then List_Text[index] = filePos elseif (type == "LI") then List_Text_Img[index] = filePos elseif (type == "FM") then Flight_Mode = text elseif (type == "RX") then RxName[index] = text else assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, FileState.lineNo, type)) end end gc() end -- for end -- if return 0 end ------------------------------------------------------------------------------------------------------------ -- Init local function DSM_Init() --LOG_open() --LOG_write("--- NEW SESSION\n") --DSM_Init_Model() --Set protocol to talk to multiBuffer(0, string.byte('D')) --test if value has been written if multiBuffer(0) ~= string.byte('D') then error("Not enough memory!") return 2 end if (LCD_W > 128) then TEXT_ATTR = 0 LCD_Y_LINE_HEIGHT = 25 LCD_X_MAX = 300 LCD_X_RIGHT_BUTTONS = LCD_X_MAX - 30 LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2 end Phase = PH_INIT end ----------------------------------------------------------------------------------------------------------- local initStep=0 local FileState = { lineNo=0 } local function Inc_Init() lcd.clear() lcd.drawText(1, 0, "Loading Msg file: "..(FileState.lineNo or 0)) if (initStep == 0) then if (load_msg_from_file(MSG_FILE, 0, FileState)==1) then initStep=1 FileState = {} end else Phase = PH_RX_VER -- Done Init DSM_Connect() end end ------------------------------------------------------------------------------------------------------------ -- Main local function DSM_Run(event) if event == nil then error("Cannot be run as a model script!") return 2 end if (Phase == PH_INIT) then Inc_Init() -- Incremental initialization return 0 end DSM_Display() DSM_HandleEvent(event) DSM_Send_Receive() gc() if Phase == PH_EXIT_DONE then DSM_Release() LOG_close() return 2 else return 0 end end --- gc() local M_DATA = {} -- Load Model Configuration local r = assert(loadScript(DSMLIB_PATH.."DsmMIN_P1.lua"), "Mising: DsmMIN_P1.lua") (MODEL, M_DATA, LOG_write) gc() if (r==1) then -- Translate model Configuration to DSMDATA local r = assert(loadScript(DSMLIB_PATH.."DsmMIN_P2.lua"), "Missing DsmMIN_P2.lua") (MODEL, M_DATA, LOG_write) MODEL.PORT_TEXT = nil --MODEL.TX_CH_TEXT = {} gc() else error("Cannot load Model Config") end M_DATA = nil gc() --- return { init = DSM_Init, run = DSM_Run }