forked from tytouf/libusb-cdc-example
/
cdc_example.c
147 lines (128 loc) · 4.04 KB
/
cdc_example.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
* This is a simple example to communicate with a CDC-ACM USB device
* using libusb.
*
* Author: Christophe Augier <christophe.augier@gmail.com>
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <libusb-1.0/libusb.h>
/* You may want to change the VENDOR_ID and PRODUCT_ID
* depending on your device.
*/
#define VENDOR_ID 0x2341 // Arduino LLC
#define PRODUCT_ID 0x0034 // Arduino Leonardo
#define ACM_CTRL_DTR 0x01
#define ACM_CTRL_RTS 0x02
/* We use a global variable to keep the device handle
*/
static struct libusb_device_handle *devh = NULL;
/* The Endpoint address are hard coded. You should use lsusb -v to find
* the values corresponding to your device.
*/
static int ep_in_addr = 0x83;
static int ep_out_addr = 0x02;
void write_char(unsigned char c)
{
/* To send a char to the device simply initiate a bulk_transfer to the
* Endpoint with address ep_out_addr.
*/
int actual_length;
if (libusb_bulk_transfer(devh, ep_out_addr, &c, 1,
&actual_length, 0) < 0) {
fprintf(stderr, "Error while sending char\n");
}
}
int read_chars(unsigned char * data, int size)
{
/* To receive characters from the device initiate a bulk_transfer to the
* Endpoint with address ep_in_addr.
*/
int actual_length;
int rc = libusb_bulk_transfer(devh, ep_in_addr, data, size, &actual_length,
1000);
if (rc == LIBUSB_ERROR_TIMEOUT) {
printf("timeout (%d)\n", actual_length);
return -1;
} else if (rc < 0) {
fprintf(stderr, "Error while waiting for char\n");
return -1;
}
return actual_length;
}
int main(int argc, char **argv)
{
int rc;
/* Initialize libusb
*/
rc = libusb_init(NULL);
if (rc < 0) {
fprintf(stderr, "Error initializing libusb: %s\n", libusb_error_name(rc));
exit(1);
}
/* Set debugging output to max level.
*/
libusb_set_debug(NULL, 3);
/* Look for a specific device and open it.
*/
devh = libusb_open_device_with_vid_pid(NULL, VENDOR_ID, PRODUCT_ID);
if (!devh) {
fprintf(stderr, "Error finding USB device\n");
goto out;
}
/* As we are dealing with a CDC-ACM device, it's highly probable that
* Linux already attached the cdc-acm driver to this device.
* We need to detach the drivers from all the USB interfaces. The CDC-ACM
* Class defines two interfaces: the Control interface and the
* Data interface.
*/
for (int if_num = 0; if_num < 2; if_num++) {
if (libusb_kernel_driver_active(devh, if_num)) {
libusb_detach_kernel_driver(devh, if_num);
}
rc = libusb_claim_interface(devh, if_num);
if (rc < 0) {
fprintf(stderr, "Error claiming interface: %s\n",
libusb_error_name(rc));
goto out;
}
}
/* Start configuring the device:
* - set line state
*/
rc = libusb_control_transfer(devh, 0x21, 0x22, ACM_CTRL_DTR | ACM_CTRL_RTS,
0, NULL, 0, 0);
if (rc < 0) {
fprintf(stderr, "Error during control transfer: %s\n",
libusb_error_name(rc));
}
/* - set line encoding: here 9600 8N1
* 9600 = 0x2580 ~> 0x80, 0x25 in little endian
*/
unsigned char encoding[] = { 0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08 };
rc = libusb_control_transfer(devh, 0x21, 0x20, 0, 0, encoding,
sizeof(encoding), 0);
if (rc < 0) {
fprintf(stderr, "Error during control transfer: %s\n",
libusb_error_name(rc));
}
/* We can now start sending or receiving data to the device
*/
unsigned char buf[65];
int len;
while(1) {
write_char('t');
len = read_chars(buf, 64);
buf[len] = 0;
fprintf(stdout, "Received: \"%s\"\n", buf);
sleep(1);
}
libusb_release_interface(devh, 0);
out:
if (devh)
libusb_close(devh);
libusb_exit(NULL);
return rc;
}