Merge pull request #183 from janh/fix-i2c-and-sfp-ddm

Fix I2C access and SFP diagnostic monitoring in web interface
This commit is contained in:
René van Dorst
2026-03-30 17:21:51 +00:00
committed by GitHub
3 changed files with 109 additions and 16 deletions
+85 -5
View File
@@ -40,6 +40,82 @@ function drawPorts() {
} }
} }
function parseUint16(val) {
return parseInt(val, 16) & 0xffff;
}
function parseInt16(val) {
let valInt = parseInt(val, 16);
let num = valInt & 0x7fff;
if (valInt & 0x8000) {
return num - 0x8000;
}
return num;
}
function applyCalibrationSlopeOffset(val, cal) {
if (typeof cal !== 'string') {
return val;
}
if (cal.startsWith("0x")) {
cal = cal.substring(2);
}
if (cal.length != 8) {
return val;
}
let slope = parseUint16(cal.substring(0, 4)) / 256;
let offset = parseInt16(cal.substring(4, 8));
return slope * val + offset;
}
function applyRxPowerCalibration(val, cal) {
if (typeof cal !== 'string') {
return val;
}
if (cal.startsWith("0x")) {
cal = cal.substring(2);
}
if (cal.length != 40) {
return val;
}
let bytes = cal.match(/.{1,2}/g).map(function (x) { return parseInt(x, 16); });
let view = new DataView(new Uint8Array(bytes).buffer);
return view.getFloat32(0) * Math.pow(val, 4)
+ view.getFloat32(4) * Math.pow(val, 3)
+ view.getFloat32(8) * Math.pow(val, 2)
+ view.getFloat32(12) * val
+ view.getFloat32(16);
}
function decodeSfpTemp(val, cal) {
let temp = parseInt16(val);
return applyCalibrationSlopeOffset(temp, cal) / 256;
}
function decodeSfpVcc(val, cal) {
let vcc = parseUint16(val);
return applyCalibrationSlopeOffset(vcc, cal) / 10000;
}
function decodeSfpTxBias(val, cal) {
let bias = parseUint16(val);
return applyCalibrationSlopeOffset(bias, cal) / 500;
}
function decodeSfpTxPower(val, cal) {
let txPower = parseUint16(val);
return applyCalibrationSlopeOffset(txPower, cal) / 10000;
}
function decodeSfpRxPower(val, cal) {
let rxPower = parseUint16(val);
return applyRxPowerCalibration(rxPower, cal) / 10000;
}
function convertPowerTodBm(val) {
return 10 * Math.log10(val);
}
function update(callback) { function update(callback) {
var xhttp = new XMLHttpRequest(); var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() { xhttp.onreadystatechange = function() {
@@ -98,13 +174,17 @@ function update(callback) {
iHTML += "<tr><td>Model</td><td>:</td><td>" + p.sfp_model + "</td></tr>"; iHTML += "<tr><td>Model</td><td>:</td><td>" + p.sfp_model + "</td></tr>";
iHTML += "<tr><td>Serial</td><td>:</td><td>" + p.sfp_serial + "</td></tr>"; iHTML += "<tr><td>Serial</td><td>:</td><td>" + p.sfp_serial + "</td></tr>";
if (hasExtendedStatus) { if (hasExtendedStatus) {
iHTML += "<tr><td>Temp</td><td>:</td><td>" + (Number(p.sfp_temp) >> 8) + "." + ((Number(p.sfp_temp) & 0xff)/256.0 * 100).toFixed(0) + "&#8239;&#8451;</td></tr>"; let txPower = decodeSfpTxPower(p.sfp_txpower, p.sfp_txpower_cal);
iHTML += "<tr><td>Vcc</td><td>:</td><td>" + (Number(p.sfp_vcc) / 10000.0).toFixed(2) + "&#8239;V</td></tr>"; let txPowerdBm = convertPowerTodBm(txPower);
let rxPower = decodeSfpRxPower(p.sfp_rxpower, p.sfp_rxpower_cal);
let rxPowerdBm = convertPowerTodBm(rxPower);
iHTML += "<tr><td>Temp</td><td>:</td><td>" + decodeSfpTemp(p.sfp_temp, p.sfp_temp_cal).toFixed(2) + "&#8239;&#8451;</td></tr>";
iHTML += "<tr><td>Vcc</td><td>:</td><td>" + decodeSfpVcc(p.sfp_vcc, p.sfp_vcc_cal).toFixed(2) + "&#8239;V</td></tr>";
iHTML += "<tr><td>TX-Fault</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x4)) + "</td></tr>"; iHTML += "<tr><td>TX-Fault</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x4)) + "</td></tr>";
iHTML += "<tr><td>TX-Disabled</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x80)) + "</td></tr>"; iHTML += "<tr><td>TX-Disabled</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x80)) + "</td></tr>";
iHTML += "<tr><td>TX-Bias</td><td>:</td><td>" + (Number(p.sfp_txbias) / 500.0).toFixed(1) + "&#8239;mA</td></tr>"; iHTML += "<tr><td>TX-Bias</td><td>:</td><td>" + decodeSfpTxBias(p.sfp_txbias, p.sfp_txbias_cal).toFixed(1) + "&#8239;mA</td></tr>";
iHTML += "<tr><td>TX-Power</td><td>:</td><td>" + (Number(p.sfp_txpower) / 10.0).toFixed(0) + "&#8239;mW</td></tr>"; iHTML += "<tr><td>TX-Power</td><td>:</td><td>" + txPower.toFixed(3) + "&#8239;mW / " + txPowerdBm.toFixed(2) + "&#8239;dBm</td></tr>";
iHTML += "<tr><td>RX-Power</td><td>:</td><td>" + (Number(p.sfp_rxpower) / 10.0).toFixed(0) + "&#8239;mW</td></tr>"; iHTML += "<tr><td>RX-Power</td><td>:</td><td>" + rxPower.toFixed(3) + "&#8239;mW / " + rxPowerdBm.toFixed(2) + "&#8239;dBm</td></tr>";
} }
// Not all devices & modules have LOS pin... // Not all devices & modules have LOS pin...
const rx_los_pin = p.sfp_los !== null ? Boolean(Number(p.sfp_los)) : null; const rx_los_pin = p.sfp_los !== null ? Boolean(Number(p.sfp_los)) : null;
+21 -8
View File
@@ -175,11 +175,15 @@ void send_sfp_info(uint8_t sfp)
void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len) void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len)
{ {
// maximum supported transfer size is 16 bytes
if (len > 16)
return;
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address
reg &= 0x7f; reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | len & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff); REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff);
} else { } else {
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | len & 0xf, 0x50 >> 5, (0x50 << 3) & 0xff); REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x50 >> 5, (0x50 << 3) & 0xff);
} }
reg_read_m(RTL837X_REG_I2C_CTRL); reg_read_m(RTL837X_REG_I2C_CTRL);
@@ -196,12 +200,9 @@ void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len)
reg_read_m(RTL837X_REG_I2C_CTRL); reg_read_m(RTL837X_REG_I2C_CTRL);
} while (sfr_data[3] & 0x1); } while (sfr_data[3] & 0x1);
for (uint8_t i = 0; i < len & 0xf; i++) { for (uint8_t i = 0; i < len; i++) {
if (!(i & 0x3)) if (!(i & 0x3))
reg_read_m(RTL837X_REG_I2C_OUT + (i >> 2)); reg_read_m(RTL837X_REG_I2C_OUT + i);
if (len & 0x80)
char_to_html(sfr_data[3 - (i & 0x3)]);
else
byte_to_html(sfr_data[3 - (i & 0x3)]); byte_to_html(sfr_data[3 - (i & 0x3)]);
} }
} }
@@ -640,7 +641,6 @@ void send_status(void)
slen += strtox(outbuf + slen,",\"sfp_options\":\"0x"); slen += strtox(outbuf + slen,",\"sfp_options\":\"0x");
byte_to_html(sfp_options[machine.is_sfp[i]-1]); byte_to_html(sfp_options[machine.is_sfp[i]-1]);
if (sfp_options[machine.is_sfp[i]-1] & 0x40) { if (sfp_options[machine.is_sfp[i]-1] & 0x40) {
sfp_send_data(machine.is_sfp[i] - 1, 92, 1);
slen += strtox(outbuf + slen,"\",\"sfp_temp\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_temp\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 224, 2); sfp_send_data(machine.is_sfp[i] - 1, 224, 2);
slen += strtox(outbuf + slen,"\",\"sfp_vcc\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_vcc\":\"0x");
@@ -651,6 +651,19 @@ void send_status(void)
sfp_send_data(machine.is_sfp[i] - 1, 230, 2); sfp_send_data(machine.is_sfp[i] - 1, 230, 2);
slen += strtox(outbuf + slen,"\",\"sfp_rxpower\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_rxpower\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 232, 2); sfp_send_data(machine.is_sfp[i] - 1, 232, 2);
if (sfp_options[machine.is_sfp[i]-1] & 0x10) {
slen += strtox(outbuf + slen,"\",\"sfp_temp_cal\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 212, 4);
slen += strtox(outbuf + slen,"\",\"sfp_vcc_cal\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 216, 4);
slen += strtox(outbuf + slen,"\",\"sfp_txbias_cal\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 204, 4);
slen += strtox(outbuf + slen,"\",\"sfp_txpower_cal\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 208, 4);
slen += strtox(outbuf + slen,"\",\"sfp_rxpower_cal\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 184, 16);
sfp_send_data(machine.is_sfp[i] - 1, 200, 4);
}
slen += strtox(outbuf + slen,"\",\"sfp_state\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_state\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 238, 1); sfp_send_data(machine.is_sfp[i] - 1, 238, 1);
} }
+2 -2
View File
@@ -892,9 +892,9 @@ uint8_t sfp_read_reg(uint8_t slot, uint8_t reg)
{ {
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address
reg &= 0x7f; reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 1, 0x51 >> 5, (0x51 << 3) & 0xff); REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x51 >> 5, (0x51 << 3) & 0xff);
} else { } else {
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 1, 0x50 >> 5, (0x50 << 3) & 0xff); REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x50 >> 5, (0x50 << 3) & 0xff);
} }
reg_read_m(RTL837X_REG_I2C_CTRL); reg_read_m(RTL837X_REG_I2C_CTRL);