Skip to content

Commit 4df4ad1

Browse files
committed
Update code for new chords format & add functionality to stop program on 'q' key press.
1 parent 08e749a commit 4df4ad1

File tree

1 file changed

+26
-13
lines changed

1 file changed

+26
-13
lines changed

bioamptool.py

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import numpy as np # For handling numeric arrays
3939
import pyqtgraph as pg # For real-time plotting
4040
from pyqtgraph.Qt import QtWidgets, QtCore # PyQt components for GUI
41+
import msvcrt #for keyboard interruptions
4142

4243
# Initialize global variables for tracking and processing data
4344
total_packet_count = 0 # Total packets received in the last second
@@ -47,16 +48,19 @@
4748
previous_sample_number = None # Store the previous sample number for detecting missing samples
4849
missing_samples = 0 # Count of missing samples due to packet loss
4950
buffer = bytearray() # Buffer for storing incoming raw data from Arduino
50-
PACKET_LENGTH = 17 # Expected length of each data packet
51-
SYNC_BYTE1 = 0xA5 # First byte of sync marker
52-
SYNC_BYTE2 = 0x5A # Second byte of sync marker
51+
PACKET_LENGTH = 16 # Expected length of each data packet
52+
SYNC_BYTE1 = 0xc7 # First byte of sync marker
53+
SYNC_BYTE2 = 0x7c # Second byte of sync marker
5354
END_BYTE = 0x01 # End byte marker
55+
NUM_CHANNELS = 6
56+
HEADER_LENGTH = 3
5457
lsl_outlet = None # Placeholder for LSL stream outlet
5558
verbose = False # Flag for verbose output mode
5659
data = np.zeros((6, 2000)) # 2D array to store data for real-time plotting (6 channels, 2000 data points)
5760
csv_filename = None # Store CSV filename
5861
samples_per_second = 0 # Number of samples received per second
5962

63+
6064
# Function to automatically detect the Arduino's serial port
6165
def auto_detect_arduino(baudrate, timeout=1):
6266
ports = serial.tools.list_ports.comports() # List available serial ports
@@ -81,7 +85,6 @@ def read_arduino_data(ser, csv_writer=None):
8185

8286
raw_data = ser.read(ser.in_waiting or 1) # Read available data from the serial port
8387
buffer.extend(raw_data) # Add received data to the buffer
84-
8588
while len(buffer) >= PACKET_LENGTH: # Continue processing if the buffer contains at least one full packet
8689
sync_index = buffer.find(bytes([SYNC_BYTE1, SYNC_BYTE2])) # Search for the sync marker
8790

@@ -93,7 +96,7 @@ def read_arduino_data(ser, csv_writer=None):
9396
packet = buffer[sync_index:sync_index + PACKET_LENGTH] # Extract the packet
9497
if len(packet) == PACKET_LENGTH and packet[0] == SYNC_BYTE1 and packet[1] == SYNC_BYTE2 and packet[-1] == END_BYTE:
9598
# Extract the packet if it is valid (correct length, sync bytes, and end byte)
96-
counter = packet[3] # Read the counter byte (for tracking sample order)
99+
counter = packet[2] # Read the counter byte (for tracking sample order)
97100

98101
# Check for missing samples by comparing the counter values
99102
if previous_sample_number is not None and counter != (previous_sample_number + 1) % 256:
@@ -107,9 +110,9 @@ def read_arduino_data(ser, csv_writer=None):
107110

108111
# Extract channel data (6 channels, 2 bytes per channel)
109112
channel_data = []
110-
for i in range(4, 16, 2): # Loop through channel data bytes
111-
high_byte = packet[i]
112-
low_byte = packet[i + 1]
113+
for channel in range(NUM_CHANNELS): # Loop through channel data bytes
114+
high_byte = packet[2*channel + HEADER_LENGTH]
115+
low_byte = packet[2*channel + HEADER_LENGTH + 1]
113116
value = (high_byte << 8) | low_byte # Combine high and low bytes
114117
channel_data.append(float(value)) # Convert to float and add to channel data
115118

@@ -249,6 +252,7 @@ def parse_data(port, baudrate, lsl_flag=False, csv_flag=False, gui_flag=False, v
249252
start_timer() # Start timers for logging
250253

251254
try:
255+
ser.write(b'START\n')
252256
while True:
253257
read_arduino_data(ser, csv_writer) # Read and process data from Arduino
254258
current_time = time.time() # Get the current time
@@ -262,13 +266,22 @@ def parse_data(port, baudrate, lsl_flag=False, csv_flag=False, gui_flag=False, v
262266
log_ten_minute_data(verbose) # Log data for the last 10 minutes
263267
if gui_flag:
264268
QtWidgets.QApplication.processEvents() # Process GUI events if GUI is enabled
265-
266-
except KeyboardInterrupt: # Handle interruption (Ctrl+C)
269+
270+
if msvcrt.kbhit() and msvcrt.getch() == b'q': # Exit the loop if 'q' is pressed
271+
ser.write(b'STOP\n')
272+
print("Process interrupted by user")
273+
break
274+
275+
except KeyboardInterrupt:
276+
ser.write(b'STOP\n')
277+
print("Process interrupted by user")
278+
279+
finally:
267280
if csv_file:
268-
csv_file.close() # Close CSV file
269-
print(f"CSV recording stopped. Data saved to {csv_filename}.") # Notify user
281+
csv_file.close()
282+
print(f"CSV recording saved as {csv_filename}")
270283
print(f"Exiting.\nTotal missing samples: {missing_samples}") # Print final missing samples count
271-
284+
272285
# Main entry point of the script
273286
def main():
274287
global verbose

0 commit comments

Comments
 (0)