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

« back to all changes in this revision

Viewing changes to drivers/belkin.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
1
/* belkin.c - model specific routines for Belkin Smart-UPS units.
2
2
 
3
3
   Copyright (C) 2000 Marcus Mļæ½ller <marcus@ebootis.de>
4
 
     
 
4
 
5
5
   based on:
6
6
 
7
7
   apcsmart.c - model specific routines for APC smart protocol units
24
24
*/
25
25
 
26
26
#include "main.h"
 
27
#include "serial.h"
 
28
 
27
29
#include "belkin.h"
28
30
 
29
 
#define DRV_VERSION "0.11"
30
 
 
31
 
int init_communication(void)
 
31
#define DRV_VERSION "0.21"
 
32
 
 
33
static void send_belkin_command(char cmd, const char *subcmd, const char *data)
 
34
{
 
35
        ser_send(upsfd, "~00%c%03d%s%s", cmd, strlen(data) + 3, subcmd, data);
 
36
}
 
37
 
 
38
static int init_communication(void)
32
39
{
33
40
        int     i;
34
41
        int     res;
37
44
        res = -1;
38
45
        for (i = 1; i <= 10 && res == -1; i++) {
39
46
                send_belkin_command(STATUS,MANUFACTURER,"");
40
 
                res = get_belkin_reply(temp);
 
47
                res = get_belkin_reply(temp);
41
48
        }
42
49
 
43
50
        if (res == -1 || strcmp(temp,"BELKIN")) 
46
53
        return 0;
47
54
}
48
55
 
49
 
void do_status(void)
 
56
static char *get_belkin_field(const char *in, char *out, size_t outlen, 
 
57
        size_t num)
 
58
{
 
59
        size_t  i, c = 1;
 
60
        char    *ptr;
 
61
 
 
62
        /* special case */
 
63
        if (num == 1) {
 
64
                snprintf(out, outlen, "%s", in);
 
65
                ptr = strchr(out, ';');
 
66
 
 
67
                if (ptr)
 
68
                        *ptr = '\0';
 
69
 
 
70
                return out;
 
71
        }               
 
72
 
 
73
        for (i = 0; i < strlen(in); i++) {
 
74
                if (in[i] == ';')
 
75
                        c++;
 
76
 
 
77
                if (c == num) {
 
78
                        snprintf(out, outlen, "%s", &in[i + 1]);
 
79
                        ptr = strchr(out, ';');
 
80
 
 
81
                        if (ptr)
 
82
                                *ptr = '\0';
 
83
                        return out;
 
84
                }
 
85
        }
 
86
 
 
87
        return NULL;
 
88
}
 
89
 
 
90
static int do_status(void)
50
91
{
51
92
        char    temp[SMALLBUF], st[SMALLBUF];
52
93
        int     res;
55
96
        res = get_belkin_reply(temp);
56
97
        if (res == -1) {
57
98
                dstate_datastale();
58
 
                return;
 
99
                return 0;
59
100
        }
60
101
 
61
102
        status_init();
72
113
 
73
114
                        send_belkin_command(STATUS,STAT_BATTERY,"");
74
115
                        res = get_belkin_reply(temp);
75
 
                        if (res == -1)
76
 
                                return;
 
116
 
 
117
                        if (res == -1) {
 
118
                                dstate_datastale();
 
119
                                return 0;
 
120
                        }
77
121
 
78
122
                        get_belkin_field(temp, st, sizeof(st), 10);
79
123
                        res = atoi(st);
80
124
                        get_belkin_field(temp, st, sizeof(st), 2);
81
125
 
82
126
                        if (*st == '1' || res < LOW_BAT) 
83
 
                                status_set("LB");               /* low battery */
 
127
                                status_set("LB");       /* low battery */
84
128
                }
85
129
                else
86
130
                        status_set("OL");       /* on line */
88
132
 
89
133
        status_commit();
90
134
        dstate_dataok();
 
135
 
 
136
        return 1;
91
137
}
92
138
 
93
 
int init_ups_data(void)
 
139
static int do_broken_rat(char *buf)
 
140
{
 
141
        int     ret, cnt;
 
142
        char    tmp[8];
 
143
 
 
144
        usleep(25000);
 
145
 
 
146
        ret = ser_get_buf_len(upsfd, tmp, 7, 3, 0);
 
147
 
 
148
        if (ret != 7)
 
149
                return -1;
 
150
 
 
151
        tmp[7] = '\0';
 
152
        cnt = atoi(tmp + 4);
 
153
 
 
154
        if ((cnt < 1) || (cnt > 255))
 
155
                return -1;
 
156
 
 
157
        usleep(5000 * cnt);
 
158
 
 
159
        /* firmware 001 only sends 50 bytes instead of the proper 53 */
 
160
        if (cnt == 53)
 
161
                cnt = 50;
 
162
 
 
163
        ret = ser_get_buf_len(upsfd, buf, 50, cnt, 0);
 
164
        buf[cnt] = 0;
 
165
 
 
166
        return ret;
 
167
}       
 
