2
bestuferrups.c - model specific routines for Best Power Micro-Ferrups
4
This module is a 40% rewritten mangle of the bestfort module by
5
Grant, which is a 75% rewritten mangle of the bestups module by
6
Russell. It has no test battery command since my ME3100 does this
7
by itself. (same as Grant's driver in this respect)
9
Copyright (C) 2002 Andreas Wrede <andreas@planix.com>
10
Copyright (C) 2000 John Stone <johns@megapixel.com>
11
Copyright (C) 2000 Grant Taylor <gtaylor@picante.com>
12
Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
14
This program is free software; you can redistribute it and/or modify
15
it under the terms of the GNU General Public License as published by
16
the Free Software Foundation; either version 2 of the License, or
17
(at your option) any later version.
19
This program is distributed in the hope that it will be useful,
20
but WITHOUT ANY WARRANTY; without even the implied warranty of
21
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
GNU General Public License for more details.
24
You should have received a copy of the GNU General Public License
25
along with this program; if not, write to the Free Software
26
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30
#define DRV_VERSION "0.01"
35
#define IGNCHARS "\012"
40
#define MD1KVA 300 /* Software version P5.05 dated 05/18/89 */
49
/* Blob of UPS configuration data from the formatconfig string */
51
int valid; /* set to 1 when this is filled in */
53
float idealbvolts; /* various interestin battery voltages */
56
int va; /* capacity of UPS in Volt-Amps */
57
int watts; /* capacity of UPS in watts */
58
int model; /* enumerated model type */
64
/* Set up all the funky shared memory stuff used to communicate with upsd */
65
void upsdrv_initinfo (void)
67
/* now set up room for all future variables that are supported */
69
dstate_setinfo("ups.mfr", "%s", "Best Power");
72
dstate_setinfo("ups.model", "Micro Ferrups (ME) %d", fc.va);
75
dstate_setinfo("ups.model", "Micro Ferrups (MD) %d", fc.va);
78
exit(1); /* Will never get here, upsdrv_initups() will catch */
80
fprintf(stderr, "Best Power %s detected\n",
81
dstate_getinfo("ups.model"));
82
fprintf(stderr, "Battery voltages %5.1f nominal, %5.1f full, %5.1f empty\n",
89
/* Debugging display from kermit:
91
----------------------------------------------------
92
time^M^M^JFeb 20, 22:13:32^M^J^M^J=>id^M^JUnit ID "ME3.1K12345"^M^J^M^J=>
93
----------------------------------------------------
96
int execute(char *cmd, char *result, int resultsize)
102
upsrecv(buf, sizeof(buf), '\012', "");
103
ret=upsrecv(result, resultsize, '\015', "\012");
104
upsrecv(buf, sizeof(buf), '>', "");
110
void upsdrv_updateinfo(void)
116
"upsupdate run before ups_ident() read ups config\n");
120
if (execute("f\r", fstring, sizeof(fstring)) > 0) {
121
int inverter=0, charger=0, vin=0, vout=0, btimeleft=0, linestat=0,
123
double ampsout=0.0, vbatt=0.0, battpercent=0.0, loadpercent=0.0,
124
upstemp=0.0, acfreq=0.0;
127
/* Inverter status. 0=off 1=on */
128
memcpy(tmp, fstring+16, 2);
130
inverter = atoi(tmp);
132
/* Charger status. 0=off 1=on */
133
memcpy(tmp, fstring+18, 2);
137
/* Input Voltage. integer number */
138
memcpy(tmp, fstring+24, 4);
142
/* Output Voltage. integer number */
143
memcpy(tmp, fstring+28, 4);
147
/* Iout. int times 10 */
148
memcpy(tmp, fstring+36, 4);
150
ampsout = ((double)(atoi(tmp)) / 10.0);
152
/* Battery voltage. int times 10 */
153
memcpy(tmp, fstring+50, 4);
155
vbatt = ((double)(atoi(tmp)) / 10.0);
157
/* Volt-amps out. int */
158
memcpy(tmp, fstring+40, 6);
162
/* Line status. Bitmask */
163
memcpy(tmp, fstring+72, 2);
165
linestat = atoi(tmp);
167
/* Alarm status reg 1. Bitmask */
168
memcpy(tmp, fstring+20, 2);
172
/* Alarm status reg 2. Bitmask */
173
memcpy(tmp, fstring+22, 2);
175
alstat = alstat | (atoi(tmp) << 8);
177
/* AC line frequency */
178
memcpy(tmp, fstring+54, 4);
180
acfreq = ((double)(atoi(tmp)) / 100.0);
182
/* Runtime remaining */
183
memcpy(tmp, fstring+58, 4);
185
btimeleft = atoi(tmp);
187
/* UPS Temperature */
188
memcpy(tmp, fstring+62, 4);
190
upstemp = (double)(atoi(tmp));
195
if (execute("d 16\r", fstring, sizeof(fstring)) > 0) {
197
sscanf(fstring, "16 FullLoad%% %d", &l);
198
loadpercent = (double) l;
202
if (execute("d 22\r", fstring, sizeof(fstring)) > 0) {
204
sscanf(fstring, "22 FullLoad%% %d", &l);
205
loadpercent = (double) l;
208
default: /* Will never happen, caught in upsdrv_initups() */
209
fprintf(stderr, "Uknown model in upsdrv_updateinfo()\n");
212
/* Compute battery percent left based on battery voltages. */
213
battpercent = ((vbatt - fc.emptyvolts)
214
/ (fc.fullvolts - fc.emptyvolts) * 100.0);
215
if (battpercent < 0.0)
217
else if (battpercent > 100.0)
220
/* Compute status string */
222
int lowbatt, overload, replacebatt, boosting, trimming;
224
lowbatt = alstat & (1<<1);
225
overload = alstat & (1<<6);
226
replacebatt = alstat & (1<<10);
227
boosting = inverter && (linestat & (1<<2)) && (vin < 115);
228
trimming = inverter && (linestat & (1<<2)) && (vin > 115);
257
"Poll: inverter %d charger %d vin %d vout %d vaout %d btimeleft %d\n",
258
inverter, charger, vin, vout, vaout, btimeleft);
260
" ampsout %5.1f vbatt %5.1f batpcnt %5.1f loadpcnt %5.1f upstemp %5.1f acfreq %5.2f\n",
261
ampsout, vbatt, battpercent, loadpercent, upstemp, acfreq);
265
/* Stuff information into info structures */
267
dstate_setinfo("input.voltage", "%05.1f", (double)vin);
268
dstate_setinfo("output.voltage", "%05.1f", (double)vout);
269
dstate_setinfo("battery.charge", "%02.1f", battpercent);
270
dstate_setinfo("ups.load", "%02.1f", loadpercent);
271
dstate_setinfo("battery.voltage", "%02.1f", vbatt);
272
dstate_setinfo("input.frequency", "%05.2f", (double)acfreq);
273
dstate_setinfo("ups.temperature", "%05.1f", (double)upstemp);
274
dstate_setinfo("battery.runtime", "%d", btimeleft);
282
} /* if (execute("f\r", fstring, sizeof(fstring)) > 0) */
293
printf ("Syncing: ");
296
/* A bit better sanity might be good here. As is, we expect the
297
human to observe the time being totally not a time. */
299
if (execute("time\r", buf, sizeof(buf)) > 0) {
300
fprintf(stderr, "UPS Time: %s\n", buf);
302
fprintf(stderr, "Error connecting to UPS.\n");
307
/* power down the attached load immediately */
308
void upsdrv_shutdown(void)
310
/* NB: hard-wired password */
312
upssend("off 1 a\r"); /* power off in 1 second and restart when line power returns */
315
/* list flags and values that you want to receive via -x */
316
void upsdrv_makevartable(void)
318
/* allow '-x xyzzy' */
319
/* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */
321
/* allow '-x foo=<some value>' */
322
/* addvar(VAR_VALUE, "foo", "Override foo setting"); */
325
void upsdrv_help(void)
330
void upsdrv_banner(void)
332
printf("Network UPS Tools - Best Ferrups Series ME %s (%s)\n\n",
333
DRV_VERSION, UPS_VERSION);
336
static void sync_serial(void) {
340
upsrecv(buffer,sizeof(buffer), '\r', "\012");
341
upsrecv(buffer, sizeof(buffer), ENDCHAR, IGNCHARS);
343
while (upsrecv(buffer,sizeof(buffer), '>', "\012") <= 0) {
348
/* Begin code stolen from bestups.c */
349
static void setup_serial(void)
353
if (tcgetattr(upsfd, &tio) == -1)
356
tio.c_iflag = IXON | IXOFF;
358
tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
363
#ifdef HAVE_CFSETISPEED
364
cfsetispeed(&tio, B1200); /* baud change here */
365
cfsetospeed(&tio, B1200);
367
#error This system lacks cfsetispeed() and has no other means to set the speed
370
if (tcsetattr(upsfd, TCSANOW, &tio) == -1)
372
/* end code stolen from bestups.c */
378
void upsdrv_initups ()
380
char temp[256], fcstring[512];
382
open_serial(device_path, B1200);
388
if (execute("id\r", fcstring, sizeof(fcstring)) < 0) {
389
fprintf(stderr, "Failed execute in ups_ident()\n");
393
/* response is a one-line packed string starting with $ */
394
if (memcmp(fcstring, "Unit", 4)) {
395
fprintf(stderr, "Bad response from formatconfig command in ups_ident()\n");
396
fprintf(stderr, "id: %s\n", fcstring);
401
fprintf(stderr, "id: %s\n", fcstring);
403
/* chars 4:2 are a two-digit ascii hex enumerated model code */
404
memcpy(temp, fcstring+9, 2);
407
if (memcmp(temp, "ME", 2) == 0) {
410
if (memcmp(temp, "C1", 2) == 0) {
411
/* Better way to identify unit is using "d 15\r", which results in
412
"15 M# MD1KVA", "id\r" yields "Unit ID "C1K03588"" */
420
/* determine shutdown battery voltage */
421
if (execute("d 29\r", fcstring, sizeof(fcstring)) > 0) {
422
sscanf(fcstring, "29 LowBat %f", &fc.emptyvolts);
424
/* determine fully charged battery voltage */
425
if (execute("d 31\r", fcstring, sizeof(fcstring)) > 0) {
426
sscanf(fcstring, "31 HiBatt %f", &fc.fullvolts);
428
fc.fullvolts = 54.20;
429
/* determine "ideal" voltage by a guess */
430
fc.idealbvolts = ((fc.fullvolts - fc.emptyvolts) * 0.7) + fc.emptyvolts;
434
fc.watts = 770; /* Approximate, based on 0.7 power factor */
435
/* determine shutdown battery voltage */
436
if (execute("d 27\r", fcstring, sizeof(fcstring)) > 0) {
437
sscanf(fcstring, "27 LowBatt %f", &fc.emptyvolts);
439
/* determine fully charged battery voltage */
440
if (execute("d 28\r", fcstring, sizeof(fcstring)) > 0) {
441
sscanf(fcstring, "28 Hi Batt %f", &fc.fullvolts);
443
fc.fullvolts = 13.70;
444
/* determine "ideal" voltage by a guess */
445
fc.idealbvolts = ((fc.fullvolts - fc.emptyvolts) * 0.7) + fc.emptyvolts;
448
fprintf(stderr, "Uknown model %s in ups_ident()\n", temp);
457
void upsdrv_cleanup(void)