coffee.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /*
  2. * coffee.cpp
  3. *
  4. * Created on: Sep 25, 2017
  5. * Author: sebastian
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <errno.h>
  11. #include <stdint.h>
  12. #include <wiringPi.h>
  13. #include <pthread.h>
  14. #include <unistd.h>
  15. #include <iostream>
  16. #include <csignal>
  17. #include <time.h>
  18. #include <ctime>
  19. #include "coffee.h"
  20. #include "hal.h"
  21. #include "logger.h"
  22. #include "timer.h"
  23. #include "database.h"
  24. coffee_status_t state;
  25. coffee_menuPage_t page;
  26. coffee_mode_t mode;
  27. int sigValue;
  28. int brewTime; //Brew time in ms
  29. timer brewTimer(&brewTimeHandler);
  30. uint64_t totalHeatingTime; //local copies of the corresponding database entries
  31. uint16_t brewCounter;
  32. bool initalHeating;
  33. bool descaling; //flag to indicate descaling and cleaning
  34. uint16_t descBrewcount;
  35. time_t descRawTimestamp;
  36. const char* PageName[] = { "SoftOff", "Kill", "Stats", "Temp", "Clean", "Demo",
  37. "Exit" };
  38. const char* StateName[] = { "OFF", "HEATING", "INITHEAT", "IDLE", "BREW",
  39. "BREWMAN", "CLEAN", "ERROR", "WAITOFF" };
  40. /**
  41. * Thread for the finite state machine
  42. * It represents the current state of the machine and handles signals coming from
  43. * the pressure control, buttons, the brew switch and the proximity sensor
  44. * @param threadid the ID of the thread
  45. */
  46. void *coffeeThread(void *threadid) {
  47. logger(V_BASIC, "Initializing coffee thread...\n");
  48. //installing new Signal handler for coffeethread
  49. struct sigaction action;
  50. sigemptyset(&action.sa_mask);
  51. action.sa_flags = SA_SIGINFO;
  52. action.sa_sigaction = coffeeHandler;
  53. sigaction(SIGUSR2, &action, NULL);
  54. brewTimer.setDivider(4);
  55. brewTimer.stop();
  56. brewTime = 0;
  57. initalHeating = true;
  58. mode = MODE_STATE; //Unless we enter the menu we start in state mode
  59. page = PAGE_SOFTOFF;
  60. descaling = false;
  61. //read the database values
  62. if (!(totalHeatingTime = sqlGetConf(CFGHeatingTime))) {
  63. logger_error("coffee.cpp: Couldn't read the heating time from the database");
  64. //pthread_exit(EXIT_SUCCESS);
  65. exit(EXIT_FAILURE);
  66. }
  67. if (!(brewCounter = sqlGetConf(CFGbrewcounter))) {
  68. logger_error("coffee.cpp: Couldn't read the brew counter from the database");
  69. //pthread_exit(EXIT_SUCCESS);
  70. exit(EXIT_FAILURE);
  71. }
  72. if (!(descRawTimestamp = (time_t) sqlGetConf(CFGDescTimestamp))) {
  73. logger_error("coffee.cpp: Couldn't read the descaling time from the database");
  74. //pthread_exit(EXIT_SUCCESS);
  75. exit(EXIT_FAILURE);
  76. }
  77. if (!(descBrewcount = sqlGetConf(CFGDescBrewCount))) {
  78. logger_error("coffee.cpp: Couldn't read the descaling brewcount time from the database");
  79. //pthread_exit(EXIT_SUCCESS);
  80. exit(EXIT_FAILURE);
  81. }
  82. checkDescaling();
  83. event_subscribe("terminate", &coffeeTerminate);
  84. logger(V_BREW, "Determining inital state\n");
  85. //determine inital state
  86. if (halGetRelaisState(RELAIS_POWER) && halGetRelaisState(RELAIS_HEAT)
  87. && !halGetRelaisState(RELAIS_PUMP)) {
  88. //wait for heat relais to switch
  89. sleep(1);
  90. if (halIsHeating()) { //Heating is on
  91. changeState(STATE_INITALHEATING);
  92. } else {
  93. initalHeating = false;
  94. changeState(STATE_IDLE);
  95. }
  96. } else if (halGetRelaisState(RELAIS_PUMP)) {
  97. logger_error("Whoops, why is the pump running...\n");
  98. changeState(STATE_ERROR);
  99. } else {
  100. changeState(STATE_OFF);
  101. }
  102. logger(V_BREW, "Starting Coffee FSM\n");
  103. //begin FSM
  104. while (1) {
  105. /*
  106. * Menue FSM
  107. */
  108. switch (page) {
  109. case PAGE_SOFTOFF: //this page is only available when the machine is on
  110. if (SigValueEmpty() && mode == MODE_MENU)
  111. pause();
  112. switch (getSigValue(MODE_MENU)) {
  113. case SigInt0Rls:
  114. changeState(STATE_WAIT_OFF);
  115. leaveMenu();
  116. break;
  117. case SigInt1Psh:
  118. changePage(PAGE_KILL);
  119. break;
  120. }
  121. break;
  122. case PAGE_KILL: //this page is only available when the machine is on
  123. if (SigValueEmpty() && mode == MODE_MENU)
  124. pause();
  125. switch (getSigValue(MODE_MENU)) {
  126. case SigInt0Rls:
  127. if (halIsHeating()) {
  128. coffeeIncreaseHeatingTime(halgetHeatingTime());
  129. }
  130. changeState(STATE_OFF);
  131. leaveMenu();
  132. break;
  133. case SigInt1Psh:
  134. if (state == STATE_IDLE || state == STATE_HEATING) {
  135. changePage(PAGE_CLEAN);
  136. } else {
  137. changePage(PAGE_DEMO);
  138. }
  139. break;
  140. }
  141. break;
  142. case PAGE_CLEAN: //this page is only be available when the machine is hot
  143. if (SigValueEmpty() && mode == MODE_MENU)
  144. pause();
  145. switch (getSigValue(MODE_MENU)) {
  146. case SigInt0Rls:
  147. changeMode(MODE_STATE);
  148. if (!halProxSensorCovered()) {
  149. changeState(STATE_CLEANING);
  150. leaveMenu();
  151. } else {
  152. changeState(STATE_FULLTANK);
  153. leaveMenu();
  154. }
  155. break;
  156. case SigInt1Psh:
  157. changePage(PAGE_DEMO);
  158. break;
  159. }
  160. break;
  161. case PAGE_DEMO:
  162. if (SigValueEmpty() && mode == MODE_MENU)
  163. pause();
  164. switch (getSigValue(MODE_MENU)) {
  165. case SigInt1Psh:
  166. changePage(PAGE_TEMP);
  167. break;
  168. }
  169. break;
  170. case PAGE_TEMP:
  171. if (SigValueEmpty() && mode == MODE_MENU)
  172. pause();
  173. switch (getSigValue(MODE_MENU)) {
  174. case SigInt1Psh:
  175. changePage(PAGE_STATS);
  176. break;
  177. }
  178. break;
  179. //TODO: Add page heating time in minutes and Wh
  180. case PAGE_STATS:
  181. if (SigValueEmpty() && mode == MODE_MENU)
  182. pause();
  183. switch (getSigValue(MODE_MENU)) {
  184. case SigInt1Psh:
  185. changePage(PAGE_EXIT);
  186. break;
  187. }
  188. break;
  189. //TODO: Add page when next descaling is necessary
  190. case PAGE_EXIT:
  191. if (SigValueEmpty() && mode == MODE_MENU)
  192. pause();
  193. switch (getSigValue(MODE_MENU)) {
  194. case SigInt0Rls:
  195. leaveMenu();
  196. break;
  197. case SigInt1Psh:
  198. if (state == STATE_HEATING || state == STATE_ERROR
  199. || state == STATE_IDLE
  200. || state == STATE_INITALHEATING) {
  201. changePage(PAGE_SOFTOFF);
  202. } else {
  203. changePage(PAGE_DEMO);
  204. }
  205. break;
  206. }
  207. break;
  208. } //end switch (page)
  209. /*
  210. * Hardware FSM
  211. */
  212. switch (state) {
  213. /*
  214. *
  215. */
  216. case STATE_OFF:
  217. if (mode == MODE_STATE) {
  218. halMachineOff();
  219. writeBackCache();
  220. changePage(PAGE_DEMO);
  221. if (SigValueEmpty())
  222. pause();
  223. }
  224. switch (getSigValue(MODE_STATE)) {
  225. case SigInt0Rls:
  226. //Check waterlevel in gray water tank
  227. //turn machine on
  228. halMachineOn();
  229. sleep(1);
  230. if (halIsHeating() && !halProxSensorCovered()) { //check if System starts to heat when turned on
  231. changeState(STATE_INITALHEATING);
  232. } else if (!halIsHeating() && !halProxSensorCovered()) {
  233. changeState(STATE_IDLE);
  234. } else if (halProxSensorCovered()) {
  235. logger_error("Empty Tank please!\n");
  236. changeState(STATE_FULLTANK);
  237. }
  238. if (page != PAGE_SOFTOFF)
  239. changePage(PAGE_SOFTOFF); //the machine is on, the menu starts with the turning off page
  240. break;
  241. case SigInt1Psh:
  242. //Enter the menu
  243. if (page != PAGE_DEMO)
  244. changePage(PAGE_DEMO); //machine is off, the menu starts with the demo page
  245. changeMode(MODE_MENU);
  246. break;
  247. }
  248. break;
  249. /*
  250. *
  251. */
  252. case STATE_WAIT_OFF:
  253. if (SigValueEmpty() && mode == MODE_STATE)
  254. pause();
  255. switch (getSigValue(MODE_STATE)) {
  256. case SigPressOpn:
  257. usleep(100000); //wait so no load will be switched
  258. coffeeIncreaseHeatingTime(halgetHeatingTime());
  259. changeState(STATE_OFF);
  260. break;
  261. case SigInt0Psh:
  262. case SigInt1Psh:
  263. if (halProxSensorCovered()) {
  264. changeState(STATE_FULLTANK);
  265. } else if (initalHeating) {
  266. changeState(STATE_INITALHEATING);
  267. } else {
  268. changeState(STATE_HEATING);
  269. }
  270. break;
  271. }
  272. break;
  273. /*
  274. *
  275. */
  276. case STATE_INITALHEATING:
  277. initalHeating = true;
  278. if (SigValueEmpty() && mode == MODE_STATE)
  279. pause();
  280. switch (getSigValue(MODE_STATE)) {
  281. // case SigInt0RlsLong:
  282. // //Turn machine off again
  283. // coffeeIncreaseHeatingTime(halgetHeatingTime());
  284. // changeState(STATE_OFF);
  285. // break;
  286. //
  287. // case SigInt0Rls:
  288. // changeState(STATE_WAIT_OFF);
  289. // break;
  290. case SigProxCvrd:
  291. changeState(STATE_FULLTANK);
  292. break;
  293. case SigPressOpn:
  294. //Inital heating finished
  295. initalHeating = false;
  296. coffeeIncreaseHeatingTime(halgetHeatingTime());
  297. changeState(STATE_IDLE);
  298. break;
  299. case SigInt1Psh:
  300. changeMode(MODE_MENU);
  301. break;
  302. }
  303. break;
  304. /*
  305. *
  306. */
  307. case STATE_HEATING:
  308. if (SigValueEmpty() && mode == MODE_STATE)
  309. pause();
  310. switch (getSigValue(MODE_STATE)) {
  311. // case SigInt1RlsLong:
  312. // //Turn machine _immediately_ off again
  313. // coffeeIncreaseHeatingTime(halgetHeatingTime());
  314. // changeState(STATE_OFF);
  315. // break;
  316. //
  317. // case SigInt1Rls:
  318. // //turn machine off when heating is finished
  319. // changeState(STATE_WAIT_OFF);
  320. // break;
  321. case SigPressOpn:
  322. coffeeIncreaseHeatingTime(halgetHeatingTime());
  323. changeState(STATE_IDLE);
  324. break;
  325. case SigInt0Psh:
  326. //start to brew a delicious coffee
  327. changeState(STATE_BREW);
  328. break;
  329. case SigProxCvrd:
  330. changeState(STATE_FULLTANK);
  331. break;
  332. case SigBrewOn:
  333. //someone brews manually
  334. changeState(STATE_BREWMANUAL);
  335. break;
  336. case SigInt1Psh:
  337. //Enter the menu
  338. changeMode(MODE_MENU);
  339. break;
  340. }
  341. break;
  342. /*
  343. *
  344. */
  345. case STATE_IDLE:
  346. if (SigValueEmpty() && mode == MODE_STATE)
  347. pause();
  348. switch (getSigValue(MODE_STATE)) {
  349. // case SigInt1RlsLong:
  350. // //turn machine _immediately_ off
  351. // changeState(STATE_OFF);
  352. // break;
  353. //
  354. // case SigInt1Rls:
  355. // changeState(STATE_OFF);
  356. // break;
  357. case SigPressCls:
  358. changeState(STATE_HEATING);
  359. break;
  360. case SigInt0Psh:
  361. changeState(STATE_BREW);
  362. break;
  363. case SigProxCvrd:
  364. changeState(STATE_FULLTANK);
  365. break;
  366. case SigBrewOn:
  367. //someone brews manually
  368. changeState(STATE_BREWMANUAL);
  369. break;
  370. case SigInt1Psh:
  371. //Enter the menu
  372. changeMode(MODE_MENU);
  373. break;
  374. }
  375. break;
  376. /*
  377. *
  378. */
  379. case STATE_BREW:
  380. //make sure the tank is not full
  381. if (halProxSensorCovered()) {
  382. changeState(STATE_FULLTANK);
  383. logger_error("coffee.cpp: Full tank detection failed..\n");
  384. } else {
  385. coffeeBrew();
  386. checkDescaling();
  387. logger(V_BREW, "Finishing brewing\n");
  388. if (!halProxSensorCovered()) {
  389. if (halIsHeating()) {
  390. changeState(STATE_HEATING);
  391. } else {
  392. changeState(STATE_IDLE);
  393. }
  394. } else {
  395. changeState(STATE_FULLTANK);
  396. }
  397. }
  398. break;
  399. /*
  400. *
  401. */
  402. case STATE_BREWMANUAL:
  403. if (SigValueEmpty() && mode == MODE_STATE)
  404. pause();
  405. break;
  406. /*
  407. *
  408. */
  409. case STATE_CLEANING: //this can only be executed once the machine is hot!
  410. if (!halProxSensorCovered()) {
  411. //execute the cleaning procedure
  412. coffeeClean();
  413. if (halIsHeating()) {
  414. changeState(STATE_HEATING);
  415. } else {
  416. changeState(STATE_IDLE);
  417. }
  418. } else {
  419. changeState(STATE_FULLTANK);
  420. }
  421. break;
  422. /*
  423. * Full tank is detected at the beginning and the end of a brewing process, during
  424. * idle times, initial heating and heating
  425. */
  426. case STATE_FULLTANK:
  427. if (SigValueEmpty() && mode == MODE_STATE)
  428. pause();
  429. switch (getSigValue(MODE_STATE)) {
  430. case SigInt1Psh:
  431. case SigInt0Psh:
  432. if (halIsHeating() && initalHeating) {
  433. changeState(STATE_INITALHEATING);
  434. } else if (halIsHeating() && !initalHeating) {
  435. changeState(STATE_HEATING);
  436. } else {
  437. changeState(STATE_IDLE);
  438. }
  439. break;
  440. }
  441. break;
  442. /*
  443. *
  444. */
  445. case STATE_ERROR:
  446. if (SigValueEmpty() && mode == MODE_STATE)
  447. pause();
  448. switch (getSigValue(MODE_STATE)) {
  449. case SigInt1RlsLong:
  450. case SigInt0RlsLong:
  451. if (halIsHeating()) {
  452. coffeeIncreaseHeatingTime(halgetHeatingTime());
  453. }
  454. changeState(STATE_OFF);
  455. break;
  456. }
  457. }
  458. }
  459. pthread_exit(EXIT_SUCCESS);
  460. }
  461. /**
  462. * Handler for the Signal send to this thread
  463. * It saves the type of signal received and tracks the time between a push and release event of up to 4 signals
  464. * The time is stored in the HalEvent variable when a release event is received
  465. * @param signum
  466. * @param siginfo
  467. * @param context
  468. */
  469. void coffeeHandler(int signum, siginfo_t *siginfo, void *context) {
  470. sigval_t sigVal = (siginfo->si_value);
  471. sigValue = sigVal.sival_int;
  472. logger(V_BREW, "coffee.cpp: CoffeeHandler called with Signal %d\n",
  473. sigValue);
  474. }
  475. /**
  476. * returns the Signal value from the last received Signal for the given mode and clears the variable
  477. * @return value sent with the last signal
  478. */
  479. int getSigValue(coffee_mode_t mode) {
  480. int tmp = sigValue;
  481. if (mode == MODE_MENU) {
  482. switch (sigValue) {
  483. case SigInt0Psh:
  484. case SigInt0Rls:
  485. case SigInt0RlsLong:
  486. case SigInt1Psh:
  487. case SigInt1Rls:
  488. case SigInt1RlsLong:
  489. sigValue = 0;
  490. return tmp;
  491. break;
  492. default:
  493. break;
  494. }
  495. } else { //State Mode
  496. sigValue = 0;
  497. return tmp;
  498. }
  499. //int tmp = sigValue;
  500. //sigValue = 0;
  501. //return tmp;
  502. return 0;
  503. }
  504. bool SigValueEmpty(void) {
  505. if (sigValue == 0)
  506. return true;
  507. else
  508. return false;
  509. }
  510. /**
  511. * Changes the state of the machine to newState
  512. * prints the change to the logger
  513. * @param newState
  514. */
  515. void changeState(coffee_status_t newState) {
  516. logger(V_BREW, "Changing state to %s\n", StateName[newState]);
  517. state = newState;
  518. event_trigger("statechange", &state, sizeof(state));
  519. }
  520. /*
  521. * Change Page to new menu page
  522. */
  523. void changePage(coffee_menuPage_t newPage) {
  524. logger(V_BREW, "Change Page to %s\n", PageName[newPage]);
  525. event_trigger("pagechange", &newPage, sizeof(newPage));
  526. page = newPage;
  527. }
  528. /*
  529. * Changes the mode of the machine to the given mode
  530. */
  531. void changeMode(coffee_mode_t newMode) {
  532. if (newMode == MODE_MENU)
  533. logger(V_BREW, "Changing to menu mode\n");
  534. else
  535. logger(V_BREW, "Changing to state mode\n");
  536. event_trigger("modechange", &newMode, sizeof(newMode));
  537. mode = newMode;
  538. }
  539. /*
  540. * leaving the menu
  541. * sets the start page for the next menu call to softoff
  542. */
  543. void leaveMenu() {
  544. logger(V_BREW, "Leaving the menu again...\n");
  545. //leave the menu again
  546. changeMode(MODE_STATE);
  547. //change page to initial page
  548. changePage(PAGE_SOFTOFF);
  549. }
  550. /**
  551. * Returns the current state of the FSM
  552. */
  553. coffee_status_t getState(void) {
  554. return state;
  555. }
  556. /**
  557. * Returns the local up-to-date brewcounter
  558. */
  559. uint16_t getBrewCounter(void) {
  560. return brewCounter;
  561. }
  562. /**
  563. * Counter for the brew time
  564. * refresh every 200ms
  565. */
  566. void brewTimeHandler(void) {
  567. brewTime += 200;
  568. }
  569. /**
  570. * handles program termination
  571. */
  572. void coffeeTerminate(event_t *event) {
  573. logger(V_BREW, "Coffee.cpp: Terminating\n");
  574. //stop brewing
  575. halRelaisOff(RELAIS_PUMP);
  576. brewTimer.stop();
  577. writeBackCache();
  578. }
  579. /**
  580. * Function to write back the values of the local copies
  581. * brewCounter and totalHeatingTime
  582. *
  583. */
  584. void writeBackCache(void) {
  585. if (sqlSetConf(CFGbrewcounter, brewCounter)) {
  586. logger_error("coffee.cpp: Couldn't write brewcounter to database");
  587. return;
  588. }
  589. if (sqlSetConf(CFGHeatingTime, totalHeatingTime)) {
  590. logger_error("coffee.cpp: Couldn't write heating time to database");
  591. return;
  592. }
  593. if (sqlSetConf(CFGDescBrewCount, descBrewcount)) {
  594. logger_error("coffee.cpp: Couldn't write descaling brewcount to database");
  595. return;
  596. }
  597. if (sqlSetConf(CFGDescTimestamp, (uint64_t)descRawTimestamp)) {
  598. logger_error("coffee.cpp: Couldn't write descaling timestamp to database");
  599. return;
  600. }
  601. }
  602. /*
  603. * Procedure for cleaning the machine
  604. */
  605. void coffeeClean(void) {
  606. logger(V_BREW, "Cleaning...\n");
  607. for (int i = 0; i < 20; i++) {
  608. halRelaisOn(RELAIS_PUMP);
  609. //TODO the sleep function returns when a signal is delivered
  610. //this causes the cleaning to not work properly when the pressure is triggered
  611. sleep(3);
  612. halRelaisOff(RELAIS_PUMP);
  613. sleep(15);
  614. }
  615. updateDescaling();
  616. descaling = false;
  617. event_trigger("descaling", &descaling, sizeof(bool));
  618. }
  619. /**
  620. * Brewing process
  621. */
  622. void coffeeBrew(void) {
  623. coffeeIncreaseBrewCounter();
  624. /*
  625. * Preinfusion
  626. */
  627. logger(V_BREW, "Starting preinfusion...\n");
  628. halResetFlow();
  629. halRelaisOn(RELAIS_PUMP);
  630. brewTime = 0;
  631. brewTimer.start();
  632. while (halGetFlow() < AMOUNT_PREINFUSION) {
  633. usleep(50000);
  634. if (getSigValue(MODE_STATE) == SigInt0Psh){
  635. stopBrewing();
  636. return;
  637. }
  638. }
  639. stopBrewing();
  640. /*
  641. * Wait for coffee to soak in infused water
  642. */
  643. brewTimer.start();
  644. while (brewTime < TIME_SOAK) {
  645. usleep(100000);
  646. if (getSigValue(MODE_STATE) == SigInt0Psh) {
  647. stopBrewing();
  648. return;
  649. }
  650. }
  651. stopBrewing();
  652. /*
  653. * Brewing the actual espresso
  654. */
  655. logger(V_BREW, "Starting infusion...\n");
  656. halRelaisOn(RELAIS_PUMP);
  657. brewTimer.start();
  658. while (brewTime < TIME_INFUSION && halGetFlow() < AMOUNT_DBLESPRESSO) {
  659. usleep(100000);
  660. if (getSigValue(MODE_STATE) == SigInt0Psh){
  661. stopBrewing();
  662. break;
  663. }
  664. }
  665. stopBrewing();
  666. return;
  667. //TODO: I want to see the total elapes brewing time!!
  668. }
  669. /*
  670. * Wrapper function for the end of a brewing process
  671. * this function stops the pump, brewtimer and resets the flow and brew time to zero
  672. */
  673. void stopBrewing() {
  674. halRelaisOff(RELAIS_PUMP);
  675. brewTimer.stop();
  676. brewTime = 0;
  677. halResetFlow();
  678. }
  679. /**
  680. *
  681. */
  682. void coffeeIncreaseBrewCounter(void) {
  683. brewCounter++;
  684. }
  685. /**
  686. *
  687. */
  688. void coffeeIncreaseHeatingTime(uint64_t heatingTime) {
  689. totalHeatingTime += heatingTime;
  690. }
  691. /**
  692. * Checks if the descaling is necessary
  693. * uses descBrewcount and descTimestamp
  694. */
  695. void checkDescaling(){
  696. time_t rawtime;
  697. time(&rawtime);
  698. double diffseconds = difftime(rawtime, descRawTimestamp);
  699. diffseconds /= 24*60*60;
  700. if((brewCounter - descBrewcount) >= DIRTY_ESPRESSO) {
  701. logger(V_BREW, "Descaling necessary due to quantity: %d\n", brewCounter - descBrewcount);
  702. descaling = true;
  703. event_trigger("descaling", &descaling, sizeof(bool));
  704. }
  705. if(diffseconds >= DIRTY_TIME) {
  706. logger(V_BREW, "Descaling necessary due to time in days: %d\n", diffseconds);
  707. descaling = true;
  708. event_trigger("descaling", &descaling, sizeof(bool));
  709. }
  710. }
  711. /**
  712. * updates the corresponding variables after a descaling process
  713. */
  714. void updateDescaling(){
  715. descBrewcount = brewCounter;
  716. time_t newDesTimestamp;
  717. time(&newDesTimestamp);
  718. if(newDesTimestamp == -1){
  719. logger(V_BREW, "Whoops, couldn't retrieve new descaling timestamp\n");
  720. }
  721. else {
  722. descRawTimestamp = newDesTimestamp;
  723. }
  724. }