WITecCOM.py 26.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# -*- coding: utf-8 -*-
"""
GEPARD - Gepard-Enabled PARticle Detection
Copyright (C) 2018  Lars Bittrich and Josef Brandt, Leibniz-Institut für 
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>    

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program, see COPYING.  
If not, see <https://www.gnu.org/licenses/>.
"""

import os
import sys
Josef Brandt's avatar
Josef Brandt committed
24

25 26 27 28 29 30 31
try:
    import pythoncom
    import win32com.client
except ImportError:
    os.environ["NO_WITEC_CONTROL"] = "True"
    
from time import sleep, time
32
try:            #when running the witectesting, the paths have to be differently, as it is in the same directory as the other raman com modules
Raman's avatar
Raman committed
33 34
    from .ramanbase import RamanBase
    from .configRaman import RamanSettingParam
Josef Brandt's avatar
Josef Brandt committed
35
except ModuleNotFoundError:
36 37
    from ramanbase import RamanBase
    from configRaman import RamanSettingParam
38
from socket import gethostname
39
from ..errors import showErrorMessageAsWidget
40 41 42


class WITecCOM(RamanBase):
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
    def comErrorRepeater(comCallFunction):
        """
        A wrapper function for handling rarely occuring com errors.
        If a com error occurs, a sleep time of one second is done, than the function is repeated.
        This is done three times. If still no success was achieved, the com interface is reconnected
        and, again, the function is started three times at maximum.
        If none of this worked, an error message is shown and an exception is raised.
    
        Parameters
        ----------
        comCallFunction : function object
            The function to apply the wrapper to.
    
        Returns
        -------
        wrapper : function object
            The wrapped function
    
        """
        def wrapper(*args, **kwargs):
63
            def tryFunctionThreeTimes(c):
64 65
                success = False
                for _ in range(3):
66
                    result = None
67
                    c += 1
68
                    try:
69
                        result = comCallFunction(*args, **kwargs)
70 71 72
                        success = True
                        break
                    except pythoncom.com_error:
73 74 75
                        comObj.logger.warning(
                            f'Unsuccessful {c}. attempt for COM call of function {comCallFunction.__name__}\n{pythoncom.com_error}'
                        )
76
                        sleep(1.)
77 78 79
                return success, result, c

            c = 0
80
            comObj = args[0]   #self is always passed as first argument
81
            functionSucceeded, result, c = tryFunctionThreeTimes(c)
82
            if not functionSucceeded:
83
                comObj.logger.warning(f'Reconnecting for function {comCallFunction.__name__}')
84 85 86 87
                comObj.disconnect()
                sleep(1.)
                comObj.connect()
                
88
                functionSucceeded, result, c = tryFunctionThreeTimes(c)
89
                if not functionSucceeded:
90 91
                    comObj.logger.warning(f'COM error: function {comCallFunction.__name__} could not be executed')
                    showErrorMessageAsWidget(f'COM error on function {comCallFunction.__name__}')
92
                    raise pythoncom.com_error
93
            return result
94 95
        return wrapper
    
96
    CLSID = "{C45E77CE-3D66-489A-B5E2-159F443BD1AA}"
97 98 99 100 101 102
    
    magn = 20
    
    ramanParameters = [RamanSettingParam('IntegrationTime (s)', 'double', default=0.5, minVal=0.01, maxVal=100),
                       RamanSettingParam('Accumulations', 'int', default=5, minVal=1, maxVal=100)]
    
103
    def __init__(self, logger, hostname=None):
104
        super().__init__()
Josef Brandt's avatar
 
Josef Brandt committed
105
        self.name = 'WITecCOM'
106 107 108 109
        if hostname is None:
            hostname = gethostname()
        self.IBUCSAccess = win32com.client.DispatchEx(self.CLSID, machine=hostname, 
                                                      clsctx=pythoncom.CLSCTX_REMOTE_SERVER)
110 111
        self.advancedInterface = False
        self.doAutoFocus = False
112
        self.logger = logger
113
            
114 115 116 117 118 119
    def connect(self):
        if not self.IBUCSAccess.RequestWriteAccess(True):
            self.connected = False
            return False
        
        IBUCSCore = win32com.client.CastTo(self.IBUCSAccess, 'IBUCSCore')
