1 /*!@file tripplite_usb.c
2  * @brief Driver for Tripp Lite non-PDC/HID USB models.
3  */
4 /*
5    tripplite_usb.c was derived from tripplite.c by Charles Lepple
6    tripplite.c was derived from Russell Kroll's bestups.c by Rik Faith.
7 
8    Copyright (C) 1999  Russell Kroll <rkroll@exploits.org>
9    Copyright (C) 2001  Rickard E. (Rik) Faith <faith@alephnull.com>
10    Copyright (C) 2004  Nicholas J. Kain <nicholas@kain.us>
11    Copyright (C) 2005-2008, 2014  Charles Lepple <clepple+nut@gmail.com>
12 
13    This program is free software; you can redistribute it and/or modify
14    it under the terms of the GNU General Public License as published by
15    the Free Software Foundation; either version 2 of the License, or
16    (at your option) any later version.
17 
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21    GNU General Public License for more details.
22 
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27 
28 
29 /* % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
30  *
31  * Protocol 1001
32  *
33  * OMNIVS Commands: (capital letters are literals, lower-case are variables)
34  * :B     -> Bxxxxyy (xxxx/55.0: Hz in, yy/16: battery voltage)
35  * :F     -> F1143_A (where _ = \0) Firmware version?
36  * :L     -> LvvvvXX (vvvv/2.0: VAC out)
37  * :P     -> P01000X (1000VA unit)
38  * :S     -> Sbb_XXX (bb = 10: on-line, 11: on battery)
39  * :V     -> V102XXX (firmware/protocol version?)
40  * :Wt    -> Wt      (watchdog; t = time in seconds (binary, not hex),
41  *                   0 = disable; if UPS is not pinged in this interval, it
42  *                   will power off the load, and then power it back on after
43  *                   a delay.)
44  *
45  * % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
46  *
47  * The outgoing commands are sent with HID Set_Report commands over EP0
48  * (control message), and incoming commands are received on EP1IN (interrupt
49  * endpoint). The UPS completely ignores the conventions of Set_Idle (where
50  * you NAK the interrupt read if you have no new data), so you constantly have
51  * to poll EP1IN.
52  *
53  * The descriptors say that bInterval is 10 ms. You generally need to wait at
54  * least 80-90 ms to get some characters back from the device.  If it takes
55  * more than 250 ms, you probably need to resend the command.
56  *
57  * All outgoing commands are followed by a checksum, which is 255 - (sum of
58  * characters after ':'), and then by '\r'. All responses should start with
59  * the command letter that was sent (no colon), and should be followed by
60  * '\r'. If the command is not supported (or apparently if there is a serial
61  * timeout internally), the previous response will be echoed back.
62  *
63  * % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
64  *
65  * SMARTPRO commands (3003):
66  *
67  * :A     -> ?          (start self-test)
68  * :D     -> D7187      (? - doesn't match tripplite.c)
69  * :F     -> F1019 A    firmware rev
70  * :H__   -> H          (delay before action?)
71  * :I_    -> I          (set flags for conditions that cause a reset?)
72  * :J__   -> J          (set 16-bit unit ID)
73  * :K#0   ->            (turn outlet off: # in 0..2; 0 is main relay)
74  * :K#1   ->            (turn outlet on: # in 0..2)
75  * :L     -> L290D_X
76  * :M     -> M007F      (min/max voltage seen)
77  * :N__   -> N
78  * :P     -> P01500X    (max power)
79  * :Q     ->            (while online: reboot)
80  * :R     -> R<01><FF>  (query flags for conditions that cause a reset?)
81  * :S     -> S100_Z0    (status?)
82  * :T     -> T7D2581    (temperature, frequency)
83  * :U     -> U<FF><FF>  (unit ID, 1-65535)
84  * :V     -> V1062XX	(outlets in groups of 2-2-4, with the groups of 2
85  * 			 individually switchable.)
86  * :W_    -> W_		(watchdog)
87  * :Z     -> Z		(reset for max/min; takes a moment to complete)
88  *
89  * % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
90  *
91  * The SMARTPRO unit seems to be slightly saner with regard to message
92  * polling. It specifies an interrupt in interval of 100 ms, but I just
93  * started at a 2 second timeout to obtain the above table.
94  *
95  * % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
96  *
97  * Commands from serial tripplite.c:
98  *
99  * :N%02X -- delay the UPS for provided time (hex seconds)
100  * :H%06X -- reboot the UPS.  UPS will restart after provided time (hex s)
101  * :A     -- begins a self-test
102  * :C     -- fetches result of a self-test
103  * :K1    -- turns on power receptacles
104  * :K0    -- turns off power receptacles
105  * :G     -- unconfirmed: shuts down UPS until power returns
106  * :Q1    -- enable "Remote Reboot"
107  * :Q0    -- disable "Remote Reboot"
108  * :W     -- returns 'W' data
109  * :L     -- returns 'L' data
110  * :V     -- returns 'V' data (firmware revision)
111  * :X     -- returns 'X' data (firmware revision)
112  * :D     -- returns general status data
113  * :B     -- returns battery voltage (hexadecimal decivolts)
114  * :I     -- returns minimum input voltage (hexadecimal hertz) [sic]
115  * :M     -- returns maximum input voltage (hexadecimal hertz) [sic]
116  * :P     -- returns power rating
117  * :Z     -- unknown
118  * :U     -- unknown
119  * :O     -- unknown
120  * :E     -- unknown
121  * :Y     -- returns mains frequency  (':D' is preferred)
122  * :T     -- returns ups temperature  (':D' is preferred)
123  * :R     -- returns input voltage    (':D' is preferred)
124  * :F     -- returns load percentage  (':D' is preferred)
125  * :S     -- enables remote reboot/remote power on
126  */
127 
128 /* Watchdog for 3005 is 15 - 255 seconds.
129  */
130 
131 #include "main.h"
132 #include "libusb.h"
133 #include <math.h>
134 #include <ctype.h>
135 #include <usb.h>
136 #include "usb-common.h"
137 
138 #define DRIVER_NAME		"Tripp Lite OMNIVS / SMARTPRO driver"
139 #define DRIVER_VERSION	"0.29"
140 
141 /* driver description structure */
142 upsdrv_info_t	upsdrv_info = {
143 	DRIVER_NAME,
144 	DRIVER_VERSION,
145 	"Charles Lepple <clepple+nut@gmail.com>\n" \
146 	"Russell Kroll <rkroll@exploits.org>\n" \
147 	"Rickard E. (Rik) Faith <faith@alephnull.com>\n" \
148 	"Nicholas J. Kain <nicholas@kain.us>",
149 	DRV_EXPERIMENTAL,
150 	{ NULL }
151 };
152 
153 /* TrippLite */
154 #define TRIPPLITE_VENDORID 0x09ae
155 
156 /* USB IDs device table */
157 static usb_device_id_t tripplite_usb_device_table[] = {
158 	/* e.g. OMNIVS1000, SMART550USB, ... */
159 	{ USB_DEVICE(TRIPPLITE_VENDORID, 0x0001), NULL },
160 
161 	/* Terminating entry */
162 	{ -1, -1, NULL }
163 };
164 
subdriver_match_func(USBDevice_t * hd,void * privdata)165 static int subdriver_match_func(USBDevice_t *hd, void *privdata)
166 {
167 	switch (is_usb_device_supported(tripplite_usb_device_table, hd))
168 	{
169 	case SUPPORTED:
170 		return 1;
171 
172 	case POSSIBLY_SUPPORTED:
173 		/* by default, reject, unless the productid option is given */
174 		if (getval("productid")) {
175 			return 1;
176 		}
177 	case NOT_SUPPORTED:
178 	default:
179 		return 0;
180 	}
181 }
182 
183 static USBDeviceMatcher_t subdriver_matcher = {
184 	&subdriver_match_func,
185 	NULL,
186 	NULL
187 };
188 
189 static enum tl_model_t {
190 	TRIPP_LITE_UNKNOWN = 0,
191 	TRIPP_LITE_OMNIVS,
192 	TRIPP_LITE_OMNIVS_2001,
193 	TRIPP_LITE_SMARTPRO,
194 	TRIPP_LITE_SMART_0004,
195 	TRIPP_LITE_SMART_3005
196 } tl_model = TRIPP_LITE_UNKNOWN;
197 
198 /*! Are the values encoded in ASCII or binary?
199  * TODO: Add 3004?
200  */
is_binary_protocol()201 static int is_binary_protocol()
202 {
203 	switch(tl_model) {
204 	case TRIPP_LITE_SMART_3005:
205 		return 1;
206 	default:
207 		return 0;
208 	}
209 }
210 
211 /*! Is this the "SMART" family of protocols?
212  * TODO: Add 3004?
213  */
is_smart_protocol()214 static int is_smart_protocol()
215 {
216 	switch(tl_model) {
217 	case TRIPP_LITE_SMARTPRO:
218 	case TRIPP_LITE_SMART_0004:
219 	case TRIPP_LITE_SMART_3005:
220 		return 1;
221 	default:
222 		return 0;
223 	}
224 }
225 
226 /*!@brief If a character is not printable, return a dot. */
227 #define toprint(x) (isalnum((unsigned)x) ? (x) : '.')
228 
229 #define ENDCHAR 13
230 
231 #define MAX_SEND_TRIES 10
232 #define SEND_WAIT_SEC 0
233 #define SEND_WAIT_NSEC (1000*1000*100)
234 
235 #define MAX_RECV_TRIES 10
236 #define RECV_WAIT_MSEC 1000	/*!< was 100 for OMNIVS; SMARTPRO units need longer */
237 
238 #define MAX_RECONNECT_TRIES 10
239 
240 #define DEFAULT_OFFDELAY   64  /*!< seconds (max 0xFF) */
241 #define DEFAULT_STARTDELAY 60  /*!< seconds (max 0xFFFFFF) */
242 #define DEFAULT_BOOTDELAY  64  /*!< seconds (max 0xFF) */
243 #define MAX_VOLT 13.4          /*!< Max battery voltage (100%) */
244 #define MIN_VOLT 11.0          /*!< Min battery voltage (10%) */
245 
246 static USBDevice_t *hd = NULL;
247 static USBDevice_t curDevice;
248 static USBDeviceMatcher_t *reopen_matcher = NULL;
249 static USBDeviceMatcher_t *regex_matcher = NULL;
250 static usb_dev_handle *udev;
251 static usb_communication_subdriver_t	*comm_driver = &usb_subdriver;
252 
253 /* We calculate battery charge (q) as a function of voltage (V).
254  * It seems that this function probably varies by firmware revision or
255  * UPS model - the Windows monitoring software gives different q for a
256  * given V than the old open source Tripp Lite monitoring software.
257  *
258  * The discharge curve should be the same for any given battery chemistry,
259  * so it should only be necessary to specify the minimum and maximum
260  * voltages likely to be seen in operation.
261  */
262 
263 /* Interval notation for Q% = 10% <= [minV, maxV] <= 100%  */
264 static double V_interval[2] = {MIN_VOLT, MAX_VOLT};
265 
266 static int battery_voltage_nominal = 12,
267 	   input_voltage_nominal = 120,
268 	   input_voltage_scaled = 120,
269 	/* input_voltage_maximum = -1,
270 	   input_voltage_minimum = -1, */
271 	   switchable_load_banks = 0,
272            unit_id = -1; /*!< range: 1-65535, most likely */
273 
274 /*! Time in seconds to delay before shutting down. */
275 static unsigned int offdelay = DEFAULT_OFFDELAY;
276 /* static unsigned int bootdelay = DEFAULT_BOOTDELAY; */
277 
278 /*!@brief Try to reconnect once.
279  * @return 1 if reconnection was successful.
280  */
reconnect_ups(void)281 static int reconnect_ups(void)
282 {
283 	int ret;
284 
285 	if (hd != NULL) {
286 		return 1;
287 	}
288 
289 	upsdebugx(2, "==================================================");
290 	upsdebugx(2, "= device has been disconnected, try to reconnect =");
291 	upsdebugx(2, "==================================================");
292 
293 	ret = comm_driver->open(&udev, &curDevice, reopen_matcher, NULL);
294 	if (ret < 1) {
295 		upslogx(LOG_INFO, "Reconnecting to UPS failed; will retry later...");
296 		dstate_datastale();
297 		return 0;
298 	}
299 
300 	hd = &curDevice;
301 
302 	return ret;
303 }
304 
305 
306 /*!@brief Convert a string to printable characters (in-place)
307  *
308  * @param[in,out] str	String to convert
309  * @param[in] len	Maximum number of characters to convert, or <= 0 to
310  * convert all.
311  *
312  * Uses toprint() macro defined above.
313  */
toprint_str(char * str,int len)314 void toprint_str(char *str, int len)
315 {
316 	int i;
317 	if(len <= 0) len = strlen(str);
318 	for(i=0; i < len; i++)
319 		str[i] = toprint(str[i]);
320 }
321 
322 /*!@brief Convert N characters from hex to decimal
323  *
324  * @param start		Beginning of string to convert
325  * @param len		Maximum number of characters to consider (max 32)
326  *
327  * @a len characters of @a start are copied to a temporary buffer, then passed
328  * to strtol() to be converted to decimal.
329  *
330  * @return See strtol(3)
331  */
hex2d(const unsigned char * start,unsigned int len)332 static int hex2d(const unsigned char *start, unsigned int len)
333 {
334 	unsigned char buf[32];
335 	buf[31] = '\0';
336 
337 	strncpy((char *)buf, (const char *)start, (len < (sizeof buf) ? len : (sizeof buf - 1)));
338 	if(len < sizeof(buf)) buf[len] = '\0';
339 	return strtol((char *)buf, NULL, 16);
340 }
341 
342 /*!@brief Convert N characters from big-endian binary to decimal
343  *
344  * @param start		Beginning of string to convert
345  * @param len		Maximum number of characters to consider (max 32)
346  *
347  * @a len characters of @a start are shifted into an accumulator.
348  *
349  * We assume len < sizeof(int), and that value > 0.
350  *
351  * @return the value
352  */
bin2d(const unsigned char * start,unsigned int len)353 static unsigned int bin2d(const unsigned char *start, unsigned int len)
354 {
355 	unsigned int value = 0, index = 0;
356 	for(index = 0; index < len; index++) {
357 		value <<= 8;
358 		value |= start[index];
359 	}
360 
361 	return value;
362 }
363 
hex_or_bin2d(const unsigned char * start,unsigned int len)364 static int hex_or_bin2d(const unsigned char *start, unsigned int len)
365 {
366 	if(is_binary_protocol()) {
367 		return bin2d(start, len);
368 	}
369 	return hex2d(start, len);
370 }
371 
372 /*!@brief Dump message in both hex and ASCII
373  *
374  * @param[in] msg	Buffer to dump
375  * @param[in] len	Number of bytes to dump
376  *
377  * @return		Pointer to static buffer with decoded message
378  */
hexascdump(unsigned char * msg,size_t len)379 static const char *hexascdump(unsigned char *msg, size_t len)
380 {
381 	size_t i;
382 	static unsigned char buf[256];
383 	unsigned char *bufp, *end;
384 
385 	bufp = buf;
386 	end = bufp + sizeof(buf);
387 	buf[0] = 0;
388 
389 	/* Dump each byte in hex: */
390 	for(i=0; i<len && end-bufp>=3; i++) {
391 		bufp += sprintf((char *)bufp, "%02x ", msg[i]);
392 	}
393 
394 	/* Dump single-quoted string with printable version of each byte: */
395 	if (end-bufp > 0) *bufp++ = '\'';
396 
397 	for(i=0; i<len && end-bufp>0; i++) {
398 		*bufp++ = toprint(msg[i]);
399 	}
400 	if (end-bufp > 0) *bufp++ = '\'';
401 
402 	if (end-bufp > 0)
403 		*bufp = '\0';
404 	else
405 		*--end='\0';
406 
407 	return (char *)buf;
408 }
409 
decode_protocol(unsigned int proto)410 enum tl_model_t decode_protocol(unsigned int proto)
411 {
412 	switch(proto) {
413 		case 0x0004:
414 			upslogx(3, "Using older SMART protocol (%04x)", proto);
415 			return TRIPP_LITE_SMART_0004;
416 		case 0x1001:
417 			upslogx(3, "Using OMNIVS protocol (%x)", proto);
418 			return TRIPP_LITE_OMNIVS;
419 		case 0x2001:
420 			upslogx(3, "Using OMNIVS 2001 protocol (%x)", proto);
421 			return TRIPP_LITE_OMNIVS_2001;
422 		case 0x3003:
423 			upslogx(3, "Using SMARTPRO protocol (%x)", proto);
424 			return TRIPP_LITE_SMARTPRO;
425 		case 0x3005:
426 			upslogx(3, "Using binary SMART protocol (%x)", proto);
427 			return TRIPP_LITE_SMART_3005;
428 		default:
429 			printf("Unknown protocol (%04x)", proto);
430 			break;
431 	}
432 
433 	return TRIPP_LITE_UNKNOWN;
434 }
435 
decode_v(const unsigned char * value)436 void decode_v(const unsigned char *value)
437 {
438 	unsigned char ivn, lb;
439 	int bv;
440 
441 	if(is_binary_protocol()) {
442 		/* 0x00 0x0c -> 12V ? */
443 		battery_voltage_nominal = (value[2] << 8) | value[3];
444 	} else {
445 		bv = hex2d(value+2, 2);
446 		battery_voltage_nominal = bv * 6;
447 	}
448 
449  	ivn = value[1];
450 	lb = value[4];
451 
452 	switch(ivn) {
453 		case '0': input_voltage_nominal =
454 			  input_voltage_scaled  = 100;
455 			  break;
456 
457 		case 2: /* protocol 3005 */
458 		case '1': input_voltage_nominal =
459 			  input_voltage_scaled  = 120;
460 			  break;
461 
462 		case '2': input_voltage_nominal =
463 			  input_voltage_scaled  = 230;
464 			  break;
465 
466 		case '3': input_voltage_nominal = 208;
467 			  input_voltage_scaled  = 230;
468 			  break;
469 
470 		default:
471 			  upslogx(2, "Unknown input voltage range: 0x%02x", (unsigned int)ivn);
472 			  break;
473 	}
474 
475 	if( (lb >= '0') && (lb <= '9') ) {
476 		switchable_load_banks = lb - '0';
477 	} else {
478 		if(is_binary_protocol()) {
479 			switchable_load_banks = lb;
480 		} else {
481 			if( lb != 'X' ) {
482 				upslogx(2, "Unknown number of switchable load banks: 0x%02x",
483 					(unsigned int)lb);
484 			}
485 		}
486 	}
487 	upsdebugx(2, "Switchable load banks: %d", switchable_load_banks);
488 }
489 
490 void upsdrv_initinfo(void);
491 
492 /*!@brief Report a USB comm failure, and reconnect if necessary
493  *
494  * @param[in] res	Result code from libusb/libhid call
495  * @param[in] msg	Error message to display
496  */
usb_comm_fail(int res,const char * msg)497 void usb_comm_fail(int res, const char *msg)
498 {
499 	static int try = 0;
500 
501 	switch(res) {
502 		case -EBUSY:
503 			upslogx(LOG_WARNING, "%s: Device claimed by another process", msg);
504 			fatalx(EXIT_FAILURE, "Terminating: EBUSY");
505 			break;
506 
507 		default:
508 			upslogx(LOG_WARNING, "%s: Device detached? (error %d: %s)", msg, res, usb_strerror());
509 
510 			upslogx(LOG_NOTICE, "Reconnect attempt #%d", ++try);
511 			hd = NULL;
512 			reconnect_ups();
513 
514 			if(hd) {
515 				upslogx(LOG_NOTICE, "Successfully reconnected");
516 				try = 0;
517 				upsdrv_initinfo();
518 			} else {
519 				if(try > MAX_RECONNECT_TRIES) {
520 					fatalx(EXIT_FAILURE, "Too many unsuccessful reconnection attempts");
521 				}
522 			}
523 			break;
524 	}
525 }
526 
527 /*!@brief Send a command to the UPS, and wait for a reply.
528  *
529  * All of the UPS commands are challenge-response. If a command does not have
530  * anything to return, it simply returns the command character.
531  *
532  * @param[in] msg	Command string, minus the ':' or CR
533  * @param[in] msg_len	Be sure to use sizeof(msg) instead of strlen(msg),
534  * since some commands have embedded NUL characters
535  * @param[out] reply	Reply (but check return code for validity)
536  * @param[out] reply_len (currently unused)
537  *
538  * @return number of chars in reply, excluding terminating NUL
539  * @return 0 if command was not accepted
540  */
send_cmd(const unsigned char * msg,size_t msg_len,unsigned char * reply,size_t reply_len)541 static int send_cmd(const unsigned char *msg, size_t msg_len, unsigned char *reply, size_t reply_len)
542 {
543 	unsigned char buffer_out[8];
544 	unsigned char csum = 0;
545 	int ret = 0, send_try, recv_try=0, done = 0;
546 	size_t i = 0;
547 
548 	upsdebugx(3, "send_cmd(msg_len=%u, type='%c')", (unsigned)msg_len, msg[0]);
549 
550 	if(msg_len > 5) {
551 		fatalx(EXIT_FAILURE, "send_cmd(): Trying to pass too many characters to UPS (%u)", (unsigned)msg_len);
552 	}
553 
554 	buffer_out[0] = ':';
555 	for(i=1; i<8; i++) buffer_out[i] = '\0';
556 
557 	for(i=0; i<msg_len; i++) {
558 		buffer_out[i+1] = msg[i];
559 		csum += msg[i];
560 	}
561 
562 	buffer_out[i] = 255-csum;
563 	buffer_out[i+1] = ENDCHAR;
564 
565 	upsdebugx(5, "send_cmd: sending  %s", hexascdump(buffer_out, sizeof(buffer_out)));
566 
567 	for(send_try=0; !done && send_try < MAX_SEND_TRIES; send_try++) {
568 		upsdebugx(6, "send_cmd send_try %d", send_try+1);
569 
570 		ret = comm_driver->set_report(udev, 0, buffer_out, sizeof(buffer_out));
571 
572 		if(ret != sizeof(buffer_out)) {
573 			upslogx(1, "libusb_set_report() returned %d instead of %u",
574 				ret, (unsigned)(sizeof(buffer_out)));
575 			return ret;
576 		}
577 
578 #if ! defined(__FreeBSD__)
579 		if(!done) { usleep(1000*100); /* TODO: nanosleep */ }
580 #endif
581 
582 		for(recv_try=0; !done && recv_try < MAX_RECV_TRIES; recv_try++) {
583 			upsdebugx(7, "send_cmd recv_try %d", recv_try+1);
584 			ret = comm_driver->get_interrupt(udev, reply, sizeof(buffer_out), RECV_WAIT_MSEC);
585 			if(ret != sizeof(buffer_out)) {
586 				upslogx(1, "libusb_get_interrupt() returned %d instead of %u while sending %s",
587 					ret, (unsigned)(sizeof(buffer_out)),
588 					hexascdump(buffer_out, sizeof(buffer_out)));
589 			}
590 			done = (ret == sizeof(buffer_out)) && (buffer_out[1] == reply[0]);
591 		}
592 	}
593 
594 	if(ret == sizeof(buffer_out)) {
595 		upsdebugx(5, "send_cmd: received %s (%s)", hexascdump(reply, sizeof(buffer_out)),
596 				done ? "OK" : "bad");
597 	}
598 
599 	upsdebugx(((send_try > 2) || (recv_try > 2)) ? 3 : 6,
600 			"send_cmd: send_try = %d, recv_try = %d\n", send_try, recv_try);
601 
602 	return done ? sizeof(buffer_out) : 0;
603 }
604 
605 /*!@brief Send an unknown command to the UPS, and store response in a variable
606  *
607  * @param msg Command string (usually a character and a null)
608  * @param len Length of command plus null
609  *
610  * The variables are of the form "ups.debug.X" where "X" is the command
611  * character.
612  */
debug_message(const char * msg,int len)613 void debug_message(const char *msg, int len)
614 {
615 	int ret;
616 	unsigned char tmp_value[9];
617 	char var_name[20], err_msg[80];
618 
619 	snprintf(var_name, sizeof(var_name), "ups.debug.%c", *msg);
620 
621 	ret = send_cmd((const unsigned char *)msg, len, tmp_value, sizeof(tmp_value));
622 	if(ret <= 0) {
623 		sprintf(err_msg, "Error reading '%c' value", *msg);
624 		usb_comm_fail(ret, err_msg);
625 		return;
626 	}
627 	dstate_setinfo(var_name, "%s", hexascdump(tmp_value+1, 7));
628 }
629 
630 #if 0
631 /* using the watchdog to reboot won't work while polling */
632 static void do_reboot_wait(unsigned dly)
633 {
634 	int ret;
635 	char buf[256], cmd_W[]="Wx";
636 
637 	cmd_W[1] = dly;
638 	upsdebugx(3, "do_reboot_wait(wait=%d): N", dly);
639 
640 	ret = send_cmd(cmd_W, sizeof(cmd_W), buf, sizeof(buf));
641 }
642 
643 static int do_reboot_now(void)
644 {
645 	do_reboot_wait(1);
646 	return 0;
647 }
648 
649 static void do_reboot(void)
650 {
651 	do_reboot_wait(bootdelay);
652 }
653 #endif
654 
655 /*! Called by 'tripplite_usb -k' */
soft_shutdown(void)656 static int soft_shutdown(void)
657 {
658 	int ret;
659 	unsigned char buf[256], cmd_N[]="N\0x", cmd_G[] = "G";
660 
661 	/* Already binary: */
662 	cmd_N[2] = offdelay;
663 	cmd_N[1] = offdelay >> 8;
664 	upsdebugx(3, "soft_shutdown(offdelay=%d): N", offdelay);
665 
666 	ret = send_cmd(cmd_N, sizeof(cmd_N), buf, sizeof(buf));
667 
668 	if(ret != 8) {
669 		upslogx(LOG_ERR, "Could not set offdelay to %d", offdelay);
670 		return ret;
671 	}
672 
673 	sleep(2);
674 
675 	/*! The unit must be on battery for this to work.
676 	 *
677 	 * @todo check for on-battery condition, and print error if not.
678 	 * @todo Find an equivalent command for non-OMNIVS models.
679 	 */
680 	ret = send_cmd(cmd_G, sizeof(cmd_G), buf, sizeof(buf));
681 
682 	if(ret != 8) {
683 		upslogx(LOG_ERR, "Could not turn off UPS (is it still on battery?)");
684 		return 0;
685 	}
686 
687 	return 1;
688 }
689 
690 #if 0
691 static int hard_shutdown(void)
692 {
693 	int ret;
694 	char buf[256], cmd_N[]="N\0x", cmd_K[] = "K\0";
695 
696 	cmd_N[2] = offdelay;
697 	cmd_N[1] = offdelay >> 8;
698 	upsdebugx(3, "hard_shutdown(offdelay=%d): N", offdelay);
699 
700 	ret = send_cmd(cmd_N, sizeof(cmd_N), buf, sizeof(buf));
701 	if(ret != 8) return ret;
702 
703 	sleep(2);
704 
705 	ret = send_cmd(cmd_K, sizeof(cmd_K), buf, sizeof(buf));
706 	return (ret == 8);
707 }
708 #endif
709 
710 /*!@brief Turn an outlet on or off.
711  *
712  * @return 1 if the command worked, 0 if not.
713  */
control_outlet(int outlet_id,int state)714 static int control_outlet(int outlet_id, int state)
715 {
716 	char k_cmd[10], buf[10];
717 	int ret;
718 
719 	switch(tl_model) {
720 		case TRIPP_LITE_SMARTPRO:   /* tested */
721 		case TRIPP_LITE_SMART_0004: /* untested */
722 			snprintf(k_cmd, sizeof(k_cmd)-1, "N%02X", 5);
723 			ret = send_cmd((unsigned char *)k_cmd, strlen(k_cmd) + 1, (unsigned char *)buf, sizeof buf);
724 			snprintf(k_cmd, sizeof(k_cmd)-1, "K%d%d", outlet_id, state & 1);
725 			ret = send_cmd((unsigned char *)k_cmd, strlen(k_cmd) + 1, (unsigned char *)buf, sizeof buf);
726 
727 			if(ret != 8) {
728 				upslogx(LOG_ERR, "Could not set outlet %d to state %d, ret = %d", outlet_id, state, ret);
729 				return 0;
730 			} else {
731 				return 1;
732 			}
733 			break;
734 		case TRIPP_LITE_SMART_3005:
735 			snprintf(k_cmd, sizeof(k_cmd)-1, "N%c", 5);
736 			ret = send_cmd((unsigned char *)k_cmd, strlen(k_cmd) + 1, (unsigned char *)buf, sizeof buf);
737 			snprintf(k_cmd, sizeof(k_cmd)-1, "K%c%c", outlet_id, state & 1);
738 			ret = send_cmd((unsigned char *)k_cmd, strlen(k_cmd) + 1, (unsigned char *)buf, sizeof buf);
739 
740 			if(ret != 8) {
741 				upslogx(LOG_ERR, "Could not set outlet %d to state %d, ret = %d", outlet_id, state, ret);
742 				return 0;
743 			} else {
744 				return 1;
745 			}
746 			break;
747 		default:
748 			upslogx(LOG_ERR, "control_outlet unimplemented for protocol %04x", tl_model);
749 	}
750 	return 0;
751 }
752 
753 /*!@brief Handler for "instant commands"
754  */
instcmd(const char * cmdname,const char * extra)755 static int instcmd(const char *cmdname, const char *extra)
756 {
757 	unsigned char buf[10];
758 
759 	if(is_smart_protocol()) {
760 		if (!strcasecmp(cmdname, "test.battery.start")) {
761 			send_cmd((const unsigned char *)"A", 2, buf, sizeof buf);
762 			return STAT_INSTCMD_HANDLED;
763 		}
764 
765 		if(!strcasecmp(cmdname, "reset.input.minmax")) {
766 			return (send_cmd((const unsigned char *)"Z", 2, buf, sizeof buf) == 2) ? STAT_INSTCMD_HANDLED : STAT_INSTCMD_UNKNOWN;
767 		}
768 	}
769 
770 	if (!strcasecmp(cmdname, "load.off")) {
771 		return control_outlet(0, 0) ? STAT_INSTCMD_HANDLED : STAT_INSTCMD_UNKNOWN;
772 	}
773 	if (!strcasecmp(cmdname, "load.on")) {
774 		return control_outlet(0, 1) ? STAT_INSTCMD_HANDLED : STAT_INSTCMD_UNKNOWN;
775 	}
776 	/* code for individual outlets is in setvar() */
777 #if 0
778 	if (!strcasecmp(cmdname, "shutdown.reboot")) {
779 		do_reboot_now();
780 		return STAT_INSTCMD_HANDLED;
781 	}
782 	if (!strcasecmp(cmdname, "shutdown.reboot.graceful")) {
783 		do_reboot();
784 		return STAT_INSTCMD_HANDLED;
785 	}
786 	if (!strcasecmp(cmdname, "shutdown.stayoff")) {
787 		hard_shutdown();
788 		return STAT_INSTCMD_HANDLED;
789 	}
790 #endif
791 	if (!strcasecmp(cmdname, "shutdown.return")) {
792 		soft_shutdown();
793 		return STAT_INSTCMD_HANDLED;
794 	}
795 
796 	upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
797 	return STAT_INSTCMD_UNKNOWN;
798 }
799 
setvar(const char * varname,const char * val)800 static int setvar(const char *varname, const char *val)
801 {
802 	if (!strcasecmp(varname, "ups.delay.shutdown")) {
803 		offdelay = atoi(val);
804 		dstate_setinfo("ups.delay.shutdown", "%d", offdelay);
805 		return STAT_SET_HANDLED;
806 	}
807 
808 	if (unit_id >= 0 && !strcasecmp(varname, "ups.id")) {
809                 int new_unit_id, ret;
810 		unsigned char J_msg[] = "J__", buf[9];
811 
812 		new_unit_id = atoi(val);
813 		J_msg[1] = new_unit_id >> 8;
814 		J_msg[2] = new_unit_id & 0xff;
815                 ret = send_cmd(J_msg, sizeof(J_msg), buf, sizeof(buf));
816 
817 		if(ret <= 0) {
818 			upslogx(LOG_NOTICE, "Could not set Unit ID (return code: %d).", ret);
819 			return STAT_SET_UNKNOWN;
820 		}
821 
822 		dstate_setinfo("ups.id", "%s", val);
823 		return STAT_SET_HANDLED;
824 	}
825 
826 	if(!strncmp(varname, "outlet.", strlen("outlet."))) {
827 		char outlet_name[80];
828 		char index_str[10], *first_dot, *next_dot;
829 		int index_chars, index, state, ret;
830 
831 		first_dot = strstr(varname, ".");
832 		next_dot = strstr(first_dot + 1, ".");
833 		index_chars = next_dot - (first_dot + 1);
834 
835 		if(index_chars > 9) return STAT_SET_UNKNOWN;
836 		if(strcmp(next_dot, ".switch")) return STAT_SET_UNKNOWN;
837 
838 		strncpy(index_str, first_dot + 1, index_chars);
839 		index_str[index_chars] = 0;
840 
841 		index = atoi(index_str);
842 		upslogx(LOG_DEBUG, "outlet.%d.switch = %s", index, val);
843 
844 		if(!strcasecmp(val, "on") || !strcmp(val, "1")) {
845 			state = 1;
846 		} else {
847 			state = 0;
848 		}
849 
850 		upslogx(LOG_DEBUG, "outlet.%d.switch = %s -> %d", index, val, state);
851 
852 		snprintf(outlet_name, sizeof(outlet_name)-1, "outlet.%d.switch", index);
853 
854 		ret = control_outlet(index, state);
855 		if(ret) {
856 			dstate_setinfo(outlet_name, "%d", state);
857 			return STAT_SET_HANDLED;
858 		} else {
859 			return STAT_SET_UNKNOWN;
860 		}
861 	}
862 
863 #if 0
864 	if (!strcasecmp(varname, "ups.delay.start")) {
865 		startdelay = atoi(val);
866 		dstate_setinfo("ups.delay.start", val);
867 		return STAT_SET_HANDLED;
868 	}
869 	if (!strcasecmp(varname, "ups.delay.reboot")) {
870 		bootdelay = atoi(val);
871 		dstate_setinfo("ups.delay.reboot", val);
872 		return STAT_SET_HANDLED;
873 	}
874 #endif
875 	return STAT_SET_UNKNOWN;
876 }
877 
upsdrv_initinfo(void)878 void upsdrv_initinfo(void)
879 {
880 	const unsigned char proto_msg[] = "\0", f_msg[] = "F", p_msg[] = "P",
881 		s_msg[] = "S", u_msg[] = "U", v_msg[] = "V", w_msg[] = "W\0";
882 	char *model, *model_end;
883 	unsigned char proto_value[9], f_value[9], p_value[9], s_value[9],
884 	     u_value[9], v_value[9], w_value[9];
885 	int  va, ret;
886 	unsigned int proto_number = 0;
887 
888 	/* Read protocol: */
889 	ret = send_cmd(proto_msg, sizeof(proto_msg), proto_value, sizeof(proto_value)-1);
890 	if(ret <= 0) {
891 		fatalx(EXIT_FAILURE, "Error reading protocol");
892 	}
893 
894 	proto_number = ((unsigned)(proto_value[1]) << 8)
895 			          | (unsigned)(proto_value[2]);
896 	tl_model = decode_protocol(proto_number);
897 
898 	if(tl_model == TRIPP_LITE_UNKNOWN)
899 		dstate_setinfo("ups.debug.0", "%s", hexascdump(proto_value+1, 7));
900 
901 	dstate_setinfo("ups.firmware.aux", "protocol %04x", proto_number);
902 
903 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
904 
905 	/* Reset watchdog: */
906 	/* Watchdog not supported on TRIPP_LITE_SMARTPRO models */
907 	if(tl_model != TRIPP_LITE_SMARTPRO ) {
908 		ret = send_cmd(w_msg, sizeof(w_msg), w_value, sizeof(w_value)-1);
909 		if(ret <= 0) {
910 			if(ret == -EPIPE) {
911 				fatalx(EXIT_FAILURE, "Could not reset watchdog. Please check and"
912 						"see if usbhid-ups(8) works with this UPS.");
913 			} else {
914 				upslogx(3, "Could not reset watchdog. Please send model "
915 						"information to nut-upsdev mailing list");
916 			}
917 		}
918 	}
919 
920 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
921 
922 	ret = send_cmd(s_msg, sizeof(s_msg), s_value, sizeof(s_value)-1);
923 	if(ret <= 0) {
924 		fatalx(EXIT_FAILURE, "Could not retrieve status ... is this an OMNIVS model?");
925 	}
926 
927 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
928 
929 	dstate_setinfo("ups.mfr", "%s", "Tripp Lite");
930 
931 	/* Get nominal power: */
932 	ret = send_cmd(p_msg, sizeof(p_msg), p_value, sizeof(p_value)-1);
933 	va = strtol((char *)(p_value+1), NULL, 10);
934 
935 	if(tl_model == TRIPP_LITE_SMART_0004) {
936 		dstate_setinfo("ups.debug.P","%s", hexascdump(p_value+1, 7));
937 		va *= 10; /* TODO: confirm? */
938 	}
939 
940 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
941 
942 	/* trim "TRIPP LITE" from beginning of model */
943 	model = strdup(hd->Product);
944 	if(strstr(model, hd->Vendor) == model) {
945 		model += strlen(hd->Vendor);
946 	}
947 
948 	/* trim leading spaces: */
949 	for(; *model == ' '; model++);
950 
951 	/* Trim trailing spaces */
952 	for(model_end = model + strlen(model) - 1;
953 			model_end > model && *model_end == ' ';
954 			model_end--) {
955 		*model_end = '\0';
956 	}
957 
958 	dstate_setinfo("ups.model", "%s", model);
959 
960 	dstate_setinfo("ups.power.nominal", "%d", va);
961 
962 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
963 
964         /* Fetch firmware version: */
965 	ret = send_cmd(f_msg, sizeof(f_msg), f_value, sizeof(f_value)-1);
966 
967 	toprint_str((char *)(f_value+1), 6);
968 	f_value[7] = 0;
969 
970 	dstate_setinfo("ups.firmware", "F%s", f_value+1);
971 
972 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
973 
974 	/* Get configuration: */
975 
976 	ret = send_cmd(v_msg, sizeof(v_msg), v_value, sizeof(v_value)-1);
977 
978 	decode_v(v_value);
979 
980 	/* FIXME: redundant, but since it's static, we don't need to poll
981 	 * every time.
982 	 */
983 	debug_message("V", 2);
984 
985 	if(switchable_load_banks > 0) {
986 		int i;
987 		char outlet_name[80];
988 
989 		for(i = 1; i <= switchable_load_banks + 1; i++) {
990 			snprintf(outlet_name, sizeof(outlet_name), "outlet.%d.id", i);
991 			dstate_setinfo(outlet_name, "%d", i);
992 
993 			snprintf(outlet_name, sizeof(outlet_name), "outlet.%d.desc", i);
994 			dstate_setinfo(outlet_name, "Load %d", i);
995 
996 			snprintf(outlet_name, sizeof(outlet_name), "outlet.%d.switchable", i);
997 			if( i <= switchable_load_banks ) {
998 				dstate_setinfo(outlet_name, "1");
999 				snprintf(outlet_name, sizeof(outlet_name)-1, "outlet.%d.switch", i);
1000 				dstate_setinfo(outlet_name, "1");
1001 				dstate_setflags(outlet_name, ST_FLAG_RW | ST_FLAG_STRING);
1002 				dstate_setaux(outlet_name, 3);
1003 			} else {
1004 				/* Last bank is not switchable: */
1005 				dstate_setinfo(outlet_name, "0");
1006 			}
1007 
1008 		}
1009 
1010 		/* For the main relay: */
1011 		dstate_addcmd("load.on");
1012 		dstate_addcmd("load.off");
1013 	}
1014 
1015 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1016 
1017 	if(tl_model != TRIPP_LITE_OMNIVS && tl_model != TRIPP_LITE_SMART_0004) {
1018 		/* Unit ID might not be supported by all models: */
1019 		ret = send_cmd(u_msg, sizeof(u_msg), u_value, sizeof(u_value)-1);
1020 		if(ret <= 0) {
1021 			upslogx(LOG_INFO, "Unit ID not retrieved (not available on all models)");
1022 		} else {
1023 			unit_id = (int)((unsigned)(u_value[1]) << 8)
1024 				| (unsigned)(u_value[2]);
1025 		}
1026 
1027 		if(tl_model == TRIPP_LITE_SMART_0004) {
1028 			debug_message("U", 2);
1029 		}
1030 	}
1031 
1032 	if(unit_id >= 0) {
1033 		dstate_setinfo("ups.id", "%d", unit_id);
1034 		dstate_setflags("ups.id", ST_FLAG_RW | ST_FLAG_STRING);
1035 		dstate_setaux("ups.id", 5);
1036 		upslogx(LOG_DEBUG,"Unit ID: %d", unit_id);
1037 	}
1038 
1039 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1040 
1041 	dstate_setinfo("input.voltage.nominal", "%d", input_voltage_nominal);
1042 	dstate_setinfo("battery.voltage.nominal", "%d", battery_voltage_nominal);
1043 	dstate_setinfo("ups.debug.load_banks", "%d", switchable_load_banks);
1044 
1045 	dstate_setinfo("ups.delay.shutdown", "%d", offdelay);
1046 	dstate_setflags("ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING);
1047 	dstate_setaux("ups.delay.shutdown", 3);
1048 
1049 #if 0
1050 	dstate_setinfo("ups.delay.start", "%d", startdelay);
1051 	dstate_setflags("ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING);
1052 	dstate_setaux("ups.delay.start", 8);
1053 
1054 	dstate_setinfo("ups.delay.reboot", "%d", bootdelay);
1055 	dstate_setflags("ups.delay.reboot", ST_FLAG_RW | ST_FLAG_STRING);
1056 	dstate_setaux("ups.delay.reboot", 3);
1057 #endif
1058 
1059 	if(is_smart_protocol()) {
1060 		dstate_addcmd("test.battery.start");
1061 		dstate_addcmd("reset.input.minmax");
1062 	}
1063 
1064 	dstate_addcmd("shutdown.return");
1065 
1066 #if 0
1067 	dstate_addcmd("shutdown.stayoff");
1068 
1069 	dstate_addcmd("test.battery.start"); /* Turns off automatically */
1070 
1071 	dstate_addcmd("load.off");
1072 	dstate_addcmd("load.on");
1073 
1074 	dstate_addcmd("shutdown.reboot");
1075 	dstate_addcmd("shutdown.reboot.graceful");
1076 #endif
1077 
1078 	upsh.instcmd = instcmd;
1079 	upsh.setvar = setvar;
1080 
1081 	printf("Attached to %s %s\n",
1082 			dstate_getinfo("ups.mfr"), dstate_getinfo("ups.model"));
1083 }
1084 
upsdrv_shutdown(void)1085 void upsdrv_shutdown(void)
1086 {
1087 	soft_shutdown();
1088 }
1089 
upsdrv_updateinfo(void)1090 void upsdrv_updateinfo(void)
1091 {
1092 	unsigned char b_msg[] = "B", d_msg[] = "D", l_msg[] = "L",
1093 			s_msg[] = "S", m_msg[] = "M", t_msg[] = "T";
1094 	unsigned char b_value[9], d_value[9], l_value[9], s_value[9],
1095 			m_value[9], t_value[9];
1096 	int bp, freq;
1097 	double bv_12V = 0.0; /*!< battery voltage, relative to a 12V battery */
1098 	double battery_voltage; /*!< the total battery voltage */
1099 
1100 	unsigned int s_value_1;
1101 
1102 	int ret;
1103 
1104 	status_init();
1105 
1106 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1107 
1108 	/* General status (e.g. "S10") */
1109 	ret = send_cmd(s_msg, sizeof(s_msg), s_value, sizeof(s_value));
1110 	if(ret <= 0) {
1111 		dstate_datastale();
1112 		usb_comm_fail(ret, "Error reading S value");
1113 		return;
1114 	}
1115 
1116 	if(tl_model != TRIPP_LITE_OMNIVS && tl_model != TRIPP_LITE_OMNIVS_2001) {
1117 		dstate_setinfo("ups.debug.S","%s", hexascdump(s_value+1, 7));
1118 	}
1119 
1120 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1121 
1122 	if(tl_model == TRIPP_LITE_OMNIVS) {
1123 		switch(s_value[2]) {
1124 			case '0':
1125 				status_set("OL");
1126 				break;
1127 			case '1':
1128 				status_set("OB");
1129 				break;
1130 			case '2':
1131 				/* "charge-only" mode, no AC in or out... the PC
1132 				 * shouldn't see this, because there is no power in
1133 				 * that case (OMNIVS), but it's here for testing.
1134 				 *
1135 				 * Entered by holding down the power button.
1136 				 */
1137 				status_set("BYPASS");
1138 				break;
1139 			case '3':
1140 				/* I have seen this once when switching from off+LB to charging */
1141 				upslogx(LOG_WARNING, "Unknown value for s[2]: 0x%02x", s_value[2]);
1142 				break;
1143 			default:
1144 				upslogx(LOG_ERR, "Unknown value for s[2]: 0x%02x", s_value[2]);
1145 				dstate_datastale();
1146 				break;
1147 		}
1148 	}
1149 
1150 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1151 
1152 	if(is_smart_protocol() || tl_model == TRIPP_LITE_OMNIVS_2001) {
1153 
1154 		unsigned int s_value_2 = s_value[2];
1155 
1156 		if(is_binary_protocol()) {
1157 			s_value_2 += '0';
1158 		}
1159 		switch(s_value_2) {
1160 			case '0':
1161 				dstate_setinfo("battery.test.status", "Battery OK");
1162 				break;
1163 			case '1':
1164 				dstate_setinfo("battery.test.status", "Battery bad - replace");
1165 				break;
1166 			case '2':
1167 				status_set("CAL");
1168 				break;
1169 			case '3':
1170 				status_set("OVER");
1171 				dstate_setinfo("battery.test.status", "Overcurrent?");
1172 				break;
1173 			case '4':
1174 				/* The following message is confusing, and may not be accurate: */
1175 				/* dstate_setinfo("battery.test.status", "Battery state unknown"); */
1176 				break;
1177 			case '5':
1178 				status_set("OVER");
1179 				dstate_setinfo("battery.test.status", "Battery fail - overcurrent?");
1180 				break;
1181 			default:
1182 				upslogx(LOG_ERR, "Unknown value for s[2]: 0x%02x", s_value[2]);
1183 				dstate_datastale();
1184 				break;
1185 		}
1186 
1187 
1188 		if(s_value[4] & 4) {
1189 			status_set("OFF");
1190 		} else {
1191 			/* Online/on battery: */
1192 			if(s_value[4] & 1) {
1193 				status_set("OB");
1194 			} else {
1195 				status_set("OL");
1196 			}
1197 		}
1198 
1199 #if 0
1200 		/* Apparently, this value changes more frequently when the
1201 		 * battery is discharged, but it does not track the actual
1202 		 * state-of-charge. See battery.charge calculation below.
1203 		 */
1204 		if(tl_model == TRIPP_LITE_SMARTPRO) {
1205 			unsigned battery_charge;
1206 			battery_charge = (unsigned)(s_value[5]);
1207 			dstate_setinfo("battery.charge",  "%u", battery_charge);
1208 		}
1209 #endif
1210 	}
1211 
1212 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1213 
1214 	s_value_1 = s_value[1];
1215 	if(is_binary_protocol()) {
1216 		s_value_1 += '0';
1217 	}
1218 
1219 	switch(s_value_1) {
1220 		case '0':
1221 			status_set("LB");
1222 			break;
1223 		case '1': /* Depends on s_value[2] */
1224 			break;
1225 		case '2':
1226 			if( tl_model == TRIPP_LITE_SMARTPRO ) {
1227 				status_set("RB");
1228 				break;
1229 			} /* else fall through: */
1230 		default:
1231 			upslogx(LOG_ERR, "Unknown value for s[1]: 0x%02x", s_value[1]);
1232 			dstate_datastale();
1233 			break;
1234 	}
1235 
1236 	status_commit();
1237 
1238 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1239 
1240 	if( tl_model == TRIPP_LITE_OMNIVS || tl_model == TRIPP_LITE_OMNIVS_2001 ) {
1241 		ret = send_cmd(b_msg, sizeof(b_msg), b_value, sizeof(b_value));
1242 		if(ret <= 0) {
1243 			dstate_datastale();
1244 			usb_comm_fail(ret, "Error reading B value");
1245 			return;
1246 		}
1247 
1248 		dstate_setinfo("input.voltage", "%.2f", hex2d(b_value+1, 4)/3600.0*input_voltage_scaled);
1249 
1250 		bv_12V = hex2d(b_value+5, 2)/16.0;
1251 
1252 		/* TODO: use battery_voltage_nominal, even though it is most likely 12V */
1253 		dstate_setinfo("battery.voltage", "%.2f", bv_12V);
1254 	}
1255 
1256 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1257 
1258 	if( is_smart_protocol() ) {
1259 
1260 		ret = send_cmd(d_msg, sizeof(d_msg), d_value, sizeof(d_value));
1261 		if(ret <= 0) {
1262 			dstate_datastale();
1263 			usb_comm_fail(ret, "Error reading D value");
1264 			return;
1265 		}
1266 
1267 		dstate_setinfo("input.voltage", "%d",
1268 				hex_or_bin2d(d_value+1, 2) * input_voltage_scaled / 120);
1269 
1270 		/* TODO: factor out the two constants */
1271 		bv_12V = hex_or_bin2d(d_value+3, 2) / 10.0 ;
1272 		battery_voltage = bv_12V * battery_voltage_nominal / 12.0;
1273 
1274 		dstate_setinfo("battery.voltage", "%.2f", battery_voltage);
1275 
1276 		/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1277 
1278 		ret = send_cmd(m_msg, sizeof(m_msg), m_value, sizeof(m_value));
1279 
1280                 if(m_value[5] != 0x0d) { /* we only expect 4 hex/binary digits */
1281 			dstate_setinfo("ups.debug.M", "%s", hexascdump(m_value+1, 7));
1282 		}
1283 
1284 		if(ret <= 0) {
1285 			dstate_datastale();
1286 			usb_comm_fail(ret, "Error reading M (min/max input voltage)");
1287 			return;
1288 		}
1289 
1290 		dstate_setinfo("input.voltage.minimum", "%3d", hex_or_bin2d(m_value+1, 2) * input_voltage_scaled / 120);
1291 		dstate_setinfo("input.voltage.maximum", "%3d", hex_or_bin2d(m_value+3, 2) * input_voltage_scaled / 120);
1292 
1293 		/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1294 
1295 		ret = send_cmd(t_msg, sizeof(t_msg), t_value, sizeof(t_value));
1296 		dstate_setinfo("ups.debug.T", "%s", hexascdump(t_value+1, 7));
1297 		if(ret <= 0) {
1298 			dstate_datastale();
1299 			usb_comm_fail(ret, "Error reading T value");
1300 			return;
1301 		}
1302 
1303 		if( tl_model == TRIPP_LITE_SMARTPRO ) {
1304 			freq = hex2d(t_value + 3, 3);
1305 			dstate_setinfo("input.frequency", "%.1f", freq / 10.0);
1306 
1307 			switch(t_value[6]) {
1308 				case '1':
1309 					dstate_setinfo("input.frequency.nominal", "%d", 60);
1310 					break;
1311 				case '0':
1312 					dstate_setinfo("input.frequency.nominal", "%d", 50);
1313 					break;
1314 			}
1315                 }
1316 
1317 		if( tl_model == TRIPP_LITE_SMART_0004 ) {
1318 			freq = hex2d(t_value + 3, 4);
1319 			dstate_setinfo("input.frequency", "%.1f", freq / 10.0);
1320 		}
1321 
1322 		if( tl_model == TRIPP_LITE_SMART_3005 ) {
1323 			dstate_setinfo("ups.temperature", "%d", (unsigned)(hex2d(t_value+1, 1)));
1324 		} else {
1325 			/* I'm guessing this is a calibration constant of some sort. */
1326 			dstate_setinfo("ups.temperature", "%.1f", (unsigned)(hex2d(t_value+1, 2)) * 0.3636 - 21);
1327 		}
1328 	}
1329 
1330 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1331 
1332 	if( tl_model == TRIPP_LITE_OMNIVS || tl_model == TRIPP_LITE_OMNIVS_2001 ||
1333 	    tl_model == TRIPP_LITE_SMARTPRO || tl_model == TRIPP_LITE_SMART_0004 ) {
1334 		/* dq ~= sqrt(dV) is a reasonable approximation
1335 		 * Results fit well against the discrete function used in the Tripp Lite
1336 		 * source, but give a continuous result. */
1337 		if (bv_12V >= V_interval[1])
1338 			bp = 100;
1339 		else if (bv_12V <= V_interval[0])
1340 			bp = 10;
1341 		else
1342 			bp = (int)(100*sqrt((bv_12V - V_interval[0])
1343 						/ (V_interval[1] - V_interval[0])));
1344 
1345 		dstate_setinfo("battery.charge",  "%3d", bp);
1346 	}
1347 
1348 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1349 
1350 	ret = send_cmd(l_msg, sizeof(l_msg), l_value, sizeof(l_value));
1351 	if(ret <= 0) {
1352 		dstate_datastale();
1353 		usb_comm_fail(ret, "Error reading L value");
1354 		return;
1355 	}
1356 
1357 	switch(tl_model) {
1358 		case TRIPP_LITE_OMNIVS:
1359 		case TRIPP_LITE_OMNIVS_2001:
1360 			dstate_setinfo("output.voltage", "%.1f", hex2d(l_value+1, 4)/240.0*input_voltage_scaled);
1361 			break;
1362 		case TRIPP_LITE_SMARTPRO:
1363 			dstate_setinfo("ups.load", "%d", hex2d(l_value+1, 2));
1364 			break;
1365 		case TRIPP_LITE_SMART_0004:
1366 			dstate_setinfo("ups.load", "%d", hex2d(l_value+1, 2));
1367 			dstate_setinfo("ups.debug.L","%s", hexascdump(l_value+1, 7));
1368 			break;
1369 		default:
1370 			dstate_setinfo("ups.debug.L","%s", hexascdump(l_value+1, 7));
1371 			break;
1372 	}
1373 
1374 	/* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */
1375 
1376 	if(tl_model != TRIPP_LITE_OMNIVS && tl_model != TRIPP_LITE_OMNIVS_2001) {
1377 		debug_message("D", 2);
1378 
1379 		/* We already grabbed these above: */
1380 		if(tl_model != TRIPP_LITE_SMARTPRO) {
1381 			debug_message("V", 2); /* Probably not necessary - seems to be static */
1382 			debug_message("M", 2);
1383 			debug_message("T", 2);
1384 			debug_message("P", 2);
1385 		}
1386 		/* debug_message("U", 2); */
1387 	}
1388 
1389 	dstate_dataok();
1390 }
1391 
upsdrv_help(void)1392 void upsdrv_help(void)
1393 {
1394 }
1395 
upsdrv_makevartable(void)1396 void upsdrv_makevartable(void)
1397 {
1398 	char msg[256];
1399 
1400 	snprintf(msg, sizeof msg, "Set shutdown delay, in seconds (default=%d)",
1401 		DEFAULT_OFFDELAY);
1402 	addvar(VAR_VALUE, "offdelay", msg);
1403 
1404 	/* allow -x vendor=X, vendorid=X, product=X, productid=X, serial=X */
1405 	nut_usb_addvars();
1406 
1407 	snprintf(msg, sizeof msg, "Minimum battery voltage, corresponding to 10%% charge (default=%.1f)",
1408 		MIN_VOLT);
1409 	addvar(VAR_VALUE, "battery_min", msg);
1410 
1411 	snprintf(msg, sizeof msg, "Maximum battery voltage, corresponding to 100%% charge (default=%.1f)",
1412 		MAX_VOLT);
1413 	addvar(VAR_VALUE, "battery_max", msg);
1414 
1415 #if 0
1416 	snprintf(msg, sizeof msg, "Set start delay, in seconds (default=%d).",
1417 		DEFAULT_STARTDELAY);
1418 	addvar(VAR_VALUE, "startdelay", msg);
1419 	snprintf(msg, sizeof msg, "Set reboot delay, in seconds (default=%d).",
1420 		DEFAULT_BOOTDELAY);
1421 	addvar(VAR_VALUE, "rebootdelay", msg);
1422 #endif
1423 }
1424 
1425 /*!@brief Initialize UPS and variables from ups.conf
1426  *
1427  * @todo Allow binding based on firmware version (which seems to vary wildly
1428  * from unit to unit)
1429  */
upsdrv_initups(void)1430 void upsdrv_initups(void)
1431 {
1432 	char *regex_array[6];
1433 	char *value;
1434 	int r;
1435 
1436 	/* process the UPS selection options */
1437 	regex_array[0] = NULL; /* handled by USB IDs device table */
1438 	regex_array[1] = getval("productid");
1439 	regex_array[2] = getval("vendor"); /* vendor string */
1440 	regex_array[3] = getval("product"); /* product string */
1441 	regex_array[4] = getval("serial"); /* probably won't see this */
1442 	regex_array[5] = getval("bus");
1443 
1444 	r = USBNewRegexMatcher(&regex_matcher, regex_array, REG_ICASE | REG_EXTENDED);
1445 	if (r==-1) {
1446 		fatal_with_errno(EXIT_FAILURE, "USBNewRegexMatcher");
1447 	} else if (r) {
1448 		fatalx(EXIT_FAILURE, "invalid regular expression: %s", regex_array[r]);
1449 	}
1450 
1451 	/* link the matchers */
1452 	regex_matcher->next = &subdriver_matcher;
1453 
1454 	/* Search for the first supported UPS matching the regular
1455 	 *            expression */
1456 	r = comm_driver->open(&udev, &curDevice, regex_matcher, NULL);
1457 	if (r < 1) {
1458 		fatalx(EXIT_FAILURE, "No matching USB/HID UPS found");
1459 	}
1460 
1461 	hd = &curDevice;
1462 
1463 	upslogx(1, "Detected a UPS: %s/%s", hd->Vendor ? hd->Vendor : "unknown", hd->Product ? hd->Product : "unknown");
1464 
1465 	dstate_setinfo("ups.vendorid", "%04x", hd->VendorID);
1466 	dstate_setinfo("ups.productid", "%04x", hd->ProductID);
1467 
1468 	/* create a new matcher for later reopening */
1469 	r = USBNewExactMatcher(&reopen_matcher, hd);
1470 	if (r) {
1471 		fatal_with_errno(EXIT_FAILURE, "USBNewExactMatcher");
1472 	}
1473 	/* link the two matchers */
1474 	reopen_matcher->next = regex_matcher;
1475 
1476 	value = getval("offdelay");
1477 	if (value) {
1478 		offdelay = atoi(value);
1479 		upsdebugx(2, "Setting 'offdelay' to %d", offdelay);
1480 	}
1481 
1482 	value = getval("battery_min");
1483 	if (value) {
1484 		V_interval[0] = atof(value);
1485 		upsdebugx(2, "Setting 'battery_min' to %.g", V_interval[0]);
1486 	}
1487 
1488 	value = getval("battery_max");
1489 	if (value) {
1490 		V_interval[1] = atof(value);
1491 		upsdebugx(2, "Setting 'battery_max' to %.g", V_interval[1]);
1492 	}
1493 
1494 #if 0
1495 	if (getval("startdelay"))
1496 		startdelay = atoi(getval("startdelay"));
1497 	if (getval("rebootdelay"))
1498 		bootdelay = atoi(getval("rebootdelay"));
1499 #endif
1500 }
1501 
upsdrv_cleanup(void)1502 void upsdrv_cleanup(void)
1503 {
1504 	comm_driver->close(udev);
1505 	USBFreeExactMatcher(reopen_matcher);
1506 	USBFreeRegexMatcher(regex_matcher);
1507 }
1508