Skip to content

Creating a Language Binding

George Morgan edited this page Feb 7, 2018 · 3 revisions

Language - Python

Language bindings are the gateway between high level programming languages and the device's hardware. This article will describe how to create a language binding that uses libflipper to bring support for the Flipper platform to the Python programming language.

The Foreign Function Interface (FFI)

The only language feature that the target language must have is a Foreign Function Interface, or FFI for short. A FFI enables a high level language to interact with lower level code written in C, C++, or other compiled language. The platform level library, libflipper, is written in C and exposes a handful of functions and data structures that can be accessed from a higher level language's FFI. These primitives can be used to call functions on and transfer data between an application written in the target language and the Flipper hardware.

This article outlines how to create a language binding for the Python programming language. One of Python's most powerful FFIs is called ctypes. Ctypes makes it very intuitive to call a function that exists in a C library from Python.

The Basics of Libflipper

Review the libflipper Wiki page here.

Before attempting to write a language binding, you should have a thorough understanding of how libflipper works and how to use it to interact with the device. The basics of how libflipper calls functions is reiterated here.

lf_invoke

The most integral function exposed by libflipper is lf_invoke. This function performs a remote procedure call to a package loaded on the attached device. A package is simply a collection of functions that are loaded into the device's memory. These functions are normal C functions and can be executed on the device remotely from libflipper. In order to perform an invocation, the package must be loaded on the device and the order of the arguments accepted by the function, as well as their types, must be known.

/* Load the module from the host onto the device. */
struct _lf_module *foo = lf_load("/path/to/some/module.bin");
/* Invoke the function called 'my_function' on the device. */
lf_invoke(foo, "my_function", lf_int_t, lf_args(lf_int(1234), lf_char('b')));

In this example, a module called foo is loaded onto the device. This module contains a function called my_function with the signature int my_function(int a, char b);. Calling lf_invoke as demonstrated will load the foo module module onto the device and run my_function with parameter a as 1234 and parameter b as 'b'.

Clone this wiki locally