1 /* Modified for the LUFA HID Bootloader by Dean Camera
2 * http://www.lufa-lib.org
4 * THIS MODIFIED VERSION IS UNSUPPORTED BY PJRC.
7 /* Teensy Loader, Command Line Interface
8 * Program and Reboot Teensy Board with HalfKay Bootloader
9 * http://www.pjrc.com/teensy/loader_cli.html
10 * Copyright 2008-2016, PJRC.COM, LLC
12 * You may redistribute this program and/or modify it under the terms
13 * of the GNU General Public License as published by the Free Software
14 * Foundation, version 3 of the License.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see http://www.gnu.org/licenses/
25 /* Want to incorporate this code into a proprietary application??
26 * Just email paul@pjrc.com to ask. Usually it's not a problem,
27 * but you do need to ask to use this code in any way other than
28 * those permitted by the GNU General Public License, version 3 */
30 /* For non-root permissions on ubuntu or similar udev-based linux
31 * http://www.pjrc.com/teensy/49-teensy.rules
42 void usage(const char *err
)
44 if(err
!= NULL
) fprintf(stderr
, "%s\n\n", err
);
46 "Usage: hid_bootloader_cli --mcu=<MCU> [-w] [-h] [-n] [-b] [-v] <file.hex>\n"
47 "\t-w : Wait for device to appear\n"
48 "\t-r : Use hard reboot if device not online\n"
49 "\t-s : Use soft reboot if device not online (Teensy 3.x & 4.x)\n"
50 "\t-n : No reboot after programming\n"
51 "\t-b : Boot only, do not program\n"
52 "\t-v : Verbose output\n"
53 "\nUse `hid_bootloader_cli --list-mcus` to list supported MCUs.\n"
54 "\nFor support and more information, please visit:\n"
55 "\thttp://www.lufa-lib.org\n"
57 "\nBased on the TeensyHID command line programmer software:\n"
58 "\thttp://www.pjrc.com/teensy/loader_cli.html\n");
62 // USB Access Functions
63 int teensy_open(void);
64 int teensy_write(void *buf
, int len
, double timeout
);
65 void teensy_close(void);
66 int hard_reboot(void);
67 int soft_reboot(void);
69 // Intel Hex File Functions
70 int read_intel_hex(const char *filename
);
71 int ihex_bytes_within_range(int begin
, int end
);
72 void ihex_get_data(int addr
, int len
, unsigned char *bytes
);
73 int memory_is_blank(int addr
, int block_size
);
76 int printf_verbose(const char *format
, ...);
77 void delay(double seconds
);
78 void die(const char *str
, ...);
79 void parse_options(int argc
, char **argv
);
80 void boot(unsigned char *buf
, int write_size
);
82 // options (from user via command line args)
83 int wait_for_device_to_appear
= 0;
84 int hard_reboot_device
= 0;
85 int soft_reboot_device
= 0;
86 int reboot_after_programming
= 1;
89 int code_size
= 0, block_size
= 0;
90 const char *filename
=NULL
;
93 /****************************************************************/
97 /****************************************************************/
99 int main(int argc
, char **argv
)
101 unsigned char buf
[2048];
102 int num
, addr
, r
, write_size
;
104 int first_block
=1, waited
=0;
106 // parse command line arguments
107 parse_options(argc
, argv
);
108 if (!filename
&& !boot_only
) {
109 usage("Filename must be specified");
112 usage("MCU type must be specified");
114 printf_verbose("Teensy Loader, Command Line, Version 2.2\n");
116 if (block_size
== 512 || block_size
== 1024) {
117 write_size
= block_size
+ 64;
119 write_size
= block_size
+ 2;
123 // read the intel hex file
124 // this is done first so any error is reported before using USB
125 num
= read_intel_hex(filename
);
126 if (num
< 0) die("error reading intel hex file \"%s\"", filename
);
127 printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n",
128 filename
, num
, (double)num
/ (double)code_size
* 100.0);
131 // open the USB device
133 if (teensy_open()) break;
134 if (hard_reboot_device
) {
135 if (!hard_reboot()) die("Unable to find rebootor\n");
136 printf_verbose("Hard Reboot performed\n");
137 hard_reboot_device
= 0; // only hard reboot once
138 wait_for_device_to_appear
= 1;
140 if (soft_reboot_device
) {
142 printf_verbose("Soft reboot performed\n");
144 soft_reboot_device
= 0;
145 wait_for_device_to_appear
= 1;
147 if (!wait_for_device_to_appear
) die("Unable to open device (hint: try -w option)\n");
149 printf_verbose("Waiting for Teensy device...\n");
150 printf_verbose(" (hint: press the reset button)\n");
155 printf_verbose("Found HalfKay Bootloader\n");
158 boot(buf
, write_size
);
163 // if we waited for the device, read the hex file again
164 // perhaps it changed while we were waiting?
166 num
= read_intel_hex(filename
);
167 if (num
< 0) die("error reading intel hex file \"%s\"", filename
);
168 printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n",
169 filename
, num
, (double)num
/ (double)code_size
* 100.0);
173 printf_verbose("Programming");
175 for (addr
= 0; addr
< code_size
; addr
+= block_size
) {
176 if (!first_block
&& !ihex_bytes_within_range(addr
, addr
+ block_size
- 1)) {
177 // don't waste time on blocks that are unused,
178 // but always do the first one to erase the chip
181 if (!first_block
&& memory_is_blank(addr
, block_size
)) continue;
183 if (block_size
<= 256 && code_size
< 0x10000) {
185 buf
[1] = (addr
>> 8) & 255;
186 ihex_get_data(addr
, block_size
, buf
+ 2);
187 write_size
= block_size
+ 2;
188 } else if (block_size
== 256) {
189 buf
[0] = (addr
>> 8) & 255;
190 buf
[1] = (addr
>> 16) & 255;
191 ihex_get_data(addr
, block_size
, buf
+ 2);
192 write_size
= block_size
+ 2;
193 } else if (block_size
== 512 || block_size
== 1024) {
195 buf
[1] = (addr
>> 8) & 255;
196 buf
[2] = (addr
>> 16) & 255;
197 memset(buf
+ 3, 0, 61);
198 ihex_get_data(addr
, block_size
, buf
+ 64);
199 write_size
= block_size
+ 64;
201 die("Unknown code/block size\n");
203 r
= teensy_write(buf
, write_size
, first_block ?
5.0 : 0.5);
204 if (!r
) die("error writing to Teensy\n");
207 printf_verbose("\n");
209 // reboot to the user's new code
210 if (reboot_after_programming
) {
211 boot(buf
, write_size
);
220 /****************************************************************/
222 /* USB Access - libusb (Linux & FreeBSD) */
224 /* Uses libusb v0.1. To install: */
225 /* - [debian, ubuntu, mint] apt install libusb-dev */
226 /* - [redhat, centos] yum install libusb-devel */
227 /* - [fedora] dnf install libusb-devel */
228 /* - [arch linux] pacman -S libusb-compat */
229 /* - [gentoo] emerge dev-libs/libusb-compat */
231 /* - [freebsd] seems to be preinstalled */
232 /****************************************************************/
234 #if defined(USE_LIBUSB)
236 // http://libusb.sourceforge.net/doc/index.html
239 usb_dev_handle
* open_usb_device(int vid
, int pid
)
242 struct usb_device
*dev
;
250 //printf_verbose("\nSearching for USB device:\n");
251 for (bus
= usb_get_busses(); bus
; bus
= bus
->next
) {
252 for (dev
= bus
->devices
; dev
; dev
= dev
->next
) {
253 //printf_verbose("bus \"%s\", device \"%s\" vid=%04X, pid=%04X\n",
254 // bus->dirname, dev->filename,
255 // dev->descriptor.idVendor,
256 // dev->descriptor.idProduct
258 if (dev
->descriptor
.idVendor
!= vid
) continue;
259 if (dev
->descriptor
.idProduct
!= pid
) continue;
262 printf_verbose("Found device but unable to open\n");
265 #ifdef LIBUSB_HAS_GET_DRIVER_NP
266 r
= usb_get_driver_np(h
, 0, buf
, sizeof(buf
));
268 r
= usb_detach_kernel_driver_np(h
, 0);
271 printf_verbose("Device is in use by \"%s\" driver\n", buf
);
276 // Mac OS-X - removing this call to usb_claim_interface() might allow
277 // this to work, even though it is a clear misuse of the libusb API.
278 // normally Apple's IOKit should be used on Mac OS-X
280 r
= usb_claim_interface(h
, 0);
283 printf_verbose("Unable to claim interface, check USB permissions\n");
294 static usb_dev_handle
*libusb_teensy_handle
= NULL
;
296 int teensy_open(void)
299 libusb_teensy_handle
= open_usb_device(0x16C0, 0x0478);
301 if (!libusb_teensy_handle
)
302 libusb_teensy_handle
= open_usb_device(0x03eb, 0x2067);
304 if (libusb_teensy_handle
) return 1;
308 int teensy_write(void *buf
, int len
, double timeout
)
312 if (!libusb_teensy_handle
) return 0;
313 while (timeout
> 0) {
314 r
= usb_control_msg(libusb_teensy_handle
, 0x21, 9, 0x0200, 0,
315 (char *)buf
, len
, (int)(timeout
* 1000.0));
316 if (r
>= 0) return 1;
317 //printf("teensy_write, r=%d\n", r);
319 timeout
-= 0.01; // TODO: subtract actual elapsed time
324 void teensy_close(void)
326 if (!libusb_teensy_handle
) return;
327 usb_release_interface(libusb_teensy_handle
, 0);
328 usb_close(libusb_teensy_handle
);
329 libusb_teensy_handle
= NULL
;
332 int hard_reboot(void)
334 usb_dev_handle
*rebootor
;
337 rebootor
= open_usb_device(0x16C0, 0x0477);
340 rebootor
= open_usb_device(0x03eb, 0x2067);
342 if (!rebootor
) return 0;
343 r
= usb_control_msg(rebootor
, 0x21, 9, 0x0200, 0, "reboot", 6, 100);
344 usb_release_interface(rebootor
, 0);
350 int soft_reboot(void)
352 usb_dev_handle
*serial_handle
= NULL
;
354 serial_handle
= open_usb_device(0x16C0, 0x0483);
357 serial_handle
= open_usb_device(0x03eb, 0x2067);
359 if (!serial_handle
) {
360 char *error
= usb_strerror();
361 printf("Error opening USB device: %s\n", error
);
365 char reboot_command
[] = {0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08};
366 int response
= usb_control_msg(serial_handle
, 0x21, 0x20, 0, 0, reboot_command
, sizeof reboot_command
, 10000);
368 usb_release_interface(serial_handle
, 0);
369 usb_close(serial_handle
);
372 char *error
= usb_strerror();
373 printf("Unable to soft reboot with USB error: %s\n", error
);
383 /****************************************************************/
385 /* USB Access - Microsoft WIN32 */
387 /****************************************************************/
389 #if defined(USE_WIN32)
391 // http://msdn.microsoft.com/en-us/library/ms790932.aspx
393 #include <setupapi.h>
394 #include <ddk/hidsdi.h>
395 #include <ddk/hidclass.h>
397 HANDLE
open_usb_device(int vid
, int pid
)
401 DWORD index
, required_size
;
402 SP_DEVICE_INTERFACE_DATA iface
;
403 SP_DEVICE_INTERFACE_DETAIL_DATA
*details
;
404 HIDD_ATTRIBUTES attrib
;
408 HidD_GetHidGuid(&guid
);
409 info
= SetupDiGetClassDevs(&guid
, NULL
, NULL
, DIGCF_PRESENT
| DIGCF_DEVICEINTERFACE
);
410 if (info
== INVALID_HANDLE_VALUE
) return NULL
;
411 for (index
=0; 1 ;index
++) {
412 iface
.cbSize
= sizeof(SP_DEVICE_INTERFACE_DATA
);
413 ret
= SetupDiEnumDeviceInterfaces(info
, NULL
, &guid
, index
, &iface
);
415 SetupDiDestroyDeviceInfoList(info
);
418 SetupDiGetInterfaceDeviceDetail(info
, &iface
, NULL
, 0, &required_size
, NULL
);
419 details
= (SP_DEVICE_INTERFACE_DETAIL_DATA
*)malloc(required_size
);
420 if (details
== NULL
) continue;
421 memset(details
, 0, required_size
);
422 details
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA
);
423 ret
= SetupDiGetDeviceInterfaceDetail(info
, &iface
, details
,
424 required_size
, NULL
, NULL
);
429 h
= CreateFile(details
->DevicePath
, GENERIC_READ
|GENERIC_WRITE
,
430 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
431 FILE_FLAG_OVERLAPPED
, NULL
);
433 if (h
== INVALID_HANDLE_VALUE
) continue;
434 attrib
.Size
= sizeof(HIDD_ATTRIBUTES
);
435 ret
= HidD_GetAttributes(h
, &attrib
);
440 if (attrib
.VendorID
!= vid
|| attrib
.ProductID
!= pid
) {
444 SetupDiDestroyDeviceInfoList(info
);
450 int write_usb_device(HANDLE h
, void *buf
, int len
, int timeout
)
452 static HANDLE event
= NULL
;
453 unsigned char tmpbuf
[1089];
457 if (len
> sizeof(tmpbuf
) - 1) return 0;
459 event
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
);
460 if (!event
) return 0;
463 memset(&ov
, 0, sizeof(ov
));
466 memcpy(tmpbuf
+ 1, buf
, len
);
467 if (!WriteFile(h
, tmpbuf
, len
+ 1, NULL
, &ov
)) {
468 if (GetLastError() != ERROR_IO_PENDING
) return 0;
469 r
= WaitForSingleObject(event
, timeout
);
470 if (r
== WAIT_TIMEOUT
) {
474 if (r
!= WAIT_OBJECT_0
) return 0;
476 if (!GetOverlappedResult(h
, &ov
, &n
, FALSE
)) return 0;
477 if (n
<= 0) return 0;
481 void print_win32_err(void)
486 err
= GetLastError();
487 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, err
,
488 0, buf
, sizeof(buf
), NULL
);
489 printf("err %ld: %s\n", err
, buf
);
492 static HANDLE win32_teensy_handle
= NULL
;
494 int teensy_open(void)
497 win32_teensy_handle
= open_usb_device(0x16C0, 0x0478);
499 if (!win32_teensy_handle
)
500 win32_teensy_handle
= open_usb_device(0x03eb, 0x2067);
503 if (win32_teensy_handle
) return 1;
507 int teensy_write(void *buf
, int len
, double timeout
)
510 uint32_t begin
, now
, total
;
512 if (!win32_teensy_handle
) return 0;
513 total
= (uint32_t)(timeout
* 1000.0);
514 begin
= timeGetTime();
517 r
= write_usb_device(win32_teensy_handle
, buf
, len
, total
- (now
- begin
));
521 } while (now
- begin
< total
);
525 void teensy_close(void)
527 if (!win32_teensy_handle
) return;
528 CloseHandle(win32_teensy_handle
);
529 win32_teensy_handle
= NULL
;
532 int hard_reboot(void)
537 rebootor
= open_usb_device(0x16C0, 0x0477);
540 rebootor
= open_usb_device(0x03eb, 0x2067);
542 if (!rebootor
) return 0;
543 r
= write_usb_device(rebootor
, "reboot", 6, 100);
544 CloseHandle(rebootor
);
548 int soft_reboot(void)
550 printf("Soft reboot is not implemented for Win32\n");
558 /****************************************************************/
560 /* USB Access - Apple's IOKit, Mac OS-X */
562 /****************************************************************/
564 #if defined(USE_APPLE_IOKIT)
566 // http://developer.apple.com/technotes/tn2007/tn2187.html
567 #include <IOKit/IOKitLib.h>
568 #include <IOKit/hid/IOHIDLib.h>
569 #include <IOKit/hid/IOHIDDevice.h>
571 struct usb_list_struct
{
575 struct usb_list_struct
*next
;
578 static struct usb_list_struct
*usb_list
=NULL
;
579 static IOHIDManagerRef hid_manager
=NULL
;
581 void attach_callback(void *context
, IOReturn r
, void *hid_mgr
, IOHIDDeviceRef dev
)
584 struct usb_list_struct
*n
, *p
;
588 type
= IOHIDDeviceGetProperty(dev
, CFSTR(kIOHIDVendorIDKey
));
589 if (!type
|| CFGetTypeID(type
) != CFNumberGetTypeID()) return;
590 if (!CFNumberGetValue((CFNumberRef
)type
, kCFNumberSInt32Type
, &vid
)) return;
591 type
= IOHIDDeviceGetProperty(dev
, CFSTR(kIOHIDProductIDKey
));
592 if (!type
|| CFGetTypeID(type
) != CFNumberGetTypeID()) return;
593 if (!CFNumberGetValue((CFNumberRef
)type
, kCFNumberSInt32Type
, &pid
)) return;
594 n
= (struct usb_list_struct
*)malloc(sizeof(struct usb_list_struct
));
596 //printf("attach callback: vid=%04X, pid=%04X\n", vid, pid);
601 if (usb_list
== NULL
) {
604 for (p
= usb_list
; p
->next
; p
= p
->next
) ;
609 void detach_callback(void *context
, IOReturn r
, void *hid_mgr
, IOHIDDeviceRef dev
)
611 struct usb_list_struct
*p
, *tmp
, *prev
=NULL
;
617 prev
->next
= p
->next
;
631 void init_hid_manager(void)
633 CFMutableDictionaryRef dict
;
636 if (hid_manager
) return;
637 hid_manager
= IOHIDManagerCreate(kCFAllocatorDefault
, kIOHIDOptionsTypeNone
);
638 if (hid_manager
== NULL
|| CFGetTypeID(hid_manager
) != IOHIDManagerGetTypeID()) {
639 if (hid_manager
) CFRelease(hid_manager
);
640 printf_verbose("no HID Manager - maybe this is a pre-Leopard (10.5) system?\n");
643 dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
644 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
646 IOHIDManagerSetDeviceMatching(hid_manager
, dict
);
648 IOHIDManagerScheduleWithRunLoop(hid_manager
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
);
649 IOHIDManagerRegisterDeviceMatchingCallback(hid_manager
, attach_callback
, NULL
);
650 IOHIDManagerRegisterDeviceRemovalCallback(hid_manager
, detach_callback
, NULL
);
651 ret
= IOHIDManagerOpen(hid_manager
, kIOHIDOptionsTypeNone
);
652 if (ret
!= kIOReturnSuccess
) {
653 IOHIDManagerUnscheduleFromRunLoop(hid_manager
,
654 CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
);
655 CFRelease(hid_manager
);
656 printf_verbose("Error opening HID Manager\n");
660 static void do_run_loop(void)
662 while (CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0, true) == kCFRunLoopRunHandledSource
) ;
665 IOHIDDeviceRef
open_usb_device(int vid
, int pid
)
667 struct usb_list_struct
*p
;
672 for (p
= usb_list
; p
; p
= p
->next
) {
673 if (p
->vid
== vid
&& p
->pid
== pid
) {
674 ret
= IOHIDDeviceOpen(p
->ref
, kIOHIDOptionsTypeNone
);
675 if (ret
== kIOReturnSuccess
) return p
->ref
;
681 void close_usb_device(IOHIDDeviceRef dev
)
683 struct usb_list_struct
*p
;
686 for (p
= usb_list
; p
; p
= p
->next
) {
688 IOHIDDeviceClose(dev
, kIOHIDOptionsTypeNone
);
694 static IOHIDDeviceRef iokit_teensy_reference
= NULL
;
696 int teensy_open(void)
699 iokit_teensy_reference
= open_usb_device(0x16C0, 0x0478);
701 if (!iokit_teensy_reference
)
702 iokit_teensy_reference
= open_usb_device(0x03eb, 0x2067);
704 if (iokit_teensy_reference
) return 1;
708 int teensy_write(void *buf
, int len
, double timeout
)
712 // timeouts do not work on OS-X
713 // IOHIDDeviceSetReportWithCallback is not implemented
714 // even though Apple documents it with a code example!
715 // submitted to Apple on 22-sep-2009, problem ID 7245050
716 if (!iokit_teensy_reference
) return 0;
718 double start
= CFAbsoluteTimeGetCurrent();
719 while (CFAbsoluteTimeGetCurrent() - timeout
< start
) {
720 ret
= IOHIDDeviceSetReport(iokit_teensy_reference
,
721 kIOHIDReportTypeOutput
, 0, buf
, len
);
722 if (ret
== kIOReturnSuccess
) return 1;
729 void teensy_close(void)
731 if (!iokit_teensy_reference
) return;
732 close_usb_device(iokit_teensy_reference
);
733 iokit_teensy_reference
= NULL
;
736 int hard_reboot(void)
738 IOHIDDeviceRef rebootor
;
741 rebootor
= open_usb_device(0x16C0, 0x0477);
744 rebootor
= open_usb_device(0x03eb, 0x2067);
746 if (!rebootor
) return 0;
747 ret
= IOHIDDeviceSetReport(rebootor
,
748 kIOHIDReportTypeOutput
, 0, (uint8_t *)("reboot"), 6);
749 close_usb_device(rebootor
);
750 if (ret
== kIOReturnSuccess
) return 1;
754 int soft_reboot(void)
756 printf("Soft reboot is not implemented for OSX\n");
764 /****************************************************************/
766 /* USB Access - BSD's UHID driver */
768 /****************************************************************/
770 #if defined(USE_UHID)
772 // Thanks to Todd T Fries for help getting this working on OpenBSD
773 // and to Chris Kuethe for the initial patch to use UHID.
775 #include <sys/ioctl.h>
778 #include <dev/usb/usb.h>
779 #ifndef USB_GET_DEVICEINFO
780 #include <dev/usb/usb_ioctl.h>
783 int open_usb_device(int vid
, int pid
)
788 struct usb_device_info info
;
791 dir
= opendir("/dev");
793 while ((d
= readdir(dir
)) != NULL
) {
794 if (strncmp(d
->d_name
, "uhid", 4) != 0) continue;
795 snprintf(buf
, sizeof(buf
), "/dev/%s", d
->d_name
);
796 fd
= open(buf
, O_RDWR
);
797 if (fd
< 0) continue;
798 r
= ioctl(fd
, USB_GET_DEVICEINFO
, &info
);
800 // NetBSD: added in 2004
801 // OpenBSD: added November 23, 2009
802 // FreeBSD: missing (FreeBSD 8.0) - USE_LIBUSB works!
803 die("Error: your uhid driver does not support"
804 " USB_GET_DEVICEINFO, please upgrade!\n");
809 //printf("%s: v=%d, p=%d\n", buf, info.udi_vendorNo, info.udi_productNo);
810 if (info
.udi_vendorNo
== vid
&& info
.udi_productNo
== pid
) {
820 static int uhid_teensy_fd
= -1;
822 int teensy_open(void)
825 uhid_teensy_fd
= open_usb_device(0x16C0, 0x0478);
827 if (uhid_teensy_fd
< 0)
828 uhid_teensy_fd
= open_usb_device(0x03eb, 0x2067);
830 if (uhid_teensy_fd
< 0) return 0;
834 int teensy_write(void *buf
, int len
, double timeout
)
838 // TODO: imeplement timeout... how??
839 r
= write(uhid_teensy_fd
, buf
, len
);
840 if (r
== len
) return 1;
844 void teensy_close(void)
846 if (uhid_teensy_fd
>= 0) {
847 close(uhid_teensy_fd
);
852 int hard_reboot(void)
856 rebootor_fd
= open_usb_device(0x16C0, 0x0477);
859 rebootor_fd
= open_usb_device(0x03eb, 0x2067);
861 if (rebootor_fd
< 0) return 0;
862 r
= write(rebootor_fd
, "reboot", 6);
865 if (r
== 6) return 1;
869 int soft_reboot(void)
871 printf("Soft reboot is not implemented for UHID\n");
879 /****************************************************************/
881 /* Read Intel Hex File */
883 /****************************************************************/
885 // the maximum flash image size we can support
886 // chips with larger memory may be used, but only this
887 // much intel-hex data can be loaded into memory!
888 #define MAX_MEMORY_SIZE 0x100000
890 static unsigned char firmware_image
[MAX_MEMORY_SIZE
];
891 static unsigned char firmware_mask
[MAX_MEMORY_SIZE
];
892 static int end_record_seen
=0;
893 static int byte_count
;
894 static unsigned int extended_addr
= 0;
895 static int parse_hex_line(char *line
);
897 int read_intel_hex(const char *filename
)
905 for (i
=0; i
<MAX_MEMORY_SIZE
; i
++) {
906 firmware_image
[i
] = 0xFF;
907 firmware_mask
[i
] = 0;
911 fp
= fopen(filename
, "r");
913 //printf("Unable to read file %s\n", filename);
918 if (!fgets(buf
, sizeof(buf
), fp
)) break;
921 if (parse_hex_line(buf
) == 0) {
922 printf("Warning, HEX parse error line %d\n", lineno
);
926 if (end_record_seen
) break;
927 if (feof(stdin
)) break;
934 /* from ihex.c, at http://www.pjrc.com/tech/8051/pm2_docs/intel-hex.html */
936 /* parses a line of intel hex code, stores the data in bytes[] */
937 /* and the beginning address in addr, and returns a 1 if the */
938 /* line was valid, or a 0 if an error occured. The variable */
939 /* num gets the number of bytes that were stored into bytes[] */
943 parse_hex_line(char *line
)
946 int sum
, len
, cksum
, i
;
950 if (line
[0] != ':') return 0;
951 if (strlen(line
) < 11) return 0;
953 if (!sscanf(ptr
, "%02x", &len
)) return 0;
955 if ((int)strlen(line
) < (11 + (len
* 2)) ) return 0;
956 if (!sscanf(ptr
, "%04x", &addr
)) return 0;
958 /* printf("Line: length=%d Addr=%d\n", len, addr); */
959 if (!sscanf(ptr
, "%02x", &code
)) return 0;
960 if (addr
+ extended_addr
+ len
>= MAX_MEMORY_SIZE
) return 0;
962 sum
= (len
& 255) + ((addr
>> 8) & 255) + (addr
& 255) + (code
& 255);
968 if (code
== 2 && len
== 2) {
969 if (!sscanf(ptr
, "%04x", &i
)) return 1;
971 sum
+= ((i
>> 8) & 255) + (i
& 255);
972 if (!sscanf(ptr
, "%02x", &cksum
)) return 1;
973 if (((sum
& 255) + (cksum
& 255)) & 255) return 1;
974 extended_addr
= i
<< 4;
975 //printf("ext addr = %05X\n", extended_addr);
977 if (code
== 4 && len
== 2) {
978 if (!sscanf(ptr
, "%04x", &i
)) return 1;
980 sum
+= ((i
>> 8) & 255) + (i
& 255);
981 if (!sscanf(ptr
, "%02x", &cksum
)) return 1;
982 if (((sum
& 255) + (cksum
& 255)) & 255) return 1;
983 extended_addr
= i
<< 16;
984 if (code_size
> 1048576 && block_size
>= 1024 &&
985 extended_addr
>= 0x60000000 && extended_addr
< 0x60000000 + code_size
) {
986 // Teensy 4.0 HEX files have 0x60000000 FlexSPI offset
987 extended_addr
-= 0x60000000;
989 //printf("ext addr = %08X\n", extended_addr);
991 return 1; // non-data line
995 if (sscanf(ptr
, "%02x", &i
) != 1) return 0;
997 firmware_image
[addr
+ extended_addr
+ num
] = i
;
998 firmware_mask
[addr
+ extended_addr
+ num
] = 1;
1002 if (num
>= 256) return 0;
1004 if (!sscanf(ptr
, "%02x", &cksum
)) return 0;
1005 if (((sum
& 255) + (cksum
& 255)) & 255) return 0; /* checksum error */
1009 int ihex_bytes_within_range(int begin
, int end
)
1013 if (begin
< 0 || begin
>= MAX_MEMORY_SIZE
||
1014 end
< 0 || end
>= MAX_MEMORY_SIZE
) {
1017 for (i
=begin
; i
<=end
; i
++) {
1018 if (firmware_mask
[i
]) return 1;
1023 void ihex_get_data(int addr
, int len
, unsigned char *bytes
)
1027 if (addr
< 0 || len
< 0 || addr
+ len
>= MAX_MEMORY_SIZE
) {
1028 for (i
=0; i
<len
; i
++) {
1033 for (i
=0; i
<len
; i
++) {
1034 if (firmware_mask
[addr
]) {
1035 bytes
[i
] = firmware_image
[addr
];
1043 int memory_is_blank(int addr
, int block_size
)
1045 if (addr
< 0 || addr
> MAX_MEMORY_SIZE
) return 1;
1047 while (block_size
&& addr
< MAX_MEMORY_SIZE
) {
1048 if (firmware_mask
[addr
] && firmware_image
[addr
] != 255) return 0;
1058 /****************************************************************/
1060 /* Misc Functions */
1062 /****************************************************************/
1064 int printf_verbose(const char *format
, ...)
1069 va_start(ap
, format
);
1071 r
= vprintf(format
, ap
);
1078 void delay(double seconds
)
1081 Sleep(seconds
* 1000.0);
1083 usleep(seconds
* 1000000.0);
1087 void die(const char *str
, ...)
1092 vfprintf(stderr
, str
, ap
);
1093 fprintf(stderr
, "\n");
1098 #define strcasecmp stricmp
1102 static const struct {
1107 {"at90usb162", 15872, 128},
1108 {"atmega32u4", 32256, 128},
1109 {"at90usb646", 64512, 256},
1110 {"at90usb1286", 130048, 256},
1111 #if defined(USE_LIBUSB) || defined(USE_APPLE_IOKIT) || defined(USE_WIN32)
1112 {"mkl26z64", 63488, 512},
1113 {"mk20dx128", 131072, 1024},
1114 {"mk20dx256", 262144, 1024},
1115 {"mk66fx1m0", 1048576, 1024},
1116 {"mk64fx512", 524288, 1024},
1117 {"imxrt1062", 2031616, 1024},
1119 // Add duplicates that match friendly Teensy Names
1120 // Match board names in boards.txt
1121 {"TEENSY2", 32256, 128},
1122 {"TEENSY2PP", 130048, 256},
1123 {"TEENSYLC", 63488, 512},
1124 {"TEENSY30", 131072, 1024},
1125 {"TEENSY31", 262144, 1024},
1126 {"TEENSY32", 262144, 1024},
1127 {"TEENSY35", 524288, 1024},
1128 {"TEENSY36", 1048576, 1024},
1129 {"TEENSY40", 2031616, 1024},
1130 {"TEENSY41", 8126464, 1024},
1139 printf("Supported MCUs are:\n");
1140 for(i
=0; MCUs
[i
].name
!= NULL
; i
++)
1141 printf(" - %s\n", MCUs
[i
].name
);
1146 void read_mcu(char *name
)
1151 fprintf(stderr
, "No MCU specified.\n");
1155 for(i
=0; MCUs
[i
].name
!= NULL
; i
++) {
1156 if(strcasecmp(name
, MCUs
[i
].name
) == 0) {
1157 code_size
= MCUs
[i
].code_size
;
1158 block_size
= MCUs
[i
].block_size
;
1163 fprintf(stderr
, "Unknown MCU type \"%s\"\n", name
);
1168 void parse_flag(char *arg
)
1171 for(i
=1; arg
[i
]; i
++) {
1173 case 'w': wait_for_device_to_appear
= 1; break;
1174 case 'r': hard_reboot_device
= 1; break;
1175 case 's': soft_reboot_device
= 1; break;
1176 case 'n': reboot_after_programming
= 0; break;
1177 case 'v': verbose
= 1; break;
1178 case 'b': boot_only
= 1; break;
1180 fprintf(stderr
, "Unknown flag '%c'\n\n", arg
[i
]);
1187 void parse_options(int argc
, char **argv
)
1192 for (i
=1; i
<argc
; i
++) {
1195 //backward compatibility with previous versions.
1196 if(strncmp(arg
, "-mmcu=", 6) == 0) {
1197 read_mcu(strchr(arg
, '=') + 1);
1200 else if(arg
[0] == '-') {
1202 char *name
= &arg
[2];
1203 char *val
= strchr(name
, '=');
1205 //value must be the next string.
1209 //we found an =, so split the string at it.
1214 if(strcasecmp(name
, "help") == 0) usage(NULL
);
1215 else if(strcasecmp(name
, "mcu") == 0) read_mcu(val
);
1216 else if(strcasecmp(name
, "list-mcus") == 0) list_mcus();
1218 fprintf(stderr
, "Unknown option \"%s\"\n\n", arg
);
1222 else parse_flag(arg
);
1224 else filename
= arg
;
1228 void boot(unsigned char *buf
, int write_size
)
1230 printf_verbose("Booting\n");
1231 memset(buf
, 0, write_size
);
1235 teensy_write(buf
, write_size
, 0.5);