//
// AutoLoc Linear Actuator Control Software
//
// AutoLoc linear actuators use a DC motor and simple polarity reversing to extend
// and retract.  They also feature a hall effect sensor that sends pulses as it moves.
// 
// http://www.carid.com/images/autoloc/vertical-doors/pdf/la24-installation-instructions.pdf
// 
// This code taken from:
// http://forum.arduino.cc/index.php?topic=236470.0
// which originally took the code from here:
// http://learn.robotgeek.com/demo-code/123-arduino-linear-actuator-tutorial-preset-position-button-control.html
//
// 

unsigned long lastStepTime = 0; // Time stamp of last pulse
int trigDelay = 500; 
int resetdelay = 2000;
const int relay1 = 8;     // extend relay output pin connection
const int relay2 = A5;     // retract relay output pin connection
const int HALL0 = 2; // interupt pin connection - See attachInterrupt() docs for your board
unsigned long prevTimer;  //some global variables available anywhere in the program
unsigned long startMillis;
const unsigned long pause = 3000;
volatile int counter = 0;
int counterState = 0;        // current state of the button
int lastButtonState = 0;     // previous state of the button

long lastDebounce0 = 0;
long debounceDelay = 10;     // Ignore bounces under 10ms

volatile int CurrentPosition = 0; 
int goalPosition = 0;
int lastgoalPosition = 0;
boolean Extending = false;
boolean Retracting = false;

// void actuatorExtend(){
//       digitalWrite(relay1, HIGH);  // Always turn one off and then the other on
//       digitalWrite(relay2, LOW);   // so that there are never two relays on (BIG!)
// }

// void actuatorRetract(){
//       digitalWrite(relay2, HIGH);  // Always turn one off and then the other on
//       digitalWrite(relay1, LOW);   // so that there are never two relays on (BIG!)
// }

// void actuatorStop() {
//     digitalWrite(relay2, HIGH);
//     digitalWrite(relay1, HIGH);
// }
#define NUM_FWD_GEARS               7
#define BUTTON_READ_INTERVAL        50ul    //mS    time between up/down button reads

#define NO_PRESS                    0x00    //mask  bit mask for no buttons pressed
#define BUTTON_UP_PRESSED           0x01    //mask  bit mask for up button pressed
#define BUTTON_DOWN_PRESSED         0x02    //mask  bit mask for down button pressed

#define TCC_DELAY                   1000ul  //mS    after TCC is enabled, time delay before activation

const byte buttonUP = A0;                    //pin   Push Button for UP shift
const byte buttonDOWN = A2;                  //pin   Push Button for Down shift
const byte switchTOWMODE = 7;               //pin   Switch for tow/haul mode
const byte solA = 9;                        //pin   Solenoid A output
const byte solB = 10;                        //pin   Solenoid B output
const byte TCC  = 6;                        //pin   TCC output
int incomingByte; 
byte
    gearSelection,
    lastGearSelection,
    lastUp,
    lastDn,
    lastTM;
    // Park,
    // Reverse,
    // Neutral,
    // First,
    // Second,
    // Third,
    // Fourth;
bool
    bTCCStatus;
unsigned long
    timeTCCSolenoid;

typedef struct structGearSolenoidProfiles
{
    byte    goalPosition;
    byte    solenoid_A;
    byte    solenoid_B;
    bool    bTCCGearEnable;
    
}sGearSolenoidProfiles;

enum  {Park, Reverse,Neutral,First,Second,Third,Fourth};

//
// How does Arduino know reverse, park or drive?
//
const sGearSolenoidProfiles GearSolenoidProfiles[NUM_FWD_GEARS] = 
{
    {
        //Park,
        goalPosition = 0,
        .solenoid_A = HIGH,
        .solenoid_B = LOW,
        .bTCCGearEnable = false
    },
    {
        //Reverse,
        goalPosition = 200,
        .solenoid_A = LOW,
        .solenoid_B = LOW,
        .bTCCGearEnable = false
    },
    {
        //Neutral,
        goalPosition = 375,
        .solenoid_A = HIGH,
        .solenoid_B = LOW,
        .bTCCGearEnable = false
    },
    {
        //First,
        goalPosition = 525,
        .solenoid_A = LOW,
        .solenoid_B = LOW,
        .bTCCGearEnable = false
    },
    {
        //Second,
        goalPosition = 525,
        .solenoid_A = LOW,
        .solenoid_B = HIGH,
        .bTCCGearEnable = false
    },
    { 
        //Third,
        goalPosition = 525,
        .solenoid_A = LOW,
        .solenoid_B = HIGH,
        .bTCCGearEnable = true
    },
    {
        //Fourth,
        goalPosition = 525,
        .solenoid_A = HIGH,
        .solenoid_B = HIGH,
        .bTCCGearEnable = true
    }
    
};//GearSolenoidProfiles[]


