简体   繁体   中英

How to pass arrays and struct to c function that wants 3 u32 pointers as arguments (ctypes)

I have to wrap a c library by using python.

  • This library is useful to do a lot of low-level stuff (like JTAG communication, PCI, GPIO and so on).
  • The problems come when I have to map 3 variables to other 3 variables initialized by the library.
  • This should be done by a library function that takes 3 pointers as arguments.
  • These 3 variables are: 2-dim array, 1-dim array and a struct.
  • As my colleague told me, this function should take those 3 pointers and assign to them the addresses of three library variables.
  • Unfortunately the mapping doesn't work if I use python (I tried with c# and it works).

After a lot of attempts I am here to ask you for some help. I do not have the c-library code but only the header, so I can post only the python code and the declaration of the two functions I use.

From the header:

//the function that should map the variables
u32 TDO_data_transfer(u32* tdo_arr, u32* tdo_arr_ind, u32* data_struct)
//a function that modifies the arrays and the struct
u32 IR_DR_all_DUTs()

From my Python script:

from ctypes import *

#Simplify wrapping ctypes functions
def wrap_function(lib, funcname, restype, argtypes):
    func = lib.__getattr__(funcname)
    func.restype = restype
    func.argtypes = argtypes
    return func

filename = "libIBISGen3.so"
libc = CDLL(filename)

tdo=c_uint32()
tdo_ind=c_uint32()    
tdo_arr = pointer(tdo)
tdo_arr_ind = pointer(tdo_ind)

class cerberus_parameter_s(Structure):
    _fields_ = [
        ('opCode', c_uint8),
        ('bitCount', c_uint16),
        ('data', c_uint32*32),
        ('tmsAddress', c_uint8),
        ('readTDO', c_bool),        
        ('isIR', c_bool),
        ('dataTDI', c_uint32*32)
     ]

#create cerberus struct
dt= (c_uint32 * 32)(0)
dtTDI= (c_uint32 * 32)(0)
cerberus= cerberus_parameter_s(0,0,dt,0,0,0,dtTDI)

TDO_data_transfer = wrap_function(libc, 'TDO_data_transfer', c_uint32, [POINTER(c_uint32), POINTER(c_uint32), POINTER(cerberus_parameter_s)])
print(cerberus.readTDO)
print("TDO_data_transfer() returns: ", TDO_data_transfer(tdo_arr, tdo_arr_ind, byref(cerberus)))
print(cerberus.readTDO)
print(cerberus.data[0])
print(tdo_arr[5])

irDrAllDuts = wrap_function(libc, 'IR_DR_all_DUTs', c_uint32,[])
print("IR_DR_all_DUTs() returns: ", irDrAllDuts())
print(cerberus.readTDO)
print(cerberus.data[0])
print(tdo_arr[5])

Output:

TDO_data_transfer() returns:  0
False
0
0
IR_DR_all_DUTs() returns:  50
False
0
0

The last 3 values should be different. I know: I have changed the third argument type in my script to pass the structure, but I don't know how to do it in another way. This is the first problem. At least I should see changes in tdo_arr and tdo_arr_ind after calling IR_DR_all_DUTs() but nothing happens.

As suggested, I post also some parts of the c# code made by my colleague. He made a wrapper and then the script. As long as the struct wasn't well allocated in the memory, he allocated manually every parameter to make the script working, but theoretically, this should not be a problem using ctypes.

C# wrapper:

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace IBISGen3CBFramework
{
  public static class libIBIS_Gen3
  {
    ...
    public static unsafe class JTagParameter
    {
        public static byte* OpCode;
        public static ushort* BitCount;
        public static uint* DataTms;
        public static byte* TmsAddress;
        public static byte* ReadTdo;
        public static byte* IsIr;
        public static uint* DataTdi;

        public static int GetDataMaxLength()
        {
            return (int)(((uint)TmsAddress - (uint)DataTms) >> 2);
        }
        public static void Init(uint* structStartAddress)
        {
            uint nAddr = (uint)structStartAddress;
            OpCode = (byte*)nAddr;
            BitCount = (ushort*)(nAddr + 2);
            DataTms = (uint*)(nAddr + 4);
            TmsAddress = (byte*)(nAddr + 0x84);
            ReadTdo = (byte*)(nAddr + 0x85);
            IsIr = (byte*)(nAddr + 0x86);
            DataTdi = (uint*)(nAddr + 0x88);
        }
    }
    ...
    [DllImport("libIBIS_Gen3", EntryPoint = "TDO_data_transfer")]
    private static extern uint TDO_data_transfer(ref IntPtr resultPtr, ref IntPtr lengthPtr, ref IntPtr structPtr);
    public static unsafe void GetResultPointer(out uint* resultArr, out uint* lengthArr, out uint maxLength)  
    {
        IntPtr ptr = new IntPtr();
        IntPtr ptr2 = new IntPtr();
        IntPtr ptr3 = new IntPtr();
        maxLength = TDO_data_transfer(ref ptr, ref ptr2, ref ptr3);
        resultArr = (uint*)ptr.ToPointer();
        lengthArr = (uint*)ptr2.ToPointer();
        JTagParameter.Init((uint*)ptr3.ToPointer());
    }
  }
}

Is there anyone who could help me, please?

PS: feel free to correct my english in order to make the question clearer.

The following should work (of course not tested):

from ctypes import *

#Simplify wrapping ctypes functions
def wrap_function(lib, funcname, restype, argtypes):
    func = lib.__getattr__(funcname)
    func.restype = restype
    func.argtypes = argtypes
    return func

filename = "libIBISGen3.so"
libc = CDLL(filename)

class cerberus_parameter_s(Structure):
    _fields_ = [
        ('opCode', c_uint8),
        ('bitCount', c_uint16),
        ('data', c_uint32*32),
        ('tmsAddress', c_uint8),
        ('readTDO', c_bool),        
        ('isIR', c_bool),
        ('dataTDI', c_uint32*32)
     ]

tdo_arr = POINTER(c_uint32)()
tdo_arr_ind = POINTER(c_uint32)()
cerberus_p = POINTER(cerberus_parameter_s)()

TDO_data_transfer = wrap_function(libc, 'TDO_data_transfer', c_uint32, [POINTER(POINTER(c_uint32)), POINTER(POINTER(c_uint32)), POINTER(POINTER(cerberus_parameter_s))])
print("TDO_data_transfer() returns: ", TDO_data_transfer(byref(tdo_arr), byref(tdo_arr_ind), byref(cerberus_p)))

cerberus = cerberus_p.contents
print(cerberus.readTDO)
print(cerberus.data[0])
print(tdo_arr[5])

irDrAllDuts = wrap_function(libc, 'IR_DR_all_DUTs', c_uint32,[])
print("IR_DR_all_DUTs() returns: ", irDrAllDuts())
print(cerberus.readTDO)
print(cerberus.data[0])
print(tdo_arr[5])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM