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

« back to all changes in this revision

Viewing changes to drivers/bestfortress.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:
1
 
/*
2
 
   bestfortress.c - model specific routines for (very) old Best Power Fortress
3
 
 
4
 
   Copyright (C) 2002  Russell Kroll <rkroll@exploits.org> (skeleton)
5
 
             (C) 2002  Holger Dietze <holger.dietze@advis.de>
6
 
 
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.
11
 
 
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.
16
 
 
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
20
 
*/
21
 
 
22
 
/*
23
 
        anything commented is optional
24
 
        anything else is mandatory
25
 
*/
26
 
 
27
 
#include "main.h"
28
 
 
29
 
#define ENDCHAR         '\r'
30
 
#define IGNCHARS        " \n"
31
 
 
32
 
#if defined(__sgi) && ! defined(__GNUC__)
33
 
#define        inline  __inline
34
 
#endif
35
 
 
36
 
void instcmd (int auxcmd, int dlen, char *data);
37
 
void upsdrv_setvar (int, int, char *);
38
 
 
39
 
void upsdrv_initinfo(void)
40
 
{
41
 
        dstate_setinfo("ups.mfr", "Best Power");
42
 
        dstate_setinfo("ups.model", "Fortress");
43
 
        dstate_setinfo("battery.voltage.nominal", "24");
44
 
 
45
 
        /*addinfo (INFO_ALRM_OVERLOAD, "", 0, 0);*/ /* Flag */
46
 
        /*addinfo (INFO_ALRM_TEMP, "", 0, 0);*/ /* Flag */
47
 
 
48
 
        dstate_setinfo("ups.delay.shutdown", "10");     /* write only */        
49
 
        
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
55
 
           
56
 
           comm mode    p6=0 dumb DONT USE (will lose access to parameter setting!)
57
 
                        p6=1 B1200
58
 
                        p6=2 B2400
59
 
                        P6=3 B4800
60
 
                        p6=4 B9600
61
 
           maybe cycle through speeds to autodetect?
62
 
 
63
 
           echo off     e0
64
 
           echo on      e1
65
 
        */
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);
69
 
 
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);
73
 
 
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);
77
 
 
78
 
        upsh.instcmd = instcmd; 
79
 
        upsh.setvar = upsdrv_setvar;
80
 
 
81
 
        dstate_addcmd("shutdown.return");
82
 
        dstate_addcmd("load.off");
83
 
}
84
 
 
85
 
/* convert hex digit to int */
86
 
static inline int fromhex (char c)
87
 
{
88
 
        return (c >= '0' && c <= '9') ? c - '0'
89
 
                : (c >= 'A' && c <= 'F') ? c - 'A' + 10
90
 
                : (c >= 'a' && c <= 'f') ? c - 'a' + 10
91
 
                : 0;
92
 
}
93
 
 
94
 
/* do checksumming on UPS response */
95
 
static int checksum (char * s)
96
 
{
97
 
        int i;
98
 
        int sum;
99
 
        for (i = 40, sum = 0; s[0] && s[1] && i > 0; i--, s += 2) {
100
 
                sum += (fromhex (s[0]) << 4) + fromhex (s[1]);
101
 
        }
102
 
        return sum;
103
 
}
104
 
 
105
 
/* set info to integer value */
106
 
static inline void setinfo_int (int id, char * s, int len)
107
 
{
108
 
        char buf[10];
109
 
        
110
 
        if (len > sizeof(buf)) len = sizeof(buf)-1;
111
 
        strncpy (buf, s, len);
112
 
        buf[len] = 0;
113
 
        setinfo (id, "%d", atoi (buf));
114
 
}
115
 
 
116
 
/* set info to integer value (for runtime remaining)
117
 
   value is expressed in minutes, but desired in seconds
118
 
 */
119
 
static inline void setinfo_int_minutes (int id, char * s, int len)
120
 
{
121
 
        char buf[10];
122
 
        
123
 
        if (len > sizeof(buf)) len = sizeof(buf)-1;
124
 
        strncpy (buf, s, len);
125
 
        buf[len] = 0;
126
 
        setinfo (id, "%d", 60*atoi (buf));
127
 
}
128
 
 
129
 
/* set info to float value */
130
 
static inline void setinfo_float (int id, char * fmt, char * s, int len, double factor)
131
 
{
132
 
        char buf[10];
133
 
        if (len > sizeof(buf)) len = sizeof(buf)-1;
134
 
        strncpy (buf, s, len);
135
 
        buf[len] = 0;
136
 
        setinfo (id, fmt, factor * (double)atoi (buf));
137
 
}
138
 
 
139
 
/* read out UPS and store info */
140
 
void upsdrv_updateinfo(void)
141
 
{
142
 
        char temp[256];
143
 
        char *p;
144
 
        
145
 
        int checksum_ok, is_online=1, is_off, low_batt, trimming, boosting;
146
 
        
147
 
        upssend ("f\r");
148
 
        
149
 
        do {
150
 
                if (upsrecv (temp, sizeof(temp), ENDCHAR, IGNCHARS) <= 0) {
151
 
                        upsflushin (0, 0, "\r ");
152
 
                        upssend ("f\r");
153
 
                }
154
 
        } while (temp[0] == 0);
155
 
        /* setinfo (INFO_, ""); */
156
 
        p = temp;
157
 
        
158
 
        /*syslog (LOG_DAEMON | LOG_NOTICE,"ups: got '%s'\n", p);*/
159
 
        /* status example:
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
164
 
        */
165
 
 
166
 
        /* last bytes are a checksum:
167
 
           interpret response as hex string, sum of all bytes must be zero
168
 
        */
169
 
        checksum_ok = (checksum (p) & 0xff) == 0;
170
 
 
171
 
        if (!checksum_ok) {
172
 
                dstate_datastale();
173
 
                return;
174
 
        }
175
 
        
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);
184
 
        
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
191
 
                         simulate one) */
