12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070 |
- /*
- * coffee.cpp
- *
- * Created on: Sep 25, 2017
- * Author: sebastian
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <stdint.h>
- #include <wiringPi.h>
- #include <pthread.h>
- #include <unistd.h>
- #include <iostream>
- #include <csignal>
- #include <time.h>
- #include <ctime>
- #include "coffee.h"
- #include "hal.h"
- #include "logger.h"
- #include "timer.h"
- #include "database.h"
- coffee_status_t state;
- coffee_menuPage_t page;
- coffee_mode_t mode;
- int sigValue;
- int menuTimeout;
- uint16_t brewTime; //Brew time in ms
- uint16_t lastBrewTime;
- timer brewTimer(&brewTimeHandler);
- timer menuTimer(&menuTimeHandler);
- uint64_t totalHeatingTime; //local copies of the corresponding database entries
- uint16_t brewCounter;
- uint16_t currentCleanCycle;
- bool initalHeating;
- bool descaling; //flag to indicate descaling and cleaning
- uint16_t descBrewcount;
- time_t descRawTimestamp;
- const char* PageName[] = { "SoftOff", "Kill", "Stats", "Stats2", "Descaling", "Temp", "Clean", "Restart",
- "Exit" };
- const char* StateName[] = { "OFF", "HEATING", "INITHEAT", "IDLE", "BREW",
- "BREWMAN", "CLEAN", "ERROR", "WAITOFF" };
- /**
- * 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;
- currentCleanCycle = 0;
- menuTimer.setDivider(4);
- menuTimer.stop();
- menuTimeout = 0;
- initalHeating = true;
- mode = MODE_STATE; //Unless we enter the menu we start in state mode
- page = PAGE_SOFTOFF;
- descaling = false;
- //read the database values
- if (!(totalHeatingTime = sqlGetConf(CFGHeatingTime))) {
- logger_error("coffee.cpp: Couldn't read the heating time from the database\n");
- //pthread_exit(EXIT_SUCCESS);
- exit(EXIT_FAILURE);
- }
- if (!(brewCounter = sqlGetConf(CFGbrewcounter))) {
- logger_error("coffee.cpp: Couldn't read the brew counter from the database\n");
- //pthread_exit(EXIT_SUCCESS);
- exit(EXIT_FAILURE);
- }
- if (!(descRawTimestamp = (time_t) sqlGetConf(CFGDescTimestamp))) {
- logger_error("coffee.cpp: Couldn't read the descaling time from the database\n");
- //pthread_exit(EXIT_SUCCESS);
- exit(EXIT_FAILURE);
- }
- if (!(descBrewcount = sqlGetConf(CFGDescBrewCount))) {
- logger_error("coffee.cpp: Couldn't read the descaling brewcount time from the database\n");
- //pthread_exit(EXIT_SUCCESS);
- exit(EXIT_FAILURE);
- }
- checkDescaling();
- event_subscribe("terminate", &coffeeTerminate);
- 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
- coffeeNap(1,0);
- if (halIsHeating()) { //Heating is on
- changeState(STATE_INITALHEATING);
- } else {
- initalHeating = false;
- changeState(STATE_IDLE);
- }
- } else if (halGetRelaisState(RELAIS_PUMP)) {
- logger_error("Whoops, why is the pump running...\n");
- changeState(STATE_ERROR);
- } else {
- changeState(STATE_OFF);
- }
- logger(V_BREW, "Starting Coffee FSM\n");
- //begin FSM
- while (1) {
- /*
- * Menue FSM
- */
- switch (page) {
- case PAGE_NULL:
- break;
- case PAGE_SOFTOFF: //this page is only available when the machine is on
- if (SigValueEmpty() && mode == MODE_MENU)
- pause();
- switch (getSigValue(MODE_MENU)) {
- case SigInt0Rls:
- if(halIsHeating()){
- changeState(STATE_WAIT_OFF);
- }
- else {
- changeState(STATE_OFF);
- }
- leaveMenu();
- break;
- case SigRotCW:
- changePage(PAGE_KILL);
- break;
- case SigRotCCW:
- changePage(PAGE_EXIT);
- break;
- }
- break;
- case PAGE_KILL: //this page is only available when the machine is on
- if (SigValueEmpty() && mode == MODE_MENU)
- pause();
- switch (getSigValue(MODE_MENU)) {
- case SigInt0Rls:
- if (halIsHeating()) {
- coffeeIncreaseHeatingTime(halgetHeatingTime());
- }
- changeState(STATE_OFF);
- leaveMenu();
- break;
- case SigRotCW:
- if (state == STATE_IDLE || state == STATE_HEATING) {
- changePage(PAGE_CLEAN);
- } else {
- changePage(PAGE_RESTART);
- }
- break;
- case SigRotCCW:
- changePage(PAGE_SOFTOFF);
- break;
- }
- break;
- case PAGE_CLEAN: //this page is only be available when the machine is hot
- if (SigValueEmpty() && mode == MODE_MENU)
- pause();
- switch (getSigValue(MODE_MENU)) {
- case SigInt0Rls:
- changeMode(MODE_STATE);
- if (!halProxSensorCovered()) {
- changeState(STATE_CLEANING);
- leaveMenu();
- } else {
- changeState(STATE_FULLTANK);
- leaveMenu();
- }
- break;
- case SigRotCW:
- changePage(PAGE_RESTART);
- break;
- case SigRotCCW:
- changePage(PAGE_KILL);
- break;
- }
- break;
- case PAGE_RESTART:
- if (SigValueEmpty() && mode == MODE_MENU)
- pause();
- switch (getSigValue(MODE_MENU)) {
- case SigInt0Rls:
- event_trigger("terminate");
- coffeeNap(4, 0);
- exit(EXIT_SUCCESS);
- break;
- case SigRotCW:
- changePage(PAGE_TEMP);
- break;
- case SigRotCCW:
- if(state == STATE_IDLE || state == STATE_HEATING){
- changePage(PAGE_CLEAN);
- } else if (state == STATE_ERROR || state == STATE_INITALHEATING) {
- changePage(PAGE_KILL);
- } else {
- changePage(PAGE_EXIT);
- }
- break;
- }
- break;
- case PAGE_TEMP:
- if (SigValueEmpty() && mode == MODE_MENU)
- pause();
- switch (getSigValue(MODE_MENU)) {
- case SigRotCW:
- changePage(PAGE_STATS);
- break;
- case SigRotCCW:
- changePage(PAGE_RESTART);
- break;
- }
- break;
- case PAGE_STATS:
- if (SigValueEmpty() && mode == MODE_MENU)
- pause();
- switch (getSigValue(MODE_MENU)) {
- case SigRotCW:
- changePage(PAGE_STATS2);
- break;
- case SigRotCCW:
- changePage(PAGE_TEMP);
- break;
- }
- break;
- case PAGE_STATS2:
- if (SigValueEmpty() && mode == MODE_MENU)
- pause();
- switch (getSigValue(MODE_MENU)) {
- case SigRotCW:
- changePage(PAGE_DESCALING);
- break;
- case SigRotCCW:
- changePage(PAGE_STATS);
- break;
- }
- break;
- case PAGE_DESCALING:
- if (SigValueEmpty() && mode == MODE_MENU)
- pause();
- switch (getSigValue(MODE_MENU)) {
- case SigRotCW:
- changePage(PAGE_EXIT);
- break;
- case SigRotCCW:
- changePage(PAGE_STATS2);
- break;
- }
- break;
- case PAGE_EXIT:
- if (SigValueEmpty() && mode == MODE_MENU)
- pause();
- switch (getSigValue(MODE_MENU)) {
- case SigInt0Rls:
- leaveMenu();
- break;
- case SigRotCW:
- if (state == STATE_HEATING || state == STATE_ERROR
- || state == STATE_IDLE
- || state == STATE_INITALHEATING) {
- changePage(PAGE_SOFTOFF);
- } else {
- changePage(PAGE_RESTART);
- }
- break;
- case SigRotCCW:
- changePage(PAGE_DESCALING);
- break;
- }
- break;
- } //end switch (page)
- /*
- * Hardware FSM
- */
- switch (state) {
- case STATE_NULL:
- break;
- /*
- *
- */
- case STATE_OFF:
- if (mode == MODE_STATE) {
- halMachineOff();
- writeBackCache();
- //TODO this might be a bit confusing to change the page here even if the menu isnt actually displayed
- changePage(PAGE_RESTART);
- if (SigValueEmpty())
- pause();
- }
- switch (getSigValue(MODE_STATE)) {
- case SigInt0Rls:
- case SigPowerUp:
- //Check waterlevel in gray water tank
- //turn machine on
- halMachineOn();
- coffeeNap(1,0);
- if (halIsHeating() && !halProxSensorCovered()) { //check if System starts to heat when turned on
- changeState(STATE_INITALHEATING);
- } else if (!halIsHeating() && !halProxSensorCovered()) {
- changeState(STATE_IDLE);
- } else if (halProxSensorCovered()) {
- logger_error("Empty Tank please!\n");
- changeState(STATE_FULLTANK);
- }
- if (page != PAGE_SOFTOFF)
- changePage(PAGE_SOFTOFF); //the machine is on, the menu starts with the turning off page
- break;
- case SigRotCCW:
- case SigRotCW:
- case SigInt1Rls:
- //Enter the menu
- /* This should be not necessary!
- * if (page != PAGE_DEMO)
- changePage(PAGE_DEMO); //machine is off, the menu starts with the demo page*/
- enterMenu();
- break;
- }
- break;
- /*
- *
- */
- case STATE_WAIT_OFF:
- if (SigValueEmpty() && mode == MODE_STATE)
- pause();
- switch (getSigValue(MODE_STATE)) {
- case SigPressOpn:
- coffeeNap(1,0); //wait so no load will be switched
- coffeeIncreaseHeatingTime(halgetHeatingTime());
- changeState(STATE_OFF);
- break;
- case SigInt0Rls:
- case SigInt1Rls:
- case SigPowerUp:
- if (halProxSensorCovered()) {
- changeState(STATE_FULLTANK);
- } else if (initalHeating) {
- changeState(STATE_INITALHEATING);
- } else {
- changeState(STATE_HEATING);
- }
- break;
- }
- break;
- /*
- *
- */
- case STATE_INITALHEATING:
- initalHeating = true;
- if (SigValueEmpty() && mode == MODE_STATE)
- pause();
- switch (getSigValue(MODE_STATE)) {
- // case SigInt0RlsLong:
- // //Turn machine off again
- // coffeeIncreaseHeatingTime(halgetHeatingTime());
- // changeState(STATE_OFF);
- // break;
- //
- // case SigInt0Rls:
- // changeState(STATE_WAIT_OFF);
- // break;
- case SigProxCvrd:
- changeState(STATE_FULLTANK);
- break;
- case SigPressOpn:
- //Inital heating finished
- initalHeating = false;
- coffeeIncreaseHeatingTime(halgetHeatingTime());
- changeState(STATE_IDLE);
- break;
- case SigPowerDown:
- changeState(STATE_WAIT_OFF);
- break;
- case SigRotCCW:
- case SigRotCW:
- case SigInt1Rls:
- enterMenu();
- break;
- }
- break;
- /*
- *
- */
- case STATE_HEATING:
- if (SigValueEmpty() && mode == MODE_STATE)
- pause();
- switch (getSigValue(MODE_STATE)) {
- // case SigInt1RlsLong:
- // //Turn machine _immediately_ off again
- // coffeeIncreaseHeatingTime(halgetHeatingTime());
- // changeState(STATE_OFF);
- // break;
- //
- // case SigInt1Rls:
- // //turn machine off when heating is finished
- // changeState(STATE_WAIT_OFF);
- // break;
- case SigPressOpn:
- coffeeIncreaseHeatingTime(halgetHeatingTime());
- changeState(STATE_IDLE);
- break;
- case SigInt0Rls:
- //start to brew a delicious coffee
- changeState(STATE_BREW);
- break;
- case SigProxCvrd:
- changeState(STATE_FULLTANK);
- break;
- case SigBrewOn:
- //someone brews manually
- changeState(STATE_BREWMANUAL);
- break;
- case SigPowerDown:
- changeState(STATE_WAIT_OFF);
- break;
- case SigRotCCW:
- case SigRotCW:
- case SigInt1Rls:
- //Enter the menu
- enterMenu();
- break;
- }
- break;
- /*
- *
- */
- case STATE_IDLE:
- if (SigValueEmpty() && mode == MODE_STATE)
- pause();
- switch (getSigValue(MODE_STATE)) {
- // case SigInt1RlsLong:
- // //turn machine _immediately_ off
- // changeState(STATE_OFF);
- // break;
- //
- // case SigInt1Rls:
- // changeState(STATE_OFF);
- // break;
- case SigPressCls:
- changeState(STATE_HEATING);
- break;
- case SigInt0Rls:
- changeState(STATE_BREW);
- break;
- case SigProxCvrd:
- changeState(STATE_FULLTANK);
- break;
- case SigBrewOn:
- //someone brews manually
- changeState(STATE_BREWMANUAL);
- break;
- case SigPowerDown:
- changeState(STATE_OFF);
- break;
- case SigRotCCW:
- case SigRotCW:
- case SigInt1Rls:
- //Enter the menu
- enterMenu();
- break;
- }
- break;
- /*
- *
- */
- case STATE_BREW:
- //make sure the tank is not full
- if (halProxSensorCovered()) {
- changeState(STATE_FULLTANK);
- logger_error("coffee.cpp: Full tank detection failed..\n");
- } else {
- coffeeBrew();
- checkDescaling();
- logger(V_BREW, "Finishing brewing\n");
- if (!halProxSensorCovered()) {
- if (halIsHeating()) {
- changeState(STATE_HEATING);
- } else {
- changeState(STATE_IDLE);
- }
- } else {
- changeState(STATE_FULLTANK);
- }
- }
- break;
- /*
- *
- */
- case STATE_BREWMANUAL:
- coffeeManualBrewStart();
- if (SigValueEmpty() && mode == MODE_STATE)
- pause();
- switch (getSigValue(MODE_STATE)) {
- case SigBrewOff:
- coffeeManualBrewStop();
- if (halIsHeating()) {
- changeState(STATE_HEATING);
- } else {
- changeState(STATE_IDLE);
- }
- break;
- }
- break;
- /*
- *
- */
- case STATE_CLEANING: //this can only be executed once the machine is hot!
- //TODO Show the progress of the cleaning process
- if (!halProxSensorCovered()) {
- //execute the cleaning procedure
- coffeeClean();
- if (halIsHeating()) {
- changeState(STATE_HEATING);
- } else {
- changeState(STATE_IDLE);
- }
- } else {
- changeState(STATE_FULLTANK);
- }
- break;
- /*
- * Full tank is detected at the beginning and the end of a brewing process, during
- * idle times, initial heating and heating
- */
- case STATE_FULLTANK:
- if (SigValueEmpty() && mode == MODE_STATE)
- pause();
- switch (getSigValue(MODE_STATE)) {
- case SigInt1Rls:
- case SigInt0Rls:
- if (halIsHeating() && initalHeating) {
- changeState(STATE_INITALHEATING);
- } else if (halIsHeating() && !initalHeating) {
- changeState(STATE_HEATING);
- } else {
- changeState(STATE_IDLE);
- }
- break;
- }
- break;
- /*
- *
- */
- case STATE_ERROR:
- if (SigValueEmpty() && mode == MODE_STATE)
- pause();
- switch (getSigValue(MODE_STATE)) {
- case SigInt0RlsLong:
- if (halIsHeating()) {
- coffeeIncreaseHeatingTime(halgetHeatingTime());
- }
- changeState(STATE_OFF);
- break;
- }
- }
- }
- pthread_exit(EXIT_SUCCESS);
- }
- /**
- * Handler for the Signal send to this thread
- * It saves the type of signal received and tracks the time between a push and release event of up to 4 signals
- * The time is stored in the HalEvent variable when a release event is received
- * @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, "coffee.cpp: CoffeeHandler called with Signal %s\n",
- SigName[sigValue]);
- }
- /**
- * returns the Signal value from the last received Signal for the given mode and clears the variable
- * @return value sent with the last signal
- */
- int getSigValue(coffee_mode_t mode) {
- int tmp = sigValue;
- if (mode == MODE_MENU) {
- switch (sigValue) {
- case SigInt0Psh:
- case SigInt0Rls:
- case SigInt0RlsLong:
- case SigInt1Psh:
- case SigInt1Rls:
- case SigRotCCW:
- case SigRotCW:
- sigValue = 0;
- menuTimeout = 0;
- return tmp;
- break;
- default:
- break;
- }
- } else { //State Mode
- sigValue = 0;
- return tmp;
- }
- //int tmp = sigValue;
- //sigValue = 0;
- //return tmp;
- return 0;
- }
- bool SigValueEmpty(void) {
- if (sigValue == 0)
- return true;
- else
- return false;
- }
- /**
- * Changes the state of the machine to newState
- * prints the change to the logger
- * @param newState
- */
- void changeState(coffee_status_t newState) {
- logger(V_BREW, "Changing state to %s\n", StateName[newState]);
- state = newState;
- event_trigger("statechange", &state, sizeof(state));
- }
- /*
- * Change Page to new menu page
- */
- void changePage(coffee_menuPage_t newPage) {
- logger(V_BREW, "Change Page to %s\n", PageName[newPage]);
- event_trigger("pagechange", &newPage, sizeof(newPage));
- page = newPage;
- }
- /*
- * Changes the mode of the machine to the given mode
- */
- void changeMode(coffee_mode_t newMode) {
- if (newMode == MODE_MENU)
- logger(V_BREW, "Changing to menu mode\n");
- else
- logger(V_BREW, "Changing to state mode\n");
- event_trigger("modechange", &newMode, sizeof(newMode));
- mode = newMode;
- }
- /*
- * leaving the menu
- * sets the start page for the next menu call to softoff
- */
- void leaveMenu(void) {
- logger(V_BREW, "Leaving the menu again\n");
- //leave the menu again
- changeMode(MODE_STATE);
- //change page to initial page
- changePage(PAGE_SOFTOFF);
- //stop the timeout counter
- menuTimeout = 0;
- menuTimer.stop();
- }
- /**
- * entering the menu
- * starts the timeoutcounter and changes the mode to the Menu Mode
- */
- void enterMenu(void) {
- logger(V_BREW, "Entering the menu\n");
- changeMode(MODE_MENU);
- menuTimeout = 0;
- menuTimer.start();
- }
- /**
- * Returns the current cleaning cycle
- */
- uint16_t getCurrentCleanCycle(void) {
- return currentCleanCycle;
- }
- /**
- * Returns the current state of the FSM
- */
- coffee_status_t getState(void) {
- return state;
- }
- uint16_t getBrewTime(void) {
- return brewTime;
- }
- /**
- * Returns the last elapsed brew time in ms
- */
- uint16_t getLastBrewTime(void) {
- return lastBrewTime;
- }
- /**
- * Returns the local up-to-date brewcounter
- */
- uint16_t getBrewCounter(void) {
- return brewCounter;
- }
- /**
- * Returns the total heating time in seconds
- */
- uint64_t getTotalHeatingTime(void) {
- return totalHeatingTime;
- }
- /**
- * Returns the value of the brewcounter when the last descaling happened
- */
- uint16_t getDescBrewCounter (void) {
- return descBrewcount;
- }
- /**
- * Returns the raw time stamp when the last descaling happened
- */
- time_t * getDescTimestamp (void) {
- return &descRawTimestamp;
- }
- /**
- * Counter for the brew time
- * refresh every 200ms
- */
- void brewTimeHandler(void) {
- brewTime += 200;
- }
- /**
- * Counter for the menu timeout
- * When no input is coming from the user the machine leaves the menu automatically after MENUTIMEOUT seconds
- */
- void menuTimeHandler(void){
- menuTimeout += 200;
- if((menuTimeout/1000) >= MENUTIMEOUT) {
- leaveMenu();
- }
- }
- /**
- * handles program termination
- */
- void coffeeTerminate(event_t *event) {
- logger(V_BREW, "Coffee.cpp: Terminating\n");
- //stop brewing
- halRelaisOff(RELAIS_PUMP);
- brewTimer.stop();
- writeBackCache();
- }
- /**
- * coffeeNap does almost the same as sleep() but resumes to sleep after a signal got delivered
- * sec: seconds to sleep
- * nanosec: nanoseconds to sleep
- */
- void coffeeNap (uint64_t sec, uint64_t nanosec){
- struct timespec sleepTime;
- clock_gettime(CLOCK_REALTIME, &sleepTime);
- sleepTime.tv_sec += sec;
- sleepTime.tv_nsec += nanosec;
- //overflow
- if(sleepTime.tv_nsec >= 1000000000) {
- sleepTime.tv_nsec -= 1000000000;
- sleepTime.tv_sec++;
- }
- int errval = 0;
- do{
- errval = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &sleepTime, NULL);
- }
- while(errval == EINTR);
- if(errval) logger_error("coffee.cpp: suspending thread failed with error %d\n", errval);
- }
- /**
- * Function to write back the values of the local copies
- * brewCounter and totalHeatingTime
- *
- */
- void writeBackCache(void) {
- logger(V_BREW, "Writing back cache...\n");
- logger(V_BREW, "Writing back brewCounter with %d\n", brewCounter);
- if (sqlSetConf(CFGbrewcounter, brewCounter)) {
- logger_error("coffee.cpp: Couldn't write brewcounter to database");
- return;
- }
- logger(V_BREW, "Writing back total heating Time with %lld sec\n", totalHeatingTime);
- if (sqlSetConf(CFGHeatingTime, totalHeatingTime)) {
- logger_error("coffee.cpp: Couldn't write heating time to database");
- return;
- }
- logger(V_BREW, "Writing back descaling brew counter %d\n", descBrewcount);
- if (sqlSetConf(CFGDescBrewCount, descBrewcount)) {
- logger_error("coffee.cpp: Couldn't write descaling brewcount to database");
- return;
- }
- struct tm * timeinfo;
- timeinfo = localtime(&descRawTimestamp);
- logger(V_BREW, "Writing back descaling timestamp %d-%d-%d %d:%d\n", timeinfo->tm_mday, timeinfo->tm_mon, timeinfo->tm_year+1900, timeinfo->tm_hour, timeinfo->tm_min);
- if (sqlSetConf(CFGDescTimestamp, (uint64_t)descRawTimestamp)) {
- logger_error("coffee.cpp: Couldn't write descaling timestamp to database");
- return;
- }
- }
- /*
- * Procedure for cleaning the machine
- */
- void coffeeClean(void) {
- logger(V_BREW, "Cleaning...\n");
- for (int i = 0; i < CLEANING_CYCLES; i++) {
- currentCleanCycle++;
- halPumpOn();
- coffeeNap(3,0);
- halPumpOff();
- coffeeNap(15,0);
- }
- updateDescaling();
- descaling = false;
- currentCleanCycle = 0;
- event_trigger("descaling", &descaling, sizeof(bool));
- }
- /*
- *
- */
- void coffeeManualBrewStart (void) {
- logger(V_BREW, "Starting manual brewing...\n");
- coffeeIncreaseBrewCounter();
- brewTime = 0;
- brewTimer.start();
- }
- /*
- *
- */
- void coffeeManualBrewStop (void) {
- lastBrewTime = brewTime;
- brewTime = 0;
- brewTimer.stop();
- }
- /**
- * Brewing process
- */
- void coffeeBrew(void) {
- coffeeIncreaseBrewCounter();
- halIncreaseLogCycleCounter();
- /*
- * Preinfusion
- */
- logger(V_BREW, "Starting preinfusion...\n");
- halResetFlow();
- halPumpOn();
- brewTime = 0;
- brewTimer.start();
- while (halGetFlow() < AMOUNT_PREINFUSION && brewTime < TIME_PREINFUSION) {
- //TODO don't use coffeeNap here since we don't want to resume to sleep after a signal got caught...
- coffeeNap(0, 50000000);
- if (getSigValue(MODE_STATE) == SigInt0Rls){
- stopBrewing();
- return;
- }
- }
- stopBrewing();
- /*
- * Wait for coffee to soak in infused water
- */
- brewTimer.start();
- while (brewTime < TIME_SOAK) {
- coffeeNap(1, 100000000);
- if (getSigValue(MODE_STATE) == SigInt0Rls) {
- stopBrewing();
- return;
- }
- }
- stopBrewing();
- /*
- * Brewing the actual espresso
- */
- logger(V_BREW, "Starting infusion...\n");
- halPumpOn();
- brewTimer.start();
- while (brewTime < TIME_INFUSION && halGetFlow() < AMOUNT_DBLESPRESSO) {
- coffeeNap(1, 100000000);
- if (getSigValue(MODE_STATE) == SigInt0Rls){
- stopBrewing();
- break;
- }
- }
- stopBrewing();
- halIncreaseLogCycleCounter();
- return;
- }
- /*
- * Wrapper function for the end of a brewing process
- * this function stops the pump, brewtimer and resets the flow and brew time to zero
- */
- void stopBrewing() {
- halPumpOff();
- brewTimer.stop();
- lastBrewTime = brewTime;
- brewTime = 0;
- halResetFlow();
- }
- /**
- *
- */
- void coffeeIncreaseBrewCounter(void) {
- brewCounter++;
- }
- /**
- *
- */
- void coffeeIncreaseHeatingTime(uint64_t heatingTime) {
- totalHeatingTime += heatingTime;
- }
- /**
- * Checks if the descaling is necessary
- * uses descBrewcount and descTimestamp
- */
- void checkDescaling(){
- int16_t dirtyEspresso = checkDirtyEspresso ();
- int16_t dirtyTime = checkDirtyTime ();
- if(dirtyEspresso <= 0) {
- logger(V_BREW, "Descaling necessary due to quantity: %d\n", dirtyEspresso);
- descaling = true;
- event_trigger("descaling", &descaling, sizeof(bool));
- }
- if(dirtyTime <= 0) {
- logger(V_BREW, "Descaling necessary due to time in days: %d\n", dirtyTime);
- descaling = true;
- event_trigger("descaling", &descaling, sizeof(bool));
- }
- }
- /**
- * this function returns the remaining espressi to be brewed before the descaling event is fired
- * returns a positive integer when there are cups remaining
- * and a negative when the number of cups are exceeded
- * Number of cups after a descaling is defined with DIRTY_ESPRESSO
- */
- int16_t checkDirtyEspresso (void) {
- return descBrewcount + DIRTY_ESPRESSO - brewCounter;
- }
- /**
- * Returns the remaining days before the next descaling event is fired
- * returns a positive integer if there is time left and a negative one if the descaling time was exceeded
- */
- int16_t checkDirtyTime (void) {
- time_t rawtime;
- time(&rawtime);
- double diffseconds = difftime(rawtime, descRawTimestamp);
- diffseconds /= 24*60*60; //calculate the days
- return DIRTY_TIME - diffseconds;
- }
- /**
- * updates the corresponding variables after a descaling process
- */
- void updateDescaling(){
- descBrewcount = brewCounter;
- time_t newDesTimestamp;
- time(&newDesTimestamp);
- if(newDesTimestamp == -1){
- logger(V_BREW, "Whoops, couldn't retrieve new descaling timestamp\n");
- }
- else {
- descRawTimestamp = newDesTimestamp;
- }
- }
|