~iheino+ub/+junk/nut-upsconf-docfix

« back to all changes in this revision

Viewing changes to drivers/isbmex.c

  • Committer: Tuomas Heino
  • Author(s): Laurent Bigonville
  • Date: 2014-04-22 20:46:12 UTC
  • Revision ID: iheino+ub@cc.hut.fi-20140422204612-1x2gh3nkezfsdao4
Tags: upstream-2.7.2
ImportĀ upstreamĀ versionĀ 2.7.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* isbmex.c - model specific routines for SOLA/BASIC Mexico (ISBMEX) models
 
2
 
 
3
   Copyright (C) 2005 Ricardo Martinezgarza <ricardo@nexxis.com.mx>
 
4
   Copyright (C) 2002 Edscott Wilson Garcia <edscott@imp.mx>
 
5
   Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
 
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
#include "main.h"
 
24
#include "serial.h"
 
25
 
 
26
#include <math.h>               /* for sqrt */
 
27
#include <string.h>
 
28
 
 
29
#define DRIVER_NAME     "ISBMEX UPS driver"
 
30
#define DRIVER_VERSION  "0.06"
 
31
 
 
32
/* driver description structure */
 
33
upsdrv_info_t   upsdrv_info = {
 
34
        DRIVER_NAME,
 
35
        DRIVER_VERSION,
 
36
        "Ricardo Martinezgarza <ricardo@nexxis.com.mx>\n" \
 
37
        "Edscott Wilson Garcia <edscott@imp.mx>\n" \
 
38
        "Russell Kroll <rkroll@exploits.org>",
 
39
        DRV_STABLE,
 
40
        { NULL }
 
41
};
 
42
 
 
43
#define xDEBUG
 
44
 
 
45
#ifdef DEBUG
 
46
#define D(x) x
 
47
#else
 
48
#define D(x)
 
49
#endif
 
50
 
 
51
/*#define ENDCHAR       '&'*/
 
52
#define MAXTRIES 15
 
53
/* #define IGNCHARS     ""      */
 
54
 
 
55
float lagrange(unsigned int vbyte)
 
56
{
 
57
        float f0, f1, f2, f3, f4, f5, f6;
 
58
        float a, b, c, d, e, g, h;
 
59
        const float x0=144.0, x1=154.0, x2=184.0, x3=195.0, x4=215.0, x5=228.0, x6=249.0;
 
60
        const float fX0=95.1, fX1=98.3, fX2=112.6, fX3=116.5, fX4=126.0, fX5=131.0, fX6=140.3;
 
61
 
 
62
        if(vbyte < 144) return 0.0;
 
63
 
 
64
        f0 = vbyte - x0;
 
65
        f1 = vbyte - x1;
 
66
        f2 = vbyte - x2;
 
67
        f3 = vbyte - x3;
 
68
        f4 = vbyte - x4;
 
69
        f5 = vbyte - x5;
 
70
        f6 = vbyte - x6;
 
71
 
 
72
        b = (f1 * f2 * f3 * f4 * f5 * f6 * fX0)/((x0 - x1) * (x0 - x2));
 
73
        b = b / ((x0 - x3) * (x0 - x4));
 
74
        b = b / ((x0 - x5) * (x0 - x6));
 
75
 
 
76
        c = (f0 * f2 * f3 * f4 * f5 * f6 * fX1)/((x1 - x0) * (x1 - x2));
 
77
        c = c / ((x1 - x3) * (x1 - x4));
 
78
        c = c / ((x1 - x5) * (x1 - x6));
 
79
 
 
80
        d = (f0 * f1 * f3 * f4 * f5 * f6 * fX2)/((x2 - x0) * (x2 - x1));
 
81
        d = d / ((x2 - x3) * (x2 - x4));
 
82
        d = d / ((x2 - x5) * (x2 - x6));
 
83
 
 
84
        e = (f0 * f1 * f2 * f4 * f5 * f6 * fX3)/((x3 - x0) * (x3 - x1));
 
85
        e = e / ((x3 - x2) * (x3 - x4));
 
86
        e = e / ((x3 - x5) * (x3 - x6));
 
87
 
 
88
        a = (f0 * f1 * f2 * f3 * f5 * f6 * fX4)/((x4 - x0) * (x4 - x1));
 
89
        a = a / ((x4 - x2) * (x4 - x3));
 
90
        a = a / ((x4 - x5) * (x4 - x6));
 
91
 
 
92
        g = (f0 * f1 * f2 * f3 * f4 * f6 * fX5)/((x5 - x0) * (x5 - x1));
 
93
        g = g / ((x5 - x2) * (x5 - x3));
 
94
        g = g / ((x5 - x4) * (x5 - x6));
 
95
 
 
96
        h = (f0 * f1 * f2 * f3 * f4 * f5 * fX6)/((x6 - x0) * (x6 - x1));
 
97
        h = h / ((x6 - x2) * (x6 - x3));
 
98
        h = h / ((x6 - x4) * (x6 - x5));
 
99
 
 
100
        return a + b + c + d + e + g + h;
 
101
}
 
