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,253 @@
1
+ import { createConsole } from "../utils/Console.ts";
2
+ import EventDispatcher, { BoundEventListeners, Event, EventListenerMap, EventMap } from "../utils/EventDispatcher.ts";
3
+ import { addEventListeners, removeEventListeners } from "../utils/EventUtils.ts";
4
+ import Device, {
5
+ DeviceEvent,
6
+ DeviceEventType,
7
+ DeviceEventMessages,
8
+ DeviceEventTypes,
9
+ BoundDeviceEventListeners,
10
+ DeviceEventMap,
11
+ } from "../Device.ts";
12
+ import DevicePairSensorDataManager, { DevicePairSensorDataEventDispatcher } from "./DevicePairSensorDataManager.ts";
13
+ import { capitalizeFirstCharacter } from "../utils/stringUtils.ts";
14
+ import { InsoleSide, InsoleSides } from "../InformationManager.ts";
15
+ import { VibrationConfiguration } from "../vibration/VibrationManager.ts";
16
+ import { SensorConfiguration } from "../sensor/SensorConfigurationManager.ts";
17
+ import { DevicePairSensorDataEventMessages, DevicePairSensorDataEventTypes } from "./DevicePairSensorDataManager.ts";
18
+ import { AddPrefixToInterfaceKeys, ExtendInterfaceValues, KeyOf } from "../utils/TypeScriptUtils.ts";
19
+ import DeviceManager from "../DeviceManager.ts";
20
+
21
+ const _console = createConsole("DevicePair", { log: true });
22
+
23
+ interface BaseDevicePairDeviceEventMessage {
24
+ device: Device;
25
+ side: InsoleSide;
26
+ }
27
+ type DevicePairDeviceEventMessages = ExtendInterfaceValues<
28
+ AddPrefixToInterfaceKeys<DeviceEventMessages, "device">,
29
+ BaseDevicePairDeviceEventMessage
30
+ >;
31
+ type DevicePairDeviceEventType = KeyOf<DevicePairDeviceEventMessages>;
32
+ function getDevicePairDeviceEventType(deviceEventType: DeviceEventType) {
33
+ return `device${capitalizeFirstCharacter(deviceEventType)}` as DevicePairDeviceEventType;
34
+ }
35
+ const DevicePairDeviceEventTypes = DeviceEventTypes.map((eventType) =>
36
+ getDevicePairDeviceEventType(eventType)
37
+ ) as DevicePairDeviceEventType[];
38
+
39
+ export const DevicePairConnectionEventTypes = ["isConnected"] as const;
40
+ export type DevicePairConnectionEventType = (typeof DevicePairConnectionEventTypes)[number];
41
+
42
+ export interface DevicePairConnectionEventMessages {
43
+ isConnected: { isConnected: boolean };
44
+ }
45
+
46
+ export const DevicePairEventTypes = [
47
+ ...DevicePairConnectionEventTypes,
48
+ ...DevicePairSensorDataEventTypes,
49
+ ...DevicePairDeviceEventTypes,
50
+ ] as const;
51
+ export type DevicePairEventType = (typeof DevicePairEventTypes)[number];
52
+
53
+ export type DevicePairEventMessages = DevicePairConnectionEventMessages &
54
+ DevicePairSensorDataEventMessages &
55
+ DevicePairDeviceEventMessages;
56
+
57
+ export type DevicePairEventDispatcher = EventDispatcher<DevicePair, DevicePairEventType, DevicePairEventMessages>;
58
+ export type DevicePairEventMap = EventMap<DevicePair, DeviceEventType, DevicePairEventMessages>;
59
+ export type DevicePairEventListenerMap = EventListenerMap<DevicePair, DeviceEventType, DevicePairEventMessages>;
60
+ export type DevicePairEvent = Event<DevicePair, DeviceEventType, DevicePairEventMessages>;
61
+ export type BoundDevicePairEventListeners = BoundEventListeners<DevicePair, DeviceEventType, DevicePairEventMessages>;
62
+
63
+ class DevicePair {
64
+ constructor() {
65
+ this.#sensorDataManager.eventDispatcher = this.#eventDispatcher as DevicePairSensorDataEventDispatcher;
66
+ }
67
+
68
+ get sides() {
69
+ return InsoleSides;
70
+ }
71
+
72
+ #eventDispatcher: DevicePairEventDispatcher = new EventDispatcher(this as DevicePair, DevicePairEventTypes);
73
+ get addEventListener() {
74
+ return this.#eventDispatcher.addEventListener;
75
+ }
76
+ get #dispatchEvent() {
77
+ return this.#eventDispatcher.dispatchEvent;
78
+ }
79
+ get removeEventListener() {
80
+ return this.#eventDispatcher.removeEventListener;
81
+ }
82
+ get waitForEvent() {
83
+ return this.#eventDispatcher.waitForEvent;
84
+ }
85
+
86
+ // SIDES
87
+ #left?: Device;
88
+ get left() {
89
+ return this.#left;
90
+ }
91
+
92
+ #right?: Device;
93
+ get right() {
94
+ return this.#right;
95
+ }
96
+
97
+ get isConnected() {
98
+ return InsoleSides.every((side) => this[side]?.isConnected);
99
+ }
100
+ get isPartiallyConnected() {
101
+ return InsoleSides.some((side) => this[side]?.isConnected);
102
+ }
103
+ get isHalfConnected() {
104
+ return this.isPartiallyConnected && !this.isConnected;
105
+ }
106
+ #assertIsConnected() {
107
+ _console.assertWithError(this.isConnected, "devicePair must be connected");
108
+ }
109
+
110
+ assignInsole(device: Device) {
111
+ if (!device.isInsole) {
112
+ _console.warn("device is not an insole");
113
+ return;
114
+ }
115
+ const side = device.insoleSide;
116
+
117
+ const currentDevice = this[side];
118
+
119
+ if (device == currentDevice) {
120
+ _console.log("device already assigned");
121
+ return;
122
+ }
123
+
124
+ if (currentDevice) {
125
+ this.#removeDeviceEventListeners(currentDevice);
126
+ }
127
+ this.#addDeviceEventListeners(device);
128
+
129
+ switch (side) {
130
+ case "left":
131
+ this.#left = device;
132
+ break;
133
+ case "right":
134
+ this.#right = device;
135
+ break;
136
+ }
137
+
138
+ _console.log(`assigned ${side} insole`, device);
139
+
140
+ this.resetPressureRange();
141
+
142
+ this.#dispatchEvent("isConnected", { isConnected: this.isConnected });
143
+ this.#dispatchEvent("deviceIsConnected", { device, isConnected: device.isConnected, side });
144
+
145
+ return currentDevice;
146
+ }
147
+
148
+ #addDeviceEventListeners(device: Device) {
149
+ addEventListeners(device, this.#boundDeviceEventListeners);
150
+ DeviceEventTypes.forEach((deviceEventType) => {
151
+ // @ts-expect-error
152
+ device.addEventListener(deviceEventType, this.#redispatchDeviceEvent.bind(this));
153
+ });
154
+ }
155
+ #removeDeviceEventListeners(device: Device) {
156
+ removeEventListeners(device, this.#boundDeviceEventListeners);
157
+ DeviceEventTypes.forEach((deviceEventType) => {
158
+ // @ts-expect-error
159
+ device.removeEventListener(deviceEventType, this.#redispatchDeviceEvent.bind(this));
160
+ });
161
+ }
162
+
163
+ #removeInsole(device: Device) {
164
+ const foundDevice = InsoleSides.some((side) => {
165
+ if (this[side] != device) {
166
+ return false;
167
+ }
168
+
169
+ _console.log(`removing ${side} insole`, device);
170
+ removeEventListeners(device, this.#boundDeviceEventListeners);
171
+ delete this[side];
172
+
173
+ return true;
174
+ });
175
+ if (foundDevice) {
176
+ this.#dispatchEvent("isConnected", { isConnected: this.isConnected });
177
+ }
178
+ return foundDevice;
179
+ }
180
+
181
+ #boundDeviceEventListeners: BoundDeviceEventListeners = {
182
+ isConnected: this.#onDeviceIsConnected.bind(this),
183
+ sensorData: this.#onDeviceSensorData.bind(this),
184
+ getType: this.#onDeviceType.bind(this),
185
+ };
186
+
187
+ #redispatchDeviceEvent(deviceEvent: DeviceEvent) {
188
+ const { type, target: device, message } = deviceEvent;
189
+ this.#dispatchEvent(getDevicePairDeviceEventType(type), {
190
+ ...message,
191
+ device,
192
+ side: device.insoleSide,
193
+ });
194
+ }
195
+
196
+ #onDeviceIsConnected(deviceEvent: DeviceEventMap["isConnected"]) {
197
+ this.#dispatchEvent("isConnected", { isConnected: this.isConnected });
198
+ }
199
+
200
+ #onDeviceType(deviceEvent: DeviceEventMap["getType"]) {
201
+ const { target: device } = deviceEvent;
202
+ if (this[device.insoleSide] == device) {
203
+ return;
204
+ }
205
+ const foundDevice = this.#removeInsole(device);
206
+ if (!foundDevice) {
207
+ return;
208
+ }
209
+ this.assignInsole(device);
210
+ }
211
+
212
+ // SENSOR CONFIGURATION
213
+ setSensorConfiguration(sensorConfiguration: SensorConfiguration) {
214
+ InsoleSides.forEach((side) => {
215
+ this[side]?.setSensorConfiguration(sensorConfiguration);
216
+ });
217
+ }
218
+
219
+ // SENSOR DATA
220
+ #sensorDataManager = new DevicePairSensorDataManager();
221
+ #onDeviceSensorData(deviceEvent: DeviceEventMap["sensorData"]) {
222
+ if (this.isConnected) {
223
+ this.#sensorDataManager.onDeviceSensorData(deviceEvent);
224
+ }
225
+ }
226
+ resetPressureRange() {
227
+ this.#sensorDataManager.resetPressureRange();
228
+ }
229
+
230
+ // VIBRATION
231
+ async triggerVibration(vibrationConfigurations: VibrationConfiguration[], sendImmediately?: boolean) {
232
+ const promises = InsoleSides.map((side) => {
233
+ return this[side]?.triggerVibration(vibrationConfigurations, sendImmediately);
234
+ }).filter(Boolean);
235
+ return Promise.allSettled(promises);
236
+ }
237
+
238
+ // SHARED INSTANCE
239
+ static #shared = new DevicePair();
240
+ static get shared() {
241
+ return this.#shared;
242
+ }
243
+ static {
244
+ DeviceManager.AddEventListener("deviceConnected", (event) => {
245
+ const { device } = event.message;
246
+ if (device.isInsole) {
247
+ this.#shared.assignInsole(device);
248
+ }
249
+ });
250
+ }
251
+ }
252
+
253
+ export default DevicePair;
@@ -0,0 +1,82 @@
1
+ import { createConsole } from "../utils/Console.ts";
2
+ import CenterOfPressureHelper from "../utils/CenterOfPressureHelper.ts";
3
+ import { PressureData } from "../sensor/PressureSensorDataManager.ts";
4
+ import { CenterOfPressure } from "../utils/CenterOfPressureHelper.ts";
5
+ import { InsoleSide, InsoleSides } from "../InformationManager.ts";
6
+ import { DeviceEventMap } from "../Device.ts";
7
+
8
+ const _console = createConsole("DevicePairPressureSensorDataManager", { log: true });
9
+
10
+ export type DevicePairRawPressureData = { [insoleSide in InsoleSide]: PressureData };
11
+
12
+ export interface DevicePairPressureData {
13
+ rawSum: number;
14
+ normalizedSum: number;
15
+ center?: CenterOfPressure;
16
+ normalizedCenter?: CenterOfPressure;
17
+ }
18
+
19
+ export interface DevicePairPressureDataEventMessage {
20
+ pressure: DevicePairPressureData;
21
+ }
22
+
23
+ export interface DevicePairPressureDataEventMessages {
24
+ pressure: DevicePairPressureDataEventMessage;
25
+ }
26
+
27
+ class DevicePairPressureSensorDataManager {
28
+ #rawPressure: Partial<DevicePairRawPressureData> = {};
29
+
30
+ #centerOfPressureHelper = new CenterOfPressureHelper();
31
+
32
+ resetPressureRange() {
33
+ this.#centerOfPressureHelper.reset();
34
+ }
35
+
36
+ onDevicePressureData(event: DeviceEventMap["pressure"]) {
37
+ const { pressure } = event.message;
38
+ const insoleSide = event.target.insoleSide;
39
+ _console.log({ pressure, insoleSide });
40
+ this.#rawPressure[insoleSide] = pressure;
41
+ if (this.#hasAllPressureData) {
42
+ return this.#updatePressureData();
43
+ } else {
44
+ _console.log("doesn't have all pressure data yet...");
45
+ }
46
+ }
47
+
48
+ get #hasAllPressureData() {
49
+ return InsoleSides.every((side) => side in this.#rawPressure);
50
+ }
51
+
52
+ #updatePressureData() {
53
+ const pressure: DevicePairPressureData = { rawSum: 0, normalizedSum: 0 };
54
+
55
+ InsoleSides.forEach((side) => {
56
+ pressure.rawSum += this.#rawPressure[side]!.scaledSum;
57
+ pressure.normalizedSum += this.#rawPressure[side]!.normalizedSum;
58
+ });
59
+
60
+ if (pressure.normalizedSum > 0) {
61
+ pressure.center = { x: 0, y: 0 };
62
+ InsoleSides.forEach((side) => {
63
+ const sidePressure = this.#rawPressure[side]!;
64
+ const normalizedPressureSumWeight = sidePressure.normalizedSum / pressure.normalizedSum;
65
+ if (normalizedPressureSumWeight > 0) {
66
+ pressure.center!.y += sidePressure.normalizedCenter!.y * normalizedPressureSumWeight;
67
+ if (side == "right") {
68
+ pressure.center!.x = normalizedPressureSumWeight;
69
+ }
70
+ }
71
+ });
72
+
73
+ pressure.normalizedCenter = this.#centerOfPressureHelper.updateAndGetNormalization(pressure.center);
74
+ }
75
+
76
+ _console.log({ devicePairPressure: pressure });
77
+
78
+ return pressure;
79
+ }
80
+ }
81
+
82
+ export default DevicePairPressureSensorDataManager;
@@ -0,0 +1,90 @@
1
+ import DevicePairPressureSensorDataManager, {
2
+ DevicePairPressureDataEventMessages,
3
+ } from "./DevicePairPressureSensorDataManager.ts";
4
+ import { createConsole } from "../utils/Console.ts";
5
+ import { InsoleSide } from "../InformationManager.ts";
6
+ import { SensorType } from "../sensor/SensorDataManager.ts";
7
+ import { DeviceEventMap, SpecificDeviceEvent } from "../Device.ts";
8
+ import EventDispatcher from "../utils/EventDispatcher.ts";
9
+ import DevicePair from "./DevicePair.ts";
10
+ import { AddKeysAsPropertyToInterface, ExtendInterfaceValues, ValueOf } from "../utils/TypeScriptUtils.ts";
11
+
12
+ const _console = createConsole("DevicePairSensorDataManager", { log: true });
13
+
14
+ export const DevicePairSensorTypes = ["pressure", "sensorData"] as const;
15
+ export type DevicePairSensorType = (typeof DevicePairSensorTypes)[number];
16
+
17
+ export const DevicePairSensorDataEventTypes = DevicePairSensorTypes;
18
+ export type DevicePairSensorDataEventType = (typeof DevicePairSensorDataEventTypes)[number];
19
+
20
+ export type DevicePairSensorDataTimestamps = { [insoleSide in InsoleSide]: number };
21
+
22
+ interface BaseDevicePairSensorDataEventMessage {
23
+ timestamps: DevicePairSensorDataTimestamps;
24
+ }
25
+
26
+ type BaseDevicePairSensorDataEventMessages = DevicePairPressureDataEventMessages;
27
+ type _DevicePairSensorDataEventMessages = ExtendInterfaceValues<
28
+ AddKeysAsPropertyToInterface<BaseDevicePairSensorDataEventMessages, "sensorType">,
29
+ BaseDevicePairSensorDataEventMessage
30
+ >;
31
+
32
+ export type DevicePairSensorDataEventMessage = ValueOf<_DevicePairSensorDataEventMessages>;
33
+ interface AnyDevicePairSensorDataEventMessages {
34
+ sensorData: DevicePairSensorDataEventMessage;
35
+ }
36
+ export type DevicePairSensorDataEventMessages = _DevicePairSensorDataEventMessages &
37
+ AnyDevicePairSensorDataEventMessages;
38
+
39
+ export type DevicePairSensorDataEventDispatcher = EventDispatcher<
40
+ DevicePair,
41
+ DevicePairSensorDataEventType,
42
+ DevicePairSensorDataEventMessages
43
+ >;
44
+
45
+ class DevicePairSensorDataManager {
46
+ eventDispatcher!: DevicePairSensorDataEventDispatcher;
47
+ get dispatchEvent() {
48
+ return this.eventDispatcher.dispatchEvent;
49
+ }
50
+
51
+ #timestamps: { [sensorType in SensorType]?: Partial<DevicePairSensorDataTimestamps> } = {};
52
+
53
+ pressureSensorDataManager = new DevicePairPressureSensorDataManager();
54
+ resetPressureRange() {
55
+ this.pressureSensorDataManager.resetPressureRange();
56
+ }
57
+
58
+ onDeviceSensorData(event: DeviceEventMap["sensorData"]) {
59
+ const { timestamp, sensorType } = event.message;
60
+
61
+ _console.log({ sensorType, timestamp, event });
62
+
63
+ if (!this.#timestamps[sensorType]) {
64
+ this.#timestamps[sensorType] = {};
65
+ }
66
+ this.#timestamps[sensorType]![event.target.insoleSide] = timestamp;
67
+
68
+ let value;
69
+ switch (sensorType) {
70
+ case "pressure":
71
+ value = this.pressureSensorDataManager.onDevicePressureData(event as unknown as DeviceEventMap["pressure"]);
72
+ break;
73
+ default:
74
+ _console.log(`uncaught sensorType "${sensorType}"`);
75
+ break;
76
+ }
77
+
78
+ if (value) {
79
+ const timestamps = Object.assign({}, this.#timestamps[sensorType]) as DevicePairSensorDataTimestamps;
80
+ // @ts-expect-error
81
+ this.dispatchEvent(sensorType as DevicePairSensorDataEventType, { sensorType, timestamps, [sensorType]: value });
82
+ // @ts-expect-error
83
+ this.dispatchEvent("sensorData", { sensorType, timestamps, [sensorType]: value });
84
+ } else {
85
+ _console.log("no value received");
86
+ }
87
+ }
88
+ }
89
+
90
+ export default DevicePairSensorDataManager;
@@ -0,0 +1,189 @@
1
+ import EventDispatcher, { BoundEventListeners, Event, EventMap } from "../utils/EventDispatcher.ts";
2
+ import { addEventListeners } from "../utils/EventUtils.ts";
3
+ import { createConsole } from "../utils/Console.ts";
4
+ import Timer from "../utils/Timer.ts";
5
+ import { DeviceType } from "../InformationManager.ts";
6
+
7
+ const _console = createConsole("BaseScanner");
8
+
9
+ export const ScannerEventTypes = [
10
+ "isScanningAvailable",
11
+ "isScanning",
12
+ "discoveredDevice",
13
+ "expiredDiscoveredDevice",
14
+ ] as const;
15
+ export type ScannerEventType = (typeof ScannerEventTypes)[number];
16
+
17
+ export interface DiscoveredDevice {
18
+ bluetoothId: string;
19
+ name: string;
20
+ deviceType: DeviceType;
21
+ rssi: number;
22
+ }
23
+
24
+ interface ScannerDiscoveredDeviceEventMessage {
25
+ discoveredDevice: DiscoveredDevice;
26
+ }
27
+
28
+ export interface ScannerEventMessages {
29
+ discoveredDevice: ScannerDiscoveredDeviceEventMessage;
30
+ expiredDiscoveredDevice: ScannerDiscoveredDeviceEventMessage;
31
+ isScanningAvailable: { isScanningAvailable: boolean };
32
+ isScanning: { isScanning: boolean };
33
+ }
34
+
35
+ export type ScannerEventDispatcher = EventDispatcher<BaseScanner, ScannerEventType, ScannerEventMessages>;
36
+ export type ScannerEventMap = EventMap<BaseScanner, ScannerEventType, ScannerEventMessages>;
37
+ export type ScannerEvent = Event<BaseScanner, ScannerEventType, ScannerEventMessages>;
38
+ export type BoundScannerEventListeners = BoundEventListeners<BaseScanner, ScannerEventType, ScannerEventMessages>;
39
+
40
+ export type DiscoveredDevicesMap = { [deviceId: string]: DiscoveredDevice };
41
+
42
+ abstract class BaseScanner {
43
+ // IS SUPPORTED
44
+ protected get baseConstructor() {
45
+ return this.constructor as typeof BaseScanner;
46
+ }
47
+ static get isSupported() {
48
+ return false;
49
+ }
50
+ get isSupported() {
51
+ return this.baseConstructor.isSupported;
52
+ }
53
+
54
+ #assertIsSupported() {
55
+ _console.assertWithError(this.isSupported, `${this.constructor.name} is not supported`);
56
+ }
57
+
58
+ // CONSTRUCTOR
59
+ #assertIsSubclass() {
60
+ _console.assertWithError(this.constructor != BaseScanner, `${this.constructor.name} must be subclassed`);
61
+ }
62
+ constructor() {
63
+ this.#assertIsSubclass();
64
+ this.#assertIsSupported();
65
+ addEventListeners(this, this.#boundEventListeners);
66
+ }
67
+
68
+ #boundEventListeners: BoundScannerEventListeners = {
69
+ discoveredDevice: this.#onDiscoveredDevice.bind(this),
70
+ isScanning: this.#onIsScanning.bind(this),
71
+ };
72
+
73
+ // EVENT DISPATCHER
74
+ #eventDispatcher: ScannerEventDispatcher = new EventDispatcher(this as BaseScanner, ScannerEventTypes);
75
+ get addEventListener() {
76
+ return this.#eventDispatcher.addEventListener;
77
+ }
78
+ protected get dispatchEvent() {
79
+ return this.#eventDispatcher.dispatchEvent;
80
+ }
81
+ get removeEventListener() {
82
+ return this.#eventDispatcher.removeEventListener;
83
+ }
84
+ get waitForEvent() {
85
+ return this.#eventDispatcher.waitForEvent;
86
+ }
87
+
88
+ // AVAILABILITY
89
+ get isScanningAvailable() {
90
+ return false;
91
+ }
92
+ #assertIsAvailable() {
93
+ _console.assertWithError(this.isScanningAvailable, "not available");
94
+ }
95
+
96
+ // SCANNING
97
+ get isScanning() {
98
+ return false;
99
+ }
100
+ #assertIsScanning() {
101
+ _console.assertWithError(this.isScanning, "not scanning");
102
+ }
103
+ #assertIsNotScanning() {
104
+ _console.assertWithError(!this.isScanning, "already scanning");
105
+ }
106
+
107
+ startScan() {
108
+ this.#assertIsAvailable();
109
+ this.#assertIsNotScanning();
110
+ }
111
+ stopScan() {
112
+ this.#assertIsScanning();
113
+ }
114
+ #onIsScanning(event: ScannerEventMap["isScanning"]) {
115
+ if (this.isScanning) {
116
+ this.#discoveredDevices = {};
117
+ this.#discoveredDeviceTimestamps = {};
118
+ } else {
119
+ this.#checkDiscoveredDevicesExpirationTimer.stop();
120
+ }
121
+ }
122
+
123
+ // DISCOVERED DEVICES
124
+ #discoveredDevices: DiscoveredDevicesMap = {};
125
+ get discoveredDevices(): Readonly<DiscoveredDevicesMap> {
126
+ return this.#discoveredDevices;
127
+ }
128
+ get discoveredDevicesArray() {
129
+ return Object.values(this.#discoveredDevices).sort((a, b) => {
130
+ return this.#discoveredDeviceTimestamps[a.bluetoothId] - this.#discoveredDeviceTimestamps[b.bluetoothId];
131
+ });
132
+ }
133
+ #assertValidDiscoveredDeviceId(discoveredDeviceId: string) {
134
+ _console.assertWithError(
135
+ this.#discoveredDevices[discoveredDeviceId],
136
+ `no discovered device with id "${discoveredDeviceId}"`
137
+ );
138
+ }
139
+
140
+ #onDiscoveredDevice(event: ScannerEventMap["discoveredDevice"]) {
141
+ const { discoveredDevice } = event.message;
142
+ this.#discoveredDevices[discoveredDevice.bluetoothId] = discoveredDevice;
143
+ this.#discoveredDeviceTimestamps[discoveredDevice.bluetoothId] = Date.now();
144
+ this.#checkDiscoveredDevicesExpirationTimer.start();
145
+ }
146
+
147
+ #discoveredDeviceTimestamps: { [id: string]: number } = {};
148
+
149
+ static #DiscoveredDeviceExpirationTimeout = 5000;
150
+ static get DiscoveredDeviceExpirationTimeout() {
151
+ return this.#DiscoveredDeviceExpirationTimeout;
152
+ }
153
+ get #discoveredDeviceExpirationTimeout() {
154
+ return BaseScanner.DiscoveredDeviceExpirationTimeout;
155
+ }
156
+ #checkDiscoveredDevicesExpirationTimer = new Timer(this.#checkDiscoveredDevicesExpiration.bind(this), 1000);
157
+ #checkDiscoveredDevicesExpiration() {
158
+ const entries = Object.entries(this.#discoveredDevices);
159
+ if (entries.length == 0) {
160
+ this.#checkDiscoveredDevicesExpirationTimer.stop();
161
+ return;
162
+ }
163
+ const now = Date.now();
164
+ entries.forEach(([id, discoveredDevice]) => {
165
+ const timestamp = this.#discoveredDeviceTimestamps[id];
166
+ if (now - timestamp > this.#discoveredDeviceExpirationTimeout) {
167
+ _console.log("discovered device timeout");
168
+ delete this.#discoveredDevices[id];
169
+ delete this.#discoveredDeviceTimestamps[id];
170
+ this.dispatchEvent("expiredDiscoveredDevice", { discoveredDevice });
171
+ }
172
+ });
173
+ }
174
+
175
+ // DEVICE CONNECTION
176
+ async connectToDevice(deviceId: string) {
177
+ this.#assertIsAvailable();
178
+ }
179
+
180
+ // RESET
181
+ get canReset() {
182
+ return false;
183
+ }
184
+ reset() {
185
+ _console.log("resetting...");
186
+ }
187
+ }
188
+
189
+ export default BaseScanner;