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

« back to all changes in this revision

Viewing changes to drivers/energizerups.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:
23
23
 
24
24
#include <asm/types.h>
25
25
#include <sys/ioctl.h>
 
26
 
 
27
#ifndef HID_MAX_USAGES
 
28
#define HID_MAX_USAGES 1024 /* horrible workaround hack */
 
29
#endif
 
30
 
26
31
#include <linux/hiddev.h>
27
32
#include <fcntl.h>
28
33
#include <stdio.h>
29
34
#include <signal.h>
30
35
#include <sys/select.h>
 
36
#include <ctype.h>
31
37
 
32
38
#include "main.h"
33
39
 
34
 
#define DRV_VERSION     "0.01"
 
40
#define DRV_VERSION "0.02"
35
41
 
36
42
#define NUM_EVTS 64
37
43
 
 
44
#define RETRIES 3
 
45
 
38
46
/* Response to I identification queries is in the following format:
39
47
 *
40
48
 * 012345678901234567890123456789012345678
41
49
 * #Energizer       ER-HMOF600 A0        ^M
42
50
 * #Energizer       ER-OF800   A0        ^M
43
51
 */
44
 
#define MANUFR  (buf+1)
45
 
#define MDLNUM  (buf+17)
46
 
#define HWVERS  (buf+28)
 
52
#define MANUFR (buf+1)
 
53
#define MDLNUM (buf+17)
 
54
#define HWVERS (buf+28)
47
55
 
48
56
/* Response to Q1 queries is in the following format:
49
57
 *
50
58
 * 01234567890123456789012345678901234567890123456
51
59
 * (118.6 118.6 118.6 020 60.0 13.8 32.0 00001000^M
52
60
 */
53
 
#define INVOLT  (buf+1)
54
 
#define OUTVOLT (buf+13)
55
 
#define LOADPCT (buf+19)
56
 
#define ACFREQ  (buf+23)
57
 
#define BATVOLT (buf+28)
58
 
#define UPSTEMP (buf+33)
59
 
#define STATUS  (buf+38)
 
61
#define INVOLT (buf+1)
 
62
#define OUTVOLT (buf+13)
 
63
#define LOADPCT (buf+19)
 
64
#define ACFREQ (buf+23)
 
65
#define BATVOLT (buf+28)
 
66
#define UPSTEMP (buf+33)
 
67
#define STATUS (buf+38)
60
68
 
61
 
#define OBFLAG  (STATUS[0]=='1'||STATUS[5]=='1')
62
 
#define LBFLAG  (STATUS[1]=='1')
63
 
#define BYPASS  (STATUS[2]=='1')
64
 
#define BEEPER  (STATUS[7]=='1')
 
69
#define OBFLAG (STATUS[0]=='1'||STATUS[5]=='1')
 
70
#define LBFLAG (STATUS[1]=='1')
 
71
#define BYPASS (STATUS[2]=='1')
 
72
#define BEEPER (STATUS[7]=='1')
65
73
 
66
74
/* A calibration test of the ER-HMOF600 shows its maximum voltage at
67
 
 * 14.0V during charging, falling down to 13.6 if the UPS is turned off
68
 
 * for three minutes (but connected to line power) and to 12.8V
 
75
 * 14.0V during charging, falling to 13.6 when the UPS is turned off
 
76
 * for three minutes (while still connected to line power) and to 12.8V
69
77
 * immediately after starting a test with a 60W load. The 'low battery'
70
 
 * warning came at 11.0V, and a discharge time to LB with a 60W light
71
 
 * bulb took 35 minutes. The UPS ran another 5 minutes on LB before
 
78
 * warning came on at 11.0V. The discharge time to LB with a 60W light
 
79
 * bulb was 35 minutes. The UPS ran another 5 minutes on LB before
72
80
 * shutting down, at which time the battery voltage was 10.1V. When
73
81
 * charging resumed at the moment the LB warning came on, the battery
74
82
 * started at 12.0V.
83
91
 * the values of other similar UPSs.
84
92
 */
85
93
 
86
 
#define LOWVOLT (OBFLAG?11.0:12.0)
87
 
