Skip to content

Instantly share code, notes, and snippets.

@samm-git
Last active May 14, 2024 03:23
Show Gist options
  • Save samm-git/a76058a03fe28aa2f5407f6826c93b6a to your computer and use it in GitHub Desktop.
Save samm-git/a76058a03fe28aa2f5407f6826c93b6a to your computer and use it in GitHub Desktop.
// marantz wired remote control demo
// inspired by https://github.com/Arduino-IRremote/Arduino-IRremote
// see https://smallhacks.wordpress.com/2021/07/07/controlling-marantz-amplifier-using-arduino-via-remote-socket/
/* some definitions from the IRremote Arduino Library */
#define RC5_ADDRESS_BITS 5
#define RC5_COMMAND_BITS 6
#define RC5_EXT_BITS 6
#define RC5_COMMAND_FIELD_BIT 1
#define RC5_TOGGLE_BIT 1
#define RC5_BITS (RC5_COMMAND_FIELD_BIT + RC5_TOGGLE_BIT + RC5_ADDRESS_BITS + RC5_COMMAND_BITS) // 13
#define RC5X_BITS (RC5_BITS + RC5_EXT_BITS) // 19
#define RC5_UNIT 889 // (32 cycles of 36 kHz)
#define RC5_DURATION (15L * RC5_UNIT) // 13335
#define RC5_REPEAT_PERIOD (128L *RC5_UNIT) // 113792
#define RC5_REPEAT_SPACE (RC5_REPEAT_PERIOD - RC5_DURATION) // 100 ms
#define IR_TX_PIN 5 // pin to use for tx
//#define TRACE // print binary commands to serial
uint8_t sLastSendToggleValue = 0;
/*
* normal Philips RC-5 as in the https://en.wikipedia.org/wiki/RC-5
* code taken from IRremote with some changes
*/
int sendRC5(uint8_t aAddress, uint8_t aCommand, uint_fast8_t aNumberOfRepeats)
{
digitalWrite(IR_TX_PIN, LOW);
uint16_t tIRData = ((aAddress & 0x1F) << RC5_COMMAND_BITS);
if (aCommand < 0x40)
{
// set field bit to lower field / set inverted upper command bit
tIRData |= 1 << (RC5_TOGGLE_BIT + RC5_ADDRESS_BITS + RC5_COMMAND_BITS);
}
else
{
// let field bit zero
aCommand &= 0x3F;
}
tIRData |= aCommand;
tIRData |= 1 << RC5_BITS;
if (sLastSendToggleValue == 0)
{
sLastSendToggleValue = 1;
// set toggled bit
tIRData |= 1 << (RC5_ADDRESS_BITS + RC5_COMMAND_BITS);
}
else
{
sLastSendToggleValue = 0;
}
uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
while (tNumberOfCommands > 0)
{
for (int i = 13; 0 <= i; i--)
{
#ifdef TRACE
Serial.print((tIRData &(1 << i)) ? '1' : '0');
#endif
(tIRData &(1 << i)) ? send_1() : send_0();
}
tNumberOfCommands--;
if (tNumberOfCommands > 0)
{
// send repeated command in a fixed raster
delay(RC5_REPEAT_SPACE / 1000);
}
#ifdef TRACE
Serial.print("\n");
#endif
}
digitalWrite(IR_TX_PIN, LOW);
return 0;
}
/*
* Marantz 20 bit RC5 extension, see
* http://lirc.10951.n7.nabble.com/Marantz-RC5-22-bits-Extend-Data-Word-possible-with-lircd-conf-semantic-td9784.html
* could be combined with sendRC5, but ATM split to simplify debugging
*/
int sendRC5_X(uint8_t aAddress, uint8_t aCommand, uint8_t aExt, uint_fast8_t aNumberOfRepeats)
{
uint32_t tIRData = (uint32_t)(aAddress & 0x1F) << (RC5_COMMAND_BITS + RC5_EXT_BITS);
digitalWrite(IR_TX_PIN, LOW);
if (aCommand < 0x40)
{
// set field bit to lower field / set inverted upper command bit
tIRData |= (uint32_t) 1 << (RC5_TOGGLE_BIT + RC5_ADDRESS_BITS + RC5_COMMAND_BITS + RC5_EXT_BITS);
}
else
{
// let field bit zero
aCommand &= 0x3F;
}
tIRData |= (uint32_t)(aExt & 0x3F);
tIRData |= (uint32_t) aCommand << RC5_EXT_BITS;
tIRData |= (uint32_t) 1 << RC5X_BITS;
if (sLastSendToggleValue == 0)
{
sLastSendToggleValue = 1;
// set toggled bit
tIRData |= (uint32_t) 1 << (RC5_ADDRESS_BITS + RC5_COMMAND_BITS + RC5_EXT_BITS);
}
else
{
sLastSendToggleValue = 0;
}
uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
while (tNumberOfCommands > 0)
{
for (int i = 19; 0 <= i; i--)
{
#ifdef TRACE
Serial.print((tIRData &((uint32_t) 1 << i)) ? '1' : '0');
#endif
(tIRData &((uint32_t) 1 << i)) ? send_1() : send_0();
if (i == 12)
{
#ifdef TRACE
Serial.print("<p>");
#endif
// space marker for marantz rc5 extension
delayMicroseconds(RC5_UNIT *2 *2);
}
}
#ifdef TRACE
Serial.print("\n");
#endif
tNumberOfCommands--;
if (tNumberOfCommands > 0)
{
// send repeated command in a fixed raster
delay(RC5_REPEAT_SPACE / 1000);
}
}
digitalWrite(IR_TX_PIN, LOW);
return 0;
}
void setup()
{
//start serial connection
Serial.begin(115200);
// configure output pin
pinMode(IR_TX_PIN, OUTPUT);
}
void send_0()
{
digitalWrite(IR_TX_PIN, HIGH);
delayMicroseconds(RC5_UNIT);
digitalWrite(IR_TX_PIN, LOW);
delayMicroseconds(RC5_UNIT);
}
void send_1()
{
digitalWrite(IR_TX_PIN, LOW);
delayMicroseconds(RC5_UNIT);
digitalWrite(IR_TX_PIN, HIGH);
delayMicroseconds(RC5_UNIT);
}
void loop()
{
// demo to switch outputs and turn device on/off
sendRC5(21, 63, 1); // phono
delay(500);
sendRC5(20, 63, 1); // cd
delay(500);
sendRC5(17, 63, 1); // tuner
delay(500);
sendRC5_X(16, 0, 6, 1); // aux1
delay(500);
sendRC5_X(16, 0, 7, 1); // aux2
delay(500);
sendRC5(16, 12, 1); // standby
delay(2000);
}
@samm-git
Copy link
Author

