I am developing a program to control the locks and latches on a number of vent doors. It's going well so far and I have completed the latch portion and am about to start on the locks.
I wrote init functions to initialize the I/O pins. The buttonInit() function will work for both locks and latches, but latchInit() as written will only work for latches as it takes a latch object as an input parameter. Since a lockInit() function would be identical it would be nice if I could have one function that could initialize the output pins for either a latch or lock object.
So my question is how do I get a function to accept either a latch or a (future)lock object as an input parameter?
// ================= GLOBAL VARIABLES ================
const uint8_t LATCH1_BUTTON_PIN = 12;
const uint8_t LATCH1_OUTPUT_PIN = 13;
const uint8_t LATCH_DISABLE_SENSOR_PIN = 11;
enum ButtonStates
{
NO_CHANGE, // No change in event status
PRESS, // Press event begins
QUICK_PRESS, // Event has ended as a quick press
LONG_PRESS // Event has ended as a long press
};
// ================= STRUCTS ================
struct Button
{
ButtonStates buttonState;
uint8_t ButtonPin;
uint8_t ButtonBuffer = 0;
bool IsButtonPressed = false;
uint32_t ButtonTimerStart = 0;
uint32_t ButtonTimerInterval = 10;
uint8_t PressIntervals = 1;
uint8_t ReleaseIntervals = 4;
uint32_t PressStartTime = 0;
static const uint32_t PressThresholdTime = 350;
bool LongPressDetected = false;
};
struct Latch
{
uint8_t LatchPin;
bool LatchActive = false;
uint32_t LatchStartTime = 0;
static const uint32_t LATCH_ACTIVATION_INTERVAL = 500;
static const uint32_t LATCH_REACTIVATION_DELAY = 250;
};
// ================= OBJECTS ================
Button Latch1Input;
Latch Latch1Output;
// ================================================================
// SETUP FUNCTIONS
// ================================================================
void setup()
{
pinMode (LATCH_DISABLE_SENSOR_PIN, INPUT_PULLUP);
buttonInit(Latch1Input, LATCH1_BUTTON_PIN);
latchInit (Latch1Output, LATCH1_OUTPUT_PIN);
}
void buttonInit (Button &button, const uint8_t &BUTTON_PIN)
{
button.ButtonPin = BUTTON_PIN;
pinMode (button.ButtonPin, INPUT_PULLUP);
}
void latchInit (Latch &latch, const uint8_t &LATCH_PIN)/* */
{
latch.LatchPin = LATCH_PIN;
pinMode (latch.LatchPin, OUTPUT);
}
// ================================================================
// Loop
// ================================================================
void loop()
{
updateLatch(Latch1Output, Latch1Input);
}
// ================================================================
// updateLatch
// ================================================================
void updateLatch (Latch &latch, Button &button)
{
uint32_t currentTime = millis();
if (latch.LatchActive)
{
if (currentTime - latch.LatchStartTime >= latch.LATCH_ACTIVATION_INTERVAL)
{
digitalWrite(latch.LatchPin, LOW);
if (currentTime - latch.LatchStartTime >= (latch.LATCH_ACTIVATION_INTERVAL + latch.LATCH_REACTIVATION_DELAY))
{
latch.LatchActive = false;
}
}
}
else if (!digitalRead(LATCH_DISABLE_SENSOR_PIN))
{
if (updateButton(button, currentTime) == PRESS)
{
digitalWrite(latch.LatchPin, HIGH);
latch.LatchStartTime = currentTime;
latch.LatchActive = true;
}
}
}
// ================================================================
// updateButton
// ================================================================
ButtonStates updateButton (Button &button, const uint32_t &CURRENT_TIME)
{
// ============== set default return value ==============
button.buttonState = NO_CHANGE;
if (CURRENT_TIME - button.ButtonTimerStart >= button.ButtonTimerInterval)
{
// ============== reset timer ==============
button.ButtonTimerStart += button.ButtonTimerInterval;
// ============== limit intervals to max allowed by the buffer size ==============
// ============== byte sized buffer allows max 7 intervals, int allows 15 ==============
//const uint8_t MAX_INTERVALS = 7;
const uint8_t MAX_INTERVALS = (sizeof(button.ButtonBuffer) <<3) -1;
if (button.PressIntervals > MAX_INTERVALS)
{
button.PressIntervals = MAX_INTERVALS;
}
if (button.ReleaseIntervals > MAX_INTERVALS)
{
button.ReleaseIntervals = MAX_INTERVALS;
}
// ============== shift oldest read out and add new read ==============
button.ButtonBuffer = (button.ButtonBuffer << 1) + (!digitalRead (button.ButtonPin));
if (button.IsButtonPressed == false)
{
uint8_t pressDebounceMask = (1 << (button.PressIntervals + 1)) - 1;
if (button.ButtonBuffer & pressDebounceMask)
{
button.IsButtonPressed = true;
button.buttonState = PRESS;
button.PressStartTime = CURRENT_TIME;
}
}
else // button.IsButtonPressed == true
{
uint8_t releaseDebounceMask = (MAX_INTERVALS - button.ReleaseIntervals); // Number of reads to ignore
if (CURRENT_TIME - button.PressStartTime >= button.PressThresholdTime)
{
if (!button.LongPressDetected)
{
button.LongPressDetected = true;
}
}
if (button.ButtonBuffer << releaseDebounceMask)
{
button.IsButtonPressed = false;
if (button.LongPressDetected)
{
button.buttonState = LONG_PRESS;
button.LongPressDetected = false;
}
else
{
button.buttonState = QUICK_PRESS;
}
}
}
}
return button.buttonState;
}