hal.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. /*
  2. * hal.cpp
  3. *
  4. * Created on: Aug 3, 2016
  5. * Author: Philipp Hinz, Sebastian Vendt
  6. */
  7. #include <wiringPi.h>
  8. #include <stdlib.h>
  9. #include <stdint.h>
  10. #include <errno.h>
  11. #include <string.h>
  12. #include <signal.h>
  13. #include <ctime>
  14. #include <time.h>
  15. #include <unistd.h>
  16. #include "hal.h"
  17. #include "global.h"
  18. #include "logger.h"
  19. #include "timer.h"
  20. #include "database.h"
  21. const char* SigName[] = {
  22. "NULL",
  23. "SigInt0Psh",
  24. "SigInt0Rls",
  25. "SigInt0RlsLong",
  26. "SigInt1Psh",
  27. "SigInt1Rls",
  28. "SigInt1RlsLong",
  29. "SigPressCls",
  30. "SigPressOpn",
  31. "SigProxOpn",
  32. "SigProxCvrd",
  33. "SigBrewOn",
  34. "SigBrewOff",
  35. "SigPowerUp",
  36. "SigPowerDown",
  37. "SigRotCW",
  38. "SigRotCCW"};
  39. typedef struct timespec timespec;
  40. volatile int flowcnt = 0;
  41. int lastFlowcnt = 0;
  42. int flowResetValue = -1;
  43. bool brewmanual = false;
  44. time_t heatingCycleStart = 0;
  45. uint64_t totalHeatingTime = 0; //local copies of the corresponding database entries
  46. int Int0Time, Int1Time;
  47. int idleCounter;
  48. bool idle;
  49. bool flagIgnoreRlsInt0, flagIgnoreRlsInt1;
  50. //storage for the last state of the buttons, the proximity sensor and the pressure sensor
  51. int pinState[4] = {1, 1, 1, 0};
  52. //state of the rotary encoder
  53. //0: rotary1 state at t-1
  54. //1: rotary2 state at t-1
  55. //2: rotary1 state at t
  56. //3: rotary2 state at t
  57. int rotaryState[4] = {1, 0, 0, 1};
  58. timer Int0Timer(&halInt0TimerHandler);
  59. timer Int1Timer(&halInt1TimerHandler);
  60. timer idleTimer(&halIdleTimerHandler);
  61. timer flowResetTimer (&flowResetTimerHandler);
  62. timer flowTimer(&halFlowTimerHandler);
  63. timespec flowTimestep[] = {{0,0},{0,0}};
  64. uint8_t flowIndex = 0;
  65. int16_t tickCounter = 0; //rotary encoder
  66. uint16_t flowtime = 0;
  67. uint16_t lastFlowTime = 0;
  68. bool brewSigFired = false;
  69. //delay of the debounce in milliseconds
  70. #define DELAY_DEBOUNCE 50
  71. #define DELAY_MICRODEB 2
  72. //display turn off after idle time in min
  73. //minimal time is 2min
  74. #define IDLE_TIME 10
  75. /**
  76. * Initializes HAL
  77. */
  78. void halInit(void) {
  79. pinMode(RELAIS_HEAT, OUTPUT);
  80. pinMode(RELAIS_PUMP, OUTPUT);
  81. pinMode(RELAIS_POWER, OUTPUT);
  82. pinMode(PIN_PRESSURE_CTRL, INPUT);
  83. pinMode(PIN_PROXIMITY_SENSOR, INPUT);
  84. pinMode(PIN_INT0, INPUT);
  85. pinMode(PIN_INT1, INPUT);
  86. pinMode(PIN_FLOW, INPUT);
  87. pinMode(PIN_DISP, OUTPUT);
  88. pinMode(PIN_ROTARY1, INPUT);
  89. pinMode(PIN_ROTARY2, INPUT);
  90. idleTimer.setDivider(ms2Divider(60000));
  91. idleCounter = 0;
  92. idle = false;
  93. clock_gettime(CLOCK_REALTIME, &flowTimestep[0]);
  94. clock_gettime(CLOCK_REALTIME, &flowTimestep[1]);
  95. halDisplayOn();
  96. if (!(totalHeatingTime = sqlGetConf(CFGHeatingTime))) {
  97. logger_error("hal.cpp: Couldn't read the total heating time from the database\n");
  98. //pthread_exit(EXIT_SUCCESS);
  99. exit(EXIT_FAILURE);
  100. }
  101. if (optPower) {
  102. halMachineOn();
  103. } else {
  104. halMachineOff();
  105. }
  106. sleep(1); //wait till the machine eventually turned on when optPower
  107. pinState[3] = halIsHeating();
  108. Int0Timer.setDivider(ms2Divider(200));
  109. Int1Timer.setDivider(ms2Divider(200));
  110. Int0Time = 0;
  111. Int1Time = 0;
  112. flowResetTimer.setDivider(ms2Divider(TIME_FLOWRESET));
  113. flowTimer.setDivider(ms2Divider(200));
  114. flagIgnoreRlsInt0 = false;
  115. flagIgnoreRlsInt1 = false;
  116. event_subscribe("terminate", &halTerminate, "hal.cpp");
  117. if (wiringPiISR(PIN_INT0, INT_EDGE_BOTH, &halInt0) < 0) {
  118. logger_error("Unable to setup ISR0: %s\n", strerror(errno));
  119. return;
  120. }
  121. if (wiringPiISR(PIN_INT1, INT_EDGE_BOTH, &halInt1) < 0) {
  122. logger_error("Unable to setup ISR1: %s\n", strerror(errno));
  123. return;
  124. }
  125. if (wiringPiISR(PIN_FLOW, INT_EDGE_FALLING, &halIntFlow) < 0) {
  126. logger_error("Unable to setup ISRFLOW: %s\n", strerror(errno));
  127. return;
  128. }
  129. if (wiringPiISR(PIN_PRESSURE_CTRL, INT_EDGE_BOTH, &halIntPressure) < 0) {
  130. logger_error("Unable to setup ISRPressure: %s\n", strerror(errno));
  131. return;
  132. }
  133. if (wiringPiISR(PIN_PROXIMITY_SENSOR, INT_EDGE_BOTH, &halIntProximity) < 0) {
  134. logger_error("Unable to setup ISRProximity: %s\n", strerror(errno));
  135. return;
  136. }
  137. if (wiringPiISR(PIN_ROTARY1, INT_EDGE_BOTH, &halIntRotary) < 0) {
  138. logger_error("Unable to setup ISRRotary2: %s\n", strerror(errno));
  139. return;
  140. }
  141. logger(V_BASIC, "hal.cpp: Initialized\n");
  142. }
  143. /**
  144. * Switches relais on
  145. * @param relais Relais ID
  146. */
  147. void halRelaisOn(int relais) {
  148. halRelaisSet(relais, LOW);
  149. }
  150. /**
  151. * Turn the display off
  152. */
  153. void halDisplayOff(){
  154. digitalWrite(PIN_DISP, LOW);
  155. }
  156. /**
  157. * Turn the display on
  158. */
  159. void halDisplayOn(){
  160. digitalWrite(PIN_DISP, HIGH);
  161. }
  162. /**
  163. * Switches relais off
  164. * @param relais Relais ID
  165. */
  166. void halRelaisOff(int relais) {
  167. halRelaisSet(relais, HIGH);
  168. }
  169. /**
  170. * Switches relais to state
  171. * @param relais Relais ID
  172. * @param state LOW(0) or HIGH(1)
  173. */
  174. void halRelaisSet(int relais, int state) {
  175. if (state != HIGH && state != LOW)
  176. return;
  177. switch (relais) {
  178. case RELAIS_POWER:
  179. case RELAIS_HEAT:
  180. case RELAIS_PUMP:
  181. digitalWrite(relais, state);
  182. break;
  183. }
  184. }
  185. /**
  186. * Returns the state of the relais relais
  187. * Returns HIGH when Relais is ON
  188. * @param relais Relais ID
  189. */
  190. int halGetRelaisState(int relais) {
  191. switch (relais) {
  192. case RELAIS_POWER:
  193. case RELAIS_HEAT:
  194. case RELAIS_PUMP:
  195. return !digitalRead(relais);
  196. break;
  197. }
  198. return -1;
  199. }
  200. /**
  201. *
  202. */
  203. void halIntRotary(void) {
  204. //delay(DELAY_MICRODEB);
  205. rotaryState[2] = digitalRead(PIN_ROTARY1);
  206. rotaryState[3] = digitalRead(PIN_ROTARY2);
  207. if (rotaryState[0] != rotaryState[2]) {
  208. //check for the status of the other pin
  209. if (rotaryState[1] != rotaryState[3]) {
  210. if ((rotaryState[2] == HIGH && rotaryState[3] == LOW) || (rotaryState[2] == LOW && rotaryState[3] == HIGH)) {
  211. //clockwise rotation
  212. tickCounter++;
  213. if (!(abs(tickCounter) % ROTARY_STEPSIZE)) {
  214. //logger(V_HAL, "rotary encoder CW \n");
  215. halSendSignal(SigRotCW);
  216. tickCounter = 0;
  217. }
  218. } else if ((rotaryState[2] == HIGH && rotaryState[3] == HIGH) || (rotaryState[2] == LOW && rotaryState[3] == LOW)) {
  219. //counterclockwise rotation
  220. tickCounter--;
  221. if (!(abs(tickCounter) % ROTARY_STEPSIZE)) {
  222. //logger(V_HAL, "rotary encoder CCW \n");
  223. halSendSignal(SigRotCCW);
  224. tickCounter = 0;
  225. }
  226. }
  227. rotaryState[1] = rotaryState[3];
  228. }
  229. rotaryState[0] = rotaryState[2];
  230. }
  231. }
  232. /**
  233. * Interrupt routine for Int0 (Top button)
  234. */
  235. void halInt0(void) {
  236. //wait for a debounce
  237. delay(DELAY_DEBOUNCE);
  238. if (halGetInt0() && !pinState[0]) { //released
  239. logger(V_HAL, "Int0 released\n");
  240. pinState[0] = 1;
  241. if (flagIgnoreRlsInt0) {
  242. flagIgnoreRlsInt0 = false;
  243. } else {
  244. Int0Time = 0;
  245. Int0Timer.stop();
  246. halSendSignal(SigInt0Rls);
  247. }
  248. } else if(!halGetInt0() && pinState[0]) { //pressed
  249. logger(V_HAL, "Int0 pushed\n");
  250. pinState[0] = 0;
  251. halSendSignal(SigInt0Psh);
  252. Int0Time = 0;
  253. Int0Timer.start();
  254. }
  255. }
  256. /**
  257. *
  258. */
  259. void halInt0TimerHandler(void) {
  260. Int0Time += 200;
  261. if (Int0Time >= (TIME_BUTTONLONGPRESS * 1000)) {
  262. halSendSignal(SigInt0RlsLong);
  263. flagIgnoreRlsInt0 = true;
  264. Int0Time = 0;
  265. Int0Timer.stop();
  266. }
  267. }
  268. /**
  269. *
  270. */
  271. void halIdleTimerHandler(void) {
  272. if(++idleCounter == IDLE_TIME){
  273. halEnterIdle();
  274. }
  275. }
  276. /**
  277. * Interrupt routine for Int1 (Bottom button)
  278. */
  279. void halInt1(void) {
  280. delay(DELAY_DEBOUNCE);
  281. if (halGetInt1() && !pinState[1]) {
  282. logger(V_HAL, "Int1 released\n");
  283. pinState[1] = 1;
  284. if (flagIgnoreRlsInt1) {
  285. flagIgnoreRlsInt1 = false;
  286. } else {
  287. Int1Time = 0;
  288. Int1Timer.stop();
  289. halSendSignal(SigInt1Rls);
  290. }
  291. } else if(!halGetInt1() && pinState[1]) {
  292. logger(V_HAL, "Int1 pushed\n");
  293. pinState[1] = 0;
  294. halSendSignal(SigInt1Psh);
  295. Int1Time = 0;
  296. Int1Timer.start();
  297. }
  298. }
  299. /*
  300. *
  301. */
  302. void halInt1TimerHandler(void) {
  303. Int1Time += 200;
  304. if (Int1Time >= (TIME_BUTTONLONGPRESS * 1000)) {
  305. halSendSignal(SigInt1RlsLong);
  306. flagIgnoreRlsInt1 = true;
  307. Int1Time = 0;
  308. Int1Timer.stop();
  309. }
  310. }
  311. /**
  312. * Timer handler to auto-reset the flow counter.
  313. * The timer is started when the flow interrupt is triggered.
  314. * It compares the last value (flowResetValue) with the current flow value
  315. * If they match (e.g no flow within 1000ms) the flow counter is reseted.
  316. * Setting the last value to -1 ensures that when the timer gets called immediately after it is started the comparison will fail.
  317. * This implementation is read-only and so it doesn't need semaphores.
  318. */
  319. void flowResetTimerHandler() {
  320. if(flowResetValue == flowcnt) {
  321. halResetFlow();
  322. return;
  323. }
  324. flowResetValue = flowcnt;
  325. }
  326. /**
  327. *
  328. */
  329. void halFlowTimerHandler() {
  330. flowtime += 200;
  331. }
  332. /**
  333. * Interrupt routine for the flow sensor
  334. * It counts the edges and stores the value in flowcnt
  335. */
  336. void halIntFlow(void) {
  337. //halRelaisOff(RELAIS_POWER);
  338. if(!flowResetTimer.isActive()) flowResetTimer.start();
  339. flowcnt++;
  340. logger(V_HAL, "IntFlow triggered #%d total: %.2fml\n", flowcnt, halGetFlow());
  341. //tracking of flowtime
  342. if(!flowTimer.isActive()) flowTimer.start();
  343. if (halGetFlow() >= BREW_MANUAL_TRIGGER && !brewSigFired) {
  344. halSendSignal(SigBrewOn);
  345. brewSigFired = true;
  346. }
  347. //subroutine to log the flow to the database
  348. /*timespec deltaT;
  349. clock_gettime(CLOCK_REALTIME, &flowTimestep[flowIndex]);
  350. timespec_diff(&flowTimestep[((flowIndex + 1) % 2)], &flowTimestep[flowIndex], &deltaT);
  351. if (sqlLogFlow(logcycle, halGetFlow()*1000, deltaT.tv_sec * 1000 + deltaT.tv_nsec/1000000)) {
  352. logger_error("hal.cpp: could not log flow to database!");
  353. return;
  354. }
  355. flowIndex = (flowIndex + 1) % 2;*/
  356. }
  357. /**
  358. * Interrupt routine for the pressure control
  359. * It captures the time at closing point and opening point
  360. * Reading heating time via the getHeatingTime function
  361. */
  362. void halIntPressure(void) {
  363. delay(DELAY_DEBOUNCE);
  364. if (halIsHeating() && !pinState[3]) {
  365. logger(V_HAL, "hal.cpp: Pressure Control closed\n");
  366. pinState[3] = 1;
  367. halStartHeatingTime();
  368. halSendSignal(SigPressCls);
  369. } else if(!halIsHeating() && pinState[3]) {
  370. logger(V_HAL, "hal.cpp: Pressure Control opened\n");
  371. pinState[3] = 0;
  372. halStopHeatingTime();
  373. halSendSignal(SigPressOpn);
  374. }
  375. }
  376. /**
  377. *
  378. */
  379. void halStartHeatingTime(void) {
  380. time(&heatingCycleStart);
  381. }
  382. /**
  383. *
  384. */
  385. void halStopHeatingTime(void) {
  386. if (heatingCycleStart != 0) { //only track time if stopwatch was started!
  387. uint64_t timediff = (uint64_t) difftime(time(0), heatingCycleStart);
  388. logger(V_HAL, "Heating time: %f\n", timediff);
  389. totalHeatingTime += timediff;
  390. heatingCycleStart = 0;
  391. }
  392. }
  393. /**
  394. * Method to handle toggle of the proximity sensor
  395. */
  396. void halIntProximity(void) {
  397. delay(DELAY_DEBOUNCE);
  398. if (halProxSensorCovered() && !pinState[2]) {
  399. logger(V_HAL, "IntProximity triggered\n");
  400. pinState[2] = 1;
  401. halSendSignal(SigProxCvrd);
  402. } else if(!halProxSensorCovered() && pinState[2]){
  403. logger(V_HAL, "IntProximity triggered\n");
  404. pinState[2] = 0;
  405. halSendSignal(SigProxOpn);
  406. }
  407. }
  408. /**
  409. * Returns total flow through sensor in ml
  410. */
  411. float halGetFlow(void) {
  412. return flowcnt * FLOW_ML_PULSE;
  413. }
  414. /**
  415. * Returns the total flow time in ms
  416. */
  417. uint16_t halGetFlowTime(void){
  418. return flowtime;
  419. }
  420. /*
  421. * Returns the last total flow through the sensor in ml after reset
  422. */
  423. float halGetLastFlow(void) {
  424. return lastFlowcnt * FLOW_ML_PULSE;
  425. }
  426. /**
  427. * Returns the total flow time in ms before the last reset.
  428. */
  429. uint16_t halGetLastFlowTime(void){
  430. return lastFlowTime;
  431. }
  432. /**
  433. * Resets the Flow counter. Do not call this function manually. It will be automatically triggered
  434. * from the flow reset timer routine!
  435. */
  436. void halResetFlow(void) {
  437. logger(V_HAL, "Flow counter reset, amount so far: %.2f ml\n", halGetFlow());
  438. lastFlowcnt = flowcnt;
  439. flowcnt = 0;
  440. lastFlowTime = flowtime;
  441. flowtime = 0;
  442. flowResetTimer.stop();
  443. flowTimer.stop();
  444. flowResetValue = -1;
  445. if(brewSigFired) {
  446. brewSigFired = false;
  447. halSendSignal(SigBrewOff);
  448. }
  449. }
  450. /**
  451. * Reads the status of the Pressure Control
  452. * @return 1 (true) for closed Pressure Control (heating) and 0 (false) for open
  453. */
  454. bool halIsHeating(void) {
  455. //TODO: eventually rely on the pinState variable instead of reading the pin
  456. //then the state of the pin needs to be set at the very beginning of the initialization
  457. if (digitalRead(PIN_PRESSURE_CTRL) == 0) return true;
  458. else return false;
  459. }
  460. /**
  461. *
  462. */
  463. uint64_t getTotalHeatingTime() {
  464. return totalHeatingTime;
  465. }
  466. /**
  467. * Returns status of the proximity switch
  468. * @return 1 if the proximity switch is covered and 0 if uncovered
  469. */
  470. bool halProxSensorCovered(void) {
  471. if(digitalRead(PIN_PROXIMITY_SENSOR) == 0){
  472. return false;
  473. } else {
  474. return true;
  475. }
  476. }
  477. /**
  478. * Returns the value of the top button Int0 (low active)
  479. * @return LOW or HIGH
  480. */
  481. int halGetInt0(void) {
  482. return digitalRead(PIN_INT0);
  483. }
  484. /**
  485. * Returns the value of the bottom button Int1 (low active)
  486. * @return LOW or HIGH
  487. */
  488. int halGetInt1(void) {
  489. return digitalRead(PIN_INT1);
  490. }
  491. /**
  492. * send Signal to coffee thread
  493. * @param val Integer value assigned to signal
  494. */
  495. void halSendSignal(HalSig val) {
  496. //reboot pi when lower button is pressed long
  497. if (val == SigInt1RlsLong) {
  498. event_trigger("terminate");
  499. sleep(3);
  500. system("reboot");
  501. }
  502. if (halIdle(val)) return;
  503. sigval value = { 0 };
  504. value.sival_int = (int) val;
  505. try {
  506. if (pthread_sigqueue(thread[THREAD_COFFEE], SIGUSR2, value)) {
  507. logger_error("hal.cpp: Failed to queue signal %d %s\n", val, strerror(errno));
  508. //No Signals reach the state machine anymore...
  509. exit(EXIT_FAILURE);
  510. }
  511. } catch (int e) {
  512. logger_error("Whoops.. %d\n", e);
  513. }
  514. }
  515. /**
  516. * Turn machine on
  517. */
  518. void halMachineOn(void) {
  519. halRelaisOn(RELAIS_HEAT);
  520. halRelaisOff(RELAIS_PUMP);
  521. halRelaisOn(RELAIS_POWER);
  522. idleTimer.stop();
  523. if(halIsHeating()) halStartHeatingTime();
  524. logger(V_HAL, "hal.cpp: Turning machine on\n");
  525. }
  526. /**
  527. * Turn machine off
  528. */
  529. void halMachineOff(void) {
  530. halRelaisOff(RELAIS_HEAT);
  531. halRelaisOff(RELAIS_PUMP);
  532. halRelaisOff(RELAIS_POWER);
  533. idleCounter = 0;
  534. idleTimer.start();
  535. halStopHeatingTime();
  536. halWriteBackCache();
  537. logger(V_HAL, "hal.cpp: Turning machine off\n");
  538. }
  539. /**
  540. *
  541. */
  542. void halEnterIdle(void){
  543. logger(V_HAL, "hal.cpp: Entering Idle Mode\n");
  544. idleTimer.stop();
  545. halDisplayOff();
  546. idle = true;
  547. }
  548. /**
  549. *
  550. */
  551. void halLeaveIdle(void) {
  552. idleCounter = 0;
  553. logger(V_HAL, "hal.cpp: Leaving Idle Mode\n");
  554. halDisplayOn();
  555. idleTimer.start();
  556. idle = false;
  557. }
  558. /**
  559. * processes the signal value with respect to the idle state
  560. * returns true, if the current signal should be dropped
  561. */
  562. bool halIdle(HalSig val){
  563. //idle processing filter for signals
  564. if (idle) {
  565. switch (val) {
  566. case SigInt0Psh:
  567. case SigInt1Psh:
  568. return true;
  569. break;
  570. case SigInt0Rls:
  571. case SigInt0RlsLong:
  572. case SigInt1Rls:
  573. case SigRotCCW:
  574. case SigRotCW:
  575. halLeaveIdle();
  576. return true;
  577. break;
  578. case SigPowerUp:
  579. halLeaveIdle();
  580. return false;
  581. break;
  582. default:
  583. return false;
  584. }
  585. } else {
  586. //reset the idle time on every input
  587. halResetIdleTimer();
  588. return false;
  589. }
  590. }
  591. /**
  592. *
  593. */
  594. void halResetIdleTimer(void) {
  595. idleCounter = 0;
  596. }
  597. /**
  598. * Wrapper function to turn the pump on.
  599. */
  600. void halPumpOn(){
  601. halRelaisOn(RELAIS_PUMP);
  602. }
  603. /**
  604. * Wrapper function to turn the pump off
  605. * and to measure how long the pump is running
  606. */
  607. void halPumpOff(void){
  608. halRelaisOff(RELAIS_PUMP);
  609. }
  610. /**
  611. * Function to calculate the difference between two timespecs
  612. */
  613. void timespec_diff(timespec *start, timespec *stop, timespec *result) {
  614. long int secDiff = stop->tv_sec - start->tv_sec;
  615. long int nsecDiff = stop->tv_nsec - start->tv_nsec;
  616. if (secDiff > 0) {
  617. if (nsecDiff >= 0) {
  618. result->tv_sec = secDiff;
  619. result->tv_nsec = nsecDiff;
  620. } else if (nsecDiff < 0) {
  621. result->tv_sec = --secDiff;
  622. result->tv_nsec = 1000000000 + nsecDiff;
  623. }
  624. } else if (secDiff < 0) {
  625. if (nsecDiff >= 0) {
  626. result->tv_sec = ++secDiff;
  627. result->tv_nsec = -(1000000000 - nsecDiff);
  628. } else if (nsecDiff < 0) {
  629. result->tv_sec = secDiff;
  630. result->tv_nsec = nsecDiff;
  631. }
  632. } else if (secDiff == 0){
  633. result->tv_sec = secDiff;
  634. result->tv_nsec = nsecDiff;
  635. }
  636. return;
  637. }
  638. /*
  639. * Handler for Termination of the hal
  640. */
  641. void halTerminate(event_t *event){
  642. halStopHeatingTime();
  643. halWriteBackCache();
  644. }
  645. /*
  646. * writing back non volatile variables of the hal to the database: totalHeatingTime
  647. */
  648. void halWriteBackCache(){
  649. if (sqlSetConf(CFGHeatingTime, totalHeatingTime)) {
  650. logger_error("hal.cpp: Couldn't write heating time to database");
  651. return;
  652. }
  653. logger(V_BREW, "Writing back heating time: %lld sec\n", totalHeatingTime);
  654. }