Exemplo n.º 1
0
static int do_command(const unsigned char *command, char *reply, int cmd_len)
{
	int	ret;

	ret = ser_send_buf(upsfd, command, cmd_len);
	if (ret < 0) {
		upsdebug_with_errno(2, "send");
		return -1;
	} else if (ret < cmd_len) {
		upsdebug_hex(2, "send: truncated", command, ret);
		return -1;
	}

	upsdebug_hex(2, "send", command, ret);

	ret = ser_get_buf_len(upsfd, reply, 8, 1, 0); /* it needs that this driver works with USB to Serial cable */
	if (ret < 0) {
		upsdebug_with_errno(2, "read");
		return -1;
	} else if (ret < 6) {
		upsdebug_hex(2, "read: truncated", reply, ret);
		return -1;
	} else if (reply[7] != cksum(reply, 7)) {
		upsdebug_hex(2, "read: checksum error", reply, ret);
		return -1;
	}

	upsdebug_hex(2, "read", reply, ret);
	return ret;
}
Exemplo n.º 2
0
/* Return the physical value associated with the given HIDData path.
 * return 1 if OK, 0 on fail, -errno otherwise (ie disconnect).
 */
int HIDGetDataValue(hid_dev_handle_t udev, HIDData_t *hiddata, double *Value, int age)
{
	int	r;
	long	hValue;

	if (hiddata == NULL) {
		return 0;
	}

	r = get_item_buffered(reportbuf, udev, hiddata, &hValue, age);
	if (r<0) {
		upsdebug_with_errno(1, "Can't retrieve Report %02x", hiddata->ReportID);
		return -errno;
	}

	*Value = hValue;
	
	/* Convert Logical Min, Max and Value into Physical */
	*Value = logical_to_physical(hiddata, hValue);
	
	/* Process exponents and units */
	*Value *= exponent(10, get_unit_expo(hiddata));

	return 1;
}
Exemplo n.º 3
0
/* returns < 0 on errors, 0 on timeout and > 0 on success. */
static int upscrecv(char *buf)
{
	int	res;

	/* NOTE: the serial port is set to use Canonical Mode Input Processing,
	   which means ser_get_buf() either returns one line terminated with
	   ENDCHAR, an error or times out. */

	while (1) {
		res = ser_get_buf(upsfd, buf, UPSC_BUFLEN, input_timeout_sec, 0);
		if (res != 1) {
			break;
		}

		/* Only one character, must be ENDCHAR */
		upsdebugx(3, "upscrecv: Empty line");
	}

	if (res < 0) {
		upsdebug_with_errno(3, "upscrecv");
	} else if (res == 0) {
		upsdebugx(3, "upscrecv: Timeout");
	} else {
		upsdebugx(3, "upscrecv: %u bytes:\t'%s'", res-1, str_rtrim(buf, ENDCHAR));
	}

	return res;
}
Exemplo n.º 4
0
/* On success, return item count >0. When no notifications are available,
 * return 'error' or 'no event' code.
 */
