#include #include #include #include #include #include #include #include #include #include #define PRINT_FIELD(field) printf(#field ": %04x\n", field) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define READ_BUFFER_LENGTH 64 struct msg { int direction; unsigned char data[64]; }; enum direction { IN = 666, OUT, }; static int is_printable(const unsigned char c) { return c >= 0x20 && c < 0x80; } static int datalen(const unsigned char *data) { int i, len; for (i = 0, len = 0; i < 64; i++) if (data[i]) len = i; return len + 1; } static void print_hex(const unsigned char *data, int len) { int i; for (i = 0; i < len; i++) printf("0x%02x ", data[i]); printf("\n"); } static void print_ascii(const unsigned char *data, int len) { int i; for (i = 0; i < len; i++) printf("%c", is_printable(data[i]) ? data[i] : '.'); printf("\n"); } int hid_read(unsigned char *data, int bufsize, int fd) { struct hiddev_event readBuffer[READ_BUFFER_LENGTH]; int ret, n, i; ret = read(fd, readBuffer, sizeof(readBuffer)); if (ret < 0) return ret; n = ret / sizeof(readBuffer[0]); for (i = 0; i < n && i < bufsize; i++) data[i] = readBuffer[i].value; return n; } int hid_write(const unsigned char data[64], int fd , int usage_code) { int rc = 0, uindex, error; struct hiddev_usage_ref uref; struct hiddev_report_info rinfo; uref.report_id = *data++; uref.report_type = HID_REPORT_TYPE_OUTPUT; uref.field_index = 0; uref.usage_code = usage_code; for (uindex = 0; uindex < 63; uindex++) { uref.usage_index = uindex; uref.value = *data++; rc = ioctl(fd, HIDIOCSUSAGE, &uref); if (rc != 0) goto err; } rinfo.report_type = HID_REPORT_TYPE_OUTPUT; rinfo.report_id = 0x0; rinfo.num_fields = 1; rc = ioctl(fd, HIDIOCSREPORT, &rinfo); if (rc != 0) goto err2; return 0; err2: printf("HIDIOCSREPORT\n"); err: error = errno; printf("Error in IOCTL: %s\n", strerror(error)); return rc; } int get_usagecode(int fd) { struct hiddev_usage_ref uref; int rc, error; uref.report_type = HID_REPORT_TYPE_OUTPUT; uref.report_id = 0x0; uref.field_index = 0; uref.usage_index = 0; rc = ioctl(fd, HIDIOCGUCODE, &uref); if (rc < 0) { error = errno; printf("Error gettin usage code: %s\n", strerror(error)); return rc; } return uref.usage_code; } int hiddev_open(const char *device_path, int *usage_code) { struct hiddev_devinfo device_info; struct hiddev_report_info rinfo; int ret, error; int fd; fd = ret = open(device_path, O_RDWR); if (fd < 0) goto err; rinfo.report_type = HID_REPORT_TYPE_OUTPUT; rinfo.report_id = HID_REPORT_ID_FIRST; ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo); if (ret < 0) goto err; PRINT_FIELD(rinfo.report_type); PRINT_FIELD(rinfo.report_id); PRINT_FIELD(rinfo.num_fields); *usage_code = get_usagecode(fd); if (*usage_code < 0) return -8; ret = ioctl(fd, HIDIOCGDEVINFO, &device_info); if (ret < 0) goto err; PRINT_FIELD(device_info.bustype); PRINT_FIELD(device_info.busnum); PRINT_FIELD(device_info.devnum); PRINT_FIELD(device_info.ifnum); PRINT_FIELD(device_info.vendor); PRINT_FIELD(device_info.product); PRINT_FIELD(device_info.version); PRINT_FIELD(device_info.num_applications); return fd; err: error = errno; printf("Error opening device %s: %s\n", device_path, strerror(error)); return ret; } int send_msg(const struct msg *msg, int fd, int usage_code) { int ret; if (msg->direction != OUT) { printf("Message direction is not OUT\n"); exit(1); } usleep(1000 * 1000); printf("Sending: "); print_hex(msg->data + 1, datalen(msg->data) - 1); print_ascii(msg->data + 1, datalen(msg->data) - 1); ret = hid_write(msg->data, fd, usage_code); if (ret) exit(1); return 0; } int read_and_verify(struct msg *msg, int fd) { unsigned char buf[64]; int ret, offset = 0; while (offset < 64) { ret = hid_read(buf + offset, sizeof(buf) - offset, fd); if (ret < 0) goto err; offset += ret; } memcpy(msg->data, buf, sizeof(buf)); printf("Got data %d: ", datalen(buf)); // print_hex(buf, datalen(buf)); print_ascii(buf, datalen(buf)); err: return 0; } int read_msgs(int fd) { struct msg msg; while (1) { read_and_verify(&msg, fd); if (datalen(msg.data) <= 36) break; } return 0; } #define SET_FIRST_BYTE(byte) \ do { \ memset(&msg.data, 0, sizeof(msg.data)); \ msg.data[4] = (byte); \ j = 5; \ } while (0) #define SET_BYTE(idx, byte) \ do { \ msg.data[(idx) + 4] = (byte); \ j = (idx) + 1; \ } while (0) #define SET_BYTES(byte) msg.data[j++] = (byte) int send_pattern(int fd, int uc, unsigned char byte1, unsigned char byte2) { int j; struct msg msg; msg.direction = OUT; SET_FIRST_BYTE(0x01); SET_BYTES(0x04); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 0x15); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 0x05); send_msg(&msg, fd, uc); read_msgs(fd); SET_FIRST_BYTE(0x02); SET_BYTES(byte1); SET_BYTES('|'); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, byte2); send_msg(&msg, fd, uc); read_msgs(fd); return 0; } int communicate(int fd, int uc) { int i, j; struct msg msg, in; msg.direction = OUT; read_msgs(fd); SET_FIRST_BYTE(0x01); SET_BYTES(0x04); send_msg(&msg, fd, uc); usleep(100 * 1000); SET_BYTE(1, 0x06); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 0x15); for (i = 0; i < 6; i++) { send_msg(&msg, fd, uc); read_msgs(fd); } usleep(1000 * 1000); read_msgs(fd); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 0x05); send_msg(&msg, fd, uc); read_msgs(fd); send_pattern(fd, uc, 'R', 'A'); send_pattern(fd, uc, 'R', 'C'); send_pattern(fd, uc, 'R', 'D'); send_pattern(fd, uc, 'R', 'G'); send_pattern(fd, uc, 'R', 'I'); send_pattern(fd, uc, 'R', 'M'); send_pattern(fd, uc, 'R', 'P'); send_pattern(fd, uc, 'R', 'R'); send_pattern(fd, uc, 'R', 'S'); send_pattern(fd, uc, 'R', 'T'); send_pattern(fd, uc, 'R', 'U'); send_pattern(fd, uc, 'R', 'V'); send_pattern(fd, uc, 'R', 'W'); send_pattern(fd, uc, 'R', 'X'); send_pattern(fd, uc, 'W', 'K'); SET_FIRST_BYTE(0x08); SET_BYTES('O'); SET_BYTES('b'); SET_BYTES('p'); SET_BYTES('s'); SET_BYTES('e'); SET_BYTES('c'); SET_BYTES('3'); SET_BYTES('|'); send_msg(&msg, fd, uc); read_msgs(fd); SET_FIRST_BYTE(0x02); SET_BYTES('R'); SET_BYTES('|'); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 'Y'); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 'W'); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 'K'); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 'C'); send_msg(&msg, fd, uc); read_msgs(fd); send_pattern(fd, uc, 'R', 'Z'); SET_FIRST_BYTE(0x01); SET_BYTES(0x04); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 0x15); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 0x05); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 0x04); send_msg(&msg, fd, uc); read_msgs(fd); send_msg(&msg, fd, uc); read_msgs(fd); SET_BYTE(1, 0x06); send_msg(&msg, fd, uc); read_msgs(fd); send_msg(&msg, fd, uc); read_msgs(fd); send_msg(&msg, fd, uc); read_msgs(fd); do { send_msg(&msg, fd, uc); read_and_verify(&in, fd); } while (datalen(in.data) > 45); return 0; } int main(int argc, char *argv[]) { int fd, usage_code; fd = hiddev_open(argv[1], &usage_code); if (fd < 0) return 1; communicate(fd, usage_code); return 0; }