USB HID裝置資料的讀取
阿新 • • 發佈:2019-02-12
USB裝置(HID)
Android下獲取HID資料的方式:
1.通過讀取/dev/hidrawX裝置節點 看名字就知道意思了(這個需要在編譯的時候開啟)
2.如果是標準HID裝置,還可以通過/dev/input裡的裝置節點讀取
方式一.通過input/event獲得資料
這裡的資料被轉化為統一的結構,結構的定義在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 <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <linux/input.h> #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); }
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
一種解決思路是通過解析這個裝置檔案進行查詢
方式二.通過hidraw節點獲得原生資料
這種方式很普通直接讀寫裝置獲得資料即可,然後按照協議的資料解析即可。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/input.h>
#include <linux/hidraw.h>
#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;
}
獲取設別節點的VID和PID可以通過ioctl查詢HIDIOCGRAWINFO獲得。
結構體定義在hidraw.h中
修改hidrawX裝置節點許可權的方法
1.修改uevent.rc檔案
修改編譯後的uevent.rc檔案。檔案位置在 out/target/product/XXXXXXX/root 路徑下
增加:
/dev/hidraw* 0666 root root
這樣預設是把hidraw*的所有許可權都改成0666了。然後在進行打包成映象。
2.修改原始碼
其實應該還有種方法是在原始碼建立hidraw的節點時的許可權。
3.監聽修改許可權服務
這種方法是。寫一個監聽服務,可以輪詢檢視插上的hid裝置。根據hid的PID和VID修改許可權。
然後把服務設定成開機啟動
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <linux/hidraw.h>
#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;
}