2

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 );

1 Answer 1

2

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"
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.