Странное измененное поведение при линковке из .so файла с помощью ctypes в python - PullRequest
2 голосов
/ 21 мая 2010

Я пишу программу для обработки данных с высокоскоростной камеры для моего доктора философии. проект. Эта камера поставляется с SDK в виде файла .so в Linux для связи с камерой и получения изображений. Как уже говорилось, это высокоскоростная камера, доставляющая много данных (несколько ГБ в минуту). Для обработки такого количества данных в SDK есть очень удобная функция буферизации, которая распределяет данные непосредственно на жесткий диск через DMA в форме файла FITS, необработанного двоичного формата с заголовком, который используется в астрономии. Эта функция прекрасно работает, когда я пишу небольшую программу на C, связываю файл .so и вызываю функцию спула таким образом. Но когда я обертываю файл .so ctypes и вызываю функции из python, все функции работают, кроме функции спула. Когда я вызываю функцию спула, она не возвращает ошибок, но буферный файл данных искажается, файл имеет правильный формат, но половина всех фреймов равна нулю. В моем мире не имеет смысла, что функция в файле .so должна вести себя по-разному, в зависимости от того, из какой программы она вызывается, моей собственной маленькой программы на C или python, которая, в конце концов, всего лишь большая программа на C. Есть ли у какого-либо тела ключ к пониманию того, что отличается при вызове .so из разных программ?

Буду очень благодарен за любые предложения

Несмотря на то, что камера коммерческая, некоторые драйверы доступны и доступны, хотя и немного сложнее. (к сожалению, не функция спулинга, кажется) У меня есть объект в python для камеры Генделя.

Начало занятия гласит:

class Andor:
  def __init__(self,handle=100):
    #cdll.LoadLibrary("/usr/local/lib/libandor.so")
    self.dll = CDLL("/usr/local/lib/libandor.so")
error = self.dll.SetCurrentCamera(c_long(handle))
    error = self.dll.Initialize("/usr/local/etc/andor/")

    cw = c_int()
    ch = c_int()
    self.dll.GetDetector(byref(cw), byref(ch))

Соответствующая функция гласит:

def SetSpool(self, active, method, path, framebuffersize):
    error = self.dll.SetSpool(active, method, c_char_p(path), framebuffersize)
    self.verbose(ERROR_CODE[error], sys._getframe().f_code.co_name)
    return ERROR_CODE[error]

И в соответствующем заголовке написано:

unsigned int SetSingleTrackHBin(int bin);

unsigned int SetSpool(int active, int method, char * path, int framebuffersize);

unsigned int SetStorageMode(at_32 mode);

unsigned int SetTemperature(int temperature);

Код для запуска камеры будет выглядеть примерно так:

cam = andor.Andor()
cam.SetReadMode(4)
cam.SetFrameTransferMode(1)
cam.SetShutter(0,1,0,0)
cam.SetSpool(1,5,'/tmp/test.fits',10);
cam.GetStatus()
if cam.status == 'DRV_IDLE':
acquireEvent.clear()
cam.SetAcquisitionMode(3)
cam.SetExposureTime(0.0)
cam.SetNumberKinetics(exposureNumber)
cam.StartAcquisition()

1 Ответ

0 голосов
/ 02 сентября 2010

Я предполагаю, что это не сам вызов функции спулинга, а серия вызовов, в результате которой искаженные значения передаются в / из библиотеки.

Вы на 64-битной платформе? Если не указать restype для чего-либо, что возвращает 64-битное целое число (long с gcc) или указатель, то эти значения будут молча усечены до 32 бит. Кроме того, обработка ctypes.c_voidp немного удивительна - restype значения ctypes.c_voidp не усекаются, а возвращаются в интерпретаторе Python как тип int, с предсказуемо веселыми результатами, если высокие указатели возвращаются как параметры другие функции без приведения.

Я не проверял его, но оба эти условия могут также повлиять на 32-разрядные платформы для значений, превышающих sys.maxint.

Единственный способ быть на 100% уверенным, что вы передаете и получаете ожидаемые значения, это указать argtypes и restype для всех функций, которые вы вызываете. И это включает в себя создание Structure классов и связанных POINTER s для всех struct s, с которыми работают эти функции, даже непрозрачных struct s.

...