-
Notifications
You must be signed in to change notification settings - Fork 156
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.
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.
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'
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);
});
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