apcupsd-ups: ignore generated files
[networkupstools/kirr.git] / drivers / isbmex.c
blob17328b2abe1bbe6c0d1bf57f7ce4887c9847686a
1 /* isbmex.c - model specific routines for SOLA/BASIC Mexico (ISBMEX) models
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>
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.
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.
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
23 #include "main.h"
24 #include "serial.h"
26 #include <math.h> /* for sqrt */
27 #include <string.h>
29 #define DRIVER_NAME "ISBMEX UPS driver"
30 #define DRIVER_VERSION "0.06"
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 }
43 #define xDEBUG
45 #ifdef DEBUG
46 #define D(x) x
47 #else
48 #define D(x)
49 #endif
51 /*#define ENDCHAR '&'*/
52 #define MAXTRIES 15
53 /* #define IGNCHARS "" */
55 float lagrange(unsigned int vbyte)
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;
62 if(vbyte < 144) return 0.0;
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;
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));
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));
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));
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));
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));
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));
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));
100 return a + b + c + d + e + g + h;
103 float interpol(float vbytes)
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;
112 if(vbytes < x[0]) return 0.0;
113 if(vbytes > x[6]) return f[6];
114 for(i=0; i<=n; i++)
116 if((int)vbytes == x[i]) return f[i];
118 for(i=0; i<=n; i++)
120 l[i] = 1.0;
121 for(j=0; j<=n; j++)
123 if(j!=i) l[i] *= (float)(x[i] - x[j]);
125 l[i] = f[i] / l[i];
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;
134 void upsdrv_initinfo(void)
136 dstate_setinfo("ups.mfr", "Sola/Basic Mexico");
137 dstate_setinfo("ups.model", "SR-Inet 280/300/400/480/500/800/1000");
139 /* high/low voltage */
140 dstate_setinfo("input.transfer.low", "102.0"); /* defined */
141 dstate_setinfo("input.transfer.high", "140.0"); /* defined */
143 dstate_setinfo("output.voltage", "120.0"); /* defined */
145 /* addinfo(INFO_, "", 0, 0); */
146 /*printf("Using %s %s on %s\n", getdata(INFO_MFR), getdata(INFO_MODEL), device_path);*/
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;
160 bytes_per_packet=*we_know;
161 D(printf("getpacket with %d\n",bytes_per_packet);)
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;
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;
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;
193 if (!bytes_per_packet){ /* packet size determination */
194 /* if (r%10 && r%9) {
195 printf("disregarding incomplete packet\n");
196 return NULL;
198 if (r%10==0) *we_know=10;
199 else if (r%9==0) *we_know=9;
200 return NULL;
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;
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;
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
226 return s;
229 void upsdrv_updateinfo(void)
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;
237 for (i=0;i<5;i++) {
238 if ((buf=getpacket(&bytes_per_packet)) != NULL) break;
240 if (!bytes_per_packet || !buf) {
241 dstate_datastale();
242 return;
245 /* do the parsing */
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])));
256 snprintf(buf2,16,"%5.1f",in_volt);
257 D(printf("utility=%s\n",buf2);)
258 dstate_setinfo("input.voltage", "%s", buf2);
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);
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);
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);
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);
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;
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;
304 D(printf("\n");)
305 status_commit();
309 dstate_dataok();
310 return;
313 void upsdrv_shutdown(void)
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) */
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++)
329 ser_send_char(upsfd, '#');
330 usleep(50000);
335 void upsdrv_help(void)
339 /* list flags and values that you want to receive via -x */
340 void upsdrv_makevartable(void)
344 void upsdrv_initups(void)
346 upsfd = ser_open(device_path);
347 ser_set_speed(upsfd, device_path, B9600);
350 void upsdrv_cleanup(void)
352 ser_close(upsfd, device_path);