forked from arduino/arduino-serial-plotter-webapp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmsgAggregatorWorker.ts
115 lines (98 loc) · 3.34 KB
/
msgAggregatorWorker.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Worker.ts
// eslint-disable-next-line no-restricted-globals
const ctx: Worker = self as any;
// Respond to message from parent thread
ctx.addEventListener("message", (event) => {
const { command, message } = event.data;
if (command === "cleanup") {
buffer = "";
discardFirstLine = true;
}
if (message) {
ctx.postMessage(parseSerialMessages(message));
}
});
let buffer = "";
let discardFirstLine = true;
const separator = "\n";
var re = new RegExp(`(${separator})`, "g");
export const parseSerialMessages = (
messages: string[]
): {
datasetNames: string[];
parsedLines: { [key: string]: number }[];
} => {
// when the serial is real fast, the first line can be incomplete and contain incomplete messages
// so we need to discard it and start aggregating from the first encountered separator
let joinMessages = messages.join("");
if (discardFirstLine) {
const firstSeparatorIndex = joinMessages.indexOf(separator);
if (firstSeparatorIndex > -1) {
joinMessages = joinMessages.substring(
firstSeparatorIndex + separator.length
);
discardFirstLine = false;
} else {
return {
datasetNames: [],
parsedLines: [],
};
}
}
//add any leftover from the buffer to the first line
const messagesAndBuffer = ((buffer || "") + joinMessages)
.split(re)
.filter((message) => message.length > 0);
// remove the previous buffer
buffer = "";
// check if the last message contains the delimiter, if not, it's an incomplete string that needs to be added to the buffer
if (messagesAndBuffer[messagesAndBuffer.length - 1] !== separator) {
buffer = messagesAndBuffer[messagesAndBuffer.length - 1];
messagesAndBuffer.splice(-1);
}
const datasetNames: { [key: string]: boolean } = {};
const parsedLines: { [key: string]: number }[] = [];
// for each line, explode variables
messagesAndBuffer
.filter((message) => message !== separator)
.forEach((message) => {
const parsedLine: { [key: string]: number } = {};
//there are two supported formats:
// format1: <value1> <value2> <value3>
// format2: name1:<value1>,name2:<value2>,name3:<value3>
// if we find a colon, we assume the latter is being used
let tokens: string[] = [];
if (message.indexOf(":") > 0) {
message.split(",").forEach((keyValue: string) => {
let [key, value] = keyValue.split(":");
key = key && key.trim();
value = value && value.trim();
if (key && key.length > 0 && value && value.length > 0) {
tokens.push(...[key, value]);
}
});
} else {
// otherwise they are spaces
const values = message.split(/\s/);
values.forEach((value, i) => {
if (value.length) {
tokens.push(...[`value ${i + 1}`, value]);
}
});
}
for (let i = 0; i < tokens.length - 1; i = i + 2) {
const varName = tokens[i];
const varValue = parseFloat(tokens[i + 1]);
//skip line endings
if (varName.length === 0) {
continue;
}
// add the variable to the map of variables
datasetNames[varName] = true;
parsedLine[varName] = varValue;
}
parsedLines.push(parsedLine);
});
return { parsedLines, datasetNames: Object.keys(datasetNames) };
};
export {};