The controller was clearly marked with a sticker indicating operation at 27 MHz (FCC ID: NPI71646). That would have been my first guess anyway as it is a very popular frequency for radio-controlled toys. Since several of us were having a HackRF party, I decided to see if I could control the car with my HackRF Jawbreaker.
After verifying that the car worked with the original controller, I recorded several waveforms with the hackrf-transfer utility. I made eight separate recordings, one for each active controller state: forward, backward, left, right, forward/left, forward/right, backward/left, and backward/right.The recordings were quite clean even though 27 MHz is below Jawbreaker's official operating range (30 MHz to 6000 MHz). In fact, I had captured some apparently good recordings of NFC transactions at 13.56 MHz just the day before. The major drop-off in performance I've observed on Jawbreakers I've tested has been just below 10 MHz.
The first HackRF transmission I tried was by building a small flowgraph in GNU Radio Companion to replay the captured waveforms with my Jawbreaker one at a time. With the car's controller switched off, I was able to make the car move with a simple replay! The best waveform worked at a distance of up to 20 meters even though I put very little effort into cleaning up the waveform or adjusting the power level.
Although I didn't have much time left before I had to catch my flight home, I wanted to see if I could synthesize control transmissions in software on my laptop instead of replaying captured waveforms (that included received noise and minor defects such as quantization and DC offset).
The first step toward synthesizing control transmissions was to analyze the captured waveforms. I found that each transmission consisted of a series of pulses at 27.145 MHz. The pulses were all at the same power level. Each pulse lasted one of two durations and was followed by a pause of consistent length. It looked like On-Off Keying (OOK) with data encoded in the number of consecutive short pulses.
Each transmission featured a repeated pattern of four long pulses (each 1.875 ms long, separated by 0.625 ms pauses) followed by some number of short pulses (each 0.625 ms long, separated by 0.625 ms pauses). The repeated pattern continued for as long as the controller was held in a particular state. The number of consecutive short pulses depended on the state of the controller:
- forward: 10 short pulses
- forward/left: 28 short pulses
- forward/right: 34 short pulses
- backward: 40 short pulses
- backward/left: 52 short pulses
- backward/right: 46 short pulses
- left: 58 short pulses
- right: 64 short pulses
That's as far as I got.