computers

Emulating a Sony Stereo Remote Control

I have a few Sony stereos about the place that largely (these days) act as amplification for something or other.  One I use with a TV, using it’s AUX setting to feed in an audio input.  The only problem is that there is no way to select the AUX input from the front panel – it has to be done with a remote control. But the remote that came with it doesn’t have an option for AUX either – it has CD, tape or tuner, but no AUX.  The only way to get to the AUX setting is using the “function” button which cycles between CD, tape, tuner and AUX!

But I’ve now lost the remote (and the spare remote I was saving “just in case” and the spare, spare turns out only works with power, CD and volume, not “function”) and someone changed the mode to CD and there is no way to get it back onto AUX!  I have a few other remote controls for Sony stereos and they have various combinations of CD, tape, tuner, MD, second tape deck, and so on.  But it seems that only the power, CD and volume controls are common, so no escape there, and second hand ones online seem to be going for upwards of £10!

So I turned to an Arduino, an infrared LED and the following websites to help:

And the Arduino IRemote library from Ken Shirrif: https://github.com/Arduino-IRremote/Arduino-IRremote.

The problem is that the usual way to use an Arduino and the IRemote library is to first get it to “dump” the IR parameters for your controller by using a LED receiver and your existing remote control.  But I’ve lost mine, so no joy there.

As I say, I did have some similar remotes and wondered if sampling the selection buttons from them might lead to an obvious omission that I could infer was the AUX setting.  So using the “ReceiveDump” sample application and the following circuit I was able to grab the magic numbers from some of the remotes I still have.

Arduino IR RX_bb

WARNING: Check the pinout for the IR receiver you have, there are several different varieties! I’ve found some with the pinouts reversed to that shown above.

This gives an output over the serial link like the following:

Protocol=Sony Address=0x10 Command=0x25 Raw-Data=0x825 12 bits LSB first

Send with: IrSender.sendSony(0x10, 0x25, <numberOfRepeats>);

Raw result in internal ticks (50 us) - with leading gap
rawData[26]: 
-65535
+47,-13
+22,-13 +11,-12 +23,-13 +11,-12
+11,-13 +23,-13 +10,-13 +11,-13
+11,-12 +11,-13 +11,-13 +23
Sum: 378
Raw result in microseconds - with leading gap
rawData[26]: 
-3276750
+2350,- 650
+1100,- 650 + 550,- 600 +1150,- 650 + 550,- 600
+ 550,- 650 +1150,- 650 + 500,- 650 + 550,- 650
+ 550,- 600 + 550,- 650 + 550,- 650 +1150
Sum: 18900

Result as internal ticks (50 us) array - compensated with MARK_EXCESS_MICROS=20
uint8_t rawTicks[25] = {47,13, 22,13, 11,12, 23,13, 11,12, 11,13, 23,13, 10,13, 11,13, 11,12, 11,13, 11,13, 23}; // Protocol=Sony Address=0x10 Command=0x25 Raw-Data=0x825 12 bits LSB first

Result as microseconds array - compensated with MARK_EXCESS_MICROS=20
uint16_t rawData[25] = {2330,670, 1080,670, 530,620, 1130,670, 530,620, 530,670, 1130,670, 480,670, 530,670, 530,620, 530,670, 530,670, 1130}; // Protocol=Sony Address=0x10 Command=0x25 Raw-Data=0x825 12 bits LSB first

uint16_t address = 0x10;
uint16_t command = 0x25;
uint32_t data = 0x825;

Pronto Hex as string
char prontoData[] = "0000 006D 000D 0000 005B 0018 002B 0018 0016 0016 002D 0018 0016 0016 0016 0018 002D 0018 0014 0018 0016 0018 0016 0016 0016 0018 0016 0018 002D 06C3 ";

The most useful bits are the address and command portions.  These relate to the two values required to be passed back into the Arduino IRemote library sendSony() call to send that command back out over the IR LED (also shown in the circuit above).

Unfortunately there was no simple sequence of commands being detected for which I could infer some missing values!  Here is a selection of the values I was receiving for the various “CD”, “Tape”, “Tuner”, “MD”, “Aux”, and similar buttons on a RM-AMU179 and RM-SR5 remote:

Address Command   Raw-Data
 0x10    0x25      0x825    - CD
0x410    0x17     0x20817   - USB
 0x90    0x29      0x4829   - DAB
 0x10    0x18      0x818    - FM
 0x10    0x6E      0x86E    - Audio IN
 0x11    0x32      0x8B2    - CD
 0xD     0xF       0x68F    - Tuner
 0xE     0X74      0x774    - Deck A
 0xE     0x34      0x734    - Deck B
 0xF     0x2A      0x7AA    - MD

I can’t spot a pattern!  And looking more closely at the following site: http://www.hifi-remote.com/sony/Sony_rcvr.htm we can see that the selection options are pretty much “all over the place”.  I did have one “brute force” attempt at sending a selection of potentially useful looking candidates over in a loop:

for (int i=29; i<38; i++)
{
  IrSender.sendSony(0x10, i, 3, 12);
  delay(1000);
}

for (int i=64; i<74; i++)
{
  IrSender.sendSony(0x10, i, 3, 12);
  delay(1000);
}

for (int i=104; i<108; i++)
{
  IrSender.sendSony(0x10, i, 3, 12);
  delay(1000);
}

But all I could make it recognise were Tape (0x10, 0x23 or 35) and CD (0x10, 0x25 or 37).  So, over to “plan B”.

The Linux IR Control (LIRC) project has a really extensive list of IR codes for controllers, and I was able to work out that my stereo uses the Sony RM-SC1 remote control. I wasn’t able to find the setting for the AUX input (although with time that still might be possible), but I was able to find the magic numbers that need to be sent to enable the “function” button to allow me to cycle between CD, tape, tuner and AUX.

