/* apcsmart.h - command table for APC smart protocol units Copyright (C) 1999 Russell Kroll (C) 2000 Nigel Metheringham 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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "serial.h" #include "timehead.h" #define APC_TABLE_VERSION "version 2.1" /* Basic UPS reply line structure */ #define ENDCHAR 10 /* APC ends responses with LF */ /* these two are only used during startup */ #define IGNCHARS "\015+$|!~%?=*#&" /* special characters to ignore */ #define MINIGNCHARS "\015+$|!" /* minimum set of special characters to ignore */ /* normal polls: characters we don't want to parse (including a few alerts) */ #define POLL_IGNORE "\015?=*&|" /* alert characters we care about - OL, OB, LB, not LB, RB */ #define POLL_ALERT "$!%+#" #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 /* it only does two strings, and they're both the same length */ #define APC_STRLEN 8 /* --------------- */ /* status bits */ #define APC_STAT_CAL 1 /* calibration */ #define APC_STAT_TRIM 2 /* SmartTrim */ #define APC_STAT_BOOST 4 /* SmartBoost */ #define APC_STAT_OL 8 /* on line */ #define APC_STAT_OB 16 /* on battery */ #define APC_STAT_OVER 32 /* overload */ #define APC_STAT_LB 64 /* low battery */ #define APC_STAT_RB 128 /* replace battery */ /* serial protocol: special commands - initialization and such */ #define APC_STATUS 'Q' #define APC_GOSMART 'Y' #define APC_GODUMB 'R' #define APC_CMDSET 'a' #define APC_CAPABILITY 26 /* ^Z */ #define APC_NEXTVAL '-' /* --------------- */ /* Driver command table flag values */ #define APC_POLL 0x0001 /* Poll this variable regularly */ #define APC_IGNORE 0x0002 /* Never poll this */ #define APC_PRESENT 0x0004 /* 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_REPEAT 0x0200 /* Command needs sending twice */ #define APC_FORMATMASK 0xFF0000 /* Mask for apc data formats */ #define APC_F_PERCENT 0x020000 /* Data in a percent format */ #define APC_F_VOLT 0x030000 /* Data in a voltage format */ #define APC_F_AMP 0x040000 /* Data in a current/amp format */ #define APC_F_CELSIUS 0x050000 /* Data in a temp/C format */ #define APC_F_HEX 0x060000 /* Data in a hex number format */ #define APC_F_DEC 0x070000 /* Data in a decimal format */ #define APC_F_SECONDS 0x100000 /* Time in seconds */ #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 */ typedef struct { const char *name; /* the variable name */ unsigned int flags; /* various flags */ char cmd; /* command character */ } apc_vartab_t; apc_vartab_t apc_vartab[] = { { "ups.firmware", 0, 'b' }, { "ups.firmware.aux", 0, 'v' }, { "ups.model", 0, 0x01 }, /* FUTURE: depends on variable naming scheme */ #if 0 { "ups.model.code", 0, 'V' }, #endif { "ups.serial", 0, 'n' }, { "ups.mfr.date", 0, 'm' }, { "ups.temperature", APC_POLL|APC_F_CELSIUS, 'C' }, { "ups.load", APC_POLL|APC_F_PERCENT, 'P' }, { "ups.test.interval", APC_F_HOURS, 'E' }, { "ups.test.result", APC_POLL, 'X' }, { "ups.delay.start", APC_F_SECONDS, 'r' }, { "ups.delay.shutdown", APC_F_SECONDS, 'p' }, { "ups.id", APC_STRING, 'c' }, { "ups.contacts", APC_POLL|APC_F_HEX, 'i' }, { "ups.display.language", 0, 0x0C }, { "input.voltage", APC_POLL|APC_F_VOLT, 'L' }, { "input.frequency", APC_POLL|APC_F_DEC, 'F' }, { "input.sensitivity", 0, 's' }, { "input.quality", APC_POLL|APC_F_HEX, '9' }, { "input.transfer.low", APC_F_VOLT, 'l' }, { "input.transfer.high", APC_F_VOLT, 'u' }, { "input.transfer.reason", APC_POLL|APC_F_REASON, 'G' }, { "input.voltage.maximum", APC_POLL|APC_F_VOLT, 'M' }, { "input.voltage.minimum", APC_POLL|APC_F_VOLT, 'N' }, { "output.current", APC_POLL|APC_F_AMP, '/' }, { "output.voltage", APC_POLL|APC_F_VOLT, 'O' }, { "output.voltage.nominal", APC_F_VOLT, 'o' }, { "ambient.humidity", APC_POLL|APC_F_PERCENT, 'h' }, { "ambient.humidity.high", APC_F_PERCENT, '{' }, { "ambient.humidity.low", APC_F_PERCENT, '}' }, { "ambient.temperature", APC_POLL|APC_F_CELSIUS, 't' }, { "ambient.temperature.high", APC_F_CELSIUS, '[' }, { "ambient.temperature.low", APC_F_CELSIUS, ']' }, { "battery.date", APC_STRING, 'x' }, { "battery.charge", APC_POLL|APC_F_PERCENT, 'f' }, { "battery.charge.restart", APC_F_PERCENT, 'e' }, { "battery.voltage", APC_POLL|APC_F_VOLT, 'B' }, { "battery.voltage.nominal", 0, 'g' }, { "battery.runtime", APC_POLL|APC_F_MINUTES, 'j' }, { "battery.runtime.low", APC_F_MINUTES, 'q' }, { "battery.packs", APC_F_DEC, '>' }, { "battery.packs.bad", APC_F_DEC, '<' }, { "battery.alarm.threshold", 0, 'k' }, /* todo: I = alarm enable (hex field) - split into alarm.n.enable J = alarm status (hex field) - split into alarm.n.status 0x15 = output voltage selection (APC_F_VOLT) 0x5C = load power (APC_POLL|APC_F_PERCENT) */ {NULL, 0, 0}, }; /* ------ instant commands ------ */ #define APC_CMD_FPTEST 'A' #define APC_CMD_CALTOGGLE 'D' #define APC_CMD_SHUTDOWN 'K' #define APC_CMD_SOFTDOWN 'S' #define APC_CMD_SIMPWF 'U' #define APC_CMD_BTESTTOGGLE 'W' #define APC_CMD_OFF 'Z' #define APC_CMD_ON 0x0E /* ^N */ #define APC_CMD_BYPTOGGLE '^' typedef struct { const char *name; int flags; char cmd; } apc_cmdtab_t; apc_cmdtab_t apc_cmdtab[] = { { "load.off", APC_NASTY|APC_REPEAT, APC_CMD_OFF }, { "load.on", APC_REPEAT, APC_CMD_ON }, { "test.panel.start", 0, APC_CMD_FPTEST }, { "test.failure.start", 0, APC_CMD_SIMPWF }, { "test.battery.start", 0, APC_CMD_BTESTTOGGLE }, { "test.battery.stop", 0, APC_CMD_BTESTTOGGLE }, { "shutdown.return", APC_NASTY, APC_CMD_SOFTDOWN }, { "shutdown.stayoff", APC_NASTY|APC_REPEAT, APC_CMD_SHUTDOWN }, { "calibrate.start", 0, APC_CMD_CALTOGGLE }, { "calibrate.stop", 0, APC_CMD_CALTOGGLE }, { "bypass.start", 0, APC_CMD_BYPTOGGLE }, { "bypass.stop", 0, APC_CMD_BYPTOGGLE }, { NULL, 0, 0 } }; /* things to ignore in protocol_verify - useless variables, etc. */ #define CMD_IGN_CHARS "\032-78@.,~\047\177QHRTYayz)1IJ" /* compatibility with hardware that doesn't do APC_CMDSET ('a') */ struct { const char *firmware; const char *cmdchars; int flags; } compat_tab[] = { /* APC Matrix */ { "0ZI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 }, { "5UI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 }, { "5ZM", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 }, /* APC600 */ { "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 }, /* SmartUPS 1250. */ { "8QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "8QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "8TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "8TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, /* CS 350 */ { "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 }, { NULL, NULL, 0 }, };