@neurodevs/node-lsl 18.0.0 → 19.0.0
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/.vscode/launch.json +54 -58
- package/.vscode/settings.json +61 -66
- package/.vscode/tasks.json +98 -129
- package/README.md +14 -12
- package/build/__tests__/AbstractPackageTest.d.ts +16 -12
- package/build/__tests__/AbstractPackageTest.js +48 -20
- package/build/__tests__/AbstractPackageTest.js.map +1 -1
- package/build/__tests__/impl/BleDeviceController.test.d.ts +59 -0
- package/build/__tests__/impl/BleDeviceController.test.js +364 -0
- package/build/__tests__/impl/BleDeviceController.test.js.map +1 -0
- package/build/__tests__/impl/LslEventMarkerEmitter.test.js +1 -1
- package/build/__tests__/impl/LslEventMarkerEmitter.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamInlet.test.js +2 -2
- package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamOutlet.test.js +11 -13
- package/build/__tests__/impl/LslStreamOutlet.test.js.map +1 -1
- package/build/__tests__/impl/LslWebSocketBridge.test.js +3 -3
- package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
- package/build/__tests__/impl/UsbDeviceController.test.d.ts +17 -0
- package/build/__tests__/impl/UsbDeviceController.test.js +81 -0
- package/build/__tests__/impl/UsbDeviceController.test.js.map +1 -0
- package/build/__tests__/impl/WindowedClockRegressor.test.d.ts +19 -0
- package/build/__tests__/impl/WindowedClockRegressor.test.js +172 -0
- package/build/__tests__/impl/WindowedClockRegressor.test.js.map +1 -0
- package/build/impl/LslStreamInlet.d.ts +1 -0
- package/build/impl/LslStreamInlet.js +2 -1
- package/build/impl/LslStreamInlet.js.map +1 -1
- package/build/impl/LslStreamOutlet.d.ts +3 -2
- package/build/impl/LslStreamOutlet.js +4 -3
- package/build/impl/LslStreamOutlet.js.map +1 -1
- package/build/impl/LslWebSocketBridge.js +2 -2
- package/build/impl/LslWebSocketBridge.js.map +1 -1
- package/build/impl/WindowedClockRegressor.d.ts +24 -0
- package/build/impl/WindowedClockRegressor.js +73 -0
- package/build/impl/WindowedClockRegressor.js.map +1 -0
- package/build/impl/controllers/BleDeviceController.d.ts +60 -0
- package/build/impl/controllers/BleDeviceController.js +153 -0
- package/build/impl/controllers/BleDeviceController.js.map +1 -0
- package/build/impl/controllers/UsbDeviceController.d.ts +23 -0
- package/build/impl/controllers/UsbDeviceController.js +40 -0
- package/build/impl/controllers/UsbDeviceController.js.map +1 -0
- package/build/impl/workers/inlet/StreamInletWorker.d.ts +4 -4
- package/build/impl/workers/inlet/StreamInletWorker.js +12 -12
- package/build/impl/workers/inlet/StreamInletWorker.js.map +1 -1
- package/build/impl/workers/outlet/LslStreamOutlet.worker.d.ts +3 -3
- package/build/impl/workers/outlet/LslStreamOutlet.worker.js +7 -7
- package/build/impl/workers/outlet/LslStreamOutlet.worker.js.map +1 -1
- package/build/index.d.ts +14 -4
- package/build/index.js +17 -5
- package/build/index.js.map +1 -1
- package/build/scripts/discoverMuse.d.ts +1 -0
- package/build/scripts/discoverMuse.js +40 -0
- package/build/scripts/discoverMuse.js.map +1 -0
- package/build/scripts/runMuse.d.ts +1 -0
- package/build/scripts/runMuse.js +40 -0
- package/build/scripts/runMuse.js.map +1 -0
- package/build/scripts/runUsb.d.ts +1 -0
- package/build/scripts/runUsb.js +14 -0
- package/build/scripts/runUsb.js.map +1 -0
- package/build/testDoubles/BleController/FakeBleController.d.ts +26 -0
- package/build/testDoubles/BleController/FakeBleController.js +47 -0
- package/build/testDoubles/BleController/FakeBleController.js.map +1 -0
- package/build/testDoubles/BleController/SpyBleController.d.ts +14 -0
- package/build/testDoubles/BleController/SpyBleController.js +48 -0
- package/build/testDoubles/BleController/SpyBleController.js.map +1 -0
- package/build/testDoubles/ClockRegressor/FakeClockRegressor.d.ts +17 -0
- package/build/testDoubles/ClockRegressor/FakeClockRegressor.js +23 -0
- package/build/testDoubles/ClockRegressor/FakeClockRegressor.js.map +1 -0
- package/build/testDoubles/StreamOutlet/FakeStreamOutlet.d.ts +2 -2
- package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js +5 -2
- package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js.map +1 -1
- package/build/testDoubles/UsbController/FakeUsbController.d.ts +12 -0
- package/build/testDoubles/UsbController/FakeUsbController.js +25 -0
- package/build/testDoubles/UsbController/FakeUsbController.js.map +1 -0
- package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.js.map +1 -1
- package/build/testDoubles/generateRandomOutletOptions.js +1 -1
- package/build/testDoubles/generateRandomOutletOptions.js.map +1 -1
- package/eslint.config.js +3 -0
- package/package.json +19 -57
- package/prettier.config.js +3 -0
- package/src/__tests__/AbstractPackageTest.ts +86 -29
- package/src/__tests__/impl/BleDeviceController.test.ts +535 -0
- package/src/__tests__/impl/LslEventMarkerEmitter.test.ts +2 -1
- package/src/__tests__/impl/LslStreamInlet.test.ts +2 -2
- package/src/__tests__/impl/LslStreamOutlet.test.ts +15 -14
- package/src/__tests__/impl/LslWebSocketBridge.test.ts +4 -3
- package/src/__tests__/impl/UsbDeviceController.test.ts +109 -0
- package/src/__tests__/impl/WindowedClockRegressor.test.ts +262 -0
- package/src/impl/LslStreamInlet.ts +4 -1
- package/src/impl/LslStreamOutlet.ts +5 -4
- package/src/impl/LslWebSocketBridge.ts +2 -2
- package/src/impl/WindowedClockRegressor.ts +136 -0
- package/src/impl/controllers/BleDeviceController.ts +240 -0
- package/src/impl/controllers/UsbDeviceController.ts +65 -0
- package/src/impl/workers/inlet/StreamInletWorker.ts +12 -12
- package/src/impl/workers/outlet/LslStreamOutlet.worker.ts +8 -8
- package/src/index.ts +24 -5
- package/src/scripts/discoverMuse.ts +50 -0
- package/src/scripts/runMuse.ts +50 -0
- package/src/scripts/runUsb.ts +20 -0
- package/src/testDoubles/BleController/FakeBleController.ts +81 -0
- package/src/testDoubles/BleController/SpyBleController.ts +61 -0
- package/src/testDoubles/ClockRegressor/FakeClockRegressor.ts +46 -0
- package/src/testDoubles/StreamOutlet/FakeStreamOutlet.ts +6 -3
- package/src/testDoubles/UsbController/FakeUsbController.ts +34 -0
- package/src/testDoubles/WebSocketBridge/FakeWebSocketBridge.ts +1 -2
- package/src/testDoubles/generateRandomOutletOptions.ts +2 -1
- package/tsconfig.json +23 -27
- package/.regressionproof.json +0 -7
- package/build/.spruce/settings.json +0 -15
- package/build/__tests__/impl/LslBackpressureMonitor.test.d.ts +0 -7
- package/build/__tests__/impl/LslBackpressureMonitor.test.js +0 -26
- package/build/__tests__/impl/LslBackpressureMonitor.test.js.map +0 -1
- package/build/impl/LslBackpressureMonitor.d.ts +0 -8
- package/build/impl/LslBackpressureMonitor.js +0 -8
- package/build/impl/LslBackpressureMonitor.js.map +0 -1
- package/build/testDoubles/BackpressureMonitor/FakeBackpressureMonitor.d.ts +0 -6
- package/build/testDoubles/BackpressureMonitor/FakeBackpressureMonitor.js +0 -10
- package/build/testDoubles/BackpressureMonitor/FakeBackpressureMonitor.js.map +0 -1
- package/eslint.config.mjs +0 -3
- package/src/.spruce/settings.json +0 -15
- package/src/__tests__/impl/LslBackpressureMonitor.test.ts +0 -25
- package/src/impl/LslBackpressureMonitor.ts +0 -13
- package/src/testDoubles/BackpressureMonitor/FakeBackpressureMonitor.ts +0 -13
|
@@ -3,6 +3,7 @@ import { assertValidChannelCount, assertValidChannelFormat, assertValidChunkSize
|
|
|
3
3
|
export default class LslStreamOutlet {
|
|
4
4
|
static Class;
|
|
5
5
|
static Worker = Worker;
|
|
6
|
+
static setTimeout = setTimeout;
|
|
6
7
|
name;
|
|
7
8
|
type;
|
|
8
9
|
sourceId;
|
|
@@ -86,12 +87,12 @@ export default class LslStreamOutlet {
|
|
|
86
87
|
float32: 'pushSampleFloatTimestamp',
|
|
87
88
|
string: 'pushSampleStringTimestamp',
|
|
88
89
|
};
|
|
89
|
-
pushSample(sample,
|
|
90
|
+
pushSample(sample, timestampSec) {
|
|
90
91
|
this.worker.postMessage({
|
|
91
92
|
type: 'pushSample',
|
|
92
93
|
payload: {
|
|
93
94
|
sample,
|
|
94
|
-
|
|
95
|
+
timestampSec,
|
|
95
96
|
},
|
|
96
97
|
});
|
|
97
98
|
}
|
|
@@ -104,7 +105,7 @@ export default class LslStreamOutlet {
|
|
|
104
105
|
return LslStreamOutlet.Worker;
|
|
105
106
|
}
|
|
106
107
|
static async waitForSetup(waitAfterConstructionMs) {
|
|
107
|
-
await new Promise((resolve) => setTimeout(resolve, waitAfterConstructionMs));
|
|
108
|
+
await new Promise((resolve) => LslStreamOutlet.setTimeout(resolve, waitAfterConstructionMs));
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
111
|
//# sourceMappingURL=LslStreamOutlet.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LslStreamOutlet.js","sourceRoot":"","sources":["../../src/impl/LslStreamOutlet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAI5C,OAAO,EACH,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,uBAAuB,GAC1B,MAAM,kBAAkB,CAAA;AAEzB,MAAM,CAAC,OAAO,OAAO,eAAe;IACzB,MAAM,CAAC,KAAK,CAA0B;IACtC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"LslStreamOutlet.js","sourceRoot":"","sources":["../../src/impl/LslStreamOutlet.ts"],"names":[],"mappings":"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"}
|
|
@@ -43,7 +43,7 @@ export default class LslWebSocketBridge {
|
|
|
43
43
|
throw new Error(err);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
cannotActivateMessage = `\n\
|
|
46
|
+
cannotActivateMessage = `\n\nCannot activate bridge after destroying it! \n\nPlease create and activate a new instance. \n`;
|
|
47
47
|
async startPullingData() {
|
|
48
48
|
await this.inlet.startPulling();
|
|
49
49
|
}
|
|
@@ -51,7 +51,7 @@ export default class LslWebSocketBridge {
|
|
|
51
51
|
this.throwIfBridgeIsDestroyed(this.cannotDeactivateMessage);
|
|
52
52
|
this.stopPullingData();
|
|
53
53
|
}
|
|
54
|
-
cannotDeactivateMessage = `\n\
|
|
54
|
+
cannotDeactivateMessage = `\n\nCannot deactivate bridge after destroying it! \n\nPlease create and activate a new instance. \n`;
|
|
55
55
|
stopPullingData() {
|
|
56
56
|
this.inlet.stopPulling();
|
|
57
57
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LslWebSocketBridge.js","sourceRoot":"","sources":["../../src/impl/LslWebSocketBridge.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,EAAE,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;AAE/C,OAAO,cAGN,MAAM,qBAAqB,CAAA;AAE5B,MAAM,CAAC,OAAO,OAAO,kBAAkB;IAC5B,MAAM,CAAC,KAAK,CAA6B;IACzC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAA;IACrB,MAAM,CAAC,GAAG,GAAG,eAAe,CAAA;IAE3B,KAAK,CAAa;IAClB,WAAW,CAAkB;IAC7B,aAAa,CAAc;IAE3B,WAAW,GAAG,KAAK,CAAA;IAE3B,YAAsB,OAA0C;QAC5D,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,OAAO,CAAA;QAErD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;QAC9B,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;QAElC,IAAI,CAAC,mCAAmC,EAAE,CAAA;IAC9C,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAA+B;QACtD,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;QACpD,MAAM,YAAY,GAAuB,IAAI,CAAA;QAE7C,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAA;QACpD,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAA;QAEzD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CACnC,YAAY,EACZ,WAAW,EACX,aAAa,CAChB,CAAA;QAED,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;YAC5B,GAAG,OAAO;YACV,KAAK;YACL,WAAW;YACX,aAAa;SAChB,CAAC,CAAA;IACN,CAAC;IAEO,mCAAmC;QACvC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAA;QAClD,CAAC;IACL,CAAC;IAEgB,wBAAwB,GAAG,6DAA6D,CAAA;IAElG,KAAK,CAAC,QAAQ;QACjB,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAA;QACzD,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAA;IACjC,CAAC;IAEO,wBAAwB,CAAC,GAAW;QACxC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAA;QACxB,CAAC;IACL,CAAC;IAEgB,qBAAqB,GAAG,
|
|
1
|
+
{"version":3,"file":"LslWebSocketBridge.js","sourceRoot":"","sources":["../../src/impl/LslWebSocketBridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export default class WindowedClockRegressor implements ClockRegressor {
|
|
2
|
+
static Class?: ClockRegressorConstructor;
|
|
3
|
+
private readonly nominalHz;
|
|
4
|
+
private readonly windowLenSec;
|
|
5
|
+
private readonly defaultWindowLenSec;
|
|
6
|
+
private readonly history;
|
|
7
|
+
private slope;
|
|
8
|
+
protected constructor(nominalHz: number, options?: WindowedClockRegressorOptions);
|
|
9
|
+
static Create(nominalHz: number, options?: WindowedClockRegressorOptions): WindowedClockRegressor | ClockRegressor;
|
|
10
|
+
deriveTimestamps(deviceTime: number, earliestLslTime: number, chunkSize: number): any[];
|
|
11
|
+
private anchorTimeFor;
|
|
12
|
+
private throwIfDeviceTimeDoesNotIncrease;
|
|
13
|
+
private pruneHistoryOutsideWindow;
|
|
14
|
+
private refitSlope;
|
|
15
|
+
private get currentMeanDeviceTime();
|
|
16
|
+
private get currentMeanLslTime();
|
|
17
|
+
}
|
|
18
|
+
export interface ClockRegressor {
|
|
19
|
+
deriveTimestamps(deviceTime: number, earliestLslTime: number, chunkSize: number): number[];
|
|
20
|
+
}
|
|
21
|
+
export type ClockRegressorConstructor = new (nominalHz: number, options?: WindowedClockRegressorOptions) => ClockRegressor;
|
|
22
|
+
export interface WindowedClockRegressorOptions {
|
|
23
|
+
windowLenSec?: number;
|
|
24
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export default class WindowedClockRegressor {
|
|
2
|
+
static Class;
|
|
3
|
+
nominalHz;
|
|
4
|
+
windowLenSec;
|
|
5
|
+
defaultWindowLenSec = 30;
|
|
6
|
+
history = [];
|
|
7
|
+
slope = 1; // lsl-host-seconds per device-second
|
|
8
|
+
constructor(nominalHz, options) {
|
|
9
|
+
const { windowLenSec = this.defaultWindowLenSec } = options ?? {};
|
|
10
|
+
this.nominalHz = nominalHz;
|
|
11
|
+
this.windowLenSec = windowLenSec;
|
|
12
|
+
}
|
|
13
|
+
static Create(nominalHz, options) {
|
|
14
|
+
return new (this.Class ?? this)(nominalHz, options);
|
|
15
|
+
}
|
|
16
|
+
deriveTimestamps(deviceTime, earliestLslTime, chunkSize) {
|
|
17
|
+
this.throwIfDeviceTimeDoesNotIncrease(deviceTime);
|
|
18
|
+
this.history.push({ deviceTime, earliestLslTime });
|
|
19
|
+
this.pruneHistoryOutsideWindow();
|
|
20
|
+
this.refitSlope();
|
|
21
|
+
const anchor = this.anchorTimeFor(deviceTime);
|
|
22
|
+
const timestamps = Array(chunkSize).fill(0);
|
|
23
|
+
for (let i = 0; i <= chunkSize - 1; i++) {
|
|
24
|
+
const stepsFromLast = chunkSize - 1 - i;
|
|
25
|
+
const deviceTimeOffset = -stepsFromLast / this.nominalHz;
|
|
26
|
+
const lslTimeOffset = deviceTimeOffset * this.slope;
|
|
27
|
+
timestamps[i] = anchor + lslTimeOffset;
|
|
28
|
+
}
|
|
29
|
+
return timestamps;
|
|
30
|
+
}
|
|
31
|
+
anchorTimeFor(deviceTime) {
|
|
32
|
+
const xMean = this.currentMeanDeviceTime;
|
|
33
|
+
const yMean = this.currentMeanLslTime;
|
|
34
|
+
return yMean + this.slope * (deviceTime - xMean);
|
|
35
|
+
}
|
|
36
|
+
throwIfDeviceTimeDoesNotIncrease(deviceTime) {
|
|
37
|
+
const last = this.history[this.history.length - 1];
|
|
38
|
+
if (last && deviceTime <= last.deviceTime) {
|
|
39
|
+
throw new Error(`\nDevice time (${deviceTime}) did not increase from the previous device time (${last.deviceTime})! Device time is expected to always increase between calls, so this likely indicates a bug in the calling code.\n`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
pruneHistoryOutsideWindow() {
|
|
43
|
+
const { deviceTime: latest } = this.history[this.history.length - 1];
|
|
44
|
+
const cutoff = latest - this.windowLenSec;
|
|
45
|
+
while (this.history.length > 0 && this.history[0].deviceTime < cutoff) {
|
|
46
|
+
this.history.shift();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
refitSlope() {
|
|
50
|
+
if (this.history.length < 2) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const xMean = this.currentMeanDeviceTime;
|
|
54
|
+
const yMean = this.currentMeanLslTime;
|
|
55
|
+
let numerator = 0;
|
|
56
|
+
let denominator = 0;
|
|
57
|
+
for (const { deviceTime, earliestLslTime } of this.history) {
|
|
58
|
+
const xCentered = deviceTime - xMean;
|
|
59
|
+
numerator += xCentered * (earliestLslTime - yMean);
|
|
60
|
+
denominator += xCentered * xCentered;
|
|
61
|
+
}
|
|
62
|
+
this.slope = numerator / denominator;
|
|
63
|
+
}
|
|
64
|
+
get currentMeanDeviceTime() {
|
|
65
|
+
const totalDeviceTime = this.history.reduce((sum, { deviceTime }) => sum + deviceTime, 0);
|
|
66
|
+
return totalDeviceTime / this.history.length;
|
|
67
|
+
}
|
|
68
|
+
get currentMeanLslTime() {
|
|
69
|
+
const totalLslTime = this.history.reduce((sum, { earliestLslTime }) => sum + earliestLslTime, 0);
|
|
70
|
+
return totalLslTime / this.history.length;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=WindowedClockRegressor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WindowedClockRegressor.js","sourceRoot":"","sources":["../../src/impl/WindowedClockRegressor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Libndx, NativePeripheral } from '@neurodevs/ndx-native';
|
|
2
|
+
export default class BleDeviceController implements BleController {
|
|
3
|
+
static Class?: BleControllerConstructor;
|
|
4
|
+
static setTimeout: typeof setTimeout;
|
|
5
|
+
static waitAfterMs: number;
|
|
6
|
+
private static _ndx?;
|
|
7
|
+
static get ndx(): Libndx;
|
|
8
|
+
static set ndx(value: Libndx);
|
|
9
|
+
protected charCallbacks: CharacteristicCallbacks;
|
|
10
|
+
protected rssiIntervalMs?: number;
|
|
11
|
+
protected connected: boolean;
|
|
12
|
+
protected log: Console;
|
|
13
|
+
private deviceUuid?;
|
|
14
|
+
private deviceNamePrefix?;
|
|
15
|
+
private deviceName?;
|
|
16
|
+
private onConnected?;
|
|
17
|
+
protected constructor(options: BleControllerOptions);
|
|
18
|
+
static Create(options: BleControllerOptions): Promise<BleDeviceController | BleController>;
|
|
19
|
+
connect(): Promise<void>;
|
|
20
|
+
private discoverUuid;
|
|
21
|
+
private waitForDiscoveredUuid;
|
|
22
|
+
private createBleBackend;
|
|
23
|
+
private throwIfError;
|
|
24
|
+
private setBleRssiInterval;
|
|
25
|
+
private startBleBackend;
|
|
26
|
+
private waitForOnConnected;
|
|
27
|
+
private waitToDiscoverServices;
|
|
28
|
+
writeCharacteristic(charUuid: CharacteristicUuid, value: string): Promise<void>;
|
|
29
|
+
subscribeCharacteristics(charCallbacks: CharacteristicCallbacks): Promise<void>;
|
|
30
|
+
disconnect(): Promise<void>;
|
|
31
|
+
get uuid(): string;
|
|
32
|
+
get name(): string;
|
|
33
|
+
private get ndx();
|
|
34
|
+
}
|
|
35
|
+
export interface BleController {
|
|
36
|
+
uuid: string;
|
|
37
|
+
name: string;
|
|
38
|
+
connect(): Promise<void>;
|
|
39
|
+
subscribeCharacteristics(charCallbacks: CharacteristicCallbacks): Promise<void>;
|
|
40
|
+
writeCharacteristic(charUuid: CharacteristicUuid, value: string): Promise<void>;
|
|
41
|
+
disconnect(): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
export type BleControllerOptions = {
|
|
44
|
+
charCallbacks: CharacteristicCallbacks;
|
|
45
|
+
onConnected?: (peripheral: NativePeripheral) => void;
|
|
46
|
+
rssiIntervalMs?: number;
|
|
47
|
+
} & ({
|
|
48
|
+
deviceUuid: string;
|
|
49
|
+
deviceNamePrefix?: string;
|
|
50
|
+
} | {
|
|
51
|
+
deviceUuid?: string;
|
|
52
|
+
deviceNamePrefix: string;
|
|
53
|
+
});
|
|
54
|
+
export type BleControllerConstructor = new (options: BleControllerOptions) => BleController;
|
|
55
|
+
export type CharacteristicCallbacks = {
|
|
56
|
+
charUuid: string;
|
|
57
|
+
charName?: string;
|
|
58
|
+
onData: (data: Buffer, length: number, timestampSec: number) => void;
|
|
59
|
+
}[];
|
|
60
|
+
export type CharacteristicUuid = string;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { LibndxAdapter } from '@neurodevs/ndx-native';
|
|
2
|
+
export default class BleDeviceController {
|
|
3
|
+
static Class;
|
|
4
|
+
static setTimeout = setTimeout;
|
|
5
|
+
static waitAfterMs = 1000;
|
|
6
|
+
static _ndx;
|
|
7
|
+
static get ndx() {
|
|
8
|
+
if (!this._ndx) {
|
|
9
|
+
this._ndx = LibndxAdapter.getInstance();
|
|
10
|
+
}
|
|
11
|
+
return this._ndx;
|
|
12
|
+
}
|
|
13
|
+
static set ndx(value) {
|
|
14
|
+
this._ndx = value;
|
|
15
|
+
}
|
|
16
|
+
charCallbacks;
|
|
17
|
+
rssiIntervalMs;
|
|
18
|
+
connected = false;
|
|
19
|
+
log = console;
|
|
20
|
+
deviceUuid;
|
|
21
|
+
deviceNamePrefix;
|
|
22
|
+
deviceName;
|
|
23
|
+
onConnected;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
const { deviceUuid, deviceNamePrefix, charCallbacks, onConnected, rssiIntervalMs, } = options;
|
|
26
|
+
this.deviceUuid = deviceUuid;
|
|
27
|
+
this.deviceNamePrefix = deviceNamePrefix;
|
|
28
|
+
this.charCallbacks = charCallbacks;
|
|
29
|
+
this.onConnected = onConnected;
|
|
30
|
+
this.rssiIntervalMs = rssiIntervalMs;
|
|
31
|
+
}
|
|
32
|
+
static async Create(options) {
|
|
33
|
+
return new (this.Class ?? this)(options);
|
|
34
|
+
}
|
|
35
|
+
async connect() {
|
|
36
|
+
if (!this.deviceUuid) {
|
|
37
|
+
await this.discoverUuid();
|
|
38
|
+
}
|
|
39
|
+
this.createBleBackend();
|
|
40
|
+
this.startBleBackend();
|
|
41
|
+
await this.waitForOnConnected();
|
|
42
|
+
await this.waitToDiscoverServices();
|
|
43
|
+
this.setBleRssiInterval();
|
|
44
|
+
}
|
|
45
|
+
async discoverUuid() {
|
|
46
|
+
const { status, error } = this.ndx.discoverBleUuid({
|
|
47
|
+
namePrefix: this.deviceNamePrefix,
|
|
48
|
+
onDiscovered: (uuid) => {
|
|
49
|
+
this.deviceUuid = uuid;
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
this.throwIfError(status, error);
|
|
53
|
+
await this.waitForDiscoveredUuid();
|
|
54
|
+
}
|
|
55
|
+
async waitForDiscoveredUuid() {
|
|
56
|
+
await new Promise((resolve) => {
|
|
57
|
+
const checkDiscovered = () => {
|
|
58
|
+
if (this.deviceUuid) {
|
|
59
|
+
resolve();
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
BleDeviceController.setTimeout(checkDiscovered, 100);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
checkDiscovered();
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
createBleBackend() {
|
|
69
|
+
const { status, error } = this.ndx.createBleBackend({
|
|
70
|
+
deviceUuid: this.uuid,
|
|
71
|
+
});
|
|
72
|
+
this.throwIfError(status, error);
|
|
73
|
+
}
|
|
74
|
+
throwIfError(status, error) {
|
|
75
|
+
if (status !== 200) {
|
|
76
|
+
throw new Error(`${status} error: ${error ?? 'Unknown error'}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
setBleRssiInterval() {
|
|
80
|
+
if (this.rssiIntervalMs) {
|
|
81
|
+
this.ndx.setBleRssiInterval({
|
|
82
|
+
deviceUuid: this.uuid,
|
|
83
|
+
intervalMs: this.rssiIntervalMs,
|
|
84
|
+
onRssi: (rssi) => {
|
|
85
|
+
this.log.info(`[RSSI=${rssi}]`);
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
startBleBackend() {
|
|
91
|
+
const { status, error } = this.ndx.startBleBackend({
|
|
92
|
+
deviceUuid: this.uuid,
|
|
93
|
+
onConnected: (peripheral) => {
|
|
94
|
+
const { name } = peripheral;
|
|
95
|
+
this.deviceName = name;
|
|
96
|
+
this.connected = true;
|
|
97
|
+
this.log.info(`Connected to device ${this.uuid}!`);
|
|
98
|
+
this.onConnected?.(peripheral);
|
|
99
|
+
},
|
|
100
|
+
charCallbacks: this.charCallbacks,
|
|
101
|
+
});
|
|
102
|
+
this.throwIfError(status, error);
|
|
103
|
+
}
|
|
104
|
+
async waitForOnConnected() {
|
|
105
|
+
await new Promise((resolve) => {
|
|
106
|
+
const checkConnected = () => {
|
|
107
|
+
if (this.connected) {
|
|
108
|
+
resolve();
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
BleDeviceController.setTimeout(checkConnected, 100);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
checkConnected();
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async waitToDiscoverServices() {
|
|
118
|
+
await new Promise((resolve) => BleDeviceController.setTimeout(resolve, BleDeviceController.waitAfterMs));
|
|
119
|
+
}
|
|
120
|
+
async writeCharacteristic(charUuid, value) {
|
|
121
|
+
const { status, error } = this.ndx.writeBleCharacteristic({
|
|
122
|
+
deviceUuid: this.uuid,
|
|
123
|
+
charUuid,
|
|
124
|
+
value,
|
|
125
|
+
});
|
|
126
|
+
this.throwIfError(status, error);
|
|
127
|
+
}
|
|
128
|
+
async subscribeCharacteristics(charCallbacks) {
|
|
129
|
+
const { status, error } = this.ndx.addBleCharCallbacks({
|
|
130
|
+
deviceUuid: this.uuid,
|
|
131
|
+
charCallbacks,
|
|
132
|
+
});
|
|
133
|
+
this.throwIfError(status, error);
|
|
134
|
+
this.charCallbacks = [...this.charCallbacks, ...charCallbacks];
|
|
135
|
+
}
|
|
136
|
+
async disconnect() {
|
|
137
|
+
const { status, error } = this.ndx.stopBleBackend({
|
|
138
|
+
deviceUuid: this.uuid,
|
|
139
|
+
});
|
|
140
|
+
this.throwIfError(status, error);
|
|
141
|
+
this.connected = false;
|
|
142
|
+
}
|
|
143
|
+
get uuid() {
|
|
144
|
+
return this.deviceUuid ?? '';
|
|
145
|
+
}
|
|
146
|
+
get name() {
|
|
147
|
+
return this.deviceName ?? 'N/A';
|
|
148
|
+
}
|
|
149
|
+
get ndx() {
|
|
150
|
+
return BleDeviceController.ndx;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=BleDeviceController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BleDeviceController.js","sourceRoot":"","sources":["../../../src/impl/controllers/BleDeviceController.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export default class UsbDeviceController implements UsbController {
|
|
2
|
+
static Class?: UsbControllerConstructor;
|
|
3
|
+
private onData;
|
|
4
|
+
private serialNumber;
|
|
5
|
+
private ndx;
|
|
6
|
+
protected constructor(options: UsbControllerOptions);
|
|
7
|
+
static Create(options: UsbControllerOptions): UsbController;
|
|
8
|
+
connect(): Promise<void>;
|
|
9
|
+
private get usbControllerOptions();
|
|
10
|
+
private get startUsbControllerOptions();
|
|
11
|
+
writeUsb(value: string): Promise<void>;
|
|
12
|
+
disconnect(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export interface UsbController {
|
|
15
|
+
connect(): Promise<void>;
|
|
16
|
+
writeUsb(value: string): Promise<void>;
|
|
17
|
+
disconnect(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export interface UsbControllerOptions {
|
|
20
|
+
onData: (data: Buffer, length: number, timestampSec: number) => void;
|
|
21
|
+
serialNumber?: string;
|
|
22
|
+
}
|
|
23
|
+
export type UsbControllerConstructor = new (options?: UsbControllerOptions) => UsbController;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { LibndxAdapter } from '@neurodevs/ndx-native';
|
|
2
|
+
export default class UsbDeviceController {
|
|
3
|
+
static Class;
|
|
4
|
+
onData;
|
|
5
|
+
serialNumber;
|
|
6
|
+
ndx = LibndxAdapter.getInstance();
|
|
7
|
+
constructor(options) {
|
|
8
|
+
const { onData, serialNumber } = options ?? {};
|
|
9
|
+
this.onData = onData;
|
|
10
|
+
this.serialNumber = serialNumber ?? '';
|
|
11
|
+
}
|
|
12
|
+
static Create(options) {
|
|
13
|
+
return new (this.Class ?? this)(options);
|
|
14
|
+
}
|
|
15
|
+
async connect() {
|
|
16
|
+
this.ndx.createUsbBackend(this.usbControllerOptions);
|
|
17
|
+
this.ndx.startUsbBackend(this.startUsbControllerOptions);
|
|
18
|
+
}
|
|
19
|
+
get usbControllerOptions() {
|
|
20
|
+
return {
|
|
21
|
+
serialNumber: this.serialNumber,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
get startUsbControllerOptions() {
|
|
25
|
+
return {
|
|
26
|
+
...this.usbControllerOptions,
|
|
27
|
+
onData: this.onData,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async writeUsb(value) {
|
|
31
|
+
this.ndx.writeUsbBackend({
|
|
32
|
+
...this.usbControllerOptions,
|
|
33
|
+
value,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async disconnect() {
|
|
37
|
+
this.ndx.stopUsbBackend(this.usbControllerOptions);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=UsbDeviceController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UsbDeviceController.js","sourceRoot":"","sources":["../../../src/impl/controllers/UsbDeviceController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAErD,MAAM,CAAC,OAAO,OAAO,mBAAmB;IAC7B,MAAM,CAAC,KAAK,CAA2B;IAEtC,MAAM,CAA8D;IACpE,YAAY,CAAQ;IAEpB,GAAG,GAAG,aAAa,CAAC,WAAW,EAAE,CAAA;IAEzC,YAAsB,OAA6B;QAC/C,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,IAAI,EAAE,CAAA;QAE9C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,YAAY,GAAG,YAAY,IAAI,EAAE,CAAA;IAC1C,CAAC;IAEM,MAAM,CAAC,MAAM,CAAC,OAA6B;QAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,CAAA;IAC5C,CAAC;IAEM,KAAK,CAAC,OAAO;QAChB,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QACpD,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAA;IAC5D,CAAC;IAED,IAAY,oBAAoB;QAC5B,OAAO;YACH,YAAY,EAAE,IAAI,CAAC,YAAY;SAClC,CAAA;IACL,CAAC;IAED,IAAY,yBAAyB;QACjC,OAAO;YACH,GAAG,IAAI,CAAC,oBAAoB;YAC5B,MAAM,EAAE,IAAI,CAAC,MAAM;SACtB,CAAA;IACL,CAAC;IAEM,KAAK,CAAC,QAAQ,CAAC,KAAa;QAC/B,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC;YACrB,GAAG,IAAI,CAAC,oBAAoB;YAC5B,KAAK;SACR,CAAC,CAAA;IACN,CAAC;IAEM,KAAK,CAAC,UAAU;QACnB,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;IACtD,CAAC;CACJ"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { handleLslError, InfoHandle, InletHandle } from '@neurodevs/ndx-native';
|
|
2
2
|
import { freePointer } from 'ffi-rs';
|
|
3
3
|
import { OnDataCallback } from '../../LslStreamInlet.js';
|
|
4
4
|
import { CreateInletPayload } from './LslStreamInlet.worker.js';
|
|
5
5
|
export default class StreamInletWorker {
|
|
6
6
|
static lsl: import("@neurodevs/ndx-native").Liblsl;
|
|
7
|
-
static
|
|
7
|
+
static handleLslError: typeof handleLslError;
|
|
8
8
|
static freePointer: typeof freePointer;
|
|
9
9
|
private sourceId;
|
|
10
10
|
private chunkSize;
|
|
@@ -59,7 +59,7 @@ export default class StreamInletWorker {
|
|
|
59
59
|
startPulling(onData: OnDataCallback): void;
|
|
60
60
|
private pullLoop;
|
|
61
61
|
private pullDataOnce;
|
|
62
|
-
private
|
|
62
|
+
private handleLslErrorIfPresent;
|
|
63
63
|
private waitBetweenPulls;
|
|
64
64
|
flushInlet(): void;
|
|
65
65
|
stopPulling(): void;
|
|
@@ -68,6 +68,6 @@ export default class StreamInletWorker {
|
|
|
68
68
|
private doDestroyInlet;
|
|
69
69
|
private freeNativePointers;
|
|
70
70
|
private get lsl();
|
|
71
|
-
private get
|
|
71
|
+
private get handleLslError();
|
|
72
72
|
private get freePointer();
|
|
73
73
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { handleLslError, LiblslAdapter, } from '@neurodevs/ndx-native';
|
|
2
2
|
import { unwrapPointer, createPointer, DataType, freePointer, PointerType, } from 'ffi-rs';
|
|
3
3
|
export default class StreamInletWorker {
|
|
4
4
|
static lsl = LiblslAdapter.getInstance();
|
|
5
|
-
static
|
|
5
|
+
static handleLslError = handleLslError;
|
|
6
6
|
static freePointer = freePointer;
|
|
7
7
|
sourceId;
|
|
8
8
|
chunkSize;
|
|
@@ -117,11 +117,11 @@ export default class StreamInletWorker {
|
|
|
117
117
|
this.chunkSize === 1 ? this.pullSample : this.pullChunk;
|
|
118
118
|
}
|
|
119
119
|
pullSample = () => {
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
120
|
+
const timestampSec = this.doPullsample();
|
|
121
|
+
if (timestampSec > 0) {
|
|
122
122
|
return {
|
|
123
123
|
samples: this.readSamplesFromBuffer(),
|
|
124
|
-
timestamps: [
|
|
124
|
+
timestamps: [timestampSec],
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
127
|
return { samples: undefined, timestamps: undefined };
|
|
@@ -140,8 +140,8 @@ export default class StreamInletWorker {
|
|
|
140
140
|
return Array.from(floats);
|
|
141
141
|
}
|
|
142
142
|
pullChunk = () => {
|
|
143
|
-
const
|
|
144
|
-
if (
|
|
143
|
+
const firstTimestampSec = this.doPullChunk();
|
|
144
|
+
if (firstTimestampSec > 0) {
|
|
145
145
|
return {
|
|
146
146
|
samples: this.readSamplesFromBuffer(),
|
|
147
147
|
timestamps: this.readTimestampsFromBuffer(),
|
|
@@ -191,14 +191,14 @@ export default class StreamInletWorker {
|
|
|
191
191
|
}
|
|
192
192
|
async pullDataOnce() {
|
|
193
193
|
const { samples, timestamps } = this.pullMethod();
|
|
194
|
-
this.
|
|
194
|
+
this.handleLslErrorIfPresent();
|
|
195
195
|
if (samples && timestamps) {
|
|
196
196
|
this.onData(samples, timestamps);
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
|
-
|
|
199
|
+
handleLslErrorIfPresent() {
|
|
200
200
|
const errorCode = this.pullErrorBuffer.readInt32LE();
|
|
201
|
-
this.
|
|
201
|
+
this.handleLslError(errorCode);
|
|
202
202
|
}
|
|
203
203
|
async waitBetweenPulls() {
|
|
204
204
|
await new Promise((r) => setTimeout(r, this.waitBetweenPullsMs));
|
|
@@ -243,8 +243,8 @@ export default class StreamInletWorker {
|
|
|
243
243
|
get lsl() {
|
|
244
244
|
return StreamInletWorker.lsl;
|
|
245
245
|
}
|
|
246
|
-
get
|
|
247
|
-
return StreamInletWorker.
|
|
246
|
+
get handleLslError() {
|
|
247
|
+
return StreamInletWorker.handleLslError;
|
|
248
248
|
}
|
|
249
249
|
get freePointer() {
|
|
250
250
|
return StreamInletWorker.freePointer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StreamInletWorker.js","sourceRoot":"","sources":["../../../../src/impl/workers/inlet/StreamInletWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,
|
|
1
|
+
{"version":3,"file":"StreamInletWorker.js","sourceRoot":"","sources":["../../../../src/impl/workers/inlet/StreamInletWorker.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Liblsl,
|
|
1
|
+
import { Liblsl, handleLslError } from '@neurodevs/ndx-native';
|
|
2
2
|
import { StreamInfoOptions } from '../../LslStreamInfo.js';
|
|
3
3
|
export declare function setOutletLiblslAdapter(adapter: Liblsl): void;
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function setOutletHandleLslError(fn: typeof handleLslError): void;
|
|
5
5
|
export declare function createOutlet(msg: {
|
|
6
6
|
type: 'createOutlet';
|
|
7
7
|
payload: CreateOutletPayload;
|
|
@@ -28,5 +28,5 @@ export interface CreateOutletPayload {
|
|
|
28
28
|
}
|
|
29
29
|
export interface PushSamplePayload {
|
|
30
30
|
sample: unknown;
|
|
31
|
-
|
|
31
|
+
timestampSec?: number;
|
|
32
32
|
}
|