Skip to content

libpisoundmicro Overview#

libpisoundmicro is a straightforward C/C++ library with bindings to other languages such as Python for making use of the I/O functionalities of Pisound Micro. It completely abstracts all of the sysfs interaction details, providing a procedural or object oriented API, as well as exposing the Linux File Descriptors that can be polled to detect value changes with minimal use of host board's CPU resources.

Even though the sysfs details are completely abstracted out, it's still recommended to go through the Sysfs Interface documentation page, to gain a good understanding of the concepts and what underlying functionality is being provided.

The source code is licensed under LGPL 2.1.

Setting up for Development#

It's assumed that you're using Patchbox OS image, or have set up our APT server.

C/C++#

Simply run sudo apt install libpisoundmicro-dev and you will get the library and its development headers installed.

Python#

Python 3 bindings library can be set up by running sudo apt install pypisoundmicro.

Key Concepts#

Elements#

Pisound Micro exposes its I/O functionality through so called Elements - they have a name, are of a specific type (like an Analog Input or a Gpio Input), and have a specific set of attributes, depending on their type.

The Elements that are set up via libpisoundmicro are reference counted. Object oriented languages implicitly take care of releasing the references whenever necessary, tied to the lifetime of the objects. If using C, you have to keep track of it yourself.

Element Setup#

An Element gets created upon completion of a successful Setup request.

There's specific APIs for setting up desired types of Elements, however, sometimes it can be useful to use a generic upisnd_setup_t container type to store all the settings into it and provide it to a generic setup function which returns you an Element reference.

C#

This section is a quick overview of key concepts of C API for libpisoundmicro. There's Reference documentation available as well.

The main API header to include is pisound-micro.h:

#include <pisound-micro.h>

Link with -lpisoundmicro.

The library uses upisnd_ prefix for every C function and type exposed by it.

Init#

Before using the library's APIs, the library must first be initialized. Somewhere within the initial section of your main or dedicated initialization routine, call:

upisnd_init();

On success, it will return 0, or -1 on failure. Inspect the errno's result for insights of what could have gone wrong.

Uninit#

In your cleanup code, add a call to deinitialization function:

upisnd_uninit();

It releases all of the Elements your program still had handles to. It's a very good idea to ensure this function gets called when signals are sent to your program's process, by setting up your own signal handlers. It's a complex topic, and is out of scope of this documentation, but feel free to look at how Pisound Micro Mapper sets up signal handling, as well as see the man pages for sigaction, ppoll, pselect and related functions.

Starting up again without first releasing the Elements can lead to a situation where your program can't initialize properly due to Elements from previous run holding the pins you require.

Elements#

The library exposes Elements as reference counted objects, so every time you get a valid return of type upisnd_element_ref_t from various APIs, make sure to have a corresponding upisnd_element_unref call once your program no longer requires to keep the reference. upisnd_element_add_ref is available to increase the reference count of an Element, so you can use it in a similar manner as a smart pointer.

There's specific per-type APIs for setting up brand new Elements, like upisnd_setup_encoder. Upon success, you get a valid reference to the Element. If there was an already existing Element with exactly the same name and options, you'll get a valid reference to the Element (the refcount will be implicitly increased), and this case can be detected by checking if errno is equal to EEXIST. Upon any other error, you'll get an invalid reference (equal to NULL)

There's also a generic upisnd_setup API, taking a generic setup config container upisnd_setup_t.

Some Elements provide type specific API's, prefixed with the type, for example upisnd_element_gpio_... or upisnd_element_encoder_.... See the API Reference documentation for all of them.

Element Name#

Valid Element names are null terminated strings of bytes of up to UPISND_MAX_ELEMENT_LENGTH (64), including the null character. Forward slash (/) character is not allowed. upisnd_validate_element_name can be used to validate name strings.

The Element names can be static, but there's also a helper function to generate a unique random name that you can use, either with a common prefix or without any prefix - upisnd_generate_random_element_name.

See the Reference documentation for more details.

Element Setup Config Container#

You may build up and store the setup configuration for an Element in a upisnd_setup_t container. It can hold info for all of the Element's setup details, apart from the Analog Input's or Encoder's options, which are set in subsequent sysfs writes to appropriate attributes.

The first thing to do when building up the upisnd_setup_t is to set the Element Type. Then fill in the rest of the information which is specific for the particular type.

Finally, pass it into upisnd_setup API to setup an Element accordingly.

Value#

There's utility functions for getting a Unix File Descriptor opened for the Element's value attribute, as well as reading and writing to it. See upisnd_element_open_value_fd, upisnd_value_read and upisnd_value_write APIs.

The FD can be used for polling for changes, which is an efficient way to get notified once a change occurs. Use POLLPRI. This topic is complex and out of scope of this documentation, but there's plenty of online resources that cover it.

An Example#

See here for a working basic C example.

C++#

The C++ API of libpisoundmicro simply wraps the C APIs into object oriented classes, so it's recommended to go through C section before continuing. The C++ API also provides a helper class to help with the library's initialization and deinitialization. The Element reference counts are tied to C++ objects' lifetime, if using pure C++ API, it is not necessary to manually ref and unref upisnd_element_ref_t handles.

Just like for C, #include <pisound-micro.h> to access the libpisoundmicro APIs and link your program with -lpisoundmicro.

All of the C++ API is within the upisnd:: namespace. It also makes use of some C types, defined in global scope, with upisnd_ prefix. You can find the C++ reference documentation here.

Init and Uninit#

There's a helper class upisnd::LibInitializer which initializes libpisoundmicro library in its constructor and uninitializes it in its destructor, that makes an instance of it perfectly suited to be placed into your main function's body, or a global variable, or in a static variable of an accessor function.

Element Name#

There's also a helper class for producing Element names, called upisnd::ElementName, use its static methods to wherever an ElementName has to be passed, or plain const char * is accepted for APIs expecting upisnd::ElementName.

Value#

Finally, there's upisnd::ValueFd class that helps with interacting with the opened value FD and automatically closing it.

An Example#

See here for a working basic C++ example.

Python#

The Python wrapper is automatically generated from C and C++ headers using SWIG, pretty much everything in C and C++ sections applies to Python, the APIs are all the same, just have to be accessed in Python 3 syntax. The docstrings are available, so the API documentation is available within your development environment.

The only significant difference is that the libpisoundmicro is implicitly initialized upon importing the pypisoundmicro library.

The recommended way to import the pypisoundmicro library is:

from pypisoundmicro import *

This brings in all of the APIs into the global namespace.

An Example#

See here for a working basic Python example.