hal.cpp 16 KB

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