A small USV for ALIX boards with i2c support
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
5.3KB

  1. /***************************************************************************
  2. * Copyright (C) 05/2009 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <stdio.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <sys/socket.h>
  23. #include "configfile.h"
  24. #include "event.h"
  25. #include "logging.h"
  26. #include "unixsocket.h"
  27. #include "usvdevice.h"
  28. #define DEFAULT_SOCKET "alix-usvd.sock"
  29. #define SENDMAIL "/usr/sbin/sendmail -t"
  30. enum {
  31. STATE_IDLE = 0x01,
  32. STATE_TEST = 0x02,
  33. STATE_CHARGE = 0x04,
  34. STATE_DISCHARGE = 0x08,
  35. STATE_POWEROFF = 0x10,
  36. };
  37. static struct event_fd *listen_event;
  38. static struct event_timeout *timeout_event;
  39. static const char *mail_from;
  40. static const char *mail_to;
  41. static char * state2str(int state)
  42. {
  43. switch (state) {
  44. case STATE_IDLE:
  45. return "IDLE";
  46. case STATE_TEST:
  47. return "TEST";
  48. case STATE_CHARGE:
  49. return "CHARGE";
  50. case STATE_DISCHARGE:
  51. return "DISCHARGE";
  52. case STATE_POWEROFF:
  53. return "POWEROFF";
  54. default:
  55. return "UNKNOWN";
  56. }
  57. }
  58. static int str2state(char *buf)
  59. {
  60. int state = -1;
  61. if (strncasecmp(buf, "IDLE", 4) == 0)
  62. state = STATE_IDLE;
  63. else if (strncasecmp(buf, "TEST", 4) == 0)
  64. state = STATE_TEST;
  65. else if (strncasecmp(buf, "CHARGE", 6) == 0)
  66. state = STATE_CHARGE;
  67. else if (strncasecmp(buf, "DISCHARGE", 9) == 0)
  68. state = STATE_DISCHARGE;
  69. else if (strncasecmp(buf, "POWEROFF", 8) == 0)
  70. state = STATE_POWEROFF;
  71. return state;
  72. }
  73. static int usvstate_update(int state, struct usvdev_status *status)
  74. {
  75. static int old_state;
  76. if (status != NULL)
  77. state = status->state;
  78. if (state == old_state)
  79. return state;
  80. log_print(LOG_INFO, "usv state changed: %s => %s", state2str(old_state), state2str(state));
  81. if (mail_to != NULL) {
  82. FILE *mail = popen(SENDMAIL, "w");
  83. if (mail != NULL) {
  84. fprintf(mail, "From: %s\n", mail_from);
  85. fprintf(mail, "To: %s\n", mail_to);
  86. fprintf(mail, "Subject: alix-usvd state change: %s => %s\n\n",
  87. state2str(old_state), state2str(state));
  88. if (status != NULL) {
  89. fprintf(mail, "Current USV status:\n");
  90. fprintf(mail, "Ibat: %1.3lf mA\nUbat: %2.3lf V\nUin : %2.3lf V\n\n",
  91. status->ibat / 1000.0, status->ubat / 1000.0, status->uin / 1000.0);
  92. }
  93. fprintf(mail, "Faithfully yours, etc.\n");
  94. fclose(mail);
  95. }
  96. }
  97. old_state = state;
  98. return state;
  99. }
  100. static int unix_read_cb(int fd, void *privdata)
  101. {
  102. char buf[64];
  103. int len = read(fd, buf, sizeof(buf));
  104. if (len < 0)
  105. return -1;
  106. int new_state = str2state(buf);
  107. if (new_state != -1) {
  108. usvdev_setstate(new_state);
  109. new_state = usvstate_update(new_state, NULL);
  110. int len = snprintf(buf, sizeof(buf), "%s", state2str(new_state));
  111. write(fd, buf, len);
  112. } else if (strncasecmp(buf, "status", 6) == 0) {
  113. struct usvdev_status status;
  114. if (usvdev_getstatus(&status) == 0)
  115. usvstate_update(-1, &status);
  116. int len = snprintf(buf, sizeof(buf), "%s:%d:%d:%d",
  117. state2str(status.state),
  118. (short)status.ibat, status.ubat, status.uin);
  119. write(fd, buf, len);
  120. }
  121. close(fd);
  122. return -1;
  123. }
  124. static int status_interval(void *privdata)
  125. {
  126. struct usvdev_status status;
  127. if (usvdev_getstatus(&status) < 0)
  128. return 0;
  129. usvstate_update(-1, &status);
  130. return 0;
  131. }
  132. static int unix_accept_cb(int fd, void *privdata)
  133. {
  134. int con = accept(fd, NULL, NULL);
  135. if (con < 0) {
  136. log_print(LOG_ERROR, "unix_accept_cb: accept()");
  137. return 0;
  138. }
  139. event_add_readfd(NULL, con, unix_read_cb, NULL);
  140. return 0;
  141. }
  142. int usvstate_init(void)
  143. {
  144. const char *socket_path = config_get_string("global", "socket", DEFAULT_SOCKET);
  145. int sockfd = unix_listen(socket_path);
  146. if (sockfd < 0)
  147. return -1;
  148. listen_event = event_add_readfd(NULL, sockfd, unix_accept_cb, NULL);
  149. if (listen_event == NULL) {
  150. close(sockfd);
  151. return -1;
  152. }
  153. int interval = config_get_int("global", "check-interval", 60);
  154. struct timeval tv = { .tv_sec = interval, .tv_usec = 0 };
  155. timeout_event = event_add_timeout(&tv, status_interval, NULL);
  156. mail_from = config_get_string("alerts", "mail-from", NULL);
  157. mail_to = config_get_string("alerts", "mail-to", NULL);
  158. usvstate_update(-1, NULL);
  159. return 0;
  160. }
  161. int usvstate_close(void)
  162. {
  163. event_remove_timeout(timeout_event);
  164. event_remove_fd(listen_event);
  165. close(event_get_fd(listen_event));
  166. return 0;
  167. }