From 7c141c231d6c5353054d65e5cf93169c5a9d85b4 Mon Sep 17 00:00:00 2001 From: Michael Copland Date: Tue, 21 Jun 2016 06:35:34 +0100 Subject: Rewritten to use libusb 1.0.20 from libusb.info --- commandline/library/micronucleus_lib.c | 247 ++++++++++++++++----------------- 1 file changed, 121 insertions(+), 126 deletions(-) (limited to 'commandline/library/micronucleus_lib.c') diff --git a/commandline/library/micronucleus_lib.c b/commandline/library/micronucleus_lib.c index 0569dbe..59ca62c 100644 --- a/commandline/library/micronucleus_lib.c +++ b/commandline/library/micronucleus_lib.c @@ -4,7 +4,7 @@ (c) 2012 by ihsan Kehribar Changes for Micronucleus protocol version V2.x (c) 2014 T. Bo"scke - + 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 @@ -31,97 +31,95 @@ #include "littleWire_util.h" micronucleus* micronucleus_connect(int fast_mode) { - 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.bcdDevice >> 8) & 0xFF; - nucleus->version.minor = dev->descriptor.bcdDevice & 0xFF; - - if (nucleus->version.major > MICRONUCLEUS_MAX_MAJOR_VERSION) { - fprintf(stderr, - "Warning: device with unknown new version of Micronucleus detected.\n" - "This tool doesn't know how to upload to this new device. Updates may be available.\n" - "Device reports version as: %d.%d\n", - nucleus->version.major, nucleus->version.minor); - return NULL; - } + if (libusb_init(NULL) < 0) return NULL; - nucleus->device = usb_open(dev); - - if (nucleus->version.major>=2) { // Version 2.x - // get nucleus info - unsigned char buffer[6]; - int res = usb_control_msg(nucleus->device, USB_ENDPOINT_IN| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, 0, (char *)buffer, 6, MICRONUCLEUS_USB_TIMEOUT); - - // Device descriptor was found, but talking to it was not succesful. This can happen when the device is being reset. - if (res<0) return NULL; - - assert(res >= 6); - - 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->bootloader_start = nucleus->pages*nucleus->page_size; - - if ((nucleus->version.major>=2)&&(!fast_mode)) { - // firmware v2 reports more aggressive write times. Add 2ms if fast mode is not used. - nucleus->write_sleep = (buffer[3] & 127) + 2; - } else { - nucleus->write_sleep = (buffer[3] & 127); - } - - // if bit 7 of write sleep time is set, divide the erase time by four to - // accomodate to the 4*page erase of the ATtiny841/441 - if (buffer[3]&128) { - nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages / 4; - } else { - nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; - } - - nucleus->signature1 = buffer[4]; - nucleus->signature2 = buffer[5]; - - } else { // Version 1.x - // get nucleus info - unsigned char buffer[4]; - int res = usb_control_msg(nucleus->device, USB_ENDPOINT_IN| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, 0, (char *)buffer, 4, MICRONUCLEUS_USB_TIMEOUT); - - // Device descriptor was found, but talking to it was not succesful. This can happen when the device is being reset. - if (res<0) return NULL; - - 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->bootloader_start = nucleus->pages*nucleus->page_size; - - nucleus->write_sleep = (buffer[3] & 127); - nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; - - nucleus->signature1 = 0; - nucleus->signature2 = 0; - } + micronucleus *nucleus = malloc(sizeof(micronucleus)); + + nucleus->device = libusb_open_device_with_vid_pid(NULL, MICRONUCLEUS_VENDOR_ID, MICRONUCLEUS_PRODUCT_ID); + + if (nucleus->device) { + libusb_device* dev = libusb_get_device(nucleus->device); + struct libusb_device_descriptor desc; + + if (libusb_get_device_descriptor(dev, &desc) < 0) { + fprintf(stderr, "failed to get device descriptor"); + return NULL; + } + + nucleus->version.major = (desc.bcdDevice >> 8) & 0xFF; + nucleus->version.minor = desc.bcdDevice & 0xFF; + + if (nucleus->version.major > MICRONUCLEUS_MAX_MAJOR_VERSION) { + fprintf(stderr, + "Warning: device with unknown new version of Micronucleus detected.\n" + "This tool doesn't know how to upload to this new device. Updates may be available.\n" + "Device reports version as: %d.%d\n", + nucleus->version.major, nucleus->version.minor); + return NULL; + } + + if (nucleus->version.major>=2) { // Version 2.x + // get nucleus info + unsigned char buffer[6]; + int res = libusb_control_transfer(nucleus->device, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE, 0, 0, 0, buffer, 6, MICRONUCLEUS_USB_TIMEOUT); + + // Device descriptor was found, but talking to it was not succesful. This can happen when the device is being reset. + if (res<0) return NULL; + + assert(res >= 6); + + 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->bootloader_start = nucleus->pages*nucleus->page_size; + + if ((nucleus->version.major>=2)&&(!fast_mode)) { + // firmware v2 reports more aggressive write times. Add 2ms if fast mode is not used. + nucleus->write_sleep = (buffer[3] & 127) + 2; + } else { + nucleus->write_sleep = (buffer[3] & 127); } + + // if bit 7 of write sleep time is set, divide the erase time by four to + // accomodate to the 4*page erase of the ATtiny841/441 + if (buffer[3]&128) { + nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages / 4; + } else { + nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; + } + + nucleus->signature1 = buffer[4]; + nucleus->signature2 = buffer[5]; + + } else { // Version 1.x + // get nucleus info + unsigned char buffer[4]; + int res = libusb_control_transfer(nucleus->device, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR |LIBUSB_RECIPIENT_DEVICE, 0, 0, 0, buffer, 4, MICRONUCLEUS_USB_TIMEOUT); + + // Device descriptor was found, but talking to it was not succesful. This can happen when the device is being reset. + if (res<0) return NULL; + + 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->bootloader_start = nucleus->pages*nucleus->page_size; + + nucleus->write_sleep = (buffer[3] & 127); + nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; + + nucleus->signature1 = 0; + nucleus->signature2 = 0; } + } else { + free(nucleus); + nucleus = NULL; } return nucleus; @@ -129,7 +127,7 @@ micronucleus* micronucleus_connect(int fast_mode) { int micronucleus_eraseFlash(micronucleus* deviceHandle, micronucleus_callback progress) { int res; - res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 2, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + res = libusb_control_transfer(deviceHandle->device, LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE, 2, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); // give microcontroller enough time to erase all writable pages and come back online float i = 0; @@ -154,7 +152,7 @@ int micronucleus_eraseFlash(micronucleus* deviceHandle, micronucleus_callback pr */ if (res == -5 || res == -34 || res == -84) { if (res == -34) { - usb_close(deviceHandle->device); + libusb_close(deviceHandle->device); deviceHandle->device = NULL; } @@ -172,15 +170,15 @@ int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_siz unsigned int res; unsigned int pagecontainsdata; unsigned int userReset; - + 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; } - - pagecontainsdata=0; + + pagecontainsdata=0; // copy in bytes from user program for (page_address = 0; page_address < page_length; page_address += 1) { @@ -192,7 +190,7 @@ int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_siz } } - // Reset vector patching is done in the host tool in micronucleus >=2 + // Reset vector patching is done in the host tool in micronucleus >=2 if (deviceHandle->version.major >=2) { if ( address == 0 ) { @@ -200,90 +198,90 @@ int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_siz unsigned int word0,word1; word0 = page_buffer [1] * 0x100 + page_buffer [0]; word1 = page_buffer [3] * 0x100 + page_buffer [2]; - + if (word0==0x940c) { // long jump - userReset = word1; + userReset = word1; } else if ((word0&0xf000)==0xc000) { // rjmp - userReset = (word0 & 0x0fff) - 0 + 1; + userReset = (word0 & 0x0fff) - 0 + 1; } else { fprintf(stderr, "The reset vector of the user program does not contain a branch instruction,\n" "therefore the bootloader can not be inserted. Please rearrage your code.\n" ); - return -1; - } - - // Patch in jmp to bootloader. + return -1; + } + + // Patch in jmp to bootloader. if (deviceHandle->bootloader_start > 0x2000) { // jmp unsigned data = 0x940c; page_buffer [ 0 ] = data >> 0 & 0xff; page_buffer [ 1 ] = data >> 8 & 0xff; page_buffer [ 2 ] = deviceHandle->bootloader_start >> 0 & 0xff; - page_buffer [ 3 ] = deviceHandle->bootloader_start >> 8 & 0xff; + page_buffer [ 3 ] = deviceHandle->bootloader_start >> 8 & 0xff; } else { // rjmp - unsigned data = 0xc000 | ((deviceHandle->bootloader_start/2 - 1) & 0x0fff); + unsigned data = 0xc000 | ((deviceHandle->bootloader_start/2 - 1) & 0x0fff); page_buffer [ 0 ] = data >> 0 & 0xff; page_buffer [ 1 ] = data >> 8 & 0xff; } - + } - + if ( address >= deviceHandle->bootloader_start - deviceHandle->page_size ) { // move user reset vector to end of last page // The reset vector is always the last vector in the tinyvectortable unsigned int user_reset_addr = (deviceHandle->pages*deviceHandle->page_size) - 4; - + if (user_reset_addr > 0x2000) { // jmp unsigned data = 0x940c; page_buffer [user_reset_addr - address + 0] = data >> 0 & 0xff; page_buffer [user_reset_addr - address + 1] = data >> 8 & 0xff; page_buffer [user_reset_addr - address + 2] = userReset >> 0 & 0xff; - page_buffer [user_reset_addr - address + 3] = userReset >> 8 & 0xff; + page_buffer [user_reset_addr - address + 3] = userReset >> 8 & 0xff; } else { // rjmp - unsigned data = 0xc000 | ((userReset - user_reset_addr/2 - 1) & 0x0fff); + unsigned data = 0xc000 | ((userReset - user_reset_addr/2 - 1) & 0x0fff); page_buffer [user_reset_addr - address + 0] = data >> 0 & 0xff; page_buffer [user_reset_addr - address + 1] = data >> 8 & 0xff; } } - } - - + } + + // always write last page so bootloader can insert the tiny vector table if ( address >= deviceHandle->bootloader_start - deviceHandle->page_size ) pagecontainsdata = 1; - + // ask microcontroller to write this page's data if (pagecontainsdata) { if (deviceHandle->version.major == 1) { // Firmware rev.1 transfers a page as a single block // ask microcontroller to write this page's data - res = usb_control_msg(deviceHandle->device, - USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, + res = libusb_control_transfer(deviceHandle->device, + LIBUSB_ENDPOINT_OUT| LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1, page_length, address, page_buffer, page_length, MICRONUCLEUS_USB_TIMEOUT); } else if (deviceHandle->version.major >= 2) { // Firmware rev.2 uses individual set up packets to transfer data - res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, page_length, address, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + res = libusb_control_transfer(deviceHandle->device, LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1, page_length, address, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); if (res) return -1; int i; - + for (i=0; i< page_length; i+=4) { int w1,w2; w1=(page_buffer[i+1]<<8)+(page_buffer[i+0]<<0); w2=(page_buffer[i+3]<<8)+(page_buffer[i+2]<<0); - - res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 3, w1, w2, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + + res = libusb_control_transfer(deviceHandle->device, LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE, 3, w1, w2, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); if (res) return -1; - } - } + } + } /* res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, @@ -291,13 +289,13 @@ int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_siz page_length, address, (char*)page_buffer, page_length, MICRONUCLEUS_USB_TIMEOUT); - + if (res != page_length) return -1; */ // give microcontroller enough time to write this page and come back online delay(deviceHandle->write_sleep); } - + // call progress update callback if that's a thing if (prog) prog(((float) address) / ((float) deviceHandle->flash_size)); @@ -311,13 +309,10 @@ int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_siz int micronucleus_startApp(micronucleus* deviceHandle) { int res; - res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 4, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + res = libusb_control_transfer(deviceHandle->device, LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE, 4, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); if(res!=0) return -1; else return 0; } - - - -- cgit v1.2.3