/*
This software is intended to open and close an electric roller shutter. It is software Chibo intended to offer to MTA as a long term
viability study in bringing the electronics department in house.
It should have a basic open and close structure, driven off a remote button press, then hold the LEDS on for 2 mins when open.
After 5 mintues it should go into a deep sleep, waking off an interupt button press.
6.12.22 - Created first draft. Attempt to get basic structure correct with no error handling, deep sleep.
*/
//Include related files
#include "ioPins_MTA.h" //Sets which IO pins are connected to which device
#include "flashLeds.h" //Tests LEDS on startup
#include <Arduino.h> //Sets coding style
#include <cstdint> //Use of typesets
//System level states
enum class shutterStates {partOpenCLedON, opening, openLedOn, openLedOff, partOpenOLedON, closing, closed, partOpenCLedOFF, partOpenOLedOFF };
//Compnent level states
enum class motorMode {opening, closing, stopped };
enum class ledMode {onL, off };
//This code block sets the data structure that will be used below
struct stateData
{
motorMode MOTORMode;
ledMode LEDMode;
shutterStates bShortNext;
shutterStates bLongNext;
shutterStates timeOutEvent;
u_int32_t timeOut;
};
//set the states and order the states will go in
constexpr stateData StateDataTable[] PROGMEM =
{
{ motorMode::stopped, ledMode::onL, shutterStates::opening, shutterStates::partOpenCLedOFF, shutterStates::partOpenCLedOFF, 8000 }, //Shutter part open from closing, LED ON
{ motorMode::opening, ledMode::onL, shutterStates::partOpenOLedON, shutterStates::partOpenOLedON, shutterStates::openLedOn, 5000 }, //Shutter opening
{ motorMode::stopped, ledMode::onL, shutterStates::closing, shutterStates::openLedOff, shutterStates::openLedOff, 8000 }, //shutter open LED on
{ motorMode::stopped, ledMode::off, shutterStates::closing, shutterStates::openLedOn, shutterStates::openLedOff, 0 }, //Shutter open LED off
{ motorMode::stopped, ledMode::onL, shutterStates::closing, shutterStates::partOpenOLedOFF, shutterStates::partOpenOLedOFF, 8000 }, //Shutter part open from opening, LED ON
{ motorMode::closing, ledMode::onL, shutterStates::partOpenCLedON, shutterStates::partOpenCLedON, shutterStates::closed, 5000 }, //Shutter closing
{ motorMode::stopped, ledMode::off, shutterStates::opening, shutterStates::opening, shutterStates::closed, 0 }, //Shutter closed
{ motorMode::stopped, ledMode::off, shutterStates::opening, shutterStates::partOpenCLedON, shutterStates::partOpenCLedOFF, 0 }, //Shutter part open from closing, LED OFF
{ motorMode::stopped, ledMode::off, shutterStates::closing, shutterStates::partOpenOLedON, shutterStates::partOpenOLedOFF, 0 }, //Shutter part open from opening, LED OFF
};
void setup()
{
setupPins();
Serial.begin(115200);
flashLeds();
Serial.print("Welcome to the controller, design by CHIBO 2022");
digitalWrite(ledPin, HIGH);
}
shutterStates state = shutterStates::partOpenCLedON; //Start program from this state
//introduce global runtime variables
u_int32_t lastStateChange = 0; //time of last state change
u_int32_t nextStateSwitch = 0; //variable for next state change timer
u_int32_t buttonPressAt = 0; //When was button press initiated
u_int32_t buttonReleaseAt = 0; //When was button press finished
u_int32_t buttondur = 0; //Duration of button press
byte timer = 0; //timer for button flag
bool lastButtonstate = false; //last button state
bool nowButtonState = false; //current button state
u_int32_t currentTime = 0; //current time
//Motor function for each state
void setMotorState(motorMode motor)
{
if (motorMode::opening == motor)
{
digitalWrite(motorOut1, HIGH);
digitalWrite(motorOut2, LOW);
}
else if (motorMode::closing == motor)
{
digitalWrite(motorOut1, LOW);
digitalWrite(motorOut2, HIGH);
}
else if (motorMode::stopped == motor)
{
digitalWrite(motorOut1, LOW);
digitalWrite(motorOut2, LOW);
}
}
//LED function for each state
void setLEDState(ledMode LeD)
{
if (ledMode::onL == LeD)
{
digitalWrite(ledPin, HIGH);
}
else if (ledMode::off == LeD)
{
digitalWrite(ledPin,LOW);
}
}
//Find current state
void currentStateDec()
{
if(shutterStates::partOpenCLedON == state){
Serial.println("partOpenCLedON");
}
else if(shutterStates::opening == state){
Serial.println("opening");
}
else if(shutterStates::openLedOn == state){
Serial.println("openLedOn");
}
else if(shutterStates::openLedOff == state){
Serial.println("openLedOff");
}
else if(shutterStates::partOpenOLedON == state){
Serial.println("partOpenOLedON");
}
else if(shutterStates::closing == state){
Serial.println("closing");
}
else if(shutterStates::closed == state){
Serial.println("closed");
}
else if(shutterStates::partOpenCLedOFF == state){
Serial.println("partOpenCLedOFF");
}
else if(shutterStates::partOpenOLedOFF == state){
Serial.println("partOpenOLedOFF");
}
else {
Serial.println("Not in state");
}
}
//Logic to switch between states
void runStructTable(uint32_t CurrentTime, uint32_t ButtonDur){
stateData ramData;
memcpy_P(&ramData, &StateDataTable[(uint16_t)state], sizeof(stateData));
//Switch variables
bool bTimedOut = ((CurrentTime - lastStateChange) >= nextStateSwitch); //Test for timeout
if(ButtonDur>100) //100ms debounce time
{
if(ButtonDur<2000) {
Serial.println("short");
state = ramData.bShortNext;
lastStateChange = CurrentTime;
currentStateDec();
}
else if(ButtonDur>2000){
Serial.println("long");
state = ramData.bLongNext;
lastStateChange = CurrentTime;
currentStateDec();
}
buttondur = 0;
}
else if(bTimedOut)
{
if(nextStateSwitch>1){
Serial.println("Timeout");
state = ramData.timeOutEvent;
nextStateSwitch = ramData.timeOut; //Change timeout timer
lastStateChange = CurrentTime;
currentStateDec();
}
}
setLEDState(ramData.LEDMode);
setMotorState(ramData.MOTORMode);
nextStateSwitch = ramData.timeOut; //Change timeout timer
}
//Main loop
void loop(){
//Get current time
currentTime = millis();
//Read button state
nowButtonState = digitalRead(button);
//If button pressed, start button duration timer
if(timer == 0 && digitalRead(button)==LOW){
buttonPressAt = millis(); //get button pressed at time
timer=1; //start timer flag
Serial.print("Button pressed at: "); //print to serial monitor
Serial.print(buttonPressAt);
}
//If button released, stop timer and calculate duration
if (timer == 1 && digitalRead(button)==HIGH){
buttonReleaseAt = millis(); //Record when button released
timer=0; //Stop timer
Serial.print(" Button released at: "); //print to screen
Serial.print(buttonReleaseAt);
buttondur = buttonReleaseAt-buttonPressAt; //calculate duration
Serial.print(" Button duration: "); //print duration to screen
Serial.println(buttondur);
if (buttondur<0){buttondur = 0;}; //logic check on calculation
}
runStructTable(currentTime, buttondur); //Call change state logic
}