簡體   English   中英

如何為 NI VeriStand 共享庫傳遞帶有 ctypes 的數組

[英]How to pass arrays with ctypes for NI VeriStand shared library

我有一個需要從 Python 中執行的 Simulink 模型。 我一直在使用 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 - 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 )來封裝它們
  • 它似乎沒有檢查指針(第一個nullptr ),然后只將數據轉儲到它們的地址,從不懷疑它是否越界。 這意味着函數調用者必須為所有緩沖區分配足夠的空間,以便信息適合。通常,處理這種情況:
    • 通過另一個指定緩沖區大小的參數,如果函數有更多數據要放入緩沖區,它要么不做任何事情要么填充緩沖區,最后返回錯誤
    • 函數分配內存(釋放它是調用者的責任)
  • 我看到對於許多字段,聲明了長度為 1 的數組。 如果應該只返回一個元素,則不(ctypes.c_double * 1)(-999.99)數組( (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 代碼上,而是在我調用 C 代碼的方式上。 第一次調用該函數以獲取要分配的數組的長度,第二次調用以將變量復制到數組中。

self._lib_get_state = self._model.NIRT_GetSimState

self.num_cont_states = c_int(-999)
self.num_disc_states = c_int(-999)
self.num_clock_ticks = c_int(-999)

self._lib_get_state(byref(self.num_cont_states), byref(c_char()), byref(c_double()),
    byref(self.num_disc_states), byref(c_char()), byref(c_double()),
    byref(self.num_clock_ticks), byref(c_char()), byref(c_int()))

self._cont_states_names = create_string_buffer(b'\000' * (100*self.num_cont_states.value))
self._cont_states = (c_double*self.num_cont_states.value)()
self._disc_states_names = create_string_buffer(b'\000' * (100*self.num_disc_states.value))
self._disc_states = (c_double*self.num_disc_states.value)()
self._clock_ticks_names = create_string_buffer(b'\000' * (100*self.num_clock_ticks.value))
self._clock_ticks = (c_int*self.num_clock_ticks.value)()

self._lib_get_state(byref(self.num_cont_states), self._cont_states_names,
    self._cont_states, byref(self.num_disc_states), self._disc_states_names,
    self._disc_states, byref(self.num_clock_ticks), self._clock_ticks_names,
    self._clock_ticks)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM