Skip to content

Commit

Permalink
extend output array with new types of data (#633)
Browse files Browse the repository at this point in the history
* update the format to add new sensors

Signed-off-by: Andrey Parfenov <a1994ndrey@gmail.com>
  • Loading branch information
Andrey1994 committed May 30, 2023
1 parent b7e4dca commit 4870729
Show file tree
Hide file tree
Showing 19 changed files with 1,915 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ public enum BoardIds
EXPLORE_4_CHAN_BOARD = 44,
EXPLORE_8_CHAN_BOARD = 45,
GANGLION_NATIVE_BOARD = 46,
EMOTIBIT_BOARD = 47
EMOTIBIT_BOARD = 47,
GALEA_BOARD_V4 = 48,
GALEA_SERIAL_BOARD_V4 = 49
};


Expand Down
103 changes: 103 additions & 0 deletions emulator/brainflow_emulator/galea_manual_v4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import enum
import logging
import random
import socket
import struct
import time


class State(enum.Enum):
wait = 'wait'
stream = 'stream'


class Message(enum.Enum):
start_stream = b'b'
stop_stream = b's'
ack_values = (b'd', b'~6', b'~5', b'o', b'F0')
ack_from_device = b'A'
time_calc_command = b'F4444444'


class GaleaEmulator(object):

def __init__(self):
self.local_ip = '127.0.0.1'
self.local_port = 2390
self.server_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
self.server_socket.settimeout(
0.1) # decreases sampling rate significantly because it will wait for recv 0.1 sec but it's just a test
self.server_socket.bind((self.local_ip, self.local_port))
self.state = State.wait.value
self.addr = None
self.package_num = 0
self.transaction_size = 12
self.package_size = 114

def run(self):
start_time = time.time()
while True:
try:
msg, self.addr = self.server_socket.recvfrom(128)
if msg == Message.start_stream.value:
self.state = State.stream.value
elif msg == Message.stop_stream.value:
self.state = State.wait.value
elif msg in Message.ack_values.value or msg.decode('utf-8').startswith('x'):
self.server_socket.sendto(Message.ack_from_device.value, self.addr)
elif msg == Message.time_calc_command.value:
cur_time = time.time()
resp = bytearray(struct.pack('d', (cur_time - start_time) * 1000))
self.server_socket.sendto(resp, self.addr)
else:
if msg:
# we dont handle board config characters because they dont change package format
logging.warn('received unexpected string %s', str(msg))
except socket.timeout:
logging.debug('timeout for recv')

if self.state == State.stream.value:
transaction = list()
for _ in range(self.transaction_size):
single_package = list()
for i in range(self.package_size):
single_package.append(random.randint(0, 255))
single_package[0] = self.package_num

cur_time = time.time()
timestamp = bytearray(struct.pack('d', (cur_time - start_time) * 1000))
eda = bytearray(struct.pack('f', random.random()))
ppg_red = bytearray(struct.pack('i', int(random.random() * 5000)))
ppg_ir = bytearray(struct.pack('i', int(random.random() * 5000)))

for i in range(88, 96):
single_package[i] = timestamp[i - 88]
for i in range(1, 5):
single_package[i] = eda[i - 1]
for i in range(84, 88):
single_package[i] = ppg_ir[i - 84]
for i in range(80, 84):
single_package[i] = ppg_red[i - 80]
single_package[77] = random.randint(0, 100)

self.package_num = self.package_num + 1
if self.package_num % 256 == 0:
self.package_num = 0
transaction.append(single_package)
try:
package = list()
for i in range(self.transaction_size):
package.extend(bytes(transaction[i]))
self.server_socket.sendto(bytes(package), self.addr)
except socket.timeout:
logging.info('timeout for send')


def main():
emulator = GaleaEmulator()
emulator.run()


if __name__ == '__main__':
logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s', level=logging.INFO)
main()
150 changes: 150 additions & 0 deletions emulator/brainflow_emulator/galea_serial_manual_v4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import logging
import os
import random
import struct
import subprocess
import threading
import time

import pkg_resources
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 = 'COM16'
s_name = 'COM17'

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(m_name, s_name):
master = Serial('\\\\.\\%s' % m_name, timeout=0)
listen_thread = Listener(master, write, read)
listen_thread.start()
listen_thread.join()
master.close()
return stdout, stderr


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

def run(self):
start_time = time.time()
while True:
res = self.read(self.port, 9)
if len(res) < 1:
time.sleep(1)
continue
logging.info('read "%s"' % res)
if 'F444' in res.decode('utf-8'):
cur_time = time.time()
resp = bytearray(struct.pack('d', (cur_time - start_time) * 1000))
self.write(self.port, resp)
logging.info('sent resp to calc time command')
elif 'b' in res.decode('utf-8'):
self.writer_process = GaleaWriter(self.port, 0.005, self.write)
self.writer_process.daemon = True
self.writer_process.start()
elif 's' in res.decode('utf-8'):
if self.writer_process is not None:
if self.writer_process.is_alive():
self.writer_process.need_data = False
self.writer_process.join()
else:
# we dont handle commands to turn on/off channels, gain signal and so on. such commands dont change package format
logging.info('got command "%s"' % res)


class GaleaWriter(threading.Thread):

def __init__(self, port, delay, write):
threading.Thread.__init__(self)
self.port = port
self.write = write
self.delay = delay
self.package_size = 114 * 12
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)
for i in range(self.package_size):
package.append(random.randint(0, 255))
package.append(0xC0)
logging.debug('package is %s' % ' '.join([str(x) for x in package]))
self.write(self.port, bytes(package))

self.package_num = self.package_num + 1
time.sleep(self.delay)


def main():
m_name, s_name = get_ports_windows()
test_serial(m_name, s_name)


if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
main()

0 comments on commit 4870729

Please sign in to comment.