void actuatorExtend(){
      digitalWrite(relay1, LOW);  // Always turn one off and then the other on
      digitalWrite(relay2, HIGH);   // so that there are never two relays on (BIG!)
}

void actuatorRetract(){
      digitalWrite(relay2, LOW);  // Always turn one off and then the other on
      digitalWrite(relay1, HIGH);   // so that there are never two relays on (BIG!)
}

void actuatorStop() {
    digitalWrite(relay2, HIGH);
    digitalWrite(relay1, HIGH);
}


void setup() 
{
    pinMode( buttonUP, INPUT_PULLUP );
    lastUp = digitalRead( buttonUP );       //set initial button state
    pinMode( buttonDOWN, INPUT_PULLUP );
    lastDn = digitalRead( buttonDOWN );     //set initial button state
    pinMode( switchTOWMODE, INPUT_PULLUP );
        
    pinMode( solA, OUTPUT );                //Solenoid A set as output
    pinMode( solB, OUTPUT );                //Solenoid B set as output
    pinMode( TCC, OUTPUT );                 //TCC set as output

    digitalWrite( solA, LOW );             //set intital state as off
    digitalWrite( solB, LOW );
    digitalWrite( TCC, LOW );

    //internal flag for TCC status
    bTCCStatus = false;
    gearSelection = 0;          //start in "1st" gear for this test
    lastGearSelection = 0xff;   //ensure we change into correct gear first pass by making last != current
    
  Serial.begin(9600);
  
  pinMode(HALL0, INPUT);        // reedSwitch is an input

  attachInterrupt(1, trigger0, RISING);  // See attachInterrupt() doc for YOUR BOARD
  
  // Set both output pins
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  
  // Initialize both relays to off (make sure whatever relay setup you use defaults
  // to OFF since there may be some delay between power-up and this code executing!
  digitalWrite(relay2, HIGH);
  digitalWrite(relay1, HIGH);
}


void actuator(void) 
{
  
if (Extending == true && CurrentPosition > goalPosition ) {    
      actuatorStop();
      Extending = false; 
}
  
if (Retracting == true && CurrentPosition < goalPosition) {
       actuatorStop();
       Retracting = false; 
}
//  if (Serial.available() > 0) {   
//     // read the oldest byte in the serial buffer:
//     incomingByte = Serial.read();

 if ((GearSolenoidProfiles[gearSelection].goalPosition)> CurrentPosition)  {
  
    //if (goalPosition = ""); {
      //if (goalPosition > CurrentPosition) {
        Retracting = false;
        Extending = true;
        actuatorExtend ();
        Serial.println(CurrentPosition); 
        Serial.print(counter);
      }     
      
      else if  ((GearSolenoidProfiles[gearSelection].goalPosition)< CurrentPosition)  {                                                               //(goalPosition < CurrentPosition) {
        Retracting = true;
        Extending = false;
        actuatorRetract();
        Serial.print(CurrentPosition); 
        Serial.print(counter);
      }
  if (incomingByte == 'S') {
       actuatorStop();
       Serial.println("Stop"); 
     }
  
}



                  
    // if (incomingByte == 'B') { 
    //   goalPosition = 200; 
    //   if (CurrentPosition < goalPosition ) {
    //     Retracting = false;
    //     Extending = true;
    //     actuatorExtend ();
    //     Serial.println("BExtending");   
    //   }  
    //   else if (goalPosition < CurrentPosition) {
    //     Retracting = true;
    //     Extending = false;
    //     actuatorRetract();
    //     Serial.println("BRetracting");            
    //    } 
    //  }
  
    // if (incomingByte == 'C') {
    //   goalPosition = 400;
    //   if (goalPosition > CurrentPosition) {
    //     Retracting = false;
    //     Extending = true;
    //     actuatorExtend ();
    //     Serial.println("AExtending"); 
    //   }     
      
    //   else if (goalPosition < CurrentPosition) {
    //     Retracting = true;
    //     Extending = false;
    //     actuatorRetract();
    //     Serial.println("ARetracting");  
    //   }
    // }
                  
    // if (incomingByte == 'D') { 
    //   goalPosition = 525; 
    //   if (CurrentPosition < goalPosition ) {
    //     Retracting = false;
    //     Extending = true;
    //     actuatorExtend ();
    //     Serial.println("BExtending");   
    //   }  
    //   else if (goalPosition < CurrentPosition) {
    //     Retracting = true;
    //     Extending = false;
    //     actuatorRetract();
    //     Serial.println("BRetracting");            
    //    } 
    //  }
    
 
     
     
  


