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

« back to all changes in this revision

Viewing changes to drivers/masterguard.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
/*
 
2
    Copyright (C) 2001 Michael Spanier <mail@michael-spanier.de>
 
3
    
 
4
    masterguard.c created on 15.8.2001
 
5
    
 
6
    This program is free software; you can redistribute it and/or modify
 
7
    it under the terms of the GNU General Public License as published by
 
8
    the Free Software Foundation; either version 2 of the License, or
 
9
    (at your option) any later version.
 
10
    
 
11
    This program is distributed in the hope that it will be useful,
 
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
    GNU General Public License for more details.
 
15
    
 
16
    You should have received a copy of the GNU General Public License
 
17
    along with this program; if not, write to the Free Software
 
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
19
*/
 
20
 
 
21
 
 
22
/********************************************************************
 
23
 *
 
24
 * Please if you edit this code convert tabs to spaces and use
 
25
 * four characters indent.
 
26
 * If you don't know what this means use the vim editor.
 
27
 * 
 
28
 * Have fun
 
29
 *      Michael
 
30
 * 
 
31
 ********************************************************************/
 
32
#include "main.h"
 
33
 
 
34
#define UPSDELAY 3
 
35
#define MAXTRIES 10
 
36
 
 
37
#define Q1  1
 
38
#define Q3  2
 
39
 
 
40
#define DEBUG 1
 
41
#define DRIVERVERSION "0.22"
 
42
 
 
43
int     type;
 
44
char    name[31];
 
45
char    firmware[6];
 
46
 
 
47
/********************************************************************
 
48
 *
 
49
 * Helper function to split a sting into words by splitting at the 
 
50
 * SPACE character.
 
51
 *
 
52
 * Adds up to maxlen characters to the char word. 
 
53
 * Returns NULL on reaching the end of the string.
 
54
 * 
 
55
 ********************************************************************/
 
56
char *StringSplit( char *source, char *word, int maxlen )
 
57
{
 
58
    int     i;
 
59
    int     len;
 
60
    int     wc=0;
 
61
   
 
62
    word[0] = '\0';
 
63
    len = strlen( source );
 
64
    for( i = 0; i < len; i++ )
 
65
    {
 
66
        if( source[i] == ' ' )
 
67
        {
 
68
            word[wc] = '\0';
 
69
            return source + i + 1;
 
70
        }
 
71
        word[wc] = source[i];
 
72
        wc++;
 
73
    }
 
74
    word[wc] = '\0';
 
75
    return NULL;
 
76
}
 
77
     
 
78
/********************************************************************
 
79
 *
 
80
 * Helper function to drop all whitespaces within a string.
 
81
 * 
 
82
 * "word" must be large enought to hold "source", for the worst case
 
83
 * "word" has to be exacly the size of "source".
 
84
 * 
 
85
 ********************************************************************/
 
86
void StringStrip( char *source, char *word )
 
87
{
 
88
    int     wc=0;
 
89
    int     i;
 
90
    int     len;
 
91
 
 
92
    word[0] = '\0';
 
93
    len = strlen( source );
 
94
    for( i = 0; i < len; i++ )
 
95
    {
 
96
        if( source[i] == ' ' )
 
97
            continue;
 
98
        if( source[i] == '\n' )
 
99
            continue;
 
100
        if( source[i] == '\t' )
 
101
            continue;
 
102
        word[wc] = source[i];
 
103
        wc++;
 
104
    }
 
105
    word[wc] = '\0';
 
106
}
 
107
 
 
108
/********************************************************************
 
109
 *
 
110
 * Function parses the status flags which occure in the Q1 and Q3
 
111
 * command. Sets the INFO_STATUS value ( OL, OB, ... )
 
112
 * 
 
113
 ********************************************************************/
 
114
void parseFlags( char *flags )
 
