hal.cpp 16 KB

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