1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <assert.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <stdbool.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include <fuchsia/hardware/input/c/fidl.h>
15 #include <lib/fdio/unsafe.h>
16 #include <zircon/types.h>
17
18 #define CLEAR_SCREEN printf("\033[2J")
19 #define CURSOR_MOVE(r, c) printf("\033[%d;%dH", r, c)
20 #define CLEAR_LINE printf("\033[2K")
21
process_sensor_input(void * buf,size_t len)22 static void process_sensor_input(void* buf, size_t len) {
23 uint8_t* report = buf;
24 if (len < 1) {
25 printf("bad report size: %zd < %d\n", len, 1);
26 return;
27 }
28
29
30 uint8_t report_id = report[0];
31 CURSOR_MOVE(report_id + 1, 0);
32 CLEAR_LINE;
33
34 // TODO(teisenbe): Once we can decode these reports, output them decoded.
35 printf("%3d:", report_id);
36 for (size_t i = 1; i < len; ++i) {
37 printf(" %02x", report[i]);
38 }
39 printf("\n");
40 fflush(stdout);
41 }
42
main(int argc,char * argv[])43 int main(int argc, char* argv[]) {
44 if (argc != 2) {
45 printf("Usage: %s /dev/class/input/<id>\n", argv[0]);
46 return -1;
47 }
48
49 void* buf = NULL;
50 uint8_t* rpt_desc = NULL;
51 const char* devname = argv[1];
52 int fd = open(devname, O_RDONLY);
53 if (fd < 0) {
54 printf("failed to open %s: %d\n", devname, errno);
55 return -1;
56 }
57
58 fdio_t* io = fdio_unsafe_fd_to_io(fd);
59 if (io == NULL) {
60 printf("failed to convert fd\n");
61 return -1;
62 }
63 zx_handle_t svc = fdio_unsafe_borrow_channel(io);
64
65 int ret;
66 uint16_t rpt_desc_len = 0;
67
68 zx_status_t status = fuchsia_hardware_input_DeviceGetReportDescSize(svc, &rpt_desc_len);
69 if (status != ZX_OK) {
70 printf("failed to get report descriptor length for %s: %d\n", devname, status);
71 ret = -1;
72 goto cleanup;
73 }
74
75 rpt_desc = malloc(rpt_desc_len);
76 if (rpt_desc == NULL) {
77 printf("no memory!\n");
78 ret = -1;
79 goto cleanup;
80 }
81
82 size_t actual = 0;
83 status = fuchsia_hardware_input_DeviceGetReportDesc(svc, rpt_desc, rpt_desc_len, &actual);
84 if (status != ZX_OK) {
85 printf("failed to get report descriptor for %s: %d\n", devname, status);
86 ret = -1;
87 goto cleanup;
88 }
89
90 assert(rpt_desc_len > 0);
91 assert(rpt_desc_len == actual);
92 assert(rpt_desc);
93
94 uint16_t max_rpt_sz = 0;
95 status = fuchsia_hardware_input_DeviceGetMaxInputReportSize(svc, &max_rpt_sz);
96 if (status != ZX_OK) {
97 printf("failed to get max report size: %d\n", status);
98 ret = -1;
99 goto cleanup;
100 }
101 buf = malloc(max_rpt_sz);
102 if (buf == NULL) {
103 printf("no memory!\n");
104 ret = -1;
105 goto cleanup;
106 }
107
108 CLEAR_SCREEN;
109 fflush(stdout);
110 while (1) {
111 ssize_t r = read(fd, buf, max_rpt_sz);
112 if (r < 0) {
113 printf("sensor read error: %zd (errno=%d)\n", r, errno);
114 break;
115 }
116
117 process_sensor_input(buf, r);
118 }
119
120 ret = 0;
121 cleanup:
122 free(buf);
123 free(rpt_desc);
124 fdio_unsafe_release(io);
125 close(fd);
126 return ret;
127 }
128