Updating main command line input args, and libusb logging/debug messages.

now able to accept LIBUSB_LOG_LEVEL from commandline to turn on/off error
messges at runtime.  Also setting level > 0 will print messages during
device discovery and connection.  Still need to permit kazzo firmware
version to be provided on commandline to support K flag.

fixing dictionary call typo with semicolon and setting buffer length
to always be provided with function call instead of dictionary call
deciding what it should be based on the opcode.

Adding some speed notes and other speed related discussions to buffer
dictionary.
This commit is contained in:
Paul Molloy 2016-12-02 22:59:54 -06:00
parent 2f8823053e
commit 132360f305
6 changed files with 236 additions and 112 deletions

View File

@ -16,18 +16,21 @@
*/ */
//default call dictionary without print option //default call dictionary without print option
int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length) int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata,
uint8_t endpoint, uint8_t *buffer, uint16_t length)
{ {
return dictionary_call_print_option( ~TRUE, transfer, dictionary, opcode, addr, miscdata, endpoint, buffer, length); return dictionary_call_print_option( ~TRUE, transfer, dictionary, opcode, addr, miscdata, endpoint, buffer, length);
} }
//debug call dictionary without print option //debug call dictionary without print option
int dictionary_call_debug( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length) int dictionary_call_debug( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata,
uint8_t endpoint, uint8_t *buffer, uint16_t length)
{ {
return dictionary_call_print_option( TRUE, transfer, dictionary, opcode, addr, miscdata, endpoint, buffer, length); return dictionary_call_print_option( TRUE, transfer, dictionary, opcode, addr, miscdata, endpoint, buffer, length);
} }
int dictionary_call_print_option( int print_debug; USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length) int dictionary_call_print_option( int print_debug, USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata,
uint8_t endpoint, uint8_t *buffer, uint16_t length)
{ {
transfer->request = dictionary; transfer->request = dictionary;
transfer->wValueMSB = miscdata; transfer->wValueMSB = miscdata;
@ -37,11 +40,14 @@ int dictionary_call_print_option( int print_debug; USBtransfer *transfer, uint8_
//default IN for now reading back error codes from short commands //default IN for now reading back error codes from short commands
transfer->endpoint = endpoint; transfer->endpoint = endpoint;
transfer->wLength = length;
//default length of zero //default length of zero
transfer->wLength = 0; // transfer->wLength = 0;
//return data buffer big enough for one data packet //return data buffer big enough for one data packet
uint8_t rbuf[8]; uint8_t rbuf[8];
if ( buffer == NULL ) {
rbuf[0] = 0xA5; rbuf[0] = 0xA5;
rbuf[1] = 0xC3; rbuf[1] = 0xC3;
rbuf[2] = 0xA5; rbuf[2] = 0xA5;
@ -51,12 +57,15 @@ int dictionary_call_print_option( int print_debug; USBtransfer *transfer, uint8_
rbuf[6] = 0xA5; rbuf[6] = 0xA5;
rbuf[7] = 0xC3; rbuf[7] = 0xC3;
transfer->data = rbuf; transfer->data = rbuf;
} else {
transfer->data = buffer;
}
debug("\ndictionary call dict:%d opcode:%d/%x addr:%x data:%x", dictionary, opcode, opcode, addr, miscdata); debug("\ndictionary call dict:%d opcode:%d/%x addr:%x data:%x", dictionary, opcode, opcode, addr, miscdata);
switch (dictionary) { switch (dictionary) {
case PINPORT: debug("dict: PINPORT"); case PINPORT: debug("dict: PINPORT");
transfer->wLength = 1; //transfer->wLength = 1;
switch (opcode) { switch (opcode) {
case PP_OPCODE_ONLY_MIN ... PP_OPCODE_ONLY_MAX: case PP_OPCODE_ONLY_MIN ... PP_OPCODE_ONLY_MAX:
debug("PP_OPCODE_ONLY"); debug("PP_OPCODE_ONLY");
@ -72,7 +81,7 @@ int dictionary_call_print_option( int print_debug; USBtransfer *transfer, uint8_
break; break;
case PP_OPCODE_8BRV_MIN ... PP_OPCODE_8BRV_MAX: case PP_OPCODE_8BRV_MIN ... PP_OPCODE_8BRV_MAX:
debug("PP_OPCODE_8BRV"); debug("PP_OPCODE_8BRV");
transfer->wLength = 2; // transfer->wLength = 2;
break; break;
default: //pinport opcode min/max definition error default: //pinport opcode min/max definition error
sentinel("bad PP opcode min/max err:%d",ERR_BAD_PP_OP_MINMAX); sentinel("bad PP opcode min/max err:%d",ERR_BAD_PP_OP_MINMAX);
@ -80,14 +89,14 @@ int dictionary_call_print_option( int print_debug; USBtransfer *transfer, uint8_
break; //end of PINPORT break; //end of PINPORT
case IO: debug("dict: IO"); case IO: debug("dict: IO");
transfer->wLength = 1; // transfer->wLength = 1;
switch (opcode) { switch (opcode) {
case IO_OPCODE_ONLY_MIN ... IO_OPCODE_ONLY_MAX: case IO_OPCODE_ONLY_MIN ... IO_OPCODE_ONLY_MAX:
debug("IO_OPCODE_ONLY"); debug("IO_OPCODE_ONLY");
break; break;
case IO_OPCODE_RTN_MIN ... IO_OPCODE_RTN_MAX: case IO_OPCODE_RTN_MIN ... IO_OPCODE_RTN_MAX:
debug("IO_OPCODE_RTN"); debug("IO_OPCODE_RTN");
transfer->wLength = 8; // transfer->wLength = 8;
break; break;
default: //io opcode min/max definition error default: //io opcode min/max definition error
sentinel("bad IO opcode min/max err:%d",ERR_BAD_IO_OP_MINMAX); sentinel("bad IO opcode min/max err:%d",ERR_BAD_IO_OP_MINMAX);
@ -95,14 +104,14 @@ int dictionary_call_print_option( int print_debug; USBtransfer *transfer, uint8_
break; //end of IO break; //end of IO
case NES: debug("dict: NES"); case NES: debug("dict: NES");
transfer->wLength = 1; // transfer->wLength = 1;
switch (opcode) { switch (opcode) {
case NES_OPCODE_24BOP_MIN ... NES_OPCODE_24BOP_MAX: case NES_OPCODE_24BOP_MIN ... NES_OPCODE_24BOP_MAX:
debug("NES_OPCODE_24BOP"); debug("NES_OPCODE_24BOP");
break; break;
case NES_OPCODE_16BOP_8BRV_MIN ... NES_OPCODE_16BOP_8BRV_MAX: case NES_OPCODE_16BOP_8BRV_MIN ... NES_OPCODE_16BOP_8BRV_MAX:
debug("NES_OPCODE_16BOP_8BRV"); debug("NES_OPCODE_16BOP_8BRV");
transfer->wLength = 2; // transfer->wLength = 2;
break; break;
default: //nes opcode min/max definition error default: //nes opcode min/max definition error
sentinel("bad NES opcode min/max err:%d",ERR_BAD_NES_OP_MINMAX); sentinel("bad NES opcode min/max err:%d",ERR_BAD_NES_OP_MINMAX);
@ -110,14 +119,14 @@ int dictionary_call_print_option( int print_debug; USBtransfer *transfer, uint8_
break; //end of NES break; //end of NES
case SNES: debug("dict: SNES"); case SNES: debug("dict: SNES");
transfer->wLength = 1; // transfer->wLength = 1;
switch (opcode) { switch (opcode) {
case SNES_OPCODE_24BOP_MIN ... SNES_OPCODE_24BOP_MAX: case SNES_OPCODE_24BOP_MIN ... SNES_OPCODE_24BOP_MAX:
debug("SNES_OPCODE_24BOP"); debug("SNES_OPCODE_24BOP");
break; break;
case SNES_OPCODE_24BOP_8BRV_MIN ... SNES_OPCODE_24BOP_8BRV_MAX: case SNES_OPCODE_24BOP_8BRV_MIN ... SNES_OPCODE_24BOP_8BRV_MAX:
debug("SNES_OPCODE_24BOP_8BRV"); debug("SNES_OPCODE_24BOP_8BRV");
transfer->wLength = 2; // transfer->wLength = 2;
break; break;
default: //snes opcode min/max definition error default: //snes opcode min/max definition error
sentinel("bad SNES opcode min/max err:%d",ERR_BAD_SNES_OP_MINMAX); sentinel("bad SNES opcode min/max err:%d",ERR_BAD_SNES_OP_MINMAX);
@ -125,14 +134,14 @@ int dictionary_call_print_option( int print_debug; USBtransfer *transfer, uint8_
break; //end of SNES break; //end of SNES
case BUFFER: debug("dict: BUFFER"); case BUFFER: debug("dict: BUFFER");
transfer->wLength = length; // transfer->wLength = length;
if (buffer != NULL) { if (buffer != NULL) {
transfer->data = (unsigned char *)buffer; transfer->data = (unsigned char *)buffer;
} }
break; //end of BUFF break; //end of BUFF
case USB: debug("dict: USB"); case USB: debug("dict: USB");
transfer->wLength = length; // transfer->wLength = length;
break; break;
default: default:

View File

@ -19,13 +19,15 @@
#include "shared_errors.h" #include "shared_errors.h"
#include "shared_dictionaries.h" #include "shared_dictionaries.h"
//default call dictionary without print option
int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata,
uint8_t endpoint, uint8_t *buffer, uint16_t length);
//dictionary call with debug prints //debug call dictionary without print option
int dictionary_call_debug( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length); int dictionary_call_debug( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata,
uint8_t endpoint, uint8_t *buffer, uint16_t length);
//dictionary call without printing output int dictionary_call_print_option( int print_debug, USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata,
int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length); uint8_t endpoint, uint8_t *buffer, uint16_t length);
int dictionary_call_print_option( int print_debug, USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length);
#endif #endif

View File

@ -21,18 +21,38 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
check(argc > 1, "USAGE: inlretro <action o/f>");
//lower case flags suggested for average user
int e_flag = 0; //FORCE ERASE
int f_flag = 0; //FORCE ALL CHECKS PASSING
int h_flag = 0; //HELP MESSAGE
int i_flag = 0; //input file is interlaced
int n_flag = 0; //LED OFF
int o_flag = 0; //LED ON int o_flag = 0; //LED ON
int f_flag = 0; //LED OFF int t_flag = 0; //test all SRAMs found
int e_flag = 0; //ERASE int x_flag = 0; //disable all auto detecting
int m_flag = 0; //MIRROR int y_flag = 0; //diable all auto doubling
int t_flag = 0; //TEST
char *w_value = NULL; //WRITE FILE char *b_value = NULL; //SUBMAPPER #
char *d_value = NULL; //DUMP FILE char *c_value = NULL; //CONSOLE NAME
char *s_value = NULL; //SAVE FILE char *d_value = NULL; //DUMP TO FILE
char *i_value = NULL; //iNES MAPPER char *m_value = NULL; //MAPPER #
char *b_value = NULL; //BOARD char *p_value = NULL; //PROGRAM FILE
char *s_value = NULL; //SCRIPT FILE
char *v_value = NULL; //MAPPER VARIANT
//upper case flags suggested for ADVANCED users
int T_flag = 0; //TEST
char *C_value = NULL; //program chr file
char *L_value = NULL; //LIBUSB debugging value
char *K_value = NULL; //connect to kazzo firmware version #
char *O_value = NULL; //start programming at offset base value
char *P_value = NULL; //program prg file
char *S_value = NULL; //program SNES binary file
char *W_value = NULL; //program WRAM/SRAM file
int index = 0; int index = 0;
int rv = 0; int rv = 0;
@ -41,53 +61,88 @@ int main(int argc, char *argv[])
//getopt returns args till done then returns -1 //getopt returns args till done then returns -1
//string of possible args : denotes 1 required additional arg //string of possible args : denotes 1 required additional arg
//:: denotes optional additional arg follows //:: denotes optional additional arg follows
while( (rv = getopt( argc, argv, "ofemtw:d:s:i:b:")) != -1) { while( (rv = getopt( argc, argv, "onefhitxyTb:c:d:m:p:s:v:C:L:K:O:P:S:W:")) != -1) {
switch(rv) { switch(rv) {
case 'o': o_flag = 1; break; case 'o': o_flag = 1; break;
case 'f': f_flag = 1; break; case 'n': n_flag = 1; break;
case 'e': e_flag = 1; break; case 'e': e_flag = 1; break;
case 'm': m_flag = 1; break; case 'f': f_flag = 1; break;
case 'h': h_flag = 1; break;
case 'i': i_flag = 1; break;
case 't': t_flag = 1; break; case 't': t_flag = 1; break;
case 'w': w_value = optarg; break; case 'x': x_flag = 1; break;
case 'd': d_value = optarg; break; case 'y': y_flag = 1; break;
case 's': s_value = optarg; break; case 'T': T_flag = 1; break;
case 'i': i_value = optarg; break;
case 'b': b_value = optarg; break; case 'b': b_value = optarg; break;
case 'c': c_value = optarg; break;
case 'd': d_value = optarg; break;
case 'm': m_value = optarg; break;
case 'p': p_value = optarg; break;
case 's': s_value = optarg; break;
case 'v': v_value = optarg; break;
case 'C': C_value = optarg; break;
case 'L': L_value = optarg; break;
case 'K': K_value = optarg; break;
case 'O': O_value = optarg; break;
case 'P': P_value = optarg; break;
case 'S': S_value = optarg; break;
case 'W': W_value = optarg; break;
case '?': case '?':
if ( optopt == 'w' ) { if(( optopt == 'b' )
log_err("Option -%c requires an argument.", optopt); || ( optopt == 'c' )
} else if ( optopt == 'd' ) { || ( optopt == 'd' )
log_err("Option -%c requires an argument.", optopt); || ( optopt == 'm' )
} else if ( optopt == 's' ) { || ( optopt == 'p' )
log_err("Option -%c requires an argument.", optopt); || ( optopt == 's' )
} else if ( optopt == 'i' ) { || ( optopt == 'v' )
log_err("Option -%c requires an argument.", optopt); || ( optopt == 'C' )
} else if ( optopt == 'b' ) { || ( optopt == 'L' )
|| ( optopt == 'K' )
|| ( optopt == 'O' )
|| ( optopt == 'P' )
|| ( optopt == 'S' )
|| ( optopt == 'W' )){
log_err("Option -%c requires an argument.", optopt); log_err("Option -%c requires an argument.", optopt);
goto error;
} else if ( isprint(optopt)) { } else if ( isprint(optopt)) {
log_err("Unknown option -%c .", optopt); log_err("Unknown option -%c .", optopt);
goto error;
} else { } else {
log_err("Unknown option character '\\x%x'", optopt); log_err("Unknown option character '\\x%x'", optopt);
goto error;
} }
log_err("Improper arguements passed"); log_err("Improper arguements passed");
goto error;
break; break;
default: default:
sentinel("getopt failed to catch all arg cases"); sentinel("getopt failed to catch all arg cases");
} }
} }
debug("flags= o:%d f:%d e:%d m:%d t:%d", o_flag, f_flag, e_flag, m_flag, t_flag);
debug("args= w:%s d:%s s:%s i:%s b:%s", w_value, d_value, s_value, i_value, b_value); debug("flags= o:%d n:%d e:%d f:%d h:%d i:%d t:%d x:%d y:%d T:%d",
o_flag, n_flag, e_flag, f_flag, h_flag, i_flag, t_flag, x_flag, y_flag, T_flag );
debug("args= b:%s c:%s d:%s m:%s p:%s", b_value, c_value, d_value, m_value, p_value);
debug("args= s:%s v:%s C:%s L:%s K:%s", s_value, v_value, C_value, L_value, K_value);
debug("args= O:%s P:%s S:%s W:%s", O_value, P_value, S_value, W_value);
for( index = optind; index < argc; index++) { for( index = optind; index < argc; index++) {
log_err("Non-option arguement: %s \n", argv[index]); log_err("Non-option arguement: %s \n", argv[index]);
} }
//TODO display better help message
if (h_flag) {
printf("you've asked for help but the help message still needs created...\n");
return 0;
}
//context set to NULL since only acting as single user of libusb //context set to NULL since only acting as single user of libusb
libusb_context *context = NULL; libusb_context *context = NULL;
//create USBtransfer struct to hold all transfer info //create USBtransfer struct to hold all transfer info
USBtransfer *transfer = malloc( sizeof(USBtransfer)); USBtransfer *transfer = malloc( sizeof(USBtransfer));
check_mem(transfer); check_mem(transfer);
@ -96,21 +151,54 @@ int main(int argc, char *argv[])
//libusb_device_handle *rprog_handle = NULL; //libusb_device_handle *rprog_handle = NULL;
transfer->handle = NULL; transfer->handle = NULL;
//open INL retro prog with firmware version 2.0 or greater //open INL retro prog with firmware version 2.0 or greater
transfer->handle = open_usb_device( context ); //command line arg L_value to set different LIBUSB debugging options
//any value > 0 also prints debug statements in open_usb_device function
int libusb_log = LIBUSB_LOG_LEVEL_NONE; // 0: default no msgs ever printed
if (L_value != NULL) {
check( isdigit(L_value[0]), "Invalid LIBUSB_LOG_LEVEL: %s, only single digit allowed", L_value);
check( strlen(L_value) == 1, "Invalid LIBUSB_LOG_LEVEL: %s, only single digit allowed", L_value);
libusb_log = atoi(L_value);
check( ((libusb_log >= LIBUSB_LOG_LEVEL_NONE) && (libusb_log <=LIBUSB_LOG_LEVEL_DEBUG)),
"Invalid LIBUSB_LOG_LEVEL: %d, must be from 0 to 4", libusb_log );
printf("setting LIBUSB_LOG_LEVEL to: %d\n", libusb_log);
if (libusb_log == 0) { printf("\tNONE: default no messages ever printed by library\n"); }
if (libusb_log == 1) { printf("\tERROR: error messages are printed to stderr\n"); }
if (libusb_log == 2) { printf("\tWARNING: warning and error messages are printed to stderr\n"); }
if (libusb_log == 3) { printf("\tINFO: informational, warning, & error messages are printed to stdout\n"); }
if (libusb_log == 4) { printf("\tDEBUG: debug, info, warning, & error messages are printed to stdout\n"); }
}
if (K_value != NULL) {
//TODO take K_value option to connect to different version kazzo
}
transfer->handle = open_usb_device( context, libusb_log );
check( transfer->handle != NULL, "Unable to open INL retro-prog usb device handle."); check( transfer->handle != NULL, "Unable to open INL retro-prog usb device handle.");
//report successful connection to INL retro-prog
printf("Successfully found and connected to INL retro-prog with firmware version 2.0\n");
//create board object/struct
//attempt to detect board inserted in device
// -x flag turns off all autodection
if (!x_flag) {
printf("attempting to detect cartridge...\n");
} else {
printf("auto-detection turned off\n");
}
if (e_flag) erase_nes( transfer );
if (T_flag) test_function( transfer );
//handle simple LED ON/OFF within main for now
//TODO cut this newbie code out of here
int xfr_cnt = 0; int xfr_cnt = 0;
uint8_t rbuf[8]; uint8_t rbuf[8];
int i; int i;
if (e_flag) erase_nes( transfer ); if (o_flag | n_flag) {
if (t_flag) test_function( transfer );
//handle simple LED ON/OFF within main for now
if (o_flag | f_flag) {
printf("before return buffer: "); printf("before return buffer: ");
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
rbuf[i] = 7; rbuf[i] = 7;
@ -120,7 +208,7 @@ int main(int argc, char *argv[])
transfer->endpoint = USB_IN; transfer->endpoint = USB_IN;
transfer->request = PINPORT; transfer->request = PINPORT;
if (o_flag) transfer->wValueLSB = LED_ON; if (o_flag) transfer->wValueLSB = LED_ON;
if (f_flag) transfer->wValueLSB = LED_OFF; if (n_flag) transfer->wValueLSB = LED_OFF;
transfer->data = rbuf; transfer->data = rbuf;
transfer->wLength = 1; transfer->wLength = 1;
@ -137,24 +225,6 @@ int main(int argc, char *argv[])
//if (o_flag) { //ON send REQ_LED_ON
// xfr_cnt = usb_transfer( transfer.handle,
// REQ_LED_ON,
// (unsigned char *)buffer254, sizeof(buffer254) );
// printf("total bytes xfrd: %d \n", xfr_cnt);
//}
//if (f_flag) { //OFF send REQ_LED_OFF
// xfr_cnt = usb_write_to_device( transfer.handle,
// REQ_LED_OFF, (unsigned char *)buffer254, sizeof(buffer254) );
// printf("total bytes xfrd: %d \n", xfr_cnt);
//}
//if (w_value) { //OFF send REQ_LED_OFF
// check( write_file( transfer.handle, w_value, i_value, b_value) == SUCCESS,
// "Failed to write file: %s", w_value);
//}
close_usb( context, transfer->handle); close_usb( context, transfer->handle);
return 0; return 0;

View File

@ -20,7 +20,7 @@
//LIBUSB_ENDPOINT_IN In: device-to-host. //LIBUSB_ENDPOINT_IN In: device-to-host.
//LIBUSB_ENDPOINT_OUT Out: host-to-device. //LIBUSB_ENDPOINT_OUT Out: host-to-device.
libusb_device_handle * open_usb_device( libusb_context *context ) libusb_device_handle * open_usb_device( libusb_context *context, int log_level )
{ {
int rv = 0; int rv = 0;
@ -28,23 +28,16 @@ libusb_device_handle * open_usb_device( libusb_context *context )
//libusb_context *context = NULL; //libusb_context *context = NULL;
//passed in from main //passed in from main
debug("Initalizing libusb"); if (log_level>0) printf("Initalizing libusb\n");
//initialize libusb must be called prior to any other libusb function //initialize libusb must be called prior to any other libusb function
//returns 0 on success LIBUSB_ERROR code on failure //returns 0 on success LIBUSB_ERROR code on failure
//int libusb_init ( libusb_context ** context) //int libusb_init ( libusb_context ** context)
int usb_init = libusb_init(&context); int usb_init = libusb_init(&context);
debug("Initalized libusb");
check( usb_init == LIBUSB_SUCCESS, "Failed to initialize libusb: %s", libusb_strerror(usb_init)); check( usb_init == LIBUSB_SUCCESS, "Failed to initialize libusb: %s", libusb_strerror(usb_init));
if (log_level>0) printf("Successfully initalized libusb\n");
//void libusb_set_debug ( libusb_context * ctx, int level ) //void libusb_set_debug ( libusb_context * ctx, int level )
libusb_set_debug(context, LIBUSB_LOG_LEVEL_ERROR); libusb_set_debug(context, log_level);
//LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default)
//LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr
//LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr
//LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout,
// warning and error messages are printed to stderr
//LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout,
// warnings and errors to stderr
//discover all usb devices //discover all usb devices
libusb_device **device_list = NULL; libusb_device **device_list = NULL;
@ -52,10 +45,10 @@ libusb_device_handle * open_usb_device( libusb_context *context )
// Returns a list of USB devices currently attached to the system. // Returns a list of USB devices currently attached to the system.
// return value is number of devices plus one as list is null terminated, or LIBUSB_ERROR if negative. // return value is number of devices plus one as list is null terminated, or LIBUSB_ERROR if negative.
// Must free device list after done with it // Must free device list after done with it
debug("getting device list"); if (log_level>0) printf("Getting USB device list\n");
ssize_t dev_count = libusb_get_device_list( context, &device_list); ssize_t dev_count = libusb_get_device_list( context, &device_list);
debug("got device list");
check( dev_count >= 0, "libusb unable to find any devices: %s", libusb_strerror(dev_count)); check( dev_count >= 0, "libusb unable to find any devices: %s", libusb_strerror(dev_count));
if (log_level>0) printf("Successfully retrieved USB device list\n");
ssize_t i = 0; ssize_t i = 0;
@ -77,34 +70,35 @@ libusb_device_handle * open_usb_device( libusb_context *context )
const char *rprog_prod = "INL Retro-Prog"; const char *rprog_prod = "INL Retro-Prog";
uint16_t min_fw_ver = 0x200; uint16_t min_fw_ver = 0x200;
debug("searching %d total devices", dev_count-1); if (log_level>0) printf("Searching %d total devices\n", dev_count-1);
for( i=0; i<dev_count; i++) { for( i=0; i<dev_count; i++) {
device = device_list[i]; device = device_list[i];
debug("getting dev desc %d", i); if (log_level>0) printf("getting dev desc #%d ", i);
rv = libusb_get_device_descriptor( device, &desc); rv = libusb_get_device_descriptor( device, &desc);
check( rv == LIBUSB_SUCCESS, "Unable to get device #%d descriptor: %s", i, libusb_strerror(rv)); check( rv == LIBUSB_SUCCESS, "Unable to get device #%d descriptor: %s", i, libusb_strerror(rv));
debug("checking %x vendor", desc.idVendor); if (log_level>0) printf("checking %x vendor ", desc.idVendor);
debug("checking %x product", desc.idProduct); if (log_level>0) printf("checking %x product\n", desc.idProduct);
if ((desc.idVendor == 0x16C0) && (desc.idProduct == 0x05DC)) { if ((desc.idVendor == 0x16C0) && (desc.idProduct == 0x05DC)) {
//Found a V-USB device with default VID/PID now see if it's actually a kazzo //Found a V-USB device with default VID/PID now see if it's actually a kazzo
debug("found vend %x prod %x\n", desc.idVendor, desc.idProduct); if (log_level>0) printf("found vend ID:%x prod ID:%x ", desc.idVendor, desc.idProduct);
debug("manf: %d prod: %d\n", desc.iManufacturer, desc.iProduct); if (log_level>0) printf("manf: %d prod: %d\n", desc.iManufacturer, desc.iProduct);
//opening device allows performing I/O via USB with device //opening device allows performing I/O via USB with device
rv = libusb_open( device, &handle ); rv = libusb_open( device, &handle );
check( rv == LIBUSB_SUCCESS, "Unable to open USB device: %s", libusb_strerror(rv)); check( rv == LIBUSB_SUCCESS, "Unable to open USB device: %s", libusb_strerror(rv));
if (log_level>0) printf("device opened successfully\n");
if (desc.iManufacturer) { if (desc.iManufacturer) {
if ( libusb_get_string_descriptor_ascii( handle, if ( libusb_get_string_descriptor_ascii( handle,
desc.iManufacturer, (unsigned char *)manf, sizeof(manf) ) > LIBUSB_SUCCESS) { desc.iManufacturer, (unsigned char *)manf, sizeof(manf) ) > LIBUSB_SUCCESS) {
debug("manf_ascii: %s\n",manf); if (log_level>0) printf("manf_ascii: %s\n",manf);
} }
} }
if (desc.iProduct) { if (desc.iProduct) {
if ( libusb_get_string_descriptor_ascii( handle, if ( libusb_get_string_descriptor_ascii( handle,
desc.iProduct, (unsigned char *)prod, sizeof(prod) ) > LIBUSB_SUCCESS) { desc.iProduct, (unsigned char *)prod, sizeof(prod) ) > LIBUSB_SUCCESS) {
debug("prod_ascii: %s\n",prod); if (log_level>0) printf("prod_ascii: %s\n",prod);
} }
} }
@ -116,11 +110,10 @@ libusb_device_handle * open_usb_device( libusb_context *context )
} }
if ( strcmp( manf, inl_manf) == 0) { if ( strcmp( manf, inl_manf) == 0) {
debug("INL manufactured device found."); if (log_level>0) printf("INL manufactured device found\n");
if ( strcmp( prod, rprog_prod) == 0) { if ( strcmp( prod, rprog_prod) == 0) {
debug("INL Retro-Prog found."); if (log_level>0) printf("INL Retro-Prog found\n");
debug("bcd Device fw version: %x required: %x", if (log_level>0) printf("bcd Device fw version: %x required: %x\n", desc.bcdDevice, min_fw_ver);
desc.bcdDevice, min_fw_ver);
if (desc.bcdDevice < min_fw_ver) { if (desc.bcdDevice < min_fw_ver) {
//close device since can't use it //close device since can't use it
log_warn("INL Retro-Prog found, but firmware is too old, see Readme for instructions to update firmware."); log_warn("INL Retro-Prog found, but firmware is too old, see Readme for instructions to update firmware.");
@ -134,15 +127,18 @@ libusb_device_handle * open_usb_device( libusb_context *context )
//Getting here means the device was opened because it matched V-USB //Getting here means the device was opened because it matched V-USB
//VID/PID, but it wasn't a compatible device. //VID/PID, but it wasn't a compatible device.
//Can't use this device, so close it //Can't use this device, so close it
if (log_level>0) printf("VID/PID matched, but manf/prod didn't match, closing device\n");
libusb_close(handle); libusb_close(handle);
handle = NULL; //Don't want to try and reclose handle = NULL; //Don't want to try and reclose
} }
} }
//looped through all devices retroprog will be assigned if it was found. //looped through all devices retroprog will be assigned if it was found.
check( retroprog != NULL, "Could not find INL retro-prog USB device"); check( retroprog != NULL, "Could not find INL retro-prog USB device");
if (log_level>0) printf("INL retro-prog USB device successfully found\n");
//free device list now that INL retro-prog was found and opened //free device list now that INL retro-prog was found and opened
//void libusb_free_device_list ( libusb_device ** list, int unref_devices ) //void libusb_free_device_list ( libusb_device ** list, int unref_devices )
if (log_level>0) printf("Freeing USB device list\n");
libusb_free_device_list( device_list, 1); //don't completely understand the unref_devices = 1... libusb_free_device_list( device_list, 1); //don't completely understand the unref_devices = 1...
device_list = NULL; //denote that device list is free if end up in error device_list = NULL; //denote that device list is free if end up in error
//Guess this is what you're supposed to do.. //Guess this is what you're supposed to do..
@ -166,6 +162,7 @@ libusb_device_handle * open_usb_device( libusb_context *context )
libusb_free_device_list( device_list, 1); libusb_free_device_list( device_list, 1);
} }
if (log_level>0) printf("Returning device handle to main\n");
return handle; return handle;
error: error:

View File

@ -97,7 +97,7 @@ typedef struct USBtransfer {
unsigned char *data; unsigned char *data;
} USBtransfer; } USBtransfer;
libusb_device_handle * open_usb_device( libusb_context *context ); libusb_device_handle * open_usb_device( libusb_context *context, int log_level );
void close_usb(libusb_context *context, libusb_device_handle *handle); void close_usb(libusb_context *context, libusb_device_handle *handle);

View File

@ -387,6 +387,11 @@
// 1% greater bus util compared to 254byte xfr // 1% greater bus util compared to 254byte xfr
// 2.2% speedup compared to 256 in 254 // 2.2% speedup compared to 256 in 254
// USB 1.1 Low speed 1.5Mbps
// maximum theoretical bus utiliation with transfers styles above
// 1.5Mbps * 33% utilization = 495Kbps = 61.8KBps
// Will never get to this maximum, as this assumes that bus is in use 100% of the time with no
// delays waiting for responses etc. But gives sense of scale for what's possible
// Probably decent overall speedup by eliminating multiple status packets. Not sure how many // Probably decent overall speedup by eliminating multiple status packets. Not sure how many
// NAK's the old firmware was sending while the device programmed the entire 256byte buffer. // NAK's the old firmware was sending while the device programmed the entire 256byte buffer.
@ -399,7 +404,7 @@
// start programming mid usb transfer once it's full. Want to make effor to hide flash programming // start programming mid usb transfer once it's full. Want to make effor to hide flash programming
// wait time behind usb transfer time. // wait time behind usb transfer time.
// some speed testing: // some speed testing with 16bit return length variable:
// 128Byte OUT (write) transfers with long transfers DISABLED: 20.04sec/512KByte = 25.55KBps // 128Byte OUT (write) transfers with long transfers DISABLED: 20.04sec/512KByte = 25.55KBps
// 128Byte OUT (write) transfers with long transfers ENABLED: 20.7 sec/512KByte = 24.7 KBps // 128Byte OUT (write) transfers with long transfers ENABLED: 20.7 sec/512KByte = 24.7 KBps
// 256Byte OUT (write) transfers with long transfers ENABLED: 18.56sec/512KByte = 27.6 KBps // 256Byte OUT (write) transfers with long transfers ENABLED: 18.56sec/512KByte = 27.6 KBps
@ -408,10 +413,23 @@
// 128Byte IN (read) with long xfr DISABLED, w/usbFuncRd: 34.9 sec/512KByte = 14.7 KBps // 128Byte IN (read) with long xfr DISABLED, w/usbFuncRd: 34.9 sec/512KByte = 14.7 KBps
// 1033*254Byte IN (read) long xfr DISABLED, w/o usbFuncRd: 28.35sec/512KByte = 18.1 KBps // 1033*254Byte IN (read) long xfr DISABLED, w/o usbFuncRd: 28.35sec/512KByte = 18.1 KBps
// //
// after concluding that would not be using long transfers, the return length variable
// was reduced to 8bits (single byte unsigned int) and slight improvement was found:
// 254Byte OUT (write) transfers with long transfers DISABLED: 17.5 sec/512KByte = 29.2 KBps (assuming 2 bytes stuffed in setup packet)
//
// adding a few checks to usbFunctionWrite to ensure buffer is proper status and not won't be overflowed
// presented small reduction in speed:
// 254Byte OUT (write) transfers with long transfers DISABLED: 18.1 sec/512KByte = 28.4 KBps (assuming 2 bytes stuffed in setup packet)
//
// These tests did nothing with payload once it arrived, so these are practical maximums of V-usb. // These tests did nothing with payload once it arrived, so these are practical maximums of V-usb.
// Conclusion: // Conclusion:
// -enabling long transfers slows writes (and probably reads) // -enabling long transfers slows writes (and probably reads)
// -reads are much slower than writes. // -reads are much slower than writes.
// found a vusb forum thread quoting 22KBps reads at transfer size of 200bytes
// he was using atmega16 with 12Mhz clock, so doesn't look like we can
// replicate this even with our 'better' conditions. But our
// writes are exceeding his 24KBps transfer speeds so we'll take it..
// https://forums.obdev.at/viewtopic.php?t=3059
// -enabling usbFunctionRead is slower compared to using usbFunctionSetup alone. // -enabling usbFunctionRead is slower compared to using usbFunctionSetup alone.
// -using 254B xfrs with 2 bytes stuffed in setup packet gives decent boost for writes. // -using 254B xfrs with 2 bytes stuffed in setup packet gives decent boost for writes.
// this is primarily due to speed up of not having long transfers enabled. // this is primarily due to speed up of not having long transfers enabled.
@ -422,6 +440,34 @@
// separate buffer and sent separately once full. // separate buffer and sent separately once full.
// Only other way without complicating dump algo would be to implement usbFuncRd // Only other way without complicating dump algo would be to implement usbFuncRd
// but that would slow things down and negate the speed boost.. // but that would slow things down and negate the speed boost..
//
// Speed testing with old firmware and app:
// fairly certain these were long transfers of 256 bytes each
// 512KB write 30.2sec = 16.7KBps
// 512KB read 34.2sec = 15.0KBps
//
// Haven't tested for comparison's sake, but original anago/unagi firmware/app was even slower I believe
// Found quote of Memblers finding ~19sec for 128KB PRG-ROM = 6.7KBps for reads...
// So shouldn't be hard to beat those speeds
//
// Checking SST 39SF040 datasheet, the byte program time is max 20usec * 256B page = 5.12usec per page
// We have some additional CPU execution time overhead above that 5.12usec per page
// but that shouldn't be significant in comparison, still lots of margin to meet 50usec usbPoll requirement
// if slow down is noticed during flashing/dumping may be helpful to call usbPoll mid page so
// the next data packet doesn't have to wait for the last page to complete before it can be accepted/sent
// to/from the driver.
//
// Sector erases are maximum of 25usec however which should probably be avoided or used with caution
// between usbPoll. However exiting back to main and continuing to poll USB and erasure should be fine
// as erasing doesn't have to be monitored.
//
// Chip erasure is max of 100usec which will most certainly violate 50usec usbPoll req't so make sure
// we don't sit and spin waiting for chip to erase without calling usbPoll...
//
// SNES 4-8MB chip erasure is on the order of 30sec so certainly need to be considerate of flash timing
// depending on the chip in use. Avoiding SNES chip erasure when possible presents large chance for
// speedup!
//
#endif #endif