Interfacing with C++ libraries from micropython

Hey,

I’m currently working on a project that I’ve written a C++ library for. I’m now wondering what the idiomatic way would be to call the library from micropython code. Do I have to create a interface myself or is there a much easier (more automated) way? As I need to interface with external hardware I’d like to not have to re-implement everything for micropython.

I’m using FemtoIDE to test and compile the programs.

Any help or hints into the right direction are very much appreciated.

2 Likes

You have to implement the wrapper functions in two places.

  1. Make a methods in MicroPython C-implementation. That enables to call the functions from a python script.
  2. Create a “python binding” wrapper with which you can forward the C-method to C++ method call to PokittoLib (or your own C++ API).

So the call goes like this:
python script => micropython internal C-implementation => C/C++ wrapper => PokittoLib

This is e.g. how I have made the Tilemap class of PokittoLib to be used from the python script.

So there is not very easy way :wink:

Of course, as everything is open source, you can make all kinds of dirty hacks and use existing PokittoLib functions (which have python bindings already) for the purpose they are not designed for, but that is evil :wink:

3 Likes

I’m also interested in this.

Could you give an example with some code?
(It doesn’t have to be complex, forwarding some integers to a C++ function would be enough.)

I’ve used Lua’s C API before to bind C++ code to Lua functions,
but I’ve never seen an example of doing it with Python so I’m interested to see whether it’s a similar mechanism.

1 Like

If your C++ library is very simple, it might still be easier to reimplement it in python. MicroPython has a
(somewhat limited) support for reading and writing to GPIO pins. I have used it with the “Joystick & rumble” PEX extension hat, where it worked well:

Btw. The online python editor is by far the easiest way to make python programs for Pokitto. It is also the preferred way.

Thanks for your reply. Really appreciate the help.

I need to use I²C (for a port expander that is ultimately controlling some LED) and things like 1-Wire for stuff like a DHT11 sensor. It would also be easier for me to only have my code in one place and not needing to re-implement everything a second time.

Currently I create a corresponding object in C++ then then allows to call some functions.
e.g.

Led led;
led.on(0); //argument is a uint8_t 0-7

Ideally I’d like to use this C++ code to:

import LED as led
led.on(0)

I’m not sure if what I want is possible or practical but it would make my life a little easier.
The methods only really every need one argument or return one value, most of them are void with no arguments. So generally really simple.
I’ve placed all my C++ stuff into a folder in PokittoLib\Pokitto to have it in one place and then reference it in the project.json from Femto IDE.

I have found the PythonBindings.h in the PokittoLib but I don’t really see the big picture yet. What exact part of the implementation is in this file?

Should I extend those files or would it be possible to just reference my implementations via a include? Ideally I want to modify the original PokittoLib as little as necessary but have my code integrating as seamless as possible.

A simple example would be really nice if that would be possible.

2 Likes

Python only interfaces with functions that have C linkage,
so you’ll most likely have to manually create wrapper functions.

Theoretically it should be possible to automate the creation of wrapper functions,
but I’m not aware of any program that can do so,
and writing one would be quite difficult.

Agreed, I’d very much like to see an example.

I read both PythonBindings.h and PythonBindings.cpp,
and it actually left me with more questions rather than less.

1 Like

The missing piece is here, in a different repository. I have forked the official MicroPython repository and made necessary changes for Pokitto.
In modUPyGame.c the actual python modules and classes are created in C. It calls those bindings API methods mentioned above.

What makes this a bit difficult is the conventions of Python C-implementation (e.g. how Python modules and classes are defined in C-structs), and that you have to set up a separate compiling environment (I use Cygwin) for MicroPython.

1 Like

I think I’d have to do a lot of documentation reading to make sense of all of that.
I can understand a few things here and there.
(If the Pokitto can digest all of this then it ought to be able to manage modified Lua.)

This certainly implies that @ThxAndBye is going to have quite a bit of work ahead of them.

Is there some decent documentation of all the mp_ stuff somewhere?


Going slightly off-piste one moment…

If n_args is 2 or 3, does this not cause a buffer overrun bug?

It seems that mp_arg_check_num(n_args, n_kw, 1, 4, false); checks ((n_args >= 1) && (n_args <= 4)), in which case a value of 2 or 3 ought to result in an attempt to read args[3] (and args[3]), which I would assume is beyond the end of args.

Or am I missing something?

I was actually thinking if it would make sense to make a very simple “user extension” API in Python for this kind of needs? I mean a simple way to send and receive data between Python and C++ programs. That would make possible to do “hybrid Python & C++ programs”.

