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

« back to all changes in this revision

Viewing changes to drivers/mustek.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
/* mustek.c - model specific routines for mustek UPS models
 
2
 
 
3
Based on blazer.c driver from nut 2.0.0.
 
4
 
 
5
Modified to work with Mustek PowerMust by Martin Hajduch (martin@hajduch.de).
 
6
If it does not work as expected, please send me a note.
 
7
Well, you can send me a note even if it works as expected ;-)
 
8
 
 
9
Copyright (C) 1999  Russell Kroll <rkroll@exploits.org>
 
10
2002  Phil Hutton <mustek-driver@hutton.sh>
 
11
2003  Arnaud Quette <arnaud.quette@free.fr>
 
12
2004  Martin Hajduch <martin@hajduch.de>
 
13
 
 
14
This program is free software; you can redistribute it and/or modify
 
15
it under the terms of the GNU General Public License as published by
 
16
the Free Software Foundation; either version 2 of the License, or
 
17
(at your option) any later version.
 
18
 
 
19
This program is distributed in the hope that it will be useful,
 
20
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
GNU General Public License for more details.
 
23
 
 
24
You should have received a copy of the GNU General Public License
 
25
along with this program; if not, write to the Free Software
 
26
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
27
*/
 
28
 
 
29
#include "main.h"
 
30
#include "serial.h"
 
31
 
 
32
#define DRV_VERSION     "0.2"
 
33
 
 
34
#define ENDCHAR         13      /* replies end with CR */
 
35
#define UPSDELAY        3
 
36
#define MAXTRIES        10
 
37
#define SENDDELAY       100000  /* 100 ms delay between chars on transmit */
 
38
#define SER_WAIT_SEC    2       /* allow 3.0 sec for responses */
 
39
#define SER_WAIT_USEC   0
 
40
 
 
41
static  float   lowvolt = 0, highvolt = 0, voltrange = 0;
 
42
static  int     poll_failures = 0;
 
43
static  int     inverted_bypass_bit = 0;
 
44
 
 
45
 
 
46
static int instcmd(const char *cmdname, const char *extra)
 
47
{
 
48
  /* Stop battery test */
 
49
  if (!strcasecmp(cmdname, "test.battery.stop")) {
 
50
    ser_send_pace(upsfd, SENDDELAY, "CT\r");
 
51
    return STAT_INSTCMD_HANDLED;
 
52
  }
 
53
  
 
54
  /* Start battery test */
 
55
  if (!strcasecmp(cmdname, "test.battery.start")) {
 
56
    ser_send_pace(upsfd, SENDDELAY, "T\r");
 
57
    return STAT_INSTCMD_HANDLED;
 
58
  }
 
59
  
 
60
  upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
 
61
  return STAT_INSTCMD_UNKNOWN;
 
62
}
 
63
 
 
64
void upsdrv_initinfo(void)
 
65
{
 
66
  dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
 
67
  dstate_setinfo("ups.mfr", "Mustek");
 
68
  dstate_setinfo("ups.model", "PowerMust");
 
69
  
 
70
  dstate_addcmd("test.battery.start");
 
71
  dstate_addcmd("test.battery.stop");
 
72
  
 
73
  printf("Detected UPS on %s\n", device_path);
 
74
  
 
75
  upsh.instcmd = instcmd;
 
76
  
 
77
  /* paranoia - cancel any shutdown that might already be running */
 
78
  ser_send_pace(upsfd, SENDDELAY, "C\r");
 
79
}
 
80
 
 
81
static void ups_sync(void)
 
