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..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; }; @@ -59,8 +63,10 @@ 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 && + !isCliOnlyMode() && + Date.now() - rebootTimestamp <= REBOOT_CONNECT_MAX_TIME_MS ) { connectDisconnect(); } @@ -587,6 +593,11 @@ function setRtc() { function finishOpen() { CONFIGURATOR.connectionValid = true; + if (isCliOnlyMode()) { + connectCli(); + return; + } + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_45) && FC.CONFIG.buildOptions.length) { GUI.allowedTabs = Array.from(GUI.defaultAllowedTabs); @@ -652,7 +663,7 @@ function onConnect() { }) .show(); - if (FC.CONFIG.flightControllerVersion !== "") { + 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 +679,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) { @@ -798,9 +809,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")); 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 @@ -