Skip to content

Commit

Permalink
orn recording and timescale backward compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
salman2135 committed Apr 22, 2024
1 parent 6e89a71 commit ea8aadd
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 21 deletions.
21 changes: 15 additions & 6 deletions src/explorepy/packet.py
Expand Up @@ -13,7 +13,7 @@

logger = logging.getLogger(__name__)

TIMESTAMP_SCALE = 100000



class PACKET_ID(IntEnum):
Expand Down Expand Up @@ -58,7 +58,7 @@ def __init__(self, timestamp, payload, time_offset=0):
time_offset (double): Time offset defined by parser. It will be the timestamp of the first packet when
streaming in realtime. It will be zero while converting a binary file.
"""
self.timestamp = timestamp / TIMESTAMP_SCALE + time_offset
self.timestamp = timestamp + time_offset
self._convert(payload[:-4])
self._check_fletcher(payload[-4:])

Expand Down Expand Up @@ -126,7 +126,15 @@ def _convert(self, bin_data):
n_chan = -1
data = data.reshape((self.n_packet, n_chan)).astype(float).T
gain = EXG_UNIT * ((2 ** 23) - 1) * 6.0
self.data = np.round(data * self.v_ref / gain, 2)

if isinstance(self, EEG_BLE):
self.data = np.round(data * self.v_ref / gain, 2)
return
# legacy code for devices other than BLE
self.data = np.round(data[1:, :] * self.v_ref / gain, 2)
# EEG32: status bits will change in future releases as we need to use 4 bytes for 32 channel status
self.status = self.int32_to_status(data[0, :])


@staticmethod
def int32_to_status(data):
Expand Down Expand Up @@ -178,8 +186,7 @@ def get_ptp(self):
return np.ptp(self.data, axis=1)

def __str__(self):
return "EEG: " + str(self.data[:, -1]) + "\tEEG STATUS: ADS: " +\
str(self.status['ads'][-1]) + ", SR: " + str(self.status['sr'][-1])
return "EEG: " + str(self.data[:, -1])


class EEG94(EEG):
Expand All @@ -202,8 +209,10 @@ class EEG98_USBC(EEG):
def __init__(self, timestamp, payload, time_offset=0):
super().__init__(timestamp, payload, time_offset, v_ref=2.4, n_packet=16)

class EEG_BLE(EEG):
pass

class EEG98_BLE(EEG):
class EEG98_BLE(EEG_BLE):
"""EEG packet for 8 channel device"""

def __init__(self, timestamp, payload, time_offset=0):
Expand Down
15 changes: 8 additions & 7 deletions src/explorepy/parser.py
Expand Up @@ -10,19 +10,18 @@
from explorepy._exceptions import FletcherError
from explorepy.packet import (
PACKET_CLASS_DICT,
TIMESTAMP_SCALE,
DeviceInfo,
PacketBIN
)
from explorepy.settings_manager import SettingsManager
from explorepy.tools import get_local_time

from explorepy.tools import get_local_time, is_ble_device, TIMESTAMP_SCALE_BLE, TIMESTAMP_SCALE

logger = logging.getLogger(__name__)


class Parser:
"""Data parser class"""

def __init__(self, callback, mode='device', debug=True):
"""
Args:
Expand Down Expand Up @@ -55,7 +54,7 @@ def start_streaming(self, device_name, mac_address):
if explorepy.get_bt_interface() == 'sdk':
from explorepy.btcpp import SDKBtClient
self.stream_interface = SDKBtClient(device_name=device_name, mac_address=mac_address)
elif explorepy.get_bt_interface() == 'ble':
elif is_ble_device():
from explorepy.btcpp import BLEClient
self.stream_interface = BLEClient(device_name=device_name, mac_address=mac_address)
elif explorepy.get_bt_interface() == 'mock':
Expand Down Expand Up @@ -142,7 +141,7 @@ def _stream_loop(self):
logger.warning('The binary file is corrupted. Conversion has ended incompletely.')
self.stop_streaming()
except FletcherError:
if explorepy.get_bt_interface() == 'ble':
if is_ble_device():
logger.warning('Incomplete packet received, parsing will continue.')
self.seek_new_pid.set()
else:
Expand Down Expand Up @@ -179,11 +178,12 @@ def _generate_packet(self):
payload = struct.unpack('<H', raw_payload)[0]
if payload > 500:
raise FletcherError
timestamp = struct.unpack('<I', raw_timestamp)[0]