115
{
 
116
        status_init();
 
117
 
 
118
        if( flags[0] == '1' )
 
119
                status_set("OB");
 
120
        else
 
121
                status_set("OL");
 
122
 
 
123
        if( flags[1] == '1' )
 
124
                status_set("LB");
 
125
 
 
126
        if( flags[2] == '1' )
 
127
                status_set("BOOST");
 
128
 
 
129
/* this has no mapping */
 
130
#if 0
 
131
        if( flags[3] == '1' )
 
132
                setinfo( INFO_ALRM_GENERAL, "1" );
 
133
#endif
 
134
 
 
135
#if 0
 
136
        /* and these are... ? */
 
137
 
 
138
        if( flags[5] == '1' )
 
139
                status_set("TIP");
 
140
        if( flags[6] == '1' )
 
141
                status_set("SD");
 
142
#endif
 
143
 
 
144
        status_commit();
 
145
 
 
146
    if( DEBUG )
 
147
        printf( "Status is %s\n", dstate_getinfo("ups.status"));
 
148
}
 
149
 
 
150
/********************************************************************
 
151
 *
 
152
 * Function parses the response of the query1 ( "Q1" ) command.
 
153
 * Also sets various values (IPFreq ... )
 
154
 * 
 
155
 ********************************************************************/
 
156
void query1( char *buf )
 
157
{
 
158
    #define WORDMAXLEN 255
 
159
    char    value[WORDMAXLEN];
 
160
    char    word[WORDMAXLEN];
 
161
    char    *newPOS;
 
162
    char    *oldPOS;
 
163
    int     count = 0;
 
164
 
 
165
    if( DEBUG )
 
166
        printf( "Q1 Buffer is : %s\n" , buf + 1 );
 
167
    oldPOS = buf + 1;
 
168
    newPOS = oldPOS;
 
169
  
 
170
    do
 
171
    {
 
172
        newPOS = StringSplit( oldPOS, word, WORDMAXLEN );
 
173
        StringStrip( word, value);
 
174
        oldPOS = newPOS;
 
175
 
 
176
        if( DEBUG )
 
177
        {
 
178
            printf( "value=%s\n", value );
 
179
            fflush( stdout );
 
180
        }
 
181
        switch( count ) 
 
182
        {
 
183
            case  0:
 
184
                    /* IP Voltage */
 
185
                    dstate_setinfo("input.voltage", "%s", value );
 
186
                    break;
 
187
            case  1:
 
188
                    /* IP Fault Voltage */
 
189
                    break;
 
190
            case  2:
 
191
                    /* OP Voltage */
 
192
                    dstate_setinfo("output.voltage", "%s", value);
 
193
                    break;
 
194
            case  3:
 
195
                    /* OP Load*/
 
196
                    dstate_setinfo("ups.load", "%s", value );
 
197
                    break;
 
198
            case  4:
 
199
                    /* IP Frequency */
 
200
                    dstate_setinfo("input.frequency", "%s", value);
 
201
                    break;
 
202
            case  5:
 
203
                    /* Battery Cell Voltage */
 
204
                    dstate_setinfo("battery.voltage", "%s", value);
 
205
                    break;
 
206
            case  6:
 
207
                    /* UPS Temperature */
 
208
                    dstate_setinfo("ups.temperature", "%s", value );
 
209
                    break;
 
210
            case  7:
 
211
                    /* Flags */
 
212
                    parseFlags( value );
 
213
                    break;
 
214
            default:
 
215
                    /* Should never be reached */
 
216
                    break;
 
217
        }
 
218
        count ++;
 
219
        oldPOS = newPOS;
 
220
    }
 
221
    while( newPOS != NULL );
 
222
}
 
223
 
 
224
/********************************************************************
 
225
 *
 
226
 * Function parses the response of the query3 ( "Q3" ) command.
 
227
 * Also sets various values (IPFreq ... )
 
228
 * 
 
229
 ********************************************************************/
 
230
void query3( char *buf )
 
