~ubuntu-branches/ubuntu/saucy/nut/saucy

« back to all changes in this revision

Viewing changes to drivers/bestups.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Quette
  • Date: 2004-05-28 13:10:01 UTC
  • mto: (16.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20040528131001-yj2m9qcez4ya2w14
Tags: upstream-1.4.2
ImportĀ upstreamĀ versionĀ 1.4.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* bestups.c - model specific routines for Best-UPS Fortress models
 
2
 
 
3
   Copyright (C) 1999  Russell Kroll <rkroll@exploits.org>
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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
 
18
*/
 
19
 
 
20
#include "main.h"
 
21
 
 
22
#define ENDCHAR  13     /* replies end with CR */
 
23
#define UPSDELAY  5
 
24
#define MAXTRIES 10
 
25
 
 
26
#define DRV_VERSION "0.60"
 
27
 
 
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;
 
32
 
 
33
static void setmodel(const char *abbr, const char *va)
 
34
{
 
35
        if (!strcmp(abbr, "FOR")) {
 
36
                dstate_setinfo("ups.mfr", "%s", "Best Power");
 
37
                dstate_setinfo("ups.model", "Fortress %s", va);
 
38
                return;
 
39
        }
 
40
 
 
41
        if (!strcmp(abbr, "FTC")) {
 
42
                dstate_setinfo("ups.mfr", "%s", "Best Power");
 
43
                dstate_setinfo("ups.model", "Fortress Telecom %s", va);
 
44
                return;
 
45
        }
 
46
 
 
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;
 
51
                return;
 
52
        }
 
53
 
 
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;
 
58
                return;
 
59
        }
 
60
 
 
61
        if (!strcmp(abbr, "325")) {
 
62
                dstate_setinfo("ups.mfr", "%s", "Sola Australia");
 
63
                dstate_setinfo("ups.model", "Sola 325 %s", va);
 
64
                return;
 
65
        }
 
66
 
 
67
        if (!strcmp(abbr, "520")) {
 
68
                dstate_setinfo("ups.mfr", "%s", "Sola Australia");
 
69
                dstate_setinfo("ups.model", "Sola 520 %s", va);
 
70
                return;
 
71
        }
 
72
 
 
73
        if (!strcmp(abbr, "620")) {
 
74
                dstate_setinfo("ups.mfr", "%s", "Sola Australia");
 
75
                dstate_setinfo("ups.model", "Sola 620 %s", va);
 
76
                return;
 
77
        }
 
78
 
 
79
        if (!strcmp(abbr, "AX1")) {
 
80
                dstate_setinfo("ups.mfr", "%s", "Best Power");
 
81
                dstate_setinfo("ups.model", "Axxium Rackmount %s", va);
 
82
                return;
 
83
        }
 
84
 
 
85
        dstate_setinfo("ups.mfr", "%s", "Unknown");
 
86
        dstate_setinfo("ups.model", "Unknown %s (%s)", abbr, va);
 
87
 
 
88
        printf("Unknown model detected - please report this ID: '%s'\n", abbr);
 
89
}
 
90
 
 
91
int instcmd(const char *cmdname, const char *extra)
 
92
{
 
93
        if (!strcasecmp(cmdname, "test.battery.stop")) {
 
94
                upssendchar('C');
 
95
                upssendchar('T');
 
96
                upssendchar(13);
 
97
 
 
98
                return STAT_INSTCMD_HANDLED;
 
99
        }
 
100
 
 
101
        if (!strcasecmp(cmdname, "test.battery.start")) {
 
102
                upssendchar('T');
 
103
                upssendchar(13);
 
104
 
 
105
                return STAT_INSTCMD_HANDLED;
 
106
        }
 
107
 
 
108
        upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
 
109
        return STAT_INSTCMD_UNKNOWN;
 
110
}
 
111
 
 
112
void upsdrv_initinfo(void)
 
113
{
 
114
        dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
 
115
        dstate_addcmd("test.battery.start");
 
116
        dstate_addcmd("test.battery.stop");
 
117
 
 
118
        setmodel(modelname, va);
 
119
        printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"), 
 
120
                dstate_getinfo("ups.model"), device_path);
 
121
 
 
122
        upsh.new_instcmd = instcmd;
 
123
 
 
124
        /* paranoia - cancel any shutdown that might already be running */
 
125
        upssendchar('C');
 
126
        upssendchar(13);
 
127
}
 
128
 
 
129
static void setup_serial(void)
 
