Reverse engineering a ceiling fan

Tonight I was visiting a friend of mine, and noticed a strange looking switch on the wall. My friend explained that it was a wireless controller for his ceiling fan. Since we’re both radio geeks, and I happened to have my BladeRF with me, I got the idea to reverse engineer it.

The first step was to figure out what frequency the controller was transmitting on. The BladeRF makes that a fairly easy task, since it has a bandwidth of 28 MHz. I fired up gqrx to get a nice waterfall view of all that bandwidth. My first guess was that the signal might be on the 902-928 MHz band, and sure enough, I spotted a signal popping up at 911.24 MHz whenever I pressed a button on the controller. But it was quite weak, which led me to suspect it might be a harmonic. Indeed, when I tuned lower I found a very strong signal at 303.747 MHz, and I could easily detect it from across the room.

The next step was to check what modulation scheme the controller used. Most simple devices like this are using either on-off keying or frequency-shift keying. Zooming in on the signal in gqrx, I saw only a single peak, which suggested on-off keying.

I knew my trusty RTL-SDR dongle would be more than capable of receiving and demodulating the signal, so I threw together a very simple GNU Radio flow graph to show me the amplitude of the 303.747 MHz signal over time:


Here’s what I saw on the scope, once I set it to trigger on a rising edge and pressed the “light” button on the ceiling fan controller:


The transmission was short enough that I could just read the bits off visually: 1011011001011001001001001001001001011. And by measuring the time from the start to the end of those bits, I worked out that the symbol rate was about 3211 baud.

In fact, all the buttons generated very similar 37-bit patterns:

off:   1011011001011001001001001001001011001
low:   1011011001011001001001001011001001001
med:   1011011001011001001001011001001001001
high:  1011011001011001001011001001001001001
light: 1011011001011001001001001001001001011

The bits were repeated for as long as a button was held, with about another 37 bits worth of zeroes between each repetition.

Given this information, it was trivial to build a flow graph to transmit an on-off keying signal using the BladeRF:


My first attempt was unsuccessful, but it turned out the problem was just that the output gain wasn’t set high enough. Bringing it up to about 15 dB was sufficient to reliably control the ceiling fan!

The whole reverse engineering project took only about a half an hour, which really demonstrates the power of software-defined radio.

I’ve already added the receiver and transmitter to my sdr-examples repository on Github:

Receiver: ceiling_fan_rx.grc
Transmitter: ceiling_fan_tx.grc

Update: Looking at the bit patterns above, it is apparent that the bits come in groups of three: either 001 or 011. Presumably, 001 represents a baseband 0, and 011 represents a baseband 1. That is, a narrow pulse represents a zero and a wide pulse represents a one. That would make the baseband bit patterns as follows:

off:   0110100000010
low:   0110100001000
med:   0110100010000
high:  0110100100000
light: 0110100000001

Digital amateur TV on 70cm, 33cm and 23cm

I love my BladeRF! It’s a very versatile SDR transceiver, and I’ve used it to receive and transmit all sorts of signals. Most recently I got it transmitting DVB-T digital television signals on the amateur radio bands, with my trusty NooElec TV28T serving as the receiver. (It is a TV tuner, after all, so why not use it as one for once?) In this post, I’ll show you how to replicate what I’ve done.

First off, you’ll need two laptops running Linux: one to transmit, and one to receive. The transmit laptop needs to have the latest version of GNU Radio installed. If you’re running Ubuntu, the easiest way to get that done is to use OZ9AEC’s package archive. At a command prompt, run the following:

sudo add-apt-repository ppa:gqrx/snapshots
sudo apt-get install gnuradio gnuradio-dev gqrx libboost-all-dev libcppunit-dev swig liblog4cpp5-dev

Once that’s done, you’ll need to install YO3IIU’s DVB-T package for GNU Radio:

git clone
cd gr-dvbt
mkdir build
cd build
sudo make install
sudo ldconfig
cd ..

Next, grab my collection of SDR examples:

git clone