120
        self.VersionInterface = IBUCSCore.GetSubSystemDefaultInterface("Status|Software|Application|ProgramVersion")
Raman's avatar
Raman committed
121 122 123 124 125 126 127
        self.VersionMan = win32com.client.CastTo(self.VersionInterface, 'IBUCSStatusContainer')
        self.VersionMan.Update()
        version = self.VersionMan.GetSingleValueAsString()[1]
        try:
            vnr = version.split(",")[1].split(" Release")[0].strip()
        except:
            vnr = ""                
128 129 130
        try:
            vnr = float(vnr)
        except ValueError:
131
            self.logger.critical(f"WITec: unknown version format: {version}")
132
            vnr = 0.0 # version format unknown        
Raman's avatar
Raman committed
133
        self.version = vnr
134
        
135 136 137 138 139 140 141 142
        self.PosXInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SamplePositioning|AbsolutePositionX")
        self.PosYInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SamplePositioning|AbsolutePositionY")
        self.PosZInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|ScanTable|PositionMicroscopeZ")
        self.GoToInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SamplePositioning|GoToPosition")
        self.PosXCurInterface = IBUCSCore.GetSubSystemDefaultInterface("Status|Software|SamplePositioner|CurrentPositionX")
        self.PosYCurInterface = IBUCSCore.GetSubSystemDefaultInterface("Status|Software|SamplePositioner|CurrentPositionY")
        self.PosZCurInterface = IBUCSCore.GetSubSystemDefaultInterface("Status|Software|SamplePositioner|CurrentPositionZ")
        self.PosZCurUserInterface = IBUCSCore.GetSubSystemDefaultInterface("Status|Hardware|Controller|DataChannels|StepperMotorPosition")
Lars Bittrich's avatar
Lars Bittrich committed
143
        
144 145 146 147 148 149 150 151 152
        self.PosXFloatMan = win32com.client.CastTo(self.PosXInterface, 'IBUCSFloat')
        self.PosYFloatMan = win32com.client.CastTo(self.PosYInterface, 'IBUCSFloat')
        self.PosZFloatMan = win32com.client.CastTo(self.PosZInterface, 'IBUCSFloat')
        self.PosXCurFloatMan = win32com.client.CastTo(self.PosXCurInterface, 'IBUCSStatusContainer')
        self.PosYCurFloatMan = win32com.client.CastTo(self.PosYCurInterface, 'IBUCSStatusContainer')
        self.PosZCurFloatMan = win32com.client.CastTo(self.PosZCurInterface, 'IBUCSStatusContainer')
        self.PosZCurUserFloatMan = win32com.client.CastTo(self.PosZCurUserInterface, 'IBUCSStatusContainer')
        self.GoToTrigger = win32com.client.CastTo(self.GoToInterface, 'IBUCSTrigger')
        
153 154 155 156 157 158 159 160 161 162 163 164 165
        if vnr<5.1:
            self.ImageNameInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MultiCommVideoSystem|BitmapFileName")
            self.ImageNameMan = win32com.client.CastTo(self.ImageNameInterface, 'IBUCSString')
            self.ImageSaveInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MultiCommVideoSystem|SaveColorBitmapToFile")
            self.ImageSaveMan = win32com.client.CastTo(self.ImageSaveInterface, 'IBUCSTrigger')
            
            self.ImageHeightInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|Video|Calibration|ImageHeightMicrons")
            self.ImageHeightMan = win32com.client.CastTo(self.ImageHeightInterface, 'IBUCSFloat')
            self.ImageWidthInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|Video|Calibration|ImageWidthMicrons")
            self.ImageWidthMan = win32com.client.CastTo(self.ImageWidthInterface, 'IBUCSFloat')
            self.ImageRotationInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|Video|Calibration|RotationDegrees")
            self.ImageRotationMan = win32com.client.CastTo(self.ImageRotationInterface, 'IBUCSFloat')
        else:
Raman's avatar
Raman committed
166
            self.ImageNameInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|Video|VideoImageFileName")
167
            self.ImageNameMan = win32com.client.CastTo(self.ImageNameInterface, 'IBUCSString')
Raman's avatar
Raman committed
168
            self.ImageSaveInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|Video|AcquireVideoImageToFile")
169 170
            self.ImageSaveMan = win32com.client.CastTo(self.ImageSaveInterface, 'IBUCSTrigger')
            
Raman's avatar
Raman committed
171
            self.ImageHeightInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|Video|Calibration|ImageHeightMicrons")
172
            self.ImageHeightMan = win32com.client.CastTo(self.ImageHeightInterface, 'IBUCSFloat')
Raman's avatar
Raman committed
173
            self.ImageWidthInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|Video|Calibration|ImageWidthMicrons")
174
            self.ImageWidthMan = win32com.client.CastTo(self.ImageWidthInterface, 'IBUCSFloat')
Raman's avatar
Raman committed
175
            self.ImageRotationInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|Video|Calibration|RotationDegrees")
176
            self.ImageRotationMan = win32com.client.CastTo(self.ImageRotationInterface, 'IBUCSFloat')
177
        
Elisa Kanaki's avatar
Elisa Kanaki committed
178 179 180 181 182 183 184
        if vnr>=5.2:
            self.TimeSeriesSlowNameInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|Naming|SampleName")
            self.TimeSeriesSlowNumInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|Naming|Counter")
        else:
            self.TimeSeriesSlowNameInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerTimeSeriesSlow|Naming|DataName")
            self.TimeSeriesSlowNumInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerTimeSeriesSlow|Naming|DataNumber")
        
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
        self.SequencerStartInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerSingleSpectrum|Start")
        self.SequencerStartTrigger = win32com.client.CastTo(self.SequencerStartInterface, 'IBUCSTrigger')
        
        self.SequencerBusyInterface = IBUCSCore.GetSubSystemDefaultInterface("Status|Software|Sequencers|IsASequencerActive")
        self.SequencerBusyStatus = win32com.client.CastTo(self.SequencerBusyInterface, 'IBUCSStatusContainer') 
        
        self.TimeSeriesSlowNumMeasurementsInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerTimeSeriesSlow|AmountOfMeasurements")
        self.TimeSeriesSlowNumMeasurementsMan = win32com.client.CastTo(self.TimeSeriesSlowNumMeasurementsInterface, 'IBUCSInt')
        self.TimeSeriesSlowNameMan = win32com.client.CastTo(self.TimeSeriesSlowNameInterface, 'IBUCSString')
        self.TimeSeriesSlowNumAccumulationsInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerTimeSeriesSlow|SpectrumAcquisition|Accumulations")
        self.TimeSeriesSlowNumAccumulationsMan = win32com.client.CastTo(self.TimeSeriesSlowNumAccumulationsInterface, 'IBUCSInt')
        self.TimeSeriesSlowIntTimeInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerTimeSeriesSlow|SpectrumAcquisition|IntegrationTime")
        self.TimeSeriesSlowIntTimeMan = win32com.client.CastTo(self.TimeSeriesSlowIntTimeInterface, 'IBUCSFloat')
        self.TimeSeriesSlowNumMan = win32com.client.CastTo(self.TimeSeriesSlowNumInterface, 'IBUCSInt')
        self.TimeSeriesSlowModeInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerTimeSeriesSlow|MeasurementMode")
        self.TimeSeriesSlowModeMan = win32com.client.CastTo(self.TimeSeriesSlowModeInterface, 'IBUCSEnum')
        self.TimeSeriesSlowNextInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerTimeSeriesSlow|NextMeasurement")
        self.TimeSeriesSlowNextMan = win32com.client.CastTo(self.TimeSeriesSlowNextInterface, 'IBUCSTrigger')
        
        self.TimeSeriesSlowStartInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerTimeSeriesSlow|Start")
        self.TimeSeriesSlowStartMan = win32com.client.CastTo(self.TimeSeriesSlowStartInterface, 'IBUCSTrigger')
        
        self.TimeSeriesSlowStopInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|StopSequencer")
        self.TimeSeriesSlowStopMan = win32com.client.CastTo(self.TimeSeriesSlowStopInterface, 'IBUCSTrigger')
        
        self.TimeSeriesSlowIndNextInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerTimeSeriesSlow|IndexOfNextMeasurement")
        self.TimeSeriesSlowIndNextMan = win32com.client.CastTo(self.TimeSeriesSlowIndNextInterface, 'IBUCSInt')
        
        self.TimeSeriesSlowActivityInterface = IBUCSCore.GetSubSystemDefaultInterface("Status|Software|Sequencers|ActiveSequencer|CurrentActivity")
        self.TimeSeriesSlowActivityMan = win32com.client.CastTo(self.TimeSeriesSlowActivityInterface, 'IBUCSStatusContainer')
        
        self.RamanRelativeXInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|Video|ProbePosition|RelativeX")
        self.RamanRelativeXMan = win32com.client.CastTo(self.RamanRelativeXInterface, 'IBUCSFloat')
        self.RamanRelativeYInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|Video|ProbePosition|RelativeY")
        self.RamanRelativeYMan = win32com.client.CastTo(self.RamanRelativeYInterface, 'IBUCSFloat')
        
        self.BrightnessInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|WhiteLight|Top|BrightnessPercentage")
        self.BrightnessMan = win32com.client.CastTo(self.BrightnessInterface, 'IBUCSFloat')
        
