I know I promised to blog some more about how I set this blog up, but I've been too excited to to get playing with the GPIO (General Purpose Output) pins on my Pi.  Honestly, setting up this blog was pretty freaking easy. It basically consisted of downloading CommandBox, installing ContentBox (via CommandBox) and starting the embedded server.  Boom.  Now, on to the GPIO :)

A Taste of Cobbler

The input/output pins are what make the Pi really similar to my Arduino. They're the glue that allow hardware and software to really meet.  Except on my Arduino, I must use C that's compiled to machine code and loaded onto a basic microcontroller.  My Pi runs an actual operating system, so I can use whatever high-level language I fancy and bring whatever syntax and productivity I want along for the ride.

Early model Pis had 26 GPIO pins, but now there's a total of 40 which are presented as two rows of headers on the board, 20 pins apiece.  The easiest way to work with your GPIO pins is to get a cobbler board.  This is a cable that plugs into your pin header and connects to another small board with a similar pin header designed to plug into a breadboard.  Now you have plenty of room to "cobble" together your circuit.  See what they did there?  I used this model from Amazon for $12.30.

The Circuit

I built a very simple circuit to play with that consists of a single LED run through a 220K Ohm resistor.  This short lead (cathode) goes to any ground.  I connected the the long lead (anode) to my 220K Ohm resistor which goes to to one of the input/output pins.  This is a little frustrating about Pis, but there are THREE different standards for what the pins are named.  Here are the three different names for the output pin I used:

  • Pin 12 -- Physical location on the header
  • BCM 18 -- Corresponding pin on the actual Broadcom chip
  • Wiring Pi pin 1 -- A hardware-abstracted wiring scheme

So depending on who you talk to, I used pin 12, 18 or 1.  Yeah, that.  The Pi4j library uses the Wiring Pi format, which is meant to insulate your code against future hardware changes.  Wiring Pi is a low-level GPIO access library written in C that the Java lib uses under the covers.

Click to enlarge

 

You never want to hook an LED straight to a power source without an resistor in series.  Diodes have no significant impedance once they've been forward-biased so the current will increase exponentially as per Ohm's law and burn out the LED.  Most hobby LEDs have a forward voltage of 2-3 V and only need around 20mA of current.

Pi4j

Pi4j is a Java library for interacting with your Pi's GPIO pins, and like I stated before, it's a wrapper of a smaller C library.  If you decide you trust the P14j guy's enough to lend them root access to your Pi, you can install it very quickly like so:

curl -s get.pi4j.com | sudo bash

This grabs a shell script off their site and feeds it into bash for root-level execution.  I don't actually know if their apt-get installation is a requirement, or if you can just dump in the jar files.  After finding no information online and (still) not getting approved for the forum I resolved to just try it.  After it didn't work, I broke down and ran their installer only to find it still didn't work and eventually ended up pinning down a bug in Railo related to serializing Java objects as JSON.  I'm not sure what all the installer did, so I can't really uninstall it to find out if it was required.

Java is great, but CFML is better!  That's why we're going to drop the core jar files into our CommandBox classpath so we can directly access the Pi4j classes in the REPL or in our CFML commands.  I copied the following jar files over to CommandBox:

cp /opt/pi4j/lib/pi4j-core.jar ~/.CommandBox/lib/
cp /opt/pi4j/lib/pi4j-device.jar ~/.CommandBox/lib/
cp /opt/pi4j/lib/pi4j-service.jar ~/.CommandBox/lib/
cp /opt/pi4j/lib/pi4j-gpio-extension.jar ~/.CommandBox/lib/

That's it! CommandBox is ready to rock and roll.

Fire up the REPL

Now, I mentioned a Railo bug above that kept me from getting this working the first time.  Technically, the Pi4j bits were working, but when the CommandBox REPL tried to serialize the Java objects with SerialzieJSON(), Railo would go into an endless CPU-hogging loop.  Sadly, an empty catch{} block was involved so some actual error inside Railo was getting thrown and swallowed repeatedly.  I changed the REPL a bit to limit what it attempts to serialize and this is on the bleeding edge of CommandBox.  If you've installed 1.0 final, please download the bleeding edge binary from our integration server.  Running this command will also update you, or at least output the link for you.

