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-2010, PJRC.COM, LLC 
  13  * You may redistribute this program and/or modify it under the terms 
  14  * of the GNU General Public License as published by the Free Software 
  15  * Foundation, version 3 of the License. 
  17  * This program is distributed in the hope that it will be useful, 
  18  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  20  * GNU General Public License for more details. 
  22  * You should have received a copy of the GNU General Public License 
  23  * along with this program.  If not, see http://www.gnu.org/licenses/ 
  26 /* Want to incorporate this code into a proprietary application?? 
  27  * Just email paul@pjrc.com to ask.  Usually it's not a problem, 
  28  * but you do need to ask to use this code in any way other than 
  29  * those permitted by the GNU General Public License, version 3  */ 
  31 /* For non-root permissions on ubuntu or similar udev-based linux 
  32  * http://www.pjrc.com/teensy/49-teensy.rules 
  44         fprintf(stderr
, "Usage: hid_bootloader_cli -mmcu=<MCU> [-w] [-h] [-n] [-v] <file.hex>\n"); 
  45         fprintf(stderr
, "\t-w : Wait for device to appear\n"); 
  46         fprintf(stderr
, "\t-r : Use hard reboot if device not online\n"); 
  47         fprintf(stderr
, "\t-n : No reboot after programming\n"); 
  48         fprintf(stderr
, "\t-v : Verbose output\n"); 
  49         fprintf(stderr
, "\n<MCU> = atmegaXXuY or at90usbXXXY"); 
  51         fprintf(stderr
, "\nFor support and more information, please visit:\n"); 
  52         fprintf(stderr
, "http://www.lufa-lib.org\n"); 
  54         fprintf(stderr
, "\nBased on the TeensyHID command line programmer software:\n"); 
  55         fprintf(stderr
, "http://www.pjrc.com/teensy/loader_cli.html\n"); 
  59 // USB Access Functions 
  60 int teensy_open(void); 
  61 int teensy_write(void *buf
, int len
, double timeout
); 
  62 void teensy_close(void); 
  63 int hard_reboot(void); 
  65 // Intel Hex File Functions 
  66 int read_intel_hex(const char *filename
); 
  67 int ihex_bytes_within_range(int begin
, int end
); 
  68 void ihex_get_data(int addr
, int len
, unsigned char *bytes
); 
  71 int printf_verbose(const char *format
, ...); 
  72 void delay(double seconds
); 
  73 void die(const char *str
, ...); 
  74 void parse_options(int argc
, char **argv
); 
  76 // options (from user via command line args) 
  77 int wait_for_device_to_appear 
= 0; 
  78 int hard_reboot_device 
= 0; 
  79 int reboot_after_programming 
= 1; 
  81 int code_size 
= 0, block_size 
= 0; 
  82 const char *filename
=NULL
; 
  85 /****************************************************************/ 
  89 /****************************************************************/ 
  91 int main(int argc
, char **argv
) 
  93         unsigned char buf
[260]; 
  94         int num
, addr
, r
, first_block
=1, waited
=0; 
  96         // parse command line arguments 
  97         parse_options(argc
, argv
); 
  99                 fprintf(stderr
, "Filename must be specified\n\n"); 
 103                 fprintf(stderr
, "MCU type must be specified\n\n"); 
 106         printf_verbose("Teensy Loader, Command Line, Version 2.0\n"); 
 108         // read the intel hex file 
 109         // this is done first so any error is reported before using USB 
 110         num 
= read_intel_hex(filename
); 
 111         if (num 
< 0) die("error reading intel hex file \"%s\"", filename
); 
 112         printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n", 
 113                 filename