Josef Brandt's avatar
Josef Brandt committed
224 225 226
        try:
            self.getAdvancedCOMFeatures(IBUCSCore)
            self.advancedInterface = True
227
            self.doAutoFocus = False
Josef Brandt's avatar
Josef Brandt committed
228 229 230
        except pythoncom.com_error:
            self.advancedInterface = False
            
231 232 233
        self.connected = True
        return True
    
Josef Brandt's avatar
Josef Brandt committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    def getAdvancedCOMFeatures(self, IBUCSCore):
        self.AutoFocusInterface = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerAutoFocus|Start")
        self.AutoFocusMan = win32com.client.CastTo(self.AutoFocusInterface, 'IBUCSTrigger')
        
        self.SilentSpecTextInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|SequencerSingleSpectrum|SilentSpectrumAsText")
        self.SilentSpecText = win32com.client.CastTo(self.SilentSpecTextInterface, 'IBUCSString')
                
        self.SilentSpecDoInterface = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|SequencerSingleSpectrum|DoSilentSpectrum")
        self.DoSilentSpectrum = win32com.client.CastTo(self.SilentSpecDoInterface, 'IBUCSBool')
        
        self.SingleSpecIntegrationTime = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerSingleSpectrum|IntegrationTime")
        self.SingleSpecIntegrationTimeMan = win32com.client.CastTo(self.SingleSpecIntegrationTime, 'IBUCSFloat')
        self.SingleSpecNumAccs = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|SequencerSingleSpectrum|NrOfAccumulations")
        self.SingleSpecNumAccsMan = win32com.client.CastTo(self.SingleSpecNumAccs, 'IBUCSInt')
        
        self.BeamPathState = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|BeamPath|State")
        self.BeamPathSetRamanState = IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|BeamPath|SetStateRaman")
        self.MicroscopeIdle = IBUCSCore.GetSubSystemDefaultInterface("UserParameters|MicroscopeStateOnIdle")
        
        self.BeamPathSetVideoStateInterface =IBUCSCore.GetSubSystemDefaultInterface("MultiComm|MicroscopeControl|BeamPath|SetStateVideo")
        self.BeamPathSetVideoState = win32com.client.CastTo(self.BeamPathSetVideoStateInterface, 'IBUCSTrigger')
        
        try:
Josef Brandt's avatar
Josef Brandt committed
257
            from .spechandler import SpectraAcquisition
Josef Brandt's avatar
Josef Brandt committed
258
        except ModuleNotFoundError:
Josef Brandt's avatar
Josef Brandt committed
259
            from spechandler import SpectraAcquisition
260
        
Josef Brandt's avatar
Josef Brandt committed
261
        self.advSpec = SpectraAcquisition(self)
262 263
        if 'Autofocus' not in [param.name for param in self.ramanParameters]:
            self.ramanParameters.append(RamanSettingParam('Autofocus', 'checkBox', default=False))
264
            self.ramanParameters.append(RamanSettingParam('Spectra Batch Size', 'int', default=1000, minVal=1, maxVal=1e6))
