python - 如何将数组和结构传递给需要 3 个 u32 指针作为参数的 c 函数(ctypes)

标签 python c pointers shared-libraries ctypes

我必须使用 python 包装一个 C 库。

  • 这个库对于做很多低级的事情很有用(比如 JTAG 通信、PCI、GPIO 等)。
  • 当我必须将 3 个变量映射到库初始化的其他 3 个变量时,问题就出现了。
  • 这应该由一个以 3 个指针作为参数的库函数来完成。
  • 这 3 个变量是:2 维数组、1 维数组和结构体。
  • 正如我的同事告诉我的,这个函数应该采用这 3 个指针,并将三个库变量的地址分配给它们。
  • 不幸的是,如果我使用 python,映射将不起作用(我尝试使用 c# 并且它有效)。

经过多次尝试,我来这里向您寻求帮助。我没有 c 库代码,只有标题,所以我只能发布 python 代码和我使用的两个函数的声明。

来自标题:

//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()

来 self 的 Python 脚本:

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])

输出:

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

最后 3 个值应该不同。我知道:我已经更改了脚本中的第三个参数类型以传递结构,但我不知道如何以其他方式执行此操作。这是第一个问题。至少在调用 IR_DR_all_DUTs() 后我应该看到 tdo_arr 和 tdo_arr_ind 发生变化,但没有任何反应。

根据建议,我还发布了我同事编写的 C# 代码的一些部分。他制作了包装,然后制作了脚本。只要结构体在内存中分配得不好,他就会手动分配每个参数以使脚本正常工作,但理论上,使用 ctypes 应该不会出现问题。

C# 包装器:

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());
    }
  }
}

请问有谁可以帮助我吗?

PS:请随时纠正我的英语以使问题更清楚。

最佳答案

以下内容应该有效(当然未经测试):

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])

关于python - 如何将数组和结构传递给需要 3 个 u32 指针作为参数的 c 函数(ctypes),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58803314/

相关文章:

python - 作为键的单词词典和作为值出现的句子

python - 可以在不填充数据的情况下创建 BigQuery 表/模式吗?

c - 如何使用指针传递结构的二维数组

谁能解释一下C指针

c++ - C++ vector 迭代器与指针

python - 有 SimpleHTTPServer 的 Tornado 等效项吗?

python scipy差分进化优化失败,workers not 1

c - 没有功能指针的状态机

c - Windows 10 中的原始 UDP 套接字导致网络问题

在主函数中更改全局数组的大小