
#include "Arduino.h"
#include "SoftwareSerial.h"


// Define commands
#define POWERNOFF   0x0A
#define VOLUP       0x04
#define VOLDOWN     0x05
#define SOURCE      0x08
#define EQUALIZER   0x0D
#define MUTE        0x0E
#define NEXTTRACK   0x12
#define PREVTRACK   0x13
#define FOLDERFORW  0x14
#define FOLDERBACK  0x15

//Define outputs
#define VOLUP_PIN    2 // D2
#define VOLDOWN_PIN     3 // D3
#define NEXTTRACK_PIN      5 // D4
#define PREVTRACK_PIN    4 // D5
#define SOURCE_PIN   6 // D6
#define SCROLLUP_PIN    9 // B1
#define SCROLLDOWN_PIN    10 // B2

// Connect optocoupler input through a 1k resistor to this pin
#define OUTPUTPIN   8 // D8

// On-board LED, useful for debugging
#define LEDPIN     13 // D13

// Pulse width in µs
#define PULSEWIDTH 555

// Address that the radio responds to
#define ADDRESS 0x47//47

unsigned long currentTime, holdbutton;
unsigned long loopTime;
int PrevState = 0;

void setup() 
{
  
    currentTime = millis();    
    loopTime = currentTime; 
    pinMode(OUTPUTPIN, OUTPUT);    // Set the proper pin as output
    digitalWrite(OUTPUTPIN, LOW);  // Output LOW to make sure optocoupler is off
  
    // Set the pins connected to the steering wheel remote as input / output
    pinMode(VOLUP_PIN, INPUT_PULLUP);
    pinMode(VOLDOWN_PIN, INPUT_PULLUP);
    pinMode(NEXTTRACK_PIN, INPUT_PULLUP);
    pinMode(PREVTRACK_PIN, INPUT_PULLUP);
    pinMode(SOURCE_PIN, INPUT_PULLUP);
    pinMode(SCROLLUP_PIN, INPUT_PULLUP);
    pinMode(SCROLLDOWN_PIN, INPUT_PULLUP);
      
    pinMode(LEDPIN, OUTPUT);                  // Set pin connected to on-board LED as output...
    digitalWrite(LEDPIN, LOW);     

    digitalWrite(LEDPIN, HIGH); 
    delay(1000);
    digitalWrite(LEDPIN, LOW); 
    // ...and turn LED off
}

unsigned char GetInput(void) 
{

  currentTime = millis();
  
    if(currentTime >= (loopTime + 10))
    {
      
          //VOLUP
          if(PrevState == VOLUP_PIN && digitalRead(VOLUP_PIN))
          {
            PrevState = 0;
            return VOLUP;   
          }
          else if (PrevState == VOLUP_PIN && currentTime >= (holdbutton + 500))
          {
              holdbutton = currentTime;
              return VOLUP;
          }
          else if(PrevState == 0 && !digitalRead(VOLUP_PIN))
          {
            holdbutton = currentTime;
            PrevState = VOLUP_PIN; 
          }
    
          //VOLDOWN
          if(PrevState == VOLDOWN_PIN && digitalRead(VOLDOWN_PIN))
          {
            PrevState = 0;
            return VOLDOWN;
          }
          else if (PrevState == VOLDOWN_PIN && currentTime >= (holdbutton + 500))
          {
              holdbutton = currentTime;
              return VOLDOWN;
          }
          else if(PrevState == 0 && !digitalRead(VOLDOWN_PIN))
          {
            holdbutton = currentTime;
            PrevState = VOLDOWN_PIN; 
          }    
    
          //NEXTTRACK
          if(PrevState == NEXTTRACK_PIN && digitalRead(NEXTTRACK_PIN))
          {
            PrevState = 0;
            return NEXTTRACK;
            }
          else if(PrevState == 0 && !digitalRead(NEXTTRACK_PIN))
          {
            PrevState = NEXTTRACK_PIN; 
          }  
    
          //PREVTRACK
          if(PrevState == PREVTRACK_PIN && digitalRead(PREVTRACK_PIN))
          {
            PrevState = 0;
            return PREVTRACK;
            }
          else if(PrevState == 0 && !digitalRead(PREVTRACK_PIN))
          {
            PrevState = PREVTRACK_PIN; 
          }  


          //SOURCE - PAUSE(LONG PUSH 1sec)
          if((PrevState == SOURCE_PIN && digitalRead(SOURCE_PIN)) || (PrevState == POWERNOFF && digitalRead(SOURCE_PIN)))
          {
            if(PrevState == SOURCE_PIN)
            {
               PrevState = 0;
              return SOURCE;
            }
            else if (PrevState == POWERNOFF)
            {
              PrevState = 0;
              return 0;
            }
          }
          else if(PrevState == 0 && !digitalRead(SOURCE_PIN))
          {
            holdbutton = currentTime;
            PrevState = SOURCE_PIN; 
          }  
          //PAUSE(LONG PUSH 1sec)
          if(PrevState == SOURCE_PIN && currentTime >= (holdbutton + 1000))
          {
              PrevState = POWERNOFF;
              return MUTE;
          }

            
          //SCROLLUP_PIN
          if(PrevState == SCROLLUP_PIN && digitalRead(SCROLLUP_PIN))
          {
             PrevState = 0;
             if(digitalRead(SCROLLDOWN_PIN))
             {
                return FOLDERFORW;
             }
             else
            {
                return FOLDERBACK;              
            }
             
          }
          else if(PrevState == 0 && !digitalRead(SCROLLUP_PIN))
          {
                PrevState = SCROLLUP_PIN; 
          }  
          loopTime = currentTime;  // Updates loopTime
      }
      return 0;
}

