Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 389e3af

Browse files
authoredMar 10, 2025··
Adding BioListener boards support (#759)
* initial version of BioListener communication over tcp
1 parent 2ed99c6 commit 389e3af

File tree

18 files changed

+957
-22
lines changed

18 files changed

+957
-22
lines changed
 

‎.github/workflows/run_unix.yml

+2
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ jobs:
251251
run: sudo -H python3 $GITHUB_WORKSPACE/emulator/brainflow_emulator/streaming_board_emulator.py python3 $GITHUB_WORKSPACE/python_package/examples/tests/brainflow_get_data.py --board-id -2 --ip-address 225.1.1.1 --ip-port 6677 --master-board -1
252252
- name: Streaming Python Markers
253253
run: sudo -H python3 $GITHUB_WORKSPACE/emulator/brainflow_emulator/streaming_board_emulator.py python3 $GITHUB_WORKSPACE/python_package/examples/tests/markers.py --board-id -2 --ip-address 225.1.1.1 --ip-port 6677 --master-board -1
254+
- name: BioListener Python
255+
run: sudo -H python3 $GITHUB_WORKSPACE/emulator/brainflow_emulator/biolistener_emulator.py python3 $GITHUB_WORKSPACE/python_package/examples/tests/brainflow_get_data.py --board-id 64 --ip-address 127.0.0.1 --ip-port 12345
254256
- name: Denoising Python
255257
run: sudo -H python3 $GITHUB_WORKSPACE/python_package/examples/tests/denoising.py
256258
- name: Serialization Python

‎.github/workflows/run_windows.yml

+3
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ jobs:
186186
- name: KnightBoard Windows Python Test
187187
run: python %GITHUB_WORKSPACE%\emulator\brainflow_emulator\knightboard_windows.py python %GITHUB_WORKSPACE%\python_package\examples\tests\brainflow_get_data.py --board-id 57 --serial-port
188188
shell: cmd
189+
- name: BioListener Windows Python Test
190+
run: python %GITHUB_WORKSPACE%\emulator\brainflow_emulator\biolistener_emulator.py python %GITHUB_WORKSPACE%\python_package\examples\tests\brainflow_get_data.py --board-id 64 --ip-address 127.0.0.1 --ip-port 12345
191+
shell: cmd
189192
# Signal Processing Testing
190193
- name: Serialization Rust Test
191194
run: |

‎csharp_package/brainflow/brainflow/board_controller_library.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ public enum BoardIds
122122
OB5000_8_CHANNELS_BOARD = 60,
123123
SYNCHRONI_PENTO_8_CHANNELS_BOARD = 61,
124124
SYNCHRONI_UNO_1_CHANNELS_BOARD = 62,
125-
125+
OB3000_24_CHANNELS_BOARD = 63,
126+
BIOLISTENER_BOARD = 64,
126127
};
127128

128129

‎docs/SupportedBoards.rst

