@neurodevs/node-lsl 20.0.0 → 22.1.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/README.md +6 -6
- package/build/__tests__/AbstractPackageTest.d.ts +2 -1
- package/build/__tests__/AbstractPackageTest.js +9 -7
- package/build/__tests__/AbstractPackageTest.js.map +1 -1
- package/build/__tests__/impl/{BleDeviceController.test.d.ts → BleGattController.test.d.ts} +3 -3
- package/build/__tests__/impl/{BleDeviceController.test.js → BleGattController.test.js} +65 -65
- package/build/__tests__/impl/BleGattController.test.js.map +1 -0
- package/build/__tests__/impl/BleObserverController.test.d.ts +22 -0
- package/build/__tests__/impl/BleObserverController.test.js +112 -0
- package/build/__tests__/impl/BleObserverController.test.js.map +1 -0
- package/build/__tests__/impl/{LslEventMarkerEmitter.test.d.ts → LslEventMarkerOutlet.test.d.ts} +3 -3
- package/build/__tests__/impl/{LslEventMarkerEmitter.test.js → LslEventMarkerOutlet.test.js} +35 -36
- package/build/__tests__/impl/LslEventMarkerOutlet.test.js.map +1 -0
- package/build/__tests__/impl/LslJsonOutlet.test.d.ts +14 -0
- package/build/__tests__/impl/LslJsonOutlet.test.js +118 -0
- package/build/__tests__/impl/LslJsonOutlet.test.js.map +1 -0
- package/build/__tests__/impl/LslStreamInfo.test.js +0 -1
- package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamInlet.test.js +0 -1
- package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamOutlet.test.js +0 -1
- package/build/__tests__/impl/LslStreamOutlet.test.js.map +1 -1
- package/build/__tests__/impl/LslWebSocketBridge.test.js +0 -1
- package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
- package/build/__tests__/impl/UsbDeviceController.test.js.map +1 -1
- package/build/impl/{LslEventMarkerEmitter.d.ts → LslEventMarkerOutlet.d.ts} +6 -6
- package/build/impl/{LslEventMarkerEmitter.js → LslEventMarkerOutlet.js} +2 -2
- package/build/impl/LslEventMarkerOutlet.js.map +1 -0
- package/build/impl/LslJsonOutlet.d.ts +33 -0
- package/build/impl/LslJsonOutlet.js +44 -0
- package/build/impl/LslJsonOutlet.js.map +1 -0
- package/build/impl/LslStreamOutlet.d.ts +3 -4
- package/build/impl/controllers/{BleDeviceController.d.ts → BleGattController.d.ts} +10 -10
- package/build/impl/controllers/{BleDeviceController.js → BleGattController.js} +18 -18
- package/build/impl/controllers/BleGattController.js.map +1 -0
- package/build/impl/controllers/BleObserverController.d.ts +24 -0
- package/build/impl/controllers/BleObserverController.js +49 -0
- package/build/impl/controllers/BleObserverController.js.map +1 -0
- package/build/impl/controllers/UsbDeviceController.d.ts +9 -9
- package/build/impl/controllers/UsbDeviceController.js +7 -7
- package/build/impl/controllers/UsbDeviceController.js.map +1 -1
- package/build/index.d.ts +24 -16
- package/build/index.js +29 -19
- package/build/index.js.map +1 -1
- package/build/scripts/runEventMarkerOutlet.js +12 -0
- package/build/scripts/runEventMarkerOutlet.js.map +1 -0
- package/build/scripts/runMuse.js +2 -2
- package/build/scripts/runMuse.js.map +1 -1
- package/build/testDoubles/{BleController/FakeBleController.d.ts → BleGatt/FakeBleGatt.d.ts} +6 -6
- package/build/testDoubles/{BleController/FakeBleController.js → BleGatt/FakeBleGatt.js} +8 -8
- package/build/testDoubles/BleGatt/FakeBleGatt.js.map +1 -0
- package/build/testDoubles/{BleController/SpyBleController.d.ts → BleGatt/SpyBleGatt.d.ts} +4 -4
- package/build/testDoubles/{BleController/SpyBleController.js → BleGatt/SpyBleGatt.js} +3 -3
- package/build/testDoubles/BleGatt/SpyBleGatt.js.map +1 -0
- package/build/testDoubles/BleObserver/FakeBleObserver.d.ts +10 -0
- package/build/testDoubles/BleObserver/FakeBleObserver.js +20 -0
- package/build/testDoubles/BleObserver/FakeBleObserver.js.map +1 -0
- package/build/testDoubles/{LslEmitter/FakeLslEmitter.d.ts → EventMarkerOutlet/FakeEventMarkerOutlet.d.ts} +2 -2
- package/build/testDoubles/{LslEmitter/FakeLslEmitter.js → EventMarkerOutlet/FakeEventMarkerOutlet.js} +7 -7
- package/build/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.js.map +1 -0
- package/build/testDoubles/{LslEmitter/SpyLslEmitter.d.ts → EventMarkerOutlet/SpyEventMarkerOutlet.d.ts} +3 -3
- package/build/testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.js +23 -0
- package/build/testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.js.map +1 -0
- package/build/testDoubles/{LslEmitter/ThrowingLslEmitter.d.ts → EventMarkerOutlet/ThrowingEventMarkerOutlet.d.ts} +2 -2
- package/build/testDoubles/{LslEmitter/ThrowingLslEmitter.js → EventMarkerOutlet/ThrowingEventMarkerOutlet.js} +2 -2
- package/build/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.js.map +1 -0
- package/build/testDoubles/JsonOutlet/FakeJsonOutlet.d.ts +10 -0
- package/build/testDoubles/JsonOutlet/FakeJsonOutlet.js +20 -0
- package/build/testDoubles/JsonOutlet/FakeJsonOutlet.js.map +1 -0
- package/build/testDoubles/UsbDevice/FakeUsbDevice.d.ts +12 -0
- package/build/testDoubles/UsbDevice/FakeUsbDevice.js +25 -0
- package/build/testDoubles/UsbDevice/FakeUsbDevice.js.map +1 -0
- package/package.json +3 -3
- package/src/__tests__/AbstractPackageTest.ts +9 -7
- package/src/__tests__/impl/{BleDeviceController.test.ts → BleGattController.test.ts} +43 -43
- package/src/__tests__/impl/BleObserverController.test.ts +158 -0
- package/src/__tests__/impl/{LslEventMarkerEmitter.test.ts → LslEventMarkerOutlet.test.ts} +20 -19
- package/src/__tests__/impl/LslJsonOutlet.test.ts +135 -0
- package/src/__tests__/impl/LslStreamInfo.test.ts +0 -1
- package/src/__tests__/impl/LslStreamInlet.test.ts +0 -1
- package/src/__tests__/impl/LslStreamOutlet.test.ts +0 -1
- package/src/__tests__/impl/LslWebSocketBridge.test.ts +0 -1
- package/src/__tests__/impl/UsbDeviceController.test.ts +2 -2
- package/src/impl/{LslEventMarkerEmitter.ts → LslEventMarkerOutlet.ts} +8 -6
- package/src/impl/LslJsonOutlet.ts +87 -0
- package/src/impl/LslStreamOutlet.ts +7 -5
- package/src/impl/controllers/{BleDeviceController.ts → BleGattController.ts} +23 -28
- package/src/impl/controllers/BleObserverController.ts +85 -0
- package/src/impl/controllers/UsbDeviceController.ts +14 -16
- package/src/index.ts +40 -24
- package/src/scripts/{runLslEmitter.ts → runEventMarkerOutlet.ts} +5 -5
- package/src/scripts/runMuse.ts +2 -2
- package/src/testDoubles/{BleController/FakeBleController.ts → BleGatt/FakeBleGatt.ts} +14 -14
- package/src/testDoubles/{BleController/SpyBleController.ts → BleGatt/SpyBleGatt.ts} +5 -5
- package/src/testDoubles/BleObserver/FakeBleObserver.ts +28 -0
- package/src/testDoubles/{LslEmitter/FakeLslEmitter.ts → EventMarkerOutlet/FakeEventMarkerOutlet.ts} +8 -8
- package/src/testDoubles/{LslEmitter/SpyLslEmitter.ts → EventMarkerOutlet/SpyEventMarkerOutlet.ts} +7 -7
- package/src/testDoubles/{LslEmitter/ThrowingLslEmitter.ts → EventMarkerOutlet/ThrowingEventMarkerOutlet.ts} +3 -3
- package/src/testDoubles/JsonOutlet/FakeJsonOutlet.ts +25 -0
- package/src/testDoubles/UsbDevice/FakeUsbDevice.ts +34 -0
- package/build/__tests__/impl/BleDeviceController.test.js.map +0 -1
- package/build/__tests__/impl/LslEventMarkerEmitter.test.js.map +0 -1
- package/build/impl/LslEventMarkerEmitter.js.map +0 -1
- package/build/impl/controllers/BleDeviceController.js.map +0 -1
- package/build/scripts/runLslEmitter.js +0 -12
- package/build/scripts/runLslEmitter.js.map +0 -1
- package/build/testDoubles/BleController/FakeBleController.js.map +0 -1
- package/build/testDoubles/BleController/SpyBleController.js.map +0 -1
- package/build/testDoubles/LslEmitter/FakeLslEmitter.js.map +0 -1
- package/build/testDoubles/LslEmitter/SpyLslEmitter.js +0 -23
- package/build/testDoubles/LslEmitter/SpyLslEmitter.js.map +0 -1
- package/build/testDoubles/LslEmitter/ThrowingLslEmitter.js.map +0 -1
- package/build/testDoubles/UsbController/FakeUsbController.d.ts +0 -12
- package/build/testDoubles/UsbController/FakeUsbController.js +0 -25
- package/build/testDoubles/UsbController/FakeUsbController.js.map +0 -1
- package/src/testDoubles/UsbController/FakeUsbController.ts +0 -34
- /package/build/scripts/{runLslEmitter.d.ts → runEventMarkerOutlet.d.ts} +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { test, assert } from '@neurodevs/node-tdd'
|
|
2
2
|
|
|
3
3
|
import UsbDeviceController, {
|
|
4
|
-
|
|
4
|
+
UsbDevice,
|
|
5
5
|
} from '../../impl/controllers/UsbDeviceController.js'
|
|
6
6
|
import AbstractPackageTest from '../AbstractPackageTest.js'
|
|
7
7
|
import { FakeLibndx } from '@neurodevs/ndx-native'
|
|
8
8
|
|
|
9
9
|
export default class UsbDeviceControllerTest extends AbstractPackageTest {
|
|
10
|
-
private static instance:
|
|
10
|
+
private static instance: UsbDevice
|
|
11
11
|
|
|
12
12
|
private static readonly serialNumber = this.generateId()
|
|
13
13
|
private static readonly valueToWrite = this.generateId()
|
|
@@ -5,8 +5,8 @@ import LslStreamOutlet, {
|
|
|
5
5
|
LslOutlet,
|
|
6
6
|
} from './LslStreamOutlet.js'
|
|
7
7
|
|
|
8
|
-
export default class
|
|
9
|
-
public static Class?:
|
|
8
|
+
export default class LslEventMarkerOutlet implements EventMarkerOutlet {
|
|
9
|
+
public static Class?: EventMarkerOutletConstructor
|
|
10
10
|
|
|
11
11
|
protected outlet: LslOutlet
|
|
12
12
|
private isRunning = false
|
|
@@ -17,7 +17,7 @@ export default class LslEventMarkerEmitter implements LslEmitter {
|
|
|
17
17
|
this.outlet = outlet
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
public static async Create(options?:
|
|
20
|
+
public static async Create(options?: EventMarkerOutletOptions) {
|
|
21
21
|
const outlet = await this.LslStreamOutlet(options)
|
|
22
22
|
return new (this.Class ?? this)(outlet)
|
|
23
23
|
}
|
|
@@ -110,16 +110,18 @@ export default class LslEventMarkerEmitter implements LslEmitter {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export interface
|
|
113
|
+
export interface EventMarkerOutlet {
|
|
114
114
|
emit(markerName: string, options?: EmitOptions): Promise<void>
|
|
115
115
|
emitMany(markers: TimedEventMarker[]): Promise<void>
|
|
116
116
|
interrupt(): void
|
|
117
117
|
destroy(): void
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
export type
|
|
120
|
+
export type EventMarkerOutletOptions = Partial<LslOutletOptions>
|
|
121
121
|
|
|
122
|
-
export type
|
|
122
|
+
export type EventMarkerOutletConstructor = new (
|
|
123
|
+
outlet: LslOutlet
|
|
124
|
+
) => EventMarkerOutlet
|
|
123
125
|
|
|
124
126
|
export interface EmitOptions {
|
|
125
127
|
waitAfterMs?: number
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import LslStreamOutlet, { LslOutlet } from './LslStreamOutlet.js'
|
|
2
|
+
|
|
3
|
+
export default class LslJsonOutlet implements JsonOutlet {
|
|
4
|
+
public static Class?: JsonOutletConstructor
|
|
5
|
+
public static backupIdCounter = 0
|
|
6
|
+
|
|
7
|
+
private outlet: LslOutlet
|
|
8
|
+
private maxBytesPerSample?: number
|
|
9
|
+
|
|
10
|
+
protected constructor(outlet: LslOutlet, maxBytesPerSample?: number) {
|
|
11
|
+
this.outlet = outlet
|
|
12
|
+
this.maxBytesPerSample = maxBytesPerSample
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public static async Create(options?: JsonOutletOptions) {
|
|
16
|
+
const outlet = await this.LslStreamOutlet(options)
|
|
17
|
+
return new (this.Class ?? this)(outlet, options?.maxBytesPerSample)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public pushJson(data: Json) {
|
|
21
|
+
const json = JSON.stringify(data)
|
|
22
|
+
this.throwIfPayloadTooLarge(json)
|
|
23
|
+
this.outlet.pushSample([json])
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private throwIfPayloadTooLarge(json: string) {
|
|
27
|
+
const totalBytes = Buffer.byteLength(json)
|
|
28
|
+
|
|
29
|
+
if (this.maxBytesPerSample && totalBytes > this.maxBytesPerSample) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`Payload of ${totalBytes} bytes exceeds maxBytesPerSample of ${this.maxBytesPerSample}!`
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public destroy() {
|
|
37
|
+
this.outlet.destroy()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private static LslStreamOutlet(options?: JsonOutletOptions) {
|
|
41
|
+
this.backupIdCounter++
|
|
42
|
+
|
|
43
|
+
const { channelName, maxBytesPerSample: _, ...rest } = options ?? {}
|
|
44
|
+
|
|
45
|
+
return LslStreamOutlet.Create({
|
|
46
|
+
name: `JSON (json-${this.backupIdCounter})`,
|
|
47
|
+
type: 'JSON',
|
|
48
|
+
sourceId: `json-${this.backupIdCounter}`,
|
|
49
|
+
channelNames: [channelName ?? 'JSON'],
|
|
50
|
+
channelFormat: 'string',
|
|
51
|
+
sampleRateHz: 0,
|
|
52
|
+
chunkSize: 1,
|
|
53
|
+
...rest,
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface JsonOutlet {
|
|
59
|
+
pushJson(data: Json): void
|
|
60
|
+
destroy(): void
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type Json = Record<string, unknown>
|
|
64
|
+
|
|
65
|
+
export type JsonOutletConstructor = new (
|
|
66
|
+
outlet: LslOutlet,
|
|
67
|
+
maxBytesPerSample?: number
|
|
68
|
+
) => JsonOutlet
|
|
69
|
+
|
|
70
|
+
export interface JsonOutletOptions {
|
|
71
|
+
name?: string
|
|
72
|
+
type?: string
|
|
73
|
+
sourceId?: string
|
|
74
|
+
channelName?: string
|
|
75
|
+
sampleRateHz?: number
|
|
76
|
+
chunkSize?: number
|
|
77
|
+
maxBufferedMs?: number
|
|
78
|
+
maxBytesPerSample?: number
|
|
79
|
+
manufacturer?: string
|
|
80
|
+
units?: string
|
|
81
|
+
waitAfterConstructionMs?: number
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type JsonOutletConstructorOptions = Omit<
|
|
85
|
+
JsonOutletOptions,
|
|
86
|
+
'waitAfterConstructionMs'
|
|
87
|
+
>
|
|
@@ -180,11 +180,7 @@ export interface LslOutlet {
|
|
|
180
180
|
|
|
181
181
|
export type LslOutletConstructor = new (options: LslOutletOptions) => LslOutlet
|
|
182
182
|
|
|
183
|
-
export interface LslOutletOptions
|
|
184
|
-
waitAfterConstructionMs?: number
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export interface LslOutletConstructorOptions {
|
|
183
|
+
export interface LslOutletOptions {
|
|
188
184
|
name: string
|
|
189
185
|
type: string
|
|
190
186
|
sourceId: string
|
|
@@ -195,4 +191,10 @@ export interface LslOutletConstructorOptions {
|
|
|
195
191
|
maxBufferedMs?: number
|
|
196
192
|
manufacturer?: string
|
|
197
193
|
units?: string
|
|
194
|
+
waitAfterConstructionMs?: number
|
|
198
195
|
}
|
|
196
|
+
|
|
197
|
+
export type LslOutletConstructorOptions = Omit<
|
|
198
|
+
LslOutletOptions,
|
|
199
|
+
'waitAfterConstructionMs'
|
|
200
|
+
>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LibndxAdapter, Libndx, NativePeripheral } from '@neurodevs/ndx-native'
|
|
2
2
|
|
|
3
|
-
export default class
|
|
4
|
-
public static Class?:
|
|
3
|
+
export default class BleGattController implements BleGatt {
|
|
4
|
+
public static Class?: BleGattConstructor
|
|
5
5
|
public static setTimeout = setTimeout
|
|
6
6
|
public static waitAfterMs = 1000
|
|
7
7
|
|
|
@@ -28,7 +28,7 @@ export default class BleDeviceController implements BleController {
|
|
|
28
28
|
private deviceName?: string
|
|
29
29
|
private onConnected?: (peripheral: NativePeripheral) => void
|
|
30
30
|
|
|
31
|
-
protected constructor(options:
|
|
31
|
+
protected constructor(options: BleGattOptions) {
|
|
32
32
|
const {
|
|
33
33
|
deviceUuid,
|
|
34
34
|
deviceNamePrefix,
|
|
@@ -44,7 +44,7 @@ export default class BleDeviceController implements BleController {
|
|
|
44
44
|
this.rssiIntervalMs = rssiIntervalMs
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
public static Create(options:
|
|
47
|
+
public static Create(options: BleGattOptions) {
|
|
48
48
|
return new (this.Class ?? this)(options)
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -53,13 +53,13 @@ export default class BleDeviceController implements BleController {
|
|
|
53
53
|
await this.discoverUuid()
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
56
|
+
this.createBleGattBackend()
|
|
57
|
+
this.startBleGattBackend()
|
|
58
58
|
|
|
59
59
|
await this.waitForOnConnected()
|
|
60
60
|
await this.waitToDiscoverServices()
|
|
61
61
|
|
|
62
|
-
this.
|
|
62
|
+
this.startBleGattRssiPolling()
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
private async discoverUuid() {
|
|
@@ -81,15 +81,15 @@ export default class BleDeviceController implements BleController {
|
|
|
81
81
|
if (this.deviceUuid) {
|
|
82
82
|
resolve()
|
|
83
83
|
} else {
|
|
84
|
-
|
|
84
|
+
BleGattController.setTimeout(checkDiscovered, 100)
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
checkDiscovered()
|
|
88
88
|
})
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
private
|
|
92
|
-
const { status, error } = this.ndx.
|
|
91
|
+
private createBleGattBackend() {
|
|
92
|
+
const { status, error } = this.ndx.createBleGattBackend({
|
|
93
93
|
deviceUuid: this.uuid,
|
|
94
94
|
})
|
|
95
95
|
|
|
@@ -102,9 +102,9 @@ export default class BleDeviceController implements BleController {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
private
|
|
105
|
+
private startBleGattRssiPolling() {
|
|
106
106
|
if (this.rssiIntervalMs) {
|
|
107
|
-
this.ndx.
|
|
107
|
+
this.ndx.startBleGattRssiPolling({
|
|
108
108
|
deviceUuid: this.uuid,
|
|
109
109
|
intervalMs: this.rssiIntervalMs,
|
|
110
110
|
onRssi: (rssi: number) => {
|
|
@@ -114,8 +114,8 @@ export default class BleDeviceController implements BleController {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
private
|
|
118
|
-
const { status, error } = this.ndx.
|
|
117
|
+
private startBleGattBackend() {
|
|
118
|
+
const { status, error } = this.ndx.startBleGattBackend({
|
|
119
119
|
deviceUuid: this.uuid,
|
|
120
120
|
onConnected: (peripheral: NativePeripheral) => {
|
|
121
121
|
const { name } = peripheral
|
|
@@ -136,7 +136,7 @@ export default class BleDeviceController implements BleController {
|
|
|
136
136
|
if (this.connected) {
|
|
137
137
|
resolve()
|
|
138
138
|
} else {
|
|
139
|
-
|
|
139
|
+
BleGattController.setTimeout(checkConnected, 100)
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
checkConnected()
|
|
@@ -145,10 +145,7 @@ export default class BleDeviceController implements BleController {
|
|
|
145
145
|
|
|
146
146
|
private async waitToDiscoverServices() {
|
|
147
147
|
await new Promise<void>((resolve) =>
|
|
148
|
-
|
|
149
|
-
resolve,
|
|
150
|
-
BleDeviceController.waitAfterMs
|
|
151
|
-
)
|
|
148
|
+
BleGattController.setTimeout(resolve, BleGattController.waitAfterMs)
|
|
152
149
|
)
|
|
153
150
|
}
|
|
154
151
|
|
|
@@ -156,7 +153,7 @@ export default class BleDeviceController implements BleController {
|
|
|
156
153
|
charUuid: CharacteristicUuid,
|
|
157
154
|
value: string
|
|
158
155
|
) {
|
|
159
|
-
const { status, error } = this.ndx.
|
|
156
|
+
const { status, error } = this.ndx.writeBleGattChar({
|
|
160
157
|
deviceUuid: this.uuid,
|
|
161
158
|
charUuid,
|
|
162
159
|
value,
|
|
@@ -168,7 +165,7 @@ export default class BleDeviceController implements BleController {
|
|
|
168
165
|
public async subscribeCharacteristics(
|
|
169
166
|
charCallbacks: CharacteristicCallbacks
|
|
170
167
|
) {
|
|
171
|
-
const { status, error } = this.ndx.
|
|
168
|
+
const { status, error } = this.ndx.registerBleGattCharCallbacks({
|
|
172
169
|
deviceUuid: this.uuid,
|
|
173
170
|
charCallbacks,
|
|
174
171
|
})
|
|
@@ -179,7 +176,7 @@ export default class BleDeviceController implements BleController {
|
|
|
179
176
|
}
|
|
180
177
|
|
|
181
178
|
public async disconnect() {
|
|
182
|
-
const { status, error } = this.ndx.
|
|
179
|
+
const { status, error } = this.ndx.stopBleGattBackend({
|
|
183
180
|
deviceUuid: this.uuid,
|
|
184
181
|
})
|
|
185
182
|
|
|
@@ -196,11 +193,11 @@ export default class BleDeviceController implements BleController {
|
|
|
196
193
|
}
|
|
197
194
|
|
|
198
195
|
private get ndx() {
|
|
199
|
-
return
|
|
196
|
+
return BleGattController.ndx
|
|
200
197
|
}
|
|
201
198
|
}
|
|
202
199
|
|
|
203
|
-
export interface
|
|
200
|
+
export interface BleGatt {
|
|
204
201
|
uuid: string
|
|
205
202
|
name: string
|
|
206
203
|
|
|
@@ -218,7 +215,7 @@ export interface BleController {
|
|
|
218
215
|
disconnect(): Promise<void>
|
|
219
216
|
}
|
|
220
217
|
|
|
221
|
-
export type
|
|
218
|
+
export type BleGattOptions = {
|
|
222
219
|
charCallbacks: CharacteristicCallbacks
|
|
223
220
|
onConnected?: (peripheral: NativePeripheral) => void
|
|
224
221
|
rssiIntervalMs?: number
|
|
@@ -227,9 +224,7 @@ export type BleControllerOptions = {
|
|
|
227
224
|
| { deviceUuid?: string; deviceNamePrefix: string }
|
|
228
225
|
)
|
|
229
226
|
|
|
230
|
-
export type
|
|
231
|
-
options: BleControllerOptions
|
|
232
|
-
) => BleController
|
|
227
|
+
export type BleGattConstructor = new (options: BleGattOptions) => BleGatt
|
|
233
228
|
|
|
234
229
|
export type CharacteristicCallbacks = {
|
|
235
230
|
charUuid: string
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { LibndxAdapter } from '@neurodevs/ndx-native'
|
|
2
|
+
|
|
3
|
+
export default class BleObserverController implements BleObserver {
|
|
4
|
+
public static Class?: BleObserverConstructor
|
|
5
|
+
|
|
6
|
+
private readonly deviceUuid: string
|
|
7
|
+
private readonly onAdvertisement?: OnAdvertisement
|
|
8
|
+
private readonly ndx = LibndxAdapter.getInstance()
|
|
9
|
+
|
|
10
|
+
protected constructor(options: BleObserverOptions) {
|
|
11
|
+
const { deviceUuid, onAdvertisement } = options
|
|
12
|
+
|
|
13
|
+
this.deviceUuid = deviceUuid ?? ''
|
|
14
|
+
this.onAdvertisement = onAdvertisement
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public static Create(options: BleObserverOptions) {
|
|
18
|
+
return new (this.Class ?? this)(options)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public async startObserving() {
|
|
22
|
+
this.createBleObserverBackend()
|
|
23
|
+
this.startBleObserverBackend()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private createBleObserverBackend() {
|
|
27
|
+
const { status, error } = this.ndx.createBleObserverBackend({
|
|
28
|
+
deviceUuid: this.deviceUuid,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
this.throwIfError(status, error)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private startBleObserverBackend() {
|
|
35
|
+
const { status, error } = this.ndx.startBleObserverBackend({
|
|
36
|
+
deviceUuid: this.deviceUuid,
|
|
37
|
+
onAdvertisement: (
|
|
38
|
+
data: Buffer,
|
|
39
|
+
length: number,
|
|
40
|
+
timestampSec: number
|
|
41
|
+
) => {
|
|
42
|
+
this.onAdvertisement?.(data, length, timestampSec)
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
this.throwIfError(status, error)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public async stopObserving() {
|
|
50
|
+
this.stopBleObserverBackend()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private stopBleObserverBackend() {
|
|
54
|
+
const { status, error } = this.ndx.stopBleObserverBackend({
|
|
55
|
+
deviceUuid: this.deviceUuid,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
this.throwIfError(status, error)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private throwIfError(status: number, error: string | undefined) {
|
|
62
|
+
if (status !== 200) {
|
|
63
|
+
throw new Error(`${status} error: ${error ?? 'Unknown error'}`)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export interface BleObserver {
|
|
68
|
+
startObserving(): Promise<void>
|
|
69
|
+
stopObserving(): Promise<void>
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type BleObserverConstructor = new (
|
|
73
|
+
options: BleObserverOptions
|
|
74
|
+
) => BleObserver
|
|
75
|
+
|
|
76
|
+
export type BleObserverOptions = {
|
|
77
|
+
deviceUuid: string
|
|
78
|
+
onAdvertisement?: OnAdvertisement
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type OnAdvertisement = (
|
|
82
|
+
data: Buffer,
|
|
83
|
+
length: number,
|
|
84
|
+
timestampSec: number
|
|
85
|
+
) => void
|
|
@@ -1,65 +1,63 @@
|
|
|
1
1
|
import { LibndxAdapter } from '@neurodevs/ndx-native'
|
|
2
2
|
|
|
3
|
-
export default class UsbDeviceController implements
|
|
4
|
-
public static Class?:
|
|
3
|
+
export default class UsbDeviceController implements UsbDevice {
|
|
4
|
+
public static Class?: UsbDeviceConstructor
|
|
5
5
|
|
|
6
6
|
private onData: (data: Buffer, length: number, timestampSec: number) => void
|
|
7
7
|
private serialNumber: string
|
|
8
8
|
|
|
9
9
|
private ndx = LibndxAdapter.getInstance()
|
|
10
10
|
|
|
11
|
-
protected constructor(options:
|
|
11
|
+
protected constructor(options: UsbDeviceOptions) {
|
|
12
12
|
const { onData, serialNumber } = options ?? {}
|
|
13
13
|
|
|
14
14
|
this.onData = onData
|
|
15
15
|
this.serialNumber = serialNumber ?? ''
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
public static Create(options:
|
|
18
|
+
public static Create(options: UsbDeviceOptions) {
|
|
19
19
|
return new (this.Class ?? this)(options)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
public async connect() {
|
|
23
|
-
this.ndx.createUsbBackend(this.
|
|
24
|
-
this.ndx.startUsbBackend(this.
|
|
23
|
+
this.ndx.createUsbBackend(this.usbDeviceOptions)
|
|
24
|
+
this.ndx.startUsbBackend(this.startUsbDeviceOptions)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
private get
|
|
27
|
+
private get usbDeviceOptions() {
|
|
28
28
|
return {
|
|
29
29
|
serialNumber: this.serialNumber,
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
private get
|
|
33
|
+
private get startUsbDeviceOptions() {
|
|
34
34
|
return {
|
|
35
|
-
...this.
|
|
35
|
+
...this.usbDeviceOptions,
|
|
36
36
|
onData: this.onData,
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
public async writeUsb(value: string) {
|
|
41
41
|
this.ndx.writeUsbBackend({
|
|
42
|
-
...this.
|
|
42
|
+
...this.usbDeviceOptions,
|
|
43
43
|
value,
|
|
44
44
|
})
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
public async disconnect() {
|
|
48
|
-
this.ndx.stopUsbBackend(this.
|
|
48
|
+
this.ndx.stopUsbBackend(this.usbDeviceOptions)
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export interface
|
|
52
|
+
export interface UsbDevice {
|
|
53
53
|
connect(): Promise<void>
|
|
54
54
|
writeUsb(value: string): Promise<void>
|
|
55
55
|
disconnect(): Promise<void>
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
export interface
|
|
58
|
+
export interface UsbDeviceOptions {
|
|
59
59
|
onData: (data: Buffer, length: number, timestampSec: number) => void
|
|
60
60
|
serialNumber?: string
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
export type
|
|
64
|
-
options?: UsbControllerOptions
|
|
65
|
-
) => UsbController
|
|
63
|
+
export type UsbDeviceConstructor = new (options?: UsbDeviceOptions) => UsbDevice
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
// BleObserver
|
|
2
|
+
|
|
3
|
+
export { default as BleObserverController } from './impl/controllers/BleObserverController.js'
|
|
4
|
+
export * from './impl/controllers/BleObserverController.js'
|
|
5
|
+
|
|
6
|
+
export { default as FakeBleObserver } from './testDoubles/BleObserver/FakeBleObserver.js'
|
|
7
|
+
export * from './testDoubles/BleObserver/FakeBleObserver.js'
|
|
8
|
+
|
|
1
9
|
// ClockRegressor
|
|
2
10
|
|
|
3
11
|
export { default as WindowedClockRegressor } from './impl/clocks/WindowedClockRegressor.js'
|
|
@@ -6,16 +14,38 @@ export * from './impl/clocks/WindowedClockRegressor.js'
|
|
|
6
14
|
export { default as FakeClockRegressor } from './testDoubles/ClockRegressor/FakeClockRegressor.js'
|
|
7
15
|
export * from './testDoubles/ClockRegressor/FakeClockRegressor.js'
|
|
8
16
|
|
|
9
|
-
//
|
|
17
|
+
// BleGatt
|
|
18
|
+
|
|
19
|
+
export { default as BleGattController } from './impl/controllers/BleGattController.js'
|
|
20
|
+
export * from './impl/controllers/BleGattController.js'
|
|
21
|
+
|
|
22
|
+
export { default as SpyBleGatt } from './testDoubles/BleGatt/SpyBleGatt.js'
|
|
23
|
+
export * from './testDoubles/BleGatt/SpyBleGatt.js'
|
|
24
|
+
|
|
25
|
+
export { default as FakeBleGatt } from './testDoubles/BleGatt/FakeBleGatt.js'
|
|
26
|
+
export * from './testDoubles/BleGatt/FakeBleGatt.js'
|
|
27
|
+
|
|
28
|
+
// EventMarkerOutlet
|
|
29
|
+
|
|
30
|
+
export { default as LslEventMarkerOutlet } from './impl/LslEventMarkerOutlet.js'
|
|
31
|
+
export * from './impl/LslEventMarkerOutlet.js'
|
|
10
32
|
|
|
11
|
-
export { default as
|
|
12
|
-
export * from './
|
|
33
|
+
export { default as SpyEventMarkerOutlet } from './testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.js'
|
|
34
|
+
export * from './testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.js'
|
|
13
35
|
|
|
14
|
-
export { default as
|
|
15
|
-
export * from './testDoubles/
|
|
36
|
+
export { default as FakeEventMarkerOutlet } from './testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.js'
|
|
37
|
+
export * from './testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.js'
|
|
16
38
|
|
|
17
|
-
export { default as
|
|
18
|
-
export * from './testDoubles/
|
|
39
|
+
export { default as ThrowingEventMarkerOutlet } from './testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.js'
|
|
40
|
+
export * from './testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.js'
|
|
41
|
+
|
|
42
|
+
// JsonOutlet
|
|
43
|
+
|
|
44
|
+
export { default as LslJsonOutlet } from './impl/LslJsonOutlet.js'
|
|
45
|
+
export * from './impl/LslJsonOutlet.js'
|
|
46
|
+
|
|
47
|
+
export { default as FakeJsonOutlet } from './testDoubles/JsonOutlet/FakeJsonOutlet.js'
|
|
48
|
+
export * from './testDoubles/JsonOutlet/FakeJsonOutlet.js'
|
|
19
49
|
|
|
20
50
|
// LslWsBridge
|
|
21
51
|
|
|
@@ -28,20 +58,6 @@ export * from './testDoubles/LslWsBridge/SpyLslWsBridge.js'
|
|
|
28
58
|
export { default as FakeLslWsBridge } from './testDoubles/LslWsBridge/FakeLslWsBridge.js'
|
|
29
59
|
export * from './testDoubles/LslWsBridge/FakeLslWsBridge.js'
|
|
30
60
|
|
|
31
|
-
// LslEmitter
|
|
32
|
-
|
|
33
|
-
export { default as LslEventMarkerEmitter } from './impl/LslEventMarkerEmitter.js'
|
|
34
|
-
export * from './impl/LslEventMarkerEmitter.js'
|
|
35
|
-
|
|
36
|
-
export { default as SpyLslEmitter } from './testDoubles/LslEmitter/SpyLslEmitter.js'
|
|
37
|
-
export * from './testDoubles/LslEmitter/SpyLslEmitter.js'
|
|
38
|
-
|
|
39
|
-
export { default as FakeLslEmitter } from './testDoubles/LslEmitter/FakeLslEmitter.js'
|
|
40
|
-
export * from './testDoubles/LslEmitter/FakeLslEmitter.js'
|
|
41
|
-
|
|
42
|
-
export { default as ThrowingLslEmitter } from './testDoubles/LslEmitter/ThrowingLslEmitter.js'
|
|
43
|
-
export * from './testDoubles/LslEmitter/ThrowingLslEmitter.js'
|
|
44
|
-
|
|
45
61
|
// LslInfo
|
|
46
62
|
|
|
47
63
|
export { default as LslStreamInfo } from './impl/LslStreamInfo.js'
|
|
@@ -74,13 +90,13 @@ export * from './testDoubles/LslOutlet/FakeLslOutlet.js'
|
|
|
74
90
|
|
|
75
91
|
export { default as generateRandomOutletOptions } from './testDoubles/generateRandomOutletOptions.js'
|
|
76
92
|
|
|
77
|
-
//
|
|
93
|
+
// UsbDevice
|
|
78
94
|
|
|
79
95
|
export { default as UsbDeviceController } from './impl/controllers/UsbDeviceController.js'
|
|
80
96
|
export * from './impl/controllers/UsbDeviceController.js'
|
|
81
97
|
|
|
82
|
-
export { default as
|
|
83
|
-
export * from './testDoubles/
|
|
98
|
+
export { default as FakeUsbDevice } from './testDoubles/UsbDevice/FakeUsbDevice.js'
|
|
99
|
+
export * from './testDoubles/UsbDevice/FakeUsbDevice.js'
|
|
84
100
|
|
|
85
101
|
// WebSockets
|
|
86
102
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import LslEventMarkerOutlet from '../impl/LslEventMarkerOutlet.js'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const outlet = await LslEventMarkerOutlet.Create()
|
|
4
4
|
|
|
5
5
|
const markers = [
|
|
6
6
|
{ name: 'phase-1-begin', waitAfterMs: 100 },
|
|
@@ -8,9 +8,9 @@ const markers = [
|
|
|
8
8
|
{ name: 'never-reached-marker', waitAfterMs: 100 },
|
|
9
9
|
]
|
|
10
10
|
|
|
11
|
-
void
|
|
11
|
+
void outlet.emitMany(markers)
|
|
12
12
|
|
|
13
13
|
await new Promise((resolve) => setTimeout(resolve, 250))
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
outlet.interrupt()
|
|
16
|
+
outlet.destroy()
|
package/src/scripts/runMuse.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import koffi from 'koffi'
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import BleGattController from '../impl/controllers/BleGattController.js'
|
|
4
4
|
|
|
5
5
|
const MUSE_CHARACTERISTIC_UUIDS: Record<string, string> = {
|
|
6
6
|
CONTROL: '273E0001-4C4D-454D-96BE-F03BAC821358',
|
|
@@ -32,7 +32,7 @@ const charCallbacks = Object.entries(MUSE_CHARACTERISTIC_UUIDS).map(
|
|
|
32
32
|
}
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
-
const muse =
|
|
35
|
+
const muse = BleGattController.Create({
|
|
36
36
|
deviceUuid: 'CA6A61B7-B7A8-AF24-3C9E-04A6A5012554',
|
|
37
37
|
charCallbacks,
|
|
38
38
|
rssiIntervalMs: 1000,
|