102
 
 
103
float interpol(float vbytes)
 
104
{
 
105
        const int x[7]={75,83,87,98,103,118,145};
 
106
        const float f[7]={96.0,102.0,105.0,113.0,116.0,124.0,140.0};
 
107
        float l[7];
 
108
        float t, volts;
 
109
        const int n=6;
 
110
        int i, j;
 
111
 
 
112
        if(vbytes < x[0]) return 0.0;
 
113
        if(vbytes > x[6]) return f[6];
 
114
        for(i=0; i<=n; i++)
 
115
        {
 
116
                if((int)vbytes == x[i]) return f[i];
 
117
        }
 
118
        for(i=0; i<=n; i++)
 
119
        {
 
120
                l[i] = 1.0;
 
121
                for(j=0; j<=n; j++)
 
122
                {
 
123
                        if(j!=i) l[i] *= (float)(x[i] - x[j]);
 
124
                }
 
125
                l[i] = f[i] / l[i];
 
126
        }
 
127
        t = 1.0;
 
128
        for(i=0; i<=n; i++) t *= (vbytes - (float)x[i]);
 
129
        volts = 0.0;
 
130
        for(i=0; i<=n; i++) volts += (l[i] * t / (vbytes - (float)x[i]));
 
131
        return volts;
 
132
}
 
133
 
 
134
void upsdrv_initinfo(void)
 
135
{
 
136
        dstate_setinfo("ups.mfr", "Sola/Basic Mexico");
 
137
        dstate_setinfo("ups.model", "SR-Inet 280/300/400/480/500/800/1000");
 
138
 
 
139
        /* high/low voltage */
 
140
        dstate_setinfo("input.transfer.low", "102.0");  /* defined */
 
141
        dstate_setinfo("input.transfer.high", "140.0"); /* defined */
 
142
 
 
143
        dstate_setinfo("output.voltage", "120.0");      /* defined */
 
144
         
 
145
         /* addinfo(INFO_, "", 0, 0); */
 
146
         /*printf("Using %s %s on %s\n", getdata(INFO_MFR), getdata(INFO_MODEL), device_path);*/
 
147
}
 
