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.
- package/LICENSE +21 -0
- package/README.md +21 -0
- package/build/brilliantsole.cjs +5957 -0
- package/build/brilliantsole.cjs.map +1 -0
- package/build/brilliantsole.js +5448 -0
- package/build/brilliantsole.js.map +1 -0
- package/build/brilliantsole.ls.js +4872 -0
- package/build/brilliantsole.ls.js.map +1 -0
- package/build/brilliantsole.min.js +6 -0
- package/build/brilliantsole.min.js.map +1 -0
- package/build/brilliantsole.module.d.ts +908 -0
- package/build/brilliantsole.module.js +5412 -0
- package/build/brilliantsole.module.js.map +1 -0
- package/build/brilliantsole.module.min.d.ts +908 -0
- package/build/brilliantsole.module.min.js +6 -0
- package/build/brilliantsole.module.min.js.map +1 -0
- package/build/brilliantsole.node.module.d.ts +908 -0
- package/build/brilliantsole.node.module.js +5906 -0
- package/build/brilliantsole.node.module.js.map +1 -0
- package/build/dts/BS.d.ts +25 -0
- package/build/dts/Device.d.ts +136 -0
- package/build/dts/DeviceInformationManager.d.ts +56 -0
- package/build/dts/DeviceManager.d.ts +67 -0
- package/build/dts/FileTransferManager.d.ts +84 -0
- package/build/dts/FirmwareManager.d.ts +71 -0
- package/build/dts/InformationManager.d.ts +66 -0
- package/build/dts/TfliteManager.d.ts +92 -0
- package/build/dts/connection/BaseConnectionManager.d.ts +59 -0
- package/build/dts/connection/ClientConnectionManager.d.ts +23 -0
- package/build/dts/connection/WebSocketClientConnectionManager.d.ts +23 -0
- package/build/dts/connection/bluetooth/BluetoothConnectionManager.d.ts +10 -0
- package/build/dts/connection/bluetooth/NobleConnectionManager.d.ts +42 -0
- package/build/dts/connection/bluetooth/WebBluetoothConnectionManager.d.ts +20 -0
- package/build/dts/connection/bluetooth/bluetoothUUIDs.d.ts +14 -0
- package/build/dts/connection/webSocket/ClientConnectionManager.d.ts +23 -0
- package/build/dts/connection/webSocket/WebSocketClientConnectionManager.d.ts +23 -0
- package/build/dts/devicePair/DevicePair.d.ts +60 -0
- package/build/dts/devicePair/DevicePairPressureSensorDataManager.d.ts +25 -0
- package/build/dts/devicePair/DevicePairSensorDataManager.d.ts +33 -0
- package/build/dts/scanner/BaseScanner.d.ts +66 -0
- package/build/dts/scanner/NobleScanner.d.ts +17 -0
- package/build/dts/scanner/Scanner.d.ts +3 -0
- package/build/dts/sensor/BarometerSensorDataManager.d.ts +16 -0
- package/build/dts/sensor/MotionSensorDataManager.d.ts +69 -0
- package/build/dts/sensor/PressureSensorDataManager.d.ts +36 -0
- package/build/dts/sensor/SensorConfigurationManager.d.ts +44 -0
- package/build/dts/sensor/SensorDataManager.d.ts +40 -0
- package/build/dts/server/BaseClient.d.ts +85 -0
- package/build/dts/server/BaseServer.d.ts +48 -0
- package/build/dts/server/ServerUtils.d.ts +23 -0
- package/build/dts/server/udp/UDPServer.d.ts +11 -0
- package/build/dts/server/udp/UDPUtils.d.ts +9 -0
- package/build/dts/server/websocket/WebSocketClient.d.ts +17 -0
- package/build/dts/server/websocket/WebSocketServer.d.ts +13 -0
- package/build/dts/server/websocket/WebSocketUtils.d.ts +9 -0
- package/build/dts/utils/ArrayBufferUtils.d.ts +7 -0
- package/build/dts/utils/ArrayUtils.d.ts +2 -0
- package/build/dts/utils/CenterOfPressureHelper.d.ts +15 -0
- package/build/dts/utils/Console.d.ts +34 -0
- package/build/dts/utils/EventDispatcher.d.ts +50 -0
- package/build/dts/utils/EventUtils.d.ts +6 -0
- package/build/dts/utils/MathUtils.d.ts +21 -0
- package/build/dts/utils/ParseUtils.d.ts +5 -0
- package/build/dts/utils/RangeHelper.d.ts +8 -0
- package/build/dts/utils/Text.d.ts +6 -0
- package/build/dts/utils/Timer.d.ts +14 -0
- package/build/dts/utils/TypeScriptUtils.d.ts +19 -0
- package/build/dts/utils/cbor.d.ts +6 -0
- package/build/dts/utils/checksum.d.ts +3 -0
- package/build/dts/utils/environment.d.ts +13 -0
- package/build/dts/utils/mcumgr.d.ts +88 -0
- package/build/dts/utils/stringUtils.d.ts +2 -0
- package/build/dts/vibration/VibrationManager.d.ts +45 -0
- package/build/dts/vibration/VibrationWaveformEffects.d.ts +2 -0
- package/build/index.d.ts +908 -0
- package/build/index.node.d.ts +908 -0
- package/examples/3d/index.html +109 -0
- package/examples/3d/scene.html +57 -0
- package/examples/3d/script.js +419 -0
- package/examples/balance/index.html +138 -0
- package/examples/balance/script.js +243 -0
- package/examples/basic/index.html +327 -0
- package/examples/basic/script.js +1093 -0
- package/examples/center-of-pressure/index.html +132 -0
- package/examples/center-of-pressure/script.js +207 -0
- package/examples/device-pair/index.html +72 -0
- package/examples/device-pair/script.js +187 -0
- package/examples/edge-impulse/index.html +94 -0
- package/examples/edge-impulse/script.js +1033 -0
- package/examples/graph/index.html +83 -0
- package/examples/graph/script.js +469 -0
- package/examples/machine-learning/index.html +366 -0
- package/examples/machine-learning/script.js +1774 -0
- package/examples/pressure/index.html +145 -0
- package/examples/pressure/script.js +201 -0
- package/examples/recording/index.html +187 -0
- package/examples/recording/script.js +736 -0
- package/examples/server/index.html +266 -0
- package/examples/server/script.js +925 -0
- package/examples/utils/aframe/fingertip-button-component.js +201 -0
- package/examples/utils/aframe/fingertip-collider-target-component.js +102 -0
- package/examples/utils/aframe/fingertip-colliders-component.js +147 -0
- package/examples/utils/three/three.module.min.js +24846 -0
- package/examples/webxr/index.html +221 -0
- package/examples/webxr/script.js +1127 -0
- package/package.json +83 -0
- package/src/BS.ts +68 -0
- package/src/Device.ts +734 -0
- package/src/DeviceInformationManager.ts +146 -0
- package/src/DeviceManager.ts +354 -0
- package/src/FileTransferManager.ts +452 -0
- package/src/FirmwareManager.ts +357 -0
- package/src/InformationManager.ts +283 -0
- package/src/TfliteManager.ts +450 -0
- package/src/connection/BaseConnectionManager.ts +255 -0
- package/src/connection/ClientConnectionManager.ts +120 -0
- package/src/connection/bluetooth/BluetoothConnectionManager.ts +34 -0
- package/src/connection/bluetooth/NobleConnectionManager.ts +302 -0
- package/src/connection/bluetooth/WebBluetoothConnectionManager.ts +269 -0
- package/src/connection/bluetooth/bluetoothUUIDs.ts +218 -0
- package/src/devicePair/DevicePair.ts +253 -0
- package/src/devicePair/DevicePairPressureSensorDataManager.ts +82 -0
- package/src/devicePair/DevicePairSensorDataManager.ts +90 -0
- package/src/scanner/BaseScanner.ts +189 -0
- package/src/scanner/NobleScanner.ts +195 -0
- package/src/scanner/Scanner.ts +16 -0
- package/src/sensor/BarometerSensorDataManager.ts +41 -0
- package/src/sensor/MotionSensorDataManager.ts +151 -0
- package/src/sensor/PressureSensorDataManager.ts +112 -0
- package/src/sensor/SensorConfigurationManager.ts +177 -0
- package/src/sensor/SensorDataManager.ts +166 -0
- package/src/server/BaseClient.ts +368 -0
- package/src/server/BaseServer.ts +344 -0
- package/src/server/ServerUtils.ts +93 -0
- package/src/server/udp/UDPServer.ts +229 -0
- package/src/server/udp/UDPUtils.ts +20 -0
- package/src/server/websocket/WebSocketClient.ts +179 -0
- package/src/server/websocket/WebSocketServer.ts +184 -0
- package/src/server/websocket/WebSocketUtils.ts +20 -0
- package/src/utils/ArrayBufferUtils.ts +88 -0
- package/src/utils/ArrayUtils.ts +15 -0
- package/src/utils/CenterOfPressureHelper.ts +39 -0
- package/src/utils/Console.ts +156 -0
- package/src/utils/EventDispatcher.ts +153 -0
- package/src/utils/EventUtils.ts +41 -0
- package/src/utils/MathUtils.ts +53 -0
- package/src/utils/ParseUtils.ts +46 -0
- package/src/utils/RangeHelper.ts +38 -0
- package/src/utils/Text.ts +30 -0
- package/src/utils/Timer.ts +72 -0
- package/src/utils/TypeScriptUtils.ts +22 -0
- package/src/utils/cbor.js +429 -0
- package/src/utils/checksum.ts +41 -0
- package/src/utils/environment.ts +46 -0
- package/src/utils/mcumgr.js +444 -0
- package/src/utils/stringUtils.ts +11 -0
- package/src/vibration/VibrationManager.ts +308 -0
- package/src/vibration/VibrationWaveformEffects.ts +128 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import BaseScanner, { DiscoveredDevice, ScannerEventMap } from "./BaseScanner.ts";
|
|
2
|
+
import { createConsole } from "../utils/Console.ts";
|
|
3
|
+
import { addEventListeners } from "../utils/EventUtils.ts";
|
|
4
|
+
import { serviceDataUUID, serviceUUIDs } from "../connection/bluetooth/bluetoothUUIDs.ts";
|
|
5
|
+
import Device from "../Device.ts";
|
|
6
|
+
import NobleConnectionManager, { NoblePeripheral } from "../connection/bluetooth/NobleConnectionManager.ts";
|
|
7
|
+
|
|
8
|
+
const _console = createConsole("NobleScanner", { log: true });
|
|
9
|
+
|
|
10
|
+
let isSupported = false;
|
|
11
|
+
|
|
12
|
+
/** NODE_START */
|
|
13
|
+
import noble from "@abandonware/noble";
|
|
14
|
+
import { DeviceTypes } from "../InformationManager.ts";
|
|
15
|
+
import DeviceManager from "../DeviceManager.ts";
|
|
16
|
+
isSupported = true;
|
|
17
|
+
/** NODE_END */
|
|
18
|
+
|
|
19
|
+
export const NobleStates = ["unknown", "resetting", "unsupported", "unauthorized", "poweredOff", "poweredOn"] as const;
|
|
20
|
+
export type NobleState = (typeof NobleStates)[number];
|
|
21
|
+
|
|
22
|
+
class NobleScanner extends BaseScanner {
|
|
23
|
+
static get isSupported() {
|
|
24
|
+
return isSupported;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// SCANNING
|
|
28
|
+
#_isScanning = false;
|
|
29
|
+
get #isScanning() {
|
|
30
|
+
return this.#_isScanning;
|
|
31
|
+
}
|
|
32
|
+
set #isScanning(newIsScanning) {
|
|
33
|
+
_console.assertTypeWithError(newIsScanning, "boolean");
|
|
34
|
+
if (this.isScanning == newIsScanning) {
|
|
35
|
+
_console.log("duplicate isScanning assignment");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
this.#_isScanning = newIsScanning;
|
|
39
|
+
this.dispatchEvent("isScanning", { isScanning: this.isScanning });
|
|
40
|
+
}
|
|
41
|
+
get isScanning() {
|
|
42
|
+
return this.#isScanning;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// NOBLE STATE
|
|
46
|
+
#_nobleState: NobleState = "unknown";
|
|
47
|
+
get #nobleState() {
|
|
48
|
+
return this.#_nobleState;
|
|
49
|
+
}
|
|
50
|
+
set #nobleState(newNobleState) {
|
|
51
|
+
_console.assertTypeWithError(newNobleState, "string");
|
|
52
|
+
if (this.#nobleState == newNobleState) {
|
|
53
|
+
_console.log("duplicate nobleState assignment");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
this.#_nobleState = newNobleState;
|
|
57
|
+
_console.log({ newNobleState });
|
|
58
|
+
this.dispatchEvent("isScanningAvailable", { isScanningAvailable: this.isScanningAvailable });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// NOBLE LISTENERS
|
|
62
|
+
#boundNobleListeners = {
|
|
63
|
+
scanStart: this.#onNobleScanStart.bind(this),
|
|
64
|
+
scanStop: this.#onNobleScanStop.bind(this),
|
|
65
|
+
stateChange: this.#onNobleStateChange.bind(this),
|
|
66
|
+
discover: this.#onNobleDiscover.bind(this),
|
|
67
|
+
};
|
|
68
|
+
#onNobleScanStart() {
|
|
69
|
+
_console.log("OnNobleScanStart");
|
|
70
|
+
this.#isScanning = true;
|
|
71
|
+
}
|
|
72
|
+
#onNobleScanStop() {
|
|
73
|
+
_console.log("OnNobleScanStop");
|
|
74
|
+
this.#isScanning = false;
|
|
75
|
+
}
|
|
76
|
+
#onNobleStateChange(state: NobleState) {
|
|
77
|
+
_console.log("onNobleStateChange", state);
|
|
78
|
+
this.#nobleState = state;
|
|
79
|
+
}
|
|
80
|
+
#onNobleDiscover(noblePeripheral: NoblePeripheral) {
|
|
81
|
+
_console.log("onNobleDiscover", noblePeripheral.id);
|
|
82
|
+
if (!this.#noblePeripherals[noblePeripheral.id]) {
|
|
83
|
+
noblePeripheral.scanner = this;
|
|
84
|
+
this.#noblePeripherals[noblePeripheral.id] = noblePeripheral;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let deviceType;
|
|
88
|
+
const serviceData = noblePeripheral.advertisement.serviceData;
|
|
89
|
+
if (serviceData) {
|
|
90
|
+
//_console.log("serviceData", serviceData);
|
|
91
|
+
const deviceTypeServiceData = serviceData.find((serviceDatum) => {
|
|
92
|
+
return serviceDatum.uuid == serviceDataUUID;
|
|
93
|
+
});
|
|
94
|
+
//_console.log("deviceTypeServiceData", deviceTypeServiceData);
|
|
95
|
+
if (deviceTypeServiceData) {
|
|
96
|
+
const deviceTypeEnum = deviceTypeServiceData.data.readUint8(0);
|
|
97
|
+
deviceType = DeviceTypes[deviceTypeEnum];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (deviceType == undefined) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const discoveredDevice: DiscoveredDevice = {
|
|
105
|
+
name: noblePeripheral.advertisement.localName,
|
|
106
|
+
bluetoothId: noblePeripheral.id,
|
|
107
|
+
deviceType,
|
|
108
|
+
rssi: noblePeripheral.rssi,
|
|
109
|
+
};
|
|
110
|
+
this.dispatchEvent("discoveredDevice", { discoveredDevice });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// CONSTRUCTOR
|
|
114
|
+
constructor() {
|
|
115
|
+
super();
|
|
116
|
+
addEventListeners(noble, this.#boundNobleListeners);
|
|
117
|
+
addEventListeners(this, this.#boundBaseScannerListeners);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// AVAILABILITY
|
|
121
|
+
get isScanningAvailable() {
|
|
122
|
+
return this.#nobleState == "poweredOn";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// SCANNING
|
|
126
|
+
startScan() {
|
|
127
|
+
super.startScan();
|
|
128
|
+
noble.startScanningAsync(serviceUUIDs as string[], true);
|
|
129
|
+
}
|
|
130
|
+
stopScan() {
|
|
131
|
+
super.stopScan();
|
|
132
|
+
noble.stopScanningAsync();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// RESET
|
|
136
|
+
get canReset() {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
reset() {
|
|
140
|
+
super.reset();
|
|
141
|
+
noble.reset();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// BASESCANNER LISTENERS
|
|
145
|
+
#boundBaseScannerListeners = {
|
|
146
|
+
expiredDiscoveredDevice: this.#onExpiredDiscoveredDevice.bind(this),
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
#onExpiredDiscoveredDevice(event: ScannerEventMap["expiredDiscoveredDevice"]) {
|
|
150
|
+
const { discoveredDevice } = event.message;
|
|
151
|
+
const noblePeripheral = this.#noblePeripherals[discoveredDevice.bluetoothId];
|
|
152
|
+
if (noblePeripheral) {
|
|
153
|
+
// disconnect?
|
|
154
|
+
delete this.#noblePeripherals[discoveredDevice.bluetoothId];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// DISCOVERED DEVICES
|
|
159
|
+
#noblePeripherals: { [bluetoothId: string]: NoblePeripheral } = {};
|
|
160
|
+
#assertValidNoblePeripheralId(noblePeripheralId: string) {
|
|
161
|
+
_console.assertTypeWithError(noblePeripheralId, "string");
|
|
162
|
+
_console.assertWithError(
|
|
163
|
+
this.#noblePeripherals[noblePeripheralId],
|
|
164
|
+
`no noblePeripheral found with id "${noblePeripheralId}"`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// DEVICES
|
|
169
|
+
async connectToDevice(deviceId: string) {
|
|
170
|
+
super.connectToDevice(deviceId);
|
|
171
|
+
this.#assertValidNoblePeripheralId(deviceId);
|
|
172
|
+
const noblePeripheral = this.#noblePeripherals[deviceId];
|
|
173
|
+
_console.log("connecting to discoveredDevice...", deviceId);
|
|
174
|
+
|
|
175
|
+
let device = DeviceManager.AvailableDevices.filter((device) => device.connectionType == "noble").find(
|
|
176
|
+
(device) => device.bluetoothId == deviceId
|
|
177
|
+
);
|
|
178
|
+
if (!device) {
|
|
179
|
+
device = this.#createDevice(noblePeripheral);
|
|
180
|
+
await device.connect();
|
|
181
|
+
} else {
|
|
182
|
+
await device.reconnect();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
#createDevice(noblePeripheral: NoblePeripheral) {
|
|
187
|
+
const device = new Device();
|
|
188
|
+
const nobleConnectionManager = new NobleConnectionManager();
|
|
189
|
+
nobleConnectionManager.noblePeripheral = noblePeripheral;
|
|
190
|
+
device.connectionManager = nobleConnectionManager;
|
|
191
|
+
return device;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export default NobleScanner;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createConsole } from "../utils/Console.ts";
|
|
2
|
+
import NobleScanner from "./NobleScanner.ts";
|
|
3
|
+
import BaseScanner from "./BaseScanner.ts";
|
|
4
|
+
|
|
5
|
+
const _console = createConsole("Scanner", { log: false });
|
|
6
|
+
|
|
7
|
+
let scanner: BaseScanner | undefined;
|
|
8
|
+
|
|
9
|
+
if (NobleScanner.isSupported) {
|
|
10
|
+
_console.log("using NobleScanner");
|
|
11
|
+
scanner = new NobleScanner() as BaseScanner;
|
|
12
|
+
} else {
|
|
13
|
+
_console.log("Scanner not available");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default scanner;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createConsole } from "../utils/Console.ts";
|
|
2
|
+
|
|
3
|
+
export const BarometerSensorTypes = ["barometer"] as const;
|
|
4
|
+
export type BarometerSensorType = (typeof BarometerSensorTypes)[number];
|
|
5
|
+
|
|
6
|
+
export const ContinuousBarometerSensorTypes = BarometerSensorTypes;
|
|
7
|
+
export type ContinuousBarometerSensorType = (typeof ContinuousBarometerSensorTypes)[number];
|
|
8
|
+
|
|
9
|
+
export interface BarometerSensorDataEventMessages {
|
|
10
|
+
barometer: {
|
|
11
|
+
barometer: number;
|
|
12
|
+
//altitude: number;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const _console = createConsole("BarometerSensorDataManager", { log: true });
|
|
17
|
+
|
|
18
|
+
class BarometerSensorDataManager {
|
|
19
|
+
#calculcateAltitude(pressure: number) {
|
|
20
|
+
const P0 = 101325; // Standard atmospheric pressure at sea level in Pascals
|
|
21
|
+
const T0 = 288.15; // Standard temperature at sea level in Kelvin
|
|
22
|
+
const L = 0.0065; // Temperature lapse rate in K/m
|
|
23
|
+
const R = 8.3144598; // Universal gas constant in J/(mol·K)
|
|
24
|
+
const g = 9.80665; // Acceleration due to gravity in m/s²
|
|
25
|
+
const M = 0.0289644; // Molar mass of Earth's air in kg/mol
|
|
26
|
+
|
|
27
|
+
const exponent = (R * L) / (g * M);
|
|
28
|
+
const h = (T0 / L) * (1 - Math.pow(pressure / P0, exponent));
|
|
29
|
+
|
|
30
|
+
return h;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
parseData(dataView: DataView, scalar: number) {
|
|
34
|
+
const pressure = dataView.getUint32(0, true) * scalar;
|
|
35
|
+
const altitude = this.#calculcateAltitude(pressure);
|
|
36
|
+
_console.log({ pressure, altitude });
|
|
37
|
+
return { pressure };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default BarometerSensorDataManager;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { createConsole } from "../utils/Console.ts";
|
|
2
|
+
|
|
3
|
+
const _console = createConsole("MotionSensorDataManager", { log: true });
|
|
4
|
+
|
|
5
|
+
export const MotionSensorTypes = [
|
|
6
|
+
"acceleration",
|
|
7
|
+
"gravity",
|
|
8
|
+
"linearAcceleration",
|
|
9
|
+
"gyroscope",
|
|
10
|
+
"magnetometer",
|
|
11
|
+
"gameRotation",
|
|
12
|
+
"rotation",
|
|
13
|
+
"orientation",
|
|
14
|
+
"activity",
|
|
15
|
+
"stepCounter",
|
|
16
|
+
"stepDetector",
|
|
17
|
+
"deviceOrientation",
|
|
18
|
+
] as const;
|
|
19
|
+
export type MotionSensorType = (typeof MotionSensorTypes)[number];
|
|
20
|
+
|
|
21
|
+
export const ContinuousMotionTypes = [
|
|
22
|
+
"acceleration",
|
|
23
|
+
"gravity",
|
|
24
|
+
"linearAcceleration",
|
|
25
|
+
"gyroscope",
|
|
26
|
+
"magnetometer",
|
|
27
|
+
"gameRotation",
|
|
28
|
+
"rotation",
|
|
29
|
+
] as const;
|
|
30
|
+
export type ContinuousMotionType = (typeof ContinuousMotionTypes)[number];
|
|
31
|
+
|
|
32
|
+
import { Vector3, Quaternion, Euler } from "../utils/MathUtils.ts";
|
|
33
|
+
import { ValueOf } from "../utils/TypeScriptUtils.ts";
|
|
34
|
+
|
|
35
|
+
export const Vector2Size = 2 * 2;
|
|
36
|
+
export const Vector3Size = 3 * 2;
|
|
37
|
+
export const QuaternionSize = 4 * 2;
|
|
38
|
+
|
|
39
|
+
export const ActivityTypes = ["still", "walking", "running", "bicycle", "vehicle", "tilting"] as const;
|
|
40
|
+
export type ActivityType = (typeof ActivityTypes)[number];
|
|
41
|
+
|
|
42
|
+
export interface Activity {
|
|
43
|
+
still: boolean;
|
|
44
|
+
walking: boolean;
|
|
45
|
+
running: boolean;
|
|
46
|
+
bicycle: boolean;
|
|
47
|
+
vehicle: boolean;
|
|
48
|
+
tilting: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const DeviceOrientations = [
|
|
52
|
+
"portraitUpright",
|
|
53
|
+
"landscapeLeft",
|
|
54
|
+
"portraitUpsideDown",
|
|
55
|
+
"landscapeRight",
|
|
56
|
+
"unknown",
|
|
57
|
+
] as const;
|
|
58
|
+
export type DeviceOrientation = (typeof DeviceOrientations)[number];
|
|
59
|
+
|
|
60
|
+
export interface MotionSensorDataEventMessages {
|
|
61
|
+
acceleration: { acceleration: Vector3 };
|
|
62
|
+
gravity: { gravity: Vector3 };
|
|
63
|
+
linearAcceleration: { linearAcceleration: Vector3 };
|
|
64
|
+
gyroscope: { gyroscope: Vector3 };
|
|
65
|
+
magnetometer: { magnetometer: Vector3 };
|
|
66
|
+
gameRotation: { gameRotation: Quaternion };
|
|
67
|
+
rotation: { rotation: Quaternion };
|
|
68
|
+
orientation: { orientation: Euler };
|
|
69
|
+
stepDetector: { stepDetector: Object };
|
|
70
|
+
stepCounter: { stepCounter: number };
|
|
71
|
+
activity: { activity: Activity };
|
|
72
|
+
deviceOrientation: { deviceOrientation: DeviceOrientation };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type MotionSensorDataEventMessage = ValueOf<MotionSensorDataEventMessages>;
|
|
76
|
+
|
|
77
|
+
class MotionSensorDataManager {
|
|
78
|
+
parseVector3(dataView: DataView, scalar: number): Vector3 {
|
|
79
|
+
let [x, y, z] = [dataView.getInt16(0, true), dataView.getInt16(2, true), dataView.getInt16(4, true)].map(
|
|
80
|
+
(value) => value * scalar
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const vector: Vector3 = { x, y, z };
|
|
84
|
+
|
|
85
|
+
_console.log({ vector });
|
|
86
|
+
return vector;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
parseQuaternion(dataView: DataView, scalar: number): Quaternion {
|
|
90
|
+
let [x, y, z, w] = [
|
|
91
|
+
dataView.getInt16(0, true),
|
|
92
|
+
dataView.getInt16(2, true),
|
|
93
|
+
dataView.getInt16(4, true),
|
|
94
|
+
dataView.getInt16(6, true),
|
|
95
|
+
].map((value) => value * scalar);
|
|
96
|
+
|
|
97
|
+
const quaternion: Quaternion = { x, y, z, w };
|
|
98
|
+
|
|
99
|
+
_console.log({ quaternion });
|
|
100
|
+
return quaternion;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
parseEuler(dataView: DataView, scalar: number): Euler {
|
|
104
|
+
let [heading, pitch, roll] = [
|
|
105
|
+
dataView.getInt16(0, true),
|
|
106
|
+
dataView.getInt16(2, true),
|
|
107
|
+
dataView.getInt16(4, true),
|
|
108
|
+
].map((value) => value * scalar);
|
|
109
|
+
|
|
110
|
+
pitch *= -1;
|
|
111
|
+
heading *= -1;
|
|
112
|
+
|
|
113
|
+
const euler: Euler = { heading, pitch, roll };
|
|
114
|
+
|
|
115
|
+
_console.log({ euler });
|
|
116
|
+
return euler;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
parseStepCounter(dataView: DataView) {
|
|
120
|
+
_console.log("parseStepCounter", dataView);
|
|
121
|
+
const stepCount = dataView.getUint32(0, true);
|
|
122
|
+
_console.log({ stepCount });
|
|
123
|
+
return stepCount;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
parseActivity(dataView: DataView) {
|
|
127
|
+
_console.log("parseActivity", dataView);
|
|
128
|
+
const activity: Partial<Activity> = {};
|
|
129
|
+
|
|
130
|
+
const activityBitfield = dataView.getUint8(0);
|
|
131
|
+
_console.log("activityBitfield", activityBitfield.toString(2));
|
|
132
|
+
ActivityTypes.forEach((activityType, index) => {
|
|
133
|
+
activity[activityType] = Boolean(activityBitfield & (1 << index));
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
_console.log("activity", activity);
|
|
137
|
+
|
|
138
|
+
return activity as Activity;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
parseDeviceOrientation(dataView: DataView) {
|
|
142
|
+
_console.log("parseDeviceOrientation", dataView);
|
|
143
|
+
const index = dataView.getUint8(0);
|
|
144
|
+
const deviceOrientation = DeviceOrientations[index];
|
|
145
|
+
_console.assertWithError(deviceOrientation, "undefined deviceOrientation");
|
|
146
|
+
_console.log({ deviceOrientation });
|
|
147
|
+
return deviceOrientation;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export default MotionSensorDataManager;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createConsole } from "../utils/Console.ts";
|
|
2
|
+
import CenterOfPressureHelper from "../utils/CenterOfPressureHelper.ts";
|
|
3
|
+
import RangeHelper from "../utils/RangeHelper.ts";
|
|
4
|
+
import { createArray } from "../utils/ArrayUtils.ts";
|
|
5
|
+
|
|
6
|
+
const _console = createConsole("PressureDataManager", { log: true });
|
|
7
|
+
|
|
8
|
+
export const PressureSensorTypes = ["pressure"] as const;
|
|
9
|
+
export type PressureSensorType = (typeof PressureSensorTypes)[number];
|
|
10
|
+
|
|
11
|
+
export const ContinuousPressureSensorTypes = PressureSensorTypes;
|
|
12
|
+
export type ContinuousPressureSensorType = (typeof ContinuousPressureSensorTypes)[number];
|
|
13
|
+
|
|
14
|
+
import { Vector2 } from "../utils/MathUtils.ts";
|
|
15
|
+
export type PressureSensorPosition = Vector2;
|
|
16
|
+
|
|
17
|
+
import { CenterOfPressure } from "../utils/CenterOfPressureHelper.ts";
|
|
18
|
+
|
|
19
|
+
export interface PressureSensorValue {
|
|
20
|
+
position: PressureSensorPosition;
|
|
21
|
+
rawValue: number;
|
|
22
|
+
scaledValue: number;
|
|
23
|
+
normalizedValue: number;
|
|
24
|
+
weightedValue: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface PressureData {
|
|
28
|
+
sensors: PressureSensorValue[];
|
|
29
|
+
scaledSum: number;
|
|
30
|
+
normalizedSum: number;
|
|
31
|
+
center?: CenterOfPressure;
|
|
32
|
+
normalizedCenter?: CenterOfPressure;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface PressureDataEventMessages {
|
|
36
|
+
pressure: { pressure: PressureData };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const DefaultNumberOfPressureSensors = 8;
|
|
40
|
+
|
|
41
|
+
class PressureSensorDataManager {
|
|
42
|
+
#positions: PressureSensorPosition[] = [];
|
|
43
|
+
get positions() {
|
|
44
|
+
return this.#positions;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get numberOfSensors() {
|
|
48
|
+
return this.positions.length;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
parsePositions(dataView: DataView) {
|
|
52
|
+
const positions: PressureSensorPosition[] = [];
|
|
53
|
+
|
|
54
|
+
for (
|
|
55
|
+
let pressureSensorIndex = 0, byteOffset = 0;
|
|
56
|
+
byteOffset < dataView.byteLength;
|
|
57
|
+
pressureSensorIndex++, byteOffset += 2
|
|
58
|
+
) {
|
|
59
|
+
positions.push({
|
|
60
|
+
x: dataView.getUint8(byteOffset) / 2 ** 8,
|
|
61
|
+
y: dataView.getUint8(byteOffset + 1) / 2 ** 8,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
_console.log({ positions });
|
|
66
|
+
|
|
67
|
+
this.#positions = positions;
|
|
68
|
+
|
|
69
|
+
this.#sensorRangeHelpers = createArray(this.numberOfSensors, () => new RangeHelper());
|
|
70
|
+
|
|
71
|
+
this.resetRange();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#sensorRangeHelpers!: RangeHelper[];
|
|
75
|
+
|
|
76
|
+
#centerOfPressureHelper = new CenterOfPressureHelper();
|
|
77
|
+
|
|
78
|
+
resetRange() {
|
|
79
|
+
this.#sensorRangeHelpers.forEach((rangeHelper) => rangeHelper.reset());
|
|
80
|
+
this.#centerOfPressureHelper.reset();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
parseData(dataView: DataView, scalar: number) {
|
|
84
|
+
const pressure: PressureData = { sensors: [], scaledSum: 0, normalizedSum: 0 };
|
|
85
|
+
for (let index = 0, byteOffset = 0; byteOffset < dataView.byteLength; index++, byteOffset += 2) {
|
|
86
|
+
const rawValue = dataView.getUint16(byteOffset, true);
|
|
87
|
+
const scaledValue = rawValue * scalar;
|
|
88
|
+
const rangeHelper = this.#sensorRangeHelpers[index];
|
|
89
|
+
const normalizedValue = rangeHelper.updateAndGetNormalization(scaledValue, true);
|
|
90
|
+
const position = this.positions[index];
|
|
91
|
+
pressure.sensors[index] = { rawValue, scaledValue, normalizedValue, position, weightedValue: 0 };
|
|
92
|
+
|
|
93
|
+
pressure.scaledSum += scaledValue;
|
|
94
|
+
pressure.normalizedSum += normalizedValue / this.numberOfSensors;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (pressure.scaledSum > 0) {
|
|
98
|
+
pressure.center = { x: 0, y: 0 };
|
|
99
|
+
pressure.sensors.forEach((sensor) => {
|
|
100
|
+
sensor.weightedValue = sensor.scaledValue / pressure.scaledSum;
|
|
101
|
+
pressure.center!.x += sensor.position.x * sensor.weightedValue;
|
|
102
|
+
pressure.center!.y += sensor.position.y * sensor.weightedValue;
|
|
103
|
+
});
|
|
104
|
+
pressure.normalizedCenter = this.#centerOfPressureHelper.updateAndGetNormalization(pressure.center);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_console.log({ pressure });
|
|
108
|
+
return pressure;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export default PressureSensorDataManager;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { createConsole } from "../utils/Console.ts";
|
|
2
|
+
import SensorDataManager, { SensorTypes, SensorType } from "./SensorDataManager.ts";
|
|
3
|
+
import EventDispatcher from "../utils/EventDispatcher.ts";
|
|
4
|
+
import Device, { SendMessageCallback } from "../Device.ts";
|
|
5
|
+
import autoBind from "../../node_modules/auto-bind/index.js";
|
|
6
|
+
|
|
7
|
+
const _console = createConsole("SensorConfigurationManager", { log: true });
|
|
8
|
+
|
|
9
|
+
export type SensorConfiguration = { [sensorType in SensorType]?: number };
|
|
10
|
+
|
|
11
|
+
export const MaxSensorRate = 2 ** 16 - 1;
|
|
12
|
+
export const SensorRateStep = 5;
|
|
13
|
+
|
|
14
|
+
export const SensorConfigurationMessageTypes = ["getSensorConfiguration", "setSensorConfiguration"] as const;
|
|
15
|
+
export type SensorConfigurationMessageType = (typeof SensorConfigurationMessageTypes)[number];
|
|
16
|
+
|
|
17
|
+
export const SensorConfigurationEventTypes = SensorConfigurationMessageTypes;
|
|
18
|
+
export type SensorConfigurationEventType = (typeof SensorConfigurationEventTypes)[number];
|
|
19
|
+
|
|
20
|
+
export interface SensorConfigurationEventMessages {
|
|
21
|
+
getSensorConfiguration: { sensorConfiguration: SensorConfiguration };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type SensorConfigurationEventDispatcher = EventDispatcher<
|
|
25
|
+
Device,
|
|
26
|
+
SensorConfigurationEventType,
|
|
27
|
+
SensorConfigurationEventMessages
|
|
28
|
+
>;
|
|
29
|
+
|
|
30
|
+
export type SendSensorConfigurationMessageCallback = SendMessageCallback<SensorConfigurationMessageType>;
|
|
31
|
+
|
|
32
|
+
class SensorConfigurationManager {
|
|
33
|
+
constructor() {
|
|
34
|
+
autoBind(this);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
sendMessage!: SendSensorConfigurationMessageCallback;
|
|
38
|
+
|
|
39
|
+
eventDispatcher!: SensorConfigurationEventDispatcher;
|
|
40
|
+
get addEventListener() {
|
|
41
|
+
return this.eventDispatcher.addEventListener;
|
|
42
|
+
}
|
|
43
|
+
get #dispatchEvent() {
|
|
44
|
+
return this.eventDispatcher.dispatchEvent;
|
|
45
|
+
}
|
|
46
|
+
get waitForEvent() {
|
|
47
|
+
return this.eventDispatcher.waitForEvent;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#availableSensorTypes!: SensorType[];
|
|
51
|
+
#assertAvailableSensorType(sensorType: SensorType) {
|
|
52
|
+
_console.assertWithError(this.#availableSensorTypes, "must get initial sensorConfiguration");
|
|
53
|
+
const isSensorTypeAvailable = this.#availableSensorTypes?.includes(sensorType);
|
|
54
|
+
_console.assert(isSensorTypeAvailable, `unavailable sensor type "${sensorType}"`);
|
|
55
|
+
return isSensorTypeAvailable;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
#configuration!: SensorConfiguration;
|
|
59
|
+
get configuration() {
|
|
60
|
+
return this.#configuration;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
#updateConfiguration(updatedConfiguration: SensorConfiguration) {
|
|
64
|
+
this.#configuration = updatedConfiguration;
|
|
65
|
+
_console.log({ updatedConfiguration: this.#configuration });
|
|
66
|
+
this.#dispatchEvent("getSensorConfiguration", { sensorConfiguration: this.configuration });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#isRedundant(sensorConfiguration: SensorConfiguration) {
|
|
70
|
+
let sensorTypes = Object.keys(sensorConfiguration) as SensorType[];
|
|
71
|
+
return sensorTypes.every((sensorType) => {
|
|
72
|
+
return this.configuration[sensorType] == sensorConfiguration[sensorType];
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async setConfiguration(newSensorConfiguration: SensorConfiguration, clearRest?: boolean) {
|
|
77
|
+
if (clearRest) {
|
|
78
|
+
newSensorConfiguration = Object.assign({ ...this.zeroSensorConfiguration }, newSensorConfiguration);
|
|
79
|
+
}
|
|
80
|
+
_console.log({ newSensorConfiguration });
|
|
81
|
+
if (this.#isRedundant(newSensorConfiguration)) {
|
|
82
|
+
_console.log("redundant sensor configuration");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const setSensorConfigurationData = this.#createData(newSensorConfiguration);
|
|
86
|
+
_console.log({ setSensorConfigurationData });
|
|
87
|
+
|
|
88
|
+
const promise = this.waitForEvent("getSensorConfiguration");
|
|
89
|
+
this.sendMessage([{ type: "setSensorConfiguration", data: setSensorConfigurationData.buffer }]);
|
|
90
|
+
await promise;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#parse(dataView: DataView) {
|
|
94
|
+
const parsedSensorConfiguration: SensorConfiguration = {};
|
|
95
|
+
for (let byteOffset = 0; byteOffset < dataView.byteLength; byteOffset += 3) {
|
|
96
|
+
const sensorTypeIndex = dataView.getUint8(byteOffset);
|
|
97
|
+
const sensorType = SensorTypes[sensorTypeIndex];
|
|
98
|
+
if (!sensorType) {
|
|
99
|
+
_console.warn(`unknown sensorType index ${sensorTypeIndex}`);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const sensorRate = dataView.getUint16(byteOffset + 1, true);
|
|
103
|
+
_console.log({ sensorType, sensorRate });
|
|
104
|
+
parsedSensorConfiguration[sensorType] = sensorRate;
|
|
105
|
+
}
|
|
106
|
+
_console.log({ parsedSensorConfiguration });
|
|
107
|
+
this.#availableSensorTypes = Object.keys(parsedSensorConfiguration) as SensorType[];
|
|
108
|
+
return parsedSensorConfiguration;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static #AssertValidSensorRate(sensorRate: number) {
|
|
112
|
+
_console.assertTypeWithError(sensorRate, "number");
|
|
113
|
+
_console.assertWithError(sensorRate >= 0, `sensorRate must be 0 or greater (got ${sensorRate})`);
|
|
114
|
+
_console.assertWithError(sensorRate < MaxSensorRate, `sensorRate must be 0 or greater (got ${sensorRate})`);
|
|
115
|
+
_console.assertWithError(sensorRate % SensorRateStep == 0, `sensorRate must be multiple of ${SensorRateStep}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#assertValidSensorRate(sensorRate: number) {
|
|
119
|
+
SensorConfigurationManager.#AssertValidSensorRate(sensorRate);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
#createData(sensorConfiguration: SensorConfiguration) {
|
|
123
|
+
let sensorTypes = Object.keys(sensorConfiguration) as SensorType[];
|
|
124
|
+
sensorTypes = sensorTypes.filter((sensorType) => this.#assertAvailableSensorType(sensorType));
|
|
125
|
+
|
|
126
|
+
const dataView = new DataView(new ArrayBuffer(sensorTypes.length * 3));
|
|
127
|
+
sensorTypes.forEach((sensorType, index) => {
|
|
128
|
+
SensorDataManager.AssertValidSensorType(sensorType);
|
|
129
|
+
const sensorTypeEnum = SensorTypes.indexOf(sensorType);
|
|
130
|
+
dataView.setUint8(index * 3, sensorTypeEnum);
|
|
131
|
+
|
|
132
|
+
const sensorRate = sensorConfiguration[sensorType]!;
|
|
133
|
+
this.#assertValidSensorRate(sensorRate);
|
|
134
|
+
dataView.setUint16(index * 3 + 1, sensorRate, true);
|
|
135
|
+
});
|
|
136
|
+
_console.log({ sensorConfigurationData: dataView });
|
|
137
|
+
return dataView;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ZERO
|
|
141
|
+
static #ZeroSensorConfiguration: SensorConfiguration = {};
|
|
142
|
+
static get ZeroSensorConfiguration() {
|
|
143
|
+
return this.#ZeroSensorConfiguration;
|
|
144
|
+
}
|
|
145
|
+
static {
|
|
146
|
+
SensorTypes.forEach((sensorType) => {
|
|
147
|
+
this.#ZeroSensorConfiguration[sensorType] = 0;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
get zeroSensorConfiguration() {
|
|
151
|
+
const zeroSensorConfiguration: SensorConfiguration = {};
|
|
152
|
+
SensorTypes.forEach((sensorType) => {
|
|
153
|
+
zeroSensorConfiguration[sensorType] = 0;
|
|
154
|
+
});
|
|
155
|
+
return zeroSensorConfiguration;
|
|
156
|
+
}
|
|
157
|
+
async clearSensorConfiguration() {
|
|
158
|
+
return this.setConfiguration(this.zeroSensorConfiguration);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// MESSAGE
|
|
162
|
+
parseMessage(messageType: SensorConfigurationMessageType, dataView: DataView) {
|
|
163
|
+
_console.log({ messageType });
|
|
164
|
+
|
|
165
|
+
switch (messageType) {
|
|
166
|
+
case "getSensorConfiguration":
|
|
167
|
+
case "setSensorConfiguration":
|
|
168
|
+
const newSensorConfiguration = this.#parse(dataView);
|
|
169
|
+
this.#updateConfiguration(newSensorConfiguration);
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
throw Error(`uncaught messageType ${messageType}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export default SensorConfigurationManager;
|