168
 
 
169
static int init_ups_data(void)
94
170
{
95
171
        int     res;
96
172
        double  low, high;
106
182
        send_belkin_command(STATUS, VERSION, "");
107
183
        res = get_belkin_reply(temp);
108
184
        if (res == -1)
109
 
                return (res);
 
185
                return res;
110
186
 
111
187
        dstate_setinfo("ups.firmware", "%s", temp);
112
188
 
 
189
        /* deal with stupid firmware that breaks RAT */
 
190
 
113
191
        send_belkin_command(STATUS, RATING, "");
114
 
        res = get_belkin_reply(temp);
115
 
 
116
 
        get_belkin_field(temp, st, sizeof(st), 8);
117
 
        low = atof(st) / 0.88;
118
 
 
119
 
        get_belkin_field(temp, st, sizeof(st), 9);
120
 
        high = atof(st) * 0.88;
 
192
 
 
193
        if (!strcmp(temp, "001"))
 
194
                res = do_broken_rat(temp);
 
195
        else
 
196
                res = get_belkin_reply(temp);
 
197
 
 
198
        if (res > 0) {
 
199
                get_belkin_field(temp, st, sizeof(st), 8);
 
200
                low = atof(st) / 0.88;
 
201
 
 
202
                get_belkin_field(temp, st, sizeof(st), 9);
 
203
                high = atof(st) * 0.88;
 
204
 
 
205
                dstate_setinfo("input.transfer.low", "%03.1f", low);
 
206
                dstate_setinfo("input.transfer.high", "%03.1f", high);
 
207
        }
121
208
 
122
209
        tcflush(upsfd,TCIOFLUSH);
123
210
 
124
 
        dstate_setinfo("input.transfer.low", "%03.1f", low);
125
 
        dstate_setinfo("input.transfer.high", "%03.1f", high);
126
 
 
127
211
        dstate_addcmd("load.off");
128
212
        dstate_addcmd("load.on");
129
213
        upsdrv_updateinfo();
137
221
        double  val;
138
222
        char    temp[SMALLBUF], st[SMALLBUF];
139
223
 
140
 
        do_status();
 
224
        if (!do_status())
 
225
                return;
141
226
 
142
227
        send_belkin_command(STATUS, STAT_INPUT, "");
143
228
        res = get_belkin_reply(temp);
148
233
        val = atof(st) / 10;
149
234
        dstate_setinfo("input.voltage", "%05.1f", val);
150
235
 
 
236
        get_belkin_field(temp, st, sizeof(st), 2);
 
237
        val = atof(st) / 10;
 
238
        dstate_setinfo("input.frequency", "%.1f", val);
 
239
 
151
240
        send_belkin_command(STATUS,STAT_BATTERY, "");
152
241
        res = get_belkin_reply(temp);
153
242
        if (res == -1)
157
246
        val = atof(st);
158
247
        dstate_setinfo("battery.charge", "%03.0f", val);
159
248
 
 
249
        get_belkin_field(temp, st, sizeof(st), 9);
 
250
        val = atof(st);
 
251
        dstate_setinfo("battery.temperature", "%03.0f", val);
 
252
 
160
253
        get_belkin_field(temp, st, sizeof(st), 7);
161
254
        val = atof(st) / 10;
162
255
        dstate_setinfo("battery.voltage", "%4.1f", val);
172
265
 
173
266
        get_belkin_field(temp, st, sizeof(st), 2);
174
267
        val = atof(st) / 10;
175
 
        dstate_setinfo("input.frequency", "%.1f", val);
 
268
        dstate_setinfo("output.frequency", "%.1f", val);
176
269
 
177
270
        get_belkin_field(temp, st, sizeof(st), 4);
178
271
        val = atof(st) / 10;
183
276
        dstate_setinfo("ups.load", "%03.0f", val);
184
277
}
185
278
 
186
 
 
187
 
void get_belkin_field(char *temp, char *data, size_t datalen, int n)
 
