I am trying to call some c code generated by the Matlab coder. Matlab uses a c struct called emxArray to represent matrices (documented here: http://www.mathworks.co.uk/help/fixedpoint/ug/c-code-interface-for-unbounded-arrays-and-structure-fields.html).
struct emxArray_real_T
{
double *data;
int *size;
int allocatedSize;
int numDimensions;
boolean_T canFreeData;
};
I have little experience ctypes and am struggling to create an equivalent struct that I can then use to pass vectors back and forth to the functions defined in the c .so
Here is where I have got so far in python...
class EmxArray(ctypes.Structure):
""" creates a struct to match emxArray_real_T """
_fields_ = [('data', ctypes.POINTER(ctypes.c_double)),
('size', ctypes.POINTER(ctypes.c_int)),
('allocatedSize', ctypes.c_int),
('numDimensions', ctypes.c_int),
('canFreeData', ctypes.c_bool)]
However if I define this:
data = (1.1, 1.2, 1.3, 1.4)
L = len(data)
x = EmxArray()
x.data = (ctypes.c_double * L)(*data)
x.data = (ctypes.c_int * 1)(L)
this then works
print len(x.data[:L])
for v in x.data[:L]: print v
Edit: I have tidied up and adopted Roland's suggestion and can extract the data using
data_out = x.data[:L]
I need to investigate further to see if I can successfully use this struct to pass and receive data from the c code.
Solution
Implementing the ctypes struct as suggested by Roland didn't work - the returned values were garbage, I never worked out why as I pursued a python based implementation of lilbil's answer. I've accepted that answer as it was closest...
I'll document my solution here as it might save someone else wasting as much time as I have.
Firstly I've generated a simple matlab function that multiplies each element of a function by itself & used the coder to compile this to a c .so. This is imported to python using ctypes. The code is as follows...
import ctypes
LIBTEST = '..../dll/emx_test/'
EMX = ctypes.cdll.LoadLibrary(LIBTEST + 'emx_test.so')
init = EMX.emx_test_initialize()
# Create a data structure to hold the pointer generated by emxCreateWrapper...
class Opaque(ctypes.Structure):
pass
# make some random data to pass in
data_in = [1., 2., 4., 8., 16.]
L = len(data_in)
# create an empty array of the same size for the output
data_ou = [0] * L
# put this in a ctypes array
ina = (ctypes.c_double * L)(*data_in)
oua = (ctypes.c_double * L)(*data_ou)
# create a pointer for these arrays & set the rows and columns of the matrix
inp = ctypes.pointer(ina)
oup = ctypes.pointer(oua)
nrows = ctypes.c_int(1)
ncols = ctypes.c_int(L)
# use EMX.emxCreateWrapper_real_T(double *data, int rows, int cols) to generate an emx wrapping the data
# input arg types are a pointer to the data NOTE its not great to have to resize the ctypes.c_double but cant see another way
EMX.emxCreateWrapper_real_T.argtypes = [ctypes.POINTER(ctypes.c_double * L), ctypes.c_int, ctypes.c_int]
# a pointer to the emxArray is returned and stored in Opaque
EMX.emxCreateWrapper_real_T.restype = ctypes.POINTER(Opaque)
# use emxCreateWrapper
in_emx = EMX.emxCreateWrapper_real_T(inp, nrows, ncols)
ou_emx = EMX.emxCreateWrapper_real_T(oup, nrows, ncols)
# so now we have to emx's created and have pointers to them we can run the emx_test
# emx test looks like this in matlab
#
# function res = emx_test ( in )
# res = in .* in;
# end
#
# so basically it multiplies each element of the matrix by itself
#
# therefore [1., 2., 4., 8., 16.] should become [1., 4., 8., 64., 256.]
EMX.emx_test(in_emx, ou_emx)
# and voila...that's what we get
print 'In: ', ina[:L]
print 'Out:', oua[:L]
Output:
In: [1.0, 2.0, 4.0, 8.0, 16.0]
Out:[1.0, 4.0, 16.0, 64.0, 256.0]
Thank you to everyone for your time & suggestions.
Just create a pointer, assign the data afterwards;
import ctypes
class EmxArray(ctypes.Structure):
""" creates a struct to match emxArray_real_T """
_fields_ = [('data', ctypes.POINTER(ctypes.c_double)),
('size', ctypes.POINTER(ctypes.c_int)),
('allocatedSize', ctypes.c_int),
('numDimensions', ctypes.c_int),
('canFreeData', ctypes.c_bool)]
data = (1.3, 3.5, 2.7, 4.1)
L = len(data)
e = EmxArray()
e.data = (ctypes.c_double * L)(*data)
e.size = (ctypes.c_int * 1)(L)
# et cetera