130
{       
 
131
        struct  termios tio;
 
132
 
 
133
        if (tcgetattr(upsfd, &tio) == -1)
 
134
                fatal("tcgetattr");
 
135
 
 
136
        tio.c_iflag = IXON | IXOFF;
 
137
        tio.c_oflag = 0;
 
138
        tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
 
139
        tio.c_lflag = 0;
 
140
        tio.c_cc[VMIN] = 1;
 
141
        tio.c_cc[VTIME] = 0; 
 
142
 
 
143
#ifdef HAVE_CFSETISPEED
 
144
        cfsetispeed(&tio, B2400);
 
145
        cfsetospeed(&tio, B2400);
 
146
#else
 
147
#error This system lacks cfsetispeed() and has no other means to set the speed
 
148
#endif
 
149
 
 
150
        if (tcsetattr(upsfd, TCSANOW, &tio) == -1)
 
151
                fatal("tcsetattr");
 
152
}
 
153
 
 
154
static void ups_sync(void)
 
155
{
 
156
        char    buf[256];
 
157
        int     i, ret;
 
158
 
 
159
        printf("Syncing with UPS: ");
 
160
        fflush(stdout);
 
161
 
 
162
        for (i = 0; i < MAXTRIES; i++) {
 
163
                printf(".");
 
164
                fflush(stdout);
 
165
                upssend("%s", "\rQ1\r");
 
166
                printf(".");
 
167
                fflush(stdout);
 
168
                sleep(UPSDELAY);
 
169
                printf(".");
 
170
                fflush(stdout);
 
171
 
 
172
                ret = upsrecv(buf, sizeof(buf), ENDCHAR, "");
 
173
 
 
174
                /* return once we get something that looks usable */
 
175
                if ((ret > 0) && (buf[0] == '(')) {
 
176
                        printf(" done\n");
 
177
                        return;
 
178
                }
 
179
        }
 
180
 
 
181
        fatalx("\nFailed - giving up...");
 
182
}
 
183
 
 
184
static int ups_on_line(void)
 
185
{
 
186
        int     i, ret;
 
187
        char    temp[256], stat[32];
 
188
 
 
189
        printf("Checking line status: ");
 
190
        fflush(stdout);
 
191
 
 
192
        for (i = 0; i < MAXTRIES; i++) {
 
193
                upssend("\rQ1\r");
 
194
                printf(".");
 
195
                fflush(stdout);
 
196
                sleep(UPSDELAY);
 
197
                printf(".");
 
198
                fflush(stdout);
 
199
 
 
200
                ret = upsrecv(temp, sizeof(temp), ENDCHAR, "");
 
201
 
 
202
                /* Q1 must return 46 bytes starting with a ( */
 
203
                if ((ret > 0) && (temp[0] == '(') && (strlen(temp) == 46)) {
 
204
 
 
205
                        sscanf(temp, "%*s %*s %*s %*s %*s %*s %*s %s", stat);
 
206
 
 
207
                        if (stat[0] == '0')
 
208
                                return 1;       /* on line */
 
209
 
 
210
                        return 0;       /* on battery */
 
211
                }
 
212
        }
 
213
 
 
214
        upslogx(LOG_ERR, "Status read failed: assuming on battery");
 
215
 
 
216
        return 0;       /* on battery */
 
217
}
 
218
 
 
219
void upsdrv_shutdown(void)
 
220
{
 
221
        printf("The UPS will shut down in approximately one minute.\n");
 
222
 
 
223
        if (ups_on_line())
 
224
                printf("The UPS will restart in about one minute.\n");
 
225
        else
 
226
                printf("The UPS will restart when power returns.\n");
 
227
 
 
228
        upssend("%s", "S01R0001\r");
 
229
}
 
230
 
 
231
static int get_ident(char *buf, size_t bufsize)
 
232
{
 
233
        int     i, ret;
 
234
 
 
235
        printf("Identifying UPS: ");
 
236
        fflush(stdout);
 
237
 
 
238
        for (i = 0; i < MAXTRIES; i++) {
 
239
                printf(".");
 
240
                fflush(stdout);
 
241
 
 
242
                upssend("%s", "\r\rID\r");
 
243
                printf(".");
 
244
 
 
245
                fflush(stdout);
 
246
                sleep(UPSDELAY);
 
247
                printf(".");
 
248
                fflush(stdout);
 
249
 
 
250
                ret = upsrecv(buf, bufsize, ENDCHAR, "");
 
251
 
 
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)) {
 
255
 
 
256
                        printf(" done\n");
 
257
                        return 1;
 
258
                }
 
259
        }
 
260
 
 
261
        upslogx(LOG_INFO, "Giving up on hardware detection after %d tries",
 
262
                MAXTRIES);
 
263
 
 
264
        return 0;
 
265
}
 
266
 
 
267
static void ups_ident(void)
 
