swig python interfacing to function using void **
Question: 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 );
    


Answer: 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"
    

