/**************************************
** INCLUDE AND MACROS **
**************************************/
#include <List.hpp>
#include <LiquidCrystal_I2C.h>
#define NB_VALVES 8
#define DEBUG 1
LiquidCrystal_I2C lcd(0x27, 20 , 4);
int size = 0;
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]);
const int buttonUpPin = 5; // the number of the pushbutton pin
const int buttonDownPin = 4; // 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 ledPin = 13;
int upFlag = 0;
int downFlag = 0;
bool escFlag = 0;
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;
int params[NB_VALVES];
};
struct kTimer {
int now;
int start;
int duration;
bool isRunning;
bool isFinished;
};
// Define the program here
struct kStep causticProgram[] = {
{"Charger la soude", 0, false, {0, 1, 2}},
{"Lancer moteur", 1, false, {0,2,3}},
{"Cycle 20'soude", 2, false, {5000, 0}}
};
struct kStep kegProgram[] = {
{"Purger fut", 0, false, {0, 1, 2}},
{"Purger fut 5'", 2, false, {5000, 0}},
{"Lancer moteur", 1, false, {0,2,3}},
{"Cycle 5' soude", 2, false, {5000, 0}},
{"Arreter moteur", 1, false, {0,2,3}},
{"Pause 2' soude", 2, false, {5000, 0}}
};
int sizeKegProgram = sizeof(kegProgram) / sizeof(kegProgram[0]);
int sizeCausticProgram = sizeof(causticProgram) / sizeof(causticProgram[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(13, OUTPUT);
pinMode(buttonUpPin, INPUT_PULLUP);
pinMode(buttonDownPin, 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 (nowEsc - startEsc >= 500) {
if (!escFlag){
//flag is false, so its the beginning of counter
startEsc = millis();
escFlag = true;
}
else{
nowEsc = millis();
if (nowEsc - startEsc >= 500) {
if (emergencyFlag == 1){
Serial.print("Dans ESC : deja en emergency + on ajoute resetAllFlag");
resetAllFlag = 1;
escFlag = false;
}
if (programIndex > 0) {
Serial.print("URGENCE");
updateMenuFlag = 1;
emergencyFlag = 1;
escFlag = false;
return;
}
}
}
}
}
void myEnter(){
if (programIndex == 0){
// On est dans le menu
programIndex = cursorLine + 1;
Serial.print("\nEnter :");
Serial.print(programIndex);
Serial.print("\nCursorLine :");
Serial.print(cursorLine);
}
if (emergencyFlag == 1){
Serial.print("reprise normale");
emergencyFlag = 0; //enterFlag = 1;
updateMenuFlag = 0;
escFlag = false;
}
}
void resetAll(){
for (int a = 0; a < sizeKegProgram; a++) {
Serial.print("\nReinit ");
Serial.print(kegProgram[a].name);
kegProgram[a].isComplete = false;
}
for (int a = 0; a < sizeCausticProgram; a++) {
Serial.print("\nReinit ");
Serial.print(causticProgram[a].name);
causticProgram[a].isComplete = false;
}
eraseScreen();
updateMenuFlag = 1;
}
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(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");
}
}
if (DEBUG)
Serial.print("\n");
return true;
}
bool doRun(int params[]){
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 = 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 = 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
return doAllActions(a, program);
case 1: // Run
return doAllRuns(a, program);
case 2: // Timer
return doAllTimers(a, program);
default:
break;
}
}
}
}
void updateUpDown(){
nowButton = millis();
if (nowButton - startButton >= 500) {
if (digitalRead(buttonUpPin) == 0 && (cursorLine > 0)) {
startButton = nowButton;
//Serial.print("Up");
cursorLine--;
updateMenuFlag = 1;
}
if (digitalRead(buttonDownPin) == 0 && (cursorLine < 3)) {
startButton = nowButton;
//Serial.print("Down");
cursorLine++;
updateMenuFlag = 1;
}
}
}
void displayMenu(){
updateUpDown();
if (updateMenuFlag) {
Serial.print("\nDisplay menu !");
for (int i = 0; i < menuSize; i++) {
lcd.setCursor(0, i);
lcd.print(" ");
lcd.print(menu[i]);
}
// display cursor
lcd.setCursor(0, cursorLine);
lcd.print("*");
updateMenuFlag = 0;
}
}
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 = sizeKegProgram;
doProgram("KEG PROGRAM", kegProgram, sizeKegProgram);
break;
case 2:
size = sizeCausticProgram;
doProgram("CAUSTIC PROGRAM", causticProgram, sizeCausticProgram);
break;
case 3:
Serial.print("Nothing Yet");
break;
default:
break;
}
}
}