38
38
import numpy as np # For handling numeric arrays
39
39
import pyqtgraph as pg # For real-time plotting
40
40
from pyqtgraph .Qt import QtWidgets , QtCore # PyQt components for GUI
41
+ import msvcrt #for keyboard interruptions
41
42
42
43
# Initialize global variables for tracking and processing data
43
44
total_packet_count = 0 # Total packets received in the last second
47
48
previous_sample_number = None # Store the previous sample number for detecting missing samples
48
49
missing_samples = 0 # Count of missing samples due to packet loss
49
50
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
53
54
END_BYTE = 0x01 # End byte marker
55
+ NUM_CHANNELS = 6
56
+ HEADER_LENGTH = 3
54
57
lsl_outlet = None # Placeholder for LSL stream outlet
55
58
verbose = False # Flag for verbose output mode
56
59
data = np .zeros ((6 , 2000 )) # 2D array to store data for real-time plotting (6 channels, 2000 data points)
57
60
csv_filename = None # Store CSV filename
58
61
samples_per_second = 0 # Number of samples received per second
59
62
63
+
60
64
# Function to automatically detect the Arduino's serial port
61
65
def auto_detect_arduino (baudrate , timeout = 1 ):
62
66
ports = serial .tools .list_ports .comports () # List available serial ports
@@ -81,7 +85,6 @@ def read_arduino_data(ser, csv_writer=None):
81
85
82
86
raw_data = ser .read (ser .in_waiting or 1 ) # Read available data from the serial port
83
87
buffer .extend (raw_data ) # Add received data to the buffer
84
-
85
88
while len (buffer ) >= PACKET_LENGTH : # Continue processing if the buffer contains at least one full packet
86
89
sync_index = buffer .find (bytes ([SYNC_BYTE1 , SYNC_BYTE2 ])) # Search for the sync marker
87
90
@@ -93,7 +96,7 @@ def read_arduino_data(ser, csv_writer=None):
93
96
packet = buffer [sync_index :sync_index + PACKET_LENGTH ] # Extract the packet
94
97
if len (packet ) == PACKET_LENGTH and packet [0 ] == SYNC_BYTE1 and packet [1 ] == SYNC_BYTE2 and packet [- 1 ] == END_BYTE :
95
98
# 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)
97
100
98
101
# Check for missing samples by comparing the counter values
99
102
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):
107
110
108
111
# Extract channel data (6 channels, 2 bytes per channel)
109
112
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 ]
113
116
value = (high_byte << 8 ) | low_byte # Combine high and low bytes
114
117
channel_data .append (float (value )) # Convert to float and add to channel data
115
118
@@ -249,6 +252,7 @@ def parse_data(port, baudrate, lsl_flag=False, csv_flag=False, gui_flag=False, v
249
252
start_timer () # Start timers for logging
250
253
251
254
try :
255
+ ser .write (b'START\n ' )
252
256
while True :
253
257
read_arduino_data (ser , csv_writer ) # Read and process data from Arduino
254
258
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
262
266
log_ten_minute_data (verbose ) # Log data for the last 10 minutes
263
267
if gui_flag :
264
268
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 :
267
280
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 } " )
270
283
print (f"Exiting.\n Total missing samples: { missing_samples } " ) # Print final missing samples count
271
-
284
+
272
285
# Main entry point of the script
273
286
def main ():
274
287
global verbose
0 commit comments