231
{
 
232
    #define WORDMAXLEN 255
 
233
    char    value[WORDMAXLEN];
 
234
    char    word[WORDMAXLEN];
 
235
    char    *newPOS;
 
236
    char    *oldPOS;
 
237
    int     count = 0;
 
238
 
 
239
    if( DEBUG ) 
 
240
        printf( "Q3 Buffer is : %s\n" , buf+1 );
 
241
    oldPOS = buf + 1;
 
242
    newPOS = oldPOS;
 
243
  
 
244
    do
 
245
    {
 
246
        newPOS = StringSplit( oldPOS, word, WORDMAXLEN );
 
247
        StringStrip( word, value);
 
248
        oldPOS = newPOS;
 
249
 
 
250
        /* Shortcut */
 
251
        if( newPOS == NULL )
 
252
            break;
 
253
 
 
254
        if( DEBUG )
 
255
        {
 
256
            printf( "value=%s\n", value );
 
257
            fflush( stdout );
 
258
        }
 
259
        switch( count ) 
 
260
        {
 
261
            case  0:
 
262
                    /* UPS ID */
 
263
                    break;
 
264
            case  1:
 
265
                    /* Input Voltage */
 
266
                    dstate_setinfo("input.voltage", "%s", value );
 
267
                    break;
 
268
            case  2:
 
269
                    /* Input Fault Voltage */
 
270
                    break;
 
271
            case  3:
 
272
                    /* Output Voltage */
 
273
                    dstate_setinfo("output.voltage", "%s", value);
 
274
                    break;
 
275
            case  4:
 
276
                    /* Output Current */
 
277
                    dstate_setinfo("output.current", "%s", value );
 
278
                    break;
 
279
            case  5:
 
280
                    /* Input Frequency */
 
281
                    dstate_setinfo("input.frequency", "%s", value);
 
282
                    break;
 
283
            case  6:
 
284
                    /* Battery Cell Voltage */
 
285
                    dstate_setinfo("battery.voltage", "%s", value);
 
286
                    break;
 
287
            case  7:
 
288
                    /* Temperature */
 
289
                    dstate_setinfo("ups.temperature", "%s", value );
 
290
                    break;
 
291
            case  8:
 
292
                    /* Estimated Runtime */
 
293
                    dstate_setinfo("battery.runtime", "%s", value);
 
294
                    break;
 
295
            case  9:
 
296
                    /* Charge Status */
 
297
                    dstate_setinfo("battery.charge", "%s", value);
 
298
                    break;
 
299
            case 10:
 
300
                    /* Flags */
 
301
                    parseFlags( value );
 
302
                    break;
 
303
            case 11:
 
304
                    /* Flags2 */
 
305
                    break;
 
306
            default:
 
307
                    /* This should never be reached */
 
308
                    /* printf( "DEFAULT\n" ); */
 
309
                    break;
 
310
        }
 
311
        count ++;
 
312
        oldPOS = newPOS;
 
313
    }
 
314
    while( newPOS != NULL );
 
315
}
 
316
 
 
317
/********************************************************************
 
318
 *
 
319
 * Function to parse the WhoAmI response of the UPS. Also sets the
 
320
 * values of the firmware version and the UPS identification.
 
321
 * 
 
322
 ********************************************************************/
 
323
void parseWH( char *buf )
 
324
{
 
325
    strncpy( name, buf + 16, 30 );
 
326
    name[30] = '\0';
 
327
    strncpy( firmware, buf + 4, 5 );
 
328
    firmware[5] = '\0';
 
329
    if( DEBUG )
 
330
        printf( "Name = %s, Firmware Version = %s\n", name, firmware );
 
331
}
 
332
 
 
333
/********************************************************************
 
334
 * 
 
335
 * Function to parse the old and possible broken WhoAmI response
 
336
 * and set the values for the firmware Version and the identification
 
337
 * of the UPS.
 
338
 *
 
339
 ********************************************************************/
 
340
void parseOldWH( char *buf )
 
341
{
 
342
    strncpy( name, buf + 4, 12 );
 
343
    name[12] = '\0';
 
344
    strncpy( firmware, buf, 4 );
 
345
    firmware[4] = '\0';
 
346
    if( DEBUG )
 
347
        printf( "Name = %s, Firmware Version = %s\n", name, firmware );
 
348
}
 
349
 
 
350
/********************************************************************
 
351
 *
 
352
 * Function to fake a WhoAmI response of a UPS that returns NAK.
 
353
 * 
 
354
 ********************************************************************/
 
355
void fakeWH( )
 
356
{
 
357
    strcpy( name, "GenericUPS" );
 
358
    strcpy( firmware, "unkn" );
 
359
    if( DEBUG )
 
360
        printf( "Name = %s, Firmware Version = %s\n", name, firmware );
 
361
}
 
362
 
 
363
int ups_ident( void )
 
