Skip to content

Commit ffd84f3

Browse files
committed
Added skeleton
1 parent 4b6a925 commit ffd84f3

File tree

10 files changed

+301
-4
lines changed

10 files changed

+301
-4
lines changed

locales/en/messages.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,24 @@
368368
"tabOptions": {
369369
"message": "Options"
370370
},
371+
"tabNornConfig": {
372+
"message": "NORN Config"
373+
},
374+
"nornManticore": {
375+
"message": "Manticore"
376+
},
377+
"nornVtx": {
378+
"message": "VTX"
379+
},
380+
"nornNone": {
381+
"message": "None"
382+
},
383+
"nornGenerate": {
384+
"message": "Generate"
385+
},
386+
"nornOutput": {
387+
"message": "NORN Configuration"
388+
},
371389

372390
"tabSetup": {
373391
"message": "Setup"

locales/uk/messages.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7510,5 +7510,23 @@
75107510
"osdDescElementLidar": {
75117511
"message": "$t(osdTextElementLidar.message)",
75127512
"description": "Don't translate!!!"
7513+
},
7514+
"nornManticore": {
7515+
"message": "Manticore"
7516+
},
7517+
"nornVtx": {
7518+
"message": "VTX"
7519+
},
7520+
"nornNone": {
7521+
"message": "Немає"
7522+
},
7523+
"nornGenerate": {
7524+
"message": "Згенерувати"
7525+
},
7526+
"nornOutput": {
7527+
"message": "Конфігурація"
7528+
},
7529+
"tabNornConfig": {
7530+
"message": "NORN Налаштування"
75137531
}
75147532
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"node": "20.x"
4242
},
4343
"dependencies": {
44+
"ejs": "^3.1.9",
4445
"@capacitor/android": "^7.0.1",
4546
"@capacitor/core": "^7.0.1",
4647
"@fortawesome/fontawesome-free": "^6.5.2",

src/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@
136136
<li class="tab_setup_osd"><a href="#" i18n="tabSetupOSD" class="tabicon ic_setup" i18n_title="tabSetupOSD"></a></li>
137137
<li class="tab_ports"><a href="#" i18n="tabPorts" class="tabicon ic_ports" i18n_title="tabPorts"></a></li>
138138
<li class="tab_configuration"><a href="#" i18n="tabConfiguration" class="tabicon ic_config" i18n_title="tabConfiguration"></a></li>
139+
<li class="tab_norn_config"><a href="#" i18n="tabNornConfig" class="tabicon ic_config" i18n_title="tabNornConfig"></a></li>
139140
<li class="tab_power"><a href="#" i18n="tabPower" class="tabicon ic_power" i18n_title="tabPower"></a></li>
140141
<li class="tab_failsafe"><a href="#" i18n="tabFailsafe" class="tabicon ic_failsafe" i18n_title="tabFailsafe"></a></li>
141142
<li class="tab_presets"><a href="#" i18n="tabPresets" class="tabicon ic_wizzard" i18n_title="tabPresets"></a></li>

src/js/gui.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class GuiControl {
3030
"presets",
3131
"cli",
3232
"configuration",
33+
"norn_config",
3334
"logging",
3435
"onboard_logging",
3536
"modes",

src/js/main.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@ function startProcess() {
279279
configuration.initialize(content_ready),
280280
);
281281
break;
282+
case "norn_config":
283+
import("./tabs/norn_config").then(({ norn_config }) => norn_config.initialize(content_ready));
284+
break;
282285
case "pid_tuning":
283286
import("./tabs/pid_tuning").then(({ pid_tuning }) => pid_tuning.initialize(content_ready));
284287
break;

src/js/tabs/norn_config.js

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import ejs from "ejs";
2+
import { i18n } from "../localization";
3+
import GUI, { TABS } from "../gui";
4+
import { mspHelper } from "../msp/MSPHelper";
5+
import MSP from "../msp";
6+
import MSPCodes from "../msp/MSPCodes";
7+
import $ from "jquery";
8+
9+
// Discover config sources (text-based)
10+
const templateFiles = import.meta.glob("../../norn-configs/template.ejs", { eager: true, as: "raw" });
11+
12+
const norn_config = {
13+
analyticsChanges: {},
14+
};
15+
16+
norn_config.initialize = function (callback) {
17+
const self = this;
18+
19+
GUI.active_tab = "norn_config";
20+
21+
function load_configuration_from_fc() {
22+
// Load any prerequisite data from FC, then load the HTML
23+
mspHelper.readFullConfiguration?.(() => {
24+
$("#content").load("./tabs/norn_config.html", on_tab_loaded_handler);
25+
}) || $("#content").load("./tabs/norn_config.html", on_tab_loaded_handler);
26+
}
27+
28+
function update_ui() {
29+
i18n.localizePage();
30+
31+
// Populate Manticore models (allow None) with explicit options
32+
const manticoreSelect = $("select[name='norn_manticore']");
33+
if (manticoreSelect.length) {
34+
manticoreSelect.empty();
35+
manticoreSelect.append(`<option value="">${i18n.getMessage("nornNone")}</option>`);
36+
manticoreSelect.append(`<option value="uart">UART</option>`);
37+
manticoreSelect.append(`<option value="gpio">GPIO</option>`);
38+
manticoreSelect.on("change", function () {
39+
self.analyticsChanges["NornManticore"] = $(this).val() || null;
40+
});
41+
}
42+
43+
// Populate VTX profiles (allow None) with explicit options
44+
const vtxSelect = $("select[name='norn_vtx']");
45+
if (vtxSelect.length) {
46+
vtxSelect.empty();
47+
vtxSelect.append(`<option value="">${i18n.getMessage("nornNone")}</option>`);
48+
vtxSelect.append(`<option value="3.3_vtx">3.3GHz</option>`);
49+
vtxSelect.append(`<option value="5.8_vtx">5.8GHz</option>`);
50+
vtxSelect.append(`<option value="optica">Optica</option>`);
51+
vtxSelect.on("change", function () {
52+
self.analyticsChanges["NornVtx"] = $(this).val() || null;
53+
});
54+
}
55+
56+
// Example dropdown wiring
57+
const exampleSelect = $("select[name='norn_mode']");
58+
if (exampleSelect.length) {
59+
exampleSelect.on("change", function () {
60+
const value = $(this).val();
61+
self.analyticsChanges["NornMode"] = value;
62+
});
63+
}
64+
65+
// Example button wiring
66+
$("a.generate").on("click", on_generate_handler);
67+
}
68+
69+
function on_tab_loaded_handler() {
70+
update_ui();
71+
72+
GUI.interval_add(
73+
"status_pull",
74+
function status_pull() {
75+
MSP.send_message(MSPCodes.MSP_STATUS);
76+
},
77+
500,
78+
true,
79+
);
80+
81+
GUI.content_ready(callback);
82+
}
83+
84+
// No save/copy handlers for now (kept minimal per request)
85+
86+
function readFileRaw(pathMap, path) {
87+
if (!path) return "";
88+
try {
89+
return pathMap[path] || "";
90+
} catch (e) {
91+
console.error("Cannot read", path, e);
92+
return "";
93+
}
94+
}
95+
96+
function getSelectedKeys() {
97+
const manticoreKey = $("select[name='norn_manticore']").val() || "";
98+
const vtxKey = $("select[name='norn_vtx']").val() || "";
99+
return { manticoreKey, vtxKey };
100+
}
101+
102+
function on_generate_handler(e) {
103+
e?.preventDefault?.();
104+
105+
const templatePath = Object.keys(templateFiles)[0];
106+
let result;
107+
if (templatePath) {
108+
const tpl = readFileRaw(templateFiles, templatePath);
109+
result = ejs.render(tpl, getSelectedKeys());
110+
} else {
111+
// Fallback to old behavior if template missing
112+
const parts = [];
113+
const genericPath = Object.keys(genericFiles)[0];
114+
parts.push(readFileRaw(genericFiles, genericPath));
115+
const manticorePath = $("select[name='norn_manticore']").val();
116+
if (manticorePath) parts.push(readFileRaw(manticoreFiles, manticorePath));
117+
const vtxPath = $("select[name='norn_vtx']").val();
118+
if (vtxPath) parts.push(readFileRaw(vtxFiles, vtxPath));
119+
result = parts.filter(Boolean).join("\n\n").trim();
120+
}
121+
122+
$("#norn_config_output").val(result);
123+
}
124+
125+
load_configuration_from_fc();
126+
};
127+
128+
norn_config.cleanup = function (callback) {
129+
if (callback) callback();
130+
};
131+
132+
TABS.norn_config = norn_config;
133+
export { norn_config };

src/norn-configs/template.ejs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
defaults nosave
2+
3+
batch start
4+
5+
defaults nosave
6+
7+
8+
9+
<% if (manticoreKey === 'uart') { %>
10+
# Manticore UART variant
11+
set uart1_function = RX_SERIAL
12+
set uart2_function = TELEMETRY
13+
<% } %>
14+
15+
<% if (manticoreKey === 'gpio') { %>
16+
# Manticore GPIO variant
17+
set gpio_output = ON
18+
set gpio_mode = ALTERNATE
19+
<% } %>
20+
21+
<% if (vtxKey === '5.8_vtx') { %>
22+
# 5.8GHz VTX settings
23+
set vtx_band = A
24+
set vtx_channel = 1
25+
set vtx_power = 25
26+
<% } %>
27+
28+
<% if (vtxKey === '3.3_vtx') { %>
29+
# 3.3GHz VTX settings
30+
set vtx_band = B
31+
set vtx_channel = 3
32+
set vtx_power = 100
33+
<% } %>
34+
35+
<% if (vtxKey === 'optica') { %>
36+
# Optica VTX settings
37+
set vtx_band = O
38+
set vtx_channel = 2
39+
set vtx_power = 50
40+
<% } %>
41+
42+

src/tabs/norn_config.html

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<div class="tab-norn-config">
2+
<div class="content_wrapper">
3+
<div class="tab_title" i18n="tabNornConfig"></div>
4+
<div class="cf_doc_version_bt">
5+
<a id="button-documentation" href="" target="_blank" rel="noopener noreferrer"></a>
6+
</div>
7+
8+
<div class="grid-row grid-box col2">
9+
<div class="col-span-1">
10+
<div class="gui_box grey">
11+
<div class="gui_box_titlebar">
12+
<div class="spacer_box_title" i18n="nornManticore"></div>
13+
</div>
14+
<div class="spacer_box">
15+
<div class="select">
16+
<select name="norn_manticore" id="norn_manticore">
17+
<option value="" i18n="nornNone"></option>
18+
</select>
19+
</div>
20+
</div>
21+
</div>
22+
23+
<div class="gui_box grey" style="margin-top: 16px;">
24+
<div class="gui_box_titlebar">
25+
<div class="spacer_box_title" i18n="nornVtx"></div>
26+
</div>
27+
<div class="spacer_box">
28+
<div class="select">
29+
<select name="norn_vtx" id="norn_vtx">
30+
<option value="" i18n="nornNone"></option>
31+
</select>
32+
</div>
33+
</div>
34+
</div>
35+
36+
<div class="buttons" style="margin-top: 16px;">
37+
<a href="#" class="generate regular-button" i18n="nornGenerate"></a>
38+
</div>
39+
</div>
40+
41+
<div class="col-span-1">
42+
<div class="gui_box grey">
43+
<div class="gui_box_titlebar">
44+
<div class="spacer_box_title" i18n="nornOutput"></div>
45+
</div>
46+
<div class="spacer_box">
47+
<textarea id="norn_config_output" rows="20" style="width: 100%;" readonly></textarea>
48+
</div>
49+
</div>
50+
</div>
51+
</div>
52+
</div>
53+
</div>
54+
55+

yarn.lock

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4406,7 +4406,7 @@ editorconfig@^1.0.4:
44064406
minimatch "9.0.1"
44074407
semver "^7.5.3"
44084408

4409-
ejs@^3.1.6:
4409+
ejs@^3.1.6, ejs@^3.1.9:
44104410
version "3.1.10"
44114411
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b"
44124412
integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==
@@ -9630,7 +9630,7 @@ string-argv@^0.3.2:
96309630
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
96319631
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
96329632

9633-
"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:
9633+
"string-width-cjs@npm:string-width@^4.2.0":
96349634
version "4.2.3"
96359635
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
96369636
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -9648,6 +9648,15 @@ string-width@^1.0.1, string-width@^1.0.2:
96489648
is-fullwidth-code-point "^1.0.0"
96499649
strip-ansi "^3.0.0"
96509650

9651+
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
9652+
version "4.2.3"
9653+
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
9654+
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
9655+
dependencies:
9656+
emoji-regex "^8.0.0"
9657+
is-fullwidth-code-point "^3.0.0"
9658+
strip-ansi "^6.0.1"
9659+
96519660
string-width@^2.1.0:
96529661
version "2.1.1"
96539662
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
@@ -9753,7 +9762,7 @@ stringify-object@^3.3.0:
97539762
is-obj "^1.0.1"
97549763
is-regexp "^1.0.0"
97559764

9756-
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
9765+
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
97579766
version "6.0.1"
97589767
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
97599768
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -9781,6 +9790,13 @@ strip-ansi@^4.0.0:
97819790
dependencies:
97829791
ansi-regex "^3.0.0"
97839792

9793+
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
9794+
version "6.0.1"
9795+
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
9796+
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
9797+
dependencies:
9798+
ansi-regex "^5.0.1"
9799+
97849800
strip-ansi@^7.0.1, strip-ansi@^7.1.0:
97859801
version "7.1.0"
97869802
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -11053,7 +11069,7 @@ [email protected], workbox-window@^7.3.0:
1105311069
"@types/trusted-types" "^2.0.2"
1105411070
workbox-core "7.3.0"
1105511071

11056-
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
11072+
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
1105711073
version "7.0.0"
1105811074
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
1105911075
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -11079,6 +11095,15 @@ wrap-ansi@^6.2.0:
1107911095
string-width "^4.1.0"
1108011096
strip-ansi "^6.0.0"
1108111097

11098+
wrap-ansi@^7.0.0:
11099+
version "7.0.0"
11100+
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
11101+
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
11102+
dependencies:
11103+
ansi-styles "^4.0.0"
11104+
string-width "^4.1.0"
11105+
strip-ansi "^6.0.0"
11106+
1108211107
wrap-ansi@^8.1.0:
1108311108
version "8.1.0"
1108411109
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"

0 commit comments

Comments
 (0)