+44
Original file line numberDiff line numberDiff line change
@@ -1347,3 +1347,47 @@ Supported platforms:
13471347
- Linux
13481348
- MacOS
13491349
- Devices like Raspberry Pi
1350+
1351+
1352+
BioListener
1353+
--------
1354+
1355+
BioListener
1356+
~~~~~~~~~~~~~
1357+
1358+
.. image:: https://live.staticflickr.com/65535/54273076343_6a7eb99697_k.jpg
1359+
:width: 519px
1360+
:height: 389px
1361+
1362+
`BioListener website <https://github.com/serhii-matsyshyn/biolistener/>`_
1363+
1364+
To create such board you need to specify the following board ID and fields of BrainFlowInputParams object:
1365+
1366+
- :code:`BoardIds.BIOLISTENER_BOARD`
1367+
- *optional:* :code:`ip_address`, ip address of the machine running the BrainFlow server (not the end device). If not provided, the server will listen on all network interfaces (at `0.0.0.0`)
1368+
- *optional:* :code:`ip_port`, any free local port. If the chosen port is in use, the next available free port will be used. If not provided, the search for a free port starts at `12345`
1369+
- *optional:* :code:`timeout`, timeout for device discovery, default is 3sec
1370+
1371+
Make sure to configure the BioListener board as stated in the `BioListener documentation <https://github.com/serhii-matsyshyn/biolistener/>`_ to connect to the BrainFlow server.
1372+
1373+
Initialization Example:
1374+
1375+
.. code-block:: python
1376+
1377+
params = BrainFlowInputParams()
1378+
params.ip_port = 12345
1379+
params.ip_address = "0.0.0.0"
1380+
board = BoardShim(BoardIds.BIOLISTENER_BOARD, params)
1381+
1382+
Supported platforms:
1383+
1384+
- Windows
1385+
- Linux
1386+
- MacOS
1387+
- Devices like Raspberry Pi
1388+
- Android
1389+
1390+
Available :ref:`presets-label`:
1391+
1392+
- :code:`BrainFlowPresets.DEFAULT_PRESET`, it contains EEG (EMG, ECG, EOG) data
1393+
- :code:`BrainFlowPresets.AUXILIARY_PRESET`, it contains Gyro, Accel, battery and ESP32 chip temperature data
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import datetime
2+
import enum
3+
import json
4+
import logging
5+
import random
6+
import socket
7+
import struct
8+
import subprocess
9+
import sys
10+
import threading
11+
import time
12+
13+
from brainflow_emulator.emulate_common import TestFailureError, log_multilines
14+
15+
BIOLISTENER_DATA_CHANNELS_COUNT = 8
16+
17+
BIOLISTENER_DATA_PACKET_DEBUG = 0
18+
BIOLISTENER_DATA_PACKET_BIOSIGNALS = 1
19+
BIOLISTENER_DATA_PACKET_IMU = 2
20+
21+
ADC_USED = 0 # ADS131M08
22+
23+
24+
class DataPacket:
25+
FORMAT_STRING = f'=1B 1I 1B 1I 1B {BIOLISTENER_DATA_CHANNELS_COUNT}I 1B'
26+
27+
def __init__(self, ts, tp, n, s_id, data):
28+
self.header = 0xA0
29+
self.ts = ts
30+
self.type = tp
31+
self.n = n
32+
self.s_id = s_id
33+
self.data = data
34+
self.footer = 0xC0
35+
36+
def pack(self):
37+
return struct.pack(self.FORMAT_STRING, self.header, self.ts, self.type, self.n, self.s_id, *self.data, self.footer)
38+
39+
@classmethod
40+
def unpack(cls, packed_data):
41+
format_string = cls.FORMAT_STRING
42+
unpacked_data = struct.unpack(format_string, packed_data)
43+
return cls(*unpacked_data)
44+
45+
def __repr__(self):
46+
return (f'DataPacket(header={self.header}, ts={self.ts}, type={self.type}, '
47+
f'n={self.n}, s_id={self.s_id}, data={self.data}, footer={self.footer})')
48+
49+
50+
class State(enum.Enum):
51+
wait = 'wait'
52+
stream = 'stream'
53+
54+
55+
def test_socket(cmd_list):
56+
logging.info('Running %s' % ' '.join([str(x) for x in cmd_list]))
57+
process = subprocess.Popen(cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
58+
stdout, stderr = process.communicate()
59+
60+
log_multilines(logging.info, stdout)
61+
log_multilines(logging.info, stderr)
62+
63+
if process.returncode != 0:
64+
raise TestFailureError('Test failed with exit code %s' % str(process.returncode), process.returncode)
65+
66+
return stdout, stderr
67+
68+
69+
def run_socket_server():
70+
thread = BioListenerEmulator()
71+
thread.start()
72+
return thread
73+
74+
75+
class BioListenerEmulator(threading.Thread):
76+
77+
def __init__(self):
78+
threading.Thread.__init__(self)
79+
self.local_ip = '127.0.0.1'
80+
self.local_port = 12345
81+
self.server_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
82+
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
83+
self.server_socket.settimeout(1)
84+
self.state = State.wait.value
85+
self.package_num = 0
86+
self.keep_alive = True
87+
self.connection_established = False
88+
logging.info(f"BioListener emulator started")
89+
90+
@staticmethod
91+
def volts_to_data(ref, voltage, pga_gain, adc_resolution):
92+
resolution = ref / (adc_resolution * pga_gain)
93+
94+
if voltage >= 0: # Positive range
95+
raw_code = voltage / resolution
96+
else: # Negative range
97+
raw_code = (voltage + (ref / pga_gain)) / resolution
98+
99+
raw_code = int(raw_code)
100+
raw_code = max(0, min(0xFFFFFF, raw_code)) # Ensure within 24 bit range
101+
102+
return raw_code
103+
104+
def run(self):
105+
logging.info(f"BioListener emulator connecting to {self.local_ip}:{self.local_port}...")
106+
while self.keep_alive and not self.connection_established:
107+
try:
108+
self.server_socket.connect((self.local_ip, self.local_port))
109+
self.connection_established = True
110+
break
111+
except Exception as err:
112+
logging.warning(f"Error connecting to {self.local_ip}:{self.local_port}: {err}")
113+
# A failed connect may leave the socket unusable.
114+
try:
115+
self.server_socket.close()
116+
except Exception:
117+
pass
118+
# Recreate the socket with the same options.
119+
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
120+
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
121+
self.server_socket.settimeout(1)
122+
time.sleep(0.1)
123+
124+
if self.connection_established:
125+
logging.info(f"BioListener emulator connected to {self.local_ip}:{self.local_port}")
126+
else:
127+
logging.error(f"BioListener emulator failed to connect to {self.local_ip}:{self.local_port}")
128+
return
129+
130+
started_at = time.time()
131+
while self.keep_alive:
132+
new_data_packet = DataPacket(
133+
ts=int((time.time() - started_at) * 1000),
134+
tp=BIOLISTENER_DATA_PACKET_BIOSIGNALS,
135+
n=self.package_num,
136+
s_id=ADC_USED,
137+
data=[
138+
self.volts_to_data(
139+
ref=2500000.0,
140+
voltage=random.uniform(-1000, 1000),
141+
pga_gain=8,
142+
adc_resolution=16777216.0
143+
) for _ in range(BIOLISTENER_DATA_CHANNELS_COUNT)
144+
]
145+
)
146+
self.package_num += 1
147+
148+
try:
149+
data = self.server_socket.recv(1024)
150+
message = data.decode('utf-8').strip()
151+
152+
if message:
153+
for message_part in message.split("\n"):
154+
logging.info(f"BioListener received command: {message_part}")
155+
json_str = json.loads(message_part)
156+
if json_str["command"] in (1, 2, 3, 4):
157+
logging.info("Command ignored - simulator supports only start and stop stream command")
158+
elif json_str["command"] == 5:
159+
logging.info("Start stream command received")
160+
self.state = State.stream.value
161+
elif json_str["command"] == 6:
162+
logging.info("Stop stream command received")
163+
self.state = State.wait.value
164+
else:
165+
logging.warning(f"Unknown command: {json_str['command']}")
166+
except TimeoutError:
167+
pass
168+
except socket.timeout:
169+
pass
170+
except Exception as err:
171+
logging.error(f"Error in recv thread: {err}")
172+
173+
try:
174+
if self.state == State.stream.value:
175+
self.server_socket.sendall(new_data_packet.pack())
176+
except ConnectionResetError:
177+
logging.error(f"Connection lost")
178+
except Exception as e:
179+
logging.error(f"Error: {e}")
180+
181+
182+
def main(cmd_list):
183+
if not cmd_list:
184+
raise Exception('No command to execute')
185+
server_thread = run_socket_server()
186+
187+
try:
188+
test_socket(cmd_list)
189+
finally:
190+
server_thread.keep_alive = False
191+
server_thread.join()
192+
193+
194+
if __name__ == '__main__':
195+
logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s', level=logging.INFO)
196+
main(sys.argv[1:])

‎java_package/brainflow/src/main/java/brainflow/BoardIds.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,9 @@ public enum BoardIds
7171
SYNCHRONI_OCTO_8_CHANNELS_BOARD(59),
7272
OB5000_8_CHANNELS_BOARD(60),
7373
SYNCHRONI_PENTO_8_CHANNELS_BOARD(61),
74-
SYNCHRONI_UNO_1_CHANNELS_BOARD(62);
75-
74+
SYNCHRONI_UNO_1_CHANNELS_BOARD(62),
75+
OB3000_24_CHANNELS_BOARD(63),
76+
BIOLISTENER_BOARD(64);
7677

7778
private final int board_id;
7879
private static final Map<Integer, BoardIds> bi_map = new HashMap<Integer, BoardIds> ();

‎julia_package/brainflow/src/board_shim.jl

+2-3
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,14 @@ export BrainFlowInputParams
6161
EXPLORE_PLUS_8_CHAN_BOARD = 54
6262
EXPLORE_PLUS_32_CHAN_BOARD = 55
6363
PIEEG_BOARD = 56
64-
6564
NEUROPAWN_KNIGHT_BOARD = 57
6665
SYNCHRONI_TRIO_3_CHANNELS_BOARD = 58
6766
SYNCHRONI_OCTO_8_CHANNELS_BOARD = 59
6867
OB5000_8_CHANNELS_BOARD = 60
6968
SYNCHRONI_PENTO_8_CHANNELS_BOARD = 61
7069
SYNCHRONI_UNO_1_CHANNELS_BOARD = 62
71-
72-
70+
OB3000_24_CHANNELS_BOARD = 63
71+
BIOLISTENER_BOARD = 64
7372

7473
end
7574

‎matlab_package/brainflow/BoardIds.m

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@
5959
EXPLORE_PLUS_8_CHAN_BOARD(54)
6060
EXPLORE_PLUS_32_CHAN_BOARD(55)
6161
PIEEG_BOARD(56)
62-
6362
NEUROPAWN_KNIGHT_BOARD(57)
6463
SYNCHRONI_TRIO_3_CHANNELS_BOARD(58)
6564
SYNCHRONI_OCTO_8_CHANNELS_BOARD(59)
6665
OB5000_8_CHANNELS_BOARD(60)
6766
SYNCHRONI_PENTO_8_CHANNELS_BOARD(61)
6867
SYNCHRONI_UNO_1_CHANNELS_BOARD(62)
69-
68+
OB3000_24_CHANNELS_BOARD(63)
69+
BIOLISTENER_BOARD(64)
7070
end
7171
end

‎nodejs_package/brainflow/brainflow.types.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,16 @@ export enum BoardIds {
6969
EXPLORE_PLUS_8_CHAN_BOARD = 54,
7070
EXPLORE_PLUS_32_CHAN_BOARD = 55,
7171
PIEEG_BOARD = 56,
72-
7372
NEUROPAWN_KNIGHT_BOARD = 57,
7473
SYNCHRONI_TRIO_3_CHANNELS_BOARD = 58,
7574
SYNCHRONI_OCTO_CHANNELS_BOARD = 59,
7675
OB5000_8_CHANNELS_BOARD = 60,
7776
SYNCHRONI_PENTO_8_CHANNELS_BOARD = 61,
78-
SYNCHRONI_UNO_1_CHANNELS_BOARD = 62
79-
77+
SYNCHRONI_UNO_1_CHANNELS_BOARD = 62,
78+
OB3000_24_CHANNELS_BOARD = 63,
79+
BIOLISTENER_BOARD = 64
8080
}
81+
8182
export enum IpProtocolTypes {
8283
NO_IP_PROTOCOL = 0,
8384
UDP = 1,

‎python_package/brainflow/board_shim.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ class BoardIds(enum.IntEnum):
8080
OB5000_8_CHANNELS_BOARD = 60 #:
8181
SYNCHRONI_PENTO_8_CHANNELS_BOARD = 61 #:
8282
SYNCHRONI_UNO_1_CHANNELS_BOARD = 62 #:
83-
83+
OB3000_24_CHANNELS_BOARD = 63 #:
84+
BIOLISTENER_BOARD = 64 #:
8485

8586

8687
class IpProtocolTypes(enum.IntEnum):

‎rust_package/brainflow/src/ffi/constants.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ impl BoardIds {
3232
pub const FIRST: BoardIds = BoardIds::PlaybackFileBoard;
3333
}
3434
impl BoardIds {
35-
pub const LAST: BoardIds = BoardIds::NeuropawnKnightBoard;
35+
pub const LAST: BoardIds = BoardIds::BiolistenerBoard;
3636
}
3737
#[repr(i32)]
3838
#[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone, Hash, PartialEq, Eq)]
@@ -100,7 +100,9 @@ pub enum BoardIds {
100100
SynchroniOcto8ChannelsBoard = 59,
101101
OB50008CHannelsBoard= 60 ,
102102
SynchroniPento8ChannelsBoard = 61,
103-
SynchroniUno1ChannelsBoard = 62
103+
SynchroniUno1ChannelsBoard = 62,
104+
OB300024ChannelsBoard = 63,
105+
BiolistenerBoard = 64
104106
}
105107
#[repr(i32)]
106108
#[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone, Hash, PartialEq, Eq)]

‎src/board_controller/biolistener/biolistener.cpp

+546
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
#include <string>
5+
#include <thread>
6+
7+
#include "board.h"
8+
#include "board_controller.h"
9+
10+
#include "broadcast_server.h"
11+
#include "socket_client_udp.h"
12+
#include "socket_server_tcp.h"
13+
#include "socket_server_udp.h"
14+
15+
16+
#pragma pack(push, 1)
17+
template <size_t BIOLISTENER_DATA_CHANNELS_COUNT>
18+
struct data_packet
19+
{
20+
uint8_t header;
21+
uint32_t ts;
22+
uint8_t type;
23+
uint32_t n;
24+
uint8_t s_id;
25+
uint32_t data[BIOLISTENER_DATA_CHANNELS_COUNT];
26+
uint8_t footer;
27+
};
28+
#pragma pack(pop)
29+
30+
31+
template <size_t BIOLISTENER_DATA_CHANNELS_COUNT>
32+
class BioListener : public Board
33+
{
34+
35+
private:
36+
volatile bool keep_alive;
37+
volatile bool initialized;
38+
39+
std::string ip_address;
40+
std::thread streaming_thread;
41+
SocketServerTCP *control_socket;
42+
std::mutex m;
43+
std::condition_variable cv;
44+
int control_port;
45+
int data_port;
46+
47+
size_t packet_size;
48+
49+
double timestamp_offset;
50+
51+
std::mutex m_channels_gain;
52+
double channels_gain[BIOLISTENER_DATA_CHANNELS_COUNT] {0};
53+
54+
void read_thread ();
55+
56+
int create_control_connection ();
57+
int send_control_msg (const char *msg);
58+
int wait_for_connection ();
59+
60+
static double data_to_volts (
61+
double ref, uint32_t raw_code, double pga_gain, double adc_resolution);
62+
63+
bool parse_tcp_buffer (const char *buffer, size_t buffer_size,
64+
data_packet<BIOLISTENER_DATA_CHANNELS_COUNT> &parsed_packet);
65+
66+
public:
67+
BioListener (int board_id, struct BrainFlowInputParams params);
68+
~BioListener ();
69+
70+
int prepare_session ();
71+
int start_stream (int buffer_size, const char *streamer_params);
72+
int stop_stream ();
73+
int release_session ();
74+
int config_board (std::string config, std::string &response);
75+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
3+
#define PACKET_DELIMITER_CSV '\n'
4+
5+
#define BIOLISTENER_COMMAND_UNDEFINED 0
6+
#define BIOLISTENER_COMMAND_SET_ADC_DATA_RATE 1
7+
#define BIOLISTENER_COMMAND_SET_ADC_CHANNEL_ENABLE 2
8+
#define BIOLISTENER_COMMAND_SET_ADC_CHANNEL_PGA 3
9+
#define BIOLISTENER_COMMAND_RESET_ADC 4
10+
#define BIOLISTENER_COMMAND_START_SAMPLING 5
11+
#define BIOLISTENER_COMMAND_STOP_SAMPLING 6
12+
13+
#define BIOLISTENER_DATA_PACKET_DEBUG 0
14+
#define BIOLISTENER_DATA_PACKET_BIOSIGNALS 1
15+
#define BIOLISTENER_DATA_PACKET_IMU 2
16+
17+
#define BIOLISTENER_DATA_PACKET_HEADER 0xA0
18+
#define BIOLISTENER_DATA_PACKET_FOOTER 0xC0
19+
20+
#define BIOLISTENER_ADC_ADS131M08 0
21+
#define BIOLISTENER_ADC_AD7771 1
22+
23+
#define BIOLISTENER_DEFAULT_PGA_GAIN 8
24+
25+
#define BIOLISTENER_MAX_PORTS_TO_TRY_TILL_FREE_FOUND 200
26+
#define BIOLISTENER_SLEEP_TIME_BETWEEN_SOCKET_TRIES_MS 300
27+
28+
#define FLOAT_TO_UINT32(x) (*((uint32_t *)&(x)))
29+
#define UINT32_TO_FLOAT(x) (*((float *)&(x)))

‎src/board_controller/board_controller.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "aavaa_v3.h"
1818
#include "ant_neuro.h"
19+
#include "biolistener.h"
1920
#include "board.h"
2021
#include "board_controller.h"
2122
#include "board_info_getter.h"
@@ -304,6 +305,9 @@ int prepare_session (int board_id, const char *json_brainflow_input_params)
304305
board =
305306
std::shared_ptr<Board> (new Knight ((int)BoardIds::NEUROPAWN_KNIGHT_BOARD, params));
306307
break;
308+
case BoardIds::BIOLISTENER_BOARD:
309+
board = std::shared_ptr<Board> (new BioListener<8> (board_id, params));
310+
break;
307311
default:
308312
return (int)BrainFlowExitCodes::UNSUPPORTED_BOARD_ERROR;
309313
}

‎src/board_controller/brainflow_boards.cpp

+35-6
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ BrainFlowBoards::BrainFlowBoards()
8080
{"59", json::object()},
8181
{"60", json::object()},
8282
{"61", json::object()},
83-
{"62", json::object()}
84-
83+
{"62", json::object()},
84+
{"63", json::object()},
85+
{"64", json::object()}
8586
}
8687
}};
8788

@@ -1152,7 +1153,7 @@ BrainFlowBoards::BrainFlowBoards()
11521153
{"marker_channel", 10},
11531154
{"num_rows", 11},
11541155
{"eeg_channels", {1, 2, 3, 4, 5, 6, 7}},
1155-
{"ecg_channels", {8}}
1156+
{"ecg_channels", {8}}
11561157
};
11571158
brainflow_boards_json["boards"]["60"]["default"] = {
11581159
{"name", "OB5000MAX"},
@@ -1170,7 +1171,7 @@ BrainFlowBoards::BrainFlowBoards()
11701171
{"timestamp_channel", 9},
11711172
{"marker_channel", 10},
11721173
{"num_rows", 11},
1173-
{"eeg_channels", {1, 2, 3, 4, 5, 6, 7, 8}}
1174+
{"eeg_channels", {1, 2, 3, 4, 5, 6, 7, 8}}
11741175
};
11751176
brainflow_boards_json["boards"]["62"]["default"] = {
11761177
{"name", "Sync-Uno"},
@@ -1179,7 +1180,7 @@ BrainFlowBoards::BrainFlowBoards()
11791180
{"timestamp_channel", 2},
11801181
{"marker_channel", 3},
11811182
{"num_rows", 4},
1182-
{"eeg_channels", {1}}
1183+
{"eeg_channels", {1}}
11831184
};
11841185
brainflow_boards_json["boards"]["63"]["default"] = {
11851186
{"name", "OB3000"},
@@ -1189,7 +1190,35 @@ BrainFlowBoards::BrainFlowBoards()
11891190
{"marker_channel", 26},
11901191
{"num_rows", 27},
11911192
{"eeg_channels", {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}},
1192-
{"ecg_channels", {24}}
1193+
{"ecg_channels", {24}}
1194+
};
1195+
brainflow_boards_json["boards"]["64"]["default"] =
1196+
{
1197+
{"name", "BioListener"},
1198+
{"sampling_rate", 500},
1199+
{"timestamp_channel", 11},
1200+
{"marker_channel", 12},
1201+
{"package_num_channel", 0},
1202+
{"num_rows", 13},
1203+
{"eeg_channels", {1, 2, 3, 4, 5, 6, 7, 8}},
1204+
{"emg_channels", {1, 2, 3, 4, 5, 6, 7, 8}},
1205+
{"ecg_channels", {1, 2, 3, 4, 5, 6, 7, 8}},
1206+
{"eog_channels", {1, 2, 3, 4, 5, 6, 7, 8}},
1207+
{"other_channels", {9, 10}}
1208+
};
1209+
brainflow_boards_json["boards"]["64"]["auxiliary"] =
1210+
{
1211+
{"name", "BioListener"},
1212+
{"sampling_rate", 50},
1213+
{"timestamp_channel", 11},
1214+
{"marker_channel", 12},
1215+
{"package_num_channel", 0},
1216+
{"num_rows", 13},
1217+
{"accel_channels", {1, 2, 3}},
1218+
{"gyro_channels", {4, 5, 6}},
1219+
{"temperature_channels", {7}},
1220+
{"battery_channel", 8},
1221+
{"other_channels", {9, 10}}
11931222
};
11941223
}
11951224

‎src/board_controller/build.cmake

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ SET (BOARD_CONTROLLER_SRC
8787
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/pieeg/pieeg_board.cpp
8888
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/synchroni/synchroni_board.cpp
8989
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/neuropawn/knight.cpp
90+
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/biolistener/biolistener.cpp
9091
)
9192

9293
include (${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/ant_neuro/build.cmake)
@@ -154,6 +155,7 @@ target_include_directories (
154155
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/pieeg/inc
155156
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/synchroni/inc
156157
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/neuropawn/inc
158+
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/biolistener/inc
157159
)
158160

159161
target_compile_definitions(${BOARD_CONTROLLER_NAME} PRIVATE NOMINMAX BRAINFLOW_VERSION=${BRAINFLOW_VERSION})

‎src/utils/inc/brainflow_constants.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,10 @@ enum class BoardIds : int
9595
SYNCHRONI_NEO_8_CHANNELS_BOARD = 61,
9696
SYNCHRONI_UNO_1_CHANNELS_BOARD = 62,
9797
OB3000_24_CHANNELS_BOARD = 63,
98+
BIOLISTENER_BOARD = 64,
9899
// use it to iterate
99100
FIRST = PLAYBACK_FILE_BOARD,
100-
LAST = OB3000_24_CHANNELS_BOARD
101-
101+
LAST = BIOLISTENER_BOARD
102102
};
103103

104104
enum class IpProtocolTypes : int

0 commit comments

Comments
 (0)
Please sign in to comment.