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.