~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): 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
   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
}