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
26 #include <math.h> /* for sqrt */
29 #define DRIVER_NAME "ISBMEX UPS driver"
30 #define DRIVER_VERSION "0.06"
32 /* driver description structure */
33 upsdrv_info_t upsdrv_info
= {
36 "Ricardo Martinezgarza <ricardo@nexxis.com.mx>\n" \
37 "Edscott Wilson Garcia <edscott@imp.mx>\n" \
38 "Russell Kroll <rkroll@exploits.org>",
51 /*#define ENDCHAR '&'*/
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;
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};
112 if(vbytes
< x
[0]) return 0.0;
113 if(vbytes
> x
[6]) return f
[6];
116 if((int)vbytes
== x
[i
]) return f
[i
];
123 if(j
!=i
) l
[i
] *= (float)(x
[i
] - x
[j
]);
128 for(i
=0; i
<=n
; i
++) t
*= (vbytes
- (float)x
[i
]);
130 for(i
=0; i
<=n
; i
++) volts
+= (l
[i
] * t
/ (vbytes
- (float)x
[i
]));
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
){
152 int bytes_per_packet
=0;
154 static const char *packet_id
=NULL
;
155 static char buf
[256];
160 bytes_per_packet
=*we_know
;
161 D(printf("getpacket with %d\n",bytes_per_packet
);)
164 FD_SET(upsfd
,&readfds
);
165 /* Wait up to 2 seconds. */
169 ret
=select(upsfd
+1, &readfds
, NULL
, NULL
, &tv
);
171 s
="Nothing received from UPS. Check cable conexion";
172 upslogx(LOG_ERR
, "%s", s
);
177 r
=read(upsfd
,buf
,255);
178 D(printf("%d bytes read: ",r
);)
180 if (bytes_per_packet
&& r
< bytes_per_packet
){
182 D(printf("short read...\n");)
186 ret
=select(upsfd
+1, &readfds
, NULL
, NULL
, &tv
);
187 if (!ret
) return NULL
;
188 rr
=read(upsfd
,buf
+r
,255-r
);
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");
198 if (r
%10==0) *we_know
=10;
199 else if (r
%9==0) *we_know
=9;
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 */
209 s
="isbmex: no valid packet signature!";
210 upslogx(LOG_ERR
, "%s", s
);
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");)
221 printf("Got signal:");
222 {int i
;for (i
=0;i
<strlen(s
);i
++) printf(" <%d>",(unsigned char)s
[i
]);}
229 void upsdrv_updateinfo(void)
231 static float high_volt
=-1, low_volt
=999;
232 const char *buf
=NULL
;
235 static int bytes_per_packet
=0;
238 if ((buf
=getpacket(&bytes_per_packet
)) != NULL
) break;
240 if (!bytes_per_packet
|| !buf
) {
247 float in_volt
,battpct
,acfreq
;
249 D(printf("parsing (%d bytes per packet)\n",bytes_per_packet
);)
251 if (bytes_per_packet
==9) {
252 in_volt
= lagrange((unsigned char)buf
[3]);
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];
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: ");)
284 switch (buf
[(bytes_per_packet
==10)?8:7]){
285 case 48: break; /* normal operation */
286 case 49: D(printf("BOOST ");)
289 case 50: D(printf("TRIM ");)
293 switch (buf
[(bytes_per_packet
==10)?9:8]){
294 case 48: D(printf("OL ");)
297 case 50: D(printf("LB ");)
299 case 49: D(printf("OB ");)
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
324 /* fatalx(EXIT_FAILURE, "Shutdown only supported with the Generic Driver, type 6 and special cable"); */
325 /*fatalx(EXIT_FAILURE, "shutdown not supported");*/
329 ser_send_char(upsfd
, '#');
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
);