int HIDGetEvents(hid_dev_handle_t udev, HIDData_t **event, int eventsize)
{
	unsigned char	buf[SMALLBUF];
	int		itemCount = 0;
	int		buflen, r, i;
	HIDData_t	*pData;

	/* needs libusb-0.1.8 to work => use ifdef and autoconf */
	buflen = comm_driver->get_interrupt(udev, buf, sizeof(buf), 250);
	if (buflen <= 0) {
		return buflen;	/* propagate "error" or "no event" code */
	}

	r = file_report_buffer(reportbuf, buf, buflen);
	if (r < 0) {
		upsdebug_with_errno(1, "%s: failed to buffer report", __func__);
		return -errno;
	}

	/* now read all items that are part of this report */
	for (i=0; i<pDesc->nitems; i++) {

		pData = &pDesc->item[i];

		/* Variable not part of this report */
		if (pData->ReportID != buf[0])
			continue;

		/* Not an input report */
		if (pData->Type != ITEM_INPUT)
			continue;

		/* maximum number of events reached? */
		if (itemCount >= eventsize) {
			upsdebugx(1, "%s: too many events (truncated)", __func__);
			break;
		}

		event[itemCount++] = pData;
	}

	if (itemCount == 0) {
		upsdebugx(1, "%s: unexpected input report (ignored)", __func__);
	}

	return itemCount;
}
Exemplo n.º 5
0
/* returns < 0 on errors, 0 on timeout and > 0 on success. */
static int upscsend(const char *cmd)
{
	int	res;

	res = ser_send_pace(upsfd, output_pace_usec, "%s%s%s",
		use_pre_lf ? "\n" : "",
		cmd,
		use_crlf ? "\r\n" : "\r");

	if (res < 0) {
		upsdebug_with_errno(3, "upscsend");
	} else if (res == 0) {
		upsdebugx(3, "upscsend: Timeout");
	} else {
		upsdebugx(3, "upscsend: '%s'", cmd);
	}

	return res;
}
Exemplo n.º 6
0
/* Set the given physical value for the variable associated with
 * path. return 1 if OK, 0 on fail, -errno otherwise (ie disconnect).
 */
int HIDSetDataValue(hid_dev_handle_t udev, HIDData_t *hiddata, double Value)
{
	int	i, r;
	long	hValue;

	if (hiddata == NULL) {
		return 0;
	}

	/* Test if Item is settable */
	/* FIXME: not constant == volatile, but
	* it doesn't imply that it's RW! */
	if (hiddata->Attribute == ATTR_DATA_CST) {
		return 0;
	}

	/* Process exponents and units */
	Value /= exponent(10, get_unit_expo(hiddata));
	
	/* Convert Physical Min, Max and Value into Logical */
	hValue = physical_to_logical(hiddata, Value);

	r = set_item_buffered(reportbuf, udev, hiddata, hValue);
	if (r<0) {
		upsdebug_with_errno(1, "Can't set Report %02x", hiddata->ReportID);
		return -errno;
	}

	/* flush the report buffer (data may have changed) */
	for (i=0; i<256; i++) {
		reportbuf->ts[i] = 0;
	}
	
	upsdebugx(4, "Set report succeeded");
	return 1;
}
Exemplo n.º 7
0
Arquivo: libusb.c Projeto: alfh/nut
/* On success, fill in the curDevice structure and return the report
 * descriptor length. On failure, return -1.
 * Note: When callback is not NULL, the report descriptor will be
 * passed to this function together with the udev and USBDevice_t
 * information. This callback should return a value > 0 if the device
 * is accepted, or < 1 if not. If it isn't accepted, the next device
 * (if any) will be tried, until there are no more devices left.
 */
static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDeviceMatcher_t *matcher,
	int (*callback)(usb_dev_handle *udev, USBDevice_t *hd, unsigned char *rdbuf, int rdlen))
{
#ifdef HAVE_USB_DETACH_KERNEL_DRIVER_NP
	int retries;
#endif
	int rdlen1, rdlen2; /* report descriptor length, method 1+2 */
	USBDeviceMatcher_t *m;
	struct usb_device *dev;
	struct usb_bus *bus;
	usb_dev_handle *udev;
	struct usb_interface_descriptor *iface;

	int ret, res;
	unsigned char buf[20];
	unsigned char *p;
	char string[256];
	int i;

	/* report descriptor */
	unsigned char	rdbuf[MAX_REPORT_SIZE];
	int		rdlen;

	/* libusb base init */
	usb_init();
	usb_find_busses();
	usb_find_devices();

#ifndef __linux__ /* SUN_LIBUSB (confirmed to work on Solaris and FreeBSD) */
	/* Causes a double free corruption in linux if device is detached! */
	libusb_close(*udevp);
#endif

	for (bus = usb_busses; bus; bus = bus->next) {
		for (dev = bus->devices; dev; dev = dev->next) {
			upsdebugx(2, "Checking device (%04X/%04X) (%s/%s)", dev->descriptor.idVendor,
				dev->descriptor.idProduct, bus->dirname, dev->filename);

			/* supported vendors are now checked by the
			   supplied matcher */

			/* open the device */
			*udevp = udev = usb_open(dev);
			if (!udev) {
				upsdebugx(2, "Failed to open device, skipping. (%s)", usb_strerror());
				continue;
			}

			/* collect the identifying information of this
			   device. Note that this is safe, because
			   there's no need to claim an interface for
			   this (and therefore we do not yet need to
			   detach any kernel drivers). */

			free(curDevice->Vendor);
			free(curDevice->Product);
			free(curDevice->Serial);
			free(curDevice->Bus);
			memset(curDevice, '\0', sizeof(*curDevice));

			curDevice->VendorID = dev->descriptor.idVendor;
			curDevice->ProductID = dev->descriptor.idProduct;
			curDevice->Bus = strdup(bus->dirname);

			if (dev->descriptor.iManufacturer) {
				ret = usb_get_string_simple(udev, dev->descriptor.iManufacturer,
					string, sizeof(string));
				if (ret > 0) {
					curDevice->Vendor = strdup(string);
				}
			}

			if (dev->descriptor.iProduct) {
				ret = usb_get_string_simple(udev, dev->descriptor.iProduct,
					string, sizeof(string));
				if (ret > 0) {
					curDevice->Product = strdup(string);
				}
			}

			if (dev->descriptor.iSerialNumber) {
				ret = usb_get_string_simple(udev, dev->descriptor.iSerialNumber,
					string, sizeof(string));
				if (ret > 0) {
					curDevice->Serial = strdup(string);
				}
			}

			upsdebugx(2, "- VendorID: %04x", curDevice->VendorID);
			upsdebugx(2, "- ProductID: %04x", curDevice->ProductID);
			upsdebugx(2, "- Manufacturer: %s", curDevice->Vendor ? curDevice->Vendor : "unknown");
			upsdebugx(2, "- Product: %s", curDevice->Product ? curDevice->Product : "unknown");
			upsdebugx(2, "- Serial Number: %s", curDevice->Serial ? curDevice->Serial : "unknown");
			upsdebugx(2, "- Bus: %s", curDevice->Bus ? curDevice->Bus : "unknown");

			upsdebugx(2, "Trying to match device");
			for (m = matcher; m; m=m->next) {
				ret = matches(m, curDevice);
				if (ret==0) {
					upsdebugx(2, "Device does not match - skipping");
					goto next_device;
				} else if (ret==-1) {
					fatal_with_errno(EXIT_FAILURE, "matcher");
					goto next_device;
				} else if (ret==-2) {
					upsdebugx(2, "matcher: unspecified error");
					goto next_device;
				}
			}
			upsdebugx(2, "Device matches");

			/* Now we have matched the device we wanted. Claim it. */

#ifdef HAVE_USB_DETACH_KERNEL_DRIVER_NP
			/* this method requires at least libusb 0.1.8:
			 * it force device claiming by unbinding
			 * attached driver... From libhid */
			retries = 3;
			while (usb_claim_interface(udev, 0) < 0) {

				upsdebugx(2, "failed to claim USB device: %s", usb_strerror());

				if (usb_detach_kernel_driver_np(udev, 0) < 0) {
					upsdebugx(2, "failed to detach kernel driver from USB device: %s", usb_strerror());
				} else {
					upsdebugx(2, "detached kernel driver from USB device...");
				}

				if (retries-- > 0) {
					continue;
				}

				fatalx(EXIT_FAILURE, "Can't claim USB device [%04x:%04x]: %s", curDevice->VendorID, curDevice->ProductID, usb_strerror());
			}
#else
			if (usb_claim_interface(udev, 0) < 0) {
				fatalx(EXIT_FAILURE, "Can't claim USB device [%04x:%04x]: %s", curDevice->VendorID, curDevice->ProductID, usb_strerror());
			}
#endif

			/* set default interface */
			usb_set_altinterface(udev, 0);

			if (!callback) {
				return 1;
			}

			if (!dev->config) { /* ?? this should never happen */
				upsdebugx(2, "  Couldn't retrieve descriptors");
				goto next_device;
			}

			rdlen1 = -1;
			rdlen2 = -1;

			/* Get HID descriptor */

			/* FIRST METHOD: ask for HID descriptor directly. */
			/* res = usb_get_descriptor(udev, USB_DT_HID, 0, buf, 0x9); */
			res = usb_control_msg(udev, USB_ENDPOINT_IN+1, USB_REQ_GET_DESCRIPTOR,
					      (USB_DT_HID << 8) + 0, 0, buf, 0x9, USB_TIMEOUT);

			if (res < 0) {
				upsdebugx(2, "Unable to get HID descriptor (%s)", usb_strerror());
			} else if (res < 9) {
				upsdebugx(2, "HID descriptor too short (expected %d, got %d)", 8, res);
			} else {

				upsdebug_hex(3, "HID descriptor, method 1", buf, 9);

				rdlen1 = buf[7] | (buf[8] << 8);
			}

			if (rdlen1 < -1) {
				upsdebugx(2, "Warning: HID descriptor, method 1 failed");
			}

			/* SECOND METHOD: find HID descriptor among "extra" bytes of
			   interface descriptor, i.e., bytes tucked onto the end of
			   descriptor 2. */

			/* Note: on some broken UPS's (e.g. Tripp Lite Smart1000LCD),
				only this second method gives the correct result */

			/* for now, we always assume configuration 0, interface 0,
			   altsetting 0, as above. */
			iface = &dev->config[0].interface[0].altsetting[0];
			for (i=0; i<iface->extralen; i+=iface->extra[i]) {
				upsdebugx(4, "i=%d, extra[i]=%02x, extra[i+1]=%02x", i,
					iface->extra[i], iface->extra[i+1]);
				if (i+9 <= iface->extralen && iface->extra[i] >= 9 && iface->extra[i+1] == 0x21) {
					p = &iface->extra[i];
					upsdebug_hex(3, "HID descriptor, method 2", p, 9);
					rdlen2 = p[7] | (p[8] << 8);
					break;
				}
			}

			if (rdlen2 < -1) {
				upsdebugx(2, "Warning: HID descriptor, method 2 failed");
			}

			/* when available, always choose the second value, as it
				seems to be more reliable (it is the one reported e.g. by
				lsusb). Note: if the need arises, can change this to use
				the maximum of the two values instead. */
			rdlen = rdlen2 >= 0 ? rdlen2 : rdlen1;

			if (rdlen < 0) {
				upsdebugx(2, "Unable to retrieve any HID descriptor");
				goto next_device;
			}
			if (rdlen1 >= 0 && rdlen2 >= 0 && rdlen1 != rdlen2) {
				upsdebugx(2, "Warning: two different HID descriptors retrieved (Reportlen = %d vs. %d)", rdlen1, rdlen2);
			}

			upsdebugx(2, "HID descriptor length %d", rdlen);

			if (rdlen > (int)sizeof(rdbuf)) {
				upsdebugx(2, "HID descriptor too long %d (max %d)", rdlen, (int)sizeof(rdbuf));
				goto next_device;
			}

			/* res = usb_get_descriptor(udev, USB_DT_REPORT, 0, bigbuf, rdlen); */
			res = usb_control_msg(udev, USB_ENDPOINT_IN+1, USB_REQ_GET_DESCRIPTOR,
				(USB_DT_REPORT << 8) + 0, 0, rdbuf, rdlen, USB_TIMEOUT);

			if (res < 0)
			{
				upsdebug_with_errno(2, "Unable to get Report descriptor");
				goto next_device;
			}

			if (res < rdlen)
			{
				upsdebugx(2, "Warning: report descriptor too short (expected %d, got %d)", rdlen, res);
				rdlen = res; /* correct rdlen if necessary */
			}

			res = callback(udev, curDevice, rdbuf, rdlen);
			if (res < 1) {
				upsdebugx(2, "Caller doesn't like this device");
				goto next_device;
			}

			upsdebugx(2, "Report descriptor retrieved (Reportlen = %d)", rdlen);
			upsdebugx(2, "Found HID device");
			fflush(stdout);

			return rdlen;

		next_device:
			usb_close(udev);
		}
	}

	*udevp = NULL;
	upsdebugx(2, "No appropriate HID device found");
	fflush(stdout);

	return -1;
}
Exemplo n.º 8
0
static int do_command(char type, const char *command, const char *parameters, char *response)
{
	char	buffer[SMALLBUF];
	int	count, ret;

	ser_flush_io(upsfd);

	if (response) {
		*response = '\0';
	}

	snprintf(buffer, sizeof(buffer), "~00%c%03d%s%s", type, (int)(strlen(command) + strlen(parameters)), command, parameters);

	ret = ser_send_pace(upsfd, 10000, "%s", buffer);
	if (ret <= 0) {
		upsdebug_with_errno(3, "do_command: send [%s]", buffer);
		return -1;
	}

	upsdebugx(3, "do_command: %d bytes sent [%s] -> OK", ret, buffer);

	ret = ser_get_buf_len(upsfd, (unsigned char *)buffer, 4, 3, 0);
	if (ret < 0) {
		upsdebug_with_errno(3, "do_command: read");
		return -1;
	}
	if (ret == 0) {
		upsdebugx(3, "do_command: read -> TIMEOUT");
		return -1;
	}

	buffer[ret] = '\0';
	upsdebugx(3, "do_command: %d byted read [%s]", ret, buffer);

	if (!strcmp(buffer, "~00D")) {

		ret = ser_get_buf_len(upsfd, (unsigned char *)buffer, 3, 3, 0);
		if (ret < 0) {
			upsdebug_with_errno(3, "do_command: read");
			return -1;
		}
		if (ret == 0) {
			upsdebugx(3, "do_command: read -> TIMEOUT");
			return -1;
		}

		buffer[ret] = '\0';
		upsdebugx(3, "do_command: %d bytes read [%s]", ret, buffer);

		count = atoi(buffer);
		if (count >= MAX_RESPONSE_LENGTH) {
			upsdebugx(3, "do_command: response exceeds expected size!");
			return -1;
		}

		if (count && !response) {
			upsdebugx(3, "do_command: response not expected!");
			return -1;
		}

		if (count == 0) {
			return 0;
		}

		ret = ser_get_buf_len(upsfd, (unsigned char *)response, count, 3, 0);
		if (ret < 0) {
			upsdebug_with_errno(3, "do_command: read");
			return -1;
		}
		if (ret == 0) {
			upsdebugx(3, "do_command: read -> TIMEOUT");
			return -1;
		}

		response[ret] = '\0';
		upsdebugx(3, "do_command: %d bytes read [%s]", ret, response);

		/* Tripp Lite pads their string responses with spaces.
		   I don't like that, so I remove them.  This is safe to
		   do with all responses for this protocol, so I just
		   do that here. */
		rtrim(response, ' ');

		return ret;
	}

	if (!strcmp(buffer, "~00A")) {
		return 0;
	}

	return -1;
}
Exemplo n.º 9
0
Arquivo: ivtscd.c Projeto: sbutler/nut
static int ivt_status(void)
{
	char	reply[SMALLBUF];
	int	ret, i, j = 0;

	ser_flush_io(upsfd);

	/*
	 * send: F\n
	 */
	ret = ser_send(upsfd, "F");

	if (ret < 0) {
		upsdebug_with_errno(3, "send");
		return -1;
	}

	if (ret == 0) {
		upsdebug_with_errno(3, "send: timeout");
		return -1;
	}

	upsdebugx(3, "send: F");
	sleep(1);	/* allow controller some time to digest this */
	
	/*
	 * read: R:12,57;- 1,1;20;12,57;13,18;- 2,1; 1,5;\n
	 */
	ret = ser_get_buf(upsfd, reply, sizeof(reply), 1, 0);

	if (ret < 0) {
		upsdebug_with_errno(3, "read");
		return -1;
	}

	if (ret == 0) {
		upsdebugx(3, "read: timeout");
		return -1;
	}

	upsdebugx(3, "read: %.*s", (int)strcspn(reply, "\r\n"), reply);
	upsdebug_hex(4, "  \\_", reply, ret);

	for (i = 0; i < ret; i++) {
		switch(reply[i])
		{
		case ',':	/* convert ',' to '.' */
			reply[j++] = '.';
			break;
		case ' ':	/* skip over white space */
		case '\0':	/* skip over null characters */
			break;
		default:	/* leave the rest as is */
			reply[j++] = reply[i];
			break;
		}
	}

	reply[j++] = '\0';

	ret = sscanf(reply, "R:%f;%f;%f;%f;%f;%f;%f;", &battery.voltage.act, &battery.current.act, &battery.temperature,
					&battery.voltage.min, &battery.voltage.max, &battery.current.min, &battery.current.max);

	upsdebugx(3, "Parsed %d parameters from reply", ret);
	return ret;
}
Exemplo n.º 10
0
Arquivo: upsrw.c Projeto: AlexLov/nut
static void do_setvar(const char *varname, char *uin, const char *pass)
{
	char	newval[SMALLBUF], temp[SMALLBUF], user[SMALLBUF], *ptr;
	struct passwd	*pw;

	if (uin) {
		snprintf(user, sizeof(user), "%s", uin);
	} else {
		memset(user, '\0', sizeof(user));

		pw = getpwuid(getuid());

		if (pw) {
			printf("Username (%s): ", pw->pw_name);
		} else {
			printf("Username: "******"%s", __func__);
		}

		/* deal with that pesky newline */
		if (strlen(user) > 1) {
			user[strlen(user) - 1] = '\0';
		} else {
			if (!pw) {
				fatalx(EXIT_FAILURE, "No username available - even tried getpwuid");
			}

			snprintf(user, sizeof(user), "%s", pw->pw_name);
		}
	}

	/* leaks - use -p when running in valgrind */
	if (!pass) {
		pass = GETPASS("Password: "******"getpass failed");
		}
	}

	/* Check if varname is in VAR=VALUE form */
	if ((ptr = strchr(varname, '=')) != NULL) {
		*ptr++ = 0;
		snprintf(newval, sizeof(newval), "%s", ptr);
	} else {
		printf("Enter new value for %s: ", varname);
		fflush(stdout);
		if (fgets(newval, sizeof(newval), stdin) == NULL) {
			upsdebug_with_errno(LOG_INFO, "%s", __func__);
		}
		newval[strlen(newval) - 1] = '\0';
	}

	snprintf(temp, sizeof(temp), "USERNAME %s\n", user);

	if (upscli_sendline(ups, temp, strlen(temp)) < 0) {
		fatalx(EXIT_FAILURE, "Can't set username: %s", upscli_strerror(ups));
	}

	if (upscli_readline(ups, temp, sizeof(temp)) < 0) {

		if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) {
			fatalx(EXIT_FAILURE, "Set username failed due to an unknown command. You probably need to upgrade upsd.");
		}

		fatalx(EXIT_FAILURE, "Set username failed: %s", upscli_strerror(ups));
	}

	snprintf(temp, sizeof(temp), "PASSWORD %s\n", pass);

	if (upscli_sendline(ups, temp, strlen(temp)) < 0) {
		fatalx(EXIT_FAILURE, "Can't set password: %s", upscli_strerror(ups));
	}

	if (upscli_readline(ups, temp, sizeof(temp)) < 0) {
		fatalx(EXIT_FAILURE, "Set password failed: %s", upscli_strerror(ups));
	}

	/* no upsname means die */
	if (!upsname) {
		fatalx(EXIT_FAILURE, "Error: a UPS name must be specified (upsname[@hostname[:port]])");
	}

	/* old variable names are no longer supported */
	if (!strchr(varname, '.')) {
		fatalx(EXIT_FAILURE, "Error: old variable names are not supported");
	}

	do_set(varname, newval);
}