diff --git a/src/micronucleus.c b/src/micronucleus.c index 8bbc596a..9ca911c5 100644 --- a/src/micronucleus.c +++ b/src/micronucleus.c @@ -18,23 +18,25 @@ * along with this program. If not, see . */ -// Notes: -// This file adds support for the Micronucleus bootloader V1 and V2, -// so you do no longer need the Micronucleus command-line utility. -// -// This bootloader is typically used on small ATtiny boards, -// such as Digispark (ATtiny85), Digispark Pro (ATtiny167), -// and the respective clones. -// By default, it bootloader uses the VID/PID 16d0:0753 (MCS Digistump). -// -// As the micronucleus bootloader is optimized for size, it implements -// writing to flash memory only. Since it does not support reading, -// use the -V option to prevent avrdude from verifing the flash memory. -// To have avrdude wait for the device to be connected, use the -// extended option '-x wait'. -// -// Example: -// avrdude -c micronucleus -p t85 -x wait -V -U flash:w:main.hex +/* + * Notes: + * This file adds support for the Micronucleus bootloader V1 and V2, + * so you do no longer need the Micronucleus command-line utility. + * + * This bootloader is typically used on small ATtiny boards, + * such as Digispark (ATtiny85), Digispark Pro (ATtiny167), + * and the respective clones. + * By default, it bootloader uses the VID/PID 16d0:0753 (MCS Digistump). + * + * As the micronucleus bootloader is optimized for size, it implements + * writing to flash memory only. Since it does not support reading, + * use the -V option to prevent avrdude from verifing the flash memory. + * To have avrdude wait for the device to be connected, use the + * extended option '-x wait'. + * + * Example: + * avrdude -c micronucleus -p t85 -x wait -V -U flash:w:main.hex + */ #include #include @@ -59,7 +61,7 @@ #error "libusb needs either or " #endif -//----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- #define MICRONUCLEUS_VID 0x16D0 #define MICRONUCLEUS_PID 0x0753 @@ -77,485 +79,434 @@ #define PDATA(pgm) ((struct pdata *)(pgm->cookie)) -//----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- struct pdata { - usb_dev_handle* usb_handle; - // Extended parameters - bool wait_until_device_present; - int wait_timout; // in seconds - // Bootloader version - uint8_t major_version; - uint8_t minor_version; - // Bootloader info (via USB request) - uint16_t flash_size; // programmable size (in bytes) of flash - uint8_t page_size; // size (in bytes) of page - uint8_t write_sleep; // milliseconds - uint8_t signature1; // only used in protocol v2 - uint8_t signature2; // only used in protocol v2 - // Calculated bootloader info - uint16_t pages; // total number of pages to program - uint16_t bootloader_start; // start of the bootloader (at page boundary) - uint16_t erase_sleep; // milliseconds - // State - uint16_t user_reset_vector; // reset vector of user program - bool write_last_page; // last page already programmed - bool start_program; // require start after flash + usb_dev_handle *usb_handle; + // Extended parameters + bool wait_until_device_present; + int wait_timout; // In seconds + // Bootloader version + uint8_t major_version; + uint8_t minor_version; + // Bootloader info (via USB request) + uint16_t flash_size; // Programmable size (in bytes) of flash + uint8_t page_size; // Size (in bytes) of page + uint8_t write_sleep; // Milliseconds + uint8_t signature1; // Only used in protocol v2 + uint8_t signature2; // Only used in protocol v2 + // Calculated bootloader info + uint16_t pages; // Total number of pages to program + uint16_t bootloader_start; // Start of the bootloader (at page boundary) + uint16_t erase_sleep; // Milliseconds + // State + uint16_t user_reset_vector; // Reset vector of user program + bool write_last_page; // Last page already programmed + bool start_program; // Require start after flash }; -//----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- -static void delay_ms(uint32_t duration) -{ - usleep(duration * 1000); +static void delay_ms(uint32_t duration) { + usleep(duration*1000); } static int micronucleus_check_connection(struct pdata *pdata) { - if (pdata->major_version >= 2) - { - uint8_t buffer[6] = { 0 }; - int result = usb_control_msg( - pdata->usb_handle, - USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - MICRONUCLEUS_CMD_INFO, - 0, 0, - (char*)buffer, sizeof(buffer), - MICRONUCLEUS_DEFAULT_TIMEOUT); - if(result < 0) - cx->usb_access_error = 1; - return result == sizeof(buffer) ? 0 : -1; - } - else - { - uint8_t buffer[4] = { 0 }; - int result = usb_control_msg( - pdata->usb_handle, - USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - MICRONUCLEUS_CMD_INFO, - 0, 0, - (char*)buffer, sizeof(buffer), - MICRONUCLEUS_DEFAULT_TIMEOUT); - if(result < 0) - cx->usb_access_error = 1; - return result == sizeof(buffer) ? 0 : -1; - } + if(pdata->major_version >= 2) { + uint8_t buffer[6] = { 0 }; + int result = usb_control_msg(pdata->usb_handle, + USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MICRONUCLEUS_CMD_INFO, + 0, 0, + (char *) buffer, sizeof(buffer), + MICRONUCLEUS_DEFAULT_TIMEOUT); + + if(result < 0) + cx->usb_access_error = 1; + return result == sizeof(buffer)? 0: -1; + } else { + uint8_t buffer[4] = { 0 }; + int result = usb_control_msg(pdata->usb_handle, + USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MICRONUCLEUS_CMD_INFO, + 0, 0, + (char *) buffer, sizeof(buffer), + MICRONUCLEUS_DEFAULT_TIMEOUT); + + if(result < 0) + cx->usb_access_error = 1; + return result == sizeof(buffer)? 0: -1; + } } static bool micronucleus_is_device_responsive(struct pdata *pdata, struct usb_device *device) { - pdata->usb_handle = usb_open(device); - if (pdata->usb_handle == NULL) - { - return false; - } + pdata->usb_handle = usb_open(device); + if(pdata->usb_handle == NULL) { + return false; + } - int result = micronucleus_check_connection(pdata); + int result = micronucleus_check_connection(pdata); - usb_close(pdata->usb_handle); - pdata->usb_handle = NULL; + usb_close(pdata->usb_handle); + pdata->usb_handle = NULL; - return result >= 0; + return result >= 0; } static int micronucleus_reconnect(struct pdata *pdata) { - struct usb_device* device = usb_device(pdata->usb_handle); + struct usb_device *device = usb_device(pdata->usb_handle); - usb_close(pdata->usb_handle); - pdata->usb_handle = NULL; + usb_close(pdata->usb_handle); + pdata->usb_handle = NULL; - for (int i = 0; i < 25; i++) - { - pmsg_notice("trying to reconnect ...\n"); + for(int i = 0; i < 25; i++) { + pmsg_notice("trying to reconnect ...\n"); - pdata->usb_handle = usb_open(device); - if (pdata->usb_handle != NULL) - return 0; + pdata->usb_handle = usb_open(device); + if(pdata->usb_handle != NULL) + return 0; - delay_ms(MICRONUCLEUS_CONNECT_WAIT); - } + delay_ms(MICRONUCLEUS_CONNECT_WAIT); + } - return -1; + return -1; } static int micronucleus_get_bootloader_info_v1(struct pdata *pdata) { - uint8_t buffer[4] = { 0 }; - int result = usb_control_msg( - pdata->usb_handle, - USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - MICRONUCLEUS_CMD_INFO, - 0, 0, - (char*)buffer, sizeof(buffer), - MICRONUCLEUS_DEFAULT_TIMEOUT); - if (result < 0) - { - pmsg_warning("unable to get bootloader info block: %s\n", usb_strerror()); - return result; - } - else if ((size_t) result < sizeof(buffer)) - { - pmsg_warning("received invalid bootloader info block size: %d\n", result); - return -1; - } + uint8_t buffer[4] = { 0 }; + int result = usb_control_msg(pdata->usb_handle, + USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MICRONUCLEUS_CMD_INFO, + 0, 0, + (char *) buffer, sizeof(buffer), + MICRONUCLEUS_DEFAULT_TIMEOUT); - pdata->flash_size = (buffer[0] << 8) | buffer[1]; - pdata->page_size = buffer[2]; - pdata->write_sleep = buffer[3] & 127; + if(result < 0) { + pmsg_warning("unable to get bootloader info block: %s\n", usb_strerror()); + return result; + } else if((size_t) result < sizeof(buffer)) { + pmsg_warning("received invalid bootloader info block size: %d\n", result); + return -1; + } - // Take a wild guess on the part ID, so that we can supply it for device verification - if (pdata->page_size == 128) - { - // ATtiny167 - pdata->signature1 = 0x94; - pdata->signature2 = 0x87; - } - else if (pdata->page_size == 64) - { - if (pdata->flash_size > 4096) - { - // ATtiny85 - pdata->signature1 = 0x93; - pdata->signature2 = 0x0B; - } - else - { - // ATtiny45 - pdata->signature1 = 0x92; - pdata->signature2 = 0x06; - } - } - else if (pdata->page_size == 16) - { - // ATtiny841 - pdata->signature1 = 0x93; - pdata->signature2 = 0x15; - } - else - { - // Unknown device - pdata->signature1 = 0; - pdata->signature2 = 0; - } + pdata->flash_size = (buffer[0] << 8) | buffer[1]; + pdata->page_size = buffer[2]; + pdata->write_sleep = buffer[3] & 127; - pdata->pages = (pdata->flash_size + pdata->page_size - 1) / pdata->page_size; - pdata->bootloader_start = pdata->pages * pdata->page_size; - pdata->erase_sleep = pdata->write_sleep * pdata->pages; + // Take a wild guess on the part ID, so that we can supply it for device verification + if(pdata->page_size == 128) { + // ATtiny167 + pdata->signature1 = 0x94; + pdata->signature2 = 0x87; + } else if(pdata->page_size == 64) { + if(pdata->flash_size > 4096) { + // ATtiny85 + pdata->signature1 = 0x93; + pdata->signature2 = 0x0B; + } else { + // ATtiny45 + pdata->signature1 = 0x92; + pdata->signature2 = 0x06; + } + } else if(pdata->page_size == 16) { + // ATtiny841 + pdata->signature1 = 0x93; + pdata->signature2 = 0x15; + } else { + // Unknown device + pdata->signature1 = 0; + pdata->signature2 = 0; + } - return 0; + pdata->pages = (pdata->flash_size + pdata->page_size - 1)/pdata->page_size; + pdata->bootloader_start = pdata->pages*pdata->page_size; + pdata->erase_sleep = pdata->write_sleep*pdata->pages; + + return 0; } static int micronucleus_get_bootloader_info_v2(struct pdata *pdata) { - uint8_t buffer[6] = { 0 }; - int result = usb_control_msg( - pdata->usb_handle, - USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - MICRONUCLEUS_CMD_INFO, - 0, 0, - (char*)buffer, sizeof(buffer), - MICRONUCLEUS_DEFAULT_TIMEOUT); - if (result < 0) - { - pmsg_warning("unable to get bootloader info block: %s\n", usb_strerror()); - return result; - } - else if ((size_t) result < sizeof(buffer)) - { - pmsg_warning("received invalid bootloader info block size: %d\n", result); - return -1; - } + uint8_t buffer[6] = { 0 }; + int result = usb_control_msg(pdata->usb_handle, + USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MICRONUCLEUS_CMD_INFO, + 0, 0, + (char *) buffer, sizeof(buffer), + MICRONUCLEUS_DEFAULT_TIMEOUT); - pdata->flash_size = (buffer[0] << 8) + buffer[1]; - pdata->page_size = buffer[2]; - pdata->write_sleep = (buffer[3] & 127) + 2; - pdata->signature1 = buffer[4]; - pdata->signature2 = buffer[5]; + if(result < 0) { + pmsg_warning("unable to get bootloader info block: %s\n", usb_strerror()); + return result; + } else if((size_t) result < sizeof(buffer)) { + pmsg_warning("received invalid bootloader info block size: %d\n", result); + return -1; + } - pdata->pages = (pdata->flash_size + pdata->page_size - 1) / pdata->page_size; - pdata->bootloader_start = pdata->pages * pdata->page_size; - pdata->erase_sleep = pdata->write_sleep * pdata->pages; + pdata->flash_size = (buffer[0] << 8) + buffer[1]; + pdata->page_size = buffer[2]; + pdata->write_sleep = (buffer[3] & 127) + 2; + pdata->signature1 = buffer[4]; + pdata->signature2 = buffer[5]; - // 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) != 0) - { - pdata->erase_sleep /= 4; - } + pdata->pages = (pdata->flash_size + pdata->page_size - 1)/pdata->page_size; + pdata->bootloader_start = pdata->pages*pdata->page_size; + pdata->erase_sleep = pdata->write_sleep*pdata->pages; - return 0; + /* + * 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) != 0) { + pdata->erase_sleep /= 4; + } + + return 0; } static int micronucleus_get_bootloader_info(struct pdata *pdata) { - if (pdata->major_version >= 2) - { - return micronucleus_get_bootloader_info_v2(pdata); - } - else - { - return micronucleus_get_bootloader_info_v1(pdata); - } + if(pdata->major_version >= 2) { + return micronucleus_get_bootloader_info_v2(pdata); + } else { + return micronucleus_get_bootloader_info_v1(pdata); + } } static void micronucleus_dump_device_info(struct pdata *pdata) { - pmsg_notice("Bootloader version: %d.%d\n", pdata->major_version, pdata->minor_version); - imsg_notice("Available flash size: %u\n", pdata->flash_size); - imsg_notice("Page size: %u\n", pdata->page_size); - imsg_notice("Bootloader start: 0x%04X\n", pdata->bootloader_start); - imsg_notice("Write sleep: %ums\n", pdata->write_sleep); - imsg_notice("Erase sleep: %ums\n", pdata->erase_sleep); - imsg_notice("Signature1: 0x%02X\n", pdata->signature1); - imsg_notice("Signature2: 0x%02X\n", pdata->signature2); + pmsg_notice("Bootloader version: %d.%d\n", pdata->major_version, pdata->minor_version); + imsg_notice("Available flash size: %u\n", pdata->flash_size); + imsg_notice("Page size: %u\n", pdata->page_size); + imsg_notice("Bootloader start: 0x%04X\n", pdata->bootloader_start); + imsg_notice("Write sleep: %ums\n", pdata->write_sleep); + imsg_notice("Erase sleep: %ums\n", pdata->erase_sleep); + imsg_notice("Signature1: 0x%02X\n", pdata->signature1); + imsg_notice("Signature2: 0x%02X\n", pdata->signature2); } static int micronucleus_erase_device(struct pdata *pdata) { - pmsg_debug("micronucleus_erase_device()\n"); + pmsg_debug("micronucleus_erase_device()\n"); - int result = usb_control_msg( - pdata->usb_handle, - USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - MICRONUCLEUS_CMD_ERASE, - 0, 0, - NULL, 0, - MICRONUCLEUS_DEFAULT_TIMEOUT); - if (result < 0) - { - switch (result) - { - case -EIO: - case -EPIPE: - pmsg_notice("ignoring last error of erase command: %s\n", usb_strerror()); - break; - default: - pmsg_warning("erase command failed, code %d: %s\n", result, usb_strerror()); - return result; - } + int result = usb_control_msg(pdata->usb_handle, + USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MICRONUCLEUS_CMD_ERASE, + 0, 0, + NULL, 0, + MICRONUCLEUS_DEFAULT_TIMEOUT); + + if(result < 0) { + switch (result) { + case -EIO: + case -EPIPE: + pmsg_notice("ignoring last error of erase command: %s\n", usb_strerror()); + break; + default: + pmsg_warning("erase command failed, code %d: %s\n", result, usb_strerror()); + return result; } + } - delay_ms(pdata->erase_sleep); + delay_ms(pdata->erase_sleep); - result = micronucleus_check_connection(pdata); - if (result < 0) - { - pmsg_notice("connection dropped, trying to reconnect ...\n"); + result = micronucleus_check_connection(pdata); + if(result < 0) { + pmsg_notice("connection dropped, trying to reconnect ...\n"); - result = micronucleus_reconnect(pdata); - if (result < 0) - { - pmsg_warning("unable to reconnect USB device: %s\n", usb_strerror()); - return result; - } + result = micronucleus_reconnect(pdata); + if(result < 0) { + pmsg_warning("unable to reconnect USB device: %s\n", usb_strerror()); + return result; } + } - return 0; + return 0; } static int micronucleus_patch_reset_vector(struct pdata *pdata, uint8_t *buffer) { - // Save user reset vector. - uint16_t word0 = (buffer[1] << 8) | buffer[0]; - uint16_t word1 = (buffer[3] << 8) | buffer[2]; + // Save user reset vector. + uint16_t word0 = (buffer[1] << 8) | buffer[0]; + uint16_t word1 = (buffer[3] << 8) | buffer[2]; - if (word0 == 0x940C) - { - // long jump - pdata->user_reset_vector = word1; - } - else if ((word0 & 0xF000) == 0xC000) - { - // rjmp - pdata->user_reset_vector = (word0 & 0x0FFF) + 1; - } - else - { - pmsg_error("the reset vector of the user program does not contain a branch instruction\n"); - return -1; - } + if(word0 == 0x940C) { + // Long jump + pdata->user_reset_vector = word1; + } else if((word0 & 0xF000) == 0xC000) { + // rjmp + pdata->user_reset_vector = (word0 & 0x0FFF) + 1; + } else { + pmsg_error("the reset vector of the user program does not contain a branch instruction\n"); + return -1; + } - // Patch in jmp to bootloader. - if (pdata->bootloader_start > 0x2000) - { - // jmp - uint16_t data = 0x940C; - buffer[0] = (uint8_t)(data >> 0); - buffer[1] = (uint8_t)(data >> 8); - buffer[2] = (uint8_t)(pdata->bootloader_start >> 0); - buffer[3] = (uint8_t)(pdata->bootloader_start >> 8); - } - else - { - // rjmp - uint16_t data = 0xC000 | ((pdata->bootloader_start / 2 - 1) & 0x0FFF); - buffer[0] = (uint8_t)(data >> 0); - buffer[1] = (uint8_t)(data >> 8); - } + // Patch in jmp to bootloader. + if(pdata->bootloader_start > 0x2000) { + // jmp + uint16_t data = 0x940C; - return 0; + buffer[0] = (uint8_t) (data >> 0); + buffer[1] = (uint8_t) (data >> 8); + buffer[2] = (uint8_t) (pdata->bootloader_start >> 0); + buffer[3] = (uint8_t) (pdata->bootloader_start >> 8); + } else { + // rjmp + uint16_t data = 0xC000 | ((pdata->bootloader_start/2 - 1) & 0x0FFF); + + buffer[0] = (uint8_t) (data >> 0); + buffer[1] = (uint8_t) (data >> 8); + } + + return 0; } static void micronucleus_patch_user_vector(struct pdata *pdata, uint8_t *buffer) { - uint16_t user_reset_addr = pdata->bootloader_start - 4; - uint16_t address = pdata->bootloader_start - pdata->page_size; - if (user_reset_addr > 0x2000) - { - // jmp - uint16_t data = 0x940C; - buffer[user_reset_addr - address + 0] = (uint8_t)(data >> 0); - buffer[user_reset_addr - address + 1] = (uint8_t)(data >> 8); - buffer[user_reset_addr - address + 2] = (uint8_t)(pdata->user_reset_vector >> 0); - buffer[user_reset_addr - address + 3] = (uint8_t)(pdata->user_reset_vector >> 8); - } - else - { - // rjmp - uint16_t data = 0xC000 | ((pdata->user_reset_vector - user_reset_addr / 2 - 1) & 0x0FFF); - buffer[user_reset_addr - address + 0] = (uint8_t)(data >> 0); - buffer[user_reset_addr - address + 1] = (uint8_t)(data >> 8); - } + uint16_t user_reset_addr = pdata->bootloader_start - 4; + uint16_t address = pdata->bootloader_start - pdata->page_size; + + if(user_reset_addr > 0x2000) { + // jmp + uint16_t data = 0x940C; + + buffer[user_reset_addr - address + 0] = (uint8_t) (data >> 0); + buffer[user_reset_addr - address + 1] = (uint8_t) (data >> 8); + buffer[user_reset_addr - address + 2] = (uint8_t) (pdata->user_reset_vector >> 0); + buffer[user_reset_addr - address + 3] = (uint8_t) (pdata->user_reset_vector >> 8); + } else { + // rjmp + uint16_t data = 0xC000 | ((pdata->user_reset_vector - user_reset_addr/2 - 1) & 0x0FFF); + + buffer[user_reset_addr - address + 0] = (uint8_t) (data >> 0); + buffer[user_reset_addr - address + 1] = (uint8_t) (data >> 8); + } } static int micronucleus_write_page_v1(struct pdata *pdata, uint32_t address, uint8_t *buffer, uint32_t size) { - int result = usb_control_msg( - pdata->usb_handle, - USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - MICRONUCLEUS_CMD_TRANSFER, - size, address, - (char*)buffer, size, - MICRONUCLEUS_DEFAULT_TIMEOUT); - if (result < 0) - { - pmsg_error("unable to transfer page: %s\n", usb_strerror()); - return result; - } + int result = usb_control_msg(pdata->usb_handle, + USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MICRONUCLEUS_CMD_TRANSFER, + size, address, + (char *) buffer, size, + MICRONUCLEUS_DEFAULT_TIMEOUT); - return 0; + if(result < 0) { + pmsg_error("unable to transfer page: %s\n", usb_strerror()); + return result; + } + + return 0; } static int micronucleus_write_page_v2(struct pdata *pdata, uint32_t address, uint8_t *buffer, uint32_t size) { - int result = usb_control_msg( - pdata->usb_handle, - USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - MICRONUCLEUS_CMD_TRANSFER, - size, address, - NULL, 0, - MICRONUCLEUS_DEFAULT_TIMEOUT); - if (result < 0) - { - pmsg_error("unable to transfer page: %s\n", usb_strerror()); - return result; - } + int result = usb_control_msg(pdata->usb_handle, + USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MICRONUCLEUS_CMD_TRANSFER, + size, address, + NULL, 0, + MICRONUCLEUS_DEFAULT_TIMEOUT); - for (uint32_t i = 0; i < size; i += 4) - { - int w1 = (buffer[i + 1] << 8) | (buffer[i + 0] << 0); - int w2 = (buffer[i + 3] << 8) | (buffer[i + 2] << 0); - result = usb_control_msg( - pdata->usb_handle, - USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - MICRONUCLEUS_CMD_PROGRAM, - w1, w2, - NULL, 0, - MICRONUCLEUS_DEFAULT_TIMEOUT); - if (result < 0) - { - pmsg_error("unable to transfer page: %s\n", usb_strerror()); - return result; - } - } + if(result < 0) { + pmsg_error("unable to transfer page: %s\n", usb_strerror()); + return result; + } - return 0; + for(uint32_t i = 0; i < size; i += 4) { + int w1 = (buffer[i + 1] << 8) | (buffer[i + 0] << 0); + int w2 = (buffer[i + 3] << 8) | (buffer[i + 2] << 0); + + result = usb_control_msg(pdata->usb_handle, + USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MICRONUCLEUS_CMD_PROGRAM, w1, w2, NULL, 0, MICRONUCLEUS_DEFAULT_TIMEOUT); + if(result < 0) { + pmsg_error("unable to transfer page: %s\n", usb_strerror()); + return result; + } + } + + return 0; } static int micronucleus_write_page(struct pdata *pdata, uint32_t address, uint8_t *buffer, uint32_t size) { - pmsg_debug("micronucleus_write_page(address=0x%04X, size=%d)\n", address, size); + pmsg_debug("micronucleus_write_page(address=0x%04X, size=%d)\n", address, size); - if (address == 0) - { - if (pdata->major_version >= 2) - { - int result = micronucleus_patch_reset_vector(pdata, buffer); - if (result < 0) - { - return result; - } - } + if(address == 0) { + if(pdata->major_version >= 2) { + int result = micronucleus_patch_reset_vector(pdata, buffer); - // Require last page (with application reset vector) to be written. - pdata->write_last_page = true; - - // Require software start. - pdata->start_program = true; - } - else if (address >= (uint32_t) (pdata->bootloader_start - pdata->page_size)) - { - if (pdata->major_version >= 2) - { - micronucleus_patch_user_vector(pdata, buffer); - } - - // Mark last page as written. - pdata->write_last_page = false; - } - - int result; - if (pdata->major_version >= 2) - { - result = micronucleus_write_page_v2(pdata, address, buffer, size); - } - else - { - result = micronucleus_write_page_v1(pdata, address, buffer, size); - } - - if (result < 0) - { + if(result < 0) { return result; + } } + // Require last page (with application reset vector) to be written. + pdata->write_last_page = true; - delay_ms(pdata->write_sleep); + // Require software start. + pdata->start_program = true; + } else if(address >= (uint32_t) (pdata->bootloader_start - pdata->page_size)) { + if(pdata->major_version >= 2) { + micronucleus_patch_user_vector(pdata, buffer); + } + // Mark last page as written. + pdata->write_last_page = false; + } - return 0; + int result; + + if(pdata->major_version >= 2) { + result = micronucleus_write_page_v2(pdata, address, buffer, size); + } else { + result = micronucleus_write_page_v1(pdata, address, buffer, size); + } + + if(result < 0) { + return result; + } + + delay_ms(pdata->write_sleep); + + return 0; } static int micronucleus_start(struct pdata *pdata) { - pmsg_debug("micronucleus_start()\n"); + pmsg_debug("micronucleus_start()\n"); - int result = usb_control_msg( - pdata->usb_handle, - USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - MICRONUCLEUS_CMD_START, - 0, 0, - NULL, 0, - MICRONUCLEUS_DEFAULT_TIMEOUT); - if (result < 0) - { - pmsg_warning("start command failed: %s\n", usb_strerror()); - return result; - } + int result = usb_control_msg(pdata->usb_handle, + USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + MICRONUCLEUS_CMD_START, + 0, 0, + NULL, 0, + MICRONUCLEUS_DEFAULT_TIMEOUT); - return 0; + if(result < 0) { + pmsg_warning("start command failed: %s\n", usb_strerror()); + return result; + } + + return 0; } -//----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- static void micronucleus_setup(PROGRAMMER *pgm) { - pmsg_debug("micronucleus_setup()\n"); - pgm->cookie = mmt_malloc(sizeof(struct pdata)); + pmsg_debug("micronucleus_setup()\n"); + pgm->cookie = mmt_malloc(sizeof(struct pdata)); } -static void micronucleus_teardown(PROGRAMMER* pgm) { - pmsg_debug("micronucleus_teardown()\n"); - mmt_free(pgm->cookie); - pgm->cookie = NULL; +static void micronucleus_teardown(PROGRAMMER *pgm) { + pmsg_debug("micronucleus_teardown()\n"); + mmt_free(pgm->cookie); + pgm->cookie = NULL; } static int micronucleus_initialize(const PROGRAMMER *pgm, const AVRPART *p) { - pmsg_debug("micronucleus_initialize()\n"); + pmsg_debug("micronucleus_initialize()\n"); - struct pdata *pdata = PDATA(pgm); + struct pdata *pdata = PDATA(pgm); - int result = micronucleus_get_bootloader_info(pdata); - if (result < 0) - return result; + int result = micronucleus_get_bootloader_info(pdata); - micronucleus_dump_device_info(pdata); + if(result < 0) + return result; - return 0; + micronucleus_dump_device_info(pdata); + + return 0; } static void micronucleus_display(const PROGRAMMER *pgm, const char *prefix) { @@ -563,396 +514,353 @@ static void micronucleus_display(const PROGRAMMER *pgm, const char *prefix) { } static void micronucleus_powerup(const PROGRAMMER *pgm) { - pmsg_debug("micronucleus_powerup()\n"); + pmsg_debug("micronucleus_powerup()\n"); } static void micronucleus_powerdown(const PROGRAMMER *pgm) { - pmsg_debug("micronucleus_powerdown()\n"); + pmsg_debug("micronucleus_powerdown()\n"); - struct pdata *pdata = PDATA(pgm); - if (pdata->write_last_page) - { - pdata->write_last_page = false; + struct pdata *pdata = PDATA(pgm); - uint8_t *buffer = (unsigned char *) mmt_malloc(pdata->page_size); - memset(buffer, 0xFF, pdata->page_size); - micronucleus_write_page(pdata, pdata->bootloader_start - pdata->page_size, buffer, pdata->page_size); - mmt_free(buffer); - } + if(pdata->write_last_page) { + pdata->write_last_page = false; - if (pdata->start_program) - { - pdata->start_program = false; + uint8_t *buffer = (unsigned char *) mmt_malloc(pdata->page_size); - micronucleus_start(pdata); - } + memset(buffer, 0xFF, pdata->page_size); + micronucleus_write_page(pdata, pdata->bootloader_start - pdata->page_size, buffer, pdata->page_size); + mmt_free(buffer); + } + + if(pdata->start_program) { + pdata->start_program = false; + + micronucleus_start(pdata); + } } static void micronucleus_enable(PROGRAMMER *pgm, const AVRPART *p) { - pmsg_debug("micronucleus_enable()\n"); + pmsg_debug("micronucleus_enable()\n"); } static void micronucleus_disable(const PROGRAMMER *pgm) { - pmsg_debug("micronucleus_disable()\n"); + pmsg_debug("micronucleus_disable()\n"); } static int micronucleus_program_enable(const PROGRAMMER *pgm, const AVRPART *p) { - pmsg_debug("micronucleus_program_enable()\n"); - return 0; + pmsg_debug("micronucleus_program_enable()\n"); + return 0; } static int micronucleus_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem) { - pmsg_debug("micronucleus_read_sig_bytes()\n"); + pmsg_debug("micronucleus_read_sig_bytes()\n"); - if (mem->size < 3) - { - pmsg_error("memory size %d < 3 too small for read_sig_bytes", mem->size); - return -1; - } + if(mem->size < 3) { + pmsg_error("memory size %d < 3 too small for read_sig_bytes", mem->size); + return -1; + } - struct pdata *pdata = PDATA(pgm); - mem->buf[0] = 0x1E; - mem->buf[1] = pdata->signature1; - mem->buf[2] = pdata->signature2; - return 0; + struct pdata *pdata = PDATA(pgm); + + mem->buf[0] = 0x1E; + mem->buf[1] = pdata->signature1; + mem->buf[2] = pdata->signature2; + return 0; } static int micronucleus_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { - pmsg_debug("micronucleus_chip_erase()\n"); + pmsg_debug("micronucleus_chip_erase()\n"); - struct pdata *pdata = PDATA(pgm); - return micronucleus_erase_device(pdata); + struct pdata *pdata = PDATA(pgm); + + return micronucleus_erase_device(pdata); } -static int micronucleus_open(PROGRAMMER* pgm, const char *port) { - pmsg_debug("micronucleus_open(\"%s\")\n", port); +static int micronucleus_open(PROGRAMMER *pgm, const char *port) { + pmsg_debug("micronucleus_open(\"%s\")\n", port); - struct pdata *pdata = PDATA(pgm); - const char *bus_name = NULL; - char* dev_name = NULL; + struct pdata *pdata = PDATA(pgm); + const char *bus_name = NULL; + char *dev_name = NULL; - // if no -P was given or '-P usb' was given - if (str_eq(port, "usb")) - { - port = NULL; + // If no -P was given or '-P usb' was given + if(str_eq(port, "usb")) { + port = NULL; + } else { + // Calculate bus and device names from -P option + if(str_starts(port, "usb") && ':' == port[3]) { + bus_name = port + 4; + dev_name = strchr(bus_name, ':'); + if(dev_name != NULL) { + *dev_name = '\0'; + dev_name++; + } } - else - { - // calculate bus and device names from -P option - if (str_starts(port, "usb") && ':' == port[3]) - { - bus_name = port + 4; - dev_name = strchr(bus_name, ':'); - if (dev_name != NULL) - { - *dev_name = '\0'; - dev_name++; - } - } + } + + if(port != NULL && dev_name == NULL) { + pmsg_error("invalid -P %s; use -P usb:bus:device\n", port); + return -1; + } + // Determine VID/PID + int vid = pgm->usbvid? pgm->usbvid: MICRONUCLEUS_VID; + int pid = MICRONUCLEUS_PID; + + LNODEID usbpid = lfirst(pgm->usbpid); + + if(usbpid != NULL) { + pid = *(int *) (ldata(usbpid)); + if(lnext(usbpid)) { + pmsg_warning("using PID 0x%04x, ignoring remaining PIDs in list\n", pid); } + } - if (port != NULL && dev_name == NULL) - { - pmsg_error("invalid -P %s; use -P usb:bus:device\n", port); - return -1; - } + usb_init(); - // Determine VID/PID - int vid = pgm->usbvid ? pgm->usbvid : MICRONUCLEUS_VID; - int pid = MICRONUCLEUS_PID; + bool show_retry_message = true; + bool show_unresponsive_device_message = true; - LNODEID usbpid = lfirst(pgm->usbpid); - if (usbpid != NULL) - { - pid = *(int*)(ldata(usbpid)); - if (lnext(usbpid)) - { - pmsg_warning("using PID 0x%04x, ignoring remaining PIDs in list\n", pid); - } - } + time_t start_time = time(NULL); - usb_init(); + for(;;) { + usb_find_busses(); + usb_find_devices(); - bool show_retry_message = true; - bool show_unresponsive_device_message = true; + pdata->usb_handle = NULL; - time_t start_time = time(NULL); - for (;;) - { - usb_find_busses(); - usb_find_devices(); + // Search for device + struct usb_bus *bus = NULL; - pdata->usb_handle = NULL; + for(bus = usb_busses; bus != NULL && pdata->usb_handle == NULL; bus = bus->next) { + struct usb_device *device = NULL; - // Search for device - struct usb_bus* bus = NULL; - for (bus = usb_busses; bus != NULL && pdata->usb_handle == NULL; bus = bus->next) - { - struct usb_device* device = NULL; - for (device = bus->devices; device != NULL && pdata->usb_handle == NULL; device = device->next) - { - if (device->descriptor.idVendor == vid && device->descriptor.idProduct == pid) - { - pdata->major_version = (uint8_t)(device->descriptor.bcdDevice >> 8); - pdata->minor_version = (uint8_t)(device->descriptor.bcdDevice >> 0); + for(device = bus->devices; device != NULL && pdata->usb_handle == NULL; device = device->next) { + if(device->descriptor.idVendor == vid && device->descriptor.idProduct == pid) { + pdata->major_version = (uint8_t) (device->descriptor.bcdDevice >> 8); + pdata->minor_version = (uint8_t) (device->descriptor.bcdDevice >> 0); - if (!micronucleus_is_device_responsive(pdata, device)) - { - if (show_unresponsive_device_message) - { - pmsg_warning("unresponsive Micronucleus device detected, please reconnect ...\n"); + if(!micronucleus_is_device_responsive(pdata, device)) { + if(show_unresponsive_device_message) { + pmsg_warning("unresponsive Micronucleus device detected, please reconnect ...\n"); - show_unresponsive_device_message = false; - } - - continue; - } - - pmsg_notice("found device with Micronucleus V%d.%d, bus:device: %s:%s\n", - pdata->major_version, pdata->minor_version, - bus->dirname, device->filename); - - // if -P was given, match device by device name and bus name - if (port != NULL) - { - if (dev_name == NULL || !str_eq(bus->dirname, bus_name) || !str_eq(device->filename, dev_name)) - { - continue; - } - } - - if (pdata->major_version > MICRONUCLEUS_MAX_MAJOR_VERSION) - { - pmsg_warning("device with unsupported Micronucleus version V%d.%d\n", - pdata->major_version, pdata->minor_version); - continue; - } - - pdata->usb_handle = usb_open(device); - if (pdata->usb_handle == NULL) - { - pmsg_error("unable to open USB device: %s\n", usb_strerror()); - } - } - } - } - - if (pdata->usb_handle == NULL && pdata->wait_until_device_present) - { - if (show_retry_message) - { - if (pdata->wait_timout < 0) - { - pmsg_error("no device found, waiting for device to be plugged in ...\n"); - } - else - { - pmsg_error("no device found, waiting %d seconds for device to be plugged in ...\n", - pdata->wait_timout); - } - - pmsg_error("press CTRL-C to terminate\n"); - show_retry_message = false; + show_unresponsive_device_message = false; } - if (pdata->wait_timout < 0 || (time(NULL) - start_time) < pdata->wait_timout) - { - delay_ms(MICRONUCLEUS_CONNECT_WAIT); - continue; + continue; + } + + pmsg_notice("found device with Micronucleus V%d.%d, bus:device: %s:%s\n", + pdata->major_version, pdata->minor_version, bus->dirname, device->filename); + + // If -P was given, match device by device name and bus name + if(port != NULL) { + if(dev_name == NULL || !str_eq(bus->dirname, bus_name) || !str_eq(device->filename, dev_name)) { + continue; } + } + + if(pdata->major_version > MICRONUCLEUS_MAX_MAJOR_VERSION) { + pmsg_warning("device with unsupported Micronucleus version V%d.%d\n", + pdata->major_version, pdata->minor_version); + continue; + } + + pdata->usb_handle = usb_open(device); + if(pdata->usb_handle == NULL) { + pmsg_error("unable to open USB device: %s\n", usb_strerror()); + } + } + } + } + + if(pdata->usb_handle == NULL && pdata->wait_until_device_present) { + if(show_retry_message) { + if(pdata->wait_timout < 0) { + pmsg_error("no device found, waiting for device to be plugged in ...\n"); + } else { + pmsg_error("no device found, waiting %d seconds for device to be plugged in ...\n", pdata->wait_timout); } - break; + pmsg_error("press CTRL-C to terminate\n"); + show_retry_message = false; + } + + if(pdata->wait_timout < 0 || (time(NULL) - start_time) < pdata->wait_timout) { + delay_ms(MICRONUCLEUS_CONNECT_WAIT); + continue; + } } - if (!pdata->usb_handle) - { - pmsg_error("cannot find device with Micronucleus bootloader (%04X:%04X)\n", vid, pid); - return -1; - } + break; + } - return 0; + if(!pdata->usb_handle) { + pmsg_error("cannot find device with Micronucleus bootloader (%04X:%04X)\n", vid, pid); + return -1; + } + + return 0; } -static void micronucleus_close(PROGRAMMER* pgm) -{ - pmsg_debug("micronucleus_close()\n"); +static void micronucleus_close(PROGRAMMER *pgm) { + pmsg_debug("micronucleus_close()\n"); - struct pdata *pdata = PDATA(pgm); - if (pdata->usb_handle != NULL) - { - usb_close(pdata->usb_handle); - pdata->usb_handle = NULL; - } + struct pdata *pdata = PDATA(pgm); + + if(pdata->usb_handle != NULL) { + usb_close(pdata->usb_handle); + pdata->usb_handle = NULL; + } } static int micronucleus_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, - unsigned long addr, unsigned char* value) -{ - pmsg_debug("micronucleus_read_byte(desc=%s, addr=0x%04lX)\n", mem->desc, addr); + unsigned long addr, unsigned char *value) { + pmsg_debug("micronucleus_read_byte(desc=%s, addr=0x%04lX)\n", mem->desc, addr); - if (mem_is_a_fuse(mem) || mem_is_lock(mem)) - { - *value = 0xFF; - return 0; - } - else - { - pmsg_notice("reading not supported for %s memory\n", mem->desc); - return -1; - } + if(mem_is_a_fuse(mem) || mem_is_lock(mem)) { + *value = 0xFF; + return 0; + } else { + pmsg_notice("reading not supported for %s memory\n", mem->desc); + return -1; + } } static int micronucleus_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, - unsigned long addr, unsigned char value) -{ - pmsg_debug("micronucleus_write_byte(desc=%s, addr=0x%04lX)\n", mem->desc, addr); - return -1; + unsigned long addr, unsigned char value) { + pmsg_debug("micronucleus_write_byte(desc=%s, addr=0x%04lX)\n", mem->desc, addr); + return -1; } static int micronucleus_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, - unsigned int page_size, - unsigned int addr, unsigned int n_bytes) -{ - pmsg_debug("micronucleus_paged_load(page_size=0x%X, addr=0x%X, n_bytes=0x%X)\n", page_size, addr, n_bytes); - return -1; + unsigned int page_size, unsigned int addr, unsigned int n_bytes) { + pmsg_debug("micronucleus_paged_load(page_size=0x%X, addr=0x%X, n_bytes=0x%X)\n", page_size, addr, n_bytes); + return -1; } static int micronucleus_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, - unsigned int page_size, - unsigned int addr, unsigned int n_bytes) -{ - pmsg_debug("micronucleus_paged_write(page_size=0x%X, addr=0x%X, n_bytes=0x%X)\n", page_size, addr, n_bytes); + unsigned int page_size, unsigned int addr, unsigned int n_bytes) { + pmsg_debug("micronucleus_paged_write(page_size=0x%X, addr=0x%X, n_bytes=0x%X)\n", page_size, addr, n_bytes); - if (mem_is_flash(mem)) - { - struct pdata *pdata = PDATA(pgm); + if(mem_is_flash(mem)) { + struct pdata *pdata = PDATA(pgm); - if (n_bytes > page_size) - { - pmsg_error("buffer size %u exceeds page size %u\n", n_bytes, page_size); - return -1; - } - - if (addr + n_bytes > pdata->flash_size) - { - pmsg_error("program size %u exceeds flash size %u\n", addr + n_bytes, pdata->flash_size); - return -1; - } - - uint8_t *page_buffer = (uint8_t *) mmt_malloc(pdata->page_size); - - // Note: Page size reported by the bootloader may be smaller than device page size as configured in avrdude.conf. - int result = 0; - while (n_bytes > 0) - { - size_t chunk_size = n_bytes < pdata->page_size ? n_bytes : pdata->page_size; - - memcpy(page_buffer, mem->buf + addr, chunk_size); - memset(page_buffer + chunk_size, 0xFF, pdata->page_size - chunk_size); - - result = micronucleus_write_page(pdata, addr, page_buffer, pdata->page_size); - if (result < 0) - { - break; - } - - addr += chunk_size; - n_bytes -= chunk_size; - } - - mmt_free(page_buffer); - return result; + if(n_bytes > page_size) { + pmsg_error("buffer size %u exceeds page size %u\n", n_bytes, page_size); + return -1; } - else - { - pmsg_error("unsupported memory %s\n", mem->desc); - return -1; + + if(addr + n_bytes > pdata->flash_size) { + pmsg_error("program size %u exceeds flash size %u\n", addr + n_bytes, pdata->flash_size); + return -1; } + + uint8_t *page_buffer = (uint8_t *) mmt_malloc(pdata->page_size); + + // Note: Page size reported by the bootloader may be smaller than device page size as configured in avrdude.conf. + int result = 0; + + while(n_bytes > 0) { + size_t chunk_size = n_bytes < pdata->page_size? n_bytes: pdata->page_size; + + memcpy(page_buffer, mem->buf + addr, chunk_size); + memset(page_buffer + chunk_size, 0xFF, pdata->page_size - chunk_size); + + result = micronucleus_write_page(pdata, addr, page_buffer, pdata->page_size); + if(result < 0) { + break; + } + + addr += chunk_size; + n_bytes -= chunk_size; + } + + mmt_free(page_buffer); + return result; + } else { + pmsg_error("unsupported memory %s\n", mem->desc); + return -1; + } } static int micronucleus_parseextparams(const PROGRAMMER *pgm, const LISTID xparams) { - int rv = 0; - bool help = false; - pmsg_debug("micronucleus_parseextparams()\n"); + int rv = 0; + bool help = false; - struct pdata *pdata = PDATA(pgm); - for (LNODEID node = lfirst(xparams); node; node = lnext(node)) - { - const char* extended_param = ldata(node); + pmsg_debug("micronucleus_parseextparams()\n"); - if (str_eq(extended_param, "wait")) - { - pdata->wait_until_device_present = true; - pdata->wait_timout = -1; - continue; - } + struct pdata *pdata = PDATA(pgm); - if (str_starts(extended_param, "wait=")) - { - pdata->wait_until_device_present = true; - pdata->wait_timout = atoi(extended_param + 5); - continue; - } + for(LNODEID node = lfirst(xparams); node; node = lnext(node)) { + const char *extended_param = ldata(node); - if (str_eq(extended_param, "help")) - { - help = true; - rv = LIBAVRDUDE_EXIT; - } - - if (!help) - { - pmsg_error("invalid extended parameter -x %s\n", extended_param); - rv = -1; - } - msg_error("%s -c %s extended options:\n", progname, pgmid); - msg_error(" -x wait Wait for the device to be plugged in if not connected\n"); - msg_error(" -x wait= Wait s for the device to be plugged in if not connected\n"); - msg_error(" -x help Show this help menu and exit\n"); - return rv; + if(str_eq(extended_param, "wait")) { + pdata->wait_until_device_present = true; + pdata->wait_timout = -1; + continue; } + if(str_starts(extended_param, "wait=")) { + pdata->wait_until_device_present = true; + pdata->wait_timout = atoi(extended_param + 5); + continue; + } + + if(str_eq(extended_param, "help")) { + help = true; + rv = LIBAVRDUDE_EXIT; + } + + if(!help) { + pmsg_error("invalid extended parameter -x %s\n", extended_param); + rv = -1; + } + msg_error("%s -c %s extended options:\n", progname, pgmid); + msg_error(" -x wait Wait for the device to be plugged in if not connected\n"); + msg_error(" -x wait= Wait s for the device to be plugged in if not connected\n"); + msg_error(" -x help Show this help menu and exit\n"); return rv; + } + + return rv; } void micronucleus_initpgm(PROGRAMMER *pgm) { - strcpy(pgm->type, "Micronucleus V2.0"); + strcpy(pgm->type, "Micronucleus V2.0"); - pgm->setup = micronucleus_setup; - pgm->teardown = micronucleus_teardown; - pgm->initialize = micronucleus_initialize; - pgm->display = micronucleus_display; - pgm->powerup = micronucleus_powerup; - pgm->powerdown = micronucleus_powerdown; - pgm->enable = micronucleus_enable; - pgm->disable = micronucleus_disable; - pgm->program_enable = micronucleus_program_enable; - pgm->read_sig_bytes = micronucleus_read_sig_bytes; - pgm->chip_erase = micronucleus_chip_erase; - pgm->cmd = NULL; - pgm->open = micronucleus_open; - pgm->close = micronucleus_close; - pgm->read_byte = micronucleus_read_byte; - pgm->write_byte = micronucleus_write_byte; - pgm->paged_load = micronucleus_paged_load; - pgm->paged_write = micronucleus_paged_write; - pgm->parseextparams = micronucleus_parseextparams; + pgm->setup = micronucleus_setup; + pgm->teardown = micronucleus_teardown; + pgm->initialize = micronucleus_initialize; + pgm->display = micronucleus_display; + pgm->powerup = micronucleus_powerup; + pgm->powerdown = micronucleus_powerdown; + pgm->enable = micronucleus_enable; + pgm->disable = micronucleus_disable; + pgm->program_enable = micronucleus_program_enable; + pgm->read_sig_bytes = micronucleus_read_sig_bytes; + pgm->chip_erase = micronucleus_chip_erase; + pgm->cmd = NULL; + pgm->open = micronucleus_open; + pgm->close = micronucleus_close; + pgm->read_byte = micronucleus_read_byte; + pgm->write_byte = micronucleus_write_byte; + pgm->paged_load = micronucleus_paged_load; + pgm->paged_write = micronucleus_paged_write; + pgm->parseextparams = micronucleus_parseextparams; } -#else /* !HAVE_LIBUSB */ +#else // ! HAVE_LIBUSB // Give a proper error if we were not compiled with libusb -static int micronucleus_nousb_open(PROGRAMMER* pgm, const char* name) { - pmsg_error("no usb support; please compile again with libusb installed\n"); - return -1; +static int micronucleus_nousb_open(PROGRAMMER *pgm, const char *name) { + pmsg_error("no usb support; please compile again with libusb installed\n"); + return -1; } void micronucleus_initpgm(PROGRAMMER *pgm) { - strcpy(pgm->type, "micronucleus"); - pgm->open = micronucleus_nousb_open; + strcpy(pgm->type, "micronucleus"); + pgm->open = micronucleus_nousb_open; } - -#endif /* HAVE_LIBUSB */ +#endif // HAVE_LIBUSB const char micronucleus_desc[] = "Micronucleus Bootloader";