changeset 129:0bad1499ec19

Adding teensy-loader-cli so it's not required. - This is a patched version to work with Teensy 3.1 (current version on the website doesn't work) - "Should" work with OS's other than Linux, but hasn't been tested
author Jacob Alexander <haata@kiibohd.com>
date Sat, 12 Apr 2014 20:52:32 -0700
parents f10966b3ea8a
children 033c3e01322f
files CMakeLists.txt LoadFile/CMakeLists.txt LoadFile/FindLibUSB.cmake LoadFile/bash LoadFile/load LoadFile/teensy_loader_cli.c arm.cmake setup.cmake
diffstat 8 files changed, 1249 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Wed Apr 09 21:06:57 2014 -0700
+++ b/CMakeLists.txt	Sat Apr 12 20:52:32 2014 -0700
@@ -25,8 +25,8 @@
 #| "avr"       # Teensy++ 2.0
 #| "arm"       # Teensy   3.0
 #| "arm"       # Teensy   3.1
-#set( COMPILER_FAMILY "arm" )
-set( COMPILER_FAMILY "avr" )
+set( COMPILER_FAMILY "arm" )
+#set( COMPILER_FAMILY "avr" )
 
 message( STATUS "Compiler Family:" )
 message( "${COMPILER_FAMILY}" )
@@ -142,7 +142,8 @@
 
 #| After Changes Size Information
 #| TODO Do lookup on Flash and RAM sizes and do % used
-add_custom_target( SizeAfter ALL ${SIZE} --target=${FORMAT} ${TARGET_HEX} ${TARGET_ELF}
+add_custom_target( SizeAfter ALL
+	COMMAND ${SIZE} --target=${FORMAT} ${TARGET_HEX} ${TARGET_ELF}
 	DEPENDS ${TARGET_ELF}
 	COMMENT "Size after generation\n\tFlash Usage: data (hex)\n\t  RAM Usage: data (elf)"
 )
@@ -150,17 +151,9 @@
 
 
 ###
-# Setup Loader Script
+# Setup Loader Script and Program
 #
 
 #| Provides the user with the correct teensy-loader-cli command for the built .HEX file
-#| teensy-loader-cli must be in the user's path
-if( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" )
-	configure_file( LoadFile/bash load )
-endif()
+configure_file( LoadFile/load load )
 
-#| TODO Windows
-if( ${CMAKE_SYSTEM_NAME} MATCHES "Windows" )
-	configure_file( LoadFile/bash load )
-endif()
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoadFile/CMakeLists.txt	Sat Apr 12 20:52:32 2014 -0700
@@ -0,0 +1,118 @@
+###| CMAKE teensy-loader-cli |###
+#
+# Jacob Alexander 2014
+# Written to replace the pjrc's kludey Makefiles
+#  (that require hand edits for different platforms)
+#
+# Released into the Public Domain
+#
+###
+
+#| Windows / Cygwin Compatibility options
+set( CMAKE_LEGACY_CYGWIN_WIN32 0 )
+set( CMAKE_USE_RELATIVE_PATHS  1 )
+
+
+
+###
+# Project Description
+#
+
+#| Project
+project( teensy-loader-cli )
+
+#| Target Name (output name)
+set( TARGET teensy-loader-cli )
+
+#| General Settings
+cmake_minimum_required( VERSION 2.8 )
+
+
+
+###
+# Source Defines
+#
+
+#| Sources
+set( SRCS
+	teensy_loader_cli.c
+)
+
+
+
+###
+# Platform Setup
+#
+list( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR} ) # Use local find scripts
+
+#| Linux - libusb
+if( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" )
+	# Find libusb (not 1.0)
+	find_package( LibUSB REQUIRED )
+
+	# Defines
+	set( DEFINES -s -DUSE_LIBUSB )
+
+	# Include directories
+	set( INCLUDE_DIRS ${LIBUSB_INCLUDE_DIRS} )
+
+	# Libraries
+	set( LIBS ${LIBUSB_LIBRARIES} )
+
+#| Windows
+elseif( ${CMAKE_SYSTEM_NAME} MATCHES "Windows" )
+	message( AUTHOR_WARNING "Not Tested...")
+
+	# Defines
+	set( DEFINES -s -DUSE_WIN32 )
+
+	# Libraries
+	set( LIBS hid setupapi )
+
+#| Mac OS X
+elseif( ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" )
+	message( AUTHOR_WARNING "Not Tested...")
+
+	# Defines - XXX What is SDK?
+	set( DEFINES -DUSE_APPLE_IOKIT -isysroot ${SDK} -Wl,-syslibroot,${SDK} -framework IOKit -framework CoreFoundation )
+
+#| BSD - NetBSD and OpenBSD
+elseif( ${CMAKE_SYSTEM_NAME} MATCHES "BSD" )
+	message( AUTHOR_WARNING "Not Tested...")
+
+	# Defines
+	set( DEFINES -s -DUSE_UHID )
+endif()
+
+
+
+###
+# Defines
+#
+
+#| Default CFLAGS
+set( CFLAGS -O2 -Wall )
+
+add_definitions( ${CFLAGS} ${DEFINES} )
+
+
+
+###
+# Includes
+#
+
+#| Linux
+include_directories( ${INCLUDE_DIRS} )
+
+
+
+###
+# Build Targets
+#
+
+#| Create the executable
+add_executable( ${TARGET} ${SRCS} )
+
+#| Link executable
+target_link_libraries( ${TARGET} ${LIBS} )
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoadFile/FindLibUSB.cmake	Sat Apr 12 20:52:32 2014 -0700
@@ -0,0 +1,94 @@
+# Attempts to find libusb (not libusb-1.0)
+#
+#  LIBUSB_FOUND - system has libusb
+#  LIBUSB_INCLUDE_DIRS - the libusb include directory
+#  LIBUSB_LIBRARIES - Link these to use libusb
+#  LIBUSB_DEFINITIONS - Compiler switches required for using libusb
+#
+#  Adapted from cmake-modules Google Code project
+#
+#  Copyright (c) 2006 Andreas Schneider <mail@cynapses.org>
+#
+#  (Changes for libusb) Copyright (c) 2014 Jacob Alexander <haata@kiibohd.com>
+#
+# Redistribution and use is allowed according to the terms of the New BSD license.
+#
+# CMake-Modules Project New BSD License
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+#   list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of the CMake-Modules Project nor the names of its
+#   contributors may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+
+if ( LIBUSB_LIBRARIES AND LIBUSB_INCLUDE_DIRS )
+	# in cache already
+	set( LIBUSB_FOUND TRUE )
+else ()
+	find_path( LIBUSB_INCLUDE_DIR
+		NAMES
+			usb.h
+		PATHS
+			/usr/include
+			/usr/local/include
+			/opt/local/include
+			/sw/include
+			/include
+	)
+
+	find_library( LIBUSB_LIBRARY
+		NAMES
+			usb
+		PATHS
+			/usr/lib
+			/usr/local/lib
+			/opt/local/lib
+			/sw/lib
+			/lib
+	)
+
+	set( LIBUSB_INCLUDE_DIRS ${LIBUSB_INCLUDE_DIR} )
+	set( LIBUSB_LIBRARIES ${LIBUSB_LIBRARY} )
+
+	if ( LIBUSB_INCLUDE_DIRS AND LIBUSB_LIBRARIES )
+		 set( LIBUSB_FOUND TRUE )
+	endif ()
+
+	if ( LIBUSB_FOUND )
+		if ( NOT LIBUSB_FIND_QUIETLY )
+			message( STATUS "Found libusb:" )
+			message( STATUS " - Includes: ${LIBUSB_INCLUDE_DIRS}" )
+			message( STATUS " - Libraries: ${LIBUSB_LIBRARIES}" )
+		endif ()
+	else ()
+		if ( LIBUSB_FIND_REQUIRED )
+			message( FATAL_ERROR "Could not find libusb" )
+		endif ()
+	endif ()
+
+	# show the LIBUSB_INCLUDE_DIRS and LIBUSB_LIBRARIES variables only in the advanced view
+	mark_as_advanced( LIBUSB_INCLUDE_DIRS LIBUSB_LIBRARIES )
+
+endif ()
+
--- a/LoadFile/bash	Wed Apr 09 21:06:57 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-#| Loads the hex file onto the teensy
-
-sudo teensy-loader-cli -mmcu=@MCU@ -w @TARGET_HEX@
-
-exit 0
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoadFile/load	Sat Apr 12 20:52:32 2014 -0700
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+#| First check to see teensy-loader-cli has been compiled
+if [ ! -e teensy-loader-cli/teensy-loader-cli ]; then
+	# Compile teensy-loader-cli
+	mkdir -p teensy-loader-cli
+	cd teensy-loader-cli
+	cmake @CMAKE_SOURCE_DIR@/LoadFile
+	make
+fi
+
+#| Loads the hex file onto the teensy
+sudo teensy-loader-cli/teensy-loader-cli -mmcu=@MCU@ -w @TARGET_HEX@
+
+exit 0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoadFile/teensy_loader_cli.c	Sat Apr 12 20:52:32 2014 -0700
@@ -0,0 +1,1009 @@
+/* Teensy Loader, Command Line Interface
+ * Program and Reboot Teensy Board with HalfKay Bootloader
+ * http://www.pjrc.com/teensy/loader_cli.html
+ * Copyright 2008-2010, PJRC.COM, LLC
+ * Modifications 2014, Jacob Alexander <haata@kiibohd.com>
+ *
+ * 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(void)
+{
+	fprintf(stderr, "Usage: teensy_loader_cli -mmcu=<MCU> [-w] [-h] [-n] [-v] <file.hex>\n");
+	fprintf(stderr, "\t-w : Wait for device to appear\n");
+	fprintf(stderr, "\t-r : Use hard reboot if device not online\n");
+	fprintf(stderr, "\t-n : No reboot after programming\n");
+	fprintf(stderr, "\t-v : Verbose output\n");
+#if defined(USE_LIBUSB)
+	fprintf(stderr, "\n<MCU> = atmega32u4 | at90usb162 | at90usb646 | at90usb1286 | mk20dx128 | mk20dx256\n");
+#else
+	fprintf(stderr, "\n<MCU> = atmega32u4 | at90usb162 | at90usb646 | at90usb1286\n");
+#endif
+	fprintf(stderr, "\nFor more information, please visit:\n");
+	fprintf(stderr, "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);
+
+// 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);
+
+// options (from user via command line args)
+int wait_for_device_to_appear = 0;
+int hard_reboot_device = 0;
+int reboot_after_programming = 1;
+int verbose = 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=block_size+2;
+	int first_block=1, waited=0;
+
+	// parse command line arguments
+	parse_options(argc, argv);
+	if (!filename) {
+		fprintf(stderr, "Filename must be specified\n\n");
+		usage();
+	}
+	if (!code_size) {
+		fprintf(stderr, "MCU type must be specified\n\n");
+		usage();
+	}
+	printf_verbose("Teensy Loader, Command Line, Version 2.0, Kiibohd-Mods\n");
+
+	// 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 (!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 (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 >= 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 ? 3.0 : 0.25);
+		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) {
+		printf_verbose("Booting\n");
+		buf[0] = 0xFF;
+		buf[1] = 0xFF;
+		buf[2] = 0xFF;
+		memset(buf + 3, 0, sizeof(buf) - 3);
+		teensy_write(buf, write_size, 0.25);
+	}
+	teensy_close();
+	return 0;
+}
+
+
+
+
+/****************************************************************/
+/*                                                              */
+/*             USB Access - libusb (Linux & FreeBSD)            */
+/*                                                              */
+/****************************************************************/
+
+#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");
+				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", 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
+			r = usb_claim_interface(h, 0);
+			if (r < 0) {
+				usb_close(h);
+				printf_verbose("Unable to claim interface, check USB permissions");
+				continue;
+			}
+			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;
+}
+
+#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[1040];
+	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;
+	if (!win32_teensy_handle) return 0;
+	r = write_usb_device(win32_teensy_handle, buf, len, (int)(timeout * 1000.0));
+	//if (!r) print_win32_err();
+	return r;
+}
+
+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;
+}
+
+#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");
+	}
+}
+
+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;
+	ret = IOHIDDeviceSetReport(iokit_teensy_reference,
+		kIOHIDReportTypeOutput, 0, buf, len);
+	if (ret == kIOReturnSuccess) return 1;
+	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;
+}
+
+#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;
+}
+
+#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 0x40000
+
+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
+
+void parse_options(int argc, char **argv)
+{
+	int i;
+	const char *arg;
+
+	for (i=1; i<argc; i++) {
+		arg = argv[i];
+		//printf("arg: %s\n", arg);
+		if (*arg == '-') {
+			if (strcmp(arg, "-w") == 0) {
+				wait_for_device_to_appear = 1;
+			} else if (strcmp(arg, "-r") == 0) {
+				hard_reboot_device = 1;
+			} else if (strcmp(arg, "-n") == 0) {
+				reboot_after_programming = 0;
+			} else if (strcmp(arg, "-v") == 0) {
+				verbose = 1;
+			} else if (strncmp(arg, "-mmcu=", 6) == 0) {
+				if (strcasecmp(arg+6, "at90usb162") == 0) {
+					code_size = 15872;
+					block_size = 128;
+				} else if (strcasecmp(arg+6, "atmega32u4") == 0) {
+					code_size = 32256;
+					block_size = 128;
+				} else if (strcasecmp(arg+6, "at90usb646") == 0) {
+					code_size = 64512;
+					block_size = 256;
+				} else if (strcasecmp(arg+6, "at90usb1286") == 0) {
+					code_size = 130048;
+					block_size = 256;
+#if defined(USE_LIBUSB)
+				} else if (strcasecmp(arg+6, "mk20dx128") == 0) {
+					code_size = 131072;
+					block_size = 1024;
+				} else if (strcasecmp(arg+6, "mk20dx256") == 0) {
+					code_size = 262144;
+					block_size = 1024;
+#endif
+				} else {
+					die("Unknown MCU type\n");
+				}
+			}
+		} else {
+			filename = argv[i];
+		}
+	}
+}
+
--- a/arm.cmake	Wed Apr 09 21:06:57 2014 -0700
+++ b/arm.cmake	Sat Apr 12 20:52:32 2014 -0700
@@ -35,8 +35,8 @@
 #|
 #| "mk20dx128"        # Teensy   3.0
 #| "mk20dx256"        # Teensy   3.1
