1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183 |
- /* Teensy Loader, Command Line Interface
- * Program and Reboot Teensy Board with HalfKay Bootloader
- * http://www.pjrc.com/teensy/loader_cli.html
- * Copyright 2008-2016, PJRC.COM, LLC
- *
- * You may redistribute this program and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software
- * Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see http://www.gnu.org/licenses/
- */
- /* Want to incorporate this code into a proprietary application??
- * Just email paul@pjrc.com to ask. Usually it's not a problem,
- * but you do need to ask to use this code in any way other than
- * those permitted by the GNU General Public License, version 3 */
- /* For non-root permissions on ubuntu or similar udev-based linux
- * http://www.pjrc.com/teensy/49-teensy.rules
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <stdarg.h>
- #include <string.h>
- #include <unistd.h>
- void usage(const char *err)
- {
- if(err != NULL) fprintf(stderr, "%s\n\n", err);
- fprintf(stderr,
- "Usage: teensy_loader_cli --mcu=<MCU> [-w] [-h] [-n] [-b] [-v] <file.hex>\n"
- "\t-w : Wait for device to appear\n"
- "\t-r : Use hard reboot if device not online\n"
- "\t-s : Use soft reboot if device not online (Teensy3.x only)\n"
- "\t-n : No reboot after programming\n"
- "\t-b : Boot only, do not program\n"
- "\t-v : Verbose output\n"
- "\nUse `teensy_loader_cli --list-mcus` to list supported MCUs.\n"
- "\nFor more information, please visit:\n"
- "http://www.pjrc.com/teensy/loader_cli.html\n");
- exit(1);
- }
- // USB Access Functions
- int teensy_open(void);
- int teensy_write(void *buf, int len, double timeout);
- void teensy_close(void);
- int hard_reboot(void);
- int soft_reboot(void);
- // Intel Hex File Functions
- int read_intel_hex(const char *filename);
- int ihex_bytes_within_range(int begin, int end);
- void ihex_get_data(int addr, int len, unsigned char *bytes);
- int memory_is_blank(int addr, int block_size);
- // Misc stuff
- int printf_verbose(const char *format, ...);
- void delay(double seconds);
- void die(const char *str, ...);
- void parse_options(int argc, char **argv);
- void boot(unsigned char *buf, int write_size);
- // options (from user via command line args)
- int wait_for_device_to_appear = 0;
- int hard_reboot_device = 0;
- int soft_reboot_device = 0;
- int reboot_after_programming = 1;
- int verbose = 0;
- int boot_only = 0;
- int code_size = 0, block_size = 0;
- const char *filename=NULL;
- /****************************************************************/
- /* */
- /* Main Program */
- /* */
- /****************************************************************/
- int main(int argc, char **argv)
- {
- unsigned char buf[2048];
- int num, addr, r, write_size;
- int first_block=1, waited=0;
- // parse command line arguments
- parse_options(argc, argv);
- if (!filename && !boot_only) {
- usage("Filename must be specified");
- }
- if (!code_size) {
- usage("MCU type must be specified");
- }
- printf_verbose("Teensy Loader, Command Line, Version 2.1\n");
- if (block_size == 512 || block_size == 1024) {
- write_size = block_size + 64;
- } else {
- write_size = block_size + 2;
- };
- if (boot_only) {
- if (! teensy_open()) {
- die("Could not find HalfKay");
- }
- printf_verbose("Found HalfKay Bootloader\n");
- boot(buf, write_size);
- exit(0);
- }
- // read the intel hex file
- // this is done first so any error is reported before using USB
- num = read_intel_hex(filename);
- if (num < 0) die("error reading intel hex file \"%s\"", filename);
- printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n",
- filename, num, (double)num / (double)code_size * 100.0);
- // open the USB device
- while (1) {
- if (teensy_open()) break;
- if (hard_reboot_device) {
- if (!hard_reboot()) die("Unable to find rebootor\n");
- printf_verbose("Hard Reboot performed\n");
- hard_reboot_device = 0; // only hard reboot once
- wait_for_device_to_appear = 1;
- }
- if (soft_reboot_device) {
- if (soft_reboot()) {
- printf_verbose("Soft reboot performed\n");
- }
- soft_reboot_device = 0;
- wait_for_device_to_appear = 1;
- }
- if (!wait_for_device_to_appear) die("Unable to open device\n");
- if (!waited) {
- printf_verbose("Waiting for Teensy device...\n");
- printf_verbose(" (hint: press the reset button)\n");
- waited = 1;
- }
- delay(0.25);
- }
- printf_verbose("Found HalfKay Bootloader\n");
- // if we waited for the device, read the hex file again
- // perhaps it changed while we were waiting?
- if (waited) {
- num = read_intel_hex(filename);
- if (num < 0) die("error reading intel hex file \"%s\"", filename);
- printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n",
- filename, num, (double)num / (double)code_size * 100.0);
- }
- // program the data
- printf_verbose("Programming");
- fflush(stdout);
- for (addr = 0; addr < code_size; addr += block_size) {
- if (!first_block && !ihex_bytes_within_range(addr, addr + block_size - 1)) {
- // don't waste time on blocks that are unused,
- // but always do the first one to erase the chip
- continue;
- }
- if (!first_block && memory_is_blank(addr, block_size)) continue;
- printf_verbose(".");
- if (block_size <= 256 && code_size < 0x10000) {
- buf[0] = addr & 255;
- buf[1] = (addr >> 8) & 255;
- ihex_get_data(addr, block_size, buf + 2);
- write_size = block_size + 2;
- } else if (block_size == 256) {
- buf[0] = (addr >> 8) & 255;
- buf[1] = (addr >> 16) & 255;
- ihex_get_data(addr, block_size, buf + 2);
- write_size = block_size + 2;
- } else if (block_size == 512 || block_size == 1024) {
- buf[0] = addr & 255;
- buf[1] = (addr >> 8) & 255;
- buf[2] = (addr >> 16) & 255;
- memset(buf + 3, 0, 61);
- ihex_get_data(addr, block_size, buf + 64);
- write_size = block_size + 64;
- } else {
- die("Unknown code/block size\n");
- }
- r = teensy_write(buf, write_size, first_block ? 5.0 : 0.5);
- if (!r) die("error writing to Teensy\n");
- first_block = 0;
- }
- printf_verbose("\n");
- // reboot to the user's new code
- if (reboot_after_programming) {
- boot(buf, write_size);
- }
- teensy_close();
- return 0;
- }
- /****************************************************************/
- /* */
- /* USB Access - libusb (Linux & FreeBSD) */
- /* */
- /* Uses libusb v0.1. To install: */
- /* - [debian, ubuntu, mint] apt install libusb-dev */
- /* - [redhat, centos] yum install libusb-devel */
- /* - [fedora] dnf install libusb-devel */
- /* - [arch linux] pacman -S libusb-compat */
- /* - [gentoo] emerge dev-libs/libusb-compat */
- /* */
- /* - [freebsd] seems to be preinstalled */
- /****************************************************************/
- #if defined(USE_LIBUSB)
- // http://libusb.sourceforge.net/doc/index.html
- #include <usb.h>
- usb_dev_handle * open_usb_device(int vid, int pid)
- {
- struct usb_bus *bus;
- struct usb_device *dev;
- usb_dev_handle *h;
- char buf[128];
- int r;
- usb_init();
- usb_find_busses();
- usb_find_devices();
- //printf_verbose("\nSearching for USB device:\n");
- for (bus = usb_get_busses(); bus; bus = bus->next) {
- for (dev = bus->devices; dev; dev = dev->next) {
- //printf_verbose("bus \"%s\", device \"%s\" vid=%04X, pid=%04X\n",
- // bus->dirname, dev->filename,
- // dev->descriptor.idVendor,
- // dev->descriptor.idProduct
- //);
- if (dev->descriptor.idVendor != vid) continue;
- if (dev->descriptor.idProduct != pid) continue;
- h = usb_open(dev);
- if (!h) {
- printf_verbose("Found device but unable to open\n");
- continue;
- }
- #ifdef LIBUSB_HAS_GET_DRIVER_NP
- r = usb_get_driver_np(h, 0, buf, sizeof(buf));
- if (r >= 0) {
- r = usb_detach_kernel_driver_np(h, 0);
- if (r < 0) {
- usb_close(h);
- printf_verbose("Device is in use by \"%s\" driver\n", buf);
- continue;
- }
- }
- #endif
- // Mac OS-X - removing this call to usb_claim_interface() might allow
- // this to work, even though it is a clear misuse of the libusb API.
- // normally Apple's IOKit should be used on Mac OS-X
- #if !defined(MACOSX)
- r = usb_claim_interface(h, 0);
- if (r < 0) {
- usb_close(h);
- printf_verbose("Unable to claim interface, check USB permissions\n");
- continue;
- }
- #endif
-
- return h;
- }
- }
- return NULL;
- }
- static usb_dev_handle *libusb_teensy_handle = NULL;
- int teensy_open(void)
- {
- teensy_close();
- libusb_teensy_handle = open_usb_device(0x16C0, 0x0478);
- if (libusb_teensy_handle) return 1;
- return 0;
- }
- int teensy_write(void *buf, int len, double timeout)
- {
- int r;
- if (!libusb_teensy_handle) return 0;
- while (timeout > 0) {
- r = usb_control_msg(libusb_teensy_handle, 0x21, 9, 0x0200, 0,
- (char *)buf, len, (int)(timeout * 1000.0));
- if (r >= 0) return 1;
- //printf("teensy_write, r=%d\n", r);
- usleep(10000);
- timeout -= 0.01; // TODO: subtract actual elapsed time
- }
- return 0;
- }
- void teensy_close(void)
- {
- if (!libusb_teensy_handle) return;
- usb_release_interface(libusb_teensy_handle, 0);
- usb_close(libusb_teensy_handle);
- libusb_teensy_handle = NULL;
- }
- int hard_reboot(void)
- {
- usb_dev_handle *rebootor;
- int r;
- rebootor = open_usb_device(0x16C0, 0x0477);
- if (!rebootor) return 0;
- r = usb_control_msg(rebootor, 0x21, 9, 0x0200, 0, "reboot", 6, 100);
- usb_release_interface(rebootor, 0);
- usb_close(rebootor);
- if (r < 0) return 0;
- return 1;
- }
- int soft_reboot(void)
- {
- usb_dev_handle *serial_handle = NULL;
- serial_handle = open_usb_device(0x16C0, 0x0483);
- if (!serial_handle) {
- char *error = usb_strerror();
- printf("Error opening USB device: %s\n", error);
- return 0;
- }
- char reboot_command = 134;
- int response = usb_control_msg(serial_handle, 0x21, 0x20, 0, 0, &reboot_command, 1, 10000);
- usb_release_interface(serial_handle, 0);
- usb_close(serial_handle);
- if (response < 0) {
- char *error = usb_strerror();
- printf("Unable to soft reboot with USB error: %s\n", error);
- return 0;
- }
- return 1;
- }
- #endif
- /****************************************************************/
- /* */
- /* USB Access - Microsoft WIN32 */
- /* */
- /****************************************************************/
- #if defined(USE_WIN32)
- // http://msdn.microsoft.com/en-us/library/ms790932.aspx
- #include <windows.h>
- #include <setupapi.h>
- #include <ddk/hidsdi.h>
- #include <ddk/hidclass.h>
- HANDLE open_usb_device(int vid, int pid)
- {
- GUID guid;
- HDEVINFO info;
- DWORD index, required_size;
- SP_DEVICE_INTERFACE_DATA iface;
- SP_DEVICE_INTERFACE_DETAIL_DATA *details;
- HIDD_ATTRIBUTES attrib;
- HANDLE h;
- BOOL ret;
- HidD_GetHidGuid(&guid);
- info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- if (info == INVALID_HANDLE_VALUE) return NULL;
- for (index=0; 1 ;index++) {
- iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface);
- if (!ret) {
- SetupDiDestroyDeviceInfoList(info);
- break;
- }
- SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &required_size, NULL);
- details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(required_size);
- if (details == NULL) continue;
- memset(details, 0, required_size);
- details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
- ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details,
- required_size, NULL, NULL);
- if (!ret) {
- free(details);
- continue;
- }
- h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE,
- FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED, NULL);
- free(details);
- if (h == INVALID_HANDLE_VALUE) continue;
- attrib.Size = sizeof(HIDD_ATTRIBUTES);
- ret = HidD_GetAttributes(h, &attrib);
- if (!ret) {
- CloseHandle(h);
- continue;
- }
- if (attrib.VendorID != vid || attrib.ProductID != pid) {
- CloseHandle(h);
- continue;
- }
- SetupDiDestroyDeviceInfoList(info);
- return h;
- }
- return NULL;
- }
- int write_usb_device(HANDLE h, void *buf, int len, int timeout)
- {
- static HANDLE event = NULL;
- unsigned char tmpbuf[1089];
- OVERLAPPED ov;
- DWORD n, r;
- if (len > sizeof(tmpbuf) - 1) return 0;
- if (event == NULL) {
- event = CreateEvent(NULL, TRUE, TRUE, NULL);
- if (!event) return 0;
- }
- ResetEvent(&event);
- memset(&ov, 0, sizeof(ov));
- ov.hEvent = event;
- tmpbuf[0] = 0;
- memcpy(tmpbuf + 1, buf, len);
- if (!WriteFile(h, tmpbuf, len + 1, NULL, &ov)) {
- if (GetLastError() != ERROR_IO_PENDING) return 0;
- r = WaitForSingleObject(event, timeout);
- if (r == WAIT_TIMEOUT) {
- CancelIo(h);
- return 0;
- }
- if (r != WAIT_OBJECT_0) return 0;
- }
- if (!GetOverlappedResult(h, &ov, &n, FALSE)) return 0;
- if (n <= 0) return 0;
- return 1;
- }
- void print_win32_err(void)
- {
- char buf[256];
- DWORD err;
- err = GetLastError();
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
- 0, buf, sizeof(buf), NULL);
- printf("err %ld: %s\n", err, buf);
- }
- static HANDLE win32_teensy_handle = NULL;
- int teensy_open(void)
- {
- teensy_close();
- win32_teensy_handle = open_usb_device(0x16C0, 0x0478);
- if (win32_teensy_handle) return 1;
- return 0;
- }
- int teensy_write(void *buf, int len, double timeout)
- {
- int r;
- uint32_t begin, now, total;
- if (!win32_teensy_handle) return 0;
- total = (uint32_t)(timeout * 1000.0);
- begin = timeGetTime();
- now = begin;
- do {
- r = write_usb_device(win32_teensy_handle, buf, len, total - (now - begin));
- if (r > 0) return 1;
- Sleep(10);
- now = timeGetTime();
- } while (now - begin < total);
- return 0;
- }
- void teensy_close(void)
- {
- if (!win32_teensy_handle) return;
- CloseHandle(win32_teensy_handle);
- win32_teensy_handle = NULL;
- }
- int hard_reboot(void)
- {
- HANDLE rebootor;
- int r;
- rebootor = open_usb_device(0x16C0, 0x0477);
- if (!rebootor) return 0;
- r = write_usb_device(rebootor, "reboot", 6, 100);
- CloseHandle(rebootor);
- return r;
- }
- int soft_reboot(void)
- {
- printf("Soft reboot is not implemented for Win32\n");
- return 0;
- }
- #endif
- /****************************************************************/
- /* */
- /* USB Access - Apple's IOKit, Mac OS-X */
- /* */
- /****************************************************************/
- #if defined(USE_APPLE_IOKIT)
- // http://developer.apple.com/technotes/tn2007/tn2187.html
- #include <IOKit/IOKitLib.h>
- #include <IOKit/hid/IOHIDLib.h>
- #include <IOKit/hid/IOHIDDevice.h>
- struct usb_list_struct {
- IOHIDDeviceRef ref;
- int pid;
- int vid;
- struct usb_list_struct *next;
- };
- static struct usb_list_struct *usb_list=NULL;
- static IOHIDManagerRef hid_manager=NULL;
- void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev)
- {
- CFTypeRef type;
- struct usb_list_struct *n, *p;
- int32_t pid, vid;
- if (!dev) return;
- type = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDVendorIDKey));
- if (!type || CFGetTypeID(type) != CFNumberGetTypeID()) return;
- if (!CFNumberGetValue((CFNumberRef)type, kCFNumberSInt32Type, &vid)) return;
- type = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductIDKey));
- if (!type || CFGetTypeID(type) != CFNumberGetTypeID()) return;
- if (!CFNumberGetValue((CFNumberRef)type, kCFNumberSInt32Type, &pid)) return;
- n = (struct usb_list_struct *)malloc(sizeof(struct usb_list_struct));
- if (!n) return;
- //printf("attach callback: vid=%04X, pid=%04X\n", vid, pid);
- n->ref = dev;
- n->vid = vid;
- n->pid = pid;
- n->next = NULL;
- if (usb_list == NULL) {
- usb_list = n;
- } else {
- for (p = usb_list; p->next; p = p->next) ;
- p->next = n;
- }
- }
- void detach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev)
- {
- struct usb_list_struct *p, *tmp, *prev=NULL;
- p = usb_list;
- while (p) {
- if (p->ref == dev) {
- if (prev) {
- prev->next = p->next;
- } else {
- usb_list = p->next;
- }
- tmp = p;
- p = p->next;
- free(tmp);
- } else {
- prev = p;
- p = p->next;
- }
- }
- }
- void init_hid_manager(void)
- {
- CFMutableDictionaryRef dict;
- IOReturn ret;
- if (hid_manager) return;
- hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
- if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) {
- if (hid_manager) CFRelease(hid_manager);
- printf_verbose("no HID Manager - maybe this is a pre-Leopard (10.5) system?\n");
- return;
- }
- dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
- &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (!dict) return;
- IOHIDManagerSetDeviceMatching(hid_manager, dict);
- CFRelease(dict);
- IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, attach_callback, NULL);
- IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, detach_callback, NULL);
- ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
- if (ret != kIOReturnSuccess) {
- IOHIDManagerUnscheduleFromRunLoop(hid_manager,
- CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- CFRelease(hid_manager);
- printf_verbose("Error opening HID Manager\n");
- }
- }
- static void do_run_loop(void)
- {
- while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ;
- }
- IOHIDDeviceRef open_usb_device(int vid, int pid)
- {
- struct usb_list_struct *p;
- IOReturn ret;
- init_hid_manager();
- do_run_loop();
- for (p = usb_list; p; p = p->next) {
- if (p->vid == vid && p->pid == pid) {
- ret = IOHIDDeviceOpen(p->ref, kIOHIDOptionsTypeNone);
- if (ret == kIOReturnSuccess) return p->ref;
- }
- }
- return NULL;
- }
- void close_usb_device(IOHIDDeviceRef dev)
- {
- struct usb_list_struct *p;
- do_run_loop();
- for (p = usb_list; p; p = p->next) {
- if (p->ref == dev) {
- IOHIDDeviceClose(dev, kIOHIDOptionsTypeNone);
- return;
- }
- }
- }
- static IOHIDDeviceRef iokit_teensy_reference = NULL;
- int teensy_open(void)
- {
- teensy_close();
- iokit_teensy_reference = open_usb_device(0x16C0, 0x0478);
- if (iokit_teensy_reference) return 1;
- return 0;
- }
- int teensy_write(void *buf, int len, double timeout)
- {
- IOReturn ret;
- // timeouts do not work on OS-X
- // IOHIDDeviceSetReportWithCallback is not implemented
- // even though Apple documents it with a code example!
- // submitted to Apple on 22-sep-2009, problem ID 7245050
- if (!iokit_teensy_reference) return 0;
- double start = CFAbsoluteTimeGetCurrent();
- while (CFAbsoluteTimeGetCurrent() - timeout < start) {
- ret = IOHIDDeviceSetReport(iokit_teensy_reference,
- kIOHIDReportTypeOutput, 0, buf, len);
- if (ret == kIOReturnSuccess) return 1;
- usleep(10000);
- }
- return 0;
- }
- void teensy_close(void)
- {
- if (!iokit_teensy_reference) return;
- close_usb_device(iokit_teensy_reference);
- iokit_teensy_reference = NULL;
- }
- int hard_reboot(void)
- {
- IOHIDDeviceRef rebootor;
- IOReturn ret;
- rebootor = open_usb_device(0x16C0, 0x0477);
- if (!rebootor) return 0;
- ret = IOHIDDeviceSetReport(rebootor,
- kIOHIDReportTypeOutput, 0, (uint8_t *)("reboot"), 6);
- close_usb_device(rebootor);
- if (ret == kIOReturnSuccess) return 1;
- return 0;
- }
- int soft_reboot(void)
- {
- printf("Soft reboot is not implemented for OSX\n");
- return 0;
- }
- #endif
- /****************************************************************/
- /* */
- /* USB Access - BSD's UHID driver */
- /* */
- /****************************************************************/
- #if defined(USE_UHID)
- // Thanks to Todd T Fries for help getting this working on OpenBSD
- // and to Chris Kuethe for the initial patch to use UHID.
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #include <dirent.h>
- #include <dev/usb/usb.h>
- #ifndef USB_GET_DEVICEINFO
- #include <dev/usb/usb_ioctl.h>
- #endif
- int open_usb_device(int vid, int pid)
- {
- int r, fd;
- DIR *dir;
- struct dirent *d;
- struct usb_device_info info;
- char buf[256];
- dir = opendir("/dev");
- if (!dir) return -1;
- while ((d = readdir(dir)) != NULL) {
- if (strncmp(d->d_name, "uhid", 4) != 0) continue;
- snprintf(buf, sizeof(buf), "/dev/%s", d->d_name);
- fd = open(buf, O_RDWR);
- if (fd < 0) continue;
- r = ioctl(fd, USB_GET_DEVICEINFO, &info);
- if (r < 0) {
- // NetBSD: added in 2004
- // OpenBSD: added November 23, 2009
- // FreeBSD: missing (FreeBSD 8.0) - USE_LIBUSB works!
- die("Error: your uhid driver does not support"
- " USB_GET_DEVICEINFO, please upgrade!\n");
- close(fd);
- closedir(dir);
- exit(1);
- }
- //printf("%s: v=%d, p=%d\n", buf, info.udi_vendorNo, info.udi_productNo);
- if (info.udi_vendorNo == vid && info.udi_productNo == pid) {
- closedir(dir);
- return fd;
- }
- close(fd);
- }
- closedir(dir);
- return -1;
- }
- static int uhid_teensy_fd = -1;
- int teensy_open(void)
- {
- teensy_close();
- uhid_teensy_fd = open_usb_device(0x16C0, 0x0478);
- if (uhid_teensy_fd < 0) return 0;
- return 1;
- }
- int teensy_write(void *buf, int len, double timeout)
- {
- int r;
- // TODO: imeplement timeout... how??
- r = write(uhid_teensy_fd, buf, len);
- if (r == len) return 1;
- return 0;
- }
- void teensy_close(void)
- {
- if (uhid_teensy_fd >= 0) {
- close(uhid_teensy_fd);
- uhid_teensy_fd = -1;
- }
- }
- int hard_reboot(void)
- {
- int r, rebootor_fd;
- rebootor_fd = open_usb_device(0x16C0, 0x0477);
- if (rebootor_fd < 0) return 0;
- r = write(rebootor_fd, "reboot", 6);
- delay(0.1);
- close(rebootor_fd);
- if (r == 6) return 1;
- return 0;
- }
- int soft_reboot(void)
- {
- printf("Soft reboot is not implemented for UHID\n");
- return 0;
- }
- #endif
- /****************************************************************/
- /* */
- /* Read Intel Hex File */
- /* */
- /****************************************************************/
- // the maximum flash image size we can support
- // chips with larger memory may be used, but only this
- // much intel-hex data can be loaded into memory!
- #define MAX_MEMORY_SIZE 0x100000
- static unsigned char firmware_image[MAX_MEMORY_SIZE];
- static unsigned char firmware_mask[MAX_MEMORY_SIZE];
- static int end_record_seen=0;
- static int byte_count;
- static unsigned int extended_addr = 0;
- static int parse_hex_line(char *line);
- int read_intel_hex(const char *filename)
- {
- FILE *fp;
- int i, lineno=0;
- char buf[1024];
- byte_count = 0;
- end_record_seen = 0;
- for (i=0; i<MAX_MEMORY_SIZE; i++) {
- firmware_image[i] = 0xFF;
- firmware_mask[i] = 0;
- }
- extended_addr = 0;
- fp = fopen(filename, "r");
- if (fp == NULL) {
- //printf("Unable to read file %s\n", filename);
- return -1;
- }
- while (!feof(fp)) {
- *buf = '\0';
- if (!fgets(buf, sizeof(buf), fp)) break;
- lineno++;
- if (*buf) {
- if (parse_hex_line(buf) == 0) {
- printf("Warning, HEX parse error line %d\n", lineno);
- return -2;
- }
- }
- if (end_record_seen) break;
- if (feof(stdin)) break;
- }
- fclose(fp);
- return byte_count;
- }
- /* from ihex.c, at http://www.pjrc.com/tech/8051/pm2_docs/intel-hex.html */
- /* parses a line of intel hex code, stores the data in bytes[] */
- /* and the beginning address in addr, and returns a 1 if the */
- /* line was valid, or a 0 if an error occured. The variable */
- /* num gets the number of bytes that were stored into bytes[] */
- int
- parse_hex_line(char *line)
- {
- int addr, code, num;
- int sum, len, cksum, i;
- char *ptr;
- num = 0;
- if (line[0] != ':') return 0;
- if (strlen(line) < 11) return 0;
- ptr = line+1;
- if (!sscanf(ptr, "%02x", &len)) return 0;
- ptr += 2;
- if ((int)strlen(line) < (11 + (len * 2)) ) return 0;
- if (!sscanf(ptr, "%04x", &addr)) return 0;
- ptr += 4;
- /* printf("Line: length=%d Addr=%d\n", len, addr); */
- if (!sscanf(ptr, "%02x", &code)) return 0;
- if (addr + extended_addr + len >= MAX_MEMORY_SIZE) return 0;
- ptr += 2;
- sum = (len & 255) + ((addr >> 8) & 255) + (addr & 255) + (code & 255);
- if (code != 0) {
- if (code == 1) {
- end_record_seen = 1;
- return 1;
- }
- if (code == 2 && len == 2) {
- if (!sscanf(ptr, "%04x", &i)) return 1;
- ptr += 4;
- sum += ((i >> 8) & 255) + (i & 255);
- if (!sscanf(ptr, "%02x", &cksum)) return 1;
- if (((sum & 255) + (cksum & 255)) & 255) return 1;
- extended_addr = i << 4;
- //printf("ext addr = %05X\n", extended_addr);
- }
- if (code == 4 && len == 2) {
- if (!sscanf(ptr, "%04x", &i)) return 1;
- ptr += 4;
- sum += ((i >> 8) & 255) + (i & 255);
- if (!sscanf(ptr, "%02x", &cksum)) return 1;
- if (((sum & 255) + (cksum & 255)) & 255) return 1;
- extended_addr = i << 16;
- //printf("ext addr = %08X\n", extended_addr);
- }
- return 1; // non-data line
- }
- byte_count += len;
- while (num != len) {
- if (sscanf(ptr, "%02x", &i) != 1) return 0;
- i &= 255;
- firmware_image[addr + extended_addr + num] = i;
- firmware_mask[addr + extended_addr + num] = 1;
- ptr += 2;
- sum += i;
- (num)++;
- if (num >= 256) return 0;
- }
- if (!sscanf(ptr, "%02x", &cksum)) return 0;
- if (((sum & 255) + (cksum & 255)) & 255) return 0; /* checksum error */
- return 1;
- }
- int ihex_bytes_within_range(int begin, int end)
- {
- int i;
- if (begin < 0 || begin >= MAX_MEMORY_SIZE ||
- end < 0 || end >= MAX_MEMORY_SIZE) {
- return 0;
- }
- for (i=begin; i<=end; i++) {
- if (firmware_mask[i]) return 1;
- }
- return 0;
- }
- void ihex_get_data(int addr, int len, unsigned char *bytes)
- {
- int i;
- if (addr < 0 || len < 0 || addr + len >= MAX_MEMORY_SIZE) {
- for (i=0; i<len; i++) {
- bytes[i] = 255;
- }
- return;
- }
- for (i=0; i<len; i++) {
- if (firmware_mask[addr]) {
- bytes[i] = firmware_image[addr];
- } else {
- bytes[i] = 255;
- }
- addr++;
- }
- }
- int memory_is_blank(int addr, int block_size)
- {
- if (addr < 0 || addr > MAX_MEMORY_SIZE) return 1;
- while (block_size && addr < MAX_MEMORY_SIZE) {
- if (firmware_mask[addr] && firmware_image[addr] != 255) return 0;
- addr++;
- block_size--;
- }
- return 1;
- }
- /****************************************************************/
- /* */
- /* Misc Functions */
- /* */
- /****************************************************************/
- int printf_verbose(const char *format, ...)
- {
- va_list ap;
- int r;
- va_start(ap, format);
- if (verbose) {
- r = vprintf(format, ap);
- fflush(stdout);
- return r;
- }
- return 0;
- }
- void delay(double seconds)
- {
- #ifdef WIN32
- Sleep(seconds * 1000.0);
- #else
- usleep(seconds * 1000000.0);
- #endif
- }
- void die(const char *str, ...)
- {
- va_list ap;
- va_start(ap, str);
- vfprintf(stderr, str, ap);
- fprintf(stderr, "\n");
- exit(1);
- }
- #if defined(WIN32)
- #define strcasecmp stricmp
- #endif
- static const struct {
- const char *name;
- int code_size;
- int block_size;
- } MCUs[] = {
- {"at90usb162", 15872, 128},
- {"atmega32u4", 32256, 128},
- {"at90usb646", 64512, 256},
- {"at90usb1286", 130048, 256},
- #if defined(USE_LIBUSB) || defined(USE_APPLE_IOKIT) || defined(USE_WIN32)
- {"mkl26z64", 63488, 512},
- {"mk20dx128", 131072, 1024},
- {"mk20dx256", 262144, 1024},
- {"mk66fx1m0", 1048576, 1024},
- {"mk64fx512", 524288, 1024},
- // Add duplicates that match friendly Teensy Names
- // Match board names in boards.txt
- {"TEENSY2", 32256, 128},
- {"TEENSY2PP", 130048, 256},
- {"TEENSYLC", 63488, 512},
- {"TEENSY30", 131072, 1024},
- {"TEENSY31", 262144, 1024},
- {"TEENSY35", 524288, 1024},
- {"TEENSY36", 1048576, 1024},
- #endif
- {NULL, 0, 0},
- };
- void list_mcus()
- {
- int i;
- printf("Supported MCUs are:\n");
- for(i=0; MCUs[i].name != NULL; i++)
- printf(" - %s\n", MCUs[i].name);
- exit(1);
- }
- void read_mcu(char *name)
- {
- int i;
- if(name == NULL) {
- fprintf(stderr, "No MCU specified.\n");
- list_mcus();
- }
- for(i=0; MCUs[i].name != NULL; i++) {
- if(strcasecmp(name, MCUs[i].name) == 0) {
- code_size = MCUs[i].code_size;
- block_size = MCUs[i].block_size;
- return;
- }
- }
- fprintf(stderr, "Unknown MCU type \"%s\"\n", name);
- list_mcus();
- }
- void parse_flag(char *arg)
- {
- int i;
- for(i=1; arg[i]; i++) {
- switch(arg[i]) {
- case 'w': wait_for_device_to_appear = 1; break;
- case 'r': hard_reboot_device = 1; break;
- case 's': soft_reboot_device = 1; break;
- case 'n': reboot_after_programming = 0; break;
- case 'v': verbose = 1; break;
- case 'b': boot_only = 1; break;
- default:
- fprintf(stderr, "Unknown flag '%c'\n\n", arg[i]);
- usage(NULL);
- }
- }
- }
- void parse_options(int argc, char **argv)
- {
- int i;
- char *arg;
- for (i=1; i<argc; i++) {
- arg = argv[i];
- //backward compatibility with previous versions.
- if(strncmp(arg, "-mmcu=", 6) == 0) {
- read_mcu(strchr(arg, '=') + 1);
- }
- else if(arg[0] == '-') {
- if(arg[1] == '-') {
- char *name = &arg[2];
- char *val = strchr(name, '=');
- if(val == NULL) {
- //value must be the next string.
- val = argv[++i];
- }
- else {
- //we found an =, so split the string at it.
- *val = '\0';
- val = &val[1];
- }
- if(strcasecmp(name, "help") == 0) usage(NULL);
- else if(strcasecmp(name, "mcu") == 0) read_mcu(val);
- else if(strcasecmp(name, "list-mcus") == 0) list_mcus();
- else {
- fprintf(stderr, "Unknown option \"%s\"\n\n", arg);
- usage(NULL);
- }
- }
- else parse_flag(arg);
- }
- else filename = arg;
- }
- }
- void boot(unsigned char *buf, int write_size)
- {
- printf_verbose("Booting\n");
- memset(buf, 0, write_size);
- buf[0] = 0xFF;
- buf[1] = 0xFF;
- buf[2] = 0xFF;
- teensy_write(buf, write_size, 0.5);
- }
|