Nostalgia-Tron, Part 7: LED control

Posted in Articles, Raspberry Pi, Tutorials

Man, has this series been neglected! I was going to tell you folks how I synchronized the power states of my Pi, marquee light, and monitor with an Arduino, but it turns out it’s hard to write Arduino tutorials when you’re only barely certain of what you’re doing, electronics‐wise, and at the back of your mind the whole time is a creeping suspicion that your instructions are going to get someone electrocuted.

While I work through these insecurities, let’s turn our attention elsewhere in order to get this series unstuck.

The Hardware

I’ve mentioned the Pac‐Drive briefly before. Each of my arcade buttons has an LED inside, and all of them are hooked up to the Pac‐Drive so I can coordinate which buttons get illuminated in certain situations. So far in this series I haven’t done anything with the Pac‐Drive, so all buttons are lit up all the time.

It’s got 16 terminals for LEDs. I have more than 16 buttons on my control panel, but not all of them would need to be controlled granularly. So here’s how I hooked them up when I was wiring my control panel:

  • Terminals 1–6 control Player 1’s buttons.
  • Terminals 7–12 control Player 2’s buttons.
  • Terminals 13 and 14 control the two Start buttons, respectively.
  • Terminal 15 can control both coin buttons on the front.
  • Terminal 16 can control all four of the smaller function buttons.
LED Layout
How the buttons on my control panel map to the terminals on the Pac‐Drive.

We discussed the wiring back in part two. Amazingly, that’s the easy part. Sure, it’s a bit tedious to run individual wires to each button, but it’s not exactly intellectually demanding.

The challenge

As I’ve mentioned before, most of the MAME ecosystem is Windows‐based, with Linux only an afterthought. There’s an interesting tool called LEDBlinky whose purpose is to light up only the active buttons for the game you’re playing. It integrates deeply into both MAME and the most popular frontends so that it knows which game you’re launching, knows how you’ve configured the controls in MAME, and lights up only the buttons that are used to play that particular game. And it’s only available on Windows!

I decided I wanted something similar out of my cabinet, with the caveat that I didn’t want to do anything, uh, hard or time‐consuming. Luckily, in addition to being lazy, I also set low standards for myself: all I needed was a solution that could work for the roughly 100 games I’ve put into this cabinet, not any arbitrary MAME game.

Software

Ultimarc makes great hardware, but if I had it to do over again I might’ve chosen an LED controller with an official Linux utility. Their SDK has libraries for C#, C++, VB.NET, and Delphi — none of which are useful to me.

Luckily, the Pac‐Drive is a simple HID device, much like a keyboard or a mouse. After some digging, I found this third‐party utility for Linux that allows controlling a Pac‐Drive from the command line.

It was exactly what I needed, but it’s about ten years old and took a bit of wrangling to get installed on a Pi. But I suffer so that you don’t have to.

Installing the software

First, you’ll need at least these packages:

sudo apt-get install libusb-dev build-essential

You’ll also need libhid, but it’s deprecated and therefore hard to find. There’s no package for it in APT. Even seeing the source code involved registering on some random SourceForge‐like site. And once you’ve got it you have to make a change to the source code before it’ll even compile on the Pi.

Rather than have you recapitulate this painful process, I’m hosting the fixed source code myself.

From your home directory, do:

mkdir src && cd src
wget "https://andrewdupont.net/pi/libhid-0.2.16.tar.gz"
tar xvzf libhid-0.2.16.tar.gz
cd libhid-0.2.16
./configure
make
sudo make install

If all went as planned, you should now be able to build the pacdrive binary.

cd ~/src
wget "http://www.zumbrovalley.net/pacdrive/dnld/pacdrive_0_2.tar.gz"
tar xvzf pacdrive_0_2.tar.gz
cd pacdrive_0_2
make

At this point you can do make install to put the binary in /usr/bin. I’m trying to keep customizations inside my home folder as much as possible, so instead I manually copied the pacdrive binary to /home/pi/bin. Put it wherever you like, as long as it’s in your PATH.

Does it work?

You can run pacdrive --help to brush up on the syntax. Assuming all your LEDs are on, run pacdrive -f; if everything is working properly, all your LEDs should go off. Running pacdrive -a should turn them all back on.

You can pick out individual LEDs to turn on or off, like so:

# turn everything off, then turn on LEDs 1 and 12
pacdrive -f -l1 1 -l12 1

Or you can encode each button’s on‐off state into a 16‐bit bitmask:

# set every LED on except LED #1
pacdrive -s 0xfffe

Hooking into RetroPie

Being able to control the LEDs from the command line is a major step forward. But two problems still need solving:

How will it know which LEDs to light up for which game?

