I have a home music system that uses Evation's irman to provide remote control of song selection. That lets me listen upstairs and control the music with a simple remote control.

I'm building a replacement to that system using C# (more on that in a few months), and I can't use the irman because then my main system wouldn't work. It was either order another irman, or get something different.

A couple of weeks ago, I ordered a Tira from Home Electronics. Tira is like the irman, except that it connects via USB rather than a COM port, and it supports both receiving and transmitting IR codes. That means you could, if you wanted to, build your own macro program that would take a single IR command and both control your computer and other IR-controllable devices. Home electronics also makes the Ira-2, which does mostly what the irman does.

The Tira showed up yesterday. You get the transceiver module hooked to a 6' (ish) usb cord, and a cute little baby CD with some software on it. Installation is easy - plug in the cable, and point the new hardware wizard at the drivers. It installs both a usb device and a virtual COM port, which makes it easier to control the device.

It also comes with a copy of Girder, which is a program that lets you remotely control things on your computer. I installed it and got Tira set up with it, but it was getting confusing results, and I wasn't planning on using Girder anyway, so I dove into the custom API. It's a fairly typical C-Style API with an accompanying DLL, so I dusted off my P/Invoke skills, turned on some music, and got to work.

The interface is really straightforward. You need to init the library, tell it which COM port to listen on, and then register a callback that will be called when their is data available. I got those definitions in, fired it up, hit the button on my TiVo remote, and hit a breakpoint in the callback. That took about 15 minutes total.

Encouraged by my success, I next worked on decoding the event data. The callback passes as a parameter a pointer to a 13-byte string that identifies what button you pressed (think of it as a digital fingerprint that identifies the key uniquely). I defined that as an IntPtr since IIRC, the runtime doesn't like marshalling strings in callbacks. A bit of unsafe code let me copy this to a byte array, and we were off an running. Start up the code, hit the remote button, and a nice 26 character string (the hex values of the data) shows up in the console window. Keep doing it, and it works fine... and then stops working. Hmm.

Add in some code to number the items. Try again. Each time, it writes out 35 items, and then stops. Stop. Think a bit. There's something familiar here, something about delegates and p/Invoke. Ah... When you pass a delegate to an unmanaged function, the runtime has no way of knowing what the unmanaged function does with it, so it assumes that it doesn't store it (the other assumption would mean that delegate never got free'd). In this case, that assumption is wrong, and after a short bit of time (35 iterations in my case), the GC merrily collects the delegate, the tira thread dies when it tries to call it, and things stop working.

The fix is easy - just store the delegate in a place where the GC can find it (a member variable works well), and things a great. I haven't gotten around to writing a nice C# wrapper around it, but I'll post when I get that done.

If you want to retransmit, you have to capture through a separate, more complicated interface, since the 13-byte value doesn't give the system enough info to reconstruct the correct IR signal.