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

« back to all changes in this revision

Viewing changes to drivers/cyberpower.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2005-07-20 19:48:50 UTC
  • mto: (16.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20050720194850-oo61wjr33rrx2mre
Tags: upstream-2.0.2
ImportĀ upstreamĀ versionĀ 2.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
*/
20
20
 
21
21
#include "main.h"
 
22
#include "serial.h"
22
23
 
23
24
#include <sys/ioctl.h>
24
 
#include <sys/termios.h>
25
25
 
26
26
#include "timehead.h"
27
27
 
28
 
#define DRV_VERSION "0.22"
 
28
#define DRV_VERSION "1.00"
29
29
 
30
30
/* window for repeating dangerous command (shutdown.stayoff) */
31
 
#define MINCMDTIME      3
32
 
#define MAXCMDTIME      15
33
 
 
34
 
/* limit the amount of spew that goes in the syslog when we lose the UPS */
35
 
#define CP_ERR_LIMIT 10         /* start limiting after 10 in a row     */
36
 
#define CP_ERR_RATE 100         /* then only print every 100th error    */
37
 
 
38
 
        struct  sigaction sa;
39
 
        sigset_t cp_sigmask;
40
 
        unsigned int    poll_failures = 0;
 
31
#define MINCMDTIME      3
 
32
#define MAXCMDTIME      15
 
33
 
 
34
#define UPSDELAY 50000
41
35
 
42
36
/* ups frequency */
43
 
float frequency(unsigned char in)
 
37
static float frequency(unsigned char in)
44
38
{
45
 
        float freq[22] = { 63.0, 62.7, 62.4, 62.1, 61.8, 61.4, 61.1, 60.8, 60.5, 60.2, 60.0, 59.7, 59.4, 59.1, 58.8, 58.5, 58.3, 58.0, 57.7, 57.4, 57.2, 57.0 };
 
39
        float freq[22] = { 63.0, 62.7, 62.4, 62.1, 61.8, 61.4, 61.1, 60.8, 
 
40
                60.5, 60.2, 60.0, 59.7, 59.4, 59.1, 58.8, 58.5, 58.3, 58.0,
 
41
                57.7, 57.4, 57.2, 57.0 };
46
42
        int i, j;
47
 
        
 
43
 
48
44
        for (i = 0, j = 168; i < 23; j++, i++)
49
45
                if (in == j)
50
46
                        return (float)freq[i];
53
49
}
54
50
 
55
51
/* adjust bizarre UPS data to observed voltage data */
56
 
int voltconvert(unsigned char in)
 
52
static int voltconvert(unsigned char in)
57
53
{
58
 
        int v_end[43] = { 36, 51, 55, 60, 65, 70, 75, 80, 85, 91, 98, 103, 108, 113, 118, 123, 128, 133, 138, 143, 148, 153, 158, 163, 168, 173, 178, 183, 188, 193, 198, 203, 208, 213, 218, 223, 228, 233, 238, 243, 248, 253, 255 };
59
 
        int v_adj[43] = {  3,  4,  5,  4,  3,  2,  1,  0, -1, -2, -3,  -4,  -5,  -6,  -7,  -8,  -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -33, -34, -35 };
 
54
        int v_end[43] = { 36, 51, 55, 60, 65, 70, 75, 80, 85, 91, 98, 103, 
 
55
                108, 113, 118, 123, 128, 133, 138, 143, 148, 153, 158, 163, 
 
56
                168, 173, 178, 183, 188, 193, 198, 203, 208, 213, 218, 223, 
 
57
                228, 233, 238, 243, 248, 253, 255 };
 
58
        int v_adj[43] = {  3,  4,  5,  4,  3,  2,  1,  0, -1, -2, -3,  -4,  
 
59
                -5,  -6,  -7,  -8,  -9, -10, -11, -12, -13, -14, -15, -16, 
 
60
                -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, 
 
61
                -29, -30, -31, -32, -33, -34, -35 };
60
62
        int     i;
61
63
 
62
64
        if (in < 27)
72
74
}
73
75
 
74
76
/* map UPS data to realistic percentages */
75
 
int battconvert(unsigned char in)
 
77
static int battconvert(unsigned char in)
76
78
{
77
 
        int b_val[26] = {0, 1, 1, 2, 3, 4, 6, 8, 10, 12, 15, 18, 22, 26, 30, 35, 40, 46, 52, 58, 66, 73, 81, 88, 99, 100 }; /* XXX - for load of 0 */
 
79
        /* these may only be valid for a load of 0 */
 
80
        int b_val[26] = {0, 1, 1, 2, 3, 4, 6, 8, 10, 12, 15, 18, 22, 26, 30, 
 
81
                35, 40, 46, 52, 58, 66, 73, 81, 88, 99, 100 };
78
82
 
79
83
        if (in > 185)
80
84
                return 100;
87
91
 
88
92
/* Model mapping */
89
93
struct {
90
 
        int     first;
91
 
        int     second;
92
 
        char    *pcode;
93
 
        char    *model;
94
 
}     modelmap[] = {
95
 
      
 
94
        int     first;
 
95
        int     second;
 
96
        const   char    *pcode;         /* product code - presently ignored */
 
97
        const   char    *model;
 
98
}       modelmap[] = {
 
99
 
96
100
        { 51, 51, "OP850", "850AVR"     },      /* O33 */
97
101
        { 52, 53, "OP1500", "1500AVR"   },      /* O45 */
98
102
        { 52, 51, "OP1250", "1250AVR"   },      /* O43 */
102
106
        { 51, 49, "OP800", "800AVR"     },      /* O31 */
103
107
        { 50, 57, "OP500", "500AVR"     },      /* O29 */
104
108
        { 50, 55, "OP320", "320AVR"     },      /* O27 */
 
109
        { 49, 48, "OP1000", "1000AVR"   },      /* O10 */
105
110
        {  0,  0, (char*) NULL, (char *) NULL }
106
111
};
107
112
 
156
161
        {   0,   0, 0,  0 },
157
162
};
158
163
 
159
 
float tempconvert(unsigned char in)
 
164
static float tempconvert(unsigned char in)
160
165
{
161
166
        int     i, j, found, count;
162
167
 
185
190
        return 0;
186
191
}
187
192
 
188
 
void sendtoups(char ch)
189
 
{
190
 
        write(upsfd, &ch, 1);
191
 
        usleep(50000);
192
 
}
193
 
 
194
 
static void read_timeout(int sig)
195
 
{
196
 
        /* ignore this */
197
 
        return;
198
 
}
199
 
 
200
 
static int confirm_write(const unsigned char *buf, int buflen)
201
 
{
202
 
        int     i, ret;
203
 
        unsigned        char    ch;
204
 
 
205
 
        for (i = 0; i < buflen; i++) {
206
 
                ret = write(upsfd, &buf[i], 1);
207
 
 
208
 
                if (ret < 1)
209
 
                        return 0;
210
 
 
211
 
                usleep(50000);
212
 
        }
213
 
 
214
 
        ch = 13;
215
 
        write(upsfd, &ch, 1);
216
 
 
217
 
        for (i = 0; i < buflen; i++) {
218
 
 
219
 
                alarm(2);
220
 
                ret = read(upsfd, &ch, 1);
221
 
                alarm(0);
222
 
 
223
 
                if (ch != buf[i]) {
 
193
static int confirm_write(const unsigned char *buf, size_t buflen)
 
194
{
 
195
        int     ret;
 
196
        char    verify[16];
 
197
        unsigned int    i;
 
198
 
 
199
        ret = ser_send_buf_pace(upsfd, UPSDELAY, buf, buflen);
 
200
 
 
201
        if (ret < 1) {
 
202
                upsdebugx(1, "confirm_write: ser_send_buf_pace failed");
 
203
                return 0;
 
204
        }
 
205
 
 
206
        /* don't try to read back the \r */
 
207
        ret = ser_get_buf_len(upsfd, verify, buflen - 1, 5, 0);
 
208
 
 
209
        if ((ret < 1) || (ret < ((int) buflen - 1))) {
 
210
                upsdebugx(1, "confirm_write: ret=%d, needed %d",
 
211
                        ret, buflen - 1);
 
212
                return 0;
 
213
        }
 
214
 
 
215
        for (i = 0; i < buflen - 1; i++) {
 
216
                if (buf[i] != verify[i]) {
224
217
                        upsdebugx(1, "mismatch at position %d", i);
225
218
                        return 0;
226
219
                }
234
227
/* provide a quick status check to select the right shutdown command */
235
228
static int ups_on_line(void)
236
229
{
237
 
        int     ret, count;
238
 
        char    buf[SMALLBUF], ch;
239
 
 
240
 
        sendtoups('D');
241
 
        sendtoups(13);
242
 
 
243
 
        count = 0;
244
 
 
245
 
        memset(buf, '\0', sizeof(buf));
246
 
        while (count < 14) {
247
 
 
248
 
                alarm(1);
249
 
                ret = read(upsfd, &ch, 1);
250
 
                alarm(0);
251
 
 
252
 
                if (ret < 1) {
253
 
                        upslogx(LOG_ERR, "Status read failed: assuming on battery");
254
 
                        return 0;
255
 
                }
256
 
 
257
 
                buf[count++] = ch;
 
230
        int     ret;
 
231
        char    buf[SMALLBUF];
 
232
 
 
233
        ser_send_pace(upsfd, UPSDELAY, "D\r");
 
234
 
 
235
        /* give it a chance to reply completely */
 
236
        usleep(100000);
 
237
 
 
238
        ret = ser_get_buf_len(upsfd, buf, 14, 3, 0);
 
239
 
 
240
        if (ret < 14) {
 
241
                upslogx(LOG_ERR, "Status read failed: assuming on battery");
 
242
                return 0;
258
243
        }
259
244
 
260
245
        if (buf[9] & 128)
263
248
        return 1;       /* on line */
264
249
}
265
250
 
266
 
static void setup_sigalrm(void)
267
 
{
268
 
        sigemptyset(&cp_sigmask);
269
 
        sa.sa_mask = cp_sigmask;
270
 
        sa.sa_flags = 0;
271
 
        sa.sa_handler = read_timeout;
272
 
        sigaction(SIGALRM, &sa, NULL);
273
 
}
274
 
 
275
251
/* power down the attached load immediately */
276
252
void upsdrv_shutdown(void)
277
253
{
278
254
        int     i, ret, sdlen;
279
 
        char    ch, buf[256];
 
255
        char    buf[256];
280
256
        unsigned char   sdbuf[16];
281
257
 
282
 
        setup_sigalrm();
283
 
 
284
258
        /* get this thing's attention */
285
259
        for (i = 0; i < 10; i++) {
286
260
                printf("Trying to wake up the ups... ");
287
261
                fflush(stdout);
288
262
 
289
 
                alarm(5);
290
 
                
291
 
                ch = 13;
292
 
                write(upsfd, &ch, 1);
293
 
 
294
 
                ret = read(upsfd, buf, sizeof(buf));
295
 
                alarm(0);
 
263
                ser_send_char(upsfd, 13);
 
264
                ret = ser_get_buf_len(upsfd, buf, 1, 5, 0);
296
265
 
297
266
                if (ret > 0) {
298
267
                        printf("OK\n");
304
273
 
305
274
        usleep(250000);
306
275
 
 
276
        memset(sdbuf, '\0', sizeof(sdbuf));
 
277
 
307
278
        if (ups_on_line() == 1) {
308
279
 
309
280
                /* this does not come back when on battery! */
310
281
 
311
282
                printf("Online: sending 7 byte command (back in about 45 sec)\n");
312
283
 
313
 
                sdlen = 7;
 
284
                sdlen = 8;
314
285
                sdbuf[0] = 'S';
315
286
 
316
287
                sdbuf[1] = 0x00;                /* how long until shutdown */
322
293
                                                /* 1 = about 45 seconds */
323
294
 
324
295
                sdbuf[6] = 'W';
 
296
                sdbuf[7] = '\r';
325
297
        
326
298
        } else {
327
299
 
331
303
 
332
304
                printf("On battery: sending 4 byte command (back when line power returns)\n");
333
305
 
334
 
                sdlen = 4;
 
306
                sdlen = 5;
335
307
                sdbuf[0] = 'S';
336
308
                sdbuf[1] = 0x00;
337
309
                sdbuf[2] = 0x00;
338
310
                sdbuf[3] = 'W';
 
311
                sdbuf[4] = '\r';
339
312
        }
340
313
 
341
 
        printf("Sending command...");
342
 
        fflush(stdout);
343
 
 
344
314
        for (i = 0; i < 10; i++) {
 
315
                printf("Sending command...");
 
316
                fflush(stdout);
345
317
 
346
318
                if (confirm_write(sdbuf, sdlen)) {
347
319
                        printf(" confirmed\n");
348
320
                        break;
349
321
                }
350
322
 
351
 
                printf("failed, retrying...");
 
323
                printf("failed, retrying...\n");
352
324
                fflush(stdout);
353
325
        }
354
326
}
355
327
 
356
 
static void pollfail(const char *why)
357
 
{
358
 
        poll_failures++;
359
 
 
360
 
        if ((poll_failures == CP_ERR_LIMIT) || 
361
 
                ((poll_failures % CP_ERR_RATE) == 0)) {
362
 
                upslogx(LOG_WARNING, "Warning: excessive poll failures, "
363
 
                        "limiting error reporting");
364
 
        }
365
 
 
366
 
        if ((poll_failures < CP_ERR_LIMIT) ||
367
 
                ((poll_failures % CP_ERR_RATE) == 0)) {
368
 
                upslogx(LOG_ERR, "UPS status unavailable: %s", why);
369
 
        }
370
 
}
371
 
 
372
328
void upsdrv_updateinfo(void)
373
329
{
374
 
        int     ret, count;
375
 
        char    ch, buf[SMALLBUF];
376
 
 
377
 
        sendtoups('D');
378
 
        sendtoups(13);
379
 
 
380
 
        count = 0;
381
 
 
382
 
        memset(buf, '\0', sizeof(buf));
383
 
        while (count < 14) {
384
 
 
385
 
                alarm(1);
386
 
                ret = read(upsfd, &ch, 1);
387
 
                alarm(0);
388
 
 
389
 
                if (ret < 1) {
390
 
                        pollfail("Short read from UPS");
391
 
                        dstate_datastale();
392
 
                        return;
393
 
                }
394
 
 
395
 
                buf[count++] = ch;
 
330
        int     ret;
 
331
        char    buf[SMALLBUF];
 
332
 
 
333
        ser_send_pace(upsfd, UPSDELAY, "D\r");
 
334
 
 
335
        /* give it a chance to reply completely */
 
336
        usleep(100000);
 
337
 
 
338
        ret = ser_get_buf_len(upsfd, buf, 14, 3, 0);
 
339
 
 
340
        if (ret < 14) {
 
341
                ser_comm_fail("Short read from UPS");
 
342
                dstate_datastale();
 
343
                return;
396
344
        }
397
345
 
398
346
        if (buf[0] != '#') {
399
 
                upslogx(LOG_ERR, "Invalid start char 0x%02x", buf[0] & 0xff);
 
347
                ser_comm_fail("Invalid start char 0x%02x", buf[0] & 0xff);
400
348
                dstate_datastale();
401
349
                return;
402
350
        }
403
351
 
404
352
        if ((buf[4] != 46) || (buf[8] != 46)) {
405
 
                upslogx(LOG_ERR, "Invalid separator in response");
 
353
                ser_comm_fail("Invalid separator in response (0x%02x, 0x%02x)", 
 
354
                        buf[4], buf[8]);
406
355
                dstate_datastale();
407
356
                return;
408
357
        }
409
358
 
410
 
        poll_failures = 0;
 
359
        ser_comm_good();
411
360
 
412
 
        dstate_setinfo("input.frequency",  "%2.1f", frequency(buf[7]));
 
361
        dstate_setinfo("input.frequency", "%2.1f", frequency(buf[7]));
413
362
        dstate_setinfo("ups.temperature", "%2.1f", tempconvert(buf[6]));
414
363
        dstate_setinfo("battery.charge", "%03d", battconvert(buf[5]));
415
364
        dstate_setinfo("ups.load", "%03d", (buf[3] & 0xff) * 2);
434
383
 
435
384
static int get_ident(char *buf, size_t bufsize)
436
385
{
437
 
        int     ret, tries, count;
438
 
        char    ch;
 
386
        int     ret, tries;
439
387
 
440
388
        for (tries = 0; tries < 3; tries++) {
441
 
                sendtoups('F');
442
 
                sendtoups(13);
443
 
 
444
 
                memset(buf, '\0', bufsize);
445
 
 
446
 
                alarm(1);
447
 
                ret = read(upsfd, &ch, 1);
448
 
                alarm(0);
449
 
 
450
 
                count = 0;
451
 
                while (ret == 1) {
452
 
                        buf[count++] = ch;
453
 
        
454
 
                        if ((buf[0] == '.') && (ch == 13))
455
 
                                return 1;
456
 
 
457
 
                        /* reading way too much */
458
 
                        if (count == bufsize) {
459
 
                                memset(buf, '\0', bufsize);
460
 
                                count = 0;
461
 
                        }                               
462
 
 
463
 
                        alarm(1);
464
 
                        ret = read(upsfd, &ch, 1);
465
 
                        alarm(0);
466
 
                }
 
389
                ret = ser_send_pace(upsfd, UPSDELAY, "F\r");
 
390
 
 
391
                if (ret != 2)
 
392
                        continue;
 
393
 
 
394
                /* give it a chance to reply completely */
 
395
                usleep(400000);
 
396
 
 
397
                ret = ser_get_line(upsfd, buf, bufsize, '\r', "", 3, 0);
 
398
 
 
399
                if (ret < 1)
 
400
                        continue;
 
401
 
 
402
                if (buf[0] == '.')
 
403
                        return 1;
467
404
 
468
405
                /* if we got here, then the read failed somehow */
469
406
        }
482
419
                fatalx("Unable to get initial hardware info string");
483
420
 
484
421
        if (buf[0] != '.') {
485
 
                upslogx(LOG_ERR, "Invalid start model string 0x%02x", buf[0] & 0xff);
 
422
                upslogx(LOG_ERR, "Invalid start model string 0x%02x", 
 
423
                        buf[0] & 0xff);
486
424
                return -1;
487
425
        }
488
426
 
489
427
        for (i = 0; modelmap[i].model != NULL; i++) {
490
428
                if (buf[3] == modelmap[i].first &&
491
429
                        buf[4] == modelmap[i].second) {
492
 
              
 
430
 
493
431
                        dstate_setinfo("ups.model", "%s", modelmap[i].model);
494
432
                        foundmodel = 1;
495
433
                        break;
496
434
                }
497
435
        }
498
 
           
 
436
 
499
437
        if (!foundmodel)
500
438
                dstate_setinfo("ups.model", "Unknown model - %c%c", 
501
439
                        buf[3], buf[4]);
509
447
static int instcmd_btest(void)
510
448
{
511
449
        int     i, clen;
512
 
        char    cbuf[8];
 
450
        unsigned char   cbuf[8];
513
451
 
514
452
        clen = 2;
515
453
        cbuf[0] = 'T';
527
465
static int instcmd_stayoff(void)
528
466
{
529
467
        int     i, clen;
530
 
        char    cbuf[8];
 
468
        unsigned char   cbuf[8];
531
469
        double  elapsed;
532
470
        time_t  now;
533
471
        static  time_t  last = 0;
538
476
        last = now;
539
477
 
540
478
        /* for safety this must be repeated in a small window of time */
541
 
        if ((elapsed < MINCMDTIME) || (elapsed > MAXCMDTIME)) {
 
479
        if ((elapsed < MINCMDTIME) || (elapsed > MAXCMDTIME)) {
542
480
                upsdebugx(1, "instcmd_shutdown: outside window (%2.0f)",
543
481
                        elapsed);
544
 
                return STAT_INSTCMD_HANDLED;            /* FUTURE: again */
545
 
        }
 
482
                return STAT_INSTCMD_HANDLED;            /* FUTURE: again */
 
483
        }
546
484
 
547
485
        /* this is a one-way trip unless you happen to be on battery */
548
486
 
549
 
        clen = 4;               
 
487
        clen = 5;
550
488
        cbuf[0] = 'S';
551
489
        cbuf[1] = 0x00;
552
490
        cbuf[2] = 0x00;         
553
491
        cbuf[3] = 'W';
 
492
        cbuf[4] = '\r';
554
493
 
555
494
        for (i = 0; i < 3; i++)
556
495
                if (confirm_write(cbuf, clen))
561
500
        return STAT_INSTCMD_HANDLED;            /* FUTURE: failed */
562
501
}       
563
502
 
564
 
int instcmd(const char *cmdname, const char *extra)
 
503
static int instcmd(const char *cmdname, const char *extra)
565
504
{
566
505
        if (!strcasecmp(cmdname, "test.battery.start"))
567
506
                return instcmd_btest();
575
514
/* install pointers to functions for msg handlers called from msgparse */
576
515
static void setuphandlers(void)
577
516
{
578
 
        upsh.new_instcmd = instcmd;
 
517
        upsh.instcmd = instcmd;
579
518
}
580
519
 
581
520
void upsdrv_banner(void)
582
521
{
583
522
        printf("Network UPS Tools - CyberPower driver %s (%s)\n", 
584
523
                DRV_VERSION, UPS_VERSION);
585
 
 
586
 
        experimental_driver = 1;
587
524
}
588
525
 
589
526
void upsdrv_help(void)
599
536
{
600
537
        int dtr_bit = TIOCM_DTR;
601
538
        int rts_bit = TIOCM_RTS;
602
 
        struct termios tio;
603
539
 
604
 
        open_serial(device_path, B1200);
 
540
        upsfd = ser_open(device_path);
 
541
        ser_set_speed(upsfd, device_path, B1200);
605
542
 
606
543
        /* dtr high, rts high */
607
544
        ioctl(upsfd, TIOCMBIS, &rts_bit);
608
545
        ioctl(upsfd, TIOCMBIS, &dtr_bit);
609
 
 
610
 
        tcgetattr(upsfd, &tio);
611
 
        tio.c_cflag = 0 | CS8 | CLOCAL | ~CRTSCTS | CREAD;
612
 
        cfmakeraw(&tio);
613
 
        tio.c_cflag &= ~(PARODD|CSTOPB|HUPCL|CRTSCTS);
614
 
 
615
 
        cfsetispeed(&tio, B1200);
616
 
        cfsetospeed(&tio, B1200);
617
 
        tcsetattr(upsfd, TCSANOW, &tio);
618
 
 
619
 
        /* avoid getting stuck in read() */
620
 
        setup_sigalrm();
621
546
}
622
547
 
623
548
void upsdrv_initinfo(void)
626
551
                printf("Unable to detect a CyberPower UPS on port %s\n", 
627
552
                        device_path);
628
553
                printf("Check the cabling, port name or model name and try again\n");
629
 
                exit(1);
 
554
                exit(EXIT_FAILURE);
630
555
        }
631
556
 
632
 
        dstate_setinfo("ups.mfr", "CyberPower", 0, 0);
 
557
        dstate_setinfo("ups.mfr", "CyberPower");
633
558
        dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
634
559
 
635
560
        /* poll once to put in some good data */
645
570
 
646
571
void upsdrv_cleanup(void)
647
572
{
 
573
        ser_close(upsfd, device_path);
648
574
}