brilliantsole 0.0.1

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.
Files changed (158) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/build/brilliantsole.cjs +5957 -0
  4. package/build/brilliantsole.cjs.map +1 -0
  5. package/build/brilliantsole.js +5448 -0
  6. package/build/brilliantsole.js.map +1 -0
  7. package/build/brilliantsole.ls.js +4872 -0
  8. package/build/brilliantsole.ls.js.map +1 -0
  9. package/build/brilliantsole.min.js +6 -0
  10. package/build/brilliantsole.min.js.map +1 -0
  11. package/build/brilliantsole.module.d.ts +908 -0
  12. package/build/brilliantsole.module.js +5412 -0
  13. package/build/brilliantsole.module.js.map +1 -0
  14. package/build/brilliantsole.module.min.d.ts +908 -0
  15. package/build/brilliantsole.module.min.js +6 -0
  16. package/build/brilliantsole.module.min.js.map +1 -0
  17. package/build/brilliantsole.node.module.d.ts +908 -0
  18. package/build/brilliantsole.node.module.js +5906 -0
  19. package/build/brilliantsole.node.module.js.map +1 -0
  20. package/build/dts/BS.d.ts +25 -0
  21. package/build/dts/Device.d.ts +136 -0
  22. package/build/dts/DeviceInformationManager.d.ts +56 -0
  23. package/build/dts/DeviceManager.d.ts +67 -0
  24. package/build/dts/FileTransferManager.d.ts +84 -0
  25. package/build/dts/FirmwareManager.d.ts +71 -0
  26. package/build/dts/InformationManager.d.ts +66 -0
  27. package/build/dts/TfliteManager.d.ts +92 -0
  28. package/build/dts/connection/BaseConnectionManager.d.ts +59 -0
  29. package/build/dts/connection/ClientConnectionManager.d.ts +23 -0
  30. package/build/dts/connection/WebSocketClientConnectionManager.d.ts +23 -0
  31. package/build/dts/connection/bluetooth/BluetoothConnectionManager.d.ts +10 -0
  32. package/build/dts/connection/bluetooth/NobleConnectionManager.d.ts +42 -0
  33. package/build/dts/connection/bluetooth/WebBluetoothConnectionManager.d.ts +20 -0
  34. package/build/dts/connection/bluetooth/bluetoothUUIDs.d.ts +14 -0
  35. package/build/dts/connection/webSocket/ClientConnectionManager.d.ts +23 -0
  36. package/build/dts/connection/webSocket/WebSocketClientConnectionManager.d.ts +23 -0
  37. package/build/dts/devicePair/DevicePair.d.ts +60 -0
  38. package/build/dts/devicePair/DevicePairPressureSensorDataManager.d.ts +25 -0
  39. package/build/dts/devicePair/DevicePairSensorDataManager.d.ts +33 -0
  40. package/build/dts/scanner/BaseScanner.d.ts +66 -0
  41. package/build/dts/scanner/NobleScanner.d.ts +17 -0
  42. package/build/dts/scanner/Scanner.d.ts +3 -0
  43. package/build/dts/sensor/BarometerSensorDataManager.d.ts +16 -0
  44. package/build/dts/sensor/MotionSensorDataManager.d.ts +69 -0
  45. package/build/dts/sensor/PressureSensorDataManager.d.ts +36 -0
  46. package/build/dts/sensor/SensorConfigurationManager.d.ts +44 -0
  47. package/build/dts/sensor/SensorDataManager.d.ts +40 -0
  48. package/build/dts/server/BaseClient.d.ts +85 -0
  49. package/build/dts/server/BaseServer.d.ts +48 -0
  50. package/build/dts/server/ServerUtils.d.ts +23 -0
  51. package/build/dts/server/udp/UDPServer.d.ts +11 -0
  52. package/build/dts/server/udp/UDPUtils.d.ts +9 -0
  53. package/build/dts/server/websocket/WebSocketClient.d.ts +17 -0
  54. package/build/dts/server/websocket/WebSocketServer.d.ts +13 -0
  55. package/build/dts/server/websocket/WebSocketUtils.d.ts +9 -0
  56. package/build/dts/utils/ArrayBufferUtils.d.ts +7 -0
  57. package/build/dts/utils/ArrayUtils.d.ts +2 -0
  58. package/build/dts/utils/CenterOfPressureHelper.d.ts +15 -0
  59. package/build/dts/utils/Console.d.ts +34 -0
  60. package/build/dts/utils/EventDispatcher.d.ts +50 -0
  61. package/build/dts/utils/EventUtils.d.ts +6 -0
  62. package/build/dts/utils/MathUtils.d.ts +21 -0
  63. package/build/dts/utils/ParseUtils.d.ts +5 -0
  64. package/build/dts/utils/RangeHelper.d.ts +8 -0
  65. package/build/dts/utils/Text.d.ts +6 -0
  66. package/build/dts/utils/Timer.d.ts +14 -0
  67. package/build/dts/utils/TypeScriptUtils.d.ts +19 -0
  68. package/build/dts/utils/cbor.d.ts +6 -0
  69. package/build/dts/utils/checksum.d.ts +3 -0
  70. package/build/dts/utils/environment.d.ts +13 -0
  71. package/build/dts/utils/mcumgr.d.ts +88 -0
  72. package/build/dts/utils/stringUtils.d.ts +2 -0
  73. package/build/dts/vibration/VibrationManager.d.ts +45 -0
  74. package/build/dts/vibration/VibrationWaveformEffects.d.ts +2 -0
  75. package/build/index.d.ts +908 -0
  76. package/build/index.node.d.ts +908 -0
  77. package/examples/3d/index.html +109 -0
  78. package/examples/3d/scene.html +57 -0
  79. package/examples/3d/script.js +419 -0
  80. package/examples/balance/index.html +138 -0
  81. package/examples/balance/script.js +243 -0
  82. package/examples/basic/index.html +327 -0
  83. package/examples/basic/script.js +1093 -0
  84. package/examples/center-of-pressure/index.html +132 -0
  85. package/examples/center-of-pressure/script.js +207 -0
  86. package/examples/device-pair/index.html +72 -0
  87. package/examples/device-pair/script.js +187 -0
  88. package/examples/edge-impulse/index.html +94 -0
  89. package/examples/edge-impulse/script.js +1033 -0
  90. package/examples/graph/index.html +83 -0
  91. package/examples/graph/script.js +469 -0
  92. package/examples/machine-learning/index.html +366 -0
  93. package/examples/machine-learning/script.js +1774 -0
  94. package/examples/pressure/index.html +145 -0
  95. package/examples/pressure/script.js +201 -0
  96. package/examples/recording/index.html +187 -0
  97. package/examples/recording/script.js +736 -0
  98. package/examples/server/index.html +266 -0
  99. package/examples/server/script.js +925 -0
  100. package/examples/utils/aframe/fingertip-button-component.js +201 -0
  101. package/examples/utils/aframe/fingertip-collider-target-component.js +102 -0
  102. package/examples/utils/aframe/fingertip-colliders-component.js +147 -0
  103. package/examples/utils/three/three.module.min.js +24846 -0
  104. package/examples/webxr/index.html +221 -0
  105. package/examples/webxr/script.js +1127 -0
  106. package/package.json +83 -0
  107. package/src/BS.ts +68 -0
  108. package/src/Device.ts +734 -0
  109. package/src/DeviceInformationManager.ts +146 -0
  110. package/src/DeviceManager.ts +354 -0
  111. package/src/FileTransferManager.ts +452 -0
  112. package/src/FirmwareManager.ts +357 -0
  113. package/src/InformationManager.ts +283 -0
  114. package/src/TfliteManager.ts +450 -0
  115. package/src/connection/BaseConnectionManager.ts +255 -0
  116. package/src/connection/ClientConnectionManager.ts +120 -0
  117. package/src/connection/bluetooth/BluetoothConnectionManager.ts +34 -0
  118. package/src/connection/bluetooth/NobleConnectionManager.ts +302 -0
  119. package/src/connection/bluetooth/WebBluetoothConnectionManager.ts +269 -0
  120. package/src/connection/bluetooth/bluetoothUUIDs.ts +218 -0
  121. package/src/devicePair/DevicePair.ts +253 -0
  122. package/src/devicePair/DevicePairPressureSensorDataManager.ts +82 -0
  123. package/src/devicePair/DevicePairSensorDataManager.ts +90 -0
  124. package/src/scanner/BaseScanner.ts +189 -0
  125. package/src/scanner/NobleScanner.ts +195 -0
  126. package/src/scanner/Scanner.ts +16 -0
  127. package/src/sensor/BarometerSensorDataManager.ts +41 -0
  128. package/src/sensor/MotionSensorDataManager.ts +151 -0
  129. package/src/sensor/PressureSensorDataManager.ts +112 -0
  130. package/src/sensor/SensorConfigurationManager.ts +177 -0
  131. package/src/sensor/SensorDataManager.ts +166 -0
  132. package/src/server/BaseClient.ts +368 -0
  133. package/src/server/BaseServer.ts +344 -0
  134. package/src/server/ServerUtils.ts +93 -0
  135. package/src/server/udp/UDPServer.ts +229 -0
  136. package/src/server/udp/UDPUtils.ts +20 -0
  137. package/src/server/websocket/WebSocketClient.ts +179 -0
  138. package/src/server/websocket/WebSocketServer.ts +184 -0
  139. package/src/server/websocket/WebSocketUtils.ts +20 -0
  140. package/src/utils/ArrayBufferUtils.ts +88 -0
  141. package/src/utils/ArrayUtils.ts +15 -0
  142. package/src/utils/CenterOfPressureHelper.ts +39 -0
  143. package/src/utils/Console.ts +156 -0
  144. package/src/utils/EventDispatcher.ts +153 -0
  145. package/src/utils/EventUtils.ts +41 -0
  146. package/src/utils/MathUtils.ts +53 -0
  147. package/src/utils/ParseUtils.ts +46 -0
  148. package/src/utils/RangeHelper.ts +38 -0
  149. package/src/utils/Text.ts +30 -0
  150. package/src/utils/Timer.ts +72 -0
  151. package/src/utils/TypeScriptUtils.ts +22 -0
  152. package/src/utils/cbor.js +429 -0
  153. package/src/utils/checksum.ts +41 -0
  154. package/src/utils/environment.ts +46 -0
  155. package/src/utils/mcumgr.js +444 -0
  156. package/src/utils/stringUtils.ts +11 -0
  157. package/src/vibration/VibrationManager.ts +308 -0
  158. package/src/vibration/VibrationWaveformEffects.ts +128 -0