CommandBox> upgrade --latest

Update 4/13/2015: These new REPL fixes are being released today as part of CommandBox 1.1.0.

Now run the "box" binary to drop yourself at the CommandBox interactive shell.  Please note, the Pi4j libraries require that they be run as root, so you'll need to start CommandBox as root as well.  Type "REPL" and you will open up the script REPL shell.  The following commands are lifted straight from P14j's hello world example.  The only need for the pinState and Raspipin classes are to use some of their public constants.  I'd like to write a CFML wrapper that abstracts all of this, but this works for now.  Note Gpio factory is using a common "factory" pattern where a static class creates actual instances of our GPIO controller for us.  Also note, I'm not actually instantiating the second and third classes.  CFML just creates the class object.  This can be a little confusing to CFML devs since all CFCs are instantiated.

You can copy/paste these one line at a time, or actually just paste the whole block and the REPL will run each line, one at a time:

gpio = createObject( 'java', 'com.pi4j.io.gpio.GpioFactory').getInstance()
pinState = createObject( 'java', 'com.pi4j.io.gpio.PinState')
Raspipin = createObject( 'java', 'com.pi4j.io.gpio.RaspiPin')

LED = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_01, "MyLED", PinState.HIGH)

Recap

If everything went well, your LED should be glowing right now.  That code creates the GPIO controller, then declares that Pin 1 will be a digital output pin with an initial state of "high".  Unlike the Arduino's 5v board, the "high" state on your Pi will be 3.3v.  The voltage on Pin 1 will drive our LED (through the resistor).  LEDs are fine to power via your Pi, but don't try stuff like motors as they pull more current than your Pi can safely produce.  Larger accessories must get their own relay-switched power source.

The "LED" variable in the REPL has some cool methods we can call on it.  Try these out and remember the CommandBox REPL maintains state as long as its open, so variables you set will stick around for access later.

// Have you tried turning it off and back on again?
led.low()
led.high()

// Toggle the current state
led.toggle()
led.toggle()

// On and back off once
led.pulse( 2000 )

// In a loop with a pause
for( i in [1,2,3] ) {
  LED.pulse(500,true)
  sleep(500)
}

// Same as above, but runs forever
led.blink( 500 )

// STOP THE BLINKING!!!
led.blink( 0 )
led.low()

Automation

The REPL is fun for playing around live with your Pi.  (I did all of this without ever powering it down so this site was up the whole time :)  You may also want to save your code in a file to run later.  No problem!  Place everything above in a .cfm file called coolness.cfm and run this from your Pi's bash prompt.

$> box coolness.cfm

Give CommandBox a couple seconds to start up, and your script will run.   You can trigger this from whatever you want-- a cron job, an external process, or just on boot and run it in a loop.  Hopefully there are some good ideas already knocking around in your head to build something cool with CFML.

Issues

Update 4/13/2015: I was using a release candidate version of the Pi4J jars which contained a bug.  If you use the installation method I showed above, you won't have this issue.

There's a few things to figure out, but since I can't get on the bloody Pi forum yet I haven't been able to investigate.  The first is that you are supposed to shut down the GPIO controller with a .shutdown() method but it errors when I try.  

This scheduled executor service can only be shutdown by Pi4J.

And, when I exit CommandBox there's another error-- apparently still trying hard to shut itself down.  

Exception in thread "Thread-5" java.lang.NoClassDefFoundError: com/pi4j/concurrent/DefaultExecutorServiceFactory$GpioEventServiceHolder
        at com.pi4j.concurrent.DefaultExecutorServiceFactory.getInternalGpioExecutorService(DefaultExecutorServiceFactory.java:68)
        at com.pi4j.concurrent.DefaultExecutorServiceFactory.shutdown(DefaultExecutorServiceFactory.java:129)
        at com.pi4j.io.gpio.impl.GpioControllerImpl.shutdown(GpioControllerImpl.java:915)
        at com.pi4j.io.gpio.impl.GpioControllerImpl$ShutdownHook.run(GpioControllerImpl.java:885)
Caused by: java.lang.ClassNotFoundException: com.pi4j.concurrent.DefaultExecutorServiceFactory$GpioEventServiceHolder
        at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

I'll try to get to the bottom of this once I can get approved for the forums.