Josef Brandt's avatar
Josef Brandt committed
265
    
266
    @comErrorRepeater
267 268 269 270
    def getBrightness(self):
        assert self.connected
        return self.BrightnessMan.GetValue()
    
271
    @comErrorRepeater
272 273 274 275 276 277 278 279
    def setBrightness(self, newval):
        if newval<0: 
            newval = 0.0
        elif newval>100.:
            newval = 100.0
        self.BrightnessMan.SetValue(newval)
        sleep(.1)
    
280
    @comErrorRepeater
281 282 283 284
    def getRamanPositionShift(self):
        rx = .5-self.RamanRelativeXMan.GetValue() # current assumption is, that image center is current position
        ry = self.RamanRelativeYMan.GetValue()-.5
        width, height = self.ImageWidthMan.GetValue(), self.ImageHeightMan.GetValue()
Lars Bittrich's avatar
Lars Bittrich committed
285
        return rx*width, ry*height        
286 287 288 289 290 291
    
    def disconnect(self):
        if self.connected:
            self.IBUCSAccess.RequestWriteAccess(False)
        self.connected = False
    
292
    @comErrorRepeater
293 294 295 296 297 298 299 300 301 302
    def getPosition(self):
        assert self.connected
        self.PosXCurFloatMan.Update()
        x = self.PosXCurFloatMan.GetSingleValueAsDouble()[1]
        self.PosYCurFloatMan.Update()
        y = self.PosYCurFloatMan.GetSingleValueAsDouble()[1]
        self.PosZCurFloatMan.Update()
        z = self.PosZCurFloatMan.GetSingleValueAsDouble()[1]
        return x, y, z
    
303
    @comErrorRepeater
304 305 306 307 308
    def getSoftwareZ(self):
        self.PosZCurFloatMan.Update()
        z = self.PosZCurFloatMan.GetSingleValueAsDouble()[1]
        return z
    
309
    @comErrorRepeater
310 311 312 313 314
    def getUserZ(self):
        assert self.connected
        self.PosZCurUserFloatMan.Update()
        z = self.PosZCurUserFloatMan.GetSingleValueAsDouble()[1]
        return z
315 316
    
    @comErrorRepeater
317
    def moveToAbsolutePosition(self, x, y, z=None, epsxy=0.11, epsz=0.011):
318 319 320 321 322
        assert self.connected
        initpos = self.getPosition()
        # move only if new position is really different; repeat if new position is ignored (happens some times)
        while max(abs(initpos[0]-x), abs(initpos[1]-y))>epsxy:
            t0 = time()
Josef Brandt's avatar
 
Josef Brandt committed
323 324 325 326 327 328 329 330 331 332 333 334 335
            numFails = 0
            maxFails = 50
            positionSubmitted = False
            while numFails < maxFails and not positionSubmitted:
                try:
                    self.PosXFloatMan.SetValue(x)
                    self.PosYFloatMan.SetValue(y)
                    self.GoToTrigger.OperateTrigger()
                    positionSubmitted = True
                except pythoncom.com_error:
                    numFails += 1
                    sleep(.1)
            if numFails > 0:
336
                self.logger.info(f'{numFails} of max. {maxFails} unsuccessfull position submits to Position: {x}, {y}')
Josef Brandt's avatar
 
Josef Brandt committed
337
            if not positionSubmitted:
338
                self.logger.warning(f'Error setting Position: {x}, {y}\nExpecting \"signal ignored\" warning')
339 340 341 342 343 344
            
            # wait till position is found within accuracy of epsxy; check if position changes at all
            distance = 2*epsxy
            while distance > epsxy:# and (lastpos is None or lastpos!=curpos):
                curpos = self.getPosition()
                distance = max(abs(curpos[0]-x), abs(curpos[1]-y))
345
                if ((time()-t0>0.5) and max(abs(curpos[0]-initpos[0]), abs(curpos[1]-initpos[1]))<epsxy) or (time()-t0>10.):
346
                    self.logger.warning(f"WARNING: signal ignored:, time: {time()-t0}, x: {x}, y: {y}, curPos: {curpos}, initpos: {initpos}")
