Reputation: 41
BACKGROUND. I have an API (third party provided) consisting of C header files and a shared library. I have managed to create a shell script for the build environment, along with a simple interface file for swig. I am trying to make this API accessible to an IPython environment such that I don't have to compile C code all the time to communicate with the associated hardware that leverages this API for I/O.
PROBLEM. The first function call I need to do creates a board handle (some arbitrary "object" that is used for all other function calls in the C-side. The function accepts a void **, assuming the underlying function is probably malloc-ing memory, has some sort of internal structure, and allows accessing this memory by some of the other functions. Anyhow, I can't seem to properly interface to this from Python due to the lack of support for void * and receive a typeError.
The offending C code snippet, with typedef's/defines extracted from the underlying header files is:
#define WD_PVOID void*
typedef WD_PVOID WD_BOARD;
typedef WD_UINT32 WD_RetCode;
#define WD_EXPORT extern
#define WD_CHAR8 char
#define WD_UINT32 unsigned int
#---------------------------------------
//prototype
WD_EXPORT WD_RetCode wd_CreateBoardHandle( WD_BOARD *pBoardHandle, const WD_CHAR8 *pUrl );
//interpreted prototype
//extern unsigned int wd_CreateBoardHandle( void* *pBoardHandle, const char *pUrl );
A third party provided provided example (written in C) uses the function as so (I removed superfluous stuff) :
int main(int argc, char *argv [])
{
WD_RetCode rc;
Vhdl_Example_Opts cmdOpts = VHDL_EXAMPLE_DEFAULTS;
char urlBoard[VHDL_SHORT_STRING_LENGTH];
WD_BOARD BoardHandle;
sprintf(urlBoard, "/%s/%s/wildstar7/board%d", cmdOpts.hostVal, cmdOpts.boardDomain, cmdOpts.boardSlot);
rc = wd_CreateBoardHandle(&BoardHandle,urlBoard);
}
and lastly, my watered down swig interface file (I have been trying swig typedef's and *OUTPUT with no success):
%module wdapi
%{
#include "wd_linux_pci.h"
#include "wd_types.h"
#include "wd_errors.h"
%}
%import "wd_linux_pci.h"
%import "wd_types.h"
%import "wd_errors.h"
%include <typemaps.i>
WD_EXPORT WD_RetCode wd_CreateBoardHandle( WD_BOARD *pBoardHandle, const WD_CHAR8 *pUrl );
WD_EXPORT WD_RetCode wd_OpenBoard( WD_BOARD BoardHandle );
What I would like to be able to do is to call that function in python as so:
rslt,boardHandle = wdapi.wd_CreateBoardHandle("/foo/bar/etc")
Please let me know if I can provide any other information and I greatly appreciate your help/guidance towards a solution! I have spent days trying to review other similar issues posted.
EDIT. I manipulated some typedefs from other posts with similar issues. I am able to now call the functions and receive both a value in rslt and boardHandle as an object; however, it appears the rslt value is gibberish. Here is the new swig interface file (any thoughts as to the problem?):
%module wdapi
%{
#include "wd_linux_pci.h"
#include "wd_types.h"
#include "wd_errors.h"
%}
%import "wd_linux_pci.h"
%import "wd_types.h"
%import "wd_errors.h"
%include <python/typemaps.i>
%typemap(argout) WD_BOARD *pBoardHandle
{
PyObject *obj = PyCObject_FromVoidPtr( *$1, NULL );
$result = PyTuple_Pack(2, $result, obj);
}
%typemap(in,numinputs=0) WD_BOARD *pBoardHandle (WD_BOARD temp)
{
$1 = &temp;
}
%typemap(in) WD_BOARD {
$1 = PyCObject_AsVoidPtr($input);
}
WD_EXPORT WD_RetCode wd_CreateBoardHandle( WD_BOARD *pBoardHandle, const WD_CHAR8 *pUrl );
WD_EXPORT WD_RetCode wd_OpenBoard( WD_BOARD BoardHandle );
WD_EXPORT WD_RetCode wd_DeleteBoardHandle( WD_BOARD BoardHandle );
WD_EXPORT WD_RetCode wd_IsBoardPresent( const WD_CHAR8 *pUrl, WD_BOOL *OUTPUT );
Upvotes: 2
Views: 174
Reputation: 41
I resolved my own question. The edited swig interface file, listed above in my original post, turned out to correct my issue. Turns out that somewhere along the way, I mangled the input to my function call in python and the error code returned was "undefined" from the API.
On another note, while investigating other options, I also found "ctypes" which brought me to a solution first. Rather than dealing with wrapper code and building a 2nd shared library (that calls another), ctypes allowed me to access it directly and was much easier. I will still evaluate which I will move forward with. ctypes python code is listed below for comparison (look at the c-code example I listed in the original post) :
from ctypes import cdll
from ctypes import CDLL
from ctypes import c_void_p
from ctypes import addressof
from ctypes import byref
import sys
#Update Library Path for shared API library
sys.path.append('/usr/local/lib');
#Load the API and make accessible to Python
cdll.LoadLibrary("libwdapi.so")
wdapi = CDLL("libwdapi.so")
#Create the url for the board
urlBoard='/<server>/<boardType>/<FGPAType>/<processingElement>'
#Lets create a void pointer for boardHandle object
pBoardHandle=c_void_p()
#now create & open the board
rtn = wdapi.wd_CreateBoardHandle(byref(pBoardHandle),urlBoard)
if (rtn) :
print "Error"
else :
print "Success"
Upvotes: 2