2
votes

I'm using Python and ctypes to use a .dll supplied by a company for the use with a load cell amplifier. I manage to get a reading with their software, but I can't get my Python code to work. The company is ME-MessSysteme, and the amplifier is the GSV-2 (Manual Here).

The company's description of the function:

C: int GSVread ( int no, double *ad )

Taken from here, page 44. Sorry, but the guide is in German.

I'm getting a response from the amplifier after the activate function, but when I use the GSVread function, I can't get the result. I tried to pass a pointer to a double variable as I understand it returns the value to it. When I try to access the contents I get a "ValueError: NULL pointer access".

import ctypes
ret = ctypes.POINTER(ctypes.c_double)()
print(ret)
gsv = ctypes.cdll.LoadLibrary("DLLs_SENSOLYTICS/MEGSV.dll")
print(gsv.GSVactivate(7))
print(gsv.GSVstartTransmit(7))
print(gsv.GSVread(7, ret))
print(ret.contents)

7 indicating the COM port number.

Thank you all in advance!

****UPDATE***** Following on Dan's answer, the code that works is below:

    d = ctypes.c_double()
    ret = ctypes.byref(d)

    gsv = ctypes.cdll.LoadLibrary("DLLs_SENSOLYTICS/MEGSV.dll")
    print(gsv.GSVactivate(7, ctypes.c_long(256)))
    gsv.GSVflushBuffer(7)
    print(gsv.GSVstartTransmit(7))
    time.sleep(1)
    gsv.GSVread(7, ret)
    print(d)
1
Typically, just do d = ctypes.c_double(), then gsv.GSVread(7,ctypes.byref(d)). That passes the address of d to the function, and d.value will be the result when the function returns. It's also a good habit to explicitly define .argtypes and .restype for each function so ctypes can perform type checking and properly marshal the arguments to the C function. - Mark Tolonen

1 Answers

2
votes

You need to create two objects one the double and the other the pointer to the double:

>>> d = ctypes.c_double()
>>> ret = ctypes.pointer(d)
>>> ret.contents
c_double(0.0)

This can also be written as:

ret = ctypes.pointer(ctypes.c_double())

Which is oddly similar to:

ret = ctypes.POINTER(ctypes.c_double)()

The documentation states that ctypes.byref is a faster ctypes.pointer that doesn't actually allocate a real ctypes.pointer object so it can only be used to be be passed to a reference as an argument to a C function.

To use it one has to keep a direct reference to the double to be able to access the result as ctypes.byref objects do not have a contents property.

d = ctypes.c_double()
ret = ctypes.byref(d)