/****** RFD21733 & Teensy 3.0 HCI ************/

/************ Constants **********************/
// Define pin numbers
const int ledPin = 13;   // LED Pin is 13 for the Teensy 3.0

const int in0 = 0; // Define input pin 0
const int in1 = 1; // Define input pin 1
const int in2 = 2; // Define input pin 2
const int button1 = 20; // Define input pin 20
/*********************************************/

/************ Variables **********************/
// varibles to store input states
int read0 = 0;
int read1 = 0;
int read2 = 0;
int read_button = 0;

// store recieved data (in decimal)
int rx_in = 0;
// New Data Flag
int ndf = 0;

// timers for debouncing
elapsedMicros bounce_time;
/*********************************************/

/************ Interrupt handler **************/
void isr()
{
  // Only accept new inputs if the last command 
  // has been completed
  if(ndf == 0)
  {
    // Disable external pin interrupts
    intr_dis();
    
    // Read the input
    getInput();
    
    // Enable interrupts
    intr_en();
  }
}
/*********************************************/

/************ Interrupt Disable **************/
void intr_dis(void)
{
 // Disable interrupts
 detachInterrupt(in0);
 detachInterrupt(in1);
 detachInterrupt(in2);
}
/*********************************************/

/************ Interrupt Enable ***************/
void intr_en(void)
{
 // Enable interrupts
 attachInterrupt(in0, isr, RISING); // Attach interrupt to pin 0
 attachInterrupt(in1, isr, RISING); // Attach interrupt to pin 1
 attachInterrupt(in2, isr, RISING); // Attach interrupt to pin 2
}
/*********************************************/

/************ Read Inputs ********************/
void getInput(void)
{
  // Read values from input pins
  read0 = digitalRead(in0); // get input from in0
  read1 = digitalRead(in1); // get input from in1
  read2 = digitalRead(in2); // get input from in2
  read_button = digitalRead(button1); // get input from button
    
  // Debounce
  // (IE. Accept if mechanical bounce hasn't
  // caused the command to be sent again)
  if(bounce_time > 100)
  {
    // Convert to single integer value
    rx_in = (read0*4)+(read1*2)+(read2*1);
    
    // New data so set flag
    ndf = 1;
    
    // reset timer
    bounce_time = 0;
    
    // Print the output using a serial connection
    print_input();
  }
}
/*********************************************/

/************ Serial Output ******************/
void print_input(void)
{
  // print input value and button state
  Serial.print(rx_in);

//  Serial.print("   ");
//  Serial.print(bounce_time);
  
  Serial.print("   ");
  Serial.print(read_button);

  Serial.println(" ");
}
/*********************************************/

/************ Initialisations **************/
void setup()
{
  Serial.begin(9600); // USB is always 12 Mbit/sec
  
  pinMode(ledPin, OUTPUT); // LED pin is an output  
  
  pinMode(in0, INPUT);  // Configure in0 pin as input
  pinMode(in1, INPUT);  // Configure in1 pin as input
  pinMode(in2, INPUT);  // Configure in2 pin as input
  pinMode(button1, INPUT_PULLUP);  // Configure button pin as input with pullup resistor

  // Enable interrupts on input pins
  intr_en();
  
  // The interrupts have been set to only respond to the rising edge,
  // this is so that when the RFD21733 chip automaticall resets the
  // outputs to 000 after the 20ms hang time, another interrupt isn't
  // triggered.
  
  // Flash LED to signal ready... (one second on, one second off)
  digitalWrite(ledPin, HIGH);
  delay(1000);
  digitalWrite(ledPin, LOW);
  delay(1000);
  
  Serial.println("RFD21733 Interface:");
}
/*********************************************/

/************ Main Program Loop **************/
void loop()
{
  // Check for new data
  // (by polling the new data flag)
  if(ndf == 1)
  {
    // Switch case for tasks
    switch(rx_in)
    {
      case 1:
        play_pause();
        break;
      case 2:
        next();
        break;
      case 3:
        previous();
        break;
      case 4:
        vol_up();
        break;
      case 5:
        vol_down();
        break;
      case 6:
        empty();
        break;
      case 7:
        empty();
        break;
    }
    
    // task complete so reset new data flag
    ndf = 0;
  }
}
/*********************************************/

/*********** VLC Commands for MAC ************/
void play_pause(void)
{
  // Press space bar
  Keyboard.set_key1(KEY_SPACE);
  Keyboard.send_now();
  Keyboard.set_key1(0);
  Keyboard.send_now();
}

void next(void)
{
  // Hold cmd key
  Keyboard.set_modifier(MODIFIERKEY_GUI);
  Keyboard.send_now();
  
  // Press right arrow key
  Keyboard.set_key1(KEY_RIGHT);
  Keyboard.send_now();
  Keyboard.set_key1(0);
  Keyboard.send_now();
  
  // Release cmd key
  Keyboard.set_modifier(0);
  Keyboard.send_now();
}

void previous(void)
{
  // Hold cmd key
  Keyboard.set_modifier(MODIFIERKEY_GUI);
  Keyboard.send_now();
  
  // Press left arrow key
  Keyboard.set_key1(KEY_LEFT);
  Keyboard.send_now();
  Keyboard.set_key1(0);
  Keyboard.send_now();
  
  // Release cmd key
  Keyboard.set_modifier(0);
  Keyboard.send_now();
}

void vol_up()
{
  // Hold cmd key
  Keyboard.set_modifier(MODIFIERKEY_GUI);
  Keyboard.send_now();
  
  // Press up arrow key
  Keyboard.set_key1(KEY_UP);
  Keyboard.send_now();
  Keyboard.set_key1(0);
  Keyboard.send_now();
  
  // Release cmd key
  Keyboard.set_modifier(0);
  Keyboard.send_now();
}

void vol_down()
{
  // Hold cmd key
  Keyboard.set_modifier(MODIFIERKEY_GUI);
  Keyboard.send_now();
  
  // Press down arrow key
  Keyboard.set_key1(KEY_DOWN);
  Keyboard.send_now();
  Keyboard.set_key1(0);
  Keyboard.send_now();
  
  // Release cmd key
  Keyboard.set_modifier(0);
  Keyboard.send_now();
}

void empty(void)
{
  // Place holder function
  // ...does nothing
}
/*********************************************/