268
{
 
269
        char    buf[256], *ptr, *com;
 
270
        int     i;
 
271
 
 
272
        if (!get_ident(buf, sizeof(buf)))
 
273
                fatalx("Unable to get initial hardware info string");
 
274
 
 
275
        modelname = va = NULL;
 
276
 
 
277
        /* FOR,750,120,120,20.0,27.6 */
 
278
        ptr = buf;
 
279
 
 
280
        for (i = 0; i < 6; i++) {
 
281
                com = strchr(ptr, ',');
 
282
 
 
283
                if (com)
 
284
                        *com = '\0';
 
285
 
 
286
                switch (i) {
 
287
                        case 0: modelname = xstrdup(ptr);
 
288
                                break;
 
289
                        case 1: va = xstrdup(ptr);
 
290
                                break;
 
291
                        case 2: linenorm = atoi(ptr);
 
292
                                break;
 
293
                        case 4: lowvolt = atof(ptr);
 
294
                                break;
 
295
                        case 5: highvolt = atof(ptr);
 
296
                                voltrange = highvolt - lowvolt;
 
297
                                break;
 
298
                        default:
 
299
                                break;
 
300
                }
 
301
 
 
302
                if (com)
 
303
                        ptr = com + 1;
 
304
        }
 
305
}
 
306
 
 
307
static void pollfail(char *why)
 
308
{
 
309
        poll_failures++;
 
310
 
 
311
        /* ignore the first few since these UPSes tend to drop characters */
 
312
        if (poll_failures == 3)
 
313
                upslogx(LOG_ERR, why);
 
314
 
 
315
        return;
 
316
}
 
317
 
 
318
void upsdrv_updateinfo(void)
 
319
{
 
320
        char    involt[16], outvolt[16], loadpct[16], acfreq[16], 
 
321
                battvolt[16], upstemp[16], stat[16], buf[256];
 
322
        float   bvoltp;
 
323
        int     ret;
 
324
        static  int     pass = 0;
 
325
 
 
326
        /* this UPS needs a huge delay on queries, so chop up the updates */
 
327
 
 
328
        /* half the time, send the Q1, the other half, read it */
 
329
 
 
330
        if (pass == 0) {
 
331
                upssend("%s", "\rQ1\r");
 
332
                pass = 1;
 
333
                return;
 
334
        }
 
335
 
 
336
        pass = 0;
 
337
 
 
338
        ret = upsrecv(buf, sizeof(buf), ENDCHAR, "");
 
339
 
 
340
        if (strlen(buf) < 46) {
 
341
                pollfail("Poll failed: short read from UPS");
 
342
                dstate_datastale();
 
343
                return;
 
344
        }
 
345
 
 
346
        if (strlen(buf) > 46) {
 
347
                pollfail("Poll failed: oversized read from UPS");
 
348
                dstate_datastale();
 
349
                return;
 
350
        }
 
351
 
 
352
        if (buf[0] != '(') {
 
353
                pollfail("Poll failed: invalid start character");
 
354
                dstate_datastale();
 
355
                return;
 
356
        }
 
357
 
 
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");
 
361
 
 
362
        poll_failures = 0;
 
363
 
 
364
        sscanf(buf, "%*c%s %*s %s %s %s %s %s %s", involt, outvolt, 
 
365
                loadpct, acfreq, battvolt, upstemp, stat);
 
366
        
 
367
        bvoltp = ((atof (battvolt) - lowvolt) / voltrange) * 100.0;
 
368
 
 
369
        if (bvoltp > 100.0)
 
370
                bvoltp = 100.0;
 
371
 
 
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);
 
379
 
 
380
        status_init();
 
381
 
 
382
        if (stat[0] == '0') {
 
383
                status_set("OL");               /* on line */
 
384
 
 
385
                /* only allow these when OL since they're bogus when OB */
 
386
 
 
387
                if (stat[2] == (inverted_bypass_bit ? '0' : '1')) {
 
388
                        /* boost or trim in effect */
 
389
                        if (atof(involt) < atof(outvolt))
 
390
                                status_set("BOOST");
 
391
 
 
392
                        if (atof(involt) > atof(outvolt))
 
393
                                status_set("TRIM");
 
394
                }
 
395
 
 
396
        } else {
 
397
                status_set("OB");               /* on battery */
 
398
        }
 
399
 
 
400
        if (stat[1] == '1')
 
401
                status_set("LB");               /* low battery */
 
402
 
 
403
        status_commit();
 
404
        dstate_dataok();
 
405
}
 
406
 
 
407
void upsdrv_help(void)
 
408
{
 
409
}
 
410
 
 
411
void upsdrv_makevartable(void)
 
412
{
 
413
}
 
414
 
 
415
void upsdrv_banner(void)
 
416
{
 
417
        printf("Network UPS Tools - Best UPS driver %s (%s)\n", 
 
418
                DRV_VERSION, UPS_VERSION);
 
419
}
 
420
 
 
421
void upsdrv_initups(void)
 
422
{
 
423
        upssend_delay = 100000;
 
424
        open_serial(device_path, B2400);
 
425
        setup_serial();
 
426
 
 
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;
 
430
 
 
431
        ups_sync();
 
432
        ups_ident();
 
433
}
 
434
 
 
435
void upsdrv_cleanup(void)
 
436
{
 
437
}