82
{
 
83
  char  buf[256];
 
84
  int   tries = 0, ret;
 
85
  
 
86
  printf("Syncing with UPS: ");
 
87
  fflush(stdout);
 
88
  
 
89
  for (;;) {
 
90
    tries++;
 
91
    if (tries > MAXTRIES) {
 
92
      fatalx("\nFailed - giving up...");
 
93
    }
 
94
    
 
95
    printf(".");
 
96
    fflush(stdout);
 
97
    
 
98
    ret = ser_send_pace(upsfd, SENDDELAY, "F\r");
 
99
    
 
100
    if (ret > 0) {
 
101
      
 
102
      ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
 
103
                         SER_WAIT_SEC, SER_WAIT_USEC);
 
104
      if (buf[0]=='#' && strlen(buf)>1) {
 
105
        /* F command successful ! */
 
106
        ret = ser_send_pace(upsfd, SENDDELAY, "Q1\r");
 
107
        
 
108
        if (ret > 0) {
 
109
          
 
110
          ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
 
111
                             SER_WAIT_SEC, SER_WAIT_USEC);
 
112
          if (buf[0]=='(' && strlen(buf)>2) {
 
113
            break;
 
114
          }
 
115
        }
 
116
      }
 
117
    }
 
118
    /* not successful ! */
 
119
    sleep(UPSDELAY);
 
120
    printf(".");
 
121
    fflush(stdout);
 
122
    
 
123
  }
 
124
  
 
125
  printf(" done\n");
 
126
}
 
127
 
 
128
void upsdrv_shutdown(void)
 
129
{
 
130
        ser_send_pace(upsfd, SENDDELAY, "S01R0001\r");
 
131
}
 
132
 
 
133
static void ups_ident(void)
 
134
{
 
135
  char  buf[256];
 
136
  int   tries = 0, ret;
 
137
  int   ratecurrent;
 
138
  float ratevolt, ratefreq;
 
139
  
 
140
  printf("Identifying UPS: ");
 
141
  fflush (stdout);
 
142
  
 
143
  for (;;) {
 
144
    tries++;
 
145
    if (tries > MAXTRIES) {
 
146
      upsdebugx(2, "Failed - giving up...");
 
147
      exit (1);
 
148
    }
 
149
    
 
150
    printf(".");
 
151
    fflush(stdout);
 
152
    ret = ser_send_pace(upsfd, SENDDELAY, "F\r");
 
153
    
 
154
    if (ret>0) {
 
155
      
 
156
      ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
 
157
                         SER_WAIT_SEC, SER_WAIT_USEC);
 
158
      
 
159
      /* don't be so strict about the return,
 
160
         it should look reasonable, though */
 
161
      if ((ret > 0) && (buf[0] == '#') && (strlen(buf) > 15)) {
 
162
        break;
 
163
      }
 
164
    }
 
165
    sleep(UPSDELAY);
 
166
    printf(".");
 
167
    fflush(stdout);
 
168
  }
 
169
  
 
170
  printf(" done\n");
 
171
  
 
172
  sscanf(buf, "%*c %f %d %*f %f", &ratevolt, &ratecurrent, &ratefreq);
 
173
  upsdebugx(2, "UPS is rated at %.2fV, %dA, %.2fHz.\n",
 
174
            ratevolt, ratecurrent, ratefreq);
 
175
  
 
176
  /* Just some guess ... */
 
177
  lowvolt = 9.7;
 
178
  highvolt = 13.7;
 
179
  
 
180
  voltrange = highvolt - lowvolt;
 
181
}
 
182
 
 
183
static void pollfail(const char *why)
 
184
{
 
185
  poll_failures++;
 
186
  
 
187
  /* ignore the first few since these UPSes tend to drop characters */
 
188
  if (poll_failures == 3) {
 
189
    ser_comm_fail(why);
 
190
  }
 
191
  
 
192
  return;
 
193
}
 
194
 
 
195
void upsdrv_updateinfo(void)
 
196
{
 
197
  char  utility[16], outvolt[16], loadpct[16], acfreq[16], 
 
198
    battvolt[16], upstemp[16], pstat[16], buf[256];
 
199
  float bvoltp;
 
200
  int   ret;
 
201
  
 
202
  ret = ser_send_pace(upsfd, SENDDELAY, "Q1\r");
 
203
  
 
204
  if (ret < 1) {
 
205
    pollfail("Poll failed: send status request failed");
 
206
    dstate_datastale();
 
207
    return;
 
208
  }
 
209
  
 
210
  sleep(UPSDELAY); 
 
211
  
 
212
  ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
 
213
                     SER_WAIT_SEC, SER_WAIT_USEC);
 
