from ctypes import *
from aecg100 import *
import sys
import time

ac = []
dc = []

class ChannelSetting:
    def __init__(self, dc_value=None, ac_amplify=None):
        self.dc_value = dc_value
        self.ac_amplify = ac_amplify


ECG = ChannelSetting(dc_value=0, ac_amplify=1)
G = ChannelSetting(dc_value=0, ac_amplify=30)
R = ChannelSetting(dc_value=600, ac_amplify=30)
IR = ChannelSetting(dc_value=600, ac_amplify=30)


def load_raw_data_file(file_name):
    global ac, dc
    raw_data_struct = []
    line_number = 0

    with open(file_name, 'r') as f:
        for x in f:
            x = x.strip()
            if not x:
                continue

            if line_number == 0:
                sample_rate = float(x)
            elif line_number == 1:
                size = int(x)
            elif line_number == 2:
                channel_count = int(x)
                start_index = len(ac)
                for i in range(channel_count):
                    raw_data_struct.append(PLAY_RAW_DATA())
                    ac.append((c_double * size)())
                    dc.append((c_double * size)())
            elif line_number == 3:
                signal = x.split(',')
            elif line_number >= 4:
                vals = x.split(',')
                if len(vals) >= channel_count:
                    for i, signal_name in enumerate(signal):
                        match signal_name:
                            # the amplitude of ac must less than or equal to 30mV
                            case "ECG":
                                ac[start_index + i][line_number - 4] = float(vals[i]) * ECG.ac_amplify  # ECG AC
                                dc[start_index + i][line_number - 4] = ECG.dc_value
                            case "R":
                                ac[start_index + i][line_number - 4] = float(vals[i]) * R.ac_amplify    # RED AC
                                dc[start_index + i][line_number - 4] = R.dc_value
                            case "IR":
                                ac[start_index + i][line_number - 4] = float(vals[i]) * IR.ac_amplify   # IR AC
                                dc[start_index + i][line_number - 4] = IR.dc_value
                            case "Green":
                                ac[start_index + i][line_number - 4] = float(vals[i]) * G.ac_amplify    # Green AC
                                dc[start_index + i][line_number - 4] = G.dc_value

            line_number += 1
    for i, signal_name in enumerate(signal):
        raw_data_struct[i].SampleRate = sample_rate
        raw_data_struct[i].Size = size
        raw_data_struct[i].AC = addressof(ac[start_index + i])
        raw_data_struct[i].DC = addressof(dc[start_index + i])
        raw_data_struct[i].OutputSignalCallback = OutputSignalCallback(0)

    return raw_data_struct



# Connect to 4 devices
# Change your own COM port number and DLL PATH
device1 = AECG100('./SDK/windows/AECG100x64-1.dll')
if device1.connect(9, 5000) == False: 
    sys.exit("Error: Device 1 connection failed.")

device2 = AECG100('./SDK/windows/AECG100x64-2.dll')
if device2.connect(16, 5000) == False: 
    sys.exit("Error: Device 2 connection failed.")

device3 = AECG100('./SDK/windows/AECG100x64-3.dll')
if device3.connect(3, 5000) == False: 
    sys.exit("Error: Device 3 connection failed.")

device4 = AECG100('./SDK/windows/AECG100x64-4.dll')
if device4.connect(19, 5000) == False: 
    sys.exit("Error: Device 4 connection failed.")


# Check the connections by printing out each serial number
print('device1 is connected... ({} / {})'.format(
    device1.get_serial_number(),
    device1.get_ppg_serial_number()))

print('device2 is connected... ({} / {})'.format(
    device2.get_serial_number(),
    device2.get_ppg_serial_number()))

print('device3 is connected... ({} / {})'.format(
    device3.get_serial_number(),
    device3.get_ppg_serial_number()))

print('device4 is connected... ({} / {})'.format(
    device4.get_serial_number(),
    device4.get_ppg_serial_number()))


# Create synchronization event object using device1
sync_object = device1.create_synchronization_signal()

# Assign the synchronization signal (created by device1) to all other devices
for dev in [device1, device2, device3, device4]:
    dev.set_synchronization_signal(sync_object)


# Load raw data
raw_data_list = load_raw_data_file('ecg-1hz-5mv.txt')
device1.play_raw_ecg(pointer(raw_data_list[0]))
device1.enable_player_loop(c_bool(True))

raw_data_list = load_raw_data_file('ppg_player1.txt')
device2.play_raw_ppg(1, pointer(raw_data_list[0]))
device2.enable_player_loop(c_bool(True))

raw_data_list = load_raw_data_file('sync_test_data_delay_0.00.txt')
device3.play_raw_ecg_ppg(pointer(raw_data_list[0]), 1, pointer(raw_data_list[1]))
device3.enable_player_loop(c_bool(True))

raw_data_list = load_raw_data_file('sync_test_data_delay_0.00.txt')
device4.play_raw_ecg_ppg_ex(pointer(raw_data_list[0]), pointer(raw_data_list[1]), pointer(raw_data_list[2]))
device4.enable_player_loop(c_bool(True))


input("Press Enter to start output ...")
device1.synchronization_signal_set_event(sync_object)   # Trigger synchronized playback across all devices

input("Press Enter to stop output ...")
device1.synchronization_signal_reset_event(sync_object) # Stop synchronization signal
device1.stop_play_raw()
device2.stop_play_raw()
device3.stop_play_raw()
device4.stop_play_raw()

# Release device resources after playback
device1.free()
device2.free()
device3.free()
device4.free()
