@robotical/raftjs 1.4.7 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react-native/RaftAttributeHandler.d.ts +2 -0
- package/dist/react-native/RaftAttributeHandler.js +136 -10
- package/dist/react-native/RaftAttributeHandler.js.map +1 -1
- package/dist/react-native/RaftChannel.d.ts +2 -0
- package/dist/react-native/RaftChannelBLE.native.d.ts +2 -0
- package/dist/react-native/RaftChannelBLE.native.js +14 -7
- package/dist/react-native/RaftChannelBLE.native.js.map +1 -1
- package/dist/react-native/RaftChannelBLE.web.d.ts +2 -0
- package/dist/react-native/RaftChannelBLE.web.js +24 -15
- package/dist/react-native/RaftChannelBLE.web.js.map +1 -1
- package/dist/react-native/RaftChannelSimulated.d.ts +32 -0
- package/dist/react-native/RaftChannelSimulated.js +418 -0
- package/dist/react-native/RaftChannelSimulated.js.map +1 -0
- package/dist/react-native/RaftChannelWebSerial.d.ts +2 -0
- package/dist/react-native/RaftChannelWebSerial.js +18 -9
- package/dist/react-native/RaftChannelWebSerial.js.map +1 -1
- package/dist/react-native/RaftChannelWebSocket.d.ts +2 -0
- package/dist/react-native/RaftChannelWebSocket.js +10 -0
- package/dist/react-native/RaftChannelWebSocket.js.map +1 -1
- package/dist/react-native/RaftConnector.js +13 -6
- package/dist/react-native/RaftConnector.js.map +1 -1
- package/dist/react-native/RaftCustomAttrHandler.js +15 -0
- package/dist/react-native/RaftCustomAttrHandler.js.map +1 -1
- package/dist/react-native/RaftDeviceInfo.d.ts +8 -1
- package/dist/react-native/RaftDeviceInfo.js +17 -3
- package/dist/react-native/RaftDeviceInfo.js.map +1 -1
- package/dist/react-native/RaftDeviceManager.d.ts +3 -0
- package/dist/react-native/RaftDeviceManager.js +123 -43
- package/dist/react-native/RaftDeviceManager.js.map +1 -1
- package/dist/react-native/RaftFileHandler.js +8 -8
- package/dist/react-native/RaftFileHandler.js.map +1 -1
- package/dist/react-native/RaftLog.js +1 -1
- package/dist/react-native/RaftLog.js.map +1 -1
- package/dist/react-native/RaftMsgHandler.d.ts +5 -0
- package/dist/react-native/RaftMsgHandler.js +32 -0
- package/dist/react-native/RaftMsgHandler.js.map +1 -1
- package/dist/react-native/RaftStreamHandler.js +6 -5
- package/dist/react-native/RaftStreamHandler.js.map +1 -1
- package/dist/react-native/RaftStruct.js +197 -147
- package/dist/react-native/RaftStruct.js.map +1 -1
- package/dist/react-native/RaftSysTypeManager.d.ts +2 -0
- package/dist/react-native/RaftSysTypeManager.js +25 -0
- package/dist/react-native/RaftSysTypeManager.js.map +1 -1
- package/dist/react-native/RaftSystemType.d.ts +9 -7
- package/dist/react-native/RaftSystemUtils.js +3 -1
- package/dist/react-native/RaftSystemUtils.js.map +1 -1
- package/dist/react-native/RaftUpdateManager.js +2 -2
- package/dist/react-native/RaftUpdateManager.js.map +1 -1
- package/dist/react-native/RaftUtils.d.ts +2 -0
- package/dist/react-native/RaftUtils.js +22 -2
- package/dist/react-native/RaftUtils.js.map +1 -1
- package/dist/react-native/main.d.ts +2 -0
- package/dist/react-native/main.js +4 -1
- package/dist/react-native/main.js.map +1 -1
- package/dist/web/RaftAttributeHandler.d.ts +2 -0
- package/dist/web/RaftAttributeHandler.js +136 -10
- package/dist/web/RaftAttributeHandler.js.map +1 -1
- package/dist/web/RaftChannel.d.ts +2 -0
- package/dist/web/RaftChannelBLE.web.d.ts +2 -0
- package/dist/web/RaftChannelBLE.web.js +24 -15
- package/dist/web/RaftChannelBLE.web.js.map +1 -1
- package/dist/web/RaftChannelSimulated.d.ts +32 -0
- package/dist/web/RaftChannelSimulated.js +418 -0
- package/dist/web/RaftChannelSimulated.js.map +1 -0
- package/dist/web/RaftChannelWebSerial.d.ts +2 -0
- package/dist/web/RaftChannelWebSerial.js +18 -9
- package/dist/web/RaftChannelWebSerial.js.map +1 -1
- package/dist/web/RaftChannelWebSocket.d.ts +2 -0
- package/dist/web/RaftChannelWebSocket.js +10 -0
- package/dist/web/RaftChannelWebSocket.js.map +1 -1
- package/dist/web/RaftConnector.js +13 -6
- package/dist/web/RaftConnector.js.map +1 -1
- package/dist/web/RaftCustomAttrHandler.js +15 -0
- package/dist/web/RaftCustomAttrHandler.js.map +1 -1
- package/dist/web/RaftDeviceInfo.d.ts +8 -1
- package/dist/web/RaftDeviceInfo.js +17 -3
- package/dist/web/RaftDeviceInfo.js.map +1 -1
- package/dist/web/RaftDeviceManager.d.ts +3 -0
- package/dist/web/RaftDeviceManager.js +123 -43
- package/dist/web/RaftDeviceManager.js.map +1 -1
- package/dist/web/RaftFileHandler.js +8 -8
- package/dist/web/RaftFileHandler.js.map +1 -1
- package/dist/web/RaftLog.js +1 -1
- package/dist/web/RaftLog.js.map +1 -1
- package/dist/web/RaftMsgHandler.d.ts +5 -0
- package/dist/web/RaftMsgHandler.js +32 -0
- package/dist/web/RaftMsgHandler.js.map +1 -1
- package/dist/web/RaftStreamHandler.js +6 -5
- package/dist/web/RaftStreamHandler.js.map +1 -1
- package/dist/web/RaftStruct.js +197 -147
- package/dist/web/RaftStruct.js.map +1 -1
- package/dist/web/RaftSysTypeManager.d.ts +2 -0
- package/dist/web/RaftSysTypeManager.js +25 -0
- package/dist/web/RaftSysTypeManager.js.map +1 -1
- package/dist/web/RaftSystemType.d.ts +9 -7
- package/dist/web/RaftSystemUtils.js +3 -1
- package/dist/web/RaftSystemUtils.js.map +1 -1
- package/dist/web/RaftUpdateManager.js +2 -2
- package/dist/web/RaftUpdateManager.js.map +1 -1
- package/dist/web/RaftUtils.d.ts +2 -0
- package/dist/web/RaftUtils.js +22 -2
- package/dist/web/RaftUtils.js.map +1 -1
- package/dist/web/main.d.ts +2 -0
- package/dist/web/main.js +4 -1
- package/dist/web/main.js.map +1 -1
- package/examples/dashboard/package.json +1 -1
- package/examples/dashboard/src/CommandPanel.tsx +3 -3
- package/examples/dashboard/src/ConnManager.ts +83 -6
- package/examples/dashboard/src/DeviceActionsForm.tsx +2 -2
- package/examples/dashboard/src/DevicePanel.tsx +2 -2
- package/examples/dashboard/src/Main.tsx +14 -4
- package/examples/dashboard/src/SystemTypeMarty/RICSystemUtils.ts +4 -4
- package/examples/dashboard/src/styles.css +8 -0
- package/examples/dashboard/tsconfig.json +1 -1
- package/package.json +10 -11
- package/src/RaftAttributeHandler.ts +163 -11
- package/src/RaftChannel.ts +2 -0
- package/src/RaftChannelBLE.native.ts +17 -8
- package/src/RaftChannelBLE.web.ts +28 -16
- package/src/RaftChannelSimulated.ts +482 -0
- package/src/RaftChannelWebSerial.ts +18 -7
- package/src/RaftChannelWebSocket.ts +13 -0
- package/src/RaftConnector.ts +13 -7
- package/src/RaftCustomAttrHandler.ts +17 -0
- package/src/RaftDeviceInfo.ts +27 -5
- package/src/RaftDeviceManager.ts +155 -47
- package/src/RaftFileHandler.ts +8 -8
- package/src/RaftLog.ts +1 -1
- package/src/RaftMsgHandler.ts +36 -0
- package/src/RaftStreamHandler.ts +48 -47
- package/src/RaftStruct.ts +220 -147
- package/src/RaftSysTypeManager.ts +27 -0
- package/src/RaftSystemType.ts +9 -7
- package/src/RaftSystemUtils.ts +3 -1
- package/src/RaftUpdateManager.ts +2 -2
- package/src/RaftUtils.ts +25 -5
- package/src/main.ts +2 -0
package/src/RaftStreamHandler.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { RaftOKFail, RaftStreamStartResp, RaftStreamType } from './RaftTypes';
|
|
|
15
15
|
import RaftConnector from './RaftConnector';
|
|
16
16
|
import { RaftConnEvent } from './RaftConnEvents';
|
|
17
17
|
import { RICRESTElemCode } from './RaftProtocolDefs'
|
|
18
|
+
import RaftUtils from './RaftUtils';
|
|
18
19
|
|
|
19
20
|
export default class RaftStreamHandler {
|
|
20
21
|
|
|
@@ -49,7 +50,7 @@ export default class RaftStreamHandler {
|
|
|
49
50
|
|
|
50
51
|
private _isStreaming = false;
|
|
51
52
|
private _isPaused = false;
|
|
52
|
-
private _streamBuffer = new Uint8Array();
|
|
53
|
+
private _streamBuffer: Uint8Array<ArrayBuffer> = new Uint8Array();
|
|
53
54
|
private _audioDuration = 0;
|
|
54
55
|
private _audioByteRate = 0;
|
|
55
56
|
private _streamPos = 0;
|
|
@@ -67,11 +68,11 @@ export default class RaftStreamHandler {
|
|
|
67
68
|
this.onSoktoMsg = this.onSoktoMsg.bind(this);
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
setNumBlocksWithoutPause(numBlocks: number){
|
|
71
|
+
setNumBlocksWithoutPause(numBlocks: number) {
|
|
71
72
|
this._numBlocksWithoutPause = numBlocks;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
setLegacySoktoMode(legacyMode: boolean){
|
|
75
|
+
setLegacySoktoMode(legacyMode: boolean) {
|
|
75
76
|
RaftLog.debug(`Setting legacy sokto mode to ${legacyMode}`);
|
|
76
77
|
this._legacySoktoMode = legacyMode;
|
|
77
78
|
}
|
|
@@ -83,7 +84,7 @@ export default class RaftStreamHandler {
|
|
|
83
84
|
|
|
84
85
|
// TODO - if clearExisting is not set, form a queue
|
|
85
86
|
if (this._streamIsStarting || this._lastStreamStartTime > (Date.now() - 500)) {
|
|
86
|
-
RaftLog.
|
|
87
|
+
RaftLog.warn(`Unable to start sound, too soon since last request`);
|
|
87
88
|
return;
|
|
88
89
|
}
|
|
89
90
|
|
|
@@ -94,9 +95,9 @@ export default class RaftStreamHandler {
|
|
|
94
95
|
this._soktoReceived = false;
|
|
95
96
|
this._soktoPos = 0;
|
|
96
97
|
this._streamPos = 0;
|
|
97
|
-
this._streamBuffer = streamContents;
|
|
98
|
+
this._streamBuffer = RaftUtils.toArrayBufferView(streamContents);
|
|
98
99
|
this._audioDuration = audioDuration;
|
|
99
|
-
this._audioByteRate = (streamContents.length / audioDuration)*1000;
|
|
100
|
+
this._audioByteRate = (streamContents.length / audioDuration) * 1000;
|
|
100
101
|
|
|
101
102
|
this.clearFinishPointTimeout();
|
|
102
103
|
|
|
@@ -104,12 +105,12 @@ export default class RaftStreamHandler {
|
|
|
104
105
|
(result: boolean) => {
|
|
105
106
|
this._isPaused = false;
|
|
106
107
|
this._streamIsStarting = false;
|
|
107
|
-
if (!result){
|
|
108
|
-
RaftLog.
|
|
108
|
+
if (!result) {
|
|
109
|
+
RaftLog.warn(`Unable to start stream. ufStart message send failed`);
|
|
109
110
|
return;
|
|
110
111
|
}
|
|
111
112
|
//this.streamingPerformanceChecker();
|
|
112
|
-
if (!this._isStreaming){
|
|
113
|
+
if (!this._isStreaming) {
|
|
113
114
|
this._isStreaming = true;
|
|
114
115
|
this._sendStreamBuffer();
|
|
115
116
|
}
|
|
@@ -127,7 +128,7 @@ export default class RaftStreamHandler {
|
|
|
127
128
|
return this._streamIsStarting;
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
|
|
131
|
+
|
|
131
132
|
clearFinishPointTimeout() {
|
|
132
133
|
if (this.soundFinishPoint) {
|
|
133
134
|
clearTimeout(this.soundFinishPoint);
|
|
@@ -172,7 +173,7 @@ export default class RaftStreamHandler {
|
|
|
172
173
|
RICRESTElemCode.RICREST_ELEM_CODE_COMMAND_FRAME,
|
|
173
174
|
);
|
|
174
175
|
} catch (err) {
|
|
175
|
-
RaftLog.
|
|
176
|
+
RaftLog.warn(`sendStreamStartMsg error ${err}`);
|
|
176
177
|
return false;
|
|
177
178
|
}
|
|
178
179
|
|
|
@@ -191,11 +192,11 @@ export default class RaftStreamHandler {
|
|
|
191
192
|
return true;
|
|
192
193
|
}
|
|
193
194
|
|
|
194
|
-
get maxBlockSize
|
|
195
|
+
get maxBlockSize() {
|
|
195
196
|
return this._maxBlockSize;
|
|
196
197
|
}
|
|
197
198
|
|
|
198
|
-
set maxBlockSize
|
|
199
|
+
set maxBlockSize(maxBlockSize: number) {
|
|
199
200
|
this._maxBlockSize = maxBlockSize;
|
|
200
201
|
this.DEFAULT_MAX_BLOCK_SIZE = maxBlockSize;
|
|
201
202
|
}
|
|
@@ -220,43 +221,43 @@ export default class RaftStreamHandler {
|
|
|
220
221
|
RICRESTElemCode.RICREST_ELEM_CODE_COMMAND_FRAME,
|
|
221
222
|
);
|
|
222
223
|
} catch (err) {
|
|
223
|
-
RaftLog.
|
|
224
|
+
RaftLog.warn(`sendStreamEndMsg error ${err}`);
|
|
224
225
|
return false;
|
|
225
226
|
}
|
|
226
227
|
return streamEndResp.rslt === 'ok';
|
|
227
228
|
}
|
|
228
229
|
|
|
229
|
-
/*
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
*/
|
|
230
|
+
/*
|
|
231
|
+
private async _sendAudioStopMsg(): Promise<RaftOKFail> {
|
|
232
|
+
const cmdMsg = `{"cmdName":"audio/stop"}`;
|
|
233
|
+
|
|
234
|
+
// Debug
|
|
235
|
+
RaftLog.debug(`sendAudioStopMsg ${cmdMsg}`);
|
|
236
|
+
|
|
237
|
+
// Send
|
|
238
|
+
return this._msgHandler.sendRICREST<RaftOKFail>(
|
|
239
|
+
cmdMsg,
|
|
240
|
+
RICRESTElemCode.RICREST_ELEM_CODE_COMMAND_FRAME,
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
private async _sendStreamCancelMsg(): Promise<RaftOKFail> {
|
|
246
|
+
// File cancel command message
|
|
247
|
+
const cmdMsg = `{"cmdName":"ufCancel","reqStr":"ufCancel","streamID":${this._streamID}}`;
|
|
248
|
+
|
|
249
|
+
// Debug
|
|
250
|
+
RaftLog.debug(`sendStreamCancelMsg ${cmdMsg}`);
|
|
251
|
+
|
|
252
|
+
// Send
|
|
253
|
+
return this._msgHandler.sendRICREST<RaftOKFail>(
|
|
254
|
+
cmdMsg,
|
|
255
|
+
RICRESTElemCode.RICREST_ELEM_CODE_COMMAND_FRAME,
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
*/
|
|
258
259
|
|
|
259
|
-
private async _sendStreamBuffer(): Promise<boolean> {
|
|
260
|
+
private async _sendStreamBuffer(): Promise<boolean> {
|
|
260
261
|
const streamStartTime = Date.now();
|
|
261
262
|
|
|
262
263
|
// Check streamID is valid
|
|
@@ -267,7 +268,7 @@ private async _sendStreamBuffer(): Promise<boolean> {
|
|
|
267
268
|
let blockNum = 0;
|
|
268
269
|
// Send stream blocks
|
|
269
270
|
while (this._soktoPos < this._streamBuffer.length || this._isPaused) {
|
|
270
|
-
if (this._isPaused){
|
|
271
|
+
if (this._isPaused) {
|
|
271
272
|
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
272
273
|
continue;
|
|
273
274
|
}
|
|
@@ -301,8 +302,8 @@ private async _sendStreamBuffer(): Promise<boolean> {
|
|
|
301
302
|
this._streamPos += blockSize;
|
|
302
303
|
blockNum += 1;
|
|
303
304
|
|
|
304
|
-
if (this._audioByteRate && blockNum > this._numBlocksWithoutPause){
|
|
305
|
-
const pauseTime = ((blockSize / this._audioByteRate)*1000) - 10;
|
|
305
|
+
if (this._audioByteRate && blockNum > this._numBlocksWithoutPause) {
|
|
306
|
+
const pauseTime = ((blockSize / this._audioByteRate) * 1000) - 10;
|
|
306
307
|
RaftLog.verbose(`Pausing for ${pauseTime} ms between audio packets. Bit rate ${this._audioByteRate * 8}`)
|
|
307
308
|
await new Promise((resolve) => setTimeout(resolve, pauseTime));
|
|
308
309
|
}
|
package/src/RaftStruct.ts
CHANGED
|
@@ -8,77 +8,124 @@
|
|
|
8
8
|
//
|
|
9
9
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
10
10
|
|
|
11
|
+
type FormatInstruction =
|
|
12
|
+
| { kind: "endian"; littleEndian: boolean }
|
|
13
|
+
| { kind: "spec"; code: string; repeat: number };
|
|
14
|
+
|
|
15
|
+
function parseFormatInstructions(format: string): FormatInstruction[] {
|
|
16
|
+
const instructions: FormatInstruction[] = [];
|
|
17
|
+
let idx = 0;
|
|
18
|
+
|
|
19
|
+
while (idx < format.length) {
|
|
20
|
+
|
|
21
|
+
const char = format[idx];
|
|
22
|
+
|
|
23
|
+
// Endianness specifiers
|
|
24
|
+
if (char === "<" || char === ">") {
|
|
25
|
+
instructions.push({ kind: "endian", littleEndian: char === "<" });
|
|
26
|
+
idx++;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Ignore whitespace
|
|
31
|
+
if (/\s/.test(char)) {
|
|
32
|
+
idx++;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Attribute code
|
|
37
|
+
const code = char;
|
|
38
|
+
idx++;
|
|
39
|
+
|
|
40
|
+
// Check for repeat count using [N] syntax
|
|
41
|
+
let repeat = 1;
|
|
42
|
+
if (idx < format.length && format[idx] === "[") {
|
|
43
|
+
const endIdx = format.indexOf("]", idx + 1);
|
|
44
|
+
if (endIdx === -1) {
|
|
45
|
+
throw new Error(`Invalid format string: missing closing ] in "${format}"`);
|
|
46
|
+
}
|
|
47
|
+
const repeatStr = format.slice(idx + 1, endIdx);
|
|
48
|
+
repeat = parseInt(repeatStr, 10);
|
|
49
|
+
if (!Number.isFinite(repeat) || repeat <= 0) {
|
|
50
|
+
throw new Error(`Invalid repeat count "${repeatStr}" in format string "${format}"`);
|
|
51
|
+
}
|
|
52
|
+
idx = endIdx + 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
instructions.push({ kind: "spec", code, repeat });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return instructions;
|
|
59
|
+
}
|
|
60
|
+
|
|
11
61
|
export function structUnpack(format: string, data: Uint8Array): number[] {
|
|
12
62
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
13
63
|
const results: number[] = [];
|
|
14
64
|
let offset = 0;
|
|
15
65
|
let littleEndian = false;
|
|
16
66
|
|
|
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
|
-
results.push(view.
|
|
62
|
-
offset +=
|
|
63
|
-
break;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
break;
|
|
80
|
-
default:
|
|
81
|
-
throw new Error(`Unknown format character: ${char}`);
|
|
67
|
+
const instructions = parseFormatInstructions(format);
|
|
68
|
+
|
|
69
|
+
for (const instruction of instructions) {
|
|
70
|
+
if (instruction.kind === "endian") {
|
|
71
|
+
littleEndian = instruction.littleEndian;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const { code, repeat } = instruction;
|
|
76
|
+
|
|
77
|
+
for (let count = 0; count < repeat; count++) {
|
|
78
|
+
switch (code) {
|
|
79
|
+
case "x": // Padding byte
|
|
80
|
+
offset += 1;
|
|
81
|
+
break;
|
|
82
|
+
case "c": // Char
|
|
83
|
+
case "B": // Unsigned 8-bit integer
|
|
84
|
+
case "?": // Boolean (stored as uint8)
|
|
85
|
+
results.push(view.getUint8(offset));
|
|
86
|
+
offset += 1;
|
|
87
|
+
break;
|
|
88
|
+
case "b": // Signed 8-bit integer
|
|
89
|
+
results.push(view.getInt8(offset));
|
|
90
|
+
offset += 1;
|
|
91
|
+
break;
|
|
92
|
+
case "h": // Signed 16-bit integer
|
|
93
|
+
results.push(view.getInt16(offset, littleEndian));
|
|
94
|
+
offset += 2;
|
|
95
|
+
break;
|
|
96
|
+
case "H": // Unsigned 16-bit integer
|
|
97
|
+
results.push(view.getUint16(offset, littleEndian));
|
|
98
|
+
offset += 2;
|
|
99
|
+
break;
|
|
100
|
+
case "i": // Signed 32-bit integer
|
|
101
|
+
case "l": // Signed 32-bit integer
|
|
102
|
+
results.push(view.getInt32(offset, littleEndian));
|
|
103
|
+
offset += 4;
|
|
104
|
+
break;
|
|
105
|
+
case "I": // Unsigned 32-bit integer
|
|
106
|
+
case "L": // Unsigned 32-bit integer
|
|
107
|
+
results.push(view.getUint32(offset, littleEndian));
|
|
108
|
+
offset += 4;
|
|
109
|
+
break;
|
|
110
|
+
// case "q": // Signed 64-bit integer
|
|
111
|
+
// results.push(Number(view.getBigInt64(offset, littleEndian)));
|
|
112
|
+
// offset += 8;
|
|
113
|
+
// break;
|
|
114
|
+
// case "Q": // Unsigned 64-bit integer
|
|
115
|
+
// results.push(Number(view.getBigUint64(offset, littleEndian)));
|
|
116
|
+
// offset += 8;
|
|
117
|
+
// break;
|
|
118
|
+
case "f": // 32-bit float
|
|
119
|
+
results.push(view.getFloat32(offset, littleEndian));
|
|
120
|
+
offset += 4;
|
|
121
|
+
break;
|
|
122
|
+
case "d": // 64-bit float
|
|
123
|
+
results.push(view.getFloat64(offset, littleEndian));
|
|
124
|
+
offset += 8;
|
|
125
|
+
break;
|
|
126
|
+
default:
|
|
127
|
+
throw new Error(`Unknown format character: ${code}`);
|
|
128
|
+
}
|
|
82
129
|
}
|
|
83
130
|
}
|
|
84
131
|
|
|
@@ -87,42 +134,49 @@ export function structUnpack(format: string, data: Uint8Array): number[] {
|
|
|
87
134
|
|
|
88
135
|
export function structSizeOf(format: string): number {
|
|
89
136
|
let size = 0;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
137
|
+
const instructions = parseFormatInstructions(format);
|
|
138
|
+
|
|
139
|
+
for (const instruction of instructions) {
|
|
140
|
+
if (instruction.kind === "endian") {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const { code, repeat } = instruction;
|
|
145
|
+
let unitSize: number;
|
|
146
|
+
|
|
147
|
+
switch (code) {
|
|
95
148
|
case "x": // Padding byte
|
|
96
|
-
size += 1;
|
|
97
|
-
break;
|
|
98
149
|
case "c": // Char
|
|
99
150
|
case "b": // Signed 8-bit integer
|
|
100
151
|
case "B": // Unsigned 8-bit integer
|
|
101
|
-
|
|
152
|
+
case "?": // Boolean (uint8)
|
|
153
|
+
unitSize = 1;
|
|
102
154
|
break;
|
|
103
155
|
case "h": // Signed 16-bit integer
|
|
104
156
|
case "H": // Unsigned 16-bit integer
|
|
105
|
-
|
|
157
|
+
unitSize = 2;
|
|
106
158
|
break;
|
|
107
159
|
case "i": // Signed 32-bit integer
|
|
108
160
|
case "I": // Unsigned 32-bit integer
|
|
109
161
|
case "l": // Signed 32-bit integer
|
|
110
162
|
case "L": // Unsigned 32-bit integer
|
|
111
|
-
|
|
163
|
+
unitSize = 4;
|
|
112
164
|
break;
|
|
113
165
|
// case "q": // Signed 64-bit integer
|
|
114
166
|
// case "Q": // Unsigned 64-bit integer
|
|
115
|
-
//
|
|
167
|
+
// unitSize = 8;
|
|
116
168
|
// break;
|
|
117
169
|
case "f": // 32-bit float
|
|
118
|
-
|
|
170
|
+
unitSize = 4;
|
|
119
171
|
break;
|
|
120
172
|
case "d": // 64-bit float
|
|
121
|
-
|
|
173
|
+
unitSize = 8;
|
|
122
174
|
break;
|
|
123
175
|
default:
|
|
124
|
-
throw new Error(`Unknown format character: ${
|
|
176
|
+
throw new Error(`Unknown format character: ${code}`);
|
|
125
177
|
}
|
|
178
|
+
|
|
179
|
+
size += unitSize * repeat;
|
|
126
180
|
}
|
|
127
181
|
return size;
|
|
128
182
|
}
|
|
@@ -134,74 +188,93 @@ export function structPack(format: string, values: number[]): Uint8Array {
|
|
|
134
188
|
let offset = 0;
|
|
135
189
|
let littleEndian = false;
|
|
136
190
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
view.
|
|
201
|
-
offset += 8;
|
|
202
|
-
break;
|
|
203
|
-
|
|
204
|
-
|
|
191
|
+
const instructions = parseFormatInstructions(format);
|
|
192
|
+
let valueIdx = 0;
|
|
193
|
+
|
|
194
|
+
for (const instruction of instructions) {
|
|
195
|
+
if (instruction.kind === "endian") {
|
|
196
|
+
littleEndian = instruction.littleEndian;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const { code, repeat } = instruction;
|
|
201
|
+
|
|
202
|
+
for (let count = 0; count < repeat; count++) {
|
|
203
|
+
switch (code) {
|
|
204
|
+
case "x": // Padding byte
|
|
205
|
+
offset += 1;
|
|
206
|
+
break;
|
|
207
|
+
case "c": // Char
|
|
208
|
+
case "b": // Signed 8-bit integer
|
|
209
|
+
if (valueIdx >= values.length) {
|
|
210
|
+
throw new Error("Insufficient values provided for structPack");
|
|
211
|
+
}
|
|
212
|
+
view.setInt8(offset, values[valueIdx++]);
|
|
213
|
+
offset += 1;
|
|
214
|
+
break;
|
|
215
|
+
case "B": // Unsigned 8-bit integer
|
|
216
|
+
case "?": // Boolean (uint8)
|
|
217
|
+
if (valueIdx >= values.length) {
|
|
218
|
+
throw new Error("Insufficient values provided for structPack");
|
|
219
|
+
}
|
|
220
|
+
view.setUint8(offset, values[valueIdx++]);
|
|
221
|
+
offset += 1;
|
|
222
|
+
break;
|
|
223
|
+
case "h": // Signed 16-bit integer
|
|
224
|
+
if (valueIdx >= values.length) {
|
|
225
|
+
throw new Error("Insufficient values provided for structPack");
|
|
226
|
+
}
|
|
227
|
+
view.setInt16(offset, values[valueIdx++], littleEndian);
|
|
228
|
+
offset += 2;
|
|
229
|
+
break;
|
|
230
|
+
case "H": // Unsigned 16-bit integer
|
|
231
|
+
if (valueIdx >= values.length) {
|
|
232
|
+
throw new Error("Insufficient values provided for structPack");
|
|
233
|
+
}
|
|
234
|
+
view.setUint16(offset, values[valueIdx++], littleEndian);
|
|
235
|
+
offset += 2;
|
|
236
|
+
break;
|
|
237
|
+
case "i": // Signed 32-bit integer
|
|
238
|
+
case "l": // Signed 32-bit integer
|
|
239
|
+
if (valueIdx >= values.length) {
|
|
240
|
+
throw new Error("Insufficient values provided for structPack");
|
|
241
|
+
}
|
|
242
|
+
view.setInt32(offset, values[valueIdx++], littleEndian);
|
|
243
|
+
offset += 4;
|
|
244
|
+
break;
|
|
245
|
+
case "I": // Unsigned 32-bit integer
|
|
246
|
+
case "L": // Unsigned 32-bit integer
|
|
247
|
+
if (valueIdx >= values.length) {
|
|
248
|
+
throw new Error("Insufficient values provided for structPack");
|
|
249
|
+
}
|
|
250
|
+
view.setUint32(offset, values[valueIdx++], littleEndian);
|
|
251
|
+
offset += 4;
|
|
252
|
+
break;
|
|
253
|
+
// case "q": // Signed 64-bit integer
|
|
254
|
+
// view.setBigInt64(offset, BigInt(values[valueIdx++]), littleEndian);
|
|
255
|
+
// offset += 8;
|
|
256
|
+
// break;
|
|
257
|
+
// case "Q": // Unsigned 64-bit integer
|
|
258
|
+
// view.setBigUint64(offset, BigInt(values[valueIdx++]), littleEndian);
|
|
259
|
+
// offset += 8;
|
|
260
|
+
// break;
|
|
261
|
+
case "f": // 32-bit float
|
|
262
|
+
if (valueIdx >= values.length) {
|
|
263
|
+
throw new Error("Insufficient values provided for structPack");
|
|
264
|
+
}
|
|
265
|
+
view.setFloat32(offset, values[valueIdx++], littleEndian);
|
|
266
|
+
offset += 4;
|
|
267
|
+
break;
|
|
268
|
+
case "d": // 64-bit float
|
|
269
|
+
if (valueIdx >= values.length) {
|
|
270
|
+
throw new Error("Insufficient values provided for structPack");
|
|
271
|
+
}
|
|
272
|
+
view.setFloat64(offset, values[valueIdx++], littleEndian);
|
|
273
|
+
offset += 8;
|
|
274
|
+
break;
|
|
275
|
+
default:
|
|
276
|
+
throw new Error(`Unknown format character: ${code}`);
|
|
277
|
+
}
|
|
205
278
|
}
|
|
206
279
|
}
|
|
207
280
|
|
|
@@ -53,8 +53,35 @@ export default class RaftSysTypeManager {
|
|
|
53
53
|
const serviceUUIDs = new Set<string>();
|
|
54
54
|
this._sysTypes.forEach((factory) => {
|
|
55
55
|
const sysType = factory();
|
|
56
|
+
if (!sysType.BLEServiceUUIDs) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
56
59
|
sysType.BLEServiceUUIDs.forEach((uuid) => serviceUUIDs.add(uuid));
|
|
57
60
|
});
|
|
58
61
|
return Array.from(serviceUUIDs);
|
|
59
62
|
}
|
|
63
|
+
|
|
64
|
+
// Get a list of all device name prefixes to filter on
|
|
65
|
+
getAllNamePrefixes(): string[] {
|
|
66
|
+
const deviceNames = new Set<string>();
|
|
67
|
+
this._sysTypes.forEach((factory) => {
|
|
68
|
+
const sysType = factory();
|
|
69
|
+
if (!sysType.BLEDeviceNames) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
sysType.BLEDeviceNames.forEach((name) => deviceNames.add(name));
|
|
73
|
+
});
|
|
74
|
+
return Array.from(deviceNames);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Find the system type for a given BLE device name prefix
|
|
78
|
+
getSystemTypeByBLENamePrefix(name: string): RaftSystemType | null {
|
|
79
|
+
for (const factory of this._sysTypes.values()) {
|
|
80
|
+
const sysType = factory();
|
|
81
|
+
if (sysType.BLEDeviceNames && sysType.BLEDeviceNames.some((prefix) => name.startsWith(prefix))) {
|
|
82
|
+
return sysType;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
60
87
|
}
|