347 348 349 350 351 352
                    break
                sleep(.01)
            sleep(.1)
            initpos = self.getPosition()
        if z is not None:
            self.moveZto(z, epsz)
353 354
    
    @comErrorRepeater
355 356 357 358 359 360 361 362 363 364 365 366 367
    def moveZto(self, z, epsz=0.011):
        assert self.connected
        #z = round(z,2)
        while abs(self.PosZCurFloatMan.GetSingleValueAsDouble()[1]-z)>epsz:
            initpos = self.PosZCurFloatMan.GetSingleValueAsDouble()[1]
            t0 = time()
            self.PosZFloatMan.SetValue(z)
            distance = 2*epsz
            while distance > epsz:
                self.PosZCurFloatMan.Update()
                curpos = self.PosZCurFloatMan.GetSingleValueAsDouble()[1]
                distance = abs(curpos-z)
                if ((time()-t0>0.5) and abs(curpos-initpos)<epsz)  or (time()-t0>10.):
368
                    self.logger.warning(f"WARNING: signal z ignored after {time()-t0} seconds")
369 370 371
                    break
                sleep(.01)
            sleep(.1)
372 373
    
    @comErrorRepeater
374
    def saveImage(self, fname):
375 376 377 378
        """
        Save current camera image to file name
        :return:
        """
379 380 381 382
        assert self.connected
        self.ImageNameMan.SetValue(fname)
        self.ImageSaveMan.OperateTrigger()
        sleep(.1)
Josef Brandt's avatar
Josef Brandt committed
383

384
    @comErrorRepeater
385
    def getImageDimensions(self, mode = 'df'):
386 387
        """ 
        Get the image width and height in um and the orientation angle in degrees.
388 389 390 391 392
        """
        assert self.connected
        width, height = self.ImageWidthMan.GetValue(), self.ImageHeightMan.GetValue()
        angle = self.ImageRotationMan.GetValue()
        return width, height, angle
Josef Brandt's avatar
Josef Brandt committed
393 394 395 396 397 398 399 400 401 402 403

    # IT IS NOT NEEDED, ISN'T IT??
    # def startSinglePointScan(self):
    #     assert self.connected
    #     self.SequencerStartTrigger.OperateTrigger()
    #     # Wait until sequencer has finished
    #     while True:
    #         self.SequencerBusyStatus.Update()
    #         Busy = self.SequencerBusyStatus.GetSingleValueAsInt()[1]
    #         if not Busy:
    #             break
404 405 406

####TODO: should the below methods also get the comErrorRepeater?? Repeating these commands could mess up something...
    
407
    def initiateMeasurement(self, ramanSettings):
408
        assert self.connected
409 410 411 412
        if self.advancedInterface:
            self.doAutoFocus = ramanSettings["Autofocus"]
            
        if self.advancedInterface and self.doAutoFocus:
Josef Brandt's avatar
Josef Brandt committed
413 414
            self.initateSilentSpectrumAcquisition(ramanSettings)
        else:
415
            self.initiateTimeSeriesMeasurement(ramanSettings)
416
    
417 418 419
    def triggerMeasurement(self, num):
        if self.advancedInterface and self.doAutoFocus:
            self.doSpectralAutoFocus()
Josef Brandt's avatar
Josef Brandt committed
420
            self.acquireSilentSpectrum(num)
421 422
        else:
            self.triggerTimeSeriesMeasurement(num)
423
    
Josef Brandt's avatar
Josef Brandt committed
424
    def finishMeasurement(self, aborted=False):
425
        if self.advancedInterface and self.doAutoFocus:
Josef Brandt's avatar
Josef Brandt committed
426 427 428 429
            state = self.BeamPathState.GetValue()
            if state == 'Raman':
                self.MicroscopeIdle.SetValue('BeamPath|SetStateVideo')
                self.BeamPathSetVideoState.OperateTrigger()
Josef Brandt's avatar
Josef Brandt committed
430 431
            if not aborted:
                self.advSpec.createSummarizedSpecFiles()
Josef Brandt's avatar
Josef Brandt committed
432 433
            
    def initiateTimeSeriesMeasurement(self, ramanSettings):
