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

« back to all changes in this revision

Viewing changes to drivers/sms.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
/* sms.c - driver for SMS UPS hardware
 
2
 
 
3
   Copyright (C) 2001  Marcio Gomes  <tecnica@microlink.com.br>
 
4
 
 
5
   based on fentonups.c:
 
6
 
 
7
   Copyright (C) 1999  Russell Kroll <rkroll@exploits.org>
 
8
 
 
9
   This program is free software; you can redistribute it and/or modify
 
10
   it under the terms of the GNU General Public License as published by
 
11
   the Free Software Foundation; either version 2 of the License, or
 
12
   (at your option) any later version.
 
13
 
 
14
   This program is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
   GNU General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with this program; if not, write to the Free Software
 
21
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
22
 
 
23
   2001/05/17 - Version 0.10 - Initial release
 
24
   2001/06/01 - Version 0.20 - Add Battery Informations in driver
 
25
   2001/06/04 - Version 0.30 - Updated Battery Volts range, to reflect a correct
 
26
                               percent ( % )
 
27
   2002/12/02 - Version 0.40 - Update driver to new-model, based on Fentonups 
 
28
                               driver version 0.90  
 
29
   2002/12/18 - Version 0.50 - Add Sinus Single 2 KVA in database, test with
 
30
                               new Manager III sinusoidal versions.
 
31
                               Change Detect Name, SMS do not pass real Models
 
32
                               in Megatec Info command, only the VA/KVA version
 
33
   2002/12/18 - Version 0.51 - Updated Battery Volts range, to reflect a correct
 
34
                               percent ( % )
 
35
   2002/12/27 - Version 0.60 - Add new UPS Commands SDRET, SIMPWF change BTEST1
 
36
   2002/12/28 - Version 0.70 - Add new UPS Commands SHUTDOWN,STOPSHUTD,WATCHDOG
 
37
   2003/06/11 - Version 0.71 - Converted to dstate calls and names (rkroll)
 
38
 
 
39
 
 
40
   Microlink ISP/Pop-Rio contributed with MANAGER III 1300, MANAGER III 650 UPS
 
41
   and Sinus Single 2 KVA for my tests.
 
42
 
 
43
   http://www.microlink.com.br and http://www.pop-rio.com.br
 
44
 
 
45
 
 
46
 
 
47
*/
 
48
 
 
49
#define DRV_VERSION "0.71"
 
50
 
 
51
#include "main.h"
 
52
#include "sms.h"
 
53
 
 
54
#define ENDCHAR 13      /* replies end with CR */
 
55
 
 
56
static  int     cap_upstemp = 0;
 
57
static  float   lowvolt = 0, voltrange;
 
58
static  int     lownorm, highnorm, poll_failures = 0;
 
59
 
 
60
void guessmodel(const char *raw)
 
61
{
 
62
        char    mch, mstr[256];
 
63
 
 
64
        mch = raw[17];
 
65
 
 
66
        printf ("0         1         2        3         \n");
 
67
        printf ("012345678901234567890123567890123456789\n");
 
68
        printf ("%s\n", raw);
 
69
        strlcpy(mstr, &raw[17], sizeof(mstr));
 
70
        mstr[10] = '\0';        /* 10 chars max, per the protocol */
 
71
       
 
72
        /* trim whitespace */
 
73
        rtrim(mstr, ' ');
 
74
     
 
75
        dstate_setinfo("ups.model", "SMS %s", mstr);   
 
76
        cap_upstemp = 1;
 
77
}
 
78
 
 
79
void getbaseinfo(void)
 
