diff hid-usb-to-ir.c @ 0:c6e3b362f9cf v0.2

import
author Peter Meerwald <p.meerwald@bct-electronic.com>
date Thu, 03 Jan 2013 13:08:39 +0100
parents
children 95b8b8a0b2d0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hid-usb-to-ir.c	Thu Jan 03 13:08:39 2013 +0100
@@ -0,0 +1,280 @@
+/*
+ * Demo program for the Silabs IR Gesture USB Reference Design,
+ * http://www.silabs.com/products/sensors/Pages/HID-USB-to-IR-Reference-Design.aspx
+ *
+ * Reads the part number of the cp2112 bridge,
+ * http://www.silabs.com/products/interface/usbtouart/Pages/HID-USB-to-SMBus-Bridge.aspx,
+ * and the part/revision/sequencer version of the si1143 via SMBus/I2C,
+ * finally lets the four blue LEDs dance :).
+ *
+ * Copyright (c) 2012 Peter Meerwald, <pmeerw@pmeerw.net>
+ * Released under GPLv3 license, see http://www.gnu.org/licenses/gpl-3.0.html.
+ *
+ * Depends on the HID API multi-platform library, available from
+ * http://www.signal11.us/oss/hidapi/.
+ *
+ * Build with
+ *   gcc -Wall -g -o hid-usb-to-ir hid-usb-to-ir.c `pkg-config hidapi-hidraw --libs`
+ *
+ * May need root permission to access USB device (or appropriate udev rule).
+ *
+ * Based upon information from Silabs AN495 v0.2.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "hidapi/hidapi.h"
+
+#define SI114X_SLAVE_ADDR 0x5a
+#define SI114X_HWKEY 0x07
+#define SI114x_PART_ID 0x00
+#define SI114x_REV_ID 0x01
+#define SI114x_SEQ_ID 0x02
+
+#define CP2112_GETSET_GPIO_CONFIG 0x02
+#define CP2112_GET_GPIO 0x03
+#define CP2112_SET_GPIO 0x04
+#define CP2122_GET_VERSION_INFO 0x05
+#define CP2112_GETSET_SMBUS_CONFIG 0x06
+#define CP2112_DATA_WRITE_READ_REQ 0x11
+#define CP2112_DATA_READ_RESP 0x13
+#define CP2112_DATA_WRITE 0x14
+#define CP2112_TRANSFER_STATUS_REQ 0x15
+#define CP2112_TRANSFER_STATUS_RESP 0x16
+
+#define CP2112_LED_DOWN 0x01 /* LED DS2, GPIO 0 */
+#define CP2112_LED_UP 0x02 /* LED DS3, GPIO 1 */
+#define CP2112_LED_RIGHT 0x08 /* LED DS8, GPIO 3 */
+#define CP2112_LED_LEFT 0x80 /* LED DS4, GPIO 7 */
+#define CP2112_LEDS_MASK (CP2112_LED_DOWN | CP2112_LED_UP | \
+    CP2112_LED_RIGHT | CP2112_LED_LEFT)
+
+/* get cp2112 part number and version */
+static int cp2112_get_version(hid_device *hd, unsigned char data[2]) {
+	unsigned char buf[3] = { CP2122_GET_VERSION_INFO, };
+
+	int ret = hid_get_feature_report(hd, buf, sizeof(buf));
+	if (ret < 0) {
+		fprintf(stderr, "hid_get_feature_report() failed: %ls\n",
+			hid_error(hd));
+		return -1;
+	}
+
+	data[0] = buf[1]; /* part number */
+	data[1] = buf[2]; /* version */
+
+	return 0;
+}
+
+/* configures cp2112 to automatically send read data, see AN495 section 4.6 */
+static int cp2112_set_auto_send_read(hid_device *hd, int on_off) {
+	unsigned char buf[14] = { CP2112_GETSET_SMBUS_CONFIG, };
+	int ret = hid_get_feature_report(hd, buf, sizeof(buf));
+	if (ret < 0) {
+		fprintf(stderr, "hid_get_feature_report() failed: %ls\n",
+			hid_error(hd));
+		return -1;
+	}
+
+	buf[6] = on_off;
+
+	ret = hid_send_feature_report(hd, buf, sizeof(buf));
+	if (ret < 0) {
+		fprintf(stderr, "hid_send_feature_report() failed: %ls\n",
+			hid_error(hd));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* see if the cp2112 is idle */
+static int cp2112_is_idle(hid_device *hd) {
+	unsigned char status_req[2] = { CP2112_TRANSFER_STATUS_REQ, 0x01, };
+	if (hid_write(hd, status_req, sizeof(status_req)) < 0) {
+		fprintf(stderr, "hid_write() failed: %ls\n",
+			hid_error(hd));
+		return -1;
+	}
+
+	unsigned char status_resp[7] = { 0x00, };
+	if (hid_read(hd, status_resp, sizeof(status_resp)) < 0) {
+		fprintf(stderr, "hid_read() failed: %ls\n",
+			hid_error(hd));
+		return -1;
+	}
+
+	if (status_resp[0] == CP2112_TRANSFER_STATUS_RESP) {
+		if (status_resp[1] == 0x00) /* is idle? */
+			return 1;
+	}
+
+	return 0;
+}
+
+/* write a data byte to register reg of the si1143 */
+static int cp2112_write_byte(hid_device *hd, unsigned char reg, unsigned char data) {
+	/* 0x5a is the 7-bit SMBus slave address of the si1143 */
+	unsigned char buf_out[5] = { CP2112_DATA_WRITE, SI114X_SLAVE_ADDR<<1, 0x02, };
+	buf_out[3] = reg;
+	buf_out[4] = data;
+	int ret = hid_write(hd, buf_out, sizeof(buf_out));
+	if (ret < 0) {
+		fprintf(stderr, "hid_write() failed: %ls\n",
+			hid_error(hd));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* read a data byte from register reg of the si1143 */
+static int cp2112_read_byte(hid_device *hd, unsigned char reg, unsigned char data[1]) {
+	/* 0x5a is the 7-bit SMBus slave address of the si1143 */
+	unsigned char buf_out[6] = { CP2112_DATA_WRITE_READ_REQ,
+	    SI114X_SLAVE_ADDR<<1, 0x00, 0x01, 0x01, };
+	buf_out[5] = reg;
+	int ret = hid_write(hd, buf_out, sizeof(buf_out));
+	if (ret < 0) {
+		fprintf(stderr, "hid_write() failed: %ls\n",
+			hid_error(hd));
+		return -1;
+	}
+
+	/* FIXME: may loop forever, error handling needed */
+	while (1) {
+
+		unsigned char buf_in[8] = { 0x00, };
+		ret = hid_read(hd, buf_in, sizeof(buf_in));
+		if (ret < 0) {
+			fprintf(stderr, "hid_read_() failed: %ls\n",
+				hid_error(hd));
+			return -1;
+		}
+
+
+	        if (buf_in[0] == CP2112_TRANSFER_STATUS_REQ)
+			continue;
+
+		if (buf_in[0] == CP2112_DATA_READ_RESP) {
+			if (buf_in[1] == 0x02 &&  buf_in[2] == 0x00)
+				continue; /* no data yet */
+			if (buf_in[1] == 0x02 && buf_in[2] == 0x01) {
+				data[0] = buf_in[3]; /* data available */
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
+
+/* configure cp2112 GPIO pins */
+static int cp2112_config_gpio(hid_device *hd) {
+	unsigned char buf[5] = { CP2112_GETSET_GPIO_CONFIG, };
+	int ret = hid_get_feature_report(hd, buf, sizeof(buf));
+	if (ret < 0) {
+		fprintf(stderr, "hid_get_feature_report() failed: %ls\n",
+			hid_error(hd));
+		return -1;
+	}
+
+	buf[1] = 0x8b; /* output direction for GPIOs 0, 1, 3, 7 */
+	buf[2] = 0x8b; /* push-pull for GPIOs 0, 1, 3, 7 */
+	buf[3] = 0x00; /* no special functions, i.e. use pins as GPIO */
+
+	ret = hid_send_feature_report(hd, buf, sizeof(buf));
+	if (ret < 0) {
+		fprintf(stderr, "hid_send_feature_report() failed: %ls\n",
+			hid_error(hd));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* set cp2112 GPIO pins */
+static int cp2112_set_gpio(hid_device *hd, unsigned char mask, unsigned char value) {
+	unsigned char buf[3] = { CP2112_SET_GPIO, };
+
+	buf[1] = ~value; /* set GPIO pins: 0 .. turn LED on, 1 .. off */
+	buf[2] = mask; /* mask of pins to set, ignore others */
+
+	int ret = hid_send_feature_report(hd, buf, sizeof(buf));
+	if (ret < 0) {
+		fprintf(stderr, "hid_send_feature_report() failed: %ls\n",
+			hid_error(hd));
+		return -1;
+	}
+
+	return 0;
+}
+
+int main() {
+	if (hid_init() < 0) {
+		fprintf(stderr, "hid_init() failed, exit.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* open Silabs IR Gesture USB reference design by USB product:vendor id */
+	hid_device *hd = hid_open(0x10c4, 0xea90, NULL);
+	if (hd == NULL) {
+		fprintf(stderr, "hid_open() failed\n");
+		exit(EXIT_FAILURE);
+	}
+
+	unsigned char version_data[2];
+	if (cp2112_get_version(hd, version_data) < 0)
+		exit(EXIT_FAILURE);
+	printf("cp2112 part number 0x%02x, device version %d\n", 
+		version_data[0], version_data[1]);
+
+	if (cp2112_set_auto_send_read(hd, 1) < 0)
+		exit(EXIT_FAILURE);
+
+	/* write 0x17 to si114x HW_KEY register as per datasheet */
+	if (cp2112_write_byte(hd, SI114X_HWKEY, 0x17) < 0)
+		exit(EXIT_FAILURE);
+
+	unsigned char part, rev, seq;
+	if (cp2112_read_byte(hd, SI114x_PART_ID, &part) < 0)
+		exit(EXIT_FAILURE);
+
+	if (cp2112_read_byte(hd, SI114x_REV_ID, &rev) < 0)
+		exit(EXIT_FAILURE);
+
+	if (cp2112_read_byte(hd, SI114x_SEQ_ID, &seq) < 0)
+		exit(EXIT_FAILURE);
+	printf("si114x part number 0x%02x, revision 0x%02x, sequencer 0x%02x\n",
+		part, rev, seq);
+
+	cp2112_is_idle(hd);
+
+	if (cp2112_config_gpio(hd) < 0)
+		exit(EXIT_FAILURE);
+
+	while (1) {
+		if (cp2112_set_gpio(hd, CP2112_LEDS_MASK, CP2112_LED_DOWN) < 0)
+			exit(EXIT_FAILURE);
+		usleep(50*1000);
+		if (cp2112_set_gpio(hd, CP2112_LEDS_MASK, CP2112_LED_RIGHT) < 0)
+			exit(EXIT_FAILURE);
+		usleep(50*1000);
+		if (cp2112_set_gpio(hd, CP2112_LEDS_MASK, CP2112_LED_UP) < 0)
+			exit(EXIT_FAILURE);
+		usleep(50*1000);
+		if (cp2112_set_gpio(hd, CP2112_LEDS_MASK, CP2112_LED_LEFT) < 0)
+			exit(EXIT_FAILURE);
+		usleep(50*1000);
+	}
+
+	/* never get here */
+	printf("done\n");
+
+	hid_close(hd);
+	hid_exit();
+
+	return EXIT_SUCCESS;
+}

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.