diff --git a/README.md b/README.md index a2241df..97ad2bd 100644 --- a/README.md +++ b/README.md @@ -47,4 +47,5 @@ RGB LED control tool for EdgeTX 2.11+ radios. ## Notes - Requires EdgeTX 2.11 or newer. +- Animates decorative gimbal / "bling" LEDs only (20 LEDs on TX16S Mk3, GX15 and TX15). Custom function switch RGB colours stay under Radio/Model settings. - The keeper polls `/SCRIPTS/TOOLS/RGB.dat` and runs the selected mode, so no other mode scripts are needed. diff --git a/SCRIPTS/RGBLED/rgbk.lua b/SCRIPTS/RGBLED/rgbk.lua index acd617f..9bce3c7 100644 --- a/SCRIPTS/RGBLED/rgbk.lua +++ b/SCRIPTS/RGBLED/rgbk.lua @@ -15,8 +15,42 @@ -- on-screen preview matches exactly what the keeper runs on the radio. local CFG = "/SCRIPTS/TOOLS/RGB.dat" -local N = LED_STRIP_LENGTH or 0 -local HALF = math.floor(N / 2) + +-- Decorative ("bling") LEDs only. Firmware maps Lua index 0 to the first +-- gimbal/bling LED. Function-switch LEDs stay under model on/off colours / +-- setCFSLedColor() and must not be painted here. +local function decorativeLength() + if type(BLING_LED_STRIP_LENGTH) == "number" and BLING_LED_STRIP_LENGTH > 0 then + return BLING_LED_STRIP_LENGTH + end + local n = LED_STRIP_LENGTH or 0 + if type(CFS_LED_STRIP_LENGTH) == "number" and CFS_LED_STRIP_LENGTH > 0 and n >= CFS_LED_STRIP_LENGTH then + return n - CFS_LED_STRIP_LENGTH + end + -- Pre-constant firmware: TX16S Mk3 / GX15 / TX15 report 20 bling + 6 CFS. + if n == 26 then return 20 end + return n +end + +local N = decorativeLength() +local HALF = math.max(1, math.floor(N / 2)) + +-- Bound every write to the decorative range so leftover CFS indices are never +-- touched, even if a pattern hardcodes a 10+10 gimbal layout. +local _setRGB = setRGBLedColor +local _applyRGB = applyRGBLedColors + +local function setRGBLedColor(id, r, g, b) + if type(_setRGB) ~= "function" then return false end + if type(id) ~= "number" or id < 0 or id >= N then return false end + return _setRGB(id, r, g, b) +end + +local function applyRGBLedColors() + if type(_applyRGB) == "function" then + _applyRGB() + end +end local curSel = nil local runFn = nil diff --git a/SCRIPTS/TOOLS/RGB.lua b/SCRIPTS/TOOLS/RGB.lua index e49e91b..479b4b8 100644 --- a/SCRIPTS/TOOLS/RGB.lua +++ b/SCRIPTS/TOOLS/RGB.lua @@ -3,7 +3,8 @@ local LED_DIR = "/SCRIPTS/RGBLED" local CFG_FILE = "/SCRIPTS/TOOLS/RGB.dat" -- Native "RGB Led" special function: loads .lua from /SCRIPTS/RGBLED/ -local FUNC_RGB_LED = 25 +-- Prefer the firmware constant so a future enum shift does not break setup. +local RGB_LED_FUNC = (type(FUNC_RGB_LED) == "number") and FUNC_RGB_LED or 25 -- Fixed Special Function slot for the keeper script (SF64 = index 63) local SF_SLOT = 63 local KEEPER_NAME = "rgbk" @@ -12,6 +13,7 @@ local CUSTOM_PREFIX = "custom:" local exitRequested = false local noLvgl = false +local noLeds = type(setRGBLedColor) ~= "function" or type(applyRGBLedColors) ~= "function" local selected = nil local subtitle = "" local buttons = {} @@ -156,7 +158,7 @@ end local function keeperInstalled() if type(model.getCustomFunction) ~= "function" then return false end local cur = model.getCustomFunction(SF_SLOT) - return cur ~= nil and cur.func == FUNC_RGB_LED and cur.name == KEEPER_NAME and cur.active == 1 + return cur ~= nil and cur.func == RGB_LED_FUNC and cur.name == KEEPER_NAME and cur.active == 1 end -- Install the keeper Special Function once. After it exists (and is enabled) @@ -169,7 +171,7 @@ local function ensureKeeper() return end local cur = model.getCustomFunction(SF_SLOT) - local ours = cur ~= nil and cur.func == FUNC_RGB_LED and cur.name == KEEPER_NAME + local ours = cur ~= nil and cur.func == RGB_LED_FUNC and cur.name == KEEPER_NAME if cur ~= nil and type(cur.func) == "number" and cur.func ~= 0 and not ours then lvgl.message({ title = "SF64 in use", message = "Special Function SF64 is already assigned to a different function. Free it to let the RGB LED tool use it." }) @@ -182,7 +184,7 @@ local function ensureKeeper() end model.setCustomFunction(SF_SLOT, { switch = onSwitch, - func = FUNC_RGB_LED, + func = RGB_LED_FUNC, name = KEEPER_NAME, active = 1, }) @@ -228,8 +230,10 @@ end local function selectMode(name) selected = name saveSelection(name) - preview(name) - ensureKeeper() + if not noLeds then + preview(name) + ensureKeeper() + end for key, _ in pairs(buttons) do setChecked(key, key == name) end @@ -254,9 +258,15 @@ local function buildUi() local MARGIN = 8 local GAP = 6 local LABEL_H = 28 - local y = MARGIN + if noLeds then + pg:label({ x = MARGIN, y = y, w = W - 2 * MARGIN, + text = "This radio has no RGB LED strip (setRGBLedColor missing).", + color = COLOR_THEME_WARNING }) + y = y + LABEL_H + GAP + end + local offBtn = pg:button({ x = MARGIN, y = y, w = W - 2 * MARGIN, h = EH, text = "Off", color = function() return COLOR_THEME_PRIMARY3 end, @@ -272,8 +282,9 @@ local function buildUi() text = "Setup Background Script on Model", color = function() return rgbValue({ r = 30, g = 120, b = 255 }, true) end, textColor = function() return rgbValue({ r = 30, g = 120, b = 255 }, false) end, - active = function() return not keeperInstalled() end, + active = function() return not noLeds and not keeperInstalled() end, press = function() + if noLeds then return end ensureKeeper() if keeperInstalled() then lvgl.message({ title = "Background Script Installed", @@ -341,6 +352,11 @@ local function init() if ok and info and type(info) == "table" then subtitle = info.name or "" end + if type(BLING_LED_STRIP_LENGTH) == "number" and BLING_LED_STRIP_LENGTH > 0 then + subtitle = (subtitle ~= "" and (subtitle .. " · ") or "") .. tostring(BLING_LED_STRIP_LENGTH) .. " LEDs" + elseif type(LED_STRIP_LENGTH) == "number" and LED_STRIP_LENGTH > 0 then + subtitle = (subtitle ~= "" and (subtitle .. " · ") or "") .. tostring(LED_STRIP_LENGTH) .. " LEDs" + end if lvgl == nil then noLvgl = true return @@ -365,7 +381,7 @@ local function run(event, touchState) end return 0 end - if selected then + if not noLeds and selected then preview(selected) end if exitRequested then