Help: the problem of realizing serial communication using Web Serial API. Every 1000ms, my sensor will send a piece of data with a format similar to "CH1CH2CH3: 2.408130 2.456470 13152-1552 9440", and I need to obtain two groups of decimals represented by CH1 and CH2, that is, the first two decimals are assigned values for V1 and V2 respectively, and the subsequent calculations are also based on this. Now I can receive data after opening the serial port connection, but V1 and V2 are displayed as "NAN", that is, null values, and the console shows that I have successfully received the data. I suspect that there is something wrong with my data analysis, but I can't solve it at present. Do any bosses know how to modify my code?
What I have tried:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>针灸数据采集</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/x-icon" href="data:image/png;base64,iVBORw0KGgo=">
<meta charset="utf-8" />
</head>
<body>
<canvas id="myChart" height="60px"></canvas>
<div>
<button id="butConnect">打开连接</button>
<span style="padding: 1%"></span>
<button id="butEnd">关闭连接</button>
<span style="padding: 1%"></span>
<button id="butClearData">清空接收数据</button>
</div>
<div style="margin: 10px">
<label for="ch1-average">前端电压平均值:</label>
<input type="text" id="ch1-average" readonly />
<label for="ch2-average">后端电压平均值:</label>
<input type="text" id="ch2-average" readonly />
<label for="ch1-variance">前端电压方差:</label>
<input type="text" id="ch1-variance" readonly />
<label for="ch2-variance">后端电压方差:</label>
<input type="text" id="ch2-variance" readonly />
</div>
<div style="margin: 10px">接收数据:</div>
<div id="received-data-list" style="border: groove; margin: 10px"></div>
<script>
var ctx = document.getElementById("myChart").getContext("2d");
var chart = new Chart(ctx, {
type: "line",
data: {
labels: [],
datasets: [
{
label: "前端薄膜电压",
borderColor: "rgb(255, 99, 132)",
data: [],
fill: false,
},
{
label: "后端薄膜电压",
borderColor: "blue",
data: [],
fill: false,
},
],
},
options: {
title: {
display: true,
text: new Date().toLocaleDateString(),
},
},
});
const dataList = document.getElementById("received-data-list");
let keepReading = true;
let reader;
let writer;
let receivedBytes = new Uint8Array();
const frameLength = 43;
const dataArr = [];
document.getElementById("butConnect").addEventListener("click", async () => {
try {
const port = await navigator.serial.requestPort();
await port.open({ baudRate: 9600 });
keepReading = true;
reader = port.readable.getReader();
writer = port.writable.getWriter();
console.log("Port opened successfully");
receivedBytes = new Uint8Array();
dataList.innerHTML = "";
chart.data.labels = [];
chart.data.datasets[0].data = [];
chart.data.datasets[1].data = [];
chart.update();
console.log("All data cleared");
const writeInt = setInterval(async () => {
await writer.ready;
const commandframe = new TextEncoder().encode("read_data");
await writer.write(commandframe);
console.log("Command frame written");
}, 1000);
while (port.readable && keepReading) {
try {
const { value, done } = await reader.read();
if (done) {
reader.releaseLock();
writer.releaseLock();
break;
}
if (value) {
receivedBytes = concatBytes(receivedBytes, value);
if (receivedBytes.length >= frameLength) {
const receivedData = new TextDecoder().decode(receivedBytes);
console.log(`Received data: ${receivedData}`);
let parsedData = receivedData.match(/^CH[1-3]\s(CH1\s+([\d\.]+)\s+)?(CH2\s+([\d\.]+)\s+)?(CH3\s+([\d\.]+)\s+)?/);
if (parsedData) {
let V1 = parseFloat(parsedData[2]);
let V2 = parseFloat(parsedData[4]);
let datatime = new Date();
let frame = {
datatime,
V1,
V2,
};
console.log(`Valid data: ${frame}`);
dataArr.push(frame);
dataList.innerHTML += `<p>[${datatime.toLocaleString()}] -> V1: ${V1}, V2: ${V2}</p>`;
chart.data.labels.push(datatime.toLocaleTimeString());
chart.data.datasets[0].data.push(frame.V1);
chart.data.datasets[1].data.push(frame.V2);
chart.update();
console.log("Chart updated");
}
receivedBytes = new Uint8Array();
}
}
} catch (error) {
console.error(error);
} finally {
console.log("Reading loop finished");
}
}
clearInterval(writeInt);
await port.close();
console.log("Port closed");
} catch (error) {
console.error(error);
}
});
document.getElementById("butEnd").addEventListener("click", async () => {
keepReading = false;
reader.cancel();
const jsonHandle = await window.showSaveFilePicker();
const writableStream = await jsonHandle.createWritable();
const aBlob = new Blob([JSON.stringify(dataArr)], {
type: "text/plain",
});
await writableStream.write(aBlob);
receivedBytes = new Uint8Array();
await writableStream.close();
console.log("Data saved to file");
let filteredArr = dataArr.filter((item) => item.datatime >= openTimestamp);
let ch1Arr = filteredArr.map((item) => item.V1);
let ch2Arr = filteredArr.map((item) => item.V2);
let ch1Avg = ch1Arr.reduce((acc, val) => acc + val, 0) / ch1Arr.length;
let ch2Avg = ch2Arr.reduce((acc, val) => acc + val, 0) / ch2Arr.length;
let ch1Variance = ch1Arr.reduce((acc, val) => acc + (val - ch1Avg) ** 2, 0) / ch1Arr.length;
let ch2Variance = ch2Arr.reduce((acc, val) => acc + (val - ch2Avg) ** 2, 0) / ch2Arr.length;
document.getElementById("ch1-average").value = ch1Avg.toFixed(6);
document.getElementById("ch2-average").value = ch2Avg.toFixed(6);
document.getElementById("ch1-variance").value = ch1Variance.toFixed(6);
document.getElementById("ch2-variance").value = ch2Variance.toFixed(6);
console.log("Data analysis completed and results displayed");
});
document.getElementById("butClearData").addEventListener("click", () => {
receivedBytes = new Uint8Array();
dataList.innerHTML = "";
chart.data.labels = [];
chart.data.datasets[0].data = [];
chart.data.datasets[1].data = [];
chart.update();
console.log("All data cleared");
});
function concatBytes(uint8a, uint8b) {
let tmp = new Uint8Array(uint8a.length + uint8b.length);
tmp.set(uint8a, 0);
tmp.set(uint8b, uint8a.length);
return tmp;
}
</script>
</body>
</html>