diff options
-rw-r--r-- | commandline/examples/micronucleus.c | 497 | ||||
-rw-r--r-- | commandline/library/micronucleus_lib.c | 242 | ||||
-rw-r--r-- | commandline/library/micronucleus_lib.h | 75 |
3 files changed, 435 insertions, 379 deletions
diff --git a/commandline/examples/micronucleus.c b/commandline/examples/micronucleus.c index c0530f2..5fb4c32 100644 --- a/commandline/examples/micronucleus.c +++ b/commandline/examples/micronucleus.c @@ -1,24 +1,24 @@ /* - Created: September 2012 - by ihsan Kehribar <ihsan@kehribar.me> - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: + Created: September 2012 + by ihsan Kehribar <ihsan@kehribar.me> + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. */ #include <stdio.h> @@ -30,11 +30,12 @@ #define FILE_TYPE_INTEL_HEX 1 #define FILE_TYPE_RAW 2 +#define CONNECT_WAIT 750 /* milliseconds to wait after detecting device on usb bus - probably excessive */ /****************************************************************************** * Global definitions ******************************************************************************/ -unsigned char dataBuffer[65536 + 256]; /* buffer for file data */ +unsigned char dataBuffer[65536 + 256]; /* buffer for file data */ /*****************************************************************************/ /****************************************************************************** @@ -44,246 +45,292 @@ static int parseRaw(char *hexfile, char* buffer, int *startAddr, int *endAddr); static int parseIntelHex(char *hexfile, char* buffer, int *startAddr, int *endAddr); /* taken from bootloadHID example from obdev */ static int parseUntilColon(FILE *fp); /* taken from bootloadHID example from obdev */ static int parseHex(FILE *fp, int numDigits); /* taken from bootloadHID example from obdev */ +static void printProgress(float progress); +static void setProgressData(char* friendly, int step); +static int progress_step = 0; // current step +static int progress_total_steps = 0; // total steps for upload +static char* progress_friendly_name; // name of progress section +static int dump_progress = 0; // output computer friendly progress info /*****************************************************************************/ /****************************************************************************** * Main function! ******************************************************************************/ -int main(int argc, char **argv) -{ - int res; - char *file = NULL; - micronucleus *myDevice = NULL; +int main(int argc, char **argv) { + int res; + char *file = NULL; + micronucleus *my_device = NULL; - // parse arguments - int run = 0; - int file_type = FILE_TYPE_INTEL_HEX; - int arg_pointer = 1; - char* usage = "usage: micronucleus [--run] [--type intel-hex|raw] [<intel-hexfile>|-]"; - - while (arg_pointer < argc) { - if (strcmp(argv[arg_pointer], "--run") == 0) { - run = 1; - } else if (strcmp(argv[arg_pointer], "--type") == 0) { - arg_pointer += 1; - if (strcmp(argv[arg_pointer], "intel-hex") == 0) { - file_type = FILE_TYPE_INTEL_HEX; - } else if (strcmp(argv[arg_pointer], "raw") == 0) { - file_type = FILE_TYPE_RAW; - } else { - printf("Unknown File Type specified with --type option"); - } - } else if (strcmp(argv[arg_pointer], "--help") == 0 || strcmp(argv[arg_pointer], "-h") == 0) { - puts(usage); - return EXIT_SUCCESS; - } else { - file = argv[arg_pointer]; - } - arg_pointer += 1; + // parse arguments + int run = 0; + int file_type = FILE_TYPE_INTEL_HEX; + int arg_pointer = 1; + char* usage = "usage: micronucleus [--run] [--dump-progress] [--type intel-hex|raw] [<intel-hexfile>|-]"; + progress_step = 0; + progress_total_steps = 5; // steps: waiting, connecting, parsing, erasing, writing, (running)? + dump_progress = 0; + + while (arg_pointer < argc) { + if (strcmp(argv[arg_pointer], "--run") == 0) { + run = 1; + progress_total_steps += 1; + } else if (strcmp(argv[arg_pointer], "--type") == 0) { + arg_pointer += 1; + if (strcmp(argv[arg_pointer], "intel-hex") == 0) { + file_type = FILE_TYPE_INTEL_HEX; + } else if (strcmp(argv[arg_pointer], "raw") == 0) { + file_type = FILE_TYPE_RAW; + } else { + printf("Unknown File Type specified with --type option"); + } + } else if (strcmp(argv[arg_pointer], "--help") == 0 || strcmp(argv[arg_pointer], "-h") == 0) { + puts(usage); + return EXIT_SUCCESS; + } else if (strcmp(argv[arg_pointer], "--dump-progress") == 0) { + dump_progress = 1; + } else { + file = argv[arg_pointer]; } - if (argc < 2) { - puts(usage); - return EXIT_FAILURE; - } - - - printf("> Please plug the device ... \n"); - printf("> Press CTRL+C to terminate the program.\n"); - - while(myDevice == NULL) - { - myDevice = micronucleus_connect(); - delay(250); - } - - printf("> Device is found!\n"); - - delay(750); - myDevice = micronucleus_connect(); - - if(myDevice->page_size == 64) - { - printf("> Device looks like ATtiny85!\n"); - } - else if(myDevice->page_size == 32) - { - printf("> Device looks like ATtiny45!\n"); - } - else - { - printf("> Unsupported device!\n"); - return EXIT_FAILURE; - } - - printf("> Available space for user application: %d bytes\n", myDevice->flash_size); - printf("> Suggested sleep time between sending pages: %ums\n", myDevice->write_sleep); - printf("> Whole page count: %d\n", myDevice->pages); - printf("> Erase function sleep duration: %dms\n", myDevice->erase_sleep); - - memset(dataBuffer, 0xFF, sizeof(dataBuffer)); + arg_pointer += 1; + } + + if (argc < 2) { + puts(usage); + return EXIT_FAILURE; + } + + setProgressData("waiting", 1); + printProgress(0.5); + printf("> Please plug the device ... \n"); + printf("> Press CTRL+C to terminate the program.\n"); + + while (my_device == NULL) { + my_device = micronucleus_connect(); + delay(250); + } + + printf("> Device is found!\n"); + + // wait for CONNECT_WAIT milliseconds with progress output + float wait = 0.0f; + setProgressData("connecting", 2); + while (wait < CONNECT_WAIT) { + printProgress((wait / ((float) CONNECT_WAIT)) * 0.9f); + wait += 50.0f; + delay(50); + } + + my_device = micronucleus_connect(); + printProgress(1.0); - int startAddress = 1, endAddress = 0; - if (file_type = FILE_TYPE_INTEL_HEX) { - if (parseIntelHex(file, dataBuffer, &startAddress, &endAddress)) { - printf("> Error loading or parsing hex file.\n"); - return EXIT_FAILURE; - } - } else if (FILE_TYPE_RAW) { - if (parseRaw(file, dataBuffer, &startAddress, &endAddress)) { - printf("> Error loading raw file.\n"); - return EXIT_FAILURE; - } + if (my_device->page_size == 64) { + printf("> Device looks like ATtiny85!\n"); + } + else if (my_device->page_size == 32) { + printf("> Device looks like ATtiny45!\n"); + } else { + printf("> Unsupported device!\n"); + return EXIT_FAILURE; + } + + printf("> Available space for user application: %d bytes\n", my_device->flash_size); + printf("> Suggested sleep time between sending pages: %ums\n", my_device->write_sleep); + printf("> Whole page count: %d\n", my_device->pages); + printf("> Erase function sleep duration: %dms\n", my_device->erase_sleep); + + setProgressData("parsing", 3); + printProgress(0.0); + memset(dataBuffer, 0xFF, sizeof(dataBuffer)); + + int startAddress = 1, endAddress = 0; + if (file_type = FILE_TYPE_INTEL_HEX) { + if (parseIntelHex(file, dataBuffer, &startAddress, &endAddress)) { + printf("> Error loading or parsing hex file.\n"); + return EXIT_FAILURE; } - - if(startAddress >= endAddress) - { - printf("> No data in input file, exiting.\n"); - return EXIT_FAILURE; - } - - if(endAddress > myDevice->flash_size) - { - printf("> Program file is %d bytes too big for the bootloader!\n", endAddress - myDevice->flash_size); - return EXIT_FAILURE; - } - - /* Prints the decoded intel hex file */ - /*printf("> Decoded hex file starts ... \n"); - for(i=startAddress;i<endAddress;i+=16) - { - printf("%5d:\t",i); - for(k=0;k<16;k++) - printf("%2X ",dataBuffer[i+k]); - printf("\n"); - } - printf("> Decoded hex file ends ... \n");*/ - - printf("> Erasing the memory ...\n"); - res = micronucleus_eraseFlash(myDevice); - if(res!=0) - { - printf(">> Abort mission! An error has occured ...\n"); - printf(">> Please unplug the device and restart the program. \n"); - return EXIT_FAILURE; - } - - printf("> Starting to upload ...\n"); - res = micronucleus_writeFlash(myDevice,endAddress,dataBuffer); - if(res!=0) - { - printf(">> Abort mission! An error has occured ...\n"); - printf(">> Please unplug the device and restart the program. \n"); - return EXIT_FAILURE; - } - - if (run) - { - printf("> Starting the user app ...\n"); - res = micronucleus_startApp(myDevice); - if(res!=0) - { - printf(">> Abort mission! An error has occured ...\n"); - printf(">> Please unplug the device and restart the program. \n"); - return EXIT_FAILURE; - } + } else if (FILE_TYPE_RAW) { + if (parseRaw(file, dataBuffer, &startAddress, &endAddress)) { + printf("> Error loading raw file.\n"); + return EXIT_FAILURE; } + } + + printProgress(1.0); - printf(">> Micronucleus done. Thank you!\n"); - - return EXIT_SUCCESS; + if (startAddress >= endAddress) { + printf("> No data in input file, exiting.\n"); + return EXIT_FAILURE; + } + + if (endAddress > my_device->flash_size) { + printf("> Program file is %d bytes too big for the bootloader!\n", endAddress - my_device->flash_size); + return EXIT_FAILURE; + } + + setProgressData("erasing", 4); + printf("> Erasing the memory ...\n"); + res = micronucleus_eraseFlash(my_device, printProgress); + if (res != 0) { + printf(">> Abort mission! An error has occured ...\n"); + printf(">> Please unplug the device and restart the program. \n"); + return EXIT_FAILURE; + } + printProgress(1.0); + + printf("> Starting to upload ...\n"); + setProgressData("writing", 5); + res = micronucleus_writeFlash(my_device, endAddress, dataBuffer, printProgress); + if (res != 0) { + printf(">> Abort mission! An error has occured ...\n"); + printf(">> Please unplug the device and restart the program. \n"); + return EXIT_FAILURE; + } + + if (run) { + + printf("> Starting the user app ...\n"); + setProgressData("running", 6); + printProgress(0.0); + + res = micronucleus_startApp(my_device); + + if (res != 0) { + printf(">> Abort mission! An error has occured ...\n"); + printf(">> Please unplug the device and restart the program. \n"); + return EXIT_FAILURE; + } + + printProgress(1.0); + } + + printf(">> Micronucleus done. Thank you!\n"); + + return EXIT_SUCCESS; } /******************************************************************************/ /******************************************************************************/ -static int parseUntilColon(FILE *fp) -{ -int c; +static void printProgress(float progress) { + static int last_step; + + if (dump_progress) { + printf("status:%s,step:%d,steps:%d,progress:%f\n", progress_friendly_name, progress_step, progress_total_steps, progress); + } else { + #ifndef WIN + if (last_step == progress_step) { + printf("\033[1F\033[2K"); // move cursor to previous line and erase last update in this progress sequence + } + #endif + printf("%s: %d%% complete\n", progress_friendly_name, (int) (progress * 100.0f)); + } + + last_step = progress_step; +} - do{ - c = getc(fp); - }while(c != ':' && c != EOF); - return c; +static void setProgressData(char* friendly, int step) { + progress_friendly_name = friendly; + progress_step = step; } /******************************************************************************/ /******************************************************************************/ -static int parseHex(FILE *fp, int numDigits) -{ -int i; -char temp[9]; - - for(i = 0; i < numDigits; i++) - temp[i] = getc(fp); - temp[i] = 0; - return strtol(temp, NULL, 16); +static int parseUntilColon(FILE *file_pointer) { + int character; + + do { + character = getc(file_pointer); + } while(character != ':' && character != EOF); + + return character; } /******************************************************************************/ /******************************************************************************/ -static int parseIntelHex(char *hexfile, char* buffer, int *startAddr, int *endAddr) -{ -int address, base, d, segment, i, lineLen, sum; -FILE *input; +static int parseHex(FILE *file_pointer, int num_digits) { + int iter; + char temp[9]; - input = strcmp(hexfile, "-") == 0 ? stdin : fopen(hexfile, "r"); - if(input == NULL){ - printf("> Error opening %s: %s\n", hexfile, strerror(errno)); - return 1; - } - while(parseUntilColon(input) == ':'){ - sum = 0; - sum += lineLen = parseHex(input, 2); - base = address = parseHex(input, 4); - sum += address >> 8; - sum += address; - sum += segment = parseHex(input, 2); /* segment value? */ - if(segment != 0) /* ignore lines where this byte is not 0 */ - continue; - for(i = 0; i < lineLen ; i++){ - d = parseHex(input, 2); - buffer[address++] = d; - sum += d; - } - sum += parseHex(input, 2); - if((sum & 0xff) != 0){ - printf("> Warning: Checksum error between address 0x%x and 0x%x\n", base, address); - } - if(*startAddr > base) - *startAddr = base; - if(*endAddr < address) - *endAddr = address; - } - fclose(input); - return 0; + for(iter = 0; iter < num_digits; iter++) { + temp[iter] = getc(file_pointer); + } + temp[iter] = 0; + + return strtol(temp, NULL, 16); } /******************************************************************************/ /******************************************************************************/ -static int parseRaw(char *filename, char* data_buffer, int *start_address, int *end_address) { - FILE *input; - - input = strcmp(filename, "-") == 0 ? stdin : fopen(filename, "r"); +static int parseIntelHex(char *hexfile, char* buffer, int *startAddr, int *endAddr) { + int address, base, d, segment, i, lineLen, sum; + FILE *input; + + input = strcmp(hexfile, "-") == 0 ? stdin : fopen(hexfile, "r"); + if (input == NULL) { + printf("> Error opening %s: %s\n", hexfile, strerror(errno)); + return 1; + } + + while (parseUntilColon(input) == ':') { + sum = 0; + sum += lineLen = parseHex(input, 2); + base = address = parseHex(input, 4); + sum += address >> 8; + sum += address; + sum += segment = parseHex(input, 2); /* segment value? */ + if (segment != 0) { /* ignore lines where this byte is not 0 */ + continue; + } - if (input == NULL) { - printf("> Error reading %s: %s\n", filename, strerror(errno)); - return 1; + for (i = 0; i < lineLen; i++) { + d = parseHex(input, 2); + buffer[address++] = d; + sum += d; } - *start_address = 0; - *end_address = 0; + sum += parseHex(input, 2); + if ((sum & 0xff) != 0) { + printf("> Warning: Checksum error between address 0x%x and 0x%x\n", base, address); + } - // read in bytes from file - int byte = 0; - while (1) { - byte = getc(input); - if (byte == EOF) break; - - *data_buffer = byte; - data_buffer += 1; - *end_address += 1; + if(*startAddr > base) { + *startAddr = base; } + if(*endAddr < address) { + *endAddr = address; + } + } + + fclose(input); + return 0; +} +/******************************************************************************/ + +/******************************************************************************/ +static int parseRaw(char *filename, char* data_buffer, int *start_address, int *end_address) { + FILE *input; + + input = strcmp(filename, "-") == 0 ? stdin : fopen(filename, "r"); + + if (input == NULL) { + printf("> Error reading %s: %s\n", filename, strerror(errno)); + return 1; + } + + *start_address = 0; + *end_address = 0; + + // read in bytes from file + int byte = 0; + while (1) { + byte = getc(input); + if (byte == EOF) break; - fclose(input); - return 0; + *data_buffer = byte; + data_buffer += 1; + *end_address += 1; + } + + fclose(input); + return 0; } /******************************************************************************/ diff --git a/commandline/library/micronucleus_lib.c b/commandline/library/micronucleus_lib.c index a719690..2e63425 100644 --- a/commandline/library/micronucleus_lib.c +++ b/commandline/library/micronucleus_lib.c @@ -1,24 +1,24 @@ /* - Created: September 2012 - by ihsan Kehribar <ihsan@kehribar.me> - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: + Created: September 2012 + by ihsan Kehribar <ihsan@kehribar.me> + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. */ /***************************************************************/ @@ -27,114 +27,120 @@ #include "micronucleus_lib.h" #include "littleWire_util.h" -micronucleus* micronucleus_connect() -{ - micronucleus *nucleus = NULL; - struct usb_bus *busses; - - // intialise usb and find micronucleus device - usb_init(); - usb_find_busses(); - usb_find_devices(); - - busses = usb_get_busses(); - struct usb_bus *bus; - for (bus = busses; bus; bus = bus->next) - { - struct usb_device *dev; - - for (dev = bus->devices; dev; dev = dev->next) - { - /* Check if this device is a micronucleus */ - if (dev->descriptor.idVendor == MICRONUCLEUS_VENDOR_ID && dev->descriptor.idProduct == MICRONUCLEUS_PRODUCT_ID) - { - nucleus = malloc(sizeof(micronucleus)); - nucleus->version.major = (dev->descriptor.bcdUSB >> 8) & 0xFF; - nucleus->version.minor = dev->descriptor.bcdUSB & 0xFF; - nucleus->device = usb_open(dev); - - // get nucleus info - unsigned char buffer[4]; - int res = usb_control_msg(nucleus->device, 0xC0, 0, 0, 0, buffer, 4, MICRONUCLEUS_USB_TIMEOUT); - assert(res == 4); - - nucleus->flash_size = (buffer[0]<<8) + buffer[1]; - nucleus->page_size = buffer[2]; - nucleus->pages = (nucleus->flash_size / nucleus->page_size); - if (nucleus->pages * nucleus->page_size < nucleus->flash_size) nucleus->pages += 1; - nucleus->write_sleep = buffer[3]; - nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; - } - } - } +micronucleus* micronucleus_connect() { + micronucleus *nucleus = NULL; + struct usb_bus *busses; + + // intialise usb and find micronucleus device + usb_init(); + usb_find_busses(); + usb_find_devices(); + + busses = usb_get_busses(); + struct usb_bus *bus; + for (bus = busses; bus; bus = bus->next) { + struct usb_device *dev; + + for (dev = bus->devices; dev; dev = dev->next) { + /* Check if this device is a micronucleus */ + if (dev->descriptor.idVendor == MICRONUCLEUS_VENDOR_ID && dev->descriptor.idProduct == MICRONUCLEUS_PRODUCT_ID) { + nucleus = malloc(sizeof(micronucleus)); + nucleus->version.major = (dev->descriptor.bcdUSB >> 8) & 0xFF; + nucleus->version.minor = dev->descriptor.bcdUSB & 0xFF; + nucleus->device = usb_open(dev); + + // get nucleus info + unsigned char buffer[4]; + int res = usb_control_msg(nucleus->device, 0xC0, 0, 0, 0, buffer, 4, MICRONUCLEUS_USB_TIMEOUT); + assert(res == 4); + + nucleus->flash_size = (buffer[0]<<8) + buffer[1]; + nucleus->page_size = buffer[2]; + nucleus->pages = (nucleus->flash_size / nucleus->page_size); + if (nucleus->pages * nucleus->page_size < nucleus->flash_size) nucleus->pages += 1; + nucleus->write_sleep = buffer[3]; + nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; + } + } + } - return nucleus; + return nucleus; } -int micronucleus_eraseFlash(micronucleus* deviceHandle) -{ - int res; - res = usb_control_msg(deviceHandle->device, 0xC0, 2, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); - - // give microcontroller enough time to erase all writable pages and come back online - delay(deviceHandle->erase_sleep); - - if(res!=0) - return -1; - else - return 0; +int micronucleus_eraseFlash(micronucleus* deviceHandle, micronucleus_callback progress) { + int res; + res = usb_control_msg(deviceHandle->device, 0xC0, 2, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + + // give microcontroller enough time to erase all writable pages and come back online + float i = 0; + while (i < 1.0) { + // update progress callback if one was supplied + if (progress) progress(i); + + delay(((float) deviceHandle->erase_sleep) / 100.0f); + i += 0.01; + } + + if(res!=0) + return -1; + else + return 0; } -int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_size, unsigned char* program) -{ - unsigned char page_length = deviceHandle->page_size; - unsigned char page_buffer[page_length]; - unsigned int address; // overall flash memory address - unsigned int page_address; // address within this page when copying buffer - unsigned int res; +int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_size, unsigned char* program, micronucleus_callback prog) { + unsigned char page_length = deviceHandle->page_size; + unsigned char page_buffer[page_length]; + unsigned int address; // overall flash memory address + unsigned int page_address; // address within this page when copying buffer + unsigned int res; - for (address = 0; address < deviceHandle->flash_size; address += deviceHandle->page_size) { - // work around a bug in older bootloader versions - if (deviceHandle->version.major == 1 && deviceHandle->version.minor <= 2 - && address / deviceHandle->page_size == deviceHandle->pages - 1) { - page_length = deviceHandle->flash_size % deviceHandle->page_size; - } - - // copy in bytes from user program - for (page_address = 0; page_address < page_length; page_address += 1) { - if (address + page_address > program_size) { - page_buffer[page_address] = 0xFF; // pad out remainder with unprogrammed bytes - } else { - page_buffer[page_address] = program[address + page_address]; // load from user program - } - } - - // ask microcontroller to write this page's data - res = usb_control_msg(deviceHandle->device, - USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 1, - page_length, address, - page_buffer, page_length, - MICRONUCLEUS_USB_TIMEOUT); - - // give microcontroller enough time to write this page and come back online - delay(deviceHandle->write_sleep); - - if (res != 64) return -1; - } - - return 0; + for (address = 0; address < deviceHandle->flash_size; address += deviceHandle->page_size) { + // work around a bug in older bootloader versions + if (deviceHandle->version.major == 1 && deviceHandle->version.minor <= 2 + && address / deviceHandle->page_size == deviceHandle->pages - 1) { + page_length = deviceHandle->flash_size % deviceHandle->page_size; + } + + // copy in bytes from user program + for (page_address = 0; page_address < page_length; page_address += 1) { + if (address + page_address > program_size) { + page_buffer[page_address] = 0xFF; // pad out remainder with unprogrammed bytes + } else { + page_buffer[page_address] = program[address + page_address]; // load from user program + } + } + + // ask microcontroller to write this page's data + res = usb_control_msg(deviceHandle->device, + USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, + page_length, address, + page_buffer, page_length, + MICRONUCLEUS_USB_TIMEOUT); + + // call progress update callback if that's a thing + if (prog) prog(((float) address) / ((float) deviceHandle->flash_size)); + + // give microcontroller enough time to write this page and come back online + delay(deviceHandle->write_sleep); + + if (res != 64) return -1; + } + + // call progress update callback with completion status + if (prog) prog(1.0); + + return 0; } -int micronucleus_startApp(micronucleus* deviceHandle) -{ - int res; - res = usb_control_msg(deviceHandle->device, 0xC0, 4, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); - - if(res!=0) - return -1; - else - return 0; +int micronucleus_startApp(micronucleus* deviceHandle) { + int res; + res = usb_control_msg(deviceHandle->device, 0xC0, 4, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + + if(res!=0) + return -1; + else + return 0; } diff --git a/commandline/library/micronucleus_lib.h b/commandline/library/micronucleus_lib.h index dcbac83..d022877 100644 --- a/commandline/library/micronucleus_lib.h +++ b/commandline/library/micronucleus_lib.h @@ -2,46 +2,46 @@ #define MICRONUCLEUS_LIB_H /* - Created: September 2012 - by ihsan Kehribar <ihsan@kehribar.me> - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: + Created: September 2012 + by ihsan Kehribar <ihsan@kehribar.me> + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. */ /******************************************************************************** * Header files ********************************************************************************/ #if defined WIN - #include <lusb0_usb.h> // this is libusb, see http://libusb.sourceforge.net/ + #include <lusb0_usb.h> // this is libusb, see http://libusb.sourceforge.net/ #else - #include <usb.h> // this is libusb, see http://libusb.sourceforge.net/ + #include <usb.h> // this is libusb, see http://libusb.sourceforge.net/ #endif -//#include "opendevice.h" // common code moved to separate module +//#include "opendevice.h" // common code moved to separate module #include <assert.h> /*******************************************************************************/ /******************************************************************************** * USB details ********************************************************************************/ -#define MICRONUCLEUS_VENDOR_ID 0x16D0 -#define MICRONUCLEUS_PRODUCT_ID 0x0753 -#define MICRONUCLEUS_USB_TIMEOUT 0xFFFF +#define MICRONUCLEUS_VENDOR_ID 0x16D0 +#define MICRONUCLEUS_PRODUCT_ID 0x0753 +#define MICRONUCLEUS_USB_TIMEOUT 0xFFFF /*******************************************************************************/ /******************************************************************************** @@ -50,22 +50,24 @@ //typedef usb_dev_handle micronucleus; // representing version number of micronucleus device typedef struct _micronucleus_version { - unsigned char major; - unsigned char minor; + unsigned char major; + unsigned char minor; } micronucleus_version; // handle representing one micronucleus device typedef struct _micronucleus { - usb_dev_handle *device; - // general information about device - micronucleus_version version; - unsigned int flash_size; // programmable size (in bytes) of progmem - unsigned int page_size; // size (in bytes) of page - unsigned int pages; // total number of pages to program - unsigned int write_sleep; // milliseconds - unsigned int erase_sleep; // milliseconds + usb_dev_handle *device; + // general information about device + micronucleus_version version; + unsigned int flash_size; // programmable size (in bytes) of progmem + unsigned int page_size; // size (in bytes) of page + unsigned int pages; // total number of pages to program + unsigned int write_sleep; // milliseconds + unsigned int erase_sleep; // milliseconds } micronucleus; +typedef void (*micronucleus_callback)(float progress); + /*******************************************************************************/ /******************************************************************************** @@ -78,13 +80,14 @@ micronucleus* micronucleus_connect(); /******************************************************************************** * Erase the flash memory ********************************************************************************/ -int micronucleus_eraseFlash(micronucleus* deviceHandle); +int micronucleus_eraseFlash(micronucleus* deviceHandle, micronucleus_callback progress); /*******************************************************************************/ /******************************************************************************** * Write the flash memory ********************************************************************************/ -int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_length, unsigned char* program); +int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_length, + unsigned char* program, micronucleus_callback progress); /*******************************************************************************/ /******************************************************************************** |