nidaqmx-python icon indicating copy to clipboard operation
nidaqmx-python copied to clipboard

Event Callbacks Contain Unusable Parameters

Open maxxboehme opened this issue 3 years ago • 5 comments

Original discussion on NI's forms.

DAQmx's event callback signatures include a Task ID and callbackData parameters even though there currently isn't a way to get a task object from a Task ID or be able to pass in user provided callbackData (register_every_n_samples_acquired_into_buffer_event passes None as the data.)

Having to specify these to parameters in the signature even though they are not usable is confusing the users.

These are 2 ideas on how to improve this.

  • Provide a way to pass in user provided data and get a task object from a Task ID.
  • Make the callback signature that users provide not have to specify those and wrap their callback in an internal one to the event register functions.
    • Might also be able to pass reference to task object that referenced it by passing self from internal_callback wrapper.

maxxboehme avatar Feb 08 '22 21:02 maxxboehme

Is there really no way to pass user variables in for callback_data? That would be unfortunate.

joshSonera avatar Aug 31 '22 04:08 joshSonera

You can reference variables in the callback by creating an inner function (also called nested function) and Python allows you to reference variables from the enclosing function. You can see this being done in the every_n_samples_event.py example with the "callback" inner function referencing "samples" from the enclosed function.

maxxboehme avatar Aug 31 '22 14:08 maxxboehme

Ahh I see, thank you very much!

joshSonera avatar Aug 31 '22 20:08 joshSonera

Thanks, this helped me as well.

For anyone else reading this in the future, here the perma-link to the code version referenced above by @maxxboehme :

https://github.com/ni/nidaqmx-python/blob/caf1b1cede57b5413d96077ba3ee61e243d83547/nidaqmx_examples/every_n_samples_event.py#L21

JoKeyser avatar Jul 25 '24 15:07 JoKeyser

FYI, here are two ways to pass user variables to the callback without using local functions (untested):

  • Use functools.partial
    def callback_with_extra_param(extra_param, task_handle, every_n_samples_event_type, number_of_samples, callback_data):
        ...
    
    callback = functools.partial(callback_with_extra_param, 123)
    task.register_every_n_samples_acquired_into_buffer_event(1000, callback)
    
  • Write a class with a __call__ method
    class CallbackWithExtraParam:
        def __init__(self, extra_param):
            self.extra_param = extra_param
    
        def __call__(self, task_handle, every_n_samples_event_type, number_of_samples, callback_data):
           ...
    
    callback = CallbackWithExtraParam(123)
    task.register_every_n_samples_acquired_into_buffer_event(1000, callback)
    

(Still, we should fix this.)

bkeryan avatar Jul 25 '24 20:07 bkeryan