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