MSLNZ / msl-equipment

Manage and communicate with equipment in the laboratory
MIT License
15 stars 13 forks source link

Avantes disconnect() error #5

Closed mgehring999 closed 3 years ago

mgehring999 commented 3 years ago

I am getting the following error when using function disconnect() from Avantes with two devices. The error occurs only when two devices are used. I'm using Python 3.8.1 with Sublime Text 3

Avantes<Avantes|AvaSpec-2048CL-EVO|1911274U1 at SDK::C:/AvaSpecX64-DLL_9.10.1.0/
avaspecx64.dll> The <_FuncPtr object at 0x000000563E61AEE0> function returned Fa
lse
Traceback (most recent call last):
  File "junk/msl-test.py", line 92, in <module>
    while time.time()-start_time < total_time:
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "junk/msl-test.py", line 110, in <module>
    device.deactivate()
  File "C:\Users\Marc\AppData\Local\Programs\Python\Python38\lib\site-packages\m
sl\equipment\resources\avantes\avaspec.py", line 230, in deactivate
    self.sdk.AVS_Deactivate(self._handle)
  File "C:\Users\Marc\AppData\Local\Programs\Python\Python38\lib\site-packages\m
sl\equipment\resources\avantes\avaspec.py", line 207, in _check_bool
    self.raise_exception('The {} function returned False'.format(func))
  File "C:\Users\Marc\AppData\Local\Programs\Python\Python38\lib\site-packages\m
sl\equipment\connection.py", line 85, in raise_exception
    raise self._exception_handler('{!r}\n{}'.format(self, msg))
msl.equipment.exceptions.AvantesError: Avantes<Avantes|AvaSpec-2048CL-EVO|191127
4U1 at SDK::C:/AvaSpecX64-DLL_9.10.1.0/avaspecx64.dll>
The <_FuncPtr object at 0x000000563E61AEE0> function returned False
Avantes<Avantes|AvaSpec-2048CL-EVO|1911274U1 at SDK::C:/AvaSpecX64-DLL_9.10.1.0/
avaspecx64.dll> The <_FuncPtr object at 0x000000563E61AEE0> function returned Fa
lse
Exception ignored in: <function Connection.__del__ at 0x000000562DF218B0>
Traceback (most recent call last):
  File "C:\Users\Marc\AppData\Local\Programs\Python\Python38\lib\site-packages\m
sl\equipment\connection.py", line 74, in __del__
  File "C:\Users\Marc\AppData\Local\Programs\Python\Python38\lib\site-packages\m
sl\equipment\resources\avantes\avaspec.py", line 506, in disconnect
  File "C:\Users\Marc\AppData\Local\Programs\Python\Python38\lib\site-packages\m
sl\equipment\resources\avantes\avaspec.py", line 230, in deactivate
  File "C:\Users\Marc\AppData\Local\Programs\Python\Python38\lib\site-packages\m
sl\equipment\resources\avantes\avaspec.py", line 207, in _check_bool
  File "C:\Users\Marc\AppData\Local\Programs\Python\Python38\lib\site-packages\m
sl\equipment\connection.py", line 85, in raise_exception
msl.equipment.exceptions.AvantesError: Avantes<Avantes|AvaSpec-2048CL-EVO|191127
4U1 at SDK::C:/AvaSpecX64-DLL_9.10.1.0/avaspecx64.dll>
The <_FuncPtr object at 0x000000563E61AEE0> function returned False

The following code raises this error:

import time
from msl.equipment import EquipmentRecord, ConnectionRecord, Backend
from msl.equipment.resources.avantes.avaspec import ControlSettingsType

record1 = EquipmentRecord(
    manufacturer='Avantes',
    model='AvaSpec-2048CL-EVO',  # update for your device
    serial='1911275U1',  # update for your device
    connection=ConnectionRecord(
   address='SDK::C:/AvaSpecX64-DLL_9.10.1.0/avaspecx64.dll',  # update the path to the DLL file
    backend=Backend.MSL,
     )
 )

record2 = EquipmentRecord(
    manufacturer='Avantes',
    model='AvaSpec-2048CL-EVO',  # update for your device
    serial='1911274U1',  # update for your device
    connection=ConnectionRecord(
   address='SDK::C:/AvaSpecX64-DLL_9.10.1.0/avaspecx64.dll',  # update the path to the DLL file
    backend=Backend.MSL,
     )
 )

