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 <zircon/device/input.h>
15#include <zircon/types.h>
16
17#define CLEAR_SCREEN printf("\033[2J")
18#define CURSOR_MOVE(r, c) printf("\033[%d;%dH", r, c)
19#define CLEAR_LINE printf("\033[2K")
20
21static void process_sensor_input(void* buf, size_t len) {
22    uint8_t* report = buf;
23    if (len < 1) {
24        printf("bad report size: %zd < %d\n", len, 1);
25        return;
26    }
27
28
29    uint8_t report_id = report[0];
30    CURSOR_MOVE(report_id + 1, 0);
31    CLEAR_LINE;
32
33    // TODO(teisenbe): Once we can decode these reports, output them decoded.
34    printf("%3d:", report_id);
35    for (size_t i = 1; i < len; ++i) {
36        printf(" %02x", report[i]);
37    }
38    printf("\n");
39    fflush(stdout);
40}
41
42int main(int argc, char* argv[]) {
43    if (argc != 2) {
44        printf("Usage: %s /dev/class/input/<id>\n", argv[0]);
45        return -1;
46    }
47
48    const char* devname = argv[1];
49    int fd = open(devname, O_RDONLY);
50    if (fd < 0) {
51        printf("failed to open %s: %d\n", devname, errno);
52        return -1;
53    }
54
55    size_t rpt_desc_len = 0;
56    uint8_t* rpt_desc = NULL;
57
58    ssize_t ret = ioctl_input_get_report_desc_size(fd, &rpt_desc_len);
59    if (ret < 0) {
60        printf("failed to get report descriptor length for %s: %zd\n", devname, ret);
61        return -1;
62    }
63
64    rpt_desc = malloc(rpt_desc_len);
65    if (rpt_desc == NULL) {
66        printf("no memory!\n");
67        return -1;
68    }
69
70    ret = ioctl_input_get_report_desc(fd, rpt_desc, rpt_desc_len);
71    if (ret < 0) {
72        printf("failed to get report descriptor for %s: %zd\n", devname, ret);
73        return -1;
74    }
75
76    assert(rpt_desc_len > 0);
77    assert(rpt_desc);
78
79    input_report_size_t max_rpt_sz = 0;
80    ret = ioctl_input_get_max_reportsize(fd, &max_rpt_sz);
81    if (ret < 0) {
82        printf("failed to get max report size: %zd\n", ret);
83        return -1;
84    }
85    void* buf = malloc(max_rpt_sz);
86    if (buf == NULL) {
87        printf("no memory!\n");
88        return -1;
89    }
90
91    CLEAR_SCREEN;
92    fflush(stdout);
93    while (1) {
94        ssize_t r = read(fd, buf, max_rpt_sz);
95        if (r < 0) {
96            printf("sensor read error: %zd (errno=%d)\n", r, errno);
97            break;
98        }
99
100        process_sensor_input(buf, r);
101    }
102
103    free(buf);
104    free(rpt_desc);
105    close(fd);
106    return 0;
107}
108