Skip to content

HID example description*

1. Overview*

The vsp project supports the use of HID. This article describes how to use HID in vsp; the HID communication in this example is bare data communication, and users can choose different HID protocols according to their needs;

2. HID host computer*

The program used to test the HID up and down communication between GX8008C and PC, the host computer program is based on the linux platform; the code path is in "vsp/tools/hid_host_compter/hid-example.c"

hid-example.c
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* Linux */
#include <linux/types.h>
#include <linux/input.h>
#include <linux/hidraw.h>

/*
 * Ugly hack to work around failing compilation on systems that don't
 * yet populate new version of hidraw.h to userspace.
 */
#ifndef HIDIOCSFEATURE
#warning Please have your distro update the userspace kernel headers
#define HIDIOCSFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
#define HIDIOCGFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
#endif

/* Unix */
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <sys/select.h>
#include <sys/time.h>


/* C */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

//#define TEST_READ             // 测试读
//#define TEST_WRITE            // 测试写
#define TEST_WRITE_AND_READ     // 测试读写

static int write_func(int fd, unsigned char *data, unsigned int size);

void my_sleep(int ms)           // 延时接口
{
    struct timeval delay;
    delay.tv_sec = 0;
    delay.tv_usec = ms * 1000; // 20 ms
    select(0, NULL, NULL, NULL, &delay);
}

#define MAX_PACKET_SIZE 64      // 最大数据包大小
int main(int argc, char **argv)
{
    unsigned char buf[MAX_PACKET_SIZE];
    char *device = "/dev/hidraw2";      // 默认设备为/dev/hidraw2,可根据实际设备传入参数
    int i, ret;
    int fd;

    if (argc > 1)
        device = argv[1];               // 有设备参数传入;没有传入的话默认为/dev/hidraw2

    /* Open the Device with non-blocking reads. In real life,
       don't use a hard coded path; use libudev instead. */
    fd = open(device, O_RDWR);
    if (fd < 0) {
        perror("Unable to open device");
        return 1;
    }

#ifdef TEST_READ                    // 接收测试
    while (1) {
        ret = read(fd, buf, sizeof(buf));
        if (ret < 0) {
            perror("read");
            break;
        } else {
            printf("read %d bytes : ", ret);
            for (i = 0; i < ret; i++)
                printf("%c ", buf[i]);
            puts("\n");
        }
    }
#endif

#ifdef TEST_WRITE                       // 发送测试
    memset(buf, 0x11, sizeof(buf));
    ret = write_func(fd, buf, sizeof(buf));
    if (ret != 0) {
        printf ("write failed, ret : %d\n", ret);
    }
#endif

#ifdef TEST_WRITE_AND_READ              // 接收与发送共同测试
    char *send_str = "hello hid";       // 发送数据为“hello hid”
    while (1) {
        ret = write_func(fd, send_str, strlen(send_str));
        if (ret != 0) {
            printf ("write failed, ret : %d\n", ret);
            break;
        }

        ret = read(fd, buf, sizeof(buf));
        puts(&buf[1]);
        if (ret != sizeof(buf)) {
            printf ("read failed, ret : %d\n", ret);
            break;
        }

        my_sleep(2000);
    }
#endif

    close(fd);
    return 0;
}

static int write_func(int fd, unsigned char *data, unsigned int size)       // hid下发接口
{
    unsigned char *buff;
    unsigned int send_len = size + 1;
    int ret;

    if (size == 0)
        return 0;

    buff = (unsigned char *)malloc(send_len);
    if (!buff) {
        printf ("malloc failed, size : %d\n", send_len);
        return -1;
    }

    buff[0] = 0xF2; // report ID
    memcpy(&buff[1], data, size);

    ret = write(fd, buff, send_len);
    if (ret != send_len) {
        printf ("write failed, except : %d, ret : %d\n", send_len, ret);
        return -1;
    }
    free (buff);

    return 0;
}

3. Lower computer test program*

The lower computer is GX8008C; the following is the GX8008C test code that has been included in vsp_sdk, and the path is "vsp/mcu/vsp/hook/vsp_hook_hid_demo.c"

vsp_hook_hid_demo.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "vsp_hook.h"
#include <driver/usb_gadget.h>
#include <driver/uac2_core.h>
#include <driver/delay.h>

#define LOG_TAG "[HOOK]"

//=================================================================================================
// Hook Event Process

# define HID_MAX_PACKET_SIZE 64
# define HID_RECV_REPORT_ID 0xF2
# define HID_SEND_REPORT_ID 0xF1
static int s_hid_handle;
int HookProcessInit(void)
{
    s_hid_handle = HidOpen();
    return 0;
}

int HookEventResponse(PLC_EVENT plc_event) { return 0;}

int HookProcessTick(void)
{
    unsigned char hid_send_buff[HID_MAX_PACKET_SIZE];
    unsigned char hid_recv_buff[HID_MAX_PACKET_SIZE];
    static unsigned int i = 0;
    int ret;

    memset (hid_recv_buff, 0, sizeof(hid_recv_buff));
    memset (hid_send_buff, 0, sizeof(hid_send_buff));

    // 对方可以发送小数据量进行测试
    ret = HidRead(s_hid_handle, hid_recv_buff, sizeof(hid_recv_buff));
    if (ret > 0) {
        // decoder report id
        if (hid_recv_buff[0] == HID_RECV_REPORT_ID) {
            printf ("received: [%s]; index: %d\n", &hid_recv_buff[1], i);
            sprintf (hid_send_buff, "xxxrecved : %s  index:%d", &hid_recv_buff[1], i);
            hid_send_buff[0] = HID_SEND_REPORT_ID;
            ret = HidWrite(s_hid_handle, hid_send_buff, sizeof(hid_send_buff));
            if (ret != sizeof(hid_send_buff)) {
                printf ("hid write ret : %d\n", ret);
            } else {
                printf ("send: [%s]; send repoot ID %d\n", &hid_send_buff[1], hid_send_buff[0]);
            }
        } else {
            printf("Failed! This demo need Report-ID: %d, but now is %d!\n", HID_RECV_REPORT_ID, hid_recv_buff[0]);
        }
        i++;
    }
    mdelay(1000);
    return 0;
}

4. Test example steps*

4.1 Lower computer GX8008C preparation*

  • a. Download vsp_sdk, open the terminal, and enter the sdk directory.
  • b. Copy "configs/nationalchip_public_version/8008c_wukong_prime_1v4_hid_demo.config" to .config.
  • c. Execute make menuconfig, then exit and save.
  • d. Execute make clean; make.
  • e. After compiling, burn the firmware into GX8008C, and then power on.
  • d. After power on, you can view the specific device number of the device through ls /dev/hidraw*.

Attention

Please refer to Environment Construction and Compilation and Burning for the specific operations of downloading SDK, compiling, and burning mentioned above.

4.2 Preparation on the PC End of the Host Computer*

  • a. Open the terminal and navigate to the vsp_sdk directory: "vsp/tools/hid_host_compter".
  • b. Run the command make to generate the hid_example executable. By default, it tests sending and receiving functionality, but you can modify the test mode according to your needs before running make again.
  • c. Execute ./hid-example /dev/hidraw* with the specific device number referred to in section 4.1.
  • d. After the execution is successful, you can receive the data sent by hid.