Android下获取HID数据的方式:
1.通过读取/dev/hidrawX设备节点 看名字就知道意思了(这个需要在编译的时候打开)
2.如果是标准HID设备,还可以通过/dev/input里的设备节点读取
这里的数据被转化为统一的结构,结构的定义在input.h中,值也在头文件中定义。几个结构体定义如下:
我们在event节点读取设备,所以格式就是input_event,单帧timeval时间数据结构长度加8字节数据。
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
#define EV_VERSION 0x010000
struct input_id {
__u16 bustype;
__u16 vendor;
__u16 product;
__u16 version;
};
struct input_absinfo {
__s32 value;
__s32 minimum;
__s32 maximum;
__s32 fuzz;
__s32 flat;
};
题外话:之前比较好奇USB设备为什么能将不同的设备的协议转化为相同的结构。得到的结果好像是可以将自己的协议解析告诉USB协议告诉系统,然后让系统按自己的协议进行解析。[…]
首先获取数据作为测试test.cpp。这里数据解析是绝对数据解析。
#include
#include
#include
#include
#include
#include
#include
#include
#define MOUSE_DEV_PATH "/dev/input/event1"
int x = 0;
int y = 0;
int main()
{
unsigned char data[sizeof(input_event)];
input_event dev_data;
int fd = open(MOUSE_DEV_PATH, O_RDONLY);
if (fd == -1)
{
printf("mouse device open fail\n");
return -1;
}
printf("open successful");
while (1)
{
int size = read (fd, (unsigned char*)data, sizeof(input_event));
printf("size:%d", size);
memcpy(&dev_data, data, sizeof(input_event));
if (dev_data.type == EV_REL)
{
if (dev_data.code == REL_X)
{
x += dev_data.value;
if (x < 0) x = 0;
printf("rel X:%d", dev_data.value);
}
else if(dev_data.code == REL_Y)
{
printf("rel Y:%d", dev_data.value);
y += dev_data.value;
if (y < 0) y = 0;
}
printf("\nx=%d,y=%d\n", x, y);
}
printf("\n");
for (int i = 0; i < size; ++i)
printf(" %3d", data[i]);
printf("\n");
}
close(fd);
}
Android.mk
MY_LOCAL_PATH:=$(call my-dir)
LOCAL_PATH:=$(MY_LOCAL_PATH)
MY_LOCAL_ANDSRC:=/home/Android7.1.1
include $(CLEAR_VARS)
LOCAL_MODULE:=mytest
LOCAL_SRC_FILES:=test.cpp
include $(BUILD_EXECUTABLE)
event的设备号会因插入顺序而不同,所以需要自动获得设备。
可以通过查看:
cat /proc/bus/input/devices
可以得到对应的vid和pid对应的event
I: Bus=0003 Vendor=17ef Product=6019 Version=0111
N: Name=" Mouse"
P: Phys=usb-fe3c0000.usb-1.7/input0
S: Sysfs=/devices/platform/fe3c0000.usb/usb2/2-1/2-1.7/2-1.7:1.0/0003:XXXX:XXXX.0001/input/input2
U: Uniq=
H: Handlers=event2 cpufreq
B: PROP=0
B: EV=17
B: KEY=70000 0 0 0 0
B: REL=103
B: MSC=10
一种解决思路是通过解析这个设备文件进行查找
也可也通过ioctl EVIOCGID来获得VID和PID,参考:https://blog.csdn.net/tankai19880619/article/details/38663709
这种方式很普通直接读写设备获得数据即可,然后按照协议的数据解析即可。
#include
#include
#include
#include
#include
#include
#include
#include
#define MOUSE_DEV_PATH "/dev/hidraw0"
unsigned char buffer[1000];
int main()
{
struct hidraw_devinfo info;
int fd = open(MOUSE_DEV_PATH, O_RDONLY);
if (fd == -1)
{
printf("mouse device open fail\n");
return -1;
}
int rc = ioctl(fd, HIDIOCGRAWINFO, &info);
if (rc < 0)
{
printf("readerror!\n");
return 1;
}
printf("HID device info %04x:%04x:%04x is\n", info.bustype,info.vendor, info.product);
unsigned char buff[96];
printf("open successful\n");
while (1)
{
int size = read(fd, buffer, 64);
printf("\nsize:%d\t", size);
for (int i = 0; i < size; ++i)
printf("%d ", buffer[i]);
printf("\n");
}
return 0;
}
如果没有hidraw设备节点,可参考这个:
https://blog.csdn.net/qq_33750826/article/details/78952249
hidraw的参考文档:https://www.kernel.org/doc/Documentation/hid/hidraw.txt
获取设别节点的VID和PID可以通过ioctl查询HIDIOCGRAWINFO获得。
结构体定义在hidraw.h中
修改编译后的uevent.rc文件。文件位置在 out/target/product/XXXXXXX/root 路径下
增加:
/dev/hidraw* 0666 root root
这样默认是把hidraw*的所有权限都改成0666了。然后在进行打包成镜像。
如果要在源码里修改配置信息可参考:
https://www.jb51.net/article/73073.htm
其实应该还有种方法是在源码创建hidraw的节点时的权限。
这种方法是。写一个监听服务,可以轮询查看插上的hid设备。根据hid的PID和VID修改权限。
然后把服务设置成开机启动
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEV_BASE_PATH "/dev/hidraw"
#define MAX_SUPPORT_DEV 20
#define PRODUCT_VID
#define PRODUCT_PID
int main()
{
int fd;
struct hidraw_devinfo info;
char path[20];
struct stat buf;
while (1)
{
for (int i = 0; i < MAX_SUPPORT_DEV; ++i)
{
sprintf(path, "%s%d", DEV_BASE_PATH, i);
stat(path, &buf);
if (!(buf.st_mode & S_IROTH))
{
if((fd = open(path, O_RDONLY)) < 0)
continue;
int rc = ioctl(fd, HIDIOCGRAWINFO, &info);
if (rc < 0)
continue;
if ((info.vendor == PRODUCT_VID) && (info.product == PRODUCT_PID))
{
fchmod(fd,0666);
close(fd);
break;
}
}
}
sleep(3);
}
return 0;
}