samm-git commented Feb 5, 2023

@anker2000 I was using a logic analyzer with my own rc5 decoder. I never completed it to the stage where it's fine to upstream it.

Also you can just try to write program to check all the codes, i don't think it could harm.

@Johanvanderveen
Copy link

Hi,
I am having issues with sending the codes for commands without an extension.
Thanks, at least this program did turn off my ampl. and was able to mute and unmute. Other commands failed.
I am having issues with sending the codes for commands without an extension. The power-on does not work in for my SR5004 amplifiers.
Also tried codes for Direct Volume, without succes. I hope you have a fix for this maybe.

@dubosc2
Copy link

dubosc2 commented Mar 16, 2024

Hi, I am having issues with sending the codes for commands without an extension. Thanks, at least this program did turn off my ampl. and was able to mute and unmute. Other commands failed. I am having issues with sending the codes for commands without an extension. The power-on does not work in for my SR5004 amplifiers. Also tried codes for Direct Volume, without succes. I hope you have a fix for this maybe.

Hi, for tuning on, did you try using all three different power signals? And did you disable the remote control signal receiving function on your amp?

@Inssomniak
Copy link

Inssomniak commented May 6, 2024

I don't suppose you'd know how to find the RC5 values for the "Optical 1" input on the PM6007 amp? I've been searching like crazy and had zero luck.

This is the captured code for Optical command on remote. It just toggles between the 2 inputs on the PM6006. I havent decoded it. Pulseview didnt work with my Rigol DHO800 Scope. EDIT: I get 16 01 40 by hand. Not tested.

Optical Code

@Inssomniak
Copy link

Hi, I am having issues with sending the codes for commands without an extension. Thanks, at least this program did turn off my ampl. and was able to mute and unmute. Other commands failed. I am having issues with sending the codes for commands without an extension. The power-on does not work in for my SR5004 amplifiers. Also tried codes for Direct Volume, without succes. I hope you have a fix for this maybe.

I think there’s a couple issues with the code I’m working on. The code sends 2 packets but depending on the RC5 it leaves the output a logic high between the 2 packets and confusing the amplifier. There isn’t any need for 2 packets at least on newer Marantz. Thats why I think some commands work and others did not.

@samm-git
Copy link
Author

samm-git commented May 9, 2024

btw, code i am actually using is here: https://github.com/samm-git/marantz-rc-esp32

This one was not maintained and may have some bugs, i was using it as PoC only.

@Inssomniak
Copy link

btw, code i am actually using is here: https://github.com/samm-git/marantz-rc-esp32

This one was not maintained and may have some bugs, i was using it as PoC only.

Ok thanks I checked and the code was from the link above. It still sends the same packets and it does work but my amplifier takes the 2 packets and turns up my amplifier twice as much as the remote button does despite the logic high between the packets. Eliminating the second packet I’m sure solves it for me.

IMG_3380

@samm-git
Copy link
Author

samm-git commented May 9, 2024

feel free to modify code and share if it works for you so other users will benefit. I am sending 2 packets for a very simple reason - this is how real RC works. It always sends >1 packet when you pressing with one of the bit flipped, thats kind of protection from the random things on IR channel. You may want to keep it low, should not be an issue.

@Inssomniak
Copy link

Inssomniak commented May 10, 2024

Just adding for completion here. The code for Optical above 16 01 40 does work. Also Network button code is 25 63 10 confirmed to work. Modified code adjusting the logic high for the RC5x gap to go low and removed 2nd packet. Works perfectly for the PM series of amplifiers at least. Thanks for the code :) It’s for esp8266 but I’ll post my mods soon.

@samm-git
Copy link
Author

Great news. Share your patches; I will see if they could be at least partially imported. I remember doing two packets to make my old Marantz work; maybe the logic is different in the more recent models.

@Inssomniak
Copy link

Added to my git. Not great at this whole GitHub thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment