Created
May 18, 2012 23:46
-
-
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
This file contains hidden or 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
#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; | |
} |
This file contains hidden or 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
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