Creating Python interfaces for C libraries on Raspberry Pi

This tutorial shows how to interface a C library to a Python script on Raspberry Pi with VisualGDB. We will create a Python module exporting some basic functionality from the wiringPi library to the Python script and use it to control an LED connected to Raspberry Pi. Before you begin, install VisualGDB 5.1 or later.

  1. Our first step will be to install the debug build of Python to Raspberry Pi. Connect to your board via SmarTTY and run the following commands:
    sudo apt-get update
    sudo apt-get install python3.3-dev python3.3-dbg

    00b-python3-dbg

  2. Then download, build and install the wiringPi library:
    sudo apt-get install git-core
    git clone git://git.drogon.net/wiringPi
    cd wiringPi
    ./build

    00a-build

  3. Now that both Python and wiringPi are installed on your Raspberry, we will create a Visual Studio project demonstrating how to export the wiringPi functionality to Python. Start Visual Studio and launch the VisualGDB Linux Project Wizard:01-projname
  4. Select “Create a new project -> Python-based project”:02-module
  5. Then select “Build the project locally with a cross-compiler”, pick the Raspberry Pi cross-toolchain (if it’s not installed, VisualGDB will download and install it automatically) and choose the connection to your Raspberry Pi (select “Create a new SSH connection” if it’s not in the list):03-targetOnce you have selected the toolchain and the target, click “Synchronize headers and libraries”.
  6. Proceed with the default synchronization directories (if you only installed Python and wiringPi since last sync, you can uncheck the /opt directory to save some time):04-sync
  7. Finally select your python executable. Raspberry Pi uses slightly different naming for Python directories from the Desktop Linux, so you will need to select the include folder (e.g. /usr/include/python3.3dm) manually. Note that as you are using the debug build, you need to pick a directory containing the ‘d’ letter: 06-python
  8. Press “Finish” to generate the project. Before we add any wiringPi-specific code, quickly test that the project can be built and debugged. Set a breakpoint inside HelloMethod() and hit F5 to start debugging:07-dbgc
  9. Once the breakpoint is triggered, use the Call Stack window to navigate to the <module> frame and verify that you can see the Python source as well:08-dbgpy
  10. Now we will add the wiringPi support. Include the <wiringPi.h> file and replace the HelloMethod() together with the method table with the following code:
    template <int _Value> static PyObject *SetPin(PyObject *self, PyObject *args)
    {
        int pinNumber;
     
        if (!PyArg_ParseTuple(args, "d", &pinNumber))
            return Py_BuildValue("0", 1);
        
        digitalWrite(pinNumber, _Value);
        return Py_BuildValue("i", 1);
    }
     
    template <int _Value> static PyObject *SetMode(PyObject *self, PyObject *args)
    {
        int pinNumber;
     
        if (!PyArg_ParseTuple(args, "d", &pinNumber))
            return Py_BuildValue("0", 1);
        
        pinMode(pinNumber, _Value);
        return Py_BuildValue("i", 1);
    }
     
    static PyMethodDef PythonWiringDemoMethods[] = 
    {
        {
            "sethigh",
            SetPin<HIGH>,
            METH_VARARGS,
            "Sets an output pin value to HIGH" 
        },
            
        {
            "setlow",
            SetPin<LOW>,
            METH_VARARGS,
            "Sets an output pin value to LOW" 
        },
        
        {
            "makeoutput",
            SetMode<OUTPUT>,
            METH_VARARGS,
            "Configures a pin as output" 
        },
     
    { NULL, NULL, 0, NULL }        /* End of list */
    };

    09-setpin

  11. Insert a call to wiringPiSetupGpio() to the module initialization function:gpio
  12. Finally go to VisualGDB Project Properties and add “pthread” and “wiringPi” to the library names so that your module is actually linked against the wiringPi library:11-libs
  13. Now that we have added the sethigh(), setlow() and makeoutput() methods to our module, we will modify the Python script in the project to actually call them. However first we need to find a pin that we will control. According to the Raspberry Pi 2 pinout, GPIO pin #3 is the lower pin in the 3rd row of the GPIO connector opposite to the ground pin:gpio
  14. Connect an LED there and replace the contents of the Python script with the following code to make the LED on pin #3 blink:
    import PythonWiringDemo
    from time import sleep
    pin_number = 3
    PythonWiringDemo.makeoutput(pin_number)
     
    while 1:
        PythonWiringDemo.setlow(pin_number)
        sleep(0.2)
        PythonWiringDemo.sethigh(pin_number)
        sleep(0.2)

    12-py

  15. If you try running your program now, the program will exit immediately with a message stating that you need root privilege:13-noroot
  16. Open VisualGDB Project Properties, go to the Debug Settings page and enable the “Run debugger as root” checkbox:14-root
  17. Now you can press F5 to start debugging your program. The LED should now start blinking:led
  18. Set a breakpoint at the call to PythonWiringDemo.sethigh() and wait for it to trigger:15-sethighpy
  19. Stepping in would step into the Python’s code responsible for calling C functions, so instead set a breakpoint in the SetPin() function and press F5 to continue. See how our C++ wrapper gets called from the Python script and passes the pin number specified in the script to the digitalWrite() function provided by the wiringPi library:16-sethighcpp

You can use the technique described in this tutorial to interface any C/C++ library to the your Python scripts. Simply create a Python module referencing the library, define your functions in the function table and call the functions from the Python side.