Ive got a similar question to ctypes and array of structs but im not looking to return the structure. Rather, my structure is passed into the function call as a pointer and then i want the values pointed at by the pointer. see below:
from .h:
typedef struct NIComplexNumberF32_struct {
ViReal32 real;
ViReal32 imaginary;
} NIComplexNumberF32;
ViStatus _VI_FUNC niRFSA_FetchIQSingleRecordComplexF32(
ViSession vi,
ViConstString channelList,
ViInt64 recordNumber,
ViInt64 numberOfSamples,
ViReal64 timeout,
NIComplexNumberF32* data,
niRFSA_wfmInfo* wfmInfo);
i have made several attempts, but this was my latest:
import ctypes
class NIComplexNumberF32_struct_data(ctypes.Structure):
_fields_ = [("real", ctypes.c_float),
("imaginary", ctypes.c_float)]
class niRFSA_wfmInfo_struct_data(ctypes.Structure):
_fields_ = [("absoluteInitialX", ctypes.c_double),
("relativeInitialX", ctypes.c_double),
("xIncrement", ctypes.c_double),
("actualSamples", ctypes.c_double),
("offset", ctypes.c_double),
("gain", ctypes.c_double),
("reserved1", ctypes.c_double),
("reserved2", ctypes.c_double)
]
# ViStatus _VI_FUNC niRFSA_FetchIQSingleRecordComplexF32(
# ViSession vi,
# ViConstString channelList,
# ViInt64 recordNumber,
# ViInt64 numberOfSamples,
# ViReal64 timeout,
# NIComplexNumberF32* data,
# niRFSA_wfmInfo* wfmInfo);
#create instances
data = ctypes.POINTER(NIComplexNumberF32_struct_data)()
wfmInfo = ctypes.POINTER(niRFSA_wfmInfo_struct_data)()
dll_path = r"C:\Program Files\IVI Foundation\IVI\bin\NiRFSA_64.dll"
dll = ctypes.cdll.LoadLibrary(dll_path)
dll.niRFSA_FetchIQSingleRecordComplexF32.argtypes =(ViSession,ViString,ViReal64,ViReal64,ViReal64,ctypes.POINTER(NIComplexNumberF32_struct_data),ctypes.POINTER(niRFSA_wfmInfo_struct_data) )
dll.niRFSA_FetchIQSingleRecordComplexF32(handle,bytes('','ascii'),0,1000,1,data,wfmInfo)
Traceback (most recent call last):
RuntimeError: (-1074134952) IVI: (Hex 0xBFFA0058) Null pointer passed for parameter or attribute.
What i want are the real/imag data values from the array of data structure.
I have got to be missing something dumb. Hoping someone can point me in the right direction.
thanks all!!
This:
#create instances
data = ctypes.POINTER(NIComplexNumberF32_struct_data)()
wfmInfo = ctypes.POINTER(niRFSA_wfmInfo_struct_data)()
Is equivalent to the following C code:
struct NIComplexNumberF32* = NULL;
struct niRFSA_wfmInfo* = NULL;
It only creates NULL pointers and causes the RuntimeError
you see. Instead, create instances of each structure and pass them by address using ctypes.byref()
.
Here's a working example with a simplfied API since it wasn't provided: test.c
struct NIComplexNumberF32 {
float real;
float imaginary;
};
struct niRFSA_wfmInfo {
double absoluteInitialX;
double relativeInitialX;
double xIncrement;
double actualSamples;
double offset;
double gain;
double reserved1;
double reserved2;
};
__declspec(dllexport) // I'm using Windows, so needs this for function export from DLL
void niRFSA_FetchIQSingleRecordComplexF32(struct NIComplexNumberF32* p1, struct niRFSA_wfmInfo* p2) {
p1->real = 1.5f;
p1->imaginary = 2.75f;
p2->absoluteInitialX = 1.5;
p2->relativeInitialX = 2.5;
p2->xIncrement = 3.5;
p2->actualSamples = 4.5;
p2->offset = 5.5;
p2->gain = 6.5;
p2->reserved1 = 0.0;
p2->reserved2 = 0.0;
}
test.py
import ctypes as ct
class NIComplexNumberF32(ct.Structure):
_fields_ = (("real", ct.c_float),
("imaginary", ct.c_float))
# helper to print fields
def __repr__(self):
return f'({self.real}{self.imaginary:+}j)'
class niRFSA_wfmInfo(ct.Structure):
_fields_ = (("absoluteInitialX", ct.c_double),
("relativeInitialX", ct.c_double),
("xIncrement", ct.c_double),
("actualSamples", ct.c_double),
("offset", ct.c_double),
("gain", ct.c_double),
("reserved1", ct.c_double),
("reserved2", ct.c_double))
dll = ct.CDLL('./test')
dll.niRFSA_FetchIQSingleRecordComplexF32.argtypes = ct.POINTER(NIComplexNumberF32), ct.POINTER(niRFSA_wfmInfo)
dll.niRFSA_FetchIQSingleRecordComplexF32.restype = None
data = NIComplexNumberF32(5.125, 7.375) # If you want to initialize the fields to something besides default
print(data) # Uses __str__ or _repr__ function for display if defined (in that order)
wfmInfo = niRFSA_wfmInfo() # Init fields using defaults (0.0 for double type)
# This function doesn't use the input values.
# It returns data in both structures.
dll.niRFSA_FetchIQSingleRecordComplexF32(ct.byref(data), ct.byref(wfmInfo))
print(data) # Uses defined representation function (__repr__)
# access attributes directly...
print(wfmInfo.absoluteInitialX)
print(wfmInfo.relativeInitialX)
print(wfmInfo.gain)
Output:
(5.125+7.375j)
(1.5+2.75j)
1.5
2.5
6.5