|
1 | 1 | """Specification/abstract parent for BLE2LSL device files.
|
2 | 2 |
|
3 | 3 | To support a new BLE device, create a new module in `ble2lsl.devices` and
|
4 |
| -include a `PARAMS` dictionary containing: |
5 |
| - manufacturer (str): The name of the device's manufacturer. |
6 |
| - name (str): The name of the device. |
| 4 | +include the following module-level attributes: |
| 5 | +
|
| 6 | + NAME (str): The device's name. |
7 | 7 | Used for automatically finding the device address, so should be some
|
8 | 8 | substring of the name found by `pygatt`'s '`adapter.scan`.
|
9 |
| -
|
10 |
| - streams (dict): Contains stream-specific non-BLE parameters. Each member |
11 |
| - should be a dictionary with the names of the potential stream |
12 |
| - subscriptions as keys for the stream's respective value(s) of the |
13 |
| - parameter. |
14 |
| -
|
15 |
| - type (dict[str]): The type of data to be streamed. Should be an `XDF`_ |
16 |
| - format string when available. |
17 |
| - channel_count (dict[int]): The number of channels in the stream. |
18 |
| - nominal_srate (dict[float]): The stream's design sample rate (Hz). |
19 |
| - Used to generate regular timestamps for incoming samples. |
20 |
| - channel_format (dict[str]): The LSL datatype of the stream's data. |
21 |
| - LSL streams are of a single datatype, so one string should be given |
22 |
| - for each stream. |
23 |
| - numpy_dtype (dict[str or numpy.dtype]): The NumPy datatype of the data. |
24 |
| - This will not always be identical to `channel_format`; for example, |
25 |
| - `'string'` is the string type in LSL but not in NumPy. |
26 |
| - units (dict[Iterable[str]]): The units for each channel in the stream. |
27 |
| - ch_names (dict[Iterable[str]]): The name of each channel in the stream. |
28 |
| - chunk_size (dict[int]): No. of samples pushed at once through LSL. |
29 |
| -
|
30 |
| - ble (dict): Contains BLE-specific parameters. |
31 |
| - address_type (BLEAddressType): One of `BLEAddressType.public` or |
32 |
| - `BLEAddressType.random`, depending on the device. |
33 |
| - interval_min (int): Minimum BLE connection interval. |
34 |
| - interval_max (int): Maximum BLE connection interval. |
35 |
| - Connection intervals are multiples of 1.25 ms. |
36 |
| - send (str): UUID for the send/control characteristic. |
37 |
| - Control commands (e.g. to start streaming) are written to this |
38 |
| - characteristic. |
39 |
| - stream_on: Command to write to start streaming. |
40 |
| - stream_off: Command to write to end streaming. |
41 |
| - disconnect (str, optional): UUID for the disconnect characteristic. |
| 9 | + MANUFACTURER (str): The name of the device's manufacturer. |
| 10 | + STREAMS (List[str]): Names of data sources provided by the device. |
| 11 | + PARAMS (dict): Device-specific parameters, containing two dictionaries: |
| 12 | + streams (dict): Contains general per-stream parameters. Each member |
| 13 | + should be a dictionary with the names of the potential stream |
| 14 | + subscriptions as keys for the stream's respective value(s) of the |
| 15 | + parameter. (See `muse2016` module for an example of how to do this |
| 16 | + without being very messy.) |
| 17 | +
|
| 18 | + type (dict[str]): The type of data to be streamed. Should be an |
| 19 | + `XDF` format string when possible. |
| 20 | + channel_count (dict[int]): The number of channels in the stream. |
| 21 | + nominal_srate (dict[float]): The stream's design sample rate (Hz). |
| 22 | + Used to generate dejittered timestamps for incoming samples. |
| 23 | + channel_format (dict[str]): The LSL datatype of the stream's data. |
| 24 | + LSL streams are of a single datatype, so one string should be |
| 25 | + given for each stream. |
| 26 | + numpy_dtype (dict[str or numpy.dtype]): The Numpy datatype for |
| 27 | + stream data. |
| 28 | + This will not always be identical to `channel_format`; for |
| 29 | + example, `'string'` is the string type in LSL but not in Numpy. |
| 30 | + units (dict[Iterable[str]]): Units for each channel in the stream. |
| 31 | + ch_names (dict[Iterable[str]]): Name of each channel in the stream. |
| 32 | + chunk_size (dict[int]): No. of samples pushed at once through LSL. |
| 33 | +
|
| 34 | + ble (dict): Contains BLE-specific device parameters. Must contain |
| 35 | + keys for each of the streams named in `STREAMS`, with values of |
| 36 | + one or more characteristic UUIDs that `ble2lsl` must subscribe |
| 37 | + to when providing that stream. Some of these may be redundant or |
| 38 | + empty strings, as long as the device's `PacketHandler` separates |
| 39 | + incoming packets' data into respective streams (for example, |
| 40 | + see `ganglion`). |
| 41 | +
|
| 42 | + address_type (BLEAddressType): One of `BLEAddressType.public` or |
| 43 | + `BLEAddressType.random`, depending on the device. |
| 44 | + interval_min (int): Minimum BLE connection interval. |
| 45 | + interval_max (int): Maximum BLE connection interval. |
| 46 | + Connection intervals are multiples of 1.25 ms. A good choice of |
| 47 | + `interval_min` and `interval_max` may be necessary to prevent |
| 48 | + dropped packets. |
| 49 | + send (str): UUID for the send/control characteristic. |
| 50 | + Control commands (e.g. to start streaming) are written to this |
| 51 | + characteristic. |
| 52 | + stream_on: Command to write to start streaming. |
| 53 | + stream_off: Command to write to end streaming. |
42 | 54 |
|
43 | 55 |
|
44 | 56 | As devices typically do not share a common format for the packets sent over
|
45 | 57 | BLE, include a subclass of `PacketHandler` in the device file. This subclass
|
46 | 58 | should provide a `process_packet` method, to which BLE2LSL will pass incoming
|
47 | 59 | packets and the handles of the BLE characteristics from which they were
|
48 |
| -received. This method should perform any necessary processing (delegating to |
49 |
| -other methods in the device file if necessary) and pass the stream name, array |
50 |
| -of sample IDs, and array of chunk data to the callback function passed to |
51 |
| -`PacketHandler` during its instantiation by `ble2lsl.Streamer`. |
52 |
| -
|
53 |
| -To provide an LSL stream for a data stream provided by the device, the |
54 |
| -following should be implemented: |
55 |
| - * A name for the LSL stream/data source with corresponding entries in |
56 |
| - each member of `PARAMS["streams"]`, and an entry with the same name |
| 60 | +received. This method should perform any necessary processing on the packets, |
| 61 | +delegating to other methods in the device file if necessary. After filling the |
| 62 | +`_chunks` and `_chunk_idxs` attributes for a given stream, the chunk may be |
| 63 | +enqueued for processing by `ble2lsl` by passing the stream name to |
| 64 | +`_enqueue_chunk()`. |
| 65 | +
|
| 66 | +Summary of necessary inclusions to support a data source provided by a device: |
| 67 | + * A name for the stream in `STREAMS`. |
| 68 | + * Corresponding entries in each member of `PARAMS["streams"]`, and an entry |
57 | 69 | in `PARAMS["ble"]` containing one or more UUIDs for characteristics
|
58 |
| - that constitute a BLE subscription to the data source. A list of the |
59 |
| - available stream names must be provided in the `STREAMS` attribute. |
| 70 | + that constitute a BLE subscription to the data source. |
60 | 71 | * A means for `process_packet` to map an incoming packet to the appropriate
|
61 |
| - stream name, typically using its handle; by passing this name to the |
62 |
| - callback this ensures a chunk is pushed to the appropriate LSL stream by |
63 |
| - `ble2lsl.Streamer`. |
| 72 | + stream name, typically using its handle; by passing this name with the |
| 73 | + enqueued chunk, this ensures it is pushed to the appropriate LSL stream |
| 74 | + by `ble2lsl.Streamer`. |
64 | 75 | * Methods to process the contents of the packets and render them into
|
65 | 76 | appropriately-sized chunks as specified by the `channel_count` and
|
66 | 77 | `chunk_size` members of `PARAMS["streams"]`, and to return the chunks
|
|
69 | 80 |
|
70 | 81 | See `ble2lsl.devices.muse2016` for an example device implementation.
|
71 | 82 |
|
72 |
| -When a user instantiates `ble2lsl.Streamer`, they may provide a list of stream |
73 |
| -names to which to subscribe, which should be some subset of the `STREAMS` |
74 |
| -attribute of the respective device file. |
| 83 | +When a user instantiates `ble2lsl.Streamer`, they may provide a list |
| 84 | +`DEFAULT_SUBSCRIPTIONS` of stream names to which to subscribe, which should be |
| 85 | +some subset of the `STREAMS` attribute of the respective device file. |
75 | 86 |
|
76 | 87 | .. _XDF:
|
77 | 88 | https://github.com/sccn/xdf/wiki/Specifications
|
|
0 commit comments