我必须使用 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/