#define VOLTRNG 1.8
88
 
#define LOXFER  84
89
 
#define LONORM  98
90
 
#define HINORM  126
91
 
#define HIXFER  142
 
94
#define LOWVOLT (OBFLAG?11.0:12.0)
 
95
#define VOLTRNG 1.8
 
96
#define LOXFER 84
 
97
#define LONORM 98
 
98
#define HINORM 126
 
99
#define HIXFER 142
92
100
 
93
101
#define hidsend(x) hidcmd(x,NULL,0)
94
102
 
103
111
 
104
112
void sendstring(int fd, char *psz)
105
113
{
106
 
        struct hiddev_report_info rinfo;
107
 
        struct hiddev_usage_ref uref;
108
 
        int i, j;
109
 
        unsigned char c;
110
 
 
111
 
        uref.usage_index = 0;
112
 
        i = 0;
113
 
 
114
 
        do
115
 
        {
116
 
                c = (*psz) ? *psz :0x0D;
117
 
                for (j = 0; j < 8; j++)
118
 
                {
119
 
                        uref.report_type = HID_REPORT_TYPE_OUTPUT;
120
 
                        uref.report_id = 0;
121
 
                        uref.field_index = 0;
122
 
                        uref.usage_code = 0x90001 + uref.usage_index;
123
 
                        uref.value = (c & 1);
124
 
                        if (ioctl(fd, HIDIOCSUSAGE, &uref) < 0)
125
 
                                fatalx("Error (SUSAGE) while talking to the UPS");
126
 
                        uref.usage_index++;
127
 
                        c >>= 1;
128
 
                }
129
 
                if (*psz == 0 || ++i == 8)
130
 
                {
131
 
                        i = 0;
132
 
                        while (uref.usage_index++ < 63)
133
 
                        {
134
 
                                uref.report_type = HID_REPORT_TYPE_OUTPUT;
135
 
                                uref.report_id = 0;
136
 
                                uref.field_index = 0;
137
 
                                uref.usage_code = 0x90001 + uref.usage_index;
138
 
                                uref.value = 0;
139
 
                                if (ioctl(fd, HIDIOCSUSAGE, &uref) < 0)
140
 
                                        fatalx("Error (SUSAGE) while talking to the UPS");
141
 
                        }
142
 
                        uref.usage_index = 0;
143
 
 
144
 
                        rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
145
 
                        rinfo.report_id = 0;
146
 
                        rinfo.num_fields = 1;
147
 
                        if (ioctl(fd, HIDIOCSREPORT, &rinfo) < 0)
148
 
                                fatalx("Error (SREPORT) while talking to the UPS");
149
 
                }
150
 
        } while (*psz++);
 
114
    struct hiddev_report_info rinfo;
 
115
    struct hiddev_usage_ref uref;
 
116
    int i, j;
 
117
    unsigned char c;
 
118
 
 
119
    uref.usage_index = 0;
 
120
    i = 0;
 
121
 
 
122
    do
 
123
    {
 
124
        c = (*psz) ? *psz :0x0D;
 
125
        for (j = 0; j < 8; j++)
 
126
        {
 
127
            uref.report_type = HID_REPORT_TYPE_OUTPUT;
 
128
            uref.report_id = 0;
 
129
            uref.field_index = 0;
 
130
            uref.usage_code = 0x90001 + uref.usage_index;
 
131
            uref.value = (c & 1);
 
132
            if (ioctl(fd, HIDIOCSUSAGE, &uref) < 0)
 
133
                fatalx("Error (SUSAGE) while talking to the UPS");
 
134
            uref.usage_index++;
 
135
            c >>= 1;
 
136
        }
 
137
        if (*psz == 0 || ++i == 8)
 
138
        {
 
139
            i = 0;
 
140
            while (uref.usage_index++ < 63)
 
141
            {
 
142
                uref.report_type = HID_REPORT_TYPE_OUTPUT;
 
143
                uref.report_id = 0;
 
144
                uref.field_index = 0;
 
145
                uref.usage_code = 0x90001 + uref.usage_index;
 
146
                uref.value = 0;
 
147
                if (ioctl(fd, HIDIOCSUSAGE, &uref) < 0)
 
148
                    fatalx("Error (SUSAGE) while talking to the UPS");
 
149
            }
 
150
            uref.usage_index = 0;
 
151
 
 
152
            rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
 
153
            rinfo.report_id = 0;
 
154
            rinfo.num_fields = 1;
 
155
            if (ioctl(fd, HIDIOCSREPORT, &rinfo) < 0)
 
156
                fatalx("Error (SREPORT) while talking to the UPS");
 
157
        }
 
158
    } while (*psz++);
 
159
}
 
160
 
 
161
/*
 
162
 * Helper function to "fake" the first eight bytes of the UPS response. For
 
163
 * reasons that I don't understand, on 2.6.x kernels the first eight characters
 
164
 * never appear (i.e., the event interface starts with a set of blank
 
165
 * characters, then we receive events that show changed bits... for the
 
166
 * SECOND set of 8 characters. This is admittedly a disgusting hack, but then
 
167
 * again, this serial-to-USB interface is such a hack anyway, it's a miracle it
 
168
 * works! In any case, the point is that this way, we can make the UPS work,
 
169
 * which is the whole point of this exercise.
 
170
 */
 
171
int fake_hid_ev_bits(int r, char *buf, int size)
 
172
{
 
173
    if (r == 31)
 
174
    {
 
175
        memmove(buf + 8, buf, size - 8);
 
176
        strncpy(buf, "#Energiz", 8);
 
177
        r += 8;
 
178
    }
 
179
    else if ((r == 38 || r == 39) && isdigit(buf[0]))
 
180
    {
 
181
        memmove(buf + 8, buf, size - 8);
 
182
        strncpy(buf, "(117.0 1", 8);
 
183
        r += 8;
 
184
    }
 
185
    return r;
151
186
}
152
187
 
153
188
/*
167
202
 
168
203
int hidcmd(unsigned char *pCmd, unsigned char *pRsp, int l)
169
204
{
170
 
        int fd, rd, i, j, k, hid;
171
 
        fd_set rdfs;
172
 
        struct timeval tv;
173
 
        struct hiddev_event ev[NUM_EVTS];
174
 
        struct hiddev_usage_ref uref;
175
 
        unsigned char data[8];
176
 
 
177
 
        if ((fd = open(device_path, O_RDWR)) < 0)
178
 
                fatalx("Cannot communicate with UPS at %s", device_path);
179
 
 
180
 
        FD_ZERO(&rdfs);
181
 
        FD_SET(fd, &rdfs);
182
 
 
183
 
        memset(data, 0, sizeof(data));
184
 
        for (i = 0; i < 64; i++)
185
 
        {
186
 
                uref.report_type = HID_REPORT_TYPE_INPUT;
187
 
                uref.report_id = 0;
188
 
                uref.field_index = 0;
189
 
                uref.usage_index = i;
190
 
                ioctl(fd, HIDIOCGUCODE, &uref);
191
 
                ioctl(fd, HIDIOCGUSAGE, &uref);
192
 
 
193
 
                if (uref.value) data[i >> 3] |= 1 << (i & 7);
194
 
        }
195
 
 
196
 
        sendstring(fd, pCmd);
197
 
 
198
 
        k = 0;
199
 
 
200
 
        if (pRsp != NULL)
201
 
        {
202
 
                hid = -1;
203
 
                while (l > 0)
204
 
                {
205
 
                        tv.tv_sec = 0;
206
 
                        tv.tv_usec = 500000;
207
 
                        if (select(fd+1, &rdfs, 0, 0, &tv) <= 0) break;
208
 
                        rd = read(fd, ev, sizeof(ev));
209
 
                        if (rd < (int) sizeof(ev[0]))
210
 
                                fatalx("Communication failure with UPS");
211
 
 
212
 
                        for (i = 0; i < rd / sizeof(ev[0]); i++)
213
 
                        {
214
 
                                if (hid >= 0 && ev[i].hid <= hid)
215
 
                                {
216
 
                                        for (j = 0; j < 8; j++)
217
 
                                        {
218
 
                                                if (k < l - 1)
219
 
                                                {
220
 
                                                        if (k > 0 || data[j] != 0xFF) pRsp[k++] = data[j];
221
 
                                                }
222
 
                                                else break;
223
 
                                        }
224
 
                                }
225
 
                                j = (ev[i].hid - 1) & 0x3F;
226
 
                                if (ev[i].value) data[j >> 3] |= 1 << (j & 7);
227
 
                                else data[j >> 3] &= ~(1 << (j & 7));
228
 
                                hid = ev[i].hid;
229
 
                        }
230
 
                }
231
 
                if (hid >= 0) for (j = 0; j < ((hid - 1) & 0x3F) >> 3; j++)
232
 
                {
233
 
                        if (k < l - 1)
234
 
                        {
235
 
                                if (k > 0 || data[j] != 0xFF) pRsp[k++] = data[j];
236
 
                        }
237
 
                        else break;
238
 
                }
239
 
                pRsp[k] = '\0';
240
 
        }
241
 
        close(fd);
242
 
        return k;
 
205
    unsigned int i;
 
206
    int fd, rd, j, k, hid;
 
207
    fd_set rdfs;
 
208
    struct timeval tv;
 
209
    struct hiddev_event ev[NUM_EVTS];
 
210
    struct hiddev_usage_ref uref;
 
211
    unsigned char data[8];
 
212
 
 
213
    if ((fd = open(device_path, O_RDWR)) < 0)
 
214
        fatalx("Cannot communicate with UPS at %s", device_path);
 
215
 
 
216
    FD_ZERO(&rdfs);
 
217
    FD_SET(fd, &rdfs);
 
218
 
 
219
    memset(data, 0, sizeof(data));
 
220
    for (i = 0; i < 64; i++)
 
221
    {
 
222
        uref.report_type = HID_REPORT_TYPE_INPUT;
 
223
        uref.report_id = 0;
 
224
        uref.field_index = 0;
 
225
        uref.usage_index = i;
 
226
        ioctl(fd, HIDIOCGUCODE, &uref);
 
227
        ioctl(fd, HIDIOCGUSAGE, &uref);
 
228
 
 
229
        if (uref.value) data[i >> 3] |= 1 << (i & 7);
 
230
    }
 
231
 
 
232
    sendstring(fd, pCmd);
 
233
 
 
234
    k = 0;
 
235
 
 
236
    if (pRsp != NULL)
 
237
    {
 
238
        hid = -1;
 
239
        while (l > 0)
 
240
        {
 
241
            tv.tv_sec = 0;
 
242
            tv.tv_usec = 500000;
 
243
            if (select(fd+1, &rdfs, 0, 0, &tv) <= 0) break;
 
244
            rd = read(fd, ev, sizeof(ev));
 
245
            if (rd < (int) sizeof(ev[0]))
 
246
                fatalx("Communication failure with UPS");
 
247
 
 
248
            for (i = 0; i < rd / sizeof(ev[0]); i++)
 
249
            {
 
250
                if (hid >= 0 && (int) ev[i].hid <= hid)
 
251
                {
 
252
                    for (j = 0; j < 8; j++)
 
253
                    {
 
254
                        if (k < l - 1)
 
255
                        {
 
256
                            if (k > 0 || data[j] != 0xFF) pRsp[k++] = data[j];
 
257
                        }
 
258
                        else break;
 
259
                    }
 
260
                }
 
261
                j = (ev[i].hid - 1) & 0x3F;
 
262
                if (ev[i].value) data[j >> 3] |= 1 << (j & 7);
 
263
                else data[j >> 3] &= ~(1 << (j & 7));
 
264
                hid = ev[i].hid;
 
265
            }
 
266
        }
 
267
        if (hid >= 0) for (j = 0; j < ((hid - 1) & 0x3F) >> 3; j++)
 
268
        {
 
269
            if (k < l - 1)
 
270
            {
 
271
                if (k > 0 || data[j] != 0xFF) pRsp[k++] = data[j];
 
272
            }
 
273
            else break;
 
274
        }
 
275
        pRsp[k] = '\0';
 
276
    }
 
277
    close(fd);
 
278
    return pRsp ? fake_hid_ev_bits(k, pRsp, l) : k;
243
279
}
244
280
 
245
281
 
246
282
int instcmd(const char *cmdname, const char *extra)
247
283
{
248
 
        if (!strcasecmp(cmdname, "test.battery.start"))
249
 
        {
250
 
                hidsend("TL");
251
 
                upslogx(LOG_NOTICE, "UPS test start");
252
 
                return STAT_INSTCMD_HANDLED;
253
 
        }
254
 
 
255
 
        if (!strcasecmp(cmdname, "test.battery.stop"))
256
 
        {
257
 
                hidsend("CT");
258
 
                upslogx(LOG_NOTICE, "UPS test stop");
259
 
                return STAT_INSTCMD_HANDLED;
260
 
        }
261
 
 
262
 
        if (!strcasecmp(cmdname, "beeper.on") ||
263
 
                !strcasecmp(cmdname, "beeper.off"))
264
 
        {
265
 
                char buf[128];
266
 
                int r;
267
 
 
268
 
                /* Find out beeper status and send appropriate command. */
269
 
 
270
 
                r = hidcmd("Q1", buf, sizeof(buf));
271
 
                if (r < 46 || r > 47 || buf[0] != '(')
272
 
                        r = hidcmd("Q1", buf, sizeof(buf));
273
 
                if (r >= 46 && r <= 47 && buf[0] == '(')
274
 
                {
275
 
                        if (OBFLAG && !LBFLAG)  /* Otherwise there's not much we can do */
276
 
                        {
277
 
                                if ((BEEPER && !strcasecmp(cmdname, "beeper.off")) ||
278
 
                                        (!BEEPER && !strcasecmp(cmdname, "beeper.on")))
279
 
                                                hidsend("Q");
280
 
                                return STAT_INSTCMD_HANDLED;
281
 
                        }
282
 
                }
283
 
                return STAT_INSTCMD_HANDLED;    /* FUTURE: failure */
284
 
        }
285
 
 
286
 
        upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
287
 
        return STAT_INSTCMD_UNKNOWN;
 
284
    if (!strcasecmp(cmdname, "test.battery.start"))
 
285
    {
 
286
        hidsend("TL");
 
287
        upslogx(LOG_NOTICE, "UPS test start");
 
288
        return STAT_INSTCMD_HANDLED;
 
289
    }
 
290
 
 
291
    if (!strcasecmp(cmdname, "test.battery.stop"))
 
292
    {
 
293
        hidsend("CT");
 
294
        upslogx(LOG_NOTICE, "UPS test stop");
 
295
        return STAT_INSTCMD_HANDLED;
 
296
    }
 
297
 
 
298
    if (!strcasecmp(cmdname, "beeper.on") ||
 
299
        !strcasecmp(cmdname, "beeper.off"))
 
300
    {
 
301
        char buf[128];
 
302
        int r;
 
303
        int c = 0;
 
304
 
 
305
        /* Find out beeper status and send appropriate command. */
 
306
 
 
307
        r = hidcmd("Q1", buf, sizeof(buf));
 
308
        while (c++ < RETRIES && (r < 46 || r > 47 || buf[0] != '('))
 
309
            r = hidcmd("Q1", buf, sizeof(buf));
 
310
        if (r >= 46 && r <= 47 && buf[0] == '(')
 
311
        {
 
312
            if (OBFLAG && !LBFLAG)  /* Otherwise there's not much we can do */
 
313
            {
 
314
                if ((BEEPER && !strcasecmp(cmdname, "beeper.off")) ||
 
315
                    (!BEEPER && !strcasecmp(cmdname, "beeper.on")))
 
316
                        hidsend("Q");
 
317
                return STAT_INSTCMD_HANDLED;
 
318
            }
 
319
        }
 
320
        return STAT_INSTCMD_HANDLED;    /* FUTURE: failure */
 
321
    }
 
322
 
 
323
    upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
 
