Skip to content

Instantly share code, notes, and snippets.

@jboone
Created May 18, 2012 23:46
Show Gist options
  • Save jboone/2728205 to your computer and use it in GitHub Desktop.
Save jboone/2728205 to your computer and use it in GitHub Desktop.
First hacked-up attempt at high-speed USB bulk transfers to LPC43xx microcontroller
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libusb.h>
bool read_file_to_buffer(const char* const filename, uint8_t* const buffer, uint32_t buffer_size) {
memset(buffer, 0x69, buffer_size);
FILE* f = fopen(filename, "rb");
if( f == NULL ) {
printf("fopen() failed\n");
return false;
}
fread(buffer, buffer_size, 1, f);
fclose(f);
return true;
}
static float
TimevalDiff(const struct timeval *a, const struct timeval *b)
{
return (a->tv_sec - b->tv_sec) + 1e-6f * (a->tv_usec - b->tv_usec);
}
struct timeval time_start;
uint32_t byte_count = 0;
void transfer_callback(struct libusb_transfer* transfer) {
if( transfer->status == LIBUSB_TRANSFER_COMPLETED ) {
byte_count += transfer->actual_length;
libusb_submit_transfer(transfer);
} else {
printf("transfer status was not 'completed'\n");
}
}
int main(int argc, char** argv) {
if( argc != 3 ) {
printf("Usage: usb_test <first file to transmit> <second file to transmit>\n");
return -1;
}
const uint32_t buffer_size = 65536;
unsigned char buffer_1[buffer_size], buffer_2[buffer_size];
unsigned char* buffer[2] = {
buffer_1,
buffer_2
};
if( read_file_to_buffer(argv[1], buffer[0], buffer_size) != true ) {
printf("Failed to read file 1\n");
return -2;
}
if( read_file_to_buffer(argv[2], buffer[1], buffer_size) != true ) {
printf("Failed to read file 2\n");
return -3;
}
libusb_context* context;
int result = libusb_init(&context);
if( result != 0 ) {
printf("libusb_init() failed: %d\n", result);
return -4;
}
libusb_device_handle* device = libusb_open_device_with_vid_pid(context, 0x1fc9, 0x000c);
if( device == NULL ) {
printf("libusb_open_device_with_vid_pid() failed\n");
return -5;
}
//int speed = libusb_get_device_speed(device);
//printf("device speed: %d\n", speed);
// TODO: Not setting configuration because it was causing
// repeated calls on the host that would prime endpoints
// multiple times, and confuse them (for the first transfer).
/*
result = libusb_set_configuration(device, 1);
if( result != 0 ) {
printf("libusb_set_configuration() failed: %d\n", result);
return -6;
}
*/
result = libusb_claim_interface(device, 0);
if( result != 0 ) {
printf("libusb_claim_interface() failed: %d\n", result);
return -7;
}
unsigned char endpoint_address = 0x02;
const uint32_t transfer_count = 256;
struct libusb_transfer* transfers[transfer_count];
for(uint32_t transfer_index=0; transfer_index<transfer_count; transfer_index++) {
transfers[transfer_index] = libusb_alloc_transfer(0);
if( transfers[transfer_index] == 0 ) {
printf("libusb_alloc_transfer() failed\n");
return -6;
}
libusb_fill_bulk_transfer(
transfers[transfer_index],
device,
endpoint_address,
(unsigned char*)malloc(buffer_size),
buffer_size,
&transfer_callback,
NULL,
0
);
if( transfers[transfer_index]->buffer == 0 ) {
printf("malloc() failed\n");
return -7;
}
//(if( transfer_index & 2 ) {
memcpy(transfers[transfer_index]->buffer, buffer[transfer_index & 1], buffer_size);
//}
int error = libusb_submit_transfer(transfers[transfer_index]);
if( error != 0 ) {
printf("libusb_submit_transfer() failed: %d\n", error);
return -8;
}
}
//////////////////////////////////////////////////////////////
struct timeval timeout = { 0, 200000 };
struct timeval time_now;
const double progress_interval = 1.0;
gettimeofday(&time_start, NULL);
uint32_t call_count = 0;
do {
int error = libusb_handle_events_timeout(context, &timeout);
if( error != 0 ) {
printf("libusb_handle_events_timeout() failed: %d\n", error);
return -10;
}
if( (call_count & 0xFF) == 0 ) {
gettimeofday(&time_now, NULL);
const float time_difference = TimevalDiff(&time_now, &time_start);
if( time_difference >= progress_interval ) {
const float rate = float(byte_count) / time_difference;
printf("%.1f/%.3f = %.1f MiB/second\n",
byte_count / 1e6f,
time_difference,
rate / 1e6f
);
time_start = time_now;
byte_count = 0;
}
}
call_count += 1;
} while(true);
/*
printf("transferring...\n");
int buffer_number = 0;
while(true) {
int bytes_transferred = 0;
unsigned int timeout = 0;
result = libusb_bulk_transfer(
device, endpoint_address, buffer[buffer_number],
buffer_size, &bytes_transferred, timeout
);
if( result != 0 ) {
printf("libusb_bulk_transfer() failed: %d\n", result);
return -1000;
}
if( bytes_transferred != buffer_size ) {
printf("libusb_bulk_transfer() failed: transferred (%d) != buffer size (%d)\n",
bytes_transferred,
buffer_size
);
return -1001;
}
buffer_number = 1 - buffer_number;
byte_count += bytes_transferred;
}
*/
//////////////////////////////////////////////////////////////
result = libusb_release_interface(device, 0);
if( result != 0 ) {
printf("libusb_release_interface() failed: %d\n", result);
return -2000;
}
libusb_close(device);
libusb_exit(context);
return 0;
}
Bus 250 Device 006: ID 1fc9:000c
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x1fc9
idProduct 0x000c
bcdDevice 0.01
iManufacturer 0
iProduct 0
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 32
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255
bInterfaceSubClass 255
bInterfaceProtocol 255
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment