diff --git a/bin/minimize.lua b/bin/minimize.lua index f9ea3fe7..22cb23b2 100644 --- a/bin/minimize.lua +++ b/bin/minimize.lua @@ -166,6 +166,7 @@ local mspRcTuningReplacements = { { ".yaw_dynamic_ceiling_gain", "[28]" }, { ".yaw_dynamic_deadband_gain", "[29]" }, { ".yaw_dynamic_deadband_filter", "[30]" }, + { ".cyclic_ring", "[31]" }, } local mspPidTuningReplacements = { diff --git a/src/SCRIPTS/RF2/F/language.lua b/src/SCRIPTS/RF2/F/language.lua new file mode 100644 index 00000000..4dd33023 --- /dev/null +++ b/src/SCRIPTS/RF2/F/language.lua @@ -0,0 +1,33 @@ +local function loadTranslations(l) + local file = "LANG/" .. l .. ".lua" + local chunk, err = rf2.loadScript(file) + if not chunk then + -- It's normal for a language file not to exist, so we don't log an error. + -- The fallback mechanism will handle it. + return nil + end + local ok, result = pcall(chunk) + if not ok then + return nil + end + return result +end + +--- +-- Loads the translation file for the current system language. +-- It falls back to English ('en') if the system language file is not found, +-- and then to an empty table if English is also not found. +-- @return table The translations table. +local function getTranslations() + local settings = getGeneralSettings() + local lang = settings.language + local translations = loadTranslations(lang) or loadTranslations("en") or {} + + function translations.t(key) + return translations[key] or key + end + + return translations +end + +return getTranslations() \ No newline at end of file diff --git a/src/SCRIPTS/RF2/IMG/acc.png b/src/SCRIPTS/RF2/IMG/acc.png new file mode 100644 index 00000000..01302fdc Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/acc.png differ diff --git a/src/SCRIPTS/RF2/IMG/advanced.png b/src/SCRIPTS/RF2/IMG/advanced.png new file mode 100644 index 00000000..2636bbbf Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/advanced.png differ diff --git a/src/SCRIPTS/RF2/IMG/esc.png b/src/SCRIPTS/RF2/IMG/esc.png new file mode 100644 index 00000000..85e5c350 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/esc.png differ diff --git a/src/SCRIPTS/RF2/IMG/fblstatus.png b/src/SCRIPTS/RF2/IMG/fblstatus.png new file mode 100644 index 00000000..5f6a076d Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/fblstatus.png differ diff --git a/src/SCRIPTS/RF2/IMG/filters.png b/src/SCRIPTS/RF2/IMG/filters.png new file mode 100644 index 00000000..0ebec176 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/filters.png differ diff --git a/src/SCRIPTS/RF2/IMG/flrtr.png b/src/SCRIPTS/RF2/IMG/flrtr.png new file mode 100644 index 00000000..bc410e8d Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/flrtr.png differ diff --git a/src/SCRIPTS/RF2/IMG/governor.png b/src/SCRIPTS/RF2/IMG/governor.png new file mode 100644 index 00000000..e70cd45b Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/governor.png differ diff --git a/src/SCRIPTS/RF2/IMG/hobbywing.png b/src/SCRIPTS/RF2/IMG/hobbywing.png new file mode 100644 index 00000000..a37f63b5 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/hobbywing.png differ diff --git a/src/SCRIPTS/RF2/IMG/info.png b/src/SCRIPTS/RF2/IMG/info.png new file mode 100644 index 00000000..825dc9d5 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/info.png differ diff --git a/src/SCRIPTS/RF2/IMG/mainrotor.png b/src/SCRIPTS/RF2/IMG/mainrotor.png new file mode 100644 index 00000000..f36c370d Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/mainrotor.png differ diff --git a/src/SCRIPTS/RF2/IMG/mixer.png b/src/SCRIPTS/RF2/IMG/mixer.png new file mode 100644 index 00000000..be752dff Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/mixer.png differ diff --git a/src/SCRIPTS/RF2/IMG/msp_exp.png b/src/SCRIPTS/RF2/IMG/msp_exp.png new file mode 100644 index 00000000..446e1be4 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/msp_exp.png differ diff --git a/src/SCRIPTS/RF2/IMG/pids-bandwidth.png b/src/SCRIPTS/RF2/IMG/pids-bandwidth.png new file mode 100644 index 00000000..7313a4a2 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/pids-bandwidth.png differ diff --git a/src/SCRIPTS/RF2/IMG/pids-controller.png b/src/SCRIPTS/RF2/IMG/pids-controller.png new file mode 100644 index 00000000..0f5e871b Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/pids-controller.png differ diff --git a/src/SCRIPTS/RF2/IMG/pids.png b/src/SCRIPTS/RF2/IMG/pids.png new file mode 100644 index 00000000..3df79d21 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/pids.png differ diff --git a/src/SCRIPTS/RF2/IMG/rates.png b/src/SCRIPTS/RF2/IMG/rates.png new file mode 100644 index 00000000..620083b2 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/rates.png differ diff --git a/src/SCRIPTS/RF2/IMG/rescue.png b/src/SCRIPTS/RF2/IMG/rescue.png new file mode 100644 index 00000000..8d806a41 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/rescue.png differ diff --git a/src/SCRIPTS/RF2/IMG/rfstatus.png b/src/SCRIPTS/RF2/IMG/rfstatus.png new file mode 100644 index 00000000..8612410d Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/rfstatus.png differ diff --git a/src/SCRIPTS/RF2/IMG/scorpion.png b/src/SCRIPTS/RF2/IMG/scorpion.png new file mode 100644 index 00000000..d486e0ea Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/scorpion.png differ diff --git a/src/SCRIPTS/RF2/IMG/servos.png b/src/SCRIPTS/RF2/IMG/servos.png new file mode 100644 index 00000000..511d7af8 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/servos.png differ diff --git a/src/SCRIPTS/RF2/IMG/settings.png b/src/SCRIPTS/RF2/IMG/settings.png new file mode 100644 index 00000000..a27098ed Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/settings.png differ diff --git a/src/SCRIPTS/RF2/IMG/xdfly.png b/src/SCRIPTS/RF2/IMG/xdfly.png new file mode 100644 index 00000000..c0e48ee4 Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/xdfly.png differ diff --git a/src/SCRIPTS/RF2/IMG/yge.png b/src/SCRIPTS/RF2/IMG/yge.png new file mode 100644 index 00000000..81bffafa Binary files /dev/null and b/src/SCRIPTS/RF2/IMG/yge.png differ diff --git a/src/SCRIPTS/RF2/LANG/de.lua b/src/SCRIPTS/RF2/LANG/de.lua new file mode 100644 index 00000000..6dfb44c5 --- /dev/null +++ b/src/SCRIPTS/RF2/LANG/de.lua @@ -0,0 +1,102 @@ +-- Language file for German (de) +return { + TITLE_Menu_Menu = "Hauptmenü", + TITLE_WARNING_Save = "Speichern Warnung", + MSG_WARNING_Save_later = "Einstellungen werden nach dem Entsichern gespeichert.", + TITLE_Save_Error = "Speichern Fehler", + MSG_Save_Error = "Stellen Sie sicher, dass Ihr Heli entsichert ist.", + MENU_Save = "\xEF\x80\x99 Speichern", + MENU_Reload = "\xEF\x80\xA1 Neu laden", + MENU_Reboot = "\xEF\x81\xB9 Neustart", + PAGE_Status = "Status", + PAGE_Rates = "Drehraten", + PAGE_Rate_Dynamics = "Drehraten Adv.", + PAGE_PID_Gains = "PIDs", + PAGE_PID_Controller = "PID Regler", + PAGE_Profile_Various = "Profil - versch.", + PAGE_Profile_Rescue = "Profil - Rettung", + PAGE_Profile_Governor = "Drehzahlregler", + PAGE_Servos = "Servos", + PAGE_Mixer = "Mischer", + PAGE_Gyro_Filters = "Gyro Filter", + PAGE_Governor = "Drehzahlregler", + PAGE_Accelerometer_Trim = "ACC Trimm", + PAGE_Model = "Modell", + PAGE_Experimental = "Experimentell (!)", + PAGE_ESC_FLYROTOR = "ESC - FLYROTOR", + PAGE_ESC_HW_Platinum_V5 = "ESC - HW Platinum V5", + PAGE_ESC_Scorpion_Tribunus = "ESC - Scorpion Tribunus", + PAGE_ESC_XDFly = "ESC - XDFly", + PAGE_ESC_YGE = "ESC - YGE", + PAGE_Settings = "Einstellungen", + PAGE_Status_PID_Profile = "Aktuelles PID Profil", + PAGE_Status_Rate_Profile = "Aktuelles Raten Profil", + PAGE_Status_Real_Time_Load = "Echtzeit Last", + PAGE_Status_CPU_Load = "CPU Last", + PAGE_Status_Arming_Flags = "Arming Sperrgründe", + PAGE_Status_Dataflash_Free = "Dataflash freier Speicher", + PAGE_Status_Erase = "[Löschen]", + MSG_Erasing = "Lösche...", + ARMING_DISABLED_NO_GYRO = "Kein Gyro", + ARMING_DISABLED_FAIL_SAFE = "Failsafe", + ARMING_DISABLED_RX_FAIL_SAFE = "RX Failsafe", + ARMING_DISABLED_BAD_RX_RECOVERY = "Schlechte RX Erholung", + ARMING_DISABLED_BOX_FAIL_SAFE = "Box Failsafe", + ARMING_DISABLED_GOVERNOR = "Drehzahlregler", + ARMING_DISABLED_RPM_SIGNAL = "RPM Signal", + ARMING_DISABLED_THROTTLE = "Gas", + ARMING_DISABLED_ANGLE = "Winkel", + ARMING_DISABLED_BOOT_GRACE_TIME = "Boot Wartezeit", + ARMING_DISABLED_NO_PRE_ARM = "Kein Pre-Arm", + ARMING_DISABLED_LOAD = "Systemlast", + ARMING_DISABLED_CALIBRATING = "Kalibrierung", + ARMING_DISABLED_CLI = "CLI", + ARMING_DISABLED_CMS_MENU = "CMS Menü", + ARMING_DISABLED_BST = "BST", + ARMING_DISABLED_MSP = "MSP", + ARMING_DISABLED_PARALYZE = "Paralyze", + ARMING_DISABLED_GPS = "GPS", + ARMING_DISABLED_RESC = "Rettung", + ARMING_DISABLED_RPM_FILTER = "RPM Filter", + ARMING_DISABLED_REBOOT_REQUIRED = "Neustart erforderlich", + ARMING_DISABLED_DSHOT_BITBANG = "DSHOT Bitbang", + ARMING_DISABLED_ACC_CALIBRATION = "ACC Kalibrierung", + ARMING_DISABLED_MOTOR_PROTOCOL = "Motor Protokoll", + ARMING_DISABLED_ARM_SWITCH = "Arm Schalter", + ACC_Title = "Beschleunigungssensor", + ACC_Label = "Beschleunigungssensor Trimm", + ACC_Roll = "Roll", + ACC_Pitch = "Nick", + ACC_Calibrate = "Kalibrieren", + ACC_Calibrating = "Kalibriere...", + ACC_Help_title = "Beschleunigungssensor", + ACC_Help_text = "Der Beschleunigungssensor wird verwendet, um den Winkel des Flugcontrollers in Bezug auf den Horizont zu messen. Diese Daten werden zur Stabilisierung des Fluggeraets und zur Bereitstellung der Selbstnivellierungsfunktion verwendet.", + ACC_Calibration_Question = "Beschleunigungssensor kalibrieren?\nStellen Sie sicher, dass das Fluggerät auf einer ebenen Oberfläche platziert ist und während des Kalibrierungsprozesses ruhig bleibt.", + MENU_Yes = "Ja", + MENU_No = "Nein", + STATUS_Help_title = "Status", + STATUS_Help_text = "Diese Seite zeigt den aktuellen Status des Flugcontrollers an, einschließlich PID- und Ratenprofile, Systemlast und Arming-Sperrgründe.", + RATES_Help_title = "Drehraten", + RATES_Help_text = "Diese Seite ermöglicht es Ihnen, die Raten und Expos für Ihren Hubschrauber zu konfigurieren. Sie können Roll-, Nick-, Gier- und Kollektivraten sowie deren entsprechende Exponentialwerte anpassen.", + RATES_ADVANCE_Help_title = "Drehraten - Erweitert", + RATES_ADVANCE_Help_text = "Dynamik: Wird unabhaengig vom Rate-Typ angewendet. Anpassen, um Heli-Bewegungen weicher zu machen, z. B. fuer Scale-Helis.", + MENU_Dest_Profile = "Ziel Profil", + MENU_Copy_Profile = "[Kopiere Akt. nach Ziel]", + Rates_Yaw = "Gier", + Rates_Coll = "Kollektiv", + Rates_Type = "Raten Typ", + Model_ID = "Modell ID", + Model_Stats = "Statistiken", + Model_Stats_Enabled = "Aktiviert", + Model_Total_Flights = "Anzahl Flüge", + Model_Total_Time = "Gesamtzeit", + Model_Total_Dist = "Gesamtdistanz", + Model_Min_Armed_Time = "Min. Armed Zeit", + Model_Reset_Stats = "[Statistiken zurücksetzen]", + Model_Radio_Config = "Funk Konfiguration", + Model_Requires_Rf2bg = "Hinweis: benötigt rf2bg", + Model_Set_Name_Tx = "Name auf Sender setzen", + Model_Param = "Param", + Model_Type = "Typ", + Model_Value = "Wert", +} \ No newline at end of file diff --git a/src/SCRIPTS/RF2/LANG/en.lua b/src/SCRIPTS/RF2/LANG/en.lua new file mode 100644 index 00000000..30298bdf --- /dev/null +++ b/src/SCRIPTS/RF2/LANG/en.lua @@ -0,0 +1,102 @@ +-- Language file for english (en) +return { + TITLE_Menu_Menu = "Main Menu", + TITLE_WARNING_Save = "Save warning", + MSG_WARNING_Save_later = "Settings will be saved\nafter disarming.", + TITLE_Save_Error = "Save error", + MSG_Save_Error = "Make sure your heli\nis disarmed.", + MENU_Save = "\xEF\x80\x99 Save", + MENU_Reload = "\xEF\x80\xA1 Reload", + MENU_Reboot = "\xEF\x81\xB9 Reboot", + PAGE_Status = "Status", + PAGE_Rates = "Rates", + PAGE_Rate_Dynamics = "Rate Adv.", + PAGE_PID_Gains = "PIDs", + PAGE_PID_Controller = "PID Controller", + PAGE_Profile_Various = "Profile-Various", + PAGE_Profile_Rescue = "Profile - Rescue", + PAGE_Profile_Governor = "Governor", + PAGE_Servos = "Servos", + PAGE_Mixer = "Mixer", + PAGE_Gyro_Filters = "Gyro Filters", + PAGE_Governor = "Governor", + PAGE_Accelerometer_Trim = "ACC Trim", + PAGE_Model = "Model", + PAGE_Experimental = "Experimental (!)", + PAGE_ESC_FLYROTOR = "ESC - FLYROTOR", + PAGE_ESC_HW_Platinum_V5 = "ESC - HW Platinum V5", + PAGE_ESC_Scorpion_Tribunus = "ESC - Scorpion Tribunus", + PAGE_ESC_XDFly = "ESC - XDFly", + PAGE_ESC_YGE = "ESC - YGE", + PAGE_Settings = "Settings", + PAGE_Status_PID_Profile = "Current PID profile", + PAGE_Status_Rate_Profile = "Current rate profile", + PAGE_Status_Real_Time_Load = "Real-time load", + PAGE_Status_CPU_Load = "CPU load", + PAGE_Status_Arming_Flags = "Arming Disabled Flags", + PAGE_Status_Dataflash_Free = "Dataflash Free Space", + PAGE_Status_Erase = "[Erase]", + MSG_Erasing = "Erasing...", + ARMING_DISABLED_NO_GYRO = "No Gyro", + ARMING_DISABLED_FAIL_SAFE = "Fail Safe", + ARMING_DISABLED_RX_FAIL_SAFE = "RX Fail Safe", + ARMING_DISABLED_BAD_RX_RECOVERY = "Bad RX Recovery", + ARMING_DISABLED_BOX_FAIL_SAFE = "Box Fail Safe", + ARMING_DISABLED_GOVERNOR = "Governor", + ARMING_DISABLED_RPM_SIGNAL = "RPM Signal", + ARMING_DISABLED_THROTTLE = "Throttle", + ARMING_DISABLED_ANGLE = "Angle", + ARMING_DISABLED_BOOT_GRACE_TIME = "Boot Grace Time", + ARMING_DISABLED_NO_PRE_ARM = "No Pre Arm", + ARMING_DISABLED_LOAD = "Load", + ARMING_DISABLED_CALIBRATING = "Calibrating", + ARMING_DISABLED_CLI = "CLI", + ARMING_DISABLED_CMS_MENU = "CMS Menu", + ARMING_DISABLED_BST = "BST", + ARMING_DISABLED_MSP = "MSP", + ARMING_DISABLED_PARALYZE = "Paralyze", + ARMING_DISABLED_GPS = "GPS", + ARMING_DISABLED_RESC = "Resc", + ARMING_DISABLED_RPM_FILTER = "RPM Filter", + ARMING_DISABLED_REBOOT_REQUIRED = "Reboot Required", + ARMING_DISABLED_DSHOT_BITBANG = "DSHOT Bitbang", + ARMING_DISABLED_ACC_CALIBRATION = "Acc Calibration", + ARMING_DISABLED_MOTOR_PROTOCOL = "Motor Protocol", + ARMING_DISABLED_ARM_SWITCH = "Arm Switch", + ACC_Title = "Accelerometer", + ACC_Label = "Accelerometer Trim", + ACC_Roll = "Roll", + ACC_Pitch = "Pitch", + ACC_Calibrate = "Calibrate", + ACC_Calibrating = "Calibrating...", + ACC_Help_title = "Accelerometer", + ACC_Help_text = "The accelerometer is used to measure the angle of the flight controller in relation to the horizon. This data is used to stabilize the aircraft and provide self-leveling functionality.", + ACC_Calibration_Question = "Calibrate the accelerometer?\nMake sure the aircraft is placed on a level surface and will remain stationary during the calibration process.", + MENU_Yes = "Yes", + MENU_No = "No", + STATUS_Help_title = "Status", + STATUS_Help_text = "This page shows the current status of the flight controller, including PID and rate profiles, system load and arming disabled flags.", + RATES_Help_title = "Rates", + RATES_Help_text = "This page allows you to configure the rates and expos for your helicopter. You can adjust roll, pitch, yaw, and collective rates as well as their corresponding", + RATES_ADVANCE_Help_title = "Rates - Advanced", + RATES_ADVANCE_Help_text = "Dynamics: Applied regardless of rates type. Typically left on defaults but can be adjusted to smooth heli movements, like with scale helis.", + MENU_Dest_Profile = "Destination profile", + MENU_Copy_Profile = "[Copy Current to Dest]", + Rates_Yaw = "Yaw", + Rates_Coll = "Coll", + Rates_Type = "Rates type", + Model_ID = "Model ID", + Model_Stats = "Statistics", + Model_Stats_Enabled = "Enabled", + Model_Total_Flights = "Total flights", + Model_Total_Time = "Total time", + Model_Total_Dist = "Total distance", + Model_Min_Armed_Time = "Min armed time", + Model_Reset_Stats = "[Reset Stats]", + Model_Radio_Config = "Radio Configuration", + Model_Requires_Rf2bg = "Note: requires rf2bg", + Model_Set_Name_Tx = "Set name on TX", + Model_Param = "Param", + Model_Type = "type", + Model_Value = "value", +} \ No newline at end of file diff --git a/src/SCRIPTS/RF2/LVGL/mainMenu.lua b/src/SCRIPTS/RF2/LVGL/mainMenu.lua index da87540e..e03a2735 100644 --- a/src/SCRIPTS/RF2/LVGL/mainMenu.lua +++ b/src/SCRIPTS/RF2/LVGL/mainMenu.lua @@ -5,39 +5,97 @@ local function show(menu) local w = (LCD_W - 30) / 3 local h = 50 + -- --- FINE TUNING --- + local OFFSET_X = -6 -- Horizontal fits perfectly + local OFFSET_Y = 8 -- Correction to move text down + for i = 1, #menu.items do local item = menu.items[i] + + -- 1. Container Box + local content_box = { + type = "box", + w = w, + h = h, + + x = OFFSET_X, + y = OFFSET_Y, + + -- Center content + flexFlow = lvgl.FLOW_ROW, + flexAlignMain = lvgl.FLEX_ALIGN_CENTER, + flexAlignCross = lvgl.FLEX_ALIGN_CENTER, + flexGap = 5, + + children = {} + } + + -- 2. Fill content into the box + if item.icon and item.icon ~= "" then + if string.find(item.icon, ".png") then + -- >>> IMAGE ICON (.png) <<< + content_box.children[#content_box.children + 1] = { + type = "image", + file = item.icon, + w = 16, + h = 16 + } + -- Text next to it + content_box.children[#content_box.children + 1] = { + type = "label", + text = item.text, + color = lcd.RGB(255, 255, 255) + } + else + -- >>> SYMBOL ICON (FontAwesome) <<< + content_box.children[#content_box.children + 1] = { + type = "label", + text = item.icon .. " " .. item.text, + color = lcd.RGB(255, 255, 255) -- White + } + end + else + -- >>> NO ICON (Text Only) <<< + content_box.children[#content_box.children + 1] = { + type = "label", + text = item.text, + color = lcd.RGB(255, 255, 255) -- White + } + end + + -- 3. CREATE BUTTON children[#children + 1] = { type = "button", x = 6 + #children % 3 * (w + 4), y = 6 + math.floor(#children / 3) * (h + 4), w = w, h = h, - text = item.text, + color = lcd.RGB(48, 48, 48), -- Dark Gray press = function() if item.click then item.click(i) end - end + end, + children = {content_box} } end - local lyt = { - { - type = "page", - title = menu.title, - subtitle = menu.subtitle, - icon = rf2.baseDir .. "rf2.png", - back = function() - if menu.back then - menu.back() - end - end, - children = children - }, - } + local lyt = {{ + type = "page", + title = menu.title, + subtitle = menu.subtitle, + icon = rf2.baseDir .. "rf2.png", + back = function() + if menu.back then + menu.back() + end + end, + children = children + }} lvgl.build(lyt) end -return { show = show } \ No newline at end of file +return { + show = show +} diff --git a/src/SCRIPTS/RF2/LVGL/page.lua b/src/SCRIPTS/RF2/LVGL/page.lua index 124a958c..0b601cf6 100644 --- a/src/SCRIPTS/RF2/LVGL/page.lua +++ b/src/SCRIPTS/RF2/LVGL/page.lua @@ -16,42 +16,55 @@ local function show(page) end local function fieldIsButton(f) - -- TODO: refactor return f.t and string.sub(f.t, 1, 1) == "[" and not f.data end local children = {} + + -- OFFSET: Schiebt den Inhalt unter die Toolbar (35px Höhe + Abstand) + local CONTENT_OFFSET = 25 + + local specialFunction = nil + + -- 1. LABELS ERSTELLEN for i = 1, #page.labels do local label = page.labels[i] children[#children + 1] = { type = "label", x = label.x, - y = label.y + 3, - --text = label.t, -- no updates - text = function() return label.t end, -- does update + y = label.y + 3 + CONTENT_OFFSET, + text = function() return label.t end, font = (not (label.bold == false)) and BOLD or 0 } end + -- 2. FELDER ERSTELLEN for i = 1, #page.fields do local field = page.fields[i] + local fieldY = field.y + CONTENT_OFFSET + if field.t then children[#children + 1] = { type = "label", x = field.x, - y = field.y, + y = fieldY, text = field.t, } end - if fieldIsButton(field) then + if field.special then + rf2.log("Found special field at index " .. i) + specialFunction = function() + if field.preEdit then field.preEdit(field, page) end + end + elseif fieldIsButton(field) then children[#children + 1] = { type = "button", x = field.x, - y = field.y, + y = fieldY, w = field.w or 200, text = function() - local s = string.gsub(field.t, "[%[%]]", "") -- remove brackets around [button] + local s = string.gsub(field.t, "[%[%]]", "") return s end, press = function() @@ -64,97 +77,187 @@ local function show(page) child = { type = "label", x = field.sp or field.x, - y = field.y + 3, + y = fieldY + 3, text = field.data.value, } else child = { type = "textEdit", x = field.sp or field.x, - y = field.y, + y = fieldY, w = field.w or 125, value = field.data.value, length = field.data.max or 10, } end - children[#children + 1] = child + elseif field.data and field.data.value and type(field.data.value) == "number" then local child if field.readOnly then child = { type = "label", x = field.sp or field.x, - y = field.y + 3, + y = fieldY + 3, text = function() return formatVal(field.data.value, field) end, } elseif field.data.table then local choiceTable = lvglHelper.toChoiceTable(field.data.table, field.data.max + 1) - --rf2.print("Choice with value: " .. tostring(field.data.value)) child = { type = "choice", - --title = "todo", values = choiceTable.values, x = field.sp or field.x, - y = field.y, + y = fieldY, w = field.w or 100, get = function() return choiceTable:getChoiceKey(field.data.value) end, set = function(val) field.data.value = choiceTable:getOriginalKey(val) - if field.postEdit then - field:postEdit(page) - end + if field.postEdit then field:postEdit(page) end end, } else child = { type = "numberEdit", x = field.sp or field.x, - y = field.y, + y = fieldY, w = field.w or 75, - get = function() - return field.data.value / (field.data.mult or 1) - end, + get = function() return field.data.value / (field.data.mult or 1) end, set = function(val) local newVal = math.ceil(val * (field.data.mult or 1)) - if field.change then - field:change(newVal, page) - end + if field.change then field:change(newVal, page) end field.data.value = newVal - --rf2.print("Value after editing: %s", tostring(field.data.value)) - end, - display = function(val) - return formatVal(val * (field.data.mult or 1), field) end, + display = function(val) return formatVal(val * (field.data.mult or 1), field) end, } if field.data.min then child.min = field.data.min / (field.data.mult or 1) end if field.data.max then child.max = field.data.max / (field.data.mult or 1) end end - children[#children + 1] = child end end + -- 3. SKALIERUNG ANWENDEN (Nur auf den alten Inhalt!) + for i = 1, #children do + local child = children[i] + child.x = child.x * 1.75 + child.y = (child.y - rf2.radio.yMinLimit + 5) * 1.75 + end + + -- 4. TOOLBAR ERSTELLEN (Manuelle Positionierung) + + local toolbar = { + type = "button", + clickable = false, -- Nur als Hintergrund + + x = 0, + y = 0, + w = LCD_W, + h = 42, + + color = lcd.RGB(48, 48, 48), -- Dunkelgrau + padAll = 0, -- Kein Padding, wir positionieren selbst + + children = {} + } + + -- 4.1 BUTTONS VON RECHTS NACH LINKS AUFBAUEN + -- Wir starten am rechten Bildschirmrand und gehen schrittweise nach links. + + local currentX = LCD_W - 5 -- Startpunkt: 5px Abstand vom rechten Rand + local btnHeight = 30 -- Höhe der Buttons + local btnY = 2 -- Y-Position in der Toolbar (zentriert bei h=35) + + -- A) HELP BUTTON (?) (Ganz rechts) + if page.help then + local btnW = 40 + currentX = currentX - btnW - 10 -- X-Position berechnen + + toolbar.children[#toolbar.children + 1] = { + type = "button", + text = "?", + x = currentX, + y = btnY, + w = btnW, + h = btnHeight, + press = function() + rf2.executeScript("LVGL/messageBox").show(page.help.title, page.help.msg) + end, + } + currentX = currentX - 5 -- Lücke zum nächsten Button + end + + -- B) TOOLS BUTTON (*) (Links daneben) + if page.specialFunction then + local btnW = 40 + + currentX = currentX - btnW + if page.help == nil then + currentX = currentX - 10 -- Abstand, wenn kein Help-Button + end + + toolbar.children[#toolbar.children + 1] = { + type = "button", + text = "*", + x = currentX, + y = btnY, + w = btnW, + h = btnHeight, + press = function() + page.specialFunction() + end, + } + currentX = currentX - 5 -- Lücke + end + + -- TOOLS Reload (*) (Links daneben) + -- if page.read then + -- local btnW = 40 + + -- currentX = currentX - btnW + -- if page.help == nil then + -- currentX = currentX - 10 -- Abstand, wenn kein Help-Button + -- end + + -- toolbar.children[#toolbar.children + 1] = { + -- type = "button", + -- text = "\xEF\x80\xA1", + -- x = currentX, + -- y = btnY, + -- w = btnW, + -- h = btnHeight, + -- press = function() + -- page.read() + -- end, + -- } + -- currentX = currentX - 5 -- Lücke + -- end + + -- C) SAVE BUTTON (Links daneben) if page.isReady and not page.readOnly then - children[#children + 1] = { + local btnW = 100 + currentX = currentX - btnW + if page.help == nil and page.tools == nil then + currentX = currentX - 10 -- Abstand, wenn kein Help und Tools-Button + end + + toolbar.children[#toolbar.children + 1] = { type = "button", - x = 5, - y = children[#children].y + 35, - w = LCD_W - 20, - text = "Save", + text = rf2.i18n.t("MENU_Save"), + x = currentX, + y = btnY, + w = btnW, + h = btnHeight, + press = function() page:write() end, } end - for i = 1, #children do - local child = children[i] - child.x = child.x * 1.75 - child.y = (child.y - rf2.radio.yMinLimit + 5) * 1.75 - end + -- 5. Toolbar ganz am Ende hinzufügen + children[#children + 1] = toolbar local lyt = { { diff --git a/src/SCRIPTS/RF2/LVGL/page.luac b/src/SCRIPTS/RF2/LVGL/page.luac new file mode 100644 index 00000000..04f25f50 Binary files /dev/null and b/src/SCRIPTS/RF2/LVGL/page.luac differ diff --git a/src/SCRIPTS/RF2/LVGL/questionBox.lua b/src/SCRIPTS/RF2/LVGL/questionBox.lua new file mode 100644 index 00000000..46d4aedc --- /dev/null +++ b/src/SCRIPTS/RF2/LVGL/questionBox.lua @@ -0,0 +1,31 @@ +local function show(title, text, items) + rf2.print("Showing message: " .. title .. " - " .. text .. " with " .. #items .. " items" ) + local dg = lvgl.dialog({ title = title, w = 300, h = 200 }) + local lyt = { + { type = "label", + --align = VCENTER + CENTER, + text = text, w = 280 }, + } + local margin = 10 + local gap = 10 + local button_w = (300 - 2 * margin - (#items - 1) * gap) / #items + local y = 120 + for i = 1, #items do + local item = items[i] + rf2.log("Adding item " .. i .. ": " .. item.text) + local x = margin + (i - 1) * (button_w + gap) + lyt[#lyt + 1] = { + type = "button", text = item.text, x = x, y = y, w = button_w, + press = function() + dg:close() + if item.click then + item.click(i) + end + end + } + end + + dg:build(lyt) +end + +return { show = show } diff --git a/src/SCRIPTS/RF2/MSP/mspGovernorConfig.lua b/src/SCRIPTS/RF2/MSP/mspGovernorConfig.lua index 24835fc4..707b6411 100644 --- a/src/SCRIPTS/RF2/MSP/mspGovernorConfig.lua +++ b/src/SCRIPTS/RF2/MSP/mspGovernorConfig.lua @@ -12,7 +12,9 @@ local function getDefaults() defaults.gov_throttle_hold_timeout = { min = 0, max = 100, scale = 10, unit = rf2.units.seconds } if rf2.apiVersion < 12.09 then defaults.gov_lost_headspeed_timeout = { min = 0, max = 100, scale = 10, unit = rf2.units.seconds } - defaults.gov_autorotation_timeout = { min = 0, max = 600, scale = 10, unit = rf2.units.seconds } + end + defaults.gov_autorotation_timeout = { min = 0, max = 600, scale = 10, unit = rf2.units.seconds } + if rf2.apiVersion < 12.09 then defaults.gov_autorotation_bailout_time = { min = 0, max = 100, scale = 10, unit = rf2.units.seconds } defaults.gov_autorotation_min_entry_time = { min = 0, max = 600, scale = 10, unit = rf2.units.seconds } end @@ -28,10 +30,9 @@ local function getDefaults() defaults.gov_d_filter = { min = 0, max = 250, unit = rf2.units.herz } defaults.gov_spooldown_time = { min = 0, max = 600, scale = 10, unit = rf2.units.seconds } defaults.gov_throttle_type = { min = 0, max = 3, table = { [0] = "NORMAL", "OFF_ON", "OFF_IDLE_ON", "OFF_IDLE_AUTO_ON" } } - defaults.gov_idle_collective = { min = -100, max = 100 } - defaults.gov_wot_collective = { min = -100, max = 100 } defaults.gov_idle_throttle = { min = 0, max = 250, scale = 10, unit = rf2.units.percentage } defaults.gov_auto_throttle = { min = 0, max = 250, scale = 10, unit = rf2.units.percentage } + defaults.gov_bypass_throttle = { } end return defaults end @@ -49,11 +50,15 @@ local function getGovernorConfig(callback, callbackParam, data) data.gov_throttle_hold_timeout.value = rf2.mspHelper.readU16(buf) if rf2.apiVersion < 12.09 then data.gov_lost_headspeed_timeout.value = rf2.mspHelper.readU16(buf) - data.gov_autorotation_timeout.value = rf2.mspHelper.readU16(buf) + else + buf.offset = buf.offset + 2 + end + data.gov_autorotation_timeout.value = rf2.mspHelper.readU16(buf) + if rf2.apiVersion < 12.09 then data.gov_autorotation_bailout_time.value = rf2.mspHelper.readU16(buf) data.gov_autorotation_min_entry_time.value = rf2.mspHelper.readU16(buf) else - buf.offset = buf.offset + 4*2 + buf.offset = buf.offset + 2*2 end data.gov_handover_throttle.value = rf2.mspHelper.readU8(buf) data.gov_pwr_filter.value = rf2.mspHelper.readU8(buf) @@ -69,14 +74,17 @@ local function getGovernorConfig(callback, callbackParam, data) data.gov_d_filter.value = rf2.mspHelper.readU8(buf) data.gov_spooldown_time.value = rf2.mspHelper.readU16(buf) data.gov_throttle_type.value = rf2.mspHelper.readU8(buf) - data.gov_idle_collective.value = rf2.mspHelper.readS8(buf) - data.gov_wot_collective.value = rf2.mspHelper.readS8(buf) + buf.offset = buf.offset + 2 data.gov_idle_throttle.value = rf2.mspHelper.readU8(buf) data.gov_auto_throttle.value = rf2.mspHelper.readU8(buf) + data.gov_bypass_throttle = {} + for i = 0, 8 do + data.gov_bypass_throttle[#data.gov_bypass_throttle + 1] = rf2.mspHelper.readU8(buf) + end end callback(callbackParam, data) end, - simulatorResponse = { 2, 200, 0, 100, 0, 20, 0, 20, 0, 30, 0, 10, 0, 0, 0, 0, 0, 50, 0, 10, 5, 10, 0, 10, 5, 0, 30, 0, 0, 161, 246, 0, 0 } + simulatorResponse = { 2, 200, 0, 100, 0, 20, 0, 20, 0, 50, 0, 0, 0, 50, 0, 0, 0, 0, 0, 20, 5, 10, 0, 5, 0, 50, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } rf2.mspQueue:add(message) end @@ -95,14 +103,16 @@ local function setGovernorConfig(config) rf2.mspHelper.writeU16(message.payload, config.gov_throttle_hold_timeout.value) if rf2.apiVersion < 12.09 then rf2.mspHelper.writeU16(message.payload, config.gov_lost_headspeed_timeout.value) - rf2.mspHelper.writeU16(message.payload, config.gov_autorotation_timeout.value) + else + rf2.mspHelper.writeU16(message.payload, 0) + end + rf2.mspHelper.writeU16(message.payload, config.gov_autorotation_timeout.value) + if rf2.apiVersion < 12.09 then rf2.mspHelper.writeU16(message.payload, config.gov_autorotation_bailout_time.value) rf2.mspHelper.writeU16(message.payload, config.gov_autorotation_min_entry_time.value) else rf2.mspHelper.writeU16(message.payload, 0) rf2.mspHelper.writeU16(message.payload, 0) - rf2.mspHelper.writeU16(message.payload, 0) - rf2.mspHelper.writeU16(message.payload, 0) end rf2.mspHelper.writeU8(message.payload, config.gov_handover_throttle.value) rf2.mspHelper.writeU8(message.payload, config.gov_pwr_filter.value) @@ -118,10 +128,13 @@ local function setGovernorConfig(config) rf2.mspHelper.writeU8(message.payload, config.gov_d_filter.value) rf2.mspHelper.writeU16(message.payload, config.gov_spooldown_time.value) rf2.mspHelper.writeU8(message.payload, config.gov_throttle_type.value) - rf2.mspHelper.writeU8(message.payload, config.gov_idle_collective.value) - rf2.mspHelper.writeU8(message.payload, config.gov_wot_collective.value) + rf2.mspHelper.writeU8(message.payload, 0) + rf2.mspHelper.writeU8(message.payload, 0) rf2.mspHelper.writeU8(message.payload, config.gov_idle_throttle.value) rf2.mspHelper.writeU8(message.payload, config.gov_auto_throttle.value) + for i = 0, 8 do + rf2.mspHelper.writeU8(message.payload, config.gov_bypass_throttle[i + 1] or 0) + end end rf2.mspQueue:add(message) end diff --git a/src/SCRIPTS/RF2/MSP/mspRcTuning.lua b/src/SCRIPTS/RF2/MSP/mspRcTuning.lua index 4573480a..82941ae4 100644 --- a/src/SCRIPTS/RF2/MSP/mspRcTuning.lua +++ b/src/SCRIPTS/RF2/MSP/mspRcTuning.lua @@ -40,6 +40,10 @@ local function getDefaults() defaults.yaw_dynamic_deadband_filter = { min = 0, max = 250, scale = 10, unit = rf2.units.herz } end + if rf2.apiVersion >= 12.09 then + defaults.cyclic_ring = { min = 0, max = 250 } + end + defaults.columnHeaders = { "", "", "", "", "", "" } return defaults @@ -97,9 +101,12 @@ local function getRcTuning(callback, callbackParam, data) data.yaw_dynamic_deadband_gain.value = rf2.mspHelper.readU8(buf) data.yaw_dynamic_deadband_filter.value = rf2.mspHelper.readU8(buf) end + if rf2.apiVersion >= 12.09 then + data.cyclic_ring.value = rf2.mspHelper.readU8(buf) + end callback(callbackParam, data) end, - simulatorResponse = { 4, 18, 25, 32, 20, 0, 0, 18, 25, 32, 20, 0, 0, 32, 50, 45, 10, 0, 0, 56, 0, 56, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 60 }, + simulatorResponse = { 4, 18, 25, 32, 20, 0, 0, 18, 25, 32, 20, 0, 0, 32, 50, 45, 10, 0, 0, 56, 0, 56, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 60, 150 }, } rf2.mspQueue:add(message) end @@ -144,6 +151,9 @@ local function setRcTuning(data) rf2.mspHelper.writeU8(message.payload, data.yaw_dynamic_deadband_gain.value) rf2.mspHelper.writeU8(message.payload, data.yaw_dynamic_deadband_filter.value) end + if rf2.apiVersion >= 12.09 then + rf2.mspHelper.writeU8(message.payload, data.cyclic_ring.value) + end rf2.mspQueue:add(message) end diff --git a/src/SCRIPTS/RF2/PAGES/accelerometer.lua b/src/SCRIPTS/RF2/PAGES/accelerometer.lua index 1ca785a2..84d9d051 100644 --- a/src/SCRIPTS/RF2/PAGES/accelerometer.lua +++ b/src/SCRIPTS/RF2/PAGES/accelerometer.lua @@ -8,15 +8,68 @@ template = nil local yMinLim = rf2.radio.yMinLimit local x = margin local y = yMinLim - lineSpacing -local function incY(val) y = y + val return y end +local function incY(val) + y = y + val + return y +end local labels = {} +local help = {} local fields = {} +local specialFunction = nil local mspAccTrim = "mspAccTrim" local data = rf2.useApi(mspAccTrim).getDefaults() +local mspCalibrating = "mspAccCalibration" +local t = rf2.i18n.t + +help = { + title = t("ACC_Help_title"), + msg = t("ACC_Help_text") +} + +labels[#labels + 1] = { + t = t("ACC_Label"), + x = x, + y = incY(lineSpacing) +} +fields[#fields + 1] = { + t = t("ACC_Roll"), + x = x + indent, + y = incY(lineSpacing), + sp = x + sp, + data = data.roll_trim +} +fields[#fields + 1] = { + t = t("ACC_Pitch"), + x = x + indent, + y = incY(lineSpacing), + sp = x + sp, + data = data.pitch_trim +} + +local function onAccCalibratingDone(msg) + rf2.log("Acc calibration done, msg: " .. tostring(msg)) + rf2.clearWaitMessage() +end + +local showPopupMenu = function() + local items = {} + + items[#items + 1] = { + text = t("MENU_Yes"), + click = function() + rf2.setWaitMessage(t("ACC_Calibrating")) + rf2.useApi(mspCalibrating).calibrate(onAccCalibratingDone, "OK") + end + } + + items[#items + 1] = { + text = t("MENU_No"), + click = nil + } + rf2.executeScript("LVGL/questionBox").show(help.title, t("ACC_Calibration_Question"), items) +end -labels[#labels + 1] = { t = "Accelerometer Trim", x = x, y = incY(lineSpacing) } -fields[#fields + 1] = { t = "Roll", x = x + indent, y = incY(lineSpacing), sp = x + sp, data = data.roll_trim } -fields[#fields + 1] = { t = "Pitch", x = x + indent, y = incY(lineSpacing), sp = x + sp, data = data.pitch_trim } +specialFunction = showPopupMenu local function receivedData(page) rf2.onPageReady(page) @@ -30,7 +83,10 @@ return { rf2.useApi(mspAccTrim).write(data) rf2.settingsSaved(true, false) end, - title = "Accelerometer", - labels = labels, - fields = fields + title = t("ACC_Title"), + labels = labels, + fields = fields, + help = help, + specialFunction = specialFunction, + } diff --git a/src/SCRIPTS/RF2/PAGES/governor.lua b/src/SCRIPTS/RF2/PAGES/governor.lua index 0f02e8df..eb6c4785 100644 --- a/src/SCRIPTS/RF2/PAGES/governor.lua +++ b/src/SCRIPTS/RF2/PAGES/governor.lua @@ -23,16 +23,13 @@ if rf2.apiVersion >= 12.09 then fields[#fields + 1] = { t = "Handover throttle", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_handover_throttle } fields[#fields + 1] = { t = "Throttle Hold TO", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_throttle_hold_timeout } incY(lineSpacing * 0.5) - labels[#labels + 1] = { t = "Throttle Curve", x = x, y = incY(lineSpacing) } - fields[#fields + 1] = { t = "Coll -> Idle", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_idle_collective } - fields[#fields + 1] = { t = "Coll -> Full", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_wot_collective } - incY(lineSpacing * 0.5) labels[#labels + 1] = { t = "Ramp Time", x = x, y = incY(lineSpacing) } fields[#fields + 1] = { t = "Startup time", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_startup_time } fields[#fields + 1] = { t = "Spoolup time", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_spoolup_time } fields[#fields + 1] = { t = "Spooldown time", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_spooldown_time } fields[#fields + 1] = { t = "Tracking time", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_tracking_time } fields[#fields + 1] = { t = "Recovery time", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_recovery_time } + fields[#fields + 1] = { t = "AR timeout", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_autorotation_timeout } incY(lineSpacing * 0.5) labels[#labels + 1] = { t = "Filters", x = x, y = incY(lineSpacing) } fields[#fields + 1] = { t = "HS filter cutoff", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_rpm_filter } diff --git a/src/SCRIPTS/RF2/PAGES/model.lua b/src/SCRIPTS/RF2/PAGES/model.lua index e5e282dc..92fff57f 100644 --- a/src/SCRIPTS/RF2/PAGES/model.lua +++ b/src/SCRIPTS/RF2/PAGES/model.lua @@ -15,6 +15,7 @@ local modelName = "---" local flighStats = rf2.useApi("mspFlightStats").getDefaults() local pilotConfig = rf2.useApi("mspPilotConfig").getDefaults() local setNameOnTxFieldIndex +local t = rf2.i18n.t local function buildForm(page) page.labels = nil @@ -27,12 +28,12 @@ local function buildForm(page) y = yMinLim - tableSpacing.header labels[#labels + 1] = { t = modelName, x = x, y = incY(lineSpacing) } - fields[#fields + 1] = { t = "Model ID", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_id } + fields[#fields + 1] = { t = t("Model_ID"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_id } if rf2.apiVersion >= 12.09 then incY(lineSpacing * 0.5) - labels[#labels + 1] = { t = "Statistics", x = x, y = incY(lineSpacing) } - fields[#fields + 1] = { t = "Enabled", x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.statsEnabled, + labels[#labels + 1] = { t = t("Model_Stats"), x = x, y = incY(lineSpacing) } + fields[#fields + 1] = { t = t("Model_Stats_Enabled"), x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.statsEnabled, postEdit = function(self, page) if self.data.value == 0 then flighStats.stats_min_armed_time_s.value = -1 -- stats disabled @@ -45,7 +46,7 @@ local function buildForm(page) } if flighStats.statsEnabled.value and flighStats.statsEnabled.value == 1 then - fields[#fields + 1] = { t = "Total flights", x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_total_flights, readOnly = true } + fields[#fields + 1] = { t = t("Model_Total_Flights"), x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_total_flights, readOnly = true } local function formatSeconds(seconds) local days = math.floor(seconds / 86400) @@ -64,10 +65,10 @@ local function buildForm(page) end end local totalTime = formatSeconds(flighStats.stats_total_time_s.value) - fields[#fields + 1] = { t = "Total time", x = x, y = incY(lineSpacing), sp = x + sp, data = { value = totalTime }, readOnly = true } + fields[#fields + 1] = { t = t("Model_Total_Time"), x = x, y = incY(lineSpacing), sp = x + sp, data = { value = totalTime }, readOnly = true } - fields[#fields + 1] = { t = "Total distance", x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_total_dist_m, readOnly = true } - fields[#fields + 1] = { t = "Min armed time", x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_min_armed_time_s } + fields[#fields + 1] = { t = t("Model_Total_Dist"), x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_total_dist_m, readOnly = true } + fields[#fields + 1] = { t = t("Model_Min_Armed_Time"), x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_min_armed_time_s } local function resetStats(self, page) flighStats.stats_total_flights.value = 0 @@ -76,13 +77,13 @@ local function buildForm(page) buildForm(page) rf2.onPageReady(page) end - fields[#fields + 1] = { t = "[Reset Stats]", x = x + indent * 3, y = incY(lineSpacing * 1.3), preEdit = resetStats } + fields[#fields + 1] = { t = t("Model_Reset_Stats"), x = x + indent * 3, y = incY(lineSpacing * 1.3), preEdit = resetStats } end end incY(lineSpacing * 0.5) - labels[#labels + 1] = { t = "Radio Configuration", x = x, y = incY(lineSpacing) } - labels[#labels + 1] = { t = "Note: requires rf2bg", x = x + indent, y = incY(lineSpacing), bold = false } + labels[#labels + 1] = { t = t("Model_Radio_Config"), x = x, y = incY(lineSpacing) } + labels[#labels + 1] = { t = t("Model_Requires_Rf2bg"), x = x + indent, y = incY(lineSpacing), bold = false } local function getAutoSetName() if rf2.apiVersion >= 12.07 and rf2.apiVersion < 12.09 then @@ -93,15 +94,15 @@ local function buildForm(page) end incY(lineSpacing * 0.25) setNameOnTxFieldIndex = #fields + 1 - fields[setNameOnTxFieldIndex] = { t = "Set name on TX", x = x, y = incY(lineSpacing), sp = x + sp, data = { value = getAutoSetName() or 0, min = 0, max = 1, table = { [0] = "Off", "On" } } } + fields[setNameOnTxFieldIndex] = { t = t("Model_Set_Name_Tx"), x = x, y = incY(lineSpacing), sp = x + sp, data = { value = getAutoSetName() or 0, min = 0, max = 1, table = { [0] = "Off", "On" } } } incY(lineSpacing * 0.25) - fields[#fields + 1] = { t = "Param1 type", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param1_type } - fields[#fields + 1] = { t = "Param1 value", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param1_value } - fields[#fields + 1] = { t = "Param2 type", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param2_type } - fields[#fields + 1] = { t = "Param2 value", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param2_value } - fields[#fields + 1] = { t = "Param3 type", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param3_type } - fields[#fields + 1] = { t = "Param3 value", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param3_value } + fields[#fields + 1] = { t = t("Model_Param") .. " 1 " .. t("Model_Type"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param1_type } + fields[#fields + 1] = { t = t("Model_Param") .. " 1 " .. t("Model_Value"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param1_value } + fields[#fields + 1] = { t = t("Model_Param") .. " 2 " .. t("Model_Type"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param2_type } + fields[#fields + 1] = { t = t("Model_Param") .. " 2 " .. t("Model_Value"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param2_value } + fields[#fields + 1] = { t = t("Model_Param") .. " 3 " .. t("Model_Type"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param3_type } + fields[#fields + 1] = { t = t("Model_Param") .. " 3 " .. t("Model_Value"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param3_value } page.labels = labels page.fields = fields diff --git a/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua b/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua index b27a7bfa..48101c28 100644 --- a/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua +++ b/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua @@ -14,6 +14,13 @@ local rateSwitcher = rf2.executeScript("PAGES/helpers/rateSwitcher.lua") local rcTuning = rf2.useApi("mspRcTuning").getDefaults() collectgarbage() +local t = rf2.i18n.t + +help = { + title = t("RATES_ADVANCE_Help_title"), + msg = t("RATES_ADVANCE_Help_text") +} + local tableStartY = yMinLim - lineSpacing y = tableStartY labels = {} @@ -67,6 +74,11 @@ if rf2.apiVersion >= 12.08 then fields[#fields + 1] = { t = "Deadband filter", x = x + indent, y = incY(lineSpacing), sp = x + sp, data = rcTuning.yaw_dynamic_deadband_filter } end +if rf2.apiVersion >= 12.09 then + incY(lineSpacing * 0.5) + fields[#fields + 1] = { t = "Cyclic ring", x = x, y = incY(lineSpacing), sp = x + sp, data = rcTuning.cyclic_ring } +end + local function receivedRcTuning(page) rf2.onPageReady(page) end @@ -84,6 +96,7 @@ return { labels = labels, fields = fields, rateSwitcher = rateSwitcher, + help = help, timer = function(self) self.rateSwitcher.checkStatus(self) diff --git a/src/SCRIPTS/RF2/PAGES/rates.lua b/src/SCRIPTS/RF2/PAGES/rates.lua index eadb9bfd..9e4aef17 100644 --- a/src/SCRIPTS/RF2/PAGES/rates.lua +++ b/src/SCRIPTS/RF2/PAGES/rates.lua @@ -20,6 +20,14 @@ local rcTuning = rf2.useApi("mspRcTuning").getDefaults() collectgarbage() local editing = false local profileAdjustmentTS = nil +local help = {} +local t = rf2.i18n.t + +help = { + title = t("RATES_Help_title"), + msg = t("RATES_Help_text") +} + local startEditing = function(field, page) editing = true @@ -52,10 +60,10 @@ local function buildForm() labels[#labels + 1] = { t = "", x = x, y = incY(tableSpacing.header) } labels[#labels + 1] = { t = "", x = x, y = incY(tableSpacing.header) } - labels[#labels + 1] = { t = "Roll", x = x, y = incY(tableSpacing.row) } - labels[#labels + 1] = { t = "Pitch", x = x, y = incY(tableSpacing.row) } - labels[#labels + 1] = { t = "Yaw", x = x, y = incY(tableSpacing.row) } - labels[#labels + 1] = { t = "Coll", x = x, y = incY(tableSpacing.row) } + labels[#labels + 1] = { t = t("ACC_Roll"), x = x, y = incY(tableSpacing.row) } + labels[#labels + 1] = { t = t("ACC_Pitch"), x = x, y = incY(tableSpacing.row) } + labels[#labels + 1] = { t = t("Rates_Yaw"), x = x, y = incY(tableSpacing.row) } + labels[#labels + 1] = { t = t("Rates_Coll"), x = x, y = incY(tableSpacing.row) } x = x + tableSpacing.col y = tableStartY @@ -86,12 +94,12 @@ local function buildForm() x = margin incY(lineSpacing * 0.5) - fields[13] = { t = "Rates type", x = x, y = incY(lineSpacing), sp = x + sp, data = rcTuning.rates_type, postEdit = function(self, page) page.updateRatesType(page) end } + fields[13] = { t = t("Rates_Type"), x = x, y = incY(lineSpacing), sp = x + sp, data = rcTuning.rates_type, postEdit = function(self, page) page.updateRatesType(page) end } incY(lineSpacing * 0.5) - fields[14] = { t = "Current rate profile", x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { min = 0, max = 5, value = rcTuning.currentRateProfile, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endRateEditing } - fields[15] = { t = "Destination profile", x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { min = 0, max = 5, value = rcTuning.destRateProfile, table = { [0] = "1", "2", "3", "4", "5", "6" } } } - fields[#fields + 1] = { t = "[Copy Current to Dest]", x = x + indent, y = incY(lineSpacing), preEdit = copyProfile } + fields[14] = { t = t("PAGE_Status_Rate_Profile"), x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { min = 0, max = 5, value = rcTuning.currentRateProfile, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endRateEditing } + fields[15] = { t = t("MENU_Dest_Profile"), x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { min = 0, max = 5, value = rcTuning.destRateProfile, table = { [0] = "1", "2", "3", "4", "5", "6" } } } + fields[#fields + 1] = { t = t("MENU_Copy_Profile"), x = x + indent, y = incY(lineSpacing), preEdit = copyProfile } --rf2.showMemoryUsage("after buildform") end @@ -125,6 +133,7 @@ return { title = "Rates", labels = labels, fields = fields, + help = help, updateRatesType = function(self, applyDefaults) rf2.useApi("mspRcTuning").getRateDefaults(rcTuning, rcTuning.rates_type.value) diff --git a/src/SCRIPTS/RF2/PAGES/status.lua b/src/SCRIPTS/RF2/PAGES/status.lua index 0731809c..d5926925 100644 --- a/src/SCRIPTS/RF2/PAGES/status.lua +++ b/src/SCRIPTS/RF2/PAGES/status.lua @@ -17,6 +17,13 @@ local fcStatus = {} local dataflashSummary = {} local erasingDataflash = false local editing = false +local help = {} +local t = rf2.i18n.t + +help = { + title = t("STATUS_Help_title"), + msg = t("STATUS_Help_text") +} local startEditing = function(field, page) editing = true @@ -32,57 +39,57 @@ local endRateEditing = function(field, page) mspSetProfile.setRateProfile(field.data.value) end -fields[1] = { t = "Current PID profile", x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { value = nil, min = 0, max = 5, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endPidEditing } -fields[2] = { t = "Current rate profile", x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { value = nil, min = 0, max = 5, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endRateEditing } +fields[1] = { t = t("PAGE_Status_PID_Profile"), x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { value = nil, min = 0, max = 5, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endPidEditing } +fields[2] = { t = t("PAGE_Status_Rate_Profile"), x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { value = nil, min = 0, max = 5, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endRateEditing } incY(lineSpacing * 0.25) -fields[3] = { t = "Real-time load", x = x, y = incY(lineSpacing), sp = x + sp, data = { value = 0, scale = 10, unit = rf2.units.percentage }, readOnly = true } -fields[4] = { t = "CPU load", x = x, y = incY(lineSpacing), sp = x + sp, data = { value = 0, scale = 10, unit = rf2.units.percentage }, readOnly = true } +fields[3] = { t = t("PAGE_Status_Real_Time_Load"), x = x, y = incY(lineSpacing), sp = x + sp, data = { value = 0, scale = 10, unit = rf2.units.percentage }, readOnly = true } +fields[4] = { t = t("PAGE_Status_CPU_Load"), x = x, y = incY(lineSpacing), sp = x + sp, data = { value = 0, scale = 10, unit = rf2.units.percentage }, readOnly = true } incY(lineSpacing * 0.25) -labels[1] = { t = "Arming Disabled Flags", x = x, y = incY(lineSpacing) } +labels[1] = { t = t("PAGE_Status_Arming_Flags"), x = x, y = incY(lineSpacing) } labels[2] = { t = "---", x = x + indent, y = incY(lineSpacing), bold = false } incY(lineSpacing * 0.25) -labels[3] = { t = "Dataflash Free Space", x = x, y = incY(lineSpacing) } +labels[3] = { t = t("PAGE_Status_Dataflash_Free"), x = x, y = incY(lineSpacing) } labels[4] = { t = "---", x = x + indent, y = incY(lineSpacing), bold = false } -fields[5] = { t = "[Erase]", x = x + indent * 7, y = y } +fields[5] = { t = t("PAGE_Status_Erase"), x = x + indent * 7, y = y } local function armingDisableFlagsToString(flags) - local t = "" + local s = "" for i = 0, 25 do if bit32.band(flags, bit32.lshift(1, i)) ~= 0 then - if t ~= "" then t = t .. ", " end - if i == 0 then t = t .. "No Gyro" end - if i == 1 then t = t .. "Fail Safe" end - if i == 2 then t = t .. "RX Fail Safe" end - if i == 3 then t = t .. "Bad RX Recovery" end - if i == 4 then t = t .. "Box Fail Safe" end - if i == 5 then t = t .. "Governor" end - if i == 6 then t = t .. "RPM Signal" end - if i == 7 then t = t .. "Throttle" end - if i == 8 then t = t .. "Angle" end - if i == 9 then t = t .. "Boot Grace Time" end - if i == 10 then t = t .. "No Pre Arm" end - if i == 11 then t = t .. "Load" end - if i == 12 then t = t .. "Calibrating" end - if i == 13 then t = t .. "CLI" end - if i == 14 then t = t .. "CMS Menu" end - if i == 15 then t = t .. "BST" end - if i == 16 then t = t .. "MSP" end - if i == 17 then t = t .. "Paralyze" end - if i == 18 then t = t .. "GPS" end - if i == 19 then t = t .. "Resc" end - if i == 20 then t = t .. "RPM Filter" end - if i == 21 then t = t .. "Reboot Required" end - if i == 22 then t = t .. "DSHOT Bitbang" end - if i == 23 then t = t .. "Acc Calibration" end - if i == 24 then t = t .. "Motor Protocol" end - if i == 25 then t = t .. "Arm Switch" end + if s ~= "" then s = s .. ", " end + if i == 0 then s = s .. t("ARMING_DISABLED_NO_GYRO") end + if i == 1 then s = s .. t("ARMING_DISABLED_FAIL_SAFE") end + if i == 2 then s = s .. t("ARMING_DISABLED_RX_FAIL_SAFE") end + if i == 3 then s = s .. t("ARMING_DISABLED_BAD_RX_RECOVERY") end + if i == 4 then s = s .. t("ARMING_DISABLED_BOX_FAIL_SAFE") end + if i == 5 then s = s .. t("ARMING_DISABLED_GOVERNOR") end + if i == 6 then s = s .. t("ARMING_DISABLED_RPM_SIGNAL") end + if i == 7 then s = s .. t("ARMING_DISABLED_THROTTLE") end + if i == 8 then s = s .. t("ARMING_DISABLED_ANGLE") end + if i == 9 then s = s .. t("ARMING_DISABLED_BOOT_GRACE_TIME") end + if i == 10 then s = s .. t("ARMING_DISABLED_NO_PRE_ARM") end + if i == 11 then s = s .. t("ARMING_DISABLED_LOAD") end + if i == 12 then s = s .. t("ARMING_DISABLED_CALIBRATING") end + if i == 13 then s = s .. t("ARMING_DISABLED_CLI") end + if i == 14 then s = s .. t("ARMING_DISABLED_CMS_MENU") end + if i == 15 then s = s .. t("ARMING_DISABLED_BST") end + if i == 16 then s = s .. t("ARMING_DISABLED_MSP") end + if i == 17 then s = s .. t("ARMING_DISABLED_PARALYZE") end + if i == 18 then s = s .. t("ARMING_DISABLED_GPS") end + if i == 19 then s = s .. t("ARMING_DISABLED_RESC") end + if i == 20 then s = s .. t("ARMING_DISABLED_RPM_FILTER") end + if i == 21 then s = s .. t("ARMING_DISABLED_REBOOT_REQUIRED") end + if i == 22 then s = s .. t("ARMING_DISABLED_DSHOT_BITBANG") end + if i == 23 then s = s .. t("ARMING_DISABLED_ACC_CALIBRATION") end + if i == 24 then s = s .. t("ARMING_DISABLED_MOTOR_PROTOCOL") end + if i == 25 then s = s .. t("ARMING_DISABLED_ARM_SWITCH") end end end - if t == "" then t = "-" end - return t + if s == "" then s = "-" end + return s end local function getFreeDataflashSpace() @@ -101,6 +108,7 @@ return { labels = labels, fields = fields, readOnly = true, + help = help, timer = function(self) if rf2.mspQueue:isProcessed() then @@ -132,7 +140,7 @@ return { onClickErase = function(field, self) erasingDataflash = true - rf2.setWaitMessage("Erasing...") + rf2.setWaitMessage(t("MSG_Erasing")) mspDataflash.eraseDataflash(self.onErasedDataflash, self) rf2.lcdNeedsInvalidate = true end, diff --git a/src/SCRIPTS/RF2/pages.lua b/src/SCRIPTS/RF2/pages.lua index ad911683..bf99db10 100644 --- a/src/SCRIPTS/RF2/pages.lua +++ b/src/SCRIPTS/RF2/pages.lua @@ -1,45 +1,70 @@ local PageFiles = {} local settings = rf2.loadSettings() +local t = rf2.i18n.t + +local SYMBOL = { + RATES = rf2.baseDir .. "IMG/" .. "rates.png", + PID = rf2.baseDir .. "IMG/" .. "pids.png", + STATUS = rf2.baseDir .. "IMG/" .. "rfstatus.png", + PID_CONTROLLER = rf2.baseDir .. "IMG/" .. "pids-controller.png", + PROFILE = rf2.baseDir .. "IMG/" .. "profile.png", + MAINROTOR = rf2.baseDir .. "IMG/" .. "mainrotor.png", + RESCUE = rf2.baseDir .. "IMG/" .. "rescue.png", + GOVERNOR = rf2.baseDir .. "IMG/" .. "governor.png", + SERVOS = rf2.baseDir .. "IMG/" .. "servos.png", + MIXER = rf2.baseDir .. "IMG/" .. "mixer.png", + FILTERS = rf2.baseDir .. "IMG/" .. "filters.png", + ACCELEROMETER = rf2.baseDir .. "IMG/" .. "acc.png", + FBLSTATUS = rf2.baseDir .. "IMG/" .. "fblstatus.png", + MSP_EXP = rf2.baseDir .. "IMG/" .. "msp_exp.png", + FLRTR = rf2.baseDir .. "IMG/" .. "fltr.png", + HOBBYWING = rf2.baseDir .. "IMG/" .. "hobbywing.png", + SCORPION = rf2.baseDir .. "IMG/" .. "scorpion.png", + XDFLY = rf2.baseDir .. "IMG/" .. "xdfly.png", + YGE = rf2.baseDir .. "IMG/" .. "yge.png", + SETTINGS = rf2.baseDir .. "IMG/" .. "settings.png", + ADVANCED = rf2.baseDir .. "IMG/" .. "advanced.png" +} -- Rotorflight pages. -PageFiles[#PageFiles + 1] = { title = "Status", script = "status" } -PageFiles[#PageFiles + 1] = { title = "Rates", script = "rates" } -PageFiles[#PageFiles + 1] = { title = "Rate Dynamics", script = "rate_dynamics" } -PageFiles[#PageFiles + 1] = { title = "PID Gains", script = "profile_pids" } -PageFiles[#PageFiles + 1] = { title = "PID Controller", script = "profile_pidcon" } -PageFiles[#PageFiles + 1] = { title = "Profile - Various", script = "profile_various" } -PageFiles[#PageFiles + 1] = { title = "Profile - Rescue", script = "profile_rescue" } -PageFiles[#PageFiles + 1] = { title = "Profile - Governor", script = "profile_governor" } -PageFiles[#PageFiles + 1] = { title = "Servos", script = "servos" } -PageFiles[#PageFiles + 1] = { title = "Mixer", script = "mixer" } -PageFiles[#PageFiles + 1] = { title = "Gyro Filters", script = "filters" } -PageFiles[#PageFiles + 1] = { title = "Governor", script = "governor" } -PageFiles[#PageFiles + 1] = { title = "Accelerometer Trim", script = "accelerometer" } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Status"), script = "status", icon=SYMBOL.STATUS } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Rates"), script = "rates", icon=SYMBOL.RATES } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Rate_Dynamics"), script = "rate_dynamics", icon=SYMBOL.ADVANCED } +PageFiles[#PageFiles + 1] = { title = t("PAGE_PID_Gains"), script = "profile_pids", icon=SYMBOL.PID } +PageFiles[#PageFiles + 1] = { title = t("PAGE_PID_Controller"), script = "profile_pidcon", icon=SYMBOL.PID_CONTROLLER } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Various"), script = "profile_various", icon=SYMBOL.MAINROTOR } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Rescue"), script = "profile_rescue", icon=SYMBOL.RESCUE } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Governor"), script = "profile_governor", icon=SYMBOL.GOVERNOR } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Servos"), script = "servos", icon=SYMBOL.SERVOS } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Mixer"), script = "mixer", icon=SYMBOL.MIXER } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Gyro_Filters"), script = "filters", icon=SYMBOL.FILTERS } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Governor"), script = "governor", icon=SYMBOL.GOVERNOR } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Accelerometer_Trim"), script = "accelerometer", icon=SYMBOL.ACCELEROMETER } if rf2.apiVersion >= 12.07 then if settings.showModelOnTx == 1 then - PageFiles[#PageFiles + 1] = { title = "Model", script = "model" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_Model"), script = "model", icon=SYMBOL.FBLSTATUS } end if settings.showExperimental == 1 then - PageFiles[#PageFiles + 1] = { title = "Experimental (!)", script = "experimental" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_Experimental"), script = "experimental", icon=SYMBOL.MSP_EXP } end if settings.showFlyRotor == 1 then - PageFiles[#PageFiles + 1] = { title = "ESC - FLYROTOR", script = "esc_flyrotor" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_FLYROTOR"), script = "esc_flyrotor", icon=SYMBOL.FLRTR } end if settings.showPlatinumV5 == 1 then - PageFiles[#PageFiles + 1] = { title = "ESC - HW Platinum V5", script = "esc_hwpl5" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_HW_Platinum_V5"), script = "esc_hwpl5", icon=SYMBOL.HOBBYWING } end if settings.showTribunus == 1 then - PageFiles[#PageFiles + 1] = { title = "ESC - Scorpion Tribunus", script = "esc_scorp" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_Scorpion_Tribunus"), script = "esc_scorp", icon=SYMBOL.SCORPION } end if rf2.apiVersion >= 12.08 and settings.showXdfly == 1 then - PageFiles[#PageFiles + 1] = { title = "ESC - XDFly", script = "esc_xdfly" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_XDFly"), script = "esc_xdfly", icon=SYMBOL.XDFLY } end if settings.showYge == 1 then - PageFiles[#PageFiles + 1] = { title = "ESC - YGE", script = "esc_yge" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_YGE"), script = "esc_yge", icon=SYMBOL.YGE } end - PageFiles[#PageFiles + 1] = { title = "Settings", script = "settings" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_Settings"), script = "settings", icon=SYMBOL.SETTINGS } end return PageFiles diff --git a/src/SCRIPTS/RF2/tool.lua b/src/SCRIPTS/RF2/tool.lua index 4c56c636..43c8d85a 100644 --- a/src/SCRIPTS/RF2/tool.lua +++ b/src/SCRIPTS/RF2/tool.lua @@ -7,6 +7,10 @@ local useLvgl = false if scriptsCompiled then --print("RF2: Before rf2.lua: ", collectgarbage("count") * 1024) assert(loadScript("rf2.lua"))() + + local i18n = assert(loadScript("F/language.lua"))() + rf2.i18n = i18n + --rf2.showMemoryUsage("rf2 loaded") rf2.radio = rf2.executeScript("radios").msp --rf2.showMemoryUsage("radios loaded") diff --git a/src/SCRIPTS/RF2/ui_init.lua b/src/SCRIPTS/RF2/ui_init.lua index 2e2576a2..b19a7149 100644 --- a/src/SCRIPTS/RF2/ui_init.lua +++ b/src/SCRIPTS/RF2/ui_init.lua @@ -9,6 +9,12 @@ local function init() return false end + if rf2.runningInSimulator then + rf2.apiVersion = apiVersion or 12.06 + collectgarbage() + return true + end + if not apiVersion and (not lastRunTS or lastRunTS + 2 < rf2.clock()) then returnTable.t = "Waiting for API version" mspApiVersion.getApiVersion(function(_, version) apiVersion = version end) diff --git a/src/SCRIPTS/RF2/ui_lvgl_framework.lua b/src/SCRIPTS/RF2/ui_lvgl_framework.lua index f8668712..4633bc05 100644 --- a/src/SCRIPTS/RF2/ui_lvgl_framework.lua +++ b/src/SCRIPTS/RF2/ui_lvgl_framework.lua @@ -12,6 +12,8 @@ local ui = { previousState = nil } +local t = rf2.i18n.t + local PageFiles = nil local Page = nil local CurrentPageIndex = -1 @@ -42,12 +44,14 @@ ui.loadPage = function() Page:read() end + + ui.showMainMenu = function() Page = nil local menu = { title = "Rotorflight " .. rf2.luaVersion, - subtitle = "Main Menu", + subtitle = t("TITLE_Menu_Menu"), items = {}, back = function() ui.state = ui.status.exit end } @@ -63,6 +67,7 @@ ui.showMainMenu = function() local text = string.gsub(page.title, "^ESC %- ", "") -- remove leading 'ESC - ' from page title menu.items[#menu.items + 1] = { text = text, + icon = page.icon, click = onMenuItemClick } end @@ -104,9 +109,9 @@ ui.saveSettingsToEeprom = function(eepromWrite, reboot) if not ui.saveWarningShown then ui.saveWarningShown = true if rf2.apiVersion >= 12.08 then - rf2.executeScript("LVGL/messageBox").show("Save warning", "Settings will be saved\nafter disarming.") + rf2.executeScript("LVGL/messageBox").show(t("TITLE_WARNING_Save"), t("MSG_WARNING_Save_later")) else - rf2.executeScript("LVGL/messageBox").show("Save error", "Make sure your heli\nis disarmed.") + rf2.executeScript("LVGL/messageBox").show(t("TITLE_Save_Error"), t("MSG_Save_Error")) end ui.refresh() end @@ -122,19 +127,19 @@ ui.showPopupMenu = function() if Page then if not Page.readOnly then menu.items[#menu.items + 1] = { - text = "Save", + text = t("MENU_Save"), click = function() Page:write() end } end menu.items [#menu.items + 1] = { - text = "Reload", + text = t("MENU_Reload"), click = function() Page:read() end } end menu.items[#menu.items + 1] = { - text = "Reboot", + text = t("MENU_Reboot"), click = function() rebootFc() end }