80
{
 
81
        char    temp[256], model[32], *raw;
 
82
        int     modelnum, i;
 
83
 
 
84
        /* dummy read attempt to sync - throw it out */
 
85
        upssend("I\r");
 
86
        upsrecv(temp, sizeof(temp), ENDCHAR, "");
 
87
 
 
88
        /* now retrieve information and parse */
 
89
        upssend("I\r");
 
90
        upsrecv(temp, sizeof(temp), ENDCHAR, "");
 
91
        raw = xstrdup(temp);
 
92
 
 
93
        if (temp[0] != '#')
 
94
                fatalx("Bad UPS info start character [%s]", temp);
 
95
 
 
96
        temp[11] = 0;
 
97
        temp[27] = 0;
 
98
 
 
99
        /* manufacturer */
 
100
        rtrim(&temp[1], ' ');
 
101
 
 
102
        dstate_setinfo("ups.mfr", "%s", &temp[1]);
 
103
 
 
104
/*
 
105
        0         1         2        3         
 
106
        012345678901234567890123567890123456789
 
107
        #SMS LTDA         1300 VA   VER 1.0 
 
108
        #SMS LTDA        1300VA SEN VER 5.0 
 
109
        #SMS LTDA             2 KVA   VER 1.0 
 
110
*/
 
111
        /* grab full model string */
 
112
 
 
113
        rtrim(&temp[17], ' ');
 
114
 
 
115
        snprintf(model, sizeof(model), "%s", &temp[17]);
 
116
/*        printf("->%s<-\n",model);  */
 
117
        modelnum = -1;
 
118
 
 
119
        /* figure out official model name and voltage info from table */
 
120
        for (i = 0; modeltab[i].mtext != NULL; i++) {
 
121
                if (!strcmp(modeltab[i].mtext, model)) {
 
122
                        modelnum = i;
 
123
                        lowvolt = modeltab[i].lowvolt;
 
124
                        voltrange = modeltab[i].voltrange;
 
125
                        cap_upstemp = modeltab[i].has_temp;
 
126
                        break;
 
127
                }
 
128
        }
 
129
 
 
130
        /* table lookup fails -> guess */
 
131
        if (modelnum == -1)
 
132
                guessmodel (raw);
 
133
        else {
 
134
                dstate_setinfo("ups.model", "%s", modeltab[modelnum].desc);
 
135
 
 
136
                dstate_setinfo("input.transfer.low", "%i", 
 
137
                        modeltab[modelnum].lowxfer);
 
138
                dstate_setinfo("input.transfer.high", "%i", 
 
139
                        modeltab[modelnum].highxfer);
 
140
 
 
141
                lownorm = modeltab[modelnum].lownorm;
 
142
                highnorm = modeltab[modelnum].highnorm;
 
143
        }
 
144
 
 
145
        /* now add instant command support info */
 
146
        dstate_addcmd("test.battery.start");
 
147
        dstate_addcmd("test.battery.stop");
 
148
        dstate_addcmd("shutdown.return");       /* was CMD_SDRET */
 
149
        dstate_addcmd("test.failure.start");
 
150
        dstate_addcmd("shutdown.stayoff");      /* was CMD_SHUTDOWN */
 
151
        dstate_addcmd("shutdown.stop");
 
152
        dstate_addcmd("reset.watchdog");
 
153
 
 
154
        printf("Detected %s on %s\n", dstate_getinfo("ups.model"), device_path);
 
155
        free(raw);
 
156
 
 
157
        /* paranoia - cancel any shutdown that might already be running */
 
158
        upssend("C\r");
 
159
}
 
160
 
 
161
int instcmd(const char *cmdname, const char *extra)
 
162
{
 
163
        if (!strcasecmp(cmdname, "test.battery.stop")) {
 
164
                upssend("CT\r");
 
165
                return STAT_INSTCMD_HANDLED;
 
166
        }
 
167
 
 
168
        if (!strcasecmp(cmdname, "test.battery.start")) {
 
169
                upssend("TL\r");/* start battery test until bat low */
 
170
                return STAT_INSTCMD_HANDLED;
 
171
        }
 
172
 
 
173
        if (!strcasecmp(cmdname, "test.failure.start")) {
 
174
                upssend("T\r");
 
175
                return STAT_INSTCMD_HANDLED;
 
176
        }
 
177
 
 
178
        if (!strcasecmp(cmdname, "shutdown.return")) {
 
179
                /* shutdown and restart */
 
180
                upssend("C\r");
 
181
                upssend("S.3R0003\r");
 
182
                return STAT_INSTCMD_HANDLED;
 
183
        }
 
184
 
 
185
        if (!strcasecmp(cmdname, "shutdown.stayoff")) {
 
186
                /* shutdown now (one way) */
 
187
                upssend("C\r");
 
188
                upssend("S.3\r");
 
189
                return STAT_INSTCMD_HANDLED;
 
190
        }
 
191
 
 
192
        if (!strcasecmp(cmdname, "shutdown.stop")) {
 
193
                /* Cancel Shutdown  */
 
194
                upssend("C\r");
 
195
                return STAT_INSTCMD_HANDLED;
 
196
        }
 
197
 
 
198
        if (!strcasecmp(cmdname, "reset.watchdog")) {
 
199
                /* WATCHDOG Crontab Function */
 
200
                upssend("C\r");
 
201
                upssend("S05R0003\r");
 
202
                return STAT_INSTCMD_HANDLED;
 
203
        }
 
204
 
 
205
        upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
 
206
        return STAT_INSTCMD_UNKNOWN;
 
207
}
 
208
 
 
209
void upsdrv_initinfo(void)
 
210
{
 
211
        getbaseinfo();
 
212
 
 
213
        upsh.new_instcmd = instcmd;
 
214
        dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
 
215
}
 
216
 
 
217
void pollfail(char *why)
 
218
{
 
219
        poll_failures++;
 
220
 
 
221
        /* don't spew into the syslog forever */
 
222
        if (poll_failures < 3)
 
223
                upslogx(LOG_ERR, why);
 
224
 
 
225
        return;
 
226
}
 
227
 
 
228
void upsdrv_updateinfo(void)
 
