Reverse Engineering the Remote Controls

or Why Every Engineer Should Learn Python

Alexander Rowsell
Supplyframe
5 min readMar 12, 2018

--

Prototype of my remote control

Recently, I decided to resurrect an old project that I started a couple years ago. I have a hi-fi system that I have cobbled together from bits and pieces gathered over the years. I have a pretty cool Pioneer 300 CD Jukebox, a Technics turntable, Nikko parametric equalizer, Denon DRA-295 Receiver, and Harmon/Kardon speakers. I value having immediate access to high-quality music.

If I want to hear a song, I want to hear it both loudly and right now.

Unfortunately, the Denon receiver does not have an infrared remote. Neither does the Pioneer CD player. The remotes for these devices are expensive on eBay, and while some universal remotes might support the Pioneer, they definitely would not support the Denon. You can buy high-end universal remotes that are protocol-agnostic and simply store the frequency and timing information, but why buy one when I can just build one myself?

The first step was to try and find control codes for these two machines. If I had the remotes in hand to work from I could just reverse-engineer it, but I don’t. And, if I had remotes, this whole project would be unnecessary.

Most online repositories of infrared codes are in a format called Pronto HEX. This is basically a giant text file where each line is an individual command. The first few bytes describe the frequency of the pulses, and the rest of the bytes specify the ON/OFF timing to send that particular code. This is a great format if you don’t know anything about the protocol, as it is literally just storing the exact sequence of pulses necessary to generate a command; however, it is extremely size inefficient. The Pronto HEX file I found for Denon receivers has over 1500 lines of text! If you can specify the protocol in your code, you can store each code as an unsigned 32-bit variable. Much smaller than the 242K of text it would otherwise take!

Testing the infrared LED

But how can we get from Pronto HEX to an unsigned 32-bit integer? The codes, as mentioned before, are simply the amount of time to keep the IR LED on or off. In the protocol the Denon uses, as with most infrared protocols, it is the ratio between these two numbers that determine if the bit sent is a 0 or a 1. Simple enough — we just need to strip the header bytes, then divide each pair of numbers and look at the result to determine the binary output. But we’re talking about 1500 lines of text here! Doing that by hand would take days of extremely tedious work. Luckily, we have computers! My first thought was to write a program in C, my mother tongue of programming languages, so to speak. Unfortunately, manipulating text and text files in C is really a pain. And then a light bulb turned on in the back of my head — use a scripting language!

I had recently started to learn Python, and it seemed perfect for the task. Good at handling text? Check. Good at math? Python technically has infinite floating-point precision. Check. Easy to write, so I can lash together something quickly? Check. Python is the only language I’ve come across where the learning curve is so shallow. It takes so little time to get started, especially if you have experience with programming already. The syntax takes a bit of getting used to (I’m personally not a fan of using indentation alone to separate logical structures in code), but there are so many preexisting modules that it makes any task trivial. As an embedded programmer, I don’t view Python as a language to delve deep into — rather, I view it as something to get the hang of to help automate mundane tasks such as this one. With 25 lines of Python, this task is almost trivial. I think of Python as a monkey see, monkey do language. Unlike functional or procedural languages like C or Java, you don’t need to spend a lot of time understanding the syntax of the language before starting to make things with it. If you know any programming language at all, you can easily just look at other scripts, as well as a few online resources, and be making useful scripts in no time. Let’s take a look at how simple it is:

That’s it! It’s such an easy task that we don’t even need to import any modules. We open both the input and output files, loop through each line in the input file, shuffle it around to make it into a Python list (one of the data primitives in Python) and then do the simple math to convert it into a binary string! Then we write that output to a file, and close the files. There’s not an ounce more fat in this script than is absolutely needed. This is the power of a scripting language, and why they are such a good companion to lower-level languages like C. For instance, in the nested for loop, notice how we can essentially cast directly from a string to an integer. Try doing that in C!

3D render of the final PCB!

I highly recommend the book Learning Python by Mark Lutz. It’s published by O’Reilly, and it’s an excellent resource. I also have the Python Pocket Reference, which is super handy. Just remember that for automating tasks like the above, you really don’t need to go all out! You don’t need to learn about lambda statements or generator functions. Just take advantage of the extremely rich and versatile Python libraries that exist, and help get your work done more quickly! I have a GitHub repository with some useful Python scripts I’ve written to automate some other boring tasks. Feel free to take a look at it here! Don’t hesitate to contact me if you need any help!

--

--