One of the most interesting features of computers like the Raspberry Pi is the ability to interact with the physical world via GPIO (general purpose input/output) pins.

GPIO pins can capture inputs from multiple sources—including data from temperature, humidity, or one-axis sensors—and write output, which can anything from turning on an LED to controlling DC motors, LCD displays, or D/A converters.

What is Bulldog?

In short, Bulldog is a Java library that lets developers access GPIO and other low-level IO interfaces like I2C, SPI, or PWM. With it, you can control LEDs, actuators, servos, or gather sensor data.

Since it's a Java library, it requires a JVM to be running on the target device. Nevertheless, it also has a native core written in C (bridged to Java via JNI). Its main purpose is to load memory content (/dev/mem). Using this native approach, we can control GPIOs much faster.

Bulldog aims to be platform agnostic, meaning code can be run on multiple platforms. It currently supports various popular single-board computers, including Raspberry Pi, BeagleBoneBlack, and CubieBoard.

Integration

There is also a component for Apache Camel that wraps Bulldog Library features. For those who haven't heard about Apache Camel, it's an open source Java framework that focuses on making integration easier and more accessible to developers. Via concrete implementations of Enterprise Integration Patterns (EIPs), developers are able to integrate SBCs with a great variety of transports and APIs. It supports components like MQTT, HTTP, AMQP, ElasticSearch, Google services, JDBC, Eclipse Kura, (S)FTP, and more.

At the moment, the camel-bulldog component supports only GPIO and I2C. However, support for the rest of Bulldog features is coming soon.

Using Bulldog

There are two ways to start using Bulldog. The first is to put a board implementation into your Maven dependencies:

<dependency >

<groupId > io.silverspoon </groupId >

<artifactId > bulldog-board-${board-name} </artifactId >

<version > ${version.bulldog} </version >

</dependency >

To make things easier, you can add all board implementations on the classpath. They won't collide. Bulldog will automatically pick up the correct one according to which platform is running your code. After configuring your dependencies, you can author simple Java code to control a GPIO pin. The following snippet binds on the first GPIO pin (depends on the actual platform which physical pin it is):

import io.silverspoon.bulldog.core.gpio.DigitalOutput ;

import io.silverspoon.bulldog.core.platform.Board ;

import io.silverspoon.bulldog.core.platform.Platform ;

import io.silverspoon.bulldog.core.util.BulldogUtil ;



public class BulldogLED {



public static void main ( String [ ] args ) {

// Detect the board we are running on

Board board = Platform. createBoard ( ) ;



// Set up a digital output

DigitalOutput output = board. getPins ( ) . get ( 0 ) . as ( DigitalOutput. class ) ;



// Blink the LED

output. high ( ) ;

BulldogUtil. sleepMs ( 1000 ) ;

output. low ( ) ;

}

} BulldogLEDmainargsBoard boardPlatform.DigitalOutput outputboard.DigitalOutput.output.BulldogUtil.output.

The other option is to use bulldog-camel component. Again, you need to add a new Maven dependency to your Apache Camel project. It will automatically feed in all possible bulldog dependencies:

<dependencies >

<dependency >

<groupId > io.silverspoon </groupId >

<artifactId > camel-bulldog </artifactId >

<version > ${version.bulldog} </version >

</dependency >

</dependencies >

After doing so, you can create a Camel route like the following:

<?xml version = "1.0" encoding = "UTF-8" ?>

<beans xmlns = "http://www.springframework.org/schema/beans" xmlns:camel = "http://camel.apache.org/schema/spring"

xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd" >



<bean id = "properties" class = "org.apache.camel.component.properties.PropertiesComponent" >

<property name = "location" value = "classpath:gpio.properties" />

</bean >



<camelContext trace = "false" xmlns = "http://camel.apache.org/schema/spring" >

<restConfiguration bindingMode = "auto" component = "jetty" port = "8080" />



<rest path = "/rest" >

<post uri = "/led" >

<to uri = "bulldog://gpio?pin={{pin}}" />

</post >

</rest >

</camelContext >

</beans >

The above Camel route exposes a RESTful interface to control GPIO pin. Pretty quick isn't it?

Performance

What makes us think it's so fast? We did a brief performance comparison between our library and one of the most popular GPIO libraries out there, Pi4J. We used a USB oscilloscope to measure the frequency in which a Java program can set values on a GPIO pin on a Raspberry Pi 2 B+.

Bulldog can write a GPIO value with a frequency of 1.080 MHz (one million times per second), whereas Pi4J is about 1kHz (1,000 times per second). We are not considering it an official performance test, but the difference is easy to see. Bulldog is more than thousand times faster!

The source code we used for testing can be found on GitHub.