434 435 436 437 438
        self.timeseries = ramanSettings['numPoints']
        self.TimeSeriesSlowNameMan.SetValue(ramanSettings['filename'])
        self.TimeSeriesSlowNumMeasurementsMan.SetValue(ramanSettings['numPoints'])
        self.TimeSeriesSlowNumAccumulationsMan.SetValue(ramanSettings['Accumulations'])
        self.TimeSeriesSlowIntTimeMan.SetValue(ramanSettings['IntegrationTime (s)'])
439 440 441
        self.TimeSeriesSlowModeMan.SetValueNumeric(0)
        self.TimeSeriesSlowNumMan.SetValue(0)
        self.TimeSeriesSlowStartMan.OperateTrigger()
Josef Brandt's avatar
Josef Brandt committed
442
    
443 444 445 446 447 448 449 450 451 452 453 454
        sleep(0.1)
        t1 = time()
        while True:
            self.TimeSeriesSlowActivityMan.Update()
            valid, act = self.TimeSeriesSlowActivityMan.GetSingleValueAsString()
            if act=="Waiting for next Measurement":
                break
            else:
                sleep(0.02)
                if time()-t1>3.:
                    print("Waiting for measurement ready...")
                    t1 = time()
Josef Brandt's avatar
Josef Brandt committed
455 456 457
    
    def initateSilentSpectrumAcquisition(self, ramanSettings):
        self.advSpec.setDatasetPath(ramanSettings['path'])
458
        self.advSpec.setSpectraBatchSize(ramanSettings['Spectra Batch Size'])
459 460 461
        
        self.doAutoFocus = ramanSettings['Autofocus']
        
Josef Brandt's avatar
Josef Brandt committed
462
        # self.advSpec.createTmpSpecFolder()
Josef Brandt's avatar
Josef Brandt committed
463 464 465 466 467 468 469 470
        state = self.BeamPathState.GetValue()
        if state == 'Video':
            self.MicroscopeIdle.SetValue('BeamPath|SetStateRaman')
            self.BeamPathSetRamanState.OperateTrigger()
        self.SingleSpecIntegrationTimeMan.SetValue(ramanSettings['IntegrationTime (s)'])
        self.SingleSpecNumAccsMan.SetValue(ramanSettings['Accumulations'])
    
    def triggerTimeSeriesMeasurement(self, num):
471 472 473 474 475 476 477 478 479 480 481 482
        assert self.timeseries
        self.TimeSeriesSlowNextMan.OperateTrigger()
        # Wait until sequencer has finished
        sleep(0.1)
        t1 = time()
        while True:
            ind = self.TimeSeriesSlowIndNextMan.GetValue()
            if ind>num:
                break
            else:
                sleep(0.02)
                if time()-t1>3.:
483
                    self.logger.info("Waiting for next index...")
484 485 486 487 488 489 490 491
                    t1 = time()
        while True:
            valid, act = self.TimeSeriesSlowActivityMan.GetSingleValueAsString()
            if act=="Waiting for next Measurement":
                break
            else:
                sleep(0.02)
                if time()-t1>3.:
492
                    self.logger.info("Waiting for measurement ready...")
493 494 495
                    t1 = time()
        if num==self.timeseries-1:
            self.timeseries = False
Josef Brandt's avatar
Josef Brandt committed
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
    
    def doSpectralAutoFocus(self):
        assert self.advancedInterface
        self.AutoFocusMan.OperateTrigger()
        self.waitForSequencerToFinish()
    
    def acquireSilentSpectrum(self, num):
        assert self.advancedInterface
        self.DoSilentSpectrum.SetValue(True)
        self.SequencerStartTrigger.OperateTrigger()
        self.waitForSequencerToFinish()
        
        out_spec = self.SilentSpecText.GetValue()
        out_spec = out_spec.split('\n')
        self.advSpec.registerNewSpectrum(out_spec, num)
        return out_spec
    
513
    @comErrorRepeater
Josef Brandt's avatar
Josef Brandt committed
514 515 516 517 518 519
    def waitForSequencerToFinish(self):
        while True:
            self.SequencerBusyStatus.Update()
            Busy = self.SequencerBusyStatus.GetSingleValueAsInt()[1]
            if not Busy:
                break