Included in that collection is, a script written by W6RZ that lets you transmit DVB-T from the command line using a BladeRF. Since amateur stations typically operate at much lower power than commercial broadcasters, I’ve modified it to use the lowest available bit rate, which should maximize the distance at which the signal can be received. (If you want to experiment with higher bit rates, you can change the “channel_mhz”, “mode”, “code_rate”, “constellation” and “guard_interval” variables. You’ll also need to adjust the mux rate of your transport stream, which can be calculated using W6RZ’s dvbrate.c.) The script is configured to transmit at a centre frequency of 441 MHz, so be sure to attach a suitable 70cm antenna to your BladeRF’s TX port before transmitting.

The script expects to be given an MPEG transport stream as input. Fortunately, we can produce one in real time using avconv. It can record video from the laptop’s webcam and audio from the laptop’s microphone, and encode them into a suitable transport stream. To let avconv and talk to each other, we’ll create a fifo:

mkfifo in.fifo

Then we launch and tell it to read from the fifo:

sdr-examples/ in.fifo

You’ll see some output, but nothing will be transmitted yet because no data is arriving in the fifo. To fix that, open a second terminal window and run avconv like so. Be sure to replace XXXXXX with your own call sign, which will be displayed in the lower right corner of the video.

avconv -f alsa -i pulse -f video4linux2 -s 640x480 -i /dev/video0 -vf drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf:text="XXXXXX":x=440:y=420:fontsize=48:fontcolor=white@0.6:box=1:boxcolor=black@0.2 -vcodec mpeg2video -s 640x480 -r 60 -b 4000000 -acodec mp2 -ar 48000 -ab 192000 -ac 2 -muxrate 4524064 -mpegts_transport_stream_id 1025 -mpegts_service_id 1 -mpegts_pmt_start_pid 0x1020 -mpegts_start_pid 0x0121 -f mpegts -y in.fifo

You may need to install additional packages so that avconv has access to all the codecs it needs. If all goes well, your two terminal windows should look like this:


Now, over to the receiving laptop, which will use an RTL-SDR dongle to pick up the signal. Since support for the RTL2832 chip was only recently added to the Linux kernel, you’ll want to be running a recent Linux distribution such as Ubuntu 13.10. Make sure you have vlc installed:

sudo apt-get install vlc

Then launch vlc like so:

vlc dvb://frequency=441000000:bandwidth=6

If all goes well, you’ll see your video and hear your audio!


Now that you’ve succeeded on the 70cm band, you may want to try this on the 33cm and 23cm bands as well. Unfortunately, the Linux drivers for the RTL-SDR dongle currently limit its maximum frequency to 862 MHz, a bit below the 33cm band. Until the drivers get updated (I’ve already submitted a patch request), you can work around the problem by patching the kernel modules on your receiving laptop using the script in my sdr-examples repository:

sudo sdr-examples/

If everything worked correctly, the script should print out “Success!” twice. If you saw that, then reboot, and you should now be able to tune all the way up to 1750 MHz. On the transmitting laptop, change the “center_freq” variable to 913000000 for 33cm or 1279000000 for 23cm, put an appropriate antenna on your BladeRF’s TX port, and fire up and avconv again. On the receiving laptop, fire up vlc again, putting the appropriate value in for the “frequency” parameter.

In my experiments, I found that the BladeRF put out the most power on the 33cm band. I was able to receive the signal all around the house, using a rubber duck 33cm antenna on the BladeRF and the RTL-SDR dongle’s stock antenna. I’ve had a QSO with VA3DGN on 70cm. To get the signal beyond my house, I hooked the BladeRF up to a Down East Microwave 70cm 25 watt power amplifier.

Have fun with DVB-T! I’d love to hear back if you make any contacts.

Tracking planes for $20 or less

My new favourite toy is a cheap $20 USB TV tuner. It’s made to receive DVB-T signals, which aren’t even used in North America. So what use could I possibly have for it?

