hal.cpp 16 KB

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