coffee.cpp 18 KB

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