diff --git a/html/main.js b/html/main.js
index d9ed749..8eefa01 100644
--- a/html/main.js
+++ b/html/main.js
@@ -40,6 +40,78 @@ 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 update(callback) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
@@ -98,13 +170,13 @@ function update(callback) {
iHTML += "
| Model | : | " + p.sfp_model + " |
";
iHTML += "| Serial | : | " + p.sfp_serial + " |
";
if (hasExtendedStatus) {
- iHTML += "| Temp | : | " + (Number(p.sfp_temp) >> 8) + "." + ((Number(p.sfp_temp) & 0xff)/256.0 * 100).toFixed(0) + " ℃ |
";
- iHTML += "| Vcc | : | " + (Number(p.sfp_vcc) / 10000.0).toFixed(2) + " V |
";
+ iHTML += "| Temp | : | " + decodeSfpTemp(p.sfp_temp, p.sfp_temp_cal).toFixed(2) + " ℃ |
";
+ iHTML += "| Vcc | : | " + decodeSfpVcc(p.sfp_vcc, p.sfp_vcc_cal).toFixed(2) + " V |
";
iHTML += "| TX-Fault | : | " + (Boolean(Number(p.sfp_state) & 0x4)) + " |
";
iHTML += "| TX-Disabled | : | " + (Boolean(Number(p.sfp_state) & 0x80)) + " |
";
- iHTML += "| TX-Bias | : | " + (Number(p.sfp_txbias) / 500.0).toFixed(1) + " mA |
";
- iHTML += "| TX-Power | : | " + (Number(p.sfp_txpower) / 10000.0).toFixed(3) + " mW |
";
- iHTML += "| RX-Power | : | " + (Number(p.sfp_rxpower) / 10000.0).toFixed(3) + " mW |
";
+ iHTML += "| TX-Bias | : | " + decodeSfpTxBias(p.sfp_txbias, p.sfp_txbias_cal).toFixed(1) + " mA |
";
+ iHTML += "| TX-Power | : | " + decodeSfpTxPower(p.sfp_txpower, p.sfp_txpower_cal).toFixed(3) + " mW |
";
+ iHTML += "| RX-Power | : | " + decodeSfpRxPower(p.sfp_rxpower, p.sfp_rxpower_cal).toFixed(3) + " mW |
";
}
// Not all devices & modules have LOS pin...
const rx_los_pin = p.sfp_los !== null ? Boolean(Number(p.sfp_los)) : null;
diff --git a/httpd/page_impl.c b/httpd/page_impl.c
index c40dca3..b49f356 100644
--- a/httpd/page_impl.c
+++ b/httpd/page_impl.c
@@ -651,6 +651,19 @@ void send_status(void)
sfp_send_data(machine.is_sfp[i] - 1, 230, 2);
slen += strtox(outbuf + slen,"\",\"sfp_rxpower\":\"0x");
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");
sfp_send_data(machine.is_sfp[i] - 1, 238, 1);
}