From: Drashna Jael're Date: Thu, 15 Jul 2021 15:06:14 +0000 (-0700) Subject: Update hid_bootloader_cli code X-Git-Url: http://git.linex4red.de/pub/lufa.git/commitdiff_plain/3528d8da3976828850ec0c56be01022f9174ee58?ds=inline;hp=--cc Update hid_bootloader_cli code --- 3528d8da3976828850ec0c56be01022f9174ee58 diff --git a/Bootloaders/HID/HostLoaderApp/Makefile b/Bootloaders/HID/HostLoaderApp/Makefile index d7d6458a5..3fbc7bd95 100644 --- a/Bootloaders/HID/HostLoaderApp/Makefile +++ b/Bootloaders/HID/HostLoaderApp/Makefile @@ -3,31 +3,50 @@ OS ?= LINUX #OS ?= MACOSX #OS ?= BSD +# uncomment this to use libusb on Macintosh, instead of Apple's HID manager via IOKit +# this is technically not the "correct" way to support Macs, but it's been reported to +# work. +#USE_LIBUSB ?= YES + ifeq ($(OS), LINUX) # also works on FreeBSD CC ?= gcc CFLAGS ?= -O2 -Wall hid_bootloader_cli: hid_bootloader_cli.c - $(CC) $(CFLAGS) -s -DUSE_LIBUSB -o hid_bootloader_cli hid_bootloader_cli.c -lusb + $(CC) $(CFLAGS) $(CPPFLAGS) -DUSE_LIBUSB -o hid_bootloader_cli hid_bootloader_cli.c -lusb $(LDFLAGS) else ifeq ($(OS), WINDOWS) -CC = i586-mingw32msvc-gcc +CC ?= i586-mingw32msvc-gcc CFLAGS ?= -O2 -Wall -LDLIB = -lsetupapi -lhid hid_bootloader_cli.exe: hid_bootloader_cli.c - $(CC) $(CFLAGS) -s -DUSE_WIN32 -o hid_bootloader_cli.exe hid_bootloader_cli.c $(LDLIB) + $(CC) $(CFLAGS) -s -DUSE_WIN32 -o hid_bootloader_cli.exe hid_bootloader_cli.c -lhid -lsetupapi -lwinmm else ifeq ($(OS), MACOSX) +ifeq ($(USE_LIBUSB), YES) +CC ?= gcc +CFLAGS ?= -O2 -Wall +hid_bootloader_cli: hid_bootloader_cli.c + $(CC) $(CFLAGS) -DUSE_LIBUSB -DMACOSX -o hid_bootloader_cli hid_bootloader_cli.c -lusb -I /usr/local/include -L/usr/local/lib + +else CC ?= gcc -SDK ?= /Developer/SDKs/MacOSX10.5.sdk +SDK ?= $(shell xcrun --show-sdk-path) +#SDK ?= /Developer/SDKs/MacOSX10.6.sdk # the old way... +#SDK = /Developer_xcode32/SDKs/MacOSX10.5.sdk # the very old way! +#CC = /Developer_xcode32/usr/bin/gcc-4.0 +#CFLAGS = -O2 -Wall -arch i386 -arch ppc CFLAGS ?= -O2 -Wall hid_bootloader_cli: hid_bootloader_cli.c +ifeq ($(SDK),) + $(error SDK was not found. To use this type of compilation please install Xcode) +endif $(CC) $(CFLAGS) -DUSE_APPLE_IOKIT -isysroot $(SDK) -o hid_bootloader_cli hid_bootloader_cli.c -Wl,-syslibroot,$(SDK) -framework IOKit -framework CoreFoundation +endif else ifeq ($(OS), BSD) # works on NetBSD and OpenBSD -CC ?= gcct +CC ?= gcc CFLAGS ?= -O2 -Wall hid_bootloader_cli: hid_bootloader_cli.c $(CC) $(CFLAGS) -s -DUSE_UHID -o hid_bootloader_cli hid_bootloader_cli.c @@ -37,4 +56,4 @@ endif clean: - rm -f hid_bootloader_cli hid_bootloader_cli.exe + rm -f hid_bootloader_cli hid_bootloader_cli.exe* diff --git a/Bootloaders/HID/HostLoaderApp/hid_bootloader_cli.c b/Bootloaders/HID/HostLoaderApp/hid_bootloader_cli.c index b54f943b1..f29dc81fc 100644 --- a/Bootloaders/HID/HostLoaderApp/hid_bootloader_cli.c +++ b/Bootloaders/HID/HostLoaderApp/hid_bootloader_cli.c @@ -7,8 +7,7 @@ /* Teensy Loader, Command Line Interface * Program and Reboot Teensy Board with HalfKay Bootloader * http://www.pjrc.com/teensy/loader_cli.html - * Copyright 2008-2010, PJRC.COM, LLC - * + * Copyright 2008-2016, PJRC.COM, LLC * * You may redistribute this program and/or modify it under the terms * of the GNU General Public License as published by the Free Software @@ -32,6 +31,7 @@ * http://www.pjrc.com/teensy/49-teensy.rules */ + #include #include #include @@ -39,20 +39,23 @@ #include #include -void usage(void) +void usage(const char *err) { - fprintf(stderr, "Usage: hid_bootloader_cli -mmcu= [-w] [-h] [-n] [-v] \n"); - fprintf(stderr, "\t-w : Wait for device to appear\n"); - fprintf(stderr, "\t-r : Use hard reboot if device not online\n"); - fprintf(stderr, "\t-n : No reboot after programming\n"); - fprintf(stderr, "\t-v : Verbose output\n"); - fprintf(stderr, "\n = atmegaXXuY or at90usbXXXY"); - - fprintf(stderr, "\nFor support and more information, please visit:\n"); - fprintf(stderr, "http://www.lufa-lib.org\n"); - - fprintf(stderr, "\nBased on the TeensyHID command line programmer software:\n"); - fprintf(stderr, "http://www.pjrc.com/teensy/loader_cli.html\n"); + if(err != NULL) fprintf(stderr, "%s\n\n", err); + fprintf(stderr, + "Usage: hid_bootloader_cli --mcu= [-w] [-h] [-n] [-b] [-v] \n" + "\t-w : Wait for device to appear\n" + "\t-r : Use hard reboot if device not online\n" + "\t-s : Use soft reboot if device not online (Teensy 3.x & 4.x)\n" + "\t-n : No reboot after programming\n" + "\t-b : Boot only, do not program\n" + "\t-v : Verbose output\n" + "\nUse `hid_bootloader_cli --list-mcus` to list supported MCUs.\n" + "\nFor support and more information, please visit:\n" + "\thttp://www.lufa-lib.org\n" + + "\nBased on the TeensyHID command line programmer software:\n" + "\thttp://www.pjrc.com/teensy/loader_cli.html\n"); exit(1); } @@ -61,23 +64,28 @@ int teensy_open(void); int teensy_write(void *buf, int len, double timeout); void teensy_close(void); int hard_reboot(void); +int soft_reboot(void); // Intel Hex File Functions int read_intel_hex(const char *filename); int ihex_bytes_within_range(int begin, int end); void ihex_get_data(int addr, int len, unsigned char *bytes); +int memory_is_blank(int addr, int block_size); // Misc stuff int printf_verbose(const char *format, ...); void delay(double seconds); void die(const char *str, ...); void parse_options(int argc, char **argv); +void boot(unsigned char *buf, int write_size); // options (from user via command line args) int wait_for_device_to_appear = 0; int hard_reboot_device = 0; +int soft_reboot_device = 0; int reboot_after_programming = 1; int verbose = 0; +int boot_only = 0; int code_size = 0, block_size = 0; const char *filename=NULL; @@ -90,27 +98,35 @@ const char *filename=NULL; int main(int argc, char **argv) { - unsigned char buf[260]; - int num, addr, r, first_block=1, waited=0; + unsigned char buf[2048]; + int num, addr, r, write_size; + + int first_block=1, waited=0; // parse command line arguments parse_options(argc, argv); - if (!filename) { - fprintf(stderr, "Filename must be specified\n\n"); - usage(); + if (!filename && !boot_only) { + usage("Filename must be specified"); } if (!code_size) { - fprintf(stderr, "MCU type must be specified\n\n"); - usage(); + usage("MCU type must be specified"); } - printf_verbose("Teensy Loader, Command Line, Version 2.0\n"); + printf_verbose("Teensy Loader, Command Line, Version 2.2\n"); - // read the intel hex file - // this is done first so any error is reported before using USB - num = read_intel_hex(filename); - if (num < 0) die("error reading intel hex file \"%s\"", filename); - printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n", - filename, num, (double)num / (double)code_size * 100.0); + if (block_size == 512 || block_size == 1024) { + write_size = block_size + 64; + } else { + write_size = block_size + 2; + }; + + if (!boot_only) { + // read the intel hex file + // this is done first so any error is reported before using USB + num = read_intel_hex(filename); + if (num < 0) die("error reading intel hex file \"%s\"", filename); + printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n", + filename, num, (double)num / (double)code_size * 100.0); + } // open the USB device while (1) { @@ -121,7 +137,14 @@ int main(int argc, char **argv) hard_reboot_device = 0; // only hard reboot once wait_for_device_to_appear = 1; } - if (!wait_for_device_to_appear) die("Unable to open device\n"); + if (soft_reboot_device) { + if (soft_reboot()) { + printf_verbose("Soft reboot performed\n"); + } + soft_reboot_device = 0; + wait_for_device_to_appear = 1; + } + if (!wait_for_device_to_appear) die("Unable to open device (hint: try -w option)\n"); if (!waited) { printf_verbose("Waiting for Teensy device...\n"); printf_verbose(" (hint: press the reset button)\n"); @@ -131,6 +154,12 @@ int main(int argc, char **argv) } printf_verbose("Found HalfKay Bootloader\n"); + if (boot_only) { + boot(buf, write_size); + teensy_close(); + return 0; + } + // if we waited for the device, read the hex file again // perhaps it changed while we were waiting? if (waited) { @@ -144,21 +173,34 @@ int main(int argc, char **argv) printf_verbose("Programming"); fflush(stdout); for (addr = 0; addr < code_size; addr += block_size) { - if (addr > 0 && !ihex_bytes_within_range(addr, addr + block_size - 1)) { + if (!first_block && !ihex_bytes_within_range(addr, addr + block_size - 1)) { // don't waste time on blocks that are unused, // but always do the first one to erase the chip continue; } + if (!first_block && memory_is_blank(addr, block_size)) continue; printf_verbose("."); - if (code_size < 0x10000) { + if (block_size <= 256 && code_size < 0x10000) { buf[0] = addr & 255; buf[1] = (addr >> 8) & 255; - } else { + ihex_get_data(addr, block_size, buf + 2); + write_size = block_size + 2; + } else if (block_size == 256) { buf[0] = (addr >> 8) & 255; buf[1] = (addr >> 16) & 255; + ihex_get_data(addr, block_size, buf + 2); + write_size = block_size + 2; + } else if (block_size == 512 || block_size == 1024) { + buf[0] = addr & 255; + buf[1] = (addr >> 8) & 255; + buf[2] = (addr >> 16) & 255; + memset(buf + 3, 0, 61); + ihex_get_data(addr, block_size, buf + 64); + write_size = block_size + 64; + } else { + die("Unknown code/block size\n"); } - ihex_get_data(addr, block_size, buf + 2); - r = teensy_write(buf, block_size + 2, first_block ? 3.0 : 0.25); + r = teensy_write(buf, write_size, first_block ? 5.0 : 0.5); if (!r) die("error writing to Teensy\n"); first_block = 0; } @@ -166,11 +208,7 @@ int main(int argc, char **argv) // reboot to the user's new code if (reboot_after_programming) { - printf_verbose("Booting\n"); - buf[0] = 0xFF; - buf[1] = 0xFF; - memset(buf + 2, 0, sizeof(buf) - 2); - teensy_write(buf, block_size + 2, 0.25); + boot(buf, write_size); } teensy_close(); return 0; @@ -183,6 +221,14 @@ int main(int argc, char **argv) /* */ /* USB Access - libusb (Linux & FreeBSD) */ /* */ +/* Uses libusb v0.1. To install: */ +/* - [debian, ubuntu, mint] apt install libusb-dev */ +/* - [redhat, centos] yum install libusb-devel */ +/* - [fedora] dnf install libusb-devel */ +/* - [arch linux] pacman -S libusb-compat */ +/* - [gentoo] emerge dev-libs/libusb-compat */ +/* */ +/* - [freebsd] seems to be preinstalled */ /****************************************************************/ #if defined(USE_LIBUSB) @@ -195,9 +241,7 @@ usb_dev_handle * open_usb_device(int vid, int pid) struct usb_bus *bus; struct usb_device *dev; usb_dev_handle *h; - #ifdef LIBUSB_HAS_GET_DRIVER_NP char buf[128]; - #endif int r; usb_init(); @@ -215,7 +259,7 @@ usb_dev_handle * open_usb_device(int vid, int pid) if (dev->descriptor.idProduct != pid) continue; h = usb_open(dev); if (!h) { - printf_verbose("Found device but unable to open"); + printf_verbose("Found device but unable to open\n"); continue; } #ifdef LIBUSB_HAS_GET_DRIVER_NP @@ -224,7 +268,7 @@ usb_dev_handle * open_usb_device(int vid, int pid) r = usb_detach_kernel_driver_np(h, 0); if (r < 0) { usb_close(h); - printf_verbose("Device is in use by \"%s\" driver", buf); + printf_verbose("Device is in use by \"%s\" driver\n", buf); continue; } } @@ -232,12 +276,15 @@ usb_dev_handle * open_usb_device(int vid, int pid) // Mac OS-X - removing this call to usb_claim_interface() might allow // this to work, even though it is a clear misuse of the libusb API. // normally Apple's IOKit should be used on Mac OS-X + #if !defined(MACOSX) r = usb_claim_interface(h, 0); if (r < 0) { usb_close(h); - printf_verbose("Unable to claim interface, check USB permissions"); + printf_verbose("Unable to claim interface, check USB permissions\n"); continue; } + #endif + return h; } } @@ -254,8 +301,8 @@ int teensy_open(void) if (!libusb_teensy_handle) libusb_teensy_handle = open_usb_device(0x03eb, 0x2067); - if (!libusb_teensy_handle) return 0; - return 1; + if (libusb_teensy_handle) return 1; + return 0; } int teensy_write(void *buf, int len, double timeout) @@ -263,10 +310,15 @@ int teensy_write(void *buf, int len, double timeout) int r; if (!libusb_teensy_handle) return 0; - r = usb_control_msg(libusb_teensy_handle, 0x21, 9, 0x0200, 0, (char *)buf, - len, (int)(timeout * 1000.0)); - if (r < 0) return 0; - return 1; + while (timeout > 0) { + r = usb_control_msg(libusb_teensy_handle, 0x21, 9, 0x0200, 0, + (char *)buf, len, (int)(timeout * 1000.0)); + if (r >= 0) return 1; + //printf("teensy_write, r=%d\n", r); + usleep(10000); + timeout -= 0.01; // TODO: subtract actual elapsed time + } + return 0; } void teensy_close(void) @@ -295,6 +347,36 @@ int hard_reboot(void) return 1; } +int soft_reboot(void) +{ + usb_dev_handle *serial_handle = NULL; + + serial_handle = open_usb_device(0x16C0, 0x0483); + + if (!serial_handle) + serial_handle = open_usb_device(0x03eb, 0x2067); + + if (!serial_handle) { + char *error = usb_strerror(); + printf("Error opening USB device: %s\n", error); + return 0; + } + + char reboot_command[] = {0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08}; + int response = usb_control_msg(serial_handle, 0x21, 0x20, 0, 0, reboot_command, sizeof reboot_command, 10000); + + usb_release_interface(serial_handle, 0); + usb_close(serial_handle); + + if (response < 0) { + char *error = usb_strerror(); + printf("Unable to soft reboot with USB error: %s\n", error); + return 0; + } + + return 1; +} + #endif @@ -368,7 +450,7 @@ HANDLE open_usb_device(int vid, int pid) int write_usb_device(HANDLE h, void *buf, int len, int timeout) { static HANDLE event = NULL; - unsigned char tmpbuf[1040]; + unsigned char tmpbuf[1089]; OVERLAPPED ov; DWORD n, r; @@ -392,9 +474,21 @@ int write_usb_device(HANDLE h, void *buf, int len, int timeout) if (r != WAIT_OBJECT_0) return 0; } if (!GetOverlappedResult(h, &ov, &n, FALSE)) return 0; + if (n <= 0) return 0; return 1; } +void print_win32_err(void) +{ + char buf[256]; + DWORD err; + + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, + 0, buf, sizeof(buf), NULL); + printf("err %ld: %s\n", err, buf); +} + static HANDLE win32_teensy_handle = NULL; int teensy_open(void) @@ -405,16 +499,27 @@ int teensy_open(void) if (!win32_teensy_handle) win32_teensy_handle = open_usb_device(0x03eb, 0x2067); - if (!win32_teensy_handle) return 0; - return 1; + + if (win32_teensy_handle) return 1; + return 0; } int teensy_write(void *buf, int len, double timeout) { int r; + uint32_t begin, now, total; + if (!win32_teensy_handle) return 0; - r = write_usb_device(win32_teensy_handle, buf, len, (int)(timeout * 1000.0)); - return r; + total = (uint32_t)(timeout * 1000.0); + begin = timeGetTime(); + now = begin; + do { + r = write_usb_device(win32_teensy_handle, buf, len, total - (now - begin)); + if (r > 0) return 1; + Sleep(10); + now = timeGetTime(); + } while (now - begin < total); + return 0; } void teensy_close(void) @@ -440,6 +545,12 @@ int hard_reboot(void) return r; } +int soft_reboot(void) +{ + printf("Soft reboot is not implemented for Win32\n"); + return 0; +} + #endif @@ -542,7 +653,7 @@ void init_hid_manager(void) IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); CFRelease(hid_manager); - printf_verbose("Error opening HID Manager"); + printf_verbose("Error opening HID Manager\n"); } } @@ -590,8 +701,8 @@ int teensy_open(void) if (!iokit_teensy_reference) iokit_teensy_reference = open_usb_device(0x03eb, 0x2067); - if (!iokit_teensy_reference) return 0; - return 1; + if (iokit_teensy_reference) return 1; + return 0; } int teensy_write(void *buf, int len, double timeout) @@ -603,9 +714,15 @@ int teensy_write(void *buf, int len, double timeout) // even though Apple documents it with a code example! // submitted to Apple on 22-sep-2009, problem ID 7245050 if (!iokit_teensy_reference) return 0; - ret = IOHIDDeviceSetReport(iokit_teensy_reference, - kIOHIDReportTypeOutput, 0, buf, len); - if (ret == kIOReturnSuccess) return 1; + + double start = CFAbsoluteTimeGetCurrent(); + while (CFAbsoluteTimeGetCurrent() - timeout < start) { + ret = IOHIDDeviceSetReport(iokit_teensy_reference, + kIOHIDReportTypeOutput, 0, buf, len); + if (ret == kIOReturnSuccess) return 1; + usleep(10000); + } + return 0; } @@ -634,6 +751,12 @@ int hard_reboot(void) return 0; } +int soft_reboot(void) +{ + printf("Soft reboot is not implemented for OSX\n"); + return 0; +} + #endif @@ -657,11 +780,6 @@ int hard_reboot(void) #include #endif -#ifndef USB_GET_DEVICEINFO -# define USB_GET_DEVICEINFO 0 -# error The USB_GET_DEVICEINFO ioctl() value is not defined for your system. -#endif - int open_usb_device(int vid, int pid) { int r, fd; @@ -717,7 +835,7 @@ int teensy_write(void *buf, int len, double timeout) { int r; - // TODO: implement timeout... how?? + // TODO: imeplement timeout... how?? r = write(uhid_teensy_fd, buf, len); if (r == len) return 1; return 0; @@ -748,6 +866,12 @@ int hard_reboot(void) return 0; } +int soft_reboot(void) +{ + printf("Soft reboot is not implemented for UHID\n"); + return 0; +} + #endif @@ -761,7 +885,7 @@ int hard_reboot(void) // the maximum flash image size we can support // chips with larger memory may be used, but only this // much intel-hex data can be loaded into memory! -#define MAX_MEMORY_SIZE 0x10000 +#define MAX_MEMORY_SIZE 0x100000 static unsigned char firmware_image[MAX_MEMORY_SIZE]; static unsigned char firmware_mask[MAX_MEMORY_SIZE]; @@ -795,8 +919,7 @@ int read_intel_hex(const char *filename) lineno++; if (*buf) { if (parse_hex_line(buf) == 0) { - //printf("Warning, parse error line %d\n", lineno); - fclose(fp); + printf("Warning, HEX parse error line %d\n", lineno); return -2; } } @@ -812,7 +935,7 @@ int read_intel_hex(const char *filename) /* parses a line of intel hex code, stores the data in bytes[] */ /* and the beginning address in addr, and returns a 1 if the */ -/* line was valid, or a 0 if an error occurred. The variable */ +/* line was valid, or a 0 if an error occured. The variable */ /* num gets the number of bytes that were stored into bytes[] */ @@ -820,23 +943,23 @@ int parse_hex_line(char *line) { int addr, code, num; - int sum, len, cksum, i; - char *ptr; - - num = 0; - if (line[0] != ':') return 0; - if (strlen(line) < 11) return 0; - ptr = line+1; - if (!sscanf(ptr, "%02x", &len)) return 0; - ptr += 2; - if ((int)strlen(line) < (11 + (len * 2)) ) return 0; - if (!sscanf(ptr, "%04x", &addr)) return 0; - ptr += 4; - /* printf("Line: length=%d Addr=%d\n", len, addr); */ - if (!sscanf(ptr, "%02x", &code)) return 0; + int sum, len, cksum, i; + char *ptr; + + num = 0; + if (line[0] != ':') return 0; + if (strlen(line) < 11) return 0; + ptr = line+1; + if (!sscanf(ptr, "%02x", &len)) return 0; + ptr += 2; + if ((int)strlen(line) < (11 + (len * 2)) ) return 0; + if (!sscanf(ptr, "%04x", &addr)) return 0; + ptr += 4; + /* printf("Line: length=%d Addr=%d\n", len, addr); */ + if (!sscanf(ptr, "%02x", &code)) return 0; if (addr + extended_addr + len >= MAX_MEMORY_SIZE) return 0; - ptr += 2; - sum = (len & 255) + ((addr >> 8) & 255) + (addr & 255) + (code & 255); + ptr += 2; + sum = (len & 255) + ((addr >> 8) & 255) + (addr & 255) + (code & 255); if (code != 0) { if (code == 1) { end_record_seen = 1; @@ -846,7 +969,7 @@ parse_hex_line(char *line) if (!sscanf(ptr, "%04x", &i)) return 1; ptr += 4; sum += ((i >> 8) & 255) + (i & 255); - if (!sscanf(ptr, "%02x", &cksum)) return 1; + if (!sscanf(ptr, "%02x", &cksum)) return 1; if (((sum & 255) + (cksum & 255)) & 255) return 1; extended_addr = i << 4; //printf("ext addr = %05X\n", extended_addr); @@ -855,27 +978,32 @@ parse_hex_line(char *line) if (!sscanf(ptr, "%04x", &i)) return 1; ptr += 4; sum += ((i >> 8) & 255) + (i & 255); - if (!sscanf(ptr, "%02x", &cksum)) return 1; + if (!sscanf(ptr, "%02x", &cksum)) return 1; if (((sum & 255) + (cksum & 255)) & 255) return 1; extended_addr = i << 16; + if (code_size > 1048576 && block_size >= 1024 && + extended_addr >= 0x60000000 && extended_addr < 0x60000000 + code_size) { + // Teensy 4.0 HEX files have 0x60000000 FlexSPI offset + extended_addr -= 0x60000000; + } //printf("ext addr = %08X\n", extended_addr); } return 1; // non-data line } byte_count += len; - while (num != len) { - if (sscanf(ptr, "%02x", &i) != 1) return 0; + while (num != len) { + if (sscanf(ptr, "%02x", &i) != 1) return 0; i &= 255; firmware_image[addr + extended_addr + num] = i; firmware_mask[addr + extended_addr + num] = 1; - ptr += 2; - sum += i; - (num)++; - if (num >= 256) return 0; - } - if (!sscanf(ptr, "%02x", &cksum)) return 0; - if (((sum & 255) + (cksum & 255)) & 255) return 0; /* checksum error */ - return 1; + ptr += 2; + sum += i; + (num)++; + if (num >= 256) return 0; + } + if (!sscanf(ptr, "%02x", &cksum)) return 0; + if (((sum & 255) + (cksum & 255)) & 255) return 0; /* checksum error */ + return 1; } int ihex_bytes_within_range(int begin, int end) @@ -912,6 +1040,21 @@ void ihex_get_data(int addr, int len, unsigned char *bytes) } } +int memory_is_blank(int addr, int block_size) +{ + if (addr < 0 || addr > MAX_MEMORY_SIZE) return 1; + + while (block_size && addr < MAX_MEMORY_SIZE) { + if (firmware_mask[addr] && firmware_image[addr] != 255) return 0; + addr++; + block_size--; + } + return 1; +} + + + + /****************************************************************/ /* */ /* Misc Functions */ @@ -921,22 +1064,21 @@ void ihex_get_data(int addr, int len, unsigned char *bytes) int printf_verbose(const char *format, ...) { va_list ap; - int r = 0; + int r; va_start(ap, format); if (verbose) { r = vprintf(format, ap); fflush(stdout); + return r; } - va_end(ap); - - return r; + return 0; } void delay(double seconds) { - #ifdef USE_WIN32 - sleep(seconds * 1000.0); + #ifdef WIN32 + Sleep(seconds * 1000.0); #else usleep(seconds * 1000000.0); #endif @@ -949,65 +1091,146 @@ void die(const char *str, ...) va_start(ap, str); vfprintf(stderr, str, ap); fprintf(stderr, "\n"); - va_end(ap); - exit(1); } -#if defined USE_WIN32 +#if defined(WIN32) #define strcasecmp stricmp #endif + +static const struct { + const char *name; + int code_size; + int block_size; +} MCUs[] = { + {"at90usb162", 15872, 128}, + {"atmega32u4", 32256, 128}, + {"at90usb646", 64512, 256}, + {"at90usb1286", 130048, 256}, +#if defined(USE_LIBUSB) || defined(USE_APPLE_IOKIT) || defined(USE_WIN32) + {"mkl26z64", 63488, 512}, + {"mk20dx128", 131072, 1024}, + {"mk20dx256", 262144, 1024}, + {"mk66fx1m0", 1048576, 1024}, + {"mk64fx512", 524288, 1024}, + {"imxrt1062", 2031616, 1024}, + + // Add duplicates that match friendly Teensy Names + // Match board names in boards.txt + {"TEENSY2", 32256, 128}, + {"TEENSY2PP", 130048, 256}, + {"TEENSYLC", 63488, 512}, + {"TEENSY30", 131072, 1024}, + {"TEENSY31", 262144, 1024}, + {"TEENSY32", 262144, 1024}, + {"TEENSY35", 524288, 1024}, + {"TEENSY36", 1048576, 1024}, + {"TEENSY40", 2031616, 1024}, + {"TEENSY41", 8126464, 1024}, +#endif + {NULL, 0, 0}, +}; + + +void list_mcus() +{ + int i; + printf("Supported MCUs are:\n"); + for(i=0; MCUs[i].name != NULL; i++) + printf(" - %s\n", MCUs[i].name); + exit(1); +} + + +void read_mcu(char *name) +{ + int i; + + if(name == NULL) { + fprintf(stderr, "No MCU specified.\n"); + list_mcus(); + } + + for(i=0; MCUs[i].name != NULL; i++) { + if(strcasecmp(name, MCUs[i].name) == 0) { + code_size = MCUs[i].code_size; + block_size = MCUs[i].block_size; + return; + } + } + + fprintf(stderr, "Unknown MCU type \"%s\"\n", name); + list_mcus(); +} + + +void parse_flag(char *arg) +{ + int i; + for(i=1; arg[i]; i++) { + switch(arg[i]) { + case 'w': wait_for_device_to_appear = 1; break; + case 'r': hard_reboot_device = 1; break; + case 's': soft_reboot_device = 1; break; + case 'n': reboot_after_programming = 0; break; + case 'v': verbose = 1; break; + case 'b': boot_only = 1; break; + default: + fprintf(stderr, "Unknown flag '%c'\n\n", arg[i]); + usage(NULL); + } + } +} + + void parse_options(int argc, char **argv) { int i; - const char *arg; + char *arg; for (i=1; i