From 6441e8575230d305726ca594db0049a982abdff6 Mon Sep 17 00:00:00 2001 From: Tobias Diedrich Date: Sat, 20 Dec 2025 08:33:34 +0100 Subject: [PATCH 01/15] Add rounding to baud rate calculation Without rounding: - Divisor: 33 = (125000000 / 115200 / 32) - RCAP2 value: 65503 - Actual baud rate: 118371 = (125000000 / 32 / 33) - Error: 2.75% With rounding: - Divisor: 34 = ((125000000 / 115200 + 16) / 32) - RCAP2 value: 65502 - Actual baud rate: 114889 = (125000000 / 32 / 34) - Error: 0.27% Should fix https://github.com/logicog/RTLPlayground/issues/48 --- rtlplayground.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtlplayground.c b/rtlplayground.c index 7beb6b3..51f22f3 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -1649,8 +1649,8 @@ void setup_serial(void) // The RCAP2 registers contain the high/low byte that is loaded into // timer2 when T2 overflows to 0x10000 - RCAP2H = (0x10000 - (CLOCK_HZ / SERIAL_BAUD_RATE / 32)) >> 8; - RCAP2L = (0x10000 - (CLOCK_HZ / SERIAL_BAUD_RATE / 32)) % 0xff; + RCAP2H = (0x10000 - ((CLOCK_HZ / SERIAL_BAUD_RATE + 16) / 32)) >> 8; + RCAP2L = (0x10000 - ((CLOCK_HZ / SERIAL_BAUD_RATE + 16) / 32)) % 0xff; PCON |= 0x80; // Double the Baud Rate From 36d5ee3ddddac4fdb88292b562bda9ab5db85593 Mon Sep 17 00:00:00 2001 From: logicog Date: Tue, 16 Dec 2025 19:27:07 +0100 Subject: [PATCH 02/15] Add port speed page --- html/navigation.js | 2 +- html/ports.html | 21 +++++++++++ html/ports.js | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 html/ports.html create mode 100644 html/ports.js diff --git a/html/navigation.js b/html/navigation.js index 0e38d7b..0444467 100644 --- a/html/navigation.js +++ b/html/navigation.js @@ -1,5 +1,6 @@ document.getElementById('sidebar').innerHTML = ""; - diff --git a/html/ports.html b/html/ports.html new file mode 100644 index 0000000..6b15e50 --- /dev/null +++ b/html/ports.html @@ -0,0 +1,21 @@ + + + + + FreeSwitchOS Port Configuration + + + +
+
+

Port Configuration

