4L80e controller

An attempt at adding a tow-mode input.

#define NUM_FWD_GEARS               4       //#     number of forward speeds

#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 = 2;                    //pin   Push Button for UP shift
const byte buttonDOWN = 4;                  //pin   Push Button for Down shift
const byte switchTOWMODE = 7;               //pin   Switch for tow/haul mode
const byte solA = 3;                        //pin   Solenoid A output
const byte solB = 5;                        //pin   Solenoid B output
const byte TCC  = 6;                        //pin   TCC output

byte
    gearSelection,
    lastGearSelection,
    lastUp,
    lastDn,
    lastTM;
bool
    bTCCStatus;
unsigned long
    timeTCCSolenoid;

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

//
// How does Arduino know reverse, park or drive?
//
const sGearSolenoidProfiles GearSolenoidProfiles[NUM_FWD_GEARS] =
{
    {
        //1st
        .solenoid_A = HIGH,
        .solenoid_B = LOW,
        .bTCCGearEnable = false
    },
    {
        //2nd
        .solenoid_A = LOW,
        .solenoid_B = LOW,
        .bTCCGearEnable = false
    },
    {
        //3rd
        .solenoid_A = LOW,
        .solenoid_B = HIGH,
        .bTCCGearEnable = true
    },
    {
        //4th
        .solenoid_A = HIGH,
        .solenoid_B = HIGH,
        .bTCCGearEnable = true
    }
    
};//GearSolenoidProfiles[]

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
    
}//setup

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

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