, num
, (double)num 
/ (double)code_size 
* 100.0); 
 115         // open the USB device 
 117                 if (teensy_open()) break; 
 118                 if (hard_reboot_device
) { 
 119                         if (!hard_reboot()) die("Unable to find rebootor\n"); 
 120                         printf_verbose("Hard Reboot performed\n"); 
 121                         hard_reboot_device 
= 0; // only hard reboot once 
 122                         wait_for_device_to_appear 
= 1; 
 124                 if (!wait_for_device_to_appear
) die("Unable to open device\n"); 
 126                         printf_verbose("Waiting for Teensy device...\n"); 
 127                         printf_verbose(" (hint: press the reset button)\n"); 
 132         printf_verbose("Found HalfKay Bootloader\n"); 
 134         // if we waited for the device, read the hex file again 
 135         // perhaps it changed while we were waiting? 
 137                 num 
= read_intel_hex(filename
); 
 138                 if (num 
< 0) die("error reading intel hex file \"%s\"", filename
); 
 139                 printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n", 
 140                         filename
, num
, (double)num 
/ (double)code_size 
* 100.0); 
 144         printf_verbose("Programming"); 
 146         for (addr 
= 0; addr 
< code_size
; addr 
+= block_size
) { 
 147                 if (addr 
> 0 && !ihex_bytes_within_range(addr
, addr 
+ block_size 
- 1)) { 
 148                         // don't waste time on blocks that are unused, 
 149                         // but always do the first one to erase the chip 
 153                 if (code_size 
< 0x10000) { 
 155                         buf
[1] = (addr 
>> 8) & 255; 
 157                         buf
[0] = (addr 
>> 8) & 255; 
 158                         buf
[1] = (addr 
>> 16) & 255; 
 160                 ihex_get_data(addr
, block_size
, buf 
+ 2); 
 161                 r 
= teensy_write(buf
, block_size 
+ 2, first_block ? 
3.0 : 0.25); 
 162                 if (!r
) die("error writing to Teensy\n"); 
 165         printf_verbose("\n"); 
 167         // reboot to the user's new code 
 168         if (reboot_after_programming
) { 
 169                 printf_verbose("Booting\n"); 
 172                 memset(buf 
+ 2, 0, sizeof(buf
) - 2); 
 173                 teensy_write(buf
, block_size 
+ 2, 0.25); 
 182 /****************************************************************/ 
 184 /*             USB Access - libusb (Linux & FreeBSD)            */ 
 186 /****************************************************************/ 
 188 #if defined(USE_LIBUSB) 
 190 // http://libusb.sourceforge.net/doc/index.html 
 193 usb_dev_handle 
* open_usb_device(int vid
, int pid
) 
 196         struct usb_device 
*dev
; 
 204         //printf_verbose("\nSearching for USB device:\n"); 
 205         for (bus 
= usb_get_busses(); bus
; bus 
= bus
->next
) { 
 206                 for (dev 
= bus
->devices
; dev
; dev 
= dev
->next
) { 
 207                         //printf_verbose("bus \"%s\", device \"%s\" vid=%04X, pid=%04X\n", 
 208                         //      bus->dirname, dev->filename, 
 209                         //      dev->descriptor.idVendor, 
 210                         //      dev->descriptor.idProduct 
 212                         if (dev
->descriptor
.idVendor 
!= vid
) continue; 
 213                         if (dev
->descriptor
.idProduct 
!= pid
) continue; 
 216                                 printf_verbose("Found device but unable to open"); 
 219                         #ifdef LIBUSB_HAS_GET_DRIVER_NP 
 220                         r 
= usb_get_driver_np(h
, 0, buf
, sizeof(buf
)); 
 222                                 r 
= usb_detach_kernel_driver_np(h
, 0); 
 225                                         printf_verbose("Device is in use by \"%s\" driver", buf
); 
 230                         // Mac OS-X - removing this call to usb_claim_interface() might allow 
 231                         // this to work, even though it is a clear misuse of the libusb API. 
 232                         // normally Apple's IOKit should be used on Mac OS-X 
 233                         r 
= usb_claim_interface(h
, 0); 
 236                                 printf_verbose("Unable to claim interface, check USB permissions"); 
 245 static usb_dev_handle 
*libusb_teensy_handle 
= NULL
; 
 247 int teensy_open(void) 
 250         libusb_teensy_handle 
= open_usb_device(0x16C0, 0x0478); 
 252         if (!libusb_teensy_handle
) 
 253                 libusb_teensy_handle 
= open_usb_device(0x03eb, 0x2067); 
 255         if (!libusb_teensy_handle
) return 0; 
 259 int teensy_write(void *buf
, int len
, double timeout
) 
 263         if (!libusb_teensy_handle
) return 0; 
 264         r 
= usb_control_msg(libusb_teensy_handle
, 0x21, 9, 0x0200, 0, (char *)buf
, 
 265                 len
, (int)(timeout 
* 1000.0)); 
 270 void teensy_close(void) 
 272         if (!libusb_teensy_handle
) return; 
 273         usb_release_interface(libusb_teensy_handle
, 0); 
 274         usb_close(libusb_teensy_handle
); 
 275         libusb_teensy_handle 
= NULL
; 
 278 int hard_reboot(void) 
 280         usb_dev_handle 
*rebootor
; 
 283         rebootor 
= open_usb_device(0x16C0, 0x0477); 
 286                 rebootor 
= open_usb_device(0x03eb, 0x2067); 
 288         if (!rebootor
) return 0; 
 289         r 
= usb_control_msg(rebootor
, 0x21, 9, 0x0200, 0, "reboot", 6, 100); 
 290         usb_release_interface(rebootor
, 0); 
 299 /****************************************************************/ 
 301 /*               USB Access - Microsoft WIN32                   */ 
 303 /****************************************************************/ 
 305 #if defined(USE_WIN32) 
 307 // http://msdn.microsoft.com/en-us/library/ms790932.aspx 
 309 #include <setupapi.h> 
 310 #include <ddk/hidsdi.h> 
 311 #include <ddk/hidclass.h> 
 313 HANDLE 
open_usb_device(int vid
, int pid
) 
 317         DWORD index
, required_size
; 
 318         SP_DEVICE_INTERFACE_DATA iface
; 
 319         SP_DEVICE_INTERFACE_DETAIL_DATA 
*details
; 
 320         HIDD_ATTRIBUTES attrib
; 
 324         HidD_GetHidGuid(&guid
); 
 325         info 
= SetupDiGetClassDevs(&guid
, NULL
, NULL
, DIGCF_PRESENT 
| DIGCF_DEVICEINTERFACE
); 
 326         if (info 
== INVALID_HANDLE_VALUE
) return NULL
; 
 327         for (index
=0; 1 ;index
++) { 
 328                 iface
.cbSize 
= sizeof(SP_DEVICE_INTERFACE_DATA
); 
 329                 ret 
= SetupDiEnumDeviceInterfaces(info
, NULL
, &guid
, index
, &iface
); 
 331                         SetupDiDestroyDeviceInfoList(info
); 
 334                 SetupDiGetInterfaceDeviceDetail(info
, &iface
, NULL
, 0, &required_size
, NULL
); 
 335                 details 
= (SP_DEVICE_INTERFACE_DETAIL_DATA 
*)malloc(required_size
); 
 336                 if (details 
== NULL
) continue; 
 337                 memset(details
, 0, required_size
); 
 338                 details
->cbSize 
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA
); 
 339                 ret 
= SetupDiGetDeviceInterfaceDetail(info
, &iface
, details
, 
 340                         required_size
, NULL
, NULL
); 
 345                 h 
= CreateFile(details
->DevicePath
, GENERIC_READ
|GENERIC_WRITE
, 
 346                         FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 
 347                         FILE_FLAG_OVERLAPPED
, NULL
); 
 349                 if (h 
== INVALID_HANDLE_VALUE
) continue; 
 350                 attrib
.Size 
= sizeof(HIDD_ATTRIBUTES
); 
 351                 ret 
= HidD_GetAttributes(h
, &attrib
); 
 356                 if (attrib
.VendorID 
!= vid 
|| attrib
.ProductID 
!= pid
) { 
 360                 SetupDiDestroyDeviceInfoList(info
); 
 366 int write_usb_device(HANDLE h
, void *buf
, int len
, int timeout
) 
 368         static HANDLE event 
= NULL
; 
 369         unsigned char tmpbuf
[1040]; 
 373         if (len 
> sizeof(tmpbuf
) - 1) return 0; 
 375                 event 
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
); 
 376                 if (!event
) return 0; 
 379         memset(&ov
, 0, sizeof(ov
)); 
 382         memcpy(tmpbuf 
+ 1, buf
, len
); 
 383         if (!WriteFile(h
, tmpbuf
, len 
+ 1, NULL
, &ov
)) { 
 384                 if (GetLastError() != ERROR_IO_PENDING
) return 0; 
 385                 r 
= WaitForSingleObject(event
, timeout
); 
 386                 if (r 
== WAIT_TIMEOUT
) { 
 390                 if (r 
!= WAIT_OBJECT_0
) return 0; 
 392         if (!GetOverlappedResult(h
, &ov
, &n
, FALSE
)) return 0; 
 393         if (n 
<= 0) return 0; 
 397 void print_win32_err(void) 
 402         err 
= GetLastError(); 
 403         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, err
, 
 404                 0, buf
, sizeof(buf
), NULL
); 
 405         printf("err %ld: %s\n", err
, buf
); 
 408 static HANDLE win32_teensy_handle 
= NULL
; 
 410 int teensy_open(void) 
 413         win32_teensy_handle 
= open_usb_device(0x16C0, 0x0478); 
 415         if (!win32_teensy_handle
) 
 416                 win32_teensy_handle 
= open_usb_device(0x03eb, 0x2067); 
 418         if (!win32_teensy_handle
) return 0; 
 422 int teensy_write(void *buf
, int len
, double timeout
) 
 425         if (!win32_teensy_handle
) return 0; 
 426         r 
= write_usb_device(win32_teensy_handle
, buf
, len
, (int)(timeout 
* 1000.0)); 
 430 void teensy_close(void) 
 432         if (!win32_teensy_handle
) return; 
 433         CloseHandle(win32_teensy_handle
); 
 434         win32_teensy_handle 
= NULL
; 
 437 int hard_reboot(void) 
 442         rebootor 
= open_usb_device(0x16C0, 0x0477); 
 445                 rebootor 
= open_usb_device(0x03eb, 0x2067); 
 447         if (!rebootor
) return 0; 
 448         r 
= write_usb_device(rebootor
, "reboot", 6, 100); 
 449         CloseHandle(rebootor
); 
 457 /****************************************************************/ 
 459 /*             USB Access - Apple's IOKit, Mac OS-X             */ 
 461 /****************************************************************/ 
 463 #if defined(USE_APPLE_IOKIT) 
 465 // http://developer.apple.com/technotes/tn2007/tn2187.html 
 466 #include <IOKit/IOKitLib.h> 
 467 #include <IOKit/hid/IOHIDLib.h> 
 468 #include <IOKit/hid/IOHIDDevice.h> 
 470 struct usb_list_struct 
{ 
 474         struct usb_list_struct 
*next
; 
 477 static struct usb_list_struct 
*usb_list
=NULL
; 
 478 static IOHIDManagerRef hid_manager
=NULL
; 
 480 void attach_callback(void *context
, IOReturn r
, void *hid_mgr
, IOHIDDeviceRef dev
) 
 483         struct usb_list_struct 
*n
, *p
; 
 487         type 
= IOHIDDeviceGetProperty(dev
, CFSTR(kIOHIDVendorIDKey
)); 
 488         if (!type 
|| CFGetTypeID(type
) != CFNumberGetTypeID()) return; 
 489         if (!CFNumberGetValue((CFNumberRef
)type
, kCFNumberSInt32Type
, &vid
)) return; 
 490         type 
= IOHIDDeviceGetProperty(dev
, CFSTR(kIOHIDProductIDKey
)); 
 491         if (!type 
|| CFGetTypeID(type
) != CFNumberGetTypeID()) return; 
 492         if (!CFNumberGetValue((CFNumberRef
)type
, kCFNumberSInt32Type
, &pid
)) return; 
 493         n 
= (struct usb_list_struct 
*)malloc(sizeof(struct usb_list_struct
)); 
 495         //printf("attach callback: vid=%04X, pid=%04X\n", vid, pid); 
 500         if (usb_list 
== NULL
) { 
 503                 for (p 
= usb_list
; p
->next
; p 
= p
->next
) ; 
 508 void detach_callback(void *context
, IOReturn r
, void *hid_mgr
, IOHIDDeviceRef dev
) 
 510         struct usb_list_struct 
*p
, *tmp
, *prev
=NULL
; 
 516                                 prev
->next 
= p
->next
; 
 530 void init_hid_manager(void) 
 532         CFMutableDictionaryRef dict
; 
 535         if (hid_manager
) return; 
 536         hid_manager 
= IOHIDManagerCreate(kCFAllocatorDefault
, kIOHIDOptionsTypeNone
); 
 537         if (hid_manager 
== NULL 
|| CFGetTypeID(hid_manager
) != IOHIDManagerGetTypeID()) { 
 538                 if (hid_manager
) CFRelease(hid_manager
); 
 539                 printf_verbose("no HID Manager - maybe this is a pre-Leopard (10.5) system?\n"); 
 542         dict 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, 
 543                 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 545         IOHIDManagerSetDeviceMatching(hid_manager
, dict
); 
 547         IOHIDManagerScheduleWithRunLoop(hid_manager
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
); 
 548         IOHIDManagerRegisterDeviceMatchingCallback(hid_manager
, attach_callback
, NULL
); 
 549         IOHIDManagerRegisterDeviceRemovalCallback(hid_manager
, detach_callback
, NULL
); 
 550         ret 
= IOHIDManagerOpen(hid_manager
, kIOHIDOptionsTypeNone
); 
 551         if (ret 
!= kIOReturnSuccess
) { 
 552                 IOHIDManagerUnscheduleFromRunLoop(hid_manager
, 
 553                         CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
); 
 554                 CFRelease(hid_manager
); 
 555                 printf_verbose("Error opening HID Manager"); 
 559 static void do_run_loop(void) 
 561         while (CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0, true) == kCFRunLoopRunHandledSource
) ; 
 564 IOHIDDeviceRef 
open_usb_device(int vid
, int pid
) 
 566         struct usb_list_struct 
*p
; 
 571         for (p 
= usb_list
; p
; p 
= p
->next
) { 
 572                 if (p
->vid 
== vid 
&& p
->pid 
== pid
) { 
 573                         ret 
= IOHIDDeviceOpen(p
->ref
, kIOHIDOptionsTypeNone
); 
 574                         if (ret 
== kIOReturnSuccess
) return p
->ref
; 
 580 void close_usb_device(IOHIDDeviceRef dev
) 
 582         struct usb_list_struct 
*p
; 
 585         for (p 
= usb_list
; p
; p 
= p
->next
) { 
 587                         IOHIDDeviceClose(dev
, kIOHIDOptionsTypeNone
); 
 593 static IOHIDDeviceRef iokit_teensy_reference 
= NULL
; 
 595 int teensy_open(void) 
 598         iokit_teensy_reference 
= open_usb_device(0x16C0, 0x0478); 
 600         if (!iokit_teensy_reference
) 
 601                 iokit_teensy_reference 
= open_usb_device(0x03eb, 0x2067); 
 603         if (!iokit_teensy_reference
) return 0; 
 607 int teensy_write(void *buf
, int len
, double timeout
) 
 611         // timeouts do not work on OS-X 
 612         // IOHIDDeviceSetReportWithCallback is not implemented 
 613         // even though Apple documents it with a code example! 
 614         // submitted to Apple on 22-sep-2009, problem ID 7245050 
 615         if (!iokit_teensy_reference
) return 0; 
 616         ret 
= IOHIDDeviceSetReport(iokit_teensy_reference
, 
 617                 kIOHIDReportTypeOutput
, 0, buf
, len
); 
 618         if (ret 
== kIOReturnSuccess
) return 1; 
 622 void teensy_close(void) 
 624         if (!iokit_teensy_reference
) return; 
 625         close_usb_device(iokit_teensy_reference
); 
 626         iokit_teensy_reference 
= NULL
; 
 629 int hard_reboot(void) 
 631         IOHIDDeviceRef rebootor
; 
 634         rebootor 
= open_usb_device(0x16C0, 0x0477); 
 637                 rebootor 
= open_usb_device(0x03eb, 0x2067); 
 639         if (!rebootor
) return 0; 
 640         ret 
= IOHIDDeviceSetReport(rebootor
, 
 641                 kIOHIDReportTypeOutput
, 0, (uint8_t *)("reboot"), 6); 
 642         close_usb_device(rebootor
); 
 643         if (ret 
== kIOReturnSuccess
) return 1; 
 651 /****************************************************************/ 
 653 /*              USB Access - BSD's UHID driver                  */ 
 655 /****************************************************************/ 
 657 #if defined(USE_UHID) 
 659 // Thanks to Todd T Fries for help getting this working on OpenBSD 
 660 // and to Chris Kuethe for the initial patch to use UHID. 
 662 #include <sys/ioctl.h> 
 665 #include <dev/usb/usb.h> 
 666 #ifndef USB_GET_DEVICEINFO 
 667 #include <dev/usb/usb_ioctl.h> 
 670 int open_usb_device(int vid
, int pid
) 
 675         struct usb_device_info info
; 
 678         dir 
= opendir("/dev"); 
 680         while ((d 
= readdir(dir
)) != NULL
) { 
 681                 if (strncmp(d
->d_name
, "uhid", 4) != 0) continue; 
 682                 snprintf(buf
, sizeof(buf
), "/dev/%s", d
->d_name
); 
 683                 fd 
= open(buf
, O_RDWR
); 
 684                 if (fd 
< 0) continue; 
 685                 r 
= ioctl(fd
, USB_GET_DEVICEINFO
, &info
); 
 687                         // NetBSD: added in 2004 
 688                         // OpenBSD: added November 23, 2009 
 689                         // FreeBSD: missing (FreeBSD 8.0) - USE_LIBUSB works! 
 690                         die("Error: your uhid driver does not support" 
 691                           " USB_GET_DEVICEINFO, please upgrade!\n"); 
 696                 //printf("%s: v=%d, p=%d\n", buf, info.udi_vendorNo, info.udi_productNo); 
 697                 if (info
.udi_vendorNo 
== vid 
&& info
.udi_productNo 
== pid
) { 
 707 static int uhid_teensy_fd 
= -1; 
 709 int teensy_open(void) 
 712         uhid_teensy_fd 
= open_usb_device(0x16C0, 0x0478); 
 714         if (uhid_teensy_fd 
< 0) 
 715                 uhid_teensy_fd 
= open_usb_device(0x03eb, 0x2067); 
 717         if (uhid_teensy_fd 
< 0) return 0; 
 721 int teensy_write(void *buf
, int len
, double timeout
) 
 725         // TODO: imeplement timeout... how?? 
 726         r 
= write(uhid_teensy_fd
, buf
, len
); 
 727         if (r 
== len
) return 1; 
 731 void teensy_close(void) 
 733         if (uhid_teensy_fd 
>= 0) { 
 734                 close(uhid_teensy_fd
); 
 739 int hard_reboot(void) 
 743         rebootor_fd 
= open_usb_device(0x16C0, 0x0477); 
 746                 rebootor_fd 
= open_usb_device(0x03eb, 0x2067); 
 748         if (rebootor_fd 
< 0) return 0; 
 749         r 
= write(rebootor_fd
, "reboot", 6); 
 752         if (r 
== 6) return 1; 
 760 /****************************************************************/ 
 762 /*                     Read Intel Hex File                      */ 
 764 /****************************************************************/ 
 766 // the maximum flash image size we can support 
 767 // chips with larger memory may be used, but only this 
 768 // much intel-hex data can be loaded into memory! 
 769 #define MAX_MEMORY_SIZE 0x10000 
 771 static unsigned char firmware_image
[MAX_MEMORY_SIZE
]; 
 772 static unsigned char firmware_mask
[MAX_MEMORY_SIZE
]; 
 773 static int end_record_seen
=0; 
 774 static int byte_count
; 
 775 static unsigned int extended_addr 
= 0; 
 776 static int parse_hex_line(char *line
); 
 778 int read_intel_hex(const char *filename
) 
 786         for (i
=0; i
<MAX_MEMORY_SIZE
; i
++) { 
 787                 firmware_image
[i
] = 0xFF; 
 788                 firmware_mask
[i
] = 0; 
 792         fp 
= fopen(filename
, "r"); 
 794                 //printf("Unable to read file %s\n", filename); 
 799                 if (!fgets(buf
, sizeof(buf
), fp
)) break; 
 802                         if (parse_hex_line(buf
) == 0) { 
 803                                 //printf("Warning, parse error line %d\n", lineno); 
 807                 if (end_record_seen
) break; 
 808                 if (feof(stdin
)) break; 
 815 /* from ihex.c, at http://www.pjrc.com/tech/8051/pm2_docs/intel-hex.html */ 
 817 /* parses a line of intel hex code, stores the data in bytes[] */ 
 818 /* and the beginning address in addr, and returns a 1 if the */ 
 819 /* line was valid, or a 0 if an error occured.  The variable */ 
 820 /* num gets the number of bytes that were stored into bytes[] */ 
 824 parse_hex_line(char *line
) 
 827         int sum
, len
, cksum
, i
; 
 831         if (line
[0] != ':') return 0; 
 832         if (strlen(line
) < 11) return 0; 
 834         if (!sscanf(ptr
, "%02x", &len
)) return 0; 
 836         if ((int)strlen(line
) < (11 + (len 
* 2)) ) return 0; 
 837         if (!sscanf(ptr
, "%04x", &addr
)) return 0; 
 839           /* printf("Line: length=%d Addr=%d\n", len, addr); */ 
 840         if (!sscanf(ptr
, "%02x", &code
)) return 0; 
 841         if (addr 
+ extended_addr 
+ len 
>= MAX_MEMORY_SIZE
) return 0; 
 843         sum 
= (len 
& 255) + ((addr 
>> 8) & 255) + (addr 
& 255) + (code 
& 255); 
 849                 if (code 
== 2 && len 
== 2) { 
 850                         if (!sscanf(ptr
, "%04x", &i
)) return 1; 
 852                         sum 
+= ((i 
>> 8) & 255) + (i 
& 255); 
 853                         if (!sscanf(ptr
, "%02x", &cksum
)) return 1; 
 854                         if (((sum 
& 255) + (cksum 
& 255)) & 255) return 1; 
 855                         extended_addr 
= i 
<< 4; 
 856                         //printf("ext addr = %05X\n", extended_addr); 
 858                 if (code 
== 4 && len 
== 2) { 
 859                         if (!sscanf(ptr
, "%04x", &i
)) return 1; 
 861                         sum 
+= ((i 
>> 8) & 255) + (i 
& 255); 
 862                         if (!sscanf(ptr
, "%02x", &cksum
)) return 1; 
 863                         if (((sum 
& 255) + (cksum 
& 255)) & 255) return 1; 
 864                         extended_addr 
= i 
<< 16; 
 865                         //printf("ext addr = %08X\n", extended_addr); 
 867                 return 1;       // non-data line 
 871                 if (sscanf(ptr
, "%02x", &i
) != 1) return 0; 
 873                 firmware_image
[addr 
+ extended_addr 
+ num
] = i
; 
 874                 firmware_mask
[addr 
+ extended_addr 
+ num
] = 1; 
 878                 if (num 
>= 256) return 0; 
 880         if (!sscanf(ptr
, "%02x", &cksum
)) return 0; 
 881         if (((sum 
& 255) + (cksum 
& 255)) & 255) return 0; /* checksum error */ 
 885 int ihex_bytes_within_range(int begin
, int end
) 
 889         if (begin 
< 0 || begin 
>= MAX_MEMORY_SIZE 
|| 
 890            end 
< 0 || end 
>= MAX_MEMORY_SIZE
) { 
 893         for (i
=begin
; i
<=end
; i
++) { 
 894                 if (firmware_mask
[i
]) return 1; 
 899 void ihex_get_data(int addr
, int len
, unsigned char *bytes
) 
 903         if (addr 
< 0 || len 
< 0 || addr 
+ len 
>= MAX_MEMORY_SIZE
) { 
 904                 for (i
=0; i
<len
; i
++) { 
 909         for (i
=0; i
<len
; i
++) { 
 910                 if (firmware_mask
[addr
]) { 
 911                         bytes
[i
] = firmware_image
[addr
]; 
 919 /****************************************************************/ 
 923 /****************************************************************/ 
 925 int printf_verbose(const char *format
, ...) 
 930         va_start(ap
, format
); 
 932                 r 
= vprintf(format
, ap
); 
 939 void delay(double seconds
) 
 942         Sleep(seconds 
* 1000.0); 
 944         usleep(seconds 
* 1000000.0); 
 948 void die(const char *str
, ...) 
 953         vfprintf(stderr
, str
, ap
); 
 954         fprintf(stderr
, "\n"); 
 959 #define strcasecmp stricmp 
 962 void parse_options(int argc
, char **argv
) 
 967         for (i
=1; i
<argc
; i
++) { 
 971                         if (strcmp(arg
, "-w") == 0) { 
 972                                 wait_for_device_to_appear 
= 1; 
 973                         } else if (strcmp(arg
, "-r") == 0) { 
 974                                 hard_reboot_device 
= 1; 
 975                         } else if (strcmp(arg
, "-n") == 0) { 
 976                                 reboot_after_programming 
= 0; 
 977                         } else if (strcmp(arg
, "-v") == 0) { 
 979                         } else if (strncmp(arg
, "-mmcu=", 6) == 0) { 
 982                                 uint8_t valid_prefix 
= 0; 
 984                                 if (strncmp(arg
, "at90usb", 7) == 0) { 
 987                                 } else if (strncmp(arg
, "atmega", 6) == 0) { 
 991                                         die("Unknown MCU type\n"); 
 994                                 if (strncmp(arg
, "128", 3) == 0) { 
 995                                         code_size  
= 128 * 1024; 
 997                                 } else if (strncmp(arg
, "64", 2) == 0) { 
 998                                         code_size  
= 64 * 1024; 
1000                                 } else if (strncmp(arg
, "32", 2) == 0) { 
1001                                         code_size  
= 32 * 1024; 
1003                                 } else if (strncmp(arg
, "16", 2) == 0) { 
1004                                         code_size  
= 16 * 1024; 
1006                                 } else if (strncmp(arg
, "8", 1) == 0) { 
1007                                         code_size  
= 8 * 1024; 
1010                                         die("Unknown MCU type\n");