364
{
 
365
    char    buf[255];
 
366
    int     ret;
 
367
 
 
368
    /* Check presence of Q1 */
 
369
    ret = upssend( "Q1\x0D" );
 
370
    ret = upsrecv( buf, 250, '\x0D', "");
 
371
    ret = strlen( buf );
 
372
    if( ret != 46 ) 
 
373
    {
 
374
        /* No Q1 response found */
 
375
        type   = 0;
 
376
        return -1;
 
377
    }
 
378
    else
 
379
    {
 
380
        if( DEBUG )
 
381
            printf( "Found Q1\n" );
 
382
        type = Q1;
 
383
    }
 
384
 
 
385
    /* Check presence of Q3 */
 
386
    ret = upssend( "Q3\x0D" );
 
387
    ret = upsrecv( buf, 250, '\x0D', "");
 
388
    ret = strlen( buf );
 
389
    if( ret == 70 ) 
 
390
    {
 
391
        if( DEBUG )
 
392
            printf( "Found Q3\n" );
 
393
        type = Q1 | Q3;
 
394
    }
 
395
    
 
396
    /* Check presence of WH ( Who am I ) */
 
397
    ret = upssend( "WH\x0D" );
 
398
    ret = upsrecv( buf, 250, '\x0D', "");
 
399
    ret = strlen( buf );
 
400
    if( ret == 112 )
 
401
    {
 
402
        if( DEBUG )
 
403
            printf( "WH found\n" );
 
404
        parseWH( buf );
 
405
    }
 
406
    else if( ret == 53 )
 
407
    {
 
408
        if( DEBUG )
 
409
            printf( "Old (broken) WH found\n" );
 
410
        parseOldWH( buf );
 
411
    }
 
412
    else if( ret == 3 && strcmp(buf, "NAK") == 0 )
 
413
    {
 
414
        if( DEBUG )
 
415
            printf( "WH was NAKed\n" );
 
416
        fakeWH( );
 
417
    }
 
418
    else if( ret > 0 )
 
419
    {
 
420
        if( DEBUG )
 
421
            printf( "WH says <%s> with length %i\n", buf, ret );
 
422
        upslog( LOG_INFO, 
 
423
                "New WH String found. Please report to maintainer\n" );
 
424
    }
 
425
    return 1;
 
426
 
427
 
 
428
/********************************************************************
 
429
 *
 
430
 * 
 
431
 * 
 
432
 * 
 
433
 ********************************************************************/
 
434
void upsdrv_help( void )
 
435
{
 
436
 
 
437
}
 
438
 
 
439
/********************************************************************
 
440
 *
 
441
 * Function to initialize the fields of the ups driver.
 
442
 * 
 
443
 ********************************************************************/
 
444
void upsdrv_initinfo(void)
 
445
{
 
446
        dstate_setinfo("ups.mfr", "MASTERGUARD");
 
447
        dstate_setinfo("ups.model", "unknown");
 
448
        
 
449
        /*
 
450
        dstate_addcmd("test.battery.stop");
 
451
        dstate_addcmd("test.battery.start");
 
452
        */
 
453
 
 
454
        if( strlen( name ) > 0 )
 
455
                dstate_setinfo("ups.model", "%s", name);
 
456
        if( strlen( firmware ) > 0 )
 
457
                dstate_setinfo("ups.firmware", "%s", firmware);
 
458
 
 
459
        dstate_setinfo("driver.version.internal", "%s", DRIVERVERSION);
 
460
}
 
461
 
 
462
/********************************************************************
 
463
 *
 
464
 * This is the main function. It gets called if the driver wants 
 
465
 * to update the ups status and the informations.
 
466
 * 
 
467
 ********************************************************************/
 
468
void upsdrv_updateinfo(void)
 
469
{
 
470
    char    buf[255];
 
471
    int     ret;
 
472
    int     lenRSP=0;
 
473
    
 
474
    if( DEBUG ) 
 
475
        printf( "update info\n" );
 
476
 
 
477
    /* Q3 found ? */
 
478
    if( type & Q3 )
 
479
    {
 
480
        upssend( "Q3\x0D" );
 
481
        lenRSP = 70;
 
482
    }
 
483
    /* Q1 found ? */
 
484
    else if( type & Q1 )
 
485
    {
 
486
        upssend( "Q1\x0D" );
 
487
        lenRSP = 46;
 
488
    }
 
489
    /* Should never be reached */
 
490
    else
 
491
    {
 
492
        fatalx("Error, no Query mode defined. Please file bug against driver.");
 
493
    }
 
494
 
 
495
    sleep( UPSDELAY );
 
496
    
 
497
    buf[0] = '\0';
 
498
    upsrecv( buf, 250, '\x0D', "\n");
 
499
    ret = strlen( buf );
 
500
 
 
501
    if( ret != lenRSP ) 
 
502
    {
 
503
        if( DEBUG ) 
 
504
            printf( "buf = %s len = %i\n", buf, ret );
 
505
        upslog( LOG_ERR, "Error in UPS response " );
 
506
        dstate_datastale();
 
507
        return;
 
508
    }
 
509
    
 
510
    /* Parse the response from the UPS */
 
511
    if( type & Q3 )
 
512
    {
 
513
        query3( buf );
 
514
        dstate_dataok();
 
515
        return;
 
516
    }
 
517
    if( type & Q1 )
 
518
    {
 
519
        query1( buf );
 
520
        dstate_dataok();
 
521
        return;
 
522
    }
 
523
}
 
524
 
 
525
/********************************************************************
 
526
 *
 
527
 * Called if the driver wants to shutdown the UPS.
 
528
 * ( also used by the "-k" command line switch )
 
529
 * 
 
530
 * This cuts the utility from the UPS after 20 seconds and restores
 
531
 * the utility one minute _after_ the utility to the UPS has restored
 
532
 *
 
533
 ********************************************************************/
 
534
void upsdrv_shutdown(void)
 
535
{
 
536
        /* ups will come up within a minute if utility is restored */
 
537
    upssend( "S.2R0001\x0D" );
 
538
}
 
539
 
 
540
/********************************************************************
 
541
 *
 
542
 * Populate the command line switches.
 
543
 * 
 
544
 * CS:  Cancel the shutdown process
 
545
 * 
 
546
 ********************************************************************/
 
547
void upsdrv_makevartable(void)
 
548
{
 
549
    addvar( VAR_FLAG, "CS", "Cancel Shutdown" );
 
550
}
 
551
 
 
552
/********************************************************************
 
553
 *
 
554
 * The UPS banner shown during the startup.
 
555
 * Spiffy isn't it?  ;-)
 
556
 * 
 
557
 ********************************************************************/
 
558
void upsdrv_banner(void)
 
559
{
 
560
        printf("Network UPS Tools - MASTERGUARD UPS driver %s (%s)\n\n",
 
561
            DRIVERVERSION, UPS_VERSION);
 
562
    
 
563
}
 
564
 
 
565
/********************************************************************
 
566
 *
 
567
 * This is the first function called by the UPS driver.
 
568
 * Detects the UPS and handles the command line args.
 
569
 * 
 
570
 ********************************************************************/
 
571
void upsdrv_initups(void)
 
572
{
 
573
    int     count = 0;
 
574
    int     fail  = 0;
 
575
    int     good  = 0;
 
576
    
 
577
        /* setup serial port */
 
578
    upssend_delay = 100; 
 
579
        open_serial( device_path, B2400 );
 
580
   
 
581
    name[0] = '\0';
 
582
    firmware[0] = '\0';
 
583
 
 
584
        /* probe ups type */
 
585
    do
 
586
    {
 
587
        count++;
 
588
 
 
589
        if( ups_ident( ) != 1 )
 
590
            fail++;
 
591
        /* at least two good identifications */
 
592
        if( (count - fail) == 2 )
 
593
        {
 
594
            good = 1;
 
595
            break;
 
596
        }
 
597
    } while( (count<MAXTRIES) | (good) );
 
598
 
 
599
    if( ! good )
 
600
    {        
 
601
        printf( "No MASTERGUARD UPS found\n" );
 
602
        exit( 1 );
 
603
    }
 
604
       
 
605
    printf( "MASTERGUARD UPS found\n" );
 
606
    
 
607
    /* Cancel Shutdown */
 
608
    if( testvar("CS") )
 
609
    {
 
610
       upssend( "C\x0D" );
 
611
       exit( 1 );
 
612
    }
 
613
}
 
614
 
 
615
/********************************************************************
 
616
 *
 
617
 * VIM Preferences.
 
618
 * As you probably know vim is the best editor ever ;-)
 
619
 * http://www.vim.org
 
620
 *
 
621
 * vim:ts=4:sw=4:tw=78:et
 
622
 * 
 
623
 ********************************************************************/
 
624
 
 
625
void upsdrv_cleanup(void)
 
626
{
 
627
}