// Start Code Arduino Sketch Z-5300 SoundTouch Wired Remote Control. // NonaSuomy /* D0 D1 RST GND GND VCC RX TX /DTR +--------------------------------+ | [ ] [ ] [ ] [ ] [ ] [ ] | | FTDI | D1 | [ ]1/TX RAW[ ] | D0 | [ ]0/RX GND[ ] | | [ ]RST SCL/A5[ ] RST[ ] | C6 | [ ]GND SDA/A4[ ] VCC[ ] | D2 | [ ]2/INT0 ___ A3[ ] | C3 D3 |~[ ]3/INT1 / \ A2[ ] | C2 D4 | [ ]4 /PRO \ A1[ ] | C1 D5 |~[ ]5 \ MINI/ A0[ ] | C0 D6 |~[ ]6 \___/ SCK/13[ ] | B5 D7 | [ ]7 A7[ ] MISO/12[ ] | B4 B0 | [ ]8 A6[ ] MOSI/11[ ]~| B3 B1 |~[ ]9 SS/10[ ]~| B2 | [RST-BTN] | +--------------------------------+ */ // 1. GND // 2. Headphones 1 // 3. GND // 4. Headphones 2 // 5. GND // 6. +5V power to remote // 7. GND // 8. GND // 9. GND // 10. not connected (I think so) // 11. STBY command from remote to system // 12. MUTE command from remote to system // 13. Spatial stereo command from remote to system // 14. I2C SCL from remote to system (NJW1150) // 15. I2C SDA from remote to system (NJW1150) // 12 Pin Header to VGA // |010305070911| // |020406081012| // Header>VGA // 01>01 // 02>02 // 03>03 // 04>04 // 05>05 // 06>06 // 07>07 // 08>15 // 09>14 // 10>13 // 11>12 // 12>11 #include #include #include // Pinout. #define ENCODER_A 2 #define ENCODER_B 3 #define POWER 5 #define MATRIX 6 #define MUTE 7 #define SELECT 8 #define STANDBY 9 #define IR_RECEIVE_PIN 11 #define DECODE_NEC #define MATRIX_LED 12 #define BUILTIN_LED 13 // Power LED and IR Signal Notification #define RGB_BLUE 14 #define RGB_GREEN 15 #define RGB_RED 16 // Volume Controls. int standbyPin = STANDBY; int mutePin = MUTE; int matrixPin = MATRIX; int selectPin = SELECT; int powswiPin = POWER; // Colour Pins. int redPin = RGB_RED; int greenPin = RGB_GREEN; int bluePin = RGB_BLUE; int powerledPin = BUILTIN_LED; int matrixledPin = MATRIX_LED; // Tell IRremote which Arduino pin is connected to the IR Receiver (TSOP4838). int recvPin = IR_RECEIVE_PIN; // Arduino pin the IR receiver is attached to. IRrecv irrecv(recvPin); // Enable IR pin. unsigned long lastCode; // Store last code sent, in case of repeat code. // 7 LED's for volume indication. class irCodes { public: enum Constants { //irVolUp = 0xFF7887, // 16742535 Volume Up. //irVolDown = 0xFF50AF, // 16732335 Volume Down. //irMode = 0xFF2AD5, // Volume, Sub, Fader, Center. 4 LED's for mode indication. //irMute = 0xFF6897, // Mute. //irPower = 0xFFB24D, // Power. //irMatrix = 0xFF30CF // On/Off. 1 LED for power indication. irVolUp = 0xCC33BF40, // 16742535 Volume Up. Toshiba FF irVolDown = 0xCB34BF40, // 16732335 Volume Down. Toshiba REW irMode = 0xCA35BF40, // Volume, Sub, Fader, Center. 4 LED's for mode indication. Toshiba PAUSE/STEP irMute = 0xCE31BF40, // Mute. Toshiba STOP irPower = 0xBD42BF40, // Power. Toshiba EJECT irMatrix = 0xCF30BF40 // On/Off. 1 LED for power indication. Toshiba PLAY }; }; // Hold volume control data in multidimensional array. // CurrentValue,MinValue,MaxValue,Red,Green,Blue. int mem[][6] = { // 00 VOL : Volume control for all channel (1dB/step)[00000000]0dB to -79dB[1001111], Default Value: MUTE[1010000]. // Maximum Attenuation: Master Volume: -79dB, Trimmer: -20dB. // Minimum Attenuation: Master Volume: 0dB, Trimmer: 0dB. { 25, 0, 80, 200, 0, 80 }, // VOL // 01 L-BAL : Balance control for Left channel (1dB/step) [00000]0dB to -30dB[11110], MUTE[11111] Default Value: 0dB[00000]). { 0, 0, 31, 0, 255, 255 }, // LBAL // 02 R-BAL : Balance control for Right channel (1dB/step) [00000]0dB to -30dB[11110], MUTE[11111] Default Value: 0dB[00000]). { 0, 0, 31, 0, 0, 255 }, // RBAL // 03 C TRIM :Volume Center Channel Trimmer Control ([00000]0dB to -20dB[10100] Default Value: -10dB[01010]). { 10, 0, 20, 255, 255, 0 }, // CTRIM // 04 SL TRIM :Volume Surround Left Channel Trimmer Control ([00000]0dB to -20dB[10100] Default Value: -10dB[01010]). { 10, 0, 20, 0, 255, 0 }, // LTRIM // 05 SR TRIM :Volume Surround Right Channel Trimmer Control ([00000]0dB to -20dB[10100] Default Value: -10dB[01010]). { 10, 0, 20, 255, 0, 0 }, // RTRIM // 06 SW TRIM :Volume Sub Woofer Channel Trimmer Control ([00000]0dB to -20dB[10100] Default Value: -10dB[01010]). { 10, 0, 20, 255, 0, 255 }, // WTRIM // 07 TONE CONTROL ([11011101]+10dB to -10dB[01010101]). // TREBLE BASS // D7 D6 D5 D4 D3 D2 D1 D0 // 1 0 0 0 1 0 0 0 {10001000} { 136, 0, 255, 255, 255, 255 }, // TONE //{ 0, 0, 15, 255, 255, 255 }, // TONE BASS //{ 0, 16, 240, 255, 200, 255 },// TONE TREBLE // 08 MUTE CONTROL (0=OFF 1=MUTE). { 1, 0, 1, 50, 0, 0 }, // MUTE // 09 TONE BASS CONTROL { 0, 0, 15, 255, 255, 255 }, // TONE BASS // 10 TONE TREBLE CONTROL { 0, 0, 15, 255, 200, 255 },// TONE TREBLE X 16 // 11 POWER CONTROL (1=OFF 0=ON). { 0, 0, 1, 0, 0, 0 }, // POWER // 12 MATRIX CONTROL (0=OFF 1=ON). { 0, 0, 1, 0, 0, 255 } // MATRIX }; // Button debounce variables. int buttonStateSelect = LOW; // Tracks the state of the button, low if not pressed, high if pressed. int buttonStatePower = LOW; // Tracks the state of the button, low if not pressed, high if pressed. long lastDebounceTime = 0; // Last time the output pin was toggled. long debounceDelay = 250; // Debounce time; increase if the output flickers. // Button current value selected. int selectState = 0; // Tracks the state of the select command. int stateSelectLast = 0; // Track last state of the select command. // Encoder Stuff. // Change these pin numbers to the pins connected to your encoder. // Best Performance: both pins have interrupt capability. // Good Performance: only the first pin has interrupt capability. // Low Performance: neither pin has interrupt capability. // Avoid using pins with LEDs attached. Encoder EncKnob(ENCODER_A, ENCODER_B); // Generate Encoder EncKnob. long EncPosition = -999; // Define encoder starting position. long newENC; // Capture new encoder position. // Setup our microcontroller. void setup() { // Start I2C; Wire.begin(); // Start serial for debugging. Serial.begin(9600); //irrecv.enableIRIn(); // Start the receiver. irrecv.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK); // standbyPin & mutePin require to be put to ground in order for the unit to turn on. // Configure Remote other buttons. pinMode(standbyPin, OUTPUT); pinMode(mutePin, OUTPUT); pinMode(matrixPin, OUTPUT); // Configure colour LED. pinMode(redPin, OUTPUT); pinMode(greenPin, OUTPUT); pinMode(bluePin, OUTPUT); pinMode(powerledPin, OUTPUT); pinMode(matrixledPin, OUTPUT); // Hardware remote buttons. pinMode(selectPin, INPUT); pinMode(powswiPin, INPUT); // Make sure power is off before starting control. Serial.println("Power Off"); digitalWrite(standbyPin, HIGH); digitalWrite(mutePin, HIGH); mem[8][0] = 1; // Set Mute On. mem[9][0] = 1; // Set Power Off. mem[10][0] = 1; // Set Matrix On. // Turn power on to unit. Serial.println("Power On"); digitalWrite(standbyPin, LOW); digitalWrite(mutePin, LOW); digitalWrite(matrixPin, HIGH); //digitalWrite(matrixledPin, HIGH); mem[9][0] = 0; // Set Mute Off. mem[9][0] = 0; // Set Power On. mem[10][0] = 0; // Set Matrix Off. if ((digitalRead(standbyPin) == LOW) && (digitalRead(mutePin) == LOW)) { digitalWrite(matrixledPin, HIGH); } // Send I2C command to unmute the system, as it starts up muted. Serial.println("UNMUTE"); i2cmd(0, 80); i2cmd(8, 0); // Write the initial volume state to the active encoder position. EncKnob.write(mem[selectState][0]); setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); } // Send I2C commands to NJW1150. void i2cmd(int cmd, int val) { Wire.beginTransmission(0x44); // Send I2C command to NJW1150's default address. Wire.write(cmd); // Item to control. Wire.write(val); // Value to set to. Wire.endTransmission(); // Send data via I2C. Serial.print("CMD: "); Serial.print(cmd); Serial.print(", Value: "); Serial.println(val); } // Change colour of LED to show the state we are in for sending commands to NJW1150. void setColor(int red, int green, int blue) { #ifdef COMMON_ANODE red = 255 - red; green = 255 - green; blue = 255 - blue; #endif analogWrite(redPin, red); analogWrite(greenPin, green); analogWrite(bluePin, blue); } // Main Programming Loop. void loop() { if (irrecv.decode()) { // Received an IR signal? // Print a short summary of received data //irrecv.printIRResultShort(&Serial); //irrecv.printIRSendUsage(&Serial); //irrecv.decodedIRData.decodedRawData if (IrReceiver.decodedIRData.protocol == UNKNOWN) { Serial.println(F("Received noise or an unknown (or not yet enabled) protocol")); // We have an unknown protocol here, print more info IrReceiver.printIRResultRawFormatted(&Serial, true); } Serial.println(); Serial.print("Debug All IR Values: "); Serial.println(irrecv.decodedIRData.decodedRawData, HEX); irrecv.resume(); // Enable receiving of the next value. if (irrecv.decodedIRData.decodedRawData) { // Receive a code that is repeated: 0xFFFFFFFF lastCode = irrecv.decodedIRData.decodedRawData; // Store last code value. } { switch (lastCode) { case irCodes::irVolUp: // Volume UP button pressed. Serial.print("irVolUp "); Serial.print("Real Value: "); Serial.println(irrecv.decodedIRData.decodedRawData, HEX); Serial.print("Repeated Value: "); Serial.println(lastCode, HEX); selectState = 0; Serial.print("State: "); Serial.println(selectState); // Set LED colour to show which item in the mode select the control is at (Red = Vol, etc). setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); newENC = newENC - 1; Serial.print("newENC: "); Serial.println(newENC); EncKnob.write(newENC); // Reset encoder to prior value if above max of volume processor. if (newENC > mem[selectState][2]) { Serial.print("Reset encoder to highest value allowed "); Serial.println(mem[selectState][2]); EncKnob.write(mem[selectState][2]); } // Reset encoder to prior value if above min of volume processor. else if (newENC < mem[selectState][1]) { Serial.print("Reset encoder to lowest value allowed "); Serial.println(mem[selectState][1]); EncKnob.write(mem[selectState][1]); } mem[selectState][0] = newENC; // Update mem variable with current encoder value selected. i2cmd(selectState, newENC); // Send I2C command with updated encoder value to NJW1150. stateSelectLast = selectState; // Track last select state change. break; case irCodes::irVolDown: // Volume DOWN button pressed. Serial.print("irVolDown "); Serial.print("Real Value: "); Serial.println(irrecv.decodedIRData.decodedRawData, HEX); Serial.print("Repeated Value: "); Serial.println(lastCode, HEX); selectState = 0; Serial.print("State: "); Serial.println(selectState); // Set LED colour to show which item in the mode select the control is at (Red = Vol, etc). setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); newENC = newENC + 1; Serial.print("newENC: "); Serial.println(newENC); EncKnob.write(newENC); // Reset encoder to prior value if above max of volume processor. if (newENC > mem[selectState][2]) { Serial.print("Reset encoder to highest value allowed "); Serial.println(mem[selectState][2]); EncKnob.write(mem[selectState][2]); } // Reset encoder to prior value if above min of volume processor. else if (newENC < mem[selectState][1]) { Serial.print("Reset encoder to lowest value allowed "); Serial.println(mem[selectState][1]); EncKnob.write(mem[selectState][1]); } mem[selectState][0] = newENC; // Update mem variable with current encoder value selected. i2cmd(selectState, newENC); // Send I2C command with updated encoder value to NJW1150. stateSelectLast = selectState; // Track last select state change. break; case irCodes::irMode: // Mode button pressed. Serial.print("irMode "); Serial.print("Real Value: "); Serial.println(irrecv.decodedIRData.decodedRawData, HEX); Serial.print("Repeated Value: "); Serial.println(lastCode, HEX); selectState++; // Reset count if over max mode number. if (selectState > 10) { selectState = 0; } switch (selectState) { case 0: Serial.print("Master Volume: "); break; case 1: Serial.print("Left Balance: "); break; case 2: Serial.print("Right Balance: "); break; case 3: Serial.print("Center Trim: "); break; case 4: Serial.print("Left Trim: "); break; case 5: Serial.print("Right Trim: "); break; case 6: Serial.print("Subwoofer Trim: "); break; case 7: Serial.print("Tone Control: "); break; case 8: Serial.print("Mute Control: "); break; case 9: Serial.print("Base Control: "); break; case 10: Serial.print("Treble Control: "); break; } Serial.print("State: "); Serial.println(selectState); break; case irCodes::irMute: // Mute button pressed. Serial.print("irMute "); Serial.print("Real Value: "); Serial.println(irrecv.decodedIRData.decodedRawData, HEX); Serial.print("Repeated Value: "); Serial.println(lastCode, HEX); selectState = 8; if (mem[selectState][0] == 1) { Serial.println("UNMUTE"); setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); // LOW the mute pin to unmute the system. digitalWrite(mutePin,LOW); mem[selectState][0] = 0; // Update mem variable with current mute value selected. //i2cmd(selectState, newENC); // Send I2C command with updated mute value to NJW1150. selectState = 0; setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); } else { // HIGH the mute pin to mute the system. Serial.println("MUTE"); digitalWrite(mutePin,HIGH); mem[selectState][0] = 1; // Update mem variable with current mute value selected. //i2cmd(selectState, newENC); // Send I2C command with updated mute value to NJW1150. setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); selectState = 0; } break; case irCodes::irPower: // Power button pressed. Serial.print("irPower "); Serial.print("Real Value: "); Serial.println(irrecv.decodedIRData.decodedRawData, HEX); Serial.print("Repeated Value: "); Serial.println(lastCode, HEX); selectState = 11; if (mem[selectState][0] == 1) { Serial.println("Power On"); setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); // LOW the standby pin to turn on the system. digitalWrite(mutePin,LOW); digitalWrite(standbyPin,LOW); mem[selectState][0] = 0; // Update mem variable with current power value selected. selectState = 0; setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); } else { // HIGH the standby pin to turn off the system. Serial.println("Power Off"); digitalWrite(mutePin,HIGH); digitalWrite(standbyPin,HIGH); mem[selectState][0] = 1; // Update mem variable with current power value selected. setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); selectState = 0; } break; case irCodes::irMatrix: // Matrix button pressed. Serial.print("irMatrix "); Serial.print("Real Value: "); Serial.println(irrecv.decodedIRData.decodedRawData, HEX); Serial.print("Repeated Value: "); Serial.println(lastCode, HEX); selectState = 12; if (mem[selectState][0] == 1) { Serial.println("Matrix Off"); // LOW the Matrix pin to disable spatial audio. digitalWrite(matrixPin,LOW); mem[selectState][0] = 0; // Update mem variable with current matrix value selected. selectState = 0; setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); } else { // HIGH the Matrix pin to enable spatial audio. Serial.println("Matrix On"); digitalWrite(matrixPin,HIGH); mem[selectState][0] = 1; // Update mem variable with current matrix value selected. setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); selectState = 0; } break; } } //delay(1000); } // Sample the state of the button. buttonStateSelect = digitalRead(selectPin); buttonStatePower = digitalRead(powswiPin); // Filter out any noise by setting a time buffer. if ((millis() - lastDebounceTime) > debounceDelay) { // If the button has been pressed. if (buttonStateSelect == HIGH) { selectState++; lastDebounceTime = millis(); // Set the current time. // Reset count if over max mode number. if (selectState > 10) { selectState = 0; } // Configure encoder with the value from memory before changing control. EncKnob.write(mem[selectState][0]); } if (buttonStatePower == HIGH) { if ((digitalRead(standbyPin) == HIGH) &&(digitalRead(mutePin) == HIGH)) { // Make sure power is off before starting control. // Turn power on to unit. Serial.println("Power On"); digitalWrite(standbyPin, LOW); digitalWrite(mutePin, LOW); digitalWrite(powerledPin, HIGH); // Send I2C command to unmute the system, as it starts up muted. Serial.println("UNMUTE"); i2cmd(0, 80); i2cmd(8, 0); } else if ((digitalRead(standbyPin) == LOW) && (digitalRead(mutePin) == LOW)) { Serial.println("Power Off"); digitalWrite(standbyPin, HIGH); digitalWrite(mutePin, HIGH); digitalWrite(powerledPin, LOW); } lastDebounceTime = millis(); } } // Check if encoder has changed its position from last time or state select (LED Colour update workaround). newENC = EncKnob.read(); if (newENC != EncPosition || stateSelectLast != selectState) { EncPosition = newENC; Serial.print("ENC = "); Serial.print(newENC); Serial.println(); // NJW1150 6 Channel Electronic Volume Control. // 6-Chnnel Master Volume 0 to –79dB, MUTE. // Balance control for L, R-ch 0 to –30dB, MUTE. // Trim Level Control for C, SL, SR, SW-ch 0 to –20dB. // Independent Tone Control (Bass, Treble) for L, R-ch. // I2C Control Command. Serial.print("State: "); Serial.println(selectState); // Set LED colour to show which item in the mode select the control is at (Red = Vol, etc). setColor(mem[selectState][3], mem[selectState][4], mem[selectState][5]); // Reset encoder to prior value if above max of volume processor. if (newENC > mem[selectState][2]) { Serial.print("Reset encoder to highest value allowed "); Serial.println(mem[selectState][2]); EncKnob.write(mem[selectState][2]); } // Reset encoder to prior value if above min of volume processor. else if (newENC < mem[selectState][1]) { Serial.print("Reset encoder to lowest value allowed "); Serial.println(mem[selectState][1]); EncKnob.write(mem[selectState][1]); } mem[selectState][0] = newENC; // Update mem variable with current encoder value selected. i2cmd(selectState, newENC); // Send I2C command with updated encoder value to NJW1150. stateSelectLast = selectState; // Track last select state change. } // Encoder Change. } // Loop.