From 09956a970a3eb13137a0e1563fb7a56d145f10c8 Mon Sep 17 00:00:00 2001
From: Christoph Schmidt <christoph.,schmidt@tugraz.at>
Date: Wed, 24 Jan 2024 17:01:49 +0100
Subject: [PATCH] Measurement Routine moved to examples. Now measureme and
 updated the README.md

---
 README.md                                     | 52 +++++++++++++++++--
 examples/MeasurementRoutine.py                | 20 +++----
 examples/main.py                              | 28 +++++-----
 .../controller/MainThreadController.py        | 23 ++++----
 .../BaseMeasurementRoutine.py                 |  5 +-
 5 files changed, 84 insertions(+), 44 deletions(-)

diff --git a/README.md b/README.md
index eede008..e4b4e33 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,52 @@ To start the software, simply run the `examples/main.py` file.
 python main.py
 ```
 
-# Measuring using Flexsensor
+# Defining a measurement routine
+The measurement routine is defined in a python file. Each measurement routine must inherit from the `BaseMeasurementRoutine` class.
+Note that the base class has an overloaded constructor that requires the following parameters:
+- `prober`: The Prober.Controller object that is used to measure the structures
+- `config`: The FlexSensorConfig object that is used to measure the structures
+```python
+import FlexSensor as fs
+
+class MeasurementRoutine(fs.BaseMeasurementRoutine):
+
+    def __init__(prober: Prober.Controller,
+                 config: fs.FlexSensorConfig):
+        super().__init__(prober, config)
+
+    @Slot()
+    def run(self): 
+        # your code here
+```
+In the `run` method, the measurement routine is defined. 
+The `run` method is called by the `MeasurementRoutineThread` class, which is a QThread object. This allows to run the method
+in a separate thread, while the GUI remains responsive. 
+
+
+
+# Measuring using FlexSensor
+It is often useful to measure a large number of structures on a wafer. For this, the software allows to define a
+measurement routine that is executed for each structure. 
+The `vas`-File allows to define a list of structures that are measured. Thede file is parsed and passed
+to the `MeasurementRoutine` class.
+```python
+import FlexSensor as fs
+# ...
+def readVasFile(self):
+    self.parsed_file = fs.VASInputFileParser()
+    
+    selected_file, self.grouped_structures, self.bookmarks = self.parsed_file.read_file(
+         input_file='structure_file.vas'
+     )
+# ...
+```
+The `VASInputFileParser` class parses the `vas`-File and returns a list of structures that are measured.
+- `selected_file`: The selected file. In case the file is not found, the user is prompted to select a file by a file dialog.
+- `grouped_structures`: A list of structures that are measured. Each structure is a python dictionary that contains the
+  information on how to measure the structure.
+- `bookmarks`: A list of bookmarks that are defined in the `vas`-File. These bookmarks are used to create a Klayout
+  bookmark file that can be used to navigate to the structures in Klayout.
 ## Input Structure File
 The measuring process relies on a ```vas```-File that store the positions to the structures. in priciple 
 this file os a list of python dictionary in a predefined format, that allows the easy definiton
@@ -69,7 +114,7 @@ Sometimes it is useful to define a group of measurement points that are equally
 mrr1     = {'y_in' : -1845, 'x_in' : 960, 'y_out' : -2015, 'x_out' : -155,  'num' : 6, 'spacing' : 100, 'repetitons': 200}
 ```
 
-## Setup bevore measuring
+## Setup before measuring
 1. Open the correct wafer map. 
 Open the wafer Map under **Velox** -> **WaferMap**. Load the correct wafer file and select or deselect dies you do not 
 want to capture. 
@@ -91,13 +136,12 @@ Set our fiber to the correct height. Then use the "Set Contact height". Otherwis
 This step is crucial and needed to train the output positions.
 
 