Back in February, Linux kernel developer Antti Palosaari discovered that certain USB TV tuners can be configured to send the raw, unprocessed radio signal straight to the computer for decoding in software. (They use this mode when tuning FM or DAB radio signals. Think of it as the Winmodem approach to radio.) Palosaari realized that by running the right software, almost any radio signal could be received by these tuners. Not long thereafter, the RTL-SDR project was born, allowing these tuners to be used in Linux.

I should note that receiving (and transmitting) radio signals in software is nothing new. Software-defined radio has been around for years, but the hardware required (such as the Ettus Research USRP has generally been expensive. The availability of a $20 software-defined radio receiver has truly opened up the world of radio to anyone who takes the time to learn.

Since getting my hands on a compatible TV tuner, I’ve been able to listen to police radio, pager networks, garage door openers, air traffic control, and lots more. I recently tweeted that I had succeeded in tracking the aircraft in my area by using my TV tuner as an ADS-B receiver and feeding the output into Google Earth. This caught the interest of a pilot friend of mine, so I thought I’d put together a tutorial for anyone interested in capturing these signals. Although the tutorial is specific to ADS-B, keep in mind that the software tools (and in particular GNU Radio) can be reconfigured to tune in virtually any radio signal.

So let’s get started!

  1. Purchase a USB TV tuner based on the Realtek RTL2832U chip. For best results, choose one that uses the Elonics E4000 tuner, which will let you tune in the widest range of frequencies, from 64 to 1700 MHz. The OsmoSDR site has a list of supported hardware to get you started. I chose the Newsky TV28T tuner, which I purchased from Aliexpress. (I paid 40 USD for two tuners, shipping included.)
  2. If you’re not running it already, download and install Ubuntu Desktop 12.04 LTS. I would recommend using the 64-bit version.
  3. Install all the available Ubuntu software updates using Update Manager and restart.
  4. Download, build and install GNU Radio using the build-gnuradio script. This can be done in a terminal window by running the following commands:

    cd ~
    mkdir build-gnuradio
    cd build-gnuradio/
    chmod a+x ./build-gnuradio

    Note that GNU Radio is quite a large piece of software and has a lot of dependencies, so the install process can take a long time.

  5. Download, build and install gr-air-modes. This is the piece of software that knows how to decode the ADS-B signals that many planes transmit. In a terminal window, run the following commands:

    cd ~
    git clone
    cd gr-air-modes
    cmake .
    sudo make install
    sudo ldconfig

  6. Plug in your TV tuner, and check whether you can receive ADS-B traffic by running the following in a terminal window: --rtlsdr

    If it works, you should see output like the following:

    (-42 0.0000000000) Type 11 (all call reply) from c0636c in reply to interrogator 0 with capability level 6
    (-41 0.0000000000) Type 17 BDS0,5 (position report) from c078b2 at (45.199942, -75.541590) at 30050ft
    (-39 0.0000000000) Type 11 (all call reply) from c078b2 in reply to interrogator 0 with capability level 6
    (-39 0.0000000000) Type 17 BDS0,9-1 (track report) from c078b2 with velocity 443kt heading 259 VS 1664
    (-40 0.0000000000) Type 17 BDS0,5 (position report) from c078b2 at (45.199616, -75.544069) at 30075ft
    (-42 0.0000000000) Type 17 BDS0,5 (position report) from c078b2 at (45.199265, -75.546504) at 30100ft

    We’re already seeing some GPS coordinates and altitudes! Press CTRL-C to stop it for now.

    If you don’t see any traffic, try going outside for better reception.

  7. To see the output in a more convenient form, we’ll use Google Earth. Download the 64-bit .deb version from the download page, and open the file to run the installer.
  8. For nicer-looking fonts in Google Earth, install the xfonts-75dpi and xfonts-100dpi packages by running the following in a terminal window:

    sudo apt-get install xfonts-75dpi xfonts-100dpi

    Then log out and log back in so the new fonts will get loaded.

  9. Launch Google Earth.
  10. If Google Earth fails to launch, it may be because it can’t find libGL. (This happened on one of my two laptops.) To fix it, run the following command in a terminal window:

    sudo ln -s /usr/lib/i386-linux-gnu/mesa/ /usr/lib/

  11. Run again, this time telling it to write its output to a KML file, the format used by Google Earth. In a terminal window, run the following: --rtlsdr --kml=planes.kml

  12. In Google Earth, select “Network Link” from the “Add” menu. Enter “Planes” in the “Name” field, then click the Browse button next to the “Link” field and choose the “planes.kml” file in the file chooser. Click on the “Refresh” tab and set a time-based refresh to occur periodically with a frequency of 5 seconds. Click “OK”, then zoom in to your location. With any luck, you should see some planes start to appear and move around!
  13. To see more details about a plane, click the “X” that appears on the map. Or go to the “Places” section in the left sidebar and expand “Planes” and “Aircraft locations”.

    Here’s a screenshot of Air Canada flight 839 coming in for a landing at YOW, with several more planes at cruising altitude in the background:

Screenshot of gr-air-modes in Google Earth

I hope you find this tutorial useful, and that you’ll do more exploring with software-defined radio once you’ve succeeded in watching planes!

Moving from Tomboy to Gnote in Ubuntu 12.04

Gnote in the tray

Yesterday I updated from Ubuntu 10.04 to 12.04. As usual, I did a completely fresh install, only copying over the things I still need. Tomboy is at the top of that list, so I copied over my ~/.local/share/tomboy/ directory. I read that Gnote is now the preferred replacement for Tomboy, so I installed it and was pleased to see that it read in my Tomboy notes automatically. But it didn’t put an icon in my tray, and that was my favourite Tomboy feature. To get the tray icon back, I did the following:

Fisrt, I added gnote to the systray whitelist:

gsettings set com.canonical.Unity.Panel systray-whitelist "['JavaEmbeddedFrame', 'Wine', 'Update-notifier', 'gnote']"

Next, I set Gnote to auto-start:

mkdir ~/.config/autostart
cp /usr/share/applications/gnote.desktop ~/.config/autostart/
chmod u+x ~/.config/autostart/gnote.desktop

Finally, I turned on the tray icon in Gnote itself: Edit → Preferences → Use Status Icon. After logging out and back in, Gnote started up in the tray just the way Tomboy used to.

Using the Raspberry Pi’s serial port

The stock Debian image for the Raspberry Pi uses the UART as a serial console. I was able to connect to it from my Ubuntu laptop via my 3.3-volt USB FTDI TTL-232 cable. I connected Raspberry Pi’s ground pin to the ground pin of the FTDI, the Rasberry Pi’s TX pin to the FTDI’s RX pin and vice versa. (The Raspberry Pi’s pinout is available here.) Then on my Ubuntu laptop I installed minicom (sudo apt-get install minicom) and fired it up with:

minicom -b 115200 -o -D /dev/ttyUSB0

After typing in a username, I got a password prompt and was able to log in. Also, the serial console allowed me to see all the kernel output during boot, which could be handy someday.

But I wanted to use the Raspberry Pi’s UART for my own purposes, not as a serial console. To achieve that, I did the following.

First, I made a backup of the /boot/cmdline.txt file, which contains the kernel parameters:

sudo cp /boot/cmdline.txt /boot/cmdline_backup.txt

Then I edited it:

sudo vi /boot/cmdline.txt

Originally it contained:

dwc_otg.lpm_enable=0 rpitestmode=1 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

I deleted the two parameters involving the serial port (ttyAMA0) to get the following:

dwc_otg.lpm_enable=0 rpitestmode=1 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

I rebooted (sudo reboot) to confirm that kernel output was no longer going to the serial port. But the serial console was still available. So I edited /etc/inittab:

sudo vi /etc/inittab

I commented out the following line:

2:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

Finally, I rebooted again and confirmed that nothing was touching the serial port anymore. Then, to test it out I installed minicom on the Raspberry Pi:

sudo apt-get install minicom

And ran it:

minicom -b 115200 -o -D /dev/ttyAMA0

After firing up minicom on my Ubuntu laptop again, I was able to send data in both directions!

Now to get the Raspberry Pi talking to an Arduino…

Making the Raspberry Pi a little less British

Raspberry Pi

After a month and a half of obsessively checking for status updates, I finally received my Raspberry Pi yesterday. I love it!

The first thing I noticed after booting up the stock Debian image was that things are set up for British users. Most annoyingly, the symbols on the keyboard weren’t where I expected them to be. To arrive at a more Canadian configuration, I did the following.

First, I changed the system locale, turning off en_GB.UTF-8 and turning on en_CA.UTF-8:

sudo dpkg-reconfigure locales

Next, I changed the keyboard layout:

sudo dpkg-reconfigure keyboard-configuration

Next, I changed the time zone:

sudo dpkg-reconfigure tzdata

And finally, I changed to a Canadian Debian mirror by editing the “sources.list” file:

sudo vi /etc/apt/sources.list

On the first line, I changed “” to “”:

deb squeeze main

# Nokia Qt5 development
deb unstable main

After rebooting (sudo reboot) and updating my package list (sudo apt-get update) I had a pleasantly Canadian Pi. 🙂

UPDATE: Rohan Kapoor has turned these instructions into an excellent tutorial with lots of screenshots: “Americanizing” the Raspberry Pi. I highly recommend it if you’re a beginner having trouble following my instructions.

WIND Mobile: A bad first impression

I’ve been wanting to try WIND Mobile for a while now, but my phone (Nexus One) didn’t support the frequency bands used by the new carriers. But recently I replaced it with a Galaxy Nexus, which supports the frequencies of all the Canadian carriers. WIND had a great deal on ($40 for unlimited everything), so I grabbed a WIND SIM card and signed up online.

I didn’t want to port my number over until I was sure WIND’s coverage was adequate, so I declined the option when I activated my SIM. A few days later I was satisfied, so I called up WIND customer care to request the port. The person who answered my call told me it was impossible to port a number to a SIM that was already activated, and that I was stuck with the number that I had been assigned. Not happy with this response, I asked whether there wasn’t some other possibility, and I was told that I could go to a WIND store and get a replacement SIM, which could then have my number ported to it.

I phoned my nearest WIND store, and was told it would cost $25 to get a replacement SIM. Obviously I had no intention of paying $25 to fix a problem on WIND’s end, so I headed to Howard Forums to see whether other customers had faced the same problem. It didn’t take long to find several discussion threads on the topic. Some customers had managed to get a free replacement SIM at a WIND store, and others had eventually convinced WIND to cancel and re-activate their existing SIM, entering a port request with the new activation.

I called back, hoping to get a different customer care rep. This time, the rep was happy to put through a port request for me, but said the request would need to be handled by their back office staff, and would take three to five business days. While this seemed like an awfully long time for such a simple request, it sounded like a better option than making a trip to a WIND store, so I asked the rep to put through the request. She took down my information and gave me a reference number.

After four business days had passed, I was getting impatient. So I called back and gave my reference number. The rep told me that the reference number didn’t exist in their system. He looked up my account, and found that no port request had been made. I explained what had been done on my previous call, but the rep insisted that it was not even possible; I could not port a number to a SIM that had already been activated. The rep told me I would need to go to a WIND store and get a new SIM, which he insisted I would not be charged for.

At this point I was irate. How could my request have disappeared into thin air? I called back one more time, hoping there was somebody in customer care who could actually help me. The fourth rep again couldn’t find my request from the previous week, but after explaining my situation he told me that my number could easily be ported in to my existing SIM. He only had to cancel my existing SIM and re-activate it. He was able to do that within minutes, and my number was ported within the hour.

Clearly WIND has a big problem with insufficiently trained customer care reps. Two out of the four reps I spoke to didn’t know it was even possible to help me, and one was too incompetent to do it properly. My tweets to @WINDmobile during the ordeal went unanswered, as did an email to customer care. While I plan to stay with WIND for the time being, in the hope that their network is better than their customer care, I will definitely not be recommending them to friends. Koodo will remain my recommendation.

Getting rid of tearing in MythTV

I just upgraded to MythTV 0.24, and so far it’s looking great! Closed captions look much nicer and the revamped on-screen display looks very sharp. But one problem I’d seen occasionally in 0.23 seemed to be worse: tearing in video playback. I used to see tearing only occasionally in HD playback, but after the upgrade I started to see it more frequently, and in SD playback as well. After a bit of quick googling, I found a solution in the MythTV wiki. I added the following to my frontend’s /etc/X11/xorg.conf file:

Section "Extensions"
Option "Composite" "Disable"

After a quick restart, the tearing was completely gone. Yay!

Switching to WordPress

I was starting to get tired of Drupal, so I thought I’d switch my blog over to WordPress. So far I’m impressed. The installation was simple, and I was up and running in minutes. I thought of using a script to copy my old blog postings over, but since there weren’t many I just did it by hand. Now I’m putting the finishing touches on. Please let me know if you notice any problems.

My submission to the Copyright Consultation

I just sent my submission to the Canadian Copyright Consultation. There’s still time to submit, if you haven’t done so already. I’d recommend reading Professor Michael Geist’s submission to get some ideas.

Here’s my submission:

Having read over the previous copyright bill (C-61), I would like to voice my opposition to the inclusion of anti-circumvention provisions in the new copyright bill. My reasons are as follows:

  1. The anti-circumvention provisions in bill C-61 would have made it illegal for consumers to unlock their cell phones. This would further stifle competition in Canada’s wireless sector by making it more difficult for consumers to switch carriers, since they would have to purchase new hardware. It is my view that competitiveness would be maximized by banning the practice of cell phone locking, rather than protecting it in law. The owner of a cell phone should be free to use it with the carrier of his or her choice.
  2. Users of the Linux operating system, myself included, must use a circumvention tool (libdvdcss) to play legally purchased DVDs on their computers. I see no reason why the use or distribution of this tool should be restricted, since it has many uses which do not infringe upon copyright.
  3. The anti-circumvention provisions in bill C-61 would have allowed copyright holders to take away users’ fair dealing rights simply by applying technological protection measures (TPMs) to their works. Fair dealing rights are a critical part of our copyright legislation, and we must not allow them to be taken away by anti-circumvention legislation.
  4. Technological protection measures can be harmful to consumers. For example, in 2005 Sony sold music CDs containing software intended to prevent unauthorized copying. This software installed itself without requesting the user’s consent and could not be un-installed. It also made the user’s computer unstable and vulnerable to attack. Other copy protection schemes use a central server to decide whether to allow users to access content they have purchased. When this server ceases to function, whether intentionally or unintentionally, users lose access to their content. In 2008, this occurred when Yahoo shut down its DRM server. I believe that rather than protecting TPMs in law, we should be protecting consumers from them by limiting their use.
  5. Technological protection measures can harm competition. For example, until recently, users who purchased songs through the Apple iTunes music store could only play such content on Apple iPods. A user wishing to switch to another brand of music player would be unable to do so without losing access to their purchased content. It is my opinion that users should be able to access legally purchased content on the device of their choice. Protecting TPMs in law would undermine this goal.

I would further like to make the following suggestions for the upcoming copyright legislation:

  1. Crown copyright should be abolished. I believe that the benefit to the public of putting works produced by the government into the public domain would greatly outweigh the resultant loss of revenue to the government. This model is used in the United States, where works produced by its federal government are not entitled to domestic copyright protection.
  2. The term of copyright protection should be reduced. In my opinion, twenty years from the date of publication should suffice, since most works cease to be comercially exploitable before that point anyway. This would vastly enrich the pool of works in the public domain, upon which creators could freely build.

Clayton Smith
Ottawa, Ontario