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>
27 #include <strings.h> /* strcasecmp() */
34 #include "apcsmart_tabs.h"
36 /* driver description structure */
37 upsdrv_info_t upsdrv_info
= {
40 "Russell Kroll <rkroll@exploits.org>\n"
41 "Nigel Metheringham <Nigel.Metheringham@Intechnology.co.uk>\n"
42 "Michal Soltys <soltys@ziu.info>",
44 { &apc_tab_info
, NULL
}
47 static int ups_status
= 0;
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 *) = {
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
82 static apc_vartab_t
*vt_lookup_char(char cmdchar
)
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
];
94 static apc_vartab_t
*vt_lookup_name(const char *var
)
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
];
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
);
117 static int rexhlp(const char *rex
, const char *val
)
119 static const char *empty
= "";
127 regcomp(&mbuf
, rex
, REG_EXTENDED
|REG_NOSUB
);
128 ret
= regexec(&mbuf
, val
, 0, 0, 0);
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
];
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';
148 switch (vt
->flags
& APC_F_MASK
) {
157 /* no conversion for any of these */
158 strcpy(temp
, upsval
);
162 /* convert to seconds */
164 tval
= 60 * 60 * strtol(upsval
, NULL
, 10);
166 snprintf(temp
, sizeof(temp
), "%d", tval
);
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
);
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";
185 strcpy(temp
, upsval
);
190 /* this should never happen */
191 logx(LOG_CRIT
, "unable to convert [%s]", vt
->name
);
192 strcpy(temp
, upsval
);
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
)
212 const char dir
[] = { 's', 'g' };
213 struct termios
*tio
[] = { tioset
, tioget
};
218 const struct cchar cchars1
[] = {
220 { "discard", VDISCARD
},
237 { "reprint", VREPRINT
},
241 { "status", VSTATUS
},
246 { "werase", VWERASE
},
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
++) {
254 tio
[i
]->c_lflag
&= ~PENDIN
;
257 tio
[i
]->c_lflag
&= ~FLUSHO
;
260 #endif /* defined(PENDIN) || defined(FLUSHO) */
262 if (!memcmp(tio
[0], tio
[1], sizeof(*tio
[0])))
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
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
;
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"))
312 memset(&tio
, 0, sizeof(tio
));
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
;
324 tio
.c_lflag
|= NOKERNINFO
;
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
;
339 if (tcflush(upsfd
, TCIOFLUSH
))
340 fate("tcflush(%s)", device_path
);
344 * Note, that tcsetattr() returns success if /any/ of the requested
345 * changes could be successfully carried out. Thus the more complicated
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)
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 */
384 static void alert_handler(char ch
)
387 case '!': /* clear OL, set OB */
389 ups_status
&= ~APC_STAT_OL
;
390 ups_status
|= APC_STAT_OB
;
393 case '$': /* clear OB, set OL */
395 ups_status
&= ~APC_STAT_OB
;
396 ups_status
|= APC_STAT_OL
;
399 case '%': /* set LB */
401 ups_status
|= APC_STAT_LB
;
404 case '+': /* clear LB */
406 ups_status
&= ~APC_STAT_LB
;
409 case '#': /* set RB */
411 ups_status
|= APC_STAT_RB
;
414 case '?': /* set OVER */
416 ups_status
|= APC_STAT_OVER
;
419 case '=': /* clear OVER */
421 ups_status
&= ~APC_STAT_OVER
;
425 debx(1, "got 0x%02x (unhandled)", ch
);
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
= "";
441 int i
, ret
, sec
= 3, usec
= 0;
446 if (flags
& SER_D0
) {
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
) {
458 if (flags
& SER_AA
) {
462 if (flags
& SER_CC
) {
467 if (flags
& SER_CS
) {
473 memset(buf
, '\0', buflen
);
475 while (count
< buflen
- 1) {
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
);
484 /* error or no timeout allowed */
485 if (ret
< 0 || (ret
== 0 && !(flags
& SER_TO
))) {
487 ser_comm_fail("serial port read error: %u(%s): %s", ln
, fn
, strerror(errno
));
489 ser_comm_fail("serial port read timeout: %u(%s)", ln
, fn
);
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
508 for (i
= 0; i
< ret
; i
++) {
510 if (count
== buflen
- 1) {
511 ser_comm_fail("serial port read overflow: %u(%s)", ln
, fn
);
512 tcflush(upsfd
, TCIFLUSH
);
515 /* standard "line received" condition */
516 if (temp
[i
] == ENDCHAR
) {
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.
533 memset(buf
, '\0', buflen
);
535 ret
= select_read(upsfd
, temp
, sizeof(temp
), 1, 0);
537 ser_comm_fail("serial port read error: %u(%s): %s", ln
, fn
, strerror(errno
));
546 if (strchr(iset
, temp
[i
]) || temp
[i
] == '*') {
550 if (strchr(aset
, temp
[i
])) {
551 alert_handler(temp
[i
]);
555 buf
[count
++] = temp
[i
];
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
)
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;
580 ser_comm_fail("serial port write error: %u(%s): %s", ln
, fn
, strerror(errno
));
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
)
604 ret
= apc_write_i(*code
, fn
, ln
);
607 /* peek for the answer - anything at this point is failure */
608 ret
= apc_read(temp
, sizeof(temp
), SER_DX
|SER_TO
);
614 ret
= ser_send_pace(upsfd
, 50000, "%s", code
+ 1);
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
));
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
)
629 ret
= apc_write_i(code
, fn
, ln
);
632 /* peek for the answer - anything at this point is failure */
633 ret
= apc_read(temp
, sizeof(temp
), SER_DX
|SER_TO
);
640 ret
= apc_write_i(code
, fn
, ln
);
646 /* all flags other than SER_AA are ignored */
647 static void apc_flush(int flags
)
651 if (flags
& SER_AA
) {
652 tcflush(upsfd
, TCOFLUSH
);
654 while(apc_read(temp
, sizeof(temp
), SER_D0
|SER_TO
|SER_AA
) > 0);
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
;
668 /* standard not packed var */
669 if (!(vt
->flags
& APC_PACK
)) {
670 dstate_delinfo(vt
->name
);
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
);
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
;
691 /* standard not packed var */
692 if (!(vt
->flags
& APC_PACK
)) {
693 dstate_setinfo(vt
->name
, "%s", convert_data(vt
, upsval
));
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
);
707 com
= strchr(curr
, ',');
712 } while(++c
< APC_PACK_MAX
&& com
);
715 * unlikely, but keep things tidy - remove leftover values, if
716 * subsequent read returns less
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
)
724 "packed variable %s [%s] longer than %d fields,\n"
725 "ignoring remaining fields",
726 vt
->name
, prtchr(vt
->cmd
), c
);
731 *nidx
= (char)('1' + c
);
733 dstate_setinfo(name
, "%s", convert_data(vt
, vidx
[c
]));
735 dstate_setinfo(name
, "N/A");
739 static const char *preread_data(apc_vartab_t
*vt
)
742 static char temp
[APC_LBUF
];
744 debx(1, "%s [%s]", vt
->name
, prtchr(vt
->cmd
));
747 ret
= apc_write(vt
->cmd
);
752 ret
= apc_read(temp
, sizeof(temp
), SER_TO
);
754 if (ret
< 1 || !strcmp(temp
, "NA")) {
756 logx(LOG_ERR
, "%s [%s] timed out or not supported", vt
->name
, prtchr(vt
->cmd
));
763 static int poll_data(apc_vartab_t
*vt
)
767 if (!(vt
->flags
& APC_PRESENT
))
770 debx(1, "%s [%s]", vt
->name
, prtchr(vt
->cmd
));
773 if (apc_write(vt
->cmd
) != 1)
775 if (apc_read(temp
, sizeof(temp
), SER_AA
) < 1)
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);
784 apc_dstate_setinfo(vt
, temp
);
789 static int update_status(void)
794 debx(1, "[%s]", prtchr(APC_STATUS
));
797 if (apc_write(APC_STATUS
) != 1)
799 ret
= apc_read(buf
, sizeof(buf
), SER_AA
);
801 if ((ret
< 1) || (!strcmp(buf
, "NA"))) {
803 logx(LOG_WARNING
, "failed");
807 ups_status
= strtol(buf
, 0, 16) & 0xff;
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
)
825 upslogx(LOG_WARNING
, "%s [%s] - %s invalid", name
, prtchr(cmd
), tag
);
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
);
843 static int var_verify(apc_vartab_t
*vt
)
847 if (vt
->flags
& APC_MULTI
) {
848 /* APC_MULTI are handled by deprecate_vars() */
849 vt
->flags
|= APC_PRESENT
;
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
);
860 vt
->flags
|= APC_PRESENT
;
861 apc_dstate_setinfo(vt
, temp
);
862 var_string_setup(vt
);
864 confirm_cv(vt
->cmd
, "variable", vt
->name
);
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)
880 apc_vartab_t
*vt
, *vtn
;
882 for (i
= 0; apc_vartab
[i
].name
!= NULL
; 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
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
);
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
)
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
;
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");
930 upsloc
= ptr
[strlen(ptr
) - 1];
934 /* get capability string */
936 if (apc_write(APC_CAPS
) != 1)
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
954 upslogx(LOG_WARNING
, "APC cannot do capabilities but said it could !");
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
);
968 if (temp
[1] == '#') { /* Matrix-UPS */
976 /* command char, location, # of entries, entry length */
978 while (ptr
[0] != '\0') {
980 ptr
+= 2; /* jump over repeating ## */
982 /* check for idiocy */
983 if (ptr
>= endtemp
) {
984 /* if we expected this, just ignore it */
987 fatalx(EXIT_FAILURE
, "capability string has overflowed, please report this error !");
992 nument
= ptr
[2] - 48;
993 entlen
= ptr
[3] - 48;
996 vt
= vt_lookup_char(cmd
);
997 valid
= vt
&& ((loc
== upsloc
) || (loc
== '4')) && !(vt
->flags
& APC_PACK
);
999 /* mark this as writable */
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
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
++) {
1022 snprintf(etmp
, entlen
+ 1, "%s", entptr
);
1023 dstate_addenum(vt
->name
, "%s", convert_data(vt
, etmp
));
1033 static void legacy_verify(const char *var
)
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
1041 for (i
= 0; apc_vartab
[i
].name
!= NULL
; i
++) {
1042 if (strcmp(apc_vartab
[i
].name
, var
))
1044 var_verify(&apc_vartab
[i
]);
1048 static void protocol_verify(unsigned char cmd
)
1054 /* don't bother with cmd/var we don't care about */
1055 if (strchr(APC_UNR_CMDS
, cmd
))
1059 * loop necessary for apc:nut 1:n cases (e.g. T -> device.uptime,
1060 * ambient.0.temperature)
1063 for (i
= 0; apc_vartab
[i
].name
!= NULL
; i
++) {
1064 vt
= &apc_vartab
[i
];
1074 * see if it's a command
1075 * loop necessary for apc:nut 1:n cases (e.g. D -> calibrate.start,
1079 for (i
= 0; apc_cmdtab
[i
].name
!= NULL
; i
++) {
1080 ct
= &apc_cmdtab
[i
];
1083 ct
->flags
|= APC_PRESENT
;
1084 dstate_addcmd(ct
->name
);
1085 confirm_cv(cmd
, "command", ct
->name
);
1093 * epilogue - unrecognized command / variable not included
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");
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");
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)
1143 upsdebugx(1, "attempting firmware lookup using [%s]", prtchr(APC_FW_OLD
));
1146 if (apc_write(APC_FW_OLD
) != 1)
1148 if ((ret
= apc_read(buf
, sizeof(buf
), SER_TO
)) < 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)
1160 if (apc_read(buf
, sizeof(buf
), SER_TO
) < 1)
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 !");
1173 if (rexhlp("^[a-fA-F0-9]{2}$", buf
)) {
1175 * certain old set of UPSes that return voltage above 255V
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
);
1188 if (strspn(apc_compattab
[i
].firmware
, "05")) {
1189 dstate_setinfo("ups.model", "Matrix-UPS");
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
]);
1200 return 1; /* matched */
1207 static int getbaseinfo(void)
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();
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
1230 if (apc_write(APC_CMDSET
) != 1)
1232 if ((ret
= apc_read(temp
, sizeof(temp
), SER_CS
|SER_TO
)) < 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");
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
]);
1252 /* if capabilities are supported, add them here */
1253 if (strchr(cmds
, APC_CAPS
)) {
1254 upsdebugx(1, "parsing out caps");
1260 /* check for calibration status and either start or stop */
1261 static int do_cal(int start
)
1263 char temp
[APC_LBUF
];
1267 ret
= apc_write(APC_STATUS
);
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 */
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
);
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
);
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 */
1336 /* get the UPS talking to us in smart mode */
1337 static int smartmode(void)
1340 char temp
[APC_LBUF
];
1343 ret
= apc_write(APC_GOSMART
);
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 !");
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
)
1367 char temp
[APC_LBUF
];
1369 for (tries
= 0; tries
< cnt
; tries
++) {
1372 if (apc_write(APC_GOSMART
) != 1)
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 */
1380 /* error, so we didn't timeout - wait a bit before retry */
1383 if (apc_write(27) != 1) /* ESC */
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
)
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
);
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
)
1428 debx(1, "issuing [%s]", prtchr(APC_CMD_SOFTDOWN
));
1429 if (apc_write(APC_CMD_SOFTDOWN
) != 1)
1430 return STAT_INSTCMD_FAILED
;
1434 /* soft hibernate, hack version for CS 350 & co. */
1435 static int sdcmd_CS(const void *foo
)
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
) {
1443 debx(1, "issuing [%s]", prtchr(APC_CMD_SIMPWF
));
1444 ret
= apc_write(APC_CMD_SIMPWF
);
1446 return STAT_INSTCMD_FAILED
;
1448 /* eat response, allow timeout */
1449 ret
= apc_read(temp
, sizeof(temp
), SER_D1
|SER_TO
);
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
;
1473 padto
= cnt
== 2 ? 2 : 3;
1475 temp
[0] = APC_CMD_GRACEDOWN
;
1477 for (i
= cnt
; i
< padto
; i
++) {
1482 debx(1, "issuing [%s] with %d minutes of additional wakeup delay",
1483 prtchr(APC_CMD_GRACEDOWN
), (int)strtol(awd
, NULL
, 10)*6);
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
;
1493 if (ret
== STAT_INSTCMD_HANDLED
|| padto
== 3)
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
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
)
1515 debx(1, "issuing [%s]", prtchr(APC_CMD_SHUTDOWN
));
1518 ret
= apc_write_rep(APC_CMD_SHUTDOWN
);
1520 return STAT_INSTCMD_FAILED
;
1525 /* shutdown: Z - immediate poweroff */
1526 static int sdcmd_Z(const void *foo
)
1530 debx(1, "issuing [%s]", prtchr(APC_CMD_OFF
));
1533 ret
= apc_write_rep(APC_CMD_OFF
);
1535 return STAT_INSTCMD_FAILED
;
1538 /* note: ups will not reply anything after this command */
1542 static void upsdrv_shutdown_simple(void)
1544 unsigned int sdtype
= 0;
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
);
1554 case 5: /* hard hibernate */
1555 sdcmd_AT(getval("awd"));
1557 case 4: /* special hack for CS 350 and similar models */
1561 case 3: /* delayed poweroff */
1565 case 2: /* instant poweroff */
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"));
1583 * Send @nnn or S, depending on OB / OL status
1585 if (ups_status
& APC_STAT_OL
) /* on line */
1586 sdcmd_AT(getval("awd"));
1592 static void upsdrv_shutdown_advanced(void)
1598 val
= getval("advorder");
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
1607 for (i
= 0; i
< len
; i
++) {
1608 switch (val
[i
] - '0') {
1610 arg
= getval("awd");
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
];
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);
1635 logx(LOG_WARNING
, "status read failed, assuming LB+OB");
1636 ups_status
= APC_STAT_LB
| APC_STAT_OB
;
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();
1646 upsdrv_shutdown_simple();
1649 static int update_info(int all
)
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)
1659 if (!poll_data(&apc_vartab
[i
])) {
1660 debx(1, "aborting scan");
1665 debx(1, "scan completed");
1669 static int setvar_enum(apc_vartab_t
*vt
, const char *val
)
1672 char orig
[APC_LBUF
], temp
[APC_LBUF
];
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)",
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
;
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 */
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 */
1745 return STAT_SET_FAILED
;
1748 static int setvar_string(apc_vartab_t
*vt
, const char *val
)
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
;
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)",
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 */
1785 if (apc_write_long(temp
) != APC_STRLEN
+ 1)
1786 return STAT_SET_FAILED
;
1788 ret
= apc_read(temp
, sizeof(temp
), SER_AA
);
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 */
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
)
1812 vt
= vt_lookup_name(varname
);
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
;
1833 static int do_loadon(void)
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
)
1855 char temp
[APC_LBUF
];
1859 if (ct
->flags
& APC_REPEAT
) {
1860 ret
= apc_write_rep(ct
->cmd
);
1863 ret
= apc_write(ct
->cmd
);
1868 return STAT_INSTCMD_FAILED
;
1871 ret
= apc_read(temp
, sizeof(temp
), SER_AA
);
1874 return STAT_INSTCMD_FAILED
;
1876 if (strcmp(temp
, "OK")) {
1877 logx(LOG_WARNING
, "got [%s] after command [%s]",
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
)
1892 static time_t last
= 0;
1896 elapsed
= difftime(now
, last
);
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
);
1909 static int instcmd(const char *cmd
, const char *ext
)
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
))
1918 /* if cmd specifies regex, ext must match */
1919 if (apc_cmdtab
[i
].ext
) {
1920 if (!rexhlp(apc_cmdtab
[i
].ext
, ext
))
1922 /* if cmd doesn't specify regex, ext must be NULL */
1927 ct
= &apc_cmdtab
[i
];
1932 logx(LOG_WARNING
, "unknown command [%s %s]", cmd
,
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
,
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"))
1953 if (!strcasecmp(cmd
, "calibrate.stop"))
1956 if (!strcasecmp(cmd
, "load.on"))
1959 if (!strcasecmp(cmd
, "load.off"))
1962 if (!strcasecmp(cmd
, "shutdown.stayoff"))
1965 if (!strcasecmp(cmd
, "shutdown.return")) {
1969 if (toupper(*ext
) == 'A')
1970 return sdcmd_AT(ext
+ 3);
1972 if (toupper(*ext
) == 'C')
1976 /* nothing special here */
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)
2001 "\nFor detailed information, please refer to:\n"
2003 " - http://www.networkupstools.org/docs/man/apcsmart.html\n"
2007 void upsdrv_initups(void)
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
);
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
];
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
);
2078 * seems to be ok so far, it must be set so initial call of
2079 * upsdrv_updateinfo() doesn't begin with stale condition
2084 void upsdrv_updateinfo(void)
2086 static int last_worked
= 0;
2087 static time_t last_full
= 0;
2091 /* try to wake up a dead ups once in awhile */
2092 if (dstate_is_stale()) {
2094 debx(1, "comm lost");
2096 /* reset this so a full update runs when the UPS returns */
2099 if (++last_worked
< 10)
2102 /* become aggressive after a few tries */
2103 debx(1, "nudging ups with 'Y', iteration #%d ...", last_worked
);
2110 if (!update_status()) {
2117 /* refresh all variables hourly */
2118 /* does not catch measure-ups II insertion/removal */
2119 if (difftime(now
, last_full
) > 3600) {
2125 if (update_info(all
)) {