1

I am currently trying to wrap a c-dll to controll a camera connected via USB. To grab image data off the camera, the SDK-Provider (Thorlabs) describes two possibilities:

  • Poll the camera in a loop
  • Use callbacks

I wrapped the DLL and got the polling method to work, which basically consists of calling a method which returns either NULL or the pending frame.

The DLL also provides methods to assign callback functions to certain events, such as camera connected/disconnected and frame available. The C-code from the example looks like this:

void camera_connect_callback(char* cameraSerialNumber, enum USB_PORT_TYPE usb_bus_speed, void* context)
{
    printf("camera %s connected with bus speed = %d!\n", cameraSerialNumber, usb_bus_speed);
}


int main(void)
{

    [...]

    // Set the camera connect event callback. This is used to register for run time camera connect events.
    if (tl_camera_set_camera_connect_callback(camera_connect_callback, 0))
    {
        printf("Failed to set camera connect callback!\n");
        close_sdk_dll();
        return 1;
    }

    [...]
}

My goal is now to get the callback working with python, so that python methods are called from the dll. Therefore, I used CFFI in API-mode to compile the wrapper, then tried to pass a callback method to the DLL in the same fashion:

@ffi.callback("void(char*, void*)")
def disconnect_callback(serialNumber, context):
    print("Disconnect callback was called!")

[...]

print("Set disconnect callback: {}".format(lib.tl_camera_set_camera_disconnect_callback(disconnect_callback, ffi.NULL)))

[...]

For testing purposes I only included the simplest callback in the working polling example. The setter method returns 0 but the method is never executed.

Is this even the right way of accomplishing my goal? Do I need to introduce some kind of threading so that the callback can interrupt the sequential execution of the remaining program? There is not much documentation or examples on this topic so Im really hoping you guys can help me out.

EDIT

So I tried a very basic example which works and technically answeres my question, but does not solve my problem.

if I define a C callback method as follows:

#include <math.h>

int quadcalc(int input, int (*getval)(int)){
    return (int) pow(getval(input), 2);
}

I can assign a handler as expected: (After compiling of course)

@ffi.callback("int(int)")
def callback_func(value):
    return int(rnd.random() * value)


if __name__ == '__main__':
    print(lib.quadcalc(10, callback_func))

And everything works as expected. Unfortunately, this doesn't work on the actual Problem. So callback works in general, but not in the specific case, which is why the question is still open.

1 Answers1

1

Do I need to introduce some kind of threading so that the callback can interrupt the sequential execution of the remaining program?

Invoking the Callback method takes care of setting up alternate program flows to capture the event, so it can be routed to a handler to be processed. When the defined event occurs, it does need handler code. For example, here is a very generic, but complete example of code that uses a callback in C (including the handler function.):

void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
    for (size_t i=0; i<arraySize; i++)
        array[i] = getNextValue();
}

// handler function
int getNextRandomValue(void)
{
    return rand();
}

int main(void)
{
    int myarray[10];
    populate_array(myarray, 10, getNextRandomValue);
    ...
}

There is an equally good example just below the first one, here.

Beyond these, there is a good tutorial in the CFFI documentation, with the first section dedicated to addressing your title question How to make a C-DLL wrapped with CFFI to callback python:

The first section presents a simple working example of using CFFI to call a C function in a compiled shared object (DLL) from Python.

Steps are: (see link above for details of each step.)
- Create the file piapprox_build.py:
- Execute this script:
- At runtime, you use the extension module like this:

...In the rest of this page, we describe some more advanced examples and other CFFI modes...

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • Thanks for your answer! To be clear, I got the DLL wrapping part working, to the point where I can call any method defined in the C-header for the DLL. I just cant get the callbacks to work at all. the C-Code example I posted does also work when compiled, but the assignment of python methods as callbacks is not working as I had hoped. Im quite sure its just wrong implementation – user3183627 Feb 18 '19 at 15:38
  • 1
    Are the callbacks referred to by the supplier SDK-Provider (Thorlabs) provided by them, or are you expected to define them? – ryyker Feb 18 '19 at 15:40
  • 1
    @user3183627 - Take a look at _[this link](https://valelab4.ucsf.edu/svn/micromanager2/trunk/DeviceAdapters/IDS_uEye/IDS_uEye.cpp)_. It refers to Thorlabs, and use of callbacks. It may provide some insight. – ryyker Feb 18 '19 at 15:45
  • The thorlabs SDK supplies the "set_callback_xxx" methods. The following typedefs are found in the header: `typedef void(*TL_CAMERA_CONNECT_CALLBACK)(char* cameraSerialNumber, enum TL_CAMERA_USB_PORT_TYPE usb_port_type, void* context);` `typedef int(*TL_CAMERA_SET_CAMERA_CONNECT_CALLBACK)(TL_CAMERA_CONNECT_CALLBACK handler, void* context);` – user3183627 Feb 18 '19 at 15:46
  • In the example code I provided in my answer above, only the callback _handler function_ is applicable if you find the right _installCallback_ method in that library. In the environment I use for example I simply call a provided function to create a callback, eg: CreateComCallback(,,,,handlerFunction,,); creates an instance for me. All I have to do is create the handler function. This appears to be what you need to do. ( i.e.1) call the correct _installCallback_ function from their selection of canned callbacks. 2) define you handler function. ) – ryyker Feb 18 '19 at 15:53