If you haven't read Part 5 - start here!
Hacking the remote codes
The Arduino IR Lib IRremote.h comes in very handy when you want to read the commands send from you remote.
You can use the same parts i used to create a IR receiver to build you own hacking tool.
The IRremote library comes with a sample Program that does the exact same thing that my small IR snooping program does.
Snooping program.
#include <IRremote.h>
int RECV_PIN = 11;
String stringOne = "";
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn();
}
void loop()
{
if (irrecv.decode(&results))
{
Serial.println(results.value, HEX);
irrecv.resume();
}
}
Black goes out of the image to pin 11. |
I took the original Pioneer remote control and pushed all buttons to see what comes out.
Out comes a 32 bit hex number. For example: 0x85ae817 when play is pressed.
The results of the Snooping Program
Button Pressed | Header (HEX) | Payload (HEX) |
---|---|---|
Power | 0x857a | 0x38c7 |
Mode | 0x857a | 0xE21d |
Reset / Tape Capacity | 0x857a | 0x12Ed |
Open / Close | 0x857a | 0x4ab5 |
Stop | 0x857a | 0x6897 |
Play | 0x857a | 0xe817 |
Rewind | 0x857a | 0x8877 |
Pause | 0x857a | 0x18e7 |
Fast Forward | 0x857a | 0x08f7 |
Record (two buttons) | 0x857a | 0x28d7 |
Rec Mute | 0x857a | 0x48b7 |
As you can see the header is always the same, Two Bytes indicating that this is for a Pioneer tape deck. Hex 0x857a.
The next Two byte is the Payload or the actual command.
In a brute force scenario this leaves out Hex 0xffff, minus the 11 codes i already know, in human numbers - 65524 possible codes to run through.
Brute force is very time consuming, but maybe there is a system to the commands.
For example the Play and Pause buttons are very similar. 0xe817 and 0x18e7. The first 4 bit (e) has swapped place with the first 4 bit of the next byte. Even Stop is similar, it has 8 and 7 in it - 0x6897
For those playing along a home - 4 bit is called a nibble. Another fun fact, Pioneer uses NEC IR command Protocol, which are based around 4 bit cpu's.
Rewind is 0x8877 and Fast Forward is 0x08F7. Again something happened to the first nibble of each byte.
Looking at all the commands it is obvious that the 8 and 7 are in most common commands. Like Play, Pause and so on. Fixing 8 and 7 into a mask like this 0x_8_7 leaves 256 minus 8 commands to brute force through.
But there is more, if you look at the Payload codes in 4 bit binary, like the Play Button, it looks like this.
0xe817 = 1110 (e) 1000 (8) 0001 (1) and 0111 (7)
Command-set is red - command is green.
1000 (8) and 0111 (7) are complementary nibbles - they always adds up to 16, but so are the two other pairs 1110 (E) and 0001 (1) - and if you look at all the commands, they are all complementary.
The whole thing is setup in 16 sets of commands.
In the above scanning program i found 3 Command-sets: 0x_8_7, 0x_2_D and 0x_A_5. But there are more sets beginning at 0x_0_F going to 0x_F_0. A command set like 0x_0_E is not valid because 0 and E aren't complementary, but 0x_1_E is valid. So we have 16 sets of commands.
And the commands within the command-sets have 16 valid commands. 16 times 16 equals 256 commands in total. One could say it's a waste of possible commands you could have 65535, but hey - room for 256 is more than enough in this world for a Tape recorder.
To brute force this is a piece of cake. 🎂
My old Arduino grinding through all 256 Commands |
I ran all 256 codes (twice) and found 3 new code: 😁
- Monitor button - 0xb847
- Meter Mode - 0xf20d
- (changing meter from normal to top level, then to bias level and then back again)
- Return to Zero - 0x728d
- (which rewinds the cassette to 0000 or the beginning of the tape, whatever comes first)
As you can see those are unfortunately all in two of the knows Command-sets. The 0x_8_7 and the 0x_2_d. All of the other sets turned up blank.
Of the three new codes the most practical is, in my opinion, the Monitor button.
Here is my Brute-Force Program, which isn't so brute:
#include <IRremote.h>
IRsend irsend;
long pioneerCassette = 0x857A0000;
long knownCodes[] = { 0x38C7, 0xE21D, 0x12ED, 0x4AB5, 0x6897, 0xE817, 0x8877, 0xE817 , 0x08F7, 0x28D7, 0x48B7 };
void setup()
{
Serial.begin(9600);
}
void loop() {
long testCode = 0x0;
for (int bc = 0; bc < 16; bc++) // Counting command sets
{
unsigned int bch = bc << 8;
byte bcl = ~bc - 0xf0;
baseCode = pioneerCassette + bch + bcl;
for (int c = 0; c < 16; c++) // Counting commands
{
unsigned int ch = c << 12;
byte cl = (~c - 0xf0) << 4;
testCode = baseCode + ch + cl;
if (!isKnownCode(testCode))
{
Serial.print("SENDING:");
Serial.println(monitorCode, HEX);
for (int i = 0; i < 3; i++) {
irsend.sendNEC(testCode, 32);
delay(40);
}
while(Serial.available() < 1)
{
// read anything serial input
// press enter sends the next command
}
while(Serial.available() > 0)
{
// clear read buffer with a dummy read
byte dummyread = Serial.read();
}
delay(500); // half a second delay between each command
}
else
{
Serial.print("IGNORING:");
Serial.println(testCode, HEX);
}
}
}
}
boolean isKnownCode(long code)
{
int arraySize = sizeof (knownCodes) / sizeof(long);
for (int x = 0; x < arraySize; x++)
{
if ((pioneerCassette + knownCodes[x]) == code)
{
return true;
}
}
return false;
}
Hope this helps you hunting codes for your device.
Cheers 🍻
Per