timestamp = struct.unpack('<I', raw_timestamp)[0]
timestamp /= TIMESTAMP_SCALE_BLE if is_ble_device() else TIMESTAMP_SCALE
# Timestamp conversion
if self._time_offset is None:
self._time_offset = get_local_time() - timestamp / TIMESTAMP_SCALE
self._time_offset = get_local_time() - timestamp
timestamp = 0

payload_data = self.stream_interface.read(payload - 4)
Expand Down Expand Up @@ -218,6 +218,7 @@ def _parse_packet(self, pid, timestamp, bin_data):

class FileHandler:
"""Binary file handler"""

def __init__(self, filename):
"""
Args:
Expand Down
8 changes: 5 additions & 3 deletions src/explorepy/stream_processor.py
Expand Up @@ -36,7 +36,7 @@
from explorepy.tools import (
ImpedanceMeasurement,
PhysicalOrientation,
get_local_time
get_local_time, TIMESTAMP_SCALE_BLE, is_ble_device, TIMESTAMP_SCALE
)


Expand Down Expand Up @@ -324,8 +324,10 @@ def set_ext_marker(self, marker_string, time_lsl=None):
"""Set an external marker in the stream"""
logger.info(f"Setting a software marker with code: {marker_string}")
if time_lsl is None:
marker = ExternalMarker.create(lsl_time=self._get_sw_marker_time(), marker_string=marker_string)
self.process(marker)
time_lsl = self._get_sw_marker_time()
time_lsl /= TIMESTAMP_SCALE_BLE if is_ble_device() else TIMESTAMP_SCALE
ext_marker = ExternalMarker.create(marker_string=marker_string, lsl_time=time_lsl)
self.process(ext_marker)

def compare_device_info(self, new_device_info):
"""Compare a device info dict with the current version
Expand Down
18 changes: 13 additions & 5 deletions src/explorepy/tools.py
Expand Up @@ -33,14 +33,17 @@
from explorepy.filters import ExGFilter
from explorepy.packet import (
EEG,
BleImpedancePacket
BleImpedancePacket, Orientation
)
from explorepy.settings_manager import SettingsManager


logger = logging.getLogger(__name__)
lock = Lock()

TIMESTAMP_SCALE_BLE = 100000
TIMESTAMP_SCALE = 10000

MAX_CHANNELS = 32
EXG_CHANNELS = [f"ch{i}" for i in range(1, MAX_CHANNELS + 1)]
EXG_UNITS = ['uV' for ch in EXG_CHANNELS]
Expand All @@ -58,6 +61,8 @@ def get_local_time():
"""
return local_clock()

def is_ble_device():
return explorepy.get_bt_interface() == 'ble'

def bt_scan():
""" Scan for nearby Explore devices
Expand Down Expand Up @@ -513,10 +518,13 @@ def write_data(self, packet):
"""
time_vector, sig = packet.get_data(self._fs)

if self._rec_time_offset is None:
self._rec_time_offset = time_vector[0]
data = np.concatenate((np.array(time_vector)[:, np.newaxis].T, np.array(sig)), axis=0)
if isinstance(packet, Orientation):
if len(time_vector) == 1:
data = np.array(time_vector + sig)[:, np.newaxis]
else:
if self._rec_time_offset is None:
self._rec_time_offset = time_vector[0]
data = np.concatenate((np.array(time_vector)[:, np.newaxis].T, np.array(sig)), axis=0)
data = np.round(data, 4)
if self.file_type == 'edf':
if isinstance(packet, EEG):
Expand Down

0 comments on commit ea8aadd

Please sign in to comment.