It could be as simple as (in pseudo code):

// PythonBindings API
Set(cmdID, dataPtr = null, dataSize=0)
Get(cmdID, dataPtr, dataSize)

The command ids would be totally user program specific.

So the Python code could call:

UserExt.set( motor_off_cmd)
UserExt.set( motor_state_cmd, data)
motor_state = UserExt.get( motor_state_cmd)

And the PokittoLib C++ program would have:

MyUserExtensionCommandCallback( method, cmdID, dataPtr, dataSize)
{
   if(method == SET && cmdID == MOTOR_OFF_CMD)
   {
   ...
   }
   ...
}

Of course, this would not work in the Online Python Editor, as it do not allow C++ changes to be made. It would work with Code::Blocks (Pokitto Simulator), EmBitz (HW) and Femto (not tested yet).

Btw. Why do you want to make a Python program? Would it be easier to make a C++ program as your library is C++ already?

1 Like

I’d be fine to write a C++ program, even if C/C++ isn’t really in my comfort zone, but the library is supposed to be used for teaching purposes and Python is the preferred language. That’s the reason why I want to implement a Python interface.

A simple interface between Python and C/C++ code would be really cool. Currently the interfacing looks like lots of boilerplate and I don’t really understand every detail of it to create my own. (What goes where, the complete control flow trough the individual files and how to easily expand it).

If Python were written in C++ instead of C then you could probably hide a lot of the boilerplate using template magic.

This is more or less implementing bytecode.

There might be an easier way depending on how data is actually passed around in Python.

For the sake of comparison, in Lua, all values are passed on the data stack of the lua context,
and all values are effectively a sum type (tagged union) of the permitted data types.

I’ve never been a fan of online editors anyway…

If you skip the online editor then you can try Boost.Python:

struct World
{
    void set(std::string msg) { this->msg = msg; }
    std::string greet() { return msg; }
    std::string msg;
};
#include <boost/python.hpp>
using namespace boost::python;

BOOST_PYTHON_MODULE(hello)
{
    class_<World>("World")
        .def("greet", &World::greet)
        .def("set", &World::set)
    ;
}
>>> import hello
>>> planet = hello.World()
>>> planet.set('howdy')
>>> planet.greet()
'howdy'

But whether or not it would work for Pokitto and micropython I have no idea.


For anyone in particular or just as a general teaching thing?

Why?

Unfortunately that’s the case with most bytecode-based/interpreted languages implemented in C.
There will always be boilerplate simply to interface C/C++'s static type system with the target language’s dynamic type system and general infrastructure.
(I.e. language binding.)

As I said before, it is possible to automatically generate that boilerplate,
but it would require either writing a parser to read the input code and then generate the boilerplate,
or some clever C++ magic (like the functionality provided by Boost.Python).

Not that I know. I had to have learned it by studying the code.:frowning:

a good point. i need to check that.

Learning Finnish? :wink:

2 Likes

What are you planning to use for teaching, the Online Editor (https://pyinsky.herokuapp.com/) or Femto IDE?

Currently PyInSky is used but Femto IDE is fine too, since it doesn’t require to be installed on the computer and can just be copied or directly started from a USB.

1 Like

Ok, when you make your library first to work in C++ in Pokitto, I can make an API for it in Python.

2 Likes

Thanks for the generous offer. Is it possible to implement the API for Python as a separate entity and then include it in one of the files in the PikittoLib?
Since it’ll need expansion in the future for other sensors, I’d like to be able to expand it myself, if possible.

My class for the LEDs has those public methods:

class LED
{

public:
    LED();
    ~LED();
    void allOff();
    void allOn();
    void on(uint8_t position);
    void off(uint8_t position);
    void toggle(uint8_t position);
};

It unfortunately just has void return types so if there are special step needed to return a single value then an example would be cool too.

Do you want to make a contribution to PokittoLib/Micropython or do you want to be able to make a program specific “user extension” to Python API?

Just to make clear that MicroPython already contains a Pin class that can be used to set/unset leds connected to digital pins.

Does your library already compile under PokittoLib?

I’d prefer a user extension specific to the library, since it requires custom hardware.

The LEDs are connected to a TCA9554 IO expander and thus the default implementation wouldn’t work.
The Pins from the PEX are in use for other things and I try to rely as much as possible on the implementations from the PokittoLib.

Yes, the C++ that I have so far works like a charm.