I don’t have the patience or the systems programming expertise to figure out how to ask MAME which buttons are mapped for a particular game. And even if I could figure that out, I’d have a solution which worked only for MAME and not for Daphne (the Dragon’s Lair/Space Ace emulator) nor any future emulators I may choose to install.

Instead I’m just going to create a simple config file for each game. This will allow me to specify which controls should be active when that game is running. It’s more bookkeeping, but it’ll work exactly the same way across emulators.

Here’s what I came up with:

  1. Create a /home/pi/leds directory.
  2. Inside that directory, create another directory for each system you want to emulate. I’ve got arcade and daphne; you may have others.
  3. Inside each system’s directory, define a text file whose name matches the name of the game. For instance, the two‐player version of The Simpsons is named simpsons2p, so I’d create /home/pi/leds/arcade/simpsons2p.cfg with the following contents: 1, 2, 7, 8. In other words: light up buttons 1, 2, 7, and 8, and turn off all other buttons.

How will we light up the LEDs on game launch?

In RetroPie, all emulator launches go through a script called runcommand.sh. This wrapper script is responsible for a number of lifecycle tasks — displaying the pre‐launch menu, applying a CPU governor if one is configured for that game, switching video modes, and so on.

RetroPie 4.0 added the ability to hook into this lifecycle with scripts named runcommand-onstart.sh and runcommand-onend.sh. These scripts receive a few arguments, among them the system and ROM name — which is all the information we need to look up a game’s LED config and apply it.

This is a big deal. We don’t need to integrate with MAME. The fact that RetroPie launches every game the exact same way regardless of platform means that we can ignore the emulator entirely. Adding LED metadata for a game is a 30‐second process that works exactly the same way for all games that RetroPie can run.

I’ve used Python for scripting in previous installments, but I don’t need the GPIO library for this task, so I’ll use Ruby instead. It’s not installed by default on Raspbian Jessie, but sudo apt-get install ruby2.1 will take care of that. (2.1 was the latest stable version in APT when I first did this; grab a newer version if it’s available.)

Last time I threw a few long code blocks into the post. This time I’m putting the scripts into a Gist. Open it in another tab and follow along.

led-start and led-end are the Ruby scripts; place them in /home/pi/bin. Before reading the config for a game, led-start will read a global config at /home/pi/.ledrc (if it exists). My .ledrc looks like this:

+13, +14, +15, +16

The leading + means “force to be on”; this allows the start buttons, coin buttons, and function buttons to default to on without my having to include them in every single game’s config file. This is a bit overengineered, but it saved me a lot of time when composing the configs by hand.

led-end is much simpler; all we need to do is turn all LEDs back on.

These utilities get used by runcommand-onstart.sh and runcommand-onend.sh, respectively. Those scripts should go in /opt/retropie/configs/all. If you’re a seasoned RetroPie veteran, these files might already exist with contents of your invention; if so just combine the two files. You’re smart enough to work that out.

The proof

If nothing explodes, here’s roughly what should happen:

Buttons that have no function in NBA Jam get dimmed.

What’s the point of all this?

I’m not sure. I had fun doing it, though.

What I like about the RetroPie experience isn’t just the cheap hardware; it’s that the barrier for experimentation is much lower. Unix is a pneumatic system where all the tubes are transparent — you can reason about it on a high level even when you don’t understand the particulars.

Thus you don’t have to follow a tutorial to the exact letter. Often you can just grab your favorite parts from three different tutorials and duct‐tape them together like I did. It’s exciting. This project is a long train of what‐if thoughts that I saw through to completion. If you like this idea, feel free to steal it in its entirety. But also feel free to break it into parts and use those parts to build your own train.

Next time

Retain everything you learned about the runcommand.sh lifecycle — you’ll need that knowledge for the next installment, when we automatically switch the joystick between 4‐way and 8‐way mode according to what the game requires.

Comments

Leave a comment

(Huh?)
What's allowed? Markdown syntax, with these caveats…
GitHub-Flavored Markdown

A couple aspects of GFM are supported:

  • Three backticks (```) above and below a section of code mark a code block. Begin a JavaScript code block with ```js, or a Ruby code block with ```ruby, or an HTML code block with ```html.
  • Underscores in the middle of words (cool_method_name) will not be interpreted as emphasis.
HTML tags/attributes allowed

Whether you're writing HTML or Markdown, the resulting HTML will be sanitized to remove anything not on this list.

<a href="" title="" class=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class=""> <del datetime=""> <em> <i> <li> <ol> <pre> <q cite=""> <s> <strike> <strong> <ul>

Now what? Subscribe to this entry's comment feed to follow the discussion.