void loop() 
{
 unsigned char Key = GetInput(); 
  if (Key) 
  { 
     SendCommand(Key);
      delay(2);
      SendCommand(Key);
      delay(20);   
  }
}

// Send a value (7 bits, LSB is sent first, value can be an address or command)
void SendValue(unsigned char value) {
  unsigned char i, tmp = 1;
  for (i = 0; i < sizeof(value) * 8 - 1; i++) {
    if (value & tmp)  // Do a bitwise AND on the value and tmp
      SendOne();
    else
      SendZero();
    tmp = tmp << 1; // Bitshift left by 1
  }
}

// Send a command to the radio, including the header, start bit, address and stop bits
void SendCommand(unsigned char value) {
  unsigned char i;
  Preamble();       
  for (i = 0; i < 1; i++) {           // Repeat address, command and stop bits three times so radio will pick them up properly
    SendValue(ADDRESS);               // Send the address
    SendValue((unsigned char)value);  // Send the command
    Postamble();                      // Send signals to follow a command to the radio
  }
}

// Signals to transmit a '0' bit
void SendZero() {
  digitalWrite(OUTPUTPIN, HIGH);      // Output HIGH for 1 pulse width
  digitalWrite(LEDPIN, HIGH);         // Turn on on-board LED
  delayMicroseconds(PULSEWIDTH);
  digitalWrite(OUTPUTPIN, LOW);       // Output LOW for 1 pulse width
  digitalWrite(LEDPIN, LOW);          // Turn off on-board LED
  delayMicroseconds(PULSEWIDTH);
}

// Signals to transmit a '1' bit
void SendOne() {
  digitalWrite(OUTPUTPIN, HIGH);      // Output HIGH for 1 pulse width
  digitalWrite(LEDPIN, HIGH);         // Turn on on-board LED
  delayMicroseconds(PULSEWIDTH);
  digitalWrite(OUTPUTPIN, LOW);       // Output LOW for 3 pulse widths
  digitalWrite(LEDPIN, LOW);          // Turn off on-board LED
  delayMicroseconds(PULSEWIDTH * 3);
}

// Signals to precede a command to the radio
void Preamble() {
  // HEADER: always LOW (1 pulse width), HIGH (16 pulse widths), LOW (8 pulse widths)
  digitalWrite(OUTPUTPIN, LOW);       // Make sure output is LOW for 1 pulse width, so the header starts with a rising edge
  digitalWrite(LEDPIN, LOW);          // Turn off on-board LED
  delayMicroseconds(PULSEWIDTH * 1);
  digitalWrite(OUTPUTPIN, HIGH);      // Start of header, output HIGH for 16 pulse widths
  digitalWrite(LEDPIN, HIGH);         // Turn on on-board LED
  delayMicroseconds(PULSEWIDTH * 16);
  digitalWrite(OUTPUTPIN, LOW);       // Second part of header, output LOW 8 pulse widths
  digitalWrite(LEDPIN, LOW);          // Turn off on-board LED
  delayMicroseconds(PULSEWIDTH * 8);
  
  // START BIT: always 1
  SendOne();
}

// Signals to follow a command to the radio
void Postamble() {
  // STOP BITS: always 1
  SendOne();
  SendOne();
}
