brilliantsole 0.0.27 → 0.0.29

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 (202) hide show
  1. package/assets/3d/anchor.glb +0 -0
  2. package/assets/3d/coin.glb +0 -0
  3. package/assets/3d/glasses.glb +0 -0
  4. package/assets/audio/bounceMedium.wav +0 -0
  5. package/assets/audio/bounceStrong.wav +0 -0
  6. package/assets/audio/bounceWeak.wav +0 -0
  7. package/assets/audio/coin.wav +0 -0
  8. package/assets/audio/getUp.wav +0 -0
  9. package/assets/audio/grab.wav +0 -0
  10. package/assets/audio/kick.wav +0 -0
  11. package/assets/audio/platterFadeIn old.wav +0 -0
  12. package/assets/audio/platterFadeIn.wav +0 -0
  13. package/assets/audio/platterFadeOut.wav +0 -0
  14. package/assets/audio/punch.wav +0 -0
  15. package/assets/audio/punchSqueak.wav +0 -0
  16. package/assets/audio/purr.wav +0 -0
  17. package/assets/audio/purrFadeOut.wav +0 -0
  18. package/assets/audio/release.wav +0 -0
  19. package/assets/audio/splat.wav +0 -0
  20. package/assets/audio/stomp.wav +0 -0
  21. package/build/brilliantsole.cjs +3091 -741
  22. package/build/brilliantsole.cjs.map +1 -1
  23. package/build/brilliantsole.js +2759 -709
  24. package/build/brilliantsole.js.map +1 -1
  25. package/build/brilliantsole.ls.js +2602 -543
  26. package/build/brilliantsole.ls.js.map +1 -1
  27. package/build/brilliantsole.min.js +1 -1
  28. package/build/brilliantsole.min.js.map +1 -1
  29. package/build/brilliantsole.module.d.ts +295 -65
  30. package/build/brilliantsole.module.js +2749 -710
  31. package/build/brilliantsole.module.js.map +1 -1
  32. package/build/brilliantsole.module.min.d.ts +295 -65
  33. package/build/brilliantsole.module.min.js +1 -1
  34. package/build/brilliantsole.module.min.js.map +1 -1
  35. package/build/brilliantsole.node.module.d.ts +289 -62
  36. package/build/brilliantsole.node.module.js +3080 -742
  37. package/build/brilliantsole.node.module.js.map +1 -1
  38. package/build/dts/BS-output.d.ts +10 -0
  39. package/build/dts/BS.d.ts +21 -8
  40. package/build/dts/CameraManager.d.ts +72 -0
  41. package/build/dts/Device.d.ts +64 -13
  42. package/build/dts/DeviceInformationManager.d.ts +4 -4
  43. package/build/dts/DeviceManager.d.ts +2 -0
  44. package/build/dts/FileTransferManager.d.ts +18 -8
  45. package/build/dts/InformationManager.d.ts +2 -0
  46. package/build/dts/MicrophoneManager.d.ts +88 -0
  47. package/build/dts/TfliteManager.d.ts +22 -2
  48. package/build/dts/WifiManager.d.ts +61 -0
  49. package/build/dts/connection/BaseConnectionManager.d.ts +35 -3
  50. package/build/dts/connection/ClientConnectionManager.d.ts +7 -2
  51. package/build/dts/connection/bluetooth/NobleConnectionManager.d.ts +2 -1
  52. package/build/dts/connection/bluetooth/WebBluetoothConnectionManager.d.ts +1 -0
  53. package/build/dts/connection/bluetooth/bluetoothUUIDs.d.ts +2 -2
  54. package/build/dts/connection/udp/UDPConnectionManager.d.ts +28 -0
  55. package/build/dts/connection/webSocket/WebSocketConnectionManager.d.ts +25 -0
  56. package/build/dts/devicePair/DevicePair.d.ts +5 -5
  57. package/build/dts/scanner/BaseScanner.d.ts +4 -1
  58. package/build/dts/scanner/NobleScanner.d.ts +2 -1
  59. package/build/dts/sensor/MotionSensorDataManager.d.ts +5 -2
  60. package/build/dts/sensor/SensorDataManager.d.ts +5 -4
  61. package/build/dts/server/BaseClient.d.ts +5 -3
  62. package/build/dts/server/ServerUtils.d.ts +1 -1
  63. package/build/dts/server/websocket/WebSocketUtils.d.ts +1 -1
  64. package/build/dts/utils/AudioUtils.d.ts +2 -0
  65. package/build/dts/utils/Console.d.ts +2 -0
  66. package/build/dts/utils/ThrottleUtils.d.ts +2 -0
  67. package/build/dts/vibration/VibrationManager.d.ts +19 -2
  68. package/build/index.d.ts +292 -62
  69. package/build/index.node.d.ts +286 -59
  70. package/examples/3d/scene.html +19 -5
  71. package/examples/3d-generic/index.html +144 -0
  72. package/examples/3d-generic/script.js +266 -0
  73. package/examples/basic/index.html +267 -17
  74. package/examples/basic/script.js +958 -105
  75. package/examples/camera/barcode-detector.js +109 -0
  76. package/examples/camera/depth-estimation.js +71 -0
  77. package/examples/camera/face-detector.js +119 -0
  78. package/examples/camera/face-landmark.js +111 -0
  79. package/examples/camera/gesture-recognition.js +97 -0
  80. package/examples/camera/hand-landmark.js +74 -0
  81. package/examples/camera/image-segmentation.js +98 -0
  82. package/examples/camera/image-to-text.js +43 -0
  83. package/examples/camera/image-upscale.js +75 -0
  84. package/examples/camera/index.html +129 -0
  85. package/examples/camera/object-detection.js +98 -0
  86. package/examples/camera/pose-landmark.js +60 -0
  87. package/examples/camera/script.js +316 -0
  88. package/examples/camera/utils.js +165 -0
  89. package/examples/camera/yolo-tiny.js +54 -0
  90. package/examples/camera/yolo.js +119 -0
  91. package/examples/edge-impulse/script.js +157 -48
  92. package/examples/edge-impulse-test/README.md +11 -0
  93. package/examples/edge-impulse-test/edge-impulse-standalone.js +7228 -0
  94. package/examples/edge-impulse-test/edge-impulse-standalone.wasm +0 -0
  95. package/examples/edge-impulse-test/index.html +75 -0
  96. package/examples/edge-impulse-test/run-impulse.js +135 -0
  97. package/examples/edge-impulse-test/script.js +200 -0
  98. package/examples/glasses-gestures/README.md +11 -0
  99. package/examples/glasses-gestures/edge-impulse-standalone.js +7228 -0
  100. package/examples/glasses-gestures/edge-impulse-standalone.wasm +0 -0
  101. package/examples/glasses-gestures/index.html +69 -0
  102. package/examples/glasses-gestures/run-impulse.js +135 -0
  103. package/examples/glasses-gestures/script.js +226 -0
  104. package/examples/gloves/edge-impulse-standalone.js +7228 -0
  105. package/examples/gloves/edge-impulse-standalone.wasm +0 -0
  106. package/examples/gloves/index.html +4 -1
  107. package/examples/gloves/run-impulse.js +135 -0
  108. package/examples/gloves/script.js +367 -51
  109. package/examples/graph/script.js +94 -37
  110. package/examples/microphone/gender.js +54 -0
  111. package/examples/microphone/index.html +102 -0
  112. package/examples/microphone/script.js +394 -0
  113. package/examples/microphone/utils.js +45 -0
  114. package/examples/microphone/whisper-realtime.js +166 -0
  115. package/examples/microphone/whisper.js +132 -0
  116. package/examples/punch/index.html +135 -0
  117. package/examples/punch/punch.tflite +0 -0
  118. package/examples/punch/script.js +169 -0
  119. package/examples/server/index.html +98 -22
  120. package/examples/server/script.js +317 -109
  121. package/examples/ukaton-firmware-update/merged-firmware.bin +0 -0
  122. package/examples/utils/aframe/aframe-master.min.js +2 -0
  123. package/examples/utils/aframe/bs-vibration.js +150 -0
  124. package/examples/utils/aframe/force-pushable.js +80 -0
  125. package/examples/utils/aframe/grabbable-anchor.js +46 -0
  126. package/examples/utils/aframe/grabbable-listener.js +31 -0
  127. package/examples/utils/aframe/grabbable-physics-body.js +190 -0
  128. package/examples/utils/aframe/grow-shrink.js +25 -0
  129. package/examples/utils/aframe/hand-punch.js +119 -0
  130. package/examples/utils/aframe/my-obb-collider.js +293 -0
  131. package/examples/utils/aframe/occlude-hand-tracking-controls.js +47 -0
  132. package/examples/utils/aframe/occlude-mesh.js +42 -0
  133. package/examples/utils/aframe/palm-up-detector.js +47 -0
  134. package/examples/utils/aframe/shadow-material.js +20 -0
  135. package/examples/utils/aframe/soft-shadow-light.js +9 -0
  136. package/examples/webxr-2/assets/3d/soccerBall.glb +0 -0
  137. package/examples/webxr-2/assets/audio/shellBounce.wav +0 -0
  138. package/examples/webxr-2/assets/audio/shellHit.wav +0 -0
  139. package/examples/webxr-2/assets/audio/shellKick.wav +0 -0
  140. package/examples/webxr-2/assets/audio/soccerBounce.wav +0 -0
  141. package/examples/webxr-2/assets/audio/soccerKick.mp3 +0 -0
  142. package/examples/webxr-2/assets/images/shellTexture.png +0 -0
  143. package/examples/webxr-2/components/bs-ankle.js +337 -0
  144. package/examples/webxr-2/components/coin.js +84 -0
  145. package/examples/webxr-2/components/custom-wrap.js +17 -0
  146. package/examples/webxr-2/components/goomba.js +3250 -0
  147. package/examples/webxr-2/components/init-shell-material.js +215 -0
  148. package/examples/webxr-2/components/platter.js +172 -0
  149. package/examples/webxr-2/components/shell.js +374 -0
  150. package/examples/webxr-2/components/soccer-ball.js +250 -0
  151. package/examples/webxr-2/components/squashed-goomba.js +249 -0
  152. package/examples/webxr-2/edge-impulse-standalone.js +7228 -0
  153. package/examples/webxr-2/edge-impulse-standalone.wasm +0 -0
  154. package/examples/webxr-2/index.html +996 -0
  155. package/examples/webxr-2/kick.tflite +0 -0
  156. package/examples/webxr-2/kick2.tflite +0 -0
  157. package/examples/webxr-2/run-impulse.js +135 -0
  158. package/examples/webxr-2/script.js +384 -0
  159. package/examples/webxr-3/components/bs-camera.js +65 -0
  160. package/examples/webxr-3/index.html +134 -0
  161. package/examples/webxr-3/script.js +432 -0
  162. package/package.json +2 -1
  163. package/src/.prettierrc +4 -0
  164. package/src/BS.ts +79 -8
  165. package/src/CameraManager.ts +497 -0
  166. package/src/Device.ts +691 -86
  167. package/src/DeviceInformationManager.ts +19 -10
  168. package/src/DeviceManager.ts +85 -25
  169. package/src/FileTransferManager.ts +145 -20
  170. package/src/InformationManager.ts +40 -15
  171. package/src/MicrophoneManager.ts +599 -0
  172. package/src/TfliteManager.ts +171 -25
  173. package/src/WifiManager.ts +323 -0
  174. package/src/connection/BaseConnectionManager.ts +130 -30
  175. package/src/connection/ClientConnectionManager.ts +34 -10
  176. package/src/connection/bluetooth/BluetoothConnectionManager.ts +8 -2
  177. package/src/connection/bluetooth/NobleConnectionManager.ts +147 -41
  178. package/src/connection/bluetooth/WebBluetoothConnectionManager.ts +99 -34
  179. package/src/connection/bluetooth/bluetoothUUIDs.ts +40 -13
  180. package/src/connection/udp/UDPConnectionManager.ts +356 -0
  181. package/src/connection/websocket/WebSocketConnectionManager.ts +282 -0
  182. package/src/devicePair/DevicePair.ts +95 -25
  183. package/src/devicePair/DevicePairPressureSensorDataManager.ts +27 -7
  184. package/src/scanner/BaseScanner.ts +49 -11
  185. package/src/scanner/NobleScanner.ts +76 -14
  186. package/src/sensor/MotionSensorDataManager.ts +21 -6
  187. package/src/sensor/PressureSensorDataManager.ts +37 -8
  188. package/src/sensor/SensorConfigurationManager.ts +73 -22
  189. package/src/sensor/SensorDataManager.ts +109 -23
  190. package/src/server/BaseClient.ts +150 -36
  191. package/src/server/BaseServer.ts +50 -2
  192. package/src/server/ServerUtils.ts +39 -9
  193. package/src/server/udp/UDPServer.ts +73 -22
  194. package/src/server/udp/UDPUtils.ts +9 -2
  195. package/src/server/websocket/WebSocketClient.ts +27 -7
  196. package/src/server/websocket/WebSocketUtils.ts +4 -2
  197. package/src/utils/AudioUtils.ts +65 -0
  198. package/src/utils/Console.ts +62 -9
  199. package/src/utils/ParseUtils.ts +24 -5
  200. package/src/utils/ThrottleUtils.ts +62 -0
  201. package/src/utils/Timer.ts +1 -1
  202. package/src/vibration/VibrationManager.ts +166 -40
