]>
Commit | Line | Data |
---|---|---|
003ccfa3 | 1 | /* everups.c - support for Ever UPS models |
2 | ||
3 | Copyright (C) 2003 Mikolaj Tutak <mtutak@eranet.pl> | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | */ | |
19 | ||
20 | #include "main.h" | |
21 | #include <sys/ioctl.h> | |
22 | ||
23 | #define DEFAULT_SERIALNUMBER "Unknown" | |
24 | ||
25 | #define BATT_DISCHARGED_VOLT 100.0 /* battery completly discharged */ | |
26 | #define BATT_MIN_OB_VOLTAGE 105.0 /* min. battery voltage for OB work - default */ | |
27 | #define BATT_MAX_OB_VOLTAGE 125.0 /* 100% charged battery - OB */ | |
28 | #define BATT_MAX_OFF_VOLT 134.0 /* 100% charged battery - OFF */ | |
29 | #define BATT_MAX_OL_VOLT 140.0 /* 100% charged battery - OL*/ | |
30 | ||
31 | #define EVER_SET_FLAGS 13 | |
32 | #define EVER_SET_SBTIME 28 | |
33 | ||
34 | #define EVER_GET_FLAGS 141 | |
35 | #define EVER_GET_MODEL 173 | |
36 | #define EVER_GET_STATUS 175 | |
37 | #define EVER_GET_BATTV 189 | |
38 | #define EVER_GET_LINEV 245 | |
39 | ||
40 | #define EVER_FRAME_INIT 208 | |
41 | ||
42 | #define EVER_FRAME_ACK 208 | |
43 | #define EVER_FRAME_NACK 209 | |
44 | ||
45 | #define EVER_FLAG_RESET 1 /* ??? */ | |
46 | #define EVER_FLAG_SELFTEST 2 | |
47 | #define EVER_FLAG_BEEPOFF 4 | |
48 | #define EVER_FLAG_POWEROFF 8 | |
49 | #define EVER_FLAG_SELFTESTFAIL 16 /* ??? */ | |
50 | #define EVER_FLAG_5 32 | |
51 | #define EVER_FLAG_6 64 | |
52 | #define EVER_FLAG_7 128 | |
53 | ||
54 | ||
55 | char *ever_serialnumber = DEFAULT_SERIALNUMBER; | |
56 | unsigned char ever_upstype = 0; | |
57 | unsigned char ever_debug = 0; | |
58 | unsigned int batt_min_ob_voltage = BATT_MIN_OB_VOLTAGE; | |
59 | ||
60 | /* used external variables */ | |
61 | extern int sddelay; /* shutdown delay, set by "-d $delay" in main.c */ | |
62 | extern int do_forceshutdown; /* shutdown delay, set by "-k" in main.c */ | |
63 | ||
64 | int ever_initframe(int tries) | |
65 | { | |
66 | int i; | |
67 | unsigned char buffer[2]; | |
68 | ||
69 | for( i=0; i<tries ; i++ ) { | |
70 | upssendchar( EVER_FRAME_INIT ); | |
71 | upsrecvchars( (char*)buffer, 1 ); | |
72 | ||
73 | if( buffer[0] == EVER_FRAME_ACK ) | |
74 | return 1; | |
75 | ||
76 | if( buffer[0] == EVER_FRAME_NACK ) | |
77 | upsrecvchars( (char*)buffer, 2 ); | |
78 | ||
79 | /* tcflush( upsfd, TCIOFLUSH ); */ | |
80 | upsflushin(0, nut_debug_level, ""); | |
81 | usleep( 250000 ); | |
82 | }; | |
83 | ||
84 | /* tcflush( upsfd, TCIOFLUSH ); */ | |
85 | upsflushin(0, nut_debug_level, ""); | |
86 | upslogx( LOG_INFO, "everups: ever_initframe() failed (%i tries)", tries ); | |
87 | return 0; | |
88 | } | |
89 | ||
90 | int ever_initups() | |
91 | { | |
92 | unsigned char tmp[2]; | |
93 | ||
94 | if( !ever_initframe(5) ) | |
95 | return 0; | |
96 | ||
97 | upssendchar( EVER_FRAME_INIT ); | |
98 | upsrecvchars( (char*)tmp, 2 ); | |
99 | usleep( 250000 ); | |
100 | ||
101 | return 1; | |
102 | } | |
103 | ||
104 | int ever_getupstype() | |
105 | { | |
106 | if( !ever_initframe(1) ) | |
107 | return 0; | |
108 | ||
109 | upssendchar( EVER_GET_MODEL ); | |
110 | upsrecvchars( (char*)&ever_upstype, 1 ); | |
111 | return 1; | |
112 | } | |
113 | ||
114 | char *ever_getupsname() | |
115 | { | |
116 | switch(ever_upstype) | |
117 | { | |
118 | case 67: return "NET 500-DPC"; | |
119 | case 68: return "NET 700-DPC"; | |
120 | case 69: return "NET 1000-DPC"; | |
121 | case 70: return "NET 1400-DPC"; | |
122 | case 71: return "NET 2200-DPC"; | |
123 | ||
124 | case 73: return "NET 700-DPC"; | |
125 | case 74: return "NET 1000-DPC"; | |
126 | case 75: return "NET 1400-DPC"; | |
127 | case 76: return "NET 500-DPC"; | |
128 | ||
129 | case 81: return "AP 450-PRO"; | |
130 | case 82: return "AP 650-PRO"; | |
131 | ||
132 | default: return "Unknown"; | |
133 | } | |
134 | } | |
135 | ||
136 | void ever_change_flags(unsigned char set_flags, unsigned char reset_flags) | |
137 | { | |
138 | unsigned char ups_flags; | |
139 | ||
140 | if ( !ever_initframe(2) ) | |
141 | return; | |
142 | ||
143 | upssendchar( EVER_GET_FLAGS ); | |
144 | upsrecvchars( (char*)&ups_flags, 1 ); | |
145 | ||
146 | if ( !ever_initframe(1) ) | |
147 | return; | |
148 | ||
149 | upssendchar( EVER_SET_FLAGS ); | |
150 | upssendchar( (ups_flags|set_flags)&(~reset_flags) ); | |
151 | } | |
152 | ||
153 | void ever_beepon(void) | |
154 | { | |
155 | ever_change_flags( 0, EVER_FLAG_BEEPOFF|EVER_FLAG_POWEROFF ); | |
156 | } | |
157 | ||
158 | void ever_beepoff(void) | |
159 | { | |
160 | ever_change_flags( EVER_FLAG_BEEPOFF, EVER_FLAG_POWEROFF ); | |
161 | } | |
162 | ||
163 | void ever_poweroff(int delay) | |
164 | { | |
165 | if ( !ever_initframe(2) ) | |
166 | return; | |
167 | ||
168 | upssendchar( EVER_SET_SBTIME ); | |
169 | upssendchar( (char)((float)delay/1.28+0.5) ); /* (1*1.28) sec */ | |
170 | ||
171 | ever_change_flags( EVER_FLAG_POWEROFF, 0 ); | |
172 | } | |
173 | ||
174 | void ever_poweron(void) | |
175 | { | |
176 | ever_change_flags( EVER_FLAG_RESET, EVER_FLAG_POWEROFF ); | |
177 | } | |
178 | ||
179 | void ever_autotest(void) | |
180 | { | |
181 | ever_change_flags( EVER_FLAG_SELFTEST, EVER_FLAG_SELFTESTFAIL|EVER_FLAG_POWEROFF ); | |
182 | } | |
183 | ||
184 | /* registered instant commands */ | |
185 | void instcmd (int auxcmd, int dlen, char *data) | |
186 | { | |
187 | switch (auxcmd) { | |
188 | case CMD_BTEST1: /* start battery test */ | |
189 | ever_autotest(); | |
190 | break; | |
191 | case CMD_OFF: /* power off load */ | |
192 | ever_poweroff(0); | |
193 | break; | |
194 | case CMD_ON: /* power on load */ | |
195 | ever_poweron(); | |
196 | break; | |
197 | default: | |
198 | upslogx( LOG_ERR, "instcmd: unknown type 0x%04x\n", auxcmd ); | |
199 | } | |
200 | } | |
201 | ||
202 | void setvar (int auxcmd, int dlen, char *data) | |
203 | { | |
204 | switch (auxcmd) { | |
205 | case INFO_LOWXFER: | |
206 | break; | |
207 | ||
208 | case INFO_HIGHXFER: | |
209 | break; | |
210 | ||
211 | case INFO_AUDIBLEALRM: | |
212 | upslogx( LOG_ERR, "setvar: unknown type %i\n", dlen ); | |
213 | if( dlen == 3 && data[0]=='O' && data[1]=='F' && data[2]=='F' ) | |
214 | ever_beepoff(); | |
215 | else | |
216 | ever_beepon(); | |
217 | break; | |
218 | ||
219 | default: | |
220 | upslogx( LOG_ERR, "setvar: unknown type 0x%04x\n", auxcmd ); | |
221 | } | |
222 | } | |
223 | ||
224 | void init_serial(void) | |
225 | { | |
226 | int clr_bit = TIOCM_DTR | TIOCM_RTS; | |
227 | ioctl( upsfd, TIOCMBIC, &clr_bit ); | |
228 | } | |
229 | ||
230 | void upsdrv_updateinfo(void) | |
231 | { | |
232 | int battery = 0; | |
233 | int standby = 0; | |
234 | char temp[VALSIZE]; | |
235 | unsigned char recBuf[2]; | |
236 | unsigned char ups_status; | |
237 | unsigned char ups_flags; | |
238 | unsigned int accuVoltage; | |
239 | unsigned int lineVoltage; | |
240 | double batteryCharge; | |
241 | ||
242 | /**** | |
243 | Line status | |
244 | 175->UPS, UPS=HGFEDCBA | |
245 | A=1 - battery | |
246 | A=0 & C=1 - standby | |
247 | ****/ | |
248 | ||
249 | if( !ever_initframe(2) ) | |
250 | return; | |
251 | ||
252 | upssendchar( EVER_GET_STATUS ); | |
253 | upsrecvchars( (char*)&ups_status, 1 ); | |
254 | ||
255 | battery = ( (ups_status&5)==4 ); | |
256 | standby = ( (ups_status&1)==1 ); | |
257 | ||
258 | /**** | |
259 | Read UPS flags | |
260 | ****/ | |
261 | ||
262 | if ( !ever_initframe(1) ) | |
263 | return; | |
264 | ||
265 | upssendchar( EVER_GET_FLAGS ); | |
266 | upsrecvchars( (char*)&ups_flags, 1 ); | |
267 | ||
268 | /**** | |
269 | Accumulator voltage value | |
270 | ****/ | |
271 | ||
272 | if( !ever_initframe(1) ) | |
273 | return; | |
274 | ||
275 | upssendchar( EVER_GET_BATTV ); | |
276 | upsrecvchars( (char*)recBuf, 1 ); | |
277 | ||
278 | accuVoltage = 150*(recBuf[0])/255; | |
279 | ||
280 | /**** | |
281 | Line voltage | |
282 | ****/ | |
283 | ||
284 | if( !ever_initframe(1) ) | |
285 | return; | |
286 | ||
287 | upssendchar( EVER_GET_LINEV ); | |
288 | upsrecvchars( (char*)recBuf, 2 ); | |
289 | ||
290 | if ( ever_upstype > 72 && ever_upstype < 77) | |
291 | lineVoltage = 100*(recBuf[0]+256*recBuf[1])/352; | |
292 | else | |
293 | lineVoltage = 100*(recBuf[0]+256*recBuf[1])/372; | |
294 | ||
295 | /**** | |
296 | Battery charge | |
297 | ****/ | |
298 | ||
299 | ||
300 | if( battery ) | |
301 | batteryCharge = 100.0 * (accuVoltage - BATT_DISCHARGED_VOLT) / (BATT_MAX_OB_VOLTAGE - BATT_DISCHARGED_VOLT); | |
302 | else if( standby ) | |
303 | batteryCharge = 100.0 * (accuVoltage - BATT_DISCHARGED_VOLT) / (BATT_MAX_OFF_VOLT - BATT_DISCHARGED_VOLT); | |
304 | else /* online */ | |
305 | batteryCharge = 100.0 * (accuVoltage - BATT_DISCHARGED_VOLT) / (BATT_MAX_OL_VOLT - BATT_DISCHARGED_VOLT); | |
306 | ||
307 | if( batteryCharge > 100 ) | |
308 | batteryCharge = 100; | |
309 | else if( batteryCharge < 0 ) | |
310 | batteryCharge = 0; | |
311 | ||
312 | status_init(); | |
313 | ||
314 | if( standby ) | |
315 | status_set( "OFF" ); | |
316 | else if( battery ) | |
317 | status_set( "OB" ); | |
318 | else | |
319 | status_set( "OL" ); | |
320 | ||
321 | if( battery && accuVoltage <= batt_min_ob_voltage ) | |
322 | status_set( "LB" ); | |
323 | ||
324 | /*** | |
325 | if( ups_flags&EVER_FLAG_POWEROFF ) | |
326 | status_set( "OFFPEND" ); | |
327 | ***/ | |
328 | ||
329 | if( ups_flags&EVER_FLAG_SELFTEST ) | |
330 | status_set( "TESTPEND" ); | |
331 | ||
332 | if( ups_flags&EVER_FLAG_SELFTESTFAIL ) | |
333 | status_set( "TESTFAIL" ); | |
334 | ||
335 | status_commit(); | |
336 | ||
337 | snprintf( temp, VALSIZE, "%03u", lineVoltage ); | |
338 | setinfo ( INFO_UTILITY, temp ); | |
339 | ||
340 | snprintf( temp,VALSIZE, "%03.1f", (double)accuVoltage/10.0 ); | |
341 | setinfo ( INFO_BATTVOLT, temp ); | |
342 | ||
343 | snprintf( temp, VALSIZE, "%03.1f", batteryCharge ); | |
344 | setinfo ( INFO_BATTPCT, temp ); | |
345 | ||
346 | setinfo( INFO_AUDIBLEALRM, (ups_flags&EVER_FLAG_BEEPOFF)?"OFF":"ON" ); | |
347 | ||
348 | setinfo( INFO_LOWXFER, "???" ); | |
349 | setinfo( INFO_HIGHXFER, "???" ); | |
350 | ||
351 | if( ever_debug > 0 ) { | |
352 | setinfo( INFO_COPYRIGHT, "STAT:%02X FLAG:%02X min OB: %2.1fV", (int)ups_status, (int)ups_flags, (double)batt_min_ob_voltage/10.0 ); | |
353 | } | |
354 | ||
355 | ||
356 | writeinfo(); | |
357 | } | |
358 | ||
359 | /* initialize UPS */ | |
360 | void upsdrv_initups(void) | |
361 | { | |
362 | /* check serial number from arguments */ | |
363 | if( getval("serialnumber") != NULL ) { | |
364 | ever_serialnumber = getval("serialnumber"); | |
365 | }; | |
366 | ||
367 | if( getval("minbattvolt") != NULL ) { | |
368 | int minbattvolt = (int)(atof(getval("minbattvolt"))*10); | |
369 | ||
370 | if( minbattvolt >= BATT_DISCHARGED_VOLT && minbattvolt <= BATT_MAX_OB_VOLTAGE ) | |
371 | batt_min_ob_voltage = minbattvolt; | |
372 | }; | |
373 | ||
374 | if( getval("debug") != NULL ) { | |
375 | ever_debug = atoi( getval("debug") ); | |
376 | }; | |
377 | ||
378 | upsdebugx( 1, "Values of arguments:" ); | |
379 | upsdebugx( 1, " serial number: '%s'", ever_serialnumber ); | |
380 | ||
381 | open_serial( device_path, B300 ); | |
382 | init_serial(); | |
383 | ||
384 | ever_initups(); | |
385 | ever_getupstype(); | |
386 | } | |
387 | ||
388 | void upsdrv_shutdown(void) | |
389 | { | |
390 | if (do_forceshutdown == 1) { | |
391 | /* power down the attached load immediately */ | |
392 | printf("Forced UPS shutdown triggered, do it...\n"); | |
393 | } else { | |
394 | /* power down the attached load after the given delay */ | |
395 | printf("UPS shutdown with '%d' seconds delay triggered, wait now...\n", sddelay); | |
396 | sleep(sddelay); | |
397 | }; | |
398 | ||
399 | ever_poweroff(2); /* power off load after 2 sec */ | |
400 | } | |
401 | ||
402 | /* display help */ | |
403 | void upsdrv_help(void) | |
404 | { | |
405 | } | |
406 | ||
407 | /* display banner */ | |
408 | void upsdrv_banner(void) | |
409 | { | |
410 | printf("Network UPS Tools - Ever UPS driver 0.02 (%s)\n\n", UPS_VERSION); | |
411 | } | |
412 | ||
413 | /* tell main how many entries we need */ | |
414 | int upsdrv_infomax(void) | |
415 | { | |
416 | return 32; | |
417 | } | |
418 | ||
419 | /* initialize information */ | |
420 | void upsdrv_initinfo(void) | |
421 | { | |
422 | /* write constant data for this model */ | |
423 | addinfo( INFO_MFR, "Ever", 0, 0 ); | |
424 | addinfo( INFO_MODEL, ever_getupsname(), 0, 0 ); | |
425 | addinfo( INFO_SERIAL, ever_serialnumber, 0, 0 ); | |
426 | ||
427 | /* add other things to monitor */ | |
428 | addinfo( INFO_STATUS, "", 0, 0 ); | |
429 | addinfo( INFO_UTILITY, "", 0, 0 ); | |
430 | addinfo( INFO_BATTPCT, "", 0, 0 ); | |
431 | addinfo( INFO_BATTVOLT, "", 0, 0 ); | |
432 | ||
433 | /* now add the instant commands */ | |
434 | addinfo( INFO_INSTCMD, "", 0, CMD_BTEST1 ); | |
435 | addinfo( INFO_INSTCMD, "", 0, CMD_OFF ); | |
436 | addinfo( INFO_INSTCMD, "", 0, CMD_ON ); | |
437 | ||
438 | /* RW variables */ | |
439 | addinfo( INFO_AUDIBLEALRM, "", FLAG_RW | FLAG_ENUM, 2 ); | |
440 | addinfo( INFO_ENUM, "ON", 1, INFO_AUDIBLEALRM ); | |
441 | addinfo( INFO_ENUM, "OFF", 0, INFO_AUDIBLEALRM ); | |
442 | addinfo( INFO_LOWXFER, "", FLAG_RW | FLAG_STRING, 3 ); | |
443 | addinfo( INFO_HIGHXFER, "", FLAG_RW | FLAG_STRING, 3 ); | |
444 | ||
445 | /* display debug info as copyright */ | |
446 | if( ever_debug > 0 ) { | |
447 | addinfo( INFO_COPYRIGHT, "", 0, 0 ); | |
448 | } | |
449 | ||
450 | upsh.instcmd = instcmd; | |
451 | upsh.setvar = setvar; | |
452 | } | |
453 | ||
454 | /* list flags and values that you want to receive via -x */ | |
455 | void upsdrv_makevartable(void) | |
456 | { | |
457 | char temp[256]; | |
458 | ||
459 | addvar( VAR_VALUE, "serialnumber", "Specify serial number, because it cannot detected automagically (default="DEFAULT_SERIALNUMBER")" ); | |
460 | ||
461 | snprintf( temp, 256, "Specify battery voltage when UPS change state from OB to LB (min=%2.1fV, max=%2.1fV, default=%2.1f)", | |
462 | (double)BATT_DISCHARGED_VOLT/10.0, (double)BATT_MAX_OB_VOLTAGE/10.0, (double)BATT_MIN_OB_VOLTAGE/10.0 ); | |
463 | addvar( VAR_VALUE, "minbattvolt", temp ); | |
464 | ||
465 | addvar( VAR_VALUE, "debug", "Specify this param if you want to debug driver" ); | |
466 | } |