From d73ccdaeeb40dc8ebf3566eb7740d9395ae01b00 Mon Sep 17 00:00:00 2001
From: Leolab Cavity CAD PC <quantuminfo.leolab@gmail.com>
Date: Mon, 3 Feb 2025 10:40:36 +0100
Subject: [PATCH] Fastcomtech: Work in progress from last week

---
 FastComtecMCS8A/MCS8A_default_config.SET |  8 +-
 FastComtecMCS8A/blacs_workers.py         | 93 ++++++++++++------------
 FastComtecMCS8A/fastcomtec_api.py        |  5 +-
 FastComtecMCS8A/labscript_devices.py     | 11 +++
 4 files changed, 65 insertions(+), 52 deletions(-)

diff --git a/FastComtecMCS8A/MCS8A_default_config.SET b/FastComtecMCS8A/MCS8A_default_config.SET
index 4d9575d..0484c1c 100644
--- a/FastComtecMCS8A/MCS8A_default_config.SET
+++ b/FastComtecMCS8A/MCS8A_default_config.SET
@@ -1,10 +1,10 @@
 [MCS8A A] 208 FW 3.104 SV 1.243 
 range=256
 periods=2
-sweepmode=22fd2098
+sweepmode=22fd2088
 fstchan=0
 holdafter=0
-streamstatus=3
+streamstatus=0
 calreg0=0
 calreg1=0
 calreg2=0
@@ -27,8 +27,8 @@ timepreset=0.000
 digio=0
 digval=0
 autoinc=0 
-savedata=0 
-mpafmt=asc
+savedata=2 
+mpafmt=dat
 sephead=1 
 fmt=dat
 smoothpts=5 
diff --git a/FastComtecMCS8A/blacs_workers.py b/FastComtecMCS8A/blacs_workers.py
index 670ad98..e927992 100644
--- a/FastComtecMCS8A/blacs_workers.py
+++ b/FastComtecMCS8A/blacs_workers.py
@@ -14,13 +14,20 @@ import os
 import labscript_utils.h5_lock
 import h5py
 import numpy as np
+import time
 
 class MCS8AWorker(Worker):
 
     def init(self):
+        self.start = time.perf_counter()
         self.base_dir = "C:/mcs8x64/"
         self.data_mame_tmp = "CHN2_tmp"
-        self.data_path_tmp = self.base_dir + self.data_mame_tmp + ".dat"
+        
+        # ONLY FOR MPA AND AUTOSAVE
+        self.data_path_tmp = self.base_dir + self.data_mame_tmp + ".mpa"
+        # ONLY FOR DAT WITHOUT AUTOSAVE
+        # self.data_path_tmp = self.base_dir + self.data_mame_tmp
+
         self.device = fastcomtec_api.FastComTec()
         print("Connected...")
         # print("Status: ", self.device.get_acq_status())
@@ -28,21 +35,44 @@ class MCS8AWorker(Worker):
         # load (default) config
         if not os.path.realpath(self.config_path) == self.config_path.replace("/","\\"):
             self.config_path = os.path.dirname(os.path.realpath(__file__)) + "\\" + self.config_path
-        print("test123")
-        # self.device.load_config(self.config_path)
-        print(f"Data file path: {self.data_mame_tmp}")
+            self.config_path = self.config_path.replace("\\", "/")
+
+        print("Load config...", self.config_path)
+        self.device.load_config(self.config_path)
+
+
+        # print(f"Data file path: {self.data_path_tmp}")
+        
+        # ONLY FOR MPA AND AUTOSAVE
         # self.device._send_dll_command(f"mpaname={self.data_path_tmp}") # mpa might be slow
-        self.device._send_dll_command("MC_B")
-        self.device._send_dll_command(f"datname={self.data_mame_tmp}")
-        self.device._send_dll_command("fmt=dat") 
+        self.device._send_dll_command("mpafmt=dat")
+        self.device._send_dll_command("savedata=2")
+
+        # ONLY FOR DAT WITHOUT AUTOSAVE
+        # self.device._send_dll_command(f"datname={self.data_mame_tmp}")
+        # self.device._send_dll_command("fmt=dat")
         self.smart_cache = {}
 
         print('init completed')
     
     def transition_to_buffered(self, device_name, h5_file, initial_values, fresh):
-        
+        print(f"Cycle time: {time.perf_counter()-self.start:.1f} s")
+        self.start = time.perf_counter()
+
         self.h5file = h5_file # save for 'transition_to_manual'
