/* 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
* http://www.pjrc.com/teensy/49-teensy.rules
*/
+
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
-void usage(void)
+void usage(const char *err)
{
- fprintf(stderr, "Usage: hid_bootloader_cli -mmcu=<MCU> [-w] [-h] [-n] [-v] <file.hex>\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<MCU> = 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=<MCU> [-w] [-h] [-n] [-b] [-v] <file.hex>\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);
}
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;
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) {
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");
}
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) {
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;
}
// 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;
/* */
/* 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)
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();
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
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;
}
}
// 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;
}
}
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)
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)
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
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;
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)
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)
return r;
}
+int soft_reboot(void)
+{
+ printf("Soft reboot is not implemented for Win32\n");
+ return 0;
+}
+
#endif
IOHIDManagerUnscheduleFromRunLoop(hid_manager,
CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
CFRelease(hid_manager);
- printf_verbose("Error opening HID Manager");
+ printf_verbose("Error opening HID Manager\n");
}
}
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)
// 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;
}
return 0;
}
+int soft_reboot(void)
+{
+ printf("Soft reboot is not implemented for OSX\n");
+ return 0;
+}
+
#endif
#include <dev/usb/usb_ioctl.h>
#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;
{
int r;
- // TODO: implement timeout... how??
+ // TODO: imeplement timeout... how??
r = write(uhid_teensy_fd, buf, len);
if (r == len) return 1;
return 0;
return 0;
}
+int soft_reboot(void)
+{
+ printf("Soft reboot is not implemented for UHID\n");
+ return 0;
+}
+
#endif
// 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];
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;
}
}
/* 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[] */
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;
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);
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)
}
}
+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 */
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
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<argc; i++) {
arg = argv[i];
- if (*arg == '-') {
- if (strcmp(arg, "-w") == 0) {
- wait_for_device_to_appear = 1;
- } else if (strcmp(arg, "-r") == 0) {
- hard_reboot_device = 1;
- } else if (strcmp(arg, "-n") == 0) {
- reboot_after_programming = 0;
- } else if (strcmp(arg, "-v") == 0) {
- verbose = 1;
- } else if (strncmp(arg, "-mmcu=", 6) == 0) {
- arg += 6;
-
- if (strncmp(arg, "at90usb", 7) == 0) {
- arg += 7;
- } else if (strncmp(arg, "atmega", 6) == 0) {
- arg += 6;
- } else {
- die("Unknown MCU type\n");
+ //backward compatibility with previous versions.
+ if(strncmp(arg, "-mmcu=", 6) == 0) {
+ read_mcu(strchr(arg, '=') + 1);
+ }
+
+ else if(arg[0] == '-') {
+ if(arg[1] == '-') {
+ char *name = &arg[2];
+ char *val = strchr(name, '=');
+ if(val == NULL) {
+ //value must be the next string.
+ val = argv[++i];
+ }
+ else {
+ //we found an =, so split the string at it.
+ *val = '\0';
+ val = &val[1];
}
- if (strncmp(arg, "128", 3) == 0) {
- code_size = 128 * 1024;
- block_size = 256;
- } else if (strncmp(arg, "64", 2) == 0) {
- code_size = 64 * 1024;
- block_size = 256;
- } else if (strncmp(arg, "32", 2) == 0) {
- code_size = 32 * 1024;
- block_size = 128;
- } else if (strncmp(arg, "16", 2) == 0) {
- code_size = 16 * 1024;
- block_size = 128;
- } else if (strncmp(arg, "8", 1) == 0) {
- code_size = 8 * 1024;
- block_size = 128;
- } else {
- die("Unknown MCU type\n");
+ if(strcasecmp(name, "help") == 0) usage(NULL);
+ else if(strcasecmp(name, "mcu") == 0) read_mcu(val);
+ else if(strcasecmp(name, "list-mcus") == 0) list_mcus();
+ else {
+ fprintf(stderr, "Unknown option \"%s\"\n\n", arg);
+ usage(NULL);
}
}
- } else {
- filename = argv[i];
+ else parse_flag(arg);
}
+ else filename = arg;
}
}
+void boot(unsigned char *buf, int write_size)
+{
+ printf_verbose("Booting\n");
+ memset(buf, 0, write_size);
+ buf[0] = 0xFF;
+ buf[1] = 0xFF;
+ buf[2] = 0xFF;
+ teensy_write(buf, write_size, 0.5);
+}