@neurodevs/ndx-native 0.1.0 → 0.3.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/.regressionproof.json +7 -0
- package/.vscode/launch.json +52 -57
- package/.vscode/settings.json +62 -66
- package/.vscode/tasks.json +123 -129
- package/README.md +1 -0
- package/build/.spruce/settings.json +7 -7
- package/build/__tests__/AbstractPackageTest.d.ts +1 -0
- package/build/__tests__/AbstractPackageTest.js +1 -0
- package/build/__tests__/AbstractPackageTest.js.map +1 -1
- package/build/__tests__/impl/LabrecorderAdapter.test.d.ts +1 -1
- package/build/__tests__/impl/LabrecorderAdapter.test.js +9 -9
- package/build/__tests__/impl/LabrecorderAdapter.test.js.map +1 -1
- package/build/__tests__/impl/LiblslAdapter.test.d.ts +3 -4
- package/build/__tests__/impl/LiblslAdapter.test.js +18 -28
- package/build/__tests__/impl/LiblslAdapter.test.js.map +1 -1
- package/build/__tests__/impl/LibndxAdapter.test.d.ts +35 -0
- package/build/__tests__/impl/LibndxAdapter.test.js +258 -0
- package/build/__tests__/impl/LibndxAdapter.test.js.map +1 -0
- package/build/__tests__/impl/LibxdfAdapter.test.d.ts +1 -2
- package/build/__tests__/impl/LibxdfAdapter.test.js +5 -6
- package/build/__tests__/impl/LibxdfAdapter.test.js.map +1 -1
- package/build/impl/LiblslAdapter.d.ts +11 -13
- package/build/impl/LiblslAdapter.js +115 -123
- package/build/impl/LiblslAdapter.js.map +1 -1
- package/build/impl/LibndxAdapter.d.ts +57 -0
- package/build/impl/LibndxAdapter.js +145 -0
- package/build/impl/LibndxAdapter.js.map +1 -0
- package/build/impl/LibxdfAdapter.d.ts +3 -3
- package/build/impl/LibxdfAdapter.js +10 -7
- package/build/impl/LibxdfAdapter.js.map +1 -1
- package/build/index.d.ts +6 -2
- package/build/index.js +8 -3
- package/build/index.js.map +1 -1
- package/build/lib/{handleError.d.ts → handleLslError.d.ts} +1 -1
- package/build/lib/{handleError.js → handleLslError.js} +2 -2
- package/build/lib/handleLslError.js.map +1 -0
- package/build/testDoubles/Liblsl/FakeLiblsl.d.ts +3 -3
- package/build/testDoubles/Liblsl/FakeLiblsl.js +3 -3
- package/build/testDoubles/Liblsl/FakeLiblsl.js.map +1 -1
- package/build/testDoubles/Libndx/FakeLibndx.d.ts +22 -0
- package/build/testDoubles/Libndx/FakeLibndx.js +58 -0
- package/build/testDoubles/Libndx/FakeLibndx.js.map +1 -0
- package/build/types.d.ts +2 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/eslint.config.js +3 -0
- package/package.json +15 -31
- package/prettier.config.js +3 -0
- package/src/.spruce/settings.json +7 -7
- package/src/__tests__/AbstractPackageTest.ts +2 -0
- package/src/__tests__/impl/LabrecorderAdapter.test.ts +27 -11
- package/src/__tests__/impl/LiblslAdapter.test.ts +19 -28
- package/src/__tests__/impl/LibndxAdapter.test.ts +279 -0
- package/src/__tests__/impl/LibxdfAdapter.test.ts +5 -6
- package/src/impl/LiblslAdapter.ts +125 -135
- package/src/impl/LibndxAdapter.ts +204 -0
- package/src/impl/LibxdfAdapter.ts +13 -15
- package/src/index.ts +11 -3
- package/src/lib/{handleError.ts → handleLslError.ts} +1 -1
- package/src/testDoubles/Liblsl/FakeLiblsl.ts +3 -3
- package/src/testDoubles/Libndx/FakeLibndx.ts +74 -0
- package/src/types.ts +7 -0
- package/tsconfig.json +24 -27
- package/build/lib/handleError.js.map +0 -1
- package/eslint.config.mjs +0 -3
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { test, assert } from '@neurodevs/node-tdd'
|
|
2
|
+
|
|
3
|
+
import LibndxAdapter, {
|
|
4
|
+
Libndx,
|
|
5
|
+
LibndxBindings,
|
|
6
|
+
} from '../../impl/LibndxAdapter.js'
|
|
7
|
+
import AbstractPackageTest from '../AbstractPackageTest.js'
|
|
8
|
+
import { DataType, define, OpenParams } from 'ffi-rs'
|
|
9
|
+
import { FfiRsDefineOptions } from '../../types.js'
|
|
10
|
+
import FakeLibndx from '../../testDoubles/Libndx/FakeLibndx.js'
|
|
11
|
+
|
|
12
|
+
export default class LibndxAdapterTest extends AbstractPackageTest {
|
|
13
|
+
public static ffiRsDefine = define
|
|
14
|
+
|
|
15
|
+
private static instance: Libndx
|
|
16
|
+
private static libndxPath = this.generateId()
|
|
17
|
+
private static shouldThrowWhenLoadingBindings: boolean
|
|
18
|
+
private static fakeBindings: LibndxBindings
|
|
19
|
+
|
|
20
|
+
private static ffiRsOpenOptions?: OpenParams
|
|
21
|
+
private static ffiRsDefineOptions?: FfiRsDefineOptions
|
|
22
|
+
|
|
23
|
+
private static readonly bleDeviceUuid = this.generateId()
|
|
24
|
+
private static readonly ftdiSerialNumber = this.generateId()
|
|
25
|
+
|
|
26
|
+
protected static async beforeEach() {
|
|
27
|
+
await super.beforeEach()
|
|
28
|
+
|
|
29
|
+
this.shouldThrowWhenLoadingBindings = false
|
|
30
|
+
this.fakeBindings = this.FakeBindings()
|
|
31
|
+
this.clearAndFakeFfi()
|
|
32
|
+
|
|
33
|
+
this.resetInstance()
|
|
34
|
+
this.instance = this.LibndxAdapter()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@test()
|
|
38
|
+
protected static async createsInstance() {
|
|
39
|
+
assert.isTruthy(this.instance, 'Failed to create instance!')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@test()
|
|
43
|
+
protected static async throwsWhenBindingsFailToLoad() {
|
|
44
|
+
this.resetInstance()
|
|
45
|
+
this.shouldThrowWhenLoadingBindings = true
|
|
46
|
+
|
|
47
|
+
const err = assert.doesThrow(() => this.LibndxAdapter())
|
|
48
|
+
const actual = (err.message ?? err.stack).replace(/\s+/g, '')
|
|
49
|
+
|
|
50
|
+
assert.isEqual(
|
|
51
|
+
actual,
|
|
52
|
+
this.failedToLoadError,
|
|
53
|
+
'Did not receive the expected error!'
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@test()
|
|
58
|
+
protected static async callsFfiRsOpenWithRequiredOptions() {
|
|
59
|
+
assert.isEqualDeep(this.ffiRsOpenOptions, {
|
|
60
|
+
library: 'ndx',
|
|
61
|
+
path: this.libndxPath,
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@test()
|
|
66
|
+
protected static async callsFfiRsDefineWithRequiredOptions() {
|
|
67
|
+
assert.isEqualDeep(
|
|
68
|
+
this.ffiRsDefineOptions,
|
|
69
|
+
{
|
|
70
|
+
create_ble_backend: {
|
|
71
|
+
library: 'ndx',
|
|
72
|
+
retType: DataType.String,
|
|
73
|
+
paramsType: [DataType.String],
|
|
74
|
+
},
|
|
75
|
+
start_ble_backend: {
|
|
76
|
+
library: 'ndx',
|
|
77
|
+
retType: DataType.String,
|
|
78
|
+
paramsType: [DataType.String],
|
|
79
|
+
},
|
|
80
|
+
stop_ble_backend: {
|
|
81
|
+
library: 'ndx',
|
|
82
|
+
retType: DataType.String,
|
|
83
|
+
paramsType: [DataType.String],
|
|
84
|
+
},
|
|
85
|
+
destroy_ble_backend: {
|
|
86
|
+
library: 'ndx',
|
|
87
|
+
retType: DataType.String,
|
|
88
|
+
paramsType: [DataType.String],
|
|
89
|
+
},
|
|
90
|
+
create_ftdi_backend: {
|
|
91
|
+
library: 'ndx',
|
|
92
|
+
retType: DataType.String,
|
|
93
|
+
paramsType: [DataType.String],
|
|
94
|
+
},
|
|
95
|
+
start_ftdi_backend: {
|
|
96
|
+
library: 'ndx',
|
|
97
|
+
retType: DataType.String,
|
|
98
|
+
paramsType: [DataType.String],
|
|
99
|
+
},
|
|
100
|
+
stop_ftdi_backend: {
|
|
101
|
+
library: 'ndx',
|
|
102
|
+
retType: DataType.String,
|
|
103
|
+
paramsType: [DataType.String],
|
|
104
|
+
},
|
|
105
|
+
destroy_ftdi_backend: {
|
|
106
|
+
library: 'ndx',
|
|
107
|
+
retType: DataType.String,
|
|
108
|
+
paramsType: [DataType.String],
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
'Did not pass valid options to ffiRsDefine!'
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@test()
|
|
116
|
+
protected static async getInstanceReturnsASingleton() {
|
|
117
|
+
assert.isEqual(LibndxAdapter.getInstance(), LibndxAdapter.getInstance())
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@test()
|
|
121
|
+
protected static canSetInstance() {
|
|
122
|
+
const fake = new FakeLibndx()
|
|
123
|
+
LibndxAdapter.setInstance(fake)
|
|
124
|
+
assert.isEqual(LibndxAdapter.getInstance(), fake)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@test()
|
|
128
|
+
protected static async createBleBackendCallsBindingAndReturnsJsonString() {
|
|
129
|
+
const raw = this.instance.createBleBackend({
|
|
130
|
+
deviceUuid: this.bleDeviceUuid,
|
|
131
|
+
})
|
|
132
|
+
const json = JSON.parse(raw)
|
|
133
|
+
|
|
134
|
+
assert.isTruthy(json, 'createBleBackend did not return a JSON string!')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@test()
|
|
138
|
+
protected static async startBleBackendCallsBindingAndReturnsJsonString() {
|
|
139
|
+
const raw = this.instance.startBleBackend({
|
|
140
|
+
deviceUuid: this.bleDeviceUuid,
|
|
141
|
+
})
|
|
142
|
+
const json = JSON.parse(raw)
|
|
143
|
+
|
|
144
|
+
assert.isTruthy(json, 'startBleBackend did not return a JSON string!')
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@test()
|
|
148
|
+
protected static async stopBleBackendCallsBindingAndReturnsJsonString() {
|
|
149
|
+
const raw = this.instance.stopBleBackend({
|
|
150
|
+
deviceUuid: this.bleDeviceUuid,
|
|
151
|
+
})
|
|
152
|
+
const json = JSON.parse(raw)
|
|
153
|
+
|
|
154
|
+
assert.isTruthy(json, 'stopBleBackend did not return a JSON string!')
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@test()
|
|
158
|
+
protected static async destroyBleBackendCallsBindingAndReturnsJsonString() {
|
|
159
|
+
const raw = this.instance.destroyBleBackend({
|
|
160
|
+
deviceUuid: this.bleDeviceUuid,
|
|
161
|
+
})
|
|
162
|
+
const json = JSON.parse(raw)
|
|
163
|
+
|
|
164
|
+
assert.isTruthy(json, 'destroyBleBackend did not return a JSON string!')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@test()
|
|
168
|
+
protected static async createFtdiBackendCallsBindingAndReturnsJsonString() {
|
|
169
|
+
const raw = this.instance.createFtdiBackend({
|
|
170
|
+
serialNumber: this.ftdiSerialNumber,
|
|
171
|
+
})
|
|
172
|
+
const json = JSON.parse(raw)
|
|
173
|
+
|
|
174
|
+
assert.isTruthy(json, 'createFtdiBackend did not return a JSON string!')
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@test()
|
|
178
|
+
protected static async startFtdiBackendCallsBindingAndReturnsJsonString() {
|
|
179
|
+
const raw = this.instance.startFtdiBackend({
|
|
180
|
+
serialNumber: this.ftdiSerialNumber,
|
|
181
|
+
})
|
|
182
|
+
const json = JSON.parse(raw)
|
|
183
|
+
|
|
184
|
+
assert.isTruthy(json, 'startFtdiBackend did not return a JSON string!')
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@test()
|
|
188
|
+
protected static async stopFtdiBackendCallsBindingAndReturnsJsonString() {
|
|
189
|
+
const raw = this.instance.stopFtdiBackend({
|
|
190
|
+
serialNumber: this.ftdiSerialNumber,
|
|
191
|
+
})
|
|
192
|
+
const json = JSON.parse(raw)
|
|
193
|
+
|
|
194
|
+
assert.isTruthy(json, 'stopFtdiBackend did not return a JSON string!')
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
@test()
|
|
198
|
+
protected static async destroyFtdiBackendCallsBindingAndReturnsJsonString() {
|
|
199
|
+
const raw = this.instance.destroyFtdiBackend({
|
|
200
|
+
serialNumber: this.ftdiSerialNumber,
|
|
201
|
+
})
|
|
202
|
+
const json = JSON.parse(raw)
|
|
203
|
+
|
|
204
|
+
assert.isTruthy(
|
|
205
|
+
json,
|
|
206
|
+
'destroyFtdiBackend did not return a JSON string!'
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private static clearAndFakeFfi() {
|
|
211
|
+
delete this.ffiRsOpenOptions
|
|
212
|
+
delete this.ffiRsDefineOptions
|
|
213
|
+
this.fakeFfiRsOpen()
|
|
214
|
+
this.fakeFfiRsDefine()
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private static fakeFfiRsOpen() {
|
|
218
|
+
LibndxAdapter.ffiRsOpen = (options) => {
|
|
219
|
+
this.ffiRsOpenOptions = options
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private static fakeFfiRsDefine() {
|
|
224
|
+
LibndxAdapter.ffiRsDefine = ((options) => {
|
|
225
|
+
this.ffiRsDefineOptions = options
|
|
226
|
+
|
|
227
|
+
if (this.shouldThrowWhenLoadingBindings) {
|
|
228
|
+
throw new Error(this.fakeErrorMessage)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return this.fakeBindings as any
|
|
232
|
+
}) as typeof define
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private static get failedToLoadError() {
|
|
236
|
+
return `
|
|
237
|
+
\n -----------------------------------
|
|
238
|
+
\n Failed to load libndx! Tried to load from:
|
|
239
|
+
\n ${this.libndxPath}
|
|
240
|
+
\n Instructions to save your day (on MacOS):
|
|
241
|
+
\n 1. git clone https://github.com/neurodevs/libndx.git
|
|
242
|
+
\n 2. cd libndx && cmake -S . -B build && cmake --build build
|
|
243
|
+
\n 3. sudo cp build/libndx.dylib /opt/local/lib/
|
|
244
|
+
\n 4. Try whatever you were doing again!
|
|
245
|
+
\n Modify step 3 for your OS if you are not on MacOS.
|
|
246
|
+
\n If you're still unsure, ask an LLM with this error and your OS.
|
|
247
|
+
\n You could also post an issue on the repo:
|
|
248
|
+
\n https://github.com/neurodevs/ndx-native/issues
|
|
249
|
+
\n Good luck!
|
|
250
|
+
\n @ericthecurious
|
|
251
|
+
\n -----------------------------------
|
|
252
|
+
\n Original error: ${this.fakeErrorMessage}
|
|
253
|
+
\n
|
|
254
|
+
`.replace(/\s+/g, '')
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private static FakeBindings(): LibndxBindings {
|
|
258
|
+
return {
|
|
259
|
+
create_ble_backend: () => JSON.stringify({}),
|
|
260
|
+
start_ble_backend: () => JSON.stringify({}),
|
|
261
|
+
stop_ble_backend: () => JSON.stringify({}),
|
|
262
|
+
destroy_ble_backend: () => JSON.stringify({}),
|
|
263
|
+
create_ftdi_backend: () => JSON.stringify({}),
|
|
264
|
+
start_ftdi_backend: () => JSON.stringify({}),
|
|
265
|
+
stop_ftdi_backend: () => JSON.stringify({}),
|
|
266
|
+
destroy_ftdi_backend: () => JSON.stringify({}),
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private static resetInstance() {
|
|
271
|
+
LibndxAdapter.resetInstance()
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private static LibndxAdapter() {
|
|
275
|
+
return LibndxAdapter.getInstance({
|
|
276
|
+
libndxPath: this.libndxPath,
|
|
277
|
+
})
|
|
278
|
+
}
|
|
279
|
+
}
|
|
@@ -7,10 +7,10 @@ import { test, assert } from '@neurodevs/node-tdd'
|
|
|
7
7
|
import { DataType, OpenParams } from 'ffi-rs'
|
|
8
8
|
|
|
9
9
|
import LibxdfAdapter, {
|
|
10
|
-
FfiRsDefineOptions,
|
|
11
10
|
LibxdfBindings,
|
|
12
11
|
XdfFile,
|
|
13
12
|
} from '../../impl/LibxdfAdapter.js'
|
|
13
|
+
import { FfiRsDefineOptions } from 'types.js'
|
|
14
14
|
import SpyLibxdf from '../../testDoubles/Libxdf/SpyLibxdf.js'
|
|
15
15
|
import AbstractPackageTest from '../AbstractPackageTest.js'
|
|
16
16
|
|
|
@@ -44,8 +44,8 @@ export default class LibxdfTest extends AbstractPackageTest {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
@test()
|
|
47
|
-
protected static
|
|
48
|
-
assert.isTruthy(this.instance, '
|
|
47
|
+
protected static createsInstance() {
|
|
48
|
+
assert.isTruthy(this.instance, 'Failed to create instance!')
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
@test()
|
|
@@ -90,7 +90,7 @@ export default class LibxdfTest extends AbstractPackageTest {
|
|
|
90
90
|
paramsType: [DataType.String],
|
|
91
91
|
},
|
|
92
92
|
},
|
|
93
|
-
'
|
|
93
|
+
'Did not pass valid options to ffiRsDefine!'
|
|
94
94
|
)
|
|
95
95
|
}
|
|
96
96
|
|
|
@@ -101,7 +101,7 @@ export default class LibxdfTest extends AbstractPackageTest {
|
|
|
101
101
|
assert.isEqualDeep(
|
|
102
102
|
this.loadXdfCalls[0],
|
|
103
103
|
[this.path],
|
|
104
|
-
'
|
|
104
|
+
'Did not call load_xdf_to_json(path)!'
|
|
105
105
|
)
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -241,7 +241,6 @@ export default class LibxdfTest extends AbstractPackageTest {
|
|
|
241
241
|
private static readonly fakeNominalSampleRate = 0
|
|
242
242
|
private static readonly fakeEventName = generateId()
|
|
243
243
|
private static readonly fakeEventTimestamp = 0
|
|
244
|
-
private static readonly fakeErrorMessage = 'Fake error message!'
|
|
245
244
|
|
|
246
245
|
private static fakeSerializedXdf = `{"streams": [{"stream_id": ${this.fakeStreamId}, "time_series": [], "time_stamps": [], "stream_info": {"channel_count": ${this.fakeChannelCount}, "channel_format": "${this.fakeChannelFormat}", "nominal_srate": ${this.fakeNominalSampleRate}, "stream_name": "${this.fakeStreamName}", "stream_type": "${this.fakeStreamType}"}}], "events": [{"stream_id": ${this.fakeStreamId}, "event_name": "${this.fakeEventName}", "event_timestamp": ${this.fakeEventTimestamp}}]}`
|
|
247
246
|
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from 'ffi-rs'
|
|
10
10
|
|
|
11
11
|
import { CHANNEL_FORMATS } from '../consts.js'
|
|
12
|
-
import { LslErrorCode } from '../lib/
|
|
12
|
+
import { LslErrorCode } from '../lib/handleLslError.js'
|
|
13
13
|
|
|
14
14
|
export default class LiblslAdapter implements Liblsl {
|
|
15
15
|
public static open = open
|
|
@@ -29,20 +29,6 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
29
29
|
this.tryToLoadBindings()
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
private tryToLoadBindings() {
|
|
33
|
-
try {
|
|
34
|
-
this.loadBindings()
|
|
35
|
-
} catch (error) {
|
|
36
|
-
this.throwFailedToLoadLiblsl(error as Error)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private throwFailedToLoadLiblsl(error: Error) {
|
|
41
|
-
throw new Error(
|
|
42
|
-
`Loading the liblsl dylib failed! I tried to load it from ${this.liblslPath}.\n\n${error.message}\n\n`
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
32
|
public static getInstance() {
|
|
47
33
|
if (!this.instance) {
|
|
48
34
|
this.setInstance(new this())
|
|
@@ -58,9 +44,13 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
58
44
|
delete this.instance
|
|
59
45
|
}
|
|
60
46
|
|
|
61
|
-
private
|
|
62
|
-
|
|
63
|
-
|
|
47
|
+
private tryToLoadBindings() {
|
|
48
|
+
try {
|
|
49
|
+
this.openLiblsl()
|
|
50
|
+
this.defineBindings()
|
|
51
|
+
} catch (error) {
|
|
52
|
+
this.throwFailedToLoadLiblsl(error as Error)
|
|
53
|
+
}
|
|
64
54
|
}
|
|
65
55
|
|
|
66
56
|
private openLiblsl() {
|
|
@@ -70,8 +60,113 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
70
60
|
})
|
|
71
61
|
}
|
|
72
62
|
|
|
73
|
-
private
|
|
74
|
-
|
|
63
|
+
private defineBindings() {
|
|
64
|
+
this.bindings = this.define({
|
|
65
|
+
lsl_local_clock: {
|
|
66
|
+
library: 'lsl',
|
|
67
|
+
retType: DataType.Double,
|
|
68
|
+
paramsType: [],
|
|
69
|
+
},
|
|
70
|
+
lsl_create_streaminfo: {
|
|
71
|
+
library: 'lsl',
|
|
72
|
+
retType: DataType.External,
|
|
73
|
+
paramsType: [
|
|
74
|
+
DataType.String,
|
|
75
|
+
DataType.String,
|
|
76
|
+
DataType.I32,
|
|
77
|
+
DataType.Double,
|
|
78
|
+
DataType.I32,
|
|
79
|
+
DataType.String,
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
lsl_destroy_streaminfo: {
|
|
83
|
+
library: 'lsl',
|
|
84
|
+
retType: DataType.Void,
|
|
85
|
+
paramsType: [DataType.External],
|
|
86
|
+
},
|
|
87
|
+
lsl_create_outlet: {
|
|
88
|
+
library: 'lsl',
|
|
89
|
+
retType: DataType.External,
|
|
90
|
+
paramsType: [DataType.External, DataType.I32, DataType.I32],
|
|
91
|
+
},
|
|
92
|
+
lsl_push_sample_ft: {
|
|
93
|
+
library: 'lsl',
|
|
94
|
+
retType: DataType.I32,
|
|
95
|
+
paramsType: [
|
|
96
|
+
DataType.External,
|
|
97
|
+
DataType.FloatArray,
|
|
98
|
+
DataType.Double,
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
lsl_push_sample_strt: {
|
|
102
|
+
library: 'lsl',
|
|
103
|
+
retType: DataType.I32,
|
|
104
|
+
paramsType: [
|
|
105
|
+
DataType.External,
|
|
106
|
+
DataType.StringArray,
|
|
107
|
+
DataType.Double,
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
lsl_destroy_outlet: {
|
|
111
|
+
library: 'lsl',
|
|
112
|
+
retType: DataType.Void,
|
|
113
|
+
paramsType: [DataType.External],
|
|
114
|
+
},
|
|
115
|
+
lsl_create_inlet: {
|
|
116
|
+
library: 'lsl',
|
|
117
|
+
retType: DataType.External,
|
|
118
|
+
paramsType: [
|
|
119
|
+
DataType.External,
|
|
120
|
+
DataType.I32,
|
|
121
|
+
DataType.I32,
|
|
122
|
+
DataType.I32,
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
lsl_inlet_flush: {
|
|
126
|
+
library: 'lsl',
|
|
127
|
+
retType: DataType.I32,
|
|
128
|
+
paramsType: [DataType.External],
|
|
129
|
+
},
|
|
130
|
+
lsl_destroy_inlet: {
|
|
131
|
+
library: 'lsl',
|
|
132
|
+
retType: DataType.Void,
|
|
133
|
+
paramsType: [DataType.External],
|
|
134
|
+
},
|
|
135
|
+
lsl_get_desc: {
|
|
136
|
+
library: 'lsl',
|
|
137
|
+
retType: DataType.External,
|
|
138
|
+
paramsType: [DataType.External],
|
|
139
|
+
},
|
|
140
|
+
lsl_get_channel_count: {
|
|
141
|
+
library: 'lsl',
|
|
142
|
+
retType: DataType.I32,
|
|
143
|
+
paramsType: [DataType.External],
|
|
144
|
+
},
|
|
145
|
+
lsl_append_child: {
|
|
146
|
+
library: 'lsl',
|
|
147
|
+
retType: DataType.External,
|
|
148
|
+
paramsType: [DataType.External, DataType.String],
|
|
149
|
+
},
|
|
150
|
+
lsl_append_child_value: {
|
|
151
|
+
library: 'lsl',
|
|
152
|
+
retType: DataType.External,
|
|
153
|
+
paramsType: [
|
|
154
|
+
DataType.External,
|
|
155
|
+
DataType.String,
|
|
156
|
+
DataType.String,
|
|
157
|
+
],
|
|
158
|
+
},
|
|
159
|
+
}) as LiblslBindings
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private throwFailedToLoadLiblsl(error: Error) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Loading the liblsl dylib failed! I tried to load it from ${this.liblslPath}.\n\n${error.message}\n\n`
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public localClock() {
|
|
169
|
+
return this.bindings.lsl_local_clock([])
|
|
75
170
|
}
|
|
76
171
|
|
|
77
172
|
public createStreamInfo(options: CreateStreamInfoOptions) {
|
|
@@ -119,7 +214,7 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
119
214
|
this.bindings.lsl_destroy_streaminfo([infoHandle])
|
|
120
215
|
}
|
|
121
216
|
|
|
122
|
-
public
|
|
217
|
+
public resolveByProp(options: ResolveByPropOptions) {
|
|
123
218
|
const { prop, value, minResults = 1, timeoutMs = 1000 } = options
|
|
124
219
|
|
|
125
220
|
const maxResults = 1024
|
|
@@ -134,7 +229,7 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
134
229
|
})
|
|
135
230
|
)[0]
|
|
136
231
|
|
|
137
|
-
const numResults =
|
|
232
|
+
const numResults = this.load({
|
|
138
233
|
library: 'lsl',
|
|
139
234
|
funcName: 'lsl_resolve_byprop',
|
|
140
235
|
retType: DataType.I32,
|
|
@@ -154,7 +249,6 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
154
249
|
minResults,
|
|
155
250
|
timeoutMs / 1000,
|
|
156
251
|
],
|
|
157
|
-
runInNewThread: true,
|
|
158
252
|
})
|
|
159
253
|
|
|
160
254
|
const handles: InfoHandle[] = []
|
|
@@ -233,16 +327,15 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
233
327
|
return this.bindings.lsl_get_channel_count([infoHandle])
|
|
234
328
|
}
|
|
235
329
|
|
|
236
|
-
public
|
|
330
|
+
public openStream(options: OpenStreamOptions) {
|
|
237
331
|
const { inletHandle, timeoutMs, errorCodePtr } = options
|
|
238
332
|
|
|
239
|
-
|
|
333
|
+
this.load({
|
|
240
334
|
library: 'lsl',
|
|
241
335
|
funcName: 'lsl_open_stream',
|
|
242
336
|
retType: DataType.Void,
|
|
243
337
|
paramsType: [DataType.External, DataType.Double, DataType.External],
|
|
244
338
|
paramsValue: [inletHandle, timeoutMs / 1000, errorCodePtr],
|
|
245
|
-
runInNewThread: true,
|
|
246
339
|
})
|
|
247
340
|
}
|
|
248
341
|
|
|
@@ -334,10 +427,6 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
334
427
|
this.bindings.lsl_destroy_inlet([inletHandle])
|
|
335
428
|
}
|
|
336
429
|
|
|
337
|
-
public localClock() {
|
|
338
|
-
return this.bindings.lsl_local_clock([])
|
|
339
|
-
}
|
|
340
|
-
|
|
341
430
|
private get open() {
|
|
342
431
|
return LiblslAdapter.open
|
|
343
432
|
}
|
|
@@ -353,116 +442,19 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
353
442
|
private get alloc() {
|
|
354
443
|
return LiblslAdapter.alloc
|
|
355
444
|
}
|
|
356
|
-
|
|
357
|
-
private get liblslFuncs() {
|
|
358
|
-
return {
|
|
359
|
-
lsl_create_streaminfo: {
|
|
360
|
-
library: 'lsl',
|
|
361
|
-
retType: DataType.External,
|
|
362
|
-
paramsType: [
|
|
363
|
-
DataType.String,
|
|
364
|
-
DataType.String,
|
|
365
|
-
DataType.I32,
|
|
366
|
-
DataType.Double,
|
|
367
|
-
DataType.I32,
|
|
368
|
-
DataType.String,
|
|
369
|
-
],
|
|
370
|
-
},
|
|
371
|
-
lsl_destroy_streaminfo: {
|
|
372
|
-
library: 'lsl',
|
|
373
|
-
retType: DataType.Void,
|
|
374
|
-
paramsType: [DataType.External],
|
|
375
|
-
},
|
|
376
|
-
lsl_create_outlet: {
|
|
377
|
-
library: 'lsl',
|
|
378
|
-
retType: DataType.External,
|
|
379
|
-
paramsType: [DataType.External, DataType.I32, DataType.I32],
|
|
380
|
-
},
|
|
381
|
-
lsl_push_sample_ft: {
|
|
382
|
-
library: 'lsl',
|
|
383
|
-
retType: DataType.I32,
|
|
384
|
-
paramsType: [
|
|
385
|
-
DataType.External,
|
|
386
|
-
DataType.FloatArray,
|
|
387
|
-
DataType.Double,
|
|
388
|
-
],
|
|
389
|
-
},
|
|
390
|
-
lsl_push_sample_strt: {
|
|
391
|
-
library: 'lsl',
|
|
392
|
-
retType: DataType.I32,
|
|
393
|
-
paramsType: [
|
|
394
|
-
DataType.External,
|
|
395
|
-
DataType.StringArray,
|
|
396
|
-
DataType.Double,
|
|
397
|
-
],
|
|
398
|
-
},
|
|
399
|
-
lsl_destroy_outlet: {
|
|
400
|
-
library: 'lsl',
|
|
401
|
-
retType: DataType.Void,
|
|
402
|
-
paramsType: [DataType.External],
|
|
403
|
-
},
|
|
404
|
-
lsl_create_inlet: {
|
|
405
|
-
library: 'lsl',
|
|
406
|
-
retType: DataType.External,
|
|
407
|
-
paramsType: [
|
|
408
|
-
DataType.External,
|
|
409
|
-
DataType.I32,
|
|
410
|
-
DataType.I32,
|
|
411
|
-
DataType.I32,
|
|
412
|
-
],
|
|
413
|
-
},
|
|
414
|
-
lsl_inlet_flush: {
|
|
415
|
-
library: 'lsl',
|
|
416
|
-
retType: DataType.I32,
|
|
417
|
-
paramsType: [DataType.External],
|
|
418
|
-
},
|
|
419
|
-
lsl_destroy_inlet: {
|
|
420
|
-
library: 'lsl',
|
|
421
|
-
retType: DataType.Void,
|
|
422
|
-
paramsType: [DataType.External],
|
|
423
|
-
},
|
|
424
|
-
lsl_get_desc: {
|
|
425
|
-
library: 'lsl',
|
|
426
|
-
retType: DataType.External,
|
|
427
|
-
paramsType: [DataType.External],
|
|
428
|
-
},
|
|
429
|
-
lsl_get_channel_count: {
|
|
430
|
-
library: 'lsl',
|
|
431
|
-
retType: DataType.I32,
|
|
432
|
-
paramsType: [DataType.External],
|
|
433
|
-
},
|
|
434
|
-
lsl_append_child: {
|
|
435
|
-
library: 'lsl',
|
|
436
|
-
retType: DataType.External,
|
|
437
|
-
paramsType: [DataType.External, DataType.String],
|
|
438
|
-
},
|
|
439
|
-
lsl_append_child_value: {
|
|
440
|
-
library: 'lsl',
|
|
441
|
-
retType: DataType.External,
|
|
442
|
-
paramsType: [
|
|
443
|
-
DataType.External,
|
|
444
|
-
DataType.String,
|
|
445
|
-
DataType.String,
|
|
446
|
-
],
|
|
447
|
-
},
|
|
448
|
-
lsl_local_clock: {
|
|
449
|
-
library: 'lsl',
|
|
450
|
-
retType: DataType.Double,
|
|
451
|
-
paramsType: [],
|
|
452
|
-
},
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
445
|
}
|
|
456
446
|
|
|
457
447
|
export interface Liblsl {
|
|
458
448
|
liblslPath: string
|
|
459
449
|
|
|
450
|
+
localClock(): number
|
|
451
|
+
|
|
460
452
|
createStreamInfo(options: CreateStreamInfoOptions): InfoHandle
|
|
461
453
|
destroyStreamInfo(options: DestroyStreamInfoOptions): void
|
|
462
454
|
appendChannelsToStreamInfo(options: AppendChannelsToStreamInfoOptions): void
|
|
463
455
|
getChannelCount(options: GetChannelCountOptions): number
|
|
464
456
|
|
|
465
|
-
resolveByProp(options: ResolveByPropOptions):
|
|
457
|
+
resolveByProp(options: ResolveByPropOptions): InfoHandle[]
|
|
466
458
|
|
|
467
459
|
createOutlet(options: CreateOutletOptions): OutletHandle
|
|
468
460
|
|
|
@@ -477,14 +469,12 @@ export interface Liblsl {
|
|
|
477
469
|
destroyOutlet(options: DestroyOutletOptions): void
|
|
478
470
|
|
|
479
471
|
createInlet(options: CreateInletOptions): InletHandle
|
|
480
|
-
openStream(options: OpenStreamOptions):
|
|
472
|
+
openStream(options: OpenStreamOptions): void
|
|
481
473
|
closeStream(options: CloseStreamOptions): void
|
|
482
474
|
pullSample(options: PullSampleOptions): number
|
|
483
475
|
pullChunk(options: PullChunkOptions): number
|
|
484
476
|
flushInlet(options: FlushInletOptions): void
|
|
485
477
|
destroyInlet(options: DestroyInletOptions): void
|
|
486
|
-
|
|
487
|
-
localClock(): number
|
|
488
478
|
}
|
|
489
479
|
|
|
490
480
|
export interface CreateStreamInfoOptions {
|
|
@@ -577,6 +567,8 @@ export interface DestroyInletOptions {
|
|
|
577
567
|
}
|
|
578
568
|
|
|
579
569
|
export interface LiblslBindings {
|
|
570
|
+
lsl_local_clock(args: []): number
|
|
571
|
+
|
|
580
572
|
lsl_create_streaminfo(
|
|
581
573
|
args: [string, string, number, number, number, string]
|
|
582
574
|
): InfoHandle
|
|
@@ -595,8 +587,6 @@ export interface LiblslBindings {
|
|
|
595
587
|
lsl_create_inlet(args: any): InletHandle
|
|
596
588
|
lsl_inlet_flush(args: [InletHandle]): void
|
|
597
589
|
lsl_destroy_inlet(args: any): void
|
|
598
|
-
|
|
599
|
-
lsl_local_clock(args: []): number
|
|
600
590
|
}
|
|
601
591
|
|
|
602
592
|
export type ChannelFormat = (typeof CHANNEL_FORMATS)[number]
|