From 92248f6c4ece73c3cc45be2e115468c9bd2ef321 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Mon, 22 Sep 2025 12:50:12 +0300 Subject: [PATCH 01/14] Added manticore v1 & v2 --- locales/en/messages.json | 15 +++++++ src/js/msp/MSPHelper.js | 5 +++ src/js/tabs/osd.js | 91 +++++++++++++++++++++++++++++++++++++++- src/js/tabs/ports.js | 6 +++ 4 files changed, 115 insertions(+), 2 deletions(-) diff --git a/locales/en/messages.json b/locales/en/messages.json index a7d1e0a8de..2eab0e3cd1 100755 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -1937,6 +1937,12 @@ "portsFunction_VTX_MSP": { "message": "VTX (MSP + Displayport)" }, + "portsFunction_MANTICORE_INITIATOR_V1": { + "message": "Manticore V1" + }, + "portsFunction_MANTICORE_INITIATOR_V2": { + "message": "Manticore V2" + }, "pidTuningProfileOption": { "message": "Profile $1" }, @@ -7745,6 +7751,15 @@ "message": "Sonar", "description": "Displays distance from sonar sensor in cm" }, + "osdTextElementManticoreV1": { + "message": "Manticore V1" + }, + "osdTextElementManticoreV2": { + "message": "Manticore V2" + }, + "osdTextElementManticoreV2Logger": { + "message": "Manticore V2 Logger" + }, "osdDescElementLidar": { "message": "$t(osdTextElementLidar.message)", "description": "Don't translate!!!" diff --git a/src/js/msp/MSPHelper.js b/src/js/msp/MSPHelper.js index 7112b32b0f..627066a729 100644 --- a/src/js/msp/MSPHelper.js +++ b/src/js/msp/MSPHelper.js @@ -67,6 +67,11 @@ function MspHelper() { LIDAR_TF: 15, FRSKY_OSD: 16, VTX_MSP: 17, + GIMBAL: 18, + KOLIBRI_INITIATOR: 19, + DETONATOR: 20, + MANTICORE_INITIATOR_V1: 21, + MANTICORE_INITIATOR_V2: 22, }; self.REBOOT_TYPES = { diff --git a/src/js/tabs/osd.js b/src/js/tabs/osd.js index c9d49cfdaa..c012400e6f 100644 --- a/src/js/tabs/osd.js +++ b/src/js/tabs/osd.js @@ -1773,6 +1773,78 @@ OSD.loadDisplayFields = function () { positionable: true, preview: "RF:---", }, + MB_OSD_STATS: { + name: "MB_OSD_STATS", + text: "MB_OSD_STATS", + desc: "MB_OSD_STATS", + defaultPosition: -1, + draw_order: 610, + positionable: true, + preview: "MB_OSD_STATS", + }, + MB_VRX_RSSI: { + name: "MB_VRX_RSSI", + text: "MB_VRX_RSSI", + desc: "MB_VRX_RSSI", + defaultPosition: -1, + draw_order: 610, + positionable: true, + preview: "MB_VRX_RSSI", + }, + MB_INIK_INITIATOR: { + name: "MB_INIK_INITIATOR", + text: "MB_INIK_INITIATOR", + desc: "MB_INIK_INITIATOR", + defaultPosition: -1, + draw_order: 610, + positionable: true, + preview: "MB_INIK_INITIATOR", + }, + MB_USE_KOLIBRI_INITIATOR_OSD: { + name: "MB_USE_KOLIBRI_INITIATOR_OSD", + text: "MB_USE_KOLIBRI_INITIATOR_OSD", + desc: "MB_USE_KOLIBRI_INITIATOR_OSD", + defaultPosition: -1, + draw_order: 610, + positionable: true, + preview: "MB_USE_KOLIBRI_INITIATOR_OSD", + }, + MB_LASERDETON_INITIATOR_OSD: { + name: "MB_LASERDETON_INITIATOR_OSD", + text: "MB_LASERDETON_INITIATOR_OSD", + desc: "MB_LASERDETON_INITIATOR_OSD", + defaultPosition: -1, + draw_order: 610, + positionable: true, + preview: "MB_LASERDETON_INITIATOR_OSD", + }, + MANTICORE_INITIATOR_V1: { + name: "MANTICORE_INITIATOR_V1", + text: "osdTextElementManticoreV1", + desc: "osdTextElementManticoreV1", + defaultPosition: -1, + draw_order: 1075, + positionable: true, + preview: "MANTICORE V1", + }, + MANTICORE_INITIATOR_V2: { + name: "MANTICORE_INITIATOR_V2", + text: "osdTextElementManticoreV2", + desc: "osdTextElementManticoreV2", + defaultPosition: -1, + draw_order: 1075, + positionable: true, + preview: "MANTICORE V2", + }, + MANTICORE_INITIATOR_LOGGER_V2: { + name: "MANTICORE_INITIATOR_LOGGER_V2", + text: "osdTextElementManticoreV2Logger", + desc: "osdTextElementManticoreV2Logger", + defaultPosition: -1, + draw_order: 1076, + positionable: true, + preview: "MANTICORE V2 LOGGER", + }, }; if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47)) { @@ -2220,6 +2292,14 @@ OSD.chooseFields = function () { F.CUSTOM_MSG2, F.CUSTOM_MSG3, F.OSD_LIDAR_DIST, + F.MB_OSD_STATS, + F.MB_VRX_RSSI, + F.MB_INIK_INITIATOR, + F.MB_USE_KOLIBRI_INITIATOR_OSD, + F.MB_LASERDETON_INITIATOR_OSD, + F.MANTICORE_INITIATOR_V1, + F.MANTICORE_INITIATOR_V2, + F.MANTICORE_INITIATOR_LOGGER_V2, ]); } // Choose statistic fields @@ -3544,7 +3624,11 @@ osd.initialize = function (callback) { OSD.msp.decode(info); } - if (OSD.data.state.haveMax7456FontDeviceConfigured && !OSD.data.state.isMax7456FontDeviceDetected && !OSD.data.state.haveAirbotTheiaOsdDevice) { + if ( + OSD.data.state.haveMax7456FontDeviceConfigured && + !OSD.data.state.isMax7456FontDeviceDetected && + !OSD.data.state.haveAirbotTheiaOsdDevice + ) { $(".noOsdChipDetect").show(); } @@ -3820,7 +3904,10 @@ osd.initialize = function (callback) { $(".requires-max7456").hide(); } - if (!OSD.data.state.isMax7456FontDeviceDetected || (!OSD.data.state.haveMax7456FontDeviceConfigured && !OSD.data.state.haveAirbotTheiaOsdDevice)) { + if ( + !OSD.data.state.isMax7456FontDeviceDetected || + (!OSD.data.state.haveMax7456FontDeviceConfigured && !OSD.data.state.haveAirbotTheiaOsdDevice) + ) { $(".requires-max7456-font-device-detected").addClass("disabled"); } diff --git a/src/js/tabs/ports.js b/src/js/tabs/ports.js index d50c623637..5fa27a0b6d 100644 --- a/src/js/tabs/ports.js +++ b/src/js/tabs/ports.js @@ -73,6 +73,12 @@ ports.initialize = function (callback) { functionRules.push({ name: "VTX_MSP", groups: ["peripherals"], sharableWith: ["msp"], maxPorts: 1 }); } + functionRules.push({ name: "GIMBAL", groups: ["peripherals"], maxPorts: 1 }); + functionRules.push({ name: "KOLIBRI_INITIATOR", groups: ["peripherals"], maxPorts: 1 }); + functionRules.push({ name: "DETONATOR", groups: ["peripherals"], maxPorts: 1 }); + functionRules.push({ name: "MANTICORE_INITIATOR_V1", groups: ["peripherals"], sharableWith: ["msp"], maxPorts: 1 }); + functionRules.push({ name: "MANTICORE_INITIATOR_V2", groups: ["peripherals"], sharableWith: ["msp"], maxPorts: 1 }); + for (const rule of functionRules) { rule.displayName = i18n.getMessage(`portsFunction_${rule.name}`); } From 4b6a92537548c36d5f31c990605fe93a71f58f26 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Mon, 22 Sep 2025 17:11:25 +0300 Subject: [PATCH 02/14] Disable modal window --- src/js/serial_backend.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/serial_backend.js b/src/js/serial_backend.js index 88a034e477..31ab4facce 100644 --- a/src/js/serial_backend.js +++ b/src/js/serial_backend.js @@ -508,6 +508,7 @@ function checkReportProblems() { } } + needsProblemReportingDialog = false; if (needsProblemReportingDialog) { problems.forEach((problem) => { problemItemTemplate.clone().html(problem.description).appendTo(problemDialogList); From ffd84f32d2eec8d6131c5b757c95a3b9be8c0169 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Thu, 25 Sep 2025 16:10:45 +0300 Subject: [PATCH 03/14] Added skeleton --- locales/en/messages.json | 18 +++++ locales/uk/messages.json | 18 +++++ package.json | 1 + src/index.html | 1 + src/js/gui.js | 1 + src/js/main.js | 3 + src/js/tabs/norn_config.js | 133 ++++++++++++++++++++++++++++++++++ src/norn-configs/template.ejs | 42 +++++++++++ src/tabs/norn_config.html | 55 ++++++++++++++ yarn.lock | 33 ++++++++- 10 files changed, 301 insertions(+), 4 deletions(-) create mode 100644 src/js/tabs/norn_config.js create mode 100644 src/norn-configs/template.ejs create mode 100644 src/tabs/norn_config.html diff --git a/locales/en/messages.json b/locales/en/messages.json index 2eab0e3cd1..105cff9189 100755 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -368,6 +368,24 @@ "tabOptions": { "message": "Options" }, + "tabNornConfig": { + "message": "NORN Config" + }, + "nornManticore": { + "message": "Manticore" + }, + "nornVtx": { + "message": "VTX" + }, + "nornNone": { + "message": "None" + }, + "nornGenerate": { + "message": "Generate" + }, + "nornOutput": { + "message": "NORN Configuration" + }, "tabSetup": { "message": "Setup" diff --git a/locales/uk/messages.json b/locales/uk/messages.json index 5af82e33fe..5b58a16ffb 100644 --- a/locales/uk/messages.json +++ b/locales/uk/messages.json @@ -7510,5 +7510,23 @@ "osdDescElementLidar": { "message": "$t(osdTextElementLidar.message)", "description": "Don't translate!!!" + }, + "nornManticore": { + "message": "Manticore" + }, + "nornVtx": { + "message": "VTX" + }, + "nornNone": { + "message": "Немає" + }, + "nornGenerate": { + "message": "Згенерувати" + }, + "nornOutput": { + "message": "Конфігурація" + }, + "tabNornConfig": { + "message": "NORN Налаштування" } } diff --git a/package.json b/package.json index 995de18faa..4a4dc6f06b 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "node": "20.x" }, "dependencies": { + "ejs": "^3.1.9", "@capacitor/android": "^7.0.1", "@capacitor/core": "^7.0.1", "@fortawesome/fontawesome-free": "^6.5.2", diff --git a/src/index.html b/src/index.html index f68454799c..bcfeeb0604 100644 --- a/src/index.html +++ b/src/index.html @@ -136,6 +136,7 @@
  • +
  • diff --git a/src/js/gui.js b/src/js/gui.js index e2aa085294..7e0f98e7de 100644 --- a/src/js/gui.js +++ b/src/js/gui.js @@ -30,6 +30,7 @@ class GuiControl { "presets", "cli", "configuration", + "norn_config", "logging", "onboard_logging", "modes", diff --git a/src/js/main.js b/src/js/main.js index b19fbf185c..bd426350af 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -279,6 +279,9 @@ function startProcess() { configuration.initialize(content_ready), ); break; + case "norn_config": + import("./tabs/norn_config").then(({ norn_config }) => norn_config.initialize(content_ready)); + break; case "pid_tuning": import("./tabs/pid_tuning").then(({ pid_tuning }) => pid_tuning.initialize(content_ready)); break; diff --git a/src/js/tabs/norn_config.js b/src/js/tabs/norn_config.js new file mode 100644 index 0000000000..37ee0f2bd5 --- /dev/null +++ b/src/js/tabs/norn_config.js @@ -0,0 +1,133 @@ +import ejs from "ejs"; +import { i18n } from "../localization"; +import GUI, { TABS } from "../gui"; +import { mspHelper } from "../msp/MSPHelper"; +import MSP from "../msp"; +import MSPCodes from "../msp/MSPCodes"; +import $ from "jquery"; + +// Discover config sources (text-based) +const templateFiles = import.meta.glob("../../norn-configs/template.ejs", { eager: true, as: "raw" }); + +const norn_config = { + analyticsChanges: {}, +}; + +norn_config.initialize = function (callback) { + const self = this; + + GUI.active_tab = "norn_config"; + + function load_configuration_from_fc() { + // Load any prerequisite data from FC, then load the HTML + mspHelper.readFullConfiguration?.(() => { + $("#content").load("./tabs/norn_config.html", on_tab_loaded_handler); + }) || $("#content").load("./tabs/norn_config.html", on_tab_loaded_handler); + } + + function update_ui() { + i18n.localizePage(); + + // Populate Manticore models (allow None) with explicit options + const manticoreSelect = $("select[name='norn_manticore']"); + if (manticoreSelect.length) { + manticoreSelect.empty(); + manticoreSelect.append(``); + manticoreSelect.append(``); + manticoreSelect.append(``); + manticoreSelect.on("change", function () { + self.analyticsChanges["NornManticore"] = $(this).val() || null; + }); + } + + // Populate VTX profiles (allow None) with explicit options + const vtxSelect = $("select[name='norn_vtx']"); + if (vtxSelect.length) { + vtxSelect.empty(); + vtxSelect.append(``); + vtxSelect.append(``); + vtxSelect.append(``); + vtxSelect.append(``); + vtxSelect.on("change", function () { + self.analyticsChanges["NornVtx"] = $(this).val() || null; + }); + } + + // Example dropdown wiring + const exampleSelect = $("select[name='norn_mode']"); + if (exampleSelect.length) { + exampleSelect.on("change", function () { + const value = $(this).val(); + self.analyticsChanges["NornMode"] = value; + }); + } + + // Example button wiring + $("a.generate").on("click", on_generate_handler); + } + + function on_tab_loaded_handler() { + update_ui(); + + GUI.interval_add( + "status_pull", + function status_pull() { + MSP.send_message(MSPCodes.MSP_STATUS); + }, + 500, + true, + ); + + GUI.content_ready(callback); + } + + // No save/copy handlers for now (kept minimal per request) + + function readFileRaw(pathMap, path) { + if (!path) return ""; + try { + return pathMap[path] || ""; + } catch (e) { + console.error("Cannot read", path, e); + return ""; + } + } + + function getSelectedKeys() { + const manticoreKey = $("select[name='norn_manticore']").val() || ""; + const vtxKey = $("select[name='norn_vtx']").val() || ""; + return { manticoreKey, vtxKey }; + } + + function on_generate_handler(e) { + e?.preventDefault?.(); + + const templatePath = Object.keys(templateFiles)[0]; + let result; + if (templatePath) { + const tpl = readFileRaw(templateFiles, templatePath); + result = ejs.render(tpl, getSelectedKeys()); + } else { + // Fallback to old behavior if template missing + const parts = []; + const genericPath = Object.keys(genericFiles)[0]; + parts.push(readFileRaw(genericFiles, genericPath)); + const manticorePath = $("select[name='norn_manticore']").val(); + if (manticorePath) parts.push(readFileRaw(manticoreFiles, manticorePath)); + const vtxPath = $("select[name='norn_vtx']").val(); + if (vtxPath) parts.push(readFileRaw(vtxFiles, vtxPath)); + result = parts.filter(Boolean).join("\n\n").trim(); + } + + $("#norn_config_output").val(result); + } + + load_configuration_from_fc(); +}; + +norn_config.cleanup = function (callback) { + if (callback) callback(); +}; + +TABS.norn_config = norn_config; +export { norn_config }; diff --git a/src/norn-configs/template.ejs b/src/norn-configs/template.ejs new file mode 100644 index 0000000000..8ceb1d05e5 --- /dev/null +++ b/src/norn-configs/template.ejs @@ -0,0 +1,42 @@ +defaults nosave + +batch start + +defaults nosave + + + +<% if (manticoreKey === 'uart') { %> +# Manticore UART variant +set uart1_function = RX_SERIAL +set uart2_function = TELEMETRY +<% } %> + +<% if (manticoreKey === 'gpio') { %> +# Manticore GPIO variant +set gpio_output = ON +set gpio_mode = ALTERNATE +<% } %> + +<% if (vtxKey === '5.8_vtx') { %> +# 5.8GHz VTX settings +set vtx_band = A +set vtx_channel = 1 +set vtx_power = 25 +<% } %> + +<% if (vtxKey === '3.3_vtx') { %> +# 3.3GHz VTX settings +set vtx_band = B +set vtx_channel = 3 +set vtx_power = 100 +<% } %> + +<% if (vtxKey === 'optica') { %> +# Optica VTX settings +set vtx_band = O +set vtx_channel = 2 +set vtx_power = 50 +<% } %> + + diff --git a/src/tabs/norn_config.html b/src/tabs/norn_config.html new file mode 100644 index 0000000000..bbf37c1ed1 --- /dev/null +++ b/src/tabs/norn_config.html @@ -0,0 +1,55 @@ +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + diff --git a/yarn.lock b/yarn.lock index ead226865c..3c9b08bc05 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4406,7 +4406,7 @@ editorconfig@^1.0.4: minimatch "9.0.1" semver "^7.5.3" -ejs@^3.1.6: +ejs@^3.1.6, ejs@^3.1.9: version "3.1.10" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== @@ -9630,7 +9630,7 @@ string-argv@^0.3.2: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -9648,6 +9648,15 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -9753,7 +9762,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -9781,6 +9790,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -11053,7 +11069,7 @@ workbox-window@7.3.0, workbox-window@^7.3.0: "@types/trusted-types" "^2.0.2" workbox-core "7.3.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -11079,6 +11095,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From 447ff7e99aac98b7ccc29628ffb91284ebe19518 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Wed, 1 Oct 2025 11:48:12 +0300 Subject: [PATCH 04/14] Added logic --- locales/en/messages.json | 22 ++++++- locales/uk/messages.json | 21 +++++++ src/index.html | 2 +- src/js/tabs/norn_config.js | 110 +++++++++++++++++++++++++++++++--- src/norn-configs/template.ejs | 48 +++++++++++++++ src/tabs/norn_config.html | 102 ++++++++++++++++++++++++++----- 6 files changed, 278 insertions(+), 27 deletions(-) diff --git a/locales/en/messages.json b/locales/en/messages.json index 105cff9189..9970eab536 100755 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -386,7 +386,27 @@ "nornOutput": { "message": "NORN Configuration" }, - + "nornDrone": { + "message": "Drone" + }, + "nornController": { + "message": "Controller" + }, + "nornSize": { + "message": "Size" + }, + "nornCraftName": { + "message": "Craft Name" + }, + "nornGPS": { + "message": "GPS" + }, + "nornCopy": { + "message": "Copy to clipboard" + }, + "nornSave": { + "message": "Save" + }, "tabSetup": { "message": "Setup" }, diff --git a/locales/uk/messages.json b/locales/uk/messages.json index 5b58a16ffb..471c5459aa 100644 --- a/locales/uk/messages.json +++ b/locales/uk/messages.json @@ -7526,6 +7526,27 @@ "nornOutput": { "message": "Конфігурація" }, + "nornDrone": { + "message": "Дрон" + }, + "nornController": { + "message": "Контролер" + }, + "nornSize": { + "message": "Розмір" + }, + "nornCraftName": { + "message": "Назва дрона" + }, + "nornGPS": { + "message": "GPS" + }, + "nornCopy": { + "message": "Копіювати в буффер" + }, + "nornSave": { + "message": "Зберегти" + }, "tabNornConfig": { "message": "NORN Налаштування" } diff --git a/src/index.html b/src/index.html index bcfeeb0604..df95b2f4df 100644 --- a/src/index.html +++ b/src/index.html @@ -136,7 +136,7 @@
  • -
  • +
  • diff --git a/src/js/tabs/norn_config.js b/src/js/tabs/norn_config.js index 37ee0f2bd5..6ff04c6651 100644 --- a/src/js/tabs/norn_config.js +++ b/src/js/tabs/norn_config.js @@ -28,6 +28,36 @@ norn_config.initialize = function (callback) { function update_ui() { i18n.localizePage(); + // Populate Flight Controller list (explicit options) + const fcSelect = $("select[name='norn_fc']"); + if (fcSelect.length) { + fcSelect.empty(); + fcSelect.append(``); + fcSelect.append(``); + fcSelect.append(``); + fcSelect.append(``); + fcSelect.append(``); + fcSelect.on("change", function () { + self.analyticsChanges["NornFC"] = $(this).val() || null; + }); + } + + // Populate Drone Size list (explicit options) + const droneSizeSelect = $("select[name='norn_drone_size']"); + if (droneSizeSelect.length) { + droneSizeSelect.empty(); + droneSizeSelect.append(``); + droneSizeSelect.append(``); + droneSizeSelect.append(``); + droneSizeSelect.append(``); + droneSizeSelect.append(``); + droneSizeSelect.append(``); + droneSizeSelect.append(``); + droneSizeSelect.on("change", function () { + self.analyticsChanges["NornDroneSize"] = $(this).val() || null; + }); + } + // Populate Manticore models (allow None) with explicit options const manticoreSelect = $("select[name='norn_manticore']"); if (manticoreSelect.length) { @@ -54,16 +84,24 @@ norn_config.initialize = function (callback) { } // Example dropdown wiring - const exampleSelect = $("select[name='norn_mode']"); - if (exampleSelect.length) { - exampleSelect.on("change", function () { - const value = $(this).val(); - self.analyticsChanges["NornMode"] = value; - }); - } + // none for now - // Example button wiring + // Button wiring $("a.generate").on("click", on_generate_handler); + $("a.copy").on("click", on_copy_handler); + $("a.save").on("click", on_save_handler); + + // GPS toggle wiring + const gpsToggle = $("#norn_gps"); + gpsToggle.on("change", function () { + self.analyticsChanges["NornGPS"] = $(this).is(":checked"); + }); + + // Craft name input wiring + const craftNameInput = $("#norn_craft_name"); + craftNameInput.on("input", function () { + self.analyticsChanges["NornCraftName"] = $(this).val() || null; + }); } function on_tab_loaded_handler() { @@ -94,9 +132,13 @@ norn_config.initialize = function (callback) { } function getSelectedKeys() { + const fcKey = $("select[name='norn_fc']").val() || ""; + const droneSize = $("select[name='norn_drone_size']").val() || ""; const manticoreKey = $("select[name='norn_manticore']").val() || ""; const vtxKey = $("select[name='norn_vtx']").val() || ""; - return { manticoreKey, vtxKey }; + const gpsEnabled = $("#norn_gps").is(":checked"); + const craftName = $("#norn_craft_name").val() || ""; + return { fcKey, droneSize, manticoreKey, vtxKey, gpsEnabled, craftName }; } function on_generate_handler(e) { @@ -122,6 +164,56 @@ norn_config.initialize = function (callback) { $("#norn_config_output").val(result); } + function on_copy_handler(e) { + e?.preventDefault?.(); + const text = $("#norn_config_output").val(); + if (text) { + navigator.clipboard + ?.writeText(text) + .then(() => { + console.log("Config copied to clipboard"); + }) + .catch((err) => { + console.error("Failed to copy to clipboard:", err); + }); + } + } + + function on_save_handler(e) { + e?.preventDefault?.(); + const text = $("#norn_config_output").val(); + if (!text) return; + + // Generate filename based on selected options + const parts = []; + const fcKey = $("select[name='norn_fc']").val(); + const droneSize = $("select[name='norn_drone_size']").val(); + const manticoreKey = $("select[name='norn_manticore']").val(); + const vtxKey = $("select[name='norn_vtx']").val(); + const gpsEnabled = $("#norn_gps").is(":checked"); + const craftName = $("#norn_craft_name").val(); + + if (fcKey) parts.push(fcKey); + if (droneSize) parts.push(`${droneSize}inch`); + if (manticoreKey) parts.push(manticoreKey); + if (vtxKey) parts.push(vtxKey); + if (gpsEnabled) parts.push("GPS"); + if (craftName) parts.push(craftName); + + const filename = parts.length > 0 ? `norn_config_${parts.join("_")}.txt` : "norn_config.txt"; + + // Create and trigger download + const blob = new Blob([text], { type: "text/plain" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } + load_configuration_from_fc(); }; diff --git a/src/norn-configs/template.ejs b/src/norn-configs/template.ejs index 8ceb1d05e5..bf6acc76f6 100644 --- a/src/norn-configs/template.ejs +++ b/src/norn-configs/template.ejs @@ -4,7 +4,44 @@ batch start defaults nosave +<% if (fcKey === 'f4') { %> +# Flight Controller: F4 tweaks +set pid_process_denom = 2 +<% } %> + +<% if (fcKey === 'f7') { %> +# Flight Controller: F7 tweaks +set pid_process_denom = 1 +<% } %> +<% if (fcKey === 'h7') { %> +# Flight Controller: H7 tweaks +set pid_process_denom = 1 +set cpu_overclock = ON +<% } %> + +<% if (droneSize) { %> +# Drone Size: <%= droneSize %>" +<% if (droneSize === '7') { %> +set motor_pwm_rate = 32000 +set motor_poles = 12 +<% } else if (droneSize === '8') { %> +set motor_pwm_rate = 24000 +set motor_poles = 14 +<% } else if (droneSize === '9') { %> +set motor_pwm_rate = 24000 +set motor_poles = 16 +<% } else if (droneSize === '10') { %> +set motor_pwm_rate = 16000 +set motor_poles = 18 +<% } else if (droneSize === '13') { %> +set motor_pwm_rate = 12000 +set motor_poles = 20 +<% } else if (droneSize === '15') { %> +set motor_pwm_rate = 8000 +set motor_poles = 22 +<% } %> +<% } %> <% if (manticoreKey === 'uart') { %> # Manticore UART variant @@ -39,4 +76,15 @@ set vtx_channel = 2 set vtx_power = 50 <% } %> +<% if (gpsEnabled) { %> +# GPS Enabled +feature GPS +set gps_baudrate = AUTO +<% } %> + +<% if (craftName) { %> +# Craft name +set craft_name = <%= craftName %> +<% } %> + diff --git a/src/tabs/norn_config.html b/src/tabs/norn_config.html index bbf37c1ed1..7deb3b499e 100644 --- a/src/tabs/norn_config.html +++ b/src/tabs/norn_config.html @@ -7,28 +7,94 @@
    -
    -
    -
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    -
    -
    - +
    +
    +
    +
    +
    +
    +
    + +
    +
    -
    -
    -
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    -
    -
    - +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    @@ -45,6 +111,10 @@
    +
    + + +
    From 157ff4b958efb22821dfaa1ca14090f72d6bbaa3 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Wed, 1 Oct 2025 12:26:30 +0300 Subject: [PATCH 05/14] Added logic to autodetect board once USB is connected --- src/js/tabs/firmware_flasher.js | 67 +++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/js/tabs/firmware_flasher.js b/src/js/tabs/firmware_flasher.js index a42f857ea7..8b98960a70 100644 --- a/src/js/tabs/firmware_flasher.js +++ b/src/js/tabs/firmware_flasher.js @@ -740,10 +740,60 @@ firmware_flasher.initialize = async function (callback) { STM32.rebootMode = 0; GUI.connect_lock = false; startFlashing(); + } else { + // Auto-detect board when firmware flasher tab is active and no flash-on-connect + console.log(`${self.logHead} Auto-detecting board for connected USB device`); + AutoDetect.verifyBoard(); + } + } + + function detectedSerialDevice(device) { + const isFlashOnConnect = $("input.flash_on_connect").is(":checked"); + + console.log(`${self.logHead} Detected serial device:`, device); + console.log(`${self.logHead} Reboot mode: %s, flash on connect`, STM32.rebootMode, isFlashOnConnect); + + if (STM32.rebootMode || isFlashOnConnect) { + STM32.rebootMode = 0; + GUI.connect_lock = false; + startFlashing(); + } else { + // Auto-detect board when firmware flasher tab is active and no flash-on-connect + console.log(`${self.logHead} Auto-detecting board for connected serial device`); + AutoDetect.verifyBoard(); } } EventBus.$on("port-handler:auto-select-usb-device", detectedUsbDevice); + EventBus.$on("port-handler:auto-select-serial-device", detectedSerialDevice); + + // Also listen for port changes to catch reconnections + function onPortChange(port) { + console.log(`${self.logHead} Port changed to:`, port); + // Auto-detect board when port changes and we're on firmware flasher tab + if (port && port !== "0" && !$("input.flash_on_connect").is(":checked") && !STM32.rebootMode) { + console.log(`${self.logHead} Auto-detecting board for port change`); + setTimeout(() => { + AutoDetect.verifyBoard(); + }, 500); // Small delay to ensure port is ready + } else if (!port || port === "0") { + // Clear board selection when no port is selected + console.log(`${self.logHead} Clearing board selection - no port selected`); + $('select[name="board"]').val("0").trigger("change"); + } + } + + // Listen for device removal to clear board selection + function onDeviceRemoved(devicePath) { + console.log(`${self.logHead} Device removed:`, devicePath); + // Clear board selection when device is removed + $('select[name="board"]').val("0").trigger("change"); + // Also clear any loaded firmware + clearBufferedFirmware(); + } + + EventBus.$on("ports-input:change", onPortChange); + EventBus.$on("port-handler:device-removed", onDeviceRemoved); async function saveFirmware() { const fileType = self.firmware_type; @@ -1458,6 +1508,17 @@ firmware_flasher.initialize = async function (callback) { $("a.exit_dfu").removeClass("disabled"); } + // Auto-detect board if a drone is already connected when tab becomes active + if ( + (PortHandler.portAvailable && !$('select[name="board"]').val()) || + $('select[name="board"]').val() === "0" + ) { + console.log(`${self.logHead} Auto-detecting board for already connected device`); + setTimeout(() => { + AutoDetect.verifyBoard(); + }, 1000); // Small delay to ensure tab is fully loaded + } + GUI.content_ready(callback); } @@ -1476,6 +1537,12 @@ firmware_flasher.cleanup = function (callback) { $(document).unbind("keypress"); $(document).off("click", "span.progressLabel a"); + // Clean up EventBus listeners + EventBus.$off("port-handler:auto-select-usb-device"); + EventBus.$off("port-handler:auto-select-serial-device"); + EventBus.$off("ports-input:change"); + EventBus.$off("port-handler:device-removed"); + if (callback) callback(); }; From 73c34d941789480a01ba7cd7b76e1b3b4ad2d7b2 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Mon, 6 Oct 2025 12:44:06 +0300 Subject: [PATCH 06/14] commit --- src/js/tabs/norn_config.js | 18 +++++------ src/norn-configs/README.txt | 57 +++++++++++++++++++++++++++++++++++ src/norn-configs/template.ejs | 49 ++++++++++++++++++++++-------- 3 files changed, 102 insertions(+), 22 deletions(-) create mode 100644 src/norn-configs/README.txt diff --git a/src/js/tabs/norn_config.js b/src/js/tabs/norn_config.js index 6ff04c6651..8fcd0a074e 100644 --- a/src/js/tabs/norn_config.js +++ b/src/js/tabs/norn_config.js @@ -33,10 +33,10 @@ norn_config.initialize = function (callback) { if (fcSelect.length) { fcSelect.empty(); fcSelect.append(``); - fcSelect.append(``); - fcSelect.append(``); - fcSelect.append(``); - fcSelect.append(``); + fcSelect.append(``); + fcSelect.append(``); + fcSelect.append(``); + fcSelect.append(``); fcSelect.on("change", function () { self.analyticsChanges["NornFC"] = $(this).val() || null; }); @@ -63,8 +63,8 @@ norn_config.initialize = function (callback) { if (manticoreSelect.length) { manticoreSelect.empty(); manticoreSelect.append(``); - manticoreSelect.append(``); - manticoreSelect.append(``); + manticoreSelect.append(``); + manticoreSelect.append(``); manticoreSelect.on("change", function () { self.analyticsChanges["NornManticore"] = $(this).val() || null; }); @@ -75,9 +75,9 @@ norn_config.initialize = function (callback) { if (vtxSelect.length) { vtxSelect.empty(); vtxSelect.append(``); - vtxSelect.append(``); - vtxSelect.append(``); - vtxSelect.append(``); + vtxSelect.append(``); + vtxSelect.append(``); + vtxSelect.append(``); vtxSelect.on("change", function () { self.analyticsChanges["NornVtx"] = $(this).val() || null; }); diff --git a/src/norn-configs/README.txt b/src/norn-configs/README.txt new file mode 100644 index 0000000000..82d48e876c --- /dev/null +++ b/src/norn-configs/README.txt @@ -0,0 +1,57 @@ +# NORN Configuration Template Documentation +# ====================================== +# +# This template generates Betaflight CLI configuration based on selected options. +# Available template variables (from getSelectedKeys() in norn_config.js): +# +# fcKey: Flight Controller type (from select[name='norn_fc']) +# - '': Empty/None selected +# - 'f4': FLASHHOBBYF405 (F4 chip) +# - 'f7': SPEEDYBEEF405V3 (F7 chip) +# - 'h7': TAKERF722SE or GEPRCF722 (H7 chip) - Note: both use same value +# +# droneSize: Drone frame size in inches (from select[name='norn_drone_size']) +# - '': Empty/None selected +# - '7': 7-inch frame +# - '8': 8-inch frame +# - '9': 9-inch frame +# - '10': 10-inch frame +# - '13': 13-inch frame +# - '15': 15-inch frame +# +# manticoreKey: Manticore system configuration (from select[name='norn_manticore']) +# - '': Empty/None selected +# - 'uart': UART-based Manticore setup +# - 'gpio': GPIO-based Manticore setup +# +# vtxKey: Video Transmitter configuration (from select[name='norn_vtx']) +# - '': Empty/None selected +# - '3.3_vtx': 3.3GHz VTX setup +# - '5.8_vtx': 5.8GHz VTX setup +# - 'optica': Optica VTX setup +# +# gpsEnabled: Boolean flag for GPS functionality (from #norn_gps checkbox) +# - true: Enable GPS features +# - false: No GPS configuration +# +# craftName: Custom craft name (from #norn_craft_name input) +# - '': Empty string if no name entered +# - Any string value for craft identification +# +# Template Syntax: +# - <% if (condition) { %> ... <% } %> : Conditional blocks +# - <%= variable %> : Output variable value +# - <%# comment %> : Template comments (not included in output) +# +# Example usage in conditional blocks: +# <% if (fcKey === 'f4') { %> +# # This section applies only to F4 flight controllers +# <% } %> +# +# <% if (droneSize === '7') { %> +# # This section applies only to 7-inch drones +# <% } %> +# +# Note: All select elements have an empty option for "None" selection +# Checkbox elements return boolean values (true/false) +# Input elements return string values (may be empty string) \ No newline at end of file diff --git a/src/norn-configs/template.ejs b/src/norn-configs/template.ejs index bf6acc76f6..728c1f4086 100644 --- a/src/norn-configs/template.ejs +++ b/src/norn-configs/template.ejs @@ -1,25 +1,38 @@ +<%if (fcKey) { %># FC: <%= fcKey %> +<% } %><% if (droneSize) { %># Drone Size: <%= droneSize %> +<% } %><% if (manticoreKey) { %># Manticore: <%= manticoreKey %> +<% } %><% if (vtxKey) { %># VTX: <%= vtxKey %> +<% } %><% if (gpsEnabled) { %># GPS: <%= gpsEnabled %> +<% } %><% if (craftName) { %># Craft Name: <%= craftName %> +<% } %> + defaults nosave batch start defaults nosave -<% if (fcKey === 'f4') { %> -# Flight Controller: F4 tweaks +<%# Flight Controller Configuration Blocks %> +<% if (fcKey === 'FLASHHOBBYF405') { %> set pid_process_denom = 2 <% } %> -<% if (fcKey === 'f7') { %> -# Flight Controller: F7 tweaks +<% if (fcKey === 'SPEEDYBEEF405V3') { %> set pid_process_denom = 1 <% } %> -<% if (fcKey === 'h7') { %> -# Flight Controller: H7 tweaks +<% if (fcKey === 'TAKERF722SE') { %> set pid_process_denom = 1 set cpu_overclock = ON <% } %> +<% if (fcKey === 'GEPRCF722') { %> +set pid_process_denom = 1 +set cpu_overclock = ON +<% } %> + +<%# Drone Size Configuration Block %> +<%# Motor settings optimized for different frame sizes %> <% if (droneSize) { %> # Drone Size: <%= droneSize %>" <% if (droneSize === '7') { %> @@ -43,48 +56,58 @@ set motor_poles = 22 <% } %> <% } %> -<% if (manticoreKey === 'uart') { %> +<%# Manticore System Configuration Blocks %> +<% if (manticoreKey === 'UART') { %> # Manticore UART variant +# Configure UART ports for Manticore communication set uart1_function = RX_SERIAL set uart2_function = TELEMETRY <% } %> -<% if (manticoreKey === 'gpio') { %> -# Manticore GPIO variant +<% if (manticoreKey === 'GPIO') { %> +# Manticore GPIO variant +# Configure GPIO pins for Manticore interface set gpio_output = ON set gpio_mode = ALTERNATE <% } %> -<% if (vtxKey === '5.8_vtx') { %> +<%# Video Transmitter (VTX) Configuration Blocks %> +<% if (vtxKey === '5.8VTX') { %> # 5.8GHz VTX settings +# Standard 5.8GHz video transmitter configuration set vtx_band = A set vtx_channel = 1 set vtx_power = 25 <% } %> -<% if (vtxKey === '3.3_vtx') { %> +<% if (vtxKey === '3.3VTX') { %> # 3.3GHz VTX settings +# Long-range 3.3GHz video transmitter configuration set vtx_band = B set vtx_channel = 3 set vtx_power = 100 <% } %> -<% if (vtxKey === 'optica') { %> +<% if (vtxKey === 'OPTICA') { %> # Optica VTX settings +# Digital video transmitter configuration set vtx_band = O set vtx_channel = 2 set vtx_power = 50 <% } %> +<%# GPS Configuration Block %> <% if (gpsEnabled) { %> # GPS Enabled +# Enable GPS functionality with auto baudrate detection feature GPS set gps_baudrate = AUTO <% } %> +<%# Custom Craft Name Configuration Block %> <% if (craftName) { %> # Craft name +# Set custom identification name for the craft set craft_name = <%= craftName %> <% } %> - From d965698e75018d262dbc36f892a4d961d347098a Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Mon, 6 Oct 2025 13:48:41 +0300 Subject: [PATCH 07/14] added handlebars --- package.json | 1 + src/js/tabs/norn_config.js | 12 +++- src/norn-configs/template.ejs | 113 -------------------------------- src/norn-configs/template.hbs | 117 ++++++++++++++++++++++++++++++++++ yarn.lock | 29 ++++++++- 5 files changed, 155 insertions(+), 117 deletions(-) delete mode 100644 src/norn-configs/template.ejs create mode 100644 src/norn-configs/template.hbs diff --git a/package.json b/package.json index 4a4dc6f06b..5bee84d710 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ }, "dependencies": { "ejs": "^3.1.9", + "handlebars": "^4.7.8", "@capacitor/android": "^7.0.1", "@capacitor/core": "^7.0.1", "@fortawesome/fontawesome-free": "^6.5.2", diff --git a/src/js/tabs/norn_config.js b/src/js/tabs/norn_config.js index 8fcd0a074e..9115ba88c7 100644 --- a/src/js/tabs/norn_config.js +++ b/src/js/tabs/norn_config.js @@ -1,4 +1,4 @@ -import ejs from "ejs"; +import Handlebars from "handlebars"; import { i18n } from "../localization"; import GUI, { TABS } from "../gui"; import { mspHelper } from "../msp/MSPHelper"; @@ -6,8 +6,13 @@ import MSP from "../msp"; import MSPCodes from "../msp/MSPCodes"; import $ from "jquery"; +// Register Handlebars helpers +Handlebars.registerHelper("eq", function (a, b) { + return a === b; +}); + // Discover config sources (text-based) -const templateFiles = import.meta.glob("../../norn-configs/template.ejs", { eager: true, as: "raw" }); +const templateFiles = import.meta.glob("../../norn-configs/template.hbs", { eager: true, as: "raw" }); const norn_config = { analyticsChanges: {}, @@ -148,7 +153,8 @@ norn_config.initialize = function (callback) { let result; if (templatePath) { const tpl = readFileRaw(templateFiles, templatePath); - result = ejs.render(tpl, getSelectedKeys()); + const template = Handlebars.compile(tpl); + result = template(getSelectedKeys()); } else { // Fallback to old behavior if template missing const parts = []; diff --git a/src/norn-configs/template.ejs b/src/norn-configs/template.ejs deleted file mode 100644 index 728c1f4086..0000000000 --- a/src/norn-configs/template.ejs +++ /dev/null @@ -1,113 +0,0 @@ -<%if (fcKey) { %># FC: <%= fcKey %> -<% } %><% if (droneSize) { %># Drone Size: <%= droneSize %> -<% } %><% if (manticoreKey) { %># Manticore: <%= manticoreKey %> -<% } %><% if (vtxKey) { %># VTX: <%= vtxKey %> -<% } %><% if (gpsEnabled) { %># GPS: <%= gpsEnabled %> -<% } %><% if (craftName) { %># Craft Name: <%= craftName %> -<% } %> - -defaults nosave - -batch start - -defaults nosave - -<%# Flight Controller Configuration Blocks %> -<% if (fcKey === 'FLASHHOBBYF405') { %> -set pid_process_denom = 2 -<% } %> - -<% if (fcKey === 'SPEEDYBEEF405V3') { %> -set pid_process_denom = 1 -<% } %> - -<% if (fcKey === 'TAKERF722SE') { %> -set pid_process_denom = 1 -set cpu_overclock = ON -<% } %> - -<% if (fcKey === 'GEPRCF722') { %> -set pid_process_denom = 1 -set cpu_overclock = ON -<% } %> - -<%# Drone Size Configuration Block %> -<%# Motor settings optimized for different frame sizes %> -<% if (droneSize) { %> -# Drone Size: <%= droneSize %>" -<% if (droneSize === '7') { %> -set motor_pwm_rate = 32000 -set motor_poles = 12 -<% } else if (droneSize === '8') { %> -set motor_pwm_rate = 24000 -set motor_poles = 14 -<% } else if (droneSize === '9') { %> -set motor_pwm_rate = 24000 -set motor_poles = 16 -<% } else if (droneSize === '10') { %> -set motor_pwm_rate = 16000 -set motor_poles = 18 -<% } else if (droneSize === '13') { %> -set motor_pwm_rate = 12000 -set motor_poles = 20 -<% } else if (droneSize === '15') { %> -set motor_pwm_rate = 8000 -set motor_poles = 22 -<% } %> -<% } %> - -<%# Manticore System Configuration Blocks %> -<% if (manticoreKey === 'UART') { %> -# Manticore UART variant -# Configure UART ports for Manticore communication -set uart1_function = RX_SERIAL -set uart2_function = TELEMETRY -<% } %> - -<% if (manticoreKey === 'GPIO') { %> -# Manticore GPIO variant -# Configure GPIO pins for Manticore interface -set gpio_output = ON -set gpio_mode = ALTERNATE -<% } %> - -<%# Video Transmitter (VTX) Configuration Blocks %> -<% if (vtxKey === '5.8VTX') { %> -# 5.8GHz VTX settings -# Standard 5.8GHz video transmitter configuration -set vtx_band = A -set vtx_channel = 1 -set vtx_power = 25 -<% } %> - -<% if (vtxKey === '3.3VTX') { %> -# 3.3GHz VTX settings -# Long-range 3.3GHz video transmitter configuration -set vtx_band = B -set vtx_channel = 3 -set vtx_power = 100 -<% } %> - -<% if (vtxKey === 'OPTICA') { %> -# Optica VTX settings -# Digital video transmitter configuration -set vtx_band = O -set vtx_channel = 2 -set vtx_power = 50 -<% } %> - -<%# GPS Configuration Block %> -<% if (gpsEnabled) { %> -# GPS Enabled -# Enable GPS functionality with auto baudrate detection -feature GPS -set gps_baudrate = AUTO -<% } %> - -<%# Custom Craft Name Configuration Block %> -<% if (craftName) { %> -# Craft name -# Set custom identification name for the craft -set craft_name = <%= craftName %> -<% } %> - diff --git a/src/norn-configs/template.hbs b/src/norn-configs/template.hbs new file mode 100644 index 0000000000..e9d3937c11 --- /dev/null +++ b/src/norn-configs/template.hbs @@ -0,0 +1,117 @@ +{{#if fcKey}}# FC: {{fcKey}} +{{/if}}{{#if droneSize}}# Drone Size: {{droneSize}} +{{/if}}{{#if manticoreKey}}# Manticore: {{manticoreKey}} +{{/if}}{{#if vtxKey}}# VTX: {{vtxKey}} +{{/if}}{{#if gpsEnabled}}# GPS: {{gpsEnabled}} +{{/if}}{{#if craftName}}# Craft Name: {{craftName}} +{{/if}} + +defaults nosave + +batch start + +defaults nosave + +{{!-- Flight Controller Configuration Blocks --}} +{{#if (eq fcKey 'FLASHHOBBYF405')}} +set pid_process_denom = 2 +{{/if}} + +{{#if (eq fcKey 'SPEEDYBEEF405V3')}} +set pid_process_denom = 1 +{{/if}} + +{{#if (eq fcKey 'TAKERF722SE')}} +set pid_process_denom = 1 +set cpu_overclock = ON +{{/if}} + +{{#if (eq fcKey 'GEPRCF722')}} +set pid_process_denom = 1 +set cpu_overclock = ON +{{/if}} + +{{!-- Drone Size Configuration Block --}} +{{!-- Motor settings optimized for different frame sizes --}} +{{#if droneSize}} +# Drone Size: {{droneSize}}" +{{#if (eq droneSize '7')}} +set motor_pwm_rate = 32000 +set motor_poles = 12 +{{/if}} +{{#if (eq droneSize '8')}} +set motor_pwm_rate = 24000 +set motor_poles = 14 +{{/if}} +{{#if (eq droneSize '9')}} +set motor_pwm_rate = 24000 +set motor_poles = 16 +{{/if}} +{{#if (eq droneSize '10')}} +set motor_pwm_rate = 16000 +set motor_poles = 18 +{{/if}} +{{#if (eq droneSize '13')}} +set motor_pwm_rate = 12000 +set motor_poles = 20 +{{/if}} +{{#if (eq droneSize '15')}} +set motor_pwm_rate = 8000 +set motor_poles = 22 +{{/if}} +{{/if}} + +{{!-- Manticore System Configuration Blocks --}} +{{#if (eq manticoreKey 'UART')}} +# Manticore UART variant +# Configure UART ports for Manticore communication +set uart1_function = RX_SERIAL +set uart2_function = TELEMETRY +{{/if}} + +{{#if (eq manticoreKey 'GPIO')}} +# Manticore GPIO variant +# Configure GPIO pins for Manticore interface +set gpio_output = ON +set gpio_mode = ALTERNATE +{{/if}} + +{{!-- Video Transmitter (VTX) Configuration Blocks --}} +{{#if (eq vtxKey '5.8VTX')}} +# 5.8GHz VTX settings +# Standard 5.8GHz video transmitter configuration +set vtx_band = A +set vtx_channel = 1 +set vtx_power = 25 +{{/if}} + +{{#if (eq vtxKey '3.3VTX')}} +# 3.3GHz VTX settings +# Long-range 3.3GHz video transmitter configuration +set vtx_band = B +set vtx_channel = 3 +set vtx_power = 100 +{{/if}} + +{{#if (eq vtxKey 'OPTICA')}} +# Optica VTX settings +# Digital video transmitter configuration +set vtx_band = O +set vtx_channel = 2 +set vtx_power = 50 +{{/if}} + +{{!-- GPS Configuration Block --}} +{{#if gpsEnabled}} +# GPS Enabled +# Enable GPS functionality with auto baudrate detection +feature GPS +set gps_baudrate = AUTO +{{/if}} + +{{!-- Custom Craft Name Configuration Block --}} +{{#if craftName}} +# Craft name +# Set custom identification name for the craft +set craft_name = {{craftName}} +{{/if}} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 3c9b08bc05..27d1f51072 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5941,6 +5941,18 @@ gulplog@^1.0.0: dependencies: glogg "^1.0.0" +handlebars@^4.7.8: + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.2" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -7588,7 +7600,7 @@ minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -minimist@^1.1.0, minimist@^1.2.6: +minimist@^1.1.0, minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -7760,6 +7772,11 @@ needle@^3.1.0: iconv-lite "^0.6.3" sax "^1.2.4" +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + next-tick@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" @@ -10324,6 +10341,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== +uglify-js@^3.1.4: + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== + unbox-primitive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" @@ -10911,6 +10933,11 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + workbox-background-sync@7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-7.3.0.tgz#b6340731a8d5b42b9e75a8a87c8806928e6e6303" From 4d63c86e7a9a1f35e69cf790af79ab83c5c113e2 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Mon, 6 Oct 2025 16:17:18 +0300 Subject: [PATCH 08/14] commit --- locales/en/messages.json | 3 + src/js/tabs/norn_config.js | 34 +++++++- src/norn-configs/README.txt | 45 +++++----- src/norn-configs/template.hbs | 151 +++++++++++----------------------- src/tabs/norn_config.html | 18 ++++ 5 files changed, 129 insertions(+), 122 deletions(-) diff --git a/locales/en/messages.json b/locales/en/messages.json index 9970eab536..08cf57dd5a 100755 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -398,6 +398,9 @@ "nornCraftName": { "message": "Craft Name" }, + "nornMBId": { + "message": "MB ID" + }, "nornGPS": { "message": "GPS" }, diff --git a/src/js/tabs/norn_config.js b/src/js/tabs/norn_config.js index 9115ba88c7..70f446b976 100644 --- a/src/js/tabs/norn_config.js +++ b/src/js/tabs/norn_config.js @@ -11,6 +11,29 @@ Handlebars.registerHelper("eq", function (a, b) { return a === b; }); +Handlebars.registerHelper("ne", function (a, b) { + return a !== b; +}); + +Handlebars.registerHelper("and", function (a, b) { + return a && b; +}); + +Handlebars.registerHelper("or", function (a, b) { + return a || b; +}); + +Handlebars.registerHelper("not", function (a) { + return !a; +}); + +Handlebars.registerHelper("elseif", function (condition, options) { + if (condition) { + return options.fn(this); + } + return options.inverse(this); +}); + // Discover config sources (text-based) const templateFiles = import.meta.glob("../../norn-configs/template.hbs", { eager: true, as: "raw" }); @@ -107,6 +130,12 @@ norn_config.initialize = function (callback) { craftNameInput.on("input", function () { self.analyticsChanges["NornCraftName"] = $(this).val() || null; }); + + // MB ID input wiring + const mbIdInput = $("#norn_mb_id"); + mbIdInput.on("input", function () { + self.analyticsChanges["NornMBId"] = $(this).val() || null; + }); } function on_tab_loaded_handler() { @@ -143,7 +172,8 @@ norn_config.initialize = function (callback) { const vtxKey = $("select[name='norn_vtx']").val() || ""; const gpsEnabled = $("#norn_gps").is(":checked"); const craftName = $("#norn_craft_name").val() || ""; - return { fcKey, droneSize, manticoreKey, vtxKey, gpsEnabled, craftName }; + const mbId = $("#norn_mb_id").val() || ""; + return { fcKey, droneSize, manticoreKey, vtxKey, gpsEnabled, craftName, mbId }; } function on_generate_handler(e) { @@ -198,6 +228,7 @@ norn_config.initialize = function (callback) { const vtxKey = $("select[name='norn_vtx']").val(); const gpsEnabled = $("#norn_gps").is(":checked"); const craftName = $("#norn_craft_name").val(); + const mbId = $("#norn_mb_id").val(); if (fcKey) parts.push(fcKey); if (droneSize) parts.push(`${droneSize}inch`); @@ -205,6 +236,7 @@ norn_config.initialize = function (callback) { if (vtxKey) parts.push(vtxKey); if (gpsEnabled) parts.push("GPS"); if (craftName) parts.push(craftName); + if (mbId) parts.push(`MB${mbId}`); const filename = parts.length > 0 ? `norn_config_${parts.join("_")}.txt` : "norn_config.txt"; diff --git a/src/norn-configs/README.txt b/src/norn-configs/README.txt index 82d48e876c..52dfe0fbfd 100644 --- a/src/norn-configs/README.txt +++ b/src/norn-configs/README.txt @@ -6,9 +6,10 @@ # # fcKey: Flight Controller type (from select[name='norn_fc']) # - '': Empty/None selected -# - 'f4': FLASHHOBBYF405 (F4 chip) -# - 'f7': SPEEDYBEEF405V3 (F7 chip) -# - 'h7': TAKERF722SE or GEPRCF722 (H7 chip) - Note: both use same value +# - 'FLASHHOBBYF405': FLASHHOBBYF405 (F4 chip) +# - 'SPEEDYBEEF405V3': SPEEDYBEEF405V3 (F7 chip) +# - 'TAKERF722SE': TAKERF722SE (H7 chip) +# - 'GEPRCF722': GEPRCF722 (H7 chip) # # droneSize: Drone frame size in inches (from select[name='norn_drone_size']) # - '': Empty/None selected @@ -21,14 +22,14 @@ # # manticoreKey: Manticore system configuration (from select[name='norn_manticore']) # - '': Empty/None selected -# - 'uart': UART-based Manticore setup -# - 'gpio': GPIO-based Manticore setup +# - 'UART': UART-based Manticore setup +# - 'GPIO': GPIO-based Manticore setup # # vtxKey: Video Transmitter configuration (from select[name='norn_vtx']) # - '': Empty/None selected -# - '3.3_vtx': 3.3GHz VTX setup -# - '5.8_vtx': 5.8GHz VTX setup -# - 'optica': Optica VTX setup +# - '3.3VTX': 3.3GHz VTX setup +# - '5.8VTX': 5.8GHz VTX setup +# - 'OPTICA': Optica VTX setup # # gpsEnabled: Boolean flag for GPS functionality (from #norn_gps checkbox) # - true: Enable GPS features @@ -38,20 +39,26 @@ # - '': Empty string if no name entered # - Any string value for craft identification # -# Template Syntax: -# - <% if (condition) { %> ... <% } %> : Conditional blocks -# - <%= variable %> : Output variable value -# - <%# comment %> : Template comments (not included in output) +# mbId: MB ID identifier (from #norn_mb_id input) +# - '': Empty string if no MB ID entered +# - Any string value for MB identification +# +# Template Syntax (Handlebars): +# - {{#if condition}} ... {{/if}} : Conditional blocks +# - {{variable}} : Output variable value +# - {{!-- comment --}} : Template comments (not included in output) +# - {{#if (eq variable 'value')}} : Equality comparison with helper # # Example usage in conditional blocks: -# <% if (fcKey === 'f4') { %> -# # This section applies only to F4 flight controllers -# <% } %> +# {{#if (eq fcKey 'FLASHHOBBYF405')}} +# # This section applies only to FLASHHOBBYF405 flight controllers +# {{/if}} # -# <% if (droneSize === '7') { %> -# # This section applies only to 7-inch drones -# <% } %> +# {{#if droneSize}} +# # This section applies only when drone size is selected +# {{/if}} # # Note: All select elements have an empty option for "None" selection # Checkbox elements return boolean values (true/false) -# Input elements return string values (may be empty string) \ No newline at end of file +# Input elements return string values (may be empty string) +# The 'eq' helper is registered for equality comparisons in Handlebars \ No newline at end of file diff --git a/src/norn-configs/template.hbs b/src/norn-configs/template.hbs index e9d3937c11..f578a41512 100644 --- a/src/norn-configs/template.hbs +++ b/src/norn-configs/template.hbs @@ -1,117 +1,64 @@ -{{#if fcKey}}# FC: {{fcKey}} -{{/if}}{{#if droneSize}}# Drone Size: {{droneSize}} -{{/if}}{{#if manticoreKey}}# Manticore: {{manticoreKey}} -{{/if}}{{#if vtxKey}}# VTX: {{vtxKey}} -{{/if}}{{#if gpsEnabled}}# GPS: {{gpsEnabled}} -{{/if}}{{#if craftName}}# Craft Name: {{craftName}} -{{/if}} +# FC: {{fcKey}} +# Drone Size: {{droneSize}} +# Manticore: {{manticoreKey}} +# Video: {{vtxKey}} +# GPS: {{gpsEnabled}} +# Craft Name: {{craftName}} +# MB ID: {{mbId}} defaults nosave - batch start - defaults nosave -{{!-- Flight Controller Configuration Blocks --}} -{{#if (eq fcKey 'FLASHHOBBYF405')}} -set pid_process_denom = 2 -{{/if}} - -{{#if (eq fcKey 'SPEEDYBEEF405V3')}} -set pid_process_denom = 1 -{{/if}} - -{{#if (eq fcKey 'TAKERF722SE')}} -set pid_process_denom = 1 -set cpu_overclock = ON +{{!-- GPIO Configuration --}} +{{#if (eq manticoreKey 'GPIO')}} +# RESOURCES CONFIGURATION + {{!-- FLASHHOBBYF405 specific GPIO resources --}} + {{#if (eq fcKey 'FLASHHOBBYF405')}} +resource PINIO 1 A01 +resource PINIO 2 A00 + {{/if}} + {{!-- TAKERF722SE specific GPIO resources --}} + {{#if (eq fcKey 'TAKERF722SE')}} +resource PINIO 1 A03 +resource PINIO 3 A02 + {{/if}} + {{!-- Common GPIO configuration for ALL GPIO setups --}} +set pinio_config = 1,1,1,1 +set pinio_box = 58,255,59,255 {{/if}} -{{#if (eq fcKey 'GEPRCF722')}} -set pid_process_denom = 1 -set cpu_overclock = ON +# FEATURES CONFIGURATION +{{!-- Common features for all configurations --}} +feature TELEMETRY +feature OSD +{{!-- GPS feature --}} +{{#if gpsEnabled}} +feature GPS {{/if}} -{{!-- Drone Size Configuration Block --}} -{{!-- Motor settings optimized for different frame sizes --}} -{{#if droneSize}} -# Drone Size: {{droneSize}}" -{{#if (eq droneSize '7')}} -set motor_pwm_rate = 32000 -set motor_poles = 12 -{{/if}} -{{#if (eq droneSize '8')}} -set motor_pwm_rate = 24000 -set motor_poles = 14 -{{/if}} -{{#if (eq droneSize '9')}} -set motor_pwm_rate = 24000 -set motor_poles = 16 -{{/if}} -{{#if (eq droneSize '10')}} -set motor_pwm_rate = 16000 -set motor_poles = 18 -{{/if}} -{{#if (eq droneSize '13')}} -set motor_pwm_rate = 12000 -set motor_poles = 20 +# PORTS CONFIGURATION +{{#if (ne vtxKey 'OPTICA')}} +serial UART1 8192 115200 57600 0 115200 {{/if}} -{{#if (eq droneSize '15')}} -set motor_pwm_rate = 8000 -set motor_poles = 22 -{{/if}} -{{/if}} - -{{!-- Manticore System Configuration Blocks --}} +{{!-- Manticore UART Configuration --}} {{#if (eq manticoreKey 'UART')}} -# Manticore UART variant -# Configure UART ports for Manticore communication -set uart1_function = RX_SERIAL -set uart2_function = TELEMETRY + {{#if (eq fcKey 'FLASHHOBBYF405')}} +serial UART4 4194304 115200 57600 0 115200 + {{else}} +serial UART2 4194304 115200 57600 0 115200 + {{/if}} {{/if}} - +{{!-- Manticore GPIO Configuration --}} {{#if (eq manticoreKey 'GPIO')}} -# Manticore GPIO variant -# Configure GPIO pins for Manticore interface -set gpio_output = ON -set gpio_mode = ALTERNATE -{{/if}} - -{{!-- Video Transmitter (VTX) Configuration Blocks --}} -{{#if (eq vtxKey '5.8VTX')}} -# 5.8GHz VTX settings -# Standard 5.8GHz video transmitter configuration -set vtx_band = A -set vtx_channel = 1 -set vtx_power = 25 -{{/if}} - -{{#if (eq vtxKey '3.3VTX')}} -# 3.3GHz VTX settings -# Long-range 3.3GHz video transmitter configuration -set vtx_band = B -set vtx_channel = 3 -set vtx_power = 100 -{{/if}} - -{{#if (eq vtxKey 'OPTICA')}} -# Optica VTX settings -# Digital video transmitter configuration -set vtx_band = O -set vtx_channel = 2 -set vtx_power = 50 -{{/if}} - -{{!-- GPS Configuration Block --}} + {{#if (eq fcKey 'FLASHHOBBYF405')}} +serial UART4 2097152 115200 57600 0 115200 + {{else}} +serial UART2 2097152 115200 57600 0 115200 + {{/if}} +{{/if}} +serial UART5 64 115200 57600 0 115200 +{{!-- GPS Configuration --}} {{#if gpsEnabled}} -# GPS Enabled -# Enable GPS functionality with auto baudrate detection -feature GPS -set gps_baudrate = AUTO +serial UART6 2 115200 57600 0 115200 {{/if}} - -{{!-- Custom Craft Name Configuration Block --}} -{{#if craftName}} -# Craft name -# Set custom identification name for the craft -set craft_name = {{craftName}} -{{/if}} \ No newline at end of file diff --git a/src/tabs/norn_config.html b/src/tabs/norn_config.html index 7deb3b499e..86dc9d9560 100644 --- a/src/tabs/norn_config.html +++ b/src/tabs/norn_config.html @@ -99,6 +99,24 @@
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    From 796ac22190b56375115ec66fd957e383b62c915b Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Mon, 6 Oct 2025 16:50:22 +0300 Subject: [PATCH 09/14] commit --- locales/en/messages.json | 6 +++ src/js/tabs/norn_config.js | 31 +++++++++++++++- src/norn-configs/README.txt | 9 +++++ src/norn-configs/template.hbs | 69 +++++++++++++++++++++++++++++++++++ src/tabs/norn_config.html | 31 ++++++++++++++++ 5 files changed, 145 insertions(+), 1 deletion(-) diff --git a/locales/en/messages.json b/locales/en/messages.json index 08cf57dd5a..193ac1792a 100755 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -392,6 +392,9 @@ "nornController": { "message": "Controller" }, + "nornRadioController": { + "message": "Radio Controller" + }, "nornSize": { "message": "Size" }, @@ -401,6 +404,9 @@ "nornMBId": { "message": "MB ID" }, + "nornFailSafe": { + "message": "FailSafe" + }, "nornGPS": { "message": "GPS" }, diff --git a/src/js/tabs/norn_config.js b/src/js/tabs/norn_config.js index 70f446b976..d41f192593 100644 --- a/src/js/tabs/norn_config.js +++ b/src/js/tabs/norn_config.js @@ -136,6 +136,29 @@ norn_config.initialize = function (callback) { mbIdInput.on("input", function () { self.analyticsChanges["NornMBId"] = $(this).val() || null; }); + + // Populate Controller list (explicit options) + const controllerSelect = $("select[name='norn_controller']"); + if (controllerSelect.length) { + controllerSelect.empty(); + controllerSelect.append(``); + controllerSelect.append(``); + controllerSelect.append(``); + controllerSelect.on("change", function () { + self.analyticsChanges["NornController"] = $(this).val() || null; + }); + } + + // Populate FailSafe list (explicit options) + const failSafeSelect = $("select[name='norn_failsafe']"); + if (failSafeSelect.length) { + failSafeSelect.empty(); + failSafeSelect.append(``); + failSafeSelect.append(``); + failSafeSelect.on("change", function () { + self.analyticsChanges["NornFailSafe"] = $(this).val() || null; + }); + } } function on_tab_loaded_handler() { @@ -173,7 +196,9 @@ norn_config.initialize = function (callback) { const gpsEnabled = $("#norn_gps").is(":checked"); const craftName = $("#norn_craft_name").val() || ""; const mbId = $("#norn_mb_id").val() || ""; - return { fcKey, droneSize, manticoreKey, vtxKey, gpsEnabled, craftName, mbId }; + const controller = $("select[name='norn_controller']").val() || ""; + const failSafe = $("select[name='norn_failsafe']").val() || ""; + return { fcKey, droneSize, manticoreKey, vtxKey, gpsEnabled, craftName, mbId, controller, failSafe }; } function on_generate_handler(e) { @@ -229,6 +254,8 @@ norn_config.initialize = function (callback) { const gpsEnabled = $("#norn_gps").is(":checked"); const craftName = $("#norn_craft_name").val(); const mbId = $("#norn_mb_id").val(); + const controller = $("select[name='norn_controller']").val(); + const failSafe = $("select[name='norn_failsafe']").val(); if (fcKey) parts.push(fcKey); if (droneSize) parts.push(`${droneSize}inch`); @@ -237,6 +264,8 @@ norn_config.initialize = function (callback) { if (gpsEnabled) parts.push("GPS"); if (craftName) parts.push(craftName); if (mbId) parts.push(`MB${mbId}`); + if (controller) parts.push(controller); + if (failSafe) parts.push(failSafe); const filename = parts.length > 0 ? `norn_config_${parts.join("_")}.txt` : "norn_config.txt"; diff --git a/src/norn-configs/README.txt b/src/norn-configs/README.txt index 52dfe0fbfd..bfbb658a2a 100644 --- a/src/norn-configs/README.txt +++ b/src/norn-configs/README.txt @@ -43,6 +43,15 @@ # - '': Empty string if no MB ID entered # - Any string value for MB identification # +# controller: Controller type (from select[name='norn_controller']) +# - '': Empty/None selected +# - 'BOXER': BOXER controller +# - 'TX12': TX12 controller +# +# failSafe: FailSafe configuration (from select[name='norn_failsafe']) +# - '': Empty/None selected +# - 'Default': Default failSafe configuration +# # Template Syntax (Handlebars): # - {{#if condition}} ... {{/if}} : Conditional blocks # - {{variable}} : Output variable value diff --git a/src/norn-configs/template.hbs b/src/norn-configs/template.hbs index f578a41512..981b4582b8 100644 --- a/src/norn-configs/template.hbs +++ b/src/norn-configs/template.hbs @@ -5,6 +5,8 @@ # GPS: {{gpsEnabled}} # Craft Name: {{craftName}} # MB ID: {{mbId}} +# Controller: {{controller}} +# FailSafe: {{failSafe}} defaults nosave batch start @@ -62,3 +64,70 @@ serial UART5 64 115200 57600 0 115200 {{#if gpsEnabled}} serial UART6 2 115200 57600 0 115200 {{/if}} + +# AUX CONFIGURATION +{{!-- TX12 Controller AUX Configuration --}} +{{#if (eq controller 'TX12')}} +aux 0 0 0 1800 2100 0 0 +aux 1 1 1 1400 2100 0 0 +aux 2 40 2 1400 2100 0 0 +aux 3 41 2 1800 2100 0 0 +{{/if}} +{{!-- Default AUX Configuration (for BOXER or no controller selected) --}} +{{#if (ne controller 'TX12')}} +aux 0 0 0 1800 2100 0 0 +aux 1 1 1 1700 2100 0 0 +aux 2 2 1 1300 1700 0 0 +aux 3 26 3 1675 2100 0 0 +aux 4 58 4 1800 2100 0 0 +aux 5 59 5 1800 2100 0 0 +{{/if}} + +# VTX CONFIGURATION +{{!-- 5.8GHz VTX Configuration --}} +{{#if (eq vtxKey '5.8VTX')}} +vtxtable bands 8 +vtxtable channels 8 +vtxtable band 1 BAND_A A CUSTOM 5865 5845 5825 5805 5785 5765 5745 5725 +vtxtable band 2 BAND_B B CUSTOM 5733 5752 5771 5790 5809 5828 5847 5866 +vtxtable band 3 BAND_E E CUSTOM 5705 5685 5665 5645 5885 5905 5925 5945 +vtxtable band 4 BAND_F F CUSTOM 5740 5760 5780 5800 5820 5840 5860 5880 +vtxtable band 5 BAND_R R CUSTOM 5658 5695 5732 5769 5806 5843 5880 5917 +vtxtable band 6 BAND_L L CUSTOM 5917 5800 5645 5493 5333 5200 5050 4990 +vtxtable band 7 BAND_X X CUSTOM 4990 5020 5050 5080 5110 5140 5170 5200 +vtxtable band 8 BAND_C C CUSTOM 4990 5020 5050 5080 5110 5140 5170 5200 +vtxtable powerlevels 5 +vtxtable powervalues 25 100 200 400 600 +vtxtable powerlabels 25 200 500 1.5 2.5 +{{/if}} +{{!-- 3.3GHz VTX Configuration --}} +{{#if (eq vtxKey '3.3VTX')}} +vtxtable bands 5 +vtxtable channels 8 +vtxtable band 1 BAND_A A CUSTOM 3320 3345 3370 3395 3420 3445 3470 3495 +vtxtable band 2 BAND_B B CUSTOM 3310 3330 3355 3380 3405 3430 3455 3480 +vtxtable band 3 BAND_C C CUSTOM 3490 3510 3530 3550 3570 3590 3610 3630 +vtxtable band 4 BAND_D D CUSTOM 3330 3350 3370 3390 3410 3430 3450 3470 +vtxtable band 5 BAND_E E CUSTOM 3170 3190 3210 3230 3250 3270 3290 3310 +vtxtable powerlevels 5 +vtxtable powervalues 25 100 200 400 600 +vtxtable powerlabels 250 500 1W 2W 4W +{{/if}} + +{{#if (eq failSafe 'Default')}} +# FAILSAFE CONFIGURATION +rxfail 0 s 1500 +rxfail 1 s 1500 +rxfail 2 s 1500 +rxfail 3 h +{{/if}} + +{{#if craftName}} +# CRAFT NAME CONFIGURATION +set craft_name = {{craftName}} +{{/if}} + +{{#if mbId}} +# MB CONFIGURATION +set mb_id = {{mbId}} +{{/if}} \ No newline at end of file diff --git a/src/tabs/norn_config.html b/src/tabs/norn_config.html index 86dc9d9560..df4cdd47da 100644 --- a/src/tabs/norn_config.html +++ b/src/tabs/norn_config.html @@ -112,6 +112,37 @@
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    From b076b0b4e95234592ae4f2118567077f8e93f8f9 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Mon, 6 Oct 2025 16:59:45 +0300 Subject: [PATCH 10/14] asda --- src/js/tabs/norn_config.js | 53 ++++++++++++++++++++++++++++++++++++++ src/tabs/norn_config.html | 9 +++++++ 2 files changed, 62 insertions(+) diff --git a/src/js/tabs/norn_config.js b/src/js/tabs/norn_config.js index d41f192593..ae68a04c34 100644 --- a/src/js/tabs/norn_config.js +++ b/src/js/tabs/norn_config.js @@ -67,6 +67,7 @@ norn_config.initialize = function (callback) { fcSelect.append(``); fcSelect.on("change", function () { self.analyticsChanges["NornFC"] = $(this).val() || null; + clearMandatoryFieldValidation(); }); } @@ -95,6 +96,7 @@ norn_config.initialize = function (callback) { manticoreSelect.append(``); manticoreSelect.on("change", function () { self.analyticsChanges["NornManticore"] = $(this).val() || null; + clearMandatoryFieldValidation(); }); } @@ -108,6 +110,7 @@ norn_config.initialize = function (callback) { vtxSelect.append(``); vtxSelect.on("change", function () { self.analyticsChanges["NornVtx"] = $(this).val() || null; + clearMandatoryFieldValidation(); }); } @@ -146,6 +149,7 @@ norn_config.initialize = function (callback) { controllerSelect.append(``); controllerSelect.on("change", function () { self.analyticsChanges["NornController"] = $(this).val() || null; + clearMandatoryFieldValidation(); }); } @@ -201,9 +205,58 @@ norn_config.initialize = function (callback) { return { fcKey, droneSize, manticoreKey, vtxKey, gpsEnabled, craftName, mbId, controller, failSafe }; } + function updateMandatoryFieldValidation() { + // Clear previous validation + clearMandatoryFieldValidation(); + + // Check mandatory fields and highlight missing ones + const mandatoryFields = [ + { selector: "select[name='norn_fc']", label: "Flight Controller" }, + { selector: "select[name='norn_manticore']", label: "Manticore" }, + { selector: "select[name='norn_vtx']", label: "VTX" }, + { selector: "select[name='norn_controller']", label: "Radio Controller" }, + ]; + + mandatoryFields.forEach((field) => { + const element = $(field.selector); + if (!element.val()) { + element.closest(".gui_box").addClass("mandatory-missing"); + element.addClass("mandatory-missing"); + } + }); + } + + function clearMandatoryFieldValidation() { + // Remove validation highlighting + $(".gui_box").removeClass("mandatory-missing"); + $("select, input").removeClass("mandatory-missing"); + } + function on_generate_handler(e) { e?.preventDefault?.(); + // Validate mandatory fields + const fcKey = $("select[name='norn_fc']").val(); + const manticoreKey = $("select[name='norn_manticore']").val(); + const vtxKey = $("select[name='norn_vtx']").val(); + const controller = $("select[name='norn_controller']").val(); + + const missingFields = []; + if (!fcKey) missingFields.push("Flight Controller"); + if (!manticoreKey) missingFields.push("Manticore"); + if (!vtxKey) missingFields.push("VTX"); + if (!controller) missingFields.push("Radio Controller"); + + if (missingFields.length > 0) { + // Highlight missing mandatory fields + updateMandatoryFieldValidation(); + alert(`Please select the following mandatory fields:\n${missingFields.join(", ")}`); + return; + } + + // Clear any validation highlighting + clearMandatoryFieldValidation(); + const templatePath = Object.keys(templateFiles)[0]; let result; if (templatePath) { diff --git a/src/tabs/norn_config.html b/src/tabs/norn_config.html index df4cdd47da..4339109e0d 100644 --- a/src/tabs/norn_config.html +++ b/src/tabs/norn_config.html @@ -1,4 +1,13 @@
    +
    From 6021e0032a62f5f24212d9eb65d1e315421c68d9 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Tue, 7 Oct 2025 13:56:49 +0300 Subject: [PATCH 11/14] commit --- locales/en/messages.json | 6 +++ src/js/tabs/norn_config.js | 45 ++++++++++++++++-- src/norn-configs/README.txt | 5 ++ src/norn-configs/template.hbs | 90 +++++++++++++++++++++++++++++++---- src/tabs/norn_config.html | 58 ++++++++++++++-------- 5 files changed, 172 insertions(+), 32 deletions(-) diff --git a/locales/en/messages.json b/locales/en/messages.json index 193ac1792a..0e176895f1 100755 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -407,6 +407,12 @@ "nornFailSafe": { "message": "FailSafe" }, + "nornVideoFormat": { + "message": "Video Format" + }, + "nornCamera": { + "message": "Camera" + }, "nornGPS": { "message": "GPS" }, diff --git a/src/js/tabs/norn_config.js b/src/js/tabs/norn_config.js index ae68a04c34..d9e084425e 100644 --- a/src/js/tabs/norn_config.js +++ b/src/js/tabs/norn_config.js @@ -163,6 +163,19 @@ norn_config.initialize = function (callback) { self.analyticsChanges["NornFailSafe"] = $(this).val() || null; }); } + + // Populate Video Format list (explicit options) + const videoFormatSelect = $("select[name='norn_video_format']"); + if (videoFormatSelect.length) { + videoFormatSelect.empty(); + videoFormatSelect.append(``); + videoFormatSelect.append(``); + videoFormatSelect.append(``); + videoFormatSelect.on("change", function () { + self.analyticsChanges["NornVideoFormat"] = $(this).val() || null; + clearMandatoryFieldValidation(); + }); + } } function on_tab_loaded_handler() { @@ -202,7 +215,19 @@ norn_config.initialize = function (callback) { const mbId = $("#norn_mb_id").val() || ""; const controller = $("select[name='norn_controller']").val() || ""; const failSafe = $("select[name='norn_failsafe']").val() || ""; - return { fcKey, droneSize, manticoreKey, vtxKey, gpsEnabled, craftName, mbId, controller, failSafe }; + const videoFormat = $("select[name='norn_video_format']").val() || ""; + return { + fcKey, + droneSize, + manticoreKey, + vtxKey, + gpsEnabled, + craftName, + mbId, + controller, + failSafe, + videoFormat, + }; } function updateMandatoryFieldValidation() { @@ -214,13 +239,22 @@ norn_config.initialize = function (callback) { { selector: "select[name='norn_fc']", label: "Flight Controller" }, { selector: "select[name='norn_manticore']", label: "Manticore" }, { selector: "select[name='norn_vtx']", label: "VTX" }, + { selector: "select[name='norn_video_format']", label: "Video Format" }, { selector: "select[name='norn_controller']", label: "Radio Controller" }, ]; mandatoryFields.forEach((field) => { const element = $(field.selector); if (!element.val()) { - element.closest(".gui_box").addClass("mandatory-missing"); + // For Camera section dropdowns, highlight the entire Camera section + if ( + field.selector === "select[name='norn_vtx']" || + field.selector === "select[name='norn_video_format']" + ) { + element.closest(".gui_box").addClass("mandatory-missing"); + } else { + element.closest(".gui_box").addClass("mandatory-missing"); + } element.addClass("mandatory-missing"); } }); @@ -229,6 +263,7 @@ norn_config.initialize = function (callback) { function clearMandatoryFieldValidation() { // Remove validation highlighting $(".gui_box").removeClass("mandatory-missing"); + $(".select").removeClass("mandatory-missing"); $("select, input").removeClass("mandatory-missing"); } @@ -239,18 +274,20 @@ norn_config.initialize = function (callback) { const fcKey = $("select[name='norn_fc']").val(); const manticoreKey = $("select[name='norn_manticore']").val(); const vtxKey = $("select[name='norn_vtx']").val(); + const videoFormat = $("select[name='norn_video_format']").val(); const controller = $("select[name='norn_controller']").val(); const missingFields = []; if (!fcKey) missingFields.push("Flight Controller"); if (!manticoreKey) missingFields.push("Manticore"); if (!vtxKey) missingFields.push("VTX"); + if (!videoFormat) missingFields.push("Video Format"); if (!controller) missingFields.push("Radio Controller"); if (missingFields.length > 0) { // Highlight missing mandatory fields updateMandatoryFieldValidation(); - alert(`Please select the following mandatory fields:\n${missingFields.join(", ")}`); + // alert(`Please select the following mandatory fields:\n${missingFields.join(", ")}`); return; } @@ -309,6 +346,7 @@ norn_config.initialize = function (callback) { const mbId = $("#norn_mb_id").val(); const controller = $("select[name='norn_controller']").val(); const failSafe = $("select[name='norn_failsafe']").val(); + const videoFormat = $("select[name='norn_video_format']").val(); if (fcKey) parts.push(fcKey); if (droneSize) parts.push(`${droneSize}inch`); @@ -319,6 +357,7 @@ norn_config.initialize = function (callback) { if (mbId) parts.push(`MB${mbId}`); if (controller) parts.push(controller); if (failSafe) parts.push(failSafe); + if (videoFormat) parts.push(videoFormat); const filename = parts.length > 0 ? `norn_config_${parts.join("_")}.txt` : "norn_config.txt"; diff --git a/src/norn-configs/README.txt b/src/norn-configs/README.txt index bfbb658a2a..180addd128 100644 --- a/src/norn-configs/README.txt +++ b/src/norn-configs/README.txt @@ -52,6 +52,11 @@ # - '': Empty/None selected # - 'Default': Default failSafe configuration # +# videoFormat: Video format (from select[name='norn_video_format']) +# - '': Empty/None selected +# - 'NTSC': NTSC video format +# - 'PAL': PAL video format +# # Template Syntax (Handlebars): # - {{#if condition}} ... {{/if}} : Conditional blocks # - {{variable}} : Output variable value diff --git a/src/norn-configs/template.hbs b/src/norn-configs/template.hbs index 981b4582b8..dcd272ea75 100644 --- a/src/norn-configs/template.hbs +++ b/src/norn-configs/template.hbs @@ -1,7 +1,8 @@ # FC: {{fcKey}} # Drone Size: {{droneSize}} # Manticore: {{manticoreKey}} -# Video: {{vtxKey}} +# VTX: {{vtxKey}} +# Video Format: {{videoFormat}} # GPS: {{gpsEnabled}} # Craft Name: {{craftName}} # MB ID: {{mbId}} @@ -78,14 +79,15 @@ aux 3 41 2 1800 2100 0 0 aux 0 0 0 1800 2100 0 0 aux 1 1 1 1700 2100 0 0 aux 2 2 1 1300 1700 0 0 -aux 3 26 3 1675 2100 0 0 aux 4 58 4 1800 2100 0 0 aux 5 59 5 1800 2100 0 0 {{/if}} -# VTX CONFIGURATION -{{!-- 5.8GHz VTX Configuration --}} -{{#if (eq vtxKey '5.8VTX')}} +# CAMERA/VTX CONFIGURATION +{{!-- Camera Configuration for all VTX types and video formats --}} +{{#if vtxKey}} + {{!-- 5.8GHz VTX Configuration --}} + {{#if (eq vtxKey '5.8VTX')}} vtxtable bands 8 vtxtable channels 8 vtxtable band 1 BAND_A A CUSTOM 5865 5845 5825 5805 5785 5765 5745 5725 @@ -99,9 +101,13 @@ vtxtable band 8 BAND_C C CUSTOM 4990 5020 5050 5080 5110 5140 5170 5200 vtxtable powerlevels 5 vtxtable powervalues 25 100 200 400 600 vtxtable powerlabels 25 200 500 1.5 2.5 -{{/if}} -{{!-- 3.3GHz VTX Configuration --}} -{{#if (eq vtxKey '3.3VTX')}} +set vtx_channel = 4 +set vtx_power = 4 +set vtx_low_power_disarm = ON +set vtx_freq = 5800 + {{/if}} + {{!-- 3.3GHz VTX Configuration --}} + {{#if (eq vtxKey '3.3VTX')}} vtxtable bands 5 vtxtable channels 8 vtxtable band 1 BAND_A A CUSTOM 3320 3345 3370 3395 3420 3445 3470 3495 @@ -112,6 +118,15 @@ vtxtable band 5 BAND_E E CUSTOM 3170 3190 3210 3230 3250 3270 3290 3310 vtxtable powerlevels 5 vtxtable powervalues 25 100 200 400 600 vtxtable powerlabels 250 500 1W 2W 4W +set vtx_channel = 1 +set vtx_power = 1 +set vtx_low_power_disarm = ON +set vtx_freq = 3320 + {{/if}} + {{!-- Video Format Configuration --}} + {{#if videoFormat}} +set vcd_video_system = {{videoFormat}} + {{/if}} {{/if}} {{#if (eq failSafe 'Default')}} @@ -120,6 +135,10 @@ rxfail 0 s 1500 rxfail 1 s 1500 rxfail 2 s 1500 rxfail 3 h +set failsafe_delay = 10 +set failsafe_landing_time = 200 +set failsafe_throttle = 1800 +set failsafe_procedure = AUTO-LAND {{/if}} {{#if craftName}} @@ -130,4 +149,59 @@ set craft_name = {{craftName}} {{#if mbId}} # MB CONFIGURATION set mb_id = {{mbId}} +{{/if}} + +# COMMON CONFIGURATION +set blackbox_disable_gps = ON +set dshot_bidir = ON +set motor_pwm_protocol = DSHOT300 +set vbat_min_cell_voltage = 280 +set vbat_warning_cell_voltage = 300 +set yaw_motors_reversed = ON + +# OSD CONFIGURATION +set osd_cap_alarm = 12000 +set osd_alt_alarm = 300 +set osd_vbat_pos = 257 +set osd_rssi_pos = 34 +set osd_link_quality_pos = 2101 +set osd_link_tx_power_pos = 128 +set osd_rssi_dbm_pos = 2133 +set osd_rsnr_pos = 2165 +set osd_tim_1_pos = 363 +set osd_tim_2_pos = 2455 +set osd_flymode_pos = 2082 +set osd_throttle_pos = 2273 +set osd_vtx_channel_pos = 18808 +set osd_crosshairs_pos = 2286 +set osd_ah_sbar_pos = 2287 +set osd_ah_pos = 2159 +set osd_current_pos = 2144 +set osd_mah_drawn_pos = 352 +set osd_craft_name_pos = 2433 +set osd_altitude_pos = 18681 +set osd_warnings_pos = 14666 +set osd_avg_cell_voltage_pos = 2113 +set osd_battery_usage_pos = 33122 +set osd_disarmed_pos = 298 +set osd_esc_rpm_pos = 56 +set osd_stick_overlay_left_pos = 321 +set osd_efficiency_pos = 228 +{{!-- Manticore OSD Configuration --}} +{{#if (eq manticoreKey 'GPIO')}} +set osd_manticore_initiator_v1_pos = 2090 +{{/if}} +{{#if (eq manticoreKey 'UART')}} +set osd_manticore_initiator_v2_pos = 2090 +{{/if}} +set osd_mb_stats_pos = 0 +{{!-- GPS OSD Configuration --}} +{{#if gpsEnabled}} +set osd_gps_speed_pos = 2337 +set osd_gps_lon_pos = 18827 +set osd_gps_lat_pos = 18795 +set osd_gps_sats_pos = 2209 +set osd_home_dir_pos = 2305 +set osd_home_dist_pos = 2306 +set osd_flight_dist_pos = 2241 {{/if}} \ No newline at end of file diff --git a/src/tabs/norn_config.html b/src/tabs/norn_config.html index 4339109e0d..5c435894fb 100644 --- a/src/tabs/norn_config.html +++ b/src/tabs/norn_config.html @@ -4,6 +4,7 @@ border: 2px solid #ff4444 !important; background-color: #ffe6e6 !important; } + .mandatory-missing select { border: 2px solid #ff4444 !important; } @@ -65,11 +66,11 @@
    -
    +
    -
    @@ -78,6 +79,36 @@
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    @@ -86,7 +117,8 @@
    - +
    @@ -109,7 +141,7 @@
    -
    +
    @@ -121,20 +153,6 @@
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    @@ -178,6 +196,4 @@
    -
    - - +
    \ No newline at end of file From c3b0d8afdf12d1371cd048dc602de448599e7b81 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Tue, 7 Oct 2025 14:20:52 +0300 Subject: [PATCH 12/14] Commit --- src/norn-configs/template.hbs | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/norn-configs/template.hbs b/src/norn-configs/template.hbs index dcd272ea75..a4e385e06e 100644 --- a/src/norn-configs/template.hbs +++ b/src/norn-configs/template.hbs @@ -71,8 +71,8 @@ serial UART6 2 115200 57600 0 115200 {{#if (eq controller 'TX12')}} aux 0 0 0 1800 2100 0 0 aux 1 1 1 1400 2100 0 0 -aux 2 40 2 1400 2100 0 0 -aux 3 41 2 1800 2100 0 0 +aux 2 58 2 1400 2100 0 0 +aux 3 59 2 1800 2100 0 0 {{/if}} {{!-- Default AUX Configuration (for BOXER or no controller selected) --}} {{#if (ne controller 'TX12')}} @@ -160,6 +160,7 @@ set vbat_warning_cell_voltage = 300 set yaw_motors_reversed = ON # OSD CONFIGURATION +{{!-- Common OSD settings for all video formats --}} set osd_cap_alarm = 12000 set osd_alt_alarm = 300 set osd_vbat_pos = 257 @@ -169,24 +170,34 @@ set osd_link_tx_power_pos = 128 set osd_rssi_dbm_pos = 2133 set osd_rsnr_pos = 2165 set osd_tim_1_pos = 363 -set osd_tim_2_pos = 2455 set osd_flymode_pos = 2082 set osd_throttle_pos = 2273 -set osd_vtx_channel_pos = 18808 set osd_crosshairs_pos = 2286 set osd_ah_sbar_pos = 2287 set osd_ah_pos = 2159 set osd_current_pos = 2144 set osd_mah_drawn_pos = 352 -set osd_craft_name_pos = 2433 -set osd_altitude_pos = 18681 -set osd_warnings_pos = 14666 +set osd_altitude_pos = 18681 set osd_avg_cell_voltage_pos = 2113 set osd_battery_usage_pos = 33122 set osd_disarmed_pos = 298 set osd_esc_rpm_pos = 56 set osd_stick_overlay_left_pos = 321 +{{!-- Video Format specific OSD positions --}} +{{#if (eq videoFormat 'PAL')}} +set osd_tim_2_pos = 2519 +set osd_vtx_channel_pos = 18872 +set osd_craft_name_pos = 2497 +set osd_warnings_pos = 14730 +set osd_efficiency_pos = 22 +{{/if}} +{{#if (eq videoFormat 'NTSC')}} +set osd_tim_2_pos = 2455 +set osd_vtx_channel_pos = 18808 +set osd_craft_name_pos = 2433 +set osd_warnings_pos = 14666 set osd_efficiency_pos = 228 +{{/if}} {{!-- Manticore OSD Configuration --}} {{#if (eq manticoreKey 'GPIO')}} set osd_manticore_initiator_v1_pos = 2090 @@ -198,10 +209,16 @@ set osd_mb_stats_pos = 0 {{!-- GPS OSD Configuration --}} {{#if gpsEnabled}} set osd_gps_speed_pos = 2337 -set osd_gps_lon_pos = 18827 -set osd_gps_lat_pos = 18795 set osd_gps_sats_pos = 2209 set osd_home_dir_pos = 2305 set osd_home_dist_pos = 2306 set osd_flight_dist_pos = 2241 +{{#if (eq videoFormat 'PAL')}} +set osd_gps_lon_pos = 18891 +set osd_gps_lat_pos = 18859 +{{/if}} +{{#if (eq videoFormat 'NTSC')}} +set osd_gps_lon_pos = 18827 +set osd_gps_lat_pos = 18795 +{{/if}} {{/if}} \ No newline at end of file From 5c3509e7aaaebae5fba2181610eb4f3dd44bb7e1 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Tue, 7 Oct 2025 17:07:16 +0300 Subject: [PATCH 13/14] commit --- src/js/tabs/norn_config.js | 5 +- src/norn-configs/template.hbs | 93 ++++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/js/tabs/norn_config.js b/src/js/tabs/norn_config.js index d9e084425e..90a070b4b5 100644 --- a/src/js/tabs/norn_config.js +++ b/src/js/tabs/norn_config.js @@ -81,9 +81,9 @@ norn_config.initialize = function (callback) { droneSizeSelect.append(``); droneSizeSelect.append(``); droneSizeSelect.append(``); - droneSizeSelect.append(``); droneSizeSelect.on("change", function () { self.analyticsChanges["NornDroneSize"] = $(this).val() || null; + clearMandatoryFieldValidation(); }); } @@ -237,6 +237,7 @@ norn_config.initialize = function (callback) { // Check mandatory fields and highlight missing ones const mandatoryFields = [ { selector: "select[name='norn_fc']", label: "Flight Controller" }, + { selector: "select[name='norn_drone_size']", label: "Drone Size" }, { selector: "select[name='norn_manticore']", label: "Manticore" }, { selector: "select[name='norn_vtx']", label: "VTX" }, { selector: "select[name='norn_video_format']", label: "Video Format" }, @@ -272,6 +273,7 @@ norn_config.initialize = function (callback) { // Validate mandatory fields const fcKey = $("select[name='norn_fc']").val(); + const droneSize = $("select[name='norn_drone_size']").val(); const manticoreKey = $("select[name='norn_manticore']").val(); const vtxKey = $("select[name='norn_vtx']").val(); const videoFormat = $("select[name='norn_video_format']").val(); @@ -279,6 +281,7 @@ norn_config.initialize = function (callback) { const missingFields = []; if (!fcKey) missingFields.push("Flight Controller"); + if (!droneSize) missingFields.push("Drone Size"); if (!manticoreKey) missingFields.push("Manticore"); if (!vtxKey) missingFields.push("VTX"); if (!videoFormat) missingFields.push("Video Format"); diff --git a/src/norn-configs/template.hbs b/src/norn-configs/template.hbs index a4e385e06e..6cdab0ed9e 100644 --- a/src/norn-configs/template.hbs +++ b/src/norn-configs/template.hbs @@ -221,4 +221,95 @@ set osd_gps_lat_pos = 18859 set osd_gps_lon_pos = 18827 set osd_gps_lat_pos = 18795 {{/if}} -{{/if}} \ No newline at end of file +{{/if}} + +# PROFILE CONFIGURATION +{{!-- Profile configuration for 7", 8", and 9" drones --}} +{{#if (or (eq droneSize '7') (eq droneSize '8') (eq droneSize '9'))}} +profile 0 + +set dterm_lpf1_dyn_min_hz = 60 +set dterm_lpf1_dyn_max_hz = 120 +set dterm_lpf1_static_hz = 60 +set dterm_lpf2_static_hz = 120 +set p_pitch = 38 +set i_pitch = 43 +set d_pitch = 29 +set f_pitch = 106 +set p_roll = 37 +set i_roll = 38 +set d_roll = 27 +set f_roll = 101 +set i_yaw = 44 +set f_yaw = 101 +set d_min_roll = 21 +set d_min_pitch = 23 +set auto_profile_cell_count = 6 +set thrust_linear = 20 +set simplified_pids_mode = OFF +set simplified_i_gain = 90 +set simplified_d_gain = 95 +set simplified_pi_gain = 55 +set simplified_dmax_gain = 10 +set simplified_feedforward_gain = 85 +set simplified_dterm_filter_multiplier = 80 +{{/if}} +{{!-- Profile configuration for 10" drones --}} +{{#if (eq droneSize '10')}} +profile 0 + +set dterm_lpf1_dyn_min_hz = 60 +set dterm_lpf1_dyn_max_hz = 120 +set dterm_lpf1_static_hz = 60 +set dterm_lpf2_static_hz = 120 +set simplified_dterm_filter_multiplier = 80 +{{/if}} +{{!-- Profile configuration for 13" drones --}} +{{#if (eq droneSize '13')}} +profile 0 + +set dterm_lpf1_dyn_min_hz = 60 +set dterm_lpf1_dyn_max_hz = 120 +set dterm_lpf1_static_hz = 60 +set dterm_lpf2_static_hz = 105 +set iterm_rotation = ON +set iterm_windup = 90 +set p_pitch = 56 +set i_pitch = 80 +set d_pitch = 47 +set f_pitch = 74 +set p_roll = 53 +set i_roll = 76 +set d_roll = 42 +set f_roll = 71 +set p_yaw = 50 +set i_yaw = 120 +set f_yaw = 70 +set d_max_roll = 44 +set d_max_pitch = 50 +set thrust_linear = 20 +set dyn_idle_min_rpm = 25 +set simplified_pids_mode = RP +set simplified_i_gain = 80 +set simplified_d_gain = 140 +set simplified_pi_gain = 120 +set simplified_d_max_gain = 20 +set simplified_feedforward_gain = 60 +set simplified_dterm_filter = OFF +set simplified_dterm_filter_multiplier = 80 +{{/if}} + +profile 1 +profile 2 +profile 3 + +# restore original profile selection +profile 0 + +rateprofile 0 +rateprofile 1 +rateprofile 2 +rateprofile 3 + +# restore original rateprofile selection +rateprofile 0 \ No newline at end of file From bb78543221367b0579f6616481e6e0c6f3be92f9 Mon Sep 17 00:00:00 2001 From: Kostiantyn Mazur Date: Tue, 7 Oct 2025 17:16:32 +0300 Subject: [PATCH 14/14] commit --- src/index.html | 1 + src/js/gui.js | 9 ++++++++- src/tabs/norn_config.html | 22 ++++++++-------------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/index.html b/src/index.html index df95b2f4df..3acd8137ee 100644 --- a/src/index.html +++ b/src/index.html @@ -130,6 +130,7 @@
  • +
    • diff --git a/src/js/gui.js b/src/js/gui.js index 7e0f98e7de..c86efe5bc9 100644 --- a/src/js/gui.js +++ b/src/js/gui.js @@ -19,7 +19,14 @@ class GuiControl { this.timeout_array = []; this.buttonDisabledClass = "disabled"; - this.defaultAllowedTabsWhenDisconnected = ["landing", "firmware_flasher", "privacy_policy", "options", "help"]; + this.defaultAllowedTabsWhenDisconnected = [ + "landing", + "firmware_flasher", + "privacy_policy", + "options", + "help", + "norn_config", + ]; this.defaultAllowedTabs = [ "setup", diff --git a/src/tabs/norn_config.html b/src/tabs/norn_config.html index 5c435894fb..662dad48fc 100644 --- a/src/tabs/norn_config.html +++ b/src/tabs/norn_config.html @@ -126,14 +126,11 @@
      -
      +
      -
      - -
      - +
      @@ -141,21 +138,21 @@
      -
      +
      -
      +
      - +
      + +
      +
      -
      - -
      @@ -170,9 +167,6 @@
      -
      - -