From cb9d82f970a6af7a1eb9ce9fb2d0eac9e08688c8 Mon Sep 17 00:00:00 2001 From: Mark Haslinghuis Date: Wed, 30 Jul 2025 17:21:12 +0200 Subject: [PATCH 1/5] Add CLI Only Mode as development option --- locales/en/messages.json | 8 ++++++++ src/js/serial_backend.js | 21 +++++++++++++++++---- src/js/tabs/options.js | 12 ++++++++++++ src/tabs/options.html | 29 +++++++++++++++++++++++------ 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/locales/en/messages.json b/locales/en/messages.json index ebfad073a2..e7ce2df7de 100755 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -153,10 +153,18 @@ "message": "Set connection timeout to allow longer initialisation on device plugin or reboot", "description": "Change timeout on auto-connect and reboot so the bus has more time to initialize after being detected by the system" }, + "developmentSettings": { + "message": "Development Settings", + "description": "Title for the development settings section" + }, "showAllSerialDevices": { "message": "Show all serial devices (for manufacturers or development)", "description": "Do not filter serial devices using VID/PID values (for manufacturers or development)" }, + "cliOnlyMode": { + "message": "Enable CLI only mode", + "description": "Text for the option to enable or disable CLI only mode" + }, "showManualMode": { "message": "Enable manual connection mode", "description": "Text for the option to enable or disable manual connection mode" diff --git a/src/js/serial_backend.js b/src/js/serial_backend.js index 5073ab977e..c1fd144272 100644 --- a/src/js/serial_backend.js +++ b/src/js/serial_backend.js @@ -587,6 +587,13 @@ function setRtc() { function finishOpen() { CONFIGURATOR.connectionValid = true; + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47)) { + if (getConfig("cliOnlyMode")?.cliOnlyMode) { + connectCli(); + return; + } + } + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_45) && FC.CONFIG.buildOptions.length) { GUI.allowedTabs = Array.from(GUI.defaultAllowedTabs); @@ -652,7 +659,13 @@ function onConnect() { }) .show(); - if (FC.CONFIG.flightControllerVersion !== "") { + const isCliOnlyMode = + semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47) && + getConfig("cliOnlyMode")?.cliOnlyMode && + GUI.allowedTabs.length === 1 && + GUI.allowedTabs[0] === "cli"; + + if (FC.CONFIG.flightControllerVersion !== "" && !isCliOnlyMode) { FC.FEATURE_CONFIG.features = new Features(FC.CONFIG); FC.BEEPER_CONFIG.beepers = new Beepers(FC.CONFIG); FC.BEEPER_CONFIG.dshotBeaconConditions = new Beepers(FC.CONFIG, ["RX_LOST", "RX_SET"]); @@ -668,12 +681,12 @@ function onConnect() { if (FC.CONFIG.boardType === 0 || FC.CONFIG.boardType === 2) { startLiveDataRefreshTimer(); } + + $("#sensor-status").show(); + $("#dataflash_wrapper_global").show(); } - // header bar - $("#sensor-status").show(); $("#portsinput").hide(); - $("#dataflash_wrapper_global").show(); } function onClosed(result) { diff --git a/src/js/tabs/options.js b/src/js/tabs/options.js index f35acad223..79ec757922 100644 --- a/src/js/tabs/options.js +++ b/src/js/tabs/options.js @@ -32,6 +32,7 @@ options.initialize = function (callback) { TABS.options.initShowWarnings(); TABS.options.initMeteredConnection(); TABS.options.initBackupOnFlash(); + TABS.options.initCLiOnlyMode(); GUI.content_ready(callback); }); @@ -261,6 +262,17 @@ options.initUserLanguage = function () { .trigger("change"); }; +options.initCLiOnlyMode = function () { + const cliOnlyModeElement = $("div.cliOnlyMode input"); + const result = getConfig("cliOnlyMode", false); + cliOnlyModeElement.prop("checked", !!result.cliOnlyMode).on("change", () => { + const checked = cliOnlyModeElement.is(":checked"); + setConfig({ cliOnlyMode: checked }); + }); + // Trigger change to ensure the initial state is set correctly + cliOnlyModeElement.trigger("change"); +}; + // TODO: remove when modules are in place TABS.options = options; export { options }; diff --git a/src/tabs/options.html b/src/tabs/options.html index 51fdcf8a68..1fff5f51bb 100644 --- a/src/tabs/options.html +++ b/src/tabs/options.html @@ -29,12 +29,6 @@ -
-
- -
- -
@@ -94,6 +88,29 @@
+
+
+
+
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+
+
From ff9468a0e338ff2a211003228021604cb85a266b Mon Sep 17 00:00:00 2001 From: Mark Haslinghuis Date: Wed, 30 Jul 2025 22:28:09 +0200 Subject: [PATCH 2/5] Fix reboot condition --- src/js/serial_backend.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/js/serial_backend.js b/src/js/serial_backend.js index c1fd144272..26be433674 100644 --- a/src/js/serial_backend.js +++ b/src/js/serial_backend.js @@ -59,8 +59,9 @@ export function initializeSerialBackend() { if ( !GUI.connected_to && !GUI.connecting_to && - GUI.active_tab !== "firmware_flasher" && - (PortHandler.portPicker.autoConnect || Date.now() - rebootTimestamp < REBOOT_CONNECT_MAX_TIME_MS) + !["cli", "firmware_flasher"].includes(GUI.active_tab) && + PortHandler.portPicker.autoConnect && + !(Date.now() - rebootTimestamp > REBOOT_CONNECT_MAX_TIME_MS) ) { connectDisconnect(); } @@ -811,9 +812,9 @@ export function reinitializeConnection() { } } - // Show reboot progress modal except for presets tab - if (GUI.active_tab === "presets") { - console.log("Rebooting in presets tab, skipping reboot dialog", GUI.active_tab); + // Show reboot progress modal except for cli and presets tab + if (["cli", "presets"].includes(GUI.active_tab)) { + console.log(`${logHead} Rebooting in ${GUI.active_tab} tab, skipping reboot dialog`); gui_log(i18n.getMessage("deviceRebooting")); gui_log(i18n.getMessage("deviceReady")); From 05566992c797b33d6759e84d10c306a0c0f5588b Mon Sep 17 00:00:00 2001 From: Mark Haslinghuis Date: Wed, 30 Jul 2025 22:33:06 +0200 Subject: [PATCH 3/5] Boolean checks should not be inverted --- src/js/serial_backend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/serial_backend.js b/src/js/serial_backend.js index 26be433674..ef44461aee 100644 --- a/src/js/serial_backend.js +++ b/src/js/serial_backend.js @@ -61,7 +61,7 @@ export function initializeSerialBackend() { !GUI.connecting_to && !["cli", "firmware_flasher"].includes(GUI.active_tab) && PortHandler.portPicker.autoConnect && - !(Date.now() - rebootTimestamp > REBOOT_CONNECT_MAX_TIME_MS) + Date.now() - rebootTimestamp <= REBOOT_CONNECT_MAX_TIME_MS ) { connectDisconnect(); } From ee52ba8cf47ffb92f8ad68161c8edb021b4e1b19 Mon Sep 17 00:00:00 2001 From: Mark Haslinghuis Date: Thu, 31 Jul 2025 15:32:42 +0200 Subject: [PATCH 4/5] No constraints --- src/js/serial_backend.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/js/serial_backend.js b/src/js/serial_backend.js index ef44461aee..528ca9f167 100644 --- a/src/js/serial_backend.js +++ b/src/js/serial_backend.js @@ -588,11 +588,9 @@ function setRtc() { function finishOpen() { CONFIGURATOR.connectionValid = true; - if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47)) { - if (getConfig("cliOnlyMode")?.cliOnlyMode) { - connectCli(); - return; - } + if (getConfig("cliOnlyMode")?.cliOnlyMode) { + connectCli(); + return; } if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_45) && FC.CONFIG.buildOptions.length) { @@ -661,10 +659,7 @@ function onConnect() { .show(); const isCliOnlyMode = - semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47) && - getConfig("cliOnlyMode")?.cliOnlyMode && - GUI.allowedTabs.length === 1 && - GUI.allowedTabs[0] === "cli"; + getConfig("cliOnlyMode")?.cliOnlyMode && GUI.allowedTabs.length === 1 && GUI.allowedTabs[0] === "cli"; if (FC.CONFIG.flightControllerVersion !== "" && !isCliOnlyMode) { FC.FEATURE_CONFIG.features = new Features(FC.CONFIG); From 60d0261fde280a7aa466e6f30db27caeef2f3a74 Mon Sep 17 00:00:00 2001 From: Mark Haslinghuis Date: Thu, 31 Jul 2025 16:28:51 +0200 Subject: [PATCH 5/5] Prevent auto-connect (loop) in cli only mode --- src/js/serial_backend.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/js/serial_backend.js b/src/js/serial_backend.js index 528ca9f167..8d85626e23 100644 --- a/src/js/serial_backend.js +++ b/src/js/serial_backend.js @@ -39,6 +39,10 @@ const REBOOT_CONNECT_MAX_TIME_MS = 10000; const REBOOT_GRACE_PERIOD_MS = 2000; let rebootTimestamp = 0; +function isCliOnlyMode() { + return getConfig("cliOnlyMode")?.cliOnlyMode === true; +} + const toggleStatus = function () { isConnected = !isConnected; }; @@ -61,6 +65,7 @@ export function initializeSerialBackend() { !GUI.connecting_to && !["cli", "firmware_flasher"].includes(GUI.active_tab) && PortHandler.portPicker.autoConnect && + !isCliOnlyMode() && Date.now() - rebootTimestamp <= REBOOT_CONNECT_MAX_TIME_MS ) { connectDisconnect(); @@ -588,7 +593,7 @@ function setRtc() { function finishOpen() { CONFIGURATOR.connectionValid = true; - if (getConfig("cliOnlyMode")?.cliOnlyMode) { + if (isCliOnlyMode()) { connectCli(); return; } @@ -658,10 +663,7 @@ function onConnect() { }) .show(); - const isCliOnlyMode = - getConfig("cliOnlyMode")?.cliOnlyMode && GUI.allowedTabs.length === 1 && GUI.allowedTabs[0] === "cli"; - - if (FC.CONFIG.flightControllerVersion !== "" && !isCliOnlyMode) { + if (FC.CONFIG.flightControllerVersion !== "" && !isCliOnlyMode()) { FC.FEATURE_CONFIG.features = new Features(FC.CONFIG); FC.BEEPER_CONFIG.beepers = new Beepers(FC.CONFIG); FC.BEEPER_CONFIG.dshotBeaconConditions = new Beepers(FC.CONFIG, ["RX_LOST", "RX_SET"]);