1) minor fixes
command '@' has been added to compat tables. All (?) APC models in smart
mode should handle it
ignore / alert sets have been adjusted to be more clear; lots of
comments added as well
upsdrv_shutdown_advanced() - fixed 'continue;' blocking certain
methods to be ever used
update author in comments
some other comments' updates
2) heavy stuff - ICANON
This patch add canonical processing mode. All reads and flushes are done
now by upsread() and upsflush(); '*' which is sort-of-alert (and behaves
as EOL), is handled in upsread(); upsread() behaviour is controlled
by SER_* flags; code has been updated to use new functions instead of
direct calls to ser_*();
Signed-off-by: Michal Soltys <[email protected]>
---
drivers/apcsmart.c | 270 +++++++++++++++++++++++++++++++++++-----------------
drivers/apcsmart.h | 127 ++++++++++++++++---------
2 files changed, 267 insertions(+), 130 deletions(-)
diff --git a/drivers/apcsmart.c b/drivers/apcsmart.c
index d87cc5f..0a9e1bb 100644
--- a/drivers/apcsmart.c
+++ b/drivers/apcsmart.c
@@ -3,6 +3,7 @@
Copyright (C) 1999 Russell Kroll <[email protected]>
(C) 2000 Nigel Metheringham <[email protected]>
+ (C) 2011 Michal Soltys <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -197,20 +198,99 @@ static void alert_handler(char ch)
ups_status_set();
}
-static int read_buf(char *buf, size_t buflen)
+static void upsflush(int flags)
{
- int ret;
+ char temp[64];
- ret = ser_get_line_alert(upsfd, buf, buflen, ENDCHAR, POLL_IGNORE,
- POLL_ALERT, alert_handler, SER_WAIT_SEC, SER_WAIT_USEC);
+ if (flags & SER_AL) {
+ while(ser_get_line_alert(upsfd, temp, sizeof(temp), ENDCHAR, IGN_AACHARS, ALERT_CHARS, alert_handler, 0, 0) > 0);
+ } else {
+ while(ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGN_CHARS, 0, 0) > 0);
+ }
+}
- if (ret < 1) {
- ser_comm_fail("%s", ret ? strerror(errno) : "timeout");
- return ret;
+/*
+ * we need a tiny bit different processing due to '*' and canonical mode; the
+ * function is subtly different from generic ser_get_line_alert()
+ */
+static int upsread(char *buf, size_t buflen, int flags)
+{
+ const char *iset = IGN_CHARS, *aset = "";
+ size_t count = 0;
+ int i, ret, sec = 3, usec = 0;
+ char temp[512];
+
+ if (flags & SER_CC) {
+ iset = IGN_CCCHARS;
+ /*
+ * 3 sec is near the edge of how much this command can take
+ * until ENDCHAR shows up in the input; bump to 6 seconds
+ * to be on the safe side
+ */
+ sec = 6;
+ }
+ if (flags & SER_AL) {
+ iset = IGN_AACHARS;
+ aset = ALERT_CHARS;
+ }
+ if (flags & SER_SD) {
+ /* cut down timeout to 1.5 sec */
+ sec = 1;
+ usec = 500000;
+ flags |= SER_TO;
+ }
+ if (flags & SER_AX) {
+ flags |= SER_SD;
+ }
+
+ memset(buf, '\0', buflen);
+
+ while (count < buflen - 1) {
+ ret = select_read(upsfd, temp, sizeof(temp), sec, usec);
+
+ /* error or no timeout allowed */
+ if (ret < 0 || (ret == 0 && !(flags & SER_TO))) {
+ ser_comm_fail("%s", ret ? strerror(errno) : "timeout");
+ return ret;
+ }
+ /* ok, timeout is acceptable */
+ if (ret == 0 && (flags & SER_TO)) {
+ break;
+ }
+
+ for (i = 0; i < ret; i++) {
+ /* standard "line received" condition */
+ if ((count == buflen - 1) || (temp[i] == ENDCHAR)) {
+ ser_comm_good();
+ return count;
+ }
+ /*
+ * '*' is set as a secondary EOL; return '*' only as a
+ * reply to shutdown command in sdok(); otherwise next
+ * select_read() will continue normally
+ */
+ if ((flags & SER_AX) && temp[i] == '*') {
+ buf[0] = '*';
+ buf[1] = '\0';
+ ser_comm_good();
+ return 1;
+ }
+ /* ignore set */
+ if (strchr(iset, temp[i]) || temp[i] == '*') {
+ continue;
+ }
+ /* alert set */
+ if (strchr(aset, temp[i])) {
+ alert_handler(temp[i]);
+ continue;
+ }
+
+ buf[count++] = temp[i];
+ }
}
ser_comm_good();
- return ret;
+ return count;
}
static int poll_data(apc_vartab_t *vt)
@@ -231,7 +311,7 @@ static int poll_data(apc_vartab_t *vt)
return 0;
}
- if (read_buf(tmp, sizeof(tmp)) < 1) {
+ if (upsread(tmp, sizeof(tmp), SER_AL) < 1) {
dstate_datastale();
return 0;
}
@@ -270,8 +350,7 @@ static int query_ups(const char *var, int first)
return 0;
/* empty the input buffer (while allowing the alert handler to run) */
- ret = ser_get_line_alert(upsfd, temp, sizeof(temp), ENDCHAR,
- POLL_IGNORE, POLL_ALERT, alert_handler, 0, 0);
+ upsflush(SER_AL);
ret = ser_send_char(upsfd, vt->cmd);
@@ -280,16 +359,8 @@ static int query_ups(const char *var, int first)
return 0;
}
- ret = ser_get_line_alert(upsfd, temp, sizeof(temp), ENDCHAR,
- POLL_IGNORE, POLL_ALERT, alert_handler, SER_WAIT_SEC,
- SER_WAIT_USEC);
-
- if ((ret < 1) && (first == 0)) {
- ser_comm_fail("%s", ret ? strerror(errno) : "timeout");
- return 0;
- }
-
- ser_comm_good();
+ /* at the first run, read() is allowed to timeout */
+ ret = upsread(temp, sizeof(temp), SER_AL | (first ? SER_TO : 0));
if ((ret < 1) || (!strcmp(temp, "NA"))) /* not supported */
return 0;
@@ -326,9 +397,11 @@ static void do_capabilities(void)
return;
}
- /* note different IGN set since ^Z returns things like # */
- ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR,
- MINIGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC);
+ /*
+ * note SER_CC - upsread() needs larger timeout grace and different
+ * ignore set due to certain characters like '#' being received
+ */
+ ret = upsread(temp, sizeof(temp), SER_CC);
if ((ret < 1) || (!strcmp(temp, "NA"))) {
@@ -422,7 +495,7 @@ static int update_status(void)
upsdebugx(4, "update_status");
- ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsflush(SER_AL);
ret = ser_send_char(upsfd, APC_STATUS);
@@ -432,7 +505,7 @@ static int update_status(void)
return 0;
}
- ret = read_buf(buf, sizeof(buf));
+ ret = upsread(buf, sizeof(buf), SER_AL);
if ((ret < 1) || (!strcmp(buf, "NA"))) {
dstate_datastale();
@@ -547,8 +620,7 @@ static int firmware_table_lookup(void)
return 0;
}
- ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, IGNCHARS,
- SER_WAIT_SEC, SER_WAIT_USEC);
+ ret = upsread(buf, sizeof(buf), SER_TO);
/*
* Some UPSes support both 'V' and 'b'. As 'b' doesn't always return
@@ -563,11 +635,10 @@ static int firmware_table_lookup(void)
return 0;
}
- ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, IGNCHARS,
- SER_WAIT_SEC, SER_WAIT_USEC);
+ ret = upsread(buf, sizeof(buf), SER_TO);
if (ret < 1) {
- upslog_with_errno(LOG_ERR, "firmware_table_lookup: ser_get_line failed");
+ upslog_with_errno(LOG_ERR, "firmware_table_lookup: upsread failed");
return 0;
}
}
@@ -630,8 +701,7 @@ static void getbaseinfo(void)
return;
}
- ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS,
- SER_WAIT_SEC, SER_WAIT_USEC);
+ ret = upsread(temp, sizeof(temp), SER_TO);
if ((ret < 1) || (!strcmp(temp, "NA"))) {
/* We have an old dumb UPS - go to specific code for old stuff */
@@ -640,12 +710,13 @@ static void getbaseinfo(void)
}
upsdebugx(1, "APC - Parsing out command set");
- /* We have the version.alert.cmdchars string
- NB the alert chars are normally in IGNCHARS
- so will have been pretty much edited out.
- You will need to change the ser_get_line above if
- you want to check those out too....
- */
+ /*
+ * note that upsread() above will filter commands overlapping with
+ * alerts; we don't really care about those for the needed
+ * functionality - but keep in mind 'a' reports them, should you ever
+ * need them; in such case, it would be best to e.g. add SER_CS,
+ * IGN_CSCHARS and adjust upsread() accordingly
+ */
alrts = strchr(temp, '.');
if (alrts == NULL) {
fatalx(EXIT_FAILURE, "Unable to split APC version string");
@@ -681,7 +752,7 @@ static int do_cal(int start)
return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
}
- ret = read_buf(temp, sizeof(temp));
+ ret = upsread(temp, sizeof(temp), SER_AL);
/* if we can't check the current calibration status, bail out */
if ((ret < 1) || (!strcmp(temp, "NA")))
@@ -707,7 +778,7 @@ static int do_cal(int start)
return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
}
- ret = read_buf(temp, sizeof(temp));
+ ret = upsread(temp, sizeof(temp), SER_AL);
if ((ret < 1) || (!strcmp(temp, "NA")) || (!strcmp(temp, "NO"))) {
upslogx(LOG_WARNING, "Stop calibration failed: %s",
@@ -734,7 +805,7 @@ static int do_cal(int start)
return STAT_INSTCMD_HANDLED; /* FUTURE: failure */
}
- ret = read_buf(temp, sizeof(temp));
+ ret = upsread(temp, sizeof(temp), SER_AL);
if ((ret < 1) || (!strcmp(temp, "NA")) || (!strcmp(temp, "NO"))) {
upslogx(LOG_WARNING, "Start calibration failed: %s", temp);
@@ -759,12 +830,10 @@ static int smartmode(void)
return 0;
}
- ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR,
- IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC);
+ ret = upsread(temp, sizeof(temp), SER_TO);
- if (ret > 0)
- if (!strcmp(temp, "SM"))
- return 1; /* success */
+ if (ret > 0 && !strcmp(temp, "SM"))
+ return 1; /* success */
sleep(1); /* wait before trying again */
@@ -778,8 +847,7 @@ static int smartmode(void)
}
/* eat the response (might be NA, might be something else) */
- ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR,
- IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC);
+ upsread(temp, sizeof(temp), SER_TO);
}
return 0; /* failure */
@@ -792,8 +860,12 @@ static int sdok(void)
{
char temp[16];
- ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC);
- upsdebugx(4, "sdok: got \"%s\"", temp);
+ /*
+ * older upses on failed commands might just timeout, we cut down
+ * timeout grace in upsread though
+ */
+ upsread(temp, sizeof(temp), SER_AX);
+ upsdebugx(4, "shutdown reply: got \"%s\"", temp);
if (!strcmp(temp, "*") || !strcmp(temp, "OK")) {
upsdebugx(4, "Last issued shutdown command succeeded");
@@ -807,7 +879,7 @@ static int sdok(void)
/* soft hibernate: S - working only when OB, otherwise ignored */
static int sdcmd_S(int dummy)
{
- ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsflush(0);
upsdebugx(1, "Issuing soft hibernate");
ser_send_char(upsfd, APC_CMD_SOFTDOWN);
@@ -816,15 +888,18 @@ static int sdcmd_S(int dummy)
}
/* soft hibernate, hack version for CS 350 */
-static int sdcmd_CS(int tval)
+static int sdcmd_CS(int status)
{
+ char temp[16];
+
upsdebugx(1, "Using CS 350 'force OB' shutdown method");
- if (tval & APC_STAT_OL) {
+ if (status & APC_STAT_OL) {
upsdebugx(1, "On-line - forcing OB temporarily");
ser_send_char(upsfd, 'U');
- usleep(UPSDELAY);
+ /* eat response */
+ upsread(temp, sizeof(temp), SER_SD);
}
- return sdcmd_S(tval);
+ return sdcmd_S(0);
}
/*
@@ -836,7 +911,7 @@ static int sdcmd_ATn(int cnt)
{
int n = 0, mmax, ret;
const char *strval;
- char timer[4];
+ char temp[16];
mmax = cnt == 2 ? 99 : 999;
@@ -847,14 +922,14 @@ static int sdcmd_ATn(int cnt)
n = 0;
}
- snprintf(timer, sizeof(timer), "%.*d", cnt, n);
+ snprintf(temp, sizeof(temp), "%.*d", cnt, n);
- ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsflush(0);
upsdebugx(1, "Issuing hard hibernate with %d minutes additional wakeup delay", n*6);
ser_send_char(upsfd, APC_CMD_GRACEDOWN);
usleep(CMDLONGDELAY);
- ser_send_pace(upsfd, UPSDELAY, "%s", timer);
+ ser_send_pace(upsfd, UPSDELAY, "%s", temp);
ret = sdok();
if (ret || cnt == 3)
@@ -867,8 +942,8 @@ static int sdcmd_ATn(int cnt)
* silent (YMMV);
*/
ser_send_char(upsfd, APC_CMD_GRACEDOWN);
- usleep(UPSDELAY);
- ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ /* eat response */
+ upsread(temp, sizeof(temp), SER_SD);
return 0;
}
@@ -876,7 +951,7 @@ static int sdcmd_ATn(int cnt)
/* shutdown: K - delayed poweroff */
static int sdcmd_K(int dummy)
{
- ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsflush(0);
upsdebugx(1, "Issuing delayed poweroff");
ser_send_char(upsfd, APC_CMD_SHUTDOWN);
@@ -889,7 +964,7 @@ static int sdcmd_K(int dummy)
/* shutdown: Z - immediate poweroff */
static int sdcmd_Z(int dummy)
{
- ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsflush(0);
upsdebugx(1, "Issuing immediate poweroff");
ser_send_char(upsfd, APC_CMD_OFF);
@@ -1005,16 +1080,18 @@ static void upsdrv_shutdown_advanced(int status)
*/
for (i = 0; i < strlen(strval); i++) {
- if (strval[i] - 48 == SDIDX_CS) {
- n = status;
- } else if (strval[i] - 48 == SDIDX_AT3N) {
- n = 3;
- } else if (strval[i] - 48 == SDIDX_AT2N) {
- n = 2;
- } else {
- /* the value of 'n' needs to be set at this point, but it isn't */
- continue;
+ switch (strval[i] - 48) {
+ case SDIDX_CS:
+ n = status;
+ break;
+ case SDIDX_AT3N:
+ n = 3;
+ break;
+ case SDIDX_AT2N:
+ default:
+ n = 2;
}
+
if (sdlist[strval[i] - 48](n))
break; /* finish if command succeeded */
}
@@ -1034,8 +1111,7 @@ void upsdrv_shutdown(void)
ret = ser_send_char(upsfd, APC_STATUS);
if (ret == 1) {
- ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR,
- IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC);
+ ret = upsread(temp, sizeof(temp), SER_SD);
if (ret < 1) {
upsdebugx(1, "Status read failed ! Assuming on battery state");
@@ -1105,7 +1181,7 @@ static int setvar_enum(apc_vartab_t *vt, const char *val)
char orig[256], temp[256];
const char *ptr;
- ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsflush(SER_AL);
ret = ser_send_char(upsfd, vt->cmd);
if (ret != 1) {
@@ -1113,7 +1189,7 @@ static int setvar_enum(apc_vartab_t *vt, const char *val)
return STAT_SET_HANDLED; /* FUTURE: failed */
}
- ret = read_buf(orig, sizeof(orig));
+ ret = upsread(orig, sizeof(orig), SER_AL);
if ((ret < 1) || (!strcmp(orig, "NA")))
return STAT_SET_HANDLED; /* FUTURE: failed */
@@ -1137,7 +1213,7 @@ static int setvar_enum(apc_vartab_t *vt, const char *val)
}
/* this should return either OK (if rotated) or NO (if not) */
- ret = read_buf(temp, sizeof(temp));
+ ret = upsread(temp, sizeof(temp), SER_AL);
if ((ret < 1) || (!strcmp(temp, "NA")))
return STAT_SET_HANDLED; /* FUTURE: failed */
@@ -1156,7 +1232,7 @@ static int setvar_enum(apc_vartab_t *vt, const char *val)
return STAT_SET_HANDLED; /* FUTURE: failed */
}
- ret = read_buf(temp, sizeof(temp));
+ ret = upsread(temp, sizeof(temp), SER_AL);
if ((ret < 1) || (!strcmp(temp, "NA")))
return STAT_SET_HANDLED; /* FUTURE: failed */
@@ -1199,7 +1275,7 @@ static int setvar_string(apc_vartab_t *vt, const char *val)
int ret;
char temp[256];
- ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsflush(SER_AL);
ret = ser_send_char(upsfd, vt->cmd);
if (ret != 1) {
@@ -1207,7 +1283,7 @@ static int setvar_string(apc_vartab_t *vt, const char *val)
return STAT_SET_HANDLED; /* FUTURE: failed */
}
- ret = read_buf(temp, sizeof(temp));
+ ret = upsread(temp, sizeof(temp), SER_AL);
if ((ret < 1) || (!strcmp(temp, "NA")))
return STAT_SET_HANDLED; /* FUTURE: failed */
@@ -1252,7 +1328,7 @@ static int setvar_string(apc_vartab_t *vt, const char *val)
usleep(UPSDELAY);
}
- ret = read_buf(temp, sizeof(temp));
+ ret = upsread(temp, sizeof(temp), SER_AL);
if (ret < 1) {
upslogx(LOG_ERR, "setvar_string: short final read");
@@ -1302,7 +1378,7 @@ static int do_cmd(apc_cmdtab_t *ct)
int ret;
char buf[SMALLBUF];
- ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsflush(SER_AL);
ret = ser_send_char(upsfd, ct->cmd);
if (ret != 1) {
@@ -1322,7 +1398,7 @@ static int do_cmd(apc_cmdtab_t *ct)
}
}
- ret = read_buf(buf, sizeof(buf));
+ ret = upsread(buf, sizeof(buf), SER_AL);
if (ret < 1)
return STAT_INSTCMD_HANDLED; /* FUTURE: failed */
@@ -1414,7 +1490,8 @@ void upsdrv_makevartable(void)
void upsdrv_initups(void)
{
- char *cable;
+ struct termios tio;
+ char *cable;
upsfd = ser_open(device_path);
ser_set_speed(upsfd, device_path, B2400);
@@ -1424,6 +1501,27 @@ void upsdrv_initups(void)
if (cable && !strcasecmp(cable, ALT_CABLE_1))
init_serial_0095B();
+ /* enable canonical processing */
+ memset(&tio, 0, sizeof(tio));
+ if (tcgetattr(upsfd, &tio) != 0)
+ fatal_with_errno(EXIT_FAILURE, "tcgetattr(%s)", device_path);
+
+ tio.c_lflag |= ICANON;
+ tio.c_lflag &= ~ISIG;
+
+ tio.c_iflag |= IGNCR;
+ tio.c_iflag &= ~(IXON | IXOFF);
+
+ tio.c_cc[VERASE] = _POSIX_VDISABLE;
+ tio.c_cc[VKILL] = _POSIX_VDISABLE;
+
+ tio.c_cc[VEOL] = '*'; /* specially handled in upsread() */
+ tio.c_cc[VEOL2] = _POSIX_VDISABLE;
+ tio.c_cc[VEOF] = _POSIX_VDISABLE;
+
+ if (tcsetattr(upsfd, TCSANOW, &tio) != 0)
+ fatal_with_errno(EXIT_FAILURE, "tcsetattr(%s)", device_path);
+
/* make sure we wake up if the UPS sends alert chars to us */
extrafd = upsfd;
}
@@ -1465,7 +1563,7 @@ void upsdrv_updateinfo(void)
/* try to wake up a dead ups once in awhile */
if ((dstate_is_stale()) && (!smartmode())) {
- ser_comm_fail("Communications with UPS lost - check cabling");
+ upslogx(LOG_ERR, "Communications with UPS lost - check cabling");
/* reset this so a full update runs when the UPS returns */
last_full = 0;
diff --git a/drivers/apcsmart.h b/drivers/apcsmart.h
index f143cfa..8ebb249 100644
--- a/drivers/apcsmart.h
+++ b/drivers/apcsmart.h
@@ -2,6 +2,7 @@
Copyright (C) 1999 Russell Kroll <[email protected]>
(C) 2000 Nigel Metheringham <[email protected]>
+ (C) 2011 Michal Soltys <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,27 +26,58 @@
#define APC_TABLE_VERSION "version 2.2"
+/*
+ * alerts and other stuff for quick reference:
+ *
+ * $ OL
+ * ! OB
+ * % LB
+ * + not LB
+ * # RB
+ * ? OVER
+ * = not OVER
+ * * powering down now (only older models ?), handled by upsread()
+ * otherwise ignored (it doesn't have to be in ignore sets)
+ *
+ * | eeprom change
+ * & check alarm register for fail
+ * ~ ???
+ */
+
+/*
+ * old ones for reference:
+ * #define IGNCHARS "\015+$|!~%?=#&"
+ * #define POLL_IGNORE "\015&|"
+ * #define POLL_ALERT "$!%+#?="
+ * #define MINIGNCHARS "\015+$|!"
+ * notice ~ that was present in IGNCHARS, but not in POLL_IGNORE - this kinda
+ * didn't make sense (?); new versions doesn't filter ~, but keep that in mind
+ * in case something obscure surfaces
+ * due to switch to ICANON tty mode, we removed \015 from ignored characters,
+ * as it's handled by IGNCR at read() level
+ */
+
/* Basic UPS reply line structure */
#define ENDCHAR 10 /* APC ends responses with LF */
-/* characters ignored by default */
-#define IGNCHARS "\015+$|!~%?=#&" /* special characters to ignore */
+/* what to ignore during alert aware serial reads */
+#define IGN_AACHARS "|&"
-/* these one is used only during startup, due to ^Z sending certain characters such as # */
-#define MINIGNCHARS "\015+$|!" /* minimum set of special characters to ignore */
+/* what alert_handler() should care about */
+#define ALERT_CHARS "$!%+#?="
-/* normal polls: characters we don't want to parse (including a few alerts) */
-#define POLL_IGNORE "\015&|"
+/* characters ignored by alertless reads */
+#define IGN_CHARS IGN_AACHARS ALERT_CHARS
-/* alert characters we care about - OL, OB, LB, not LB, RB, OVER, not OVER */
-#define POLL_ALERT "$!%+#?="
+/*
+ * these ones are used only during capability read, due to ^Z sending certain
+ * characters such as #; it seems it could be equal to just IGN_CHARS w/o #
+ */
+#define IGN_CCCHARS "|$!+" /* capability check ignore set */
#define UPSDELAY 50000 /* slow down multicharacter commands */
#define CMDLONGDELAY 1500000 /* some commands need a 1.5s gap for safety */
-#define SER_WAIT_SEC 3 /* wait up to 3.0 sec for ser_get calls */
-#define SER_WAIT_USEC 0
-
/* dangerous instant commands must be reconfirmed within a 12 second window */
#define MINCMDTIME 3
#define MAXCMDTIME 15
@@ -53,6 +85,13 @@
/* it only does two strings, and they're both the same length */
#define APC_STRLEN 8
+/* how upsread() should behave */
+#define SER_AL 0x01 /* run with alarm handler */
+#define SER_TO 0x02 /* allow timeout without error */
+#define SER_CC 0x04 /* prepare for capability check (^Z) processing */
+#define SER_SD 0x08 /* prepare for shutdown command processing */
+#define SER_AX 0x10 /* prepare for '*' handling */
+
/* --------------- */
/* status bits */
@@ -79,13 +118,13 @@
/* Driver command table flag values */
#define APC_POLL 0x0001 /* Poll this variable regularly */
-#define APC_PRESENT 0x0004 /* Capability seen on this UPS */
+#define APC_PRESENT 0x0002 /* Capability seen on this UPS */
#define APC_RW 0x0010 /* read-write variable */
#define APC_ENUM 0x0020 /* enumerated type */
#define APC_STRING 0x0040 /* string */
-#define APC_NASTY 0x0100 /* Nasty command - take care */
+#define APC_NASTY 0x0100 /* Nasty command - must be reconfirmed */
#define APC_REPEAT 0x0200 /* Command needs sending twice */
#define APC_FORMATMASK 0xFF0000 /* Mask for apc data formats */
@@ -100,12 +139,12 @@
#define APC_F_MINUTES 0x110000 /* Time in minutes */
#define APC_F_HOURS 0x120000 /* Time in hours */
#define APC_F_REASON 0x130000 /* Reason of transfer */
-#define APC_F_LEAVE 0 /* Just pass this through */
+#define APC_F_LEAVE 0x000000 /* Just pass this through */
typedef struct {
- const char *name; /* the variable name */
- unsigned int flags; /* various flags */
- char cmd; /* command character */
+ const char *name; /* the variable name */
+ unsigned int flags; /* various flags */
+ char cmd; /* command character */
} apc_vartab_t;
apc_vartab_t apc_vartab[] = {
@@ -252,40 +291,40 @@ struct {
int flags;
} compat_tab[] = {
/* APC Matrix */
- { "0XI", "789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
- { "0XM", "789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
- { "0ZI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
- { "5UI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
- { "5ZM", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
+ { "0XI", "@789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
+ { "0XM", "@789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
+ { "0ZI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
+ { "5UI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
+ { "5ZM", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
/* APC600 */
- { "6QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
- { "6QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
- { "6TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
- { "6TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "6QD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "6QI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "6TD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "6TI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
/* SmartUPS 900 */
- { "7QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
- { "7QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
- { "7TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
- { "7TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "7QD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "7QI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "7TD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "7TI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
/* SmartUPS 900I */
- { "7II", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
+ { "7II", "@79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
/* SmartUPS 2000I */
- { "9II", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
- { "9GI", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
+ { "9II", "@79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
+ { "9GI", "@79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
/* SmartUPS 1250 */
- { "8QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
- { "8QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
- { "8TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
- { "8TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "8QD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "8QI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "8TD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
+ { "8TI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
/* CS 350 */
- { "5.4.D", "\1ABPQRSUYbdfgjmnx9", 0 },
+ { "5.4.D", "@\1ABPQRSUYbdfgjmnx9", 0 },
/* Smart-UPS 600 */
- { "D9", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
- { "D8", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
- { "D7", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
- { "D6", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
- { "D5", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
- { "D4", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
+ { "D9", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
+ { "D8", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
+ { "D7", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
+ { "D6", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
+ { "D5", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
+ { "D4", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
{ NULL, NULL, 0 },
};
_______________________________________________
Nut-upsdev mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/nut-upsdev