USB HID Host on Linux : Based on SiLab C8051 Example Firmware, USBHIDtoUART

13 篇文章 0 订阅
4 篇文章 0 订阅

This post implementation the Linux host of SiLab 's C8051 firmwar example code : USBHIDtoUART, to complementary my previous post, the same stuff on Windows. 

The code be :

#include <linux/limits.h>

//#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <errno.h>
#include <stdint.h>
#include <limits.h>

#include <linux/types.h>
#include <linux/input.h>
#include <linux/hidraw.h>

#include <pthread.h>

#include <sys/select.h>

#include <byteswap.h>

#include <signal.h>

#define DEVICE_VENDOR_ID     (0x10C4)
#define DEVICE_PRODUCT_ID     (0x8468)
#define DEVICE_VERSION_NUMER    (0x0000)


#define HID_BUFFER_SIZE      (64)
#define OUT_DATA_SIZE      (60 + 1)

int g_is_leave_thread = 0;

int is_this_device(char *p_device_name, uint16_t vendor_id, uint16_t product_id)
{
 int i;
 int res;
 int haw_hid_file_desc;
 struct hidraw_devinfo info;

 char buf[HID_BUFFER_SIZE];

 haw_hid_file_desc = open(p_device_name, O_RDWR|O_NONBLOCK);

 if(-1 == haw_hid_file_desc)
 {
  printf("open %s error:: %s \r\n", p_device_name, strerror(errno));
  return 0;
 }/*if */

 memset(&info, 0x0, sizeof(info));
 memset(buf, 0x0, sizeof(buf));

 /* Get Raw Info */
 res = ioctl(haw_hid_file_desc, HIDIOCGRAWINFO, &info);


 if (res < 0) 
 {
  perror("HIDIOCGRAWINFO");
  return 0;
 } 
 else 
 {
  printf("Raw Info:\n");

  /*bustype number defined in linux/input.h*/
  printf("\tbustype: 0x%02x\n", info.bustype);
  printf("\tvendor id : 0x%04hx\r\n", info.vendor);
  printf("\tproduct id : 0x%04hx\r\n", info.product);
 }/*if */


 if( BUS_USB != info.bustype 
  || vendor_id != (uint16_t)info.vendor 
  || product_id != (uint16_t)info.product )
 {
  printf("ERROR : device %s is not march \r\n", p_device_name);
  printf("target vendor_id = 0x%04x, product_id = 0x%04x\r\n", 
   (uint16_t)vendor_id, (uint16_t)product_id);

  close(haw_hid_file_desc); haw_hid_file_desc = -1;
  return 0;
 }/*if */


 /* Get Raw Name */
 res = ioctl(haw_hid_file_desc, HIDIOCGRAWNAME(256), buf);
 if (res < 0)
  perror("HIDIOCGRAWNAME");
 else
  printf("Raw Name: %s\n", buf);

 /* Get Physical Location */
 res = ioctl(haw_hid_file_desc, HIDIOCGRAWPHYS(256), buf);
 if (res < 0)
  perror("HIDIOCGRAWPHYS");
 else
  printf("Raw HID Phyical Location: %s\n", buf);

 int desc_size;
 res = ioctl(haw_hid_file_desc, HIDIOCGRDESCSIZE, &desc_size);
 if (res < 0)
  perror("HIDIOCGRDESCSIZE");
 else
  printf("Report Descriptor Size: %d\n", desc_size);

 /* Get Report Descriptor */
 struct hidraw_report_descriptor rpt_desc;
 rpt_desc.size = desc_size;
 res = ioctl(haw_hid_file_desc, HIDIOCGRDESC, &rpt_desc);
 if (res < 0) {
  perror("HIDIOCGRDESC");
 } else {
  printf("Report Descriptor:\n");
  for (i = 0; i < rpt_desc.size; i++)
   printf("0x%02x ", (uint8_t)rpt_desc.value[i]);
  puts("\n");
 }

 /*dummy in C8051 USBHIDtoUART firmwire functions: Get_Report/Set_Report
  F3xx_USB0_InterruptServiceRoutine.c */

 /* Set_Report for HIDIOCSFEATURE*/
 /* Set_Report for HIDIOCGFEATURE*/

 close(haw_hid_file_desc); haw_hid_file_desc = -1;

 return 1;

}/*is_this_device*/