-# Lincence and usage
+# Licence and usage
 This software is licenced under the [GNU GPL v3](https://www.gnu.org/licenses/gpl-3.0.de.html). 
 If you use this software for your work or in your papers please cite me the following:
 
 
 
-
 # FAQ&Issues
 This section should cover the issues that may occure during usage or development. 
 ## Installation issues and running
diff --git a/examples/MeasurementRoutine.py b/examples/MeasurementRoutine.py
index 20b693e..2b07886 100644
--- a/examples/MeasurementRoutine.py
+++ b/examples/MeasurementRoutine.py
@@ -23,22 +23,18 @@ from Properties.WaferProperties import WaferProperties
 
 sys.path.append('./src')
 
-# from FlexSensor.FlexSensorConfig import FlexSensorConfig
-# from FlexSensor.MeasurementData.MeasuredData.SingleMeasuredData import SingleMeasuredData
-# from FlexSensor.MeasurementData.Properties.AD2CaptDeviceProperties import AD2CaptDeviceProperties
-# from FlexSensor.MeasurementData.Properties.LaserProperties import LaserProperties
-# from FlexSensor.MeasurementData.Properties.MeasurementProperties import MPropertiesFindPeaks, \
-#     MeasurementProperties, WaveguidePropertiesMZI
-# from FlexSensor.MeasurementData.Properties.WaferProperties import WaferProperties
-# from FlexSensor.MeasurementRoutines.BasemeasurementRoutine import BaseMeasurementRoutine
-# from FlexSensor.generics.VASInputFileParser import VASInputFileParser, Structure
-
 
 class MeasurementRoutine(fs.BaseMeasurementRoutine):
 
-    def __init__(self, laser: Laser, ad2device: AD2Dev, prober: Prober.Controller,
+    def __init__(self,
+                 laser: Laser,
+                 ad2device: AD2Dev,
+                 prober: Prober.Controller,
                  config: fs.FlexSensorConfig):
-        super().__init__(laser, ad2device, prober, config)
+        super().__init__(prober, config)
+
+        self.ad2device: AD2Dev = ad2device
+        self.laser: Laser.Controller = laser
 
         self.logger = logging.getLogger("Measurement Routine")
         # The signals for connecting to the UI
diff --git a/examples/main.py b/examples/main.py
index fc13428..a16b125 100644
--- a/examples/main.py
+++ b/examples/main.py
@@ -12,12 +12,14 @@ from PySide6.QtWidgets import QApplication
 # set env variable VELOX_SIM=TRUE
 # to use the simulator instead of the real hardware
 import os
+
 os.environ["VELOX_SIM"] = "TRUE"
 
 sys.path.append('./src')
 from MeasurementRoutine import MeasurementRoutine
 import FlexSensor
 
+
 def main(argv):
     FlexSensor.ApplicationInit.setup_logging()
     logging.info(f"Starting Velox GUI Version {FlexSensor.__version__}")
@@ -28,32 +30,32 @@ def main(argv):
 
     # Disable loggers that are not needed (e. g. numpy, etc)
     cw = FlexSensor.ConsoleWindow(app)
-    #cw.show()
+    # cw.show()
 
-    #FlexSensor.ApplicationInit.setup_logging(cw)
+    # FlexSensor.ApplicationInit.setup_logging(cw)
     FlexSensor.ApplicationInit.set_icon(app)
 
     # Read the inital config file
-
     config = FlexSensor.ApplicationInit.load_config_file(f"{FlexSensor.configs_root}/init_config.yaml")
     config.autosave(enable=True, path="autosave_configs/init_config.yaml")
 
-
+    # Start the main application
     main_model = FlexSensor.MainThreadModel(config=config)
-    #wdg = config.view.widget()
-    #wdg.show()
-    main_controller = FlexSensor.MainThreadController(main_model, MeasurementRoutine)
+    main_controller = FlexSensor.MainThreadController(main_model)
+    # Register your measurement routine here
+    main_controller.load_measurement_routine(MeasurementRoutine,
+                                             ad2device=main_model.ad2_controller,
+                                             laser=main_model.laser_controller,
+                                             )
     main_window = FlexSensor.MainWindow(main_model, main_controller)
 
-    # test_win = StructureSelector()
-    #config.save(f"{FlexSensor.configs_root}/init_config.yaml")
+
+
+
     main_window.show()
     splash_screen.finish(main_window)
-
     sys.exit(app.exec())
 
-if __name__ == "__main__":
 
+if __name__ == "__main__":
     main(sys.argv)
-
-
diff --git a/src/FlexSensor/MainWindow/controller/MainThreadController.py b/src/FlexSensor/MainWindow/controller/MainThreadController.py
index 97b2adb..910383c 100644
--- a/src/FlexSensor/MainWindow/controller/MainThreadController.py
+++ b/src/FlexSensor/MainWindow/controller/MainThreadController.py
@@ -18,7 +18,6 @@ class MainThreadController(FSBase, object):
     on_start_laser_sweep = Signal(name='on_start_laser_sweep')
 
     def __init__(self, model: MainThreadModel,
-                 measurement_routine: Type[BaseMeasurementRoutine],
                  enable_log: bool = True, log_level: int = logging.DEBUG, log_file: str = "flexsensor.log"):
         super().__init__()
 
@@ -57,7 +56,7 @@ class MainThreadController(FSBase, object):
         self._device_initialization()
 
         # Load the measurement routine
-        self.model.measurement_routine = self._load_measurement_routine(measurement_routine)
+        #self.model.measurement_routine = self._load_measurement_routine(measurement_routine)
 
         # Thread for the measurement routine
         self.measurement_thread = QThread()
@@ -105,7 +104,7 @@ class MainThreadController(FSBase, object):
         self.measurement_thread.started.connect(measurement_routine.run)
         self.logger.debug("Moved worker/measurement routine to thread and connected the signals.")
 
-    def _load_measurement_routine(self, measurement_routine: Type[BaseMeasurementRoutine]) -> BaseMeasurementRoutine:
+    def load_measurement_routine(self, measurement_routine: Type[BaseMeasurementRoutine], *args, **kwargs) -> BaseMeasurementRoutine:
         """
             Loads the measurement routine and initializes it.
 
@@ -115,16 +114,16 @@ class MainThreadController(FSBase, object):
             Raises:
                 Exception: If some or all devices have not been initialized.
         """
-        # if not self.device_are_init:
-        #    raise Exception("Some or all devices have not been initialized. First call `_device_initialization()`!")
-
-        _measurement_routine = measurement_routine(
-            self.model.laser_controller,
-            self.model.ad2_controller,
-            self.model.prober_controller,
-            self.model.config)
+        self.model.measurement_routine = measurement_routine(
+            prober=self.model.prober_controller,
+            config=self.model.config,
+            *args, **kwargs)
+        #   laser=self.model.laser_controller,
+        #    ad2device=self.model.ad2_controller,
+        #    prober=self.model.prober_controller,
+        #    config=self.model.config)
         self.logger.debug("Initialized MeasurementRoutine.")
-        return _measurement_routine
+        #return _measurement_routine
 
     def _device_initialization(self):
         """
diff --git a/src/FlexSensor/MeasurementRoutines/BaseMeasurementRoutine.py b/src/FlexSensor/MeasurementRoutines/BaseMeasurementRoutine.py
index 8d96026..bbaf795 100644
--- a/src/FlexSensor/MeasurementRoutines/BaseMeasurementRoutine.py
+++ b/src/FlexSensor/MeasurementRoutines/BaseMeasurementRoutine.py
@@ -19,13 +19,12 @@ from FlexSensor.MeasurementRoutines.WorkerSignals import WorkerSignals
 
 class BaseMeasurementRoutine(QObject, FSBase):
 
-    def __init__(self, laser: Laser.Controller, ad2device: CaptDevice.Controller, prober: ProberController, config: FlexSensorConfig):
+    def __init__(self, prober: ProberController, config: FlexSensorConfig, *args, **kwargs):
         super().__init__()
         self.logger = self.create_new_logger(self.name)
         self.config = config
 
-        self.ad2device: CaptDevice.Controller = ad2device
-        self.laser: Laser.Controller = laser
+
         self.prober: ProberController = prober
         self.logger.debug(f"{self.prober.report_kernel_version()}")
         print(self.prober)
-- 
GitLab