324
    return STAT_INSTCMD_UNKNOWN;
288
325
}
289
326
 
290
327
/*
293
330
 
294
331
void upsdrv_initinfo(void)
295
332
{
296
 
        char buf[128];
297
 
        int i, r;
298
 
 
299
 
        /* Yes, sometimes it took as many as 6-7 tries after the UPS has just
300
 
         * been turned on or after a communications problem.
301
 
         */
302
 
        for (i = 0; i < 10; i++)
303
 
        {
304
 
                r = hidcmd("I", buf, sizeof(buf));
305
 
                if (r == 39 && buf[0] == '#') break;
306
 
                sleep(3);
307
 
        }
308
 
        if (r != 39 || buf[0] != '#') fatalx("No Energizer UPS detected");
309
 
        buf[16]=buf[27]=buf[38] = '\0';
310
 
        rtrim(MANUFR, ' ');
311
 
        rtrim(MDLNUM, ' ');
312
 
        rtrim(HWVERS, ' ');
313
 
 
314
 
        dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
315
 
        dstate_setinfo("ups.mfr", MANUFR);
316
 
        dstate_setinfo("ups.model", MDLNUM);
317
 
 
318
 
        dstate_setinfo("input.transfer.low", "%d", LOXFER);
319
 
        dstate_setinfo("input.transfer.high", "%d", HIXFER);
320
 
 
321
 
        hidsend("C");
322
 
 
323
 
        /* now add instant command support info */
324
 
        dstate_addcmd("test.battery.start");
325
 
        dstate_addcmd("test.battery.stop");
326
 
        dstate_addcmd("beeper.on");
327
 
        dstate_addcmd("beeper.off");
328
 
        upsh.new_instcmd = instcmd;
 
333
    char buf[128];
 
334
    int i, r;
 
335
 
 
336
    /* Yes, sometimes it took as many as 6-7 tries after the UPS has just
 
337
     * been turned on or after a communications problem.
 
338
     */
 
339
    for (i = 0; i < 10; i++)
 
340
    {
 
341
        r = hidcmd("I", buf, sizeof(buf));
 
342
        if (r == 39 && buf[0] == '#') break;
 
343
        sleep(3);
 
344
    }
 
345
    if (r != 39 || buf[0] != '#') fatalx("No Energizer UPS detected");
 
346
    buf[16]=buf[27]=buf[38] = '\0';
 
347
    rtrim(MANUFR, ' ');
 
348
    rtrim(MDLNUM, ' ');
 
349
    rtrim(HWVERS, ' ');
 
350
 
 
351
    dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
 
352
    dstate_setinfo("ups.mfr", "%s", MANUFR);
 
353
    dstate_setinfo("ups.model", "%s", MDLNUM);
 
354
 
 
355
    dstate_setinfo("input.transfer.low", "%d", LOXFER);
 
356
    dstate_setinfo("input.transfer.high", "%d", HIXFER);
 
357
 
 
358
    hidsend("C");
 
359
 
 
360
    /* now add instant command support info */
 
361
    dstate_addcmd("test.battery.start");
 
362
    dstate_addcmd("test.battery.stop");
 
363
    dstate_addcmd("beeper.on");
 
364
    dstate_addcmd("beeper.off");
 
365
    upsh.instcmd = instcmd;
329
366
}
330
367
 
331
368
/*
334
371
 
335
372
void upsdrv_updateinfo(void)
336
373
{
337
 
        char buf[128];
338
 
        int r;
339
 
        static int f;   /* To prevent excessive logging */
340
 
        double v;
341
 
 
342
 
 
343
 
        r = hidcmd("Q1", buf, sizeof(buf));
344
 
        if (r < 46 || r > 47)
345
 
        {
346
 
                if (f++ < 3)
347
 
                        upslogx(LOG_ERR, "Invalid response length from UPS [%s]", buf);
348
 
                dstate_datastale();
349
 
                return;
350
 
        }
351
 
        if (buf[0] != '(')
352
 
        {
353
 
                if (f++ < 3)
354
 
                        upslogx(LOG_ERR, "Invalid response data from UPS [%s]", buf);
355
 
                dstate_datastale();
356
 
                return;
357
 
        }
