-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserial-protocol.js
More file actions
124 lines (107 loc) · 3.05 KB
/
serial-protocol.js
File metadata and controls
124 lines (107 loc) · 3.05 KB
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
116
117
118
119
120
121
122
123
124
const MODULE_IDS = ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
function normalizeLine(line) {
return String(line || '').trim().replace(/^-\s*/, '');
}
function parseReadingLine(line) {
const normalizedLine = normalizeLine(line);
const match = normalizedLine.match(
/^module\s+(\d+)\s+(cells\[mV\]|temp\[C\])\s+min=(-?\d+(?:\.\d+)?)\s+max=(-?\d+(?:\.\d+)?)\s+avg=(-?\d+(?:\.\d+)?)(?:\s+(.*))?$/i
);
if (!match) {
return null;
}
const [, moduleId, readingType, minValue, maxValue, avgValue, remainder = ''] = match;
const values = [];
const valuePattern = /([CT])(\d+):\s*(-?\d+(?:\.\d+)?)/g;
let valueMatch;
while ((valueMatch = valuePattern.exec(remainder)) !== null) {
values.push({
prefix: valueMatch[1].toUpperCase(),
index: Number(valueMatch[2]),
value: Number(valueMatch[3])
});
}
return {
type: 'module-reading',
payload: {
moduleId,
readingType: readingType.toLowerCase(),
min: Number(minValue),
max: Number(maxValue),
avg: Number(avgValue),
values
}
};
}
function parseStatusLine(line) {
const normalizedLine = normalizeLine(line);
const match = normalizedLine.match(/^status\s+(BMS|board|voltage|temp):\s*([A-Z_]+)$/i);
if (!match) {
return null;
}
return {
type: 'status-update',
payload: {
target: match[1].toLowerCase(),
value: match[2].toUpperCase()
}
};
}
function parseBalancingLine(line) {
const normalizedLine = normalizeLine(line);
if (!normalizedLine.startsWith('balancing ')) {
return null;
}
if (normalizedLine === 'balancing off') {
return {
type: 'balancing-update',
payload: {
enabled: false,
activeCells: []
}
};
}
const activeCells = [];
const pairPattern = /(\d+)-(\d+)/g;
let match;
while ((match = pairPattern.exec(normalizedLine)) !== null) {
activeCells.push(`${Number(match[1])}-${Number(match[2])}`);
}
return {
type: 'balancing-update',
payload: {
enabled: activeCells.length > 0,
activeCells
}
};
}
function parseModuleSiliconIdsLine(line) {
const normalizedLine = normalizeLine(line);
const match = normalizedLine.match(/^module\s+silicon\s+ids:\s*(.*)$/i);
if (!match) {
return null;
}
const rawIds = match[1]
.trim()
.split(/\s+/)
.slice(0, MODULE_IDS.length);
return {
type: 'module-silicon-ids',
payload: MODULE_IDS.map((moduleId, index) => ({
moduleId,
siliconId: rawIds[index] ?? '-'
}))
};
}
function parseSerialCommand(line) {
return (
parseStatusLine(line) ||
parseBalancingLine(line) ||
parseModuleSiliconIdsLine(line) ||
parseReadingLine(line)
);
}
module.exports = {
normalizeLine,
parseSerialCommand
};