Mercurial > hg > hid-usb-to-ir
comparison 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 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:c6e3b362f9cf |
|---|---|
| 1 /* | |
| 2 * Demo program for the Silabs IR Gesture USB Reference Design, | |
| 3 * http://www.silabs.com/products/sensors/Pages/HID-USB-to-IR-Reference-Design.aspx | |
| 4 * | |
| 5 * Reads the part number of the cp2112 bridge, | |
| 6 * http://www.silabs.com/products/interface/usbtouart/Pages/HID-USB-to-SMBus-Bridge.aspx, | |
| 7 * and the part/revision/sequencer version of the si1143 via SMBus/I2C, | |
| 8 * finally lets the four blue LEDs dance :). | |
| 9 * | |
| 10 * Copyright (c) 2012 Peter Meerwald, <pmeerw@pmeerw.net> | |
| 11 * Released under GPLv3 license, see http://www.gnu.org/licenses/gpl-3.0.html. | |
| 12 * | |
| 13 * Depends on the HID API multi-platform library, available from | |
| 14 * http://www.signal11.us/oss/hidapi/. | |
| 15 * | |
| 16 * Build with | |
| 17 * gcc -Wall -g -o hid-usb-to-ir hid-usb-to-ir.c `pkg-config hidapi-hidraw --libs` | |
| 18 * | |
| 19 * May need root permission to access USB device (or appropriate udev rule). | |
| 20 * | |
| 21 * Based upon information from Silabs AN495 v0.2. | |
| 22 */ | |
| 23 | |
| 24 #include <stdio.h> | |
| 25 #include <stdlib.h> | |
| 26 #include <string.h> | |
| 27 #include <unistd.h> | |
| 28 #include "hidapi/hidapi.h" | |
| 29 | |
| 30 #define SI114X_SLAVE_ADDR 0x5a | |
| 31 #define SI114X_HWKEY 0x07 | |
| 32 #define SI114x_PART_ID 0x00 | |
| 33 #define SI114x_REV_ID 0x01 | |
| 34 #define SI114x_SEQ_ID 0x02 | |
| 35 | |
| 36 #define CP2112_GETSET_GPIO_CONFIG 0x02 | |
| 37 #define CP2112_GET_GPIO 0x03 | |
| 38 #define CP2112_SET_GPIO 0x04 | |
| 39 #define CP2122_GET_VERSION_INFO 0x05 | |
| 40 #define CP2112_GETSET_SMBUS_CONFIG 0x06 | |
| 41 #define CP2112_DATA_WRITE_READ_REQ 0x11 | |
| 42 #define CP2112_DATA_READ_RESP 0x13 | |
| 43 #define CP2112_DATA_WRITE 0x14 | |
| 44 #define CP2112_TRANSFER_STATUS_REQ 0x15 | |
| 45 #define CP2112_TRANSFER_STATUS_RESP 0x16 | |
| 46 | |
| 47 #define CP2112_LED_DOWN 0x01 /* LED DS2, GPIO 0 */ | |
| 48 #define CP2112_LED_UP 0x02 /* LED DS3, GPIO 1 */ | |
| 49 #define CP2112_LED_RIGHT 0x08 /* LED DS8, GPIO 3 */ | |
| 50 #define CP2112_LED_LEFT 0x80 /* LED DS4, GPIO 7 */ | |
| 51 #define CP2112_LEDS_MASK (CP2112_LED_DOWN | CP2112_LED_UP | \ | |
| 52 CP2112_LED_RIGHT | CP2112_LED_LEFT) | |
| 53 | |
| 54 /* get cp2112 part number and version */ | |
| 55 static int cp2112_get_version(hid_device *hd, unsigned char data[2]) { | |
| 56 unsigned char buf[3] = { CP2122_GET_VERSION_INFO, }; | |
| 57 | |
| 58 int ret = hid_get_feature_report(hd, buf, sizeof(buf)); | |
| 59 if (ret < 0) { | |
| 60 fprintf(stderr, "hid_get_feature_report() failed: %ls\n", | |
| 61 hid_error(hd)); | |
| 62 return -1; | |
| 63 } | |
| 64 | |
| 65 data[0] = buf[1]; /* part number */ | |
| 66 data[1] = buf[2]; /* version */ | |
| 67 | |
| 68 return 0; | |
| 69 } | |
| 70 | |
| 71 /* configures cp2112 to automatically send read data, see AN495 section 4.6 */ | |
| 72 static int cp2112_set_auto_send_read(hid_device *hd, int on_off) { | |
| 73 unsigned char buf[14] = { CP2112_GETSET_SMBUS_CONFIG, }; | |
| 74 int ret = hid_get_feature_report(hd, buf, sizeof(buf)); | |
| 75 if (ret < 0) { | |
| 76 fprintf(stderr, "hid_get_feature_report() failed: %ls\n", | |
| 77 hid_error(hd)); | |
| 78 return -1; | |
| 79 } | |
| 80 | |
| 81 buf[6] = on_off; | |
| 82 | |
| 83 ret = hid_send_feature_report(hd, buf, sizeof(buf)); | |
| 84 if (ret < 0) { | |
| 85 fprintf(stderr, "hid_send_feature_report() failed: %ls\n", | |
| 86 hid_error(hd)); | |
| 87 return -1; | |
| 88 } | |
| 89 | |
| 90 return 0; | |
| 91 } | |
| 92 | |
| 93 /* see if the cp2112 is idle */ | |
| 94 static int cp2112_is_idle(hid_device *hd) { | |
| 95 unsigned char status_req[2] = { CP2112_TRANSFER_STATUS_REQ, 0x01, }; | |
| 96 if (hid_write(hd, status_req, sizeof(status_req)) < 0) { | |
| 97 fprintf(stderr, "hid_write() failed: %ls\n", | |
| 98 hid_error(hd)); | |
| 99 return -1; | |
| 100 } | |
| 101 | |
| 102 unsigned char status_resp[7] = { 0x00, }; | |
| 103 if (hid_read(hd, status_resp, sizeof(status_resp)) < 0) { | |
| 104 fprintf(stderr, "hid_read() failed: %ls\n", | |
| 105 hid_error(hd)); | |
| 106 return -1; | |
| 107 } | |
| 108 | |
| 109 if (status_resp[0] == CP2112_TRANSFER_STATUS_RESP) { | |
| 110 if (status_resp[1] == 0x00) /* is idle? */ | |
| 111 return 1; | |
| 112 } | |
| 113 | |
| 114 return 0; | |
| 115 } | |
| 116 | |
| 117 /* write a data byte to register reg of the si1143 */ | |
| 118 static int cp2112_write_byte(hid_device *hd, unsigned char reg, unsigned char data) { | |
| 119 /* 0x5a is the 7-bit SMBus slave address of the si1143 */ | |
| 120 unsigned char buf_out[5] = { CP2112_DATA_WRITE, SI114X_SLAVE_ADDR<<1, 0x02, }; | |
| 121 buf_out[3] = reg; | |
| 122 buf_out[4] = data; | |
| 123 int ret = hid_write(hd, buf_out, sizeof(buf_out)); | |
| 124 if (ret < 0) { | |
| 125 fprintf(stderr, "hid_write() failed: %ls\n", | |
| 126 hid_error(hd)); | |
| 127 return -1; | |
| 128 } | |
| 129 | |
| 130 return 0; | |
| 131 } | |
| 132 | |
| 133 /* read a data byte from register reg of the si1143 */ | |
| 134 static int cp2112_read_byte(hid_device *hd, unsigned char reg, unsigned char data[1]) { | |
| 135 /* 0x5a is the 7-bit SMBus slave address of the si1143 */ | |
| 136 unsigned char buf_out[6] = { CP2112_DATA_WRITE_READ_REQ, | |
| 137 SI114X_SLAVE_ADDR<<1, 0x00, 0x01, 0x01, }; | |
| 138 buf_out[5] = reg; | |
| 139 int ret = hid_write(hd, buf_out, sizeof(buf_out)); | |
| 140 if (ret < 0) { | |
| 141 fprintf(stderr, "hid_write() failed: %ls\n", | |
| 142 hid_error(hd)); | |
| 143 return -1; | |
| 144 } | |
| 145 | |
| 146 /* FIXME: may loop forever, error handling needed */ | |
| 147 while (1) { | |
| 148 | |
| 149 unsigned char buf_in[8] = { 0x00, }; | |
| 150 ret = hid_read(hd, buf_in, sizeof(buf_in)); | |
| 151 if (ret < 0) { | |
| 152 fprintf(stderr, "hid_read_() failed: %ls\n", | |
| 153 hid_error(hd)); | |
| 154 return -1; | |
| 155 } | |
| 156 | |
| 157 | |
| 158 if (buf_in[0] == CP2112_TRANSFER_STATUS_REQ) | |
| 159 continue; | |
| 160 | |
| 161 if (buf_in[0] == CP2112_DATA_READ_RESP) { | |
| 162 if (buf_in[1] == 0x02 && buf_in[2] == 0x00) | |
| 163 continue; /* no data yet */ | |
| 164 if (buf_in[1] == 0x02 && buf_in[2] == 0x01) { | |
| 165 data[0] = buf_in[3]; /* data available */ | |
| 166 return 0; | |
| 167 } | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 return -1; | |
| 172 } | |
| 173 | |
| 174 /* configure cp2112 GPIO pins */ | |
| 175 static int cp2112_config_gpio(hid_device *hd) { | |
| 176 unsigned char buf[5] = { CP2112_GETSET_GPIO_CONFIG, }; | |
| 177 int ret = hid_get_feature_report(hd, buf, sizeof(buf)); | |
| 178 if (ret < 0) { | |
| 179 fprintf(stderr, "hid_get_feature_report() failed: %ls\n", | |
| 180 hid_error(hd)); | |
| 181 return -1; | |
| 182 } | |
| 183 | |
| 184 buf[1] = 0x8b; /* output direction for GPIOs 0, 1, 3, 7 */ | |
| 185 buf[2] = 0x8b; /* push-pull for GPIOs 0, 1, 3, 7 */ | |
| 186 buf[3] = 0x00; /* no special functions, i.e. use pins as GPIO */ | |
| 187 | |
| 188 ret = hid_send_feature_report(hd, buf, sizeof(buf)); | |
| 189 if (ret < 0) { | |
| 190 fprintf(stderr, "hid_send_feature_report() failed: %ls\n", | |
| 191 hid_error(hd)); | |
| 192 return -1; | |
| 193 } | |
| 194 | |
| 195 return 0; | |
| 196 } | |
| 197 | |
| 198 /* set cp2112 GPIO pins */ | |
| 199 static int cp2112_set_gpio(hid_device *hd, unsigned char mask, unsigned char value) { | |
| 200 unsigned char buf[3] = { CP2112_SET_GPIO, }; | |
| 201 | |
| 202 buf[1] = ~value; /* set GPIO pins: 0 .. turn LED on, 1 .. off */ | |
| 203 buf[2] = mask; /* mask of pins to set, ignore others */ | |
| 204 | |
| 205 int ret = hid_send_feature_report(hd, buf, sizeof(buf)); | |
| 206 if (ret < 0) { | |
| 207 fprintf(stderr, "hid_send_feature_report() failed: %ls\n", | |
| 208 hid_error(hd)); | |
| 209 return -1; | |
| 210 } | |
| 211 | |
| 212 return 0; | |
| 213 } | |
| 214 | |
| 215 int main() { | |
| 216 if (hid_init() < 0) { | |
| 217 fprintf(stderr, "hid_init() failed, exit.\n"); | |
| 218 exit(EXIT_FAILURE); | |
| 219 } | |
| 220 | |
| 221 /* open Silabs IR Gesture USB reference design by USB product:vendor id */ | |
| 222 hid_device *hd = hid_open(0x10c4, 0xea90, NULL); | |
| 223 if (hd == NULL) { | |
| 224 fprintf(stderr, "hid_open() failed\n"); | |
| 225 exit(EXIT_FAILURE); | |
| 226 } | |
| 227 | |
| 228 unsigned char version_data[2]; | |
| 229 if (cp2112_get_version(hd, version_data) < 0) | |
| 230 exit(EXIT_FAILURE); | |
| 231 printf("cp2112 part number 0x%02x, device version %d\n", | |
| 232 version_data[0], version_data[1]); | |
| 233 | |
| 234 if (cp2112_set_auto_send_read(hd, 1) < 0) | |
| 235 exit(EXIT_FAILURE); | |
| 236 | |
| 237 /* write 0x17 to si114x HW_KEY register as per datasheet */ | |
| 238 if (cp2112_write_byte(hd, SI114X_HWKEY, 0x17) < 0) | |
| 239 exit(EXIT_FAILURE); | |
| 240 | |
| 241 unsigned char part, rev, seq; | |
| 242 if (cp2112_read_byte(hd, SI114x_PART_ID, &part) < 0) | |
| 243 exit(EXIT_FAILURE); | |
| 244 | |
| 245 if (cp2112_read_byte(hd, SI114x_REV_ID, &rev) < 0) | |
| 246 exit(EXIT_FAILURE); | |
| 247 | |
| 248 if (cp2112_read_byte(hd, SI114x_SEQ_ID, &seq) < 0) | |
| 249 exit(EXIT_FAILURE); | |
| 250 printf("si114x part number 0x%02x, revision 0x%02x, sequencer 0x%02x\n", | |
| 251 part, rev, seq); | |
| 252 | |
| 253 cp2112_is_idle(hd); | |
| 254 | |
| 255 if (cp2112_config_gpio(hd) < 0) | |
| 256 exit(EXIT_FAILURE); | |
| 257 | |
| 258 while (1) { | |
| 259 if (cp2112_set_gpio(hd, CP2112_LEDS_MASK, CP2112_LED_DOWN) < 0) | |
| 260 exit(EXIT_FAILURE); | |
| 261 usleep(50*1000); | |
| 262 if (cp2112_set_gpio(hd, CP2112_LEDS_MASK, CP2112_LED_RIGHT) < 0) | |
| 263 exit(EXIT_FAILURE); | |
| 264 usleep(50*1000); | |
| 265 if (cp2112_set_gpio(hd, CP2112_LEDS_MASK, CP2112_LED_UP) < 0) | |
| 266 exit(EXIT_FAILURE); | |
| 267 usleep(50*1000); | |
| 268 if (cp2112_set_gpio(hd, CP2112_LEDS_MASK, CP2112_LED_LEFT) < 0) | |
| 269 exit(EXIT_FAILURE); | |
| 270 usleep(50*1000); | |
| 271 } | |
| 272 | |
| 273 /* never get here */ | |
| 274 printf("done\n"); | |
| 275 | |
| 276 hid_close(hd); | |
| 277 hid_exit(); | |
| 278 | |
| 279 return EXIT_SUCCESS; | |
| 280 } |