148
 
 
149
static const char *getpacket(int *we_know){
 
150
  fd_set readfds;
 
151
  struct timeval tv;
 
152
  int bytes_per_packet=0;
 
153
  int ret;
 
154
  static const char *packet_id=NULL;
 
155
  static char buf[256];
 
156
  const char *s;
 
157
  ssize_t r;
 
158
 
 
159
  
 
160
  bytes_per_packet=*we_know;
 
161
  D(printf("getpacket with %d\n",bytes_per_packet);)
 
162
  
 
163
  FD_ZERO(&readfds);
 
164
  FD_SET(upsfd,&readfds);
 
165
        /* Wait up to 2 seconds. */
 
166
  tv.tv_sec = 5;
 
167
  tv.tv_usec = 0;
 
168
 
 
169
  ret=select(upsfd+1,  &readfds, NULL, NULL, &tv);
 
170
  if (!ret) {
 
171
        s="Nothing received from UPS. Check cable conexion";
 
172
        upslogx(LOG_ERR, "%s", s);
 
173
        D(printf("%s\n",s);)
 
174
        return NULL;
 
175
  }
 
176
 
 
177
  r=read(upsfd,buf,255);
 
178
  D(printf("%d bytes read: ",r);)
 
179
  buf[r]=0;
 
180
  if (bytes_per_packet && r < bytes_per_packet){
 
181
             ssize_t rr;
 
182
             D(printf("short read...\n");)
 
183
             usleep(500000);
 
184
             tv.tv_sec = 2;
 
185
             tv.tv_usec = 0;
 
186
             ret=select(upsfd+1,  &readfds, NULL, NULL, &tv);
 
187
             if (!ret) return NULL;
 
188
             rr=read(upsfd,buf+r,255-r);
 
189
             r += rr;
 
190
             if (r < bytes_per_packet) return NULL;
 
191
  }
 
192
             
 
193
  if (!bytes_per_packet){ /* packet size determination */ 
 
194
       /* if (r%10 && r%9) {
 
195
           printf("disregarding incomplete packet\n");
 
196
           return NULL;
 
197
        }*/
 
198
        if (r%10==0) *we_know=10;
 
199
        else if (r%9==0)  *we_know=9;
 
200
        return NULL;
 
201
  }
 
202
     
 
203
     /* by here we have bytes_per_packet and a complete packet */
 
204
     /* lets check if within the complete packet we have a valid packet */
 
205
 if (bytes_per_packet == 10) packet_id="&&&";  else  packet_id="***";
 
206
 s=strstr(buf,packet_id);
 
207
     /* check validity of packet */
 
208
 if (!s) {
 
209
        s="isbmex: no valid packet signature!";
 
210
        upslogx(LOG_ERR, "%s", s);
 
211
        D(printf("%s\n",s);)
 
212
        *we_know=0;
 
213
        return NULL;
 
214
 }
 
215
 D(if (s != buf) printf("overlapping packet received\n");)
 
216
 if ((int) strlen(s) < bytes_per_packet) {
 
217
                    D(printf("incomplete packet information\n");)
 
218
                    return NULL; 
 
219
 }
 
220
#ifdef DEBUG
 
221
    printf("Got signal:");
 
222
    {int i;for (i=0;i<strlen(s);i++) printf(" <%d>",(unsigned char)s[i]);}
 
223
    printf("\n");
 
224
#endif
 
225
    
 
226
 return s;
 
227
}
 
228
 
 
229
void upsdrv_updateinfo(void)
 
