2
bestfortress.c - model specific routines for (very) old Best Power Fortress
4
Copyright (C) 2002 Russell Kroll <rkroll@exploits.org> (skeleton)
5
(C) 2002 Holger Dietze <holger.dietze@advis.de>
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
anything commented is optional
24
anything else is mandatory
30
#define IGNCHARS " \n"
32
#if defined(__sgi) && ! defined(__GNUC__)
33
#define inline __inline
36
void instcmd (int auxcmd, int dlen, char *data);
37
void upsdrv_setvar (int, int, char *);
39
void upsdrv_initinfo(void)
41
dstate_setinfo("ups.mfr", "Best Power");
42
dstate_setinfo("ups.model", "Fortress");
43
dstate_setinfo("battery.voltage.nominal", "24");
45
/*addinfo (INFO_ALRM_OVERLOAD, "", 0, 0);*/ /* Flag */
46
/*addinfo (INFO_ALRM_TEMP, "", 0, 0);*/ /* Flag */
48
dstate_setinfo("ups.delay.shutdown", "10"); /* write only */
50
/* tunable via front panel: (european voltage level)
51
parameter factory default range
52
INFO_LOWXFER 196 V p7=nnn 160-210
53
INFO_HIGHXFER 254 V p8=nnn 215-274
54
INFO_LOBATTIME 2 min p2=n 1-5
56
comm mode p6=0 dumb DONT USE (will lose access to parameter setting!)
61
maybe cycle through speeds to autodetect?
66
dstate_setinfo("input.transfer.low", "");
67
dstate_setflags("input.transfer.low", ST_FLAG_STRING | ST_FLAG_RW);
68
dstate_setaux("input.transfer.low", 3);
70
dstate_setinfo("input.transfer.high", "");
71
dstate_setflags("input.transfer.high", ST_FLAG_STRING | ST_FLAG_RW);
72
dstate_setaux("input.transfer.high", 3);
74
dstate_setinfo("battery.runtime.low", "");
75
dstate_setflags("battery.runtime.low", ST_FLAG_STRING | ST_FLAG_RW);
76
dstate_setaux("battery.runtime.low", 3);
78
upsh.instcmd = instcmd;
79
upsh.setvar = upsdrv_setvar;
81
dstate_addcmd("shutdown.return");
82
dstate_addcmd("load.off");
85
/* convert hex digit to int */
86
static inline int fromhex (char c)
88
return (c >= '0' && c <= '9') ? c - '0'
89
: (c >= 'A' && c <= 'F') ? c - 'A' + 10
90
: (c >= 'a' && c <= 'f') ? c - 'a' + 10
94
/* do checksumming on UPS response */
95
static int checksum (char * s)
99
for (i = 40, sum = 0; s[0] && s[1] && i > 0; i--, s += 2) {
100
sum += (fromhex (s[0]) << 4) + fromhex (s[1]);
105
/* set info to integer value */
106
static inline void setinfo_int (int id, char * s, int len)
110
if (len > sizeof(buf)) len = sizeof(buf)-1;
111
strncpy (buf, s, len);
113
setinfo (id, "%d", atoi (buf));
116
/* set info to integer value (for runtime remaining)
117
value is expressed in minutes, but desired in seconds
119
static inline void setinfo_int_minutes (int id, char * s, int len)
123
if (len > sizeof(buf)) len = sizeof(buf)-1;
124
strncpy (buf, s, len);
126
setinfo (id, "%d", 60*atoi (buf));
129
/* set info to float value */
130
static inline void setinfo_float (int id, char * fmt, char * s, int len, double factor)
133
if (len > sizeof(buf)) len = sizeof(buf)-1;
134
strncpy (buf, s, len);
136
setinfo (id, fmt, factor * (double)atoi (buf));
139
/* read out UPS and store info */
140
void upsdrv_updateinfo(void)
145
int checksum_ok, is_online=1, is_off, low_batt, trimming, boosting;
150
if (upsrecv (temp, sizeof(temp), ENDCHAR, IGNCHARS) <= 0) {
151
upsflushin (0, 0, "\r ");
154
} while (temp[0] == 0);
155
/* setinfo (INFO_, ""); */
158
/*syslog (LOG_DAEMON | LOG_NOTICE,"ups: got '%s'\n", p);*/
160
|Vi||Vo| |Io||Psou| |Vb||f| |tr||Ti| CS
161
000000000001000000000000023802370000000200004700000267500000990030000000000301BD
162
1 1 2 2 3 3 4 4 5 5 6 6 7 7 78
163
0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 90
166
/* last bytes are a checksum:
167
interpret response as hex string, sum of all bytes must be zero
169
checksum_ok = (checksum (p) & 0xff) == 0;
176
setinfo_int (INFO_UTILITY, p+24,4);
177
setinfo_int (INFO_OUTVOLT, p+28,4);
178
setinfo_float (INFO_BATTVOLT, "%.1f", p+50,4, 0.1);
179
setinfo_float (INFO_CURRENT, "%.1f", p+36,4, 0.1);
180
setinfo_int (INFO_OUT_VA, p+40,6);
181
setinfo_float (INFO_ACFREQ, "%.1f", p+54,3, 0.1);
182
setinfo_int_minutes (INFO_BATT_RUNTIME, p+58,4);
183
setinfo_int (INFO_UPSTEMP, p+62,4);
185
is_online = p[17] == '0';
186
low_batt = fromhex(p[21]) & 8 || fromhex(p[20]) & 1;
187
is_off = p[11] == '0';
188
trimming = p[33] == '1';
189
boosting = 0; /* FIXME, don't know which bit gets set
190
(brownouts are very rare here and I can't
193
setinfo (INFO_STATUS, "%s%s%s",
194
is_online ? (is_off ? "OFF " : "OL ") : "OB ",
195
low_batt ? "LB " : "",
196
trimming ? "TRIM" : boosting ? "BOOST" : "");
198
/* setinfo(INFO_STATUS, "%s%s",
199
* (util < lownorm) ? "BOOST ", "",
200
* (util > highnorm) ? "TRIM ", "",
201
* ((flags & TIOCM_CD) == 0) ? "" : "LB ",
202
* ((flags & TIOCM_CTS) == TIOCM_CTS) ? "OB" : "OL");
209
/* Parameter setting */
211
/* all UPS tunable parameters are set with command
214
int setparam (int parameter, int dlen, char * data)
217
upssend ("p%d=%*s\r", parameter, dlen, data);
218
if (upsrecv (reply, sizeof(reply), ENDCHAR, "") < 0) return 0;
219
return strncmp (reply, "OK", 2) == 0;
222
/* ups_setsuper: set super-user access
223
(allows setting variables)
225
static void ups_setsuper (int super)
227
setparam (999, super ? 4 : 0, super ? "2639" : "");
230
/* sets whether UPS will reapply power after it has shut down and line
233
static void autorestart (int restart)
236
setparam (1, 1, restart ? "1" : "0");
240
/* set UPS parameters */
241
void upsdrv_setvar (int info, int len, char * data)
258
if (setparam (parameter, len, data)) {
259
setinfo (info, "%*s", len, data);
264
void upsdrv_shutdown(void)
268
grace = getdata(INFO_PDNGRACE);
271
grace = "1"; /* apparently, OFF0 does not work */
273
printf ("shutdown in %s seconds\n", grace);
274
/* make power return when utility power returns */
276
upssend ("OFF%s\r", grace);
277
/* I'm nearly dead, Jim */
278
/* OFF will powercycle when line power is available again */
281
void instcmd (int auxcmd, int dlen, char *data)
287
printf ("powering off\n");
292
p = getdata (INFO_PDNGRACE);
294
printf ("shutdown in %s seconds\n", p);
296
upssend ("OFF%s\r", p);
299
upslogx(LOG_INFO, "instcmd: unknown type 0x%04x", auxcmd);
303
void upsdrv_help(void)
307
/* list flags and values that you want to receive via -x */
308
void upsdrv_makevartable(void)
310
/* allow '-x xyzzy' */
311
/* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */
313
/* allow '-x foo=<some value>' */
314
/* addvar(VAR_VALUE, "foo", "Override foo setting"); */
315
addvar (VAR_VALUE, "speed", "serial line speed");
318
void upsdrv_banner(void)
320
printf("Network UPS Tools - Best Fortress UPS driver 0.01 (%s)\n\n", UPS_VERSION);
334
void upsdrv_initups(void)
336
speed_t speed = B1200;
338
char * speed_val = getval ("speed");
342
for (i=0; speed_table[i].val; i++) {
343
if (strcmp (speed_val, speed_table[i].val) == 0)
346
speed = speed_table[i].speed;
349
open_serial(device_path, speed);
350
/* TODO: probe ups type */
352
/* the upsh handlers can't be done here, as they get initialized
353
* shortly after upsdrv_initups returns to main.
357
void upsdrv_cleanup(void)