coffee.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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. #include "events.h"
  25. coffee_status_t state;
  26. int sigValue;
  27. int brewTime; //Brew time in ms
  28. timer brewTimer(&brewTimeHandler);
  29. const char* StateName[] = {"OFF", "HEATING", "INITHEAT", "IDLE", "BREW", "BREWMAN", "CLEAN", "ERROR"};
  30. /**
  31. * Thread for the finite state machine
  32. * It represents the current state of the machine and handles signals coming from
  33. * the pressure control, buttons, the brew switch and the proximity sensor
  34. * @param threadid the ID of the thread
  35. */
  36. void *coffeeThread(void *threadid) {
  37. logger(V_BASIC, "Initializing coffee thread...\n");
  38. //installing new Signal handler for coffeethread
  39. struct sigaction action;
  40. sigemptyset(&action.sa_mask);
  41. action.sa_flags = SA_SIGINFO;
  42. action.sa_sigaction = coffeeHandler;
  43. sigaction(SIGUSR2, &action, NULL);
  44. brewTimer.setDivider(4);
  45. brewTimer.stop();
  46. brewTime = 0;
  47. logger(V_BREW, "Determining inital state\n");
  48. //determine inital state
  49. if (halGetRelaisState(RELAIS_POWER) && halGetRelaisState(RELAIS_HEAT)
  50. && !halGetRelaisState(RELAIS_PUMP)) {
  51. //wait for heat relais to switch
  52. sleep(1);
  53. if (halIsHeating()) { //Heating is on
  54. changeState(STATE_INITALHEATING);
  55. } else {
  56. changeState(STATE_IDLE);
  57. }
  58. } else if (halGetRelaisState(RELAIS_PUMP)) {
  59. logger_error("Whoops, why is the pump running...\n");
  60. changeState(STATE_ERROR);
  61. } else {
  62. changeState(STATE_OFF);
  63. }
  64. logger(V_BREW, "Starting Coffee FSM\n");
  65. //begin FSM
  66. while (1) {
  67. switch (state) {
  68. /*
  69. *
  70. */
  71. case STATE_OFF:
  72. if (SigValueEmpty())
  73. pause();
  74. if (getSigValue() == SigInt0Rls) {
  75. if (halProxSensorCovered()) { //Check Waterlevel
  76. //turn machine on
  77. halMachineOn();
  78. sleep(1);
  79. if (halIsHeating()) { //check if System starts to heat when turned on
  80. changeState(STATE_INITALHEATING);
  81. } else {
  82. changeState(STATE_IDLE);
  83. }
  84. } else {
  85. changeState(STATE_ERROR);
  86. }
  87. break;
  88. }
  89. break;
  90. /*
  91. *
  92. */
  93. case STATE_INITALHEATING:
  94. if (SigValueEmpty())
  95. pause();
  96. switch (getSigValue()) {
  97. case SigInt1RlsLong:
  98. //Turn machine off again
  99. halMachineOff();
  100. coffeeIncreaseHeatingTime(halgetHeatingTime());
  101. changeState(STATE_OFF);
  102. break;
  103. case SigPressOpn:
  104. //Inital heating finished
  105. coffeeIncreaseHeatingTime(halgetHeatingTime());
  106. changeState(STATE_IDLE);
  107. break;
  108. }
  109. break;
  110. /*
  111. *
  112. */
  113. case STATE_HEATING:
  114. if (SigValueEmpty())
  115. pause();
  116. switch (getSigValue()) {
  117. case SigInt1RlsLong:
  118. //Turn machine off again
  119. halMachineOff();
  120. coffeeIncreaseHeatingTime(halgetHeatingTime());
  121. changeState(STATE_OFF);
  122. break;
  123. case SigPressOpn:
  124. coffeeIncreaseHeatingTime(halgetHeatingTime());
  125. changeState(STATE_IDLE);
  126. break;
  127. case SigInt0Psh:
  128. //start to brew a delicious coffee
  129. changeState(STATE_BREW);
  130. break;
  131. case SigBrewOn:
  132. //someone brews manually
  133. changeState(STATE_BREWMANUAL);
  134. break;
  135. }
  136. break;
  137. /*
  138. *
  139. */
  140. case STATE_IDLE:
  141. if (SigValueEmpty())
  142. pause();
  143. switch (getSigValue()) {
  144. case SigInt1RlsLong:
  145. //Turn machine off again
  146. halMachineOff();
  147. changeState(STATE_OFF);
  148. break;
  149. case SigPressCls:
  150. changeState(STATE_HEATING);
  151. break;
  152. case SigInt0Psh:
  153. //start to brew a delicious coffee
  154. changeState(STATE_BREW);
  155. break;
  156. case SigBrewOn:
  157. //someone brews manually
  158. changeState(STATE_BREWMANUAL);
  159. break;
  160. }
  161. break;
  162. /*
  163. *
  164. */
  165. case STATE_BREW:
  166. coffeeBrew();
  167. logger(V_BREW, "Finishing brewing\n");
  168. changeState(STATE_IDLE);
  169. break;
  170. /*
  171. *
  172. */
  173. case STATE_BREWMANUAL:
  174. if (SigValueEmpty())
  175. pause();
  176. break;
  177. /*
  178. *
  179. */
  180. case STATE_CLEANING:
  181. if (SigValueEmpty())
  182. pause();
  183. break;
  184. /*
  185. *
  186. */
  187. case STATE_ERROR:
  188. if (SigValueEmpty())
  189. pause();
  190. break;
  191. }
  192. }
  193. pthread_exit(EXIT_SUCCESS);
  194. }
  195. /**
  196. * Handler for the Signal send to this thread
  197. * It saves the type of signal received and tracks the time between a push and release event of up to 4 signals
  198. * The time is stored in the HalEvent variable when a release event is received
  199. * @param signum
  200. * @param siginfo
  201. * @param context
  202. */
  203. void coffeeHandler(int signum, siginfo_t *siginfo, void *context) {
  204. sigval_t sigVal = (siginfo->si_value);
  205. sigValue = sigVal.sival_int;
  206. logger(V_BREW, "CoffeeHandler called with %d\n", sigValue);
  207. }
  208. /**
  209. * returns the Signal value from the last received Signal and clears the variable
  210. * @return value sent with the last signal
  211. */
  212. int getSigValue(void) {
  213. int tmp = sigValue;
  214. sigValue = 0;
  215. return tmp;
  216. }
  217. bool SigValueEmpty(void) {
  218. if (sigValue == 0)
  219. return true;
  220. else
  221. return false;
  222. }
  223. /**
  224. * Changes the state of the machine to newState
  225. * prints the change to the logger
  226. * @param newState
  227. */
  228. void changeState(coffee_status_t newState) {
  229. logger(V_BREW, "Changing state to %s\n", StateName[newState]);
  230. state = newState;
  231. event_trigger("statechange", &state, sizeof(state));
  232. }
  233. /**
  234. * Returns the current state of the FSM
  235. */
  236. coffee_status_t getState(void) {
  237. return state;
  238. }
  239. /**
  240. * Counter for the brew time
  241. * refresh every 200ms
  242. */
  243. void brewTimeHandler(void) {
  244. brewTime += 200;
  245. }
  246. /**
  247. * handles program termination
  248. */
  249. void coffeeTerminate(void) {
  250. logger_error("Coffee thread terminated");
  251. //stop brewing
  252. halRelaisOff(RELAIS_PUMP);
  253. brewTimer.stop();
  254. }
  255. /**
  256. * Brewing process
  257. */
  258. void coffeeBrew(void) {
  259. coffeeIncreaseBrewCounter();
  260. /*
  261. * Preinfusion
  262. */
  263. logger(V_BREW, "Starting preinfusion...\n");
  264. halResetFlow();
  265. halRelaisOn(RELAIS_PUMP);
  266. brewTime = 0;
  267. brewTimer.start();
  268. while (halGetFlow() < AMOUNT_PREINFUSION) {
  269. usleep(50000);
  270. if (getSigValue() == SigInt1Psh)
  271. return;
  272. }
  273. brewTimer.stop();
  274. brewTime = 0;
  275. halRelaisOff(RELAIS_PUMP);
  276. /*
  277. * Wait for coffee to soak in infused water
  278. */
  279. brewTimer.start();
  280. while (brewTime < TIME_SOAK) {
  281. usleep(100000);
  282. if (getSigValue() == SigInt1Psh)
  283. return;
  284. }
  285. brewTimer.stop();
  286. brewTime = 0;
  287. halResetFlow();
  288. /*
  289. * Brewing the actual espresso
  290. */
  291. logger(V_BREW, "Starting infusion...\n");
  292. halRelaisOn(RELAIS_PUMP);
  293. brewTimer.start();
  294. while (brewTime < TIME_INFUSION && halGetFlow() < AMOUNT_DBLESPRESSO) {
  295. usleep(100000);
  296. if (getSigValue() == SigInt1Psh)
  297. return;
  298. }
  299. halRelaisOff(RELAIS_PUMP);
  300. halResetFlow();
  301. brewTimer.stop();
  302. brewTime = 0;
  303. changeState(STATE_IDLE);
  304. return;
  305. }
  306. /**
  307. *
  308. */
  309. void coffeeIncreaseBrewCounter(void) {
  310. uint64_t brewcounter = sqlGetConf(CFGbrewcounter);
  311. if (sqlSetConf(CFGbrewcounter, ++brewcounter)) {
  312. logger_error("Couldn't write brewcounter to database");
  313. }
  314. }
  315. /**
  316. *
  317. */
  318. void coffeeIncreaseHeatingTime(clock_t begin, clock_t end){
  319. }
  320. /**
  321. *
  322. */
  323. void coffeeIncreaseHeatingTime(uint64_t heatingTime) {
  324. uint64_t totalHeatingTime = sqlGetConf(CFGHeatingTime);
  325. if (sqlSetConf(CFGHeatingTime, (totalHeatingTime + heatingTime))) {
  326. logger_error("Couldn't write heating time to database");
  327. }
  328. }