diff --git a/host/source/dictionary.c b/host/source/dictionary.c index eba7370..f777f34 100644 --- a/host/source/dictionary.c +++ b/host/source/dictionary.c @@ -16,18 +16,21 @@ */ //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); } //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); } -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->wValueMSB = miscdata; @@ -37,26 +40,32 @@ int dictionary_call_print_option( int print_debug; USBtransfer *transfer, uint8_ //default IN for now reading back error codes from short commands transfer->endpoint = endpoint; + transfer->wLength = length; //default length of zero - transfer->wLength = 0; +// transfer->wLength = 0; //return data buffer big enough for one data packet uint8_t rbuf[8]; - rbuf[0] = 0xA5; - rbuf[1] = 0xC3; - rbuf[2] = 0xA5; - rbuf[3] = 0xC3; - rbuf[4] = 0xA5; - rbuf[5] = 0xC3; - rbuf[6] = 0xA5; - rbuf[7] = 0xC3; - transfer->data = rbuf; + + if ( buffer == NULL ) { + rbuf[0] = 0xA5; + rbuf[1] = 0xC3; + rbuf[2] = 0xA5; + rbuf[3] = 0xC3; + rbuf[4] = 0xA5; + rbuf[5] = 0xC3; + rbuf[6] = 0xA5; + rbuf[7] = 0xC3; + transfer->data = rbuf; + } else { + transfer->data = buffer; + } debug("\ndictionary call dict:%d opcode:%d/%x addr:%x data:%x", dictionary, opcode, opcode, addr, miscdata); switch (dictionary) { case PINPORT: debug("dict: PINPORT"); - transfer->wLength = 1; + //transfer->wLength = 1; switch (opcode) { case PP_OPCODE_ONLY_MIN ... PP_OPCODE_ONLY_MAX: debug("PP_OPCODE_ONLY"); @@ -72,7 +81,7 @@ int dictionary_call_print_option( int print_debug; USBtransfer *transfer, uint8_ break; case PP_OPCODE_8BRV_MIN ... PP_OPCODE_8BRV_MAX: debug("PP_OPCODE_8BRV"); - transfer->wLength = 2; +// transfer->wLength = 2; break; default: //pinport opcode min/max definition error 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 case IO: debug("dict: IO"); - transfer->wLength = 1; +// transfer->wLength = 1; switch (opcode) { case IO_OPCODE_ONLY_MIN ... IO_OPCODE_ONLY_MAX: debug("IO_OPCODE_ONLY"); break; case IO_OPCODE_RTN_MIN ... IO_OPCODE_RTN_MAX: debug("IO_OPCODE_RTN"); - transfer->wLength = 8; +// transfer->wLength = 8; break; default: //io opcode min/max definition error 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 case NES: debug("dict: NES"); - transfer->wLength = 1; +// transfer->wLength = 1; switch (opcode) { case NES_OPCODE_24BOP_MIN ... NES_OPCODE_24BOP_MAX: debug("NES_OPCODE_24BOP"); break; case NES_OPCODE_16BOP_8BRV_MIN ... NES_OPCODE_16BOP_8BRV_MAX: debug("NES_OPCODE_16BOP_8BRV"); - transfer->wLength = 2; +// transfer->wLength = 2; break; default: //nes opcode min/max definition error 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 case SNES: debug("dict: SNES"); - transfer->wLength = 1; +// transfer->wLength = 1; switch (opcode) { case SNES_OPCODE_24BOP_MIN ... SNES_OPCODE_24BOP_MAX: debug("SNES_OPCODE_24BOP"); break; case SNES_OPCODE_24BOP_8BRV_MIN ... SNES_OPCODE_24BOP_8BRV_MAX: debug("SNES_OPCODE_24BOP_8BRV"); - transfer->wLength = 2; +// transfer->wLength = 2; break; default: //snes opcode min/max definition error 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 case BUFFER: debug("dict: BUFFER"); - transfer->wLength = length; +// transfer->wLength = length; if (buffer != NULL) { transfer->data = (unsigned char *)buffer; } break; //end of BUFF case USB: debug("dict: USB"); - transfer->wLength = length; +// transfer->wLength = length; break; default: diff --git a/host/source/dictionary.h b/host/source/dictionary.h index 5f7f7d4..26b10bc 100644 --- a/host/source/dictionary.h +++ b/host/source/dictionary.h @@ -19,13 +19,15 @@ #include "shared_errors.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 -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); +//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); -//dictionary call without printing output -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_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); #endif diff --git a/host/source/inlprog.c b/host/source/inlprog.c index 2ed7789..92c6da0 100644 --- a/host/source/inlprog.c +++ b/host/source/inlprog.c @@ -21,18 +21,38 @@ int main(int argc, char *argv[]) { - check(argc > 1, "USAGE: inlretro "); + //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 f_flag = 0; //LED OFF - int e_flag = 0; //ERASE - int m_flag = 0; //MIRROR - int t_flag = 0; //TEST - char *w_value = NULL; //WRITE FILE - char *d_value = NULL; //DUMP FILE - char *s_value = NULL; //SAVE FILE - char *i_value = NULL; //iNES MAPPER - char *b_value = NULL; //BOARD + int t_flag = 0; //test all SRAMs found + int x_flag = 0; //disable all auto detecting + int y_flag = 0; //diable all auto doubling + + char *b_value = NULL; //SUBMAPPER # + char *c_value = NULL; //CONSOLE NAME + char *d_value = NULL; //DUMP TO FILE + char *m_value = NULL; //MAPPER # + 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 rv = 0; @@ -41,53 +61,88 @@ int main(int argc, char *argv[]) //getopt returns args till done then returns -1 //string of possible args : denotes 1 required additional arg //:: 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) { 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 '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 'w': w_value = optarg; break; - case 'd': d_value = optarg; break; - case 's': s_value = optarg; break; - case 'i': i_value = optarg; break; + case 'x': x_flag = 1; break; + case 'y': y_flag = 1; break; + case 'T': T_flag = 1; 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 '?': - if ( optopt == 'w' ) { - log_err("Option -%c requires an argument.", optopt); - } else if ( optopt == 'd' ) { - log_err("Option -%c requires an argument.", optopt); - } else if ( optopt == 's' ) { - log_err("Option -%c requires an argument.", optopt); - } else if ( optopt == 'i' ) { - log_err("Option -%c requires an argument.", optopt); - } else if ( optopt == 'b' ) { + if(( optopt == 'b' ) + || ( optopt == 'c' ) + || ( optopt == 'd' ) + || ( optopt == 'm' ) + || ( optopt == 'p' ) + || ( optopt == 's' ) + || ( optopt == 'v' ) + || ( optopt == 'C' ) + || ( optopt == 'L' ) + || ( optopt == 'K' ) + || ( optopt == 'O' ) + || ( optopt == 'P' ) + || ( optopt == 'S' ) + || ( optopt == 'W' )){ log_err("Option -%c requires an argument.", optopt); + goto error; + } else if ( isprint(optopt)) { log_err("Unknown option -%c .", optopt); + goto error; } else { log_err("Unknown option character '\\x%x'", optopt); + goto error; } log_err("Improper arguements passed"); + goto error; break; default: 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++) { 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 libusb_context *context = NULL; - //create USBtransfer struct to hold all transfer info USBtransfer *transfer = malloc( sizeof(USBtransfer)); check_mem(transfer); @@ -96,21 +151,54 @@ int main(int argc, char *argv[]) //libusb_device_handle *rprog_handle = NULL; transfer->handle = NULL; - //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."); + + //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; uint8_t rbuf[8]; int i; - if (e_flag) erase_nes( transfer ); - if (t_flag) test_function( transfer ); - - //handle simple LED ON/OFF within main for now - if (o_flag | f_flag) { + if (o_flag | n_flag) { printf("before return buffer: "); for (i = 0; i < 8; i++) { rbuf[i] = 7; @@ -120,7 +208,7 @@ int main(int argc, char *argv[]) transfer->endpoint = USB_IN; transfer->request = PINPORT; 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->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); return 0; diff --git a/host/source/usb_operations.c b/host/source/usb_operations.c index 90a0105..4631ebd 100644 --- a/host/source/usb_operations.c +++ b/host/source/usb_operations.c @@ -20,7 +20,7 @@ //LIBUSB_ENDPOINT_IN In: device-to-host. //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; @@ -28,23 +28,16 @@ libusb_device_handle * open_usb_device( libusb_context *context ) //libusb_context *context = NULL; //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 //returns 0 on success LIBUSB_ERROR code on failure //int libusb_init ( libusb_context ** context) int usb_init = libusb_init(&context); - debug("Initalized libusb"); 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 ) - libusb_set_debug(context, LIBUSB_LOG_LEVEL_ERROR); - //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 + libusb_set_debug(context, log_level); //discover all usb devices 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. // 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 - 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); - debug("got device list"); 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; @@ -77,34 +70,35 @@ libusb_device_handle * open_usb_device( libusb_context *context ) const char *rprog_prod = "INL Retro-Prog"; 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; i0) printf("getting dev desc #%d ", i); rv = libusb_get_device_descriptor( device, &desc); check( rv == LIBUSB_SUCCESS, "Unable to get device #%d descriptor: %s", i, libusb_strerror(rv)); - debug("checking %x vendor", desc.idVendor); - debug("checking %x product", desc.idProduct); + if (log_level>0) printf("checking %x vendor ", desc.idVendor); + if (log_level>0) printf("checking %x product\n", desc.idProduct); if ((desc.idVendor == 0x16C0) && (desc.idProduct == 0x05DC)) { //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); - debug("manf: %d prod: %d\n", desc.iManufacturer, desc.iProduct); + if (log_level>0) printf("found vend ID:%x prod ID:%x ", desc.idVendor, desc.idProduct); + if (log_level>0) printf("manf: %d prod: %d\n", desc.iManufacturer, desc.iProduct); //opening device allows performing I/O via USB with device rv = libusb_open( device, &handle ); 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 ( libusb_get_string_descriptor_ascii( handle, 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 ( libusb_get_string_descriptor_ascii( handle, 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) { - debug("INL manufactured device found."); + if (log_level>0) printf("INL manufactured device found\n"); if ( strcmp( prod, rprog_prod) == 0) { - debug("INL Retro-Prog found."); - debug("bcd Device fw version: %x required: %x", - desc.bcdDevice, min_fw_ver); + if (log_level>0) printf("INL Retro-Prog found\n"); + if (log_level>0) printf("bcd Device fw version: %x required: %x\n", desc.bcdDevice, min_fw_ver); if (desc.bcdDevice < min_fw_ver) { //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."); @@ -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 //VID/PID, but it wasn't a compatible device. //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); handle = NULL; //Don't want to try and reclose } } //looped through all devices retroprog will be assigned if it was found. 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 //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... device_list = NULL; //denote that device list is free if end up in error //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); } + if (log_level>0) printf("Returning device handle to main\n"); return handle; error: diff --git a/host/source/usb_operations.h b/host/source/usb_operations.h index c2dc57a..3503ed4 100644 --- a/host/source/usb_operations.h +++ b/host/source/usb_operations.h @@ -97,7 +97,7 @@ typedef struct USBtransfer { unsigned char *data; } 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); diff --git a/shared/shared_dict_buffer.h b/shared/shared_dict_buffer.h index c790d29..60ae402 100644 --- a/shared/shared_dict_buffer.h +++ b/shared/shared_dict_buffer.h @@ -387,6 +387,11 @@ // 1% greater bus util compared to 254byte xfr // 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 // 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 // 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 ENABLED: 20.7 sec/512KByte = 24.7 KBps // 256Byte OUT (write) transfers with long transfers ENABLED: 18.56sec/512KByte = 27.6 KBps @@ -407,11 +412,24 @@ // 128Byte IN (read) with long xfr DISABLED, w/o usbFuncRd: 30.5 sec/512KByte = 16.8 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 -// +// +// 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. // Conclusion: // -enabling long transfers slows writes (and probably reads) // -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. // -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. @@ -422,6 +440,34 @@ // separate buffer and sent separately once full. // Only other way without complicating dump algo would be to implement usbFuncRd // 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