# imports the required python code to link to the Entangleware Control software.
# Please ensure the Entangleware Control software is running before running this code
import sys
import os.path as path
sys.path.insert(0, path.join(path.dirname(path.abspath(__file__)), ".."))
import lib.entangleware_control_link as ew
import lib.entangleware_math as emath


# Connect to Entangleware Control software with a timeout of 1 second
# This will create a TCP server and multicast to the Entangleware Control software to establish communication
ew.connect(1.0)

# Opens a debug window on the Entangleware Control software to monitor Digital running state & Analog buffers
# and default output states
ew.debug_mode(True)

# set up default states
ew.set_digital_state(0.0000, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000000A)
ew.set_digital_state(0.0000, 0, 1, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000)
ew.set_digital_state(0.0000, 0, 2, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000)
ew.set_digital_state(0.0000, 0, 3, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000)
ew.set_analog_state(0.0000, 0, 0, -0.5)
ew.set_analog_state(0.0000, 0, 1, 0.5)
for index in range(30):
    ew.set_analog_state(0.0000, 0, index + 2, 0.0)

# begin building sequence to be executed with deterministic timing
ew.build_sequence()

# queue up commands to generate a 1ms wide pulse on channel 0 (scope trigger)
ew.set_digital_state(0.000, 0, 0, 0xF, 0xF, 0x1)
ew.set_digital_state(0.001, 0, 0, 0xF, 0xF, 0x0)

# This queues a digital ramp on the lowest 4 bits of board 0, connector 0
for index in range(16):
    ew.set_digital_state(0.1250 * (index + 1), 0, 0, 0xF, 0xF, index + 1)

# queues setting analog states to a specific values at a specific times.
# This is one way of setting an analog values at specific times.
ew.set_analog_state(0.001, 0, 0, 1)
ew.set_analog_state(0.25, 0, 0, 6)
ew.set_analog_state(0.50, 0, 0, 5)

# This code showcases a repeated sawtooth ramp over 4 channels at full sample rate for the 6738 DAQ board.
duration = 65536*2      # 2 full ramps
num_channels = 4        # 4 channels
sample_rate = 300000    # max sample rate of the 6738 when using the Entanglware software
timedata = [i/sample_rate + 0.75 for i in range(duration)]
analogdata = [10-20 * (i % 65536)/65536 for i in range(duration)]
for index in range(num_channels):
    # alternate way of using 'set_analog_state'
    # It 'threads' the set_analog_state method over list data 'timedata' & 'analogdata'
    # This is much faster than setting individual time/value data
    ew.set_analog_state(timedata, 0, index % 32, analogdata)


# example of an exponential ramp using an efficient algorithm to minimize the analog sample rate
# (see entangleware_math.py)
# For sophisticated ramps or waveforms, mimic this function to reduce memory and bandwidth usage
# it 'inverts' the function to calculate the expected transition times based on the quantization of the analog card
# In this example, it ramps from 10 Volts to -10 volts over the time interval 1.5 sec to 2.5 sec with a decay
# constant of -4.0. This will fully utilize the resolution of the analog card, eliminating many impotent calls to the
# set_analog_state method. When approximating a function, it is tempting to divide time into equal units but it
# is often very inefficient when the analog span is also quantized.
timedata, analogdata = emath.exponential(10.0, -10.0, 1.5, 2.5, -4.0)
ew.set_analog_state(timedata, 0, 0, analogdata)


# This will run the queued sequence: all items in queue will be sorted and duplicates removed by the
# Entangleware Control software.  The print statement is to show the reply from the Entagleware software.
print(ew.run_sequence())

# this stops queueing and clears the previously queued sequence
ew.clear_sequence()

# This disconnects from the Entangleware Control software
ew.disconnect()