-        """
+        self.mpaname = h5_file.replace("\\","/").replace(".h5",".mpa")
+        self.device._send_dll_command(f"mpaname={self.mpaname}")
+        
+        while True:
+            status = self.device.get_acq_status()
+            status = getattr(status,"started")
+            if status!=1:
+                break
+            print("Waiting for device to stop running (from previous shot)...", end="\r")
+            time.sleep(0.1)
+
+        self.device.halt_measurement()
+
         with h5py.File(h5_file,'r') as f:
             command_group = f[f"devices/{self.device_name}/commands"]
             for command in command_group.attrs:
@@ -51,49 +81,15 @@ class MCS8AWorker(Worker):
                 self.smart_cache[command] = command_group.attrs[command]
                 if command_group.attrs[command] is not None:
                     command = f"{command}={command_group.attrs[command]}"
-                print(f"sending: {command}")
                 self.device._send_dll_command(command)
                 print(f"Programmed command '{command}'")
-        """
-        try:
-            os.remove(self.base_dir + self.data_mame_tmp + ".mp")
-        except FileNotFoundError:
-            pass
-        
-        # self.device.erase_measruement()
-        ########################################
-        ### TIME DIGITIZER PARAMETERS
-        ########################################
-        self.range_dec = "1024"
-        self.bitshift_hex = "e"
-        self.device._send_dll_command(f"range={self.range_dec}") # See documentation on bitshift (C:\Users\labuser\labscript-suite\userlib\user_devices\FastComtecMCS8A\docs)
-        self.device._send_dll_command(f"bitshift={self.bitshift_hex}") # See documentation on bitshift (C:\Users\labuser\labscript-suite\userlib\user_devices\FastComtecMCS8A\docs)
+
+        # self.device.erase_measruement() # Don't erase because this takes super long for some reason
         self.device.start_measurement()
+
         return {}
 
     def transition_to_manual(self):
-        # self.device.halt_measurement()
-
-        # load data and write to file
-        # .... TODO
-        self.device._send_dll_command("savedat")
-        with h5py.File(self.h5file, 'r+') as f:
-            group = f.require_group(f"data/{self.device_name}/")
-            
-            # save photon counts
-            # data = np.random.randint(0,2,size=1000) # testing
-            # data = np.loadtxt(self.data_path_tmp)
-            data = np.fromfile(self.data_path_tmp, dtype=np.uint32)
-            print(data.sum())
-            group.create_dataset("photon_counts", compression = config.compression, data=data) # maybe save as binary dtype
-
-            # save parameters
-            # for param in parameters: 
-            group.attrs["test_param"] = 1000   
-            group.attrs["range_dec"] = self.range_dec
-            group.attrs["bitshift_hex"] = self.bitshift_hex 
-        print('tranistion to manual')
-
         return True
     
     def program_manual(self, values):
@@ -106,4 +102,7 @@ class MCS8AWorker(Worker):
         return self.transition_to_manual()
 
     def abort_transition_to_buffered(self):
-        return True
\ No newline at end of file
+        return True
+    
+    # def shutdown(self):
+    #     self.device._send_dll_command("exit")
\ No newline at end of file
diff --git a/FastComtecMCS8A/fastcomtec_api.py b/FastComtecMCS8A/fastcomtec_api.py
index da549a7..75c580a 100644
--- a/FastComtecMCS8A/fastcomtec_api.py
+++ b/FastComtecMCS8A/fastcomtec_api.py
@@ -1,7 +1,10 @@
 # -*- coding: utf-8 -*-
 
 import ctypes
-from . import fastcomtec_types
+try:
+    from . import fastcomtec_types
+except ImportError:
+    import fastcomtec_types
 import re
 from typing import NamedTuple, List
 
diff --git a/FastComtecMCS8A/labscript_devices.py b/FastComtecMCS8A/labscript_devices.py
index e6aad99..38da0e8 100644
--- a/FastComtecMCS8A/labscript_devices.py
+++ b/FastComtecMCS8A/labscript_devices.py
@@ -7,6 +7,7 @@
 #                                                                   #
 #####################################################################
 from labscript import TriggerableDevice, LabscriptError, set_passed_properties
+import numpy as np
 
 class MCS8A(TriggerableDevice):
     description = 'MCS8A'
@@ -29,6 +30,16 @@ class MCS8A(TriggerableDevice):
             raise LabscriptError("Do not set the same config command twice!")
         self.commands[command] = value
 
+    def set_binwidth_and_duration(self, binwidth, duration):
+        """
+        Parameters:
+        """
+        bitshift = round(np.log2(binwidth/400e-12))
+        self.set_dll_command(f"bitshift", hex(bitshift)[2:])
+
+        range_dec = duration/binwidth//64 * 64
+        self.set_dll_command("range", str(int(range_dec)))
+
     def generate_code(self, hdf5_file):
         group = hdf5_file.create_group(f"devices/{self.name}")
         commands_group = group.create_group("commands")
-- 
GitLab