irremote/proto_b.jpg
To view high resolution images, right click on image and select View image or Save image
A while back I bought a second hand amplifier for use with our living room stereo. The amp came with a large infrared remote controller intended to control multiple devices from the same vendor.
Now only owning the amp this ment this lovely jewel of a remote control — CNC machined from a large piece of solid aluminium — we only utilized 5 of its 35 buttons.
There's no doubt the initial high cost of this amplifier when new not only stems from its technology and parts used, but also from its lovely satin (sandblasted) anodized finished CNC machined aluminium chassis. It would be sad to waste this remote in a drawer replaced with cheap plastic multi controller. But rather than trying to modify the remote itself I looked for a solution to translate its protocol and retransmit codes our other equipment could understand.
From all the Arduino IR projects I encountered Ken Shirriff's IRremote Library seamed to be the one best meeting my need. Ken's library take care of all the heavy lifting decoding infrared light pulses and creating new pulses.
Prototype very handy placed on top of my laptop screen.
I used an 2$ Arduino Nano clone and followed Ken's instruction hooking up receiver output to PIN 11 and IR LED transmitter to PIN 3. These parts where also sourced of eBay as no-name components searching for 38kHz IR receiver and infrared LED 940nm.
I used on-board LED on PIN 13 for visual representation of code transmitting.
I had some initial problems making the code work until I understood the IR transmission had to wait to after the receiver interups where back operating again. i.e. one test for results and only store them to a variable, then resume receive operation before responding to result.
You probably don't have any of the remotes used here, but still you could upload the sketch to your Arduino board and read out IR code values your controllers give you. And then copy paste these IR codes into the sketch for quick testing of a few buttons before alter code to your requirement.
Download code ino file for Arduino Most web browsers will open ino files as plain text.
For debugging and screen output from COM port make sure this line is not comment out
#define DBUG; // comment out this line for production code.
Note: Some code are missing from preview below due to how PHP render includes on my webserver. Use the download link above to get full code.
Sorry for unspecific code formatting. It's my take on a compromise for quick editing and easy reading.
/* Retransmit B.M.C. CS2 Amp IR multicontroller code as Pioneer D6 * or DV-656A or SqueezeBox Touch or Sony MiniDisc or Samsung TV * and TOSLINK input selector * IR code depending on value of variable 'transport' * Pioneer D6 remote can also control the CS2 amp * * beta 0.21-2019 Hans R Lønningdal http://snw.lonningdal.no * Known issue - IR transmitter diode used are very directional * * Using Ken Shirriff's IRremote Library * http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html * */ #include//https://github.com/z3t0/Arduino-IRremote #define DBUG; // comment out this line for production code. DEBUG already taken by Ken :) #ifdef DBUG #define SP(x) Serial.print (x) #define SPLN(x) Serial.println (x) #define SPHEX(x) Serial.print ("0x"); Serial.println (x, HEX) #else #define SP(x) #define SPLN(x) #define SPHEX(x) #endif unsigned int RECV_PIN = 11; unsigned int STATUS_PIN = 13; IRrecv irrecv(RECV_PIN); IRsend irsend; decode_results results; // results from received IR code unsigned long newvalue; // IR code to transmit unsigned long buttonbefore; // remember last reseived button IR code value unsigned int device = 0; // used to define special feature for the remote send options unsigned int onetofour = 1; // using up/down for direct 1-4 selection on optical input selector unsigned int transport = 1; // BMC CD PROG button alter this value const unsigned int CD = 1; // Pioneer PD D6-MK2 SACD transport const unsigned int SB = 2; // SqueezeBox Touch const unsigned int MD = 3; // Sony MDE-JE770 MiniDisc const unsigned int DAC = 4; // DAC controls used to control TOSLINK selector const unsigned int TV = 5; // Samsung TV (2016) UE60KS7005 const unsigned int DV = 6; // Pioneer DV-656A DVD Audio / CD transport const unsigned int AMP = 7; // B.M.C. CS2 amp void transportStatus(unsigned int activeLED) { // adjust for digital pins used to visualize transport status for (int i = 4; i <= 6; i++) { digitalWrite(i, LOW); } digitalWrite(activeLED + 3, HIGH); } void sendCode(unsigned long button) { digitalWrite(13, HIGH); // Arduino LED // handle repeats from B.M.C. & many others. Needed as DV-656A don't // use repeat code but prefix command code with a fixed 32-bit value if (button == 0xFFFFFFFF) { // we don't want to increment Up/Down input selector for // DAC device so we keep repeat code as is // luckely the optical selector use this repeat code if (device != DAC) {button = buttonbefore;} } else { buttonbefore = button; } device = 0; // 'transport' is default CD=1, new users should test with this branch, or change 'transport' value if (transport == CD) { // verified with Pioneer D6-MK2 SACD player switch (button) { case 0x618650AF: newvalue = 0x45BA38C7; device = CD; SPLN("Power"); break; // Pioneer D6 Power (CD DISP) case 0x6186708F: newvalue = 0x45BA8A75; device = CD; SPLN("Tray"); break; // Pioneer D6 Tray (CD REP) case 0x618610EF: newvalue = 0x45BAE817; device = CD; SPLN("Play"); break; // Pioneer D6 Play case 0x6186906F: newvalue = 0x45BA6897; device = CD; SPLN("Stop"); break; // Pioneer D6 Stop case 0x618630CF: newvalue = 0x45BA708F; device = CD; SPLN("FFW"); break; // Pioneer D6 Fast Forward case 0x6186B04F: newvalue = 0x45BAF00F; device = CD; SPLN("FRW"); break; // Pioneer D6 Fast Rewind case 0x618620DF: newvalue = 0x45BA8877; device = CD; SPLN("Prew"); break; // Pioneer D6 Prew case 0x618600FF: newvalue = 0x45BA08F7; device = CD; SPLN("Next"); break; // Pioneer D6 Next case 0x618648B7: newvalue = 0x45BA807F; device = CD; SPLN("1"); break; // Pioneer D6 1 case 0x6186C837: newvalue = 0x45BA40BF; device = CD; SPLN("2"); break; // Pioneer D6 2 case 0x61868877: newvalue = 0x45BAC03F; device = CD; SPLN("3"); break; // Pioneer D6 3 case 0x618608F7: newvalue = 0x45BA20DF; device = CD; SPLN("4"); break; // Pioneer D6 4 case 0x6186F00F: newvalue = 0x45BAA05F; device = CD; SPLN("5"); break; // Pioneer D6 5 case 0x618618E7: newvalue = 0x45BA609F; device = CD; SPLN("6"); break; // Pioneer D6 6 case 0x6186E817: newvalue = 0x45BAE01F; device = CD; SPLN("7"); break; // Pioneer D6 7 case 0x618628D7: newvalue = 0x45BA10EF; device = CD; SPLN("8"); break; // Pioneer D6 8 case 0x6186A857: newvalue = 0x45BA906F; device = CD; SPLN("9"); break; // Pioneer D6 9 case 0x61866897: newvalue = 0x45BA00FF; device = CD; SPLN("0"); break; // Pioneer D6 0 case 0x618658A7: newvalue = 0x45BA18E7; device = CD; SPLN("Pause"); break; // Pioneer D6 Pause (CD CHECK) case 0x61869867: newvalue = 0x45BAA25D; device = CD; SPLN("Clear"); break; // Pioneer D6 Clear } } if (transport == SB) { // verified with SqueezeBox Touch - NEC 32-bit, first 4 digits 0x7689#### are // device/manufactor idetifier, or 16-bit pre-data as it called in lirc's database switch (button) { // https://sourceforge.net/p/lirc-remotes/code/ci/master/tree/remotes/slim_devices/Squeezebox3.lircd.conf case 0x618650AF: newvalue = 0x76897887; device = SB; SPLN("Display"); break; // SqueezeBox Display Now Playing case 0x6186708F: newvalue = 0x768938C7; device = SB; SPLN("Repeat"); break; // SqueezeBox Repeat case 0x618610EF: newvalue = 0x768910EF; device = SB; SPLN("Play"); break; // SqueezeBox Play (will power on the Touch) case 0x6186906F: newvalue = 0x768920DF; device = SB; SPLN("Stop"); break; // SqueezeBox Stop (actually Pause) case 0x618630CF: newvalue = 0x7689A05F; device = SB; SPLN("FFW"); break; // SqueezeBox Fast Forward case 0x6186B04F: newvalue = 0x7689C03F; device = SB; SPLN("FRW"); break; // SqueezeBox Fast Rewind case 0x618620DF: newvalue = 0x7689C03F; device = SB; SPLN("Prew"); break; // SqueezeBox Prew case 0x618600FF: newvalue = 0x7689A05F; device = SB; SPLN("Next"); break; // SqueezeBox Next case 0x618648B7: newvalue = 0x7689F00F; device = SB; SPLN("1"); break; // SqueezeBox 1 case 0x6186C837: newvalue = 0x768908F7; device = SB; SPLN("2"); break; // SqueezeBox 2 case 0x61868877: newvalue = 0x76898877; device = SB; SPLN("3"); break; // SqueezeBox 3 case 0x618608F7: newvalue = 0x768948B7; device = SB; SPLN("4"); break; // SqueezeBox 4 case 0x6186F00F: newvalue = 0x7689C837; device = SB; SPLN("5"); break; // SqueezeBox 5 case 0x618618E7: newvalue = 0x768928D7; device = SB; SPLN("6"); break; // SqueezeBox 6 case 0x6186E817: newvalue = 0x7689A857; device = SB; SPLN("7"); break; // SqueezeBox 7 case 0x618628D7: newvalue = 0x76896897; device = SB; SPLN("8"); break; // SqueezeBox 8 case 0x6186A857: newvalue = 0x7689E817; device = SB; SPLN("9"); break; // SqueezeBox 9 case 0x61866897: newvalue = 0x76899867; device = SB; SPLN("0"); break; // SqueezeBox 0 case 0x618658A7: newvalue = 0x768940BF; device = SB; SPLN("Power"); break; // SqueezeBox Power (CD CHECK) case 0x61869867: newvalue = 0x768922DD; device = SB; SPLN("Home"); break; // SqueezeBox Home (CD CLEAR) } } if (transport == MD) { // not verified - IR codes from Sony MDE-JE770 remote switch (button) { case 0x618650AF: newvalue = 0xA9E; device = MD; SPLN("Power"); break; // Sony Power case 0x6186708F: newvalue = 0x69E; device = MD; SPLN("Tray"); break; // Sony Tray case 0x618610EF: newvalue = 0x55E; device = MD; SPLN("Play"); break; // Sony Play case 0x6186906F: newvalue = 0x15E; device = MD; SPLN("Stop"); break; // Sony Stop case 0x618630CF: newvalue = 0x35E; device = MD; SPLN("FFW"); break; // Sony Fast Forward case 0x6186B04F: newvalue = 0xD5E; device = MD; SPLN("FRW"); break; // Sony Fast Rewind case 0x618620DF: newvalue = 0x5E; device = MD; SPLN("Prew"); break; // Sony Prew case 0x618600FF: newvalue = 0x85E; device = MD; SPLN("Next"); break; // Sony Next case 0x618648B7: newvalue = 0x1E; device = MD; SPLN("1"); break; // Sony 1 case 0x6186C837: newvalue = 0x81E; device = MD; SPLN("2"); break; // Sony 2 case 0x61868877: newvalue = 0x41E; device = MD; SPLN("3"); break; // Sony 3 case 0x618608F7: newvalue = 0xC1E; device = MD; SPLN("4"); break; // Sony 4 case 0x6186F00F: newvalue = 0x21E; device = MD; SPLN("5"); break; // Sony 5 case 0x618618E7: newvalue = 0xA1E; device = MD; SPLN("6"); break; // Sony 6 case 0x6186E817: newvalue = 0x61E; device = MD; SPLN("7"); break; // Sony 7 case 0x618628D7: newvalue = 0xE1E; device = MD; SPLN("8"); break; // Sony 8 case 0x6186A857: newvalue = 0x11E; device = MD; SPLN("9"); break; // Sony 9 case 0x61866897: newvalue = 0x91E; device = MD; SPLN("0"); break; // Sony 0 case 0x618658A7: newvalue = 0x95E; device = MD; SPLN("Pause"); break; // Sony Pause (CD CHECK) case 0x61869867: newvalue = 0xF1E; device = MD; SPLN("Clear"); break; // Sony Clear (CD CLEAR) } } if (transport == DV) { // verified with Pioneer DV-656A DVD Audio / CD transport switch (button) { case 0x618650AF: newvalue = 0xF50A3DC2; device = DV; SPLN("Power"); break; // DV-656A Power (CD DISP) case 0x6186708F: newvalue = 0xF50A6D92; device = DV; SPLN("Tray"); break; // DV-656A Tray (CD REP) case 0x618610EF: newvalue = 0xC53A7986; device = DV; SPLN("Play"); break; // DV-656A Play case 0x6186906F: newvalue = 0xC53A19E6; device = DV; SPLN("Stop"); break; // DV-656A Stop case 0x618630CF: newvalue = 0xF50A9768; device = DV; SPLN("FFW"); break; // DV-656A Fast Forward case 0x6186B04F: newvalue = 0xF50A57A8; device = DV; SPLN("FRW"); break; // DV-656A Fast Rewind case 0x618620DF: newvalue = 0xC53AB946; device = DV; SPLN("Prew"); break; // DV-656A Prew case 0x618600FF: newvalue = 0xC53A39C6; device = DV; SPLN("Next"); break; // DV-656A Next case 0x618648B7: newvalue = 0xF50A857A; device = DV; SPLN("1"); break; // DV-656A 1 case 0x6186C837: newvalue = 0xF50A45BA; device = DV; SPLN("2"); break; // DV-656A 2 case 0x61868877: newvalue = 0xF50AC53A; device = DV; SPLN("3"); break; // DV-656A 3 case 0x618608F7: newvalue = 0xF50A25DA; device = DV; SPLN("4"); break; // DV-656A 4 case 0x6186F00F: newvalue = 0xF50AA55A; device = DV; SPLN("5"); break; // DV-656A 5 case 0x618618E7: newvalue = 0xF50A659A; device = DV; SPLN("6"); break; // DV-656A 6 case 0x6186E817: newvalue = 0xF50AE51A; device = DV; SPLN("7"); break; // DV-656A 7 case 0x618628D7: newvalue = 0xF50A15EA; device = DV; SPLN("8"); break; // DV-656A 8 case 0x6186A857: newvalue = 0xF50A956A; device = DV; SPLN("9"); break; // DV-656A 9 case 0x61866897: newvalue = 0xF50A05FA; device = DV; SPLN("0"); break; // DV-656A 0 case 0x618658A7: newvalue = 0xC53AF906; device = DV; SPLN("Pause"); break;// DV-656A Pause (CD CHECK) case 0x61869867: newvalue = 0x0; device = 0; SPLN(" "); break; // CD CLEAR - device=0 ensure nothing is transmitet } } if (transport == TV) { // Samsung TV using generic codes, this 2016 model comes with Bluetooth remote switch (button) { // https://sourceforge.net/p/lirc-remotes/code/ci/master/tree/remotes/samsung/BN59-00856A.lircd.conf case 0x618650AF: newvalue = 0xE0E040BF; device = TV; SPLN("Power"); break; // SqueezeBox Power } } /*-- DAC secton of B.M.C. remote --*/ switch (button) { case 0x8666609F: // DAC DF newvalue = 0x0; // device = 0x0; //device = DAC; SPLN("DAC DF"); break; case 0x8666619E: // DAC OVS newvalue = newvalue = 0xE0E0D02F; // Samsung TV - Volume Ned device = TV; SPLN("DAC OVS"); break; case 0x8666629D: // DAC UPS newvalue = newvalue = 0xE0E0E01F; // Samsung TV - Volume Opp device = TV; SPLN("DAC UPS"); break; case 0x86662AD5: // DAC IN UP if (newvalue != 0xFFFFFFFF ) {onetofour++;} if (onetofour >= 5) {onetofour = 1;} if (onetofour == 1) {newvalue = 0x1FE807F;} // Optical Selector 1 if (onetofour == 2) {newvalue = 0x1FE20DF;} // Optical Selector 2 if (onetofour == 3) {newvalue = 0x1FEE01F;} // Optical Selector 3 if (onetofour == 4) {newvalue = 0x1FE50AF;} // Optical Selector 4 device = DAC; #ifdef DBUG SPLN("DAC Input Down"); SP("onetofour = "); SPLN(onetofour); #endif break; case 0x8666AA55: // DAC IN DOWN if (newvalue != 0xFFFFFFFF) {onetofour--;} if (onetofour <= 0) {onetofour = 4;} if (onetofour == 1) {newvalue = 0x1FE807F;} // Optical Selector 1 if (onetofour == 2) {newvalue = 0x1FE20DF;} // Optical Selector 2 if (onetofour == 3) {newvalue = 0x1FEE01F;} // Optical Selector 3 if (onetofour == 4) {newvalue = 0x1FE50AF;} // Optical Selector 4 device = DAC; #ifdef DBUG SPLN("DAC Input Down"); SP("onetofour = "); SPLN(onetofour); #endif break; case 0x8666728D: // DAC MUTE newvalue = 0x1FE58A7; // Optical Selector On/Off device = DAC; SPLN("DAC MUTE"); break; case 0x866640BF: // DAC VOL UP newvalue = 0x0; // Optical Selector device = DAC; SPLN("DAC VOL UP"); break; case 0x866641BE: // DAC VOL DOWN newvalue = 0x0; // Optical Selector device = DAC; SPLN("DAC VOL DOWN"); break; /*-- B.M.C. CD PROGRAM button used to alter internal tranport value --*/ case 0x6186D02F: transport++; if (transport >= 6) {transport = 1;} // DV-656A left out for now transportStatus(transport); delay(200); // dirty way to supress repeats SPLN("CD Program"); SP("transport = "); SPLN(transport); break; /*-- Control B.M.C. from Pioneer D6 remote - verified --*/ case 0xA55A50AF: newvalue = 0x866602FD; // Volume Up device = AMP; break; case 0xA55AD02F: newvalue = 0x8666827D; // Volume Down device = AMP; break; case 0xA55A48B7: newvalue = 0x8666A659; // Mute device = AMP; break; /*-- Pioneer D6 remote Amp Power button used to alter Input Up selector on B.M.C. CS2 --*/ case 0xA55A38C7: delay(200); newvalue = 0x8666C639; // B.M.C. CS2 Input Up will start ower from Phono 1 after XRL 2 device = AMP; break; } // end switch // finaly we're ready to send new IR code if (device >= 1) { switch (device) { case CD: irsend.sendNEC(newvalue, 32); break; // Pioneer D6 use NEC 32-bit and quicly repeats the same code case AMP: irsend.sendNEC(newvalue, 32); irsend.sendNEC(0xFFFFFFFF, 32); break; // B.M.C. use NEC 32-bit and seem to prefer at a fixed 32-bit repeat command at the end case DV: irsend.sendNEC(0xC53A9966, 32); irsend.sendNEC(newvalue, 32); break; // DV-656A use NEC 32-bit with the 32-bit prefix 0xC53A9966 case DAC: irsend.sendNEC(newvalue, 32); break; // S/P DIF Optical Selector use NEC 32 bit case SB: irsend.sendNEC(newvalue, 32); delay(5); // SB Touch seem to like a couple irsend.sendNEC(newvalue, 32); delay(5); // of repeats to give solid response irsend.sendNEC(newvalue, 32); break; // case MD: irsend.sendSony(newvalue, 12); break; // Sony MD use Sony 12-bit - not verified case TV: irsend.sendNEC(newvalue, 32); // Samsung TV (2016) actually comes with Bluetooth Smart Control delay(3); break; // need several repeats of the same code but seems more reliable with a short delay } #ifdef DBUG SP("Code sent: "); SPHEX(newvalue); } else { SPLN("This code not registered with any device."); #endif } digitalWrite(13, LOW); irrecv.enableIRIn(); } void encoding (int type) { switch (type) { default: case UNKNOWN: SP("UNKNOWN"); break ; case NEC: SP("NEC"); break ; case SONY: SP("SONY"); break ; case RC5: SP("RC5"); break ; case RC6: SP("RC6"); break ; case DISH: SP("DISH"); break ; case SHARP: SP("SHARP"); break ; case JVC: SP("JVC"); break ; case SANYO: SP("SANYO"); break ; case MITSUBISHI: SP("MITSUBISHI"); break ; case SAMSUNG: SP("SAMSUNG"); break ; case LG: SP("LG"); break ; case WHYNTER: SP("WHYNTER"); break ; case AIWA_RC_T501: SP("AIWA_RC_T501"); break ; case PANASONIC: SP("PANASONIC"); break ; case DENON: SP("Denon"); break ; } SP(" "); } void setup() { #ifdef DBUG Serial.begin(115200); while (!Serial); #endif irrecv.enableIRIn(); // Start the receiver } void loop() { newvalue = 0x0; if (irrecv.decode(&results)) { newvalue = results.value; #ifdef DBUG // Check if the buffer overflowed if (results.overflow) { SPLN("IR code too long. Edit IRremoteInt.h and increase RAWBUF"); return; } encoding(results.decode_type); SP(results.bits); SP("-bits"); SP(" "); if(results.address > 0x0){SPHEX(results.address); SP(" ");} SPHEX(newvalue); #endif irrecv.resume(); // Receive the next value } if (newvalue > 0x0) { //SPLN("Call sendCode"); sendCode(newvalue); } } /* Circuit * IR receiver output to pin 11, 5V and ground * IR LED transmiter anode to 100R resistor, other end of resistor to pin 3, IR LED cathode to ground */
When I had the Pioneer CD transport working I wondered how to make use of the DAC section of the B.M.C. controller. My Audio-GD DAC has no remote so that has to be a project for later. But I do have an optical S/P DIF selector box. It has 4 inputs where any of the four inputs can be routed to two independed outputs. Very handy where I can have a seperate output going to my MiniDisc player where I can select digital sourche to record from and still choose something else to monitor — similar to what vintage receivers used to have for tape decks and recorder.
Original IR remote for this device select inputs on numbered 1-4 direct buttons. My new main controller only has Up/Down available so some simple code had to be worked out. It has one caveat and that is it asume we always start at input 1 at power-on. The device itself remember active inputs at soft start. Still, current code is only one pushbutton away from becomming in sync until next power cycle.
It occurred to me I might be able to control my Squeezebox Touch if I make a "device selector" for several audio transports in software — effectively making my B.M.C. controller a hard to program multi controller.
B.M.C. use real tactile switches, — combined with the now custom programed repeats for the different devices give a great feel where device usually respond with a single button click.
One suprising attribute with the IR translate hub combined with B.M.C. remote and Pioneer DV-656A are much faster button response. I dedicate this to slow power-on handling in the original Pioneer remote.
/* B.M.C. Audio CS2 amp IR remote codes Input Up 0x8666C639 followed by 0xFFFFFFFF Input Down 0x866626D9 followed by 0xFFFFFFFF Volume Up 0x866602FD followed by 0xFFFFFFFF Volume Down 0x8666827D followed by 0xFFFFFFFF Mute 0x8666A659 followed by 0xFFFFFFFF When muted the amp will ignore all commands until unmuted. */
NOTE:
I noticed our Samsung TV have problem interpreting the infrared code if the remote are pointing directly towards the TV. Not able to separate the real ir remote from the translated Arduino code it won't respond until the remote are angled away from the TV.
irremote/proto_b.jpg
To view high resolution images, right click on image and select View image or Save image
Select file from list below
Ken Shirriff's blog http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html
IRremote Library GitHub https://github.com/z3t0/Arduino-IRremote
Your comment are welcome