gpt4 book ai didi

python - 如何为 NI VeriStand 共享库传递带有 ctypes 的数组

转载 作者:行者123 更新时间:2023-11-30 16:19:21 29 4
gpt4 key购买 nike

我有一个 Simulink 模型,需要在 Python 中执行。我一直在使用 NI VeriStand 生成的 C 代码来编译 Linux 共享库,该库允许我在 Python 中执行模拟。

我想做的一件事是保存模拟的状态(即连续和离散变量以及时钟滴答)。 VeriStand 导出的 C 源代码为此目的提供了一个名为 NIRT_GetSimState 的函数。

DLL_EXPORT int32_t NIRT_GetSimState(int32_t* numContStates, char  * contStatesNames, double* contStates, int32_t* numDiscStates, char
* discStatesNames, double* discStates, int32_t* numClockTicks, char
* clockTicksNames, int32_t* clockTicks)
{
int32_t count = 0;
int32_t idx = 0;
if ((numContStates != NULL) && (numDiscStates != NULL) && (numClockTicks !=
NULL)) {
if (*numContStates < 0 || *numDiscStates < 0 || *numClockTicks < 0) {
*numContStates = 1;
*numDiscStates = 0;
*numClockTicks = NUMST - TID01EQ;
return NI_OK;
}
}

if ((contStates != NULL) && (contStatesNames != NULL)) {
idx = 0;
contStates[idx] = NIRT_GetValueByDataType(&(electric_motor_X.speed), 0, 0, 0);
strcpy(contStatesNames + (idx++ * 100), "speed");
}

if ((clockTicks != NULL) && (clockTicksNames != NULL)) {
clockTicks[0] = S->Timing.clockTick0;
strcpy(clockTicksNames, "clockTick0");
}

UNUSED_PARAMETER(count);
UNUSED_PARAMETER(idx);
return NI_OK;
}

我一直在尝试找到一种在 Python 中使用此函数(从共享库加载)的方法。

from ctypes import *
self._model = CDLL(model_lib)
self._lib_get_state = self._model.NIRT_GetSimState

我想找到一种方法将正确的数据类型传递给Python中的函数。据我了解,我需要将指针传递给整数和数组。

我正在使用以下函数进行测试。我正在使用 ctypes 创建变量和数组。

def _get_state(self):
numContStates = c_int(-999)
contStatesNames = (c_wchar_p*1)('a')
contStates = (c_double*1)(-999.99)
numDiscStates = c_int(-999)
discStatesNames = (c_wchar_p*1)('a')
discStates = (c_double*1)(-999.99)
numClockTicks = c_int(-999)
clockTicksNames = (c_wchar_p*1)('a')
clockTicks = (c_int*1)(-999)
self._lib_get_state(byref(numContStates), byref(contStatesNames), byref(contStates), byref(numDiscStates), byref(discStatesNames),
byref(discStates), byref(numClockTicks), byref(clockTicksNames), byref(clockTicks))
print('Number of continuous states: ', numContStates.value)
print('Number of discrete states: ', numDiscStates.value)
print('Number of clock ticks: ', numClockTicks.value)
print('Names of continuous states: ', list(contStatesNames)) # Expecting ['speed']
print('Values of continuous states: ', list(contStates)) # Expecting [0.0]

我似乎获得了离散和连续状态数量的正确值,但具有连续状态的数组及其名称未更新。这是该函数打印的内容:

Number of continuous states:  1
Number of discrete states: 0
Number of clock ticks: 1
Names of continuous states: ['a']
Values of continuous states: [-999.99]

所以,我们可以看到函数调用没有更新数组。我认为我可能没有使用正确的数据类型来调用该函数。这是我第一次使用 ctypes。

有人可以确认一下数据类型是否有错误吗?正确的语法应该是什么?

谢谢。

最佳答案

查看[Python 3]: ctypes - A foreign function library for Python .

Python 代码有一些问题:

而且该功能的设计方式也很差:

DLL_EXPORT int32_t NIRT_GetSimState(int32_t *numContStates, char *contStatesNames,
double *contStates, int32_t *numDiscStates,
char *discStatesNames, double *discStates,
int32_t *numClockTicks, char *clockTicksNames,
int32_t *clockTicks)
  • 太多的争论。这种情况需要一个容器(struct)来封装它们
  • 它似乎没有检查指针(1st for nullptr),然后只将数据转储到它们的地址,从不怀疑它是否超出了范围界限。这意味着函数调用者必须为所有缓冲区分配足够的空间,以便容纳信息。通常,处理这种情况:
    • 通过另一个指定缓冲区大小的参数,如果函数有更多数据要放入缓冲区,它要么不执行任何操作,要么填充缓冲区,最后返回错误
    • 函数分配内存(调用者有责任释放它)
  • 我发现许多字段都声明了长度为 1 的数组。如果只应该返回一个元素,则不要将其设为数组( (ctypes.c_double * 1)(-999.99) -> ctypes.c_double(-999.99) )。无论如何,我没有改变它

基于函数体,以下是让它工作的方法(这是一种方法 - 不用说我没有测试代码):

self._lib_get_state.argtypes = [
ctypes.POINTER(ctypes.c_int32), ctypes.POINTER(ctypes.c_char),
ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_double),
ctypes.POINTER(ctypes.c_int32), ctypes.POINTER(ctypes.c_char),
ctypes.POINTER(ctypes.c_int32),
]
self._lib_get_state.restype = ctypes.c_int32

numContStates = ctypes.c_int32(-999)
contStatesNames = ctypes.create_string_buffer(106) # The "speed" text is copied 100 characters from beginning
contStates = ctypes.c_double(-999.99)
numDiscStates = ctypes.c_int32(-999)
discStatesNames = (ctypes.c_char * 1)(b"a")
discStates = (ctypes.c_double * 1)(-999.99)
numClockTicks = ctypes.c_int32(-999)
clockTicksNames = ctypes.create_string_buffer(11) # Equivalent to: ctypes.c_char * 11
clockTicks = (ctypes.c_int32 * 1)(-999)

result = self._lib_get_state(
ctypes.byref(numContStates), ctypes.cast(contStatesNames, ctypes.POINTER(ctypes.c_char)),
ctypes.byref(contStates), ctypes.byref(numDiscStates),
ctypes.cast(discStatesNames, ctypes.POINTER(ctypes.c_char)), ctypes.cast(discStates, ctypes.POINTER(ctypes.c_double)),
ctypes.byref(numClockTicks), ctypes.cast(clockTicksNames, ctypes.POINTER(ctypes.c_char)),
ctypes.byref(clockTicks))


clockTicksNames.value # This is how to get the string out

关于python - 如何为 NI VeriStand 共享库传递带有 ctypes 的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55639541/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com