From 42443c5c953a17d73fbd92a70ed8c0beb305b0a9 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 10 Sep 2019 16:46:23 +0200 Subject: [PATCH] Fixes #6679 (#6734) Fixes #6679 --- .../TOOLS}/CROSSFIRE/crossfire.lua | 0 .../{ => SCRIPTS/TOOLS}/CROSSFIRE/device.lua | 0 .../horus/SCRIPTS/TOOLS/FrSky GaSuite.lua | 515 ++++++++++++++++++ .../sdcard/horus/SCRIPTS/TOOLS/FrSky SBEC.lua | 289 ++++++++++ .../sdcard/horus/SCRIPTS/TOOLS/FrSky SxR.lua | 363 ++++++++++++ .../sdcard/horus/SCRIPTS/TOOLS/crossfire.lua | 37 ++ radio/sdcard/horus/SCRIPTS/TOOLS/readme.txt | 1 + .../taranis-x7/SCRIPTS/TOOLS/crossfire.lua | 37 ++ .../taranis-x9/SCRIPTS/TOOLS/crossfire.lua | 37 ++ radio/src/gui/480x272/radio_tools.cpp | 5 - radio/src/gui/common/stdlcd/radio_tools.cpp | 5 - radio/src/lua/api_general.cpp | 19 + 12 files changed, 1298 insertions(+), 10 deletions(-) rename radio/sdcard/horus/{ => SCRIPTS/TOOLS}/CROSSFIRE/crossfire.lua (100%) rename radio/sdcard/horus/{ => SCRIPTS/TOOLS}/CROSSFIRE/device.lua (100%) create mode 100755 radio/sdcard/horus/SCRIPTS/TOOLS/FrSky GaSuite.lua create mode 100644 radio/sdcard/horus/SCRIPTS/TOOLS/FrSky SBEC.lua create mode 100755 radio/sdcard/horus/SCRIPTS/TOOLS/FrSky SxR.lua create mode 100644 radio/sdcard/horus/SCRIPTS/TOOLS/crossfire.lua create mode 100644 radio/sdcard/horus/SCRIPTS/TOOLS/readme.txt create mode 100644 radio/sdcard/taranis-x7/SCRIPTS/TOOLS/crossfire.lua create mode 100644 radio/sdcard/taranis-x9/SCRIPTS/TOOLS/crossfire.lua diff --git a/radio/sdcard/horus/CROSSFIRE/crossfire.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/CROSSFIRE/crossfire.lua similarity index 100% rename from radio/sdcard/horus/CROSSFIRE/crossfire.lua rename to radio/sdcard/horus/SCRIPTS/TOOLS/CROSSFIRE/crossfire.lua diff --git a/radio/sdcard/horus/CROSSFIRE/device.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/CROSSFIRE/device.lua similarity index 100% rename from radio/sdcard/horus/CROSSFIRE/device.lua rename to radio/sdcard/horus/SCRIPTS/TOOLS/CROSSFIRE/device.lua diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky GaSuite.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky GaSuite.lua new file mode 100755 index 000000000..df7fce8ce --- /dev/null +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky GaSuite.lua @@ -0,0 +1,515 @@ + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + +local version = "v1.1" + +local VALUE = 0 +local COMBO = 1 +local FLPOI = 2 + + +local edit = false +local page = 1 +local current = 1 --row +local refreshState = 0 +local refreshIndex = 0 +local refreshIndex3 = 0 +local pageOffset = 0 +local pages = {} +local fields = {} +local modifications = {} +local thistime = getTime() +local lastTime = thistime +local margin = 1 +local spacing = 8 +local configFields = {} +local counter = 0 +local appId = 0 + +local function drawScreenTitle(title,page, pages) + if math.fmod(math.floor(getTime()/100),10) == 0 then + title = version + end + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + lcd.drawText(LCD_W-40, 5, page.."/"..pages, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, page, pages) + end +end + +local interfaceconfig = { + {"Sensor group select", VALUE, appId, nil, 0, 15}, +} + +local settingsFields = { + {"Software version", FLPOT, 0x0c, nil, 1, 100 }, + {"Physical ID", VALUE, 0x01, nil, 0, 26 }, + {"Application IDgroup", VALUE, 0x0D, nil, 0, 15 }, + {"Data rate(*100ms)", VALUE, 0x22, nil, 1, 255 }, +} + +local telemetryFields = { + {"TEMP1(C/F)", VALUE, 0x90, nil, -30, 600}, + {"TEMP2(C/F)", VALUE, 0x91, nil, -30, 600}, + {"SPEED(r/min)", VALUE, 0x92, nil, 0, 100000}, + {"Residual Volume(mL)", VALUE, 0x93, nil, 0, 60000}, + {"Residual Percent(%)", VALUE, 0x94, nil, 0, 100}, + {"FLOW(mL/min)", VALUE, 0x95, nil, 0, 2000}, + {"Max Flow(mL/min)", VALUE, 0x96, nil, 0, 2000}, + {"Avg Flow(mL/min)", VALUE, 0x97, nil, 0, 2000}, +} + +-- Change display attribute to current field +local function addField(step) + local field = fields[current] + local min, max + if field[2] == VALUE then + min = field[5] + max = field[6] + elseif field[2] == COMBO then + min = 0 + max = #(field[5]) - 1 + end + if field[2] ~= FLPOT then --only read ? + if field[2] == VALUE and field[6] > 256 then + if field[4] > 1000 then + step = step * 50 + field[4] = math.floor(field[4]/50) + field[4] = field[4] *50 + elseif field[4] > 500 then + step = step * 20 + field[4] = math.floor(field[4]/20) + field[4] = field[4] *20 + elseif field[4] > 200 then + step = step * 10 + field[4] = math.floor(field[4]/10) + field[4] = field[4] *10 + else + step = step * 1 + field[4] = math.floor(field[4]/1) + field[4] = field[4] *1 + end + end + if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then + field[4] = field[4] + step + end + else + field[4] = field[4] + end +end + +-- Select the next or previous page +local function selectPage(step) + page = 1 + ((page + step - 1 + #pages) % #pages) + refreshIndex = 0 + pageOffset = 0 +end + +-- Select the next or previous editable field +local function selectField(step) + current = current + step + if current > #fields then + current = #fields + elseif current < 1 then + current = 1 + end + if current > 7 + pageOffset then + pageOffset = current - 7 + elseif current <= pageOffset then + pageOffset = current - 1 + end +end + +local function drawProgressBar() + if LCD_W == 480 then + local width = (300 * refreshIndex) / #fields + lcd.drawRectangle(100, 10, 300, 6) + lcd.drawFilledRectangle(102, 13, width, 2); + else + local width = (60 * refreshIndex) / #fields + lcd.drawRectangle(45, 1, 60, 6) + lcd.drawFilledRectangle(47, 3, width, 2); + end +end + +-- Redraw the current page +local function redrawFieldsPage() + lcd.clear() + drawScreenTitle("GasSuit", page, #pages) + if refreshIndex < #fields then + drawProgressBar() + end + for index = 1, 7, 1 do + local field = fields[pageOffset+index] + if field == nil then + break + end + local attr = current == (pageOffset+index) and ((edit == true and BLINK or 0) + INVERS) or 0 + lcd.drawText(1, margin+ spacing * index, field[1]) + if field[4] == nil then + lcd.drawText(LCD_W, margin+ spacing * index, "---", attr + RIGHT) + else + if field[2] == VALUE then + if (field[3] == 0x90 or field[3] == 0x91) and field[4] == 500 then + lcd.drawText(LCD_W, margin+ spacing * index, "---", attr + RIGHT) + else + + lcd.drawNumber(LCD_W, margin+ spacing * index, field[4] , attr + RIGHT) + end + elseif field[2] == COMBO then + if field[4] >= 0 and field[4] < #(field[5]) then + lcd.drawText(LCD_W, margin+ spacing * index, field[5][1+field[4]], attr + RIGHT) + end + elseif field[2] == FLPOT then + lcd.drawText(LCD_W, margin+ spacing * index, field[4], attr + RIGHT) + end + end + end +end + +local function telemetryRead(fieldx) + return sportTelemetryPush(0x1b, 0x30, appId, fieldx) +end + +local function telemetryListen(fieldx) + return sportTelemetryPush(0x1b, 0, 0, 0) +end + +local function telemetryWrite(fieldx, valuex) + return sportTelemetryPush(0x1b, 0x31, appId, fieldx + valuex*256) +end + +local telemetryPopTimeout = 0 +local function refreshNext() + if refreshState == 0 and page ~= 3 then -- + if #modifications > 0 then -- + if modifications[1][1] ~= 0x0c then + if modifications[1][1] == 0x22 then + modifications[1][2] = modifications[1][2] + 0xf00 + end + local modificationstmp = modifications[1][2] + if modifications[1][1] == 0x8a or modifications[1][1] == 0x8b then + if configFields[11][4]== 1 then + modificationstmp = (modifications[1][2] - 32)*10 + modificationstmp = math.floor(modificationstmp/18) + end + end + telemetryWrite(modifications[1][1], modificationstmp) + refreshIndex = 0 + end + modifications[1] = nil + elseif refreshIndex < #fields then + local field = fields[refreshIndex + 1] + if telemetryRead(field[3]) == true then + refreshState = 1 + telemetryPopTimeout = getTime() + 80 + end + end + elseif refreshState == 0 and page == 3 then + if #modifications > 0 then + if modifications[1][1] == 0x96 or modifications[1][1] == 0x97 or modifications[1][1] == 0x93 then + telemetryWrite(modifications[1][1], 0) + end + modifications[1] = nil + elseif refreshIndex < #fields then + local field = fields[refreshIndex + 1] + if telemetryRead(field[3]) == true then + refreshState = 1 + telemetryPopTimeout = getTime() + 20 + end + elseif refreshIndex >= #fields then + refreshIndex = 0 + refreshState = 0 + end + elseif refreshState == 1 and page ~= 3 then + local physicalId, primId, dataId, value = sportTelemetryPop() + if primId == 0x32 and dataId >= 0x0d00 and dataId <= 0x0d7f then + local fieldId = value % 256 + local field = fields[refreshIndex + 1] + if fieldId == field[3] then + local value = math.floor(value / 256) + if field[2] == COMBO then + for index = 1, #(field[6]), 1 do + if value == field[6][index] then + value = index - 1 + break + end + end + elseif field[2] == VALUE then + value = value -- - field[8] + field[5] + end + if field[1] == "Software version" then + local flo_string = string.char(value/16%16 + 48).."."..string.char(value%16 + 48) + fields[refreshIndex + 1][4] = flo_string + else + fields[refreshIndex + 1][4] = value + end + refreshIndex = refreshIndex + 1 + refreshState = 0 + end + elseif getTime() > telemetryPopTimeout then + refreshState = 0 + end + elseif refreshState == 1 and page == 3 then + local pageID3 = 0 + local physicalId3, primId3, dataId3, value3 = sportTelemetryPop() + if value3 ~= nil then + pageID3 = value3 % 256 + value3 = math.floor(value3 / 0x100) + end + if primId3 == 0x32 and value3 ~= nil then + if pageID3 == fields[refreshIndex + 1][3] then + local field = fields[refreshIndex + 1] + if field[2] == COMBO and #field == 6 then + for index = 1, #(field[6]), 1 do + if value3 == field[6][index] then + value3 = index - 1 + break + end + end + elseif field[2] == VALUE then + if field[3] == 0x90 or field[3] == 0x91 then + value3 = math.floor(value3 % 0x10000) + if value3 > 0xf000 then + value3 = value3 - 0x10000 + end + if configFields[11][4]== 1 and (field[3] == 0x90 or field[3] == 0x91) then + value3 =(value3*18) + value3 = math.floor(value3/10)+32 + end + else + value3 = value3 + end + end + fields[refreshIndex + 1][4] = value3 + refreshIndex = refreshIndex + 1 + refreshState = 0 + end + elseif getTime() > telemetryPopTimeout then + refreshState = 0 + end + end +end + +local function updateField(field) + local value = field[4] + if field[2] == COMBO and #field == 6 then + value = field[6][1+value] + elseif field[2] == VALUE and #field == 6 then + value = value -- + field[8] - field[5] + elseif field[2] == FLPOT then + value = 0 + end + modifications[#modifications+1] = {field[3], value} +end + +-- Main1 +local function runFieldsPage(event) + if event == EVT_VIRTUAL_EXIT then + return 2 + elseif event == EVT_VIRTUAL_ENTER then + if fields[current][4] ~= nil then + edit = not edit + if edit == false then + updateField(fields[current]) + end + end + elseif edit then + if event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then + addField(1) + elseif event == EVT_VIRTUAL_PREVIOUS or event == EVT_VIRTUAL_PREVIOUS_REPT then + addField(-1) + end + else + if event == EVT_VIRTUAL_NEXT then + selectField(1) + elseif event == EVT_VIRTUAL_PREVIOUS then + selectField(-1) + end + end + redrawFieldsPage() + return 0 +end + +local function runConfigPage(event) + fields = configFields + local result = runFieldsPage(event) + return result +end + +local function runSettingsPage(event) + fields = settingsFields + return runFieldsPage(event) +end + +local function runTelemetryPage(event) + fields = telemetryFields + return runFieldsPage(event) +end + +-- Init +local function init() + current, edit, refreshState, refreshIndex = 1, false, 0, 0 + if LCD_W == 480 then + margin = 10 + spacing = 20 + end + if LCD_W == 128 then + configFields = { + {"CDI off speed limit", VALUE, 0x81, nil, 10,10000}, -- 1 + {"Milliliter per pulse", VALUE, 0x80, nil, 1, 2000}, -- 2 + {"Volume", VALUE, 0x83, nil, 10,60000}, -- 3 + -- {"Flow trigger", VALUE, 0x84, nil, 5, 50 }, + -- {"Flow Reset", COMBO, 0x85, nil, { "ON", "OFF" }, {1 , 0}}, + {"Auto Reset", COMBO, 0x8d, nil, { "ON", "OFF" }, {0 , 1}}, -- 4 + {"Reset settings", COMBO, 0x86, nil,{ "YES", "NO" }, {1 , 0} }, -- 5 + {"Volume alarm(%)", VALUE, 0x87, nil, 0, 90 }, -- 6 + {"Max.Flow alarm", VALUE, 0x88, nil, 0, 2000 }, -- 7 + {"Over speed alarm", VALUE, 0x89, nil, 0, 10000 }, -- 8 + {"Over temp1 alarm", VALUE, 0x8a, nil, 0, 600 }, -- 9 + {"Over temp2 alarm", VALUE, 0x8b, nil, 0, 600 }, -- 10 + {"Temperature C/F", COMBO, 0x8c, nil,{ "C", "F" }, {0 , 1} }, -- 11 + } + else + configFields = { + {"CDI off speed limit(*100RPM)", VALUE, 0x81, nil, 10,10000}, + {"Milliliter per pulse(*0.001mL/pul)", VALUE, 0x80, nil, 1, 2000}, + {"Volume(mL)", VALUE, 0x83, nil, 10,60000}, + -- {"Flow trigger(mL/min)", VALUE, 0x84, nil, 5, 50 }, + -- {"Flow Reset", COMBO, 0x85, nil, { "ON", "OFF" }, {1 , 0}}, + {"Auto Reset", COMBO, 0x8d, nil, { "ON", "OFF" }, {0 , 1}}, + {"Reset to factory settings", COMBO, 0x86, nil,{ "YES", "NO" }, {1 , 0} }, + {"Volume alarm(%)", VALUE, 0x87, nil, 0, 90 }, + {"Max.Flow alarm(mL/min)", VALUE, 0x88, nil, 0, 2000 }, + {"Over speed alarm(*100RPM)", VALUE, 0x89, nil, 0, 10000 }, + {"Over temperature1 alarm(C/F)", VALUE, 0x8a, nil, 0, 600 }, + {"Over temperature2 alarm(C/F)", VALUE, 0x8b, nil, 0, 600 }, + {"Temperature Celsius/Fahrenheit", COMBO, 0x8c, nil,{ "C", "F" }, {0 , 1} }, + } + end + + pages = { + runConfigPage, + runSettingsPage, + runTelemetryPage, + } + + -- Warning : GaSuite tool requires Temp2 to be connected and discovered for script to work + for index = 1, 40, 1 do + local sensor = model.getSensor(index) + if sensor ~= nil and sensor.id >= 0x0d10 and sensor.id <= 0x0d1f then + appId = sensor.id + break + end + end + + if appId == 0 then + error("No GasSuit sensor in this model!") + end +end + +local function background() + local tonefrq,tonelength,tonepause + thistime = getTime() + lastTime = thistime + refreshNext() + if page == 3 then --alarm + local alarmnum = 0 + if fields[3][4] ~= nil and configFields[9][4] ~= nil then + local speedtest = fields[3][4] + local speedover = configFields[9][4]*100 + if speedtest >= speedover then + tonefrq = 800 + math.max(0,math.floor((speedtest - speedover)/10)) + tonelength = 50 + math.max(0,(150 - math.floor((speedtest - speedover)/10))) + tonepause = tonelength + playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10) + alarmnum = alarmnum + 1 + end + end + if fields[5][4] ~= nil and configFields[7][4] ~= nil then + local Residualtest = fields[5][4] + local Residualline = configFields[6][4] + if Residualtest < Residualline then + tonefrq = 400 + tonelength = 100 + tonepause = 1000 + math.floor( Residualline - Residualtest )*30 + playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10) + alarmnum = alarmnum + 1 + end + end + if fields[6][4] ~= nil and configFields[8][4] ~= nil then + local Flowtest = fields[6][4] + local Flowover = configFields[7][4] + if Flowtest > Flowover then + tonefrq = 400 + tonelength = 100 + tonepause = 200 + playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10) + alarmnum = alarmnum + 1 + end + end + if fields[1][4] ~= nil and configFields[10][4] ~= nil then + local temp1test = fields[1][4] -- + local temp1over = configFields[9][4] + if temp1test > temp1over and (temp1test ~= 500 and temp1test ~= 932) then + tonefrq = 2000 + tonelength = 100 + tonepause = 900 + playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10) + alarmnum = alarmnum + 1 + end + end + if fields[2][4] ~= nil and configFields[11][4] ~= nil then + local temp2test = fields[2][4] + local temp2over = configFields[10][4] + if temp2test > temp2over and (temp2test ~= 500 and temp2test ~= 932) then + tonefrq = 2000 + tonelength = 300 + tonepause = 700 + playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10) + alarmnum = alarmnum + 1 + end + end + if alarmnum > 1 then + playTone(2000, 100, 100, PLAY_BACKGROUND,10) + end + alarmnum = 0 + end +end + +local function run(event) + if event == nil then + error("Cannot be run as a sensor script!") + return 2 + elseif event == EVT_VIRTUAL_NEXT_PAGE then + selectPage(1) + elseif event == EVT_VIRTUAL_PREVIOUS_PAGE then + killEvents(event); + selectPage(-1) + end + local result = pages[page](event) + if page ~= 3 then + refreshNext() + end + background() + return result +end + +return { init=init, background=background, run=run } diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky SBEC.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky SBEC.lua new file mode 100644 index 000000000..1b82bc47f --- /dev/null +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky SBEC.lua @@ -0,0 +1,289 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + +local version = "v1.2" + +local VALUE = 0 +local COMBO = 1 + +local edit = false +local page = 1 +local current = 1 --row +local refreshState = 0 +local refreshIndex = 0 +local pageOffset = 0 +local pages = {} +local fields = {} +local modifications = {} +local margin = 1 +local spacing = 8 +local appId = 0 + +local function drawScreenTitle(title,page, pages) + if math.fmod(math.floor(getTime()/100),10) == 0 then + title = version + end + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + lcd.drawText(LCD_W-40, 5, page.."/"..pages, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, page, pages) + end +end + +local settingsFields = { + {"SBEC OUTPUT (V)", VALUE, 0x80, nil, 50, 84 }, + {"Physical ID", VALUE, 0x01, nil, 0, 26 }, + {"Application IDgroup", VALUE, 0x0D, nil, 0, 15 }, + {"Data rate(*100ms)", VALUE, 0x22, nil, 1, 255 }, +} + +-- Change display attribute to current field +local function addField(step) + local field = fields[current] + local min, max + if field[2] == VALUE then + min = field[5] + max = field[6] + elseif field[2] == COMBO then + min = 0 + max = #(field[5]) - 1 + end + if field[2] ~= FLPOT then --only read ? + if field[2] == VALUE and field[6] > 256 then + if field[4] > 1000 then + step = step * 50 + field[4] = math.floor(field[4]/50) + field[4] = field[4] *50 + elseif field[4] > 500 then + step = step * 20 + field[4] = math.floor(field[4]/20) + field[4] = field[4] *20 + elseif field[4] > 200 then + step = step * 10 + field[4] = math.floor(field[4]/10) + field[4] = field[4] *10 + else + step = step * 1 + field[4] = math.floor(field[4]/1) + field[4] = field[4] *1 + end + end + if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then + field[4] = field[4] + step + end + else + field[4] = field[4] + end +end + + +-- Select the next or previous editable field +local function selectField(step) + current = current + step + if current > #fields then + current = #fields + elseif current < 1 then + current = 1 + end + if current > 7 + pageOffset then + pageOffset = current - 7 + elseif current <= pageOffset then + pageOffset = current - 1 + end +end + +local function drawProgressBar() + if LCD_W == 480 then + local width = (300 * refreshIndex) / #fields + lcd.drawRectangle(100, 10, 300, 6) + lcd.drawFilledRectangle(102, 13, width, 2); + else + local width = (60 * refreshIndex) / #fields + lcd.drawRectangle(45, 1, 60, 6) + lcd.drawFilledRectangle(47, 3, width, 2); + end +end + +-- Redraw the current page +local function redrawFieldsPage() + lcd.clear() + drawScreenTitle("SBEC", page, #pages) + if refreshIndex < #fields then + drawProgressBar() + end + for index = 1, 7, 1 do + local field = fields[pageOffset+index] + if field == nil then + break + end + local attr = current == (pageOffset+index) and ((edit == true and BLINK or 0) + INVERS) or 0 + lcd.drawText(1, margin+ spacing * index, field[1]) + if field[4] == nil then + lcd.drawText(LCD_W, margin+ spacing * index, "---", attr + RIGHT) + else + if field[2] == VALUE then + if field[3] == 0x80 then + lcd.drawNumber(LCD_W, margin+ spacing * index, field[4] , attr + RIGHT + PREC1) + else + lcd.drawNumber(LCD_W, margin+ spacing * index, field[4] , attr + RIGHT) + end + end + end + end +end + +local function telemetryRead(fieldx) + return sportTelemetryPush(0x17, 0x30, appId, fieldx) +end + +local function telemetryIdle(field) + return sportTelemetryPush(0x17, 0x21, appId, field) +end + +local function telemetryUnIdle(field) + return sportTelemetryPush(0x17, 0x20, appId, field) +end + +local function telemetryWrite(fieldx, valuex) + return sportTelemetryPush(0x17, 0x31, appId, fieldx + valuex*256) +end + +local telemetryPopTimeout = 0 +local function refreshNext() + if refreshState == 0 then + if #modifications > 0 then + local modificationstmp = modifications[1][2] + telemetryWrite(modifications[1][1], modificationstmp) + refreshIndex = 0 + modifications[1] = nil + elseif refreshIndex < #fields then + local field = fields[refreshIndex + 1] + if telemetryRead(field[3]) == true then + refreshState = 1 + telemetryPopTimeout = getTime() + 80 + end + end + elseif refreshState == 1 then + local physicalId, primId, dataId, value = sportTelemetryPop() + if primId == 0x32 and dataId == appId then + local fieldId = value % 256 + local field = fields[refreshIndex + 1] + if fieldId == field[3] then + local value = math.floor(value / 256) + if field[2] == VALUE then + value = value + end + + fields[refreshIndex + 1][4] = value + refreshIndex = refreshIndex + 1 + refreshState = 0 + end + elseif getTime() > telemetryPopTimeout then + refreshState = 0 + end + end +end + +local function updateField(field) + local value = field[4] + if field[2] == VALUE and #field == 6 then + value = value + end + modifications[#modifications+1] = {field[3], value} +end + +-- Main1 +local function runFieldsPage(event) + if event == EVT_VIRTUAL_EXIT then + telemetryUnIdle(0x80) + return 2 + elseif event == EVT_VIRTUAL_ENTER then + if fields[current][4] ~= nil then + edit = not edit + if edit == false then + updateField(fields[current]) + end + end + elseif edit then + if event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then + addField(1) + elseif event == EVT_VIRTUAL_PREVIOUS or event == EVT_VIRTUAL_PREVIOUS_REPT then + addField(-1) + end + else + if event == EVT_VIRTUAL_NEXT then + selectField(1) + elseif event == EVT_VIRTUAL_PREVIOUS then + selectField(-1) + end + end + redrawFieldsPage() + return 0 +end + +local function runSettingsPage(event) + fields = settingsFields + return runFieldsPage(event) +end + +-- Init +local function init() + current, edit, refreshState, refreshIndex = 1, false, 0, 0 + if LCD_W == 480 then + margin = 10 + spacing = 20 + end + + pages = { + runSettingsPage, + } + + for index = 1, 40, 1 do + local sensor = model.getSensor(index) + if sensor ~= nil and sensor.id >= 0x0e50 and sensor.id <= 0x0e5f then + appId = sensor.id + break + end + end + + if appId == 0 then + error("No SBEC sensor in this model!") + end + + telemetryIdle(0x80) +end + +local function run(event) + if event == nil then + error("Cannot run as a model script!") + return 2 + elseif event == EVT_PAGE_BREAK or event == EVT_PAGEDN_FIRST or event == EVT_SHIFT_BREAK then + --selectPage(1) + elseif event == EVT_PAGE_LONG or event == EVT_PAGEUP_FIRST or event == EVT_SHIFT_LONG then + --killEvents(event); + --selectPage(-1) + end + local result = pages[page](event) + + refreshNext() + + return result +end + +return { init=init, background=background, run=run } diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky SxR.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky SxR.lua new file mode 100755 index 000000000..c49b78f52 --- /dev/null +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/FrSky SxR.lua @@ -0,0 +1,363 @@ +--- - ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +----- # # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + +local version = "v2.00" + +local VALUE = 0 +local COMBO = 1 + +local COLUMN_2 = 300 + +local edit = false +local page = 1 +local current = 1 +local refreshState = 0 +local refreshIndex = 0 +local calibrationState = 0 +local pageOffset = 0 +local calibrationStep = 0 +local pages = {} +local fields = {} +local modifications = {} +local wingBitmaps = {} +local mountBitmaps = {} +local margin = 1 +local spacing = 8 +local counter = 0 + +local configFields = { + { "Wing type", COMBO, 0x80, nil, { "Normal", "Delta", "VTail" } }, + { "Mounting type", COMBO, 0x81, nil, { "Horz", "Horz rev.", "Vert", "Vert rev." } }, +} + +local wingBitmapsFile = { "bmp/plane.bmp", "bmp/delta.bmp", "bmp/vtail.bmp" } +local mountBitmapsFile = { "bmp/horz.bmp", "bmp/horz-r.bmp", "bmp/vert.bmp", "bmp/vert-r.bmp" } + +local settingsFields = { + {"SxR functions", COMBO, 0x9C, nil, { "Disable", "Enable" } }, + {"Quick Mode:", COMBO, 0xAA, nil, { "Disable", "Enable" } }, + {"CH5 mode", COMBO, 0xA8, nil, { "AIL2", "AUX1" } }, + {"CH6 mode", COMBO, 0xA9, nil, { "ELE2", "AUX2" } }, + {"AIL direction", COMBO, 0x82, nil, { "Normal", "Invers" }, { 255, 0 } }, + {"ELE direction", COMBO, 0x83, nil, { "Normal", "Invers" }, { 255, 0 } }, + {"RUD direction", COMBO, 0x84, nil, { "Normal", "Invers" }, { 255, 0 } }, + {"AIL2 direction", COMBO, 0x9A, nil, { "Normal", "Invers" }, { 255, 0 } }, + {"ELE2 direction", COMBO, 0x9B, nil, { "Normal", "Invers" }, { 255, 0 } }, + {"AIL stab gain", VALUE, 0x85, nil, 0, 200, "%"}, + {"ELE stab gain", VALUE, 0x86, nil, 0, 200, "%"}, + {"RUD stab gain", VALUE, 0x87, nil, 0, 200, "%"}, + {"AIL autolvl gain", VALUE, 0x88, nil, 0, 200, "%"}, + {"ELE autolvl gain", VALUE, 0x89, nil, 0, 200, "%"}, + {"ELE hover gain", VALUE, 0x8C, nil, 0, 200, "%"}, + {"RUD hover gain", VALUE, 0x8D, nil, 0, 200, "%"}, + {"AIL knife gain", VALUE, 0x8E, nil, 0, 200, "%"}, + {"RUD knife gain", VALUE, 0x90, nil, 0, 200, "%"}, + {"AIL autolvl offset", VALUE, 0x91, nil, -20, 20, "%", 0x6C}, + {"ELE autolvl offset", VALUE, 0x92, nil, -20, 20, "%", 0x6C}, + {"ELE hover offset", VALUE, 0x95, nil, -20, 20, "%", 0x6C}, + {"RUD hover offset", VALUE, 0x96, nil, -20, 20, "%", 0x6C}, + {"AIL knife offset", VALUE, 0x97, nil, -20, 20, "%", 0x6C}, + {"RUD knife offset", VALUE, 0x99, nil, -20, 20, "%", 0x6C}, +} + +local calibrationFields = { + { "X:", VALUE, 0x9E, 0, -100, 100, "%" }, + { "Y:", VALUE, 0x9F, 0, -100, 100, "%" }, + { "Z:", VALUE, 0xA0, 0, -100, 100, "%" } +} + +local function drawScreenTitle(title, page, pages) + if math.fmod(math.floor(getTime() / 100), 10) == 0 then + title = version + end + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + lcd.drawText(LCD_W - 40, 5, page .. "/" .. pages, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, page, pages) + end +end + +-- Change display attribute to current field +local function addField(step) + local field = fields[current] + local min, max + if field[2] == VALUE then + min = field[5] + max = field[6] + elseif field[2] == COMBO then + min = 0 + max = #(field[5]) - 1 + end + if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then + field[4] = field[4] + step + end +end + +-- Select the next or previous page +local function selectPage(step) + page = 1 + ((page + step - 1 + #pages) % #pages) + refreshIndex = 0 + calibrationStep = 0 + pageOffset = 0 +end + +-- Select the next or previous editable field +local function selectField(step) + current = 1 + ((current + step - 1 + #fields) % #fields) + if current > 7 + pageOffset then + pageOffset = current - 7 + elseif current <= pageOffset then + pageOffset = current - 1 + end +end + +local function drawProgressBar() + if LCD_W == 480 then + local width = (300 * refreshIndex) / #fields + lcd.drawRectangle(100, 10, 300, 6) + lcd.drawFilledRectangle(102, 13, width, 2); + else + local width = (60 * refreshIndex) / #fields + lcd.drawRectangle(45, 1, 60, 6) + lcd.drawFilledRectangle(47, 3, width, 2); + end +end + +-- Redraw the current page +local function redrawFieldsPage(event) + lcd.clear() + drawScreenTitle("SxR", page, #pages) + + if refreshIndex < #fields then + drawProgressBar() + end + + for index = 1, 10, 1 do + local field = fields[pageOffset + index] + if field == nil then + break + end + + local attr = current == (pageOffset + index) and ((edit == true and BLINK or 0) + INVERS) or 0 + + lcd.drawText(1, margin + spacing * index, field[1], attr) + + if field[4] == nil then + lcd.drawText(LCD_W, margin + spacing * index, "---", RIGHT + attr) + else + if field[2] == VALUE then + lcd.drawNumber(LCD_W, margin + spacing * index, field[4], RIGHT + attr) + elseif field[2] == COMBO then + if field[4] >= 0 and field[4] < #(field[5]) then + lcd.drawText(LCD_W, margin + spacing * index, field[5][1 + field[4]], RIGHT + attr) + end + end + end + end +end + +local function telemetryRead(field) + return sportTelemetryPush(0x17, 0x30, 0x0C30, field) +end + +local function telemetryWrite(field, value) + return sportTelemetryPush(0x17, 0x31, 0x0C30, field + value * 256) +end + +local telemetryPopTimeout = 0 +local function refreshNext() + if refreshState == 0 then + if calibrationState == 1 then + if telemetryWrite(0x9D, calibrationStep) == true then + refreshState = 1 + calibrationState = 2 + telemetryPopTimeout = getTime() + 120 -- normal delay is 500ms + end + elseif #modifications > 0 then + telemetryWrite(modifications[1][1], modifications[1][2]) + modifications[1] = nil + elseif refreshIndex < #fields then + local field = fields[refreshIndex + 1] + if telemetryRead(field[3]) == true then + refreshState = 1 + telemetryPopTimeout = getTime() + 80 -- normal delay is 500ms + end + end + elseif refreshState == 1 then + local physicalId, primId, dataId, value = sportTelemetryPop() + if physicalId == 0x1A and primId == 0x32 and dataId == 0x0C30 then + local fieldId = value % 256 + if calibrationState == 2 then + if fieldId == 0x9D then + refreshState = 0 + calibrationState = 0 + calibrationStep = (calibrationStep + 1) % 7 + end + else + local field = fields[refreshIndex + 1] + if fieldId == field[3] then + local value = math.floor(value / 256) + if field[3] == 0xAA then + value = bit32.band(value, 0x0001) + end + if field[3] >= 0x9E and field[3] <= 0xA0 then + local b1 = value % 256 + local b2 = math.floor(value / 256) + value = b1 * 256 + b2 + value = value - bit32.band(value, 0x8000) * 2 + end + if field[2] == COMBO and #field == 6 then + for index = 1, #(field[6]), 1 do + if value == field[6][index] then + value = index - 1 + break + end + end + elseif field[2] == VALUE and #field == 8 then + value = value - field[8] + field[5] + end + fields[refreshIndex + 1][4] = value + refreshIndex = refreshIndex + 1 + refreshState = 0 + end + end + elseif getTime() > telemetryPopTimeout then + fields[refreshIndex + 1][4] = nil + refreshIndex = refreshIndex + 1 + refreshState = 0 + calibrationState = 0 + end + end +end + +local function updateField(field) + local value = field[4] + if field[2] == COMBO and #field == 6 then + value = field[6][1 + value] + elseif field[2] == VALUE and #field == 8 then + value = value + field[8] - field[5] + end + modifications[#modifications + 1] = { field[3], value } +end + +-- Main +local function runFieldsPage(event) + if event == EVT_VIRTUAL_EXIT then -- exit script + return 2 + elseif event == EVT_VIRTUAL_ENTER then -- toggle editing/selecting current field + if fields[current][4] ~= nil then + edit = not edit + if edit == false then + updateField(fields[current]) + end + end + elseif edit then + if event == EVT_VIRTUAL_NEXT or event == EVT_VIRTUAL_NEXT_REPT then + addField(1) + elseif event == EVT_VIRTUAL_PREVIOUS or event == EVT_VIRTUAL_PREVIOUS_REPT then + addField(-1) + end + else + if event == EVT_VIRTUAL_NEXT then + selectField(1) + elseif event == EVT_VIRTUAL_PREVIOUS then + selectField(-1) + end + end + redrawFieldsPage(event) + return 0 +end + +local function runConfigPage(event) + fields = configFields + local result = runFieldsPage(event) + if LCD_W == 128 then + local mountText = { "Label is facing the sky", "Label is facing ground", "Label is left when", "Label is right when" } + if fields[2][4] ~= nil then + lcd.drawText(1, 30, "Pins toward tail") + lcd.drawText(1, 40, mountText[1 + fields[2][4]]) + if fields[2][4] > 1 then + lcd.drawText(1, 50, "looking from the tail") + end + end + else + if fields[1][4] ~= nil then + if LCD_W == 480 then + if wingBitmaps[1 + fields[1][4]] == nil then + wingBitmaps[1 + fields[1][4]] = Bitmap.open(wingBitmapsFile[1 + fields[1][4]]) + end + lcd.drawBitmap(wingBitmaps[1 + fields[1][4]], 10, 90) + else + lcd.drawPixmap(20, 28, wingBitmapsFile[1 + fields[1][4]]) + end + end + if fields[2][4] ~= nil then + if LCD_W == 480 then + if mountBitmaps[1 + fields[2][4]] == nil then + mountBitmaps[1 + fields[2][4]] = Bitmap.open(mountBitmapsFile[1 + fields[2][4]]) + end + lcd.drawBitmap(mountBitmaps[1 + fields[2][4]], 190, 110) + else + lcd.drawPixmap(128, 28, mountBitmapsFile[1 + fields[2][4]]) + end + end + end + return result +end + +local function runSettingsPage(event) + fields = settingsFields + return runFieldsPage(event) +end + +-- Init +local function init() + current, edit, refreshState, refreshIndex = 1, false, 0, 0 + if LCD_W == 480 then + margin = 10 + spacing = 20 + wingBitmapsFile = { "img/plane_b.png", "img/delta_b.png", "img/planev_b.png" } + mountBitmapsFile = { "img/up.png", "img/down.png", "img/vert.png", "img/vert-r.png" } + end + pages = { + runConfigPage, + runSettingsPage, + } +end + +-- Main +local function run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + elseif event == EVT_VIRTUAL_NEXT_PAGE then + selectPage(1) + elseif event == EVT_VIRTUAL_PREVIOUS_PAGE then + killEvents(event); + selectPage(-1) + end + + local result = pages[page](event) + refreshNext() + + return result +end + +return { init = init, run = run } + diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/crossfire.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/crossfire.lua new file mode 100644 index 000000000..de0ec06dc --- /dev/null +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/crossfire.lua @@ -0,0 +1,37 @@ +local toolName = "TNS|Crossfire configure|TNE" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + + + +-- Init +local function init() +end + +-- Run +local function run(event) + if event == nil then + error("Cannot run as a model script!") + return 2 + end + + chdir("CROSSFIRE") + return "crossfire.lua" +end + +return { init=init, run=run } diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/readme.txt b/radio/sdcard/horus/SCRIPTS/TOOLS/readme.txt new file mode 100644 index 000000000..20b95c415 --- /dev/null +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/readme.txt @@ -0,0 +1 @@ +Scripts that need to be available in TOOLS menu should be in this directory diff --git a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/crossfire.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/crossfire.lua new file mode 100644 index 000000000..62ca776d7 --- /dev/null +++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/crossfire.lua @@ -0,0 +1,37 @@ +local toolName = "TNS|Crossfire config|TNE" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + + + +-- Init +local function init() +end + +-- Run +local function run(event) + if event == nil then + error("Cannot run as a model script!") + return 2 + end + + chdir("CROSSFIRE") + return "crossfire.lua" +end + +return { init=init, run=run } diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/crossfire.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/crossfire.lua new file mode 100644 index 000000000..de0ec06dc --- /dev/null +++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/crossfire.lua @@ -0,0 +1,37 @@ +local toolName = "TNS|Crossfire configure|TNE" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + + + +-- Init +local function init() +end + +-- Run +local function run(event) + if event == nil then + error("Cannot run as a model script!") + return 2 + end + + chdir("CROSSFIRE") + return "crossfire.lua" +end + +return { init=init, run=run } diff --git a/radio/src/gui/480x272/radio_tools.cpp b/radio/src/gui/480x272/radio_tools.cpp index 5161ea7ad..283799234 100644 --- a/radio/src/gui/480x272/radio_tools.cpp +++ b/radio/src/gui/480x272/radio_tools.cpp @@ -103,11 +103,6 @@ bool menuRadioTools(event_t event) FILINFO fno; DIR dir; -#if defined(CROSSFIRE) - if(isFileAvailable(SCRIPTS_TOOLS_PATH "/CROSSFIRE/crossfire.lua")) - addRadioScriptTool(index++, SCRIPTS_TOOLS_PATH "/CROSSFIRE/crossfire.lua"); -#endif - FRESULT res = f_opendir(&dir, SCRIPTS_TOOLS_PATH); if (res == FR_OK) { for (;;) { diff --git a/radio/src/gui/common/stdlcd/radio_tools.cpp b/radio/src/gui/common/stdlcd/radio_tools.cpp index b0044c25f..5ad9f6a3a 100644 --- a/radio/src/gui/common/stdlcd/radio_tools.cpp +++ b/radio/src/gui/common/stdlcd/radio_tools.cpp @@ -102,11 +102,6 @@ void menuRadioTools(event_t event) FILINFO fno; DIR dir; -#if defined(CROSSFIRE) - if(isFileAvailable(SCRIPTS_TOOLS_PATH "/CROSSFIRE/crossfire.lua")) - addRadioScriptTool(index++, SCRIPTS_TOOLS_PATH "/CROSSFIRE/crossfire.lua"); -#endif - FRESULT res = f_opendir(&dir, SCRIPTS_TOOLS_PATH); if (res == FR_OK) { for (;;) { diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 659fb38ed..75f1a36d8 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -1357,6 +1357,24 @@ static int luaGetRSSI(lua_State * L) return 3; } +/*luadoc +@function chdir(directory) + + Change the working directory + +@param directory (string) New working directory + +@status current Introduced in 2.3.0 + +*/ + +static int luaChdir(lua_State * L) +{ + const char * directory = luaL_optstring(L, 1, nullptr); + f_chdir(directory); + return 0; +} + /*luadoc @function loadScript(file [, mode], [,env]) @@ -1554,6 +1572,7 @@ const luaL_Reg opentxLib[] = { { "defaultChannel", luaDefaultChannel }, { "getRSSI", luaGetRSSI }, { "killEvents", luaKillEvents }, + { "chdir", luaChdir }, { "loadScript", luaLoadScript }, { "getUsage", luaGetUsage }, { "resetGlobalTimer", luaResetGlobalTimer },