void *read_customed_hid_routine(void *args)
{
 char *p_device_name;
 int raw_hid_file_desc;

 p_device_name = (char*)args;
 if(NULL == p_device_name)
  pthread_exit((void *)-1);

 
 raw_hid_file_desc = open(p_device_name, O_RDONLY);

 if(-1 == raw_hid_file_desc)
  pthread_exit((void *)-2);


 while(1)
 {
  fd_set set;
  struct timeval timeout_value;

  ssize_t read_size;
  char buffer[HID_BUFFER_SIZE];

  int ret;
  int i;

  if(0 != g_is_leave_thread)
   break;

  memset(&buffer[0], 0, sizeof(buffer));

  FD_ZERO(&set);
  FD_SET(raw_hid_file_desc, &set);

  timeout_value.tv_usec = 0;
  timeout_value.tv_sec = 2;

  ret = select(raw_hid_file_desc + 1, &set, NULL, NULL, &timeout_value);

  if(-1 == ret)
  {
   printf("open select error:: %s \r\n", strerror(errno));
   continue;
  }
  else if(0 == ret)
  {
   //printf("timeout\r\n");
   continue;
  }/*if */
  
  read_size = read(raw_hid_file_desc, &buffer[0], sizeof(buffer) );

#define IN_DATA_SIZE   (60 + 1)
#define IN_DATA     (0x01)

  if( IN_DATA_SIZE != read_size)
   continue;

  if(IN_DATA != buffer[0])
   continue;
  
  for(i = 0; i < buffer[1]; i++){
   printf("%c", buffer[2 + i]);
  }/*for i*/

 }/*while*/

 close(raw_hid_file_desc);
 pthread_exit((void *)0);
}/*read_customed_hid_routine*/


void *write_customed_hid_routine(void *args)
{
 char *p_device_name;
 int raw_hid_file_desc;

 char str_for_sending[HID_BUFFER_SIZE];

 p_device_name = (char*)args;
 if(NULL == p_device_name)
  pthread_exit((void *)-1);

 
 raw_hid_file_desc = open(p_device_name, O_WRONLY);


 if(-1 == raw_hid_file_desc)
  pthread_exit((void *)-2);

 snprintf(&str_for_sending[0], HID_BUFFER_SIZE, 
  "I want to eat cat meat\r\n");

 while(1)
 {
  ssize_t written_size;
  char buffer[HID_BUFFER_SIZE];

  if(0 != g_is_leave_thread)
   break;

#define OUT_DATA_SIZE      (60 + 1)
#define OUT_DATA       (0x02)

  buffer[0] = OUT_DATA;
  buffer[1] = strlen(&str_for_sending[0]);
  memcpy(&buffer[2], &str_for_sending[0], strlen(&str_for_sending[0]));

  written_size = write(raw_hid_file_desc, &buffer[0], OUT_DATA_SIZE);

  usleep(2*1000*1000);
 }/*while*/

 close(raw_hid_file_desc);
 pthread_exit((void *)0);
}/*write_customed_hid_routine*/


void interrupt_handler(int sig)
{
 g_is_leave_thread = 1;
}/*interrupt_handler*/


int main(int argc, char *argv[])
{
 int k;
 int haw_hid_file_desc;
 char device_name[PATH_MAX];

 unsigned int baudrate;

 pthread_t read_customed_hid_thread, write_customed_hid_thread;
 int thread_ret;

 signal(SIGINT, interrupt_handler); 

 baudrate = UINT_MAX;
 snprintf(&device_name[0], PATH_MAX, "/dev/hidraw0");


 k = 0;
 while(k < argc)
 {
  if(0 == strncmp(argv[k], "-d", strlen("-d")))
  {
   if(k + 1 < argc)
   {
    snprintf(&device_name[0], PATH_MAX, "%s", argv[k + 1]);
   }
   else
   {
    printf("ERROR : -d should be followed by"
     " raw hid device (/dev/hidrawXX)\r\n");
    return 1;
   }/*if */
  }/*if*/

  if(0 == strncmp(argv[k], "-baudrate", strlen("-baudrate")))
  {
   if(k + 1 < argc)
   {
    char *p_end;
    baudrate = strtol(argv[k + 1], &p_end, 10);
   }
   else
   {
    printf("ERROR : -baudrate should be followed by "
     "baudrate value\r\n");
    return 1;
   }/*if */
  }/*if*/

  k++;
 }/*while*/

 printf("raw hid device : %s\r\n", &device_name[0]);

 if(UINT_MAX != baudrate)
  printf("baud rate will be set as %u\r\n", baudrate);

 if(0 == is_this_device(&device_name[0], DEVICE_VENDOR_ID, DEVICE_PRODUCT_ID))
 {
  return 1;
 }

 if(UINT_MAX != baudrate)
 {
  int haw_hid_file_desc;
  uint8_t buffer[HID_BUFFER_SIZE];


  haw_hid_file_desc = open(&device_name[0], O_WRONLY);

  if(-1 == haw_hid_file_desc)
   return -1;

#define OUT_CONTROL     (0xFD)
  buffer[0] = OUT_CONTROL;
  baudrate = bswap_32(baudrate);
  memcpy(&buffer[1], &baudrate, sizeof(unsigned int));

  if(OUT_DATA_SIZE != write(haw_hid_file_desc, &buffer[0], OUT_DATA_SIZE))
  {
   printf("write error:: %s \r\n", strerror(errno));
  }/*if */

  close(haw_hid_file_desc); haw_hid_file_desc = -1;
 }/*UINT_MAX != baudrate*/


 g_is_leave_thread = 0;

 pthread_create(&read_customed_hid_thread, NULL, 
  read_customed_hid_routine, (void*)&device_name[0]);

 pthread_create(&write_customed_hid_thread, NULL, 
  write_customed_hid_routine, (void*)&device_name[0]);


 pthread_join(write_customed_hid_thread, (void**)&thread_ret);
 pthread_join(read_customed_hid_thread, (void**)&thread_ret);

 return 0;
}/*main*/

 

 