229
{
 
230
        char    temp[256], utility[16], loadpct[16], acfreq[16], battvolt[16],
 
231
                upstemp[16], stat[16], outvolt[16];
 
232
        int     util, ret;
 
233
        double  bvoltp;
 
234
 
 
235
        upssend("Q1\r");
 
236
 
 
237
        ret = upsrecv (temp, sizeof(temp), ENDCHAR, "");
 
238
 
 
239
        /* sanity checks for poll data */
 
240
        if (strlen(temp) < 46) {
 
241
                pollfail("Poll failed: short read from UPS");
 
242
                dstate_datastale();
 
243
                return;
 
244
        }
 
245
 
 
246
        if (strlen(temp) > 46) {
 
247
                pollfail("Poll failed: oversized read from UPS");
 
248
                dstate_datastale();
 
249
                return;
 
250
        }
 
251
 
 
252
        if (temp[0] != '(') {
 
253
                pollfail("Poll failed: invalid start character");
 
254
                dstate_datastale();
 
255
                return;
 
256
        }
 
257
 
 
258
        if (poll_failures > 0)
 
259
                upslogx(LOG_NOTICE, "UPS poll succeeded");
 
260
 
 
261
        poll_failures = 0;              
 
262
 
 
263
        /* (MMM.M NNN.N PPP.P QQQ RR.R S.SS TT.T  b7b6b5b4b3b2b1b0<cr>
 
264
         *
 
265
         * MMM.M : input voltage (utility)
 
266
         * NNN.N : fault voltage (ignored)
 
267
         * PPP.P : output voltage
 
268
         */
 
269
 
 
270
        sscanf(temp, "%*c%s %*s %s %s %s %s %s %s", utility, outvolt, loadpct,
 
271
                acfreq, battvolt, upstemp, stat);
 
272
 
 
273
        dstate_setinfo("output.voltage", "%s", outvolt);
 
274
        dstate_setinfo("input.voltage", "%s", utility);
 
275
        dstate_setinfo("battery.voltage", "%s", battvolt);
 
276
 
 
277
        bvoltp = ((atof(battvolt) - lowvolt) / voltrange) * 100.0;
 
278
 
 
279
        if (bvoltp > 100.0)
 
280
                bvoltp = 100.0;
 
281
 
 
282
        dstate_setinfo("battery.charge", "%02.1f", bvoltp);
 
283
 
 
284
        status_init();
 
285
 
 
286
        util = atoi(utility);
 
287
 
 
288
        if (stat[0] == '0') {
 
289
                status_set("OL");               /* on line */
 
290
 
 
291
                /* only allow these when OL since they're bogus when OB */
 
292
                if (stat[2] == '1') {           /* boost or trim in effect */
 
293
                        if (util < lownorm)
 
294
                                status_set("BOOST");
 
295
 
 
296
                        if (util > highnorm)
 
297
                                status_set("TRIM");
 
298
                }
 
299
 
 
300
        } else {
 
301
                status_set("OB");               /* on battery */
 
302
        }
 
303
 
 
304
        if (stat[1] == '1')
 
305
                status_set("LB");               /* low battery */
 
306
 
 
307
        status_commit();
 
308
 
 
309
        if (cap_upstemp == 1)
 
310
                dstate_setinfo("ups.temperature", "%s", upstemp);
 
311
 
 
312
        dstate_setinfo("input.frequency", "%s", acfreq);
 
313
        dstate_setinfo("ups.load", "%s", loadpct);
 
314
 
 
315
        dstate_dataok();
 
316
}
 
317
 
 
318
/* power down the attached load immediately */
 
319
void upsdrv_shutdown(void)
 
320
{
 
321
        char    temp[256], stat[32];
 
322
 
 
323
        /* basic idea: find out line status and send appropriate command */
 
324
 
 
325
        upssend("Q1\r");
 
326
        upsrecv (temp, sizeof(temp), ENDCHAR, "");
 
327
        sscanf (temp, "%*s %*s %*s %*s %*s %*s %*s %s", stat);
 
328
 
 
329
        /* on battery: send S01<cr>, ups will return by itself on utility */
 
330
        /* on line: send S01R0003<cr>, ups will cycle and return soon */
 
331
 
 
332
        upssend("S01");
 
333
 
 
334
        if (stat[0] == '0') {                   /* on line */
 
335
                printf("On line, sending shutdown+return command...\n");
 
336
                upssend("R0003");
 
337
        } else
 
338
                printf("On battery, sending normal shutdown command...\n");
 
339
 
 
340
        upssendchar(13);        /* end sequence */
 
341
}
 
342
 
 
343
void upsdrv_help(void)
 
344
{
 
345
}
 
346
 
 
347
void upsdrv_makevartable(void)
 
348
{
 
349
}
 
350
 
 
351
void upsdrv_banner(void)
 
352
{
 
353
        printf("Network UPS Tools - SMS UPS driver %s (%s)\n", 
 
354
                DRV_VERSION, UPS_VERSION);
 
355
        printf("by Marcio Gomes at Microlink - tecnica@microlink.com.br\n\n");
 
356
}
 
357
 
 
358
void upsdrv_initups(void)
 
359
{
 
360
        open_serial(device_path, B2400);
 
361
}
 
362
 
 
363
void upsdrv_cleanup(void)
 
364
{
 
365
}