/**************************************
** INCLUDE AND MACROS **
**************************************/
#include <List.hpp>
#include <LiquidCrystal_I2C.h>
#define NB_VALVES 1
#define DEBUG 1
LiquidCrystal_I2C lcd(0x27, 20 , 4);
int size = 0;
int sizeProgram = 7;
int nowButton;
int nowTimer;
int nowDisplay;
int nowEsc;
int startButton = 0;
int startTimer = 0;
int startDisplay = 0;
int startEsc;
int programIndex = 0;
bool menuDisplayed = false;
/**************************************
** INCLUDE AND MACROS **
**************************************/
// char *menu[4] = {"KEG WASHING", "CAUSTIC PROGRAM", "NOTHING YET", "NOTHING YET"};
// char menuSize = sizeof(menu) / sizeof(menu[0]);
char menuSize = 4;
const int button30Pin = 4; // the number of the pushbutton pin
const int button20Pin = 5; // the number of the pushbutton pin
const int button10Pin = 6; // the number of the pushbutton pin
const int buttonEscPin = 3; // the number of the pushbutton pin
const int buttonEnterPin = 2; // the number of the pushbutton pin
const byte ledMotor = 11;
const byte ledCO2 = 12;
// int upFlag = 0;
// int downFlag = 0;
bool escFlag = false;
int enterFlag = 0;
int updateMenuFlag = 1;
int displayMenuFlag = 0;
int cursorLine = 0;
int isTimerRunning = 0;
int emergencyFlag = 0;
int resetAllFlag = 0;
// Struct definition
struct kStep {
char name[20]; // name of action
char type; // type of action 0 -> ACTION, 1 -> RUN, 2 -> TIMER
bool isComplete;
long int params[4];
};
struct kTimer {
long int now;
long int start;
long int duration;
bool isRunning;
bool isFinished;
};
// Define the program here
// struct kStep causticProgram1[] = {
// {"Charger la soude", 0, false, {0, 1, 2}},
// {"Lancer moteur", 1, false, {0,2,3}},
// {"Cycle 20'soude", 2, false, {5000, 0}}
// };
struct kStep Program30[] = {
{"RUN: QuickCarb", 1, false, {1}},
{"TIMER: QuickCarb 20sec", 2, false, {20000, 0}},
{"ACTION: Ouvrir CO2", 0, false, {1}},
{"TIMER: CO2 7min", 2, false, {420000, 0}},
{"ACTION: Fermer CO2", 0, false, {0}},
{"TIMER: QuickCarb 20sec", 2, false, {20000, 0}},
{"RUN: Eteindre QuickCarb", 1, false, {0}},
};
struct kStep Program20[] = {
{"RUN: QuickCarb", 1, false, {1}},
{"TIMER: QuickCarb 20sec", 2, false, {20000, 0}},
{"ACTION: Ouvrir CO2", 0, false, {1}},
{"TIMER: CO2 7min", 2, false, {280000, 0}},
{"ACTION: Fermer CO2", 0, false, {0}},
{"TIMER: QuickCarb 20sec", 2, false, {20000, 0}},
{"RUN: Eteindre QuickCarb", 1, false, {0}},
};
struct kStep Program10[] = {
{"RUN: QuickCarb", 1, false, {1}},
{"TIMER: INIT 1sec", 2, false, {1000, 0}},
{"ACTION: Ouvrir CO2", 0, false, {1}},
{"TIMER: CO2 1sec", 2, false, {1000, 0}},
{"ACTION: Fermer CO2", 0, false, {0}},
{"TIMER: QuickCarb 1sec", 2, false, {1000, 0}},
{"RUN: Eteindre QuickCarb", 1, false, {0}},
};
void setup() {
// Init the Serial console for debug
Serial.begin(9600);
// Init the screen for real interaction
lcd.init();
lcd.begin(20, 4);
// Init pin configuration
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
pinMode(button30Pin, INPUT_PULLUP);
pinMode(button20Pin, INPUT_PULLUP);
pinMode(button10Pin, INPUT_PULLUP);
pinMode(buttonEscPin, INPUT_PULLUP);
pinMode(buttonEnterPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(buttonEscPin), myEsc, FALLING);
attachInterrupt(digitalPinToInterrupt(buttonEnterPin), myEnter, FALLING);
};
bool eraseScreen(){
for (int i = 0; i < menuSize; i++) {
lcd.setCursor(0, i);
lcd.print(" ");
}
}
void myEsc(){
nowEsc = millis();
if (DEBUG){
Serial.print("ESC : button pressed\n");
}
if (nowEsc - startEsc >= 500) {
if (!escFlag){
//flag is false, so its the beginning of counter
if (DEBUG){
Serial.print("ESC : begin mode\n");
}
startEsc = millis();
escFlag = 1;
emergencyFlag = 1;
}
else{
nowEsc = millis();
if (nowEsc - startEsc >= 500) {
if (emergencyFlag == 1){
if (DEBUG){
Serial.print("Dans ESC : deja en emergency + on ajoute resetAllFlag");
}
resetAllFlag = 1;
escFlag = 0;
}
if (programIndex > 0) {
if (DEBUG){
Serial.print("URGENCE");
}
updateMenuFlag = 1;
emergencyFlag = 1;
escFlag = 0;
return;
}
}
}
}
}
void myEnter(){
if (emergencyFlag == 1){
Serial.print("reprise normale");
emergencyFlag = 0; //enterFlag = 1;
updateMenuFlag = 0;
escFlag = 0;
}
}
void resetAll(){
if (DEBUG){
Serial.print("\nReset All Programs \n");
}
for (int a = 0; a < sizeProgram; a++) {
Program30[a].isComplete = false;
Program20[a].isComplete = false;
Program10[a].isComplete = false;
}
eraseScreen();
resetAllFlag = 0;
emergencyFlag = 0;
programIndex = 0;
isTimerRunning = 0;
digitalWrite(ledCO2, LOW);
digitalWrite(ledMotor, LOW);
}
bool displayTime(struct kStep program) {
int time;
int avancement;
nowDisplay = millis();
if (nowDisplay - startDisplay >= 1000) {
startDisplay = nowDisplay;
lcd.setCursor(10, 3);
time = (nowTimer - startTimer + 50) / 1000;
lcd.print(time);
lcd.setCursor(16, 3);
avancement = time * 100 * 1000. / program.params[0];
lcd.print(avancement);
lcd.print("%");
if (DEBUG){
Serial.print(time);
Serial.print("\nAvancement :");
Serial.print(program.params[0]);
Serial.print("\n");
Serial.print(time * 1000);
Serial.print("\n");
Serial.print(program.params[0]);
Serial.print("\n");
Serial.print(program.params[0]);
Serial.print("\n");
}
return true;
}
}
bool isFinished(int interval) {
nowTimer = millis();
if (nowTimer - startTimer >= interval) // save the last time you blinked the LED
return true;
return false;
}
void initTimer(){
isTimerRunning = 1;
startTimer = millis();
}
bool doAction(long int params[]){
if (DEBUG)
Serial.print("Lets do : \n");
for (int a = 0; a < NB_VALVES; a++) {
if (DEBUG) {
Serial.print("\tvalve");
Serial.print(a);
Serial.print(": ");
Serial.print(params[a] ? "open\n" : "close\n");
digitalWrite(ledCO2, params[a] ? HIGH : LOW);
}
}
if (DEBUG)
Serial.print("\n");
return true;
}
bool doRun(long int params[]){
digitalWrite(ledMotor, params[0] ? HIGH : LOW);
return true;
}
bool finishIt(struct kStep *program){
int size;
if (DEBUG)
Serial.print("\nProgram finished !\n\n");
programIndex = 0; // + should re init all flags
size = sizeProgram;//sizeof(causticProgram) / sizeof(causticProgram[0]);
//Serial.print("\nReinit ");
for (int a = 0; a < size; a++) {
Serial.print("\nReinit ");
Serial.print(program[a].name);
program[a].isComplete = false;
}
size = sizeProgram;//sizeof(kegProgram) / sizeof(kegProgram[0]);
for (int a = 0; a < size; a++) {
Serial.print("\nReinit ");
Serial.print(program[a].name);
program[a].isComplete = false;
}
eraseScreen();
updateMenuFlag = 1;
}
void printDebug(int a, char *step, struct kStep *program, bool shouldDisplay){
Serial.print("\nStep: ");
Serial.print(a);
Serial.print(step);
Serial.print(program[a].name);
Serial.print("\n");
if (shouldDisplay) {
program[a].params[1] = 1;
}
}
bool doAllTimers(int a, struct kStep *program){
if (DEBUG)
if (!program[a].params[1])
printDebug(a, " => Timer: ", program, true);
if (!isTimerRunning) {
eraseScreen();
lcd.setCursor(0, 0);
lcd.print(program[a].name);
initTimer();
}
if (!isFinished(program[a].params[0])) {
displayTime(program[a]);
return true;
}
else {
program[a].isComplete = true;
isTimerRunning = 0;
if (a == (size - 1)) {// programm fini !
finishIt(program);
}
return true;
}
}
bool doAllRuns(int a, struct kStep *program){
if (DEBUG)
printDebug(a, " => Run: ", program, false);
if (!doRun(program[a].params))
return false; // error during doRun
program[a].isComplete = true;
if (a == size - 1) // programm fini !
finishIt(program);
return true;
}
bool doAllActions(int a, struct kStep *program){
if (DEBUG)
printDebug(a, " => Action: ", program, false);
if (!doAction(program[a].params))
return false; // error during action
program[a].isComplete = true;
if (a == size - 1) // programm fini !
finishIt(program);
return true;// we go out the entire function in order to let the loop in place
}
bool doProgram(char name[20], struct kStep *program, int size) {
for (int a = 0; a < size; a++) {
if (program[a].isComplete == false) {
// Do action :
switch (program[a].type) {
case 0: // Action (Open/Close Valve)
return doAllActions(a, program);
case 1: // Run (Start/Stop Motor)
return doAllRuns(a, program);
case 2: // Timer
return doAllTimers(a, program);
default:
break;
}
}
}
}
void updateUpDown(){
nowButton = millis();
if (nowButton - startButton >= 500) {
if (digitalRead(button30Pin) == 0) {
startButton = nowButton;
programIndex = 1;
if (DEBUG){
Serial.print("30!");
}
}
if (digitalRead(button20Pin) == 0) {
startButton = nowButton;
programIndex = 2;
if (DEBUG){
Serial.print("20L");
}
}
if (digitalRead(button10Pin) == 0) {
startButton = nowButton;
programIndex = 3;
if (DEBUG){
Serial.print("10L");
}
}
}
}
void displayMenu(){
updateUpDown();
lcd.setCursor(0, 0);
lcd.print("READY FOR 30L OR 20L");
}
void displayEmergency(){
if (updateMenuFlag) {
Serial.print("\nEmergency inside");
eraseScreen();
lcd.setCursor(0, 0);
lcd.print("STOP ?");
lcd.setCursor(0, 2);
lcd.print("rouge = oui");
lcd.setCursor(0, 3);
lcd.print("vert = non");
updateMenuFlag = 0;
}
}
void loop() {
// put your main code here, to run repeatedly:
if (emergencyFlag == 1){
if (resetAllFlag == 1){
//Serial.print("EMERGENCY + RESETALL => On reinit");
resetAll();
resetAllFlag = 0;
emergencyFlag = 0;
programIndex = 0;
}
else {
//Serial.print("EMERGENCY => On display");
displayEmergency();
}
}
else {
switch (programIndex) {
case 0:
displayMenu();
break;
case 1:
size = sizeProgram;
doProgram("30L", Program30, sizeProgram);
break;
case 2:
size = sizeProgram;
doProgram("20L", Program20, sizeProgram);
break;
case 3:
size = sizeProgram;
doProgram("10L", Program10, sizeProgram);
break;
default:
break;
}
}
}