1
/* bestups.c - model specific routines for Best-UPS Fortress models
3
Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
#define ENDCHAR 13 /* replies end with CR */
26
#define DRV_VERSION "0.60"
28
static char *modelname, *va;
29
static float lowvolt = 0, highvolt = 0, voltrange = 0;
30
static int linenorm = 0, poll_failures = 0;
31
static int inverted_bypass_bit = 0;
33
static void setmodel(const char *abbr, const char *va)
35
if (!strcmp(abbr, "FOR")) {
36
dstate_setinfo("ups.mfr", "%s", "Best Power");
37
dstate_setinfo("ups.model", "Fortress %s", va);
41
if (!strcmp(abbr, "FTC")) {
42
dstate_setinfo("ups.mfr", "%s", "Best Power");
43
dstate_setinfo("ups.model", "Fortress Telecom %s", va);
47
if (!strcmp(abbr, "PRO")) {
48
dstate_setinfo("ups.mfr", "%s", "Best Power");
49
dstate_setinfo("ups.model", "Patriot Pro %s", va);
50
inverted_bypass_bit = 1;
54
if (!strcmp(abbr, "PR2")) {
55
dstate_setinfo("ups.mfr", "%s", "Best Power");
56
dstate_setinfo("ups.model", "Patriot Pro II %s", va);
57
inverted_bypass_bit = 1;
61
if (!strcmp(abbr, "325")) {
62
dstate_setinfo("ups.mfr", "%s", "Sola Australia");
63
dstate_setinfo("ups.model", "Sola 325 %s", va);
67
if (!strcmp(abbr, "520")) {
68
dstate_setinfo("ups.mfr", "%s", "Sola Australia");
69
dstate_setinfo("ups.model", "Sola 520 %s", va);
73
if (!strcmp(abbr, "620")) {
74
dstate_setinfo("ups.mfr", "%s", "Sola Australia");
75
dstate_setinfo("ups.model", "Sola 620 %s", va);
79
if (!strcmp(abbr, "AX1")) {
80
dstate_setinfo("ups.mfr", "%s", "Best Power");
81
dstate_setinfo("ups.model", "Axxium Rackmount %s", va);
85
dstate_setinfo("ups.mfr", "%s", "Unknown");
86
dstate_setinfo("ups.model", "Unknown %s (%s)", abbr, va);
88
printf("Unknown model detected - please report this ID: '%s'\n", abbr);
91
int instcmd(const char *cmdname, const char *extra)
93
if (!strcasecmp(cmdname, "test.battery.stop")) {
98
return STAT_INSTCMD_HANDLED;
101
if (!strcasecmp(cmdname, "test.battery.start")) {
105
return STAT_INSTCMD_HANDLED;
108
upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
109
return STAT_INSTCMD_UNKNOWN;
112
void upsdrv_initinfo(void)
114
dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
115
dstate_addcmd("test.battery.start");
116
dstate_addcmd("test.battery.stop");
118
setmodel(modelname, va);
119
printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"),
120
dstate_getinfo("ups.model"), device_path);
122
upsh.new_instcmd = instcmd;
124
/* paranoia - cancel any shutdown that might already be running */
129
static void setup_serial(void)
133
if (tcgetattr(upsfd, &tio) == -1)
136
tio.c_iflag = IXON | IXOFF;
138
tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
143
#ifdef HAVE_CFSETISPEED
144
cfsetispeed(&tio, B2400);
145
cfsetospeed(&tio, B2400);
147
#error This system lacks cfsetispeed() and has no other means to set the speed
150
if (tcsetattr(upsfd, TCSANOW, &tio) == -1)
154
static void ups_sync(void)
159
printf("Syncing with UPS: ");
162
for (i = 0; i < MAXTRIES; i++) {
165
upssend("%s", "\rQ1\r");
172
ret = upsrecv(buf, sizeof(buf), ENDCHAR, "");
174
/* return once we get something that looks usable */
175
if ((ret > 0) && (buf[0] == '(')) {
181
fatalx("\nFailed - giving up...");
184
static int ups_on_line(void)
187
char temp[256], stat[32];
189
printf("Checking line status: ");
192
for (i = 0; i < MAXTRIES; i++) {
200
ret = upsrecv(temp, sizeof(temp), ENDCHAR, "");
202
/* Q1 must return 46 bytes starting with a ( */
203
if ((ret > 0) && (temp[0] == '(') && (strlen(temp) == 46)) {
205
sscanf(temp, "%*s %*s %*s %*s %*s %*s %*s %s", stat);
208
return 1; /* on line */
210
return 0; /* on battery */
214
upslogx(LOG_ERR, "Status read failed: assuming on battery");
216
return 0; /* on battery */
219
void upsdrv_shutdown(void)
221
printf("The UPS will shut down in approximately one minute.\n");
224
printf("The UPS will restart in about one minute.\n");
226
printf("The UPS will restart when power returns.\n");
228
upssend("%s", "S01R0001\r");
231
static int get_ident(char *buf, size_t bufsize)
235
printf("Identifying UPS: ");
238
for (i = 0; i < MAXTRIES; i++) {
242
upssend("%s", "\r\rID\r");
250
ret = upsrecv(buf, bufsize, ENDCHAR, "");
252
/* buf must start with ( and be in the range [25-27] */
253
if ((ret > 0) && (buf[0] != '(') && (strlen(buf) >= 25) &&
254
(strlen(buf) <= 27)) {
261
upslogx(LOG_INFO, "Giving up on hardware detection after %d tries",
267
static void ups_ident(void)
269
char buf[256], *ptr, *com;
272
if (!get_ident(buf, sizeof(buf)))
273
fatalx("Unable to get initial hardware info string");
275
modelname = va = NULL;
277
/* FOR,750,120,120,20.0,27.6 */
280
for (i = 0; i < 6; i++) {
281
com = strchr(ptr, ',');
287
case 0: modelname = xstrdup(ptr);
289
case 1: va = xstrdup(ptr);
291
case 2: linenorm = atoi(ptr);
293
case 4: lowvolt = atof(ptr);
295
case 5: highvolt = atof(ptr);
296
voltrange = highvolt - lowvolt;
307
static void pollfail(char *why)
311
/* ignore the first few since these UPSes tend to drop characters */
312
if (poll_failures == 3)
313
upslogx(LOG_ERR, why);
318
void upsdrv_updateinfo(void)
320
char involt[16], outvolt[16], loadpct[16], acfreq[16],
321
battvolt[16], upstemp[16], stat[16], buf[256];
326
/* this UPS needs a huge delay on queries, so chop up the updates */
328
/* half the time, send the Q1, the other half, read it */
331
upssend("%s", "\rQ1\r");
338
ret = upsrecv(buf, sizeof(buf), ENDCHAR, "");
340
if (strlen(buf) < 46) {
341
pollfail("Poll failed: short read from UPS");
346
if (strlen(buf) > 46) {
347
pollfail("Poll failed: oversized read from UPS");
353
pollfail("Poll failed: invalid start character");
358
/* only say this if it got high enough to log a failure note */
359
if (poll_failures >= 3)
360
upslogx(LOG_NOTICE, "UPS poll succeeded");
364
sscanf(buf, "%*c%s %*s %s %s %s %s %s %s", involt, outvolt,
365
loadpct, acfreq, battvolt, upstemp, stat);
367
bvoltp = ((atof (battvolt) - lowvolt) / voltrange) * 100.0;
372
dstate_setinfo("battery.voltage", "%s", battvolt);
373
dstate_setinfo("input.voltage", "%s", involt);
374
dstate_setinfo("output.voltage", "%s", outvolt);
375
dstate_setinfo("ups.load", "%s", loadpct);
376
dstate_setinfo("input.frequency", "%s", acfreq);
377
dstate_setinfo("ups.temperature", "%s", upstemp);
378
dstate_setinfo("battery.charge", "%02.1f", bvoltp);
382
if (stat[0] == '0') {
383
status_set("OL"); /* on line */
385
/* only allow these when OL since they're bogus when OB */
387
if (stat[2] == (inverted_bypass_bit ? '0' : '1')) {
388
/* boost or trim in effect */
389
if (atof(involt) < atof(outvolt))
392
if (atof(involt) > atof(outvolt))
397
status_set("OB"); /* on battery */
401
status_set("LB"); /* low battery */
407
void upsdrv_help(void)
411
void upsdrv_makevartable(void)
415
void upsdrv_banner(void)
417
printf("Network UPS Tools - Best UPS driver %s (%s)\n",
418
DRV_VERSION, UPS_VERSION);
421
void upsdrv_initups(void)
423
upssend_delay = 100000;
424
open_serial(device_path, B2400);
427
/* don't let upscommon warn about it since it happens way too often */
428
/* this driver does its own checking with better handling */
429
flag_timeoutfailure = -1;
435
void upsdrv_cleanup(void)