apcupsd-ups: ignore generated files
[networkupstools/kirr.git] / drivers / apcsmart.c
blob018b29dd63e46db01786b55ec4ffdce5ed75403c
1 /*
2 * apcsmart.c - driver for APC smart protocol units (originally "newapc")
4 * Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
5 * (C) 2000 Nigel Metheringham <Nigel.Metheringham@Intechnology.co.uk>
6 * (C) 2011+ Michal Soltys <soltys@ziu.info>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <sys/types.h>
24 #include <sys/file.h>
25 #include <regex.h>
26 #include <ctype.h>
27 #include <strings.h> /* strcasecmp() */
29 #include "main.h"
30 #include "serial.h"
31 #include "timehead.h"
33 #include "apcsmart.h"
34 #include "apcsmart_tabs.h"
36 /* driver description structure */
37 upsdrv_info_t upsdrv_info = {
38 DRIVER_NAME,
39 DRIVER_VERSION,
40 "Russell Kroll <rkroll@exploits.org>\n"
41 "Nigel Metheringham <Nigel.Metheringham@Intechnology.co.uk>\n"
42 "Michal Soltys <soltys@ziu.info>",
43 DRV_STABLE,
44 { &apc_tab_info, NULL }
47 static int ups_status = 0;
49 /* some forwards */
51 static int sdcmd_S(const void *);
52 static int sdcmd_AT(const void *);
53 static int sdcmd_K(const void *);
54 static int sdcmd_Z(const void *);
55 static int sdcmd_CS(const void *);
58 * following table *must* match order defined in the man page, namely:
59 * 0:: soft hibernate (*S*)
60 * 1:: hard hibernate (*@*)
61 * 2:: delayed poweroff (*K*)
62 * 3:: instant poweroff (*Z*)
63 * 4:: "force OB hack" (*CS*)
66 static int (*sdlist[])(const void *) = {
67 sdcmd_S,
68 sdcmd_AT,
69 sdcmd_K,
70 sdcmd_Z,
71 sdcmd_CS,
74 #define SDIDX_AT 1
77 * note: both lookup functions MUST be used after variable detection is
78 * completed - that is after deprecate_vars() call; the general reason for this
79 * is 1:n and n:1 nut <-> apc mappings, which are not determined prior to the
80 * detection
82 static apc_vartab_t *vt_lookup_char(char cmdchar)
84 int i;
86 for (i = 0; apc_vartab[i].name != NULL; i++)
87 if ((apc_vartab[i].flags & APC_PRESENT) &&
88 apc_vartab[i].cmd == cmdchar)
89 return &apc_vartab[i];
91 return NULL;
94 static apc_vartab_t *vt_lookup_name(const char *var)
96 int i;
98 for (i = 0; apc_vartab[i].name != NULL; i++)
99 if ((apc_vartab[i].flags & APC_PRESENT) &&
100 !strcasecmp(apc_vartab[i].name, var))
101 return &apc_vartab[i];
103 return NULL;
106 static const char *prtchr(char x)
108 static size_t curr = 24;
109 static char info[32];
111 curr = (curr + 8) & 0x1F;
112 snprintf(info + curr, 8, isprint(x) ? "%c" : "0x%02x", x);
114 return info + curr;
117 static int rexhlp(const char *rex, const char *val)
119 static const char *empty = "";
120 int ret;
121 regex_t mbuf;
123 if (!rex || !*rex)
124 return 1;
125 if (!val)
126 val = empty;
127 regcomp(&mbuf, rex, REG_EXTENDED|REG_NOSUB);
128 ret = regexec(&mbuf, val, 0, 0, 0);
129 regfree(&mbuf);
130 return !ret;
133 /* convert APC formatting to NUT formatting */
134 /* TODO: handle errors better */
135 static const char *convert_data(apc_vartab_t *vt, const char *upsval)
137 static char temp[APC_LBUF];
138 int tval;
140 /* this should never happen */
141 if (strlen(upsval) >= sizeof(temp)) {
142 logx(LOG_CRIT, "the length of [%s] is too big", vt->name);
143 memcpy(temp, upsval, sizeof(temp) - 1);
144 temp[sizeof(temp) - 1] = '\0';
145 return temp;
148 switch (vt->flags & APC_F_MASK) {
149 case APC_F_PERCENT:
150 case APC_F_VOLT:
151 case APC_F_AMP:
152 case APC_F_CELSIUS:
153 case APC_F_HEX:
154 case APC_F_DEC:
155 case APC_F_SECONDS:
156 case APC_F_LEAVE:
157 /* no conversion for any of these */
158 strcpy(temp, upsval);
159 return temp;
161 case APC_F_HOURS:
162 /* convert to seconds */
164 tval = 60 * 60 * strtol(upsval, NULL, 10);
166 snprintf(temp, sizeof(temp), "%d", tval);
167 return temp;
169 case APC_F_MINUTES:
170 /* Convert to seconds - NUT standard time measurement */
171 tval = 60 * strtol(upsval, NULL, 10);
172 /* Ignore errors - there's not much we can do */
173 snprintf(temp, sizeof(temp), "%d", tval);
174 return temp;
176 case APC_F_REASON:
177 switch (upsval[0]) {
178 case 'R': return "unacceptable utility voltage rate of change";
179 case 'H': return "high utility voltage";
180 case 'L': return "low utility voltage";
181 case 'T': return "line voltage notch or spike";
182 case 'O': return "no transfers yet since turnon";
183 case 'S': return "simulated power failure or UPS test";
184 default:
185 strcpy(temp, upsval);
186 return temp;
190 /* this should never happen */
191 logx(LOG_CRIT, "unable to convert [%s]", vt->name);
192 strcpy(temp, upsval);
193 return temp;
196 /* report differences if tcsetattr != tcgetattr, return otherwise */
199 * Aix compatible names
201 #if defined(VWERSE) && !defined(VWERASE)
202 #define VWERASE VWERSE
203 #endif /* VWERSE && !VWERASE */
205 #if defined(VDISCRD) && !defined(VDISCARD)
206 #define VDISCARD VDISCRD
207 #endif /* VDISCRD && !VDISCARD */
209 static void apc_ser_diff(struct termios *tioset, struct termios *tioget)
211 size_t i;
212 const char dir[] = { 's', 'g' };
213 struct termios *tio[] = { tioset, tioget };
214 struct cchar {
215 const char *name;
216 unsigned int sub;
218 const struct cchar cchars1[] = {
219 #ifdef VDISCARD
220 { "discard", VDISCARD },
221 #endif
222 #ifdef VDSUSP
223 { "dsusp", VDSUSP },
224 #endif
225 { "eof", VEOF },
226 { "eol", VEOL },
227 { "eol2", VEOL2 },
228 { "erase", VERASE },
229 #ifdef VINTR
230 { "intr", VINTR },
231 #endif
232 { "kill", VKILL },
233 { "lnext", VLNEXT },
234 { "min", VMIN },
235 { "quit", VQUIT },
236 #ifdef VREPRINT
237 { "reprint", VREPRINT },
238 #endif
239 { "start", VSTART },
240 #ifdef VSTATUS
241 { "status", VSTATUS },
242 #endif
243 { "stop", VSTOP },
244 { "susp", VSUSP },
245 { "time", VTIME },
246 { "werase", VWERASE },
247 { NULL },
248 }, *cp;
250 /* clear status flags so that they don't affect our binary compare */
251 #if defined(PENDIN) || defined(FLUSHO)
252 for (i = 0; i < sizeof(tio)/sizeof(tio[0]); i++) {
253 #ifdef PENDIN
254 tio[i]->c_lflag &= ~PENDIN;
255 #endif
256 #ifdef FLUSHO
257 tio[i]->c_lflag &= ~FLUSHO;
258 #endif
260 #endif /* defined(PENDIN) || defined(FLUSHO) */
262 if (!memcmp(tio[0], tio[1], sizeof(*tio[0])))
263 return;
265 upslogx(LOG_NOTICE, "%s: device reports different attributes than requested", device_path);
268 * According to the manual the most common problem is mis-matched
269 * combinations of input and output baud rates. If the combination is
270 * not supported then neither are changed. This should not be a
271 * problem here since we set them both to the same extremely common
272 * rate of 2400.
275 for (i = 0; i < sizeof(tio)/sizeof(tio[0]); i++) {
276 upsdebugx(1, "tc%cetattr(): gfmt1:cflag=%x:iflag=%x:lflag=%x:oflag=%x:", dir[i],
277 (unsigned int) tio[i]->c_cflag, (unsigned int) tio[i]->c_iflag,
278 (unsigned int) tio[i]->c_lflag, (unsigned int) tio[i]->c_oflag);
279 for (cp = cchars1; cp->name; ++cp)
280 upsdebugx(1, "\t%s=%x:", cp->name, tio[i]->c_cc[cp->sub]);
281 upsdebugx(1, "\tispeed=%d:ospeed=%d", (int) cfgetispeed(tio[i]), (int) cfgetospeed(tio[i]));
285 static void apc_ser_set(void)
287 struct termios tio, tio_chk;
288 char *val;
291 * this must be called before the rest, as ser_set_speed() performs
292 * early initialization of the port, apart from changing speed
294 ser_set_speed(upsfd, device_path, B2400);
296 val = getval("cable");
297 if (val && !strcasecmp(val, ALT_CABLE_1)) {
298 if (ser_set_dtr(upsfd, 1) == -1)
299 fatx("ser_set_dtr(%s) failed", device_path);
300 if (ser_set_rts(upsfd, 0) == -1)
301 fatx("ser_set_rts(%s) failed", device_path);
305 * that's all if we want simple non canonical mode; this is meant as a
306 * compatibility measure for windows systems and perhaps some
307 * problematic serial cards/converters
309 if ((val = getval("ttymode")) && !strcmp(val, "raw"))
310 return;
312 memset(&tio, 0, sizeof(tio));
313 errno = 0;
315 if (tcgetattr(upsfd, &tio))
316 fate("tcgetattr(%s)", device_path);
318 /* set port mode: common stuff, canonical processing */
320 tio.c_cflag |= (CS8 | CLOCAL | CREAD);
322 tio.c_lflag |= ICANON;
323 #ifdef NOKERNINFO
324 tio.c_lflag |= NOKERNINFO;
325 #endif
326 tio.c_lflag &= ~(ISIG | IEXTEN);
328 tio.c_iflag |= (IGNCR | IGNPAR);
329 tio.c_iflag &= ~(IXON | IXOFF);
331 tio.c_cc[VEOL] = '*'; /* specially handled in apc_read() */
332 #ifdef _POSIX_VDISABLE
333 tio.c_cc[VERASE] = _POSIX_VDISABLE;
334 tio.c_cc[VKILL] = _POSIX_VDISABLE;
335 tio.c_cc[VEOF] = _POSIX_VDISABLE;
336 tio.c_cc[VEOL2] = _POSIX_VDISABLE;
337 #endif
339 if (tcflush(upsfd, TCIOFLUSH))
340 fate("tcflush(%s)", device_path);
343 * warn:
344 * Note, that tcsetattr() returns success if /any/ of the requested
345 * changes could be successfully carried out. Thus the more complicated
346 * test.
348 if (tcsetattr(upsfd, TCSANOW, &tio))
349 fate("tcsetattr(%s)", device_path);
351 memset(&tio_chk, 0, sizeof(tio_chk));
352 if (tcgetattr(upsfd, &tio_chk))
353 fate("tcgetattr(%s)", device_path);
355 apc_ser_diff(&tio, &tio_chk);
358 static void ups_status_set(void)
360 status_init();
361 if (ups_status & APC_STAT_CAL)
362 status_set("CAL"); /* calibration */
363 if (ups_status & APC_STAT_TRIM)
364 status_set("TRIM"); /* SmartTrim */
365 if (ups_status & APC_STAT_BOOST)
366 status_set("BOOST"); /* SmartBoost */
367 if (ups_status & APC_STAT_OL)
368 status_set("OL"); /* on line */
369 if (ups_status & APC_STAT_OB)
370 status_set("OB"); /* on battery */
371 if (ups_status & APC_STAT_OVER)
372 status_set("OVER"); /* overload */
373 if (ups_status & APC_STAT_LB)
374 status_set("LB"); /* low battery */
375 if (ups_status & APC_STAT_RB)
376 status_set("RB"); /* replace batt */
378 if (ups_status == 0)
379 status_set("OFF");
381 status_commit();
384 static void alert_handler(char ch)
386 switch (ch) {
387 case '!': /* clear OL, set OB */
388 debx(1, "OB");
389 ups_status &= ~APC_STAT_OL;
390 ups_status |= APC_STAT_OB;
391 break;
393 case '$': /* clear OB, set OL */
394 debx(1, "OL");
395 ups_status &= ~APC_STAT_OB;
396 ups_status |= APC_STAT_OL;
397 break;
399 case '%': /* set LB */
400 debx(1, "LB");
401 ups_status |= APC_STAT_LB;
402 break;
404 case '+': /* clear LB */
405 debx(1, "not LB");
406 ups_status &= ~APC_STAT_LB;
407 break;
409 case '#': /* set RB */
410 debx(1, "RB");
411 ups_status |= APC_STAT_RB;
412 break;
414 case '?': /* set OVER */
415 debx(1, "OVER");
416 ups_status |= APC_STAT_OVER;
417 break;
419 case '=': /* clear OVER */
420 debx(1, "not OVER");
421 ups_status &= ~APC_STAT_OVER;
422 break;
424 default:
425 debx(1, "got 0x%02x (unhandled)", ch);
426 break;
429 ups_status_set();
433 * we need a tiny bit different processing due to '*' and canonical mode; the
434 * function is subtly different from generic ser_get_line_alert()
436 #define apc_read(b, l, f) apc_read_i(b, l, f, __func__, __LINE__)
437 static int apc_read_i(char *buf, size_t buflen, int flags, const char *fn, unsigned int ln)
439 const char *iset = IGN_CHARS, *aset = "";
440 size_t count = 0;
441 int i, ret, sec = 3, usec = 0;
442 char temp[APC_LBUF];
444 if (upsfd == -1)
445 return 0;
446 if (flags & SER_D0) {
447 sec = 0; usec = 0;
449 if (flags & SER_DX) {
450 sec = 0; usec = 200000;
452 if (flags & SER_D1) {
453 sec = 1; usec = 500000;
455 if (flags & SER_D3) {
456 sec = 3; usec = 0;
458 if (flags & SER_AA) {
459 iset = IGN_AACHARS;
460 aset = ALERT_CHARS;
462 if (flags & SER_CC) {
463 iset = IGN_CCCHARS;
464 aset = "";
465 sec = 6; usec = 0;
467 if (flags & SER_CS) {
468 iset = IGN_CSCHARS;
469 aset = "";
470 sec = 6; usec = 0;
473 memset(buf, '\0', buflen);
475 while (count < buflen - 1) {
476 errno = 0;
477 ret = select_read(upsfd, temp, sizeof(temp), sec, usec);
479 /* partial timeout (non-canon only paranoid check) */
480 if (ret == 0 && count) {
481 ser_comm_fail("serial port partial timeout: %u(%s)", ln, fn);
482 return -1;
484 /* error or no timeout allowed */
485 if (ret < 0 || (ret == 0 && !(flags & SER_TO))) {
486 if (ret)
487 ser_comm_fail("serial port read error: %u(%s): %s", ln, fn, strerror(errno));
488 else
489 ser_comm_fail("serial port read timeout: %u(%s)", ln, fn);
490 return ret;
492 /* ok, timeout is acceptable */
493 if (ret == 0 && (flags & SER_TO)) {
495 * but it doesn't imply ser_comm_good
497 * for example we might be in comm_fail condition,
498 * trying to "nudge" the UPS with some command
499 * obviously expecting timeout if the comm is still
500 * lost. This would result with filling logs with
501 * confusing comm lost/comm re-established pairs due to
502 * successful serial writes
504 return 0;
507 /* parse input */
508 for (i = 0; i < ret; i++) {
509 /* overflow read */
510 if (count == buflen - 1) {
511 ser_comm_fail("serial port read overflow: %u(%s)", ln, fn);
512 tcflush(upsfd, TCIFLUSH);
513 return -1;
515 /* standard "line received" condition */
516 if (temp[i] == ENDCHAR) {
517 ser_comm_good();
518 return count;
521 * '*' is set as a secondary EOL; convert to 'OK' only as a
522 * reply to shutdown command in sdok(); otherwise next
523 * select_read() will continue normally
525 if ((flags & SER_HA) && temp[i] == '*') {
527 * a bit paranoid, but remember '*' is not real EOL;
528 * there could be some firmware in existence, that
529 * would send both string: 'OK\n' and alert: '*'.
530 * Just in case, try to flush the input with small 1 sec.
531 * timeout
533 memset(buf, '\0', buflen);
534 errno = 0;
535 ret = select_read(upsfd, temp, sizeof(temp), 1, 0);
536 if (ret < 0) {
537 ser_comm_fail("serial port read error: %u(%s): %s", ln, fn, strerror(errno));
538 return ret;
540 buf[0] = 'O';
541 buf[1] = 'K';
542 ser_comm_good();
543 return 2;
545 /* ignore set */
546 if (strchr(iset, temp[i]) || temp[i] == '*') {
547 continue;
549 /* alert set */
550 if (strchr(aset, temp[i])) {
551 alert_handler(temp[i]);
552 continue;
555 buf[count++] = temp[i];
559 ser_comm_good();
560 return count;
563 #define apc_write(code) apc_write_i(code, __func__, __LINE__)
564 static int apc_write_i(unsigned char code, const char *fn, unsigned int ln)
566 int ret;
567 errno = 0;
569 if (upsfd == -1)
570 return 0;
572 ret = ser_send_char(upsfd, code);
574 * Formally any write() sould never return 0, if the count != 0. For
575 * the sake of handling any obscure nonsense, we consider such return
576 * as a failure - thus <= condition; either way, LE is pretty hard
577 * condition hardly ever happening;
579 if (ret <= 0)
580 ser_comm_fail("serial port write error: %u(%s): %s", ln, fn, strerror(errno));
582 return ret;
586 * We have to watch out for NA, here;
587 * This is generally safe, as otherwise we will just timeout. The reason we do
588 * it, is that under certain conditions an ups might respond with NA for
589 * something it would normally handle (e.g. calling @ while being in powered
590 * off or hibernated state. If we keep sending the "arguments" after getting
591 * NA, they will be interpreted as commands, which is quite a bug :)
592 * Furthermore later flushes might not work properly, if the reply to those
593 * commands are generated with some delay.
595 * We also set errno to something usable, so outside upslog calls don't output
596 * confusing "success".
598 #define apc_write_long(code) apc_write_long_i(code, __func__, __LINE__)
599 static int apc_write_long_i(const char *code, const char *fn, unsigned int ln)
601 char temp[APC_LBUF];
602 int ret;
604 ret = apc_write_i(*code, fn, ln);
605 if (ret != 1)
606 return ret;
607 /* peek for the answer - anything at this point is failure */
608 ret = apc_read(temp, sizeof(temp), SER_DX|SER_TO);
609 if (ret) {
610 errno = ECANCELED;
611 return -1;
614 ret = ser_send_pace(upsfd, 50000, "%s", code + 1);
615 if (ret >= 0)
616 ret++;
617 /* see remark in plain apc_write() */
618 if (ret != (int)strlen(code))
619 ser_comm_fail("serial port write error: %u(%s): %s", ln, fn, strerror(errno));
620 return ret;
623 #define apc_write_rep(code) apc_write_rep_i(code, __func__, __LINE__)
624 static int apc_write_rep_i(unsigned char code, const char *fn, unsigned int ln)
626 char temp[APC_LBUF];
627 int ret;
629 ret = apc_write_i(code, fn, ln);
630 if (ret != 1)
631 return ret;
632 /* peek for the answer - anything at this point is failure */
633 ret = apc_read(temp, sizeof(temp), SER_DX|SER_TO);
634 if (ret) {
635 errno = ECANCELED;
636 return -1;
638 usleep(1300000);
640 ret = apc_write_i(code, fn, ln);
641 if (ret >= 0)
642 ret++;
643 return ret;
646 /* all flags other than SER_AA are ignored */
647 static void apc_flush(int flags)
649 char temp[APC_LBUF];
651 if (flags & SER_AA) {
652 tcflush(upsfd, TCOFLUSH);
653 /* TODO */
654 while(apc_read(temp, sizeof(temp), SER_D0|SER_TO|SER_AA) > 0);
655 } else {
656 tcflush(upsfd, TCIOFLUSH);
657 /* tcflush(upsfd, TCIFLUSH); */
658 /* while(apc_read(temp, sizeof(temp), SER_D0|SER_TO)); */
662 /* apc specific wrappers around set/del info - to handle "packed" variables */
663 void apc_dstate_delinfo(apc_vartab_t *vt, int skip)
665 char name[vt->nlen0], *nidx;
666 int c;
668 /* standard not packed var */
669 if (!(vt->flags & APC_PACK)) {
670 dstate_delinfo(vt->name);
671 return;
674 strcpy(name, vt->name);
675 nidx = strstr(name,".0.") + 1;
677 for (c = skip; c < vt->cnt; c++) {
678 *nidx = (char)('1' + c);
679 dstate_delinfo(name);
682 vt->cnt = 0;
685 void apc_dstate_setinfo(apc_vartab_t *vt, const char *upsval)
687 char name[vt->nlen0], *nidx;
688 char temp[strlen(upsval) + 1], *vidx[APC_PACK_MAX], *com, *curr;
689 int c;
691 /* standard not packed var */
692 if (!(vt->flags & APC_PACK)) {
693 dstate_setinfo(vt->name, "%s", convert_data(vt, upsval));
694 return;
697 /* we have to set proper name for dstate_setinfo() calls */
698 strcpy(name, vt->name);
699 nidx = strstr(name,".0.") + 1;
701 /* split the value string */
702 strcpy(temp, upsval);
703 curr = temp;
704 c = 0;
705 do {
706 vidx[c] = curr;
707 com = strchr(curr, ',');
708 if (com) {
709 curr = com + 1;
710 *com = '\0';
712 } while(++c < APC_PACK_MAX && com);
715 * unlikely, but keep things tidy - remove leftover values, if
716 * subsequent read returns less
718 if (vt->cnt > c)
719 apc_dstate_delinfo(vt, c);
721 /* unlikely - warn user if we have more than APC_PACK_MAX fields */
722 if (c == APC_PACK_MAX && com)
723 upslogx(LOG_WARNING,
724 "packed variable %s [%s] longer than %d fields,\n"
725 "ignoring remaining fields",
726 vt->name, prtchr(vt->cmd), c);
728 vt->cnt = c;
730 while (c-- > 0) {
731 *nidx = (char)('1' + c);
732 if (*vidx[c])
733 dstate_setinfo(name, "%s", convert_data(vt, vidx[c]));
734 else
735 dstate_setinfo(name, "N/A");
739 static const char *preread_data(apc_vartab_t *vt)
741 int ret;
742 static char temp[APC_LBUF];
744 debx(1, "%s [%s]", vt->name, prtchr(vt->cmd));
746 apc_flush(0);
747 ret = apc_write(vt->cmd);
749 if (ret != 1)
750 return 0;
752 ret = apc_read(temp, sizeof(temp), SER_TO);
754 if (ret < 1 || !strcmp(temp, "NA")) {
755 if (ret >= 0)
756 logx(LOG_ERR, "%s [%s] timed out or not supported", vt->name, prtchr(vt->cmd));
757 return 0;
760 return temp;
763 static int poll_data(apc_vartab_t *vt)
765 char temp[APC_LBUF];
767 if (!(vt->flags & APC_PRESENT))
768 return 1;
770 debx(1, "%s [%s]", vt->name, prtchr(vt->cmd));
772 apc_flush(SER_AA);
773 if (apc_write(vt->cmd) != 1)
774 return 0;
775 if (apc_read(temp, sizeof(temp), SER_AA) < 1)
776 return 0;
778 /* automagically no longer supported by the hardware somehow */
779 if (!strcmp(temp, "NA")) {
780 logx(LOG_WARNING, "verified variable %s [%s] returned NA, removing", vt->name, prtchr(vt->cmd));
781 vt->flags &= ~APC_PRESENT;
782 apc_dstate_delinfo(vt, 0);
783 } else
784 apc_dstate_setinfo(vt, temp);
786 return 1;
789 static int update_status(void)
791 int ret;
792 char buf[APC_LBUF];
794 debx(1, "[%s]", prtchr(APC_STATUS));
796 apc_flush(SER_AA);
797 if (apc_write(APC_STATUS) != 1)
798 return 0;
799 ret = apc_read(buf, sizeof(buf), SER_AA);
801 if ((ret < 1) || (!strcmp(buf, "NA"))) {
802 if (ret >= 0)
803 logx(LOG_WARNING, "failed");
804 return 0;
807 ups_status = strtol(buf, 0, 16) & 0xff;
808 ups_status_set();
810 return 1;
814 * two informative functions, to not redo the same thing in few places
817 static inline void confirm_cv(unsigned char cmd, const char *tag, const char *name)
819 upsdebugx(1, "%s [%s] - %s supported", name, prtchr(cmd), tag);
822 static inline void warn_cv(unsigned char cmd, const char *tag, const char *name)
824 if (tag && name)
825 upslogx(LOG_WARNING, "%s [%s] - %s invalid", name, prtchr(cmd), tag);
826 else
827 upslogx(LOG_WARNING, "[%s] unrecognized", prtchr(cmd));
830 static void var_string_setup(apc_vartab_t *vt)
833 * handle special data for our two strings; note - STRING variables
834 * cannot be PACK at the same time
836 if (vt->flags & APC_STRING) {
837 dstate_setflags(vt->name, ST_FLAG_RW | ST_FLAG_STRING);
838 dstate_setaux(vt->name, APC_STRLEN);
839 vt->flags |= APC_RW;
843 static int var_verify(apc_vartab_t *vt)
845 const char *temp;
847 if (vt->flags & APC_MULTI) {
848 /* APC_MULTI are handled by deprecate_vars() */
849 vt->flags |= APC_PRESENT;
850 return -1;
853 temp = preread_data(vt);
854 /* no conversion here, validator should operate on raw values */
855 if (!temp || !rexhlp(vt->regex, temp)) {
856 warn_cv(vt->cmd, "variable", vt->name);
857 return 0;
860 vt->flags |= APC_PRESENT;
861 apc_dstate_setinfo(vt, temp);
862 var_string_setup(vt);
864 confirm_cv(vt->cmd, "variable", vt->name);
866 return 1;
870 * This function iterates over vartab, deprecating nut<->apc 1:n and n:1
871 * variables. We prefer earliest present variable. All the other ones must be
872 * marked as not present (which implies deprecation).
873 * This pass is requried after completion of all protocol_verify() and/or
874 * legacy_verify() calls.
876 static void deprecate_vars(void)
878 int i, j;
879 const char *temp;
880 apc_vartab_t *vt, *vtn;
882 for (i = 0; apc_vartab[i].name != NULL; i++) {
883 vt = &apc_vartab[i];
884 if (!(vt->flags & APC_MULTI) || !(vt->flags & APC_PRESENT)) {
886 * a) not interesting, or
887 * b) not marked as present earlier, or already handled
889 continue;
891 /* pre-read data, we have to verify it */
892 temp = preread_data(vt);
893 /* no conversion here, validator should operate on raw values */
894 if (!temp || !rexhlp(vt->regex, temp)) {
895 vt->flags &= ~APC_PRESENT;
897 warn_cv(vt->cmd, "variable combination", vt->name);
898 continue;
901 /* multi & present, deprecate all the remaining ones */
902 for (j = i + 1; apc_vartab[j].name != NULL; j++) {
903 vtn = &apc_vartab[j];
904 if (strcmp(vtn->name, vt->name) && vtn->cmd != vt->cmd)
905 continue;
906 vtn->flags &= ~APC_PRESENT;
909 apc_dstate_setinfo(vt, temp);
910 var_string_setup(vt);
912 confirm_cv(vt->cmd, "variable combination", vt->name);
916 static void apc_getcaps(int qco)
918 const char *ptr, *entptr;
919 char upsloc, temp[APC_LBUF], cmd, loc, etmp[APC_SBUF], *endtemp;
920 int nument, entlen, i, matrix, ret, valid;
921 apc_vartab_t *vt;
924 * If we can do caps, then we need the Firmware revision which has the
925 * locale descriptor as the last character (ugh); this is valid for
926 * both 'V' and 'b' commands.
928 ptr = dstate_getinfo("ups.firmware");
929 if (ptr)
930 upsloc = ptr[strlen(ptr) - 1];
931 else
932 upsloc = 0;
934 /* get capability string */
935 apc_flush(0);
936 if (apc_write(APC_CAPS) != 1)
937 return;
940 * note - apc_read() needs larger timeout grace (not a problem w.r.t.
941 * to nut's timing, as it's done only during setup) and different
942 * ignore set due to certain characters like '#' being received
944 ret = apc_read(temp, sizeof(temp), SER_CC|SER_TO);
946 if ((ret < 1) || (!strcmp(temp, "NA"))) {
949 * Early Smart-UPS not as smart as the later ones ...
950 * this should never happen on properly functioning hardware -
951 * as capability support was reported earlier
953 if (ret >= 0)
954 upslogx(LOG_WARNING, "APC cannot do capabilities but said it could !");
955 return;
958 /* recv always puts a \0 at the end, so this is safe */
959 /* however it assumes a zero byte cannot be embedded */
960 endtemp = &temp[0] + strlen(temp);
962 if (temp[0] != '#') {
963 upslogx(LOG_WARNING, "unknown capability start char [%c] !", temp[0]);
964 upsdebugx(1, "please report this caps string: %s", temp);
965 return;
968 if (temp[1] == '#') { /* Matrix-UPS */
969 ptr = &temp[0];
970 matrix = 1;
971 } else {
972 ptr = &temp[1];
973 matrix = 0;
976 /* command char, location, # of entries, entry length */
978 while (ptr[0] != '\0') {
979 if (matrix)
980 ptr += 2; /* jump over repeating ## */
982 /* check for idiocy */
983 if (ptr >= endtemp) {
984 /* if we expected this, just ignore it */
985 if (qco)
986 return;
987 fatalx(EXIT_FAILURE, "capability string has overflowed, please report this error !");
990 cmd = ptr[0];
991 loc = ptr[1];
992 nument = ptr[2] - 48;
993 entlen = ptr[3] - 48;
994 entptr = &ptr[4];
996 vt = vt_lookup_char(cmd);
997 valid = vt && ((loc == upsloc) || (loc == '4')) && !(vt->flags & APC_PACK);
999 /* mark this as writable */
1000 if (valid) {
1001 upsdebugx(1, "%s [%s(%c)] - capability supported", vt->name, prtchr(cmd), loc);
1003 dstate_setflags(vt->name, ST_FLAG_RW);
1005 /* make sure setvar knows what this is */
1006 vt->flags |= APC_RW | APC_ENUM;
1007 } else if (vt->flags & APC_PACK)
1009 * Currently we assume - basing on the following
1010 * feedback:
1011 * http://www.mail-archive.com/nut-upsdev@lists.alioth.debian.org/msg03398.html
1012 * - that "packed" variables are not enumerable; if at
1013 * some point in the future it turns out to be false,
1014 * the handling will have to be a bit more complex
1016 upslogx(LOG_WARNING,
1017 "WARN: packed APC variable %s [%s] reported as enumerable,\n"
1018 "please report it on the mailing list", vt->name, prtchr(cmd));
1020 for (i = 0; i < nument; i++) {
1021 if (valid) {
1022 snprintf(etmp, entlen + 1, "%s", entptr);
1023 dstate_addenum(vt->name, "%s", convert_data(vt, etmp));
1026 entptr += entlen;
1029 ptr = entptr;
1033 static void legacy_verify(const char *var)
1035 int i;
1037 * note: some NUT variables map onto multiple APC ones, e.g. firmware:
1038 * V,b -> ups.firmware; that's why we keep the loop, as it's over NUT
1039 * names
1041 for (i = 0; apc_vartab[i].name != NULL; i++) {
1042 if (strcmp(apc_vartab[i].name, var))
1043 continue;
1044 var_verify(&apc_vartab[i]);
1048 static void protocol_verify(unsigned char cmd)
1050 int i, found;
1051 apc_vartab_t *vt;
1052 apc_cmdtab_t *ct;
1054 /* don't bother with cmd/var we don't care about */
1055 if (strchr(APC_UNR_CMDS, cmd))
1056 return;
1059 * loop necessary for apc:nut 1:n cases (e.g. T -> device.uptime,
1060 * ambient.0.temperature)
1062 found = 0;
1063 for (i = 0; apc_vartab[i].name != NULL; i++) {
1064 vt = &apc_vartab[i];
1065 if (vt->cmd != cmd)
1066 continue;
1067 var_verify(vt);
1068 found = 1;
1070 if (found)
1071 return;
1074 * see if it's a command
1075 * loop necessary for apc:nut 1:n cases (e.g. D -> calibrate.start,
1076 * calibrate.stop)
1078 found = 0;
1079 for (i = 0; apc_cmdtab[i].name != NULL; i++) {
1080 ct = &apc_cmdtab[i];
1081 if (ct->cmd != cmd)
1082 continue;
1083 ct->flags |= APC_PRESENT;
1084 dstate_addcmd(ct->name);
1085 confirm_cv(cmd, "command", ct->name);
1086 found = 1;
1089 if (found)
1090 return;
1093 * epilogue - unrecognized command / variable not included
1094 * in APC_UNR_CMDS
1096 warn_cv(cmd, NULL, NULL);
1099 static void oldapcsetup(void)
1102 * note: battery.date and ups.id make little sense here, as
1103 * that would imply writability and this is an *old* apc psu
1105 legacy_verify("ups.temperature");
1106 legacy_verify("ups.load");
1107 legacy_verify("input.voltage");
1108 legacy_verify("output.voltage");
1109 legacy_verify("battery.charge");
1110 legacy_verify("battery.voltage");
1112 /* these will usually timeout */
1113 legacy_verify("ups.model");
1114 legacy_verify("ups.serial");
1115 legacy_verify("ups.firmware");
1116 legacy_verify("output.current");
1118 deprecate_vars();
1120 /* see if this might be an old Matrix-UPS instead */
1121 if (vt_lookup_name("output.current"))
1122 dstate_setinfo("ups.model", "Matrix-UPS");
1123 else {
1124 /* really old models don't support ups.model (apc: 0x01) */
1125 if (!vt_lookup_name("ups.model"))
1126 /* force the model name */
1127 dstate_setinfo("ups.model", "Smart-UPS");
1131 * If we have come down this path then we dont do capabilities and
1132 * other shiny features.
1136 /* some hardware is a special case - hotwire the list of cmdchars */
1137 static int firmware_table_lookup(void)
1139 int ret;
1140 unsigned int i, j;
1141 char buf[APC_LBUF];
1143 upsdebugx(1, "attempting firmware lookup using [%s]", prtchr(APC_FW_OLD));
1145 apc_flush(0);
1146 if (apc_write(APC_FW_OLD) != 1)
1147 return 0;
1148 if ((ret = apc_read(buf, sizeof(buf), SER_TO)) < 0)
1149 return 0;
1152 * Some UPSes support both 'V' and 'b'. As 'b' doesn't always return
1153 * firmware version, we attempt that only if 'V' doesn't work.
1155 if (!ret || !strcmp(buf, "NA")) {
1156 upsdebugx(1, "attempting firmware lookup using [%s]", prtchr(APC_FW_NEW));
1158 if (apc_write(APC_FW_NEW) != 1)
1159 return 0;
1160 if (apc_read(buf, sizeof(buf), SER_TO) < 1)
1161 return 0;
1164 upsdebugx(1, "detected firmware version: %s", buf);
1166 /* this will be reworked if we get a lot of these things */
1167 if (!strcmp(buf, "451.2.I")) {
1168 /* quirk_capability_overflow */
1169 upsdebugx(1, "WARN: quirky firmware !");
1170 return 2;
1173 if (rexhlp("^[a-fA-F0-9]{2}$", buf)) {
1175 * certain old set of UPSes that return voltage above 255V
1176 * through 'b'; see:
1177 * http://article.gmane.org/gmane.comp.monitoring.nut.user/7762
1179 strcpy(buf, "set\1");
1182 for (i = 0; apc_compattab[i].firmware != NULL; i++) {
1183 if (!strcmp(apc_compattab[i].firmware, buf)) {
1185 upsdebugx(1, "matched firmware: %s", apc_compattab[i].firmware);
1187 /* magic ? */
1188 if (strspn(apc_compattab[i].firmware, "05")) {
1189 dstate_setinfo("ups.model", "Matrix-UPS");
1190 } else {
1191 dstate_setinfo("ups.model", "Smart-UPS");
1194 /* matched - run the cmdchars from the table */
1195 upsdebugx(1, "parsing out supported cmds and vars");
1196 for (j = 0; j < strlen(apc_compattab[i].cmdchars); j++)
1197 protocol_verify(apc_compattab[i].cmdchars[j]);
1198 deprecate_vars();
1200 return 1; /* matched */
1204 return 0;
1207 static int getbaseinfo(void)
1209 unsigned int i;
1210 int ret, qco;
1211 char *cmds, temp[APC_LBUF];
1214 * try firmware lookup first; we could start with 'a', but older models
1215 * sometimes return other things than a command set
1217 qco = firmware_table_lookup();
1218 if (qco == 1)
1219 /* found compat */
1220 return 1;
1222 upsdebugx(1, "attempting var/cmdset lookup using [%s]", prtchr(APC_CMDSET));
1224 * Initially we ask the UPS what commands it takes. If this fails we are
1225 * going to need an alternate strategy - we can deal with that if it
1226 * happens
1229 apc_flush(0);
1230 if (apc_write(APC_CMDSET) != 1)
1231 return 0;
1232 if ((ret = apc_read(temp, sizeof(temp), SER_CS|SER_TO)) < 0)
1233 return 0;
1235 if (!ret || !strcmp(temp, "NA") || !rexhlp(APC_CMDSET_FMT, temp)) {
1236 /* We have an old dumb UPS - go to specific code for old stuff */
1237 upslogx(LOG_NOTICE, "very old or unknown APC model, support will be limited");
1238 oldapcsetup();
1239 return 1;
1242 upsdebugx(1, "parsing out supported cmds/vars");
1244 * returned set is verified for validity above, so just extract
1245 * what's interesting for us
1247 cmds = strrchr(temp, '.');
1248 for (i = 1; i < strlen(cmds); i++)
1249 protocol_verify(cmds[i]);
1250 deprecate_vars();
1252 /* if capabilities are supported, add them here */
1253 if (strchr(cmds, APC_CAPS)) {
1254 upsdebugx(1, "parsing out caps");
1255 apc_getcaps(qco);
1257 return 1;
1260 /* check for calibration status and either start or stop */
1261 static int do_cal(int start)
1263 char temp[APC_LBUF];
1264 int tval, ret;
1266 apc_flush(SER_AA);
1267 ret = apc_write(APC_STATUS);
1269 if (ret != 1) {
1270 return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
1273 ret = apc_read(temp, sizeof(temp), SER_AA);
1275 /* if we can't check the current calibration status, bail out */
1276 if ((ret < 1) || (!strcmp(temp, "NA"))) {
1277 upslogx(LOG_WARNING, "runtime calibration state undeterminable");
1278 return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
1281 tval = strtol(temp, 0, 16);
1283 if (tval & APC_STAT_CAL) { /* calibration currently happening */
1284 if (start == 1) {
1285 /* requested start while calibration still running */
1286 upslogx(LOG_NOTICE, "runtime calibration already in progress");
1287 return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
1290 /* stop requested */
1292 upslogx(LOG_NOTICE, "stopping runtime calibration");
1294 ret = apc_write(APC_CMD_CALTOGGLE);
1296 if (ret != 1) {
1297 return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
1300 ret = apc_read(temp, sizeof(temp), SER_AA);
1302 if ((ret < 1) || (!strcmp(temp, "NA")) || (!strcmp(temp, "NO"))) {
1303 upslogx(LOG_WARNING, "stop calibration failed, cmd returned: %s", temp);
1304 return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
1307 return STAT_INSTCMD_HANDLED; /* FUTURE: success */
1310 /* calibration not happening */
1312 if (start == 0) { /* stop requested */
1313 upslogx(LOG_NOTICE, "runtime calibration not occurring");
1314 return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
1317 upslogx(LOG_NOTICE, "starting runtime calibration");
1319 ret = apc_write(APC_CMD_CALTOGGLE);
1321 if (ret != 1) {
1322 return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
1325 ret = apc_read(temp, sizeof(temp), SER_AA);
1327 if ((ret < 1) || (!strcmp(temp, "NA")) || (!strcmp(temp, "NO"))) {
1328 upslogx(LOG_WARNING, "start calibration failed, cmd returned: %s", temp);
1329 return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
1332 return STAT_INSTCMD_HANDLED; /* FUTURE: success */
1335 #if 0
1336 /* get the UPS talking to us in smart mode */
1337 static int smartmode(void)
1339 int ret;
1340 char temp[APC_LBUF];
1342 apc_flush(0);
1343 ret = apc_write(APC_GOSMART);
1344 if (ret != 1) {
1345 return 0;
1347 ret = apc_read(temp, sizeof(temp), 0);
1349 if ((ret < 1) || (!strcmp(temp, "NA")) || (!strcmp(temp, "NO"))) {
1350 upslogx(LOG_CRIT, "enabling smartmode failed !");
1351 return 0;
1354 return 1;
1356 #endif
1359 * get the UPS talking to us in smart mode
1360 * note: this is weird overkill, but possibly excused due to some obscure
1361 * hardware/firmware combinations; simpler version commmented out above, for
1362 * now let's keep minimally adjusted old one
1364 static int smartmode(int cnt)
1366 int ret, tries;
1367 char temp[APC_LBUF];
1369 for (tries = 0; tries < cnt; tries++) {
1371 apc_flush(0);
1372 if (apc_write(APC_GOSMART) != 1)
1373 return 0;
1375 /* timeout here is intented */
1376 ret = apc_read(temp, sizeof(temp), SER_TO|SER_D1);
1377 if (ret > 0 && !strcmp(temp, "SM"))
1378 return 1; /* success */
1379 if (ret < 0)
1380 /* error, so we didn't timeout - wait a bit before retry */
1381 sleep(1);
1383 if (apc_write(27) != 1) /* ESC */
1384 return 0;
1386 /* eat the response (might be NA, might be something else) */
1387 apc_read(temp, sizeof(temp), SER_TO|SER_D1);
1390 return 0; /* failure */
1394 * all shutdown commands should respond with 'OK' or '*'
1395 * apc_read() handles conversion to 'OK' so we care only about that one
1396 * ign allows for timeout without assuming an error
1398 static int sdok(int ign)
1400 int ret;
1401 char temp[APC_SBUF];
1404 * older upses on failed commands might just timeout, we cut down
1405 * timeout grace though
1406 * furthermore, command 'Z' will not reply with anything
1408 ret = apc_read(temp, sizeof(temp), SER_HA|SER_D1|SER_TO);
1409 if (ret < 0)
1410 return STAT_INSTCMD_FAILED;
1412 debx(1, "got \"%s\"", temp);
1414 if ((!ret && ign) || !strcmp(temp, "OK")) {
1415 debx(1, "last shutdown cmd succeded");
1416 return STAT_INSTCMD_HANDLED;
1419 debx(1, "last shutdown cmd failed");
1420 return STAT_INSTCMD_FAILED;
1423 /* soft hibernate: S - working only when OB, otherwise ignored */
1424 static int sdcmd_S(const void *foo)
1426 apc_flush(0);
1427 if (!foo)
1428 debx(1, "issuing [%s]", prtchr(APC_CMD_SOFTDOWN));
1429 if (apc_write(APC_CMD_SOFTDOWN) != 1)
1430 return STAT_INSTCMD_FAILED;
1431 return sdok(0);
1434 /* soft hibernate, hack version for CS 350 & co. */
1435 static int sdcmd_CS(const void *foo)
1437 int ret;
1438 char temp[APC_SBUF];
1440 debx(1, "issuing CS 'hack' [%s+%s]", prtchr(APC_CMD_SIMPWF), prtchr(APC_CMD_SOFTDOWN));
1441 if (ups_status & APC_STAT_OL) {
1442 apc_flush(0);
1443 debx(1, "issuing [%s]", prtchr(APC_CMD_SIMPWF));
1444 ret = apc_write(APC_CMD_SIMPWF);
1445 if (ret != 1) {
1446 return STAT_INSTCMD_FAILED;
1448 /* eat response, allow timeout */
1449 ret = apc_read(temp, sizeof(temp), SER_D1|SER_TO);
1450 if (ret < 0) {
1451 return STAT_INSTCMD_FAILED;
1454 /* continue with regular soft hibernate */
1455 return sdcmd_S((void *)1);
1459 * hard hibernate: @nnn / @nn
1460 * note: works differently for older and new models, see manual page for
1461 * thorough explanation
1463 static int sdcmd_AT(const void *str)
1465 int ret, cnt, padto, i;
1466 const char *awd = str;
1467 char temp[APC_SBUF], *ptr;
1469 if (!awd)
1470 awd = "000";
1472 cnt = strlen(awd);
1473 padto = cnt == 2 ? 2 : 3;
1475 temp[0] = APC_CMD_GRACEDOWN;
1476 ptr = temp + 1;
1477 for (i = cnt; i < padto ; i++) {
1478 *ptr++ = '0';
1480 strcpy(ptr, awd);
1482 debx(1, "issuing [%s] with %d minutes of additional wakeup delay",
1483 prtchr(APC_CMD_GRACEDOWN), (int)strtol(awd, NULL, 10)*6);
1485 apc_flush(0);
1486 ret = apc_write_long(temp);
1487 if (ret != padto + 1) {
1488 upslogx(LOG_ERR, "issuing [%s] with %d digits failed", prtchr(APC_CMD_GRACEDOWN), padto);
1489 return STAT_INSTCMD_FAILED;
1492 ret = sdok(0);
1493 if (ret == STAT_INSTCMD_HANDLED || padto == 3)
1494 return ret;
1496 upslogx(LOG_ERR, "command [%s] with 2 digits doesn't work - try 3 digits", prtchr(APC_CMD_GRACEDOWN));
1498 * "tricky" part - we tried @nn variation and it (unsurprisingly)
1499 * failed; we have to abort the sequence with something bogus to have
1500 * the clean state; newer upses will respond with 'NO', older will be
1501 * silent (YMMV);
1503 apc_write(APC_GOSMART);
1504 /* eat response, allow it to timeout */
1505 apc_read(temp, sizeof(temp), SER_D1|SER_TO);
1507 return STAT_INSTCMD_FAILED;
1510 /* shutdown: K - delayed poweroff */
1511 static int sdcmd_K(const void *foo)
1513 int ret;
1515 debx(1, "issuing [%s]", prtchr(APC_CMD_SHUTDOWN));
1517 apc_flush(0);
1518 ret = apc_write_rep(APC_CMD_SHUTDOWN);
1519 if (ret != 2)
1520 return STAT_INSTCMD_FAILED;
1522 return sdok(0);
1525 /* shutdown: Z - immediate poweroff */
1526 static int sdcmd_Z(const void *foo)
1528 int ret;
1530 debx(1, "issuing [%s]", prtchr(APC_CMD_OFF));
1532 apc_flush(0);
1533 ret = apc_write_rep(APC_CMD_OFF);
1534 if (ret != 2) {
1535 return STAT_INSTCMD_FAILED;
1538 /* note: ups will not reply anything after this command */
1539 return sdok(1);
1542 static void upsdrv_shutdown_simple(void)
1544 unsigned int sdtype = 0;
1545 const char *val;
1547 if ((val = getval("sdtype")))
1548 sdtype = strtol(val, NULL, 10);
1550 debx(1, "currently: %s, sdtype: %d", (ups_status & APC_STAT_OL) ? "on-line" : "on battery", sdtype);
1552 switch (sdtype) {
1554 case 5: /* hard hibernate */
1555 sdcmd_AT(getval("awd"));
1556 break;
1557 case 4: /* special hack for CS 350 and similar models */
1558 sdcmd_CS(0);
1559 break;
1561 case 3: /* delayed poweroff */
1562 sdcmd_K(0);
1563 break;
1565 case 2: /* instant poweroff */
1566 sdcmd_Z(0);
1567 break;
1568 case 1:
1570 * Send a combined set of shutdown commands which can work
1571 * better if the UPS gets power during shutdown process
1572 * Specifically it sends both the soft shutdown 'S' and the
1573 * hard hibernate '@nnn' commands
1576 /* S works only when OB */
1577 if (!(ups_status & APC_STAT_OB) || sdcmd_S(0) != STAT_INSTCMD_HANDLED)
1578 sdcmd_AT(getval("awd"));
1579 break;
1581 default:
1583 * Send @nnn or S, depending on OB / OL status
1585 if (ups_status & APC_STAT_OL) /* on line */
1586 sdcmd_AT(getval("awd"));
1587 else
1588 sdcmd_S(0);
1592 static void upsdrv_shutdown_advanced(void)
1594 const void *arg;
1595 const char *val;
1596 size_t i, len;
1598 val = getval("advorder");
1599 len = strlen(val);
1601 debx(1, "currently: %s, advorder: %s", (ups_status & APC_STAT_OL) ? "on-line" : "on battery", val);
1604 * try each method in the list with a little bit of handling in certain
1605 * cases
1607 for (i = 0; i < len; i++) {
1608 switch (val[i] - '0') {
1609 case SDIDX_AT:
1610 arg = getval("awd");
1611 break;
1612 default:
1613 arg = NULL;
1616 if (sdlist[val[i] - '0'](arg) == STAT_INSTCMD_HANDLED)
1617 break; /* finish if command succeeded */
1621 /* power down the attached load immediately */
1622 void upsdrv_shutdown(void)
1624 char temp[APC_LBUF];
1626 if (!smartmode(1))
1627 logx(LOG_WARNING, "setting SmartMode failed !");
1629 /* check the line status */
1631 if (apc_write(APC_STATUS) == 1) {
1632 if (apc_read(temp, sizeof(temp), SER_D1) == 1) {
1633 ups_status = strtol(temp, 0, 16);
1634 } else {
1635 logx(LOG_WARNING, "status read failed, assuming LB+OB");
1636 ups_status = APC_STAT_LB | APC_STAT_OB;
1638 } else {
1639 logx(LOG_WARNING, "status write failed, assuming LB+OB");
1640 ups_status = APC_STAT_LB | APC_STAT_OB;
1643 if (testvar("advorder") && toupper(*getval("advorder")) != 'N')
1644 upsdrv_shutdown_advanced();
1645 else
1646 upsdrv_shutdown_simple();
1649 static int update_info(int all)
1651 int i;
1653 debx(1, "starting scan%s", all ? " (all vars)" : "");
1655 for (i = 0; apc_vartab[i].name != NULL; i++) {
1656 if (!all && (apc_vartab[i].flags & APC_POLL) == 0)
1657 continue;
1659 if (!poll_data(&apc_vartab[i])) {
1660 debx(1, "aborting scan");
1661 return 0;
1665 debx(1, "scan completed");
1666 return 1;
1669 static int setvar_enum(apc_vartab_t *vt, const char *val)
1671 int i, ret;
1672 char orig[APC_LBUF], temp[APC_LBUF];
1673 const char *ptr;
1675 apc_flush(SER_AA);
1676 if (apc_write(vt->cmd) != 1)
1677 return STAT_SET_FAILED;
1679 ret = apc_read(orig, sizeof(orig), SER_AA);
1681 if ((ret < 1) || (!strcmp(orig, "NA")))
1682 return STAT_SET_FAILED;
1684 ptr = convert_data(vt, orig);
1686 /* suppress redundant changes - easier on the eeprom */
1687 if (!strcmp(ptr, val)) {
1688 logx(LOG_INFO, "ignoring SET %s='%s' (unchanged value)",
1689 vt->name, val);
1691 return STAT_SET_HANDLED; /* FUTURE: no change */
1694 for (i = 0; i < 6; i++) {
1695 if (apc_write(APC_NEXTVAL) != 1)
1696 return STAT_SET_FAILED;
1698 /* this should return either OK (if rotated) or NO (if not) */
1699 ret = apc_read(temp, sizeof(temp), SER_AA);
1701 if ((ret < 1) || (!strcmp(temp, "NA")))
1702 return STAT_SET_FAILED;
1704 /* sanity checks */
1705 if (!strcmp(temp, "NO"))
1706 return STAT_SET_FAILED;
1707 if (strcmp(temp, "OK"))
1708 return STAT_SET_FAILED;
1710 /* see what it rotated onto */
1711 if (apc_write(vt->cmd) != 1)
1712 return STAT_SET_FAILED;
1714 ret = apc_read(temp, sizeof(temp), SER_AA);
1716 if ((ret < 1) || (!strcmp(temp, "NA")))
1717 return STAT_SET_FAILED;
1719 ptr = convert_data(vt, temp);
1721 debx(1, "rotate - got [%s], want [%s]", ptr, val);
1723 if (!strcmp(ptr, val)) { /* got it */
1724 logx(LOG_INFO, "SET %s='%s'", vt->name, val);
1726 /* refresh data from the hardware */
1727 poll_data(vt);
1729 return STAT_SET_HANDLED; /* FUTURE: success */
1732 /* check for wraparound */
1733 if (!strcmp(ptr, orig)) {
1734 logx(LOG_ERR, "variable %s wrapped", vt->name);
1736 return STAT_SET_FAILED;
1740 logx(LOG_ERR, "gave up after 6 tries for %s", vt->name);
1742 /* refresh data from the hardware */
1743 poll_data(vt);
1745 return STAT_SET_FAILED;
1748 static int setvar_string(apc_vartab_t *vt, const char *val)
1750 unsigned int i;
1751 int ret;
1752 char temp[APC_LBUF], *ptr;
1754 /* sanitize length */
1755 if (strlen(val) > APC_STRLEN) {
1756 logx(LOG_ERR, "value (%s) too long", val);
1757 return STAT_SET_FAILED;
1760 apc_flush(SER_AA);
1761 if (apc_write(vt->cmd) != 1)
1762 return STAT_SET_FAILED;
1764 ret = apc_read(temp, sizeof(temp), SER_AA);
1766 if ((ret < 1) || (!strcmp(temp, "NA")))
1767 return STAT_SET_FAILED;
1769 /* suppress redundant changes - easier on the eeprom */
1770 if (!strcmp(temp, val)) {
1771 logx(LOG_INFO, "ignoring SET %s='%s' (unchanged value)",
1772 vt->name, val);
1774 return STAT_SET_HANDLED; /* FUTURE: no change */
1777 /* length sanitized above */
1778 temp[0] = APC_NEXTVAL;
1779 strcpy(temp + 1, val);
1780 ptr = temp + strlen(temp);
1781 for (i = strlen(val); i < APC_STRLEN; i++)
1782 *ptr++ = '\015'; /* pad with CRs */
1783 *ptr = 0;
1785 if (apc_write_long(temp) != APC_STRLEN + 1)
1786 return STAT_SET_FAILED;
1788 ret = apc_read(temp, sizeof(temp), SER_AA);
1790 if (ret < 1) {
1791 logx(LOG_ERR, "short final read");
1792 return STAT_SET_FAILED;
1795 if (!strcmp(temp, "NO")) {
1796 logx(LOG_ERR, "got NO at final read");
1797 return STAT_SET_FAILED;
1800 /* refresh data from the hardware */
1801 poll_data(vt);
1803 logx(LOG_INFO, "SET %s='%s'", vt->name, val);
1805 return STAT_SET_HANDLED; /* FUTURE: success */
1808 static int setvar(const char *varname, const char *val)
1810 apc_vartab_t *vt;
1812 vt = vt_lookup_name(varname);
1814 if (!vt)
1815 return STAT_SET_UNKNOWN;
1817 if ((vt->flags & APC_RW) == 0) {
1818 logx(LOG_WARNING, "[%s] is not writable", varname);
1819 return STAT_SET_UNKNOWN;
1822 if (vt->flags & APC_ENUM)
1823 return setvar_enum(vt, val);
1825 if (vt->flags & APC_STRING)
1826 return setvar_string(vt, val);
1828 logx(LOG_WARNING, "unknown type for [%s]", varname);
1829 return STAT_SET_UNKNOWN;
1832 /* load on */
1833 static int do_loadon(void)
1835 apc_flush(0);
1836 debx(1, "issuing [%s]", prtchr(APC_CMD_ON));
1838 if (apc_write_rep(APC_CMD_ON) != 2)
1839 return STAT_INSTCMD_FAILED;
1842 * ups will not reply anything after this command, but might
1843 * generate brief OVER condition (which will be corrected on
1844 * the next status update)
1847 debx(1, "[%s] completed", prtchr(APC_CMD_ON));
1848 return STAT_INSTCMD_HANDLED;
1851 /* actually send the instcmd's char to the ups */
1852 static int do_cmd(const apc_cmdtab_t *ct)
1854 int ret, c;
1855 char temp[APC_LBUF];
1857 apc_flush(SER_AA);
1859 if (ct->flags & APC_REPEAT) {
1860 ret = apc_write_rep(ct->cmd);
1861 c = 2;
1862 } else {
1863 ret = apc_write(ct->cmd);
1864 c = 1;
1867 if (ret != c) {
1868 return STAT_INSTCMD_FAILED;
1871 ret = apc_read(temp, sizeof(temp), SER_AA);
1873 if (ret < 1)
1874 return STAT_INSTCMD_FAILED;
1876 if (strcmp(temp, "OK")) {
1877 logx(LOG_WARNING, "got [%s] after command [%s]",
1878 temp, ct->name);
1880 return STAT_INSTCMD_FAILED;
1883 logx(LOG_INFO, "%s completed", ct->name);
1884 return STAT_INSTCMD_HANDLED;
1887 /* some commands must be repeated in a window to execute */
1888 static int instcmd_chktime(apc_cmdtab_t *ct, const char *ext)
1890 double elapsed;
1891 time_t now;
1892 static time_t last = 0;
1894 time(&now);
1896 elapsed = difftime(now, last);
1897 last = now;
1899 /* you have to hit this in a small window or it fails */
1900 if ((elapsed < MINCMDTIME) || (elapsed > MAXCMDTIME)) {
1901 debx(1, "outside window for [%s %s] (%2.0f)",
1902 ct->name, ext ? ext : "\b", elapsed);
1903 return 0;
1906 return 1;
1909 static int instcmd(const char *cmd, const char *ext)
1911 int i;
1912 apc_cmdtab_t *ct = NULL;
1914 for (i = 0; apc_cmdtab[i].name != NULL; i++) {
1915 /* cmd must match */
1916 if (strcasecmp(apc_cmdtab[i].name, cmd))
1917 continue;
1918 /* if cmd specifies regex, ext must match */
1919 if (apc_cmdtab[i].ext) {
1920 if (!rexhlp(apc_cmdtab[i].ext, ext))
1921 continue;
1922 /* if cmd doesn't specify regex, ext must be NULL */
1923 } else {
1924 if (ext)
1925 continue;
1927 ct = &apc_cmdtab[i];
1928 break;
1931 if (!ct) {
1932 logx(LOG_WARNING, "unknown command [%s %s]", cmd,
1933 ext ? ext : "\b");
1934 return STAT_INSTCMD_INVALID;
1937 if (!(ct->flags & APC_PRESENT)) {
1938 logx(LOG_WARNING, "command [%s %s] recognized, but"
1939 " not supported by your UPS model", cmd,
1940 ext ? ext : "\b");
1941 return STAT_INSTCMD_INVALID;
1944 /* first verify if the command is "nasty" */
1945 if ((ct->flags & APC_NASTY) && !instcmd_chktime(ct, ext))
1946 return STAT_INSTCMD_HANDLED; /* future: again */
1948 /* we're good to go, handle special stuff first, then generic cmd */
1950 if (!strcasecmp(cmd, "calibrate.start"))
1951 return do_cal(1);
1953 if (!strcasecmp(cmd, "calibrate.stop"))
1954 return do_cal(0);
1956 if (!strcasecmp(cmd, "load.on"))
1957 return do_loadon();
1959 if (!strcasecmp(cmd, "load.off"))
1960 return sdcmd_Z(0);
1962 if (!strcasecmp(cmd, "shutdown.stayoff"))
1963 return sdcmd_K(0);
1965 if (!strcasecmp(cmd, "shutdown.return")) {
1966 if (!ext || !*ext)
1967 return sdcmd_S(0);
1969 if (toupper(*ext) == 'A')
1970 return sdcmd_AT(ext + 3);
1972 if (toupper(*ext) == 'C')
1973 return sdcmd_CS(0);
1976 /* nothing special here */
1977 return do_cmd(ct);
1980 /* install pointers to functions for msg handlers called from msgparse */
1981 static void setuphandlers(void)
1983 upsh.setvar = setvar;
1984 upsh.instcmd = instcmd;
1987 /* ---- functions that interface with main.c ------------------------------- */
1989 void upsdrv_makevartable(void)
1991 addvar(VAR_VALUE, "ttymode", "tty discipline selection");
1992 addvar(VAR_VALUE, "cable", "alternate cable (940-0095B) selection");
1993 addvar(VAR_VALUE, "awd", "hard hibernate's additional wakeup delay");
1994 addvar(VAR_VALUE, "sdtype", "simple shutdown method");
1995 addvar(VAR_VALUE, "advorder", "advanced shutdown control");
1998 void upsdrv_help(void)
2000 printf(
2001 "\nFor detailed information, please refer to:\n"
2002 " - apcsmart(8)\n"
2003 " - http://www.networkupstools.org/docs/man/apcsmart.html\n"
2007 void upsdrv_initups(void)
2009 char *val;
2010 apc_vartab_t *ptr;
2012 /* sanitize awd (additional waekup delay of '@' command) */
2013 if ((val = getval("awd")) && !rexhlp(APC_AWDFMT, val)) {
2014 fatalx(EXIT_FAILURE, "invalid value (%s) for option 'awd'", val);
2017 /* sanitize sdtype */
2018 if ((val = getval("sdtype")) && !rexhlp(APC_SDFMT, val)) {
2019 fatalx(EXIT_FAILURE, "invalid value (%s) for option 'sdtype'", val);
2022 /* sanitize advorder */
2023 if ((val = getval("advorder")) && !rexhlp(APC_ADVFMT, val)) {
2024 fatalx(EXIT_FAILURE, "invalid value (%s) for option 'advorder'", val);
2027 upsfd = extrafd = ser_open(device_path);
2028 apc_ser_set();
2030 /* fill length values */
2031 for (ptr = apc_vartab; ptr->name; ptr++)
2032 ptr->nlen0 = strlen(ptr->name) + 1;
2035 void upsdrv_cleanup(void)
2037 char temp[APC_LBUF];
2039 if (upsfd == -1)
2040 return;
2042 apc_flush(0);
2043 /* try to bring the UPS out of smart mode */
2044 apc_write(APC_GODUMB);
2045 apc_read(temp, sizeof(temp), SER_TO);
2046 ser_close(upsfd, device_path);
2049 void upsdrv_initinfo(void)
2051 const char *pmod, *pser;
2053 if (!smartmode(5)) {
2054 fatalx(EXIT_FAILURE,
2055 "unable to detect an APC Smart protocol UPS on port %s\n"
2056 "check the cabling, port name or model name and try again", device_path
2060 if (!getbaseinfo()) {
2061 fatalx(EXIT_FAILURE,
2062 "Problems with communicating APC UPS on port %s\n", device_path
2066 /* manufacturer ID - hardcoded in this particular module */
2067 dstate_setinfo("ups.mfr", "APC");
2069 if (!(pmod = dstate_getinfo("ups.model")))
2070 pmod = "\"unknown model\"";
2071 if (!(pser = dstate_getinfo("ups.serial")))
2072 pser = "unknown serial";
2074 upsdebugx(1, "detected %s [%s] on %s", pmod, pser, device_path);
2076 setuphandlers();
2078 * seems to be ok so far, it must be set so initial call of
2079 * upsdrv_updateinfo() doesn't begin with stale condition
2081 dstate_dataok();
2084 void upsdrv_updateinfo(void)
2086 static int last_worked = 0;
2087 static time_t last_full = 0;
2088 int all;
2089 time_t now;
2091 /* try to wake up a dead ups once in awhile */
2092 if (dstate_is_stale()) {
2093 if (!last_worked)
2094 debx(1, "comm lost");
2096 /* reset this so a full update runs when the UPS returns */
2097 last_full = 0;
2099 if (++last_worked < 10)
2100 return;
2102 /* become aggressive after a few tries */
2103 debx(1, "nudging ups with 'Y', iteration #%d ...", last_worked);
2104 if (!smartmode(1))
2105 return;
2107 last_worked = 0;
2110 if (!update_status()) {
2111 dstate_datastale();
2112 return;
2115 time(&now);
2117 /* refresh all variables hourly */
2118 /* does not catch measure-ups II insertion/removal */
2119 if (difftime(now, last_full) > 3600) {
2120 last_full = now;
2121 all = 1;
2122 } else
2123 all = 0;
2125 if (update_info(all)) {
2126 dstate_dataok();
2127 } else {
2128 dstate_datastale();