214
  
 
215
  if (ret < 1) {
 
216
    pollfail("Poll failed: read failed");
 
217
    dstate_datastale();
 
218
    return;
 
219
  }
 
220
  
 
221
  if (strlen(buf) < 40) {
 
222
    pollfail("Poll failed: short read from UPS");
 
223
    dstate_datastale();
 
224
    return;
 
225
  }
 
226
  
 
227
  if (strlen(buf) > 50) {
 
228
    pollfail("Poll failed: oversized read from UPS");
 
229
    dstate_datastale();
 
230
    return;
 
231
  }
 
232
  
 
233
  if (buf[0] != '(') {
 
234
    pollfail("Poll failed: invalid start character");
 
235
    return;
 
236
  }
 
237
  
 
238
  /* only say this if it got high enough to log a failure note */
 
239
  if (poll_failures >= 3) {
 
240
    ser_comm_good();
 
241
  }
 
242
  
 
243
  poll_failures = 0;
 
244
  
 
245
  sscanf(buf, "%*c%s %*s %s %s %s %s %s %s", utility, outvolt, 
 
246
         loadpct, acfreq, battvolt, upstemp, pstat);
 
247
  
 
248
  bvoltp = ((atof (battvolt) - lowvolt) / voltrange) * 100.0;
 
249
  
 
250
  if (bvoltp > 100.0) {
 
251
    bvoltp = 100.0;
 
252
  }
 
253
  
 
254
  dstate_setinfo("input.voltage", "%s", utility);
 
255
  dstate_setinfo("input.frequency", "%s", acfreq);
 
256
  dstate_setinfo("output.voltage", "%s", outvolt);
 
257
  dstate_setinfo("battery.charge", "%02.1f", bvoltp);
 
258
  dstate_setinfo("battery.voltage", "%s", battvolt);
 
259
  dstate_setinfo("ups.load", "%s", loadpct);
 
260
  
 
261
  status_init();
 
262
  
 
263
  if (pstat[0] == '0') {
 
264
    status_set("OL");           /* on line */
 
265
    
 
266
    /* only allow these when OL since they're bogus when OB */
 
267
    
 
268
    if (pstat[2] == (inverted_bypass_bit ? '0' : '1')) {
 
269
      /* boost or trim in effect */
 
270
      if (atof(utility) < atof(outvolt))
 
271
        status_set("BOOST");
 
272
      
 
273
      if (atof(utility) > atof(outvolt))
 
274
        status_set("TRIM");
 
275
    }
 
276
    
 
277
  } else {
 
278
    status_set("OB");           /* on battery */
 
279
  }
 
280
  
 
281
  if (pstat[1] == '1') {
 
282
    status_set("LB");           /* low battery */
 
283
  }
 
284
  
 
285
  status_commit();
 
286
  dstate_dataok();
 
287
}
 
288
 
 
289
void upsdrv_help(void)
 
290
{
 
291
}
 
292
 
 
293
void upsdrv_makevartable(void)
 
294
{
 
295
}
 
296
 
 
297
void upsdrv_banner(void)
 
298
{
 
299
  printf("Network UPS Tools - mustek UPS driver %s (%s)\n", 
 
300
         DRV_VERSION, UPS_VERSION);
 
301
}
 
302
 
 
303
void upsdrv_initups(void)
 
304
{
 
305
  upsfd = ser_open(device_path);
 
306
  ser_set_speed(upsfd, device_path, B2400);
 
307
  
 
308
  ups_sync();
 
309
  ups_ident();
 
310
}
 
311
 
 
312
void upsdrv_cleanup(void)
 
313
{
 
314
  ser_close(upsfd, device_path);
 
315
}