@@ -0,0 +1,450 @@
1
+ import { createConsole } from "./utils/Console.ts";
2
+ import EventDispatcher from "./utils/EventDispatcher.ts";
3
+ import { textDecoder, textEncoder } from "./utils/Text.ts";
4
+ import SensorDataManager, { SensorTypes } from "./sensor/SensorDataManager.ts";
5
+ import { arrayWithoutDuplicates } from "./utils/ArrayUtils.ts";
6
+ import { SensorRateStep } from "./sensor/SensorConfigurationManager.ts";
7
+ import { parseTimestamp } from "./utils/MathUtils.ts";
8
+ import { SensorType } from "./sensor/SensorDataManager.ts";
9
+ import Device, { SendMessageCallback } from "./Device.ts";
10
+ import autoBind from "auto-bind";
11
+
12
+ const _console = createConsole("TfliteManager", { log: true });
13
+
14
+ export const TfliteMessageTypes = [
15
+ "getTfliteName",
16
+ "setTfliteName",
17
+ "getTfliteTask",
18
+ "setTfliteTask",
19
+ "getTfliteSampleRate",
20
+ "setTfliteSampleRate",
21
+ "getTfliteSensorTypes",
22
+ "setTfliteSensorTypes",
23
+ "tfliteIsReady",
24
+ "getTfliteCaptureDelay",
25
+ "setTfliteCaptureDelay",
26
+ "getTfliteThreshold",
27
+ "setTfliteThreshold",
28
+ "getTfliteInferencingEnabled",
29
+ "setTfliteInferencingEnabled",
30
+ "tfliteInference",
31
+ ] as const;
32
+ export type TfliteMessageType = (typeof TfliteMessageTypes)[number];
33
+
34
+ export const TfliteEventTypes = TfliteMessageTypes;
35
+ export type TfliteEventType = (typeof TfliteEventTypes)[number];
36
+
37
+ export const TfliteTasks = ["classification", "regression"] as const;
38
+ export type TfliteTask = (typeof TfliteTasks)[number];
39
+
40
+ export interface TfliteEventMessages {
41
+ getTfliteName: { tfliteName: string };
42
+ getTfliteTask: { tfliteTask: TfliteTask };
43
+ getTfliteSampleRate: { tfliteSampleRate: number };
44
+ getTfliteSensorTypes: { tfliteSensorTypes: SensorType[] };
45
+ tfliteIsReady: { tfliteIsReady: boolean };
46
+ getTfliteCaptureDelay: { tfliteCaptureDelay: number };
47
+ getTfliteThreshold: { tfliteThreshold: number };
48
+ getTfliteInferencingEnabled: { tfliteInferencingEnabled: boolean };
49
+ tfliteInference: { tfliteInference: TfliteInference };
50
+ }
51
+
52
+ export interface TfliteInference {
53
+ timestamp: number;
54
+ values: number[];
55
+ maxValue?: number;
56
+ maxIndex?: number;
57
+ }
58
+
59
+ export type TfliteEventDispatcher = EventDispatcher<Device, TfliteEventType, TfliteEventMessages>;
60
+ export type SendTfliteMessageCallback = SendMessageCallback<TfliteMessageType>;
61
+
62
+ export const TfliteSensorTypes: SensorType[] = ["pressure", "linearAcceleration", "gyroscope", "magnetometer"] as const;
63
+ export type TfliteSensorType = (typeof TfliteSensorTypes)[number];
64
+
65
+ class TfliteManager {
66
+ constructor() {
67
+ autoBind(this);
68
+ }
69
+
70
+ sendMessage!: SendTfliteMessageCallback;
71
+
72
+ #assertValidTask(task: TfliteTask) {
73
+ _console.assertEnumWithError(task, TfliteTasks);
74
+ }
75
+ #assertValidTaskEnum(taskEnum: number) {
76
+ _console.assertWithError(taskEnum in TfliteTasks, `invalid taskEnum ${taskEnum}`);
77
+ }
78
+
79
+ eventDispatcher!: TfliteEventDispatcher;
80
+ get addEventListenter() {
81
+ return this.eventDispatcher.addEventListener;
82
+ }
83
+ get #dispatchEvent() {
84
+ return this.eventDispatcher.dispatchEvent;
85
+ }
86
+ get removeEventListener() {
87
+ return this.eventDispatcher.removeEventListener;
88
+ }
89
+ get waitForEvent() {
90
+ return this.eventDispatcher.waitForEvent;
91
+ }
92
+
93
+ // PROPERTIES
94
+
95
+ #name!: string;
96
+ get name() {
97
+ return this.#name;
98
+ }
99
+ #parseName(dataView: DataView) {
100
+ _console.log("parseName", dataView);
101
+ const name = textDecoder.decode(dataView.buffer);
102
+ this.#updateName(name);
103
+ }
104
+ #updateName(name: string) {
105
+ _console.log({ name });
106
+ this.#name = name;
107
+ this.#dispatchEvent("getTfliteName", { tfliteName: name });
108
+ }
109
+ async setName(newName: string, sendImmediately?: boolean) {
110
+ _console.assertTypeWithError(newName, "string");
111
+ if (this.name == newName) {
112
+ _console.log(`redundant name assignment ${newName}`);
113
+ return;
114
+ }
115
+
116
+ const promise = this.waitForEvent("getTfliteName");
117
+
118
+ const setNameData = textEncoder.encode(newName);
119
+ this.sendMessage([{ type: "setTfliteName", data: setNameData.buffer }], sendImmediately);
120
+
121
+ await promise;
122
+ }
123
+
124
+ #task!: TfliteTask;
125
+ get task() {
126
+ return this.#task;
127
+ }
128
+ #parseTask(dataView: DataView) {
129
+ _console.log("parseTask", dataView);
130
+ const taskEnum = dataView.getUint8(0);
131
+ this.#assertValidTaskEnum(taskEnum);
132
+ const task = TfliteTasks[taskEnum];
133
+ this.#updateTask(task);
134
+ }
135
+ #updateTask(task: TfliteTask) {
136
+ _console.log({ task });
137
+ this.#task = task;
138
+ this.#dispatchEvent("getTfliteTask", { tfliteTask: task });
139
+ }
140
+ async setTask(newTask: TfliteTask, sendImmediately?: boolean) {
141
+ this.#assertValidTask(newTask);
142
+ if (this.task == newTask) {
143
+ _console.log(`redundant task assignment ${newTask}`);
144
+ return;
145
+ }
146
+
147
+ const promise = this.waitForEvent("getTfliteTask");
148
+
149
+ const taskEnum = TfliteTasks.indexOf(newTask);
150
+ this.sendMessage([{ type: "setTfliteTask", data: Uint8Array.from([taskEnum]).buffer }], sendImmediately);
151
+
152
+ await promise;
153
+ }
154
+
155
+ #sampleRate!: number;
156
+ get sampleRate() {
157
+ return this.#sampleRate;
158
+ }
159
+ #parseSampleRate(dataView: DataView) {
160
+ _console.log("parseSampleRate", dataView);
161
+ const sampleRate = dataView.getUint16(0, true);
162
+ this.#updateSampleRate(sampleRate);
163
+ }
164
+ #updateSampleRate(sampleRate: number) {
165
+ _console.log({ sampleRate });
166
+ this.#sampleRate = sampleRate;
167
+ this.#dispatchEvent("getTfliteSampleRate", { tfliteSampleRate: sampleRate });
168
+ }
169
+ async setSampleRate(newSampleRate: number, sendImmediately?: boolean) {
170
+ _console.assertTypeWithError(newSampleRate, "number");
171
+ newSampleRate -= newSampleRate % SensorRateStep;
172
+ _console.assertWithError(
173
+ newSampleRate >= SensorRateStep,
174
+ `sampleRate must be multiple of ${SensorRateStep} greater than 0 (got ${newSampleRate})`
175
+ );
176
+ if (this.#sampleRate == newSampleRate) {
177
+ _console.log(`redundant sampleRate assignment ${newSampleRate}`);
178
+ return;
179
+ }
180
+
181
+ const promise = this.waitForEvent("getTfliteSampleRate");
182
+
183
+ const dataView = new DataView(new ArrayBuffer(2));
184
+ dataView.setUint16(0, newSampleRate, true);
185
+ this.sendMessage([{ type: "setTfliteSampleRate", data: dataView.buffer }], sendImmediately);
186
+
187
+ await promise;
188
+ }
189
+
190
+ static AssertValidSensorType(sensorType: SensorType) {
191
+ SensorDataManager.AssertValidSensorType(sensorType);
192
+ _console.assertWithError(TfliteSensorTypes.includes(sensorType), `invalid tflite sensorType "${sensorType}"`);
193
+ }
194
+
195
+ #sensorTypes: SensorType[] = [];
196
+ get sensorTypes() {
197
+ return this.#sensorTypes.slice();
198
+ }
199
+ #parseSensorTypes(dataView: DataView) {
200
+ _console.log("parseSensorTypes", dataView);
201
+ const sensorTypes: SensorType[] = [];
202
+ for (let index = 0; index < dataView.byteLength; index++) {
203
+ const sensorTypeEnum = dataView.getUint8(index);
204
+ const sensorType = SensorTypes[sensorTypeEnum];
205
+ if (sensorType) {
206
+ sensorTypes.push(sensorType);
207
+ } else {
208
+ _console.error(`invalid sensorTypeEnum ${sensorTypeEnum}`);
209
+ }
210
+ }
211
+ this.#updateSensorTypes(sensorTypes);
212
+ }
213
+ #updateSensorTypes(sensorTypes: SensorType[]) {
214
+ _console.log({ sensorTypes });
215
+ this.#sensorTypes = sensorTypes;
216
+ this.#dispatchEvent("getTfliteSensorTypes", { tfliteSensorTypes: sensorTypes });
217
+ }
218
+ async setSensorTypes(newSensorTypes: SensorType[], sendImmediately?: boolean) {
219
+ newSensorTypes.forEach((sensorType) => {
220
+ TfliteManager.AssertValidSensorType(sensorType);
221
+ });
222
+
223
+ const promise = this.waitForEvent("getTfliteSensorTypes");
224
+
225
+ newSensorTypes = arrayWithoutDuplicates(newSensorTypes);
226
+ const newSensorTypeEnums = newSensorTypes.map((sensorType) => SensorTypes.indexOf(sensorType)).sort();
227
+ _console.log(newSensorTypes, newSensorTypeEnums);
228
+ this.sendMessage(
229
+ [{ type: "setTfliteSensorTypes", data: Uint8Array.from(newSensorTypeEnums).buffer }],
230
+ sendImmediately
231
+ );
232
+
233
+ await promise;
234
+ }
235
+
236
+ #isReady!: boolean;
237
+ get isReady() {
238
+ return this.#isReady;
239
+ }
240
+ #parseIsReady(dataView: DataView) {
241
+ _console.log("parseIsReady", dataView);
242
+ const isReady = Boolean(dataView.getUint8(0));
243
+ this.#updateIsReady(isReady);
244
+ }
245
+ #updateIsReady(isReady: boolean) {
246
+ _console.log({ isReady });
247
+ this.#isReady = isReady;
248
+ this.#dispatchEvent("tfliteIsReady", { tfliteIsReady: isReady });
249
+ }
250
+ #assertIsReady() {
251
+ _console.assertWithError(this.isReady, `tflite is not ready`);
252
+ }
253
+
254
+ #captureDelay!: number;
255
+ get captureDelay() {
256
+ return this.#captureDelay;
257
+ }
258
+ #parseCaptureDelay(dataView: DataView) {
259
+ _console.log("parseCaptureDelay", dataView);
260
+ const captureDelay = dataView.getUint16(0, true);
261
+ this.#updateCaptueDelay(captureDelay);
262
+ }
263
+ #updateCaptueDelay(captureDelay: number) {
264
+ _console.log({ captureDelay });
265
+ this.#captureDelay = captureDelay;
266
+ this.#dispatchEvent("getTfliteCaptureDelay", { tfliteCaptureDelay: captureDelay });
267
+ }
268
+ async setCaptureDelay(newCaptureDelay: number, sendImmediately: boolean) {
269
+ _console.assertTypeWithError(newCaptureDelay, "number");
270
+ if (this.#captureDelay == newCaptureDelay) {
271
+ _console.log(`redundant captureDelay assignment ${newCaptureDelay}`);
272
+ return;
273
+ }
274
+
275
+ const promise = this.waitForEvent("getTfliteCaptureDelay");
276
+
277
+ const dataView = new DataView(new ArrayBuffer(2));
278
+ dataView.setUint16(0, newCaptureDelay, true);
279
+ this.sendMessage([{ type: "setTfliteCaptureDelay", data: dataView.buffer }], sendImmediately);
280
+
281
+ await promise;
282
+ }
283
+
284
+ #threshold!: number;
285
+ get threshold() {
286
+ return this.#threshold;
287
+ }
288
+ #parseThreshold(dataView: DataView) {
289
+ _console.log("parseThreshold", dataView);
290
+ const threshold = dataView.getFloat32(0, true);
291
+ this.#updateThreshold(threshold);
292
+ }
293
+ #updateThreshold(threshold: number) {
294
+ _console.log({ threshold });
295
+ this.#threshold = threshold;
296
+ this.#dispatchEvent("getTfliteThreshold", { tfliteThreshold: threshold });
297
+ }
298
+ async setThreshold(newThreshold: number, sendImmediately: boolean) {
299
+ _console.assertTypeWithError(newThreshold, "number");
300
+ _console.assertWithError(newThreshold >= 0, `threshold must be positive (got ${newThreshold})`);
301
+ if (this.#threshold == newThreshold) {
302
+ _console.log(`redundant threshold assignment ${newThreshold}`);
303
+ return;
304
+ }
305
+
306
+ const promise = this.waitForEvent("getTfliteThreshold");
307
+
308
+ const dataView = new DataView(new ArrayBuffer(4));
309
+ dataView.setFloat32(0, newThreshold, true);
310
+ this.sendMessage([{ type: "setTfliteThreshold", data: dataView.buffer }], sendImmediately);
311
+
312
+ await promise;
313
+ }
314
+
315
+ #inferencingEnabled!: boolean;
316
+ get inferencingEnabled() {
317
+ return this.#inferencingEnabled;
318
+ }
319
+ #parseInferencingEnabled(dataView: DataView) {
320
+ _console.log("parseInferencingEnabled", dataView);
321
+ const inferencingEnabled = Boolean(dataView.getUint8(0));
322
+ this.#updateInferencingEnabled(inferencingEnabled);
323
+ }
324
+ #updateInferencingEnabled(inferencingEnabled: boolean) {
325
+ _console.log({ inferencingEnabled });
326
+ this.#inferencingEnabled = inferencingEnabled;
327
+ this.#dispatchEvent("getTfliteInferencingEnabled", { tfliteInferencingEnabled: inferencingEnabled });
328
+ }
329
+ async setInferencingEnabled(newInferencingEnabled: boolean, sendImmediately: boolean = true) {
330
+ _console.assertTypeWithError(newInferencingEnabled, "boolean");
331
+ if (!newInferencingEnabled && !this.isReady) {
332
+ return;
333
+ }
334
+ this.#assertIsReady();
335
+ if (this.#inferencingEnabled == newInferencingEnabled) {
336
+ _console.log(`redundant inferencingEnabled assignment ${newInferencingEnabled}`);
337
+ return;
338
+ }
339
+
340
+ const promise = this.waitForEvent("getTfliteInferencingEnabled");
341
+
342
+ this.sendMessage(
343
+ [
344
+ {
345
+ type: "setTfliteInferencingEnabled",
346
+ data: Uint8Array.from([Number(newInferencingEnabled)]).buffer,
347
+ },
348
+ ],
349
+ sendImmediately
350
+ );
351
+
352
+ await promise;
353
+ }
354
+ async toggleInferencingEnabled() {
355
+ return this.setInferencingEnabled(!this.inferencingEnabled);
356
+ }
357
+
358
+ async enableInferencing() {
359
+ if (this.inferencingEnabled) {
360
+ return;
361
+ }
362
+ this.setInferencingEnabled(true);
363
+ }
364
+ async disableInferencing() {
365
+ if (!this.inferencingEnabled) {
366
+ return;
367
+ }
368
+ this.setInferencingEnabled(false);
369
+ }
370
+
371
+ #parseInference(dataView: DataView) {
372
+ _console.log("parseInference", dataView);
373
+
374
+ const timestamp = parseTimestamp(dataView, 0);
375
+ _console.log({ timestamp });
376
+
377
+ const values: number[] = [];
378
+ for (let index = 0, byteOffset = 2; byteOffset < dataView.byteLength; index++, byteOffset += 4) {
379
+ const value = dataView.getFloat32(byteOffset, true);
380
+ values.push(value);
381
+ }
382
+ _console.log("values", values);
383
+
384
+ const inference: TfliteInference = {
385
+ timestamp,
386
+ values,
387
+ };
388
+
389
+ if (this.task == "classification") {
390
+ let maxValue = 0;
391
+ let maxIndex = 0;
392
+ values.forEach((value, index) => {
393
+ if (value > maxValue) {
394
+ maxValue = value;
395
+ maxIndex = index;
396
+ }
397
+ });
398
+ _console.log({ maxIndex, maxValue });
399
+ inference.maxIndex = maxIndex;
400
+ inference.maxValue = maxValue;
401
+ }
402
+
403
+ this.#dispatchEvent("tfliteInference", { tfliteInference: inference });
404
+ }
405
+
406
+ parseMessage(messageType: TfliteMessageType, dataView: DataView) {
407
+ _console.log({ messageType });
408
+
409
+ switch (messageType) {
410
+ case "getTfliteName":
411
+ case "setTfliteName":
412
+ this.#parseName(dataView);
413
+ break;
414
+ case "getTfliteTask":
415
+ case "setTfliteTask":
416
+ this.#parseTask(dataView);
417
+ break;
418
+ case "getTfliteSampleRate":
419
+ case "setTfliteSampleRate":
420
+ this.#parseSampleRate(dataView);
421
+ break;
422
+ case "getTfliteSensorTypes":
423
+ case "setTfliteSensorTypes":
424
+ this.#parseSensorTypes(dataView);
425
+ break;
426
+ case "tfliteIsReady":
427
+ this.#parseIsReady(dataView);
428
+ break;
429
+ case "getTfliteCaptureDelay":
430
+ case "setTfliteCaptureDelay":
431
+ this.#parseCaptureDelay(dataView);
432
+ break;
433
+ case "getTfliteThreshold":
434
+ case "setTfliteThreshold":
435
+ this.#parseThreshold(dataView);
436
+ break;
437
+ case "getTfliteInferencingEnabled":
438
+ case "setTfliteInferencingEnabled":
439
+ this.#parseInferencingEnabled(dataView);
440
+ break;
441
+ case "tfliteInference":
442
+ this.#parseInference(dataView);
443
+ break;
444
+ default:
445
+ throw Error(`uncaught messageType ${messageType}`);
446
+ }
447
+ }
448
+ }
449
+
450
+ export default TfliteManager;
@@ -0,0 +1,255 @@
1
+ import { createConsole } from "../utils/Console.ts";
2
+ import Timer from "../utils/Timer.ts";
3
+
4
+ import { FileTransferMessageTypes } from "../FileTransferManager.ts";
5
+ import { TfliteMessageTypes } from "../TfliteManager.ts";
6
+ import { concatenateArrayBuffers } from "../utils/ArrayBufferUtils.ts";
7
+ import { parseMessage } from "../utils/ParseUtils.ts";
8
+ import { DeviceInformationMessageTypes } from "../DeviceInformationManager.ts";
9
+ import { InformationMessageTypes } from "../InformationManager.ts";
10
+ import { VibrationMessageTypes } from "../vibration/VibrationManager.ts";
11
+ import { SensorConfigurationMessageTypes } from "../sensor/SensorConfigurationManager.ts";
12
+ import { SensorDataMessageTypes } from "../sensor/SensorDataManager.ts";
13
+
14
+ const _console = createConsole("BaseConnectionManager", { log: true });
15
+
16
+ export const ConnectionTypes = ["webBluetooth", "noble", "client"] as const;
17
+ export type ConnectionType = (typeof ConnectionTypes)[number];
18
+
19
+ export const ConnectionStatuses = ["notConnected", "connecting", "connected", "disconnecting"] as const;
20
+ export type ConnectionStatus = (typeof ConnectionStatuses)[number];
21
+
22
+ export const ConnectionEventTypes = [...ConnectionStatuses, "connectionStatus", "isConnected"] as const;
23
+ export type ConnectionEventType = (typeof ConnectionEventTypes)[number];
24
+
25
+ export interface ConnectionStatusEventMessages {
26
+ notConnected: any;
27
+ connecting: any;
28
+ connected: any;
29
+ disconnecting: any;
30
+ connectionStatus: { connectionStatus: ConnectionStatus };
31
+ isConnected: { isConnected: boolean };
32
+ }
33
+
34
+ export interface TxMessage {
35
+ type: TxRxMessageType;
36
+ data?: ArrayBuffer;
37
+ }
38
+
39
+ export const TxRxMessageTypes = [
40
+ ...InformationMessageTypes,
41
+ ...SensorConfigurationMessageTypes,
42
+ ...SensorDataMessageTypes,
43
+ ...VibrationMessageTypes,
44
+ ...TfliteMessageTypes,
45
+ ...FileTransferMessageTypes,
46
+ ] as const;
47
+ export type TxRxMessageType = (typeof TxRxMessageTypes)[number];
48
+
49
+ export const SMPMessageTypes = ["smp"] as const;
50
+ export type SMPMessageType = (typeof SMPMessageTypes)[number];
51
+
52
+ export const BatteryLevelMessageTypes = ["batteryLevel"] as const;
53
+ export type BatteryLevelMessageType = (typeof BatteryLevelMessageTypes)[number];
54
+
55
+ export const MetaConnectionMessageTypes = ["rx", "tx"] as const;
56
+ export type MetaConnectionMessageType = (typeof MetaConnectionMessageTypes)[number];
57
+
58
+ export const ConnectionMessageTypes = [
59
+ ...BatteryLevelMessageTypes,
60
+ ...DeviceInformationMessageTypes,
61
+ ...MetaConnectionMessageTypes,
62
+ ...TxRxMessageTypes,
63
+ ...SMPMessageTypes,
64
+ ] as const;
65
+ export type ConnectionMessageType = (typeof ConnectionMessageTypes)[number];
66
+
67
+ export type ConnectionStatusCallback = (status: ConnectionStatus) => void;
68
+ export type MessageReceivedCallback = (messageType: ConnectionMessageType, dataView: DataView) => void;
69
+
70
+ abstract class BaseConnectionManager {
71
+ static #AssertValidTxRxMessageType(messageType: TxRxMessageType) {
72
+ _console.assertEnumWithError(messageType, TxRxMessageTypes);
73
+ }
74
+
75
+ abstract get bluetoothId(): string;
76
+
77
+ // CALLBACKS
78
+ onStatusUpdated?: ConnectionStatusCallback;
79
+ onMessageReceived?: MessageReceivedCallback;
80
+
81
+ protected get baseConstructor() {
82
+ return this.constructor as typeof BaseConnectionManager;
83
+ }
84
+ static get isSupported() {
85
+ return false;
86
+ }
87
+ get isSupported() {
88
+ return this.baseConstructor.isSupported;
89
+ }
90
+
91
+ static type: ConnectionType;
92
+ get type(): ConnectionType {
93
+ return this.baseConstructor.type;
94
+ }
95
+
96
+ /** @throws {Error} if not supported */
97
+ #assertIsSupported() {
98
+ _console.assertWithError(this.isSupported, `${this.constructor.name} is not supported`);
99
+ }
100
+
101
+ constructor() {
102
+ this.#assertIsSupported();
103
+ }
104
+
105
+ #status: ConnectionStatus = "notConnected";
106
+ get status() {
107
+ return this.#status;
108
+ }
109
+ protected set status(newConnectionStatus) {
110
+ _console.assertEnumWithError(newConnectionStatus, ConnectionStatuses);
111
+ if (this.#status == newConnectionStatus) {
112
+ _console.log(`tried to assign same connection status "${newConnectionStatus}"`);
113
+ return;
114
+ }
115
+ _console.log(`new connection status "${newConnectionStatus}"`);
116
+ this.#status = newConnectionStatus;
117
+ this.onStatusUpdated!(this.status);
118
+
119
+ if (this.isConnected) {
120
+ this.#timer.start();
121
+ } else {
122
+ this.#timer.stop();
123
+ }
124
+
125
+ if (this.#status == "notConnected") {
126
+ this.mtu = undefined;
127
+ }
128
+ }
129
+
130
+ get isConnected() {
131
+ return this.status == "connected";
132
+ }
133
+
134
+ /** @throws {Error} if connected */
135
+ #assertIsNotConnected() {
136
+ _console.assertWithError(!this.isConnected, "device is already connected");
137
+ }
138
+ /** @throws {Error} if connecting */
139
+ #assertIsNotConnecting() {
140
+ _console.assertWithError(this.status != "connecting", "device is already connecting");
141
+ }
142
+ /** @throws {Error} if not connected */
143
+ #assertIsConnected() {
144
+ _console.assertWithError(this.isConnected, "device is not connected");
145
+ }
146
+ /** @throws {Error} if disconnecting */
147
+ #assertIsNotDisconnecting() {
148
+ _console.assertWithError(this.status != "disconnecting", "device is already disconnecting");
149
+ }
150
+ /** @throws {Error} if not connected or is disconnecting */
151
+ #assertIsConnectedAndNotDisconnecting() {
152
+ this.#assertIsConnected();
153
+ this.#assertIsNotDisconnecting();
154
+ }
155
+
156
+ async connect() {
157
+ this.#assertIsNotConnected();
158
+ this.#assertIsNotConnecting();
159
+ this.status = "connecting";
160
+ }
161
+ get canReconnect() {
162
+ return false;
163
+ }
164
+ async reconnect() {
165
+ this.#assertIsNotConnected();
166
+ this.#assertIsNotConnecting();
167
+ _console.assert(this.canReconnect, "unable to reconnect");
168
+ }
169
+ async disconnect() {
170
+ this.#assertIsConnected();
171
+ this.#assertIsNotDisconnecting();
172
+ this.status = "disconnecting";
173
+ _console.log("disconnecting from device...");
174
+ }
175
+
176
+ async sendSmpMessage(data: ArrayBuffer) {
177
+ this.#assertIsConnectedAndNotDisconnecting();
178
+ _console.log("sending smp message", data);
179
+ }
180
+
181
+ #pendingMessages: TxMessage[] = [];
182
+
183
+ async sendTxMessages(messages: TxMessage[] | undefined, sendImmediately: boolean = true) {
184
+ this.#assertIsConnectedAndNotDisconnecting();
185
+
186
+ if (messages) {
187
+ this.#pendingMessages.push(...messages);
188
+ }
189
+
190
+ if (!sendImmediately) {
191
+ return;
192
+ }
193
+
194
+ _console.log("sendTxMessages", this.#pendingMessages.slice());
195
+
196
+ const arrayBuffers = this.#pendingMessages.map((message) => {
197
+ BaseConnectionManager.#AssertValidTxRxMessageType(message.type);
198
+ const messageTypeEnum = TxRxMessageTypes.indexOf(message.type);
199
+ const dataLength = new DataView(new ArrayBuffer(2));
200
+ dataLength.setUint16(0, message.data?.byteLength || 0, true);
201
+ return concatenateArrayBuffers(messageTypeEnum, dataLength, message.data);
202
+ });
203
+
204
+ if (this.mtu) {
205
+ while (arrayBuffers.length > 0) {
206
+ let arrayBufferByteLength = 0;
207
+ let arrayBufferCount = 0;
208
+ arrayBuffers.some((arrayBuffer) => {
209
+ if (arrayBufferByteLength + arrayBuffer.byteLength > this.mtu! - 3) {
210
+ return true;
211
+ }
212
+ arrayBufferCount++;
213
+ arrayBufferByteLength += arrayBuffer.byteLength;
214
+ });
215
+ const arrayBuffersToSend = arrayBuffers.splice(0, arrayBufferCount);
216
+ _console.log({ arrayBufferCount, arrayBuffersToSend });
217
+
218
+ const arrayBuffer = concatenateArrayBuffers(...arrayBuffersToSend);
219
+ _console.log("sending arrayBuffer", arrayBuffer);
220
+ await this.sendTxData(arrayBuffer);
221
+ }
222
+ } else {
223
+ const arrayBuffer = concatenateArrayBuffers(...arrayBuffers);
224
+ _console.log("sending arrayBuffer", arrayBuffer);
225
+ await this.sendTxData(arrayBuffer);
226
+ }
227
+ this.#pendingMessages.length = 0;
228
+ }
229
+
230
+ mtu?: number;
231
+
232
+ async sendTxData(data: ArrayBuffer) {
233
+ _console.log("sendTxData", data);
234
+ }
235
+
236
+ parseRxMessage(dataView: DataView) {
237
+ parseMessage(dataView, TxRxMessageTypes, this.#onRxMessage.bind(this), null, true);
238
+ }
239
+
240
+ #onRxMessage(messageType: TxRxMessageType, dataView: DataView) {
241
+ _console.log({ messageType, dataView });
242
+ this.onMessageReceived!(messageType, dataView);
243
+ }
244
+
245
+ #timer = new Timer(this.#checkConnection.bind(this), 5000);
246
+ #checkConnection() {
247
+ //console.log("checking connection...");
248
+ if (!this.isConnected) {
249
+ _console.log("timer detected disconnection");
250
+ this.status = "notConnected";
251
+ }
252
+ }
253
+ }
254
+
255
+ export default BaseConnectionManager;