From: https://lirc.sourceforge.net/remotes/sony/RM-SC1 I can see that the “function” button is described as follows:

begin remote

  name  Sony_RM-SC1_2
  bits            7
  flags SPACE_ENC|CONST_LENGTH
  eps            30
  aeps          100

  header       2450   500
  one          1260   541
  zero          650   541
  post_data_bits  8
  post_data      0x9
  gap          44783
  toggle_bit_mask 0x0

      begin codes
          function                 0x4B
          eq                       0x63
      end codes

end remote

So this is a 7-bit command with an 8-bit “post data” fixed field containing the value 0x9, which means the code required to activate it is constructed as follows:

<7-bit command> <8-bit post-data fixed value>

So this is one of the 15-bit Sony values (Sony also uses 12 and 20-bit values).

0x4B . 0x09 -> 100 1011 0000 1001

The trick is working out how to turn this into values to put into the Arduino IRemote library, which requires a “command” and an “address” for the Sony protocol.  You can read more about how to interpret these values in Ken Shirrif’s post here.

The bits as listed in the LIRC database should be read as values from right to left.  There are three formats of Sony protocol (see: https://www.sbprojects.net/knowledge/ir/sirc.php):

  • 12 bits = <7 bit command> <5 bit address>
  • 15 bits = <7 bit command> <8 bit address>
  • 20 bits = <7 bit command> <8 bits extended address> < 5 bits address>

So for our 15 bit value, we need to read the last 8 bits “back to front” as an 8-bit address:

0000 1001 -> 1001 0000 = 0x90

Then the final 7 bits are the command:

100 1011 -> 110 1001 = 0x69

This means that the call into the Arduino IRemote library we need is as follows:

 IrSender.sendSony(0x90, 0x69, 3, SIRCS_15_PROTOCOL);

Note that we need to specify we’re using the 15-bit protocol.  Cross-referencing with http://www.hifi-remote.com/sony/Sony_rcvr.htm we can look up 0x90 (144) and 0x69 (105) but that is listed as “Input +/Right” so I would never have guessed to try that from my “brute force” approach!

The easiest way to “hack” this in is to take the IRemote SimpleSender example program and place this line at the start of the main loop() function, followed by an immediate return. I included a delay and flashed the LED to show it was working.

void loop() {
  IrSender.sendSony(0x90, 0x69, 3, SIRCS_15_PROTOCOL);
  delay(200);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(200);
  digitalWrite(LED_BUILTIN, LOW);
  delay(2000);

  return;

  // rest of original loop() function

When used with an InfraRed diode on D2 (with a suitable current limiting resistor), this should result in sending the “function” button press every two seconds.

Arduino IR TX_bb

My IR LED has the following properties:

  • 5mm IR LED (940nm)
  • Vf = 1.2-1.4V
  • If = 100mA

But the Arduino’s limit is 40mA (max) or 20mA (ideal) for an IO pin to drive an LED directly.

  • So @40mA/5V -> 95Ω
  • @20mA/5V -> 190Ω

I used a 220Ω resistor as I had some spare, which means I’m running with a current of I = V/R = (5 – 1.2) / 220 ~ 17mA.

Just for completeness, looking back at my original trace, we can see that some of the values I detected used a 12-bit command at address 0x10, for example:

Protocol=Sony Address=0x10 Command=0x25 Raw-Data=0x825 12 bits LSB first

Mapping this onto the values from http://www.hifi-remote.com/sony/Sony_rcvr.htm, we can see that address 0x10 is a “Sony 16” device (0x10 = 16 in decimal), and that command 0x25 (37 decimal) is “CD, CD/SACD, Aux1”.  So again for completeness this maps as follows:

  • It is a 12-bit command, so has a 5-bit address and 7-bit command.
  • The “raw” value listed is 0x825 which is 1000 0010 0101, giving an address of 1 0000 (0x10 or 16), and a command of 010 0101 (0x25 or 37).
  • Looking in the LIRC data dump for the “Select CD command” we can see the following:
begin remote

  name  Sony_RM-SC1_1
  bits           12
  flags SPACE_ENC|CONST_LENGTH
  eps            30
  aeps          100

  header       2476   491
  one          1270   532
  zero          659   532
  gap          44783
  toggle_bit_mask 0x0

      begin codes
          KEY_SLEEP                0x061                     #  Was: sleep
          KEY_POWER                0xA81                     #  Was: power
          display                  0xD21
          clock_timer_select       0x461
          clock_timer_set          0xA61
          tuner_memory             0x701
          KEY_TAPE                 0xC41                     #  Was: tape
          KEY_CD                   0xA41                     #  Was: cd
          tuner-band               0xF01
          KEY_VOLUMEUP             0x481                     #  Was: vol_plus
          KEY_VOLUMEDOWN           0xC81                     #  Was: vol_minus
      end codes

end remote

KEY_CD is 0xA41 or 1010 0100 0001.  Decoding this “backwards” using the 12-bit format <7-bit command> <5-bit address> gives:

  • [ 1010 010 ][ 0 0001 ] -> [ 1000 0 ][ 010 0101 ]
  • Address = 00001 -> 10000 = 0x10 (16)
  • Command = 101 0010 -> 010 0101 = 0x25 (37)

So the following call would trigger this command (and it does):

 IrSender.sendSony(0x10, 0x25, 3);

Note that a bit length of 12 is assumed if none is specified.

So back to the original problem. I need to use “function” several times to select through CD – tape – tuner – AUX, so I ended up just letting the above code run until the AUX setting could be seen on the display, then I turned off the Arduino!

Kevin

Leave a comment