3d9dbca984d3132c2c0736d1228976c160362894
[pub/USBasp.git] / Bootloaders / HID / HostLoaderApp / teensy_loader_cli.c
1 /* Teensy Loader, Command Line Interface
2 * Program and Reboot Teensy Board with HalfKay Bootloader
3 * http://www.pjrc.com/teensy/loader_cli.html
4 * Copyright 2008-2010, PJRC.COM, LLC
5 *
6 * You may redistribute this program and/or modify it under the terms
7 * of the GNU General Public License as published by the Free Software
8 * Foundation, version 3 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see http://www.gnu.org/licenses/
17 */
18
19 /* Want to incorporate this code into a proprietary application??
20 * Just email paul@pjrc.com to ask. Usually it's not a problem,
21 * but you do need to ask to use this code in any way other than
22 * those permitted by the GNU General Public License, version 3 */
23
24 /* For non-root permissions on ubuntu or similar udev-based linux
25 * http://www.pjrc.com/teensy/49-teensy.rules
26 */
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 void usage(void)
37 {
38 fprintf(stderr, "Usage: teensy_loader_cli -mmcu=<MCU> [-w] [-h] [-n] [-v] <file.hex>\n");
39 fprintf(stderr, "\t-w : Wait for device to appear\n");
40 fprintf(stderr, "\t-r : Use hard reboot if device not online\n");
41 fprintf(stderr, "\t-n : No reboot after programming\n");
42 fprintf(stderr, "\t-v : Verbose output\n");
43 fprintf(stderr, "\n<MCU> = atmega32u4 | at90usb162 | at90usb646 | at90usb1286\n");
44 fprintf(stderr, "\nFor more information, please visit:\n");
45 fprintf(stderr, "http://www.pjrc.com/teensy/loader_cli.html\n");
46 exit(1);
47 }
48
49 // USB Access Functions
50 int teensy_open(void);
51 int teensy_write(void *buf, int len, double timeout);
52 void teensy_close(void);
53 int hard_reboot(void);
54
55 // Intel Hex File Functions
56 int read_intel_hex(const char *filename);
57 int ihex_bytes_within_range(int begin, int end);
58 void ihex_get_data(int addr, int len, unsigned char *bytes);
59
60 // Misc stuff
61 int printf_verbose(const char *format, ...);
62 void delay(double seconds);
63 void die(const char *str, ...);
64 void parse_options(int argc, char **argv);
65
66 // options (from user via command line args)
67 int wait_for_device_to_appear = 0;
68 int hard_reboot_device = 0;
69 int reboot_after_programming = 1;
70 int verbose = 0;
71 int code_size = 0, block_size = 0;
72 const char *filename=NULL;
73
74
75 /****************************************************************/
76 /* */
77 /* Main Program */
78 /* */
79 /****************************************************************/
80
81 int main(int argc, char **argv)
82 {
83 unsigned char buf[260];
84 int num, addr, r, first_block=1, waited=0;
85
86 // parse command line arguments
87 parse_options(argc, argv);
88 if (!filename) {
89 fprintf(stderr, "Filename must be specified\n\n");
90 usage();
91 }
92 if (!code_size) {
93 fprintf(stderr, "MCU type must be specified\n\n");
94 usage();
95 }
96 printf_verbose("Teensy Loader, Command Line, Version 2.0\n");
97
98 // read the intel hex file
99 // this is done first so any error is reported before using USB
100 num = read_intel_hex(filename);
101 if (num < 0) die("error reading intel hex file \"%s\"", filename);
102 printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n",
103 filename, num, (double)num / (double)code_size * 100.0);
104
105 // open the USB device
106 while (1) {
107 if (teensy_open()) break;
108 if (hard_reboot_device) {
109 if (!hard_reboot()) die("Unable to find rebootor\n");
110 printf_verbose("Hard Reboot performed\n");
111 hard_reboot_device = 0; // only hard reboot once
112 wait_for_device_to_appear = 1;
113 }
114 if (!wait_for_device_to_appear) die("Unable to open device\n");
115 if (!waited) {
116 printf_verbose("Waiting for Teensy device...\n");
117 printf_verbose(" (hint: press the reset button)\n");
118 waited = 1;
119 }
120 delay(0.25);
121 }
122 printf_verbose("Found HalfKay Bootloader\n");
123
124 // if we waited for the device, read the hex file again
125 // perhaps it changed while we were waiting?
126 if (waited) {
127 num = read_intel_hex(filename);
128 if (num < 0) die("error reading intel hex file \"%s\"", filename);
129 printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n",
130 filename, num, (double)num / (double)code_size * 100.0);
131 }
132
133 // program the data
134 printf_verbose("Programming");
135 fflush(stdout);
136 for (addr = 0; addr < code_size; addr += block_size) {
137 if (addr > 0 && !ihex_bytes_within_range(addr, addr + block_size - 1)) {
138 // don't waste time on blocks that are unused,
139 // but always do the first one to erase the chip
140 continue;
141 }
142 printf_verbose(".");
143 if (code_size < 0x10000) {
144 buf[0] = addr & 255;
145 buf[1] = (addr >> 8) & 255;
146 } else {
147 buf[0] = (addr >> 8) & 255;
148 buf[1] = (addr >> 16) & 255;
149 }
150 ihex_get_data(addr, block_size, buf + 2);
151 r = teensy_write(buf, block_size + 2, first_block ? 3.0 : 0.25);
152 if (!r) die("error writing to Teensy\n");
153 first_block = 0;
154 }
155 printf_verbose("\n");
156
157 // reboot to the user's new code
158 if (reboot_after_programming) {
159 printf_verbose("Booting\n");
160 buf[0] = 0xFF;
161 buf[1] = 0xFF;
162 memset(buf + 2, 0, sizeof(buf) - 2);
163 teensy_write(buf, block_size + 2, 0.25);
164 }
165 teensy_close();
166 return 0;
167 }
168
169
170
171
172 /****************************************************************/
173 /* */
174 /* USB Access - libusb (Linux & FreeBSD) */
175 /* */
176 /****************************************************************/
177
178 #if defined(USE_LIBUSB)
179
180 // http://libusb.sourceforge.net/doc/index.html
181 #include <usb.h>
182
183 usb_dev_handle * open_usb_device(int vid, int pid)
184 {
185 struct usb_bus *bus;
186 struct usb_device *dev;
187 usb_dev_handle *h;
188 char buf[128];
189 int r;
190
191 usb_init();
192 usb_find_busses();
193 usb_find_devices();
194 //printf_verbose("\nSearching for USB device:\n");
195 for (bus = usb_get_busses(); bus; bus = bus->next) {
196 for (dev = bus->devices; dev; dev = dev->next) {
197 //printf_verbose("bus \"%s\", device \"%s\" vid=%04X, pid=%04X\n",
198 // bus->dirname, dev->filename,
199 // dev->descriptor.idVendor,
200 // dev->descriptor.idProduct
201 //);
202 if (dev->descriptor.idVendor != vid) continue;
203 if (dev->descriptor.idProduct != pid) continue;
204 h = usb_open(dev);
205 if (!h) {
206 printf_verbose("Found device but unable to open");
207 continue;
208 }
209 #ifdef LIBUSB_HAS_GET_DRIVER_NP
210 r = usb_get_driver_np(h, 0, buf, sizeof(buf));
211 if (r >= 0) {
212 r = usb_detach_kernel_driver_np(h, 0);
213 if (r < 0) {
214 usb_close(h);
215 printf_verbose("Device is in use by \"%s\" driver", buf);
216 continue;
217 }
218 }
219 #endif
220 // Mac OS-X - removing this call to usb_claim_interface() might allow
221 // this to work, even though it is a clear misuse of the libusb API.
222 // normally Apple's IOKit should be used on Mac OS-X
223 r = usb_claim_interface(h, 0);
224 if (r < 0) {
225 usb_close(h);
226 printf_verbose("Unable to claim interface, check USB permissions");
227 continue;
228 }
229 return h;
230 }
231 }
232 return NULL;
233 }
234
235 static usb_dev_handle *libusb_teensy_handle = NULL;
236
237 int teensy_open(void)
238 {
239 teensy_close();
240 libusb_teensy_handle = open_usb_device(0x16C0, 0x0478);
241 if (libusb_teensy_handle) return 1;
242 return 0;
243 }
244
245 int teensy_write(void *buf, int len, double timeout)
246 {
247 int r;
248
249 if (!libusb_teensy_handle) return 0;
250 r = usb_control_msg(libusb_teensy_handle, 0x21, 9, 0x0200, 0, (char *)buf,
251 len, (int)(timeout * 1000.0));
252 if (r < 0) return 0;
253 return 1;
254 }
255
256 void teensy_close(void)
257 {
258 if (!libusb_teensy_handle) return;
259 usb_release_interface(libusb_teensy_handle, 0);
260 usb_close(libusb_teensy_handle);
261 libusb_teensy_handle = NULL;
262 }
263
264 int hard_reboot(void)
265 {
266 usb_dev_handle *rebootor;
267 int r;
268
269 rebootor = open_usb_device(0x16C0, 0x0477);
270 if (!rebootor) return 0;
271 r = usb_control_msg(rebootor, 0x21, 9, 0x0200, 0, "reboot", 6, 100);
272 usb_release_interface(rebootor, 0);
273 usb_close(rebootor);
274 if (r < 0) return 0;
275 return 1;
276 }
277
278 #endif
279
280
281 /****************************************************************/
282 /* */
283 /* USB Access - Microsoft WIN32 */
284 /* */
285 /****************************************************************/
286
287 #if defined(USE_WIN32)
288
289 // http://msdn.microsoft.com/en-us/library/ms790932.aspx
290 #include <windows.h>
291 #include <setupapi.h>
292 #include <ddk/hidsdi.h>
293 #include <ddk/hidclass.h>
294
295 HANDLE open_usb_device(int vid, int pid)
296 {
297 GUID guid;
298 HDEVINFO info;
299 DWORD index, required_size;
300 SP_DEVICE_INTERFACE_DATA iface;
301 SP_DEVICE_INTERFACE_DETAIL_DATA *details;
302 HIDD_ATTRIBUTES attrib;
303 HANDLE h;
304 BOOL ret;
305
306 HidD_GetHidGuid(&guid);
307 info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
308 if (info == INVALID_HANDLE_VALUE) return NULL;
309 for (index=0; 1 ;index++) {
310 iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
311 ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface);
312 if (!ret) {
313 SetupDiDestroyDeviceInfoList(info);
314 break;
315 }
316 SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &required_size, NULL);
317 details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(required_size);
318 if (details == NULL) continue;
319 memset(details, 0, required_size);
320 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
321 ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details,
322 required_size, NULL, NULL);
323 if (!ret) {
324 free(details);
325 continue;
326 }
327 h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE,
328 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
329 FILE_FLAG_OVERLAPPED, NULL);
330 free(details);
331 if (h == INVALID_HANDLE_VALUE) continue;
332 attrib.Size = sizeof(HIDD_ATTRIBUTES);
333 ret = HidD_GetAttributes(h, &attrib);
334 if (!ret) {
335 CloseHandle(h);
336 continue;
337 }
338 if (attrib.VendorID != vid || attrib.ProductID != pid) {
339 CloseHandle(h);
340 continue;
341 }
342 SetupDiDestroyDeviceInfoList(info);
343 return h;
344 }
345 return NULL;
346 }
347
348 int write_usb_device(HANDLE h, void *buf, int len, int timeout)
349 {
350 static HANDLE event = NULL;
351 unsigned char tmpbuf[1040];
352 OVERLAPPED ov;
353 DWORD n, r;
354
355 if (len > sizeof(tmpbuf) - 1) return 0;
356 if (event == NULL) {
357 event = CreateEvent(NULL, TRUE, TRUE, NULL);
358 if (!event) return 0;
359 }
360 ResetEvent(&event);
361 memset(&ov, 0, sizeof(ov));
362 ov.hEvent = event;
363 tmpbuf[0] = 0;
364 memcpy(tmpbuf + 1, buf, len);
365 if (!WriteFile(h, tmpbuf, len + 1, NULL, &ov)) {
366 if (GetLastError() != ERROR_IO_PENDING) return 0;
367 r = WaitForSingleObject(event, timeout);
368 if (r == WAIT_TIMEOUT) {
369 CancelIo(h);
370 return 0;
371 }
372 if (r != WAIT_OBJECT_0) return 0;
373 }
374 if (!GetOverlappedResult(h, &ov, &n, FALSE)) return 0;
375 if (n <= 0) return 0;
376 return 1;
377 }
378
379 void print_win32_err(void)
380 {
381 char buf[256];
382 DWORD err;
383
384 err = GetLastError();
385 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
386 0, buf, sizeof(buf), NULL);
387 printf("err %ld: %s\n", err, buf);
388 }
389
390 static HANDLE win32_teensy_handle = NULL;
391
392 int teensy_open(void)
393 {
394 teensy_close();
395 win32_teensy_handle = open_usb_device(0x16C0, 0x0478);
396 if (win32_teensy_handle) return 1;
397 return 0;
398 }
399
400 int teensy_write(void *buf, int len, double timeout)
401 {
402 int r;
403 if (!win32_teensy_handle) return 0;
404 r = write_usb_device(win32_teensy_handle, buf, len, (int)(timeout * 1000.0));
405 //if (!r) print_win32_err();
406 return r;
407 }
408
409 void teensy_close(void)
410 {
411 if (!win32_teensy_handle) return;
412 CloseHandle(win32_teensy_handle);
413 win32_teensy_handle = NULL;
414 }
415
416 int hard_reboot(void)
417 {
418 HANDLE rebootor;
419 int r;
420
421 rebootor = open_usb_device(0x16C0, 0x0477);
422 if (!rebootor) return 0;
423 r = write_usb_device(rebootor, "reboot", 6, 100);
424 CloseHandle(rebootor);
425 return r;
426 }
427
428 #endif
429
430
431
432 /****************************************************************/
433 /* */
434 /* USB Access - Apple's IOKit, Mac OS-X */
435 /* */
436 /****************************************************************/
437
438 #if defined(USE_APPLE_IOKIT)
439
440 // http://developer.apple.com/technotes/tn2007/tn2187.html
441 #include <IOKit/IOKitLib.h>
442 #include <IOKit/hid/IOHIDLib.h>
443 #include <IOKit/hid/IOHIDDevice.h>
444
445 struct usb_list_struct {
446 IOHIDDeviceRef ref;
447 int pid;
448 int vid;
449 struct usb_list_struct *next;
450 };
451
452 static struct usb_list_struct *usb_list=NULL;
453 static IOHIDManagerRef hid_manager=NULL;
454
455 void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev)
456 {
457 CFTypeRef type;
458 struct usb_list_struct *n, *p;
459 int32_t pid, vid;
460
461 if (!dev) return;
462 type = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDVendorIDKey));
463 if (!type || CFGetTypeID(type) != CFNumberGetTypeID()) return;
464 if (!CFNumberGetValue((CFNumberRef)type, kCFNumberSInt32Type, &vid)) return;
465 type = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductIDKey));
466 if (!type || CFGetTypeID(type) != CFNumberGetTypeID()) return;
467 if (!CFNumberGetValue((CFNumberRef)type, kCFNumberSInt32Type, &pid)) return;
468 n = (struct usb_list_struct *)malloc(sizeof(struct usb_list_struct));
469 if (!n) return;
470 //printf("attach callback: vid=%04X, pid=%04X\n", vid, pid);
471 n->ref = dev;
472 n->vid = vid;
473 n->pid = pid;
474 n->next = NULL;
475 if (usb_list == NULL) {
476 usb_list = n;
477 } else {
478 for (p = usb_list; p->next; p = p->next) ;
479 p->next = n;
480 }
481 }
482
483 void detach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev)
484 {
485 struct usb_list_struct *p, *tmp, *prev=NULL;
486
487 p = usb_list;
488 while (p) {
489 if (p->ref == dev) {
490 if (prev) {
491 prev->next = p->next;
492 } else {
493 usb_list = p->next;
494 }
495 tmp = p;
496 p = p->next;
497 free(tmp);
498 } else {
499 prev = p;
500 p = p->next;
501 }
502 }
503 }
504
505 void init_hid_manager(void)
506 {
507 CFMutableDictionaryRef dict;
508 IOReturn ret;
509
510 if (hid_manager) return;
511 hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
512 if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) {
513 if (hid_manager) CFRelease(hid_manager);
514 printf_verbose("no HID Manager - maybe this is a pre-Leopard (10.5) system?\n");
515 return;
516 }
517 dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
518 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
519 if (!dict) return;
520 IOHIDManagerSetDeviceMatching(hid_manager, dict);
521 CFRelease(dict);
522 IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
523 IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, attach_callback, NULL);
524 IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, detach_callback, NULL);
525 ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
526 if (ret != kIOReturnSuccess) {
527 IOHIDManagerUnscheduleFromRunLoop(hid_manager,
528 CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
529 CFRelease(hid_manager);
530 printf_verbose("Error opening HID Manager");
531 }
532 }
533
534 static void do_run_loop(void)
535 {
536 while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ;
537 }
538
539 IOHIDDeviceRef open_usb_device(int vid, int pid)
540 {
541 struct usb_list_struct *p;
542 IOReturn ret;
543
544 init_hid_manager();
545 do_run_loop();
546 for (p = usb_list; p; p = p->next) {
547 if (p->vid == vid && p->pid == pid) {
548 ret = IOHIDDeviceOpen(p->ref, kIOHIDOptionsTypeNone);
549 if (ret == kIOReturnSuccess) return p->ref;
550 }
551 }
552 return NULL;
553 }
554
555 void close_usb_device(IOHIDDeviceRef dev)
556 {
557 struct usb_list_struct *p;
558
559 do_run_loop();
560 for (p = usb_list; p; p = p->next) {
561 if (p->ref == dev) {
562 IOHIDDeviceClose(dev, kIOHIDOptionsTypeNone);
563 return;
564 }
565 }
566 }
567
568 static IOHIDDeviceRef iokit_teensy_reference = NULL;
569
570 int teensy_open(void)
571 {
572 teensy_close();
573 iokit_teensy_reference = open_usb_device(0x16C0, 0x0478);
574 if (iokit_teensy_reference) return 1;
575 return 0;
576 }
577
578 int teensy_write(void *buf, int len, double timeout)
579 {
580 IOReturn ret;
581
582 // timeouts do not work on OS-X
583 // IOHIDDeviceSetReportWithCallback is not implemented
584 // even though Apple documents it with a code example!
585 // submitted to Apple on 22-sep-2009, problem ID 7245050
586 if (!iokit_teensy_reference) return 0;
587 ret = IOHIDDeviceSetReport(iokit_teensy_reference,
588 kIOHIDReportTypeOutput, 0, buf, len);
589 if (ret == kIOReturnSuccess) return 1;
590 return 0;
591 }
592
593 void teensy_close(void)
594 {
595 if (!iokit_teensy_reference) return;
596 close_usb_device(iokit_teensy_reference);
597 iokit_teensy_reference = NULL;
598 }
599
600 int hard_reboot(void)
601 {
602 IOHIDDeviceRef rebootor;
603 IOReturn ret;
604
605 rebootor = open_usb_device(0x16C0, 0x0477);
606 if (!rebootor) return 0;
607 ret = IOHIDDeviceSetReport(rebootor,
608 kIOHIDReportTypeOutput, 0, (uint8_t *)("reboot"), 6);
609 close_usb_device(rebootor);
610 if (ret == kIOReturnSuccess) return 1;
611 return 0;
612 }
613
614 #endif
615
616
617
618 /****************************************************************/
619 /* */
620 /* USB Access - BSD's UHID driver */
621 /* */
622 /****************************************************************/
623
624 #if defined(USE_UHID)
625
626 // Thanks to Todd T Fries for help getting this working on OpenBSD
627 // and to Chris Kuethe for the initial patch to use UHID.
628
629 #include <sys/ioctl.h>
630 #include <fcntl.h>
631 #include <dirent.h>
632 #include <dev/usb/usb.h>
633 #ifndef USB_GET_DEVICEINFO
634 #include <dev/usb/usb_ioctl.h>
635 #endif
636
637 int open_usb_device(int vid, int pid)
638 {
639 int r, fd;
640 DIR *dir;
641 struct dirent *d;
642 struct usb_device_info info;
643 char buf[256];
644
645 dir = opendir("/dev");
646 if (!dir) return -1;
647 while ((d = readdir(dir)) != NULL) {
648 if (strncmp(d->d_name, "uhid", 4) != 0) continue;
649 snprintf(buf, sizeof(buf), "/dev/%s", d->d_name);
650 fd = open(buf, O_RDWR);
651 if (fd < 0) continue;
652 r = ioctl(fd, USB_GET_DEVICEINFO, &info);
653 if (r < 0) {
654 // NetBSD: added in 2004
655 // OpenBSD: added November 23, 2009
656 // FreeBSD: missing (FreeBSD 8.0) - USE_LIBUSB works!
657 die("Error: your uhid driver does not support"
658 " USB_GET_DEVICEINFO, please upgrade!\n");
659 close(fd);
660 closedir(dir);
661 exit(1);
662 }
663 //printf("%s: v=%d, p=%d\n", buf, info.udi_vendorNo, info.udi_productNo);
664 if (info.udi_vendorNo == vid && info.udi_productNo == pid) {
665 closedir(dir);
666 return fd;
667 }
668 close(fd);
669 }
670 closedir(dir);
671 return -1;
672 }
673
674 static int uhid_teensy_fd = -1;
675
676 int teensy_open(void)
677 {
678 teensy_close();
679 uhid_teensy_fd = open_usb_device(0x16C0, 0x0478);
680 if (uhid_teensy_fd < 0) return 0;
681 return 1;
682 }
683
684 int teensy_write(void *buf, int len, double timeout)
685 {
686 int r;
687
688 // TODO: imeplement timeout... how??
689 r = write(uhid_teensy_fd, buf, len);
690 if (r == len) return 1;
691 return 0;
692 }
693
694 void teensy_close(void)
695 {
696 if (uhid_teensy_fd >= 0) {
697 close(uhid_teensy_fd);
698 uhid_teensy_fd = -1;
699 }
700 }
701
702 int hard_reboot(void)
703 {
704 int r, rebootor_fd;
705
706 rebootor_fd = open_usb_device(0x16C0, 0x0477);
707 if (rebootor_fd < 0) return 0;
708 r = write(rebootor_fd, "reboot", 6);
709 delay(0.1);
710 close(rebootor_fd);
711 if (r == 6) return 1;
712 return 0;
713 }
714
715 #endif
716
717
718
719 /****************************************************************/
720 /* */
721 /* Read Intel Hex File */
722 /* */
723 /****************************************************************/
724
725 // the maximum flash image size we can support
726 // chips with larger memory may be used, but only this
727 // much intel-hex data can be loaded into memory!
728 #define MAX_MEMORY_SIZE 0x10000
729
730 static unsigned char firmware_image[MAX_MEMORY_SIZE];
731 static unsigned char firmware_mask[MAX_MEMORY_SIZE];
732 static int end_record_seen=0;
733 static int byte_count;
734 static unsigned int extended_addr = 0;
735 static int parse_hex_line(char *line);
736
737 int read_intel_hex(const char *filename)
738 {
739 FILE *fp;
740 int i, lineno=0;
741 char buf[1024];
742
743 byte_count = 0;
744 end_record_seen = 0;
745 for (i=0; i<MAX_MEMORY_SIZE; i++) {
746 firmware_image[i] = 0xFF;
747 firmware_mask[i] = 0;
748 }
749 extended_addr = 0;
750
751 fp = fopen(filename, "r");
752 if (fp == NULL) {
753 //printf("Unable to read file %s\n", filename);
754 return -1;
755 }
756 while (!feof(fp)) {
757 *buf = '\0';
758 if (!fgets(buf, sizeof(buf), fp)) break;
759 lineno++;
760 if (*buf) {
761 if (parse_hex_line(buf) == 0) {
762 //printf("Warning, parse error line %d\n", lineno);
763 return -2;
764 }
765 }
766 if (end_record_seen) break;
767 if (feof(stdin)) break;
768 }
769 fclose(fp);
770 return byte_count;
771 }
772
773
774 /* from ihex.c, at http://www.pjrc.com/tech/8051/pm2_docs/intel-hex.html */
775
776 /* parses a line of intel hex code, stores the data in bytes[] */
777 /* and the beginning address in addr, and returns a 1 if the */
778 /* line was valid, or a 0 if an error occured. The variable */
779 /* num gets the number of bytes that were stored into bytes[] */
780
781
782 int
783 parse_hex_line(char *line)
784 {
785 int addr, code, num;
786 int sum, len, cksum, i;
787 char *ptr;
788
789 num = 0;
790 if (line[0] != ':') return 0;
791 if (strlen(line) < 11) return 0;
792 ptr = line+1;
793 if (!sscanf(ptr, "%02x", &len)) return 0;
794 ptr += 2;
795 if ((int)strlen(line) < (11 + (len * 2)) ) return 0;
796 if (!sscanf(ptr, "%04x", &addr)) return 0;
797 ptr += 4;
798 /* printf("Line: length=%d Addr=%d\n", len, addr); */
799 if (!sscanf(ptr, "%02x", &code)) return 0;
800 if (addr + extended_addr + len >= MAX_MEMORY_SIZE) return 0;
801 ptr += 2;
802 sum = (len & 255) + ((addr >> 8) & 255) + (addr & 255) + (code & 255);
803 if (code != 0) {
804 if (code == 1) {
805 end_record_seen = 1;
806 return 1;
807 }
808 if (code == 2 && len == 2) {
809 if (!sscanf(ptr, "%04x", &i)) return 1;
810 ptr += 4;
811 sum += ((i >> 8) & 255) + (i & 255);
812 if (!sscanf(ptr, "%02x", &cksum)) return 1;
813 if (((sum & 255) + (cksum & 255)) & 255) return 1;
814 extended_addr = i << 4;
815 //printf("ext addr = %05X\n", extended_addr);
816 }
817 if (code == 4 && len == 2) {
818 if (!sscanf(ptr, "%04x", &i)) return 1;
819 ptr += 4;
820 sum += ((i >> 8) & 255) + (i & 255);
821 if (!sscanf(ptr, "%02x", &cksum)) return 1;
822 if (((sum & 255) + (cksum & 255)) & 255) return 1;
823 extended_addr = i << 16;
824 //printf("ext addr = %08X\n", extended_addr);
825 }
826 return 1; // non-data line
827 }
828 byte_count += len;
829 while (num != len) {
830 if (sscanf(ptr, "%02x", &i) != 1) return 0;
831 i &= 255;
832 firmware_image[addr + extended_addr + num] = i;
833 firmware_mask[addr + extended_addr + num] = 1;
834 ptr += 2;
835 sum += i;
836 (num)++;
837 if (num >= 256) return 0;
838 }
839 if (!sscanf(ptr, "%02x", &cksum)) return 0;
840 if (((sum & 255) + (cksum & 255)) & 255) return 0; /* checksum error */
841 return 1;
842 }
843
844 int ihex_bytes_within_range(int begin, int end)
845 {
846 int i;
847
848 if (begin < 0 || begin >= MAX_MEMORY_SIZE ||
849 end < 0 || end >= MAX_MEMORY_SIZE) {
850 return 0;
851 }
852 for (i=begin; i<=end; i++) {
853 if (firmware_mask[i]) return 1;
854 }
855 return 0;
856 }
857
858 void ihex_get_data(int addr, int len, unsigned char *bytes)
859 {
860 int i;
861
862 if (addr < 0 || len < 0 || addr + len >= MAX_MEMORY_SIZE) {
863 for (i=0; i<len; i++) {
864 bytes[i] = 255;
865 }
866 return;
867 }
868 for (i=0; i<len; i++) {
869 if (firmware_mask[addr]) {
870 bytes[i] = firmware_image[addr];
871 } else {
872 bytes[i] = 255;
873 }
874 addr++;
875 }
876 }
877
878 /****************************************************************/
879 /* */
880 /* Misc Functions */
881 /* */
882 /****************************************************************/
883
884 int printf_verbose(const char *format, ...)
885 {
886 va_list ap;
887 int r;
888
889 va_start(ap, format);
890 if (verbose) {
891 r = vprintf(format, ap);
892 fflush(stdout);
893 return r;
894 }
895 return 0;
896 }
897
898 void delay(double seconds)
899 {
900 #ifdef WIN32
901 Sleep(seconds * 1000.0);
902 #else
903 usleep(seconds * 1000000.0);
904 #endif
905 }
906
907 void die(const char *str, ...)
908 {
909 va_list ap;
910
911 va_start(ap, str);
912 vfprintf(stderr, str, ap);
913 fprintf(stderr, "\n");
914 exit(1);
915 }
916
917 #if defined(WIN32)
918 #define strcasecmp stricmp
919 #endif
920
921 void parse_options(int argc, char **argv)
922 {
923 int i;
924 const char *arg;
925
926 for (i=1; i<argc; i++) {
927 arg = argv[i];
928 //printf("arg: %s\n", arg);
929 if (*arg == '-') {
930 if (strcmp(arg, "-w") == 0) {
931 wait_for_device_to_appear = 1;
932 } else if (strcmp(arg, "-r") == 0) {
933 hard_reboot_device = 1;
934 } else if (strcmp(arg, "-n") == 0) {
935 reboot_after_programming = 0;
936 } else if (strcmp(arg, "-v") == 0) {
937 verbose = 1;
938 } else if (strncmp(arg, "-mmcu=", 6) == 0) {
939 if (strcasecmp(arg+6, "at90usb162") == 0) {
940 code_size = 15872;
941 block_size = 128;
942 } else if (strcasecmp(arg+6, "atmega32u4") == 0) {
943 code_size = 32256;
944 block_size = 128;
945 } else if (strcasecmp(arg+6, "at90usb646") == 0) {
946 code_size = 64512;
947 block_size = 256;
948 } else if (strcasecmp(arg+6, "at90usb1286") == 0) {
949 code_size = 130048;
950 block_size = 256;
951 } else {
952 die("Unknown MCU type\n");
953 }
954 }
955 } else {
956 filename = argv[i];
957 }
958 }
959 }
960