mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-12-27 23:13:14 +00:00
Compare commits
12 Commits
01aef0a822
...
pascallang
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b26c20c54 | ||
|
|
ed2e2e4f32 | ||
|
|
b2f8f482bb | ||
|
|
89023d4b55 | ||
|
|
66ac007d4c | ||
|
|
139cd4c583 | ||
|
|
0fed2486f5 | ||
|
|
11c01004bf | ||
|
|
f49f03d7da | ||
|
|
90bb5f8871 | ||
|
|
401cc76f20 | ||
|
|
6297810edc |
@@ -1,5 +1,5 @@
|
||||
local toolName = "TNS|DSM Forward Prog v0.52 (Text B&W) |TNE"
|
||||
local VERSION = "v0.52"
|
||||
local toolName = "TNS|DSM Forward Prog v0.54 (Text B&W) |TNE"
|
||||
local VERSION = "v0.54"
|
||||
|
||||
|
||||
---- #########################################################################
|
||||
@@ -28,7 +28,7 @@ local VERSION = "v0.52"
|
||||
-- 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 SIMULATION_ON = false -- FALSE: don't show simulation menu (DEFAULT), TRUE: show simulation menu
|
||||
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
|
||||
local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
|
||||
|
||||
@@ -109,8 +109,12 @@ end
|
||||
|
||||
local function GUI_Diplay_Button(x,y,w,h,text,selected)
|
||||
local attr = (selected) and INVERS or 0 -- INVERS if line Selected
|
||||
lcd.drawText(x+5,y+2, text, attr + TEXT_SIZE)
|
||||
lcd.drawRectangle(x, y, w, h, LINE_COLOR)
|
||||
if (TEXT_SIZE~=SMLSIZE) then
|
||||
lcd.drawText(x+5,y+2, text, attr + TEXT_SIZE)
|
||||
lcd.drawRectangle(x, y, w, h, LINE_COLOR)
|
||||
else -- SMALL Screen
|
||||
lcd.drawText(x,y, text, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
|
||||
local function GUI_Display_Menu(menu)
|
||||
@@ -120,11 +124,9 @@ local function GUI_Display_Menu(menu)
|
||||
-- Center Header
|
||||
local tw = openTx_lcd_sizeText(menu.Text)
|
||||
local x = w/2 - tw/2 -- Center of Screen - Center of Text
|
||||
if (x < 0) then x=0 end -- in case text is too wide
|
||||
|
||||
local bold = 0
|
||||
if (TEXT_SIZE~=SMLSIZE) then -- Ignore Bold on small size screens
|
||||
bold = BOLD
|
||||
end
|
||||
local bold = BOLD
|
||||
lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text,bold + TEXT_SIZE)
|
||||
|
||||
-- Back
|
||||
@@ -154,17 +156,16 @@ local function GUI_Display_Line_Menu(x,y,w,h,line,selected)
|
||||
-- Menu Line
|
||||
text = text .. " >"
|
||||
else -- SubHeaders and plain text lines
|
||||
if (TEXT_SIZE~=SMLSIZE) then -- ignore bold on small size screens
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0
|
||||
end
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align???
|
||||
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??
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
||||
local tw = openTx_lcd_sizeText(line.Text)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
if (x < 0) then x=0 end -- in case text is too wide
|
||||
end
|
||||
|
||||
lcd.drawText(x,y, text, attr + bold + TEXT_SIZE)
|
||||
@@ -185,17 +186,16 @@ local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
||||
header = dsmLib.GetFlightModeValue(line)
|
||||
|
||||
-- Flight mode display attributes
|
||||
if (TEXT_SIZE~=SMLSIZE) then -- ignore bold on small size screens
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0
|
||||
end
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align
|
||||
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
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
||||
local tw = openTx_lcd_sizeText(header)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
if (x < 0) then x=0 end -- in case text is too wide
|
||||
else
|
||||
-- No Flight Mode, no effects here
|
||||
header = header .. ":"
|
||||
@@ -211,7 +211,7 @@ local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
||||
attrib = INVERS
|
||||
if editing then -- blink editing entry
|
||||
attrib = attrib + BLINK
|
||||
value = "[ " .. value .. " ]"
|
||||
value = "[" .. value .. "]"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -228,7 +228,14 @@ local function GUI_ShowBitmap(x,y,imgData)
|
||||
local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|'
|
||||
local imgName, imgMsg = f(), f()
|
||||
|
||||
lcd.drawText(x, y, imgMsg or "") -- Alternate Image MSG
|
||||
if (LCD_W > 128) then
|
||||
lcd.drawText(x, y, imgMsg or "", TEXT_SIZE) -- Alternate Image MSG
|
||||
else
|
||||
local f = string.gmatch(imgMsg, '([^%:]+)') -- Iterator over values split by ':'
|
||||
local msg1,msg2 = f(), f()
|
||||
lcd.drawText(x, y, (msg1 or "")..":", TEXT_SIZE) -- Alternate Image MSG
|
||||
lcd.drawText(x, y+10, msg2 or "", TEXT_SIZE) -- Alternate Image MSG
|
||||
end
|
||||
|
||||
-- NO IMAGES in Text B&W
|
||||
--local imgPath = IMAGE_PATH .. (imgName or "")
|
||||
@@ -242,23 +249,29 @@ end
|
||||
local function GUI_Display()
|
||||
local ctx = DSM_Context
|
||||
lcd.clear()
|
||||
local header = "DSM Fwrd Programming "
|
||||
|
||||
if (TEXT_SIZE==SMLSIZE) then -- Small Screen no title
|
||||
header = ""
|
||||
end
|
||||
|
||||
local header = "DSM Fwrd Programming "
|
||||
if ctx.Phase ~= PHASE.RX_VERSION then
|
||||
header = header .. "RX "..ctx.RX.Name.." v"..ctx.RX.Version
|
||||
header = header .. ctx.RX.Name.." v"..ctx.RX.Version
|
||||
end
|
||||
|
||||
--Draw title
|
||||
if (TEXT_SIZE~=SMLSIZE) then -- ignore tool title small size screens
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
||||
else -- Small Screen
|
||||
lcd.drawText(20, LCD_Y_LOWER_BUTTONS+1, header, TEXT_SIZE)
|
||||
end
|
||||
--Draw RX Menu
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
if (ctx.isReset) then
|
||||
lcd.drawText(LCD_X_LINE_TITLE,50,"Waiting for RX to Restart", BLINK + TEXT_SIZE)
|
||||
lcd.drawText(LCD_X_LINE_TITLE,50,dsmLib.Get_Text(0x301), BLINK + TEXT_SIZE) -- Resetting
|
||||
else
|
||||
lcd.drawText(LCD_X_LINE_TITLE,50,"No compatible DSM RX...", BLINK + TEXT_SIZE)
|
||||
lcd.drawText(LCD_X_LINE_TITLE,50,dsmLib.Get_Text(0x300), BLINK + TEXT_SIZE) -- Waiting for RX Version
|
||||
end
|
||||
else
|
||||
local menu = ctx.Menu
|
||||
@@ -377,11 +390,11 @@ local function GUI_HandleEvent(event, touchState)
|
||||
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,0)
|
||||
dsmLib.GotoMenu(menu.BackId,0x80)
|
||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
||||
dsmLib.GotoMenu(menu.NextId,0)
|
||||
dsmLib.GotoMenu(menu.NextId,0x82)
|
||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
||||
dsmLib.GotoMenu(menu.PrevId,0)
|
||||
dsmLib.GotoMenu(menu.PrevId,0x81)
|
||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then
|
||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Next menu exist
|
||||
if (menuLines[ctx.SelLine].ValId==0xFFF1) then
|
||||
@@ -402,6 +415,7 @@ local function GUI_HandleEvent(event, touchState)
|
||||
-- enter Edit the current line
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = menuLines[ctx.SelLine].Val
|
||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -422,20 +436,20 @@ local function init_screen_pos()
|
||||
TEXT_SIZE = SMLSIZE
|
||||
LCD_W_USABLE = 128
|
||||
|
||||
LCD_W_BUTTONS = 30
|
||||
LCD_H_BUTTONS = 17
|
||||
LCD_X_RIGHT_BUTTONS = 128 - LCD_W_BUTTONS - 5
|
||||
LCD_W_BUTTONS = 16
|
||||
LCD_H_BUTTONS = 10
|
||||
LCD_X_RIGHT_BUTTONS = 128 - LCD_W_BUTTONS - 3
|
||||
|
||||
LCD_X_LINE_MENU = 0
|
||||
-- X offsets for (Title: [Value] debugInfo) lines
|
||||
LCD_X_LINE_TITLE = 0
|
||||
LCD_X_LINE_VALUE = 90
|
||||
LCD_X_LINE_VALUE = 75
|
||||
LCD_X_LINE_DEBUG = 110
|
||||
|
||||
LCD_Y_LINE_HEIGHT = 17
|
||||
LCD_Y_LINE_HEIGHT = 7
|
||||
LCD_Y_MENU_TITLE = 0
|
||||
LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 17
|
||||
LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + 7 * LCD_Y_LINE_HEIGHT
|
||||
LCD_Y_LINE_FIRST = LCD_Y_MENU_TITLE + 8
|
||||
LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_FIRST + (7 * LCD_Y_LINE_HEIGHT)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -443,20 +457,32 @@ local function GUI_Warning(event)
|
||||
lcd.clear()
|
||||
local header = "DSM Forward Programming "..VERSION.." "
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, TITLE_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
||||
if (LCD_W > 128) then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 17, TITLE_BGCOLOR)
|
||||
lcd.drawText(5, 0, header, MENU_TITLE_COLOR + TEXT_SIZE)
|
||||
|
||||
lcd.drawText(100,20,"INFO", BOLD)
|
||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", 0)
|
||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", 0)
|
||||
lcd.drawText(5,80,"the TX before your start programming your RX.", 0)
|
||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", 0)
|
||||
lcd.drawText(100,20,"INFO", BOLD)
|
||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", TEXT_SIZE)
|
||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", TEXT_SIZE)
|
||||
lcd.drawText(5,80,"the TX before your start programming your RX.", TEXT_SIZE)
|
||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", TEXT_SIZE)
|
||||
|
||||
lcd.drawText(5,150,"TX Servo settings are sent to the RX during 'Initial Setup'", 0)
|
||||
lcd.drawText(5,170,"as well as when using RX menu 'Relearn Servo Settings'", 0)
|
||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD)
|
||||
lcd.drawText(5,150,"TX Servo settings are sent to the RX during 'Initial Setup'", TEXT_SIZE)
|
||||
lcd.drawText(5,170,"as well as when using RX menu 'Relearn Servo Settings'", TEXT_SIZE)
|
||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD+TEXT_SIZE)
|
||||
|
||||
lcd.drawText(100,250," OK ", INVERS + BOLD)
|
||||
lcd.drawText(100,250," OK ", INVERS + BOLD + TEXT_SIZE)
|
||||
else
|
||||
lcd.drawText(0,15,"Make sure you setup your plane", TEXT_SIZE)
|
||||
lcd.drawText(0,22,"first. Wing and Tail type.", TEXT_SIZE)
|
||||
|
||||
lcd.drawText(0,30,"TX Servo settings are sent to ", TEXT_SIZE)
|
||||
lcd.drawText(0,37,"the RX during 'Initial Setup' and ", TEXT_SIZE)
|
||||
lcd.drawText(0,45,"ALWAYS TEST Gyro reactions", TEXT_SIZE)
|
||||
lcd.drawText(0,52,"before flying!!!", TEXT_SIZE)
|
||||
|
||||
lcd.drawText(10,0," OK ", INVERS + BOLD + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER then
|
||||
warningScreenON = false
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
local toolName = "TNS|DSM Forward Prog v0.52 (Color+Touch) |TNE"
|
||||
local VERSION = "v0.52"
|
||||
local toolName = "TNS|DSM Forward Prog v0.54 (Color+Touch) |TNE"
|
||||
local VERSION = "v0.54"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
@@ -27,7 +27,7 @@ local VERSION = "v0.52"
|
||||
-- Rewrite/Enhancements By: Francisco Arzu
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local SIMULATION_ON = true -- FALSE: use real communication to DSM RX (DEFAULT), TRUE: use a simulated version of RX
|
||||
local SIMULATION_ON = false -- FALSE:don't show simulation memu (DEFAULT), TRUE: show simulation menu
|
||||
local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log)
|
||||
local DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
|
||||
local USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX)
|
||||
@@ -210,12 +210,12 @@ local function GUI_Display_Line_Menu(lineNum,line,selected)
|
||||
-- Non Selectable Menu Lines, plain text
|
||||
-- Can be use for sub headers or just regular text lines (like warnings)
|
||||
|
||||
local bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0
|
||||
local bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align???
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align???
|
||||
local tw = my_lcd_sizeText(line.Text)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Center??
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center??
|
||||
local tw = my_lcd_sizeText(line.Text)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
@@ -240,12 +240,12 @@ local function GUI_Display_Line_Value(lineNum, line, value, selected, editing)
|
||||
header = dsmLib.GetFlightModeValue(line)
|
||||
|
||||
-- Bold Text???
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.BOLD) and BOLD) or 0
|
||||
bold = (dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0
|
||||
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.RIGHT) then -- Right Align
|
||||
if dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align
|
||||
local tw = my_lcd_sizeText(header)+4
|
||||
x = LCD_X_LINE_VALUE - tw -- Right
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR.CENTER) then -- Centered
|
||||
elseif dsmLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered
|
||||
local tw = my_lcd_sizeText(header)
|
||||
x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text
|
||||
end
|
||||
@@ -385,9 +385,9 @@ local function GUI_Display()
|
||||
--Draw RX Menu
|
||||
if ctx.Phase == PHASE.RX_VERSION then
|
||||
if (ctx.isReset) then
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,"Waiting for RX to Restart", BLINK)
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x301), BLINK) -- Waiting for Restart
|
||||
else
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,"No compatible DSM RX...", BLINK)
|
||||
lcd.drawText(LCD_X_LINE_TITLE,100,dsmLib.Get_Text(0x300), BLINK) -- Waiting for RX
|
||||
end
|
||||
else
|
||||
local menu = ctx.Menu
|
||||
@@ -567,11 +567,11 @@ local function GUI_HandleEvent(event, touchState)
|
||||
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,0)
|
||||
dsmLib.GotoMenu(menu.BackId,0x80)
|
||||
elseif ctx.SelLine == dsmLib.NEXT_BUTTON then -- Next
|
||||
dsmLib.GotoMenu(menu.NextId,0)
|
||||
dsmLib.GotoMenu(menu.NextId,0x82)
|
||||
elseif ctx.SelLine == dsmLib.PREV_BUTTON then -- Prev
|
||||
dsmLib.GotoMenu(menu.PrevId,0)
|
||||
dsmLib.GotoMenu(menu.PrevId,0x81)
|
||||
elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value
|
||||
|
||||
if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Navigate to Menu
|
||||
@@ -590,6 +590,7 @@ local function GUI_HandleEvent(event, touchState)
|
||||
else -- Edit the current value
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = menuLines[ctx.SelLine].Val
|
||||
dsmLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -635,11 +636,11 @@ local function GUI_Warning(event,touchState)
|
||||
lcd.drawText(100,20,"INFO", BOLD)
|
||||
lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", 0)
|
||||
lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", 0)
|
||||
lcd.drawText(5,80,"the TX before your start programming your RX.", 0)
|
||||
lcd.drawText(5,80,"the TX before your start Fwrd programming your RX.", 0)
|
||||
lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", 0)
|
||||
|
||||
lcd.drawText(5,150,"TX Servo settings are sent to the RX during 'Initial Setup'", 0)
|
||||
lcd.drawText(5,170,"as well as when using RX menu 'Relearn Servo Settings'", 0)
|
||||
lcd.drawText(5,150,"TX Gyro Servo settings are sent to the RX during 'Initial Setup'", 0)
|
||||
lcd.drawText(5,170,"as well as when using RX 'Relearn Servo Settings'", 0)
|
||||
lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD)
|
||||
|
||||
lcd.drawText(100,250," OK ", INVERS + BOLD)
|
||||
|
||||
932
Lua_scripts/DSM FwdPrg_05_MIN.lua
Normal file
932
Lua_scripts/DSM FwdPrg_05_MIN.lua
Normal file
@@ -0,0 +1,932 @@
|
||||
local toolName = "TNS|DSM Frwd Prog v0.54-beta (MIN)|TNE"
|
||||
|
||||
--local ModelParam = ...
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # 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. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for DSM description
|
||||
-- Multi_Buffer[0..2]=="DSM" -> Lua script is running
|
||||
-- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent
|
||||
-- Multi_Buffer[4..9]=6 bytes of TX to RX data
|
||||
-- Multi_Buffer[10..25]=16 bytes of RX to TX data
|
||||
--
|
||||
-- To start operation:
|
||||
-- Write 0x00 at address 3
|
||||
-- Write 0x00 at address 10
|
||||
-- Write "DSM" at address 0..2
|
||||
--###############################################################################
|
||||
|
||||
local VERSION = "v0.54-MIN"
|
||||
local 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"
|
||||
|
||||
-- Phase
|
||||
local PH_RX_VER, PH_TITLE, PH_TX_INFO, PH_LINES, PH_VALUES = 1, 2, 3, 4, 5
|
||||
local PH_VAL_CHANGING, PH_VAL_WAIT, PH_VAL_CHNG_END = 6, 7, 8
|
||||
local PH_WAIT_CMD, PH_EXIT_REQ, PH_EXIT_DONE = 9, 10, 11
|
||||
|
||||
-- Line Types
|
||||
local LT_MENU = 0x1C
|
||||
local LT_LIST, LT_LIST_VALIDATE, LT_LIST_TOG = 0x6C, 0x0C, 0x4C
|
||||
local LT_VALUE_NOCHANGING = 0x60
|
||||
local LT_VALUE_PERCENT, LT_VALUE_DEGREES = 0xC0, 0xE0
|
||||
|
||||
local Phase = PH_RX_VER
|
||||
local Waiting_RX = 0
|
||||
|
||||
local Text = {}
|
||||
local List_Text = {}
|
||||
local List_Text_Img = {}
|
||||
local Flight_Mode = { [0] = "Flight Mode" }
|
||||
local RxName = {}
|
||||
|
||||
local InactivityTime = 0
|
||||
local Value_Change_Step = 0
|
||||
local TX_Info_Step = 0
|
||||
local TX_Info_Type = 0
|
||||
local originalValue = 0
|
||||
|
||||
local ctx = {
|
||||
SelLine = 0, -- Current Selected Line
|
||||
EditLine = nil, -- Current Editing Line
|
||||
CurLine = -1, -- Current Line Requested/Parsed via h message protocol
|
||||
isReset = false -- false when starting from scracts, true when starting from Reset
|
||||
}
|
||||
|
||||
local MODEL = {
|
||||
modelName = "", -- The name of the model comming from OTX/ETX
|
||||
modelOutputChannel = {}, -- Output information from OTX/ETX
|
||||
AirWingTailDesc = "",
|
||||
|
||||
--TX_CH_TEXT = {},
|
||||
--PORT_TEXT = {},
|
||||
DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script
|
||||
}
|
||||
|
||||
local Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 }
|
||||
local MenuLines = {}
|
||||
local RX = { Name = "", Version = "" }
|
||||
|
||||
local logFile = nil
|
||||
local logCount = 0
|
||||
|
||||
local LCD_X_LINE_TITLE = 0
|
||||
local LCD_X_LINE_VALUE = 75
|
||||
|
||||
local LCD_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 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
|
||||
|
||||
---------------- 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 Get_Text(index)
|
||||
local out = Text[index] or string.format("Unknown_%X", index)
|
||||
if (index >= 0x8000) then
|
||||
out = Flight_Mode[0]
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
local function Get_Text_Value(index)
|
||||
local out = List_Text[index] or Get_Text(index)
|
||||
return out
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function Get_RxName(index)
|
||||
local out = RxName[index] or string.format("Unknown_%X", index)
|
||||
return out
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function DSM_Release()
|
||||
multiBuffer(0, 0)
|
||||
Phase = PH_EXIT_DONE
|
||||
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
|
||||
Waiting_RX = 0
|
||||
end
|
||||
|
||||
local function Value_Add(dir)
|
||||
local line = MenuLines[ctx.SelLine]
|
||||
|
||||
Speed = getRotEncSpeed()
|
||||
if Speed == ROTENC_MIDSPEED then
|
||||
line.Val = line.Val + (5 * dir)
|
||||
elseif Speed == ROTENC_HIGHSPEED then
|
||||
line.Val = line.Val + (15 * dir)
|
||||
else
|
||||
line.Val = line.Val + dir
|
||||
end
|
||||
|
||||
if line.Val > line.Max then
|
||||
line.Val = line.Max
|
||||
elseif line.Val < line.Min then
|
||||
line.Val = line.Min
|
||||
end
|
||||
|
||||
ChangePhase(PH_VAL_CHANGING)
|
||||
Value_Change_Step = 0
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local function GotoMenu(menuId, lastSelectedLine)
|
||||
Menu.MenuId = menuId
|
||||
ctx.SelLine = lastSelectedLine
|
||||
-- Request to load the menu Again
|
||||
ChangePhase(PH_TITLE)
|
||||
end
|
||||
|
||||
local function isSelectable(line)
|
||||
if (line.TextId == 0x00CD) then return true end -- Exceptiom: Level model and capture attitude
|
||||
if (line.Type == LT_MENU and line.ValId == line.MenuId) then return false end -- Menu to same page
|
||||
if (line.Type ~= LT_MENU and line.Max == 0) then return false end -- Read only data line
|
||||
if (line.Type ~= 0 and line.TextId < 0x8000) then return true end -- Not Flight Mode
|
||||
return false;
|
||||
end
|
||||
|
||||
local function isListLine(line)
|
||||
return line.Type==LT_LIST or line.Type == LT_LIST_VALIDATE or line.Type == LT_LIST_TOG
|
||||
end
|
||||
|
||||
local function DSM_Menu(event)
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if Phase == PH_RX_VER then
|
||||
DSM_Release() -- Exit program
|
||||
else
|
||||
if ctx.EditLine ~= nil then -- Editing a Line, need to restore original value
|
||||
MenuLines[ctx.EditLine].Val = originalValue
|
||||
event = EVT_VIRTUAL_ENTER
|
||||
else
|
||||
ChangePhase(PH_EXIT_REQ)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Phase == PH_RX_VER then return end -- nothing else to do
|
||||
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
if ctx.EditLine ~= nil then
|
||||
Value_Add(1)
|
||||
else
|
||||
-- not changing a value
|
||||
|
||||
if ctx.SelLine < 7 then -- On a regular line
|
||||
local num = ctx.SelLine -- Find the prev selectable
|
||||
for i = ctx.SelLine + 1, 6, 1 do
|
||||
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
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
if ctx.EditLine ~= nil 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
|
||||
elseif event == EVT_VIRTUAL_ENTER_LONG then
|
||||
if ctx.EditLine ~= nil then
|
||||
-- reset the value to default
|
||||
--if MenuLines[ctx.SelLine].Type ~= LIST_MENU_NOCHANGING then
|
||||
MenuLines[ctx.SelLine].Val = MenuLines[ctx.SelLine].Def
|
||||
ChangePhase(PH_VAL_CHANGING)
|
||||
Value_Change_Step = 0
|
||||
--end
|
||||
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 ctx.EditLine ~= nil then
|
||||
ctx.EditLine = nil -- Done Editting
|
||||
Value_Change_Step = 0
|
||||
ChangePhase(PH_VAL_CHNG_END)
|
||||
else -- Start Editing
|
||||
ctx.EditLine = ctx.SelLine
|
||||
originalValue = MenuLines[ctx.SelLine].Val
|
||||
ChangePhase(PH_VAL_WAIT)
|
||||
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]
|
||||
DSM_Send(0x20, 0x06, portNo, portNo, info[0],info[1])
|
||||
LOG_write("DSM_TxInfo_20(Port=#%d, Port Use)\n", portNo)
|
||||
|
||||
if (TX_Info_Type == 0x1F) then
|
||||
TX_Info_Step = 1
|
||||
elseif (TX_Info_Type == 0x00) then
|
||||
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("DSM_TxInfo_23(Port=#%d,ServoTravel(L=%d - R=%d))\n", portNo,leftTravel,rightTravel)
|
||||
|
||||
TX_Info_Step = 2
|
||||
elseif (TX_Info_Step == 2) then
|
||||
local data = {[0]= -- Start at 0
|
||||
{[0]= 0x0, 0x00, 0x07, 0xFF }, -- Ch1 Thr: 0 00 07 FF Subtrim ??
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch2 Ail: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch3 Elev: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch4 Rud: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch5 Gear: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch6 Aux1: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch7 Aux2: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch8 Aux3: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch9 Aux4: 0 8E 07 72 Subtrim 0
|
||||
{[0]= 0x0, 0x8E, 0x07, 0x72 }, -- Ch10 Aux5: 0 8E 07 72 Subtrim 0
|
||||
}
|
||||
local info = data[portNo]
|
||||
local b1,b2,b3,b4 = info[0], info[1], info[2], info[3]
|
||||
|
||||
DSM_Send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it.
|
||||
LOG_write("DSM_TxInfo_21(Port=#%d, SubTrim)\n", portNo)
|
||||
|
||||
if (TX_Info_Type == 0x00) then
|
||||
TX_Info_Step = 5 -- End Step
|
||||
else
|
||||
TX_Info_Step = 3
|
||||
end
|
||||
elseif (TX_Info_Step == 3) then
|
||||
LOG_write("DSM_TxInfo_24?(Port=#%d)\n", portNo)
|
||||
DSM_Send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown
|
||||
TX_Info_Step = 4
|
||||
elseif (TX_Info_Step == 4) then
|
||||
LOG_write("DSM_TxInfo_24?(Port=#%d)\n", portNo)
|
||||
DSM_Send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown
|
||||
TX_Info_Step = 5
|
||||
elseif (TX_Info_Step == 5) then
|
||||
LOG_write("DSM_TxInfo_22(Port=#%d, END of Data)\n", portNo)
|
||||
DSM_Send(0x22, 0x04, 0x00, 0x00)
|
||||
TX_Info_Step = 0 -- Done!!
|
||||
end
|
||||
|
||||
if (TX_Info_Step > 0) then
|
||||
Waiting_RX = 0 -- keep Transmitig
|
||||
end
|
||||
end
|
||||
|
||||
local function DSM_SendRequest()
|
||||
--LOG_write("DSM_SendRequest Phase=%d\n",Phase)
|
||||
-- Need to send a request
|
||||
if Phase == PH_RX_VER then -- request RX version
|
||||
DSM_Send(0x11, 0x06, 0x00, 0x14, 0x00, 0x00)
|
||||
LOG_write("GetVersion()\n")
|
||||
elseif Phase == PH_WAIT_CMD then -- keep connection open
|
||||
DSM_Send(0x00, 0x04, 0x00, 0x00)
|
||||
elseif Phase == PH_TITLE then -- request menu title
|
||||
local menuId = Menu.MenuId
|
||||
if menuId == 0 then
|
||||
DSM_Send(0x12, 0x06, 0x00, 0x14, 0x00, 0x00) -- first menu only
|
||||
else
|
||||
DSM_Send(0x16, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, ctx.SelLine)
|
||||
if (menuId == 0x0001) then -- Executed Save&Reset menu
|
||||
Phase = PH_RX_VER
|
||||
ctx.isReset = true
|
||||
end
|
||||
end
|
||||
LOG_write("GetMenu(M=0x%04X,L=%d)\n", menuId, ctx.SelLine)
|
||||
elseif Phase == PH_TX_INFO then -- TX Info
|
||||
SendTxInfo(ctx.CurLine)
|
||||
elseif Phase == PH_LINES then -- request menu lines
|
||||
local menuId = Menu.MenuId
|
||||
if ctx.CurLine == -1 then
|
||||
DSM_Send(0x13, 0x04, int16_MSB(menuId), int16_LSB(menuId)) -- GetFirstLine
|
||||
else
|
||||
DSM_Send(0x14, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, ctx.CurLine) -- line X
|
||||
end
|
||||
LOG_write("GetLines(LastLine=%d)\n", ctx.CurLine)
|
||||
elseif Phase == PH_VALUES then -- request menu values
|
||||
local menuId = Menu.MenuId
|
||||
local valId = MenuLines[ctx.CurLine].ValId
|
||||
DSM_Send(0x15, 0x06,
|
||||
int16_MSB(menuId), int16_LSB(menuId),
|
||||
int16_MSB(valId), int16_LSB(valId))
|
||||
LOG_write("GetValues(LastVId=0x%04X)\n", valId)
|
||||
elseif Phase == PH_VAL_CHANGING then -- send new value: Two steps, Update & Validate
|
||||
local line = MenuLines[ctx.SelLine]
|
||||
local valId = line.ValId
|
||||
if Value_Change_Step == 0 then
|
||||
local value = sInt16ToDsm(line.Val)
|
||||
DSM_Send(0x18, 0x06,
|
||||
int16_MSB(valId), int16_LSB(valId),
|
||||
int16_MSB(value), int16_LSB(value)) -- send current values
|
||||
LOG_write("ChangeValue(VId=0x%04X,Val=%d)\n", valId, value)
|
||||
|
||||
if line.Type == LT_LIST_VALIDATE then -- Incremental Validation??
|
||||
Value_Change_Step = 1
|
||||
Waiting_RX = 0 -- Do SEND in the next step
|
||||
end
|
||||
else
|
||||
-- Validate Value
|
||||
DSM_Send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId))
|
||||
Value_Change_Step = 0
|
||||
Phase = PH_VAL_WAIT
|
||||
LOG_write("ValidateValue(VId=0x%04X)\n", valId)
|
||||
end
|
||||
elseif Phase == PH_VAL_CHNG_END then
|
||||
DSM_Send(0x1B, 0x04, 0x00, int16_LSB(ctx.SelLine))
|
||||
Value_Change_Step = 0
|
||||
Phase = PH_WAIT_CMD
|
||||
LOG_write("ValueChangeEnd(L=%d)\n", ctx.SelLine)
|
||||
elseif Phase == PH_VAL_WAIT then
|
||||
-- Value Changing Wait
|
||||
DSM_Send(0x1A, 0x04, 0x00, int16_LSB(ctx.SelLine))
|
||||
LOG_write("ValueChangeWait(L=%d)\n", ctx.SelLine)
|
||||
elseif Phase == PH_EXIT_REQ then -- EXIT Request
|
||||
DSM_Send(0x1F, 0x02, 0xAA)
|
||||
end
|
||||
end
|
||||
|
||||
local function DSM_ProcessResponse()
|
||||
local cmd = multiBuffer(11)
|
||||
-- LOG_write("DSM_ProcessResponse BEGIN: Cmd=%x\n",cmd)
|
||||
if cmd == 0x01 then -- read version
|
||||
RX.Name = Get_RxName(multiBuffer(13))
|
||||
RX.Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16)
|
||||
--ctx.isReset = false -- no longer resetting
|
||||
Menu.MenuId = 0
|
||||
Phase = PH_TITLE
|
||||
LOG_write("Version: %s %s\n", RX.Name, RX.Version)
|
||||
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] = { MenuId = 0, Type = 0, TextId = 0, ValId = 0, Min = 0, Max = 0, Def = 0, Val = nil, Unit, Step }
|
||||
end
|
||||
ctx.CurLine = -1
|
||||
ctx.SelLine = -1 -- highlight Back
|
||||
|
||||
LOG_write("Menu: Mid=0x%04X \"%s\"\n", menu.MenuId, menu.Text)
|
||||
|
||||
if (menu.MenuId == 0x0001) then -- Still in RESETTING MENU???
|
||||
--menu.MenuId = 0
|
||||
Phase = PH_RX_VER
|
||||
else
|
||||
Phase = PH_LINES
|
||||
end
|
||||
elseif cmd == 0x03 then -- read menu lines
|
||||
local i = multiBuffer(14)
|
||||
local type = multiBuffer(15)
|
||||
local line = MenuLines[i]
|
||||
|
||||
ctx.CurLine = i
|
||||
|
||||
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))
|
||||
|
||||
-- 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))
|
||||
|
||||
if line.Type == LT_MENU then
|
||||
-- nothing to do on menu entries
|
||||
elseif isListLine(line) then
|
||||
line.Val = nil --line.Def - line.Min -- use default value not sure if needed
|
||||
line.Def = line.Min -- pointer to the start of the list in Text
|
||||
line.Max = line.Max - line.Min -- 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("Line: #%d Vid=0x%04X T=0x%02X \"%s\"\n", i, line.ValId, type, line.Text)
|
||||
Phase = PH_LINES
|
||||
elseif cmd == 0x04 then -- read menu values
|
||||
-- Identify the line and update the value
|
||||
local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15))
|
||||
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
|
||||
|
||||
local valueTxt = value
|
||||
if isListLine(line) then
|
||||
valueTxt = Get_Text_Value(line.Def + value) .. " [" .. value .. "]"
|
||||
end
|
||||
|
||||
LOG_write("Update Value: #%d VId=0x%04X Value=%s\n", i, valId, valueTxt)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (updatedLine == nil) then
|
||||
LOG_write("Cannot Find Line for ValueId=%x\n", valId)
|
||||
end
|
||||
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("TXInfoReq: Port=%d T=0x%02X\n", ctx.CurLine, TX_Info_Type)
|
||||
elseif cmd == 0xA7 then -- answer to EXIT command
|
||||
DSM_Release()
|
||||
elseif cmd == 0x00 and Phase == PH_VAL_CHANGING then
|
||||
Phase = PH_VAL_WAIT
|
||||
end
|
||||
|
||||
--LOG_write("DSM_ProcessResponse END: Cmd=%x\n",cmd)
|
||||
return cmd
|
||||
end
|
||||
|
||||
|
||||
local function DSM_Send_Receive()
|
||||
if Waiting_RX == 0 then
|
||||
Waiting_RX = 1
|
||||
DSM_SendRequest()
|
||||
multiBuffer(10, 0x00);
|
||||
InactivityTime = getTime() + 200 -- Reset Inactivity timeout
|
||||
-- -- -- -- -- -- -- -- -- -- -- -- receive part -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
elseif multiBuffer(10) == 0x09 then
|
||||
local cmd = DSM_ProcessResponse()
|
||||
-- Data processed
|
||||
multiBuffer(10, 0x00)
|
||||
if (cmd > 0x00) then -- Any non NULL response
|
||||
-- Only change to SEND mode if we received a valid response (Ignore NULL Responses, that are really heartbeat i most cases)
|
||||
Waiting_RX = 0
|
||||
InactivityTime = getTime() + 200 -- Reset Inactivity timeout
|
||||
end
|
||||
else -- No Send or Receive,
|
||||
-- Check if enouth time has passed from last transmit/receive activity
|
||||
if getTime() > InactivityTime then
|
||||
InactivityTime = getTime() + 200
|
||||
Waiting_RX = 0 -- Switch to Send mode to send heartbeat
|
||||
|
||||
if Phase == PH_EXIT_REQ then
|
||||
DSM_Release()
|
||||
end
|
||||
|
||||
if Phase ~= PH_RX_VER and Phase ~= PH_VAL_WAIT then
|
||||
Phase = 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(0, 3 * LCD_Y_LINE_HEIGHT, Get_Text(msgId), BLINK)
|
||||
return
|
||||
end
|
||||
|
||||
-- display Program version or RX version
|
||||
local msg = RX.Name .. " v" .. RX.Version
|
||||
if (ver_rx_count < 100) then
|
||||
msg = RX.Name .. " v" .. RX.Version
|
||||
ver_rx_count = ver_rx_count + 1
|
||||
else
|
||||
msg = "Frwd Prog "..VERSION
|
||||
ver_rx_count = ver_rx_count + 1
|
||||
if (ver_rx_count > 200) then ver_rx_count=0 end
|
||||
end
|
||||
lcd.drawText(30, 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)
|
||||
|
||||
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 ~= nil and line.Type ~= 0 then
|
||||
local heading = Get_Text(line.TextId)
|
||||
|
||||
if (line.TextId >= 0x8000) then -- Flight mode
|
||||
heading = " " .. Flight_Mode[0] .. " "
|
||||
if (line.Val==nil) then heading = heading .. "--" else heading = heading .. ((line.Val or 0) + 1) end
|
||||
else
|
||||
local text = "-"
|
||||
if line.Type ~= LT_MENU then -- list/value
|
||||
if line.Val ~= nil then
|
||||
if isListLine(line) then
|
||||
local textId = line.Val + line.Def
|
||||
text = Get_Text_Value(textId)
|
||||
|
||||
local imgDesc = List_Text_Img[textId]
|
||||
|
||||
if (imgDesc and i == ctx.SelLine) then -- Optional Image and Msg for selected value
|
||||
showBitmap(0, 20, imgDesc)
|
||||
end
|
||||
elseif (line.Type == LT_VALUE_PERCENT) then
|
||||
text = line.Val .. " %"
|
||||
elseif (line.Type == LT_VALUE_DEGREES) then
|
||||
text = line.Val .. " @"
|
||||
else
|
||||
text = line.Val
|
||||
end
|
||||
end -- if is Value
|
||||
|
||||
if (ctx.EditLine == i) then -- Editing a Line
|
||||
attrib = BLINK + INVERS + TEXT_ATTR
|
||||
end
|
||||
lcd.drawText(LCD_X_MAX, y, text, attrib + RIGHT) -- display value
|
||||
attrib = TEXT_ATTR
|
||||
end
|
||||
end -- Flight mode
|
||||
lcd.drawText(0, 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(0, LCD_Y_LOWER_BUTTONS, "Prev", ctx.SelLine == 8)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function load_msg_from_file(fileName, mem, Text, List_Text, List_Text_Img, RxName, Flight_Mode)
|
||||
local function rtrim(s)
|
||||
local n = string.len(s)
|
||||
while n > 0 and string.find(s, "^%s", n) do n = n - 1 end
|
||||
return string.sub(s, 1, n)
|
||||
end
|
||||
|
||||
--print(string.format("Loading messages from [%s]",fileName))
|
||||
local dataFile = io.open(fileName, "r") -- read File
|
||||
-- cannot read file???
|
||||
assert(dataFile, "Cannot load Message file:" .. fileName)
|
||||
|
||||
local data = io.read(dataFile, mem * 1024) -- read up to 10k characters (newline char also counts!)
|
||||
io.close(dataFile)
|
||||
|
||||
collectgarbage("collect")
|
||||
|
||||
local lineNo = 0
|
||||
for line in string.gmatch(data, "[^\r\n]+") do
|
||||
lineNo = lineNo + 1
|
||||
--print(string.format("Line [%d]: %s",lineNo,line))
|
||||
|
||||
-- Remove Comments
|
||||
local s = string.find(line, "--", 1, true)
|
||||
if (s ~= nil) then
|
||||
line = string.sub(line, 1, s - 1)
|
||||
end
|
||||
|
||||
line = rtrim(line)
|
||||
|
||||
if (string.len(line) > 0) then
|
||||
local a, b, c = string.match(line, "%s*(%a*)%s*|%s*(%w*)%s*|(.*)%s*")
|
||||
--print(string.format("[%s] [%s] [%s]",a,b,c))
|
||||
if (a ~= nil) then
|
||||
local index = tonumber(b)
|
||||
|
||||
if (index == nil) then
|
||||
assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, lineNo, b))
|
||||
elseif (a == "T") then
|
||||
Text[index] = c
|
||||
elseif (a == "LT") then
|
||||
List_Text[index] = c
|
||||
elseif (a == "LI") then
|
||||
List_Text_Img[index] = c
|
||||
elseif (a == "FM") then
|
||||
Flight_Mode[0] = c
|
||||
elseif (a == "RX") then
|
||||
RxName[index] = c
|
||||
else
|
||||
assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, lineNo, a))
|
||||
end
|
||||
end
|
||||
end
|
||||
if (lineNo % 50 == 0) then
|
||||
collectgarbage("collect")
|
||||
end
|
||||
end -- For
|
||||
|
||||
--print(string.format("Loaded [%d] messages",lineNo))
|
||||
data = nil
|
||||
end
|
||||
|
||||
|
||||
local function clean_msg(Text, Flight_Mode)
|
||||
local function clean_line(c)
|
||||
if (c==nil) then return c end
|
||||
local pos
|
||||
c, pos = string.gsub(c, "/b$", "")
|
||||
c, pos = string.gsub(c, "/c$", "")
|
||||
c, pos = string.gsub(c, "/r$", "")
|
||||
c, pos = string.gsub(c, "/p$", "")
|
||||
c, pos = string.gsub(c, "/m$", "")
|
||||
return c
|
||||
end
|
||||
|
||||
-- Clean the line of special markers that are only used in color vesion
|
||||
for i = 0, 0x0300 do
|
||||
Text[i] = clean_line(Text[i])
|
||||
collectgarbage("collect")
|
||||
end
|
||||
|
||||
for i = 0, #Flight_Mode do
|
||||
-- Clean the line of special markers that are only used in color vesion
|
||||
Flight_Mode[i] = clean_line(Flight_Mode[i])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function DSM_Init_Model()
|
||||
MODEL.DSM_ChannelInfo= {[0]= -- Start array at position 0
|
||||
{[0]= 0x00, 0x40}, -- Ch1 Thr (0x40)
|
||||
{[0]= 0x00, 0x01}, -- Ch2 Ail (0x01)
|
||||
{[0]= 0x00, 0x02}, -- Ch2 ElE (0x02)
|
||||
{[0]= 0x00, 0x04}, -- Ch4 Rud (0x04)
|
||||
{[0]= 0x00, 0x00}, -- Ch5 Gear (0x00)
|
||||
{[0]= 0x00, 0x00}, -- Ch6 Aux1 (0x00)
|
||||
{[0]= 0x00, 0x00}, -- Ch7 Aux2 (0x00)
|
||||
{[0]= 0x00, 0x00}, -- Ch8 Aux3 (0x00)
|
||||
{[0]= 0x00, 0x00}, -- Ch9 Aux4 (0x00)
|
||||
{[0]= 0x00, 0x00} -- Ch10 Aux5 (0x00)
|
||||
}
|
||||
|
||||
MODEL.modelOutputChannel = {[0]=
|
||||
{min=1000, max=1000}, -- Ch1
|
||||
{min=1000, max=1000}, -- Ch2
|
||||
{min=1000, max=1000}, -- Ch3
|
||||
{min=1000, max=1000}, -- Ch4
|
||||
{min=1000, max=1000}, -- Ch5
|
||||
{min=1000, max=1000}, -- Ch6
|
||||
{min=1000, max=1000}, -- Ch7
|
||||
{min=1000, max=1000}, -- Ch8
|
||||
{min=1000, max=1000}, -- Ch9
|
||||
{min=1000, max=1000} -- Ch10
|
||||
}
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Init
|
||||
local function DSM_Init()
|
||||
LOG_open()
|
||||
LOG_write("-------- NEW SESSION --------------------\n")
|
||||
|
||||
DSM_Init_Model()
|
||||
|
||||
--[[
|
||||
if (ModelParam~=nil) then
|
||||
LOG_write("Got MODEL PARAMETER... copying\n")
|
||||
MODEL.DSM_ChannelInfo = ModelParam.DSM_ChannelInfo
|
||||
else
|
||||
LOG_write("NO-PARMETER --- Create DEFAULT")
|
||||
end
|
||||
--]]
|
||||
|
||||
collectgarbage("collect")
|
||||
LOG_write("Mem before msg =%d\n",collectgarbage("count"))
|
||||
load_msg_from_file(MSG_FILE, 10, Text, List_Text, List_Text_Img, RxName, Flight_Mode)
|
||||
collectgarbage("collect")
|
||||
LOG_write("Mem after msg =%d\n",collectgarbage("count"))
|
||||
load_msg_from_file(MSG_FILE_MIN, 4, Text, List_Text, List_Text_Img, RxName, Flight_Mode)
|
||||
collectgarbage("collect")
|
||||
LOG_write("Mem after msg2 =%d\n",collectgarbage("count"))
|
||||
clean_msg(Text,Flight_Mode)
|
||||
collectgarbage("collect")
|
||||
|
||||
--Set protocol to talk to
|
||||
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
|
||||
|
||||
--Init TX buffer
|
||||
multiBuffer(3, 0x00)
|
||||
--Init RX buffer
|
||||
multiBuffer(10, 0x00)
|
||||
--Init telemetry
|
||||
multiBuffer(0, string.byte('D'))
|
||||
multiBuffer(1, string.byte('S'))
|
||||
multiBuffer(2, string.byte('M'))
|
||||
|
||||
|
||||
if (LCD_W > 128) then
|
||||
TEXT_ATTR = 0
|
||||
LCD_Y_LINE_HEIGHT = 25
|
||||
LCD_X_MAX = 300
|
||||
LCD_X_RIGHT_BUTTONS = LCD_X_MAX - 30
|
||||
|
||||
LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
local function DSM_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
else
|
||||
DSM_Display()
|
||||
DSM_Menu(event)
|
||||
DSM_Send_Receive()
|
||||
end
|
||||
if Phase == PH_EXIT_DONE then
|
||||
LOG_close()
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init = DSM_Init, run = DSM_Run }
|
||||
@@ -40,7 +40,13 @@
|
||||
|
||||
|
||||
local DEBUG_ON = ... -- Get Debug_ON from parameters. -- 0=NO DEBUG, 1=HIGH LEVEL 2=MORE DETAILS
|
||||
local LIB_VERSION = "0.52"
|
||||
|
||||
local LIB_VERSION = "0.54"
|
||||
local LANGUAGE = "en"
|
||||
|
||||
local LOG_FILE = "/LOGS/dsm_log.txt"
|
||||
local MSG_FILE = "/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_"..LANGUAGE..".txt"
|
||||
|
||||
|
||||
local Lib = { Init_Text = function (rxId) end }
|
||||
|
||||
@@ -105,8 +111,9 @@ local CH_MIX_TYPE = {
|
||||
NORM_REV = 0x70
|
||||
}
|
||||
|
||||
-- Bug in Lua compiler, confusing with global BOLD and RIGHT
|
||||
local DISP_ATTR = {
|
||||
BOLD = 0x01, RIGHT=0x02, CENTER=0x04, PERCENT = 0x10, DEGREES=0x20, FORCED_MENU = 0x40
|
||||
_BOLD = 0x01, _RIGHT=0x02, _CENTER=0x04, PERCENT = 0x10, DEGREES=0x20, FORCED_MENU = 0x40
|
||||
}
|
||||
|
||||
local DSM_Context = {
|
||||
@@ -126,6 +133,8 @@ local DSM_Context = {
|
||||
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
|
||||
}
|
||||
@@ -149,15 +158,14 @@ local TxInfo_Step = 0
|
||||
-- Text Arrays for Display Text and Debuging
|
||||
local PhaseText = {}
|
||||
local LineTypeText = {}
|
||||
local RxName = {}
|
||||
|
||||
|
||||
local Text = {} -- Text for Menu and Menu Lines (Headers only)
|
||||
local List_Text = {} -- Messages for List Options (values only)
|
||||
local List_Text_Img = {} -- If the Text has Attached Images
|
||||
local List_Values = {} -- Additiona restrictions on List Values when non contiguos (L_M1 lines has this problem)
|
||||
local RxName = {}
|
||||
local Flight_Mode = {[0]="Flight Mode"}
|
||||
|
||||
local LOG_FILE = "/LOGS/dsm_log.txt"
|
||||
local logFile = nil
|
||||
|
||||
|
||||
@@ -285,6 +293,9 @@ end
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
local function Get_Text(index)
|
||||
local out = Text[index] -- Find in regular header first
|
||||
if (index >= 0x8000) then
|
||||
out = Flight_Mode[0]
|
||||
end
|
||||
if out== nil then
|
||||
out = List_Text[index] -- Try list values, don't think is necesary, but just playing Safe
|
||||
end
|
||||
@@ -373,12 +384,13 @@ local function menuLine2String(l)
|
||||
end
|
||||
end
|
||||
|
||||
txt = string.format("L[#%s T=%s VId=0x%X Text=\"%s\"[0x%X] %s %s MId=0x%X ]",
|
||||
txt = string.format("L[#%s T=%s VId=0x%X Text=\"%s\"[0x%X] %s %s MId=0x%X A=0x%X]",
|
||||
l.lineNum, lineType2String(l.Type), l.ValId,
|
||||
l.Text, l.TextId,
|
||||
value,
|
||||
range,
|
||||
l.MenuId
|
||||
l.MenuId,
|
||||
l.TextAttr
|
||||
)
|
||||
end
|
||||
return txt
|
||||
@@ -458,29 +470,33 @@ local function isDisplayAttr(attr, bit)
|
||||
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
|
||||
local text = text1, pos;
|
||||
|
||||
text, pos = string.gsub(text, "/r", "")
|
||||
if (pos>0) then -- RIGHT
|
||||
attr = bit32.bor(attr, DISP_ATTR.RIGHT)
|
||||
end
|
||||
for i=1,2 do
|
||||
text, pos = string.gsub(text, "/c$", "")
|
||||
if (pos>0) then -- CENTER
|
||||
attr = bit32.bor(attr, DISP_ATTR._CENTER)
|
||||
end
|
||||
|
||||
text, pos = string.gsub(text, "/p", "")
|
||||
if (pos>0) then -- Percent TEXT
|
||||
attr = bit32.bor(attr, DISP_ATTR.PERCENT)
|
||||
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, "/b", "")
|
||||
if (pos>0) then -- BOLD TEXT
|
||||
attr = bit32.bor(attr, DISP_ATTR.BOLD)
|
||||
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, "/M", "")
|
||||
if (pos>0) then -- FORCED MENU Button
|
||||
attr = bit32.bor(attr, DISP_ATTR.FORCED_MENU)
|
||||
text, pos = string.gsub(text, "/b$", "")
|
||||
if (pos>0) then -- BOLD TEXT
|
||||
attr = bit32.bor(attr, DISP_ATTR._BOLD)
|
||||
end
|
||||
|
||||
text, pos = string.gsub(text, "/m$", "")
|
||||
if (pos>0) then -- FORCED MENU Button
|
||||
attr = bit32.bor(attr, DISP_ATTR.FORCED_MENU)
|
||||
end
|
||||
end
|
||||
|
||||
return text, attr
|
||||
@@ -596,14 +612,14 @@ local function DSM_ReadTxModelData()
|
||||
|
||||
-- Read Ch1 to Ch10
|
||||
local i= 0
|
||||
for i = 0, 9 do
|
||||
for i = 0, 12 do
|
||||
local ch = model.getOutput(i) -- Zero base
|
||||
if (ch~=nil) then
|
||||
MODEL.modelOutputChannel[i] = ch
|
||||
if (string.len(ch.name)==0) then
|
||||
ch.formatName = string.format("TX:Ch%i",i+1)
|
||||
ch.formatCh = string.format("TX:Ch%i",i+1)
|
||||
else
|
||||
ch.formatName = string.format("TX:Ch%i/%s",i+1,ch.name or "--")
|
||||
ch.formatCh = string.format("TX:Ch%i/%s",i+1,ch.name or "--")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -628,8 +644,14 @@ local function DSM_ReadTxModelData()
|
||||
for i = 0, 9 do
|
||||
local ch = MODEL.modelOutputChannel[i]
|
||||
if (ch~=nil) then
|
||||
MODEL.PORT_TEXT[i] = string.format("Port%i (%s) ",i+1,ch.formatName)
|
||||
LOG_write("Port%d %s [%d,%d] Rev=%d, Off=%d, ppmC=%d, syn=%d\n",i+1,ch.formatName,math.floor(ch.min/10),math.floor(ch.max/10), ch.revert, ch.offset, ch.ppmCenter, ch.symetrical)
|
||||
MODEL.TX_CH_TEXT[i] = ch.formatCh
|
||||
if LCD_W <= 128 then -- SMALLER SCREENS
|
||||
MODEL.PORT_TEXT[i] = string.format("P%i (%s) ",i+1,MODEL.TX_CH_TEXT[i])
|
||||
else
|
||||
MODEL.PORT_TEXT[i] = string.format("Port%i (%s) ",i+1,MODEL.TX_CH_TEXT[i])
|
||||
end
|
||||
|
||||
LOG_write("Port%d %s [%d,%d] Rev=%d, Off=%d, ppmC=%d, syn=%d\n",i+1,MODEL.TX_CH_TEXT[i],math.floor(ch.min/10),math.floor(ch.max/10), ch.revert, ch.offset, ch.ppmCenter, ch.symetrical)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -850,14 +872,17 @@ 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))
|
||||
-- Pascal: i think the 2nd byte is the leghts of the entire message in bytes, so instead of 0x06, should be 0x04 for here.. work both ways
|
||||
DSM_send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId))
|
||||
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))
|
||||
-- Pascal: i think the 2nd byte is the leghts of the entire message in bytes, so instead of 0x06, should be 0x04 for here.. work both ways
|
||||
local function DSM_menuValueChangingWait(lineNum, text, line)
|
||||
if (DEBUG_ON) then LOG_write("SEND DSM_menuValueChangingWait(lineNo=0x%X) Extra: Text=\"%s\" Val=%s\n", lineNum, text, lineValue2String(line)) end
|
||||
DSM_send(0x1A, 0x04, int16_MSB(lineNum), int16_LSB(lineNum))
|
||||
end
|
||||
|
||||
local function DSM_menuValueChangingWaitEnd(lineNum, text, line)
|
||||
if (DEBUG_ON) then LOG_write("SEND DSM_menuValueChangingEnd(lineNo=0x%X) Extra: Text=\"%s\" Value=%s\n", lineNum, text, lineValue2String(line)) end
|
||||
DSM_send(0x1B, 0x04, int16_MSB(lineNum), int16_LSB(lineNum))
|
||||
end
|
||||
|
||||
-- Send the functionality of the RX channel Port (channel)
|
||||
@@ -1005,25 +1030,29 @@ local function DSM_sendRequest()
|
||||
DSM_getNextMenuValue(ctx.Menu.MenuId, line.ValId, line.Text)
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line
|
||||
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)
|
||||
DSM_menuValueChangingWait(line.lineNum, line.Text, line)
|
||||
|
||||
elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value
|
||||
-- This is a 2 step operation.. Send the value first, then send the Verification.. Value_Changed_Step used for that
|
||||
-- on the validation, the RX will set a valid value if the value is invalid. A Menu_Value Message will come from the RX
|
||||
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Updat Value of SELECTED line
|
||||
local line = ctx.MenuLines[ctx.SelLine] -- Update Value of SELECTED line
|
||||
if Value_Change_Step == 0 then
|
||||
DSM_updateMenuValue(line.ValId, line.Val, line.Text, line)
|
||||
Value_Change_Step = 1
|
||||
Waiting_RX = 0 -- Keep on Transmitin State, since we want to send a ValidateMenuValue inmediatly after
|
||||
else -- Validate the value
|
||||
elseif Value_Change_Step == 1 then -- Validate the value
|
||||
DSM_validateMenuValue(line.ValId, line.Text, line)
|
||||
Value_Change_Step = 2
|
||||
Waiting_RX = 0 -- Keep on Transmitin State, since we want to send a ValidateMenuValue inmediatly after
|
||||
else -- No more waiting for changes
|
||||
DSM_menuValueChangingWaitEnd(line.lineNum, line.Text, line)
|
||||
Value_Change_Step = 0
|
||||
end
|
||||
|
||||
@@ -1310,6 +1339,69 @@ local function DSM_Send_Receive()
|
||||
end
|
||||
end
|
||||
|
||||
local function load_msg_from_file(fileName, mem, Text, List_Text, List_Text_Img, RxName, Flight_Mode)
|
||||
local function rtrim(s)
|
||||
local n = string.len(s)
|
||||
while n > 0 and string.find(s, "^%s", n) do n = n - 1 end
|
||||
return string.sub(s, 1, n)
|
||||
end
|
||||
|
||||
--print(string.format("Loading messages from [%s]",fileName))
|
||||
local dataFile = io.open(fileName, "r") -- read File
|
||||
-- cannot read file???
|
||||
assert(dataFile, "Cannot load Message file:" .. fileName)
|
||||
|
||||
local data = io.read(dataFile, mem * 1024) -- read up to 10k characters (newline char also counts!)
|
||||
io.close(dataFile)
|
||||
|
||||
collectgarbage("collect")
|
||||
|
||||
local lineNo = 0
|
||||
for line in string.gmatch(data, "[^\r\n]+") do
|
||||
lineNo = lineNo + 1
|
||||
--print(string.format("Line [%d]: %s",lineNo,line))
|
||||
|
||||
-- Remove Comments
|
||||
local s = string.find(line, "--", 1, true)
|
||||
if (s ~= nil) then
|
||||
line = string.sub(line, 1, s - 1)
|
||||
end
|
||||
|
||||
line = rtrim(line)
|
||||
|
||||
if (string.len(line) > 0) then
|
||||
local a, b, c = string.match(line, "%s*(%a*)%s*|%s*(%w*)%s*|(.*)%s*")
|
||||
--print(string.format("[%s] [%s] [%s]",a,b,c))
|
||||
if (a ~= nil) then
|
||||
local index = tonumber(b)
|
||||
|
||||
if (index == nil) then
|
||||
assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, lineNo, b))
|
||||
elseif (a == "T") then
|
||||
Text[index] = c
|
||||
elseif (a == "LT") then
|
||||
List_Text[index] = c
|
||||
elseif (a == "LI") then
|
||||
List_Text_Img[index] = c
|
||||
elseif (a == "FM") then
|
||||
Flight_Mode[0] = c
|
||||
elseif (a == "RX") then
|
||||
RxName[index] = c
|
||||
else
|
||||
assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, lineNo, a))
|
||||
end
|
||||
end
|
||||
end
|
||||
if (lineNo % 50 == 0) then
|
||||
collectgarbage("collect")
|
||||
end
|
||||
end -- For
|
||||
|
||||
--print(string.format("Loaded [%d] messages",lineNo))
|
||||
data = nil
|
||||
end
|
||||
|
||||
|
||||
-- Init
|
||||
local function DSM_Init(toolName)
|
||||
local dateTime = getDateTime()
|
||||
@@ -1353,105 +1445,69 @@ local function DSM_Init(toolName)
|
||||
LineTypeText[LINE_TYPE.VALUE_NUM_SI16] = "V_s16"
|
||||
LineTypeText[LINE_TYPE.LT_EMPTY] = "Z"
|
||||
|
||||
--RX names--
|
||||
RxName[RX.AR636B] = "AR636B"
|
||||
RxName[RX.SPM4651T] = "SPM4651T"
|
||||
RxName[RX.AR637T] = "AR637T"
|
||||
RxName[RX.AR637TA] = "AR637TA"
|
||||
RxName[RX.FC6250HX] = "FC6250HX"
|
||||
RxName[RX.AR630] = "AR630"
|
||||
RxName[RX.AR8360T] = "AR8360T"
|
||||
RxName[RX.AR10360T] = "AR10360T"
|
||||
RxName[RX.AR631] = "AR631"
|
||||
|
||||
DSM_ReadTxModelData()
|
||||
|
||||
-- Load messages from external file (/DSMLIB/msg_en.txt)
|
||||
load_msg_from_file(MSG_FILE,10,Text,List_Text,List_Text_Img,RxName,Flight_Mode)
|
||||
end
|
||||
|
||||
|
||||
local function DSM_Init_Text(rxId)
|
||||
--Text to be displayed
|
||||
-- For menu lines who are not navigation to other menus (SubHeders or Plain text)
|
||||
-- you can use some formatting options:
|
||||
-- you can use some formatting options AT THE END OF THE STRING :
|
||||
|
||||
-- Text allightment: /c = CENTER, /r = RIGHT
|
||||
-- Text effects: /b = BOLD
|
||||
-- Text formatting: /p = PERCENT numbers (forced if not in Line Type=PERCENT)
|
||||
-- Navigaton: /M = Force to be a Menu button, when a menu navigates to itself,
|
||||
-- Navigaton: /m = Force to be a Menu button, when a menu navigates to itself,
|
||||
-- is usually a message line.. but sometimes, we want to navigate to the same page to refresh values
|
||||
|
||||
-- array List_Values:
|
||||
-- For some Menu LIST VALUES, special Lines of type:LIST_MENU1, the valod options seems not
|
||||
-- For some Menu LIST VALUES, special Lines of type:LIST_MENU1, the valur options seems not
|
||||
-- to be contiguos, the array "Menu_List_Values" can help narrow down the
|
||||
-- valid menu options. I think this should come from the RX, but cant find where.
|
||||
-- Most of the times, Limes of type LIST_MENU1 comes with a 0->244 value range that is not correct
|
||||
-- usually is Ihnibit + range of contiguos values, but cant seems to find in the RX data receive the values
|
||||
-- to do it automatically
|
||||
|
||||
List_Text[0x0001] = "Off"
|
||||
List_Text[0x0002] = "On"
|
||||
local function getTxChText(ch)
|
||||
return " ("..(MODEL.TX_CH_TEXT[ch] or "--")..")"
|
||||
end
|
||||
|
||||
-- Ihn/Act List Options
|
||||
List_Text[0x0003] = "Inh"
|
||||
List_Text[0x0004] = "Act"
|
||||
-- OVERRIDES for list of valid VALUES and channel names
|
||||
|
||||
-- Channel selection for SAFE MODE and GAINS on FC6250HX
|
||||
List_Text[0x000C] = "Inhibit?" --?
|
||||
List_Text[0x000D] = "Ch5 (Gear)"
|
||||
for i = 1, 7 do List_Text[0x000D + i] = "Ch"..(i+5) .. " (Aux" .. i .. ")" end -- Aux channels
|
||||
-- List_Text[0x000C] = "Inhibit?" --?
|
||||
for i = 0, 7 do List_Text[0x000D + i] = "Ch"..(i+5) ..getTxChText(i+4) end -- Aux channels (Ch5 and Greater)
|
||||
|
||||
-- Servo Output values..
|
||||
local servoOutputValues = {0x0003,0x002D,0x002E,0x002F} --Inh (GAP), 5.5ms, 11ms, 22ms. Fixing L_m1 with 0..244 range!
|
||||
List_Text[0x002D] = "5.5ms"
|
||||
List_Text[0x002E] = "11ms"
|
||||
List_Text[0x002F] = "22ms"
|
||||
--List_Text[0x002D] = "5.5ms"
|
||||
--List_Text[0x002E] = "11ms"
|
||||
--List_Text[0x002F] = "22ms"
|
||||
|
||||
-- Gain Values
|
||||
local gainValues = {0x0032,0x0033,0x0034} -- 1X, 2X, 4X -- Fixing L_m1 with 0..244 range!
|
||||
List_Text[0x0032] = "1 X"
|
||||
List_Text[0x0033] = "2 X"
|
||||
List_Text[0x0034] = "4 X"
|
||||
--List_Text[0x0032] = "1 X"
|
||||
--List_Text[0x0033] = "2 X"
|
||||
--List_Text[0x0034] = "4 X"
|
||||
|
||||
-- List of Channels for Safe, Gains, Panic, except FC6250HX that uses other range (0x00C..0x015)
|
||||
-- the valid range Starts with GEAR if enabled (Thr,Ail,Ele,Rud are not valid, the RX reject them )
|
||||
-- Valid Values: Inhibit? (GAP), Gear,Aux1..Aux7,X-Plus-1..XPlus-8
|
||||
local channelValues = {0x0035,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049}
|
||||
|
||||
List_Text[0x0035] = "Inhibit?"
|
||||
List_Text[0x0036] = "Throttle"
|
||||
List_Text[0x0037] = "Aileron"
|
||||
List_Text[0x0038] = "Elevator"
|
||||
List_Text[0x0039] = "Rudder"
|
||||
List_Text[0x003A] = "Ch5 (Gear)"
|
||||
for i = 1, 7 do List_Text[0x003A + i] = "Ch"..(i+5) .. " (Aux" .. i .. ")" end -- Aux channels on AR637T
|
||||
--List_Text[0x0035] = "Inhibit?"
|
||||
for i = 0, 11 do List_Text[0x0036 + i] = "Ch"..(i+1) .. getTxChText(i) end -- Channels on AR637T
|
||||
|
||||
for i = 1, 8 do -- 41..49
|
||||
List_Text[0x0041 + i] = "Ch"..(i+13) .." (XPlus-" .. i .. ")"
|
||||
List_Text[0x0041 + i] = "Ch"..(i+13)
|
||||
end
|
||||
|
||||
-- ****No longer overrides of previous XPlus values, since using different array
|
||||
-- for List_Text values
|
||||
|
||||
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, AR631
|
||||
--******
|
||||
|
||||
Text[0x004A] = "Failsafe"
|
||||
Text[0x004B] = "Main Menu"
|
||||
Text[0x004E] = "Position"
|
||||
|
||||
Text[0x0050] = "Outputs";
|
||||
|
||||
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
|
||||
List_Values[0x0051]=servoOutputValues
|
||||
List_Values[0x0052]=servoOutputValues
|
||||
@@ -1461,273 +1517,30 @@ local function DSM_Init_Text(rxId)
|
||||
List_Values[0x0056]=servoOutputValues
|
||||
end
|
||||
|
||||
-- FailSafe Options
|
||||
--Text[0x005E]="Inhibit"
|
||||
List_Text[0x005F] = "Hold Last"
|
||||
List_Text[0x0060] = "Preset"
|
||||
--Text[0x0061]="Custom"
|
||||
|
||||
--FC6250HX
|
||||
Text[0x0071] = "Proportional"
|
||||
Text[0x0072] = "Integral"
|
||||
Text[0x0073] = "Derivate"
|
||||
|
||||
-- Flight mode channel selection
|
||||
Text[0x0078] = "FM Channel"
|
||||
--Text[0x0078] = "FM Channel"
|
||||
if (rxId ~= RX.FC6250HX) then List_Values[0x0078]=channelValues end --FC6250HX uses other range
|
||||
|
||||
Text[0x007F] = "Attitude Gain" -- AR636B
|
||||
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"
|
||||
--Text[0x0089] = "Gain Channel"
|
||||
if (rxId ~= RX.FC6250HX) then List_Values[0x0089]=channelValues end --FC6250HX uses other range
|
||||
|
||||
-- Gain Sensitivity selection
|
||||
Text[0x008A] = "Gain Sensitivity/r"; List_Values[0x008A]=gainValues -- Right Alight, (L_M1 was wide open range 0->244)
|
||||
|
||||
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 " -- Save & Reboot RX
|
||||
|
||||
Text[0x00A5] = "First Time Setup"
|
||||
Text[0x00AA] = "Capture Gyro Gains"
|
||||
Text[0x00AD] = "Gain Channel Select"
|
||||
--Text[0x008A] = "Gain Sensitivity/r";
|
||||
List_Values[0x008A]=gainValues -- Right Alight, (L_M1 was wide open range 0->244)
|
||||
|
||||
-- Safe mode options, Ihnibit + this values
|
||||
local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope
|
||||
List_Text[0x00B0] = "Self-Level/Angle Dem"
|
||||
List_Text[0x00B1] = "Envelope"
|
||||
--List_Text[0x00B0] = "Self-Level/Angle Dem"
|
||||
--List_Text[0x00B1] = "Envelope"
|
||||
|
||||
-- Flight Modes List Options
|
||||
List_Text[0x00B5] = "Inhibit"
|
||||
for i = 1, 10 do List_Text[0x00B5 + i] = "Flight Mode " .. i end
|
||||
|
||||
Text[0x00BE] = "Unknown_BE" -- Used in Reset menu (0x0001) while the RX is rebooting
|
||||
|
||||
Text[0x00C7] = "Calibrate Sensor"
|
||||
Text[0x00C8] = "Complete" -- FC6250HX calibration complete
|
||||
Text[0x00CA] = "SAFE/Panic Mode Setup"
|
||||
Text[0x00CD] = "Level model and capture attiude/M"; -- Different from List_Text , and force it to be a menu button
|
||||
|
||||
-- RX Orientations for AR631/AR637, Optionally attach an Image + Alt Text to display
|
||||
List_Text[0x00CB] = "Position 1"; List_Text_Img[0x00CB] = "rx_pos_1.png|Pilot View: RX Label Up, Pins Back"
|
||||
List_Text[0x00CC] = "Position 2"; List_Text_Img[0x00CC] = "rx_pos_2.png|Pilot View: RX Label Left, Pins Back"
|
||||
List_Text[0x00CD] = "Position 3"; List_Text_Img[0x00CD] = "rx_pos_3.png|Pilot View: RX Label Down, Pins Back"
|
||||
List_Text[0x00CE] = "Position 4"; List_Text_Img[0x00CE] = "rx_pos_4.png|Pilot View: RX Label Right, Pins Back"
|
||||
List_Text[0x00CF] = "Position 5"; List_Text_Img[0x00CF] = "rx_pos_5.png|Pilot View: RX Label UP, Pins to Front"
|
||||
List_Text[0x00D0] = "Position 6"; List_Text_Img[0x00D0] = "rx_pos_6.png|Pilot View: RX Label Left, Pins Front"
|
||||
List_Text[0x00D1] = "Position 7"; List_Text_Img[0x00D1] = "rx_pos_7.png|Pilot View: RX Label Down, Pins Front"
|
||||
List_Text[0x00D2] = "Position 8"; List_Text_Img[0x00D2] = "rx_pos_8.png|Pilot View: RX Label Right, Pins Front"
|
||||
List_Text[0x00D3] = "Position 9"; List_Text_Img[0x00D3] = "rx_pos_9.png|Pilot View: RX Label Up, Pins Left"
|
||||
List_Text[0x00D4] = "Position 10"; List_Text_Img[0x00D4] = "rx_pos_10.png|Pilot View: RX Label Back, Pins Left"
|
||||
List_Text[0x00D5] = "Position 11"; List_Text_Img[0x00D5] = "rx_pos_11.png|Pilot View: RX Label Down, Pins Left"
|
||||
List_Text[0x00D6] = "Position 12"; List_Text_Img[0x00D6] = "rx_pos_12.png|Pilot View: RX Label Front, Pins Left"
|
||||
List_Text[0x00D7] = "Position 13"; List_Text_Img[0x00D7] = "rx_pos_13.png|Pilot View: RX Label Up, Pins Right"
|
||||
List_Text[0x00D8] = "Position 14"; List_Text_Img[0x00D8] = "rx_pos_14.png|Pilot View: RX Label Back, Pins Right"
|
||||
List_Text[0x00D9] = "Position 15"; List_Text_Img[0x00D9] = "rx_pos_15.png|Pilot View: RX Label Down, Pins Right"
|
||||
List_Text[0x00DA] = "Position 16"; List_Text_Img[0x00DA] = "rx_pos_16.png|Pilot View: RX Label Front, Pins Right"
|
||||
List_Text[0x00DB] = "Position 17"; List_Text_Img[0x00DB] = "rx_pos_17.png|Pilot View: RX Label Back, Pins Down"
|
||||
List_Text[0x00DC] = "Position 18"; List_Text_Img[0x00DC] = "rx_pos_18.png|Pilot View: RX Label Left, Pins Down"
|
||||
List_Text[0x00DD] = "Position 19"; List_Text_Img[0x00DD] = "rx_pos_19.png|Pilot View: RX Label Front, Pins Down"
|
||||
List_Text[0x00DE] = "Position 20"; List_Text_Img[0x00DE] = "rx_pos_20.png|Pilot View: RX Label Right, Pins Down"
|
||||
List_Text[0x00DF] = "Position 21"; List_Text_Img[0x00DF] = "rx_pos_21.png|Pilot View: RX Label Back, Pins Up"
|
||||
List_Text[0x00E0] = "Position 22"; List_Text_Img[0x00E0] = "rx_pos_22.png|Pilot View: RX Label Left, Pins Up"
|
||||
List_Text[0x00E1] = "Position 23"; List_Text_Img[0x00E1] = "rx_pos_23.png|Pilot View: RX Label Front, Pins Up"
|
||||
List_Text[0x00E2] = "Position 24"; List_Text_Img[0x00E2] = "rx_pos_24.png|Pilot View: RX Label Right, Pins Up"
|
||||
List_Text[0x00E3] = "Position Invalid"; List_Text_Img[0x00E3] = "rx_pos_25.png|Cannot detect orientation of RX"
|
||||
|
||||
Text[0x00D1] = "Receiver will Reboot/b"
|
||||
--FC6250HX
|
||||
Text[0x00D2] = "Panic Channel"
|
||||
--Text[0x00D2] = "Panic Channel"
|
||||
if (rxId ~= RX.FC6250HX) then List_Values[0x00D2]=channelValues end --FC6250HX uses other range
|
||||
|
||||
Text[0x00D3] = "Swashplate"
|
||||
Text[0x00D5] = "Agility"
|
||||
Text[0x00D8] = "Stop"
|
||||
Text[0x00DA] = "SAFE/c/b" --SubTitle
|
||||
Text[0x00DB] = "Stability"
|
||||
Text[0x00DC] = "Deg. 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"
|
||||
|
||||
Text[0x00E7] = "Left"
|
||||
Text[0x00E8] = "Right"
|
||||
|
||||
-- Gain Capture options
|
||||
List_Text[0x00F2] = "Fixed"
|
||||
List_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 Model/Servo Settings (TX->RX)"
|
||||
Text[0x019C] = "Enter Receiver Bind Mode"
|
||||
Text[0x01D7] = "SAFE Select Channel"
|
||||
Text[0x01DC] = "AS3X/c/b" -- Subtitle, Center+bold
|
||||
Text[0x01DD] = "AS3X Settings"
|
||||
Text[0x01DE] = "AS3X Gains"
|
||||
Text[0x01E0] = "Rate Gains/c/b" -- SubTitle, Center+bold
|
||||
Text[0x01E2] = "SAFE Settings"
|
||||
Text[0x01E3] = "SAFE Gains"
|
||||
Text[0x01E6] = "Attitude Trim/c/b" -- SubTitle, Center+bold
|
||||
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/c/b" -- SubTitle, Center+bold
|
||||
Text[0x01F0] = "High Thr to Pitch/c/b" -- SubTitle, Center+bold
|
||||
Text[0x01F3] = "Threshold"
|
||||
Text[0x01F4] = "Angle"
|
||||
Text[0x01F6] = "Failsafe Angles/c/b" -- SubTitle, Center+bold
|
||||
|
||||
--Inh, Self-Level/Angle Dem, Envelope -- (L_M was wide open range 0->244)
|
||||
Text[0x01F8] = "Safe Mode"; 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"
|
||||
|
||||
-- First time safe setup Page 3 :
|
||||
Text[0x020E] = "AS3X gains must be tuned"
|
||||
Text[0x020F] = "and active in SAFE Flight Modes"
|
||||
Text[0x0210] = "to help reduce wobble."
|
||||
Text[0x0211] = "" -- empty
|
||||
Text[0x0212] = "" -- empty
|
||||
Text[0x0213] = "" -- empty
|
||||
|
||||
-- AS3X orientation Setting menu (Level)
|
||||
Text[0x021A] = "Set the model level,"
|
||||
Text[0x021B] = "and press Continue."
|
||||
Text[0x021C] = "" -- empty??
|
||||
Text[0x021D] = "" -- empty??
|
||||
|
||||
-- AS3X orientation Setting menu (Nose down)
|
||||
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
|
||||
|
||||
-- Utilities Copy flight modes
|
||||
Text[0x023D] = "Copy Flight Mode Settings"
|
||||
Text[0x023E] = "Source Flight Mode"
|
||||
Text[0x023F] = "Target Flight Mode"
|
||||
Text[0x0240] = "Utilities"
|
||||
|
||||
-- Gain Capture Page
|
||||
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"
|
||||
|
||||
--Utilities, Copy flight mode (Copy Confirmation, oveerriding FM)
|
||||
Text[0x0251] = "Are you sure you want to ovewrite the \"Target\""
|
||||
Text[0x0252] = "with the \"Source\" ? "
|
||||
Text[0x0253] = "" -- Blank
|
||||
|
||||
-- First time safe setup Page 1 (maybe ask to select Flight Mode cannel)
|
||||
Text[0x0255] = "Before setting up SAFE"
|
||||
Text[0x0256] = "a Flight Mode channel"
|
||||
Text[0x0257] = "most be configured."
|
||||
|
||||
--First time safe setup Page 2 (something related for flight mode)
|
||||
Text[0x025A] = "Select the desired flight mode"
|
||||
Text[0x025B] = "switch position to adjust settings"
|
||||
Text[0x025C] = "for each flight mode"
|
||||
Text[0x025D] = "" -- Blank
|
||||
Text[0x025E] = "" -- Blank
|
||||
|
||||
--Utilities, Copy flight mode (Confirm)
|
||||
Text[0x0259] = "YES"
|
||||
Text[0x0260] = "WARNING: \"Target\""
|
||||
Text[0x0261] = "flight mode will be overwritten"
|
||||
Text[0x0262] = "by \"Source\""
|
||||
|
||||
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: 1=NORMAL 2= Stunt-1, 3=Stunt-2, 4=Hold
|
||||
Text[0x8001] = "Flight Mode/c/b" -- WAS "Flight Mode 1".. This usually is a Flight Mode w value relative to 0 (AR631/AR637)
|
||||
Text[0x8002] = "Flight Mode 2/c/b" -- what RX does this show up??
|
||||
Text[0x8003] = "Flight Mode 3/c/b"
|
||||
--Text[0x01F8] = "Safe Mode";
|
||||
List_Values[0x01F8]=safeModeOptions
|
||||
end
|
||||
|
||||
-- Adjust the displayed value for Flight mode line as needed
|
||||
@@ -1750,14 +1563,14 @@ local function GetFlightModeValue(line)
|
||||
end
|
||||
else
|
||||
-- No adjustment needed
|
||||
out = header .. " " .. value
|
||||
out = header .. " " .. (value + 1)
|
||||
end
|
||||
elseif (textId == 0x8001) then -- AR630-637, AR8360T, AR10360T
|
||||
-- Seems that we really have to add +1 to the value, so Flight Mode 0 is Really Flight Mode 1
|
||||
out = header .. " " .. (value + 1)
|
||||
else
|
||||
-- Default, return the value as we Have it
|
||||
out = header .. " " .. value
|
||||
out = header .. " " .. (value + 1)
|
||||
end
|
||||
return out
|
||||
end
|
||||
@@ -1820,5 +1633,6 @@ Lib.Init = DSM_Init
|
||||
Lib.Init_Text = DSM_Init_Text
|
||||
|
||||
Lib.SetDSMChannelInfo = DSM_SetDSMChannelInfo
|
||||
Lib.Get_RxName = Get_RxName
|
||||
|
||||
return Lib
|
||||
|
||||
@@ -664,6 +664,7 @@ local function AR631_loadMenu(menuId)
|
||||
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x0101, ValId = 0x104F }
|
||||
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0102, ValId = 0x104F }
|
||||
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0103, ValId = 0x104F }
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x0104, ValId = 0x104F }
|
||||
ctx.SelLine = dsmLib.NEXT_BUTTON
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1050) then
|
||||
@@ -679,6 +680,7 @@ local function AR631_loadMenu(menuId)
|
||||
ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x0107, ValId = 0x1050 }
|
||||
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0108, ValId = 0x1050 }
|
||||
ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0109, ValId = 0x1050 }
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x010A, ValId = 0x1050 }
|
||||
ctx.SelLine = dsmLib.NEXT_BUTTON
|
||||
lastGoodMenu = menuId
|
||||
elseif (menuId==0x1051) then
|
||||
@@ -1335,8 +1337,8 @@ local function loadMenu(menuId)
|
||||
--L[#1 T=M VId=0x105E val=nil [0->0,2] Text="Other settings" MId=0x1000 ]
|
||||
|
||||
ctx.Menu = { MenuId = 0x1000, Text = "RX SIMULATION", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||
ctx.MenuLines[0] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR630/631/637 (NEW)", ValId = 0x1001,TextId=0 }
|
||||
ctx.MenuLines[1] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR630/631/637 (INITIALIZED)", ValId = 0x1002, TextId=0 }
|
||||
ctx.MenuLines[0] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR631 (NEW)", ValId = 0x1001,TextId=0 }
|
||||
ctx.MenuLines[1] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR631 (INITIALIZED)", ValId = 0x1002, TextId=0 }
|
||||
ctx.MenuLines[4] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "FC6250HX", ValId = 0x1005, TextId=0 }
|
||||
|
||||
ctx.SelLine = 0
|
||||
@@ -1344,25 +1346,25 @@ local function loadMenu(menuId)
|
||||
elseif (menuId==0x1001) then
|
||||
RX_Initialized = false
|
||||
ctx.RX.Id = dsmLib.RX.AR631
|
||||
ctx.RX.Name = "AR630/631/637-SIM"
|
||||
ctx.RX.Version = "2.38.5"
|
||||
dsmLib.Init_Text(ctx.RX.Id)
|
||||
ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM'
|
||||
ctx.RX.Version = "2.38.5"
|
||||
|
||||
RX_loadMenu = AR631_loadMenu
|
||||
RX_loadMenu(0x01000)
|
||||
elseif (menuId==0x1002) then
|
||||
ctx.RX.Id = dsmLib.RX.AR631
|
||||
ctx.RX.Name = "AR630/631/637-SIM"
|
||||
ctx.RX.Version = "2.38.5"
|
||||
dsmLib.Init_Text(ctx.RX.Id)
|
||||
ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM'
|
||||
ctx.RX.Version = "2.38.5"
|
||||
|
||||
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)
|
||||
ctx.RX.Name = dsmLib.Get_RxName(ctx.RX.Id)..' SIM'
|
||||
ctx.RX.Version = "5.6.255"
|
||||
|
||||
RX_loadMenu = FC6250HX_loadMenu
|
||||
RX_loadMenu(0x01000)
|
||||
@@ -1378,7 +1380,7 @@ local function SIM_Send_Receive()
|
||||
|
||||
if ctx.Phase == PHASE.RX_VERSION then -- request RX version
|
||||
ctx.RX.Name = "SIMULATOR"
|
||||
ctx.RX.Version = "1.0.0"
|
||||
ctx.RX.Version = "0.54"
|
||||
ctx.Phase = PHASE.MENU_TITLE
|
||||
|
||||
ctx.Refresh_Display = true
|
||||
|
||||
@@ -23,11 +23,10 @@
|
||||
-- Author: Francisco Arzu
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
local DEBUG_ON, SIMULATION_ON = ... -- Get DebugON from parameters
|
||||
local SETUP_LIB_VERSION = "0.52"
|
||||
local SETUP_LIB_VERSION = "0.54"
|
||||
|
||||
local DATA_PATH = "/SCRIPTS/TOOLS/DSMLIB/data/" -- Path to store model settings files
|
||||
local DATA_PATH = "/MODELS/DSMDATA" -- Path to store model settings files
|
||||
local dsmLib = assert(loadScript("/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua"))(DEBUG_ON)
|
||||
|
||||
local PHASE = dsmLib.PHASE
|
||||
@@ -151,10 +150,10 @@ local function printChannelSummary()
|
||||
end
|
||||
|
||||
local function printServoReverseInfo()
|
||||
print("SERVO Normal/Reversed INFORMATION")
|
||||
print("SERVO Normal/Reverse INFORMATION")
|
||||
for i=0,10 do
|
||||
local s="--"
|
||||
if (MENU_DATA[MEMU_VAR.PORT1_MODE+i] or 0) == 0 then s="NORMAL" else s="REVERT" end
|
||||
if (MENU_DATA[MEMU_VAR.PORT1_MODE+i] or 0) == 0 then s="NORMAL" else s="REVERSE" end
|
||||
print(string.format("Port%d: %s", i+1, s))
|
||||
end
|
||||
end
|
||||
@@ -194,7 +193,7 @@ local function ST_PlaneWingInit(wingType)
|
||||
elseif (wingType==WING_TYPE.AIL_2_FLP_2) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6
|
||||
MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2
|
||||
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5
|
||||
MENU_DATA[MEMU_VAR.CH_R_FLP] = PORT.PORT5
|
||||
MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT7
|
||||
elseif (wingType==WING_TYPE.ELEVON_A) then
|
||||
MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2
|
||||
@@ -415,7 +414,7 @@ function ST_LoadFileData()
|
||||
|
||||
print("Loading File:"..fname)
|
||||
|
||||
local dataFile = io.open(DATA_PATH .. fname, "r") -- read File
|
||||
local dataFile = io.open(DATA_PATH .. "/".. fname, "r") -- read File
|
||||
-- cannot read file???
|
||||
if (dataFile==nil) then return 0 end
|
||||
|
||||
@@ -459,7 +458,7 @@ function ST_SaveFileData()
|
||||
local fname = hashName(MODEL.modelName)..".txt"
|
||||
|
||||
print("Saving File:"..fname)
|
||||
local dataFile = io.open(DATA_PATH .. fname, "w") -- write File
|
||||
local dataFile = assert(io.open(DATA_PATH .. "/" .. fname, "w"),"Please create "..DATA_PATH.." folder") -- write File
|
||||
|
||||
-- Foreach MENU_DATA with a value write Var_Id:Value into file
|
||||
for i = 0, MEMU_VAR.DATA_END do
|
||||
@@ -688,7 +687,7 @@ local function ST_LoadMenu(menuId)
|
||||
local ctx = dsmLib.DSM_Context
|
||||
|
||||
local function formatTXRevert(port)
|
||||
return ((MODEL.modelOutputChannel[port].revert==0 and " (Tx:Normal)") or " (Tx:Reverted)")
|
||||
return ((MODEL.modelOutputChannel[port].revert==0 and " (Tx:Normal)") or " (Tx:Reverse)")
|
||||
end
|
||||
|
||||
clearMenuLines()
|
||||
@@ -699,7 +698,7 @@ local function ST_LoadMenu(menuId)
|
||||
|
||||
if (menuDataChanged) then
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, Text="Save Changes", TextId = 0, ValId = 0x1005 }
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Discart Changes", TextId = 0, ValId = 0x1006 }
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Discard Changes", TextId = 0, ValId = 0x1006 }
|
||||
ctx.SelLine = 4
|
||||
else
|
||||
if (SIMULATION_ON) then
|
||||
@@ -725,7 +724,7 @@ local function ST_LoadMenu(menuId)
|
||||
|
||||
|
||||
local msg1 = "Data saved to: "
|
||||
local msg2 = DATA_PATH..hashName(MODEL.modelName)..".txt"
|
||||
local msg2 = " "..DATA_PATH.."/"..hashName(MODEL.modelName)..".txt"
|
||||
|
||||
ctx.Menu = { MenuId = 0x1005, Text = "Config Saved", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, Text=msg1, TextId = 0, ValId = 0x1005 }
|
||||
@@ -736,7 +735,7 @@ local function ST_LoadMenu(menuId)
|
||||
elseif (menuId==0x1006) then
|
||||
ST_LoadFileData()
|
||||
local msg1 = "Data restored from: "
|
||||
local msg2 = DATA_PATH..hashName(MODEL.modelName)..".txt"
|
||||
local msg2 = " "..DATA_PATH.."/"..hashName(MODEL.modelName)..".txt"
|
||||
|
||||
ctx.Menu = { MenuId = 0x1006, Text = "Discart Changes", PrevId = 0, NextId = 0, BackId = 0, TextId=0 }
|
||||
ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, Text=msg1, TextId = 0, ValId = 0x1006 }
|
||||
@@ -788,7 +787,7 @@ local function ST_LoadMenu(menuId)
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftFlapText, TextId = 0, ValId = MEMU_VAR.CH_L_FLP, Min=0, Max=9, Def=0, Val= leftFlap }
|
||||
end
|
||||
if (rightFlap~=nil) then
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightFlapText, TextId = 0, ValId = MEMU_VAR.CH_L_FLP, Min=0, Max=9, Def=0, Val= leftFlap }
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightFlapText, TextId = 0, ValId = MEMU_VAR.CH_R_FLP, Min=0, Max=9, Def=0, Val= rightFlap }
|
||||
end
|
||||
|
||||
ctx.SelLine = 1
|
||||
@@ -842,7 +841,8 @@ local function ST_LoadMenu(menuId)
|
||||
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT4], TextId = 0, ValId = MEMU_VAR.PORT4_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT4_MODE], Format = formatTXRevert(PORT.PORT4) }
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT5], TextId = 0, ValId = MEMU_VAR.PORT5_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT5_MODE], Format = formatTXRevert(PORT.PORT5) }
|
||||
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text=" Usually Rud/Ail needs to be the oposite of the TX", TextId = 0, ValId = 0x1030 }
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Only Thr/Ail/Rud/Ele. This affects AS3X/SAFE reaction dir./b", TextId = 0, ValId = 0x1030 }
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Any changes, use RX 'Relearn Servo Settings'/b", TextId = 0, ValId = 0x1030 }
|
||||
|
||||
ctx.SelLine = 0
|
||||
lastGoodMenu = menuId
|
||||
@@ -855,7 +855,8 @@ local function ST_LoadMenu(menuId)
|
||||
ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT9], TextId = 0, ValId = MEMU_VAR.PORT9_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT9_MODE], Format = formatTXRevert(PORT.PORT9) }
|
||||
ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=MODEL.PORT_TEXT[PORT.PORT10], TextId = 0, ValId = MEMU_VAR.PORT10_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT10_MODE], Format = formatTXRevert(PORT.PORT10) }
|
||||
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text=" Usually Rud/Ail needs to be the oposite of the TX", TextId = 0, ValId = 0x1031 }
|
||||
ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Only Thr/Ail/Rud/Ele. This affects AS3X/SAFE reaction dir./b", TextId = 0, ValId = 0x1031 }
|
||||
ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Any changes, use RX 'Relearn Servo Settings'/b", TextId = 0, ValId = 0x1031 }
|
||||
|
||||
ctx.SelLine = 0
|
||||
lastGoodMenu = menuId
|
||||
@@ -1030,8 +1031,8 @@ local function ST_Init_Text(rxId)
|
||||
List_Text[200+TAIL_TYPE.TRAILERON_B] = "Traileron B"; List_Text_Img[200+TAIL_TYPE.TRAILERON_B] = "tt_traileron.png|Traileron B"
|
||||
|
||||
-- Servo Reverse
|
||||
List_Text[300+CH_MODE_TYPE.NORMAL] = "Normal "
|
||||
List_Text[300+CH_MODE_TYPE.REVERSE] = "Reverted"
|
||||
List_Text[300+CH_MODE_TYPE.NORMAL] = "Normal "
|
||||
List_Text[300+CH_MODE_TYPE.REVERSE] = "Reverse"
|
||||
|
||||
end
|
||||
|
||||
|
||||
15
Lua_scripts/DSMLIB/MIN_msg_fwdp_en.txt
Normal file
15
Lua_scripts/DSMLIB/MIN_msg_fwdp_en.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
-- OVERRIDES Messges for MIN 128x64 screns
|
||||
-- FORMAT <LineType>|<Msg#>|<Text>
|
||||
-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX)
|
||||
-- IMPORTANT: NO EMPTY LINES
|
||||
--
|
||||
T |0x0097|DONT USE: Factory Reset
|
||||
T |0x0098|DONT USE: Factory Reset
|
||||
T |0x00A5|DONT USE: First Time Setup
|
||||
T |0x00B0|Self-Lev/Ang Dem
|
||||
T |0x00CD|Level model & capt attitude
|
||||
T |0x0190|DONT USE: Relearn Servo Settings
|
||||
T |0x020D|DONT USE: First Time SAFE Setup
|
||||
T |0x0254|Pos = Up, Neg = Down
|
||||
T |0x0267|Pos = Nose Up/Roll Right
|
||||
T |0x0268|Neg = Nose Down/Roll Left
|
||||
@@ -1,7 +0,0 @@
|
||||
This directory contains the DSM Forward programming settings
|
||||
for each model. Like Wing Type, Tail Type, and Channels assignments.
|
||||
|
||||
The name is the first 5 characters of the model and a hash number to make them unique.
|
||||
|
||||
If you want to REDO a model from scratch, just delete the file or change the Aircraft type to reset.
|
||||
|
||||
375
Lua_scripts/DSMLIB/msg_fwdp_en.txt
Normal file
375
Lua_scripts/DSMLIB/msg_fwdp_en.txt
Normal file
@@ -0,0 +1,375 @@
|
||||
-- FORMAT <LineType>|<Msg#>|<Text>
|
||||
-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX)
|
||||
-- NO EMPTY LINES
|
||||
-- Formmatting at end of line: /c=Center, /r=Right, /b=Bold, /m=menu
|
||||
LT|0x0001|Off
|
||||
LT|0x0002|On
|
||||
-- Ihn/Act List Options
|
||||
LT|0x0003|Inh
|
||||
LT|0x0004|Act
|
||||
--
|
||||
-- Channel selection for SAFE MODE and GAINS on FC6250HX
|
||||
LT|0x000C|Inhibit?
|
||||
LT|0x000D|Ch5
|
||||
LT|0x000E|Ch6
|
||||
LT|0x000F|Ch7
|
||||
LT|0x0010|Ch8
|
||||
LT|0x0011|Ch9
|
||||
LT|0x0012|Ch10
|
||||
LT|0x0013|Ch11
|
||||
LT|0x0014|Ch12
|
||||
--
|
||||
-- Servo Output values
|
||||
LT|0x002D|5.5ms
|
||||
LT|0x002E|11ms
|
||||
LT|0x002F|22ms
|
||||
--
|
||||
-- Gain Multiplier Values
|
||||
LT|0x0032|1 X
|
||||
LT|0x0033|2 X
|
||||
LT|0x0034|4 X
|
||||
--
|
||||
LT|0x0035|Inh?
|
||||
LT|0x0036|Thr
|
||||
LT|0x0037|Ail
|
||||
LT|0x0038|Ele
|
||||
LT|0x0039|Rud
|
||||
LT|0x003A|Ch5
|
||||
LT|0x003B|Ch6
|
||||
LT|0x003C|Ch7
|
||||
LT|0x003D|Ch8
|
||||
LT|0x003E|Ch9
|
||||
LT|0x003F|Ch10
|
||||
LT|0x0040|Ch11
|
||||
LT|0x0041|Ch12
|
||||
LT|0x0042|Ch13
|
||||
LT|0x0043|Ch14
|
||||
LT|0x0044|Ch15
|
||||
LT|0x0045|Ch16
|
||||
LT|0x0046|Ch17
|
||||
LT|0x0047|Ch18
|
||||
LT|0x0048|Ch19
|
||||
LT|0x0049|Ch20
|
||||
--
|
||||
T |0x0040|Roll
|
||||
T |0x0041|Pitch
|
||||
T |0x0042|Yaw
|
||||
T |0x0043|Gain/c/b
|
||||
T |0x0045|Differential
|
||||
T |0x0046|Priority
|
||||
T |0x0049|Output Setup
|
||||
T |0x004A|Failsafe
|
||||
T |0x004B|Main Menu
|
||||
T |0x004E|Position
|
||||
--
|
||||
T |0x0050|Outputs
|
||||
T |0x0051|Output Channel 1
|
||||
T |0x0052|Output Channel 2
|
||||
T |0x0053|Output Channel 3
|
||||
T |0x0054|Output Channel 4
|
||||
T |0x0055|Output Channel 5
|
||||
T |0x0056|Output Channel 6
|
||||
--
|
||||
-- FailSafe Options
|
||||
--LT|0x005E|Inhibit
|
||||
LT|0x005F|Hold Last
|
||||
LT|0x0060|Preset
|
||||
--LT|0x0061|Custom
|
||||
--
|
||||
T |0x0071|Proportional
|
||||
T |0x0072|Integral
|
||||
T |0x0073|Derivate
|
||||
--
|
||||
T |0x0078|FM Channel
|
||||
--
|
||||
T |0x0080|Orientation
|
||||
T |0x0082|Heading
|
||||
T |0x0085|Frame Rate
|
||||
T |0x0086|System Setup
|
||||
T |0x0087|F-Mode Setup
|
||||
T |0x0088|Enabled F-Modes
|
||||
T |0x0089|Gain Channel
|
||||
T |0x008A|Gain Sensitivity/r -- Right Align
|
||||
T |0x008B|Panic
|
||||
T |0x008E|Panic Delay
|
||||
--
|
||||
LT|0x008D|560hz
|
||||
--
|
||||
-- FC6250HX: Callibration Menu -> Begin..Start, Complete, Done
|
||||
T |0x0091|Begin
|
||||
T |0x0090|Apply
|
||||
T |0x0092|Start
|
||||
T |0x0093|Complete
|
||||
T |0x0094|Done
|
||||
--
|
||||
T |0x0097|Factory Reset
|
||||
T |0x0098|Factory Reset
|
||||
--
|
||||
T |0x0099|Advanced Setup
|
||||
T |0x009A|Capture Failsafe Positions
|
||||
T |0x009C|Custom Failsafe
|
||||
--
|
||||
T |0x009F|Save Settings -- Save & Reboot RX
|
||||
--
|
||||
T |0x00A5|First Time Setup
|
||||
T |0x00AA|Capture Gyro Gains
|
||||
T |0x00AD|Gain Channel Select
|
||||
T |0x00AF|Dynamic
|
||||
T |0x00B0|Self-Level/Angle Dem
|
||||
T |0x00B1|Envelope
|
||||
--
|
||||
-- Flight Modes List Options
|
||||
LT|0x00B5|Inhibit
|
||||
LT|0x00B6|FM1
|
||||
LT|0x00B7|FM2
|
||||
LT|0x00B8|FM3
|
||||
LT|0x00B9|FM4
|
||||
LT|0x00BA|FM5
|
||||
LT|0x00BB|FM6
|
||||
LT|0x00BC|FM7
|
||||
LT|0x00BD|FM8
|
||||
LT|0x00BE|FM9
|
||||
LT|0x00BF|FM10
|
||||
--
|
||||
T |0x00BE|Unknown_BE -- Used in Reset menu (0x0001) while the RX is rebooting
|
||||
--
|
||||
T |0x00C7|Calibrate Sensor
|
||||
T |0x00CA|SAFE/Panic Mode Setup
|
||||
--
|
||||
T |0x00CD|Level model and capture attitude/m -- SPECIAL MENU to itself who is not a comment
|
||||
--
|
||||
-- RX Orientations for AR631/AR637, Optionally attach an Image + Alt Text to display
|
||||
LT|0x00CB|Pos 1
|
||||
LI|0x00CB|rx_pos_1.png|Pilot View: RX Label Up, Pins Back
|
||||
LT|0x00CC|Pos 2
|
||||
LI|0x00CC|rx_pos_2.png|Pilot View: RX Label Left, Pins Back
|
||||
LT|0x00CD|Pos 3
|
||||
LI|0x00CD|rx_pos_3.png|Pilot View: RX Label Down, Pins Back
|
||||
LT|0x00CE|Pos 4
|
||||
LI|0x00CE|rx_pos_4.png|Pilot View: RX Label Right, Pins Back
|
||||
LT|0x00CF|Pos 5
|
||||
LI|0x00CF|rx_pos_5.png|Pilot View: RX Label UP, Pins to Front
|
||||
LT|0x00D0|Pos 6
|
||||
LI|0x00D0|rx_pos_6.png|Pilot View: RX Label Left, Pins Front
|
||||
LT|0x00D1|Pos 7
|
||||
LI|0x00D1|rx_pos_7.png|Pilot View: RX Label Down, Pins Front
|
||||
LT|0x00D2|Pos 8
|
||||
LI|0x00D2|rx_pos_8.png|Pilot View: RX Label Right, Pins Front
|
||||
LT|0x00D3|Pos 9
|
||||
LI|0x00D3|rx_pos_9.png|Pilot View: RX Label Up, Pins Left
|
||||
LT|0x00D4|Pos 10
|
||||
LI|0x00D4|rx_pos_10.png|Pilot View: RX Label Back, Pins Left
|
||||
LT|0x00D5|Pos 11
|
||||
LI|0x00D5|rx_pos_11.png|Pilot View: RX Label Down, Pins Left
|
||||
LT|0x00D6|Pos 12
|
||||
LI|0x00D6|rx_pos_12.png|Pilot View: RX Label Front, Pins Left
|
||||
LT|0x00D7|Pos 13
|
||||
LI|0x00D7|rx_pos_13.png|Pilot View: RX Label Up, Pins Right
|
||||
LT|0x00D8|Pos 14
|
||||
LI|0x00D8|rx_pos_14.png|Pilot View: RX Label Back, Pins Right
|
||||
LT|0x00D9|Pos 15
|
||||
LI|0x00D9|rx_pos_15.png|Pilot View: RX Label Down, Pins Right
|
||||
LT|0x00DA|Pos 16
|
||||
LI|0x00DA|rx_pos_16.png|Pilot View: RX Label Front, Pins Right
|
||||
LT|0x00DB|Pos 17
|
||||
LI|0x00DB|rx_pos_17.png|Pilot View: RX Label Back, Pins Down
|
||||
LT|0x00DC|Pos 18
|
||||
LI|0x00DC|rx_pos_18.png|Pilot View: RX Label Left, Pins Down
|
||||
LT|0x00DD|Pos 19
|
||||
LI|0x00DD|rx_pos_19.png|Pilot View: RX Label Front, Pins Down
|
||||
LT|0x00DE|Pos 20
|
||||
LI|0x00DE|rx_pos_20.png|Pilot View: RX Label Right, Pins Down
|
||||
LT|0x00DF|Pos 21
|
||||
LI|0x00DF|rx_pos_21.png|Pilot View: RX Label Back, Pins Up
|
||||
LT|0x00E0|Pos 22
|
||||
LI|0x00E0|rx_pos_22.png|Pilot View: RX Label Left, Pins Up
|
||||
LT|0x00E1|Pos 23
|
||||
LI|0x00E1|rx_pos_23.png|Pilot View: RX Label Front, Pins Up
|
||||
LT|0x00E2|Pos 24
|
||||
LI|0x00E2|rx_pos_24.png|Pilot View: RX Label Right, Pins Up
|
||||
LT|0x00E3|Pos Invalid
|
||||
LI|0x00E3|rx_pos_25.png|Cannot detect orientation of RX
|
||||
--
|
||||
T |0x00D1|Receiver will Reboot/b
|
||||
T |0x00D2|Panic Channel
|
||||
T |0x00D3|Swashplate
|
||||
T |0x00D5|Agility
|
||||
T |0x00D8|Stop
|
||||
T |0x00DA|SAFE/c/b -- Center + Bold
|
||||
T |0x00DB|Stability
|
||||
T |0x00DC|@ per sec
|
||||
T |0x00DD|Tail rotor
|
||||
T |0x00DE|Setup
|
||||
T |0x00DF|AFR
|
||||
T |0x00E0|Collective
|
||||
T |0x00E1|Subtrim
|
||||
T |0x00E2|Phasing
|
||||
T |0x00E4|E-Ring
|
||||
T |0x00E5|Swash Type
|
||||
T |0x00E6|Travel
|
||||
T |0x00E7|Left
|
||||
T |0x00E8|Right
|
||||
--
|
||||
LT|0x00F2|Fixed
|
||||
LT|0x00F3|Adjustable
|
||||
--
|
||||
T |0x00F6|Direction
|
||||
T |0x00F8|Settings -- ?? validate on a Spektrum radio
|
||||
T |0x00F9|Gyro settings
|
||||
T |0x00FE|Stick Priority/c/b
|
||||
--
|
||||
T |0x0100|Make sure the model has been
|
||||
T |0x0101|configured, including wing type,
|
||||
T |0x0102|reversing, travel, trimmed, etc.
|
||||
T |0x0103|before continuing setup.
|
||||
T |0x0104| -- Blank
|
||||
--
|
||||
T |0x0106|Any wing type, channel assignment,
|
||||
T |0x0107|subtrim, or servo reversing changes
|
||||
T |0x0108|require running through initial
|
||||
T |0x0109|setup again.
|
||||
T |0x010A| -- Blank
|
||||
--
|
||||
T |0x0190|Relearn Servo Settings
|
||||
T |0x019C|Enter Receiver Bind Mode
|
||||
T |0x01AA|Offset
|
||||
T |0x01D7|SAFE Select Channel
|
||||
T |0x01DC|AS3X/c/b -- Center + Bold
|
||||
T |0x01DD|AS3X Settings
|
||||
T |0x01DE|AS3X Gains
|
||||
T |0x01E0|Rate Gains/c/b
|
||||
T |0x01E2|SAFE Settings
|
||||
T |0x01E3|SAFE Gains
|
||||
T |0x01E6|Attitude Trim/c/b
|
||||
T |0x01E7|Envelope
|
||||
T |0x01E9|Roll Right
|
||||
T |0x01EA|Roll Left
|
||||
T |0x01EB|Pitch Down
|
||||
T |0x01EC|Pitch Up
|
||||
T |0x01EE|Thr to Pitch
|
||||
T |0x01EF|Low Thr to Pitch/c/b
|
||||
T |0x01F0|High Thr to Pitch/c/b
|
||||
T |0x01F3|Threshold
|
||||
T |0x01F4|Angle
|
||||
T |0x01F6|Failsafe Angles/c/b
|
||||
T |0x01F8|Safe Mode
|
||||
T |0x01F9|SAFE Select
|
||||
T |0x01FC|Panic F-Mode
|
||||
T |0x01FD|FailSafe Flight Mode -- Safe Flight Mode
|
||||
T |0x0201|Throttle
|
||||
T |0x0204|Hover
|
||||
T |0x0208|Decay
|
||||
T |0x0209|Save to Backup
|
||||
T |0x020A|Restore from Backup
|
||||
T |0x020D|First Time SAFE Setup
|
||||
--
|
||||
-- First time safe setup Page 3 :
|
||||
T |0x020E|AS3X gains must be tuned
|
||||
T |0x020F|and active in SAFE Flight Modes
|
||||
T |0x0210|to help reduce wobble.
|
||||
T |0x0211| -- Blank
|
||||
T |0x0212| -- Blank
|
||||
T |0x0213| -- Blank
|
||||
--
|
||||
-- AS3X orientation Setting menu (Level)
|
||||
T |0x021A|Set the model level,
|
||||
T |0x021B|and press Continue.
|
||||
T |0x021C| -- Blank
|
||||
T |0x021D| -- Blank
|
||||
--
|
||||
-- AS3X orientation Setting menu (Nose down)
|
||||
T |0x021F|Set the model on its nose,
|
||||
T |0x0220|and press Continue. If the
|
||||
T |0x0221|orientation on the next
|
||||
T |0x0222|screen is wrong go back
|
||||
T |0x0223|and try again.
|
||||
--
|
||||
T |0x0224|Continue
|
||||
T |0x0226|Angle Limits/c/b
|
||||
T |0x0227|Other settings
|
||||
T |0x0229|Set Orientation Manually
|
||||
--
|
||||
-- Factory Default Warning
|
||||
T |0x022B|WARNING!
|
||||
T |0x022C|This will reset the
|
||||
T |0x022D|configuration to factory
|
||||
T |0x022E|defaults. This does not
|
||||
T |0x022F|affect the backup config.
|
||||
T |0x0230| -- Blank
|
||||
--
|
||||
-- Backup Warning
|
||||
T |0x0231|This will overwrite the
|
||||
T |0x0232|backup memory with your
|
||||
T |0x0233|current configuartion.
|
||||
T |0x0234| -- Blank
|
||||
T |0x0235| -- Blank
|
||||
--
|
||||
-- Restore from Backup Warning
|
||||
T |0x0236|This will overwrite the
|
||||
T |0x0237|current config with
|
||||
T |0x0238|that which is in
|
||||
T |0x0239|the backup memory.
|
||||
T |0x023A| -- blank line
|
||||
--
|
||||
-- Utilities Copy flight modes
|
||||
T |0x023D|Copy F-Mode Settings
|
||||
T |0x023E|Source F-Mode
|
||||
T |0x023F|Target F-Mode
|
||||
--
|
||||
T |0x0240|Utilities
|
||||
--
|
||||
-- Gain Capture Page
|
||||
T |0x024C|Gains will be captured on
|
||||
T |0x024D|Captured gains will be
|
||||
T |0x024E|Gains on
|
||||
T |0x024F|were captured and changed
|
||||
T |0x0250|from Adjustable to Fixed
|
||||
--
|
||||
-- Utilities, Copy flight mode (Copy Confirmation, oveerriding FM)
|
||||
T |0x0251|Are you sure you want to ovewrite the "Target"
|
||||
T |0x0252|with the "Source" ?
|
||||
T |0x0253| -- Blank
|
||||
--
|
||||
T |0x0254|Postive = Up, Negative = Down
|
||||
--
|
||||
-- First time safe setup Page 1 (maybe ask to select Flight Mode cannel)
|
||||
T |0x0255|Before setting up SAFE
|
||||
T |0x0256|a Flight Mode channel
|
||||
T |0x0257|most be configured.
|
||||
--
|
||||
-- First time safe setup Page 2 (something related for flight mode)
|
||||
T |0x025A|Select the desired flight mode
|
||||
T |0x025B|switch position to adjust settings
|
||||
T |0x025C|for each flight mode
|
||||
T |0x025D| -- Blank
|
||||
T |0x025E| -- Blank
|
||||
--
|
||||
-- Utilities, Copy flight mode (Confirm)
|
||||
T |0x0259|YES
|
||||
T |0x0260|WARNING: "Target"
|
||||
T |0x0261|F-Mode will be overwritten
|
||||
T |0x0262|by "Source"
|
||||
--
|
||||
T |0x0263|Fixed/Adjustable Gains/c/b
|
||||
T |0x0266|Heading Gain/c/b
|
||||
T |0x0267|Positive = Nose Up/Roll Right
|
||||
T |0x0268|Negative = Nose Down/Roll Left
|
||||
T |0x0269|SAFE - Thr to Pitch
|
||||
T |0x026A|Use CAUTION for Yaw gain!/b
|
||||
--
|
||||
T |0x0300|No compatible DSM RX...
|
||||
T |0x0301|Waiting for RX to Restart
|
||||
--
|
||||
FM|0x8000|Flight Mode/c/b
|
||||
--
|
||||
RX|0x0001|AR636
|
||||
RX|0x0014|SPM4651T
|
||||
RX|0x0015|AR637T
|
||||
RX|0x0016|AR637TA
|
||||
RX|0x0018|FC6250HX
|
||||
RX|0x0019|AR630
|
||||
RX|0x001A|AR8360T
|
||||
RX|0x001B|AR8020T
|
||||
RX|0x001C|AR10360T
|
||||
RX|0x001E|AR631
|
||||
|
||||
@@ -1,54 +1,115 @@
|
||||
# Credits
|
||||
Code is based on the code/work by: Pascal Langer (Author of the Multi-Module)
|
||||
Rewrite/Enhancements by: Francisco Arzu
|
||||
|
||||
Rewrite/Enhancements By: Francisco Arzu
|
||||
Thanks to all the people volunteered to test it.
|
||||
|
||||
# Introduction
|
||||
# Introduction (v0.54)
|
||||
|
||||
This script library is a rewrite of the original DSM forward programming Lua
|
||||
Script. The goal was 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. Color/Touch Gui, Text only GUI, etc.
|
||||
This script library enhances the original DSM Forward Programming tool. DSM Forward Programming is needed to setup many of the new Spektrum Receivers with Gyro AS3X/SAFE features. For the Gyro (/Safe) to correct the plane in flight, it needs to move the right surfaces therefore the RX needs to know the configuration of the plane (Wing Type, Tail Type, Mixers, Servo Assignments, Servo Reverse). That info tells the RX where the aileron(s) are (one or two), where the elevator(s) are (one or two), V-Tail, Delta Wing, etc.
|
||||
|
||||
Changes and fixes
|
||||
1. Menus to be able to configure Plane in a similar way as Spektrum Radio
|
||||
1. Make "Gyro Settings"->"Initial Setup" works (Tested on AR631,AR637xx with PLANE type of arcraft)
|
||||
2. Properly reset and restart after initial configuration and SAFE changes.
|
||||
3. Write Log of the conversation between RX/TX. To be use for debugging when some reports a problem.
|
||||
4. Provide a simulation of RX to do GUI development in Companion, and undestand patterns of how the data is organized.
|
||||
Since EdgeTx/OpenTx doesn’t have an equivalent setup that is stored in the radio, we have to create our own version. This info is stored inside the `/MODELS/DSMDATA` directory/folder (which needs to be created by manually).
|
||||
|
||||
# Tested RXs
|
||||
- AR631/AR637xx Coded a hack to be able to make `Initial Setup` to work
|
||||
- FC6250HX (Helicopter)
|
||||
|
||||
Most RX will run without problems, it could be that some others receivers will need to apply the same hack as the AR631 for some specific menus to work.
|
||||
Since is RX and Menu specific, we cannot create a general hack.
|
||||
|
||||
Please report of you have test it with other receivers to update the documentation.
|
||||
|
||||
# Flight mode/Gain channels
|
||||
|
||||
I ran into a case where trying to set Aux2 or Aux3 for flight mode, but the RX was correcting it to Aux1.. the RX only was allowing Gear or Aux1 (AR631/AR637).
|
||||
This is because the RX don't know that we are using more than 6 channels. To make the RX aware that there are other channels, while edditing the channel, you have to toggle the switch to excersist the channel (3 times), and now the RX will recognize it.
|
||||
During `"Gyro Settings->initial setup"`, the RX asks the TX for model information behind the scenes. After setup, `"Gyro Settings->System Tools-> Relearn Servo Settings"` requests the TX configuration and stores it in the RX.
|
||||
|
||||
# Deployment
|
||||
Make sure to manually create `/MODELS/DSMDATA` . The script will complain at startup if it does not exist. Here the script saves the Spektrun settings for each of your models.
|
||||
|
||||
Uncompress the Zip file (ZIP version) into your local computer.
|
||||
In another window, open your TX SDCard and go to /SCRIPTS/TOOLS.
|
||||
|
||||
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first)
|
||||
|
||||
Copy the entire DSMLIB folder.
|
||||
Copy the main script you want to use (Color or B&W).
|
||||
|
||||
|
||||
Your TX SDCard should looks like this:
|
||||
|
||||
/SCRIPTS/TOOLS
|
||||
DSM FwdPrg_05_BW.lua -- black/white text only
|
||||
DSM FwdPrg_05_Color.lua -- Color and touch radios
|
||||
DSM FwdPrg_05_MIN.lua -- `NEW!` Minimalistic version for radios with LOW memory (cannot setup new planes)
|
||||
|
||||
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
|
||||
DsmFwPrgLib.lua -- DSM Protocol Message and Menu engine
|
||||
DsmFwPrgSIMLib.lua -- Simulation of AR631, FC6250HX (For GUI development)
|
||||
SetupLib.lua -- Model Setup Screens
|
||||
msg_fwdp_en.txt -- `NEW!` Messages for forward programing externalized. To support other langs
|
||||
|
||||
/SCRIPTS/TOOLS/DSMLIB/img -- Images for RX orientations
|
||||
|
||||
Other Directories
|
||||
|
||||
/MODELS/DSMDATA --(ALL CAPITALS) Data of model config (Wing Type, Servo Assignments)
|
||||
/LOGS/dsm_log.txt --Readable log of the last RX/TX session, usefull for debugging problems
|
||||
|
||||
When upgrading from a previous version of this tool, delete your /SCRIPTS/TOOLS/DSMLIB before copying the new one (if you customized your images, inside "DSMLIB/img" do a backup first)
|
||||
|
||||
# Common Questions
|
||||
1. `RX not accepting channels higher than Ch6 for Flight-mode o Gains:`
|
||||
V0.53 and newer: The RX is listening to channel changes for this options. Configure the Switch to the channel, togling once the switch will select the channel on the menu field.
|
||||
|
||||
2. `Why Ch1 says Ch1 (TX:Ch3/Thr)?`:
|
||||
Radios with Multi-Module are usually configured to work the standard AETR convention. Spektrum uses TAER. The multi-module does the conversion when transmitting the signals. So `Spektrum Ch1 (Throttle)` really comes from the `TX Ch3`. We show both information (+name from the TX output). If your multi-module/radio is setup as TAER, the script will not do the re-arrangement.
|
||||
|
||||
3. `If i change the model name, the original model settings are lost.` This is correct, the model name is used to generate the file name (inside /MODEL/DSMDATA) who stores the model configuration. Currently EdgeTx and OpenTX has differt features where i could get either the Model Name or the YAML file where the EdgeTX model configuration is stored.. to keep the code compatible, the model name is used.
|
||||
|
||||
4. `Reversing a channel in my TX do not reverse the AS3X/SAFE reaction.` Correct, the channel stick direction and the Gyro direction are two separate things.
|
||||
|
||||
4.1: First, you have setup your model so that the sticks and switches moves the surfaces in the right direction.
|
||||
|
||||
4.2: Go to the script, `Model Setup` and setup your wing type, tail type, and select the channel assigment for each surface. Leave the servo settings the same as the values in the TX to start.
|
||||
|
||||
4.3: AR63X family: Go to `Forward programming->Gyro Setting->Initial Setup` (New/factory reset), or `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` (not new RX). This will load your current Gyro servo settings into the plane's RX.
|
||||
|
||||
4.4: Verify that the AS3X and SAFE reacts in the proper direction. You can use the Flight mode confugured as "Safe Mode: Auto-Level" to see if it moves the surfaces in the right direction.
|
||||
|
||||
4.5: If a surface don't move in the right direction, go to the `Model Setup->Gyro Channel Reverse` to reverse the Gyro on the channels needed, and do again the `Forward programming->Gyro Setting->System Setup->Relearn Servo Settings` to tranfer the new settings to the RX.
|
||||
|
||||
4.6: Specktrum TX always passes the TX servo reverse as the Gyro Reverse, but on many OpenTX/EdgeTX radios, the Rud/Ail are usually reversed by default compared to Specktrum. So far i don't think that i can use this as a rule, that is why the `Gyro Channel Reverse` page exist.
|
||||
|
||||
---
|
||||
---
|
||||
|
||||
# Changes and fixes
|
||||
V0.54:
|
||||
1. Fix a problem in the Attitude Trim page (`Gyro Settings->System Setup->SAFE/Panic Setup->Attitude Trim`). It was not saving the values after exiting the menu. This is to change what SAFE considers "Level" flying.
|
||||
2. Wings 2-Ail 2-Flaps had a bug on the 2nd flap.
|
||||
3. New Minimalistic script (`DsmFwdPrg_05_MIN.lua`): For radios with very low memory (FrSky QX7, RM Zorro, others). It can only change existing settings, but does not have the Plane Setup menus to setup a completly new plane. In some radios, the very first time it runs (compile + run), it might give you a `not enouth memory` error.. try to run it again.
|
||||
4. External menu message file (DSMLIB/msg_en.txt and msg_MIN_es.txt). Intial work to do localization and different languages.
|
||||
|
||||
V0.53:
|
||||
1. Improved channel selection (Flight mode, Panic Channel, Gains Channel). Now during editing a channel, you can select any channel (>Ch4). Also, of you toggle the switch/channel it will populate the screen.
|
||||
2. Support for smaller screens (128x64) in B&W. The problem with this older radios is memory. In some, it does not have enouth memory to load the additional DSMLIB libraries.
|
||||
3. Fix formatting problem with some TX channel names who could affect the screen.. for example, rud channel should show "Ch4/rud", but shows "Ch4ud" because /r is for right justify formatting on messages. Now the formatting is only if it appears at the end of the message.
|
||||
|
||||
V0.52:
|
||||
1. Menus to be able to configure Plane in a similar way as Spektrum Radio (v0.52)
|
||||
2. Make "Gyro Settings"->"Initial Setup" works (Tested on AR631,AR637xx with PLANE type of aircraft)
|
||||
3. Properly reset and restart after initial configuration and SAFE changes.
|
||||
4. Write Log of the conversation between RX/TX. To be used for debugging a problem is reported.
|
||||
5. Provide a simulation of RX to do GUI development in Companion, and understand patterns of how the data is organized.
|
||||
|
||||
# Tested Hardware
|
||||
- AR631/AR637xx
|
||||
- FC6250HX (Blade 230S V2 Helicopter)
|
||||
- AR636 (Blade 230S V1 Heli firmware 4.40)
|
||||
|
||||
- Radiomaster TX16S (All versions)
|
||||
- FrSky QX7, Radimaster Boxter (Minimalistic version)
|
||||
|
||||
Please report if you have tested it with other receivers to allow us to update the documentation. Code should work up to 10 channels for the main surfaces (Ail/Ele/etc). All Spektrum RX are internally 20 channels, so you can use Ch7 for Flight Mode even if your RX is only 6 channels (See common Questions)
|
||||
|
||||
/SCRIPTS/TOOLS/DsmFwdPrg_05_BW.lua -- black/white text only radios
|
||||
/SCRIPTS/TOOLS/DsmFwdPrg_05_Color.lua -- Color+touch radios
|
||||
/SCRIPTS/TOOLS/DSMLIB/ -- (ALL CAPITALS) Libraries ane extra files
|
||||
/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua -- DSM Protocol Message and Menu engine
|
||||
/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgSIMLib.lua -- Simulation of AR631, FC6250HX
|
||||
/SCRIPTS/TOOLS/DSMLIB/SetupLib.lua -- Model Setup Screns
|
||||
/SCRIPTS/TOOLS/DSMLIB/img --Images for RX orientations
|
||||
/SCRIPTS/TOOLS/DSMLIB/data --Data of model config (Wing Type, Servo Assigments)
|
||||
/LOGS/dsm_log.txt --Readable log of the last RX/TX session, usefull for debuging new RX
|
||||
|
||||
# Messages Displayed in the GUI
|
||||
|
||||
If in a screen you get text that looks like `Unknown_XX` (ex: Unknown_D3), that message has not been setup in the script in english. If you can get what is the proper message, you can send us a message to be added to the library.
|
||||
If in a screen you get text that looks like `Unknown_XX` (ex: Unknown_D3), that message has not been setup in the script in english. If you can determine what the proper message is, you can send us a message to be added to the library.
|
||||
The `XX` represents a Hex Number (0..9,A..F) message ID.
|
||||
|
||||
If you want to fix it in your local copy, all messages are towards the end in the file `SCRIPT\TOOS\DSMLIB\DsmFwPrgLib.lua`. Messages for Haders are stored in `Text` and messages for Options are stored in `List_Text`. Lua scripts are text files, and can be editted with Notepad or equivalent.
|
||||
|
||||
### Version 0.53 and older:
|
||||
If you want to fix it in your local copy, all messages are towards the end in the file `SCRIPT\TOOS\DSMLIB\DsmFwPrgLib.lua`. Messages for Headers are stored in `Text` and messages for Options are stored in `List_Text`. Lua scripts are text files, and can be edited with Notepad or equivalent.
|
||||
|
||||
Portion of DsmFwPrgLib.lua:
|
||||
|
||||
@@ -64,7 +125,7 @@ Portion of DsmFwPrgLib.lua:
|
||||
Text[0x00AA] = "Capture Gyro Gains"
|
||||
Text[0x00AD] = "Gain Channel Select"
|
||||
|
||||
-- Safe mode options, Ihnibit + thi values
|
||||
-- Safe mode options, Inhibit + the values
|
||||
local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope
|
||||
List_Text[0x00B0] = "Self-Level/Angle Dem"
|
||||
List_Text[0x00B1] = "Envelope"
|
||||
@@ -78,12 +139,18 @@ For example, if you get `Unknown_9D` in the GUI and your now that it should say
|
||||
|
||||
Text[0x009F] = "Save & Reset RX" -- TODO: Find the proper Spektrum text
|
||||
|
||||
### Version 0.54 and newer:
|
||||
The menu messages are stored in DSMLIB/msg_fwdp_en.txt (For english). Just add the message there. MIN_msg_fwdp_en.txt has shorter messages overrides for screens who are smaller (for minimalistic 128x64 version). The reference to the message file is at the file `/DSMLIB/DsmFwPrgLib.lua` if you want to change to use another language.
|
||||
|
||||
T |0x0097|Factory Reset
|
||||
LT|0x00B0|Self-Level/Angle Dem
|
||||
LT|0x00B1|Envelope
|
||||
|
||||
# LOG File
|
||||
|
||||
The log file of the last use of the script is located at `/LOGS/dsm_log.txt`. **It is overriden on every start to avoid filling up the SD card**. So if you want to keep it, copy or rename it before starting the script again. (can be renamed in the TX by browsing the SD card)
|
||||
The log file of the last use of the script is located at `/LOGS/dsm_log.txt`. **It is overridden on every start to avoid filling up the SD card**. So if you want to keep it, copy or rename it before starting the script again. (it can be renamed in the TX by browsing the SD card)
|
||||
|
||||
The log is human readable. The first number is the number of seconds since the start, and then what is the current state of the Library, and what is been sent and received. The info in the log can be easilly used to create a new simulation for that RX in the future.
|
||||
The log is human readable. The first number is the number of seconds since the start, and then what is the current state of the Library, and what has been sent and received. The info in the log can be easily used to create a new simulation for that RX in the future.
|
||||
|
||||
Example Log:
|
||||
|
||||
@@ -100,78 +167,61 @@ Example Log:
|
||||
5.970 MENU_LINES: RESPONSE MenuLine: L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ]
|
||||
6.020 MENU_LINES: SEND DSM_getNextLine(MenuId=0x1010,LastLine=3
|
||||
|
||||
Exmple of the Unknown_0x05 Lines correctly processed (receiving lines 0..5):
|
||||
|
||||
0.130 MENU_TITLE: SEND DSM_getMainMenu()
|
||||
0.230 MENU_TITLE: RESPONSE Menu: M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"[0x4B]]
|
||||
0.280 MENU_LINES: SEND DSM_getFirstMenuLine(MenuId=0x1000)
|
||||
0.400 MENU_LINES: RESPONSE MenuUknownLine_0x05: LineNum=0 DATA=RX: 09 05 00 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
0.460 MENU_UNKNOWN_LINES: CALL DSM_getNextUknownLine_0x05(LastLine=0)
|
||||
0.550 MENU_UNKNOWN_LINES: RESPONSE MenuUknownLine_0x05: LineNum=1 DATA=RX: 09 05 01 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
0.600 MENU_UNKNOWN_LINES: CALL DSM_getNextUknownLine_0x05(LastLine=1)
|
||||
0.700 MENU_UNKNOWN_LINES: RESPONSE MenuUknownLine_0x05: LineNum=2 DATA=RX: 09 05 02 01 00 00 00 07 00 00 00 00 00 00 00 00
|
||||
0.760 MENU_UNKNOWN_LINES: CALL DSM_getNextUknownLine_0x05(LastLine=2)
|
||||
|
||||
|
||||
# Validation of data by the RX
|
||||
|
||||
When you change a value in the GUI, the RX validates that the value is valid.
|
||||
For example, I ran into a case where trying to set Aux2 or Aux3 for flight mode, but the RX was correcting it back to Aux1.. the RX only was allowing Gear or Aux1 (AR631/AR637).. in this case, toggle the Switch while editing it on the screen.
|
||||
|
||||
If you go to the logs, you can see that the RX was correcting the value:
|
||||
|
||||
20.520 VALUE_CHANGE_END: SEND DSM_updateMenuValue(ValueId=0x1000,val=7) Extra: Text="FM Channel" Value=7|"Aux2"
|
||||
20.570 VALUE_CHANGE_END: SEND DSM_validateMenuValue(ValueId=0x1000) Extra: Text="FM Channel" Value=7|"Aux2"
|
||||
20.680 VALUE_CHANGE_END: RESPONSE MenuValue: UPDATED: L[#0 T=L_m1 VId=0x1000 Text="FM Channel"[0x78] Val=6|"Aux1" NL=(0->32,0,S=53) [53->85,53] MId=0x7CA6 ]
|
||||
|
||||
The RX validates the data. if you change to an invalid channel or do a invalid number range, the RX will change it at the end of editing the field.
|
||||
|
||||
---
|
||||
# Version 0.53
|
||||
- Improve Channel selection in menus
|
||||
- Support smaller screens 128x64 in the black/white mode.
|
||||
|
||||
# Version 0.52
|
||||
- Fix Reversing of Servos
|
||||
- Properly detect Moltimodule Ch settings AETR
|
||||
- Properly detect Multimodule Ch settings AETR
|
||||
---
|
||||
|
||||
# Version 0.51
|
||||
# Version 0.51 (volunteer testing version, not for production)
|
||||
- New Screens to Configure Model (Wing Type/Tail Tail, etc)
|
||||
- Finally got understanding that the previous unknown 0x05 lines are to send Model/Servo data to RX.
|
||||
- Fix use of AR636B (Firmare version 4.40.0 for Blade 230 heli, is the only one with Forward Programing)
|
||||
- Fix use of AR636B (Firmware version 4.40.0 for Blade 230 heli, is the only one with Forward Programming)
|
||||
- Aircraft types: Tested With Plane type only.. Glider and other in progress
|
||||
|
||||
### Know Problems:
|
||||
### Known Problems:
|
||||
- 4-Servo Wing type (Dual Ail/Tail) in planes give conflicting servo assignments by defaults.. Solution choose your own Ch.
|
||||
- Glider, Heli, Drong: Still in development. In glider, only a few wing type works.. needs to restrict menu options for the only valid one.
|
||||
- Glider, Heli, Drone: Still in development. In glider, only a few wing type works.. needs to restrict menu options for the only valid one.
|
||||
|
||||
|
||||
# Version 0.5
|
||||
|
||||
- Make the code more readable and understadable
|
||||
- Separate the DSM Forwards Programing logic from the GUI
|
||||
- Log the comunnication with the RX on a /LOGS/dsm_log.txt to allow to debug it easier
|
||||
- Make the code more readable and understandable
|
||||
- Separate the DSM Forwards Programming logic from the GUI
|
||||
- Log the communication with the RX on a /LOGS/dsm_log.txt to allow to debug it easier
|
||||
and see the exchange of data between the RX/TX
|
||||
- Created a black/white Text only version with only Key/Roller Inputs
|
||||
- Created a nicer GUI for EdgeTX touchscreen color Radios
|
||||
- Created a nicer GUI for EdgeTX touch screen color Radios
|
||||
- RX simulation for GUI development: turn on `SIMULATION_ON=true` in the beginning of the lua file
|
||||
- Test it on AR631, AR637xx, FC6250HX (Helicopter)
|
||||
|
||||
|
||||
### Some settings that can change (top of Lua file):
|
||||
SIMULATION_ON = false -- FALSE: use real communication to DSM RX (DEFAULT), TRUE: use a simulated version of RX
|
||||
SIMULATION_ON = false -- FALSE: hide similation menu (DEFAULT), TRUE: show RX simulation menu
|
||||
DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm_log.txt)
|
||||
DEBUG_ON_LCD = false -- Interactive Information on LCD of Menu data from RX
|
||||
USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX, OpenTX handle colors different)
|
||||
|
||||
|
||||
### Known Problems:
|
||||
1. **Incorrect List Value Options:** Some Menu List line (`LINE_TYPE.LIST_MENU1` or `L_m1` in logs), the range (min/max) of valid values seems to be incorrect, but cannot see in the data how to fix it.
|
||||
Some of the valid values are not even sequential, very spread apart. There has to be a list of valid options somewhere. Currently fixed some by overriding the valid values in the script code (config for each field).
|
||||
1. **Incorrect List Value Options:** Some Menu List line (`LINE_TYPE.LIST_MENU1` or `L_m1` in logs), the range (min/max) of valid values seems to be incorrect, but the RX corrects the values.
|
||||
in the MINimalistic version, the RX is doing all the range validation, and will show invalid options temporarilly. In an Spektrum radio, it happens so fast, that you don't notice it, but in LUA scripts who are slower, you can see it in the screen.
|
||||
In the COLOR version, The code has hardcoded the valid ranges to avoid this problem.
|
||||
|
||||
2. **Unable to Load menu lines**: The RX return unknow lines when requesting menu lines. **Realy don't understand what they are for**. Some menus
|
||||
seems to stay stuck in the same return line or no response to the request, making the RX reset/close the connection and terminate.
|
||||
Was able to hack it for AR631/AR637 `"First Time Setup"`, `"First Time SAFE Setup"`, and `"Servo Realm"`. Maybe this hack will work in other RX, so let us know if you get this problem.
|
||||
|
||||
|
||||
2. Glider/Heli/Drone wing types not ready.
|
||||
|
||||
For Helicopter, use airplane normal wing and normal tail
|
||||
|
||||
|
||||
# Version 0.2
|
||||
Original Version from Pascal Langer
|
||||
|
||||
|
||||
|
||||
683
Lua_scripts/DSM_AR636_Tel.lua
Normal file
683
Lua_scripts/DSM_AR636_Tel.lua
Normal file
@@ -0,0 +1,683 @@
|
||||
local toolName = "TNS|DSM AR636 Telemetry|TNE"
|
||||
---- ######################################################################### #
|
||||
---- # 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. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Developer: Francisco Arzu
|
||||
-- Original idea taken from DsmPID.lua.. don't know who is the author
|
||||
--
|
||||
|
||||
local DEBUG_ON = false
|
||||
--
|
||||
|
||||
local TEXT_SIZE = 0 -- NORMAL
|
||||
local X_COL1_HEADER = 6
|
||||
local X_COL1_DATA = 60
|
||||
local X_COL2_HEADER = 170
|
||||
local X_COL2_DATA = 220
|
||||
local Y_LINE_HEIGHT = 20
|
||||
local Y_HEADER = 0
|
||||
local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2
|
||||
local X_DATA_LEN = 80
|
||||
local X_DATA_SPACE = 5
|
||||
|
||||
|
||||
local function getPage(iParam)
|
||||
-- get page from 0-based index
|
||||
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
|
||||
local res = (math.floor(iParam/4)==0) and 0 or 1
|
||||
return res
|
||||
end
|
||||
|
||||
local function round(v)
|
||||
-- round float
|
||||
local factor = 100
|
||||
return math.floor(v * factor + 0.5) / factor
|
||||
end
|
||||
|
||||
|
||||
local function readValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
--v = round(v)
|
||||
return v
|
||||
end
|
||||
|
||||
local function readValueById(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return nil end
|
||||
|
||||
local v = getValue(i.id)
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function readBatValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
if (v==nil) then return "--" end
|
||||
|
||||
return string.format("%2.2f",v)
|
||||
end
|
||||
|
||||
local function readActiveParamValue(sensor)
|
||||
-- read and return a validated active parameter value
|
||||
local v = getValue(sensor)
|
||||
if (v<1 or v>8) then
|
||||
return -1
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
local function drawPIDScreen()
|
||||
-- draw labels and params on screen
|
||||
|
||||
local pageId = getValue("FLss")
|
||||
|
||||
lcd.clear()
|
||||
-- if active gain does not validate then assume
|
||||
-- Gain Adjustment Mode is disabled
|
||||
if not (pageId==4401 or pageId==4402) then
|
||||
lcd.drawText(0,0,"BLADE Gain Adjustment", TEXT_SIZE +INVERS)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Gain Adjustment Mode",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/R + Low/R + Panic (3 sec)",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: Right Stk: Up/Down to select, Left/Right change value",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE)
|
||||
return
|
||||
end
|
||||
|
||||
local activePage = (pageId % 100)-1 --Last 2 digits, make it zero base
|
||||
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Cyclic (0-200)", TEXT_SIZE + INVERS)
|
||||
lcd.drawText (X_COL2_HEADER, Y_HEADER, "Tail (0-200)", TEXT_SIZE + INVERS)
|
||||
|
||||
|
||||
|
||||
local p = readValue("FdeA")
|
||||
local i = readValue("FdeB")
|
||||
local d = readValue("FdeL")
|
||||
local r = readValue("FdeR")
|
||||
|
||||
local titles = {[0]="P:", "I:", "D:", "Resp:", "P:","I:","D:", "Filt:"}
|
||||
local values = {[0]=p,i,d,r,p,i,d,r}
|
||||
|
||||
local activeParam = readActiveParamValue("Hold")-1
|
||||
|
||||
for iParam=0,7 do
|
||||
-- highlight selected parameter
|
||||
local attr = (activeParam==iParam) and INVERS or 0
|
||||
-- circular index (per page)
|
||||
local perPageIndx = (iParam % 4)
|
||||
|
||||
-- set y draw coord
|
||||
local y = (perPageIndx+1)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- check if displaying cyclic params.
|
||||
local isCyclicPage = (getPage(iParam)==0)
|
||||
|
||||
-- labels
|
||||
local x = isCyclicPage and X_COL1_HEADER or X_COL2_HEADER
|
||||
-- labels are P,I,D for both pages except for last param
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- gains
|
||||
-- set all params for non-active page to '--' rather than 'last value'
|
||||
val = (getPage(iParam)==activePage) and values[iParam] or '--'
|
||||
x = isCyclicPage and X_COL1_DATA or X_COL2_DATA
|
||||
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function drawFlightLogScreen()
|
||||
-- draw labels and params on screen
|
||||
local h = getValue("Hold")
|
||||
local activeParam = h-1 -- H
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS)
|
||||
|
||||
-- read and return parameters
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
local r = getValue("FdeR")
|
||||
local f = getValue("FLss")
|
||||
|
||||
local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"}
|
||||
local values = {[0]=a,b,l,r,f,h}
|
||||
|
||||
local y = Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
for iParam=0,3 do -- A,B,L,R
|
||||
-- highlight selected parameter (rund)
|
||||
local attr = ((activeParam%4)==iParam) and INVERS or 0
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA + X_DATA_LEN
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_LINE_HEIGHT+Y_DATA
|
||||
for iParam=4,5 do -- F, H
|
||||
-- labels
|
||||
local x = X_COL2_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + BOLD)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL2_DATA + X_DATA_LEN
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
local bat = readBatValue("A2") or "--"
|
||||
lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE)
|
||||
|
||||
end
|
||||
|
||||
local function servoAdjustScreen()
|
||||
-- draw labels and params on screen
|
||||
local pageId = getValue("FLss") -- FLss
|
||||
local activeParam = getValue("Hold")-1 -- Hold
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0, Y_HEADER, "BLADE Servo SubTrim", TEXT_SIZE + INVERS)
|
||||
|
||||
if pageId~=1234 then
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Servo Adjustment Mode",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/L + Low/R + Panic (3 sec)",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: R Stk: Up/Down to select, Left/Right change value",TEXT_SIZE)
|
||||
lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE)
|
||||
return
|
||||
end
|
||||
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
|
||||
local titles = {[0]="Servo1:", "Servo2:", "Servo3:"}
|
||||
local values = {[0]=a,b,l}
|
||||
|
||||
for iParam=0,#values do -- S1,S2,S3
|
||||
-- highlight selected parameter
|
||||
local attr = (activeParam==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam+1)*Y_LINE_HEIGHT+Y_HEADER
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Unsigned_to_SInt16(value)
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function getDegreesValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%0.1f o",vs/10)
|
||||
end
|
||||
|
||||
|
||||
local function getDecHexValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%d (0x%04X)",vs,v)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function drawVersionScreen()
|
||||
local paramV = getValue("FdeA")
|
||||
local B = getValue("FdeB")
|
||||
local rxId = getValue("FdeL")
|
||||
local firmware = getValue("FLss")
|
||||
local prodId = getValue("Hold")
|
||||
local bat = readBatValue("A2")
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0, Y_HEADER, "BLADE Version", TEXT_SIZE + INVERS)
|
||||
|
||||
--Product ID
|
||||
local val = "ID_".. prodId
|
||||
|
||||
if (prodId==243) then val = "Blade 230 V1"
|
||||
elseif (prodId==250) then val = "Blade 230 V2 (not Smart)"
|
||||
elseif (prodId==149) then val = "Blade 250 CFX"
|
||||
end
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
lcd.drawText (X_COL1_HEADER, y, "Prod:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- RX
|
||||
val = "ID_"..rxId
|
||||
if (rxId==1) then val = "AR636"
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "RX:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- Firmware
|
||||
val = string.format("%0.2f",firmware/100)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Firmware:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, val, TEXT_SIZE)
|
||||
|
||||
-- ParamV
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Params:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, paramV, TEXT_SIZE)
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1, y, bat, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText(X_COL1_HEADER,y,"Press Panic for 3s",TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText(X_COL1_HEADER,y,"Usually Panic is Ch7 on a switch and Revesed",TEXT_SIZE)
|
||||
|
||||
end
|
||||
|
||||
local function parseFlightMode(v)
|
||||
-- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0= off, 1=init, 2=Hold, 3=Running) GG=???
|
||||
if v==nil then return "---" end
|
||||
local fm = bit32.rshift(v, 12)
|
||||
local status = bit32.band(bit32.rshift(v, 8),0xF)
|
||||
|
||||
local res = " "..fm.." "
|
||||
|
||||
if (fm==0) then res = res .. " NORMAL"
|
||||
elseif (fm==1) then res = res .. " INTERMEDIATE"
|
||||
elseif (fm==2) then res = res .. " ADVANCED"
|
||||
elseif (fm==5) then res = res .. " PANIC"
|
||||
end
|
||||
|
||||
if (status==2) then res=res .. " HOLD" end
|
||||
|
||||
if (DEBUG_ON) then
|
||||
res = res .. string.format(" (0x%04X)",v)
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
|
||||
local function drawAlpha6Monitor()
|
||||
lcd.clear()
|
||||
|
||||
local RxStatus = readValueById("2402") -- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0=init, 2=Ready, 3=Sensor Fault) GG=???
|
||||
|
||||
local ARoll = getDegreesValue("2406") --Att Roll
|
||||
local APitch = getDegreesValue("2408") --Att Pitch
|
||||
local AYaw = getDegreesValue("240B") --Att Yaw
|
||||
|
||||
|
||||
lcd.drawText (0,0, "BLADE Alpha6 Monitor", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL1_DATA+X_DATA_LEN*2
|
||||
local x_data3 = X_COL1_DATA+X_DATA_LEN*3
|
||||
|
||||
-- Flight Mode
|
||||
lcd.drawText (0,y, "F-Mode:"..parseFlightMode(RxStatus), TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (x_data1,y, "Attitude", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data2,y, "Gyro", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data3,y, "Gain", TEXT_SIZE+BOLD + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Rol:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, ARoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, APitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, AYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT + Y_LINE_HEIGHT
|
||||
lcd.drawText (0,y, "Bat: "..readBatValue("A2").." v", TEXT_SIZE)
|
||||
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local s2400 = getDecHexValue("2400")
|
||||
local s2402 = getDecHexValue("2402")
|
||||
local s2404 = getDecHexValue("2404")
|
||||
|
||||
local s240D = getDecHexValue("240D")
|
||||
|
||||
local s1G00 = getDecHexValue("1G00")
|
||||
local s1G02 = getDecHexValue("1G02")
|
||||
local s1G04 = getDecHexValue("1G04")
|
||||
local s1G06 = getDecHexValue("1G06")
|
||||
local s1G08 = getDecHexValue("1G08")
|
||||
local s1G0B = getDecHexValue("1G0B")
|
||||
local s1G0D = getDecHexValue("1G0D")
|
||||
|
||||
local titles = {[0]=
|
||||
"2400","2402/FM-S-?",
|
||||
"2404","240D",
|
||||
"1G00","1G02","1G04",
|
||||
"1G06","1G08","1G0B","1G0D"}
|
||||
|
||||
local values = {[0]=
|
||||
s2400,s2402,s2404,s240D,
|
||||
s1G00,s1G02,s1G04,
|
||||
s1G06,s1G08,s1G0B,s1G0D}
|
||||
|
||||
|
||||
-- draw labels and params on screen
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#titles do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+220
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function readAlpha3arameters()
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function drawAS3XMonitor()
|
||||
lcd.clear()
|
||||
local s1G00 = getDecHexValue("1G00")
|
||||
local s1G02 = getDecHexValue("1G02")
|
||||
local s1G04 = getDecHexValue("1G04")
|
||||
local s1G06 = getDecHexValue("1G06")
|
||||
local s1G08 = getDecHexValue("1G08")
|
||||
local s1G0B = getDecHexValue("1G0B")
|
||||
local s1G0D = getDecHexValue("1G0D")
|
||||
|
||||
local s6C00 = getDecHexValue("6C00")
|
||||
local s6C02 = getDecHexValue("6C02")
|
||||
local s6C04 = getDecHexValue("6C04")
|
||||
|
||||
|
||||
|
||||
local RRoll = bit32.rshift(getValue("1G00") or 0,8)
|
||||
local RPitch = bit32.band(getValue("1G00") or 0,0xFF)
|
||||
local RYaw = bit32.rshift(getValue("1G02") or 0,8)
|
||||
|
||||
local HRoll = bit32.band(getValue("1G02") or 0,0xFF)
|
||||
local HPitch = bit32.rshift(getValue("1G04") or 0,8)
|
||||
local HYaw = bit32.band(getValue("1G04") or 0,0xFF)
|
||||
|
||||
local ARoll = bit32.rshift(getValue("1G06") or 0,8)
|
||||
local APitch = bit32.band(getValue("1G06") or 0,0xFF)
|
||||
local AYaw = bit32.rshift(getValue("1G08") or 0,8)
|
||||
|
||||
|
||||
lcd.drawText (0,0, "Plane AR636 AS3X Gains", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL1_DATA+X_DATA_LEN*2
|
||||
local x_data3 = X_COL1_DATA+X_DATA_LEN*3.1
|
||||
|
||||
-- Flight Mode
|
||||
--lcd.drawText (0,y, "F-Mode: "..(nil or "--"), TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (x_data1,y, "Rate", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data2,y, "Head", TEXT_SIZE+BOLD + RIGHT)
|
||||
lcd.drawText (x_data3+X_DATA_SPACE*3,y, "Actual", TEXT_SIZE+BOLD + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RRoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HRoll, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, ARoll, TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RPitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HPitch, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, APitch, TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw %:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, RYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data2,y, HYaw, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, AYaw, TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local Alpha3Tags = {[0]=
|
||||
"1G00/RA+RE","1G02/RY+HA","1G04R HP+HY","1G06/AR+AP","1G08/AY+?","1G0B","1G0D","6C00","6C02","6C04"}
|
||||
|
||||
local params = {[0]=
|
||||
s1G00,s1G02,s1G04,s1G06,s1G08,s1G0B,s1G0D,s6C00,s6C02,s6C04 }
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#Alpha3Tags do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+220
|
||||
local val = Alpha3Tags[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = params[iParam]
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function openTelemetryRaw(i2cId)
|
||||
--Init telemetry (Spectrun Telemetry Raw STR)
|
||||
multiBuffer( 0, string.byte('S') )
|
||||
multiBuffer( 1, string.byte('T') )
|
||||
multiBuffer( 2, string.byte('R') )
|
||||
multiBuffer( 3, i2cId ) -- Monitor this teemetry data
|
||||
multiBuffer( 4, 0 ) -- Allow to get Data
|
||||
end
|
||||
|
||||
local function closeTelemetryRaw()
|
||||
multiBuffer(0, 0) -- Destroy the STR header
|
||||
multiBuffer(3, 0) -- Not requesting any Telementry ID
|
||||
end
|
||||
|
||||
local lineText = {nil}
|
||||
local I2C_TEXT_GEN = 0x0C
|
||||
|
||||
local function drawTextGen(event)
|
||||
if (multiBuffer(0)~=string.byte('S')) then -- First time run???
|
||||
openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN
|
||||
lineText = {nil}
|
||||
end
|
||||
|
||||
-- Proces TEXT GEN Telementry message
|
||||
if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received
|
||||
local instanceNo = multiBuffer( 5 )
|
||||
local lineNo = multiBuffer( 6 )
|
||||
local line = ""
|
||||
for i=0,13 do
|
||||
line = line .. string.char(multiBuffer( 7 + i ))
|
||||
end
|
||||
|
||||
multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message
|
||||
lineText[lineNo]=line
|
||||
end
|
||||
|
||||
lcd.clear()
|
||||
-- Header
|
||||
if (lineText[0]) then
|
||||
lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS)
|
||||
else
|
||||
lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS)
|
||||
end
|
||||
|
||||
-- Menu lines
|
||||
local y = Y_DATA
|
||||
for i=1,8 do
|
||||
if (lineText[i]) then
|
||||
lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data
|
||||
closeTelemetryRaw()
|
||||
end
|
||||
end
|
||||
|
||||
local telPage = 1
|
||||
local telPageSelected = 0
|
||||
local pageTitle = {[0]="Main", "Blade Version", "Blade Servo Adjust","Blade Gyro Adjust", "Blade Alpha6 Monitor", "Plane AS3X Monitor", "TextGen", "Flight Log"}
|
||||
|
||||
local function drawMainScreen(event)
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (AR636)", TEXT_SIZE + INVERS)
|
||||
|
||||
for iParam=1,#pageTitle do
|
||||
-- highlight selected parameter
|
||||
local attr = (telPage==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam-1)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = pageTitle[iParam]
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
if (telPage>1) then telPage = telPage - 1 end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
if (telPage<#pageTitle) then telPage = telPage + 1 end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
telPageSelected = telPage
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local pageDraw = {[0]=drawMainScreen, drawVersionScreen, servoAdjustScreen,drawPIDScreen, drawAlpha6Monitor, drawAS3XMonitor, drawTextGen, drawFlightLogScreen}
|
||||
|
||||
local function run_func(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
end
|
||||
|
||||
-- draw specific page
|
||||
pageDraw[telPageSelected](event)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if (telPageSelected==0) then return 1 end -- on Main?? Exit Script
|
||||
telPageSelected = 0 -- any page, return to Main
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function init_func()
|
||||
|
||||
if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens
|
||||
TEXT_SIZE = SMLSIZE
|
||||
X_COL1_HEADER = 0
|
||||
X_COL1_DATA = 20
|
||||
|
||||
X_COL2_HEADER = 60
|
||||
X_COL2_DATA = 90
|
||||
|
||||
X_DATA_LEN = 28
|
||||
X_DATA_SPACE = 1
|
||||
|
||||
|
||||
Y_LINE_HEIGHT = 8
|
||||
Y_DATA = Y_HEADER + Y_LINE_HEIGHT
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return { run=run_func, init=init_func }
|
||||
603
Lua_scripts/DSM_SmartRX_Tel.lua
Normal file
603
Lua_scripts/DSM_SmartRX_Tel.lua
Normal file
@@ -0,0 +1,603 @@
|
||||
local toolName = "TNS|DSM Smart RX Telemetry|TNE"
|
||||
---- ######################################################################### #
|
||||
---- # 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. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Developer: Francisco Arzu
|
||||
|
||||
|
||||
local DEBUG_ON = false
|
||||
--
|
||||
|
||||
local TEXT_SIZE = 0 -- NORMAL
|
||||
local X_COL1_HEADER = 6
|
||||
local X_COL1_DATA = 60
|
||||
local X_COL2_HEADER = 170
|
||||
local X_COL2_DATA = 220
|
||||
local Y_LINE_HEIGHT = 20
|
||||
local Y_HEADER = 0
|
||||
local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2
|
||||
local X_DATA_LEN = 80
|
||||
local X_DATA_SPACE = 5
|
||||
|
||||
|
||||
|
||||
|
||||
local function getPage(iParam)
|
||||
-- get page from 0-based index
|
||||
-- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2)
|
||||
local res = (math.floor(iParam/4)==0) and 0 or 1
|
||||
return res
|
||||
end
|
||||
|
||||
local function round(v)
|
||||
-- round float
|
||||
local factor = 100
|
||||
return math.floor(v * factor + 0.5) / factor
|
||||
end
|
||||
|
||||
|
||||
local function readValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
--v = round(v)
|
||||
return v
|
||||
end
|
||||
|
||||
local function readValueById(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return nil end
|
||||
|
||||
local v = getValue(i.id)
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function readBatValue(sensor)
|
||||
-- read from sensor, round and return
|
||||
local v = getValue(sensor)
|
||||
if (v==nil) then return v end
|
||||
|
||||
return string.format("%2.2f",v)
|
||||
end
|
||||
|
||||
local function readActiveParamValue(sensor)
|
||||
-- read and return a validated active parameter value
|
||||
local v = getValue(sensor)
|
||||
if (v<1 or v>8) then
|
||||
return -1
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function drawFlightLogScreen(event)
|
||||
-- draw labels and params on screen
|
||||
local h = getValue("Hold")
|
||||
local activeParam = h-1 -- H
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS)
|
||||
|
||||
-- read and return parameters
|
||||
local a = getValue("FdeA")
|
||||
local b = getValue("FdeB")
|
||||
local l = getValue("FdeL")
|
||||
local r = getValue("FdeR")
|
||||
local f = getValue("FLss")
|
||||
|
||||
local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"}
|
||||
local values = {[0]=a,b,l,r,f,h}
|
||||
|
||||
local y = Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
for iParam=0,3 do -- A,B,L,R
|
||||
-- highlight selected parameter (rund)
|
||||
local attr = ((activeParam%4)==iParam) and INVERS or 0
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL1_DATA + X_DATA_LEN
|
||||
if (val~=16384) then -- Active value
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_LINE_HEIGHT+Y_DATA
|
||||
for iParam=4,5 do -- F, H
|
||||
-- labels
|
||||
local x = X_COL2_HEADER
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + BOLD)
|
||||
|
||||
-- Values
|
||||
val = values[iParam]
|
||||
x = X_COL2_DATA + X_DATA_LEN
|
||||
lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
-- Bat
|
||||
y = y + Y_LINE_HEIGHT
|
||||
local bat = readBatValue("A2") or "--"
|
||||
lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE)
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local function Unsigned_to_SInt16(value)
|
||||
if value >= 0x8000 then -- Negative value??
|
||||
return value - 0x10000
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function getDegreesValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%0.1f o",vs/10)
|
||||
end
|
||||
|
||||
|
||||
local function getDecHexValue(sensor)
|
||||
local i = getFieldInfo(sensor)
|
||||
if (i==nil) then return "-unk-" end
|
||||
|
||||
local v = getValue(i.id)
|
||||
if v==nil then return "---" end
|
||||
local vs = Unsigned_to_SInt16(v)
|
||||
|
||||
return string.format("%d (0x%04X)",vs,v)
|
||||
end
|
||||
|
||||
local as3xData = {[0]=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
||||
local function drawAS3XSettings(event, page)
|
||||
local s0500 = getDecHexValue("0500")
|
||||
local s0502 = getDecHexValue("0502")
|
||||
local s0504 = getDecHexValue("0504")
|
||||
local s0506 = getDecHexValue("0506")
|
||||
local s0508 = getDecHexValue("0508")
|
||||
local s050B = getDecHexValue("050B")
|
||||
local s050D = getDecHexValue("050D")
|
||||
|
||||
local d0500 = readValueById("0500") or 0
|
||||
local flags = bit32.rshift(d0500,8)
|
||||
local state = bit32.band(d0500,0xFF)
|
||||
|
||||
local flagsMsg=""
|
||||
-- flags bits: Safe Envelop, ?, Angle Demand, Stab
|
||||
if (bit32.band(flags,0x1)~=0) then flagsMsg=flagsMsg.."AS3X Stab" end
|
||||
-- This one, only one should show
|
||||
if (bit32.band(flags,0x2)~=0) then flagsMsg=flagsMsg..", Angle Demand"
|
||||
elseif (bit32.band(flags,0x8)~=0) then flagsMsg=flagsMsg..", Safe Envelope"
|
||||
elseif (bit32.band(flags,0x4)~=0) then flagsMsg=flagsMsg..", AS3X Heading" end
|
||||
|
||||
local d0502 = readValueById("0502") or 0 -- 0x?F?S
|
||||
local fm = bit32.band(bit32.rshift(d0502,8),0xF) -- 0,1,2
|
||||
|
||||
local axis = bit32.band(d0502,0xF) -- 0=Gains,1=Headings,2=Angle Limits (cointinus iterating to provide all values)
|
||||
|
||||
local d0504 = readValueById("0504") or 0
|
||||
local d0506 = readValueById("0506") or 0
|
||||
local d0508 = readValueById("0508") or 0
|
||||
|
||||
local d0 = bit32.rshift(d0504,8)
|
||||
local d1 = bit32.band(d0504,0xFF)
|
||||
local d2 = bit32.rshift(d0506,8)
|
||||
local d3 = bit32.band(d0506,0xFF)
|
||||
local d4 = bit32.rshift(d0508,8)
|
||||
local d5 = bit32.band(d0508,0xFF)
|
||||
|
||||
--axis: 0=Gains+Headings (RG,PG,YG,RH,PH,YH), 1=Safe Gains (R,P,Y),2=Angle Limits(L,R,U,D)
|
||||
--Constantly changing from 0..2 to represent different data, thats why we have to store the values
|
||||
--in a script/global variable, and not local to the function
|
||||
local s = axis*6
|
||||
as3xData[s+0] = d0
|
||||
as3xData[s+1] = d1
|
||||
as3xData[s+2] = d2
|
||||
as3xData[s+3] = d3
|
||||
as3xData[s+4] = d4
|
||||
as3xData[s+5] = d5
|
||||
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawText (0,0, "AS3X/SAFE Settings", TEXT_SIZE + INVERS)
|
||||
|
||||
local y = Y_DATA
|
||||
-- Flight Mode
|
||||
lcd.drawText (X_COL1_HEADER,y, "FM: "..(fm+1), TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN*0.3,y, "Flags: "..flags, TEXT_SIZE)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "State: "..state, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, flagsMsg, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
|
||||
if (page==1) then
|
||||
lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "AS3X Gains", TEXT_SIZE+BOLD)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "AS3X Headings", TEXT_SIZE+BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[0], TEXT_SIZE + RIGHT) -- Roll G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[3], TEXT_SIZE + RIGHT) -- Roll H
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y,as3xData[1], TEXT_SIZE + RIGHT) -- Pitch G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[4], TEXT_SIZE + RIGHT) -- Pitch H
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[2], TEXT_SIZE + RIGHT) -- Yaw G
|
||||
lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[5], TEXT_SIZE + RIGHT) -- Yaw H
|
||||
end
|
||||
|
||||
|
||||
if (page==2) then
|
||||
local x_data1 = X_COL1_DATA+X_DATA_LEN
|
||||
local x_data2 = X_COL2_HEADER+X_DATA_LEN*1.6
|
||||
|
||||
lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "SAFE Gains", TEXT_SIZE+BOLD)
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.1,y, "Angle Limits", TEXT_SIZE+BOLD)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, as3xData[6], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Roll R:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[12], TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y,as3xData[7], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Roll L:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y,as3xData[13], TEXT_SIZE + RIGHT)
|
||||
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE)
|
||||
lcd.drawText (x_data1,y, as3xData[8], TEXT_SIZE + RIGHT)
|
||||
|
||||
lcd.drawText (X_COL2_HEADER,y, "Pitch U:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[14], TEXT_SIZE + RIGHT)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
lcd.drawText (X_COL2_HEADER,y, "Pitch D:", TEXT_SIZE)
|
||||
lcd.drawText (x_data2,y, as3xData[15], TEXT_SIZE + RIGHT)
|
||||
end
|
||||
|
||||
-- Debug Values
|
||||
if (DEBUG_ON) then
|
||||
local titles = {[0]=
|
||||
"0500","0502","0504","0506","0508","050B","050D"}
|
||||
|
||||
local values = {[0]=
|
||||
s0500,s0502,s0504,s0506,s0508,s050B,s050D }
|
||||
|
||||
y = Y_LINE_HEIGHT*2 + Y_HEADER
|
||||
for iParam=0,#titles do -- ??
|
||||
-- labels
|
||||
local x = X_COL1_HEADER+250
|
||||
local val = titles[iParam]
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
val = values[iParam] or "--"
|
||||
x = X_COL1_DATA+250
|
||||
lcd.drawText (x, y, val, TEXT_SIZE)
|
||||
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function drawAS3XSettingsP1(event)
|
||||
drawAS3XSettings(event, 1)
|
||||
end
|
||||
|
||||
local function drawAS3XSettingsP2(event)
|
||||
drawAS3XSettings(event, 2)
|
||||
end
|
||||
|
||||
|
||||
local function doFloat(v)
|
||||
if v==nil then return 0.0 end
|
||||
|
||||
local vs = string.format("%1.2f",v)
|
||||
|
||||
return vs + 0.0
|
||||
end
|
||||
|
||||
|
||||
local ESC_Title={[0]="","RPM:","Volts:","Motor:","Mot Out:","Throttle:","FET Temp:", "BEC V:", "BEC T:", "BEC A:"}
|
||||
local ESC_uom={[0]="","","V","A","%","%","C", "V","C","A"}
|
||||
local ESC_Status={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local ESC_Min={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local ESC_Max={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
|
||||
local function drawESCStatus(event)
|
||||
lcd.clear()
|
||||
ESC_Status[1] = getValue("Erpm") -- RPM
|
||||
ESC_Status[2] = doFloat(getValue("EVIN")) -- Volts
|
||||
ESC_Status[3] = doFloat(getValue("ECUR")) -- Current
|
||||
ESC_Status[4] = doFloat(getValue("EOUT")) -- % Output
|
||||
ESC_Status[5] = doFloat(getValue("ETHR")) -- Throttle % (EOUT)
|
||||
ESC_Status[6] = getValue("TFET") -- Temp FET
|
||||
|
||||
ESC_Status[7] = doFloat(getValue("VBEC")) -- Volts BEC
|
||||
ESC_Status[8] = getValue("TBEC") -- Temp BEC
|
||||
ESC_Status[9] = doFloat(getValue("CBEC")) -- Current BEC
|
||||
|
||||
for i=1,9 do
|
||||
if (ESC_Status~=nil) then
|
||||
if (ESC_Min[i]==0) then
|
||||
ESC_Min[i]=ESC_Status[i]
|
||||
else
|
||||
ESC_Min[i] = math.min(ESC_Min[i],ESC_Status[i])
|
||||
end
|
||||
|
||||
ESC_Max[i] = math.max(ESC_Max[i],ESC_Status[i])
|
||||
end
|
||||
end
|
||||
|
||||
lcd.drawText (0,0, "ESC", TEXT_SIZE+INVERS)
|
||||
|
||||
local y = 0
|
||||
local x_data = X_COL1_DATA+X_DATA_LEN*1.5
|
||||
local x_data2 = X_COL2_DATA+X_DATA_LEN*0.5
|
||||
local x_data3 = x_data2 + X_DATA_LEN*0.8
|
||||
|
||||
|
||||
lcd.drawText (x_data,y , "Status", TEXT_SIZE+BOLD+RIGHT)
|
||||
lcd.drawText (x_data2,y, "Min", TEXT_SIZE+BOLD+RIGHT)
|
||||
lcd.drawText (x_data3,y, "Max", TEXT_SIZE+BOLD+RIGHT)
|
||||
|
||||
y = Y_DATA
|
||||
for i=1,9 do
|
||||
lcd.drawText (X_COL1_HEADER,y, ESC_Title[i], TEXT_SIZE + BOLD)
|
||||
|
||||
lcd.drawText (x_data,y, ESC_Status[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data + X_DATA_SPACE,y, ESC_uom[i], TEXT_SIZE)
|
||||
|
||||
lcd.drawText (x_data2,y, ESC_Min[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data3,y, ESC_Max[i] or "--", TEXT_SIZE + RIGHT)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function drawBATStatus(event)
|
||||
local Title={[0]="","Bat:","Temp:","Rem :","Curr:","Used:","Imbal:","Cycles:", "RX:", "BCpT?:"}
|
||||
local uom={[0]="","V","C","%","mAh","mAh","mV","", "V",""}
|
||||
local Values={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
local CellValues={[0]=0,0,0,0,0,0,0,0,0,0,0}
|
||||
|
||||
lcd.clear()
|
||||
|
||||
local ESC_Volts = getValue("EVIN") or 0 -- Volts
|
||||
local ESC_Current = getValue("ECUR") or 0 -- Current
|
||||
|
||||
Values[1] = 0 -- compute later
|
||||
Values[2] = getValue("BTmp") -- Current (C)
|
||||
Values[3] = nil -- Remaining???
|
||||
Values[4] = getValue("BCur") -- Current (mAh)
|
||||
Values[5] = getValue("BUse") -- Current Used (mAh)
|
||||
Values[6] = getValue("CLMa") -- 0.0 (mV) Imbalance
|
||||
Values[7] = getValue("Cycl") -- Cycles
|
||||
Values[8] = readBatValue("A2") -- v
|
||||
Values[9] = getValue("BCpT") -- Current (mAh) ????
|
||||
|
||||
|
||||
--- Total Voltange Calculation
|
||||
local VTotal=0
|
||||
for i=1,10 do
|
||||
CellValues[i] = getValue("Cel"..i)
|
||||
VTotal = VTotal + CellValues[i]
|
||||
end
|
||||
|
||||
if (VTotal==0) then -- No Inteligent Battery,use intelligent ESC if any
|
||||
VTotal = ESC_Volts
|
||||
Values[4] = string.format("%d",ESC_Current * 1000)
|
||||
end
|
||||
|
||||
Values[1] = string.format("%2.2f",VTotal)
|
||||
|
||||
--- SCREEN
|
||||
|
||||
lcd.drawText (X_COL1_HEADER,0, "Battery Stats", TEXT_SIZE+INVERS)
|
||||
|
||||
|
||||
|
||||
local y = Y_DATA
|
||||
local x_data = X_COL1_DATA+X_DATA_LEN+X_DATA_SPACE*3
|
||||
for i=2,9 do
|
||||
lcd.drawText (X_COL1_HEADER, y, Title[i], TEXT_SIZE + BOLD)
|
||||
lcd.drawText (x_data, y, Values[i] or "--", TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE, y, uom[i], TEXT_SIZE)
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
y = Y_DATA
|
||||
x_data = X_COL2_DATA+X_DATA_LEN+X_DATA_SPACE*5
|
||||
for i=1,8 do
|
||||
if ((CellValues[i] or 0) > 0) then
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,y, "Cel "..i..":", TEXT_SIZE + BOLD)
|
||||
lcd.drawText (x_data,y, string.format("%2.2f",CellValues[i] or 0), TEXT_SIZE + RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE,y, "v", TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,0, Title[1], TEXT_SIZE + INVERS + BOLD)
|
||||
lcd.drawText (x_data,0, string.format("%2.2f",Values[1] or 0), TEXT_SIZE + INVERS+ RIGHT)
|
||||
lcd.drawText (x_data+X_DATA_SPACE, 0, uom[1], TEXT_SIZE + INVERS)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function openTelemetryRaw(i2cId)
|
||||
--Init telemetry (Spectrun Telemetry Raw STR)
|
||||
multiBuffer( 0, string.byte('S') )
|
||||
multiBuffer( 1, string.byte('T') )
|
||||
multiBuffer( 2, string.byte('R') )
|
||||
multiBuffer( 3, i2cId ) -- Monitor this teemetry data
|
||||
multiBuffer( 4, 0 ) -- Allow to get Data
|
||||
end
|
||||
|
||||
local function closeTelemetryRaw()
|
||||
multiBuffer(0, 0) -- Destroy the STR header
|
||||
multiBuffer(3, 0) -- Not requesting any Telementry ID
|
||||
end
|
||||
|
||||
local lineText = {nil}
|
||||
local I2C_TEXT_GEN = 0x0C
|
||||
local function drawTextGen(event)
|
||||
if (multiBuffer(0)~=string.byte('S')) then -- First time run???
|
||||
openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN
|
||||
lineText = {nil}
|
||||
end
|
||||
|
||||
-- Proces TEXT GEN Telementry message
|
||||
if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received
|
||||
local instanceNo = multiBuffer( 5 )
|
||||
local lineNo = multiBuffer( 6 )
|
||||
|
||||
local line = ""
|
||||
for i=0,13 do
|
||||
line = line .. string.char(multiBuffer( 7 + i ))
|
||||
end
|
||||
|
||||
multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message
|
||||
lineText[lineNo]=line
|
||||
end
|
||||
|
||||
lcd.clear()
|
||||
-- Header
|
||||
if (lineText[0]) then
|
||||
lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS)
|
||||
else
|
||||
lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS)
|
||||
end
|
||||
|
||||
-- Menu lines
|
||||
local y = Y_DATA
|
||||
for i=1,8 do
|
||||
if (lineText[i]) then
|
||||
lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE)
|
||||
end
|
||||
y = y + Y_LINE_HEIGHT
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data
|
||||
closeTelemetryRaw()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local telPage = 1
|
||||
local telPageSelected = 0
|
||||
local pageTitle = {[0]="Main", "AS3X Settings", "SAFE Settings", "ESC Status", "Battery Status","TextGen","Flight Log"}
|
||||
|
||||
local function drawMainScreen(event)
|
||||
lcd.clear()
|
||||
lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (Smart RXs)", TEXT_SIZE + INVERS)
|
||||
|
||||
for iParam=1,#pageTitle do
|
||||
-- highlight selected parameter
|
||||
local attr = (telPage==iParam) and INVERS or 0
|
||||
|
||||
-- set y draw coord
|
||||
local y = (iParam)*Y_LINE_HEIGHT+Y_DATA
|
||||
|
||||
-- labels
|
||||
local x = X_COL1_HEADER
|
||||
local val = pageTitle[iParam]
|
||||
lcd.drawText (x, y, val, attr + TEXT_SIZE)
|
||||
end
|
||||
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
if (telPage>1) then telPage = telPage - 1 end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
if (telPage<#pageTitle) then telPage = telPage + 1 end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
telPageSelected = telPage
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local pageDraw = {[0]=drawMainScreen, drawAS3XSettingsP1, drawAS3XSettingsP2, drawESCStatus, drawBATStatus, drawTextGen, drawFlightLogScreen}
|
||||
|
||||
local function run_func(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
end
|
||||
|
||||
-- draw specific page
|
||||
pageDraw[telPageSelected](event)
|
||||
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
if (telPageSelected==0) then return 1 end -- on Main?? Exit Script
|
||||
telPageSelected = 0 -- any page, return to Main
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function init_func()
|
||||
|
||||
if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens
|
||||
TEXT_SIZE = SMLSIZE
|
||||
X_COL1_HEADER = 0
|
||||
X_COL1_DATA = 20
|
||||
|
||||
X_COL2_HEADER = 60
|
||||
X_COL2_DATA = 90
|
||||
|
||||
X_DATA_LEN = 28
|
||||
X_DATA_SPACE = 1
|
||||
|
||||
|
||||
Y_LINE_HEIGHT = 8
|
||||
Y_DATA = Y_HEADER + Y_LINE_HEIGHT
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return { run=run_func, init=init_func }
|
||||
@@ -117,6 +117,7 @@
|
||||
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
49,0,KF606,KF606,1,Trim
|
||||
49,1,KF606,MIG320,1,Trim,LED
|
||||
49,2,KF606,ZCZ50,1,Trim,UNK
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
|
||||
@@ -33,7 +33,14 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
#define FX620_PAYLOAD_SIZE 7
|
||||
#define FX620_CH_OFFSET 1
|
||||
|
||||
#define FX9630_PACKET_PERIOD 8124
|
||||
#define FX9630_BIND_PACKET_PERIOD 8124
|
||||
#define FX9630_BIND_CHANNEL 51
|
||||
#define FX9630_PAYLOAD_SIZE 8
|
||||
#define FX9630_NUM_CHANNELS 3
|
||||
|
||||
//#define FORCE_FX620_ID
|
||||
//#define FORCE_FX9630_ID
|
||||
|
||||
static void __attribute__((unused)) FX_send_packet()
|
||||
{
|
||||
@@ -41,21 +48,44 @@ static void __attribute__((unused)) FX_send_packet()
|
||||
if(IS_BIND_DONE)
|
||||
{
|
||||
XN297_Hopping(hopping_frequency_no++);
|
||||
hopping_frequency_no &= 0x03;
|
||||
if(sub_protocol == FX9630)
|
||||
{
|
||||
XN297_SetTXAddr(rx_tx_addr, 4);
|
||||
if (hopping_frequency_no > FX9630_NUM_CHANNELS)
|
||||
hopping_frequency_no = 0;
|
||||
}
|
||||
else // FX816 and FX620
|
||||
{
|
||||
hopping_frequency_no &= 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
memset(packet,0x00,packet_length);
|
||||
|
||||
//Channels
|
||||
uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET;
|
||||
uint8_t val=convert_channel_8b(AILERON);
|
||||
if(val>127+FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 1:0xFF;
|
||||
else if(val<127-FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 2:0x00;
|
||||
else
|
||||
packet[offset] = sub_protocol == FX816 ? 0:0x7F;
|
||||
packet[offset+1] = convert_channel_16b_limit(THROTTLE,0,100); //FX816:0x00..0x63, FX620:0x00..0x5E but that should work
|
||||
uint8_t val;
|
||||
if (sub_protocol == FX9630)
|
||||
{
|
||||
packet[0] = convert_channel_8b(THROTTLE);
|
||||
packet[1] = convert_channel_8b(AILERON);
|
||||
packet[2] = 0xFF - convert_channel_8b(ELEVATOR);
|
||||
packet[3] = convert_channel_8b(RUDDER);
|
||||
packet[4] = 0x20;
|
||||
packet[5] = GET_FLAG(CH5_SW, 0x01); // DR toggle swich: 0 small throw, 1 large throw
|
||||
packet[5] |= (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x02 : 0x01)) << 1; // Mode A(0) : 6D small throw, B(1) : 6D large throw, C(2) : 3D
|
||||
}
|
||||
else // FX816 and FX620
|
||||
{
|
||||
uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET;
|
||||
val=convert_channel_8b(AILERON);
|
||||
if(val>127+FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 1:0xFF;
|
||||
else if(val<127-FX_SWITCH)
|
||||
packet[offset] = sub_protocol == FX816 ? 2:0x00;
|
||||
else
|
||||
packet[offset] = sub_protocol == FX816 ? 0:0x7F;
|
||||
packet[offset+1] = convert_channel_16b_limit(THROTTLE,0,100); //FX816:0x00..0x63, FX620:0x00..0x5E but that should work
|
||||
}
|
||||
|
||||
//Bind and specifics
|
||||
if(sub_protocol == FX816)
|
||||
@@ -67,7 +97,7 @@ static void __attribute__((unused)) FX_send_packet()
|
||||
packet[1] = rx_tx_addr[0];
|
||||
packet[2] = rx_tx_addr[1];
|
||||
}
|
||||
else //FX620
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
@@ -82,12 +112,27 @@ static void __attribute__((unused)) FX_send_packet()
|
||||
packet[5] = 0xAB; // Is it based on ID??
|
||||
}
|
||||
}
|
||||
else // FX9630
|
||||
{
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
memcpy(packet,rx_tx_addr, 4);
|
||||
packet[4] = hopping_frequency[1];
|
||||
packet[5] = hopping_frequency[2];
|
||||
packet[7] = 0x55;
|
||||
}
|
||||
}
|
||||
|
||||
//Check
|
||||
uint8_t last_packet_idx = packet_length-1;
|
||||
if (sub_protocol == FX9630 && IS_BIND_IN_PROGRESS)
|
||||
last_packet_idx--;
|
||||
val=0;
|
||||
for(uint8_t i=0;i<packet_length-1;i++)
|
||||
for(uint8_t i=0;i<last_packet_idx;i++)
|
||||
val+=packet[i];
|
||||
packet[packet_length-1]=val;
|
||||
if (sub_protocol == FX9630)
|
||||
val = val ^ 0xFF;
|
||||
packet[last_packet_idx]=val;
|
||||
|
||||
//Debug
|
||||
#if 0
|
||||
@@ -112,13 +157,20 @@ static void __attribute__((unused)) FX_RF_init()
|
||||
packet_period = FX816_PACKET_PERIOD;
|
||||
packet_length = FX816_PAYLOAD_SIZE;
|
||||
}
|
||||
else //FX620
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\xaa\xbb\xcc", 3);
|
||||
XN297_RFChannel(FX620_BIND_CHANNEL);
|
||||
packet_period = FX620_BIND_PACKET_PERIOD;
|
||||
packet_length = FX620_PAYLOAD_SIZE;
|
||||
}
|
||||
else // FX9630
|
||||
{
|
||||
XN297_SetTXAddr((uint8_t *)"\x56\x78\x90\x12", 4);
|
||||
XN297_RFChannel(FX9630_BIND_CHANNEL);
|
||||
packet_period = FX9630_BIND_PACKET_PERIOD;
|
||||
packet_length = FX9630_PAYLOAD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) FX_initialize_txid()
|
||||
@@ -133,7 +185,7 @@ static void __attribute__((unused)) FX_initialize_txid()
|
||||
for(uint8_t i=0;i<FX_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i]+=rx_tx_addr[3]&0x07;
|
||||
}
|
||||
else//FX620
|
||||
else if(sub_protocol == FX620)
|
||||
{
|
||||
rx_tx_addr[0] = rx_tx_addr[3];
|
||||
hopping_frequency[0] = 0x18 + rx_tx_addr[3]&0x07; // just to try something
|
||||
@@ -144,6 +196,17 @@ static void __attribute__((unused)) FX_initialize_txid()
|
||||
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
|
||||
hopping_frequency[i] = i*10 + hopping_frequency[0];
|
||||
}
|
||||
else // FX9630
|
||||
{
|
||||
#ifdef FORCE_FX9630_ID
|
||||
memcpy(rx_tx_addr,(uint8_t*)"\xCE\x31\x9B\x73", 4);
|
||||
memcpy(hopping_frequency,"\x13\x1A\x38", FX9630_NUM_CHANNELS); //Original dump=19=0x13,26=0x1A,56=0x38
|
||||
#else
|
||||
hopping_frequency[0] = 0x13; // constant
|
||||
hopping_frequency[1] = RX_num & 0x0F + 0x1A;
|
||||
hopping_frequency[2] = rx_tx_addr[3] & 0x0F + 0x38;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t FX_callback()
|
||||
|
||||
@@ -20,6 +20,7 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
|
||||
//#define FORCE_KF606_ORIGINAL_ID
|
||||
//#define FORCE_MIG320_ORIGINAL_ID
|
||||
//#define FORCE_ZCZ50_ORIGINAL_ID
|
||||
|
||||
#define KF606_INITIAL_WAIT 500
|
||||
#define KF606_PACKET_PERIOD 3000
|
||||
@@ -30,10 +31,16 @@ Multiprotocol is distributed in the hope that it will be useful,
|
||||
|
||||
static void __attribute__((unused)) KF606_send_packet()
|
||||
{
|
||||
uint8_t len = KF606_PAYLOAD_SIZE;
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
{
|
||||
packet[0] = 0xAA;
|
||||
memcpy(&packet[1],rx_tx_addr,3);
|
||||
if(sub_protocol != KF606_ZCZ50)
|
||||
{
|
||||
packet[0] = 0xAA;
|
||||
memcpy(&packet[1],rx_tx_addr,3);
|
||||
}
|
||||
else
|
||||
memcpy(packet,rx_tx_addr,4);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -43,25 +50,32 @@ static void __attribute__((unused)) KF606_send_packet()
|
||||
packet[0] = 0x55;
|
||||
packet[1] = convert_channel_8b(THROTTLE); // 0..255
|
||||
// Deadband is needed on aileron, 40 gives +-6%
|
||||
if(sub_protocol == KF606_KF606)
|
||||
switch(sub_protocol)
|
||||
{
|
||||
packet[2] = convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, Low rates:50..80..AF, High rates:3E..80..C1
|
||||
packet[3] = convert_channel_16b_limit(CH5,0xC1,0xDF); // Aileron trim must be on a separated channel C1..D0..DF
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[2] = convert_channel_8b_limit_deadband(AILERON,0x00,0x80,0xFF,40); // Aileron: High rate:2B..80..DA
|
||||
packet[3] = convert_channel_16b_limit(CH5,0x01,0x1F); // Aileron trim must be on a separated channel 01..10..1F
|
||||
packet[3] += (packet[2]-0x80)>>3; // Drive trims for more aileron authority
|
||||
if(packet[3] > 0x80)
|
||||
packet[3] = 0x01;
|
||||
else if(packet[3] > 0x1F)
|
||||
packet[3] = 0x1F;
|
||||
packet[3] |= GET_FLAG(CH6_SW, 0xC0); // 0xC0 and 0xE0 are both turning the LED off, not sure if there is another hidden feature
|
||||
case KF606_KF606:
|
||||
packet[2] = convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, Low rates:50..80..AF, High rates:3E..80..C1
|
||||
packet[3] = convert_channel_16b_limit(CH5,0xC1,0xDF); // Aileron trim must be on a separated channel C1..D0..DF
|
||||
break;
|
||||
case KF606_MIG320:
|
||||
packet[2] = convert_channel_8b_limit_deadband(AILERON,0x00,0x80,0xFF,40); // Aileron: High rate:2B..80..DA
|
||||
packet[3] = convert_channel_16b_limit(CH5,0x01,0x1F); // Aileron trim must be on a separated channel 01..10..1F
|
||||
packet[3] += (packet[2]-0x80)>>3; // Drive trims for more aileron authority
|
||||
if(packet[3] > 0x80)
|
||||
packet[3] = 0x01;
|
||||
else if(packet[3] > 0x1F)
|
||||
packet[3] = 0x1F;
|
||||
packet[3] |= GET_FLAG(CH6_SW, 0xC0); // 0xC0 and 0xE0 are both turning the LED off, not sure if there is another hidden feature
|
||||
break;
|
||||
case KF606_ZCZ50:
|
||||
len--; // uses only 3 bytes of payload
|
||||
packet[0] = packet[1]; // Throttle: 0x00..0xFF
|
||||
packet[1] = convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, low rate 0x52..0x80..0xB1, high rate: 0x41..0x80..0xC3.
|
||||
packet[2] = convert_channel_16b_limit(CH5,0x01,0x1F); // Trim: 0x01..0x10..0x1F
|
||||
packet[2] |= GET_FLAG(CH6_SW, 0xC0); // Unknown: 0x00 or 0xC0. Left top switch on original TX changes nothing on my plane. Maybe ON/OFF for main motor?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t len = KF606_PAYLOAD_SIZE;
|
||||
if(sub_protocol == KF606_MIG320)
|
||||
{
|
||||
len++;
|
||||
@@ -107,6 +121,19 @@ static void __attribute__((unused)) KF606_initialize_txid()
|
||||
hopping_frequency[0]=68;
|
||||
hopping_frequency[1]=71;
|
||||
#endif
|
||||
if(sub_protocol == KF606_ZCZ50)
|
||||
{
|
||||
rx_tx_addr[1] = rx_tx_addr[0];
|
||||
rx_tx_addr[0]=0xAA;
|
||||
}
|
||||
#ifdef FORCE_ZCZ50_ORIGINAL_ID
|
||||
rx_tx_addr[0]=0xAA;
|
||||
rx_tx_addr[1]=0x67;
|
||||
rx_tx_addr[2]=0x64;
|
||||
rx_tx_addr[3]=0x01;
|
||||
hopping_frequency[0]=48;
|
||||
hopping_frequency[1]=51;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) KF606_RF_init()
|
||||
@@ -126,7 +153,7 @@ uint16_t KF606_callback()
|
||||
if(--bind_counter==0)
|
||||
{
|
||||
BIND_DONE;
|
||||
XN297_SetTXAddr(rx_tx_addr, 3);
|
||||
XN297_SetTXAddr(rx_tx_addr, sub_protocol != KF606_ZCZ50 ? 3 : 4);
|
||||
}
|
||||
KF606_send_packet();
|
||||
return KF606_PACKET_PERIOD;
|
||||
@@ -153,3 +180,14 @@ void KF606_init()
|
||||
// P[2] = AIL 2B..80..DA
|
||||
// P[3] = TRIM 01..10..1F
|
||||
// channels 68=BB&3F+9 and 71
|
||||
|
||||
|
||||
// ZCZ50v2 protocol (with fake front propeller)
|
||||
// Bind
|
||||
// 250K C=7 S=Y A= E7 E7 E7 E7 E7 P(4)= AA 67 64 01
|
||||
// 3ms on ch7
|
||||
// Normal
|
||||
// 250K C=48 S=Y A= AA 67 64 01 P(3)= 00 80 10
|
||||
// P[0] = THR 0x00..0xFF
|
||||
// P[1] = AIL low rate 0x52..0x80..0xB1, high rate: 0x41..0x80..0xC3
|
||||
// P[2] = TRIM 0x01..0x10..0x1F + UNKNOWN 0x00 or 0xC0
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
46,V911S,V911S,E119
|
||||
47,GD00x,GD_V1,GD_V2
|
||||
48,V761,3CH,4CH,TOPRC
|
||||
49,KF606,KF606,MIG320
|
||||
49,KF606,KF606,MIG320,ZCZ50
|
||||
50,Redpine,Fast,Slow
|
||||
51,Potensic,A20
|
||||
52,ZSX,280
|
||||
@@ -55,7 +55,7 @@
|
||||
55,Frsky_RX,Multi,CloneTX,EraseTX,CPPM
|
||||
56,AFHDS2A_RX,Multi,CPPM
|
||||
57,HoTT,Sync,No_Sync
|
||||
58,FX,816,620
|
||||
58,FX,816,620,9630
|
||||
59,Bayang_RX,Multi,CPPM
|
||||
60,Pelikan,Pro,Lite,SCX24
|
||||
61,Tiger
|
||||
|
||||
@@ -171,9 +171,9 @@ const char STR_SUBTYPE_KYOSHO2[] = "\x05""KT-17";
|
||||
const char STR_SUBTYPE_FUTABA[] = "\x05""SFHSS";
|
||||
const char STR_SUBTYPE_JJRC345[] = "\x08""JJRC345\0""SkyTmblr";
|
||||
const char STR_SUBTYPE_MOULKG[] = "\x06""Analog""Digit\0";
|
||||
const char STR_SUBTYPE_KF606[] = "\x06""KF606\0""MIG320";
|
||||
const char STR_SUBTYPE_KF606[] = "\x06""KF606\0""MIG320""ZCZ50\0";
|
||||
const char STR_SUBTYPE_E129[] = "\x04""E129""C186";
|
||||
const char STR_SUBTYPE_FX[] = "\x03""816""620";
|
||||
const char STR_SUBTYPE_FX[] = "\x04""816\0""620\0""9630";
|
||||
#define NO_SUBTYPE nullptr
|
||||
|
||||
#ifdef SEND_CPPM
|
||||
@@ -315,7 +315,7 @@ const mm_protocol_definition multi_protocols[] = {
|
||||
{PROTO_FUTABA, STR_FUTABA, STR_SUBTYPE_FUTABA, 1, OPTION_RFTUNE, 1, 1, SW_CC2500, SFHSS_init, SFHSS_callback },
|
||||
#endif
|
||||
#if defined(FX_NRF24L01_INO)
|
||||
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 2, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
|
||||
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 3, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
|
||||
#endif
|
||||
#if defined(FY326_NRF24L01_INO)
|
||||
{PROTO_FY326, STR_FY326, STR_SUBTYPE_FY326, 2, OPTION_NONE, 0, 0, SW_NRF, FY326_init, FY326_callback },
|
||||
@@ -360,7 +360,7 @@ const mm_protocol_definition multi_protocols[] = {
|
||||
{PROTO_JOYSWAY, STR_JOYSWAY, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_A7105, JOYSWAY_init, JOYSWAY_callback },
|
||||
#endif
|
||||
#if defined(KF606_CCNRF_INO)
|
||||
{PROTO_KF606, STR_KF606, STR_SUBTYPE_KF606, 2, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback },
|
||||
{PROTO_KF606, STR_KF606, STR_SUBTYPE_KF606, 3, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback },
|
||||
#endif
|
||||
#if defined(KN_NRF24L01_INO)
|
||||
{PROTO_KN, STR_KN, STR_SUBTYPE_KN, 2, OPTION_NONE, 0, 0, SW_NRF, KN_init, KN_callback },
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 3
|
||||
#define VERSION_REVISION 3
|
||||
#define VERSION_PATCH_LEVEL 24
|
||||
#define VERSION_PATCH_LEVEL 25
|
||||
|
||||
#define MODE_SERIAL 0
|
||||
|
||||
@@ -450,6 +450,7 @@ enum KF606
|
||||
{
|
||||
KF606_KF606 = 0,
|
||||
KF606_MIG320 = 1,
|
||||
KF606_ZCZ50 = 2,
|
||||
};
|
||||
enum E129
|
||||
{
|
||||
@@ -460,6 +461,7 @@ enum FX
|
||||
{
|
||||
FX816 = 0,
|
||||
FX620 = 1,
|
||||
FX9630 = 2,
|
||||
};
|
||||
|
||||
#define NONE 0
|
||||
|
||||
@@ -670,6 +670,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
PROTO_FX
|
||||
FX816
|
||||
FX620
|
||||
FX9630
|
||||
PROTO_FY326
|
||||
FY326
|
||||
FY319
|
||||
@@ -717,6 +718,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
|
||||
PROTO_KF606
|
||||
KF606_KF606
|
||||
KF606_MIG320
|
||||
KF606_ZCZ50
|
||||
PROTO_KN
|
||||
WLTOYS
|
||||
FEILUN
|
||||
|
||||
@@ -110,7 +110,7 @@ CFlie|38|CFlie||||||||NRF24L01|
|
||||
[J6Pro](Protocols_Details.md#J6Pro---22)|22|||||||||CYRF6936|
|
||||
[JJRC345](Protocols_Details.md#JJRC345---71)|71|JJRC345|SkyTmblr|||||||NRF24L01|XN297
|
||||
[JOYSWAY](Protocols_Details.md#JOYSWAY---84)|84|||||||||NRF24L01|XN297
|
||||
[KF606](Protocols_Details.md#KF606---49)|49|KF606|MIG320|||||||NRF24L01|XN297
|
||||
[KF606](Protocols_Details.md#KF606---49)|49|KF606|MIG320|ZCZ50||||||NRF24L01|XN297
|
||||
[KN](Protocols_Details.md#KN---9)|9|WLTOYS|FEILUN|||||||NRF24L01|
|
||||
[Kyosho](Protocols_Details.md#Kyosho---73)|73|FHSS|Hype|||||||A7105|
|
||||
[Kyosho2](Protocols_Details.md#Kyosho2---93)|93|KT-17||||||||NRF24L01|
|
||||
@@ -520,18 +520,18 @@ Here is a table detailling the different RX output ranges based on the radio set
|
||||

|
||||
|
||||
### Sub_protocol DSM2_1F - *0*
|
||||
DSM2, Resolution 1024, servo refresh rate can only be 22ms
|
||||
Air DSM2, Resolution 1024, servo refresh rate can only be 22ms
|
||||
### Sub_protocol DSM2_2F - *1*
|
||||
DSM2, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
|
||||
Air DSM2, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
|
||||
### Sub_protocol DSMX_1F - *2*
|
||||
DSMX, Resolution 2048, servo refresh rate can only be 22ms
|
||||
Air DSMX, Resolution 2048, servo refresh rate can only be 22ms
|
||||
### Sub_protocol DSMX_2F - *3*
|
||||
DSMX, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
|
||||
Air DSMX, Resolution 2048, servo refresh rate can be 22 or 11ms. 11ms won't be available on all servo outputs when more than 7 channels are used.
|
||||
### Sub_protocol AUTO - *4*
|
||||
"AUTO" is recommended to automatically select the best settings for your DSM2 and DSMX RXs.
|
||||
"AUTO" is recommended to automatically select the best settings for your air DSM2 and DSMX RXs.
|
||||
|
||||
### Sub_protocol DSMR_1F - *5*
|
||||
DSMR receivers
|
||||
Surface DSMR receivers
|
||||
|
||||
**Only 22 IDs available**, use RX num to cycle through them.
|
||||
|
||||
@@ -615,7 +615,7 @@ Calib is the same as the original radio with both sticks down and to the left in
|
||||
Models: Eachine E129/E130 and Twister Ninja 250
|
||||
|
||||
### Sub_protocol C186 - *1*
|
||||
Models: C186/E120, C127/E110, K127
|
||||
Models: C186/E120, C127/E110, K127, C159
|
||||
|
||||
The FC of the heli seems to store the trims Trim A/E/R=CH7..9. If you use these trims, make sure to center them after powering off the heli or they will be added to the previous trims and over correct.
|
||||
|
||||
@@ -1049,6 +1049,15 @@ CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A||T||TRIM|LED
|
||||
|
||||
### Sub_protocol ZCZ50v2 - *2*
|
||||
Model: ZC-Z50 Cessna
|
||||
|
||||
This might be newer version of the model. My plane does not have front propeller, but its just fake anyway (no motor in the front).
|
||||
|
||||
CH1|CH2|CH3|CH4|CH5|CH6
|
||||
---|---|---|---|---|---
|
||||
A||T||TRIM|UNKNOWN
|
||||
|
||||
## MJXQ - *18*
|
||||
Autobind protocol
|
||||
|
||||
@@ -1783,7 +1792,7 @@ Option field | Value
|
||||
3|The module will control the brick number RX_num, RX_num+1 and RX_num+2
|
||||
4|The module will control the brick number RX_num, RX_num+1, RX_num+2 and RX_num+3
|
||||
|
||||
To associate a brick to a RX number (RX_num above), set this RX number under the protocol, set option to 1, launch a bind and power on the brick you want to control. Repeat this for every brick using a different RX number each time and then indicate the number of bricks to be comtrolled using the Option field.
|
||||
To associate a brick to a RX number (RX_num above), set this RX number under the protocol, set option to 1, launch a bind and power on the brick you want to control. Repeat this for every brick using a different RX number each time and then indicate the number of bricks to be controlled using the Option field.
|
||||
|
||||
Example: I want to control 2 bricks. I select RX number 1, set option to 1 and launch a bind on the first brick. I select RX number 2, set option to 1 and launch a bind on the second brick. Now to control both bricks I set RX number to 1 and option to 2. Therefore brick1 will react to channels CH1 to CH4 and brick2 to channel CH5 to CH8.
|
||||
On another model I can control 4 other bricks, bind each brick to RX number 3 to 6 and then finaly set RX number to 3 and option to 4 to contol the 4 bricks with CH1 to CH16.
|
||||
|
||||
Reference in New Issue
Block a user