/* * coffee.cpp * * Created on: Sep 25, 2017 * Author: sebastian */ #include #include #include #include #include #include #include #include #include #include #include #include "coffee.h" #include "hal.h" #include "logger.h" #include "timer.h" int state; int sigValue; int brewTime; //Brew time in ms timer brewTimer(&brewTimeHandler); /** * Thread for the finite state machine * It represents the current state of the machine and handles signals coming from * the pressure control, buttons, the brew switch and the proximity sensor * @param threadid the ID of the thread */ void *coffeeThread(void *threadid) { logger(V_BASIC, "Initializing coffee thread...\n"); //installing new Signal handler for coffeethread struct sigaction action; sigemptyset(&action.sa_mask); action.sa_flags = SA_SIGINFO; action.sa_sigaction = coffeeHandler; sigaction(SIGUSR2, &action, NULL); brewTimer.setDivider(4); brewTimer.stop(); brewTime = 0; state = STATE_OFF; logger(V_BREW, "Determining inital state\n"); //determine inital state if (halGetRelaisState(RELAIS_POWER) && halGetRelaisState(RELAIS_HEAT) && !halGetRelaisState(RELAIS_PUMP)) { //wait for heat relais to switch sleep(1); if (halIsHeating()) { //Heating is on changeState(STATE_INITALHEATING); } else { changeState(STATE_IDLE); } } else if (halGetRelaisState(RELAIS_PUMP)) { logger_error("Whoops, why is the pump running...\n"); changeState(STATE_ERROR); } logger(V_BREW, "Start Coffee FSM\n"); //begin FSM while(1){ switch(state){ case STATE_OFF: pause(); if (getSigValue() == SigInt0Rls) { if (halProxSensorCovered()) { //Check Waterlevel //turn machine on logger(V_BREW, "Turn machine on\n"); halRelaisOn(RELAIS_HEAT); halRelaisOff(RELAIS_PUMP); halRelaisOn(RELAIS_POWER); sleep(1); if (halIsHeating()) { //check if System starts to heat when turned on changeState(STATE_INITALHEATING); } else { changeState(STATE_IDLE); } } else { changeState(STATE_ERROR); } break; } break; case STATE_INITALHEATING: pause(); switch (getSigValue()) { case SigInt1Rls: //Turn machine off again logger(V_BREW, "Turn machine off\n"); halRelaisOff(RELAIS_HEAT); halRelaisOff(RELAIS_PUMP); halRelaisOff(RELAIS_POWER); changeState(STATE_OFF); break; case SigPressOpn: //Inital heating finished changeState(STATE_IDLE); break; } break; case STATE_HEATING: pause(); switch(getSigValue()){ case SigInt1Rls: //Turn machine off again logger(V_BREW, "Turn machine off\n"); halRelaisOff(RELAIS_HEAT); halRelaisOff(RELAIS_PUMP); halRelaisOff(RELAIS_POWER); changeState(STATE_OFF); break; case SigPressOpn: logger(V_BREW, "Change state: IDLE\n"); changeState(STATE_IDLE); break; case SigInt0Psh: //start to brew a delicious coffee changeState(STATE_BREW); break; case SigBrewOn: //someone brews manually changeState(STATE_BREWMANUAL); break; } break; case STATE_IDLE: pause(); switch(getSigValue()){ case SigInt1Rls: //Turn machine off again logger(V_BREW, "Turn machine off\n"); halRelaisOff(RELAIS_HEAT); halRelaisOff(RELAIS_PUMP); halRelaisOff(RELAIS_POWER); changeState(STATE_OFF); break; case SigPressCls: changeState(STATE_HEATING); break; case SigInt0Psh: //start to brew a delicious coffee changeState(STATE_BREW); break; case SigBrewOn: //someone brews manually changeState(STATE_BREWMANUAL); break; } break; case STATE_BREW: //Preinfusion logger(V_BREW, "Starting preinfusion...\n"); halRelaisOn(RELAIS_PUMP); brewTime = 0; brewTimer.start(); while(brewTime < TIME_PREINFUSION){ usleep(100000); } brewTimer.stop(); brewTime = 0; halRelaisOff(RELAIS_PUMP); sleep(TIME_SOAK/1000); logger(V_BREW, "Starting infusion...\n"); halResetFlow(); halRelaisOn(RELAIS_PUMP); brewTimer.start(); while(brewTime < TIME_INFUSION && halGetFlow() < TIME_DBLESPRESSO){ usleep(100000); } halRelaisOff(RELAIS_PUMP); brewTimer.stop(); brewTime = 0; logger(V_BREW, "Finish brewing\n"); changeState(STATE_IDLE); break; case STATE_BREWMANUAL: pause(); break; case STATE_CLEANING: pause(); break; case STATE_ERROR: pause(); break; } } pthread_exit(EXIT_SUCCESS); } /** * Handler for the Signal send to this thread * It safes a value sent with the signal in sigValue * @param signum * @param siginfo * @param context */ void coffeeHandler(int signum, siginfo_t *siginfo, void *context) { sigval_t sigVal = (siginfo->si_value); sigValue = sigVal.sival_int; logger(V_BREW, "CoffeeHandler called with %d\n", sigValue); } /** * returns the Signal value from the last received Signal and clears the variable * @return value sent with the last signal */ int getSigValue(void){ int tmp = sigValue; sigValue = 0; return tmp; } /** * Changes the state of the machine to newState * prints the change to the logger * @param newState */ void changeState(int newState){ logger(V_BREW, "Change state to %d\n", newState); state = newState; } /** * Counter for the brew time * refresh every 200ms */ void brewTimeHandler (void){ brewTime += 200; }