/********************************************************************************
*
* File Name : libusb-test.c
* Author : baoli
* Create Date : 2017.11.21
* Version : 1.0
* Description : libusb test
* compile command: gcc -o libusb libusb-test.c -lusb-1.0 -lpthread -lm
* History : 1. Data:
* Author:
* Modification:
*
********************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef unsigned char uchar;
typedef unsigned int uint;
#define VID 0x0471
#define PID 0x0999
#define BULK_RECV_EP 0x82
#define BULK_SEND_EP 0x02
#define INT_RECV_EP 0x81
#define INT_SEND_EP 0x01
#define SEND_BUFF_LEN 500
#define RECV_BUFF_LEN 500
#define BULK_TEST 1
#define INT_TEST 2
#define SAVE_FILE_PATH "libusb_test_recv_data"
sem_t print_sem; //信号量
FILE *g_file_stream = NULL;
int g_no_device_flag = ;
int g_file_save_en = ; //文件保存使能标志
int g_send_flag = ; //调用数据发送函数标志
uchar rev_buf[SEND_BUFF_LEN]; //usb 接收缓冲区
uchar send_buf[SEND_BUFF_LEN]; //usb发送缓冲区
libusb_device_handle *dev_handle;
char test_bytes[] =
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"
"abcdefghijklmnopqrstuvwxyz0123456789\n"; //37*15=555 bytes
int bulk_send(char *buf, int num);
int interrupt_send(char *buf, int num);
void *bulk_rev_thread(void *arg);
void *interrupt_rev_thread(void *arg);
int LIBUSB_CALL usb_event_callback(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data);
void help(void);
int str2hex(char *hex);
void hex2str(uchar *pbDest, uchar *pbSrc, ushort nLen);
void *usb_monitor_thread(void *arg);
int save_to_file(FILE *file_stream, uchar *data, int length);
void print_devs(libusb_device **devs);
int list_devices(void);
void print_endpoint(const struct libusb_endpoint_descriptor *endpoint);
void print_altsetting(const struct libusb_interface_descriptor *interface);
void print_interface(const struct libusb_interface *interface);
void print_configuration(struct libusb_config_descriptor *config);
void print_device(libusb_device *dev, struct libusb_device_descriptor *desc);
int print_descriptor(libusb_device *dev);
int get_descriptor_with_vid_pid(int vid, int pid);
void sigint_handler(int sig);
//采用bulk端点发送数据
int bulk_send(char *buf, int num)
{
int size;
int rec;
g\_send\_flag = ;
rec = libusb\_bulk\_transfer(dev\_handle, BULK\_SEND\_EP, buf, num, &size, );
if(rec == ) {
printf("bulk send sucess,length: %d bytes\\n", size);
sem\_post(&print\_sem);
}
else{
g\_send\_flag = ;
printf("bulk send faild, err: %s\\n", libusb\_error\_name(rec));
}
return ;
}
//采用interrupt端点发送数据
int interrupt_send(char *buf, int num)
{
int size;
int rec;
g\_send\_flag = ;
rec = libusb\_interrupt\_transfer(dev\_handle, INT\_SEND\_EP, buf, num, &size, );
if(rec == ) {
printf("interrupt send sucess, length: %d bytes\\n", size);
sem\_post(&print\_sem);
}
else{
g\_send\_flag = ;
printf("interrupt send faild, err: %s\\n", libusb\_error\_name(rec));
}
return ;
}
//bulk 端点接收线程
void *bulk_rev_thread(void *arg)
{
int i=;
int size;
int rec;
int save_bytes;
char hex_buf[RECV_BUFF_LEN*];
printf("bulk\_rev\_thread started.\\n");
while()
{
if(g\_no\_device\_flag){
usleep( \* );
continue;
}
memset(rev\_buf, , RECV\_BUFF\_LEN);
rec = libusb\_bulk\_transfer(dev\_handle, BULK\_RECV\_EP, rev\_buf, RECV\_BUFF\_LEN, &size, );
if(rec == )
{
if(g\_send\_flag == ) //考虑如果没有调用发送数据函数,接收到数据后调用sem\_wait会一直等待直到调用了bulk\_send,才会继续往下执行
{
g\_send\_flag = ;
sem\_wait(&print\_sem);
}
printf("\\nbulk ep rev sucess, length: %d bytes. \\n", size);
if(g\_file\_save\_en){
save\_bytes = save\_to\_file(g\_file\_stream, rev\_buf, size);
printf("save %d bytes to file.\\n", save\_bytes);
}
hex2str(hex\_buf, rev\_buf, size);
printf("data is: \\n%s\\n", rev\_buf);
printf("hex is: \\n%s\\n", hex\_buf);
}
else
{
printf("bulk ep rev faild, err: %s\\n", libusb\_error\_name(rec));
if(rec == LIBUSB\_ERROR\_IO)
g\_no\_device\_flag = ; //防止一直输出err
}
}
}
//interrupt 端点接收线程
void *interrupt_rev_thread(void *arg)
{
int i=;
int size;
int rec;
int save_bytes;
char hex_buf[RECV_BUFF_LEN*];
printf("interrupt\_rev\_thread started.\\n");
while()
{
if(g\_no\_device\_flag){
usleep( \* );
continue;
}
memset(rev\_buf, , RECV\_BUFF\_LEN);
rec = libusb\_interrupt\_transfer(dev\_handle, INT\_RECV\_EP, rev\_buf, RECV\_BUFF\_LEN, &size, );
if(rec == )
{
if(g\_send\_flag == ) //考虑如果没有调用发送数据函数,接收到数据后调用sem\_wait会一直等待直到调用了interrupt\_send,才会继续往下执行
{
g\_send\_flag = ;
sem\_wait(&print\_sem);
}
printf("\\ninterrupt ep rev sucess, length: %d bytes. \\n", size);
if(g\_file\_save\_en){
save\_bytes = save\_to\_file(g\_file\_stream, rev\_buf, size);
printf("save %d bytes to file.\\n", save\_bytes);
}
hex2str(hex\_buf, rev\_buf, size);
printf("data is: \\n%s\\n", rev\_buf);
printf("hex is: \\n%s\\n", hex\_buf);
}
else
{
printf("interrupt ep rev faild, err: %s\\n", libusb\_error\_name(rec));
if(rec == LIBUSB\_ERROR\_IO)
g\_no\_device\_flag = ; //防止一直输出err
}
}
}
//usb hotplugin callback function
int LIBUSB_CALL usb_event_callback(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
{
struct libusb_device_descriptor desc;
int r;
printf("\\nusb hotplugin event.\\n");
r = libusb\_get\_device\_descriptor(dev, &desc);
if (LIBUSB\_SUCCESS != r) {
printf("error getting device descriptor.\\n");
}
if (LIBUSB\_HOTPLUG\_EVENT\_DEVICE\_ARRIVED == event) {
printf("usb device attached: %04x:%04x\\n", desc.idVendor, desc.idProduct);
if (dev\_handle) {
libusb\_close(dev\_handle);
dev\_handle = NULL;
}
r = libusb\_open(dev, &dev\_handle);
if (LIBUSB\_SUCCESS != r) {
printf ("error opening device.\\n");
}
else {
if(libusb\_kernel\_driver\_active(dev\_handle, ) == ) { //find out if kernel driver is attached
printf("kernel driver active\\n");
if(libusb\_detach\_kernel\_driver(dev\_handle, ) == ) //detach it
printf("kernel driver detach\\n");
}
int r = libusb\_claim\_interface(dev\_handle, ); //claim interface 0 (the first) of device (mine had jsut 1)
if (r < ) {
printf("libusb\_claim\_interface failed\\n");
return ;
}
g\_no\_device\_flag = ;
printf("usb device open sucess\\n\\n");
printf("input data to send or command:");
fflush(stdout);
}
}
else if (LIBUSB\_HOTPLUG\_EVENT\_DEVICE\_LEFT == event) {
g\_no\_device\_flag = ;
printf("usb device removed: %04x:%04x\\n", desc.idVendor, desc.idProduct);
if (dev\_handle) {
libusb\_close(dev\_handle);
dev\_handle = NULL;
}
}
else
;
return ;
}
//usb hotplugin monitor thread
void * usb_monitor_thread(void *arg)
{
printf("usb monitor thread started.\n");
int r = ;
while () {
r = libusb\_handle\_events(NULL);
if (r < )
printf("libusb\_handle\_events() failed: %s\\n", libusb\_error\_name(r));
}
}
void help(void)
{
printf("usage: libusb-test [-h] [-b] [-i] [-v vid] [-p pid] [-ffile_path] [-l] [-a] \n");
printf(" -h : display usage\n");
printf(" -b : test bulk transfer\n");
printf(" -i : test interrupt transfer\n");
printf(" -v : usb VID\n");
printf(" -p : usb PID\n");
printf(" -f : file path to save data\n");
printf(" -l : list usb devices\n");
printf(" -a : print descriptor for the usb(VID:PID)\n");
return;
}
//将char类型(0-255)的buf转换成以十六进制显示的字符串。
//使用这个函数可以避免多次循环调用printf("%x", buf[i]); 提高效率,并且能避免线程切换造成输出乱序的问题。
//buf={'1', '2', '3', 'a', 'b', 'c'} -> "0x31 0x32 0x33 0x61 0x62 0x63"
//buf={0,1,2,3} -> "0x00 0x01 0x02 0x03"
void hex2str(uchar *dest, uchar *src, ushort nLen)
{
int i;
for (i=; i<nLen; i++)
{
sprintf(dest+\*i, "%#04x ", src\[i\]); //string类函数,不会造成线程切换
}
dest\[nLen\*\] = '\\0';
}
//十六进制数字字符串转数字(十六进制)
// "0x1234" -> 0x1234 or "1234" -> 0x1234
int str2hex(char *hex)
{
int sum = ;
int tmp = ;
char hex_str[];
if(strlen(hex) == ) //0x1234
memcpy(hex\_str, &hex\[\], );
else
memcpy(hex\_str, hex, );
for(int i = ; i < ; i++)
{
tmp = hex\_str\[i\] - (((hex\_str\[i\] >= '') && (hex\_str\[i\] <= '')) ? '' : \\
((hex\_str\[i\] >= 'A') && (hex\_str\[i\] <= 'Z')) ? 'A' - : 'a' - );
sum += tmp \* pow(, -i);
}
return sum;
}
//将接收到数据保存到文件中
int save_to_file(FILE *file_stream, uchar *data, int length)
{
int write_num;
write_num = fwrite(data, , length, file_stream);
fputc('\n', file_stream); //为每段数据换行,方便查看
fflush(file_stream);
return write\_num;
}
void print_devs(libusb_device **devs)
{
libusb_device *dev;
int i = , j = ;
uint8_t path[];
libusb_device_handle *handle = NULL;
char string[];
while ((dev = devs\[i++\]) != NULL) {
struct libusb\_device\_descriptor desc;
int r = libusb\_get\_device\_descriptor(dev, &desc);
if (r < ) {
printf("failed to get device descriptor\\n");
return;
}
printf("bus: %03d device: %03d, VID: %04x PID: %04x",
libusb\_get\_bus\_number(dev), libusb\_get\_device\_address(dev), desc.idVendor, desc.idProduct);
int ret = libusb\_open(dev, &handle);
if (LIBUSB\_SUCCESS == ret) {
if (desc.iProduct) {
ret = libusb\_get\_string\_descriptor\_ascii(handle, desc.iProduct, string, sizeof(string)); //显示产品信息
if (ret > )
printf(", %s", string);
}
}
printf("\\n");
if (handle)
libusb\_close(handle);
}
}
//列出系统所有的USB设备.
//包括:bus number. device number, vid, pid, product info
int list_devices(void)
{
libusb_device **devs;
int r;
ssize_t cnt;
r = libusb\_init(NULL);
if (r < )
return r;
cnt = libusb\_get\_device\_list(NULL, &devs);
if (cnt < )
return (int) cnt;
print\_devs(devs);
libusb\_free\_device\_list(devs, );
libusb\_exit(NULL);
return ;
}
void print_endpoint(const struct libusb_endpoint_descriptor *endpoint)
{
int i, ret;
printf(" Endpoint descriptor:\\n");
printf(" bEndpointAddress: %02xh\\n", endpoint->bEndpointAddress);
printf(" bmAttributes: %02xh\\n", endpoint->bmAttributes);
printf(" wMaxPacketSize: %d\\n", endpoint->wMaxPacketSize);
printf(" bInterval: %d\\n", endpoint->bInterval);
printf(" bRefresh: %d\\n", endpoint->bRefresh);
printf(" bSynchAddress: %d\\n", endpoint->bSynchAddress);
}
void print_altsetting(const struct libusb_interface_descriptor *interface)
{
int i;
printf(" Interface descriptor:\\n");
printf(" bInterfaceNumber: %d\\n", interface->bInterfaceNumber);
printf(" bAlternateSetting: %d\\n", interface->bAlternateSetting);
printf(" bNumEndpoints: %d\\n", interface->bNumEndpoints);
printf(" bInterfaceClass: %d\\n", interface->bInterfaceClass);
printf(" bInterfaceSubClass: %d\\n", interface->bInterfaceSubClass);
printf(" bInterfaceProtocol: %d\\n", interface->bInterfaceProtocol);
printf(" iInterface: %d\\n", interface->iInterface);
for (i = ; i < interface->bNumEndpoints; i++)
print\_endpoint(&interface->endpoint\[i\]);
}
void print_interface(const struct libusb_interface *interface)
{
int i;
for (i = ; i < interface->num\_altsetting; i++)
print\_altsetting(&interface->altsetting\[i\]);
}
void print_configuration(struct libusb_config_descriptor *config)
{
int i;
printf(" Configuration descriptor:\\n");
printf(" wTotalLength: %d\\n", config->wTotalLength);
printf(" bNumInterfaces: %d\\n", config->bNumInterfaces);
printf(" bConfigurationValue: %d\\n", config->bConfigurationValue);
printf(" iConfiguration: %d\\n", config->iConfiguration);
printf(" bmAttributes: %02xh\\n", config->bmAttributes);
printf(" MaxPower: %d\\n", config->MaxPower);
for (i = ; i < config->bNumInterfaces; i++)
print\_interface(&config->interface\[i\]);
}
void print_device(libusb_device *dev, struct libusb_device_descriptor *desc)
{
int i;
printf("Device descriptor:\\n");
printf(" bDescriptorType: %d\\n", desc->bDescriptorType);
printf(" bcdUSB: %#06x\\n", desc->bcdUSB);
printf(" bDeviceClass: %d\\n", desc->bDeviceClass);
printf(" bDeviceSubClass: %d\\n", desc->bDeviceSubClass);
printf(" bDeviceProtocol: %d\\n", desc->bDeviceProtocol);
printf(" bMaxPacketSize0: %d\\n", desc->bMaxPacketSize0);
printf(" idVendor: %#06x\\n", desc->idVendor);
printf(" idProduct: %#06x\\n", desc->idProduct);
printf(" bNumConfigurations: %d\\n", desc->bNumConfigurations);
for (i = ; i < desc->bNumConfigurations; i++) {
struct libusb\_config\_descriptor \*config;
int ret = libusb\_get\_config\_descriptor(dev, i, &config);
if (LIBUSB\_SUCCESS != ret) {
printf("Couldn't retrieve descriptors\\n");
continue;
}
print\_configuration(config);
libusb\_free\_config\_descriptor(config);
}
}
//打印USB设备的描述符
int print_descriptor(libusb_device *dev)
{
struct libusb_device_descriptor desc;
int ret, i;
ret = libusb\_get\_device\_descriptor(dev, &desc);
if (ret < ) {
printf("failed to get device descriptor\\n");
return -;
}
print\_device(dev, &desc);
}
//根据VID:PID,打印特定USB设备的描述符
int get_descriptor_with_vid_pid(int vid, int pid)
{
libusb_device **devs;
libusb_device *found = NULL;
libusb_device *dev;
ssize_t cnt;
int r, i;
r = libusb\_init(NULL);
if (r < )
return -;
cnt = libusb\_get\_device\_list(NULL, &devs);
if (cnt < )
return -;
while ((dev = devs\[i++\]) != NULL) {
struct libusb\_device\_descriptor desc;
r = libusb\_get\_device\_descriptor(dev, &desc);
if (r < )
return -;
if (desc.idVendor == vid && desc.idProduct == pid) {
found = dev;
break;
}
}
print\_descriptor(found);
libusb\_free\_device\_list(devs, );
libusb\_exit(NULL);
return ;
}
//ctrl+c 信号处理函数
void sigint_handler(int sig)
{
if(g_file_stream)
fclose(g_file_stream);
printf("\\nlibusb test quit.\\n");
exit();
}
int main(int argc, char **argv)
{
int r;
int opt;
int test_mode;
int vid, pid;
int send_length;
libusb\_context \*ctx = NULL;
struct sigaction act;
pthread\_t bulk\_rev\_thread\_id;
pthread\_t int\_rev\_thread\_id;
pthread\_t usb\_monitor\_thread\_id;
test\_mode = BULK\_TEST;
vid = VID;
pid = PID;
g\_file\_save\_en = ;
g\_send\_flag = ;
act.sa\_handler = sigint\_handler;
sigemptyset(&act.sa\_mask);
act.sa\_flags = ;
sigaction(SIGINT, &act, NULL);
//命令行参数解析
while((opt = getopt(argc, argv, "bif::hv:p:la")) != -)
{
switch(opt)
{
case 'b' :
test\_mode = BULK\_TEST;
break;
case 'i' :
test\_mode = INT\_TEST;
break;
case 'f' :
g\_file\_stream = fopen(optarg == NULL ? SAVE\_FILE\_PATH : optarg, "wb"); //写打开,并将文件长度截为0,没有则新建
if(g\_file\_stream)
g\_file\_save\_en = ;
else
perror("file open faild: ");
break;
case 'v' :
vid = str2hex(optarg);
break;
case 'p' :
pid = str2hex(optarg);
break;
case 'l' :
list\_devices();
exit();
break;
case 'a' :
get\_descriptor\_with\_vid\_pid(vid, pid);
exit();
break;
case 'h' :
help();
return ;
break;
default :
printf("unkonw option.\\n");
help();
return ;
}
}
printf("\\nlibusb test\\n");
if(test\_mode == BULK\_TEST)
printf("test bulk transfer\\n");
else if(test\_mode == INT\_TEST)
printf("test interrupt transfer\\n");
else{
printf("unkonw test mode.\\n");
return ;
}
printf("usb device: VID:%#06x PID:%#06x\\n\\n", vid, pid); //#:输出0x,06:vid或pid第一个数字为0时,输出0x0471而不是0x471
r = sem\_init(&print\_sem, , ); //初始化信号量,用于解决多线程下printf输出乱序的问题
if(r != )
perror("sem\_init faild: ");
r = libusb\_init(&ctx); //initialize the library for the session we just declared
if(r < ) {
printf("libusb init faild, err:%s\\n", libusb\_error\_name(r)); //there was an error
return -;
}
libusb\_set\_debug(ctx, LIBUSB\_LOG\_LEVEL\_WARNING);
if (!libusb\_has\_capability(LIBUSB\_CAP\_HAS\_HOTPLUG)) {
printf("hotplug capabilites are not supported on this platform.\\n");
libusb\_exit (NULL);
return -;
}
r = libusb\_hotplug\_register\_callback(ctx, LIBUSB\_HOTPLUG\_EVENT\_DEVICE\_ARRIVED | LIBUSB\_HOTPLUG\_EVENT\_DEVICE\_LEFT, LIBUSB\_HOTPLUG\_NO\_FLAGS, vid, pid, LIBUSB\_HOTPLUG\_MATCH\_ANY, usb\_event\_callback, NULL, NULL);
if (LIBUSB\_SUCCESS != r) {
printf("error registering callback: %s\\n", libusb\_error\_name(r));
libusb\_exit(ctx);
return -;
}
dev\_handle = libusb\_open\_device\_with\_vid\_pid(ctx, vid, pid); //open a usb device with VID&PID
if(dev\_handle == NULL) {
printf("cannot open device\\n");
return -;
}
else
printf("usb device opened.\\n");
r = libusb\_kernel\_driver\_active(dev\_handle, );
if(r == ) //ok
;
else if(r == ) {
printf("Kernel driver is active, now try detached\\n");
if(libusb\_detach\_kernel\_driver(dev\_handle, ) == ) //detach it
printf("Kernel driver is detached!\\n");
else{
printf("libusb\_detach\_kernel\_driver, err:%s\\n", libusb\_error\_name(r));
return -;
}
}
else{
printf("libusb\_kernel\_driver\_active, err:%s\\n", libusb\_error\_name(r));
return -;
}
r = libusb\_claim\_interface(dev\_handle, ); //claim interface 0 ,stm32采用接口0
if(r < ) {
printf("cannot claim interface, err:%s\\n", libusb\_error\_name(r));
return -;
}
//热插拔监听
r = pthread_create(&usb_monitor_thread_id, , usb_monitor_thread, );
if(r != )
{
perror("usb_monitor_thread creation faild\n");
}
//new thread,usb rev data
if(test\_mode == BULK\_TEST){
r = pthread\_create(&bulk\_rev\_thread\_id, NULL, bulk\_rev\_thread, NULL);
if(r != )
{
perror("thread creation faild\\n");
}
}
else if(test\_mode == INT\_TEST){
r = pthread\_create(&int\_rev\_thread\_id, NULL, interrupt\_rev\_thread, NULL);
if(r != )
{
perror("thread creation faild\\n");
}
}
while()
{
usleep( \* );
printf("\\ninput data to send or command:");
memset(send\_buf, , SEND\_BUFF\_LEN);
fgets(send\_buf, SEND\_BUFF\_LEN, stdin);
send\_length = strlen(send\_buf)-;
send\_buf\[send\_length\] = '\\0' ; //将读入的换行符转为\\0
//用于快捷发送数据,如输入test64,会自动发送64字节数据,输入test100则会自动发送100字节数据
if(strncmp(send\_buf, "test", ) == ){
send\_length = atoi(&send\_buf\[\]);
if(send\_length > strlen(test\_bytes)){
printf("send\_length:%d should less than max\_length:%ld\\n", send\_length, strlen(test\_bytes));
continue;
}
printf("test sending %d bytes.\\n", send\_length);
memcpy(send\_buf, test\_bytes, send\_length);
}
if(test\_mode == BULK\_TEST)
bulk\_send(send\_buf, send\_length);
else if(test\_mode == INT\_TEST)
interrupt\_send(send\_buf, send\_length);
else
;
}
}
#!/bin/sh
# compile command
gcc -o libusb libusb-test.c -lusb-1.0 -lpthread -lm
手机扫一扫
移动阅读更方便
你可能感兴趣的文章