@@ -0,0 +1,497 @@
1
+ import Device, { SendMessageCallback } from "./Device.ts";
2
+ import { createConsole } from "./utils/Console.ts";
3
+ import { isInNode } from "./utils/environment.ts";
4
+ import EventDispatcher from "./utils/EventDispatcher.ts";
5
+ import autoBind from "auto-bind";
6
+ import { parseMessage } from "./utils/ParseUtils.ts";
7
+ import { concatenateArrayBuffers } from "./utils/ArrayBufferUtils.ts";
8
+
9
+ const _console = createConsole("CameraManager", { log: false });
10
+
11
+ export const CameraSensorTypes = ["camera"] as const;
12
+ export type CameraSensorType = (typeof CameraSensorTypes)[number];
13
+
14
+ export const CameraCommands = [
15
+ "focus",
16
+ "takePicture",
17
+ "stop",
18
+ "sleep",
19
+ "wake",
20
+ ] as const;
21
+ export type CameraCommand = (typeof CameraCommands)[number];
22
+
23
+ export const CameraStatuses = [
24
+ "idle",
25
+ "focusing",
26
+ "takingPicture",
27
+ "asleep",
28
+ ] as const;
29
+ export type CameraStatus = (typeof CameraStatuses)[number];
30
+
31
+ export const CameraDataTypes = [
32
+ "headerSize",
33
+ "header",
34
+ "imageSize",
35
+ "image",
36
+ "footerSize",
37
+ "footer",
38
+ ] as const;
39
+ export type CameraDataType = (typeof CameraDataTypes)[number];
40
+
41
+ export const CameraConfigurationTypes = [
42
+ "resolution",
43
+ "qualityFactor",
44
+ "shutter",
45
+ "gain",
46
+ "redGain",
47
+ "greenGain",
48
+ "blueGain",
49
+ ] as const;
50
+ export type CameraConfigurationType = (typeof CameraConfigurationTypes)[number];
51
+
52
+ export const CameraMessageTypes = [
53
+ "cameraStatus",
54
+ "cameraCommand",
55
+ "getCameraConfiguration",
56
+ "setCameraConfiguration",
57
+ "cameraData",
58
+ ] as const;
59
+ export type CameraMessageType = (typeof CameraMessageTypes)[number];
60
+
61
+ export type CameraConfiguration = {
62
+ [cameraConfigurationType in CameraConfigurationType]?: number;
63
+ };
64
+ export type CameraConfigurationRanges = {
65
+ [cameraConfigurationType in CameraConfigurationType]: {
66
+ min: number;
67
+ max: number;
68
+ };
69
+ };
70
+
71
+ export const RequiredCameraMessageTypes: CameraMessageType[] = [
72
+ "getCameraConfiguration",
73
+ "cameraStatus",
74
+ ] as const;
75
+
76
+ export const CameraEventTypes = [
77
+ ...CameraMessageTypes,
78
+ "cameraImageProgress",
79
+ "cameraImage",
80
+ ] as const;
81
+ export type CameraEventType = (typeof CameraEventTypes)[number];
82
+
83
+ export interface CameraEventMessages {
84
+ cameraStatus: {
85
+ cameraStatus: CameraStatus;
86
+ previousCameraStatus: CameraStatus;
87
+ };
88
+ getCameraConfiguration: { cameraConfiguration: CameraConfiguration };
89
+ cameraImageProgress: { progress: number; type: CameraDataType };
90
+ cameraImage: { blob: Blob; url: string };
91
+ }
92
+
93
+ export type CameraEventDispatcher = EventDispatcher<
94
+ Device,
95
+ CameraEventType,
96
+ CameraEventMessages
97
+ >;
98
+ export type SendCameraMessageCallback = SendMessageCallback<CameraMessageType>;
99
+
100
+ class CameraManager {
101
+ constructor() {
102
+ autoBind(this);
103
+ }
104
+
105
+ sendMessage!: SendCameraMessageCallback;
106
+
107
+ eventDispatcher!: CameraEventDispatcher;
108
+ get #dispatchEvent() {
109
+ return this.eventDispatcher.dispatchEvent;
110
+ }
111
+ get waitForEvent() {
112
+ return this.eventDispatcher.waitForEvent;
113
+ }
114
+
115
+ requestRequiredInformation() {
116
+ _console.log("requesting required camera information");
117
+ const messages = RequiredCameraMessageTypes.map((messageType) => ({
118
+ type: messageType,
119
+ }));
120
+ this.sendMessage(messages, false);
121
+ }
122
+
123
+ // CAMERA STATUS
124
+ #cameraStatus!: CameraStatus;
125
+ get cameraStatus() {
126
+ return this.#cameraStatus;
127
+ }
128
+ #parseCameraStatus(dataView: DataView) {
129
+ const cameraStatusIndex = dataView.getUint8(0);
130
+ const newCameraStatus = CameraStatuses[cameraStatusIndex];
131
+ this.#updateCameraStatus(newCameraStatus);
132
+ }
133
+ #updateCameraStatus(newCameraStatus: CameraStatus) {
134
+ _console.assertEnumWithError(newCameraStatus, CameraStatuses);
135
+ if (newCameraStatus == this.#cameraStatus) {
136
+ _console.log(`redundant cameraStatus ${newCameraStatus}`);
137
+ return;
138
+ }
139
+ const previousCameraStatus = this.#cameraStatus;
140
+ this.#cameraStatus = newCameraStatus;
141
+ _console.log(`updated cameraStatus to "${this.cameraStatus}"`);
142
+ this.#dispatchEvent("cameraStatus", {
143
+ cameraStatus: this.cameraStatus,
144
+ previousCameraStatus,
145
+ });
146
+
147
+ if (
148
+ this.#cameraStatus != "takingPicture" &&
149
+ this.#imageProgress > 0 &&
150
+ !this.#didBuildImage
151
+ ) {
152
+ this.#buildImage();
153
+ }
154
+ }
155
+
156
+ // CAMERA COMMAND
157
+ async #sendCameraCommand(command: CameraCommand, sendImmediately?: boolean) {
158
+ _console.assertEnumWithError(command, CameraCommands);
159
+ _console.log(`sending camera command "${command}"`);
160
+
161
+ const promise = this.waitForEvent("cameraStatus");
162
+ _console.log(`setting command "${command}"`);
163
+ const commandEnum = CameraCommands.indexOf(command);
164
+ this.sendMessage(
165
+ [
166
+ {
167
+ type: "cameraCommand",
168
+ data: Uint8Array.from([commandEnum]).buffer,
169
+ },
170
+ ],
171
+ sendImmediately
172
+ );
173
+
174
+ await promise;
175
+ }
176
+ #assertIsAsleep() {
177
+ _console.assertWithError(
178
+ this.#cameraStatus == "asleep",
179
+ `camera is not asleep - currently ${this.#cameraStatus}`
180
+ );
181
+ }
182
+ #assertIsAwake() {
183
+ _console.assertWithError(
184
+ this.#cameraStatus != "asleep",
185
+ `camera is not awake - currently ${this.#cameraStatus}`
186
+ );
187
+ }
188
+ async focus() {
189
+ this.#assertIsAwake();
190
+ await this.#sendCameraCommand("focus");
191
+ }
192
+ async takePicture() {
193
+ this.#assertIsAwake();
194
+ await this.#sendCameraCommand("takePicture");
195
+ }
196
+ async stop() {
197
+ this.#assertIsAwake();
198
+ await this.#sendCameraCommand("stop");
199
+ }
200
+ async sleep() {
201
+ this.#assertIsAwake();
202
+ await this.#sendCameraCommand("sleep");
203
+ }
204
+ async wake() {
205
+ this.#assertIsAsleep();
206
+ await this.#sendCameraCommand("wake");
207
+ }
208
+
209
+ // CAMERA DATA
210
+ #parseCameraData(dataView: DataView) {
211
+ _console.log("parsing camera data", dataView);
212
+ parseMessage(
213
+ dataView,
214
+ CameraDataTypes,
215
+ this.#onCameraData.bind(this),
216
+ null,
217
+ true
218
+ );
219
+ }
220
+ #onCameraData(cameraDataType: CameraDataType, dataView: DataView) {
221
+ _console.log({ cameraDataType, dataView });
222
+ switch (cameraDataType) {
223
+ case "headerSize":
224
+ this.#headerSize = dataView.getUint16(0, true);
225
+ _console.log({ headerSize: this.#headerSize });
226
+ this.#headerData = undefined;
227
+ this.#headerProgress == 0;
228
+ break;
229
+ case "header":
230
+ this.#headerData = concatenateArrayBuffers(this.#headerData, dataView);
231
+ _console.log({ headerData: this.#headerData });
232
+ this.#headerProgress = this.#headerData?.byteLength / this.#headerSize;
233
+ _console.log({ headerProgress: this.#headerProgress });
234
+ this.#dispatchEvent("cameraImageProgress", {
235
+ progress: this.#headerProgress,
236
+ type: "header",
237
+ });
238
+ if (this.#headerProgress == 1) {
239
+ _console.log("finished getting header data");
240
+ }
241
+ break;
242
+ case "imageSize":
243
+ this.#imageSize = dataView.getUint16(0, true);
244
+ _console.log({ imageSize: this.#imageSize });
245
+ this.#imageData = undefined;
246
+ this.#imageProgress == 0;
247
+ this.#didBuildImage = false;
248
+ break;
249
+ case "image":
250
+ this.#imageData = concatenateArrayBuffers(this.#imageData, dataView);
251
+ _console.log({ imageData: this.#imageData });
252
+ this.#imageProgress = this.#imageData?.byteLength / this.#imageSize;
253
+ _console.log({ imageProgress: this.#imageProgress });
254
+ this.#dispatchEvent("cameraImageProgress", {
255
+ progress: this.#imageProgress,
256
+ type: "image",
257
+ });
258
+ if (this.#imageProgress == 1) {
259
+ _console.log("finished getting image data");
260
+ if (this.#headerProgress == 1) {
261
+ this.#buildImage();
262
+ }
263
+ }
264
+ break;
265
+ case "footerSize":
266
+ this.#footerSize = dataView.getUint16(0, true);
267
+ _console.log({ footerSize: this.#footerSize });
268
+ this.#footerData = undefined;
269
+ this.#footerProgress == 0;
270
+ break;
271
+ case "footer":
272
+ this.#footerData = concatenateArrayBuffers(this.#footerData, dataView);
273
+ _console.log({ footerData: this.#footerData });
274
+ this.#footerProgress = this.#footerData?.byteLength / this.#footerSize;
275
+ _console.log({ footerProgress: this.#footerProgress });
276
+ this.#dispatchEvent("cameraImageProgress", {
277
+ progress: this.#footerProgress,
278
+ type: "footer",
279
+ });
280
+ if (this.#footerProgress == 1) {
281
+ _console.log("finished getting footer data");
282
+ if (this.#imageProgress == 1) {
283
+ this.#buildImage();
284
+ }
285
+ }
286
+ break;
287
+ }
288
+ }
289
+
290
+ #headerSize: number = 0;
291
+ #headerData?: ArrayBuffer;
292
+ #headerProgress: number = 0;
293
+
294
+ #imageSize: number = 0;
295
+ #imageData?: ArrayBuffer;
296
+ #imageProgress: number = 0;
297
+
298
+ #footerSize: number = 0;
299
+ #footerData?: ArrayBuffer;
300
+ #footerProgress: number = 0;
301
+
302
+ #didBuildImage: boolean = false;
303
+ #buildImage() {
304
+ _console.log("building image...");
305
+ const imageData = concatenateArrayBuffers(
306
+ this.#headerData,
307
+ this.#imageData,
308
+ this.#footerData
309
+ );
310
+ _console.log({ imageData });
311
+
312
+ let blob = new Blob([imageData], { type: "image/jpeg" });
313
+ _console.log("created blob", blob);
314
+
315
+ const url = URL.createObjectURL(blob);
316
+ _console.log("created url", url);
317
+
318
+ this.#dispatchEvent("cameraImage", { url, blob });
319
+
320
+ this.#didBuildImage = true;
321
+ }
322
+
323
+ // CONFIG
324
+ #cameraConfiguration: CameraConfiguration = {};
325
+ get cameraConfiguration() {
326
+ return this.#cameraConfiguration;
327
+ }
328
+ #availableCameraConfigurationTypes!: CameraConfigurationType[];
329
+ get availableCameraConfigurationTypes() {
330
+ return this.#availableCameraConfigurationTypes;
331
+ }
332
+
333
+ #cameraConfigurationRanges: CameraConfigurationRanges = {
334
+ resolution: { min: 100, max: 720 },
335
+ qualityFactor: { min: 15, max: 60 },
336
+ shutter: { min: 4, max: 16383 },
337
+ gain: { min: 1, max: 248 },
338
+ redGain: { min: 0, max: 1023 },
339
+ greenGain: { min: 0, max: 1023 },
340
+ blueGain: { min: 0, max: 1023 },
341
+ };
342
+ get cameraConfigurationRanges() {
343
+ return this.#cameraConfigurationRanges;
344
+ }
345
+
346
+ #parseCameraConfiguration(dataView: DataView) {
347
+ const parsedCameraConfiguration: CameraConfiguration = {};
348
+
349
+ let byteOffset = 0;
350
+ while (byteOffset < dataView.byteLength) {
351
+ const cameraConfigurationTypeIndex = dataView.getUint8(byteOffset++);
352
+ const cameraConfigurationType =
353
+ CameraConfigurationTypes[cameraConfigurationTypeIndex];
354
+ _console.assertWithError(
355
+ cameraConfigurationType,
356
+ `invalid cameraConfigurationTypeIndex ${cameraConfigurationTypeIndex}`
357
+ );
358
+ parsedCameraConfiguration[cameraConfigurationType] = dataView.getUint16(
359
+ byteOffset,
360
+ true
361
+ );
362
+ byteOffset += 2;
363
+ }
364
+
365
+ _console.log({ parsedCameraConfiguration });
366
+ this.#availableCameraConfigurationTypes = Object.keys(
367
+ parsedCameraConfiguration
368
+ ) as CameraConfigurationType[];
369
+ this.#cameraConfiguration = parsedCameraConfiguration;
370
+ this.#dispatchEvent("getCameraConfiguration", {
371
+ cameraConfiguration: this.#cameraConfiguration,
372
+ });
373
+ }
374
+
375
+ #isCameraConfigurationRedundant(cameraConfiguration: CameraConfiguration) {
376
+ let cameraConfigurationTypes = Object.keys(
377
+ cameraConfiguration
378
+ ) as CameraConfigurationType[];
379
+ return cameraConfigurationTypes.every((cameraConfigurationType) => {
380
+ return (
381
+ this.cameraConfiguration[cameraConfigurationType] ==
382
+ cameraConfiguration[cameraConfigurationType]
383
+ );
384
+ });
385
+ }
386
+ async setCameraConfiguration(newCameraConfiguration: CameraConfiguration) {
387
+ _console.log({ newCameraConfiguration });
388
+ if (this.#isCameraConfigurationRedundant(newCameraConfiguration)) {
389
+ _console.log("redundant camera configuration");
390
+ return;
391
+ }
392
+ const setCameraConfigurationData = this.#createData(newCameraConfiguration);
393
+ _console.log({ setCameraConfigurationData });
394
+
395
+ const promise = this.waitForEvent("getCameraConfiguration");
396
+ this.sendMessage([
397
+ {
398
+ type: "setCameraConfiguration",
399
+ data: setCameraConfigurationData.buffer,
400
+ },
401
+ ]);
402
+ await promise;
403
+ }
404
+
405
+ #assertAvailableCameraConfigurationType(
406
+ cameraConfigurationType: CameraConfigurationType
407
+ ) {
408
+ _console.assertWithError(
409
+ this.#availableCameraConfigurationTypes,
410
+ "must get initial cameraConfiguration"
411
+ );
412
+ const isCameraConfigurationTypeAvailable =
413
+ this.#availableCameraConfigurationTypes?.includes(
414
+ cameraConfigurationType
415
+ );
416
+ _console.assertWithError(
417
+ isCameraConfigurationTypeAvailable,
418
+ `unavailable camera configuration type "${cameraConfigurationType}"`
419
+ );
420
+ return isCameraConfigurationTypeAvailable;
421
+ }
422
+
423
+ static AssertValidCameraConfigurationType(
424
+ cameraConfigurationType: CameraConfigurationType
425
+ ) {
426
+ _console.assertEnumWithError(
427
+ cameraConfigurationType,
428
+ CameraConfigurationTypes
429
+ );
430
+ }
431
+ static AssertValidCameraConfigurationTypeEnum(
432
+ cameraConfigurationTypeEnum: number
433
+ ) {
434
+ _console.assertTypeWithError(cameraConfigurationTypeEnum, "number");
435
+ _console.assertWithError(
436
+ cameraConfigurationTypeEnum in CameraConfigurationTypes,
437
+ `invalid cameraConfigurationTypeEnum ${cameraConfigurationTypeEnum}`
438
+ );
439
+ }
440
+
441
+ #createData(cameraConfiguration: CameraConfiguration) {
442
+ let cameraConfigurationTypes = Object.keys(
443
+ cameraConfiguration
444
+ ) as CameraConfigurationType[];
445
+ cameraConfigurationTypes = cameraConfigurationTypes.filter(
446
+ (cameraConfigurationType) =>
447
+ this.#assertAvailableCameraConfigurationType(cameraConfigurationType)
448
+ );
449
+
450
+ const dataView = new DataView(
451
+ new ArrayBuffer(cameraConfigurationTypes.length * 3)
452
+ );
453
+ cameraConfigurationTypes.forEach((cameraConfigurationType, index) => {
454
+ CameraManager.AssertValidCameraConfigurationType(cameraConfigurationType);
455
+ const cameraConfigurationTypeEnum = CameraConfigurationTypes.indexOf(
456
+ cameraConfigurationType
457
+ );
458
+ dataView.setUint8(index * 3, cameraConfigurationTypeEnum);
459
+
460
+ const value = cameraConfiguration[cameraConfigurationType]!;
461
+ //this.#assertValidCameraConfigurationValue(cameraConfigurationType, value);
462
+ dataView.setUint16(index * 3 + 1, value, true);
463
+ });
464
+ _console.log({ sensorConfigurationData: dataView });
465
+ return dataView;
466
+ }
467
+
468
+ // MESSAGE
469
+ parseMessage(messageType: CameraMessageType, dataView: DataView) {
470
+ _console.log({ messageType, dataView });
471
+
472
+ switch (messageType) {
473
+ case "cameraStatus":
474
+ this.#parseCameraStatus(dataView);
475
+ break;
476
+ case "getCameraConfiguration":
477
+ case "setCameraConfiguration":
478
+ this.#parseCameraConfiguration(dataView);
479
+ break;
480
+ case "cameraData":
481
+ this.#parseCameraData(dataView);
482
+ break;
483
+ default:
484
+ throw Error(`uncaught messageType ${messageType}`);
485
+ }
486
+ }
487
+
488
+ clear() {
489
+ // @ts-ignore
490
+ this.#cameraStatus = undefined;
491
+ this.#headerProgress = 0;
492
+ this.#imageProgress = 0;
493
+ this.#footerProgress = 0;
494
+ }
495
+ }
496
+
497
+ export default CameraManager;