192
 
 
193
 
        setinfo (INFO_STATUS, "%s%s%s",
194
 
                 is_online ? (is_off ? "OFF " : "OL ") : "OB ",
195
 
                 low_batt ? "LB " : "",
196
 
                 trimming ? "TRIM" : boosting ? "BOOST" : "");
197
 
 
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");
203
 
         */
204
 
 
205
 
        dstate_dataok();
206
 
}
207
 
 
208
 
 
209
 
/* Parameter setting */
210
 
 
211
 
/* all UPS tunable parameters are set with command
212
 
   'p%d=%s'
213
 
*/
214
 
int setparam (int parameter, int dlen, char * data)
215
 
{
216
 
        char reply[80];
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;
220
 
}
221
 
 
222
 
/* ups_setsuper: set super-user access
223
 
   (allows setting variables)
224
 
*/
225
 
static void ups_setsuper (int super)
226
 
{
227
 
        setparam (999, super ? 4 : 0, super ? "2639" : "");
228
 
}
229
 
 
230
 
/* sets whether UPS will reapply power after it has shut down and line
231
 
 * power returns.
232
 
 */
233
 
static void autorestart (int restart)
234
 
{
235
 
        ups_setsuper (1);
236
 
        setparam (1, 1, restart ? "1" : "0");
237
 
        ups_setsuper (0);
238
 
}
239
 
 
240
 
/* set UPS parameters */
241
 
void upsdrv_setvar (int info, int len, char * data)
242
 
{
243
 
        int parameter;
244
 
        switch (info) {
245
 
        case INFO_LOWXFER:
246
 
                parameter = 7;
247
 
                break;
248
 
        case INFO_HIGHXFER:
249
 
                parameter = 8;
250
 
                break;
251
 
        case INFO_LOBATTIME:
252
 
                parameter = 2;
253
 
                break;
254
 
        default:
255
 
                return;
256
 
        }
257
 
        ups_setsuper (1);
258
 
        if (setparam (parameter, len, data)) {
259
 
                setinfo (info, "%*s", len, data);
260
 
        }
261
 
        ups_setsuper (0);
262
 
}
263
 
 
264
 
void upsdrv_shutdown(void)
265
 
{
266
 
        const   char    *grace;
267
 
 
268
 
        grace = getdata(INFO_PDNGRACE);
269
 
 
270
 
        if (!grace)
271
 
                grace = "1"; /* apparently, OFF0 does not work */
272
 
 
273
 
        printf ("shutdown in %s seconds\n", grace);
274
 
        /* make power return when utility power returns */
275
 
        autorestart (1);
276
 
        upssend ("OFF%s\r", grace);
277
 
        /* I'm nearly dead, Jim */
278
 
        /* OFF will powercycle when line power is available again */
279
 
}
280
 
 
281
 
void instcmd (int auxcmd, int dlen, char *data)
282
 
{
283
 
        const char *p;
284
 
        
285
 
        switch (auxcmd) {
286
 
        case CMD_OFF:
287
 
                printf ("powering off\n");
288
 
                autorestart (0);
289
 
                upssend ("OFF1\r");
290
 
                break;
291
 
        case CMD_SHUTDOWN:
292
 
                p = getdata (INFO_PDNGRACE);
293
 
                if (!p) p = "1";
294
 
                printf ("shutdown in %s seconds\n", p);
295
 
                autorestart (1);
296
 
                upssend ("OFF%s\r", p);
297
 
                break;
298
 
        default:
299
 
                upslogx(LOG_INFO, "instcmd: unknown type 0x%04x", auxcmd);
300
 
        }
301
 
}
302
 
 
303
 
void upsdrv_help(void)
304
 
{
305
 
}
306
 
 
307
 
/* list flags and values that you want to receive via -x */
308
 
void upsdrv_makevartable(void)
309
 
{
310
 
        /* allow '-x xyzzy' */
311
 
        /* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */
312
 
        
313
 
        /* allow '-x foo=<some value>' */
314
 
        /* addvar(VAR_VALUE, "foo", "Override foo setting"); */
315
 
        addvar (VAR_VALUE, "speed", "serial line speed");
316
 
}
317
 
 
318
 
void upsdrv_banner(void)
319
 
{
320
 
        printf("Network UPS Tools - Best Fortress UPS driver 0.01 (%s)\n\n", UPS_VERSION);
321
 
}
322
 
 
323
 
struct {
324
 
        char * val;
325
 
        speed_t speed;
326
 
} speed_table[] = {
327
 
        {"1200", B1200},
328
 
        {"2400", B2400},
329
 
        {"4800", B4800},
330
 
        {"9600", B9600},
331
 
        {NULL, B1200},
332
 
};
333
 
 
334
 
void upsdrv_initups(void)
335
 
{
336
 
        speed_t speed = B1200;
337
 
 
338
 
        char * speed_val = getval ("speed");
339
 
 
340
 
        if (speed_val) {
341
 
                int i;
342
 
                for (i=0; speed_table[i].val; i++) {
343
 
                        if (strcmp (speed_val, speed_table[i].val) == 0)
344
 
                                break;
345
 
                }
346
 
                speed = speed_table[i].speed;
347
 
        }
348
 
        
349
 
        open_serial(device_path, speed);
350
 
        /* TODO: probe ups type */
351
 
        
352
 
        /* the upsh handlers can't be done here, as they get initialized
353
 
         * shortly after upsdrv_initups returns to main.
354
 
         */
355
 
}
356
 
 
357
 
void upsdrv_cleanup(void)
358
 
{
359
 
}