-set( CHIP "mk20dx128" )
-#set( CHIP "mk20dx256" )
+#set( CHIP "mk20dx128" )
+set( CHIP "mk20dx256" )
 
 message( STATUS "Chip Selected:" )
 message( "${CHIP}" )
--- a/setup.cmake	Wed Apr 09 21:06:57 2014 -0700
+++ b/setup.cmake	Sat Apr 12 20:52:32 2014 -0700
@@ -20,7 +20,7 @@
 #| Please look at the {Scan,Macro,USB,Debug}/module.txt for information on the modules and how to create new ones
 
 ##| Deals with acquiring the keypress information and turning it into a key index
-set(   ScanModule "SKM67001" )
+set(   ScanModule "ADCTest" )
 
 ##| Provides the mapping functions for DefaultMap and handles any macro processing before sending to the OutputModule
 set(  MacroModule "PartialMap" )
@@ -203,7 +203,6 @@
 execute_process( COMMAND git show -s --format=%ci
 	WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
 	OUTPUT_VARIABLE Git_Date_INFO
-	RESULT_VARIABLE Git_RETURN
 	ERROR_QUIET
 	OUTPUT_STRIP_TRAILING_WHITESPACE
 )
@@ -212,7 +211,6 @@
 execute_process( COMMAND git show -s --format="%cn <%ce>"
 	WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
 	OUTPUT_VARIABLE Git_Commit_Author
-	RESULT_VARIABLE Git_RETURN
 	ERROR_QUIET
 	OUTPUT_STRIP_TRAILING_WHITESPACE
 )
