-
-
Save hutorny/bc67a99bdcc649e559f0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//libusb+ch340 data transfer demo | |
//gcc usb.c `pkg-config libusb-1.0 --libs --cflags` -o usb | |
#include <errno.h> | |
#include <signal.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <sys/select.h> | |
#include <termios.h> | |
#include <libusb.h> | |
#define EP_DATA_IN (0x2|LIBUSB_ENDPOINT_IN) | |
#define EP_DATA_OUT (0x2|LIBUSB_ENDPOINT_OUT) | |
#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) | |
#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) | |
#define DEFAULT_BAUD_RATE 9600 | |
static struct libusb_device_handle *devh = NULL; | |
static struct libusb_transfer *recv_bulk_transfer = NULL; | |
uint8_t dtr = 0; | |
uint8_t rts = 0; | |
uint8_t do_exit = 0; | |
uint8_t recvbuf[1024]; | |
void writeHandshakeByte(void) { | |
if (libusb_control_transfer(devh, CTRL_OUT, 0xa4, ~((dtr ? 1 << 5 : 0) | (rts ? 1 << 6 : 0)), 0, NULL, 0, 1000) < 0) { | |
fprintf(stderr, "Faild to set handshake byte\n"); | |
} | |
} | |
int setBaudRate(int baudRate){ | |
static int baud[] = {2400, 0xd901, 0x0038, 4800, 0x6402, | |
0x001f, 9600, 0xb202, 0x0013, 19200, 0xd902, 0x000d, 38400, | |
0x6403, 0x000a, 115200, 0xcc03, 0x0008}; | |
for (int i = 0; i < sizeof(baud)/sizeof(int) / 3; i++) { | |
if (baud[i * 3] == baudRate) { | |
int r = libusb_control_transfer(devh, CTRL_OUT, 0x9a, 0x1312, baud[i * 3 + 1], NULL, 0, 1000); | |
if (r < 0) { | |
fprintf(stderr, "failed control transfer 0x9a,0x1312\n"); | |
return r; | |
} | |
r = libusb_control_transfer(devh, CTRL_OUT, 0x9a, 0x0f2c, baud[i * 3 + 2], NULL, 0, 1000); | |
if (r < 0) { | |
fprintf(stderr, "failed control transfer 0x9a,0x0f2c\n"); | |
return r; | |
} | |
return 0; | |
} | |
} | |
fprintf(stderr, "unsupported baudrate\n"); | |
return -1; | |
} | |
int init_ch34x() | |
{ | |
int r; | |
r = libusb_control_transfer(devh, CTRL_OUT, 0xa1, 0, 0, NULL, 0, 1000); | |
if (r < 0) { | |
fprintf(stderr, "failed control transfer 0xa1\n"); | |
return r; | |
} | |
r = libusb_control_transfer(devh, CTRL_OUT, 0x9a, 0x2518, 0x0050, NULL, 0, 1000); | |
if (r < 0) { | |
fprintf(stderr, "failed control transfer 0x9a,0x2518\n"); | |
return r; | |
} | |
r = libusb_control_transfer(devh, CTRL_OUT, 0xa1, 0x501f, 0xd90a, NULL, 0, 1000); | |
if (r < 0) { | |
fprintf(stderr, "failed control transfer 0xa1,0x501f\n"); | |
return r; | |
} | |
setBaudRate(DEFAULT_BAUD_RATE); | |
writeHandshakeByte(); | |
return r; | |
} | |
static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer) | |
{ | |
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { | |
fprintf(stderr, "img transfer status %d?\n", transfer->status); | |
do_exit = 2; | |
libusb_free_transfer(transfer); | |
return; | |
} | |
// printf("Data callback["); | |
for (int i = 0; i < transfer->actual_length; ++i) | |
{ | |
putchar(recvbuf[i]); | |
} | |
fflush(stdout); | |
// printf("]\n"); | |
if (libusb_submit_transfer(recv_bulk_transfer) < 0) | |
do_exit = 2; | |
} | |
int send_to_uart(void) | |
{ | |
int r; | |
unsigned char sendbuf[1024]; | |
if ((r = read(0, sendbuf, sizeof(sendbuf))) < 0) { | |
return r; | |
} else { | |
int transferred, len = r; | |
r = libusb_bulk_transfer(devh, EP_DATA_OUT, sendbuf, len, &transferred, 200); | |
// printf("read[%d]transferred[%d]\n", len, transferred); | |
if(r < 0){ | |
fprintf(stderr, "libusb_bulk_transfer error %d\n", r); | |
return r; | |
} | |
} | |
return r; | |
} | |
int kbhit() | |
{ | |
struct timeval tv = { 0L, 0L }; | |
fd_set fds; | |
FD_ZERO(&fds); | |
FD_SET(0, &fds); | |
return select(1, &fds, NULL, NULL, &tv); | |
} | |
int main(int argc, char **argv) | |
{ | |
int r = 1; | |
r = libusb_init(NULL); | |
if (r < 0) { | |
fprintf(stderr, "failed to initialise libusb\n"); | |
exit(1); | |
} | |
devh = libusb_open_device_with_vid_pid(NULL, 0x1a86, 0x7523); | |
if (devh == NULL) { | |
fprintf(stderr, "Could not find/open device\n"); | |
goto out; | |
} | |
r = libusb_claim_interface(devh, 0); | |
if (r < 0) { | |
fprintf(stderr, "usb_claim_interface error %d\n", r); | |
goto out; | |
} | |
printf("claimed interface\n"); | |
r = init_ch34x(); | |
if (r < 0) | |
goto out_release; | |
if(argc > 1) | |
setBaudRate(atoi(argv[1])); | |
printf("initialized\n"); | |
recv_bulk_transfer = libusb_alloc_transfer(0); | |
if (!recv_bulk_transfer){ | |
fprintf(stderr, "libusb_alloc_transfer error\n"); | |
goto out_release; | |
} | |
libusb_fill_bulk_transfer(recv_bulk_transfer, devh, EP_DATA_IN, recvbuf, | |
sizeof(recvbuf), cb_img, NULL, 0); | |
r = libusb_submit_transfer(recv_bulk_transfer); | |
if (r < 0){ | |
fprintf(stderr, "libusb_submit_transfer error\n"); | |
goto out_deinit; | |
} | |
// set_conio_terminal_mode(); | |
while (!do_exit) { | |
struct timeval tv = { 0L, 0L }; | |
r = libusb_handle_events_timeout(NULL, &tv); | |
if (r < 0) | |
goto out_deinit; | |
if(kbhit()){ | |
r = send_to_uart(); | |
if (r < 0) | |
goto out_deinit; | |
} | |
} | |
if (recv_bulk_transfer) { | |
r = libusb_cancel_transfer(recv_bulk_transfer); | |
if (r < 0) | |
goto out_deinit; | |
} | |
out_deinit: | |
libusb_free_transfer(recv_bulk_transfer); | |
out_release: | |
libusb_release_interface(devh, 0); | |
out: | |
libusb_close(devh); | |
libusb_exit(NULL); | |
return r >= 0 ? r : -r; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment