diff --git a/.github/workflows/run_unix.yml b/.github/workflows/run_unix.yml
index 5d50a781d..8458078b1 100644
--- a/.github/workflows/run_unix.yml
+++ b/.github/workflows/run_unix.yml
@@ -234,7 +234,9 @@ jobs:
env:
LD_LIBRARY_PATH: ${{ github.workspace }}/installed/lib
- name: Cyton Daisy Python
- run: sudo -H python3 $GITHUB_WORKSPACE/emulator/brainflow_emulator/cyton_linux.py python3 $GITHUB_WORKSPACE/python_package/examples/tests/brainflow_get_data.py --board-id 2 --serial-port
+ run: sudo -H python3 $GITHUB_WORKSPACE/emulator/brainflow_emulator/cyton_linux.py python3 $GITHUB_WORKSPACE/python_package/examples/tests/brainflow_get_data.py --board-id 2 --serial-port
+ - name: KnightBoard Python
+ run: sudo -H python3 $GITHUB_WORKSPACE/emulator/brainflow_emulator/knightboard_linux.py python3 $GITHUB_WORKSPACE/python_package/examples/tests/brainflow_get_data.py --board-id 57 --serial-port
- name: Cyton Daisy Python Markers
run: sudo -H python3 $GITHUB_WORKSPACE/emulator/brainflow_emulator/cyton_linux.py python3 $GITHUB_WORKSPACE/python_package/examples/tests/markers.py --board-id 2 --serial-port
- name: Galea Cpp
diff --git a/.github/workflows/run_windows.yml b/.github/workflows/run_windows.yml
index 519f1a371..1fa6b4174 100644
--- a/.github/workflows/run_windows.yml
+++ b/.github/workflows/run_windows.yml
@@ -183,6 +183,9 @@ jobs:
- name: FreeEEG32 Python Test
run: python %GITHUB_WORKSPACE%\emulator\brainflow_emulator\freeeeg32_windows.py python %GITHUB_WORKSPACE%\python_package\examples\tests\brainflow_get_data.py --board-id 17 --serial-port
shell: cmd
+ - name: KnightBoard Windows Python Test
+ 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
+ shell: cmd
# Signal Processing Testing
- name: Serialization Rust Test
run: |
diff --git a/csharp_package/brainflow/brainflow/board_controller_library.cs b/csharp_package/brainflow/brainflow/board_controller_library.cs
index ca545b3aa..5e0ce5c14 100644
--- a/csharp_package/brainflow/brainflow/board_controller_library.cs
+++ b/csharp_package/brainflow/brainflow/board_controller_library.cs
@@ -115,7 +115,8 @@ public enum BoardIds
AAVAA_V3_BOARD = 53,
EXPLORE_PLUS_8_CHAN_BOARD = 54,
EXPLORE_PLUS_32_CHAN_BOARD = 55,
- PIEEG_BOARD = 56
+ PIEEG_BOARD = 56,
+ NEUROPAWN_KNIGHT_BOARD = 57
};
diff --git a/docs/SupportedBoards.rst b/docs/SupportedBoards.rst
index 3b92875c1..2942b5dab 100644
--- a/docs/SupportedBoards.rst
+++ b/docs/SupportedBoards.rst
@@ -1305,3 +1305,37 @@ Supported platforms:
**Note**: Ensure that you have the necessary permissions to access the serial port on your operating system. For Unix-like systems, you may need to configure permissions for the serial port or run with sudo.
**To use this board you need to compile BrainFlow from the source code right on your Raspbery Pi device with flag --build-periphery(build.py) or with -DBUILD_PERIPHERY=ON(CMake) and install desired bindings using local libraries.**
+
+NeuroPawn
+--------
+
+Knight Board
+~~~~~~~~~~~~~
+
+.. image:: https://drive.google.com/file/d/192dUfIXKmOqcTIBr7PYJJ8VUdWCuzeIv/view?usp=sharing
+ :width: 400px
+ :height: 225px
+
+Visit us `here `_
+
+To create such board you need to specify the following board ID and fields of BrainFlowInputParams object:
+
+- :code:`BoardIds.NEUROPAWN_KNIGHT_BOARD`
+- :code:`serial_port`, e.g. COM3, /dev/tty.*
+
+Initialization Example:
+
+.. code-block:: python
+
+ params = BrainFlowInputParams()
+ params.serial_port = "COM3"
+ board = BoardShim(BoardIds.NEUROPAWN_KNIGHT_BOARD, params)
+
+**On Unix-like systems you may need to configure permissions for serial port or run with sudo.**
+
+Supported platforms:
+
+- Windows
+- Linux
+- MacOS
+- Devices like Raspberry Pi
\ No newline at end of file
diff --git a/emulator/brainflow_emulator/knightboard_emulator.py b/emulator/brainflow_emulator/knightboard_emulator.py
new file mode 100644
index 000000000..becc6cb07
--- /dev/null
+++ b/emulator/brainflow_emulator/knightboard_emulator.py
@@ -0,0 +1,52 @@
+import logging
+import threading
+import time
+from random import randint
+
+class Listener(threading.Thread):
+
+ def __init__(self, port, write, read):
+ # for windows write and read are methods from Serial object, for linux - os.read/write it doesnt work otherwise
+ threading.Thread.__init__(self)
+ self.port = port
+ self.writer_process = None
+ self.write = write
+ self.read = read
+ self.need_stop = False
+
+ def run(self):
+ self.writer_process = KnightBoardWriter(self.port, 0.005, self.write)
+ self.writer_process.daemon = True
+ self.writer_process.start()
+ time.sleep(10)
+ self.writer_process.need_data = False
+ self.writer_process.join()
+
+
+class KnightBoardWriter(threading.Thread):
+
+ def __init__(self, port, delay, write):
+ threading.Thread.__init__(self)
+ self.port = port
+ self.write = write
+ self.delay = delay
+ self.package_size = 21
+ self.package_num = 0
+ self.need_data = True
+
+ def run(self):
+ while self.need_data:
+ if self.package_num % 256 == 0:
+ self.package_num = 0
+
+ package = list()
+ package.append(0xA0)
+ package.append(self.package_num)
+ for i in range(2, self.package_size - 1):
+ package.append(randint(0, 255))
+ package.append(0xC0)
+ logging.info(bytes(package))
+ self.write(self.port, bytes(package))
+
+ self.package_num = self.package_num + 1
+ time.sleep(self.delay)
diff --git a/emulator/brainflow_emulator/knightboard_linux.py b/emulator/brainflow_emulator/knightboard_linux.py
new file mode 100644
index 000000000..926a271e2
--- /dev/null
+++ b/emulator/brainflow_emulator/knightboard_linux.py
@@ -0,0 +1,53 @@
+import logging
+import os
+import pty
+import subprocess
+import sys
+
+from brainflow_emulator.emulate_common import TestFailureError, log_multilines
+from brainflow_emulator.knightboard_emulator import Listener
+
+
+def write(port, data):
+ return os.write(port, data)
+
+
+def read(port, num_bytes):
+ return os.read(port, num_bytes)
+
+
+def get_ports_pty():
+ master, slave = pty.openpty()
+ s_name = os.ttyname(slave)
+ return master, slave, s_name
+
+
+def test_serial(cmd_list, master, slave, s_name):
+ listen_thread = Listener(master, write, read)
+ listen_thread.daemon = True
+ listen_thread.start()
+
+ cmd_to_run = cmd_list + [s_name]
+ logging.info('Running %s' % ' '.join([str(x) for x in cmd_to_run]))
+ process = subprocess.Popen(cmd_to_run, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+
+ log_multilines(logging.info, stdout)
+ log_multilines(logging.info, stderr)
+
+ if process.returncode != 0:
+ raise TestFailureError('Test failed with exit code %s' % str(process.returncode), process.returncode)
+
+ return stdout, stderr
+
+
+def main(cmd_list):
+ if not cmd_list:
+ raise Exception('No command to execute')
+ master, slave, s_name = get_ports_pty()
+ test_serial(cmd_list, master, slave, s_name)
+
+
+if __name__ == '__main__':
+ logging.basicConfig(level=logging.INFO)
+ main(sys.argv[1:])
diff --git a/emulator/brainflow_emulator/knightboard_windows.py b/emulator/brainflow_emulator/knightboard_windows.py
new file mode 100644
index 000000000..c63cdceb4
--- /dev/null
+++ b/emulator/brainflow_emulator/knightboard_windows.py
@@ -0,0 +1,100 @@
+import logging
+import os
+import subprocess
+import sys
+import time
+
+import pkg_resources
+from brainflow_emulator.emulate_common import TestFailureError, log_multilines
+from brainflow_emulator.knightboard_emulator import Listener
+from serial import Serial
+
+
+def write(port, data):
+ return port.write(data)
+
+
+def read(port, num_bytes):
+ return port.read(num_bytes)
+
+
+def get_isntaller():
+ return pkg_resources.resource_filename(__name__, os.path.join('com0com', 'setup_com0com_W7_x64_signed.exe'))
+
+
+def install_com0com():
+ this_directory = os.path.abspath(os.path.dirname(__file__))
+ directory = os.path.join(this_directory, 'com0com')
+ if not os.path.exists(directory):
+ os.makedirs(directory)
+ cmds = [get_isntaller(), '/NCRC', '/S', '/D=%s' % directory]
+ logging.info('running %s' % ' '.join(cmds))
+ p = subprocess.Popen(cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = p.communicate()
+ if p.returncode != 0:
+ logging.error('stdout is %s' % out)
+ logging.error('stderr is %s' % err)
+ raise Exception('com0com installation failure')
+ logging.info('Sleeping a few second, it doesnt work in appveyour without it')
+ time.sleep(10)
+ return directory
+
+
+def get_ports_windows():
+ directory = install_com0com()
+ # remove ports from previous run if any
+ p = subprocess.Popen([os.path.join(directory, 'setupc.exe'), 'remove', '0'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=directory)
+ stdout, stderr = p.communicate()
+ logging.info('remove stdout is %s' % stdout)
+ logging.info('remove stderr is %s' % stderr)
+
+ m_name = 'COM14'
+ s_name = 'COM15'
+
+ p = subprocess.Popen(
+ [os.path.join(directory, 'setupc.exe'), 'install', 'PortName=%s' % m_name, 'PortName=%s' % s_name],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=directory)
+ stdout, stderr = p.communicate()
+ logging.info('install stdout is %s' % stdout)
+ logging.info('install stderr is %s' % stderr)
+
+ if p.returncode != 0:
+ raise Exception('com0com failure')
+ logging.info('Sleeping a few second, it doesnt work in appveyour without it')
+ time.sleep(10)
+ return m_name, s_name
+
+
+def test_serial(cmd_list, m_name, s_name):
+ master = Serial('\\\\.\\%s' % m_name, timeout=0)
+ listen_thread = Listener(master, write, read)
+ listen_thread.daemon = True
+ listen_thread.start()
+
+ cmd_to_run = cmd_list + [s_name]
+ logging.info('Running %s' % ' '.join([str(x) for x in cmd_to_run]))
+ process = subprocess.Popen(cmd_to_run, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+
+ log_multilines(logging.info, stdout)
+ log_multilines(logging.info, stderr)
+
+ master.close()
+ if process.returncode != 0:
+ raise TestFailureError('Test failed with exit code %s' % str(process.returncode), process.returncode)
+
+ return stdout, stderr
+
+
+def main(cmd_list):
+ if not cmd_list:
+ raise Exception('No command to execute')
+
+ m_name, s_name = get_ports_windows()
+ test_serial(cmd_list, m_name, s_name)
+
+
+if __name__ == '__main__':
+ logging.basicConfig(level=logging.INFO)
+ main(sys.argv[1:])
diff --git a/java_package/brainflow/src/main/java/brainflow/BoardIds.java b/java_package/brainflow/src/main/java/brainflow/BoardIds.java
index 6377c20af..a460d98bc 100644
--- a/java_package/brainflow/src/main/java/brainflow/BoardIds.java
+++ b/java_package/brainflow/src/main/java/brainflow/BoardIds.java
@@ -65,7 +65,8 @@ public enum BoardIds
AAVAA_V3_BOARD(53),
EXPLORE_PLUS_8_CHAN_BOARD(54),
EXPLORE_PLUS_32_CHAN_BOARD(55),
- PIEEG_BOARD(56);
+ PIEEG_BOARD(56),
+ NEUROPAWN_KNIGHT_BOARD(57);
private final int board_id;
private static final Map bi_map = new HashMap ();
diff --git a/julia_package/brainflow/src/board_shim.jl b/julia_package/brainflow/src/board_shim.jl
index c21b94c83..c455c2fbd 100644
--- a/julia_package/brainflow/src/board_shim.jl
+++ b/julia_package/brainflow/src/board_shim.jl
@@ -61,6 +61,7 @@ export BrainFlowInputParams
EXPLORE_PLUS_8_CHAN_BOARD = 54
EXPLORE_PLUS_32_CHAN_BOARD = 55
PIEEG_BOARD = 56
+ NEUROPAWN_KNIGHT_BOARD = 57
end
diff --git a/matlab_package/brainflow/BoardIds.m b/matlab_package/brainflow/BoardIds.m
index ceb601a86..4c4d69a90 100644
--- a/matlab_package/brainflow/BoardIds.m
+++ b/matlab_package/brainflow/BoardIds.m
@@ -59,5 +59,6 @@
EXPLORE_PLUS_8_CHAN_BOARD(54)
EXPLORE_PLUS_32_CHAN_BOARD(55)
PIEEG_BOARD(56)
+ NEUROPAWN_KNIGHT_BOARD(57)
end
end
\ No newline at end of file
diff --git a/nodejs_package/brainflow/brainflow.types.ts b/nodejs_package/brainflow/brainflow.types.ts
index c95ec7d1c..b0730b561 100644
--- a/nodejs_package/brainflow/brainflow.types.ts
+++ b/nodejs_package/brainflow/brainflow.types.ts
@@ -68,7 +68,8 @@ export enum BoardIds {
ANT_NEURO_EE_511_BOARD = 51,
EXPLORE_PLUS_8_CHAN_BOARD = 54,
EXPLORE_PLUS_32_CHAN_BOARD = 55,
- PIEEG_BOARD = 56
+ PIEEG_BOARD = 56,
+ NEUROPAWN_KNIGHT_BOARD = 57
}
export enum IpProtocolTypes {
diff --git a/python_package/brainflow/board_shim.py b/python_package/brainflow/board_shim.py
index ced6ec9d5..0b8f5707b 100644
--- a/python_package/brainflow/board_shim.py
+++ b/python_package/brainflow/board_shim.py
@@ -74,6 +74,7 @@ class BoardIds(enum.IntEnum):
EXPLORE_PLUS_8_CHAN_BOARD = 54 #:
EXPLORE_PLUS_32_CHAN_BOARD = 55 #:
PIEEG_BOARD = 56 #:
+ NEUROPAWN_KNIGHT_BOARD = 57 #:
class IpProtocolTypes(enum.IntEnum):
diff --git a/rust_package/brainflow/src/ffi/constants.rs b/rust_package/brainflow/src/ffi/constants.rs
index 6e8d43c8d..1d295216d 100644
--- a/rust_package/brainflow/src/ffi/constants.rs
+++ b/rust_package/brainflow/src/ffi/constants.rs
@@ -94,6 +94,7 @@ pub enum BoardIds {
AavaaV3Board = 53,
ExplorePlus8ChanBoard = 54,
ExplorePlus32ChanBoard = 55,
+ NeuroPawnKnightBoard = 57
}
#[repr(i32)]
#[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone, Hash, PartialEq, Eq)]
diff --git a/src/board_controller/board_controller.cpp b/src/board_controller/board_controller.cpp
index 623499463..cb55e2e88 100644
--- a/src/board_controller/board_controller.cpp
+++ b/src/board_controller/board_controller.cpp
@@ -45,6 +45,8 @@
#include "ganglion_wifi.h"
#include "gforce_dual.h"
#include "gforce_pro.h"
+#include "json.hpp"
+#include "knight.h"
#include "muse.h"
#include "muse_bled.h"
#include "notion_osc.h"
@@ -55,8 +57,6 @@
#include "synthetic_board.h"
#include "unicorn_board.h"
-#include "json.hpp"
-
using json = nlohmann::json;
@@ -281,6 +281,10 @@ int prepare_session (int board_id, const char *json_brainflow_input_params)
case BoardIds::PIEEG_BOARD:
board = std::shared_ptr (new PIEEGBoard (board_id, params));
break;
+ case BoardIds::NEUROPAWN_KNIGHT_BOARD:
+ board =
+ std::shared_ptr (new Knight ((int)BoardIds::NEUROPAWN_KNIGHT_BOARD, params));
+ break;
default:
return (int)BrainFlowExitCodes::UNSUPPORTED_BOARD_ERROR;
}
diff --git a/src/board_controller/brainflow_boards.cpp b/src/board_controller/brainflow_boards.cpp
index f22ec341c..884e2efb5 100644
--- a/src/board_controller/brainflow_boards.cpp
+++ b/src/board_controller/brainflow_boards.cpp
@@ -74,7 +74,8 @@ BrainFlowBoards::BrainFlowBoards()
{"53", json::object()},
{"54", json::object()},
{"55", json::object()},
- {"56", json::object()}
+ {"56", json::object()},
+ {"57", json::object()}
}
}};
@@ -1095,6 +1096,17 @@ BrainFlowBoards::BrainFlowBoards()
{"eeg_channels", {1, 2, 3, 4, 5, 6, 7, 8}},
{"eeg_names", "Fp1,Fp2,C3,C4,P7,P8,O1,O2"}
};
+ brainflow_boards_json["boards"]["57"]["default"] =
+ {
+ {"name", "Knight"},
+ {"sampling_rate", 125},
+ {"timestamp_channel", 11},
+ {"marker_channel",12},
+ {"package_num_channel", 0},
+ {"num_rows", 13},
+ {"eeg_channels", {1, 2, 3, 4, 5, 6, 7, 8}},
+ {"other_channels", {9, 10}}
+ };
}
BrainFlowBoards boards_struct;
diff --git a/src/board_controller/build.cmake b/src/board_controller/build.cmake
index aeeedbaa7..9cb994390 100644
--- a/src/board_controller/build.cmake
+++ b/src/board_controller/build.cmake
@@ -85,6 +85,7 @@ SET (BOARD_CONTROLLER_SRC
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/ntl/ntl_wifi.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/aavaa/aavaa_v3.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/pieeg/pieeg_board.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/neuropawn/knight.cpp
)
include (${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/ant_neuro/build.cmake)
@@ -142,6 +143,7 @@ target_include_directories (
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/ntl/inc
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/aavaa/inc
${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/pieeg/inc
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/neuropawn/inc
)
target_compile_definitions(${BOARD_CONTROLLER_NAME} PRIVATE NOMINMAX BRAINFLOW_VERSION=${BRAINFLOW_VERSION})
diff --git a/src/board_controller/neuropawn/inc/knight.h b/src/board_controller/neuropawn/inc/knight.h
new file mode 100644
index 000000000..7edd88356
--- /dev/null
+++ b/src/board_controller/neuropawn/inc/knight.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include
+
+#include "board.h"
+#include "board_controller.h"
+#include "serial.h"
+
+class Knight : public Board
+{
+
+protected:
+ volatile bool keep_alive;
+ bool initialized;
+ bool is_streaming;
+ std::thread streaming_thread;
+ Serial *serial;
+
+ int min_package_size;
+
+ virtual int send_to_board (const char *msg);
+ virtual int send_to_board (const char *msg, std::string &response);
+ virtual std::string read_serial_response ();
+ int open_port ();
+ int set_port_settings ();
+ void read_thread ();
+
+public:
+ Knight (int board_id, struct BrainFlowInputParams params);
+ ~Knight ();
+
+ int prepare_session ();
+ int start_stream (int buffer_size, const char *streamer_params);
+ int stop_stream ();
+ int release_session ();
+ int config_board (std::string config, std::string &response);
+
+ static constexpr int start_byte = 0xA0;
+ static constexpr int end_byte = 0xC0;
+};
\ No newline at end of file
diff --git a/src/board_controller/neuropawn/knight.cpp b/src/board_controller/neuropawn/knight.cpp
new file mode 100644
index 000000000..137db4113
--- /dev/null
+++ b/src/board_controller/neuropawn/knight.cpp
@@ -0,0 +1,317 @@
+#include
+#include
+#include
+
+#include "custom_cast.h"
+#include "knight.h"
+#include "serial.h"
+#include "timestamp.h"
+
+constexpr int Knight::start_byte;
+constexpr int Knight::end_byte;
+
+Knight::Knight (int board_id, struct BrainFlowInputParams params) : Board (board_id, params)
+{
+ serial = NULL;
+ is_streaming = false;
+ keep_alive = false;
+ initialized = false;
+}
+
+Knight::~Knight ()
+{
+ skip_logs = true;
+ release_session ();
+}
+
+int Knight::prepare_session ()
+{
+ if (initialized)
+ {
+ safe_logger (spdlog::level::info, "Session already prepared");
+ return (int)BrainFlowExitCodes::STATUS_OK;
+ }
+ if (params.serial_port.empty ())
+ {
+ safe_logger (spdlog::level::err, "serial port is empty");
+ return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
+ }
+ serial = Serial::create (params.serial_port.c_str (), this);
+ int port_open = open_port ();
+ if (port_open != (int)BrainFlowExitCodes::STATUS_OK)
+ {
+ delete serial;
+ serial = NULL;
+ return port_open;
+ }
+
+ int set_settings = set_port_settings ();
+ if (set_settings != (int)BrainFlowExitCodes::STATUS_OK)
+ {
+ delete serial;
+ serial = NULL;
+ return set_settings;
+ }
+
+ initialized = true;
+ return (int)BrainFlowExitCodes::STATUS_OK;
+}
+
+int Knight::start_stream (int buffer_size, const char *streamer_params)
+{
+ if (is_streaming)
+ {
+ safe_logger (spdlog::level::err, "Streaming thread already running");
+ return (int)BrainFlowExitCodes::STREAM_ALREADY_RUN_ERROR;
+ }
+ int res = prepare_for_acquisition (buffer_size, streamer_params);
+ if (res != (int)BrainFlowExitCodes::STATUS_OK)
+ {
+ return res;
+ }
+
+ serial->flush_buffer ();
+
+ keep_alive = true;
+ streaming_thread = std::thread ([this] { this->read_thread (); });
+ is_streaming = true;
+ return (int)BrainFlowExitCodes::STATUS_OK;
+}
+
+int Knight::stop_stream ()
+{
+ if (is_streaming)
+ {
+ keep_alive = false;
+ is_streaming = false;
+ if (streaming_thread.joinable ())
+ {
+ streaming_thread.join ();
+ }
+ return (int)BrainFlowExitCodes::STATUS_OK;
+ }
+ else
+ {
+ return (int)BrainFlowExitCodes::STREAM_THREAD_IS_NOT_RUNNING;
+ }
+}
+
+int Knight::release_session ()
+{
+ if (initialized)
+ {
+ if (is_streaming)
+ {
+ stop_stream ();
+ }
+ free_packages ();
+ initialized = false;
+ }
+ if (serial)
+ {
+ serial->close_serial_port ();
+ delete serial;
+ serial = NULL;
+ }
+ return (int)BrainFlowExitCodes::STATUS_OK;
+}
+
+void Knight::read_thread ()
+{
+ /*
+ [0] 1 Byte: Start byte
+ [1] 2 Byte: Sample Number
+ [2-3] 3-4 Bytes: EXG channel 1
+ [4-5] 5-6 Bytes: Data value for EXG channel 2
+ [6-7] 7-8 Bytes: Data value for EXG channel 3
+ [8-9] 9-10 Bytes: Data value for EXG channel 4
+ [10-11] 11-12 Bytes: Data value for EXG channel 5
+ [12-13] 13-14 Bytes: Data value for EXG channel 6
+ [14-15] 15-16 Bytes: Data value for EXG channel 7
+ [16-17] 17-18 Bytes: Data value for EXG channel 8
+ [18] 19 Byte: Data LOFF STATP
+ [19] 20 Byte: Data LOFF STATN
+ [20] 21 Byte: End byte
+ */
+
+ int res;
+ unsigned char b[20] = {0};
+ float eeg_scale = 4 / float ((pow (2, 23) - 1)) / 12 * 1000000.;
+ int num_rows = board_descr["default"]["num_rows"];
+ double *package = new double[num_rows];
+ for (int i = 0; i < num_rows; i++)
+ {
+ package[i] = 0.0;
+ }
+ bool first_package_received = false;
+
+ std::vector eeg_channels = board_descr["default"]["eeg_channels"];
+ std::vector other_channels = board_descr["default"]["other_channels"];
+
+ while (keep_alive)
+ {
+ // checking the start byte
+ res = serial->read_from_serial_port (b, 1);
+ if (res != 1)
+ {
+ safe_logger (spdlog::level::debug, "unable to read 1 byte, {}");
+ continue;
+ }
+ if (b[0] != Knight::start_byte)
+ {
+ continue;
+ }
+
+ int remaining_bytes = 20;
+ int pos = 0;
+ while ((remaining_bytes > 0) && (keep_alive))
+ {
+ res = serial->read_from_serial_port (b + pos, remaining_bytes);
+ remaining_bytes -= res;
+ pos += res;
+ }
+
+ if (!keep_alive)
+ {
+ break;
+ }
+
+ if (b[19] != Knight::end_byte)
+ {
+ safe_logger (spdlog::level::warn, "Wrong end byte {}", b[19]);
+ continue;
+ }
+
+ // package number CHANGE TO 1 if not working
+ package[board_descr["default"]["package_num_channel"].get ()] = (double)b[0];
+
+ // exg data retrieval
+ for (unsigned int i = 0; i < eeg_channels.size (); i++)
+ {
+ package[eeg_channels[i]] =
+ eeg_scale * cast_16bit_to_int32 (b + 1 + 2 * i); // CHANGE TO 2+2*i if not working
+ }
+
+ // other channel data retrieval
+ package[other_channels[0]] = (double)b[17]; // LOFF STATP
+ package[other_channels[1]] = (double)b[18]; // LOFF STATN
+
+ // time stamp channel
+ package[board_descr["default"]["timestamp_channel"].get ()] = get_timestamp ();
+
+ push_package (package);
+ }
+ delete[] package;
+}
+
+int Knight::open_port ()
+{
+ if (serial->is_port_open ())
+ {
+ safe_logger (spdlog::level::err, "port {} already open", serial->get_port_name ());
+ return (int)BrainFlowExitCodes::PORT_ALREADY_OPEN_ERROR;
+ }
+
+ safe_logger (spdlog::level::info, "openning port {}", serial->get_port_name ());
+ int res = serial->open_serial_port ();
+ if (res < 0)
+ {
+ return (int)BrainFlowExitCodes::UNABLE_TO_OPEN_PORT_ERROR;
+ }
+ safe_logger (spdlog::level::trace, "port {} is open", serial->get_port_name ());
+ return (int)BrainFlowExitCodes::STATUS_OK;
+}
+
+int Knight::set_port_settings ()
+{
+ int res = serial->set_serial_port_settings (1000, false);
+ if (res < 0)
+ {
+ safe_logger (spdlog::level::err, "Unable to set port settings, res is {}", res);
+ return (int)BrainFlowExitCodes::SET_PORT_ERROR;
+ }
+ res = serial->set_custom_baudrate (115200);
+ if (res < 0)
+ {
+ safe_logger (spdlog::level::err, "Unable to set custom baud rate, res is {}", res);
+ return (int)BrainFlowExitCodes::SET_PORT_ERROR;
+ }
+ safe_logger (spdlog::level::trace, "set port settings");
+ return (int)BrainFlowExitCodes::STATUS_OK;
+}
+
+int Knight::config_board (std::string config, std::string &response)
+{
+ if (!initialized)
+ {
+ return (int)BrainFlowExitCodes::BOARD_NOT_READY_ERROR;
+ }
+ int res = (int)BrainFlowExitCodes::STATUS_OK;
+ if (is_streaming)
+ {
+ safe_logger (spdlog::level::warn,
+ "You are changing board params during streaming, it may lead to sync mismatch between "
+ "data acquisition thread and device");
+ res = send_to_board (config.c_str ());
+ }
+ else
+ {
+ // read response if streaming is not running
+ res = send_to_board (config.c_str (), response);
+ }
+
+ return res;
+}
+
+int Knight::send_to_board (const char *msg)
+{
+ int length = (int)strlen (msg);
+ safe_logger (spdlog::level::debug, "sending {} to the board", msg);
+ int res = serial->send_to_serial_port ((const void *)msg, length);
+ if (res != length)
+ {
+ return (int)BrainFlowExitCodes::BOARD_WRITE_ERROR;
+ }
+
+ return (int)BrainFlowExitCodes::STATUS_OK;
+}
+
+int Knight::send_to_board (const char *msg, std::string &response)
+{
+ int length = (int)strlen (msg);
+ safe_logger (spdlog::level::debug, "sending {} to the board", msg);
+ int res = serial->send_to_serial_port ((const void *)msg, length);
+ if (res != length)
+ {
+ response = "";
+ return (int)BrainFlowExitCodes::BOARD_WRITE_ERROR;
+ }
+ response = read_serial_response ();
+
+ return (int)BrainFlowExitCodes::STATUS_OK;
+}
+
+std::string Knight::read_serial_response ()
+{
+ constexpr int max_tmp_size = 4096;
+ unsigned char tmp_array[max_tmp_size];
+ unsigned char tmp;
+ int tmp_id = 0;
+ while (serial->read_from_serial_port (&tmp, 1) == 1)
+ {
+ if (tmp_id < max_tmp_size)
+ {
+ tmp_array[tmp_id] = tmp;
+ tmp_id++;
+ }
+ else
+ {
+ serial->flush_buffer ();
+ break;
+ }
+ }
+ tmp_id = (tmp_id == max_tmp_size) ? tmp_id - 1 : tmp_id;
+ tmp_array[tmp_id] = '\0';
+
+ return std::string ((const char *)tmp_array);
+}
\ No newline at end of file
diff --git a/src/utils/inc/brainflow_constants.h b/src/utils/inc/brainflow_constants.h
index 26034af5b..4dfea5ddf 100644
--- a/src/utils/inc/brainflow_constants.h
+++ b/src/utils/inc/brainflow_constants.h
@@ -88,6 +88,7 @@ enum class BoardIds : int
EXPLORE_PLUS_8_CHAN_BOARD = 54,
EXPLORE_PLUS_32_CHAN_BOARD = 55,
PIEEG_BOARD = 56,
+ NEUROPAWN_KNIGHT_BOARD = 57,
// use it to iterate
FIRST = PLAYBACK_FILE_BOARD,
LAST = PIEEG_BOARD