/*
 * Send a LANC command to a video camera.
 * 2013, ACC*Software, Planed by 管理人;宏哉, Programed by 松ケン,
  *   http://Next-Zero.com
 *cf. http://controlyourcamera.blogspot.com/2011/02/arduino-controlled-video-recording-over.html
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/power.h>

#define PA 1
#define PB 2
#define PC 3
#define PD 4

#define cmdPin 7 
#define lancPin 11
#define RedButton 2
#define BlueButton 3
#define YellowButton 4

int bitDuration = 104; //Duration of one LANC bit in microseconds. 

void send(unsigned char cmd1, unsigned char cmd2) ;

EMPTY_INTERRUPT( PCINT0_vect );

//pinをボタンとして初期化する。
// 入力として設定し、プルアップ。
// SLEEPから起きれるように、割り込みを有効にする。
void SetupButtonWithWakeup( byte pin )
{
    pinMode(pin, INPUT); //command with Blue button
    digitalWrite(pin, HIGH); //turn on an internal pull up resistor
    
    byte bit = digitalPinToBitMask( pin );
    byte port = digitalPinToPort(pin);
    if( port == PD ){
        PCICR |= 1;
        PCMSK0 |= bit;
    }
    if( port == PB ){
        PCICR |= 2;
        PCMSK1 |= bit;
    }
}


void Sleep(){
    sleep_enable(); 
    sleep_mode();
    //sleeping...

    //wakeup
    sleep_disable();
}

void setup() 
{
    power_adc_disable();
    power_spi_disable();
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    
    //LANC CONTROL PINs
    pinMode(lancPin, INPUT); //listens to the LANC line
    pinMode(cmdPin, OUTPUT); //writes to the LANC line
    digitalWrite(cmdPin, LOW); //set LANC line to +5V

    //BUTTON pins
    SetupButtonWithWakeup( RedButton );    //command with Red button
    SetupButtonWithWakeup( YellowButton ); //command with Blue button
    SetupButtonWithWakeup( BlueButton );   //command with Yellow button

  delay(5000); //Wait for camera to power up completly
  bitDuration = bitDuration - 8; //Writing to the digital port takes about 8 microseconds so only 96 microseconds are left till the end of each bit
}

void loop() 
{
      if (!digitalRead(RedButton)) {
        send(B00101000, B10110001); //send a command to camera with Red Button
      }
      else  if (!digitalRead(BlueButton)) {
        send(B00101000, B10110011); //send a command to camera with Blue Button
      }
      else   if (!digitalRead(YellowButton)) {
        send(B00101000, B10110111); //send a command to camera with Yellow Button
      }
      else{
          Sleep();
      }
}


void send(unsigned char cmd1, unsigned char cmd2) 
{
    for (int     cmdRepeatCount = 0; cmdRepeatCount < 5; cmdRepeatCount++) {  //repeat 5 times to make sure the camera accepts the command

        while (pulseIn(lancPin, HIGH) < 5000) {
            //"pulseIn, HIGH" catches any 0V TO +5V TRANSITION and waits until the LANC line goes back to 0V
            //"pulseIn" also returns the pulse duration so we can check if the previous +5V duration was long enough (>5ms) to be the pause before a new 8 byte data packet
            //Loop till pulse duration is >5ms
        }

        //LOW after long pause means the START bit of Byte 0 is here
        delayMicroseconds(bitDuration);  //wait START bit duration

        for( int i=0; i<8; i++){
            digitalWrite(cmdPin, (cmd1 & (1<<i) ) ? HIGH : LOW);  //Write bit 0.
            delayMicroseconds(bitDuration);
        }
        
        //Byte 0 is written now put LANC line back to +5V
        digitalWrite(cmdPin, LOW);
        delayMicroseconds(10); //make sure to be in the stop bit before byte 1

        while (digitalRead(lancPin)) {
            //Loop as long as the LANC line is +5V during the stop bit
        }

        //0V after the previous stop bit means the START bit of Byte 1 is here
        delayMicroseconds(bitDuration);  //wait START bit duration

        for( int i=0; i<8; i++){
            digitalWrite(cmdPin, (cmd2 & (1<<i) ) ? HIGH : LOW);  //Write bit 0.
            delayMicroseconds(bitDuration);
        }
        //Byte 1 is written now put LANC line back to +5V
        digitalWrite(cmdPin, LOW);

        /*Control bytes 0 and 1 are written, now don’t care what happens in Bytes 2 to 7
        and just wait for the next start bit after a long pause to send the first two command bytes again.*/


    }//While cmdRepeatCount < 5
}