279
static int get_belkin_reply(char *buf)
188
280
{
189
 
        char    st[SMALLBUF];
190
 
        int     i = 0, f = 1;
191
 
 
192
 
        strlcpy(st, temp, sizeof(st));
193
 
 
194
 
        while (f < n) {
195
 
                while (st[i] && st[i] != ';') 
196
 
                        i++;
197
 
 
198
 
                st[i++] = 0;
199
 
                f++;
 
281
        int     ret, cnt;
 
282
        char    tmp[8];
 
283
 
 
284
        usleep(25000);
 
285
 
 
286
        /* pull first 7 bytes to get data length - like ~00S004 */
 
287
        ret = ser_get_buf_len(upsfd, tmp, 7, 3, 0);
 
288
 
 
289
        if (ret != 7) {
 
290
                ser_comm_fail("Initial read returned %d bytes", ret);
 
291
                return -1;
200
292
        }
201
293
 
202
 
        f = i;
203
 
 
204
 
        while (st[i] && st[i] != ';') 
205
 
                i++;
206
 
 
207
 
        st[i] = 0;
208
 
 
209
 
        snprintf(data, datalen, "%s", st+f);
210
 
}
211
 
 
212
 
int get_belkin_reply(char *buf)
213
 
{
214
 
        int     res, cnt;
215
 
 
216
 
        res = recvbinary(buf, 7);
217
 
 
218
 
        if (res)
219
 
                return res;
220
 
 
221
 
        buf[7] = 0;
222
 
        cnt = atoi(buf + 4);
223
 
        res = recvbinary(buf, cnt);
 
294
        tmp[7] = 0;
 
295
        cnt = atoi(tmp + 4);
 
296
 
 
297
        if ((cnt < 1) || (cnt > 255))
 
298
                return -1;
 
299
 
 
300
        /* give it time to respond to us */
 
301
        usleep(5000 * cnt);
 
302
 
 
303
        ret = ser_get_buf_len(upsfd, buf, cnt, 3, 0);
 
304
 
224
305
        buf[cnt] = 0;
225
306
 
226
 
        return res;
227
 
}
228
 
 
229
 
void send_belkin_command(char command, const char *subcommand, const char *data)
230
 
{
231
 
        upssend("~00%c%03d%s%s", command, strlen(data) + 3, subcommand, data);
 
307
        if (ret != cnt) {
 
308
                ser_comm_fail("Second read returned %d bytes, expected %d",
 
309
                        ret, cnt);
 
310
                return -1;
 
311
        }
 
312
 
 
313
        ser_comm_good();
 
314
 
 
315
        return ret;
232
316
}
233
317
 
234
318
/* power down the attached load immediately */
235
319
void upsdrv_shutdown(void)
236
320
{
237
321
        int     res;
238
 
        char    temp[SMALLBUF], st[SMALLBUF];
239
322
 
240
323
        res = init_communication();
241
 
        if (res == -1) {
 
324
        if (res == -1)
242
325
                printf("Detection failed.  Trying a shutdown command anyway.\n");
243
 
                send_belkin_command(CONTROL, POWER_OFF, "1;1");
244
 
                exit(-1);
245
 
        }
246
 
 
247
 
        send_belkin_command(STATUS, STAT_STATUS, "");
248
 
        res = get_belkin_reply(temp);
249
 
        get_belkin_field(temp, st, sizeof(st), 2);
250
 
 
251
 
        if (*st == '1') {
252
 
                printf("On battery - sending shutdown comand...\n");
253
 
                send_belkin_command(CONTROL,POWER_OFF,"1;1");
254
 
                return;
255
 
        }
256
 
 
257
 
        printf("Power restored - sending shutdown+return command...\n");
258
 
 
259
 
        /* turn off the outlet in 5 seconds */
260
 
        send_belkin_command(CONTROL, POWER_OFF, "1;5");
261
 
 
262
 
        /* ... and turn it back on 10 seconds after that */ 
263
 
        send_belkin_command(CONTROL, POWER_ON, "1;15");
 
326
 
 
327
        /* tested on a F6C525-SER: this works when OL and OB */
 
328
 
 
329
        /* shutdown type 2 (UPS system) */
 
330
        send_belkin_command(CONTROL, "SDT", "2");
 
331
 
 
332
        /* SDR means "do SDT and SDA, then reboot after n minutes" */
 
333
        send_belkin_command(CONTROL, "SDR", "1");
 
334
 
 
335
        printf("UPS should power off load in 5 seconds\n");
 
336
 
 
337
        /* shutdown in 5 seconds */
 
338
        send_belkin_command(CONTROL, "SDA", "5");
264
339
}
265
340
 
266
341
/* handle the "load.off" with some paranoia */
267
 
void do_off(void)
 
342
static void do_off(void)
268
343
{
269
344
        static  time_t lastcmd = 0;
270
345
        time_t  now, elapsed;
279
354
        if ((elapsed < MINCMDTIME) || (elapsed > MAXCMDTIME)) {
280
355
 
281
356
                /* FUTURE: tell the user (via upsd) to try it again */
282
 
                /* msgreply(UPSMSG_REPAGAIN); */
283
357
                return;
284
358
        }
285
359
#endif
286
360
 
287
361
        upslogx(LOG_INFO, "Sending powerdown command to UPS\n");
288
 
        send_belkin_command(CONTROL,POWER_OFF,"1;1");
 
362
        send_belkin_command(CONTROL,POWER_OFF,"1;1");
289
363
        usleep(1500000);
290
 
        send_belkin_command(CONTROL,POWER_OFF,"1;1");
 
364
        send_belkin_command(CONTROL,POWER_OFF,"1;1");
291
365
}
292
366
 
293
 
int instcmd(const char *cmdname, const char *extra)
 
367
static int instcmd(const char *cmdname, const char *extra)
294
368
{
295
369
        if (!strcasecmp(cmdname, "load.off")) {
296
370
                do_off();
298
372
        }
299
373
 
300
374
        if (!strcasecmp(cmdname, "load.on")) {
301
 
                send_belkin_command(CONTROL,POWER_ON,"1;1");
 
375
                send_belkin_command(CONTROL,POWER_ON,"1;1");
302
376
                return STAT_INSTCMD_HANDLED;
303
377
        }
304
378
 
306
380
        return STAT_INSTCMD_UNKNOWN;
307
381
}
308
382
 
309
 
/* install pointers to functions for msg handlers called from msgparse */
310
 
void setuphandlers(void)
311
 
{
312
 
        upsh.new_instcmd = instcmd;
313
 
}
314
 
 
315
 
int send_string(char *data)
316
 
{
317
 
        tcflush(upsfd, TCIFLUSH);
318
 
        return(write(upsfd, data, strlen(data)));
319
 
}
320
 
 
321
 
int recvbinary(char *buf, int buflen)
322
 
{
323
 
        unsigned char   in;
324
 
        int     ret, counter = 0, retval = 0;
325
 
        struct  sigaction sa;
326
 
        sigset_t        bel_sigmask;
327
 
 
328
 
        sa.sa_handler = timeout;
329
 
        sigemptyset(&bel_sigmask);
330
 
        sa.sa_mask = bel_sigmask;
331
 
        sa.sa_flags = 0;
332
 
        sigaction(SIGALRM, &sa, NULL);
333
 
 
334
 
        alarm(3);
335
 
 
336
 
        while (counter < buflen) {
337
 
                ret = read(upsfd, &in, 1);
338
 
 
339
 
                if (ret > 0) {
340
 
                        buf[counter] = in;
341
 
                        counter++;
342
 
                        nolongertimeout();         
343
 
                }
344
 
                else {
345
 
                        upslogx(LOG_DEBUG, "error reading from serial device!");
346
 
                        retval = -1;
347
 
                        break;
348
 
                }
349
 
        }
350
 
        
351
 
        alarm(0);
352
 
        signal(SIGALRM, SIG_IGN);
353
 
 
354
 
        return retval;
355
 
}
356
 
 
357
 
void set_serialDTR0RTS1(void)
 
383
static void set_serialDTR0RTS1(void)
358
384
{
359
385
        int dtr_bit = TIOCM_DTR;
360
386
        int rts_bit = TIOCM_RTS;
381
407
/* prep the serial port */
382
408
void upsdrv_initups(void)
383
409
{
384
 
        open_serial(device_path, B2400);
 
410
        upsfd = ser_open(device_path);
 
411
        ser_set_speed(upsfd, device_path, B2400);
385
412
        
386
413
        set_serialDTR0RTS1();
387
414
 
398
425
                printf("Unable to detect an Belkin Smart protocol UPS on port %s\n", 
399
426
                        device_path);
400
427
                printf("Check the cabling, port name or model name and try again\n");
401
 
                exit(1);
 
428
                exit(EXIT_FAILURE);
402
429
        }
403
430
 
404
 
        /* manufacturer ID - hardcoded in this particular module */
405
 
        dstate_setinfo("ups.mfr", "BELKIN", 0, 0);
406
 
 
 
431
        dstate_setinfo("ups.mfr", "BELKIN");
407
432
        dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
408
433
 
409
434
        /* see what's out there */
412
437
        printf("Detected %s on %s\n", dstate_getinfo("ups.model"),
413
438
                device_path);
414
439
 
415
 
        setuphandlers();
 
440
        upsh.instcmd = instcmd;
416
441
}
417
442
 
418
443
void upsdrv_cleanup(void)
419
444
{
 
445
        ser_close(upsfd, device_path);
420
446
}