@@ -221,7 +219,6 @@
 execute_process( COMMAND git show -s --format=%H
 	WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
 	OUTPUT_VARIABLE Git_Commit_Revision
-	RESULT_VARIABLE Git_RETURN
 	ERROR_QUIET
 	OUTPUT_STRIP_TRAILING_WHITESPACE
 )
@@ -230,19 +227,19 @@
 execute_process( COMMAND git config --get remote.origin.url
 	WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
 	OUTPUT_VARIABLE Git_Origin_URL
-	RESULT_VARIABLE Git_RETURN
 	ERROR_QUIET
 	OUTPUT_STRIP_TRAILING_WHITESPACE
 )
 
 #| Build Date
 execute_process( COMMAND "date" "+%Y-%m-%d %T %z"
-	OUTPUT_VARIABLE ${RESULT}
+	OUTPUT_VARIABLE Build_Date
+	ERROR_QUIET
 	OUTPUT_STRIP_TRAILING_WHITESPACE
 )
 
 #| Last Commit Date
-set( GitLastCommitDate "${Git_Modified_Flag_INFO}${Git_Branch_INFO} - ${Git_Date_INFO}" )
+set( GitLastCommitDate "${Git_Modified_Status} ${Git_Branch_INFO} - ${Git_Date_INFO}" )
 
 #| Uses CMake variables to include as defines
 #| Primarily for USB configuration