358
 
        f = 0;
359
 
 
360
 
        buf[6]=buf[12]=buf[18]=buf[22]=buf[27]=buf[32]=buf[37]=buf[46] = '\0';
361
 
 
362
 
        dstate_setinfo("input.voltage", "%s", INVOLT);
363
 
        dstate_setinfo("output.voltage", "%s", OUTVOLT);
364
 
        dstate_setinfo("battery.voltage", "%s", BATVOLT);
365
 
 
366
 
        v = ((atof(BATVOLT) - LOWVOLT) / VOLTRNG) * 100.0;
367
 
        if (v > 100.0) v = 100.0;
368
 
        if (v < 0.0) v = 0.0;
369
 
        dstate_setinfo("battery.charge", "%02.1f", v);
370
 
 
371
 
        status_init();
372
 
        if (OBFLAG) status_set("OB");                           /* on battery */
373
 
        else
374
 
        {
375
 
                status_set("OL");                                               /* on line */
376
 
                /* only allow these when OL since they're bogus when OB */
377
 
                if (BYPASS)                                                             /* boost or trim in effect */
378
 
                {
379
 
                        if (atoi(INVOLT) < LONORM) status_set("BOOST");
380
 
                        else if (atoi(INVOLT) > HINORM) status_set("TRIM");
381
 
                }
382
 
        }
383
 
        if (LBFLAG) status_set("LB");           /* low battery */
384
 
 
385
 
        status_commit();
386
 
 
387
 
        dstate_setinfo("ups.temperature", "%s", UPSTEMP);
388
 
        dstate_setinfo("input.frequency", "%s", ACFREQ);
389
 
        dstate_setinfo("ups.load", "%s", LOADPCT);
390
 
        dstate_dataok();
 
374
    char buf[128];
 
375
    int r;
 
376
    static int f;  /* To prevent excessive logging */
 
377
    double v;
 
378
 
 
379
 
 
380
    r = hidcmd("Q1", buf, sizeof(buf));
 
381
    if (r < 46 || r > 47)
 
382
    {
 
383
        if (f++ < 3)
 
384
            upslogx(LOG_ERR, "Invalid response length from UPS [%s]", buf);
 
385
        else
 
386
            dstate_datastale();
 
387
        return;
 
388
    }
 
389
    if (buf[0] != '(')
 
390
    {
 
391
        if (f++ < 3)
 
392
            upslogx(LOG_ERR, "Invalid response data from UPS [%s]", buf);
 
393
        else
 
394
            dstate_datastale();
 
395
        return;
 
396
    }
 
397
    f = 0;
 
398
 
 
399
    buf[6]=buf[12]=buf[18]=buf[22]=buf[27]=buf[32]=buf[37]=buf[46] = '\0';
 
400
 
 
401
    dstate_setinfo("input.voltage", "%s", INVOLT);
 
402
    dstate_setinfo("output.voltage", "%s", OUTVOLT);
 
403
    dstate_setinfo("battery.voltage", "%s", BATVOLT);
 
404
 
 
405
    v = ((atof(BATVOLT) - LOWVOLT) / VOLTRNG) * 100.0;
 
406
    if (v > 100.0) v = 100.0;
 
407
    if (v < 0.0) v = 0.0;
 
408
    dstate_setinfo("battery.charge", "%02.1f", v);
 
409
 
 
410
    status_init();
 
411
    if (OBFLAG) status_set("OB");               /* on battery */
 
412
    else
 
413
    {
 
414
        status_set("OL");                       /* on line */
 
415
        /* only allow these when OL since they're bogus when OB */
 
416
        if (BYPASS)                             /* boost or trim in effect */
 
417
        {
 
418
            if (atoi(INVOLT) < LONORM) status_set("BOOST");
 
419
            else if (atoi(INVOLT) > HINORM) status_set("TRIM");
 
420
        }
 
421
    }
 
422
    if (LBFLAG) status_set("LB");               /* low battery */
 
423
 
 
424
    status_commit();
 
