Wednesday, April 2, 2008

Setting up LIRC with multiple devices

In the process of building my latest mythbox, I've been doing a lot of adhoc experiments with a various things over the last few weeks. I thought it was time I start putting some of them together to start moving towards a working system. One of those things I needed to do was get all 3 of my lirc devices working together. The process turned out to be a bit trickier than I expected, but I got it done, and thought I'd share the details of a couple of the trickier spots

Why three lirc devices?

I wish I could say I only needs one device, but unfortunately that's not the case. First of all, my new Thermaltake DH-101 case has a set of front panel buttons, and the driver handles those buttons by treating them like IR codes and sending them through LIRC. I certainly would like those buttons to work, so that's one device.

In addition, as I discovered in my driver writing experiment, the iMON (which handles the front panel buttons) will block the input queue if it receives certain IR signals. The only way to unblock it is to remove those signal events from the queue, and the way that gets done is by exposing a second lirc interface. So, I need to have that interface working if I want my front panel buttons to continue working.

Finally, since the iMON can only receive a very limited subset of IR signals, it is pretty much worthless as a general purpose IR receiver. Therefore, I have a separate receiver...the IRA-3 (which appears to lirc as an Irman).

Compiling LIRC to support both drivers

The 2 iMON interfaces use the lirc_imon kernel driver (via the lirc default driver), while the IRA-3 uses the irman driver. Therefor, I need to get both drivers installed. However, thats one are where lirc is a bit troublesome.

The suggested approach is to configure/make/install lirc once for each individual driver, and then configure again with the --with-driver=all flag. This will configure lirc to make and install every supported lirc driver available. That's not exactly ideal, but it works. However, when I tried that, I got errors during the build complaining the the necessary bttv libraries were not installed and it couldn't continue. Now, it seemed silly to have to install dependancies for drivers I never even planned to use, so I was determined to find a better way.

I tried every way I could think of to run configure: with individual --with-driver parameters (one for each driver), as well as using a single flag and specifying both drivers (space separated, comma separated, quoted, etc). Nothing I could come up with would work. After searching and finding no resolution, I started trying to hack the configure script (which got me nowhere). However, I eventually found a trick that worked...hack the generated makefile.

The trick here was to configure it with --with-driver=all, and then edit the drivers/Makefile script. In here, there are 3 parameters to be edited. Each parameter contains a list of all the lirc drivers. You want to remove any drivers from that list you aren't interested in. The three parameters in that file you want to edit are: lirc_driver, DIST_SUBDIRS, and SUBDIRS. Once you've modified those lines to remove the extra drivers, just run the make and make install.

Edit: Well, a few days later, I get to work trying to setup my lcd display and realize it's not working. It seems that compiling lirc for all drivers makes it pick and choose between some mutually exclusive settings. One of those setting was whether the lirc_imon driver is built for the LCD or the VFD. It picks the VFD. In order to fix this for the iMON LCD, after running configure you need to edit the config.h file (in addition to the drivers/Makefile). Change config.h so that the line:
/* #undef LIRC_IMON_LCD */

#define LIRC_IMON_LCD 1

Then continue on with the make and install. You may find a similar issue occurs with some of the other hardware.

Getting all 3 devices working

Now that I had lirc installed with all the drivers, I needed to get the 3 lirc devices functions. First steps was to test them out individually using irw and then merge them together. Unfortunately, I had an odd bug which I was able to resolve, but can't explain. My lircd.conf file has definitions for 4 remotes (my hauppauge remote, my wife's tivo remote, the iMON Pad's IR codes, and the case's front panel butons). For some reason, the Tivo/Hauppauge remotes would work no matter which order they were in, but the, but the other 2 wouldn't work with the TiVo and hauppage remotes defined first. I had to switch the order to get all 4 to work.

As far as I can tell, they are all valid definitions, and they all work. I was able to pinpoint the problem more specifically. If the earlier definition had the post_data_bits attribute definited, the iMON and front panel button definitions failed to work. Commenting it out fixed the problem with the lower definition (though it broke that one). Curiously enough, each of the 4 definitions has a post_data_bits attribute set, yet they all work fine when in the correct order. I can't seem to make sense of it.

Getting them working together

Now that I had each one working individually, I needed to get them working together through a single interface. I found documentation specifying how to use the listen and connect parameters to connect multiple lircd instances together. I tested, and that worked well enough for 2. However, as soon as I added the third, only one of the 3 would work.

It turns out that lircd has its client/server model a bit different that what I'd expect and would believe is the normal way to do it. Normally, when you have multiple processes connected together by sockets, you have one server that listens on the port and then multiple clients that connect to the one socket. And indeed, if you attempt this with lirc, it works perfectly. The one server will happily establish connections with multiple clients, but it won't actually do anything.

Instead, what you need to do is have all but 1 instance of lircd running as a server (ie: listening), and then have a single client connect to all of the servers, aggregate their data, and output it all on the single interface. Once I figured that out, it worked like a charm.

Just for reference, in case you'd like to see the actual commands I used:

lircd --driver=irman --device=/dev/lirc --pidfile=/var/run/ --listen=9988

lircd --driver=default --device=/dev/lirc1 --pidfile=/var/run/ --listen=9987

lircd --driver=default --device=/dev/lirc0 --output=/dev/lircd --pidfile=/var/run/ --connect=localhost:9988 --connect=localhost:9987

1 comment:

Daniel said...

This didn't work for me.

Although irw reports the correct data on the single socket, mythtv still only gets data from one input, depending on the order I loaded the lircds.

I'm using two /dev/inputs, FWIW.