Skip to content

Getting Started with GPIOs

Günter Obiltschnig edited this page May 13, 2019 · 3 revisions

Getting Started with GPIOs

macchina.io comes with support for GPIOs (general purpose input/output pins), using the Linux kernel's /sys/class/gpio interface. This is implemented in the devices/Linux project, which produces the io.macchina.linux bundle.

On most devices, a GPIO pin can be configured as either input or output pin. Some input pins can trigger an interrupt when its state changes.

Note: the new character device-based GPIO support introduced with Linux Kernel version 4.8 is not yet supported.

Enabling Linux GPIO Support

In order to access GPIO pins from macchina.io, GPIO support must be enabled, and specific GPIO pins must be configured. To enable GPIO support, set the linux.gpio.enable configuration property to true in the macchina.io configuration file (macchina.properties):

linux.gpio.enable = true

To make specific GPIO pins available to macchina.io, these pins must also be configured in the macchina.io configuration file. The pin number and the direction (input or output) of the pin must be specified. Note that pin numbers are hardware specific. Also, not every pin may support setting the direction - e.g. some pins may be output or input only. Please refer to your hardware documentation and the Linux Kernel support for your hardware for information on GPIO pin numbers and their capabilities.

In order to make a specific pin available as input or output pin, set the linux.gpio.pins.<num>.direction property to in or out. For example, the following setting makes pin #10 available as output pin and pin #11 available as input pin:

linux.gpio.pins.10.direction = out
linux.gpio.pins.12.direction = in

For each GPIO pin made available, an object implementing the IoT::Devices::IO interface will be available. The Linux GPIO support in macchina.io will automatically make the specific pin available to userspace using the /sys/class/gpio interface, so nothing has to be done at the Linux level.

Accessing GPIOs

Linux GPIO pins are mapped to macchina.io device service objects implementing the IoT::Devices::IO interface. They can be detected by searching for device objects with service type io.macchina.gpio. Furthermore, specific objects have a well-defined service name. For example, the service name for GPIO pin 10 will be io.macchina.linux.gpio#10.

For example, to find the services for all configured GPIO pins in JavaScript:

var gpioRefs = serviceRegistry.find('io.macchina.deviceType == "io.macchina.gpio"');

This will return an array of ServiceRef objects for all configured GPIO pins.

To search for a specific GPIO pin (e.g., 10):

var gpio10Ref = serviceRegistry.findByName('io.macchina.linux.gpio#10');
var gpio10 = gpio10Ref.instance();

To read the state of the PIN use the state() method:

var state = gpio10.state();

To change the state of an output pin, use the set() method to set a specific value (true or false), or use the toogle() method to invert the state.

gpio10.set(true);
gpio10.toggle();

The state of a pin can also be read and changed (for output pins) via the state property.

var state = gpio10.getPropertyBool('state');
gpio10.setPropertyBool('state', false);

There are also properties for reading the direction (direction, string) and pin number (device, string):

var dir = gpio10.getPropertyString('direction'); // --> 'out'
var pin = gpio10.getPropertyString('device');    // --> '10'

Reacting to State Changes

The stateChanged event can be used to detect state changes on input pins (for pins that trigger an interrupt):

gpio12.on('stateChanged', ev => {
    console.log('pin12 changed: ', ev.data);
});

C++ Example

The following example shows how to access a GPIO pin from C++:

#include "Poco/OSP/BundleActivator.h"
#include "Poco/OSP/BundleContext.h"
#include "Poco/OSP/ServiceRegistry.h"
#include "Poco/OSP/ServiceRef.h"
#include "Poco/ClassLibrary.h"
#include "IoT/Devices/IIO.h"


namespace HelloIO {


class BundleActivator: public Poco::OSP::BundleActivator
{
public:
	void start(Poco::OSP::BundleContext::Ptr pContext)
	{
		auto ioRefs = pContext->registry().find("io.macchina.deviceType == \"io.macchina.gpio\"");
		pContext->logger().information("Found %z GPIOs.", ioRefs.size());
		for (auto pIORef: ioRefs)
		{
			pContext->logger().information("IO name: %s", pIORef->name());
			const Poco::OSP::Properties& props = pIORef->properties();
			for (const auto& key: props.keys())
			{
				pContext->logger().information("Property: %s = %s", key, props[key]);
			}
			IoT::Devices::IIO::Ptr pIO = pIORef->castedInstance<IoT::Devices::IIO>();
			pContext->logger().information("IO state: %b", pIO->state());
			pContext->logger().information("IO direction: %s", pIO->getPropertyString("direction"));
		}
	}

	void stop(Poco::OSP::BundleContext::Ptr pContext)
	{
	}
};


} // namespace HelloIO


POCO_BEGIN_MANIFEST(Poco::OSP::BundleActivator)
	POCO_EXPORT_CLASS(HelloIO::BundleActivator)
POCO_END_MANIFEST