# initializes the Avantes SDK and establishes the connection to the spectrometer
ava1 = record1.connect()
ava2 = record2.connect()

## 1st device
params1 = ava1.get_parameter()
# get the number of pixels that the spectrometer has
num_pixels1 = ava1.get_num_pixels()
print('The spectrometer has %d pixels' % num_pixels1)

# get the wavelength value of each pixel
wavelengths1 = ava1.get_lambda()

# enable the 16-bit AD converter
ava1.use_high_res_adc(True)

# prepare the measurement type of the spectrometer
# (the values of just a few parameters are updated here, see the manual for more details)
cfg1 = ava1.MeasConfigType()
cfg1.m_StopPixel = num_pixels1 - 1
cfg1.m_IntegrationTime = 500  # in milliseconds
cfg1.m_NrAverages = 1  # number of averages

ava1.prepare_measure(cfg1)

## 2nd device
params2 = ava2.get_parameter()
# get the number of pixels that the spectrometer has
num_pixels2 = ava2.get_num_pixels()
print('The spectrometer has %d pixels' % num_pixels2)

# get the wavelength value of each pixel
wavelengths2 = ava2.get_lambda()

# enable the 16-bit AD converter
ava2.use_high_res_adc(True)

# prepare the measurement type of the spectrometer
# (the values of just a few parameters are updated here, see the manual for more details)
cfg2 = ava2.MeasConfigType()
cfg2.m_StopPixel = num_pixels2 - 1
cfg2.m_IntegrationTime = 500  # in milliseconds
cfg2.m_NrAverages = 1  # number of averages
CST = ControlSettingsType()
CST.m_StrobeControl = 3
cfg2.m_Control = CST
ava2.prepare_measure(cfg2)

DeviceConfig = ava2.get_parameter()
SpectrumCalibration = DeviceConfig.m_Reflectance
Smoothing = SpectrumCalibration.m_Smoothing
Smoothing.m_SmoothPix = 1
print(DeviceConfig.m_Reflectance.m_Smoothing.m_SmoothPix)
ava2.set_parameter(DeviceConfig)
DeviceConfig = ava2.get_parameter()
print(DeviceConfig.m_Reflectance.m_Smoothing.m_SmoothPix)
print(len(ava2.get_lambda()))

total_time = 600
meas_interval1 = 2
start_time = time.time()
elapsed_time1 = time.time()

devices  = [ava1, ava2]

try:
    while time.time()-start_time < total_time:
        # measurement loop
        if elapsed_time1 > meas_interval1:
            last_measure_time1 = time.time()
            # start single measurement, wait until the measurement is finished, then get the data
            for ava in devices :
                ava.measure(1)

            while not (ava2.poll_scan() and ava1.poll_scan()):
                time.sleep(0.01)
            print(ava1.poll_scan(),ava2.poll_scan())

            for ava in devices:
                time_count,data = ava.get_data()
                print("measured {}".format(ava._handle),len(data))
        elapsed_time1 = time.time() - last_measure_time1
except KeyboardInterrupt:
    for device in devices:
                device.deactivate()
        device.disconnect()
jborbely commented 3 years ago

I don't have access to two spectrometers from Avantes, so this will be difficult for me to debug.

Since this error occurs only after you have killed the script with a CTRL+C (a) does this Avantes error cause any issues in collecting/saving the data from a spectrometer or any other device you are using? or (b) is it an error that you prefer to not see before your script terminates? If (b) then you can try something like the following to suppress the error

try:
   # your while loop code
except KeyboardInterrupt:
    pass

try:
    for device in devices:
        device.deactivate()
        device.disconnect()
except:
    pass

What happens if you use two devices but only deactivate and disconnect from one of them?

jborbely commented 3 years ago

I will assume that you have implemented a workaround for this issue, but I will provide one additional comment.

The disconnect method calls the AVS_Deactivate and AVS_Done functions in the DLL. AVS_Deactivate requires the handle to a spectrometer as an input argument to close communication with that particular spectrometer (so calling device.deactivate() in a loop makes sense) but AVS_Done does not take any input arguments and, according to the manual, it "closes the communication and releases internal storage" so it should probably only be called once after the deactivate loop.

The following is an untested example

try:
   # your while loop code
except KeyboardInterrupt:
    for device in devices:
        device.deactivate()
    ava1.done()  # could use ava1 or ava2 to call the done() method once