+
+ + +
Port Current Link SpeedSelected Speed Set SpeedSet DuplexApply
+ +
+
+ + + diff --git a/html/ports.js b/html/ports.js new file mode 100644 index 0000000..0396447 --- /dev/null +++ b/html/ports.js @@ -0,0 +1,90 @@ +function createPortTable() { + var tbl = document.getElementById('speedtable'); + if (tbl.rows.length <= 2 && numPorts) { + clearInterval(pTableInterval); + const sSelect = ''; + const dSelect = ''; + for (let i = 1; i <= numPorts; i++) { + if (pIsSFP[i-1]) + continue; + console.log("Table row: " + i + "pState: " + pState[i-2]); + const tr = tbl.insertRow(); + let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i}`)); + td = tr.insertCell(); td.innerHTML = linkS[pState[i] + 1]; + td = tr.insertCell(); td.innerHTML = "Unknown"; + td = tr.insertCell(); td.innerHTML = sSelect.replaceAll("speed_sel", "speed_sel_" + i); + td = tr.insertCell(); td.innerHTML = dSelect.replaceAll("duplex_sel", "duplex_sel_" + i); + var button = ''; + td = tr.insertCell(); + td.innerHTML = button; + } + } +} + +function updatePortTable() { + console.log("updatePortTable called"); + var tbl = document.getElementById('speedtable'); + if (tbl.rows.length <= 2 || !numPorts) + return; + for (let i = 1; i <= numPorts ; i++) { + if (pIsSFP[i-1]) + continue; + tbl.rows[i].cells[1].innerHTML = `${linkS[pState[i-1]+1]}`; + var td = tbl.rows[i].cells[2]; + var adv = pAdvertised[i-1]; + console.log("pAdvertised for " + i + " is " + adv); + if (pAdvertised[i-1] == 0) + td.innerHTML = "None"; + else if (adv == 0b100000) + td.innerHTML = "2.5GBit Full Duplex"; + else if (adv == 0b010000) + td.innerHTML = "1000MBit Full Duplex"; + else if (adv == 0b111111) + td.innerHTML = "AUTO"; + else if (adv == 0b000011) + td.innerHTML = "10MBit"; + else if (adv == 0b000100) + td.innerHTML = "100MBit Half Duplex"; + } +} + +async function applySpeed(port) { + var speed = document.getElementById('speed_sel_' + port).value; + var duplex = document.getElementById('duplex_sel_' + port).value; + var cmd = "port " + port + " "; + cmd = cmd + speed; + console.log("port " + port, ", speed: " + speed, ", duplex: ", duplex); + try { + const response = await fetch('/cmd', { + method: 'POST', + body: cmd + }); + console.log('Completed!', response); + if (duplex != "any") { + cmd = "port " + port + " duplex " + duplex; + const response = await fetch('/cmd', { + method: 'POST', + body: cmd + }); + console.log('Completed!', response); + } + } catch(err) { + console.error(`Error: ${err}`); + } +} + +window.addEventListener("load", function() { + const updatePortTableInterval = setInterval(updatePortTable, 1000); +}); + +const pTableInterval = setInterval(createPortTable, 1000); From f0537d759f1b291ea8cfdc5ab4f7e8b74715441e Mon Sep 17 00:00:00 2001 From: logicog Date: Wed, 17 Dec 2025 17:40:27 +0100 Subject: [PATCH 03/15] Correct PHY registers for speed selection --- httpd/page_impl.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/httpd/page_impl.c b/httpd/page_impl.c index 6a64760..bcd620c 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -390,6 +390,8 @@ void send_status(void) for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { slen += strtox(outbuf + slen, "{\"portNum\":"); itoa_html(machine.log_to_phys_port[i]); + slen += strtox(outbuf + slen, ",\"logPort\":"); + itoa_html(i); if (machine.is_sfp[i]) { slen += strtox(outbuf + slen, ",\"isSFP\":1,\"enabled\":"); @@ -429,9 +431,20 @@ void send_status(void) slen += strtox(outbuf + slen, ",\"isSFP\":0,\"enabled\":"); phy_read(i, 0x1f, 0xa610); bool_to_html(SFR_DATA_8 == 0x20); + slen += strtox(outbuf + slen, ",\"adv\":\""); + phy_read(i, PHY_MMD_AN, 0x20); + bool_to_html(SFR_DATA_8 & 0x80); // 2500BaseN-Full + phy_read(i, PHY_MMD_CTRL, 0xa412); + bool_to_html(SFR_DATA_16 & 0x02); // 1000Base-Full + phy_read(i, PHY_MMD_AN, 0x10); + bool_to_html(SFR_DATA_16 & 0x01); // 100Base-Full + uint8_t w = SFR_DATA_8; + bool_to_html(w & 0x80); // 100Base-Half + bool_to_html(w & 0x40); // 10Base-Full + bool_to_html(w & 0x20); // 10Base-Half } - slen += strtox(outbuf + slen, ",\"link\":"); + slen += strtox(outbuf + slen, "\",\"link\":"); if (i < 8) reg_read_m(RTL837X_REG_LINKS); From eb0106d9f454dd0e380508ffbeb45206a40dff86 Mon Sep 17 00:00:00 2001 From: logicog Date: Wed, 17 Dec 2025 17:40:59 +0100 Subject: [PATCH 04/15] Correct bits in advertised PHY speeds --- rtl837x_phy.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rtl837x_phy.c b/rtl837x_phy.c index 20fd80e..9e56e63 100644 --- a/rtl837x_phy.c +++ b/rtl837x_phy.c @@ -366,7 +366,7 @@ void phy_show(uint8_t port) __banked print_string("\nAN enabled, advertising:"); phy_read(port, PHY_MMD_AN, 0x10); v = SFR_DATA_U16; - if (v & 0x0040) + if (v & 0x0020) print_string(" 10Base-Half"); if (v & 0x0040) print_string(" 10Base-Full"); @@ -378,11 +378,10 @@ void phy_show(uint8_t port) __banked v = SFR_DATA_U16; if (v & 0x0200) print_string(" 1000Base-Full"); - phy_read(port, PHY_MMD_AN, 0x10); + phy_read(port, PHY_MMD_AN, 0x20); v = SFR_DATA_U16; if (v & 0x0080) print_string(" 2500BaseN-Full"); - } phy_read(port, PHY_MMD_AN, 0x13); v = SFR_DATA_U16; From b4b8ad5738ef7bf7332a167eee22c8c5ec237204 Mon Sep 17 00:00:00 2001 From: logicog Date: Wed, 17 Dec 2025 17:42:11 +0100 Subject: [PATCH 05/15] Simulate 9-port machines --- tools/httpd_sim.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tools/httpd_sim.c b/tools/httpd_sim.c index 625894d..138faa9 100644 --- a/tools/httpd_sim.c +++ b/tools/httpd_sim.c @@ -15,7 +15,15 @@ #define PASSWORD "1234" #define SESSION_TIMEOUT 2000 -#define PORTS 6 +#define PORTS 9 +#define NSFP 1 + +#if PORTS == 9 +const uint8_t physToLogPort[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8}; +#else +const uint8_t physToLogPort[] = { 4, 5, 6, 7, 3, 8}; +#endif + time_t last_called; time_t last_session_use; @@ -125,7 +133,8 @@ void send_status(int s) for (int i = 1; i <= PORTS; i++) { v = json_object_new_object(); json_object_object_add(v, "portNum", json_object_new_int(i)); - json_object_object_add(v, "isSFP", json_object_new_int(i < 5 ? 0 : 1)); + json_object_object_add(v, "logPort", json_object_new_int(physToLogPort[i-1])); + json_object_object_add(v, "isSFP", json_object_new_int(i <= PORTS - NSFP ? 0 : 1)); json_object_object_add(v, "enabled", json_object_new_int((i % 4) ? 1 : 0)); json_object_object_add(v, "link", json_object_new_int(i % 2 ? ((i == 1)? 5 : 2) : 0)); if (i % 2) { @@ -143,7 +152,7 @@ void send_status(int s) json_object_object_add(v, "txB", json_object_new_string(txB_buff)); json_object_object_add(v, "rxG", json_object_new_string(rxG_buff)); json_object_object_add(v, "rxB", json_object_new_string(rxB_buff)); - if (i >= 5) { + if (i >= PORTS - NSFP) { uint16_t temp = 0x28fb + rand() / (RAND_MAX / 100); uint16_t vcc = 0x7eda + rand() / (RAND_MAX / 100); uint16_t txbias = 0x0d24 +rand() / (RAND_MAX / 100); @@ -169,6 +178,14 @@ void send_status(int s) json_object_object_add(v, "sfp_txpower", json_object_new_string(sfp_txpower)); json_object_object_add(v, "sfp_rxpower", json_object_new_string(sfp_rxpower)); json_object_object_add(v, "sfp_laser", json_object_new_string(sfp_laser)); + } else { + if (i == 1) + json_object_object_add(v, "adv", json_object_new_string("100000")); + else if (i==2) + json_object_object_add(v, "adv", json_object_new_string("000011")); + else + json_object_object_add(v, "adv", json_object_new_string("000100")); + } json_object_array_add(ports, v); } From 67439efd2bcca2d2ccd46775e217ad29500bdc81 Mon Sep 17 00:00:00 2001 From: logicog Date: Wed, 17 Dec 2025 17:42:36 +0100 Subject: [PATCH 06/15] Correctly display 9-port machines --- html/eee.js | 11 ++++++----- html/main.js | 11 +++++++++-- html/stat.js | 6 ++++-- httpd/page_impl.c | 19 +++++++++++-------- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/html/eee.js b/html/eee.js index cb40329..c5140eb 100644 --- a/html/eee.js +++ b/html/eee.js @@ -1,8 +1,9 @@ function createEEE() { var tbl = document.getElementById('eeetable'); - if (tbl.rows.length <= 2) { + if (tbl.rows.length <= 2 && numPorts) { + clearInterval(createEEEInterval); console.log("CREATING TABLE ", tbl.rows.length); - for (let i = 2; i < 8; i++) { + for (let i = 2; i < 2 + numPorts; i++) { console.log("Table row: " + i + "pState: " + pState[i-2]); const tr = tbl.insertRow(); let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i-1}`)); @@ -20,8 +21,8 @@ function getEEE() { const s = JSON.parse(xhttp.responseText); console.log("EEE: ", JSON.stringify(s)); var tbl = document.getElementById('eeetable'); - if (tbl.rows.length > 2) { - for (let i = 2; i < 8; i++) { + if (tbl.rows.length > 2 && numPorts) { + for (let i = 2; i < 2 + numPorts; i++) { p = s[i-2]; let n = p.portNum; console.log("Table Update row: " + i + " portNum is " + n + ", pState is " + pState[i-2]); @@ -46,4 +47,4 @@ window.addEventListener("load", function() { getEEE(); const iCount = setInterval(getEEE, 2000); }); -const stat = setInterval(createEEE, 1000); +const createEEEInterval = setInterval(createEEE, 1000); diff --git a/html/main.js b/html/main.js index 5a7473d..6e8bceb 100644 --- a/html/main.js +++ b/html/main.js @@ -5,9 +5,10 @@ var rxB = new BigInt64Array(10); const linkS = ["Disabled", "No Link", "100M", "1000M", "500M", "10G", "2.5G", "5G"]; var pState = new Int8Array(10); var pIsSFP = new Int8Array(10); +var pAdvertised = new Int8Array(10); var numPorts = 0; -const logToPhysPort = [0, 0, 0, 5, 1, 2, 3, 4, 6]; -const physToLogPort = [ 4, 5, 6, 7, 3, 8]; +var logToPhysPort = new Int8Array(10); +var physToLogPort = new Int8Array(10); function drawPorts() { var f = document.getElementById('ports'); console.log("DRAWING PORTS: ", numPorts); @@ -54,6 +55,8 @@ function update() { for (let i = 0; i < s.length; i++) { p = s[i]; let n = p.portNum; + logToPhysPort[p.logPort] = n; + physToLogPort[n-1] = p.logPort; let pid = "port" + n; let ttid = "tt_" + n; n--; @@ -84,6 +87,7 @@ function update() { var iHTML = ""; iHTML += ""; if (p.isSFP) { + pAdvertised[n] = 0; iHTML += ""; iHTML += ""; iHTML += ""; @@ -94,6 +98,9 @@ function update() { iHTML += ""; iHTML += ""; } + } else { + pAdvertised[n] = parseInt(p.adv, 2); + console.log("Advertised " + n + " entry " + p.adv + " is now " + pAdvertised[n]); } iHTML += "
Link speed:" + linkS[p.link + 1] + "
Vendor:" + p.sfp_vendor + "
Model:" + p.sfp_model + "
Serial:" + p.sfp_serial + "
TX-Power:" + (Number(p.sfp_txpower) / 10.0).toFixed(0) + " mW
RX-Power:" + (Number(p.sfp_rxpower) / 10.0).toFixed(0) + " mW
"; tt.innerHTML = iHTML; diff --git a/html/stat.js b/html/stat.js index da674b7..31973fc 100644 --- a/html/stat.js +++ b/html/stat.js @@ -1,7 +1,9 @@ function fillStats() { var tbl = document.getElementById('statstable'); + if (!numPorts) + return; if (tbl.rows.length > 1) { - for (let i = 0; i < 6; i++) { + for (let i = 0; i < numPorts; i++) { console.log("Table Update row: " + i + " state " + pState[i] + " is " + linkS[pState[i] +1]); tbl.rows[i+1].cells[1].innerHTML = `${linkS[pState[i]+1]}`; tbl.rows[i+1].cells[2].innerHTML = `${txG[i]} pkts`; @@ -10,7 +12,7 @@ function fillStats() { tbl.rows[i+1].cells[5].innerHTML = `${rxB[i]} pkts`; } } else { - for (let i = 0; i < 6; i++) { + for (let i = 0; i < numPorts; i++) { console.log("Table row: " + i); const tr = tbl.insertRow(); let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i+1}`)); diff --git a/httpd/page_impl.c b/httpd/page_impl.c index bcd620c..62d5f07 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -433,18 +433,21 @@ void send_status(void) bool_to_html(SFR_DATA_8 == 0x20); slen += strtox(outbuf + slen, ",\"adv\":\""); phy_read(i, PHY_MMD_AN, 0x20); - bool_to_html(SFR_DATA_8 & 0x80); // 2500BaseN-Full + uint16_t w = SFR_DATA_U16; + bool_to_html(!!(w & 0x80)); // 2500BaseN-Full phy_read(i, PHY_MMD_CTRL, 0xa412); - bool_to_html(SFR_DATA_16 & 0x02); // 1000Base-Full + w = SFR_DATA_U16; + bool_to_html(!!(w & 0x0200)); // 1000Base-Full phy_read(i, PHY_MMD_AN, 0x10); - bool_to_html(SFR_DATA_16 & 0x01); // 100Base-Full - uint8_t w = SFR_DATA_8; - bool_to_html(w & 0x80); // 100Base-Half - bool_to_html(w & 0x40); // 10Base-Full - bool_to_html(w & 0x20); // 10Base-Half + w = SFR_DATA_U16; + bool_to_html(!!(w & 0x0100)); // 100Base-Full + bool_to_html(!!(w & 0x80)); // 100Base-Half + bool_to_html(!!(w & 0x40)); // 10Base-Full + bool_to_html(!!(w & 0x20)); // 10Base-Half + char_to_html('"'); } - slen += strtox(outbuf + slen, "\",\"link\":"); + slen += strtox(outbuf + slen, ",\"link\":"); if (i < 8) reg_read_m(RTL837X_REG_LINKS); From 67fbad38ce99b5087a7a433efac2e91dbc4865ea Mon Sep 17 00:00:00 2001 From: logicog Date: Thu, 18 Dec 2025 20:20:42 +0100 Subject: [PATCH 07/15] Add mtu command --- cmd_parser.c | 33 +++++++++++++++++++++++++++++++++ rtl837x_regs.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/cmd_parser.c b/cmd_parser.c index 6c91ad2..b3c4b60 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -457,6 +457,37 @@ void parse_port(void) } +void parse_mtu(void) +{ + __xdata uint16_t mtu; + uint8_t p; + + print_string("\nMTU "); + if (cmd_words_b[1] > 0 && cmd_compare(1, "show")) { + for (p = machine.min_port; p <= machine.max_port; p++) { + reg_read_m(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8)); + mtu = SFR_DATA_U16 & 0x3fff; + print_string("Port "); print_byte(machine.log_to_phys_port[p]); + print_string(" MTU: 0x"); print_short(mtu); write_char('\n'); + } + } + p = cmd_buffer[cmd_words_b[1]] - '1'; + p = machine.phys_to_log_port[p]; + print_byte(p); + if (cmd_words_b[2] <= 0) { + print_string("mtu [port] [size]"); + return; + } + atoi_short(&mtu, cmd_words_b[2]); + if (mtu > 0x3fff) { + print_string("Maximum MTU is 16383\n"); + return; + } + REG_WRITE(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8), (mtu >> 10) & 0xf, (mtu >> 2) & 0xff, + ((mtu & 0x3) << 6) | ((mtu >> 8) & 0x3f), mtu & 0xff); +} + + void sfp_print_measurements(uint8_t sfp) { print_string("Options: "); print_byte(sfp_read_reg(sfp, 92)); write_char('\n'); @@ -730,6 +761,8 @@ void cmd_parser(void) __banked flash_write_bytes(flash_buf); } else if (cmd_compare(0, "port") && cmd_words_b[1] > 0) { parse_port(); + } else if (cmd_compare(0, "mtu") && cmd_words_b[1] > 0) { + parse_mtu(); } else if (cmd_compare(0, "ip")) { print_string("Got ip command: "); if (!parse_ip(cmd_words_b[1])) diff --git a/rtl837x_regs.h b/rtl837x_regs.h index dc0ea62..975b233 100644 --- a/rtl837x_regs.h +++ b/rtl837x_regs.h @@ -136,6 +136,8 @@ #define RTL837x_L2_TBL_FLUSH_CNF 0x53dc #define RTL837X_L2_LRN_PORT_CONSTRAINT 0x5384 #define RTL837X_L2_LRN_PORT_CONSTRT_ACT 0x4f80 +#define RTL8373_REG_MAC_L2_PORT_MAX_LEN 0x1250 + /* * VLAN configuration */ From 51345a07e67ac897b6bb3f59e79fd883cc3b0e3e Mon Sep 17 00:00:00 2001 From: logicog Date: Thu, 18 Dec 2025 20:23:07 +0100 Subject: [PATCH 08/15] Add mtu support in http server --- html/ports.js | 105 +++++++++++++++++++++++++++++++++++++++------- httpd/httpd.c | 2 + httpd/page_impl.c | 22 ++++++++++ httpd/page_impl.h | 1 + 4 files changed, 115 insertions(+), 15 deletions(-) diff --git a/html/ports.js b/html/ports.js index 0396447..2c6ebf2 100644 --- a/html/ports.js +++ b/html/ports.js @@ -1,3 +1,4 @@ +var mtus = new Int16Array(10); function createPortTable() { var tbl = document.getElementById('speedtable'); if (tbl.rows.length <= 2 && numPorts) { @@ -29,6 +30,34 @@ function createPortTable() { td.innerHTML = button; } } + tbl = document.getElementById('mtutable'); + if (tbl.rows.length <= 2 && numPorts) { + const mSelect = ''; + var tr = tbl.insertRow(); + for (let i = 1; i <= numPorts; i++) { + let td = tr.insertCell(); + if (pIsSFP[i-1]) + td.innerHTML = '' + else + td.innerHTML = '' + } + tr = tbl.insertRow(); + for (let i = 1; i <= numPorts; i++) { + let td = tr.insertCell(); + td.innerHTML = mSelect.replaceAll("mtu_sel", "mtu_sel_" + i); + } + tr = tbl.insertRow(); + for (let i = 1; i <= numPorts; i++) { + let td = tr.insertCell(); + td.innerHTML = ''; + } + } } function updatePortTable() { @@ -42,27 +71,35 @@ function updatePortTable() { tbl.rows[i].cells[1].innerHTML = `${linkS[pState[i-1]+1]}`; var td = tbl.rows[i].cells[2]; var adv = pAdvertised[i-1]; - console.log("pAdvertised for " + i + " is " + adv); - if (pAdvertised[i-1] == 0) - td.innerHTML = "None"; - else if (adv == 0b100000) - td.innerHTML = "2.5GBit Full Duplex"; - else if (adv == 0b010000) - td.innerHTML = "1000MBit Full Duplex"; - else if (adv == 0b111111) - td.innerHTML = "AUTO"; - else if (adv == 0b000011) - td.innerHTML = "10MBit"; - else if (adv == 0b000100) - td.innerHTML = "100MBit Half Duplex"; + switch(pAdvertised[i-1]) { + case 0x20: + td.innerHTML = "2.5GBit Full Duplex"; break; + case 0x10: + td.innerHTML = "1000MBit Full Duplex"; break; + case 0x2f: + td.innerHTML = "AUTO"; break; + case 0xc: + td.innerHTML = "100MBit"; break; + case 8: + td.innerHTML = "100MBit Full Duplex"; break; + case 4: + td.innerHTML = "100MBit Half Duplex"; break; + case 3: + td.innerHTML = "10MBit"; break; + case 2: + td.innerHTML = "10MBit Full Duplex"; break; + case 1: + td.innerHTML = "10MBit Half Duplex"; break; + default: + td.innerHTML = "None"; break; + } } } async function applySpeed(port) { var speed = document.getElementById('speed_sel_' + port).value; var duplex = document.getElementById('duplex_sel_' + port).value; - var cmd = "port " + port + " "; - cmd = cmd + speed; + var cmd = "port " + port + " " + speed; console.log("port " + port, ", speed: " + speed, ", duplex: ", duplex); try { const response = await fetch('/cmd', { @@ -83,8 +120,46 @@ async function applySpeed(port) { } } +async function applyMTU(port) { + var mtu = document.getElementById('mtu_sel_' + port).value; + var cmd = "mtu " + port + " " + mtu; + try { + const response = await fetch('/cmd', { + method: 'POST', + body: cmd + }); + console.log('MTU Completed!', response); + getMTUs(); + } catch(err) { + console.error(`Error: ${err}`); + } +} + +function getMTUs() { + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + const s = JSON.parse(xhttp.responseText); + console.log("MTUS: ", JSON.stringify(s)); + for (let i = 0; i < s.length; i++) { + p = s[i]; + let n = p.portNum; + mtus[n] = parseInt(p.mtu, 16); + var mtu = document.getElementById('mtu_sel_' + n); + if (!mtu) + continue; + mtu.value = mtus[n]; + clearInterval(pMTUInterval); + } + } + }; + xhttp.open("GET", "/mtu.json", true); + xhttp.timeout = 1500; xhttp.send(); +} + window.addEventListener("load", function() { const updatePortTableInterval = setInterval(updatePortTable, 1000); }); const pTableInterval = setInterval(createPortTable, 1000); +const pMTUInterval = setInterval(getMTUs, 1200); diff --git a/httpd/httpd.c b/httpd/httpd.c index fa9b4cb..fff640e 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -570,6 +570,8 @@ void httpd_appcall(void) send_eee(); } else if (is_word(q, "/mirror.json")) { send_mirror(); + } else if (is_word(q, "/mtu.json")) { + send_mtu(); } else if (is_word(q, "/lag.json")) { send_lag(); } else if (is_word(q, "/config")) { diff --git a/httpd/page_impl.c b/httpd/page_impl.c index 62d5f07..589eefc 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -380,6 +380,28 @@ void send_eee(void) } } +void send_mtu(void) +{ + print_string("send_mtu called\n"); + slen = strtox(outbuf, HTTP_RESPONCE_JSON); + char_to_html('['); + for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + slen += strtox(outbuf + slen, "{\"portNum\":"); + itoa_html(machine.log_to_phys_port[i]); + slen += strtox(outbuf + slen, ",\"mtu\":\"0x"); + reg_read_m(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) i << 8)); + uint16_t mtu = SFR_DATA_U16 & 0x3fff; + byte_to_html(mtu >> 8); + byte_to_html(mtu & 0xff); + char_to_html('"'); + char_to_html('}'); + if (i < machine.max_port) + char_to_html(','); + else + char_to_html(']'); + } +} + void send_status(void) { diff --git a/httpd/page_impl.h b/httpd/page_impl.h index 166a79c..064a9df 100644 --- a/httpd/page_impl.h +++ b/httpd/page_impl.h @@ -7,6 +7,7 @@ void send_vlan(uint16_t vlan); void send_basic_info(void); void send_eee(void); void send_mirror(void); +void send_mtu(void); void send_config(void); void send_cmd_log(void); void send_lag(void); From b7cfc73752efe68a6e9d2644bef64d45769bf6a1 Mon Sep 17 00:00:00 2001 From: logicog Date: Thu, 18 Dec 2025 20:23:26 +0100 Subject: [PATCH 09/15] Add support in simulator for mtus --- tools/httpd_sim.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tools/httpd_sim.c b/tools/httpd_sim.c index 138faa9..1b9f5ac 100644 --- a/tools/httpd_sim.c +++ b/tools/httpd_sim.c @@ -286,6 +286,30 @@ void send_lag(int s) } +void send_mtu(int s) +{ + struct json_object *mtus, *v; + const char *jstring; + char *header = "HTTP/1.1 200 OK\r\n" + "Content-Type: application/json; charset=UTF-8\r\n\r\n"; + + mtus = json_object_new_array_ext(PORTS); + char mtu[8]; + for (int i = 1; i <= PORTS; i++) { + v = json_object_new_object(); + json_object_object_add(v, "portNum", json_object_new_int(i)); + sprintf(mtu, "0x%04x", i % 2 ? 16383 : 1522); + json_object_object_add(v, "mtu", json_object_new_string(mtu)); + json_object_array_add(mtus, v); + } + write(s, header, strlen(header)); + + jstring = json_object_to_json_string_ext(mtus, JSON_C_TO_STRING_PLAIN); + write(s, jstring, strlen(jstring)); + json_object_put(mtus); +} + + void send_cmd_log(int s) { char *header = "HTTP/1.1 200 OK\r\n" @@ -494,6 +518,13 @@ void launch(struct Server *server) else send_lag(new_socket); goto done; + } else if (!strncmp(&buffer[4], "/mtu.json", 9)) { + printf("MTU request\n"); + if (!authenticated) + send_unauthorized(new_socket); + else + send_mtu(new_socket); + goto done; } else if (!strncmp(&buffer[4], "/vlan.json?vid=", 15)) { int vlan = atoi(&buffer[19]); printf("VLAN request for %d\n", vlan); From 3af63af4a4d4c230528c5b139259f662074f0564 Mon Sep 17 00:00:00 2001 From: logicog Date: Thu, 18 Dec 2025 20:24:44 +0100 Subject: [PATCH 10/15] Add MTU setting in web-page --- html/main.js | 1 - html/ports.html | 5 +++- html/ports.js | 75 ++++++++++++++++++------------------------------- 3 files changed, 32 insertions(+), 49 deletions(-) diff --git a/html/main.js b/html/main.js index 6e8bceb..9c48581 100644 --- a/html/main.js +++ b/html/main.js @@ -100,7 +100,6 @@ function update() { } } else { pAdvertised[n] = parseInt(p.adv, 2); - console.log("Advertised " + n + " entry " + p.adv + " is now " + pAdvertised[n]); } iHTML += ""; tt.innerHTML = iHTML; diff --git a/html/ports.html b/html/ports.html index 6b15e50..84fe41e 100644 --- a/html/ports.html +++ b/html/ports.html @@ -11,7 +11,10 @@

Port Configuration

- + +
Port Current Link SpeedSelected Speed Set SpeedSet DuplexApply
Port Current Link SpeedSet SpeedDisabledApply
+

Configure Maximum Frame Size (MTU) forwarded at Port

+
diff --git a/html/ports.js b/html/ports.js index 2c6ebf2..3548bac 100644 --- a/html/ports.js +++ b/html/ports.js @@ -1,20 +1,19 @@ var mtus = new Int16Array(10); +var clicked = new Int8Array(10); function createPortTable() { var tbl = document.getElementById('speedtable'); if (tbl.rows.length <= 2 && numPorts) { clearInterval(pTableInterval); const sSelect = ''; - const dSelect = ''; + const dSwitch = '' for (let i = 1; i <= numPorts; i++) { if (pIsSFP[i-1]) continue; @@ -22,9 +21,9 @@ function createPortTable() { const tr = tbl.insertRow(); let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i}`)); td = tr.insertCell(); td.innerHTML = linkS[pState[i] + 1]; - td = tr.insertCell(); td.innerHTML = "Unknown"; td = tr.insertCell(); td.innerHTML = sSelect.replaceAll("speed_sel", "speed_sel_" + i); - td = tr.insertCell(); td.innerHTML = dSelect.replaceAll("duplex_sel", "duplex_sel_" + i); + td = tr.insertCell(); td.innerHTML = dSwitch.replaceAll("disable_port", "disable_port_" + i) + .replace("portOnOff()", "portOnOff(" + i + ")"); var button = ''; td = tr.insertCell(); td.innerHTML = button; @@ -69,57 +68,39 @@ function updatePortTable() { if (pIsSFP[i-1]) continue; tbl.rows[i].cells[1].innerHTML = `${linkS[pState[i-1]+1]}`; - var td = tbl.rows[i].cells[2]; - var adv = pAdvertised[i-1]; - switch(pAdvertised[i-1]) { - case 0x20: - td.innerHTML = "2.5GBit Full Duplex"; break; - case 0x10: - td.innerHTML = "1000MBit Full Duplex"; break; - case 0x2f: - td.innerHTML = "AUTO"; break; - case 0xc: - td.innerHTML = "100MBit"; break; - case 8: - td.innerHTML = "100MBit Full Duplex"; break; - case 4: - td.innerHTML = "100MBit Half Duplex"; break; - case 3: - td.innerHTML = "10MBit"; break; - case 2: - td.innerHTML = "10MBit Full Duplex"; break; - case 1: - td.innerHTML = "10MBit Half Duplex"; break; - default: - td.innerHTML = "None"; break; - } + if (!clicked[i] && pState[i - 1] < 0) { + document.getElementById('speed_sel_' + i).disabled = true; + document.getElementById('disable_port_' + i).checked = true; + } } } async function applySpeed(port) { var speed = document.getElementById('speed_sel_' + port).value; - var duplex = document.getElementById('duplex_sel_' + port).value; - var cmd = "port " + port + " " + speed; - console.log("port " + port, ", speed: " + speed, ", duplex: ", duplex); + var disabled = document.getElementById('disable_port_' + port).checked; + var cmd = "port " + port + " "; + if (!disabled) + cmd = cmd + speed; + else + cmd = cmd + "off"; + console.log("CMD: " + cmd); try { const response = await fetch('/cmd', { method: 'POST', body: cmd }); console.log('Completed!', response); - if (duplex != "any") { - cmd = "port " + port + " duplex " + duplex; - const response = await fetch('/cmd', { - method: 'POST', - body: cmd - }); - console.log('Completed!', response); - } } catch(err) { console.error(`Error: ${err}`); } } +async function portOnOff(p) { + var disabled = document.getElementById('disable_port_' + p).checked; + document.getElementById('speed_sel_' + p).disabled = disabled; + clicked[p] = 1; +} + async function applyMTU(port) { var mtu = document.getElementById('mtu_sel_' + port).value; var cmd = "mtu " + port + " " + mtu; From cad74017a9b22442669d3b19e18e19954110568c Mon Sep 17 00:00:00 2001 From: logicog Date: Thu, 18 Dec 2025 20:25:04 +0100 Subject: [PATCH 11/15] Remove white space in machine.h --- machine.h | 1 - 1 file changed, 1 deletion(-) diff --git a/machine.h b/machine.h index aa518bd..22d046f 100644 --- a/machine.h +++ b/machine.h @@ -39,4 +39,3 @@ typedef struct machine { }; #endif - From 367bef2b2fe1d0b9d4319b248df2a53f59627c9f Mon Sep 17 00:00:00 2001 From: logicog Date: Sun, 21 Dec 2025 16:53:10 +0100 Subject: [PATCH 12/15] Add defines for duplex modes --- phy.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/phy.h b/phy.h index 38eb088..53c0409 100644 --- a/phy.h +++ b/phy.h @@ -16,7 +16,6 @@ #define PHY_SDS_CTRL 30 #define PHY_MMD_CTRL 31 - /* * Define registers in Auto-Negotiation page */ @@ -34,4 +33,11 @@ * Define registers in Control page */ #define PHY_CTRL_5 0x7582 + +/* + * Duplex settings + */ +#define PHY_DUPLEX_HALF 0 +#define PHY_DUPLEX_FULL 1 +#define PHY_DUPLEX_BOTH 2 #endif From 2a7bfdc11984a6d7ab91d579f5186517767c9d11 Mon Sep 17 00:00:00 2001 From: logicog Date: Sun, 21 Dec 2025 16:58:42 +0100 Subject: [PATCH 13/15] Add duplex setting in PHY speed configuration --- rtl837x_phy.c | 20 +++++++++++++++----- rtl837x_phy.h | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/rtl837x_phy.c b/rtl837x_phy.c index 9e56e63..11732b7 100644 --- a/rtl837x_phy.c +++ b/rtl837x_phy.c @@ -184,8 +184,9 @@ void phy_config_8224(void) __banked /* * Set Speed of a PHY * See e.g. RTL8221B datasheet + * duplex: 0: half, 1: full, 2: both */ -void phy_set_speed(uint8_t port, uint8_t speed) __banked +void phy_set_speed(uint8_t port, uint8_t speed, uint8_t duplex) __banked { uint16_t v; phy_read(port, PHY_MMD_CTRL, 0xa610); @@ -213,11 +214,21 @@ void phy_set_speed(uint8_t port, uint8_t speed) __banked phy_write(port, PHY_MMD_AN, 0x00, 0x2000); // Clear bit 12: No Autoneg, Set Extended Pages (bit 13) if (speed == PHY_SPEED_10M) { phy_write(port, PHY_MMD_AN, 0x20, 0x6001); - phy_write(port, PHY_MMD_AN, 0x10, 0x1461); + if (!duplex) + phy_write(port, PHY_MMD_AN, 0x10, 0x1421); + else if (duplex == 1) + phy_write(port, PHY_MMD_AN, 0x10, 0x1441); + else + phy_write(port, PHY_MMD_AN, 0x10, 0x1461); phy_modify(port, PHY_MMD_CTRL, 0xa412, 0x0200, 0x0000); } else if (speed == PHY_SPEED_100M) { phy_write(port, PHY_MMD_AN, 0x20, 0x6001); - phy_write(port, PHY_MMD_AN, 0x10, 0x1581); + if (!duplex) + phy_write(port, PHY_MMD_AN, 0x10, 0x1481); + if (duplex == 1) + phy_write(port, PHY_MMD_AN, 0x10, 0x1501); + else + phy_write(port, PHY_MMD_AN, 0x10, 0x1581); phy_modify(port, PHY_MMD_CTRL, 0xa412, 0x0200, 0x0000); } else { // AN Advertisement Register (MMD 7.0x0010) @@ -286,8 +297,7 @@ void phy_show(uint8_t port) __banked print_string("\nLink speed: "); phy_read(port, PHY_MMD_CTRL, 0xA434); v = SFR_DATA_U16; - v = ((v & 0x0600) >> 7) | ((v & 0x0030) >> 4); - switch(v) { + switch(((v & 0x0600) >> 7) | ((v & 0x0030) >> 4)) { case 0: print_string("10M"); break; diff --git a/rtl837x_phy.h b/rtl837x_phy.h index 49a13c6..d5bd2de 100644 --- a/rtl837x_phy.h +++ b/rtl837x_phy.h @@ -13,7 +13,7 @@ void rtl8224_phy_enable(void) __banked; void phy_config(uint8_t phy) __banked; void phy_config_8224(void) __banked; -void phy_set_speed(uint8_t port, uint8_t speed) __banked; +void phy_set_speed(uint8_t port, uint8_t speed, uint8_t duplex) __banked; void phy_set_duplex(uint8_t port, uint8_t fullduplex) __banked; void phy_show(uint8_t port) __banked; void phy_reset(uint8_t port) __banked; From 4878a36638aed5cea71509e020cd1441d6fcf67f Mon Sep 17 00:00:00 2001 From: logicog Date: Sun, 21 Dec 2025 16:59:54 +0100 Subject: [PATCH 14/15] Use changed signatures in parse_port for PHY speed setting --- cmd_parser.c | 57 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/cmd_parser.c b/cmd_parser.c index b3c4b60..e5bb099 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -17,6 +17,7 @@ #include "version.h" #include "machine.h" +#include "phy.h" #pragma codeseg BANK1 #pragma constseg BANK1 @@ -420,36 +421,47 @@ void parse_port(void) print_string(" is SFP no PHY information available.\n"); return; } - if (cmd_words_b[2] > 0 && cmd_compare(2, "10m")) { + if (cmd_words_b[2] <= 0) { + print_string("\nport [show|on|off|10m|100m|1g|2g5] [half|full]"); + return; + } + if (cmd_compare(2, "10m")) { print_string(" 10M\n"); - phy_set_speed(p, PHY_SPEED_10M); - } - if (cmd_words_b[2] > 0 && cmd_compare(2, "100m")) { + if (cmd_words_b[3] > 0 && cmd_compare(3, "half")) + phy_set_speed(p, PHY_SPEED_10M, PHY_DUPLEX_HALF); + else if (cmd_words_b[3] > 0 && cmd_compare(3, "full")) + phy_set_speed(p, PHY_SPEED_10M, PHY_DUPLEX_FULL); + else + phy_set_speed(p, PHY_SPEED_10M, PHY_DUPLEX_BOTH); + } else if (cmd_compare(2, "100m")) { print_string(" 100M\n"); - phy_set_speed(p, PHY_SPEED_100M); - } - if (cmd_words_b[2] > 0 && cmd_compare(2, "2g5")) { + if (cmd_words_b[3] > 0 && cmd_compare(3, "half")) + phy_set_speed(p, PHY_SPEED_100M, PHY_DUPLEX_HALF); + else if (cmd_words_b[3] > 0 && cmd_compare(3, "full")) + phy_set_speed(p, PHY_SPEED_100M, PHY_DUPLEX_FULL); + else + phy_set_speed(p, PHY_SPEED_100M, PHY_DUPLEX_BOTH); + } else if (cmd_compare(2, "2g5")) { print_string(" 2.5G\n"); - phy_set_speed(p, PHY_SPEED_2G5); - } - if (cmd_words_b[2] > 0 && cmd_compare(2, "1g")) { + phy_set_speed(p, PHY_SPEED_2G5, PHY_DUPLEX_BOTH); + } else if (cmd_compare(2, "1g")) { print_string(" 1G\n"); - phy_set_speed(p, PHY_SPEED_1G); - } - if (cmd_words_b[2] > 0 && cmd_compare(2, "auto")) { + phy_set_speed(p, PHY_SPEED_1G, PHY_DUPLEX_BOTH); + } else if (cmd_compare(2, "auto")) { print_string(" AUTO\n"); - phy_set_speed(p, PHY_SPEED_AUTO); - } - if (cmd_words_b[2] > 0 && cmd_compare(2, "off")) { + phy_set_speed(p, PHY_SPEED_AUTO, PHY_DUPLEX_BOTH); + } else if (cmd_compare(2, "off")) { print_string(" OFF\n"); - phy_set_speed(p, PHY_OFF); - } - if (cmd_words_b[2] > 0 && cmd_compare(2, "duplex")) { + phy_set_speed(p, PHY_OFF, PHY_DUPLEX_BOTH); + } else if (cmd_compare(2, "on")) { + print_string(" ON\n"); + phy_set_speed(p, PHY_SPEED_AUTO, PHY_DUPLEX_BOTH); + } else if (cmd_compare(2, "duplex")) { print_string(" DUPLEX\n"); if (cmd_words_b[3] > 0 && cmd_compare(3, "full")) - phy_set_duplex(p, 1); + phy_set_duplex(p, PHY_DUPLEX_FULL); else - phy_set_duplex(p, 0); + phy_set_duplex(p, PHY_DUPLEX_HALF); } if (cmd_words_b[2] > 0 && cmd_compare(2, "show")) { phy_show(p); @@ -462,13 +474,12 @@ void parse_mtu(void) __xdata uint16_t mtu; uint8_t p; - print_string("\nMTU "); if (cmd_words_b[1] > 0 && cmd_compare(1, "show")) { for (p = machine.min_port; p <= machine.max_port; p++) { reg_read_m(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8)); mtu = SFR_DATA_U16 & 0x3fff; print_string("Port "); print_byte(machine.log_to_phys_port[p]); - print_string(" MTU: 0x"); print_short(mtu); write_char('\n'); + write_char(' '); print_short(mtu); write_char('\n'); } } p = cmd_buffer[cmd_words_b[1]] - '1'; From 34a0e2d338c4aebb42011862db2e02d1791318ad Mon Sep 17 00:00:00 2001 From: logicog Date: Mon, 22 Dec 2025 23:29:51 +0100 Subject: [PATCH 15/15] Right align speed option selection --- html/style.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/html/style.css b/html/style.css index 477cca1..b27ad56 100644 --- a/html/style.css +++ b/html/style.css @@ -160,3 +160,5 @@ margin: 30px 0; .tt_table td { text-align: left; } +select { text-align-last: right; font-family: monospace} +option { direction: rtl; font-family: sans-serif}