IR Remote Control Modem


The general goal of the project was to develop a universal IR remote control interface for my PC. It was to be able to transmit and receive IR signals from a range of consumer electronics IR remote units.


The unit had to be low cost, easy to build, and fairly easy to write a driver for. To these ends I chose a simple parallel port interface that I could talk to by bit-banging, and listen from using interrupts.

Not the most efficient design, but simple to implement, and very low cost. The transmit circuit is a simple single transistor buffer driving two IR LEDs in the collector. The receive circuit is a single buffer/inverter transistor stage driven from an integrated 3 terminal IR demodulator chip.

The unit case is a D-25 data cable gender changer hood. A small piece of dark red plastic from a scrapped alarm clock makes a reasonable IR filter which closes one end. A standard 25 pin female data socket closes the other. A single high brightness red LED services as an indicator for RX, (and TX due to reflected signal being demodulated). A 9v (216) battery supplies power for the unit.

Logic interface is achieved by taking the MSB of the data lines (pin 9) as the TX signal, and feeding the demodulated RX signal into the ACK pin (pin 10)

The most expensive part of the device was the IR receiver chip. At almost $6 (Aus) it was about 40% of the unit cost. The IR diodes where about $2 each, the other assorted bits and pieces were of negligible cost. All materials where purchased at Jaycar Electronics.


After about 2 hours with a soldering iron and side cutters I arrived at this unit. Simple and neat, except for the 9v battery snap.

the IR modem unit
inside the IR modem
the circuit diagram

Talking To It

A simple Linux char device driver was written to talk to the device. It implements:

Honours O_NONBLOCK, is fully re-entrant, concurrent read() safe, and serializes write()s. It should compile on linux 1.2.13, 2.0.3x and 2.2.1x, and most likely will work on later kernels too, perhaps with some modification.

The User/Kernel Protocol

read() returns the timing, via do_gettimeofday(), of the rising edge of the demodulated IR signal. While this is not all the information in the signal, it is enough to decode all common IR signals.

write() is expected to atomically send a single integer (the IR carrier period in microseconds) followed by signal timing values in the form of pairs of integers; microseconds 'on' then microseconds 'off'. None of the integers passed may be zero (1 will do for the last 'off' time), for obvious reasons there is a limit on the maximum delay that will be honoured. Separation of the integers is via whitespace.

Userspace Magic

I find awk such a nice tool for quick hacks that I wrote some of the early tools to play with the modem's RX functions using it. Within a few hours I had worked out RECS-80 remotes, and the Foxtel (ST-100 cable decoder) box remote protocol.

Shortly after, I wrote a simple TX script that could change channels on the cable receiver, and later, tell my VCR to play, stop rewind, etc, basically anything I could do with the remotes.

Next I started on coding a proper C client for the device. One generic enough to send arbitrary IR signals, but with a sensible decoding chain that allows multiple plug-in protocol modules. This is where the project is currently up to. The TX hardware is used much more than the RX hardware, which sees use mainly for decoding new remotes.

The code is here: irctrl.tar.gz

Future Plans

The under utilized RX side of the device might be nice to work into a CD or MP3 player interface, or perhaps my TV card. Using a generic remote, like the one that came with the TV card, which features many buttons for TV/Stereo/VCR control, it would be possible to map many functions for remote control. (probably only useful if you are distant from your computer while enjoying its multimedia output. I guess some people will want to control their house with it :)

IR identification tags, through PAM modules, might be something fun to play with. Walk up to a workstation and it logs into your customized desktop.

open(), select(), and close() work as expected.

1 comment.