有一个滤镜轮SDK,名为“libEFWFilter.so”,由ZWO公司提供。下载链接是
https://dl.zwoastro.com/software?app=DeveloperEfwSdk&platform=windows86®ion=China
。
我想在Ubuntu20.04或CentOS7上使用python的ctypes或CFFI模块来调用这个动态库。以下是我的python程序:test.py.
#!/usr/bin/python3
import ctypes
from ctypes.util import find_library
import os
print(find_library("udev"))
print(find_library("EFWFilter"))
print(os.getcwd() + "/libEFWFilter.so.1.7")
libefw = ctypes.cdll.LoadLibrary(os.getcwd() + "/libEFWFilter.so.1.7")
当我运行这个test.py时,输出错误信息如下。
libudev.so.1
libEFWFilter.so.1.7
/home/ls/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64/libEFWFilter.so.1.7
Traceback (most recent call last):
File "test.py", line 11, in <module>
libefw = ctypes.cdll.LoadLibrary(os.getcwd() + "/libEFWFilter.so.1.7")
File "/usr/lib/python3.8/ctypes/__init__.py", line 451, in LoadLibrary
return self._dlltype(name)
File "/usr/lib/python3.8/ctypes/__init__.py", line 373, in __init__
self._handle = _dlopen(self._name, mode)
OSError: /home/ls/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64/libEFWFilter.so.1.7: undefined symbol: udev_enumerate_new
但是我已经安装了libudev库。
ls@ubuntu64:~/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64$ whereis libudev
libudev: /usr/lib/x86_64-linux-gnu/libudev.so /usr/include/libudev.h /usr/share/man/man3/libudev.3.gz
该公司提供的demo可以正确编译,可执行文件运行正常。 演示包含“main.cpp”、“EFW_filter.h”、“Makefile”。如下。
main.cpp
#include "stdio.h"
#include "EFW_filter.h"
#ifdef _WINDOWS
#include <windows.h>
#else
#include <sys/time.h>
#include <unistd.h>
#define Sleep(a) usleep((a)*1000)
#endif
int main()
{
int EFW_count = EFWGetNum();
if(EFW_count <= 0)
{
printf("no filter wheel connected, press any key to exit\n");
getchar();
return -1;
}
else
printf("attached filter wheel:\n");
EFW_INFO EFWInfo;
for(int i = 0; i < EFW_count; i++)
{
EFWGetID(i, &EFWInfo.ID);
EFWGetProperty(EFWInfo.ID, &EFWInfo);
printf("index %d: %s\n",i, EFWInfo.Name);
}
printf("\nselect one \n");
int EFWIndex, iSelectedID;
scanf("%d", & EFWIndex);
EFWGetID(EFWIndex, &iSelectedID);
if(EFWOpen(iSelectedID) != EFW_SUCCESS)
{
printf("open error,are you root?,press any key to exit\n");
getchar();
return -1;
}
if(iSelectedID < 0)
{
printf("open error,are you root?,press any key to exit\n");
getchar();
return -1;
}
else
{
EFW_ERROR_CODE err;
while(1){
err = EFWGetProperty(iSelectedID, & EFWInfo);
if(err != EFW_ERROR_MOVING )
break;
Sleep(500);
}
printf("%d slots: ", EFWInfo.slotNum);
for(int i = 0; i < EFWInfo.slotNum; i++)
printf("%d ", i + 1);
int currentSlot;
while(1)
{
err = EFWGetPosition(iSelectedID, ¤tSlot);
if(err != EFW_SUCCESS || currentSlot != -1 )
break;
Sleep(500);
}
printf("\ncurrent position: %d\n", currentSlot + 1);
int targetSlot;
char c;
printf("\nPlease input target position, type \'q\' to quit:\n");
while(1)
{
c = getchar();
if (EOF == c)
continue;
if(c == 'q')
break;
if(c >= '0' && c <= '9')
targetSlot = c - '0';
else
continue;
targetSlot--;
if(targetSlot < 0 || targetSlot >= EFWInfo.slotNum)
continue;
err = EFWSetPosition(iSelectedID, targetSlot);
if(err == EFW_SUCCESS)
printf("\nMoving...\n");
while(1)
{
err = EFWGetPosition(iSelectedID, ¤tSlot);
if(err != EFW_SUCCESS ||currentSlot != -1 )
break;
Sleep(500);
}
printf("\nPlease input target position, type \'q\' to quit:\n");
}
EFWClose(iSelectedID);
printf("main function over\n");
return 1;
}
}
EFW_filter.h
/**************************************************
this is the ZWO filter wheel EFW SDK
any question feel free contact us:[email protected]
here is the suggested procedure.
--> EFWGetNum
--> EFWGetID for each filter wheel
--> EFWGetProperty
--> EFWOpen
--> EFWGetPosition
--> EFWSetPosition
...
--> EFWClose
***************************************************/
#ifndef EFW_FILTER_H
#define EFW_FILTER_H
#ifdef _WINDOWS
#define EFW_API __declspec(dllexport)
#else
#define EFW_API
#endif
#define EFW_ID_MAX 128
typedef struct _EFW_INFO
{
int ID;
char Name[64];
int slotNum;
} EFW_INFO;
typedef enum _EFW_ERROR_CODE{
EFW_SUCCESS = 0,
EFW_ERROR_INVALID_INDEX,
EFW_ERROR_INVALID_ID,
EFW_ERROR_INVALID_VALUE,
EFW_ERROR_REMOVED, //failed to find the filter wheel, maybe the filter wheel has been removed
EFW_ERROR_MOVING,//filter wheel is moving
EFW_ERROR_ERROR_STATE,//filter wheel is in error state
EFW_ERROR_GENERAL_ERROR,//other error
EFW_ERROR_NOT_SUPPORTED,
EFW_ERROR_CLOSED,
EFW_ERROR_END = -1
}EFW_ERROR_CODE;
typedef struct _EFW_ID{
unsigned char id[8];
}EFW_ID;
typedef EFW_ID EFW_SN;
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************
Descriptions:
this should be the first API to be called
get number of connected EFW filter wheel, call this API to refresh device list if EFW is connected
or disconnected
Return: number of connected EFW filter wheel. 1 means 1 filter wheel is connected.
***************************************************************************/
EFW_API int EFWGetNum();
/***************************************************************************
Descriptions:
get the product ID of each wheel, at first set pPIDs as 0 and get length and then malloc a buffer to load the PIDs
Paras:
int* pPIDs: pointer to array of PIDs
Return: length of the array.
***************************************************************************/
EFW_API int EFWGetProductIDs(int* pPIDs);
/***************************************************************************
Descriptions:
get ID of filter wheel
Paras:
int index: the index of filter wheel, from 0 to N - 1, N is returned by GetNum()
int* ID: pointer to ID. the ID is a unique integer, between 0 to EFW_ID_MAX - 1, after opened,
all the operation is base on this ID, the ID will not change.
Return:
EFW_ERROR_INVALID_INDEX: index value is invalid
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetID(int index, int* ID);
/***************************************************************************
Descriptions:
open filter wheel
Paras:
int ID: the ID of filter wheel
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_GENERAL_ERROR: number of opened filter wheel reaches the maximum value.
EFW_ERROR_REMOVED: the filter wheel is removed.
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWOpen(int ID);
/***************************************************************************
Descriptions:
get property of filter wheel. SlotNum is 0 if not opened.
Paras:
int ID: the ID of filter wheel
EFW_INFO *pInfo: pointer to structure containing the property of EFW
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_MOVING: slot number detection is in progress, generally this error will happen soon after filter wheel is connected.
EFW_SUCCESS: operation succeeds
EFW_ERROR_REMOVED: filter wheel is removed
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetProperty(int ID, EFW_INFO *pInfo);
/***************************************************************************
Descriptions:
get position of slot
Paras:
int ID: the ID of filter wheel
int *pPosition: pointer to slot position, this value is between 0 to M - 1, M is slot number
this value is -1 if filter wheel is moving
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
EFW_ERROR_ERROR_STATE: filter wheel is in error state
EFW_ERROR_REMOVED: filter wheel is removed
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetPosition(int ID, int *pPosition);
/***************************************************************************
Descriptions:
set position of slot
Paras:
int ID: the ID of filter wheel
int Position: slot position, this value is between 0 to M - 1, M is slot number
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
EFW_ERROR_INVALID_VALUE: Position value is invalid
EFW_ERROR_MOVING: filter wheel is moving, should wait until idle
EFW_ERROR_ERROR_STATE: filter wheel is in error state
EFW_ERROR_REMOVED: filter wheel is removed
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWSetPosition(int ID, int Position);
/***************************************************************************
Descriptions:
set unidirection of filter wheel
Paras:
int ID: the ID of filter wheel
bool bUnidirectional: if set as true, the filter wheel will rotate along one direction
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWSetDirection(int ID, bool bUnidirectional);
/***************************************************************************
Descriptions:
get unidirection of filter wheel
Paras:
int ID: the ID of filter wheel
bool *bUnidirectional: pointer to unidirection value .
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetDirection(int ID, bool *bUnidirectional);
/***************************************************************************
Descriptions:
calibrate filter wheel
Paras:
int ID: the ID of filter wheel
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
EFW_ERROR_MOVING: filter wheel is moving, should wait until idle
EFW_ERROR_ERROR_STATE: filter wheel is in error state
EFW_ERROR_REMOVED: filter wheel is removed
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWCalibrate(int ID);
/***************************************************************************
Descriptions:
close filter wheel
Paras:
int ID: the ID of filter wheel
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWClose(int ID);
/***************************************************************************
Descriptions:
get version string, like "0, 4, 0824"
***************************************************************************/
EFW_API char* EFWGetSDKVersion();
/***************************************************************************
Descriptions:
get hardware error code of filter wheel
Paras:
int ID: the ID of filter wheel
bool *pErrCode: pointer to error code .
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetHWErrorCode(int ID, int *pErrCode);
/***************************************************************************
Descriptions:
Get firmware version of filter wheel
Paras:
int ID: the ID of filter wheel
int *major, int *minor, int *build: pointer to value.
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetFirmwareVersion(int ID, unsigned char *major, unsigned char *minor, unsigned char *build);
/***************************************************************************
Descriptions:
Get the serial number from a EFW
Paras:
int ID: the ID of focuser
EFW_SN* pSN: pointer to SN
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_ERROR_NOT_SUPPORTED: the firmware does not support serial number
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetSerialNumber(int ID, EFW_SN* pSN);
/***************************************************************************
Descriptions:
Set the alias to a EFW
Paras:
int ID: the ID of filter
EFW_ID alias: the struct which contains the alias
Return:
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_ERROR_NOT_SUPPORTED: the firmware does not support setting alias
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWSetID(int ID, EFW_ID alias);
#ifdef __cplusplus
}
#endif
#endif
生成文件
platform = x64
CC = g++
ifeq ($(platform), mac32)
CFLAGS += -m32 -framework IOKit -framework CoreFoundation
endif
ifeq ($(platform), mac64)
CFLAGS += -framework IOKit -framework CoreFoundation
endif
ifeq ($(platform), mac)
CFLAGS += -arch i386 -arch x86_64 -framework IOKit -framework CoreFoundation
endif
ifeq ($(platform), x86)
CFLAGS += -ludev
endif
ifeq ($(platform), x64)
CFLAGS += -ludev
endif
ifeq ($(platform), armv5)
CFLAGS += -ludev
endif
ifeq ($(platform), armv6)
CFLAGS += -ludev
endif
ifeq ($(platform), armv8)
CFLAGS += -ludev
endif
all:test_console
test_console: main.cpp
$(CC) main.cpp -o test_console $(CFLAGS) ../../lib/$(platform)/libEFWFilter.a -I../../include $(CFLAGS) -lpthread
cp test_console bin/$(platform)/
clean:
rm -f test_console
当我构建演示时,一切正常,没有错误。
我尝试过的事情:
但是上面的方法并没有解决这个“未定义符号”的问题。我注意到解决这个类似问题的一些解决方案是在 cpp 函数中添加“extern C”。但我无法做到这一点,因为我不知道 libEFWFilter.so 库的源代码。 那么我应该怎么做才能用python解决这个问题呢?非常感谢您的帮助!
@CristiFati,以下是当我在Python控制台中输入“ctypes.CDLL(“libudev.so”).udev_enumerate_new”并输入“dpkg -s libudev1:amd64”和“ldd ./libEFWFilter.so.1.7”时的输出信息在 Linux 终端中。
ls@ubuntu64:~/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64$ python3
Python 3.8.10 (default, Nov 22 2023, 10:22:35)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> print(ctypes.CDLL("libudev.so").udev_enumerate_new)
<_FuncPtr object at 0x7f70be96bb80>
>>> from ctypes.util import find_library
>>> print(find_library("udev"))
libudev.so.1
>>>
ls@ubuntu64:~/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64$ dpkg -s libudev1:amd64
Package: libudev1
Status: install ok installed
Priority: required
Section: libs
Installed-Size: 340
Maintainer: Ubuntu Developers <[email protected]>
Architecture: amd64
Multi-Arch: same
Source: systemd
Version: 245.4-4ubuntu3.23
Depends: libc6 (>= 2.30)
Description: libudev shared library
This library provides access to udev device information.
Homepage: https://www.freedesktop.org/wiki/Software/systemd
Original-Maintainer: Debian systemd Maintainers <[email protected]>
ls@ubuntu64:~/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64$ ldd ./libEFWFilter.so.1.7
linux-vdso.so.1 (0x00007ffd491f3000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f6866b1d000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f68669ce000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f68669b3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f68667c1000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6866f6e000)
从上面的消息来看,似乎没有问题。 但是“ldd ./libEFWFilter.so.1.7”的输出中没有“libudev.so”,可能是错误?,如何解决这个问题?再次感谢。