From 2249b9e9f7ec25be0d2491dba1bb005966871ac4 Mon Sep 17 00:00:00 2001
From: Johannes Schabbauer <johannes.schabbauer@tuwien.ac.at>
Date: Wed, 12 Feb 2025 17:09:07 +0100
Subject: [PATCH] ADwin: Untested code to enable using a single wait with the
 ADwin as master pseudoclock

---
 ADwinProII/ADwin_utils.py       |  6 +++++-
 ADwinProII/blacs_workers.py     | 17 +++++++++++++++++
 ADwinProII/labscript_devices.py | 17 ++++++++++++++---
 3 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/ADwinProII/ADwin_utils.py b/ADwinProII/ADwin_utils.py
index fa1d2f4..3ac371e 100644
--- a/ADwinProII/ADwin_utils.py
+++ b/ADwinProII/ADwin_utils.py
@@ -156,7 +156,11 @@ def get_ain_traces(h5file, raw_data_name="ADwinAnalogIn_DATA", convert_data=True
                 times = np.arange(acquisition_times["start_time"][i],acquisition_times["stop_time"][i],int(clock_rate//acquisition_times["storage_rate"][i])) / clock_rate
             else:
                 times = np.arange(acquisition_times["start_time"][i],acquisition_times["stop_time"][i]) / clock_rate
-            # print(times.size,acquisition.size)
+            if "waits" in f["data"]:
+                # There was a wait in the experiment, let's offset the times such that they are accurate
+                waits = f["data/waits"][:]
+                for i in range(len(waits)):
+                    times[times > waits["time"][i]] += waits["duration"][i]
             if write_hdf5:
                 data = np.rec.fromarrays([times, acquisition], dtype=dtype)
                 group.create_dataset(label, compression = config.compression, data = data)
diff --git a/ADwinProII/blacs_workers.py b/ADwinProII/blacs_workers.py
index c2db3c2..bf67faa 100644
--- a/ADwinProII/blacs_workers.py
+++ b/ADwinProII/blacs_workers.py
@@ -142,6 +142,9 @@ class ADwinProIIWorker(Worker):
             self.stop_time = group.attrs["stop_time"]
             # Send stop time to ADwin
             self.adw.Set_Par(2, int(self.stop_time * CLOCK_T12 / self.PROCESSDELAY))
+            # Send wait time and timeout to ADwin (default 0 if no waits)
+            self.adw.Set_Par(3, group.attrs.get("wait_time",0))
+            self.adw.Set_Par(5, group.attrs.get("wait_timeout",0))
             # Send data to ADwin
             AOUT = group["ANALOG_OUT/VALUES"]
             if fresh or not np.array_equal(AOUT[:],self.smart_cache["AOUT"]):
@@ -157,6 +160,7 @@ class ADwinProIIWorker(Worker):
                     self.smart_cache[name] = DOUT[:]
                     self.adw.SetData_Long(DOUT["n_cycles"], module,   1, DOUT.shape[0])
                     self.adw.SetData_Long(DOUT["bitfield"], module+1, 1, DOUT.shape[0])
+                    self.adw.Set_Par(module-1, DOUT.attrs.get("wait_time",0))
             PIDs = group["ANALOG_OUT/PID_CHANNELS"]
             if fresh or not np.array_equal(PIDs[:],self.smart_cache["PIDs"]):
                 print("PIDs programmed.")
@@ -207,6 +211,19 @@ class ADwinProIIWorker(Worker):
             # array["values"] = workload_data
             # group.create_dataset("ADwin_Workload", compression = config.compression, data = array)
             # f['devices/ADwin/ANALOG_IN'].attrs["ADwin_Workload"] = "TEST"
+
+            # Get wait duration
+            if f[f"devices/{self.device_name}"].attrs.get("wait_time", None) is not None:
+                wait_duration = self.adw.Get_Par(4) / CLOCK_T12 * self.PROCESSDELAY
+                wait_table = f["waits"]
+                dtypes = [('label', 'a256'),('time', float),('timeout', float),('duration', float),('timed_out', bool)]
+                data = np.empty(len(wait_table), dtype=dtypes)
+                data['label'] = wait_table['label']
+                data['time'] = wait_table['time']
+                data['timeout'] = wait_table['timeout']
+                data['duration'] = wait_duration
+                data['timed_out'] = wait_duration > wait_table['timeout']
+                f.create_dataset('/data/waits', data=data)
         # Delete h5file from worker, shot is finished
         self.h5file = None
         # Check if the TiCo processes were running correctly
diff --git a/ADwinProII/labscript_devices.py b/ADwinProII/labscript_devices.py
index f74a85b..c727013 100644
--- a/ADwinProII/labscript_devices.py
+++ b/ADwinProII/labscript_devices.py
@@ -14,7 +14,7 @@
 ############################################################################
 
 
-from labscript import Pseudoclock, PseudoclockDevice, ClockLine, Device, LabscriptError, config, set_passed_properties
+from labscript import Pseudoclock, PseudoclockDevice, ClockLine, Device, LabscriptError, config, set_passed_properties, compiler
 import numpy as np
 
 from . import PROCESSDELAY_T12, PROCESSDELAY_TiCo, CLOCK_T12, CLOCK_TiCo, MAX_EVENTS, MAX_PID_EVENTS, A_IN_BUFFER
@@ -198,8 +198,8 @@ class ADwinProII(PseudoclockDevice):
     
 
     def do_checks(self, outputs):
-        if self.trigger_times != [0]:
-            raise NotImplementedError('ADwin does not support retriggering or waiting.')
+        if len(self.trigger_times)>2 or self.trigger_times[1] not in compiler.wait_table:
+            raise NotImplementedError('ADwin does not support retriggering, and only supports one "wait" in the current implementation.')
         for output in outputs:
             output.do_checks(self.trigger_times)
 
@@ -242,6 +242,8 @@ class ADwinProII(PseudoclockDevice):
                 PID_config.append(device.PID_config)
             elif isinstance(device,ADwinDIO32):
                 group.create_dataset("DIGITAL_OUT/"+device.name, data=device.digital_data)
+                if compiler.wait_table:
+                    group["DIGITAL_OUT/"+device.name].attrs["wait_time"] = round( list(compiler.wait_table)[0] * device.parent_clock_line.clock_limit )
             elif isinstance(device,ADwinAI8):
                 # For the AIN table it's required that self.modules is sorted correctly!
                 analog_input.append(device.AIN_times)
@@ -312,4 +314,13 @@ class ADwinProII(PseudoclockDevice):
         # Save list of module names to connection table properties
         module_dict = {str(module.module_address) : module.name for module in self.modules}
         self.set_property("modules", module_dict, "connection_table_properties")
+
+        # Add wait time and timeout in units of ADwin process cycles
+        if len(compiler.wait_table)>1:
+            raise LabscriptError("ADwin supports only a sinlge wait for now!")
+        for time,args in compiler.wait_table.items():
+            hdf5_file[f"devices/{self.name}"].attrs["wait_time"] = round(time * self._pseudoclock_T12.clock_limit)
+            hdf5_file[f"devices/{self.name}"].attrs["wait_timeout"] = round(args[1] * self._pseudoclock_T12.clock_limit)
+            for TiCo in self.TiCos:
+                hdf5_file[f"devices/{self.name}/DIGITAL_OUT/"].attrs["wait_time"] = round(time * self._pseudoclock_T12.clock_limit)
         
\ No newline at end of file
-- 
GitLab