230
{
 
231
  static  float high_volt=-1, low_volt=999;
 
232
  const char    *buf=NULL;
 
233
  char buf2[17];
 
234
  int i;
 
235
  static int bytes_per_packet=0;
 
236
 
 
237
  for (i=0;i<5;i++) {
 
238
          if ((buf=getpacket(&bytes_per_packet)) != NULL) break;
 
239
  }
 
240
  if (!bytes_per_packet || !buf) {
 
241
        dstate_datastale();
 
242
        return;
 
243
  }
 
244
          
 
245
  /* do the parsing */
 
246
  {
 
247
     float in_volt,battpct,acfreq;
 
248
     double d;
 
249
     D(printf("parsing (%d bytes per packet)\n",bytes_per_packet);)
 
250
     /* input voltage :*/
 
251
     if (bytes_per_packet==9) {
 
252
         in_volt = lagrange((unsigned char)buf[3]);    
 
253
     } else {
 
254
         in_volt = interpol(sqrt((float)((unsigned char)buf[3]*256+(unsigned char)buf[4])));    
 
255
     }
 
256
     snprintf(buf2,16,"%5.1f",in_volt);
 
257
     D(printf("utility=%s\n",buf2);)
 
258
     dstate_setinfo("input.voltage", "%s", buf2);     
 
259
     
 
260
     if (in_volt >= high_volt) high_volt=in_volt;
 
261
     snprintf(buf2,16,"%5.1f",high_volt);
 
262
     D(printf("highvolt=%s\n",buf2);)
 
263
     dstate_setinfo("input.voltage.maximum", "%s", buf2);       
 
264
     
 
265
     if (in_volt <= low_volt)  low_volt=in_volt;
 
266
     snprintf(buf2,16,"%5.1f",low_volt);
 
267
     D(printf("lowvolt=%s\n",buf2);)
 
268
     dstate_setinfo("input.voltage.minimum", "%s", buf2);      
 
269
 
 
270
     battpct = ((double)((unsigned char)buf[(bytes_per_packet==10)?5:4])-168.0)*(100.0/(215.0-168.0));
 
271
     snprintf(buf2,16,"%5.1f",battpct);
 
272
     D(printf("battpct=%s\n",buf2);)
 
273
     dstate_setinfo("battery.charge", "%s", buf2);    
 
274
 
 
275
     d=(unsigned char)buf[(bytes_per_packet==10)?6:5]*256
 
276
             + (unsigned char)buf[(bytes_per_packet==10)?7:6];    
 
277
     acfreq = 1000000/d;
 
278
     snprintf(buf2,16,"%5.2f",acfreq);
 
279
     D(printf("acfreq=%s\n",buf2);)
 
280
     dstate_setinfo("input.frequency", "%s", buf2);    
 
281
 
 
282
     D(printf("status: ");)
 
283
     status_init();
 
284
     switch (buf[(bytes_per_packet==10)?8:7]){
 
285
         case 48: break; /* normal operation */
 
286
         case 49: D(printf("BOOST ");)
 
287
                  status_set("BOOST");
 
288
                  break;
 
289
         case 50: D(printf("TRIM ");)
 
290
                  status_set("TRIM");
 
291
         default: break;
 
292
     }
 
293
     switch (buf[(bytes_per_packet==10)?9:8]){
 
294
         case 48: D(printf("OL ");)
 
295
                  status_set("OL");
 
296
                  break; 
 
297
         case 50: D(printf("LB ");)
 
298
                  status_set("LB");
 
299
         case 49: D(printf("OB ");)
 
300
                  status_set("OB");
 
301
                  break;
 
302
         default: break;
 
303
     }
 
304
     D(printf("\n");)
 
305
     status_commit();        
 
306
                                  
 
307
             
 
308
   } 
 
309
   dstate_dataok();
 
310
   return;
 
311
}
 
312
 
 
313
void upsdrv_shutdown(void)
 
314
{
 
315
        /* shutdown is supported on models with
 
316
         * contact closure. Some ISB models with serial
 
317
         * support support contact closure, some don't.
 
318
         * If yours does support it, then a 12V signal
 
319
         * on pin 9 does the trick (only when ups is 
 
320
         * on OB condition) */
 
321
        /* 
 
322
         * here try to do the pin 9 trick, if it does not
 
323
         * work, else:*/
 
324
/*      fatalx(EXIT_FAILURE, "Shutdown only supported with the Generic Driver, type 6 and special cable");  */
 
325
        /*fatalx(EXIT_FAILURE, "shutdown not supported");*/
 
326
        int i;
 
327
        for(i=0;i<=5;i++)
 
328
        {
 
329
                ser_send_char(upsfd, '#');
 
330
                usleep(50000);
 
331
        }
 
332
}
 
333
 
 
334
 
 
335
void upsdrv_help(void)
 
336
{
 
337
}
 
338
 
 
339
/* list flags and values that you want to receive via -x */
 
340
void upsdrv_makevartable(void)
 
341
{
 
342
}
 
343
 
 
344
void upsdrv_initups(void)
 
345
{
 
346
        upsfd = ser_open(device_path);
 
347
        ser_set_speed(upsfd, device_path, B9600);
 
348
}
 
349
 
 
350
void upsdrv_cleanup(void)
 
351
{
 
352
        ser_close(upsfd, device_path);
 
353
}