void loop(void) {
    
    
    actuator();
    trigger0();
    Gear_Selection_Control();
    Gear_Solenoid_Control();
    TCC_Control();
    
}//loop



// Once we start a relay, we should start getting pulses from the sensor as the
// actuator moves. When we get a RISING edge and interrupt will be generated and
// we will jump to the following function.
void trigger0() {

if ( (millis() - lastDebounce0) > debounceDelay && Extending == true) {
      counter++;
      Serial.print(counter);
      Serial.println(" : ");
      CurrentPosition = counter;
      lastDebounce0 = millis();
    }
if ( (millis() - lastDebounce0) > debounceDelay && Retracting == true) {
      counter--;
      Serial.println(counter);   
      Serial.print(" : ");
      CurrentPosition = counter;
      lastDebounce0 = millis();
    }
}  
//       if ( Extending == true) {
//       counter++;
//       CurrentPosition = counter;
//     }
            
//       if ( Retracting == true ) {
//       counter--;
//       CurrentPosition = counter;
//     }       
// }
void Gear_Selection_Control( void )
{
    byte
        btnState;
        
    btnState = ReadButtons();
    switch( btnState )
    {
        case    NO_PRESS:
            //nothing pressed or not read (interval not elapsed); no action
        break;

        case    BUTTON_UP_PRESSED:
            if( gearSelection < (NUM_FWD_GEARS-1) )
                gearSelection++;
                
        break;

        case    BUTTON_DOWN_PRESSED:
            if( gearSelection > 0 )
                gearSelection--;    
                
        break;

        default:
            //only remaining possibility is both pressed; ignore with no action
        break;
        
    }//switch
    
}//void
    
void Gear_Solenoid_Control( void )
{
    if( gearSelection != lastGearSelection )
    {
        lastGearSelection = gearSelection;
        digitalWrite( solA, GearSolenoidProfiles[gearSelection].solenoid_A );
        digitalWrite( solB, GearSolenoidProfiles[gearSelection].solenoid_B );

        //if 
        // - the gear just selected enables the TCC, and
        // - the last gear did not enable it, and
        // - the TCC is not now enaged
        //      start the TCC delay timer
        if( bTCCStatus == false )
        {
            if( GearSolenoidProfiles[gearSelection].bTCCGearEnable == true && 
                    GearSolenoidProfiles[lastGearSelection].bTCCGearEnable == false )
            {
                timeTCCSolenoid = millis();
            
            }//if
            
        }//if
        
    }//if
    
}//Gear_Control

void TCC_Control( void )
{
    unsigned long
        tNow;
    bool
        bTCCEnabled;

    tNow = millis();
    
    //TCC enabled if:
    //  - 4th gear is engaged, OR
    //  - 3rd gear is engaged and tow-mode not selected, AND
    //  - TCC delay timer has expired
    bTCCEnabled =   ( (gearSelection == 3) || 
                    ( (gearSelection == 2 && digitalRead( switchTOWMODE ) == HIGH) ) ) &&
                    ( tNow - timeTCCSolenoid >= TCC_DELAY );  
    
    //if conditions passed and TCC is now off, turn on its solenoid
    if( bTCCEnabled )
    {
        if( bTCCStatus == false )
        {
            //turn on TCC
            digitalWrite( TCC, HIGH );
            bTCCStatus = true;
            
        }//if
        
    }//if
    else 
    {
        if( bTCCStatus == true )
        {
            //turn off TCC
            digitalWrite( TCC, LOW );
            bTCCStatus = false;
            
        }//if
        
    }//else
    
}//TCC_Control

//returns a mask:
//0b00000000 - no buttons pressed
//0b00000001 - up pressed
//0b00000010 - down pressed
//0b00000011 - both pressed
//
byte ReadButtons( void )
{
    static unsigned long
        timeButton = 0;
    unsigned long
        tNow;
    byte
        retval,
        nowButton;

    retval = NO_PRESS;
    
    tNow = millis();
    if( (tNow - timeButton) >= BUTTON_READ_INTERVAL )
    {
        //set up for next read interval
        timeButton = tNow;

        //read the button and set the flags
        nowButton = digitalRead( buttonUP );
        if( nowButton != lastUp )
        {
            lastUp = nowButton;
            if( nowButton == LOW )
                retval |= BUTTON_UP_PRESSED;
                
        }//if
        
        nowButton = digitalRead( buttonDOWN );
        if( nowButton != lastDn )
        {
            lastDn = nowButton;
            if( nowButton == LOW )
                retval |= BUTTON_DOWN_PRESSED;
                
        }//if
        
    }//if
    
    return retval;
    
}//ReadButtons
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module