The correspondent Makefile be :

all:
 gcc main.c -lpthread -o c8051hid_to_uart_example_host
clean:
 rm -rf c8051hid_to_uart_example_host

The argument are:

 

  -baudrate baudrate_value : as the same, to setting the baudrate.

 -d device_location : to specify which device would be operated. by default, the customed hid device would be /dev/hidrawX (X is a number, for example, /dev/hidraw0)

 

Result of running this binary is ommited, for it is pretty the same as Windows version.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103C8 Serial(UART) to USB HID Keyboard Mouse 串口 转 USB键盘鼠标 (1) 使用Composite Device 组合(复合)设备 (1.1) 1个Device -> 1个 Configuation -> 2个Interfance (Keyboard & Mouse) (1.2) Keyboard Interfance -> HID (boot mode) -> 2个Endpoint(IN_0x81 & OUT_0x01) -> KeyboardReportDescriptor(不使用Report ID) (1.3) Mouse Interfance -> HID (boot mode) -> 1个Endpoint(IN_0x82) -> MouseReportDescriptor(不使用Report ID) (1.4) 使用HID boot模式, 不使用Report ID, 以便兼容在 计算器设定BIOS模式 中的操作 (2) 串口接收 命令 (2.1) UART协议: 115200, n, 8, 1 (2.2) 1帧发送字符串格式, 以 '{'开始; '}'结束; ','分隔. 共9个10进制数字 例如: {1,2,3,4,5,6,7,8,9} (2.3) 第9位 区分 Keyboard(64) 或是 Mouse(128) 命令 例如: {0,0,0,0,0,0,0,0,64} --- 发送Keyboard命令 {0,0,0,0,0,0,0,0,128} --- 发送Keyboard命令 (3) 发送Keyboard键盘命令时 : 第1~8位 分别如下 (3.1) 第1位 : Key_Release = 0x00, Left_Control = 0x01, Left_Shift = 0x02, Left_Alt = 0x04, Left_GUI = 0x08, Right_Control = 0x10, Right_Shift = 0x20, Right_Alt = 0x40, Right_GUI = 0x80, 例如: {8,0,0,0,0,0,0,0,64} --- 发送 Win_Key键 {128,0,0,0,0,0,0,0,64} --- 发送 WinApp_Key键 {32,0,0,0,0,0,0,0,64} --- 发送 右Shift键 (3.2) 第2位 : 保留,不使用,一律填0 (3.3) 第3~8位 : 可以同时发送6个Keyboard按键 例如: {0,0,4,5,6,7,8,9,64} --- 发送 'abcdef'键 {2,0,4,5,6,7,8,9,64} --- 按住 左Shift 发送 'abcdef'键 => 'ABCDEF' {0,0,0,5,0,7,0,9,64} --- 发送 'bdf'键 (0表示 无按键) 按键码 可参阅: (HID Usage ID) http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf https://www.hiemalis.org/~keiji/PC/scancode-translate.pdf https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2 http://www.usb.org/developers/hidpage/Hut1_12v2.pdf (4) 发送Mouse鼠标命令时 : 第1~8位 分别如下 (4.1) 第1位 : Button_Release = 0x00, Left_Button = 0x01, Right_Button = 0x02, Mid_Button = 0x04, 例如: {1,0,0,0,0,0,0,0,128} --- 点击 左键 {2,0,0,0,0,0,0,0,128} --- 点击 右键 {4,0,0,0,0,0,0,0,128} --- 点击 中键 (4.2) 第2~4位 : 移动(X,Y), 滚轮(Wheel) X: -127~127:左右移动鼠标 Y: -127~127:上下移动鼠标 Wheel: -127~127:上下转动滚轮 例如: {0,20,-10,0,0,0,0,0,128} --- 鼠标 右移20,上移10 {0,0,0,-30,0,0,0,0,128} --- 滚轮-30 (4.2) 第5~8位 : 保留,不使用,一律填0

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值