跳转至

HID示例说明*

1. 概述*

vsp工程支持使用HID,本文描述了HID在vsp中的使用方法;本示例中的HID通信是裸数据通信,用户可以根据自己的需求选择不同的HID协议;

2. HID上位机端*

用于测试GX8008C与PC之间的HID上下通信的程序,上位机的程序是基于linux平台的;代码路径在"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. 下位机端测试程序*

下位机端是GX8008C;以下是GX8008C测试代码已包含在vsp_sdk中,路径为 "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. 测试示例步骤*

4.1 下位机GX8008C准备*

  • a. 下载vsp_sdk,打开终端进入sdk目录。
  • b. 将"configs/nationalchip_public_version/8008c_wukong_prime_1v4_hid_demo.config"拷贝到.config
  • c. 执行make menuconfig,然后退出保存。
  • d. 执行make clean;make
  • e. 编译完成之后将固件烧录到GX8008C中,然后上电
  • d. 上电之后可通过ls /dev/hidraw*查看设备的具体设备号

注意

以上的下载sdk以及编译烧录具体操作请看环境搭建和编译烧录

4.2 上位机PC端准备*

  • a. 打开终端,进入vsp_sdk目录下"vsp/tools/hid_host_compter"
  • b. 执行make,生成hid_example;默认是测试发送与接收,可根据自己的需求修改测试模式,再执行make。
  • c. 执行./hid-example /dev/hidraw*,具体设备号参考4.1。
  • d. 执行成功之后即可收到hid互发的数据