Merge pull request #102 from TylerDurden-23/opt-system-settings

Add startup config editor to system settings menu
This commit is contained in:
logicog
2026-02-16 20:53:52 +01:00
committed by GitHub
9 changed files with 166 additions and 38 deletions
+6 -1
View File
@@ -1043,7 +1043,12 @@ void execute_config(void) __banked
config_done:
// Start saving commands to cmd_history
save_cmd = 1;
}
void clear_command_history(void) __banked
{
for (cmd_history_ptr = 0; cmd_history_ptr < CMD_HISTORY_SIZE; cmd_history_ptr++)
cmd_history[cmd_history_ptr] = 0;
cmd_history_ptr = 0;
}
return;
}
+1
View File
@@ -12,4 +12,5 @@ uint8_t cmd_tokenize(void) __banked;
void cmd_parser(void) __banked;
void execute_config(void) __banked;
void print_sw_version(void) __banked;
void clear_command_history(void) __banked;
#endif
-1
View File
@@ -1 +0,0 @@
../config.txt
+2 -1
View File
@@ -49,7 +49,8 @@ async function fetchCmdLog() {
console.log("CMD-Log: ", response);
const t = await response.text();
return t;
} catch(error) {
} catch(err) {
console.error("Error: ", err);
return "";
}
}
+2 -1
View File
@@ -6,8 +6,9 @@ ul {
margin: 0;
padding: 0;
width: 12%;
height: 100%;
height: calc(100% - 50px);
position: fixed;
top: 50px;
overflow: auto;
}
+53 -17
View File
@@ -3,34 +3,70 @@
<head>
<link rel="stylesheet" href="style.css">
<title>System Settings</title>
<style>
.tab-bar { display: flex; border-bottom: 2px solid #226; margin-bottom: 0; margin-left: 16%; padding: 1px 16px; padding-bottom: 0; }
.tab-btn { padding: 10px 20px; background-color: #ddf; border: none; cursor: pointer; font-size: 1em; border-radius: 8px 8px 0 0; margin-right: 4px; }
.tab-btn:hover { background-color: #aaf; }
.tab-btn.active { background-color: #aaf; font-weight: bold; border-bottom: 2px solid #aaf; margin-bottom: -2px; }
.tab-content { display: none; }
.tab-content.active { display: block; }
</style>
</head>
<body>
<div class="tab-bar">
<button class="tab-btn active" onclick="openTab(event, 'system-tab')">System</button>
<button class="tab-btn" onclick="openTab(event, 'advanced-tab')">Advanced</button>
</div>
<nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div>
<h1>System Settings</h1>
<div class="row">
<div class="lcol"> <label for="ip">IP address:</label></div>
<div class="rcol"> <input id="ip" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
<div id="system-tab" class="tab-content active">
<h1>System Settings</h1>
<div class="row">
<div class="lcol"> <label for="ip">IP address:</label></div>
<div class="rcol"> <input id="ip" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
</div>
<div class="row">
<div class="lcol"> <label for="netmask">Netmask:</label></div>
<div class="rcol"><input id="netmask" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
</div>
<div class="row">
<div class="lcol"> <label for="gw">Gateway:</label></div>
<div class="rcol"><input id="gw" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
</div>
<br/>
When updating the above settings, remember to point your browser to the new IP afterwards:<br/>
<input style="width:40%;" class="action" id="ip_sub" onclick="ipSub();" type="button" value="Update Settings"><br/>
<br/>
Save all current settings to Flash:<br/>
<input style="width:40%;" class="action" id="flash_sub" onclick="flashSave();" type="button" value="Save Settings to Flash">
</div>
<div class="row">
<div class="lcol"> <label for="netmask">Netmask:</label></div>
<div class="rcol"><input id="netmask" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
<div id="advanced-tab" class="tab-content">
<h1>Advanced Settings</h1>
<div class="lcol"> <label for="config_display">Startup configuration:</label></div>
<textarea id="config_display" rows="8" cols="60"></textarea>
<br/><br/>
Be careful when saving the directly edited startup configuration, you can lock yourself out:<br/>
<input style="width:40%;" class="action" id="clear_config" onclick="clearConfig();" type="button" value="Clear Startup Config">
<br/>
<input style="width:40%;" class="action" id="flash_startup_sub" onclick="flashStartupSave();" type="button" value="Save Startup Settings to Flash">
<br/>
<input style="width:40%;" class="action" id="switch_reset" onclick="resetSwitch();" type="button" value="Reset Switch">
</div>
<div class="row">
<div class="lcol"> <label for="gw">Gateway:</label></div>
<div class="rcol"><input id="gw" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
</div>
<br/><br/>
When updating the above settings, remember to point your browser to the new IP afterwards:<br/>
<input style="width:40%;" class="action" id="ip_sub" onclick="ipSub();" type="button" value="Update Settings"><br/>
<br/><br/>
Save all current settings to Flash:<br/>
<input style="width:40%;" class="action" id="flash_sub" onclick="flashSave();" type="button" value="Save Settings to Flash">
</div>
<script src="/config.js"></script>
<script src="/system.js"></script>
<script src="/navigation.js"></script>
<script>
function openTab(evt, tabId) {
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
document.getElementById(tabId).classList.add('active');
evt.currentTarget.classList.add('active');
}
</script>
</body>
</html>
+55 -1
View File
@@ -42,6 +42,7 @@ async function sendConfig(c) {
}
}
async function flashSave() {
fetchConfig().then((s) => {
parseConf(s);
@@ -53,6 +54,39 @@ async function flashSave() {
sendConfig(body);
});
});
setTimeout(() => {
fetchIP();
}, 500);
}
async function flashStartupSave() {
var configContent = document.getElementById("config_display").value;
console.log("CONFIGURATION to save: ", configContent);
sendConfig(configContent);
// Clear the command log 1 second after initiating the config save
setTimeout(() => {
fetch('/cmd_log_clear', { method: 'GET' })
.then(response => console.log('Command log cleared', response))
.catch(err => console.error('Error clearing command log:', err));
}, 1000);
}
function clearConfig() {
document.getElementById("config_display").value = "";
// Validate and populate with current IP settings
for (let i=0; i<3; i++) {
if (!checkIp(document.getElementById(ips[i]).value))
return;
}
var configLines = "";
for (let i=0; i<3; i++){
var cmd = ips[i]+' '+document.getElementById(ips[i]).value;
configLines += cmd + "\n";
}
document.getElementById("config_display").value = configLines;
}
function fetchIP() {
@@ -65,12 +99,32 @@ function fetchIP() {
document.getElementById("netmask").value=s.ip_netmask;
document.getElementById("gw").value=s.ip_gateway;
clearInterval(systemInterval);
// Fetch and populate the config textbox
fetchConfig().then((configText) => {
let fullConfig = configText;
// Fetch and append cmd_log
//return fetchCmdLog().then((cmdLogText) => {
// if (cmdLogText) {
// fullConfig = fullConfig + cmdLogText;
// }
document.getElementById("config_display").value = fullConfig;
});
};
}
}
xhttp.open("GET", `/information.json`, true);
xhttp.send();
}
function resetSwitch() {
if (!confirm('Are you sure you want to reset the switch?')) {
return;
}
fetch('/reset', { method: 'GET' }).catch(() => {});
setTimeout(() => {
alert('Switch is resetting. Please wait and refresh the page.');
}, 3000);
}
window.addEventListener("load", function() {
systemInterval = setInterval(fetchIP, 1000);
});
+12
View File
@@ -301,6 +301,8 @@ uint8_t stream_upload(uint16_t bptr)
print_string("Checksum incorrect!");
}
print_string("\nUpload to flash done, will reset!\n");
// close connection to avoid retries by browser
uip_close();
reset_chip();
}
// Make sure there is a 0 at the end of the uploaded data
@@ -310,6 +312,9 @@ uint8_t stream_upload(uint16_t bptr)
flash_write_bytes(flash_buf);
if (bptr >= uip_len)
return 0;
if(!verify_crc)
//ugly hack to signal connection finished after config upload.
uip_close();
return 1;
}
if (p[bptr] == boundary[bindex]) {
@@ -593,6 +598,13 @@ void httpd_appcall(void)
send_config();
} else if (is_word(q, "/cmd_log")) {
send_cmd_log();
} else if (is_word(q, "/cmd_log_clear")) {
clear_command_history();
send_mtu(); // dummy response
} else if (is_word(q, "/reset")) {
uip_close();
delay(1000); //wait for the close packet to be sent, otherwise the browser will retry
reset_chip();
} else {
send_not_found();
}
+35 -16
View File
@@ -676,26 +676,45 @@ void send_status(void)
void send_config(void)
{
dbg_string("send_config called\n");
__xdata uint32_t pos = CONFIG_START; // 70000 , 6c000 / 0xc000 = 9
extern __xdata uint16_t len_left = CONFIG_LEN;
__xdata uint32_t pos = CONFIG_START;
__xdata uint16_t valid_len = 0;
__xdata uint16_t len_left = CONFIG_LEN;
__xdata uint8_t flash_buf[256];
slen = strtox(outbuf, HTTP_RESPONCE_TXT);
while (read_flash((CONFIG_START-CODE0_SIZE) / CODE_BANK_SIZE + 1,
(__code uint8_t *) (((CONFIG_START + len_left - CODE0_SIZE) % CODE_BANK_SIZE) + CODE0_SIZE + len_left)) == 0xff) {
dbg_short(len_left);
len_left--;
}
len_left++;
if (len_left > (TCP_OUTBUF_SIZE - slen)) {
cont_len = len_left - (TCP_OUTBUF_SIZE - slen);
len_left = TCP_OUTBUF_SIZE - slen;
cont_addr = len_left;
// Scan through config to find the end of valid data (null terminator)
do {
flash_region.addr = pos;
flash_region.len = (len_left > 256) ? 256 : len_left;
flash_read_bulk(flash_buf);
// Look for null terminator in this chunk
for (uint16_t i = 0; i < flash_region.len; i++) {
if (flash_buf[i] == 0) {
// Found end of valid data
valid_len += i;
goto found_end;
}
}
valid_len += flash_region.len;
len_left -= flash_region.len;
pos += flash_region.len;
} while (len_left > 0);
found_end:
// Now send the valid data
if (valid_len > (TCP_OUTBUF_SIZE - slen)) {
cont_len = valid_len - (TCP_OUTBUF_SIZE - slen);
valid_len = TCP_OUTBUF_SIZE - slen;
cont_addr = valid_len;
}
flash_region.addr = CONFIG_START;
flash_region.len = len_left;
flash_region.len = valid_len;
flash_read_bulk(outbuf + slen);
slen += len_left;
slen += valid_len;
}
void send_cmd_log(void)