425
 
 
426
    dstate_setinfo("ups.temperature", "%s", UPSTEMP);
 
427
    dstate_setinfo("input.frequency", "%s", ACFREQ);
 
428
    dstate_setinfo("ups.load", "%s", LOADPCT);
 
429
    dstate_dataok();
391
430
}
392
431
 
393
432
void upsdrv_shutdown(void)
394
433
{
395
 
        char buf[128];
396
 
        int r;
397
 
        int b = 1;
398
 
 
399
 
        /* Basic idea: find out line status and send appropriate command.
400
 
         * If the status query fails, we do not retry more than once (we
401
 
         * may be short on time with a dying UPS) but assume that we're
402
 
         * on battery.
403
 
         */
404
 
 
405
 
        r = hidcmd("Q1", buf, sizeof(buf));
406
 
        if (r < 46 || r > 47 || buf[0] != '(') r = hidcmd("Q1", buf, sizeof(buf));
407
 
 
408
 
        if (r >= 46 && r <= 47 && buf[0] == '(')
409
 
        {
410
 
                if (OBFLAG)
411
 
                        upslogx(LOG_WARNING, "On battery, sending shutdown command...");
412
 
                else
413
 
                {
414
 
                        b = 0;
415
 
                        upslogx(LOG_WARNING, "On line, sending shutdown+return command...");
416
 
                }
417
 
        }
418
 
        else upslogx(LOG_WARNING, "Status undetermined, assuming battery power, "
419
 
                                "sending shutdown command...");
420
 
 
421
 
        hidsend(b ? "S01" : "S01R0003");
 
434
    char buf[128];
 
435
    int r;
 
436
    int b = 1;
 
437
 
 
438
    /* Basic idea: find out line status and send appropriate command.
 
439
     * If the status query fails, we do not retry more than once (we
 
440
     * may be short on time with a dying UPS) but assume that we're
 
441
     * on battery.
 
442
     */
 
443
 
 
444
    r = hidcmd("Q1", buf, sizeof(buf));
 
445
    if (r < 46 || r > 47 || buf[0] != '(') r = hidcmd("Q1", buf, sizeof(buf));
 
446
 
 
447
    if (r >= 46 && r <= 47 && buf[0] == '(')
 
448
    {
 
449
        if (OBFLAG)
 
450
            upslogx(LOG_WARNING, "On battery, sending shutdown command...");
 
451
        else
 
452
        {
 
453
            b = 0;
 
454
            upslogx(LOG_WARNING, "On line, sending shutdown+return command...");
 
455
        }
 
456
    }
 
457
    else upslogx(LOG_WARNING, "Status undetermined, assuming battery power, "
 
458
                "sending shutdown command...");
 
459
 
 
460
    hidsend(b ? "S01" : "S01R0003");
422
461
}
423
462
 
424
463
 
429
468
/* list flags and values that you want to receive via -x */
430
469
void upsdrv_makevartable(void)
431
470
{
432
 
        /* allow '-x xyzzy' */
433
 
        /* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */
434
 
 
435
 
        /* allow '-x foo=<some value>' */
436
 
        /* addvar(VAR_VALUE, "foo", "Override foo setting"); */
437
471
}
438
472
 
439
473
void upsdrv_banner(void)
440
474
{
441
 
        printf("Network UPS Tools - Energizer USB UPS driver %s (%s)\n\n", 
442
 
                DRV_VERSION, UPS_VERSION);
443
 
        experimental_driver = 1;        /* Causes a warning to be printed */
 
475
    printf("Network UPS Tools - Energizer USB UPS driver %s (%s)\n\n", 
 
476
        DRV_VERSION, UPS_VERSION);
 
477
    experimental_driver = 1;    /* Causes a warning to be printed */
444
478
}
445
479
 
446
480
void upsdrv_initups(void)
447
481
{
448
 
        /* No initialization needed */
 
482
    /* No initialization needed */
449
483
}
450
484
 
451
485
void upsdrv_cleanup(void)
452
486
{
453
 
        /* No cleanup needed */
 
487
    /* No cleanup needed */
454
488
}