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
; 
 198         #ifdef LIBUSB_HAS_GET_DRIVER_NP 
 206         //printf_verbose("\nSearching for USB device:\n"); 
 207         for (bus 
= usb_get_busses(); bus
; bus 
= bus
->next
) { 
 208                 for (dev 
= bus
->devices
; dev
; dev 
= dev
->next
) { 
 209                         //printf_verbose("bus \"%s\", device \"%s\" vid=%04X, pid=%04X\n", 
 210                         //      bus->dirname, dev->filename, 
 211                         //      dev->descriptor.idVendor, 
 212                         //      dev->descriptor.idProduct 
 214                         if (dev
->descriptor
.idVendor 
!= vid
) continue; 
 215                         if (dev
->descriptor
.idProduct 
!= pid
) continue; 
 218                                 printf_verbose("Found device but unable to open"); 
 221                         #ifdef LIBUSB_HAS_GET_DRIVER_NP 
 222                         r 
= usb_get_driver_np(h
, 0, buf
, sizeof(buf
)); 
 224                                 r 
= usb_detach_kernel_driver_np(h
, 0); 
 227                                         printf_verbose("Device is in use by \"%s\" driver", buf
); 
 232                         // Mac OS-X - removing this call to usb_claim_interface() might allow 
 233                         // this to work, even though it is a clear misuse of the libusb API. 
 234                         // normally Apple's IOKit should be used on Mac OS-X 
 235                         r 
= usb_claim_interface(h
, 0); 
 238                                 printf_verbose("Unable to claim interface, check USB permissions"); 
 247 static usb_dev_handle 
*libusb_teensy_handle 
= NULL
; 
 249 int teensy_open(void) 
 252         libusb_teensy_handle 
= open_usb_device(0x16C0, 0x0478); 
 254         if (!libusb_teensy_handle
) 
 255                 libusb_teensy_handle 
= open_usb_device(0x03eb, 0x2067); 
 257         if (!libusb_teensy_handle
) return 0; 
 261 int teensy_write(void *buf
, int len
, double timeout
) 
 265         if (!libusb_teensy_handle
) return 0; 
 266         r 
= usb_control_msg(libusb_teensy_handle
, 0x21, 9, 0x0200, 0, (char *)buf
, 
 267                 len
, (int)(timeout 
* 1000.0)); 
 272 void teensy_close(void) 
 274         if (!libusb_teensy_handle
) return; 
 275         usb_release_interface(libusb_teensy_handle
, 0); 
 276         usb_close(libusb_teensy_handle
); 
 277         libusb_teensy_handle 
= NULL
; 
 280 int hard_reboot(void) 
 282         usb_dev_handle 
*rebootor
; 
 285         rebootor 
= open_usb_device(0x16C0, 0x0477); 
 288                 rebootor 
= open_usb_device(0x03eb, 0x2067); 
 290         if (!rebootor
) return 0; 
 291         r 
= usb_control_msg(rebootor
, 0x21, 9, 0x0200, 0, "reboot", 6, 100); 
 292         usb_release_interface(rebootor
, 0); 
 301 /****************************************************************/ 
 303 /*               USB Access - Microsoft WIN32                   */ 
 305 /****************************************************************/ 
 307 #if defined(USE_WIN32) 
 309 // http://msdn.microsoft.com/en-us/library/ms790932.aspx 
 311 #include <setupapi.h> 
 312 #include <ddk/hidsdi.h> 
 313 #include <ddk/hidclass.h> 
 315 HANDLE 
open_usb_device(int vid
, int pid
) 
 319         DWORD index
, required_size
; 
 320         SP_DEVICE_INTERFACE_DATA iface
; 
 321         SP_DEVICE_INTERFACE_DETAIL_DATA 
*details
; 
 322         HIDD_ATTRIBUTES attrib
; 
 326         HidD_GetHidGuid(&guid
); 
 327         info 
= SetupDiGetClassDevs(&guid
, NULL
, NULL
, DIGCF_PRESENT 
| DIGCF_DEVICEINTERFACE
); 
 328         if (info 
== INVALID_HANDLE_VALUE
) return NULL
; 
 329         for (index
=0; 1 ;index
++) { 
 330                 iface
.cbSize 
= sizeof(SP_DEVICE_INTERFACE_DATA
); 
 331                 ret 
= SetupDiEnumDeviceInterfaces(info
, NULL
, &guid
, index
, &iface
); 
 333                         SetupDiDestroyDeviceInfoList(info
); 
 336                 SetupDiGetInterfaceDeviceDetail(info
, &iface
, NULL
, 0, &required_size
, NULL
); 
 337                 details 
= (SP_DEVICE_INTERFACE_DETAIL_DATA 
*)malloc(required_size
); 
 338                 if (details 
== NULL
) continue; 
 339                 memset(details
, 0, required_size
); 
 340                 details
->cbSize 
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA
); 
 341                 ret 
= SetupDiGetDeviceInterfaceDetail(info
, &iface
, details
, 
 342                         required_size
, NULL
, NULL
); 
 347                 h 
= CreateFile(details
->DevicePath
, GENERIC_READ
|GENERIC_WRITE
, 
 348                         FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 
 349                         FILE_FLAG_OVERLAPPED
, NULL
); 
 351                 if (h 
== INVALID_HANDLE_VALUE
) continue; 
 352                 attrib
.Size 
= sizeof(HIDD_ATTRIBUTES
); 
 353                 ret 
= HidD_GetAttributes(h
, &attrib
); 
 358                 if (attrib
.VendorID 
!= vid 
|| attrib
.ProductID 
!= pid
) { 
 362                 SetupDiDestroyDeviceInfoList(info
); 
 368 int write_usb_device(HANDLE h
, void *buf
, int len
, int timeout
) 
 370         static HANDLE event 
= NULL
; 
 371         unsigned char tmpbuf
[1040]; 
 375         if (len 
> sizeof(tmpbuf
) - 1) return 0; 
 377                 event 
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
); 
 378                 if (!event
) return 0; 
 381         memset(&ov
, 0, sizeof(ov
)); 
 384         memcpy(tmpbuf 
+ 1, buf
, len
); 
 385         if (!WriteFile(h
, tmpbuf
, len 
+ 1, NULL
, &ov
)) { 
 386                 if (GetLastError() != ERROR_IO_PENDING
) return 0; 
 387                 r 
= WaitForSingleObject(event
, timeout
); 
 388                 if (r 
== WAIT_TIMEOUT
) { 
 392                 if (r 
!= WAIT_OBJECT_0
) return 0; 
 394         if (!GetOverlappedResult(h
, &ov
, &n
, FALSE
)) return 0; 
 398 static HANDLE win32_teensy_handle 
= NULL
; 
 400 int teensy_open(void) 
 403         win32_teensy_handle 
= open_usb_device(0x16C0, 0x0478); 
 405         if (!win32_teensy_handle
) 
 406                 win32_teensy_handle 
= open_usb_device(0x03eb, 0x2067); 
 408         if (!win32_teensy_handle
) return 0; 
 412 int teensy_write(void *buf
, int len
, double timeout
) 
 415         if (!win32_teensy_handle
) return 0; 
 416         r 
= write_usb_device(win32_teensy_handle
, buf
, len
, (int)(timeout 
* 1000.0)); 
 420 void teensy_close(void) 
 422         if (!win32_teensy_handle
) return; 
 423         CloseHandle(win32_teensy_handle
); 
 424         win32_teensy_handle 
= NULL
; 
 427 int hard_reboot(void) 
 432         rebootor 
= open_usb_device(0x16C0, 0x0477); 
 435                 rebootor 
= open_usb_device(0x03eb, 0x2067); 
 437         if (!rebootor
) return 0; 
 438         r 
= write_usb_device(rebootor
, "reboot", 6, 100); 
 439         CloseHandle(rebootor
); 
 447 /****************************************************************/ 
 449 /*             USB Access - Apple's IOKit, Mac OS-X             */ 
 451 /****************************************************************/ 
 453 #if defined(USE_APPLE_IOKIT) 
 455 // http://developer.apple.com/technotes/tn2007/tn2187.html 
 456 #include <IOKit/IOKitLib.h> 
 457 #include <IOKit/hid/IOHIDLib.h> 
 458 #include <IOKit/hid/IOHIDDevice.h> 
 460 struct usb_list_struct 
{ 
 464         struct usb_list_struct 
*next
; 
 467 static struct usb_list_struct 
*usb_list
=NULL
; 
 468 static IOHIDManagerRef hid_manager
=NULL
; 
 470 void attach_callback(void *context
, IOReturn r
, void *hid_mgr
, IOHIDDeviceRef dev
) 
 473         struct usb_list_struct 
*n
, *p
; 
 477         type 
= IOHIDDeviceGetProperty(dev
, CFSTR(kIOHIDVendorIDKey
)); 
 478         if (!type 
|| CFGetTypeID(type
) != CFNumberGetTypeID()) return; 
 479         if (!CFNumberGetValue((CFNumberRef
)type
, kCFNumberSInt32Type
, &vid
)) return; 
 480         type 
= IOHIDDeviceGetProperty(dev
, CFSTR(kIOHIDProductIDKey
)); 
 481         if (!type 
|| CFGetTypeID(type
) != CFNumberGetTypeID()) return; 
 482         if (!CFNumberGetValue((CFNumberRef
)type
, kCFNumberSInt32Type
, &pid
)) return; 
 483         n 
= (struct usb_list_struct 
*)malloc(sizeof(struct usb_list_struct
)); 
 485         //printf("attach callback: vid=%04X, pid=%04X\n", vid, pid); 
 490         if (usb_list 
== NULL
) { 
 493                 for (p 
= usb_list
; p
->next
; p 
= p
->next
) ; 
 498 void detach_callback(void *context
, IOReturn r
, void *hid_mgr
, IOHIDDeviceRef dev
) 
 500         struct usb_list_struct 
*p
, *tmp
, *prev
=NULL
; 
 506                                 prev
->next 
= p
->next
; 
 520 void init_hid_manager(void) 
 522         CFMutableDictionaryRef dict
; 
 525         if (hid_manager
) return; 
 526         hid_manager 
= IOHIDManagerCreate(kCFAllocatorDefault
, kIOHIDOptionsTypeNone
); 
 527         if (hid_manager 
== NULL 
|| CFGetTypeID(hid_manager
) != IOHIDManagerGetTypeID()) { 
 528                 if (hid_manager
) CFRelease(hid_manager
); 
 529                 printf_verbose("no HID Manager - maybe this is a pre-Leopard (10.5) system?\n"); 
 532         dict 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, 
 533                 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 535         IOHIDManagerSetDeviceMatching(hid_manager
, dict
); 
 537         IOHIDManagerScheduleWithRunLoop(hid_manager
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
); 
 538         IOHIDManagerRegisterDeviceMatchingCallback(hid_manager
, attach_callback
, NULL
); 
 539         IOHIDManagerRegisterDeviceRemovalCallback(hid_manager
, detach_callback
, NULL
); 
 540         ret 
= IOHIDManagerOpen(hid_manager
, kIOHIDOptionsTypeNone
); 
 541         if (ret 
!= kIOReturnSuccess
) { 
 542                 IOHIDManagerUnscheduleFromRunLoop(hid_manager
, 
 543                         CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
); 
 544                 CFRelease(hid_manager
); 
 545                 printf_verbose("Error opening HID Manager"); 
 549 static void do_run_loop(void) 
 551         while (CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0, true) == kCFRunLoopRunHandledSource
) ; 
 554 IOHIDDeviceRef 
open_usb_device(int vid
, int pid
) 
 556         struct usb_list_struct 
*p
; 
 561         for (p 
= usb_list
; p
; p 
= p
->next
) { 
 562                 if (p
->vid 
== vid 
&& p
->pid 
== pid
) { 
 563                         ret 
= IOHIDDeviceOpen(p
->ref
, kIOHIDOptionsTypeNone
); 
 564                         if (ret 
== kIOReturnSuccess
) return p
->ref
; 
 570 void close_usb_device(IOHIDDeviceRef dev
) 
 572         struct usb_list_struct 
*p
; 
 575         for (p 
= usb_list
; p
; p 
= p
->next
) { 
 577                         IOHIDDeviceClose(dev
, kIOHIDOptionsTypeNone
); 
 583 static IOHIDDeviceRef iokit_teensy_reference 
= NULL
; 
 585 int teensy_open(void) 
 588         iokit_teensy_reference 
= open_usb_device(0x16C0, 0x0478); 
 590         if (!iokit_teensy_reference
) 
 591                 iokit_teensy_reference 
= open_usb_device(0x03eb, 0x2067); 
 593         if (!iokit_teensy_reference
) return 0; 
 597 int teensy_write(void *buf
, int len
, double timeout
) 
 601         // timeouts do not work on OS-X 
 602         // IOHIDDeviceSetReportWithCallback is not implemented 
 603         // even though Apple documents it with a code example! 
 604         // submitted to Apple on 22-sep-2009, problem ID 7245050 
 605         if (!iokit_teensy_reference
) return 0; 
 606         ret 
= IOHIDDeviceSetReport(iokit_teensy_reference
, 
 607                 kIOHIDReportTypeOutput
, 0, buf
, len
); 
 608         if (ret 
== kIOReturnSuccess
) return 1; 
 612 void teensy_close(void) 
 614         if (!iokit_teensy_reference
) return; 
 615         close_usb_device(iokit_teensy_reference
); 
 616         iokit_teensy_reference 
= NULL
; 
 619 int hard_reboot(void) 
 621         IOHIDDeviceRef rebootor
; 
 624         rebootor 
= open_usb_device(0x16C0, 0x0477); 
 627                 rebootor 
= open_usb_device(0x03eb, 0x2067); 
 629         if (!rebootor
) return 0; 
 630         ret 
= IOHIDDeviceSetReport(rebootor
, 
 631                 kIOHIDReportTypeOutput
, 0, (uint8_t *)("reboot"), 6); 
 632         close_usb_device(rebootor
); 
 633         if (ret 
== kIOReturnSuccess
) return 1; 
 641 /****************************************************************/ 
 643 /*              USB Access - BSD's UHID driver                  */ 
 645 /****************************************************************/ 
 647 #if defined(USE_UHID) 
 649 // Thanks to Todd T Fries for help getting this working on OpenBSD 
 650 // and to Chris Kuethe for the initial patch to use UHID. 
 652 #include <sys/ioctl.h> 
 655 #include <dev/usb/usb.h> 
 656 #ifndef USB_GET_DEVICEINFO 
 657 #include <dev/usb/usb_ioctl.h> 
 660 #ifndef USB_GET_DEVICEINFO 
 661 # define USB_GET_DEVICEINFO 0 
 662 # error The USB_GET_DEVICEINFO ioctl() value is not defined for your system. 
 665 int open_usb_device(int vid
, int pid
) 
 670         struct usb_device_info info
; 
 673         dir 
= opendir("/dev"); 
 675         while ((d 
= readdir(dir
)) != NULL
) { 
 676                 if (strncmp(d
->d_name
, "uhid", 4) != 0) continue; 
 677                 snprintf(buf
, sizeof(buf
), "/dev/%s", d
->d_name
); 
 678                 fd 
= open(buf
, O_RDWR
); 
 679                 if (fd 
< 0) continue; 
 680                 r 
= ioctl(fd
, USB_GET_DEVICEINFO
, &info
); 
 682                         // NetBSD: added in 2004 
 683                         // OpenBSD: added November 23, 2009 
 684                         // FreeBSD: missing (FreeBSD 8.0) - USE_LIBUSB works! 
 685                         die("Error: your uhid driver does not support" 
 686                           " USB_GET_DEVICEINFO, please upgrade!\n"); 
 691                 //printf("%s: v=%d, p=%d\n", buf, info.udi_vendorNo, info.udi_productNo); 
 692                 if (info
.udi_vendorNo 
== vid 
&& info
.udi_productNo 
== pid
) { 
 702 static int uhid_teensy_fd 
= -1; 
 704 int teensy_open(void) 
 707         uhid_teensy_fd 
= open_usb_device(0x16C0, 0x0478); 
 709         if (uhid_teensy_fd 
< 0) 
 710                 uhid_teensy_fd 
= open_usb_device(0x03eb, 0x2067); 
 712         if (uhid_teensy_fd 
< 0) return 0; 
 716 int teensy_write(void *buf
, int len
, double timeout
) 
 720         // TODO: implement timeout... how?? 
 721         r 
= write(uhid_teensy_fd
, buf
, len
); 
 722         if (r 
== len
) return 1; 
 726 void teensy_close(void) 
 728         if (uhid_teensy_fd 
>= 0) { 
 729                 close(uhid_teensy_fd
); 
 734 int hard_reboot(void) 
 738         rebootor_fd 
= open_usb_device(0x16C0, 0x0477); 
 741                 rebootor_fd 
= open_usb_device(0x03eb, 0x2067); 
 743         if (rebootor_fd 
< 0) return 0; 
 744         r 
= write(rebootor_fd
, "reboot", 6); 
 747         if (r 
== 6) return 1; 
 755 /****************************************************************/ 
 757 /*                     Read Intel Hex File                      */ 
 759 /****************************************************************/ 
 761 // the maximum flash image size we can support 
 762 // chips with larger memory may be used, but only this 
 763 // much intel-hex data can be loaded into memory! 
 764 #define MAX_MEMORY_SIZE 0x10000 
 766 static unsigned char firmware_image
[MAX_MEMORY_SIZE
]; 
 767 static unsigned char firmware_mask
[MAX_MEMORY_SIZE
]; 
 768 static int end_record_seen
=0; 
 769 static int byte_count
; 
 770 static unsigned int extended_addr 
= 0; 
 771 static int parse_hex_line(char *line
); 
 773 int read_intel_hex(const char *filename
) 
 781         for (i
=0; i
<MAX_MEMORY_SIZE
; i
++) { 
 782                 firmware_image
[i
] = 0xFF; 
 783                 firmware_mask
[i
] = 0; 
 787         fp 
= fopen(filename
, "r"); 
 789                 //printf("Unable to read file %s\n", filename); 
 794                 if (!fgets(buf
, sizeof(buf
), fp
)) break; 
 797                         if (parse_hex_line(buf
) == 0) { 
 798                                 //printf("Warning, parse error line %d\n", lineno); 
 803                 if (end_record_seen
) break; 
 804                 if (feof(stdin
)) break; 
 811 /* from ihex.c, at http://www.pjrc.com/tech/8051/pm2_docs/intel-hex.html */ 
 813 /* parses a line of intel hex code, stores the data in bytes[] */ 
 814 /* and the beginning address in addr, and returns a 1 if the */ 
 815 /* line was valid, or a 0 if an error occurred.  The variable */ 
 816 /* num gets the number of bytes that were stored into bytes[] */ 
 820 parse_hex_line(char *line
) 
 823         int sum
, len
, cksum
, i
; 
 827         if (line
[0] != ':') return 0; 
 828         if (strlen(line
) < 11) return 0; 
 830         if (!sscanf(ptr
, "%02x", &len
)) return 0; 
 832         if ((int)strlen(line
) < (11 + (len 
* 2)) ) return 0; 
 833         if (!sscanf(ptr
, "%04x", &addr
)) return 0; 
 835           /* printf("Line: length=%d Addr=%d\n", len, addr); */ 
 836         if (!sscanf(ptr
, "%02x", &code
)) return 0; 
 837         if (addr 
+ extended_addr 
+ len 
>= MAX_MEMORY_SIZE
) return 0; 
 839         sum 
= (len 
& 255) + ((addr 
>> 8) & 255) + (addr 
& 255) + (code 
& 255); 
 845                 if (code 
== 2 && len 
== 2) { 
 846                         if (!sscanf(ptr
, "%04x", &i
)) return 1; 
 848                         sum 
+= ((i 
>> 8) & 255) + (i 
& 255); 
 849                         if (!sscanf(ptr
, "%02x", &cksum
)) return 1; 
 850                         if (((sum 
& 255) + (cksum 
& 255)) & 255) return 1; 
 851                         extended_addr 
= i 
<< 4; 
 852                         //printf("ext addr = %05X\n", extended_addr); 
 854                 if (code 
== 4 && len 
== 2) { 
 855                         if (!sscanf(ptr
, "%04x", &i
)) return 1; 
 857                         sum 
+= ((i 
>> 8) & 255) + (i 
& 255); 
 858                         if (!sscanf(ptr
, "%02x", &cksum
)) return 1; 
 859                         if (((sum 
& 255) + (cksum 
& 255)) & 255) return 1; 
 860                         extended_addr 
= i 
<< 16; 
 861                         //printf("ext addr = %08X\n", extended_addr); 
 863                 return 1;       // non-data line 
 867                 if (sscanf(ptr
, "%02x", &i
) != 1) return 0; 
 869                 firmware_image
[addr 
+ extended_addr 
+ num
] = i
; 
 870                 firmware_mask
[addr 
+ extended_addr 
+ num
] = 1; 
 874                 if (num 
>= 256) return 0; 
 876         if (!sscanf(ptr
, "%02x", &cksum
)) return 0; 
 877         if (((sum 
& 255) + (cksum 
& 255)) & 255) return 0; /* checksum error */ 
 881 int ihex_bytes_within_range(int begin
, int end
) 
 885         if (begin 
< 0 || begin 
>= MAX_MEMORY_SIZE 
|| 
 886            end 
< 0 || end 
>= MAX_MEMORY_SIZE
) { 
 889         for (i
=begin
; i
<=end
; i
++) { 
 890                 if (firmware_mask
[i
]) return 1; 
 895 void ihex_get_data(int addr
, int len
, unsigned char *bytes
) 
 899         if (addr 
< 0 || len 
< 0 || addr 
+ len 
>= MAX_MEMORY_SIZE
) { 
 900                 for (i
=0; i
<len
; i
++) { 
 905         for (i
=0; i
<len
; i
++) { 
 906                 if (firmware_mask
[addr
]) { 
 907                         bytes
[i
] = firmware_image
[addr
]; 
 915 /****************************************************************/ 
 919 /****************************************************************/ 
 921 int printf_verbose(const char *format
, ...) 
 926         va_start(ap
, format
); 
 928                 r 
= vprintf(format
, ap
); 
 936 void delay(double seconds
) 
 939         sleep(seconds 
* 1000.0); 
 941         usleep(seconds 
* 1000000.0); 
 945 void die(const char *str
, ...) 
 950         vfprintf(stderr
, str
, ap
); 
 951         fprintf(stderr
, "\n"); 
 957 #if defined USE_WIN32 
 958 #define strcasecmp stricmp 
 961 void parse_options(int argc
, char **argv
) 
 966         for (i
=1; i
<argc
; i
++) { 
 970                         if (strcmp(arg
, "-w") == 0) { 
 971                                 wait_for_device_to_appear 
= 1; 
 972                         } else if (strcmp(arg
, "-r") == 0) { 
 973                                 hard_reboot_device 
= 1; 
 974                         } else if (strcmp(arg
, "-n") == 0) { 
 975                                 reboot_after_programming 
= 0; 
 976                         } else if (strcmp(arg
, "-v") == 0) { 
 978                         } else if (strncmp(arg
, "-mmcu=", 6) == 0) { 
 981                                 if (strncmp(arg
, "at90usb", 7) == 0) { 
 983                                 } else if (strncmp(arg
, "atmega", 6) == 0) { 
 986                                         die("Unknown MCU type\n"); 
 989                                 if (strncmp(arg
, "128", 3) == 0) { 
 990                                         code_size  
= 128 * 1024; 
 992                                 } else if (strncmp(arg
, "64", 2) == 0) { 
 993                                         code_size  
= 64 * 1024; 
 995                                 } else if (strncmp(arg
, "32", 2) == 0) { 
 996                                         code_size  
= 32 * 1024; 
 998                                 } else if (strncmp(arg
, "16", 2) == 0) { 
 999                                         code_size  
= 16 * 1024; 
1001                                 } else if (strncmp(arg
, "8", 1) == 0) { 
1002                                         code_size  
= 8 * 1024; 
1005                                         die("Unknown MCU type\n");