从 dll 的 python 回调函数中接收数据

Receiving data in python callback function from dll

我正在 Python 中编写与 Avantes 的光谱仪通信的程序。有一些专有的 dll 可用,我无法访问其代码,但它们有一些不错的文档。我在寻找存储通过回调接收到的数据的好方法时遇到了一些麻烦。

专有共享库

基本上,dll 包含一个函数,我必须调用该函数才能开始测量,并且该函数接收一个回调函数,只要光谱仪完成测量,该回调函数就会被调用。函数如下:

int AVS_MeasureCallback(AvsHandle a_hDevice,void (*__Done)(AvsHandle*, int*),short a_Nmsr)

第一个参数是标识光谱仪的句柄对象,第二个是实际的回调函数,第三个是要进行的测量量。 回调函数将接收然后接收另一种类型的句柄,用于识别光谱仪和有关测量后可用数据量的信息。

Python图书馆

我正在使用 library,它有许多设备的 Python 包装器,包括我的光谱仪。

def measure_callback(self, num_measurements, callback=None):
    self.sdk.AVS_MeasureCallback(self._handle, callback, num_measurements)

并且他们还定义了以下装饰器:

MeasureCallback = FUNCTYPE(None, POINTER(c_int32), POINTER(c_int32))

想法是,当回调函数最终被调用时,这将触发 get_data() 函数,该函数将从设备中检索数据。

推荐的例子是

@MeasureCallback
def callback_fcn(handle, info):
    print('The DLL handle is:', handle.contents.value)
    if info.contents.value == 0:  # equals 0 if everything is okay (see manual)
       print('  callback data:', ava.get_data())

ava.measure_callback(-1, callback_fcn)

我的问题

我必须将接收到的数据存储在我在主代码的其他地方创建的 2D numpy 数组中,但我无法弄清楚用内部可用的新数据更新此数组的最佳方法是什么回调函数。 我想知道我是否可以将这个 numpy 数组作为参数传递给回调函数,但即使在这种情况下我也找不到一个好的方法来执行此操作,因为预计回调函数将只有这 2 个参数。


编辑 1

我找到了一个可能的解决方案 ,但我不确定这是最好的解决方案。我宁愿不创建一个新的 class 只是为了在里面保存一个 numpy 数组。


编辑 2

我实际上改变了我对我的方法的想法,因为在我的回调中我想对接收到的数据进行许多操作并将结果保存在许多不同的变量中。所以,我回到了 提到的 class 方法,我基本上会有一个 class,其中包含所有变量,这些变量将以某种方式在回调函数中使用,并且也将继承或有一个 class ava.

的对象

但是,如this other question所示,self参数在这种情况下是一个问题。

如果不想新建class,可以使用函数闭包:

# Initialize it however you want
numpy_array = ... 

def callback_fcn(handle, info):
    # Do what you want with the value of the variable
    store_data(numpy_array, ...)

# After the callback is called, you can access the changes made to the object
print(get_data(numpy_array))

这是如何工作的,当 callback_fcn 被定义时,它保留对变量 numpy_array 值的引用,所以当它被调用时,它可以操纵它,就好像它是作为参数传递给函数。所以你得到了传递它的效果,而回调调用者不必担心它。

我终于设法通过一个解决方案解决了我的问题,该解决方案包含一个新的 class 和一个闭包函数来处理描述 hereself 参数。除此之外,新创建的方法的垃圾收集会出现另一个问题。

我最终的解决方案是:

class spectrometer():
        
        def measurement_callback(self,handle,info):
            if info.contents.value >= 0:  
                timestamp,spectrum = self.ava.get_data()
                self.spectral_data[self.spectrum_index,:] = np.ctypeslib.as_array(spectrum[0:pixel_amount])
                self.timestamps[self.spectrum_index] = timestamp
                self.spectrum_index += 1
        
        def __init__(self,ava):
            self.ava = ava
            self.measurement_callback = MeasureCallback(self.measurement_callback)
            
        def register_callback(self,scans,pattern_amount,pixel_amount):
            self.spectrum_index = 0
            self.timestamps = np.empty((pattern_amount),dtype=np.uint32)
            self.spectral_data = np.empty((pattern_amount,pixel_amount),dtype=np.float64)
            self.ava.measure_callback(scans, self.measurement_callback)