Created
May 18, 2012 23:20
-
-
Save jboone/2728082 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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment