changeset 0:6f3ce6650200 main

Initial repository set up.
author Bob Cook <bob@bobcookdev.com>
date Sat, 17 Apr 2010 11:53:09 -0700
parents
children c9a76157d2f0
files main/jamdefs main/jamfile main/jamrules main/jrules/avr.common.inc main/jrules/avr.unix.inc main/jrules/avr.win.inc main/jrules/hammer.common.inc main/jrules/hammer.unix.inc main/jrules/overo.common.inc main/jrules/overo.unix.inc main/packages/avr/can/can_helpers.cpp main/packages/avr/can/can_helpers.h main/packages/avr/can/can_messages.h main/packages/avr/can/jamfile main/packages/avr/can/mcp2515.cpp main/packages/avr/can/mcp2515.h main/packages/avr/device/adc.cpp main/packages/avr/device/adc.h main/packages/avr/device/hwdefs.h main/packages/avr/device/int_helpers.cpp main/packages/avr/device/int_helpers.h main/packages/avr/device/int_helpers.inl main/packages/avr/device/jamfile main/packages/avr/device/spi.cpp main/packages/avr/device/spi.h main/packages/avr/device/spinwait.cpp main/packages/avr/device/spinwait.h main/packages/avr/device/twi_master.cpp main/packages/avr/device/twi_master.h main/packages/avr/device/twi_slave.h main/packages/avr/device/uart.cpp main/packages/avr/device/uart.h main/packages/avr/jamdefs main/packages/avr/lcd/.DS_Store main/packages/avr/lcd/cfax/cfax.cpp main/packages/avr/lcd/cfax/cfax.h main/packages/avr/lcd/cfax/jamfile main/packages/avr/lcd/jamdefs main/packages/avr/lcd/sfe569/jamfile main/packages/avr/lcd/sfe569/sfe569.cpp main/packages/avr/lcd/sfe569/sfe569.h main/packages/avr/redir/jamfile main/packages/avr/redir/redir.cpp main/packages/avr/redir/redir.h main/packages/avr/sensors/avrcam/avrcam.cpp main/packages/avr/sensors/avrcam/avrcam.h main/packages/avr/sensors/avrcam/jamfile main/packages/avr/sensors/jamdefs main/packages/avr/sensors/sca3000/jamfile main/packages/avr/sensors/sca3000/sca3000.cpp main/packages/avr/sensors/sca3000/sca3000.h main/packages/common/.DS_Store main/packages/common/gps/jamfile main/packages/common/gps/nmea.cpp main/packages/common/gps/nmea.h main/packages/common/jamdefs main/packages/common/sensors/avrcam/avrcam.cpp main/packages/common/sensors/avrcam/avrcam.h main/packages/common/sensors/avrcam/jamfile main/packages/common/sensors/jamdefs main/packages/common/test/assertions.cpp main/packages/common/test/assertions.h main/packages/common/util/bcdpacker.cpp main/packages/common/util/bcdpacker.h main/packages/common/util/cbuffer.h main/packages/common/util/cbuffer.inl main/packages/common/util/fixedpoint.cpp main/packages/common/util/fixedpoint.h main/packages/common/util/fixedpoint.inl main/packages/common/util/jamfile main/packages/common/util/misc.h main/packages/common/util/printutils.cpp main/packages/common/util/printutils.h main/packages/jamdefs main/packages/s3c2410a/cfax_iic/cfax_iic.cpp main/packages/s3c2410a/cfax_iic/cfax_iic.h main/packages/s3c2410a/cfax_iic/jamfile main/packages/s3c2410a/cfax_iic/protocol.h main/packages/s3c2410a/device/gpio.cpp main/packages/s3c2410a/device/gpio.h main/packages/s3c2410a/device/jamfile main/packages/s3c2410a/jamdefs main/packages/vs2005/include/stdint.h
diffstat 83 files changed, 15265 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/jamdefs	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,35 @@
+# -----------------------------------------------------------------------------------------
+#
+#   jamdefs
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#    
+#   Copyright (C) 2007 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /jamdefs" ; }
+
+# -----------------------------------------------------------------------------------------
+
+SubIncludeJamdefs TOP : packages ;
+
+
+# -----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/jamfile	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,38 @@
+# -----------------------------------------------------------------------------------------
+#
+#   jamfile
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#    
+#   Copyright (C) 2010 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /jamfile" ; }
+
+SubDir TOP ;
+
+
+# -----------------------------------------------------------------------------------------
+
+echo "Nothing to build at the top." ;
+
+
+# -----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/jamrules	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,230 @@
+# -----------------------------------------------------------------------------------------
+#
+#   jamrules
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#    
+#   Implements the base jamrules for all projects.
+#
+#   Copyright (C) 2009 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /jamrules" ; }
+
+
+# -----------------------------------------------------------------------------------------
+#   Name some standard files
+#
+
+JAMDEFS = jamdefs ;
+
+
+# -----------------------------------------------------------------------------------------
+#   SubDirHook is called after the built-in SubDir rule executes
+#
+
+rule SubDirHook
+{
+    ### echo "this is SubDirHook: $(1)" ;
+}
+
+SUBDIRRULES += SubDirHook ;
+
+
+# -----------------------------------------------------------------------------------------
+
+rule SubIncludeJamdefs # TOP dir ... : subdir ... ;
+{
+    local subdir ;
+    
+    for subdir in $(>)
+    {
+        local subdir_path = [ FSubDirPath $(<) $(subdir) ] ;
+        include $(JAMDEFS:D=$(subdir_path)) ;
+    }
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule MakePackageNameVar # dir ... ;
+{
+    local pkg_name = ;
+    local dir ;
+    
+    for dir in $(1)
+    {
+        if $(pkg_name)
+        {
+            pkg_name = $(pkg_name).$(dir:L) ;
+        }
+        else
+        {
+            pkg_name = $(dir:L) ;
+        }
+    }
+    
+    if ! $(pkg_name)
+    {
+        exit "MakePackageNameVar: no package path specified" ;
+    }
+    
+    pkg_name = $(pkg_name).pkg ;
+    
+    return $(pkg_name) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule PackageDirFromNameVar # pkgname ;
+{
+    if ! $(1[1]) { exit "*** PackageDirFromNameVar: must have one pkg name" ; }
+    if   $(1[2]) { exit "*** PackageDirFromNameVar: must have one pkg name" ; }
+    if   $(2[1]) { exit "*** PackageDirFromNameVar: must have one pkg name" ; }
+    
+    return $($(1)) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule DefinePackages # TOP dir ... : pkg ... ;
+{
+    local parent_dir = [ FSubDirPath $(1) ] ;
+    local pkg ;
+    
+    for pkg in $(2)
+    {
+        local pkg_name = [ MakePackageNameVar $(1[2-]) $(pkg) ] ;
+        local pkg_dir  = [ FDirName $(parent_dir) $(pkg) ] ;
+        $(pkg_name) = $(pkg_dir) ;
+    }
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule PackageSources # src ... ;
+{
+    local src ;
+    
+    for src in $(1)
+    {
+        PKG_SOURCES += [ FSubDirPath TOP $(SUBDIR_TOKENS) $(src) ] ;
+    }
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule IncludePackage # pkg ;
+{
+    if ! $(1[1]) { exit "*** IncludePackage: must have one pkg name" ; }
+    if   $(1[2]) { exit "*** IncludePackage: must have one pkg name" ; }
+    
+    # save some vars overwritten by the include/SubDir rules
+    
+    local sv_SUBDIR_UP     = $(SUBDIR_UP) ;
+    local sv_SUBDIR_DOWN   = $(SUBDIR_DOWN) ;
+    local sv_SUBDIR_ROOT   = $(SUBDIR_ROOT) ;
+    local sv_SUBDIR_TOKENS = $(SUBDIR_TOKENS) ;
+    local sv_SUBDIR        = $(SUBDIR) ;
+    local sv_SUBDIRHDRS    = $(SUBDIRHDRS) ;
+    local sv_SEARCH_SOURCE = $(SEARCH_SOURCE) ;
+    local sv_LOCATE_SOURCE = $(LOCATE_SOURCE) ;
+    local sv_LOCATE_TARGET = $(LOCATE_TARGET) ;
+    local sv_SOURCE_GRIST  = $(SOURCE_GRIST) ;
+    local sv_SUBDIRRESET   = $(SUBDIRRESET) ;
+    local sv_SUBDIRRULES   = $(SUBDIRRULES) ;
+
+    # include the specified jamfile
+    
+    local pkgdir = [ PackageDirFromNameVar $(1) ] ;    
+    include $(JAMFILE:D=$(pkgdir)) ;
+
+    # restore the saved vars
+    
+    SUBDIR_UP     = $(sv_SUBDIR_UP) ;
+    SUBDIR_DOWN   = $(sv_SUBDIR_DOWN) ;
+    SUBDIR_ROOT   = $(sv_SUBDIR_ROOT) ;
+    SUBDIR_TOKENS = $(sv_SUBDIR_TOKENS) ;
+    SUBDIR        = $(sv_SUBDIR) ;
+    SUBDIRHDRS    = $(sv_SUBDIRHDRS) ;
+    SEARCH_SOURCE = $(sv_SEARCH_SOURCE) ;
+    LOCATE_SOURCE = $(sv_LOCATE_SOURCE) ;
+    LOCATE_TARGET = $(sv_LOCATE_TARGET) ;
+    SOURCE_GRIST  = $(sv_SOURCE_GRIST) ;
+    SUBDIRRESET   = $(sv_SUBDIRRESET) ;
+    SUBDIRRULES   = $(sv_SUBDIRRULES) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+if $(NT)
+{
+    # --- AVR (8-bit) support
+    
+    local avr_common_incfile = [ FSubDirPath TOP jrules avr.common.inc ] ;
+    include $(avr_common_incfile) ;
+
+    local avr_win_incfile = [ FSubDirPath TOP jrules avr.win.inc ] ;
+    include $(avr_win_incfile) ;
+}
+else if $(UNIX)
+{
+    # --- AVR (8-bit) support
+    
+    local avr_common_incfile = [ FSubDirPath TOP jrules avr.common.inc ] ;
+    include $(avr_common_incfile) ;
+
+    local avr_unix_incfile = [ FSubDirPath TOP jrules avr.unix.inc ] ;
+    include $(avr_unix_incfile) ;
+
+    # --- HAMMER support
+
+    local hammer_common_incfile = [ FSubDirPath TOP jrules hammer.common.inc ] ;
+    include $(hammer_common_incfile) ;
+
+    local hammer_unix_incfile = [ FSubDirPath TOP jrules hammer.unix.inc ] ;
+    include $(hammer_unix_incfile) ;
+
+    # --- OVERO support
+    
+    local overo_common_incfile = [ FSubDirPath TOP jrules overo.common.inc ] ;
+    include $(overo_common_incfile) ;
+
+    local overo_unix_incfile = [ FSubDirPath TOP jrules overo.unix.inc ] ;
+    include $(overo_unix_incfile) ;
+}
+else
+{
+    exit "*** jamrules: unsupported platform" ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+SubIncludeJamdefs : TOP ;
+
+
+# -----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/jrules/avr.common.inc	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,308 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr.common.inc
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#    
+#   Implements the base jamrules for AVR (8-bit) projects.
+#
+#   Copyright (C) 2010 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /jrules/avr.common.inc" ; }
+
+
+# -----------------------------------------------------------------------------------------
+
+rule avr_executable_with_eeprom # name device : src | lib | pkg ... ;
+{
+    if ! $(1[1]) { exit "*** avr_executable: must have a exe name" ; }
+
+    # build the executuable first
+    
+    avr_executable $(1) : $(2) ;
+    
+    # override some built-in variables.
+    
+    local sv_SUFEXE        = $(SUFEXE) ;
+    local sv_LOCATE_TARGET = $(LOCATE_TARGET) ;
+    
+    SUFEXE        = .elf ;
+    LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) bin ] ;
+    
+    # now derive the eeprom hex image from the executable
+    
+    local exename eepromhex ;
+    
+    exename   = [ FAppendSuffix $(1)        : $(SUFEXE)   ] ;
+    eepromhex = [ FAppendSuffix $(1)_eeprom : .hex ] ;
+
+    Depends exe          : $(eepromhex) ;
+    Depends $(eepromhex) : $(exename) ;
+
+    MakeLocate $(eepromhex) : $(LOCATE_TARGET) ;
+    
+    Clean clean : $(eepromhex) ;
+    
+    avr_eepromhex_from_executable $(eepromhex) : $(exename) ;
+    
+    # restore the modified variables.
+    
+    SUFEXE        = $(sv_SUFEXE) ;
+    LOCATE_TARGET = $(sv_LOCATE_TARGET) ;
+}
+
+    
+# -----------------------------------------------------------------------------------------
+
+rule avr_executable # name device : src | lib | pkg ... ;
+{
+    if ! $(1[1]) { exit "*** avr_executable: must have a exe name" ; }
+    if ! $(1[2]) { exit "*** avr_executable: must have a device" ; }
+    if   $(1[3]) { exit "*** avr_executable: must not have extra names" ; }
+    if ! $(2[1]) { exit "*** avr_executable: must have at least one source file" ; }
+    
+    # override some built-in variables.
+    
+    local sv_SUFOBJ        = $(SUFOBJ) ;
+    local sv_SUFLIB        = $(SUFLIB) ;
+    local sv_SUFEXE        = $(SUFEXE) ;
+    local sv_SUFMAP        = $(SUFMAP) ;
+    local sv_SOURCE_GRIST  = $(SOURCE_GRIST) ;
+    local sv_LOCATE_TARGET = $(LOCATE_TARGET) ;
+    
+    SUFOBJ = .o ;
+    SUFLIB = .a ;
+    SUFEXE = .elf ;
+    SUFMAP = .map ;
+
+    # look for headers in the current dir as well as the top dir
+        
+    AVR_INCDIR  = [ FSubDirPath TOP ] ;
+    AVR_INCDIR += $(SUBDIR) ;
+    
+    # validate the device string; we only support specific ones.
+    
+    switch $(1[2]:L)
+    {
+        case atmega8   : AVR_DEVICE = atmega8 ;
+        case atmega88  : AVR_DEVICE = atmega88 ;
+        case atmega16  : AVR_DEVICE = atmega16 ;
+        case atmega168 : AVR_DEVICE = atmega168 ;
+        case atmega128 : AVR_DEVICE = atmega128 ;
+        case *         : exit "*** avr_executable: unsupported device $(1[2])" ;
+    }
+    
+    # sort the input files
+    
+    local f, sources, libs, packages ;
+    
+    sources  = ;
+    libs     = ;
+    packages = ;
+
+    for f in $(2)
+    {
+        switch $(f:S)
+        {
+            case .c   : sources  += $(f) ;
+            case .cpp : sources  += $(f) ;
+            case .S   : sources  += $(f) ;
+            case .lib : libs     += $(f) ;
+            case .pkg : packages += $(f) ;
+            case *    : exit "*** avr_executable: unrecognized suffix $(f:S)" ;
+        }
+    }
+    
+    # set up the required libraries from lib
+
+    local l ;
+        
+    for l in $(libs) 
+    {
+        switch $(l:L)
+        {
+            case printf_min.lib   : AVR_WHICH_PRINTF = MINIMAL ;
+            case printf_float.lib : AVR_WHICH_PRINTF = FLOATING_PT ;
+            case scanf_min.lib    : AVR_WHICH_SCANF  = MINIMAL ;
+            case scanf_float.lib  : AVR_WHICH_SCANF  = FLOATING_PT ;
+            case *                : exit "*** avr_executable: unrecognized lib $(l:L)" ;
+        }
+    }
+    
+    # build the object files from local sources
+    
+    local grist_obj = ;
+    
+    LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) gen ] ;
+    SEARCH_SOURCE = $(SUBDIR) ;
+    SOURCE_GRIST  = $(sv_SOURCE_GRIST) ;
+    avr_objects $(sources) ;
+    
+    grist_obj += [ FGristFiles $(sources:BS=$(SUFOBJ)) ] ;
+    
+    # build the object files from pkg sources
+    
+    for p in $(packages)
+    {
+        PKG_SOURCES = ;
+        IncludePackage $(p) ;
+        
+        LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) gen $(p) ] ;
+        SEARCH_SOURCE = [ PackageDirFromNameVar $(p) ] ;
+        SOURCE_GRIST  = $(sv_SOURCE_GRIST)!$(p) ;
+        avr_objects $(PKG_SOURCES) ;
+        
+        grist_obj += [ FGristFiles $(PKG_SOURCES:BS=$(SUFOBJ)) ] ;
+    }
+    
+    # build the executable target
+    
+    LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) bin ] ;
+    avr_executable_from_objects $(1[1]) : $(grist_obj) ;
+
+    # restore the modified variables.
+    
+    SUFOBJ        = $(sv_SUFOBJ) ;
+    SUFLIB        = $(sv_SUFLIB) ;
+    SUFEXE        = $(sv_SUFEXE) ;
+    SUFMAP        = $(sv_SUFMAP) ;
+    SOURCE_GRIST  = $(sv_SOURCE_GRIST) ;
+    LOCATE_TARGET = $(sv_LOCATE_TARGET) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule avr_executable_from_objects # name : gristed_obj ;
+{
+    local exename linkmap listing texthex eepromhex ;
+    
+    exename   = [ FAppendSuffix $(1) : $(SUFEXE) ] ;
+    linkmap   = [ FAppendSuffix $(1) : $(SUFMAP) ] ;
+    listing   = [ FAppendSuffix $(1) : .listing  ] ;
+    texthex   = [ FAppendSuffix $(1) : .hex      ] ;
+
+    if $(exename) != $(1)
+    {
+        Depends $(1) : $(exename) ;
+        NotFile $(1) ;
+    }
+
+    Depends exe        : $(exename) $(listing) $(texthex) ;
+    Depends $(exename) : $(2) ;
+    Depends $(linkmap) : $(exename) ;
+    Depends $(listing) : $(exename) ;
+    Depends $(texthex) : $(exename) ;
+
+    MakeLocate $(exename) : $(LOCATE_TARGET) ;
+    MakeLocate $(linkmap) : $(LOCATE_TARGET) ;
+    MakeLocate $(listing) : $(LOCATE_TARGET) ;
+    MakeLocate $(texthex) : $(LOCATE_TARGET) ;
+    
+    Clean clean : $(exename) $(linkmap) $(listing) $(texthex) ;
+
+    AVR_LINKMAP on $(exename) = [ FDirName $(LOCATE_TARGET) $(linkmap) ] ;
+    avr_link $(exename) : $(2) ;
+    
+    SEARCH     on $(exename) = $(LOCATE_TARGET) ;
+    AVR_DEVICE on $(exename) = $(AVR_DEVICE) ;
+    AVR_OPTIM  on $(exename) = -Os ;
+
+    if $(AVR_WHICH_PRINTF) = MINIMAL
+    {
+        AVR_EXTRA_LIBS on $(exename) += -Wl,-u,vfprintf -lprintf_min ;
+    }
+    else if $(AVR_WHICH_PRINTF) = FLOATING_PT
+    {
+        AVR_EXTRA_LIBS on $(exename) += -Wl,-u,vfprintf -lprintf_flt ;
+        AVR_EXTRA_LIBS on $(exename) += -lm ;
+    }
+
+    if $(AVR_WHICH_SCANF) = MINIMAL
+    {
+        AVR_EXTRA_LIBS on $(exename) += -Wl,-u,vfscanf -lscanf_min ;
+    }
+    else if $(AVR_WHICH_SCANF) = FLOATING_PT
+    {
+        AVR_EXTRA_LIBS on $(exename) += -Wl,-u,vfscanf -lscanf_flt ;
+        AVR_EXTRA_LIBS on $(exename) += -lm ;
+    }
+    
+    avr_list_from_executable    $(listing) : $(exename) ;
+    avr_texthex_from_executable $(texthex) : $(exename) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule avr_objects # src ;
+{
+    local s ;
+    
+    for s in $(1)
+    {
+        local o = [ FGristFiles $(s:BS=$(SUFOBJ)) ] ;
+        avr_object $(o) : $(s) ;
+        Depends obj : $(o) ;
+    }
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule avr_object # obj : src ;
+{
+    Clean clean : $(1) ;
+
+    MakeLocate $(1) : $(LOCATE_TARGET) ;
+    SEARCH on $(2) = $(SEARCH_SOURCE) ;
+
+    HDRS on $(1) = $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ;
+    AVR_INCDIR on $(1) = $(SEARCH_SOURCE) $(AVR_INCDIR) ;
+
+    local WINAVR_INCDIR ;
+    WINAVR_INCDIR  = c:\\WinAVR-20070525\\avr\\include ;
+    WINAVR_INCDIR += c:\\WinAVR-20070525\\lib\\gcc\\avr\\3.4.6\\include ;
+
+    HDRRULE on $(2) = HdrRule ;
+    HDRSCAN on $(2) = $(HDRPATTERN) ;
+    HDRSEARCH on $(2) = $(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(AVR_INCDIR) $(WINAVR_INCDIR) ;
+
+    HDRGRIST on $(2) = $(HDRGRIST) ;
+
+    DEFINES on $(1) += $(DEFINES) ;
+    
+    AVR_DEVICE on $(1) = $(AVR_DEVICE) ;
+
+    switch $(2:S)
+    {
+        case .c   : avr_cc  $(1) : $(2) ;
+        case .cpp : avr_c++ $(1) : $(2) ;
+        case .S   : avr_as  $(1) : $(2) ;
+        case *    : exit "*** avr_object: unrecognized suffix $(2:S)" ;
+    }
+    
+    Depends $(1) : $(2) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/jrules/avr.unix.inc	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,148 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr.unix.inc
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Implements the jamrules actions for AVR (8-bit) projects building on generic Unix-ish
+#   platforms.
+#
+#   Copyright (C) 2010 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /jrules.avr.unix.inc" ; }
+
+
+# -----------------------------------------------------------------------------------------
+# ----- avr (8-bit) support ---------------------------------------------------------------
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_as
+{
+    echo $(2)
+    avr-gcc -mmcu=$(AVR_DEVICE) -c -o $(1) -I$(AVR_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_cc
+{
+    echo $(2)
+    avr-gcc -mmcu=$(AVR_DEVICE) -Wall -Os -mcall-prologues -c -o $(1) -I$(AVR_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_c++
+{
+    echo $(2)
+    avr-gcc -mmcu=$(AVR_DEVICE) -Wall -Os -mcall-prologues -c -o $(1) -I$(AVR_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_link
+{
+    echo $(1)
+    avr-gcc -g -Wall $(AVR_OPTIM) -mmcu=$(AVR_DEVICE) -o $(1) -L$(AVR_LIBDIR) -l$(AVR_LIBS) $(AVR_EXTRA_LIBS) -Wl,-Map,$(AVR_LINKMAP) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_list_from_executable
+{
+    echo $(1)
+    avr-objdump -h -S $(2) > $(1)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_texthex_from_executable
+{
+    echo $(1)
+    avr-objcopy -j .text -j .data -O ihex $(2) $(1)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_eepromhex_from_executable
+{
+    echo $(1)
+    avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex $(2) $(1)
+}
+
+
+# -----------------------------------------------------------------------------------------
+# ----- hammer (samsung s3c2410a arm920t) support -----------------------------------------
+
+HAMMER_TOOLS_PATH = "/home/bob/software/hammer/buildroot-2009.05/build_arm/staging_dir" ;
+
+# -----------------------------------------------------------------------------------------
+
+actions hammer_as
+{
+    echo $(2)
+    $(HAMMER_TOOLS_PATH)/usr/bin/arm-linux-uclibc-gcc -c -o $(1) -I$(HAMMER_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions hammer_cc
+{
+    echo $(2)
+    $(HAMMER_TOOLS_PATH)/usr/bin/arm-linux-uclibc-gcc -Wall $(HAMMER_OPTIM) -c -o $(1) -I$(HAMMER_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions hammer_c++
+{
+    echo $(2)
+    $(HAMMER_TOOLS_PATH)/usr/bin/arm-linux-uclibc-g++ -Wall $(HAMMER_OPTIM) -c -o $(1) -I$(HAMMER_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+# avr-gcc -g -Wall $(AVR_OPTIM) -mmcu=$(AVR_DEVICE) -o $(1) -L$(AVR_LIBDIR) -l$(AVR_LIBS) $(AVR_EXTRA_LIBS) -Wl,-Map,$(AVR_LINKMAP) $(2)
+
+actions hammer_link
+{
+    echo $(1)
+    $(HAMMER_TOOLS_PATH)/usr/bin/arm-linux-uclibc-g++ -o $(1) -L$(HAMMER_LIBDIR) -l$(HAMMER_LIBS) -Wl,-Map,$(HAMMER_LINKMAP) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions hammer_list_from_executable
+{
+    echo $(1)
+    $(HAMMER_TOOLS_PATH)/usr/bin/arm-linux-uclibc-objdump -h -S $(2) > $(1)
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/jrules/avr.win.inc	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,124 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr.win.inc
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Implements the jamrules actions for AVR (8-bit) projects for the Windows platform.
+#
+#   Copyright (C) 2010 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /jrules.avr.win.inc" ; }
+
+
+JAM_WINAVR_TOOLS ?= "C:\\WinAVR-20090313" ;
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_as
+{
+    set PATH=$(JAM_WINAVR_TOOLS)\BIN;$(JAM_WINAVR_TOOLS)\UTILS\BIN
+    set AVR_DEV_ENV=$(JAM_WINAVR_TOOLS)
+    set INCLUDE=
+    set LIB=
+    echo $(2)
+    avr-gcc -mmcu=$(AVR_DEVICE) -c -o $(1) -I$(AVR_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_cc
+{
+    set PATH=$(JAM_WINAVR_TOOLS)\BIN;$(JAM_WINAVR_TOOLS)\UTILS\BIN
+    set AVR_DEV_ENV=$(JAM_WINAVR_TOOLS)
+    set INCLUDE=
+    set LIB=
+    echo $(2)
+    avr-gcc -mmcu=$(AVR_DEVICE) -Wall -Os -mcall-prologues -c -o $(1) -I$(AVR_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_c++
+{
+    set PATH=$(JAM_WINAVR_TOOLS)\BIN;$(JAM_WINAVR_TOOLS)\UTILS\BIN
+    set AVR_DEV_ENV=$(JAM_WINAVR_TOOLS)
+    set INCLUDE=
+    set LIB=
+    echo $(2)
+    avr-gcc -mmcu=$(AVR_DEVICE) -Wall -Os -mcall-prologues -c -o $(1) -I$(AVR_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_link
+{
+    set PATH=$(JAM_WINAVR_TOOLS)\BIN;$(JAM_WINAVR_TOOLS)\UTILS\BIN
+    set AVR_DEV_ENV=$(JAM_WINAVR_TOOLS)
+    set INCLUDE=
+    set LIB=
+    echo $(1)
+    avr-gcc -g -Wall $(AVR_OPTIM) -mmcu=$(AVR_DEVICE) -o $(1) -L$(AVR_LIBDIR) -l$(AVR_LIBS) $(AVR_EXTRA_LIBS) -Wl,-Map,$(AVR_LINKMAP) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_list_from_executable
+{
+    set PATH=$(JAM_WINAVR_TOOLS)\BIN;$(JAM_WINAVR_TOOLS)\UTILS\BIN
+    set AVR_DEV_ENV=$(JAM_WINAVR_TOOLS)
+    set INCLUDE=
+    set LIB=
+    echo $(1)
+    avr-objdump -h -S $(2) > $(1)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_texthex_from_executable
+{
+    set PATH=$(JAM_WINAVR_TOOLS)\BIN;$(JAM_WINAVR_TOOLS)\UTILS\BIN
+    set AVR_DEV_ENV=$(JAM_WINAVR_TOOLS)
+    set INCLUDE=
+    set LIB=
+    echo $(1)
+    avr-objcopy -j .text -j .data -O ihex $(2) $(1)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions avr_eepromhex_from_executable
+{
+    set PATH=$(JAM_WINAVR_TOOLS)\BIN;$(JAM_WINAVR_TOOLS)\UTILS\BIN
+    set AVR_DEV_ENV=$(JAM_WINAVR_TOOLS)
+    set INCLUDE=
+    set LIB=
+    echo $(1)
+    avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex $(2) $(1)
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/jrules/hammer.common.inc	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,218 @@
+# -----------------------------------------------------------------------------------------
+#
+#   jrules/hammer.common.inc
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#    
+#   Implements the base jamrules for HAMMER (Samsung S3C2410A ARM920T) projects that
+#   are common to all compilation platforms.
+#
+#   Copyright (C) 2010 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /jrules/hammer.common.inc" ; }
+
+
+# -----------------------------------------------------------------------------------------
+
+rule hammer_executable # name : src | lib | pkg ... ;
+{
+    if ! $(1[1]) { exit "*** hammer_executable: must have a exe name" ; }
+    if   $(1[2]) { exit "*** hammer_executable: must not have extra names" ; }
+    if ! $(2[1]) { exit "*** hammer_executable: must have at least one source file" ; }
+    
+    # override some built-in variables.
+    
+    local sv_SUFOBJ        = $(SUFOBJ) ;
+    local sv_SUFLIB        = $(SUFLIB) ;
+    local sv_SUFEXE        = $(SUFEXE) ;
+    local sv_SUFMAP        = $(SUFMAP) ;
+    local sv_SOURCE_GRIST  = $(SOURCE_GRIST) ;
+    local sv_LOCATE_TARGET = $(LOCATE_TARGET) ;
+    
+    SUFOBJ = .o ;
+    SUFLIB = .a ;
+    SUFEXE = ;
+    SUFMAP = .map ;
+
+    # look for headers in the current dir as well as the top dir
+        
+    HAMMER_INCDIR  = [ FSubDirPath TOP ] ;
+    HAMMER_INCDIR += $(SUBDIR) ;
+    
+    # sort the input files
+    
+    local f, sources, libs, packages ;
+    
+    sources  = ;
+    libs     = ;
+    packages = ;
+
+    for f in $(2)
+    {
+        switch $(f:S)
+        {
+            case .c   : sources  += $(f) ;
+            case .cpp : sources  += $(f) ;
+            case .S   : sources  += $(f) ;
+            case .lib : libs     += $(f) ;
+            case .pkg : packages += $(f) ;
+            case *    : exit "*** hammer_executable: unrecognized suffix $(f:S)" ;
+        }
+    }
+    
+    # set up the required libraries from libs
+
+    local l ;
+        
+    for l in $(libs) 
+    {
+        HAMMER_LIBS += $(l:B) ;
+    }
+    
+    # build the object files from local sources
+    
+    local grist_obj = ;
+    
+    LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) gen ] ;
+    SEARCH_SOURCE = $(SUBDIR) ;
+    SOURCE_GRIST  = $(sv_SOURCE_GRIST) ;
+    hammer_objects $(sources) ;
+    
+    grist_obj += [ FGristFiles $(sources:BS=$(SUFOBJ)) ] ;
+    
+    # build the object files from pkg sources
+    
+    for p in $(packages)
+    {
+        PKG_SOURCES = ;
+        IncludePackage $(p) ;
+        
+        LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) gen $(p) ] ;
+        SEARCH_SOURCE = [ PackageDirFromNameVar $(p) ] ;
+        SOURCE_GRIST  = $(sv_SOURCE_GRIST)!$(p) ;
+        hammer_objects $(PKG_SOURCES) ;
+        
+        grist_obj += [ FGristFiles $(PKG_SOURCES:BS=$(SUFOBJ)) ] ;
+    }
+    
+    # build the executable target
+    
+    LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) bin ] ;
+    hammer_executable_from_objects $(1[1]) : $(grist_obj) ;
+
+    # restore the modified variables.
+    
+    SUFOBJ        = $(sv_SUFOBJ) ;
+    SUFLIB        = $(sv_SUFLIB) ;
+    SUFEXE        = $(sv_SUFEXE) ;
+    SUFMAP        = $(sv_SUFMAP) ;
+    SOURCE_GRIST  = $(sv_SOURCE_GRIST) ;
+    LOCATE_TARGET = $(sv_LOCATE_TARGET) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule hammer_executable_from_objects # name : gristed_obj ;
+{
+    local exename linkmap listing ;
+    
+    exename   = [ FAppendSuffix $(1) : $(SUFEXE) ] ;
+    linkmap   = [ FAppendSuffix $(1) : $(SUFMAP) ] ;
+    listing   = [ FAppendSuffix $(1) : .listing  ] ;
+
+    if $(exename) != $(1)
+    {
+        Depends $(1) : $(exename) ;
+        NotFile $(1) ;
+    }
+
+    Depends exe        : $(exename) $(listing) $(texthex) ;
+    Depends $(exename) : $(2) ;
+    Depends $(linkmap) : $(exename) ;
+    Depends $(listing) : $(exename) ;
+
+    MakeLocate $(exename) : $(LOCATE_TARGET) ;
+    MakeLocate $(linkmap) : $(LOCATE_TARGET) ;
+    MakeLocate $(listing) : $(LOCATE_TARGET) ;
+    
+    Clean clean : $(exename) $(linkmap) $(listing) ;
+
+    HAMMER_LINKMAP on $(exename) = [ FDirName $(LOCATE_TARGET) $(linkmap) ] ;
+    hammer_link $(exename) : $(2) ;
+    
+    SEARCH       on $(exename) = $(LOCATE_TARGET) ;
+    HAMMER_OPTIM on $(exename) = -Os ;
+
+    hammer_list_from_executable $(listing) : $(exename) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule hammer_objects # src ;
+{
+    local s ;
+    
+    for s in $(1)
+    {
+        local o = [ FGristFiles $(s:BS=$(SUFOBJ)) ] ;
+        hammer_object $(o) : $(s) ;
+        Depends obj : $(o) ;
+    }
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule hammer_object # obj : src ;
+{
+    Clean clean : $(1) ;
+
+    MakeLocate $(1) : $(LOCATE_TARGET) ;
+    SEARCH on $(2) = $(SEARCH_SOURCE) ;
+
+    HDRS on $(1) = $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ;
+    HAMMER_INCDIR on $(1) = $(SEARCH_SOURCE) $(HAMMER_INCDIR) ;
+
+    HDRRULE on $(2) = HdrRule ;
+    HDRSCAN on $(2) = $(HDRPATTERN) ;
+    HDRSEARCH on $(2) = $(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(HAMMER_INCDIR) ;
+    HDRSEARCH on $(2) += "$(HAMMER_TOOLS_PATH)/usr/lib/gcc/arm-linux-uclibc/4.2.1" ;
+
+    HDRGRIST on $(2) = $(HDRGRIST) ;
+
+    DEFINES on $(1) += $(DEFINES) ;
+    
+    switch $(2:S)
+    {
+        case .c   : hammer_cc  $(1) : $(2) ;
+        case .cpp : hammer_c++ $(1) : $(2) ;
+        case .S   : hammer_as  $(1) : $(2) ;
+        case *    : exit "*** hammer_object: unrecognized suffix $(2:S)" ;
+    }
+    
+    Depends $(1) : $(2) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/jrules/hammer.unix.inc	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,79 @@
+# -----------------------------------------------------------------------------------------
+#
+#   jrules/hammer.unix.inc
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#    
+#   Implements the jamrules actions for HAMMER (Samsung S3C2410A ARM920T) projects for
+#   building on Unix-ish platforms.
+#
+#   Copyright (C) 2010 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /jrules/hammer.unix.inc" ; }
+
+
+HAMMER_TOOLS_PATH ?= "/home/bob/software/hammer/buildroot-2009.05/build_arm/staging_dir" ;
+
+# -----------------------------------------------------------------------------------------
+
+actions hammer_as
+{
+    echo $(2)
+    $(HAMMER_TOOLS_PATH)/usr/bin/arm-linux-uclibc-gcc -c -o $(1) -I$(HAMMER_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions hammer_cc
+{
+    echo $(2)
+    $(HAMMER_TOOLS_PATH)/usr/bin/arm-linux-uclibc-gcc -Wall $(HAMMER_OPTIM) -c -o $(1) -I$(HAMMER_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions hammer_c++
+{
+    echo $(2)
+    $(HAMMER_TOOLS_PATH)/usr/bin/arm-linux-uclibc-g++ -Wall $(HAMMER_OPTIM) -c -o $(1) -I$(HAMMER_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+# avr-gcc -g -Wall $(AVR_OPTIM) -mmcu=$(AVR_DEVICE) -o $(1) -L$(AVR_LIBDIR) -l$(AVR_LIBS) $(AVR_EXTRA_LIBS) -Wl,-Map,$(AVR_LINKMAP) $(2)
+
+actions hammer_link
+{
+    echo $(1)
+    $(HAMMER_TOOLS_PATH)/usr/bin/arm-linux-uclibc-g++ -o $(1) -L$(HAMMER_LIBDIR) -l$(HAMMER_LIBS) -Wl,-Map,$(HAMMER_LINKMAP) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions hammer_list_from_executable
+{
+    echo $(1)
+    $(HAMMER_TOOLS_PATH)/usr/bin/arm-linux-uclibc-objdump -h -S $(2) > $(1)
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/jrules/overo.common.inc	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,218 @@
+# -----------------------------------------------------------------------------------------
+#
+#   jrules/overo.common.inc
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#    
+#   Implements the base jamrules for Gumstix Overo (OMAP 3503 w/ARM Cortex-A8) projects
+#   common to all compilation platforms.
+#
+#   Copyright (C) 2010 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /jrules/overo.common.inc" ; }
+
+
+# -----------------------------------------------------------------------------------------
+
+rule overo_executable # name : src | lib | pkg ... ;
+{
+    if ! $(1[1]) { exit "*** overo_executable: must have a exe name" ; }
+    if   $(1[2]) { exit "*** overo_executable: must not have extra names" ; }
+    if ! $(2[1]) { exit "*** overo_executable: must have at least one source file" ; }
+    
+    # override some built-in variables.
+    
+    local sv_SUFOBJ        = $(SUFOBJ) ;
+    local sv_SUFLIB        = $(SUFLIB) ;
+    local sv_SUFEXE        = $(SUFEXE) ;
+    local sv_SUFMAP        = $(SUFMAP) ;
+    local sv_SOURCE_GRIST  = $(SOURCE_GRIST) ;
+    local sv_LOCATE_TARGET = $(LOCATE_TARGET) ;
+    
+    SUFOBJ = .o ;
+    SUFLIB = .a ;
+    SUFEXE = ;
+    SUFMAP = .map ;
+
+    # look for headers in the current dir as well as the top dir
+        
+    OVERO_INCDIR  = [ FSubDirPath TOP ] ;
+    OVERO_INCDIR += $(SUBDIR) ;
+    
+    # sort the input files
+    
+    local f, sources, libs, packages ;
+    
+    sources  = ;
+    libs     = ;
+    packages = ;
+
+    for f in $(2)
+    {
+        switch $(f:S)
+        {
+            case .c   : sources  += $(f) ;
+            case .cpp : sources  += $(f) ;
+            case .S   : sources  += $(f) ;
+            case .lib : libs     += $(f) ;
+            case .pkg : packages += $(f) ;
+            case *    : exit "*** overo_executable: unrecognized suffix $(f:S)" ;
+        }
+    }
+    
+    # set up the required libraries from libs
+
+    local l ;
+        
+    for l in $(libs) 
+    {
+        OVERO_LIBS += $(l:B) ;
+    }
+    
+    # build the object files from local sources
+    
+    local grist_obj = ;
+    
+    LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) gen ] ;
+    SEARCH_SOURCE = $(SUBDIR) ;
+    SOURCE_GRIST  = $(sv_SOURCE_GRIST) ;
+    overo_objects $(sources) ;
+    
+    grist_obj += [ FGristFiles $(sources:BS=$(SUFOBJ)) ] ;
+    
+    # build the object files from pkg sources
+    
+    for p in $(packages)
+    {
+        PKG_SOURCES = ;
+        IncludePackage $(p) ;
+        
+        LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) gen $(p) ] ;
+        SEARCH_SOURCE = [ PackageDirFromNameVar $(p) ] ;
+        SOURCE_GRIST  = $(sv_SOURCE_GRIST)!$(p) ;
+        overo_objects $(PKG_SOURCES) ;
+        
+        grist_obj += [ FGristFiles $(PKG_SOURCES:BS=$(SUFOBJ)) ] ;
+    }
+    
+    # build the executable target
+    
+    LOCATE_TARGET = [ FSubDirPath TOP $(SUBDIR_TOKENS) bin ] ;
+    overo_executable_from_objects $(1[1]) : $(grist_obj) ;
+
+    # restore the modified variables.
+    
+    SUFOBJ        = $(sv_SUFOBJ) ;
+    SUFLIB        = $(sv_SUFLIB) ;
+    SUFEXE        = $(sv_SUFEXE) ;
+    SUFMAP        = $(sv_SUFMAP) ;
+    SOURCE_GRIST  = $(sv_SOURCE_GRIST) ;
+    LOCATE_TARGET = $(sv_LOCATE_TARGET) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule overo_executable_from_objects # name : gristed_obj ;
+{
+    local exename linkmap listing ;
+    
+    exename   = [ FAppendSuffix $(1) : $(SUFEXE) ] ;
+    linkmap   = [ FAppendSuffix $(1) : $(SUFMAP) ] ;
+    listing   = [ FAppendSuffix $(1) : .listing  ] ;
+
+    if $(exename) != $(1)
+    {
+        Depends $(1) : $(exename) ;
+        NotFile $(1) ;
+    }
+
+    Depends exe        : $(exename) $(listing) $(texthex) ;
+    Depends $(exename) : $(2) ;
+    Depends $(linkmap) : $(exename) ;
+    Depends $(listing) : $(exename) ;
+
+    MakeLocate $(exename) : $(LOCATE_TARGET) ;
+    MakeLocate $(linkmap) : $(LOCATE_TARGET) ;
+    MakeLocate $(listing) : $(LOCATE_TARGET) ;
+    
+    Clean clean : $(exename) $(linkmap) $(listing) ;
+
+    OVERO_LINKMAP on $(exename) = [ FDirName $(LOCATE_TARGET) $(linkmap) ] ;
+    overo_link $(exename) : $(2) ;
+    
+    SEARCH      on $(exename) = $(LOCATE_TARGET) ;
+    OVERO_OPTIM on $(exename) = -Os ;
+
+    overo_list_from_executable $(listing) : $(exename) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule overo_objects # src ;
+{
+    local s ;
+    
+    for s in $(1)
+    {
+        local o = [ FGristFiles $(s:BS=$(SUFOBJ)) ] ;
+        overo_object $(o) : $(s) ;
+        Depends obj : $(o) ;
+    }
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+rule overo_object # obj : src ;
+{
+    Clean clean : $(1) ;
+
+    MakeLocate $(1) : $(LOCATE_TARGET) ;
+    SEARCH on $(2) = $(SEARCH_SOURCE) ;
+
+    HDRS on $(1) = $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ;
+    OVERO_INCDIR on $(1) = $(SEARCH_SOURCE) $(OVERO_INCDIR) ;
+
+    HDRRULE on $(2) = HdrRule ;
+    HDRSCAN on $(2) = $(HDRPATTERN) ;
+    HDRSEARCH on $(2) = $(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(OVERO_INCDIR) ;
+    HDRSEARCH on $(2) += "$(OVERO_TOOLS_PATH)/usr/lib/gcc/arm-linux-uclibc/4.2.1" ;
+
+    HDRGRIST on $(2) = $(HDRGRIST) ;
+
+    DEFINES on $(1) += $(DEFINES) ;
+    
+    switch $(2:S)
+    {
+        case .c   : overo_cc  $(1) : $(2) ;
+        case .cpp : overo_c++ $(1) : $(2) ;
+        case .S   : overo_as  $(1) : $(2) ;
+        case *    : exit "*** overo_object: unrecognized suffix $(2:S)" ;
+    }
+    
+    Depends $(1) : $(2) ;
+}
+
+
+# -----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/jrules/overo.unix.inc	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,79 @@
+# -----------------------------------------------------------------------------------------
+#
+#   jrules/overo.unix.inc
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#    
+#   Implements the jamrules actions for Gumstix Overo (OMAP 3503 w/ARM Cortex-A8) projects
+#   building on Unix-ish platforms.
+#
+#   Copyright (C) 2010 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /jrules/overo.unix.inc" ; }
+
+
+JAM_OVERO_TOOLS ?= "/opt/local/arm-elf" ;
+
+# -----------------------------------------------------------------------------------------
+
+actions overo_as
+{
+    echo $(2)
+    $(JAM_OVERO_TOOLS)/bin/gcc -c -o $(1) -I$(OVERO_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions overo_cc
+{
+    echo $(2)
+    $(JAM_OVERO_TOOLS)/bin/gcc -Wall $(OVERO_OPTIM) -c -o $(1) -I$(OVERO_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions overo_c++
+{
+    echo $(2)
+    $(JAM_OVERO_TOOLS)/bin/g++ -Wall $(OVERO_OPTIM) -c -o $(1) -I$(OVERO_INCDIR) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions overo_link
+{
+    echo $(1)
+    $(JAM_OVERO_TOOLS)/bin/g++ -o $(1) -L$(OVERO_LIBDIR) -l$(OVERO_LIBS) -Wl,-Map,$(OVERO_LINKMAP) $(2)
+}
+
+
+# -----------------------------------------------------------------------------------------
+
+actions overo_list_from_executable
+{
+    echo $(1)
+    $(JAM_OVERO_TOOLS)/bin/objdump -h -S $(2) > $(1)
+}
+
+# -----------------------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/can/can_helpers.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,94 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/can/can_helpers.cpp
+//
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides utility routines for a Controller Area Network driver.
+//
+//  Copyright (C) 2007 Bob Cook
+//    
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "can_helpers.h"
+
+
+// ----------------------------------------------------------------------------------------
+
+uint32_t can_build_message_id
+    (
+        const uint8_t  node_src,
+        const uint8_t  node_dst,
+        const uint16_t data_type
+    )
+{
+    //--    Build the full "extended" message id in our proprietary format:
+    //
+    //      00000000000000000000000000000000  uint32_t
+    //
+    //      3   2   2   1   1   1   7   3  0
+    //      1   7   3   9   5   1
+    //
+    //          +----+                        source node id (six bits)
+    //                +----+                  destination node id (six bits)
+    //                      +--------------+  message id (sixteen bits)
+    //         +                              unused (one bit)
+
+    uint32_t msg_id;
+
+    msg_id  = static_cast< uint32_t >( node_src & 0x3f ) << 22;
+    msg_id |= static_cast< uint32_t >( node_dst & 0x3f ) << 16;
+    msg_id |= static_cast< uint32_t >( data_type );
+
+    return msg_id;
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+void can_parse_message_id
+    (
+        const uint32_t& message_id,
+        uint8_t*        node_src,
+        uint8_t*        node_dst,
+        uint16_t*       data_type
+    )
+{
+    // decode the full "extended" message id in our proprietary format:
+    //
+    //      00000000000000000000000000000000  uint32_t
+    //
+    //      3   2   2   1   1   1   7   3  0
+    //      1   7   3   9   5   1
+    //
+    //          +----+                        source node id (six bits)
+    //                +----+                  destination node id (six bits)
+    //                      +--------------+  message id (sixteen bits)
+    //         +                              unused (one bit)
+
+    *data_type = static_cast< uint16_t >( message_id );
+    *node_dst  = static_cast< uint8_t >( message_id >> 16 ) & 0x3f;
+    *node_src  = static_cast< uint8_t >( message_id >> 22 ) & 0x3f;
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  end of can_helpers.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/can/can_helpers.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,72 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/can/can_helpers.h
+//
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides utility routines for a Controller Area Network driver.
+//
+//  Copyright (C) 2007 Bob Cook
+//    
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_CAN_CAN_HELPERS_H )
+#define BCDRL_AVR_CAN_CAN_HELPERS_H
+
+
+#include <stdint.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  can_build_message_id
+//
+//      Convert the tuple of a source node identifier, destination node identifier, and a
+//      unique data type identifer into a 29-bit message identifier.
+//
+//      Returns true if successfully sent.
+//
+
+uint32_t can_build_message_id
+    (
+        const uint8_t  node_src,
+        const uint8_t  node_dst,
+        const uint16_t data_type
+    );
+
+
+// ----------------------------------------------------------------------------------------
+//  can_parse_message_id
+//
+//      Decomponse a 29-bit message identifier into the original parts.
+//
+
+void can_parse_message_id
+    (
+        const uint32_t& message_id,
+        uint8_t*        node_src,
+        uint8_t*        node_dst,
+        uint16_t*       data_type
+    );
+
+
+#endif  // #if defined( BCDRL_AVR_CAN_CAN_HELPERS_H )
+// ----------------------------------------------------------------------------------------
+//  end of can_helpers.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/can/can_messages.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,105 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/can/can_messages.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides various definitions for a Controller Area Network driver.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_CAN_CAN_MESSAGES_H )
+#define BCDRL_AVR_CAN_CAN_MESSAGES_H
+
+
+#include <inttypes.h>
+
+#include "packages/common/util/fixedpoint.h"
+
+
+// ----------------------------------------------------------------------------------------
+//  debug_out
+//
+
+const uint8_t can_datatype_debug_out = 0x0001;
+
+
+// ----------------------------------------------------------------------------------------
+//  stdio
+//
+
+const uint8_t can_datatype_stdio = 0x0004;
+
+
+// ----------------------------------------------------------------------------------------
+//  utc_timestamp
+//
+
+const uint8_t can_datatype_utc_timestamp = 0x0005;
+
+typedef struct
+{
+    uint8_t packed_time[ 6 ];
+
+} can_msgdata_utc_timestamp;
+
+
+// ----------------------------------------------------------------------------------------
+//  latitude
+//
+
+const uint8_t can_datatype_latitude = 0x0006;
+
+typedef struct
+{
+    int16_t      degrees;
+    fixed16dot16 minutes;
+
+} can_msgdata_latitude;
+
+
+// ----------------------------------------------------------------------------------------
+//  longitude
+//
+
+const uint8_t can_datatype_longitude = 0x0007;
+
+typedef struct
+{
+    int16_t      degrees;
+    fixed16dot16 minutes;
+
+} can_msgdata_longitude;
+
+
+// ----------------------------------------------------------------------------------------
+//  heatbeat
+//
+
+const uint8_t  can_datatype_heatbeat = 0x0010;
+const uint32_t can_heatbeat_data     = 0x54414542;
+
+
+#endif  // #if !defined( BCDRL_AVR_CAN_CAN_MESSAGES_H )
+// ----------------------------------------------------------------------------------------
+//  end of can_messages.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/can/jamfile	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,41 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr/can/jamfile
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Copyright (C) 2007 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /packages/avr/can/jamfile" ; }
+
+SubDir TOP packages avr can ;
+
+
+# -----------------------------------------------------------------------------------------
+
+PackageSources
+    can_helpers.cpp
+    mcp2515.cpp
+    ;
+    
+# -----------------------------------------------------------------------------------------
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/can/mcp2515.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,1100 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/can/mcp2515.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file implements CAN support using the Microchip MCP2515 via SPI.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "mcp2515.h"
+
+#include <avr/io.h>
+
+#include "packages/avr/device/int_helpers.h"
+#include "packages/avr/device/spi.h"
+#include "packages/avr/device/spinwait.h"
+
+#include "packages/common/util/cbuffer.h"
+
+
+// ----------------------------------------------------------------------------------------
+
+#include "project_defs.h"
+
+#if defined( PRJ_MCP2515_ENABLE_DEBUG )
+
+#include <stdio.h>
+#include <avr/pgmspace.h>
+
+#endif
+
+
+#if defined( PRJ_MCP2515_ENABLE )
+
+
+// ----------------------------------------------------------------------------------------
+
+#if !defined( PRJ_MCP2515_SELECT_DDR )
+#error PRJ_MCP2515_SELECT_DDR is required!
+#endif
+
+#if !defined( PRJ_MCP2515_SELECT_PORT )
+#error PRJ_MCP2515_SELECT_PORT is required!
+#endif
+
+#if !defined( PRJ_MCP2515_SELECT_PIN )
+#error PRJ_MCP2515_SELECT_PIN is required!
+#endif
+
+#if defined( PRJ_MCP2515_USE_HW_RESET )
+
+#if !defined( PRJ_MCP2515_RESET_DDR )
+#error PRJ_MCP2515_RESET_DDR is required!
+#endif
+
+#if !defined( PRJ_MCP2515_RESET_PORT )
+#error PRJ_MCP2515_RESET_PORT is required!
+#endif
+
+#if !defined( PRJ_MCP2515_RESET_PIN )
+#error PRJ_MCP2515_RESET_PIN is required!
+#endif
+
+#endif  // PRJ_MCP2515_USE_HW_RESET
+
+#if defined( PRJ_MCP2515_USE_INTERRUPT_RXTX )
+
+#if !defined( PRJ_MCP2515_RX_BUFFER_SIZE )
+#define PRJ_MCP2515_RX_BUFFER_SIZE 4
+#endif
+
+#if !defined( PRJ_MCP2515_TX_BUFFER_SIZE )
+#define PRJ_MCP2515_TX_BUFFER_SIZE 6
+#endif
+
+#endif  // PRJ_MCP2515_USE_INTERRUPT_RXTX
+
+
+// ----------------------------------------------------------------------------------------
+// MCP2515 command definitions
+
+const uint8_t MCP_COMMAND_WRITE  = 0x02;
+const uint8_t MCP_COMMAND_READ   = 0x03;
+const uint8_t MCP_COMMAND_BITMOD = 0x05;
+
+const uint8_t MCP_COMMAND_LOAD_TX0 = 0x40;
+const uint8_t MCP_COMMAND_LOAD_TX1 = 0x42;
+const uint8_t MCP_COMMAND_LOAD_TX2 = 0x44;
+
+const uint8_t MCP_COMMAND_RTS_TX0 = 0x81;
+const uint8_t MCP_COMMAND_RTS_TX1 = 0x82;
+const uint8_t MCP_COMMAND_RTS_TX2 = 0x84;
+const uint8_t MCP_COMMAND_RTS_ALL = 0x87;
+
+const uint8_t MCP_COMMAND_READ_RX0 = 0x90;
+const uint8_t MCP_COMMAND_READ_RX1 = 0x94;
+
+const uint8_t MCP_COMMAND_READ_STATUS = 0xa0;
+const uint8_t MCP_COMMAND_RX_STATUS   = 0xb0;
+
+const uint8_t MCP_COMMAND_RESET = 0xc0;
+
+
+// ----------------------------------------------------------------------------------------
+// MCP2515 mode definitions
+
+const uint8_t MCP_MODE_NORMAL     = 0x00;
+const uint8_t MCP_MODE_SLEEP      = 0x20;
+const uint8_t MCP_MODE_LOOPBACK   = 0x40;
+const uint8_t MCP_MODE_LISTENONLY = 0x60;
+const uint8_t MCP_MODE_CONFIG     = 0x80;
+const uint8_t MCP_MODE_POWERUP    = 0xE0;
+
+
+// ----------------------------------------------------------------------------------------
+// MCP2515 interrupt enable & flag definitions
+
+const uint8_t MCP_INTERRUPT_MERR = ( 1 << 7 );
+const uint8_t MCP_INTERRUPT_WAKI = ( 1 << 6 );
+const uint8_t MCP_INTERRUPT_ERRI = ( 1 << 5 );
+const uint8_t MCP_INTERRUPT_TX2I = ( 1 << 4 );
+const uint8_t MCP_INTERRUPT_TX1I = ( 1 << 3 );
+const uint8_t MCP_INTERRUPT_TX0I = ( 1 << 2 );
+const uint8_t MCP_INTERRUPT_RX1I = ( 1 << 1 );
+const uint8_t MCP_INTERRUPT_RX0I = ( 1 << 0 );
+
+
+// ----------------------------------------------------------------------------------------
+// MCP2515 register definitions
+
+const uint8_t MCP_REGISTER_RXF0SIDH = 0x00;
+const uint8_t MCP_REGISTER_RXF0SIDL = 0x01;
+const uint8_t MCP_REGISTER_RXF0EID8 = 0x02;
+const uint8_t MCP_REGISTER_RXF0EID0 = 0x03;
+
+const uint8_t MCP_REGISTER_RXF1SIDH = 0x04;
+const uint8_t MCP_REGISTER_RXF1SIDL = 0x05;
+const uint8_t MCP_REGISTER_RXF1EID8 = 0x06;
+const uint8_t MCP_REGISTER_RXF1EID0 = 0x07;
+
+const uint8_t MCP_REGISTER_RXF2SIDH = 0x08;
+const uint8_t MCP_REGISTER_RXF2SIDL = 0x09;
+const uint8_t MCP_REGISTER_RXF2EID8 = 0x0a;
+const uint8_t MCP_REGISTER_RXF2EID0 = 0x0b;
+
+const uint8_t MCP_REGISTER_RXF3SIDH = 0x10;
+const uint8_t MCP_REGISTER_RXF3SIDL = 0x11;
+const uint8_t MCP_REGISTER_RXF3EID8 = 0x12;
+const uint8_t MCP_REGISTER_RXF3EID0 = 0x13;
+
+const uint8_t MCP_REGISTER_RXF4SIDH = 0x14;
+const uint8_t MCP_REGISTER_RXF4SIDL = 0x15;
+const uint8_t MCP_REGISTER_RXF4EID8 = 0x16;
+const uint8_t MCP_REGISTER_RXF4EID0 = 0x17;
+
+const uint8_t MCP_REGISTER_RXF5SIDH = 0x18;
+const uint8_t MCP_REGISTER_RXF5SIDL = 0x19;
+const uint8_t MCP_REGISTER_RXF5EID8 = 0x1a;
+const uint8_t MCP_REGISTER_RXF5EID0 = 0x1b;
+
+const uint8_t MCP_REGISTER_TEC = 0x1c;
+const uint8_t MCP_REGISTER_REC = 0x1d;
+
+const uint8_t MCP_REGISTER_CNF1 = 0x2a;
+const uint8_t MCP_REGISTER_CNF2 = 0x29;
+const uint8_t MCP_REGISTER_CNF3 = 0x28;
+
+const uint8_t MCP_REGISTER_CANINTE = 0x2B;
+const uint8_t MCP_REGISTER_CANINTF = 0x2C;
+
+const uint8_t MCP_REGISTER_TXB0CTRL = 0x30;
+const uint8_t MCP_REGISTER_TXB0SIDH = 0x31;
+const uint8_t MCP_REGISTER_TXB0SIDL = 0x32;
+const uint8_t MCP_REGISTER_TXB0EID8 = 0x33;
+const uint8_t MCP_REGISTER_TXB0EID0 = 0x34;
+const uint8_t MCP_REGISTER_TXB0DLC  = 0x35;
+const uint8_t MCP_REGISTER_TXB0DATA = 0x36;
+
+const uint8_t MCP_REGISTER_TXB1CTRL = 0x40;
+const uint8_t MCP_REGISTER_TXB1SIDH = 0x41;
+const uint8_t MCP_REGISTER_TXB1SIDL = 0x42;
+const uint8_t MCP_REGISTER_TXB1EID8 = 0x43;
+const uint8_t MCP_REGISTER_TXB1EID0 = 0x44;
+const uint8_t MCP_REGISTER_TXB1DLC  = 0x45;
+const uint8_t MCP_REGISTER_TXB1DATA = 0x46;
+
+const uint8_t MCP_REGISTER_TXB2CTRL = 0x50;
+const uint8_t MCP_REGISTER_TXB2SIDH = 0x51;
+const uint8_t MCP_REGISTER_TXB2SIDL = 0x52;
+const uint8_t MCP_REGISTER_TXB2EID8 = 0x53;
+const uint8_t MCP_REGISTER_TXB2EID0 = 0x54;
+const uint8_t MCP_REGISTER_TXB2DLC  = 0x55;
+const uint8_t MCP_REGISTER_TXB2DATA = 0x56;
+
+const uint8_t MCP_REGISTER_RXB0CTRL = 0x60;
+const uint8_t MCP_REGISTER_RXB0SIDH = 0x61;
+const uint8_t MCP_REGISTER_RXB0SIDL = 0x62;
+const uint8_t MCP_REGISTER_RXB0EID8 = 0x63;
+const uint8_t MCP_REGISTER_RXB0EID0 = 0x64;
+const uint8_t MCP_REGISTER_RXB0DLC  = 0x65;
+const uint8_t MCP_REGISTER_RXB0DATA = 0x66;
+
+const uint8_t MCP_REGISTER_RXB1CTRL = 0x70;
+const uint8_t MCP_REGISTER_RXB1SIDH = 0x71;
+const uint8_t MCP_REGISTER_RXB1SIDL = 0x72;
+const uint8_t MCP_REGISTER_RXB1EID8 = 0x73;
+const uint8_t MCP_REGISTER_RXB1EID0 = 0x74;
+const uint8_t MCP_REGISTER_RXB1DLC  = 0x75;
+const uint8_t MCP_REGISTER_RXB1DATA = 0x76;
+
+const uint8_t MCP_REGISTER_TXRTSCTRL = 0x0d;
+const uint8_t MCP_REGISTER_CANSTAT   = 0x0e;
+const uint8_t MCP_REGISTER_CANCTRL   = 0x0f;
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_MCP2515_USE_INTERRUPT_RXTX )
+
+typedef struct
+{
+    uint32_t id;
+    uint8_t  priority;
+    uint8_t  length;
+    uint8_t  data[ 8 ];
+
+}   mcp2515_data_t;
+
+static cbuffer< mcp2515_data_t, uint8_t, PRJ_MCP2515_RX_BUFFER_SIZE > g_rx_buffer;
+static cbuffer< mcp2515_data_t, uint8_t, PRJ_MCP2515_TX_BUFFER_SIZE > g_tx_buffer;
+
+#endif  // PRJ_MCP2515_USE_INTERRUPT_RXTX
+
+
+// ----------------------------------------------------------------------------------------
+
+inline void device_select()
+{
+    PRJ_MCP2515_SELECT_PORT &= ~( 1 << PRJ_MCP2515_SELECT_PIN );
+}
+
+inline void device_unselect()
+{
+    PRJ_MCP2515_SELECT_PORT |= ( 1 << PRJ_MCP2515_SELECT_PIN );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static uint8_t read_register( uint8_t address )
+{
+    uint8_t result;
+
+    device_select();
+
+    spi_write( MCP_COMMAND_READ );
+    spi_write( address );
+    result = spi_read();
+
+    device_unselect();
+
+    return result;
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static void read_register( uint8_t address, uint8_t* values, uint8_t count )
+{
+    device_select();
+
+    spi_write( MCP_COMMAND_READ );
+    spi_write( address );
+
+    while ( count > 0 ) 
+    {
+        *values++ = spi_read();
+        --count;
+    }
+
+    device_unselect();
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static void write_register( uint8_t address, uint8_t value )
+{
+    device_select();
+    
+    spi_write( MCP_COMMAND_WRITE );
+    spi_write( address );
+    spi_write( value );
+
+    device_unselect();
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static void write_register( uint8_t address, const uint8_t* values, uint8_t count )
+{
+    device_select();
+
+    spi_write( MCP_COMMAND_WRITE );
+    spi_write( address );
+
+    while ( count > 0 )
+    {
+        spi_write( *values++ );
+        --count;
+    }
+
+    device_unselect();
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static void modify_register( uint8_t address, uint8_t mask, const uint8_t value )
+{
+    device_select();
+    
+    spi_write( MCP_COMMAND_BITMOD );
+    spi_write( address );
+    spi_write( mask );
+    spi_write( value );
+
+    device_unselect();
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  mapping the four register bytes to the uint32_t CAN identifier: 
+//
+//  + the first eleven bits contain the standard ID
+//  + the next eighteen bits contain the extended ID
+//
+//      00000000000000000000000000000000  uint32_t
+//
+//      3   2   2   1   1   1   7   3  0
+//      1   7   3   9   5   1
+//
+//                           +--+------+  std
+//         +-+------++------+             ext
+//
+//                           76543210     SIDH
+//         10                        765  SIDL
+//           76543210                     EID8
+//                   76543210             EID0
+
+static uint32_t get_can_id( uint8_t sidh_register )
+{
+    uint8_t address_data[ 4 ];  // SIDH, SIDL, EID8, EID0
+
+    read_register( sidh_register, address_data, 4 );
+
+    uint32_t result;
+     
+    result  = static_cast< uint32_t >( address_data[ 0 ] ) << 3;
+    result |= static_cast< uint32_t >( address_data[ 1 ] ) >> 5;
+    result |= static_cast< uint32_t >( address_data[ 1 ] & 0x3 ) << 27;
+    result |= static_cast< uint32_t >( address_data[ 3 ] ) << 11;
+    result |= static_cast< uint32_t >( address_data[ 2 ] ) << 19;
+
+    return result;
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  uses the same format as for get_can_id()
+
+static void set_can_id( uint8_t sidh_register, uint32_t id )
+{
+    uint8_t address_data[ 4 ];  // SIDH, SIDL, EID8, EID0
+
+    address_data[ 0 ] = static_cast< uint8_t >( id >> 3 );
+    address_data[ 1 ] = static_cast< uint8_t >( id ) << 5;
+    id >>= 11;
+    address_data[ 3 ] = static_cast< uint8_t >( id );
+    id >>= 8;
+    address_data[ 2 ] = static_cast< uint8_t >( id );
+    id >>= 8;
+    address_data[ 1 ] |= static_cast< uint8_t >( id ) & 0x3;
+    address_data[ 1 ] |= ( 1 << 3 ); // EXIDE
+
+    write_register( sidh_register, address_data, 4 );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_MCP2515_USE_INTERRUPT_RXTX )
+
+static void read_into_rx_buffer( uint8_t rx_ctrl_register )    
+{
+    mcp2515_data_t  msg;
+
+    //--    Copy out the message identifier.
+
+    msg.id = get_can_id( rx_ctrl_register + 1 /* SIDH */ );
+
+    //--    Retrieve the request flag or data.
+
+    uint8_t dlc = read_register( rx_ctrl_register + 5 /* DLC */ );
+
+    if ( dlc & ( 1 << 6 ) ) // RTR bit
+    {
+        msg.length = 0xff;  // signifies this is a request rather than a message
+    }
+    else
+    {
+        msg.length = dlc;
+        read_register( rx_ctrl_register + 6, msg.data, dlc );
+    }
+    
+    //--    Add it to the queue.
+
+    g_rx_buffer.push( msg );
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_MCP2515_USE_INTERRUPT_RXTX )
+
+static void send_from_tx_buffer()
+{
+    mcp2515_data_t  msg = g_tx_buffer.pop();
+
+    //--    Load the destination address.
+
+    set_can_id( MCP_REGISTER_TXB0CTRL + 1 /* SIDH */, msg.id );
+
+    //--    Request or message? Set up the registers appropriately.
+
+    if ( msg.length == 0xff )
+    {
+        write_register( MCP_REGISTER_TXB0CTRL + 5 /* DLC */, ( 1 << 6 ) );
+    }
+    else
+    {
+        //--    Load the message contents.
+
+        write_register( MCP_REGISTER_TXB0CTRL + 5 /* DLC */, msg.length );
+
+        write_register( MCP_REGISTER_TXB0CTRL + 6 /* DATA */,
+                        msg.data, 
+                        msg.length );
+    }
+
+    //--    Fire off the transmit.
+
+    modify_register( MCP_REGISTER_TXB0CTRL, 0x0b, ( 0x08 | msg.priority ) );
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if !defined( PRJ_MCP2515_USE_INTERRUPT_RXTX )
+
+static bool find_empty_transmit_buffer( uint8_t* txbufctrl )
+{
+    if ( ( read_register( MCP_REGISTER_TXB0CTRL ) & ( 1 << 3 ) ) == 0 )
+    {
+        *txbufctrl = MCP_REGISTER_TXB0CTRL;
+        return true;
+    }
+    else if ( ( read_register( MCP_REGISTER_TXB1CTRL ) & ( 1 << 3 ) ) == 0 )
+    {
+        *txbufctrl = MCP_REGISTER_TXB1CTRL;
+        return true;
+    }
+    else if ( ( read_register( MCP_REGISTER_TXB2CTRL ) & ( 1 << 3 ) ) == 0 )
+    {
+        *txbufctrl = MCP_REGISTER_TXB2CTRL;
+        return true;
+    }
+
+    return false;
+}
+    
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+    
+bool mcp2515_init()
+{
+    //--    Configure the SPI hardware; the caller might have done it but it doesn't
+    //      hurt to do it again.
+
+    spi_init();
+
+    //--    Configure our select line.
+
+    PRJ_MCP2515_SELECT_DDR |= ( 1 << PRJ_MCP2515_SELECT_PIN );
+    device_unselect();
+
+    //--    Configure our reset line (if supplied); it should be pulled high normally.
+
+#if defined( PRJ_MCP2515_USE_HW_RESET )
+
+    PRJ_MCP2515_RESET_DDR  |= ( 1 << PRJ_MCP2515_RESET_PIN );
+    PRJ_MCP2515_RESET_PORT |= ( 1 << PRJ_MCP2515_RESET_PIN );
+
+#endif
+    
+    //--    Reset the MCP2515 chip.
+
+    mcp2515_reset();
+
+    //--    Set mode to configuration operation.
+    
+    modify_register( MCP_REGISTER_CANCTRL, 0xe0, 0x80 );
+    
+    if ( ( read_register( MCP_REGISTER_CANCTRL ) & 0xe0 ) != 0x80 )
+    {
+        return false;
+    }
+
+    //--    Set up the bus speed via the bit timing registers; this depends on the input
+    //      clock frequency for the chip.
+
+#if defined( PRJ_MCP2515_CANBUS_20_KHZ ) && defined( PRJ_MCP2515_FREQUENCY_4_MHZ )
+
+    //--    SWJ = 0 (1 x TQ), BRP = 4
+
+    write_register( MCP_REGISTER_CNF1, ( ( 0 << 6 ) | ( 4 ) ) );
+
+    //--    BLTMODE = 1, SAM = 0, PHSEG1 = 7 (8 x TQ), PRSEG = 2 (3 x TQ)
+
+    write_register( MCP_REGISTER_CNF2, ( ( 1 << 7 ) | ( 0 << 6 ) | ( 7 << 3 ) | ( 2 ) ) );
+        
+    //--    SOF = 0, WAKFIL = 0, PHSEG2 = 7 (8 x TQ)
+
+    write_register( MCP_REGISTER_CNF3, ( ( 0 << 7 ) | ( 0 << 6 ) | ( 7 ) ) );
+
+
+#elif defined( PRJ_MCP2515_CANBUS_125_KHZ ) && defined( PRJ_MCP2515_FREQUENCY_4_MHZ )
+
+    //--    SWJ = 0 (1 x TQ), BRP = 0
+
+    write_register( MCP_REGISTER_CNF1, ( ( 0 << 6 ) | ( 0 ) ) );
+
+    //--    BLTMODE = 1, SAM = 0, PHSEG1 = 5 (6 x TQ), PRSEG = 2 (3 x TQ)
+
+    write_register( MCP_REGISTER_CNF2, ( ( 1 << 7 ) | ( 0 << 6 ) | ( 5 << 3 ) | ( 2 ) ) );
+        
+    //--    SOF = 0, WAKFIL = 0, PHSEG2 = 5 (6 x TQ)
+
+    write_register( MCP_REGISTER_CNF3, ( ( 0 << 7 ) | ( 0 << 6 ) | ( 5 ) ) );
+
+
+#elif defined( PRJ_MCP2515_CANBUS_20_KHZ ) && defined( PRJ_MCP2515_FREQUENCY_16_MHZ )
+
+    //--    SWJ = 0 (1 x TQ), BRP = 19
+
+    write_register( MCP_REGISTER_CNF1, ( ( 0 << 6 ) | ( 19 ) ) );
+
+    //--    BLTMODE = 1, SAM = 0, PHSEG1 = 7 (8 x TQ), PRSEG = 2 (3 x TQ)
+
+    write_register( MCP_REGISTER_CNF2, ( ( 1 << 7 ) | ( 0 << 6 ) | ( 7 << 3 ) | ( 2 ) ) );
+        
+    //--    SOF = 0, WAKFIL = 0, PHSEG2 = 7 (8 x TQ)
+
+    write_register( MCP_REGISTER_CNF3, ( ( 0 << 7 ) | ( 0 << 6 ) | ( 7 ) ) );
+
+
+#elif defined( PRJ_MCP2515_CANBUS_125_KHZ ) && defined( PRJ_MCP2515_FREQUENCY_16_MHZ )
+
+    //--    SWJ = 0 (1 x TQ), BRP = 3
+
+    write_register( MCP_REGISTER_CNF1, ( ( 0 << 6 ) | ( 3 ) ) );
+
+    //--    BLTMODE = 1, SAM = 0, PHSEG1 = 5 (6 x TQ), PRSEG = 2 (3 x TQ)
+
+    write_register( MCP_REGISTER_CNF2, ( ( 1 << 7 ) | ( 0 << 6 ) | ( 5 << 3 ) | ( 2 ) ) );
+        
+    //--    SOF = 0, WAKFIL = 0, PHSEG2 = 5 (6 x TQ)
+
+    write_register( MCP_REGISTER_CNF3, ( ( 0 << 7 ) | ( 0 << 6 ) | ( 5 ) ) );
+
+
+#else
+#error Unsupported CAN bus speed selection!
+#endif
+
+    //--    Reset the three transmit buffers.
+
+    write_register( MCP_REGISTER_TXB0CTRL, 0x00 );
+    write_register( MCP_REGISTER_TXB1CTRL, 0x00 );
+    write_register( MCP_REGISTER_TXB2CTRL, 0x00 );
+
+    //--    Reset the two receive buffers.
+
+    write_register( MCP_REGISTER_RXB0CTRL, 0x00 );
+    write_register( MCP_REGISTER_RXB1CTRL, 0x00 );
+
+    //--    Clear all receive filters.
+
+    set_can_id( MCP_REGISTER_RXF0SIDH, 0x0000 );
+    set_can_id( MCP_REGISTER_RXF1SIDH, 0x0000 );
+    set_can_id( MCP_REGISTER_RXF2SIDH, 0x0000 );
+    set_can_id( MCP_REGISTER_RXF3SIDH, 0x0000 );
+    set_can_id( MCP_REGISTER_RXF4SIDH, 0x0000 );
+    set_can_id( MCP_REGISTER_RXF5SIDH, 0x0000 );
+
+    //--    Enable both receive-buffers to receive messages with standard and extended ids;
+    //      enable message receive rollover.
+
+    write_register( MCP_REGISTER_RXB0CTRL,
+                    ( ( 1 << 6 )          // RMX1
+                    | ( 1 << 5 )          // RMX0
+                    | ( 0 << 3 )          // RXRTR
+                    | ( 1 << 2 )          // BUKT
+                    | ( 0 << 1 )          // BUKT1
+                    | ( 0 << 0 ) ) );     // FILHIT0
+
+    write_register( MCP_REGISTER_RXB1CTRL,
+                    ( ( 1 << 6 )          // RMX1
+                    | ( 1 << 5 )          // RMX0
+                    | ( 0 << 3 )          // RXRTR
+                    | ( 0 << 2 )          // BUKT
+                    | ( 0 << 1 )          // BUKT1
+                    | ( 0 << 0 ) ) );     // FILHIT0
+
+    //--    Set up the interrupt-driven RX and TX, if required.
+
+#if defined( PRJ_MCP2515_USE_INTERRUPT_RXTX )
+
+    modify_register( MCP_REGISTER_CANINTF, MCP_INTERRUPT_TX0I, 0xff );
+    modify_register( MCP_REGISTER_CANINTE, MCP_INTERRUPT_RX0I, 0xff );
+
+#endif
+
+    //--    Set mode to normal operation.
+
+    modify_register( MCP_REGISTER_CANCTRL, 0xe0, 0x00 );
+
+    if ( ( read_register( MCP_REGISTER_CANCTRL ) & 0xe0 ) != 0x00 )
+    {
+        return false;
+    }
+
+    return true;
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+void mcp2515_reset()
+{
+    //--    Do a hardware reset if we have hardware support; otherwise do it via software.
+
+#if defined( PRJ_MCP2515_USE_HW_RESET )
+
+    PRJ_MCP2515_RESET_PORT &= ~( 1 << PRJ_MCP2515_RESET_PIN );
+    spinwait_delay_ms( 10 );
+    PRJ_MCP2515_RESET_PORT |= ( 1 << PRJ_MCP2515_RESET_PIN );
+    spinwait_delay_ms( 10 );
+
+#else
+
+    //--    Wait for the hardware to stabilize; this isn't required on resets other than
+    //      the first, but it doesn't hurt.
+
+    spinwait_delay_ms( 10 );
+
+    device_select();
+    spi_write( MCP_COMMAND_RESET );
+    device_unselect();
+    spinwait_delay_ms( 10 );    // approximately long enough
+
+#endif
+
+    //--    Reset sets up configuration mode, switch back to normal operation.
+
+    modify_register( MCP_REGISTER_CANCTRL, 0xe0, 0x00 );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_MCP2515_USE_INTERRUPT_RXTX ) || defined( PRJ_MCP2515_USE_INTERRUPT_ERR )
+
+void mcp2515_process_interrupt()
+{
+    //--    The exact nature of the interrupt is contained in the CANINTF register.
+
+    uint8_t canintf = read_register( MCP_REGISTER_CANINTF );
+
+    if ( canintf & MCP_INTERRUPT_RX1I )
+    {
+        read_into_rx_buffer( MCP_REGISTER_RXB1CTRL );
+        modify_register( MCP_REGISTER_CANINTF, MCP_INTERRUPT_RX1I, 0x00 );
+    }
+
+    if ( canintf & MCP_INTERRUPT_RX0I )
+    {
+        read_into_rx_buffer( MCP_REGISTER_RXB0CTRL );
+        modify_register( MCP_REGISTER_CANINTF, MCP_INTERRUPT_RX0I, 0x00 );
+    }
+    
+    if ( canintf & MCP_INTERRUPT_TX0I )
+    {
+        if ( g_tx_buffer.is_empty() )
+        {
+            modify_register( MCP_REGISTER_CANINTE, MCP_INTERRUPT_TX0I, 0x00 );
+        }
+        else
+        {
+            modify_register( MCP_REGISTER_CANINTF, MCP_INTERRUPT_TX0I, 0x00 );
+            send_from_tx_buffer();
+        }
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+bool mcp2515_read    
+    (
+        uint32_t* can_id,
+        bool*     is_request,
+        uint8_t*  data_ptr,
+        uint8_t*  length
+    )
+{
+    
+#if defined( PRJ_MCP2515_USE_INTERRUPT_RXTX )
+
+    //--    Pending message?
+
+    if ( g_rx_buffer.is_empty() )
+    {
+        return false;
+    }
+
+    //--    Fetch it from the queue and copy it out.
+
+    mcp2515_data_t  msg = g_rx_buffer.pop();
+
+    *can_id = msg.id;
+    
+    if ( msg.length == 0xff )
+    {
+        *is_request = true;
+    }
+    else
+    {
+        *is_request = false;
+        *length     = msg.length;
+
+        for ( uint8_t i = 0; i < msg.length; i++ )
+        {
+            *data_ptr++ = msg.data[ i ];
+        }
+    }
+
+    return true;
+
+#else
+
+    //--    Look for a pending message.
+
+    uint8_t read_status = read_register( MCP_REGISTER_CANINTF );
+    uint8_t rx_ctrl_register;
+
+    if ( ( read_status & 0x01 ) != 0 ) // RX0IF
+    {
+        rx_ctrl_register = MCP_REGISTER_RXB0CTRL;
+    }
+    else if ( ( read_status & 0x02 ) != 0 ) // RX1IF
+    {
+        rx_ctrl_register = MCP_REGISTER_RXB1CTRL;
+    }
+    else
+    {
+        return false;
+    }
+
+    //--    Copy out the message identifier.
+
+    *can_id = get_can_id( rx_ctrl_register + 1 ); // SIDH
+
+    //--    Retrieve the request flag or data.
+
+    uint8_t dlc = read_register( rx_ctrl_register + 5 ); // DLC
+
+    if ( dlc & ( 1 << 6 ) ) // RTR bit
+    {
+        *is_request = true;
+    }
+    else
+    {
+        *is_request = false;
+        *length = dlc;
+        read_register( rx_ctrl_register + 6, data_ptr, dlc );
+    }
+
+    //--    Clear the message pending flag.
+
+    if ( rx_ctrl_register == MCP_REGISTER_RXB0CTRL )
+    {
+        modify_register( MCP_REGISTER_CANINTF, 0x01, 0x00 ); // RX0IF
+    }
+    else if ( rx_ctrl_register == MCP_REGISTER_RXB1CTRL )
+    {
+        modify_register( MCP_REGISTER_CANINTF, 0x02, 0x00 ); // RX1IF
+    }
+
+    return true;
+
+#endif  // PRJ_MCP2515_USE_INTERRUPT_RXTX
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+bool mcp2515_send
+    (
+        const uint32_t& can_id,
+        const uint8_t*  data_ptr,
+        uint8_t         length,
+        uint8_t         priority
+    )
+{
+    
+#if defined( PRJ_MCP2515_USE_INTERRUPT_RXTX )
+
+    //--    Got space in the buffer?
+
+    if ( g_tx_buffer.is_full() )
+    {
+        return false;
+    }
+
+    //--    Add the message to the buffer, then enable the interrupt to trigger a
+    //      transmit. Note this must be done with interrupts disabled to avoid a
+    //      race condition that hangs here.
+
+    mcp2515_data_t  msg;
+    
+    msg.id       = can_id;
+    msg.priority = priority;
+    msg.length   = length;
+
+    for ( uint8_t i = 0; i < length; i++ )
+    {
+        msg.data[ i ] = *data_ptr++;
+    }
+    
+    g_tx_buffer.push( msg );
+
+    {
+        guard_disable_interrupts no_ints;
+
+        modify_register( MCP_REGISTER_CANINTE, MCP_INTERRUPT_TX0I, 0xff );
+    }
+
+    return true;
+
+#else
+
+    //--    Find an empty buffer.
+
+    uint8_t tx_ctrl_register;
+
+    if ( ! find_empty_transmit_buffer( &tx_ctrl_register ) )
+    {
+        return false;
+    }
+
+    //--    Load the destination address.
+
+    set_can_id( tx_ctrl_register + 1 /* SIDH */, can_id );
+
+    //--    Load the message contents.
+
+    write_register( tx_ctrl_register + 5, // DLC 
+                    length );
+
+    write_register( tx_ctrl_register + 6, // DATA
+                    data_ptr, 
+                    length );
+
+    //--    Fire off the transmit.
+
+    modify_register( tx_ctrl_register, 0x0b, ( 0x08 | priority ) );
+
+    return true;
+
+#endif  // PRJ_MCP2515_USE_INTERRUPT_RXTX
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+bool mcp2515_request( const uint32_t& can_id, uint8_t priority )
+{
+    
+#if defined( PRJ_MCP2515_USE_INTERRUPT_RXTX )
+
+    //--    Got space in the buffer?
+
+    if ( g_tx_buffer.is_full() )
+    {
+        return false;
+    }
+
+    //--    Add the message to the buffer, then enable the interrupt to trigger a
+    //      transmit. Note this must be done with interrupts disabled to avoid a
+    //      race condition that hangs here.
+
+    mcp2515_data_t  msg;
+    
+    msg.id       = can_id;
+    msg.priority = priority;
+    msg.length   = 0xff; // request, not an actual message
+    
+    g_tx_buffer.push( msg );
+
+    {
+        guard_disable_interrupts no_ints;
+
+        modify_register( MCP_REGISTER_CANINTE, MCP_INTERRUPT_TX0I, 0xff );
+    }
+
+    return true;
+
+#else
+
+    //--    Find an empty buffer.
+
+    uint8_t tx_ctrl_register;
+
+    if ( ! find_empty_transmit_buffer( &tx_ctrl_register ) )
+    {
+        return false;
+    }
+
+    //--    Load the destination address.
+
+    set_can_id( tx_ctrl_register + 1 /* SIDH */, can_id );
+
+    //--    Set the RTR bit in the DLC register.
+
+    write_register( tx_ctrl_register + 5 /* DLC */, ( 1 << 6 ) );
+
+    //--    Fire off the transmit.
+
+    modify_register( tx_ctrl_register, 0x0b, ( 0x08 | priority ) );
+
+    return true;
+
+#endif  // PRJ_MCP2515_USE_INTERRUPT_RXTX
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_MCP2515_ENABLE_DEBUG )
+    
+static void print_register( const prog_char* label, uint8_t address )
+{
+    uint8_t value = read_register( address );
+
+    printf_P( label );
+    
+    for ( uint8_t i = 0; i < 8; i++ )
+    {
+        if ( value & 0x80 )
+        {
+            putchar( '1' );
+        }
+        else
+        {
+            putchar( '0' );
+        }
+        value = value << 1;
+    }
+
+    putchar( '\n' );
+}
+
+void mcp2515_debug_print_registers()
+{
+    printf_P( PSTR("MCP2515 registers:\n") );
+
+    print_register( PSTR("    TXRTSCTRL: "), MCP_REGISTER_TXRTSCTRL );
+    print_register( PSTR("    CANSTAT  : "), MCP_REGISTER_CANSTAT );
+    print_register( PSTR("    CANCTRL  : "), MCP_REGISTER_CANCTRL );
+    putchar( '\n' );
+
+    print_register( PSTR("    TXB0CTRL : "), MCP_REGISTER_TXB0CTRL );
+    print_register( PSTR("    TXB0SIDH : "), MCP_REGISTER_TXB0SIDH );
+    print_register( PSTR("    TXB0SIDL : "), MCP_REGISTER_TXB0SIDL );
+    print_register( PSTR("    TXB0EID8 : "), MCP_REGISTER_TXB0EID8 );
+    print_register( PSTR("    TXB0EID0 : "), MCP_REGISTER_TXB0EID0 );
+    printf_P( PSTR("    TXB0DLC  : %u"), read_register( MCP_REGISTER_TXB0DLC ) );
+    putchar( '\n' );
+    
+    print_register( PSTR("    TXB1CTRL : "), MCP_REGISTER_TXB1CTRL );
+    print_register( PSTR("    TXB1SIDH : "), MCP_REGISTER_TXB1SIDH );
+    print_register( PSTR("    TXB1SIDL : "), MCP_REGISTER_TXB1SIDL );
+    print_register( PSTR("    TXB1EID8 : "), MCP_REGISTER_TXB1EID8 );
+    print_register( PSTR("    TXB1EID0 : "), MCP_REGISTER_TXB1EID0 );
+    printf_P( PSTR("    TXB1DLC  : %u"), read_register( MCP_REGISTER_TXB1DLC ) );
+    putchar( '\n' );
+    
+    print_register( PSTR("    TXB2CTRL : "), MCP_REGISTER_TXB2CTRL );
+    print_register( PSTR("    TXB2SIDH : "), MCP_REGISTER_TXB2SIDH );
+    print_register( PSTR("    TXB2SIDL : "), MCP_REGISTER_TXB2SIDL );
+    print_register( PSTR("    TXB2EID8 : "), MCP_REGISTER_TXB2EID8 );
+    print_register( PSTR("    TXB2EID0 : "), MCP_REGISTER_TXB2EID0 );
+    printf_P( PSTR("    TXB2DLC  : %u"), read_register( MCP_REGISTER_TXB2DLC ) );
+    putchar( '\n' );
+    
+    print_register( PSTR("    RXB0CTRL : "), MCP_REGISTER_RXB0CTRL );
+    print_register( PSTR("    RXB0SIDH : "), MCP_REGISTER_RXB0SIDH );
+    print_register( PSTR("    RXB0SIDL : "), MCP_REGISTER_RXB0SIDL );
+    print_register( PSTR("    RXB0EID8 : "), MCP_REGISTER_RXB0EID8 );
+    print_register( PSTR("    RXB0EID0 : "), MCP_REGISTER_RXB0EID0 );
+    printf_P( PSTR("    RXB0DLC  : %u"), read_register( MCP_REGISTER_RXB0DLC ) );
+    putchar( '\n' );
+    
+    print_register( PSTR("    RXB1CTRL : "), MCP_REGISTER_RXB1CTRL );
+    print_register( PSTR("    RXB1SIDH : "), MCP_REGISTER_RXB1SIDH );
+    print_register( PSTR("    RXB1SIDL : "), MCP_REGISTER_RXB1SIDL );
+    print_register( PSTR("    RXB1EID8 : "), MCP_REGISTER_RXB1EID8 );
+    print_register( PSTR("    RXB1EID0 : "), MCP_REGISTER_RXB1EID0 );
+    printf_P( PSTR("    RXB0DLC  : %u"), read_register( MCP_REGISTER_RXB1DLC ) );
+    putchar( '\n' );
+    
+    for ( uint8_t i = 0; i < 0x80; i++ )
+    {
+        if ( ( ( i % 0x10 ) == 0 ) && ( i != 0 ) )
+        {
+            putchar( '\n' );
+            printf_P( PSTR("0x%X: "), i );
+        }
+        else if ( i == 0 )
+        {
+            printf_P( PSTR("0x00: ") );
+        }
+    
+        uint8_t reg = read_register( i );
+    
+        printf_P( PSTR("0x") );
+        if ( reg < 0x10 )
+        {
+            putchar( '0' );
+        }
+        printf_P( PSTR("%X "), reg );
+    }
+
+    putchar( '\n' );
+}
+
+#endif  // PRJ_MCP2515_ENABLE_DEBUG
+
+
+// ----------------------------------------------------------------------------------------
+
+#endif  // PRJ_MCP2515_ENABLE
+
+
+// ----------------------------------------------------------------------------------------
+//  end of mcp2515.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/can/mcp2515.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,182 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/can/mcp2515.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file implements CAN support using the Microchip MCP2515 via SPI.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_CAN_MCP2515_H )
+#define BCDRL_AVR_CAN_MCP2515_H
+
+
+#include <stdint.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  enable MCP2515 support with:
+//
+//      + PRJ_MCP2515_ENABLE
+//
+//  specify the SELECT pin for SPI communications with:
+//
+//      + PRJ_MCP2515_SELECT_DDR
+//      + PRJ_MCP2515_SELECT_PORT
+//      + PRJ_MCP2515_SELECT_PIN
+//
+//  specify the (optional) RESET pin with:
+//
+//      + PRJ_MCP2515_USE_HW_RESET
+//      + PRJ_MCP2515_RESET_DDR
+//      + PRJ_MCP2515_RESET_PORT
+//      + PRJ_MCP2515_RESET_PIN
+//
+//  enable interrupt-driven RX and TX with:
+//
+//      + PRJ_MCP2515_USE_INTERRUPT_RXTX
+//      + PRJ_MCP2515_RX_BUFFER_SIZE (14 bytes each, default is 4)
+//      + PRJ_MCP2515_TX_BUFFER_SIZE (14 bytes each, default is 6)
+//
+//  specify the CAN bus speed with one of:
+//
+//      + PRJ_MCP2515_CANBUS_20_KHZ
+//      + PRJ_MCP2515_CANBUS_125_KHZ
+//
+//  specify the clock frequency for the MCP2515 with one of:
+//
+//      + PRJ_MCP2515_FREQUENCY_4_MHZ
+//      + PRJ_MCP2515_FREQUENCY_16_MHZ
+//
+//  enable the debug support with:
+//
+//      + PRJ_MCP2515_ENABLE_DEBUG
+//
+// ----------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------------------
+
+const uint8_t mcp2515_max_message_data = 0x08;
+
+const uint8_t mcp2515_priority_urgent = 0x03;
+const uint8_t mcp2515_priority_high   = 0x02;
+const uint8_t mcp2515_priority_normal = 0x01;
+const uint8_t mcp2515_priority_low    = 0x00;
+
+
+// ----------------------------------------------------------------------------------------
+//  mcp2515_init
+//
+//      Initialize the MCP2515 h/w according to the project_defs.h specification.
+//
+//      Returns true if the initialization was successful.
+//
+
+bool mcp2515_init();
+
+    
+// ----------------------------------------------------------------------------------------
+//  mcp2515_reset
+//
+//      Reset the MCP2515 h/w. Any pending messages in the transmit or recieve buffers
+//      are lost.
+//
+
+void mcp2515_reset();
+
+
+// ----------------------------------------------------------------------------------------
+//  mcp2515_process_interrupt
+//
+//      Respond to the INTERRUPT pin transitioning to a low state.
+//
+//      Only compiled if PRJ_MCP2515_USE_INTERRUPT_RXTX is defined.
+//
+
+void mcp2515_process_interrupt();
+
+
+// ----------------------------------------------------------------------------------------
+//  mcp2515_read
+//
+//      Read a pending message from one of the MCP2515 receive buffers. Does not block if
+//      no message is available.
+//
+//      Returns true if a message was successfully received.
+//
+
+bool mcp2515_read    
+    (
+        uint32_t* can_id,
+        bool*     is_request,
+        uint8_t*  data_ptr,
+        uint8_t*  length
+    );
+
+
+// ----------------------------------------------------------------------------------------
+//  mcp2515_send
+//
+//      Queue an outgoing message into one of the MCP2515 transmit buffers.
+//
+//      Returns true if the message was successfully sent.
+//
+
+bool mcp2515_send
+    (
+        const uint32_t& can_id,
+        const uint8_t*  data_ptr,
+        uint8_t         length,
+        uint8_t         priority = mcp2515_priority_normal
+    );
+
+
+// ----------------------------------------------------------------------------------------
+//  mcp2515_request
+//
+//      Queue an outgoing request into one of the MCP2515 transmit buffers.
+//
+//      Returns true if the request was successfully sent.
+//
+
+bool mcp2515_request( const uint32_t& can_id, uint8_t priority = mcp2515_priority_normal );
+
+
+// ----------------------------------------------------------------------------------------
+//  mcp2515_debug_print_registers
+//
+//      Print the current state of the MCP2515 h/w registers to stdout.
+//
+//      Only compiled if PRJ_MCP2515_ENABLE_DEBUG is defined.
+//
+
+void mcp2515_debug_print_registers();
+
+
+#endif  // #if defined( BCDRL_AVR_CAN_MCP2515_H )
+// ----------------------------------------------------------------------------------------
+//  end of mcp2515.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/adc.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,293 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/adc.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides a basic Analog to Digitial Conversion (ADC) library.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "adc.h"
+
+#include <avr/io.h>
+
+#include "packages/avr/device/spinwait.h"
+
+#include "hwdefs.h"
+#include "project_defs.h"
+
+
+// ----------------------------------------------------------------------------------------
+//  Project-specific definitions
+//
+
+#if defined( PRJ_ADC_ENABLED )
+
+#if !defined( HW_HAS_ADC )
+#error Target HW has no ADC!
+#endif
+
+#if !defined( PRJ_ADC_CLOCK_FACTOR_DIV_2 ) \
+    && !defined( PRJ_ADC_CLOCK_FACTOR_DIV_4 ) \
+    && !defined( PRJ_ADC_CLOCK_FACTOR_DIV_8 ) \
+    && !defined( PRJ_ADC_CLOCK_FACTOR_DIV_16 ) \
+    && !defined( PRJ_ADC_CLOCK_FACTOR_DIV_32 ) \
+    && !defined( PRJ_ADC_CLOCK_FACTOR_DIV_64 ) \
+    && !defined( PRJ_ADC_CLOCK_FACTOR_DIV_128 )
+#error Must define an ADC clock prescalar value!
+#endif
+
+#endif // #if defined( PRJ_ADC_ENABLED )
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_ADC_ENABLED )
+
+void adc_init()
+{
+    //--    Set the pins for each requested channel as input.
+
+    HW_ADC_DDR &= ~( 0
+
+#if defined( PRJ_ADC_USE_CHANNEL_6 )
+
+        | ( 1 << PC6 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_5 )
+
+        | ( 1 << PC5 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_4 )
+
+        | ( 1 << PC4 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_3 )
+
+        | ( 1 << PC3 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_2 )
+
+        | ( 1 << PC2 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_1 )
+
+        | ( 1 << PC1 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_0 )
+
+        | ( 1 << PC0 )
+
+#endif
+
+        );
+
+    //--    Disable the internal pull-ups on the specified input pins.
+
+    HW_ADC_PORT &= ~( 0
+
+#if defined( PRJ_ADC_USE_CHANNEL_6 )
+
+        | ( 1 << PC6 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_5 )
+
+        | ( 1 << PC5 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_4 )
+
+        | ( 1 << PC4 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_3 )
+
+        | ( 1 << PC3 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_2 )
+
+        | ( 1 << PC2 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_1 )
+
+        | ( 1 << PC1 )
+
+#endif
+
+#if defined( PRJ_ADC_USE_CHANNEL_0 )
+
+        | ( 1 << PC0 )
+
+#endif
+
+        );
+
+    //--    Enable the ADC with the specified parameters. We start the first conversion
+    //      immediately and block until it finishes.
+
+    HW_ADC_REG_ADCSR = 0
+        
+        | ( 1 << ADEN ) 
+        | ( 1 << ADSC )
+
+#if defined( HW_ADC_REG_ADCSR_ADATE )
+
+        | ( 0 << HW_ADC_REG_ADCSR_ADATE )
+
+#elif defined( HW_ADC_REG_ADCSR_ADFR )
+
+        | ( 0 << HW_ADC_REG_ADCSR_ADFR )
+
+#endif
+
+        | ( 0 << ADIF )
+        | ( 0 << ADIE )
+
+#if defined( PRJ_ADC_CLOCK_FACTOR_DIV_2 )
+    
+        | ( 0 << ADPS2 ) | ( 0 << ADPS1 ) | ( 0 << ADPS0 )
+
+#elif defined( PRJ_ADC_CLOCK_FACTOR_DIV_4 )
+
+        | ( 0 << ADPS2 ) | ( 1 << ADPS1 ) | ( 0 << ADPS0 )
+
+#elif defined( PRJ_ADC_CLOCK_FACTOR_DIV_8 )
+
+        | ( 0 << ADPS2 ) | ( 1 << ADPS1 ) | ( 1 << ADPS0 )
+
+#elif defined( PRJ_ADC_CLOCK_FACTOR_DIV_16 )
+
+        | ( 1 << ADPS2 ) | ( 0 << ADPS1 ) | ( 0 << ADPS0 )
+
+#elif defined( PRJ_ADC_CLOCK_FACTOR_DIV_32 )
+
+        | ( 1 << ADPS2 ) | ( 0 << ADPS1 ) | ( 1 << ADPS0 )
+
+#elif defined( PRJ_ADC_CLOCK_FACTOR_DIV_64 )
+
+        | ( 1 << ADPS2 ) | ( 1 << ADPS1 ) | ( 0 << ADPS0 )
+
+#elif defined( PRJ_ADC_CLOCK_FACTOR_DIV_128 )
+
+        | ( 1 << ADPS2 ) | ( 1 << ADPS1 ) | ( 1 << ADPS0 )
+
+#endif
+
+        ;
+
+    //--    Wait for the first conversion to complete before returning.
+
+    while ( ( HW_ADC_REG_ADCSR & ( 1 << ADSC ) ) != 0 ) ;
+
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_ADC_ENABLED )
+
+void adc_stop()
+{
+    HW_ADC_REG_ADCSR = 0;
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_ADC_ENABLED )
+
+uint16_t adc_read( uint8_t channel )
+{
+    HW_ADC_REG_ADMUX = channel;
+    HW_ADC_REG_ADCSR |= ( 1 << ADSC );
+
+    while ( ( HW_ADC_REG_ADCSR & ( 1 << ADSC ) ) != 0 ) ; // wait for the conversion
+
+    uint16_t result = ADCL;
+    result |= ( ADCH << 8 );
+    return result;
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_ADC_ENABLED ) && defined( PRJ_ADC_EXTENDED_READ )
+
+void adc_read
+    (
+        uint8_t   channel,
+        uint16_t* data,
+        uint8_t   count,
+        uint8_t   delay_ms
+    )
+{
+    HW_ADC_REG_ADMUX = channel;
+
+    for ( uint8_t i = 0; i < count; i++ )
+    {
+        HW_ADC_REG_ADCSR |= ( 1 << ADSC );
+
+        while ( ( HW_ADC_REG_ADCSR & ( 1 << ADSC ) ) != 0 ) ; // wait for the conversion
+
+        uint16_t result = ADCL;
+        result |= ( ADCH << 8 );
+
+        *data = result;
+        data++;
+
+        spinwait_delay_ms( delay_ms );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+//  end of adc.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/adc.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,115 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/adc.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides a basic Analog to Digitial Conversion (ADC) library.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_DEVICE_ADC_H )
+#define BCDRL_AVR_DEVICE_ADC_H
+
+
+#include <stdint.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  enable adc by defining:
+//  
+//      + PRJ_ADC_ENABLED
+//
+//  select the adc clock prescalar with one (and only one) of:
+//
+//      + PRJ_ADC_CLOCK_FACTOR_DIV_2
+//      + PRJ_ADC_CLOCK_FACTOR_DIV_4
+//      + PRJ_ADC_CLOCK_FACTOR_DIV_8
+//      + PRJ_ADC_CLOCK_FACTOR_DIV_16
+//      + PRJ_ADC_CLOCK_FACTOR_DIV_32
+//      + PRJ_ADC_CLOCK_FACTOR_DIV_64
+//      + PRJ_ADC_CLOCK_FACTOR_DIV_128
+//
+//  select the analog voltage reference with one (and only one) of:
+//
+//      + PRJ_ADC_REFERENCE_EXTERNAL_AREF
+//      + PRJ_ADC_REFERENCE_INTERNAL_2.56V
+//      + PRJ_ADC_REFERENCE_AREF_IS_AVCC
+//
+//  optional library functions:
+//
+//      + PRJ_ADC_EXTENDED_READ
+//      + PRJ_ADC_USE_NOISE_REDUCTION
+//
+// ----------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------------------
+//  adc_init
+//
+//      Initialize the ADC h/w; call this once, before reading samples.
+//
+
+void adc_init();
+
+
+// ----------------------------------------------------------------------------------------
+//  adc_stop
+//
+//      Shut down the ADC h/w.
+//
+
+void adc_stop();
+
+
+// ----------------------------------------------------------------------------------------
+//  adc_read
+//
+//      Read a sample from the specified ADC channel. Blocks until a sample is available.
+//
+
+uint16_t adc_read( uint8_t channel );
+
+
+// ----------------------------------------------------------------------------------------
+//  adc_read
+//
+//      Read a series of values from a given channel, optionally delay between each.
+//
+//      This function is only available if PRJ_ADC_EXTENDED_READ is defined.
+//      
+
+void adc_read
+    (
+        uint8_t   channel,
+        uint16_t* data,
+        uint8_t   count,
+        uint8_t   delay_ms = 10
+    );
+
+
+#endif  // #if !defined( BCDRL_AVR_DEVICE_ADC_H )
+// ----------------------------------------------------------------------------------------
+//  end of adc.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/hwdefs.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,402 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/hwdefs.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides abstracted definitions for the underlying AVR hardware.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+ 
+
+#if !defined( BCDRL_AVR_DEVICE_HWDEFS_H )
+#define BCDRL_AVR_DEVICE_HWDEFS_H
+
+
+#include <avr/io.h>
+
+#include "project_defs.h"
+
+
+// ----------------------------------------------------------------------------------------
+
+#if !defined( __AVR_ATmega8__ ) \
+    && !defined( __AVR_ATmega16__ ) \
+    && !defined( __AVR_ATmega88__ ) \
+    && !defined( __AVR_ATmega168__ ) \
+    && !defined( __AVR_ATmega128__ )
+#error Unsupported Hardware
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+//  General Definitions
+    
+#if defined( __AVR_ATmega8__ )
+
+#define     HW_HAS_PORTA
+#define     HW_HAS_PORTB
+#define     HW_HAS_PORTC
+#define     HW_HAS_PORTD
+
+#define     HW_RAM_SIZE                 1024
+#define     HW_FLASH_SIZE               (8 * 1024)
+#define     HW_EEPROM_SIZE              512
+
+#define     HW_RESET_PORT               PORTC
+#define     HW_RESET_DDR                DDRC
+#define     HW_RESET_PIN                PC6
+
+#elif defined( __AVR_ATmega88__ )
+
+#define     HW_HAS_PORTA
+#define     HW_HAS_PORTB
+#define     HW_HAS_PORTC
+#define     HW_HAS_PORTD
+
+#define     HW_RAM_SIZE                 1024
+#define     HW_FLASH_SIZE               (8 * 1024)
+#define     HW_EEPROM_SIZE              512
+
+#define     HW_RESET_PORT               PORTC
+#define     HW_RESET_DDR                DDRC
+#define     HW_RESET_PIN                PC6
+
+#elif defined( __AVR_ATmega168__ )
+
+#define     HW_HAS_PORTA
+#define     HW_HAS_PORTB
+#define     HW_HAS_PORTC
+#define     HW_HAS_PORTD
+
+#define     HW_RAM_SIZE                 1024
+#define     HW_FLASH_SIZE               (16 * 1024)
+#define     HW_EEPROM_SIZE              512
+
+#define     HW_RESET_PORT               PORTC
+#define     HW_RESET_DDR                DDRC
+#define     HW_RESET_PIN                PC6
+
+#elif defined( __AVR_ATmega16__ )
+
+#define     HW_HAS_PORTA
+#define     HW_HAS_PORTB
+#define     HW_HAS_PORTC
+#define     HW_HAS_PORTD
+
+#define     HW_RAM_SIZE                 1024
+#define     HW_FLASH_SIZE               (16 * 1024)
+#define     HW_EEPROM_SIZE              512
+
+#elif defined( __AVR_ATmega128__ )
+
+#define     HW_HAS_PORTA
+#define     HW_HAS_PORTB
+#define     HW_HAS_PORTC
+#define     HW_HAS_PORTD
+#define     HW_HAS_PORTE
+#define     HW_HAS_PORTF
+#define     HW_HAS_PORTG
+
+#define     HW_RAM_SIZE                 4096
+#define     HW_FLASH_SIZE               (128 * 1024)
+#define     HW_EEPROM_SIZE              4096
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+//  SPI hardware
+    
+#if defined( __AVR_ATmega8__ )
+
+#define     HW_HAS_SPI
+
+#define     HW_SPI_PORT                 PORTB
+#define     HW_SPI_DDR                  DDRB
+
+#define     HW_SPI_SCK_PIN              PB5
+#define     HW_SPI_MISO_PIN             PB4
+#define     HW_SPI_MOSI_PIN             PB3
+#define     HW_SPI_SS_PIN               PB2
+
+#elif defined( __AVR_ATmega88__ )
+
+#define     HW_HAS_SPI
+
+#define     HW_SPI_PORT                 PORTB
+#define     HW_SPI_DDR                  DDRB
+
+#define     HW_SPI_SCK_PIN              PB5
+#define     HW_SPI_MISO_PIN             PB4
+#define     HW_SPI_MOSI_PIN             PB3
+#define     HW_SPI_SS_PIN               PB2
+
+#elif defined( __AVR_ATmega168__ )
+
+#define     HW_HAS_SPI
+
+#define     HW_SPI_PORT                 PORTB
+#define     HW_SPI_DDR                  DDRB
+
+#define     HW_SPI_SCK_PIN              PB5
+#define     HW_SPI_MISO_PIN             PB4
+#define     HW_SPI_MOSI_PIN             PB3
+#define     HW_SPI_SS_PIN               PB2
+
+#elif defined( __AVR_ATmega16__ )
+
+#define     HW_HAS_SPI
+
+#define     HW_SPI_PORT                 PORTB
+#define     HW_SPI_DDR                  DDRB
+
+#define     HW_SPI_SCK_PIN              PB7
+#define     HW_SPI_MISO_PIN             PB6
+#define     HW_SPI_MOSI_PIN             PB5
+#define     HW_SPI_SS_PIN               PB4
+
+#elif defined( __AVR_ATmega128__ )
+
+#define     HW_HAS_SPI
+
+#define     HW_SPI_PORT                 PORTB
+#define     HW_SPI_DDR                  DDRB
+
+#define     HW_SPI_SCK_PIN              PB1
+#define     HW_SPI_MISO_PIN             PB3
+#define     HW_SPI_MOSI_PIN             PB2
+#define     HW_SPI_SS_PIN               PB0
+
+#else
+#error Unsupported Hardware
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+//  USART hardware
+    
+#if defined( __AVR_ATmega8__ )
+
+#define     HW_HAS_UART0
+#define     HW_HAS_UART0_SPEED2X
+ 
+#define     HW_UART0_PORT               PORTD
+#define     HW_UART0_DDR                DDRD
+
+#define     HW_UART0_RX_PIN             PD0
+#define     HW_UART0_TX_PIN             PD1
+
+#elif defined( __AVR_ATmega88__ )
+
+#define     HW_HAS_UART0
+#define     HW_HAS_UART0_SPEED2X
+
+#define     HW_UART0_PORT               PORTD
+#define     HW_UART0_DDR                DDRD
+
+#define     HW_UART0_RX_PIN             PD0
+#define     HW_UART0_TX_PIN             PD1
+
+#elif defined( __AVR_ATmega168__ )
+
+#define     HW_HAS_UART0
+#define     HW_HAS_UART0_SPEED2X
+
+#define     HW_UART0_PORT               PORTD
+#define     HW_UART0_DDR                DDRD
+
+#define     HW_UART0_RX_PIN             PD0
+#define     HW_UART0_TX_PIN             PD1
+
+#elif defined( __AVR_ATmega16__ )
+
+#define     HW_HAS_UART0
+ 
+#define     HW_UART0_PORT               PORTD
+#define     HW_UART0_DDR                DDRD
+
+#define     HW_UART0_RX_PIN             PD0
+#define     HW_UART0_TX_PIN             PD1
+
+#elif defined( __AVR_ATmega128__ )
+
+#define     HW_HAS_UART0
+#define     HW_HAS_UART0_SPEED2X
+
+#define     HW_UART0_PORT               PORTE
+#define     HW_UART0_DDR                DDRE
+
+#define     HW_UART0_RX_PIN             PE0
+#define     HW_UART0_TX_PIN             PE1
+
+#define     HW_HAS_UART1
+#define     HW_HAS_UART1_SPEED2X
+
+#define     HW_UART1_PORT               PORTD
+#define     HW_UART1_DDR                DDRD
+
+#define     HW_UART1_RX_PIN             PD2
+#define     HW_UART1_TX_PIN             PD3
+
+#else
+#error Unsupported Hardware
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+//  TWI hardware
+    
+#if defined( __AVR_ATmega8__ )
+
+#define     HW_HAS_TWI
+
+#define     HW_TWI_PORT                 PORTC
+#define     HW_TWI_DDR                  DDRC
+
+#define     HW_TWI_SDA_PIN              PC4
+#define     HW_TWI_SCL_PIN              PC5
+
+#elif defined( __AVR_ATmega88__ )
+
+#define     HW_HAS_TWI
+
+#define     HW_TWI_PORT                 PORTC
+#define     HW_TWI_DDR                  DDRC
+
+#define     HW_TWI_SDA_PIN              PC4
+#define     HW_TWI_SCL_PIN              PC5
+
+#elif defined( __AVR_ATmega168__ )
+
+#define     HW_HAS_TWI
+
+#define     HW_TWI_PORT                 PORTC
+#define     HW_TWI_DDR                  DDRC
+
+#define     HW_TWI_SDA_PIN              PC4
+#define     HW_TWI_SCL_PIN              PC5
+
+#elif defined( __AVR_ATmega16__ )
+
+#define     HW_HAS_TWI
+
+#define     HW_TWI_PORT                 PORTC
+#define     HW_TWI_DDR                  DDRC
+
+#define     HW_TWI_SDA_PIN              PC1
+#define     HW_TWI_SCL_PIN              PC0
+
+#elif defined( __AVR_ATmega128__ )
+
+#define     HW_HAS_TWI
+
+#define     HW_TWI_PORT                 PORTD
+#define     HW_TWI_DDR                  DDRD
+
+#define     HW_TWI_SDA_PIN              PD1
+#define     HW_TWI_SCL_PIN              PD0
+
+#else
+#error Unsupported Hardware
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+//  ADC hardware
+    
+#if defined( __AVR_ATmega8__ )
+
+#define     HW_HAS_ADC
+
+#define     HW_ADC_PORT                 PORTC
+#define     HW_ADC_DDR                  DDRC
+#define     HW_ADC_NUM_CHANNELS         8
+
+#define     HW_ADC_REG_ADCSR            ADCSRA
+#define     HW_ADC_REG_ADCSR_ADFR       ADFR
+
+#define     HW_ADC_REG_ADMUX            ADMUX
+
+#elif defined( __AVR_ATmega88__ )
+
+#define     HW_HAS_ADC
+
+#define     HW_ADC_PORT                 PORTC
+#define     HW_ADC_DDR                  DDRC
+#define     HW_ADC_NUM_CHANNELS         8
+
+#define     HW_ADC_REG_ADCSR            ADCSRA
+#define     HW_ADC_REG_ADCSR_ADFR       ADATE
+#define     HW_ADC_NUM_CHANNELS         8
+
+#define     HW_ADC_REG_ADMUX            ADMUX
+
+#elif defined( __AVR_ATmega168__ )
+
+#define     HW_HAS_ADC
+
+#define     HW_ADC_PORT                 PORTC
+#define     HW_ADC_DDR                  DDRC
+#define     HW_ADC_NUM_CHANNELS         8
+
+#define     HW_ADC_REG_ADCSR            ADCSRA
+#define     HW_ADC_REG_ADCSR_ADFR       ADATE
+#define     HW_ADC_NUM_CHANNELS         8
+
+#define     HW_ADC_REG_ADMUX            ADMUX
+
+#elif defined( __AVR_ATmega16__ )
+
+#define     HW_HAS_ADC
+
+#define     HW_ADC_PORT                 PORTA
+#define     HW_ADC_DDR                  DDRA
+#define     HW_ADC_NUM_CHANNELS         8
+
+#define     HW_ADC_REG_ADCSR            ADCSRA
+#define     HW_ADC_REG_ADCSR_ADATE      ADATE
+
+#define     HW_ADC_REG_ADMUX            ADMUX
+
+#elif defined( __AVR_ATmega128__ )
+
+#define     HW_HAS_ADC
+
+#define     HW_ADC_PORT                 PORTF
+#define     HW_ADC_DDR                  DDRF
+#define     HW_ADC_NUM_CHANNELS         8
+
+#define     HW_ADC_REG_ADCSR            ADCSRA
+#define     HW_ADC_REG_ADCSR_ADFR       ADFR
+#define     HW_ADC_NUM_CHANNELS         8
+
+#define     HW_ADC_REG_ADMUX            ADMUX
+
+#else
+#error Unsupported Hardware
+#endif
+
+
+#endif  // #if !defined( BCDRL_AVR_DEVICE_HWDEFS_H )
+// ----------------------------------------------------------------------------------------
+//  end of hwdefs.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/int_helpers.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,77 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/int_helpers.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides support routines for dealing with interrupts.
+//
+//  Copyright (C) 2008 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "int_helpers.h"
+
+#include "project_defs.h"
+
+
+// ----------------------------------------------------------------------------------------
+  
+void interrupts_clear_all()
+{
+
+#if defined( __AVR_ATmega8__ )
+
+    TIMSK = 0;
+    GICR &= ~( ( 1 << INT1 ) | ( 1 << INT0 ) );
+
+#elif defined( __AVR_ATmega16__ )
+
+    TMSK = 0;
+    GICR &= ~( ( 1 << INT1 ) | ( 1 << INT0 ) | ( 1 << INT2 ) );
+
+#elif defined( __AVR_ATmega88__ ) || defined( __AVR_ATmega168__ )
+
+    TIMSK0 = 0;
+    TIMSK1 = 0;
+    TIMSK2 = 0;
+
+    EIMSK = 0;
+
+    PCICR  = 0;
+    PCMSK0 = 0;
+    PCMSK1 = 0;
+    PCMSK2 = 0;
+
+#elif defined( __AVR_ATmega128__ )
+
+    TIMSK  = 0;
+    ETIMSK = 0;
+
+#else
+#error Unsupported Hardware
+#endif
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  end of int_helpers.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/int_helpers.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,74 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/int_helpers.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides support routines for dealing with interrupts.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_DEVICE_INT_HELPERS_H )
+#define BCDRL_AVR_DEVICE_INT_HELPERS_H
+
+
+#include <stdint.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  interrupts_clear_all
+//
+//      Reset all the enable bits for all possible interrupts.
+//
+
+void interrupts_clear_all();
+
+
+// ----------------------------------------------------------------------------------------
+//  guard_disable_interrupts
+//
+
+class guard_disable_interrupts
+{
+    public:
+    
+        guard_disable_interrupts();
+        ~guard_disable_interrupts();
+    
+    private:
+    
+        guard_disable_interrupts( const guard_disable_interrupts& copy );
+        guard_disable_interrupts& operator=( const guard_disable_interrupts& copy );
+
+        uint8_t m_sreg;
+};
+
+
+// ----------------------------------------------------------------------------------------
+
+#include "int_helpers.inl"
+
+
+#endif  // #if !defined( BCDRL_AVR_DEVICE_INT_HELPERS_H )
+// ----------------------------------------------------------------------------------------
+//  end of int_helpers.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/int_helpers.inl	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,52 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/int_helpers.inl
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides support routines for dealing with interrupts.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include <avr/interrupt.h>
+
+
+// ----------------------------------------------------------------------------------------
+
+inline guard_disable_interrupts::guard_disable_interrupts()
+{
+    m_sreg = SREG;
+    cli();
+}
+
+
+// ----------------------------------------------------------------------------------------
+        
+inline guard_disable_interrupts::~guard_disable_interrupts()
+{
+    SREG = m_sreg;
+}
+    
+
+// ----------------------------------------------------------------------------------------
+//  end of int_helpers.inl
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/jamfile	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,45 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr/device/jamfile
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Copyright (C) 2007 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /packages/avr/device/jamfile" ; }
+
+SubDir TOP packages avr device ;
+
+
+# -----------------------------------------------------------------------------------------
+
+PackageSources
+    adc.cpp
+    int_helpers.cpp
+    spi.cpp
+    spinwait.cpp
+    twi_master.cpp
+    uart.cpp
+    ;
+    
+# -----------------------------------------------------------------------------------------
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/spi.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,236 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/spi.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides the interface for the SPI library.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "spi.h"
+
+#include <avr/io.h>
+
+
+// ----------------------------------------------------------------------------------------
+
+#include "hwdefs.h"
+#include "project_defs.h"
+
+#if defined( PRJ_SPI_ENABLE_MASTER ) || defined( PRJ_SPI_ENABLE_SLAVE )
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SPI_ENABLE_MASTER ) && defined( PRJ_SPI_ENABLE_SLAVE )
+#error Must define only one SPI flavor!
+#endif
+
+#if !defined( PRJ_SPI_BUS_MODE_0 ) && !defined( PRJ_SPI_BUS_MODE_1 )    \
+    && !defined( PRJ_SPI_BUS_MODE_2 ) && !defined( PRJ_SPI_BUS_MODE_3 )
+#error Must define an SPI bus mode!
+#endif
+
+#if !defined( PRJ_SPI_DATA_DIRECTION_MSB ) && !defined( PRJ_SPI_DATA_DIRECTION_LSB )
+#error Must define an SPI data direction flag!
+#endif
+
+#if !defined( PRJ_SPI_CLOCK_FACTOR_DIV_2 )       \
+    && !defined( PRJ_SPI_CLOCK_FACTOR_DIV_4 )    \
+    && !defined( PRJ_SPI_CLOCK_FACTOR_DIV_8 )    \
+    && !defined( PRJ_SPI_CLOCK_FACTOR_DIV_16 )   \
+    && !defined( PRJ_SPI_CLOCK_FACTOR_DIV_32 )   \
+    && !defined( PRJ_SPI_CLOCK_FACTOR_DIV_64 )   \
+    && !defined( PRJ_SPI_CLOCK_FACTOR_DIV_128 )
+#error Must define an SPI bus clock rate!
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+void spi_init()
+{
+    HW_SPI_DDR |= ( 1 << HW_SPI_SCK_PIN  )
+               |  ( 1 << HW_SPI_MOSI_PIN )
+
+#if defined( PRJ_SPI_USE_SLAVE_SELECT ) && defined( PRJ_SPI_ENABLE_MASTER )
+
+               |  ( 1 << HW_SPI_SS_PIN )
+
+#endif
+               ;
+
+    HW_SPI_DDR &= ~( 0
+                    
+               | ( 1 << HW_SPI_MISO_PIN )
+    
+#if defined( PRJ_SPI_USE_SLAVE_SELECT ) && defined( PRJ_SPI_ENABLE_SLAVE )
+
+               | ( 1 << HW_SPI_SS_PIN )
+
+#endif
+               );
+
+    SPCR = 0
+        
+         | ( 0 << SPIE )                // SPI interrupt not enabled
+         | ( 1 << SPE  )                // SPI bus enabled
+
+#if defined( PRJ_SPI_DATA_DIRECTION_MSB )
+
+         | ( 0 << 5 )
+
+#elif defined( PRJ_SPI_DATA_DIRECTION_LSB )
+
+         | ( 1 << 5 )
+
+#endif
+
+#if defined( PRJ_SPI_ENABLE_MASTER )
+
+         | ( 1 << MSTR )
+
+#elif defined( PRJ_SPI_ENABLE_SLAVE )
+
+         | ( 0 << MSTR )
+
+#endif
+
+#if defined( PRJ_SPI_BUS_MODE_0 )
+
+         | ( ( 0 << 3 ) | ( 0 << 2 ) )
+
+#elif defined( PRJ_SPI_BUS_MODE_1 )
+
+         | ( ( 0 << 3 ) | ( 1 << 2 ) )
+
+#elif defined( PRJ_SPI_BUS_MODE_2 )
+
+         | ( ( 1 << 3 ) | ( 0 << 2 ) )
+
+#elif defined( PRJ_SPI_BUS_MODE_3 )
+
+         | ( ( 1 << 3 ) | ( 1 << 2 ) )
+
+#endif
+
+#if defined( PRJ_SPI_CLOCK_FACTOR_DIV_2 )
+
+         | ( ( 0 << 1 ) | ( 0 << 0 ) )
+
+#elif defined( PRJ_SPI_CLOCK_FACTOR_DIV_4 )
+
+         | ( ( 0 << 1 ) | ( 0 << 0 ) )
+
+#elif defined( PRJ_SPI_CLOCK_FACTOR_DIV_8 )
+
+         | ( ( 0 << 1 ) | ( 1 << 0 ) )
+
+#elif defined( PRJ_SPI_CLOCK_FACTOR_DIV_16 )
+
+         | ( ( 0 << 1 ) | ( 1 << 0 ) )
+
+#elif defined( PRJ_SPI_CLOCK_FACTOR_DIV_32 )
+
+         | ( ( 1 << 1 ) | ( 0 << 0 ) )
+
+#elif defined( PRJ_SPI_CLOCK_FACTOR_DIV_64 )
+
+         | ( ( 1 << 1 ) | ( 0 << 0 ) )
+
+#elif defined( PRJ_SPI_CLOCK_FACTOR_DIV_128 )
+
+         | ( ( 1 << 1 ) | ( 1 << 0 ) )
+
+#endif
+
+         ;
+
+#if defined( PRJ_SPI_CLOCK_FACTOR_DIV_2 )       \
+    || defined( PRJ_SPI_CLOCK_FACTOR_DIV_8 )    \
+    || defined( PRJ_SPI_CLOCK_FACTOR_DIV_32 )
+
+    SPSR = ( 1 << SPI2X );
+
+#endif
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+void spi_stop()
+{
+    SPCR &= ~( 1 << SPE );  // SPI bus disabled
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+void spi_write( uint8_t data )
+{
+
+#if defined( PRJ_SPI_USE_SLAVE_SELECT )
+
+    HW_SPI_PORT |= ( 1 << HW_SPI_SS_PIN );
+
+#endif
+
+    SPDR = data;
+
+    // spin-wait for transmission to complete 
+    while ( ! ( SPSR & ( 1 << SPIF ) ) );
+
+    volatile uint8_t unused = SPDR;
+    (void) unused;
+
+#if defined( PRJ_SPI_USE_SLAVE_SELECT )
+
+    HW_SPI_PORT &= ~( 1 << HW_SPI_SS_PIN );
+
+#endif
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+uint8_t spi_read()
+{
+    SPDR = 0;
+
+    // spin-wait for reception to complete
+    while ( ! ( SPSR & ( 1 << SPIF ) ) );
+
+    return SPDR;
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+#endif  // PRJ_SPI_ENABLE_MASTER || PRJ_SPI_ENABLE_SLAVE
+
+
+// ----------------------------------------------------------------------------------------
+//  end of spi.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/spi.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,114 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/spi.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides the interface for the SPI library.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_DEVICE_SPI_H )
+#define BCDRL_AVR_DEVICE_SPI_H
+
+
+#include <stdint.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  enable the SPI support with one (and only one) of:
+//  
+//      + PRJ_SPI_ENABLE_MASTER
+//      + PRJ_SPI_ENABLE_SLAVE
+//
+//  specify the bus mode using one (and only one) of:
+//
+//      + PRJ_SPI_BUS_MODE_0
+//      + PRJ_SPI_BUS_MODE_1
+//      + PRJ_SPI_BUS_MODE_2
+//      + PRJ_SPI_BUS_MODE_3
+//
+//  specify the data direction using one (and only one) of:
+//
+//      + PRJ_SPI_DATA_DIRECTION_MSB
+//      + PRJ_SPI_DATA_DIRECTION_LSB
+//
+//  specify the clock rate using one (and only one) of:
+//
+//      + PRJ_SPI_CLOCK_FACTOR_DIV_2
+//      + PRJ_SPI_CLOCK_FACTOR_DIV_4
+//      + PRJ_SPI_CLOCK_FACTOR_DIV_8
+//      + PRJ_SPI_CLOCK_FACTOR_DIV_16
+//      + PRJ_SPI_CLOCK_FACTOR_DIV_32
+//      + PRJ_SPI_CLOCK_FACTOR_DIV_64
+//      + PRJ_SPI_CLOCK_FACTOR_DIV_128
+//
+//  optionally define:
+//
+//      + PRJ_SPI_USE_SLAVE_SELECT
+//
+// ----------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------------------
+//  spi_init
+//
+//      Initialize and configure the Serial Peripheral Interface hardware according to
+//      the project_defs.h specification.
+//
+
+void spi_init();
+
+
+// ----------------------------------------------------------------------------------------
+//  spi_stop
+//
+//      Disable the SPI h/w.
+//
+
+void spi_stop();
+
+    
+// ----------------------------------------------------------------------------------------
+//  spi_read
+//
+//      Read a byte from the SPI h/w register. Blocks until a byte is available.
+//
+
+uint8_t spi_read();
+
+
+// ----------------------------------------------------------------------------------------
+//  spi_write
+//
+//      Write a byte to the SPI h/w register. Blocks until the write is complete.
+//
+
+void spi_write( uint8_t data );
+
+
+#endif  // #if !defined( BCDRL_AVR_DEVICE_SPI_H )
+// ----------------------------------------------------------------------------------------
+//  end of spi.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/spinwait.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,112 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/spinwait.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides spin-wait delay routines for the Atmel AVR processor family.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "spinwait.h"
+
+
+// ----------------------------------------------------------------------------------------
+
+#include "project_defs.h"
+
+
+// ----------------------------------------------------------------------------------------
+
+#if !defined( PRJ_CPU_FREQ )
+#error undefined value PRJ_CPU_FREQ
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+void spinwait_delay_us( uint16_t microseconds )
+{
+    register uint16_t loop_count;
+
+    // each loop requires 4 instructions, so there is a fixed number of loops required
+    // to delay one microsecond but this varies by clock speed.
+
+#if ( PRJ_CPU_FREQ == 1000000 )
+    
+    // 1mhz clock
+    loop_count = microseconds / 4;
+
+#elif ( PRJ_CPU_FREQ == 2000000 )
+    
+    // 2mhz clock
+    loop_count = microseconds / 2;
+
+#elif ( PRJ_CPU_FREQ == 4000000 )
+    
+    // 4mhz clock
+    loop_count = microseconds;
+
+#elif ( PRJ_CPU_FREQ == 8000000 )
+    
+    // 8mhz clock
+    loop_count = microseconds * 2;
+
+#elif ( PRJ_CPU_FREQ == 16000000 )
+
+    // 16mhz clock
+    loop_count = microseconds * 4;
+
+#elif ( PRJ_CPU_FREQ == 20000000 )
+    
+    // 20mhz clock
+    loop_count = microseconds * 5;
+
+#else
+#error PRJ_CPU_FREQ unrecognized setting!
+#endif
+
+    __asm__ volatile (
+        "1: sbiw %0,1" "\n\t"
+        "brne 1b"
+        : "=w" ( loop_count )
+        : "0"  ( loop_count )
+    );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+void spinwait_delay_ms( uint16_t milliseconds )
+{
+    uint16_t i;
+
+    for ( i = 0; i < milliseconds; ++i )
+    {
+        spinwait_delay_us( 1000 );
+    }
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  end of spinwait.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/spinwait.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,66 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/spinwait.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides spin-wait delay routines for the Atmel AVR processor family.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCD_AVR_DEVICE_SPINWAIT_H )
+#define BCD_AVR_DEVICE_SPINWAIT_H
+
+
+#include <inttypes.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  PRJ_CPU_FREQ <long>
+//
+// ----------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------------------
+//  spinwait_delay_us
+//
+//      Spin-wait for the specified number of microseconds.
+//
+
+void spinwait_delay_us( uint16_t microseconds );
+
+
+// ----------------------------------------------------------------------------------------
+//  spinwait_delay_ms
+//
+//      Spin-wait for the specified number of milliseconds.
+//
+
+void spinwait_delay_ms( uint16_t milliseconds );
+
+
+#endif  // #if !defined( BCD_AVR_DEVICE_SPINWAIT_H )
+// ----------------------------------------------------------------------------------------
+//  end of spinwait.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/twi_master.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,267 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/twi_master.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides the interface for the TWI library, using master mode.
+//
+//  Copyright (C) 2008 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+//  This implementation was heavily inspired by the "i2cmaster.c" from Peter Fleury.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "twi_master.h"
+
+#include <avr/interrupt.h>
+#include <util/twi.h>
+
+#include "hwdefs.h"
+#include "project_defs.h"
+
+
+// ----------------------------------------------------------------------------------------
+//  Project-specific definitions
+//
+
+#if defined( PRJ_TWI_MASTER_ENABLE )
+
+#if !defined( HW_HAS_TWI )
+#error Target HW has no TWI
+#endif
+
+#if !defined( PRJ_TWI_BUS_FREQ )
+#error Must define PRJ_TWI_BUS_FREQ
+#endif
+
+#if ( ( ( PRJ_CPU_FREQ / PRJ_TWI_BUS_FREQ ) - 16 ) / 2 <= 10 )
+#error Selected PRJ_TWI_BUS_FREQ is too high for selected PRJ_CPU_FREQ
+#endif
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_TWI_MASTER_ENABLE )
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_init
+//
+
+void twi_master_init()
+{
+    TWSR = 0; // no prescalar
+    TWBR = ( ( PRJ_CPU_FREQ / PRJ_TWI_BUS_FREQ ) - 16 ) / 2;
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_start
+//
+
+bool twi_master_start( const uint8_t address )
+{
+    //--    Send START condition.
+
+    TWCR = ( 1 << TWINT ) | ( 1 << TWSTA ) | ( 1 << TWEN );
+
+    //--    Wait until transmission completed.
+
+    while ( ! ( TWCR & ( 1 << TWINT ) ) );
+
+    //--    Check status.
+
+    uint8_t status = TW_STATUS & 0xF8;
+
+    if ( ( status != TW_START) && ( status != TW_REP_START ) )
+    {
+        return false;
+    }
+
+    //--    Send device address.
+
+    TWDR = address;
+    TWCR = ( 1 << TWINT ) | ( 1 << TWEN );
+
+    //--    Wail until transmission completed and ACK/NACK has been received.
+
+    while ( ! ( TWCR & ( 1 << TWINT ) ) );
+
+    //--    Check status.
+
+    status = TW_STATUS & 0xF8;
+
+    if ( ( status != TW_MT_SLA_ACK ) && ( status != TW_MR_SLA_ACK ) )
+    {
+        return false;
+    }
+
+    return true;
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_start_repeated
+//
+
+bool twi_master_start_repeated( const uint8_t address )
+{
+    return twi_master_start( address );
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_start_wait
+//
+
+void twi_master_start_wait( const uint8_t address )
+{
+    for ( ;; )
+    {
+        //--    Send START condition.
+        
+        TWCR = (1 << TWINT ) | ( 1 << TWSTA ) | ( 1 << TWEN );
+    
+        //--    Wait until transmission completed.
+
+        while ( ! ( TWCR & ( 1 << TWINT ) ) );
+    
+        //--    Check status.
+
+        uint8_t status = TW_STATUS & 0xf8;
+
+        if ( ( status != TW_START) && ( status != TW_REP_START ) ) 
+        {
+            continue;   // loop around, try again
+        }
+    
+        //--    Send device address.
+
+        TWDR = address;
+        TWCR = ( 1 << TWINT ) | ( 1 << TWEN );
+    
+        //--    Wait until transmission completed.
+
+        while ( ! ( TWCR & ( 1 << TWINT ) ) );
+    
+        //--    Check status.
+
+        status = TW_STATUS & 0xf8;
+
+        if ( ( status == TW_MT_SLA_NACK ) || ( status ==TW_MR_DATA_NACK ) ) 
+        {
+            //--    Device busy, send stop condition to terminate write operation.
+
+            TWCR = ( 1 << TWINT ) | ( 1 << TWEN ) | ( 1 << TWSTO );
+            
+            //--    Wait until stop condition is executed and bus released.
+
+            while ( TWCR & ( 1 << TWSTO ) );
+            
+            continue;
+        }
+
+        //--    Success!
+
+        return;
+     }
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_write
+//
+//      Send a byte to the remote device. Assumes twi_master_start() was successful.
+//
+//      Returns true if the byte was sent successfully.
+//
+
+bool twi_master_write( const uint8_t data )
+{
+    //--    Send.
+
+    TWDR = data;
+    TWCR = ( 1 << TWINT ) | ( 1 << TWEN );
+
+    //--    wait until transmission completed.
+
+    while ( ! ( TWCR & ( 1 << TWINT ) ) );
+
+    //--    Check the result.
+
+    if ( ( TW_STATUS & 0xf8 ) != TW_MT_DATA_ACK )
+    {
+        return false;
+    }
+
+    return true;
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_read_and_request_more
+//
+//      Read a byte from the remote device, and signal that we intend to receive more
+//      data from the device immediately afterwards.
+//
+
+uint8_t twi_master_read_and_request_more()
+{
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_read_and_stop
+//
+//      Read a byte from the remote device, and signal this is the last read (puts a
+//      stop condition on the bus).
+//
+
+uint8_t twi_master_read_and_stop()
+{
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_send_stop
+//
+
+void twi_master_send_stop()
+{
+    /* send stop condition */
+    TWCR = ( 1 << TWINT ) | ( 1 << TWEN ) | ( 1 << TWSTO );
+    
+    // wait until stop condition is executed and bus released
+    while(TWCR & (1<<TWSTO));
+}
+
+
+
+// ----------------------------------------------------------------------------------------
+
+#endif  // #if defined( PRJ_TWI_MASTER_ENABLE )
+
+
+// ----------------------------------------------------------------------------------------
+//  end of twi_master.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/twi_master.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,136 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/twi_master.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides the interface for the TWI library, using master mode.
+//
+//  Copyright (C) 2008 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_DEVICE_TWI_MASTER_H )
+#define BCDRL_AVR_DEVICE_TWI_MASTER_H
+
+
+#include <stdint.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  enable TWI master mode by:
+//  
+//      + PRJ_TWI_MASTER_ENABLE
+//
+//  specify the bus speed (for the master) with:
+//
+//      + PRJ_TWI_BUS_FREQ
+//
+// ----------------------------------------------------------------------------------------
+
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_init
+//
+//      Initialize the TWI h/w for master mode; call this once, before doing any i/o.
+//
+
+void twi_master_init();
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_start
+//
+//      Issue a start condition and send the address of the device to communicate with.
+//
+//      Returns true if the device is now accessible.
+//
+
+bool twi_master_start( const uint8_t address );
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_start_repeated
+//
+//      Similar to twi_master_start() except this is a repeated start.
+//
+//      Returns true if the device is now accessible.
+//
+
+bool twi_master_start_repeated( const uint8_t address );
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_start_wait
+//
+//      Similar to twi_master_start() except it waits for the bus and device to become 
+//      accessible.
+//
+
+void twi_master_start_wait( const uint8_t address );
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_write
+//
+//      Send a byte to the remote device. Assumes twi_master_start() was successful.
+//
+//      Returns true if the byte was sent successfully.
+//
+
+bool twi_master_write( const uint8_t data );
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_read_and_request_more
+//
+//      Read a byte from the remote device, and signal that we intend to receive more
+//      data from the device immediately afterwards.
+//
+
+uint8_t twi_master_read_and_request_more();
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_read_and_stop
+//
+//      Read a byte from the remote device, and signal this is the last read (puts a
+//      stop condition on the bus).
+//
+
+uint8_t twi_master_read_and_stop();
+
+
+// ----------------------------------------------------------------------------------------
+//  twi_master_send_stop
+//
+//      Send a stop condition on the bus.
+//
+
+void twi_master_send_stop();
+
+
+#endif  // #if !defined( BCDRL_AVR_DEVICE_TWI_MASTER_H )
+// ----------------------------------------------------------------------------------------
+//  end of twi_master.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/twi_slave.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,110 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/twi_slave.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides the interface for the TWI (slave mode) library.
+//
+//  Copyright (C) 2009 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_DEVICE_TWI_SLAVE_H )
+#define BCDRL_AVR_DEVICE_TWI_SLAVE_H
+
+
+#include <stdint.h>
+#include <avr/pgmspace.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  enable TWI slave mode with:
+//  
+//      + PRJ_TWI_SLAVE_ENABLED
+//
+//  enable the "extended" read and write modes with:
+//
+//      + PRJ_TWI_SLAVE_EXTENDED_READ_WRITE
+//
+//  optionally define:
+//
+//      + PRJ_TWI_SLAVE_BUFFER_SIZE <int>    [default 16]
+//
+// ----------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------------------
+//  twis_init
+//
+//      Initialize the TWI h/w for "slave" mode; call this once, before doing any i/o.
+//
+//      Specify the 7-bit address; do not left-shift the address (the library does that
+//      for you automatically). Also specify whether messages sent as a "general call"
+//      should be received or ignored.
+//
+
+void twis_init( uint8_t slaveAddress, bool recieveGeneralMessages );
+
+
+// ----------------------------------------------------------------------------------------
+//  twis_stop
+//
+//      Shut down the TWI slave reciever.
+//
+
+void twis_stop();
+
+
+// ----------------------------------------------------------------------------------------
+//  twis_is_data_available
+//
+//      Returns true if any bytes are available.
+//
+
+bool twis_is_data_available();
+
+
+// ----------------------------------------------------------------------------------------
+//  twis_read
+//
+//      Read data from the buffer. Returns the actual number of bytes copied. This
+//      may result in reading zero bytes.
+//      
+
+uint8_t twis_read( uint8_t* data, uint8_t maxlen );
+
+
+// ----------------------------------------------------------------------------------------
+//  twis_write
+//
+//      Send data from the slave to the master. The length of the data must not exceed
+//      the size specified by PRJ_TWI_SLAVE_BUFFER_SIZE.
+//      
+
+void twis_write( const uint8_t* data, uint8_t len );
+
+
+#endif  // #if !defined( BCDRL_AVR_DEVICE_TWI_SLAVE_H )
+// ----------------------------------------------------------------------------------------
+//  end of twi_slave.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/uart.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,884 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/uart.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides the implementation for the UART library.
+//
+//  Copyright (C) 2008 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "uart.h"
+
+#include <avr/interrupt.h>
+
+#include "hwdefs.h"
+#include "project_defs.h"
+
+#include "packages/common/util/cbuffer.h"
+
+
+// ----------------------------------------------------------------------------------------
+//  Project-specific definitions
+//
+
+#if !defined( HW_HAS_UART0 )
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE ) || defined( PRJ_UART0_USE_POLLED_MODE )
+#error Target HW has no UART0
+#endif
+#if defined( PRJ_UART0_EXTENDED_READ_WRITE )
+#error Target HW has no UART0
+#endif
+#endif
+
+#if !defined( HW_HAS_UART1 )
+#if defined( PRJ_UART1_USE_INTERRUPT_MODE ) || defined( PRJ_UART1_USE_POLLED_MODE )
+#error Target HW has no UART1
+#endif
+#if defined( PRJ_UART1_EXTENDED_READ_WRITE )
+#error Target HW has no UART1
+#endif
+#endif
+
+#if !defined( PRJ_UART0_BUFFER_SIZE )
+#define PRJ_UART0_BUFFER_SIZE 16
+#endif
+
+#if ( PRJ_UART0_BUFFER_SIZE == 0 )
+#error PRJ_UART0_BUFFER_SIZE cannot be zero!
+#endif
+
+#if !defined( PRJ_UART1_BUFFER_SIZE )
+#define PRJ_UART1_BUFFER_SIZE 16
+#endif
+
+#if ( PRJ_UART1_BUFFER_SIZE == 0 )
+#error PRJ_UART1_BUFFER_SIZE cannot be zero!
+#endif
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE ) || defined( PRJ_UART1_USE_INTERRUPT_MODE )
+#if ( ( 2 * PRJ_UART0_BUFFER_SIZE + 2 * PRJ_UART1_BUFFER_SIZE ) > HW_RAM_SIZE )
+#error Target HW has insufficient RAM for specified buffer sizes
+#endif
+#endif
+
+#if !defined( PRJ_UART0_USE_INTERRUPT_MODE )
+#undef PRJ_UART0_BUFFER_SIZE
+#endif
+
+#if !defined( PRJ_UART1_USE_INTERRUPT_MODE )
+#undef PRJ_UART1_BUFFER_SIZE
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+//  Note: none of the hardware-specific checks below will error on unrecognized chips
+//  so make that check here.
+//
+
+#if !defined( __AVR_ATmega8__ ) \
+    && !defined( __AVR_ATmega16__ ) \
+    && !defined( __AVR_ATmega88__ ) \
+    && !defined( __AVR_ATmega168__ ) \
+    && !defined( __AVR_ATmega128__ )
+#error Unsupported Hardware
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE ) || defined( PRJ_UART0_USE_POLLED_MODE )
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+static cbytebuffer< PRJ_UART0_BUFFER_SIZE > uart0_rx_buffer;
+static cbytebuffer< PRJ_UART0_BUFFER_SIZE > uart0_tx_buffer;
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+ISR( USART_RXC_vect )
+
+#elif defined( __AVR_ATmega88__ ) || defined( __AVR_ATmega168__ )
+
+ISR( USART_RX_vect )
+
+#elif defined( __AVR_ATmega128__ )
+
+ISR( USART0_RX_vect )
+
+#endif
+{
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+    uint8_t data = UDR;
+
+#elif defined( __AVR_ATmega88__ ) \
+      || defined( __AVR_ATmega168__ ) \
+      || defined( __AVR_ATmega128__ )
+
+    uint8_t data = UDR0;
+
+#endif
+
+    // TODO: error checking in the USRC register, after reading UDR
+
+    if ( uart0_rx_buffer.is_full() )
+    {
+        // overflow error
+
+        // TODO
+    }
+    else
+    {
+        uart0_rx_buffer.push( data );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+ISR( USART_UDRE_vect )
+
+#elif defined( __AVR_ATmega88__ ) || defined( __AVR_ATmega168__ )
+
+ISR( USART_UDRE_vect )
+
+#elif defined( __AVR_ATmega128__ )
+
+ISR( USART0_UDRE_vect )
+
+#endif
+{
+    if ( ! uart0_tx_buffer.is_empty() )
+    {
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+        UDR = uart0_tx_buffer.pop();
+
+#elif defined( __AVR_ATmega88__ ) \
+      || defined( __AVR_ATmega168__ ) \
+      || defined( __AVR_ATmega128__ )
+
+        UDR0 = uart0_tx_buffer.pop();
+
+#endif
+
+    }
+    else
+    {
+        // tx buffer empty, disable the interrupt
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+        UCSRB &= ~( 1 << UDRIE );
+
+#elif defined( __AVR_ATmega88__ ) \
+      || defined( __AVR_ATmega168__ ) \
+      || defined( __AVR_ATmega128__ )
+
+        UCSR0B &= ~( 1 << UDRIE0 );
+
+#endif
+
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+void uart0_init()
+{
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+    UCSRB = 0
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+          | ( 1 << RXCIE )                      // enable receive complete interrupts
+          | ( 0 << TXCIE )                      // no transmit complete interrupts
+          | ( 0 << UDRIE )                      // no data register empty interrupts
+
+#else // defined( PRJ_UART0_USE_POLLED_MODE )
+
+          | ( 0 << RXCIE )                      // no interrupts
+          | ( 0 << TXCIE )
+          | ( 0 << UDRIE )
+
+#endif
+        
+          | ( 1 << RXEN  )                      // receiver enabled
+          | ( 1 << TXEN  )                      // transmitter enabled
+          | ( 0 << UCSZ2 )                      // eight data bits
+          | ( 0 << RXB8  )                      // rx ninth-bit (ro)
+          | ( 0 << TXB8  )                      // tx ninth-bit
+          ;
+    
+    UCSRC = 0
+
+          | ( 1 << URSEL )                      // writing the UCSCR register
+          | ( 0 << UMSEL )                      // asynchronous mode
+          | ( 0 << UPM1  )                      // parity mode disabled
+          | ( 0 << UPM0  )
+          | ( 0 << USBS  )                      // one stop bit
+          | ( 1 << UCSZ1 )                      // eight data bits
+          | ( 1 << UCSZ0 )
+          | ( 0 << UCPOL )                      // unused in async mode
+          ;
+
+    //-------------------------------------------------------------------------------------
+
+#elif defined( __AVR_ATmega88__ ) || defined( __AVR_ATmega168__ )
+
+    UCSR0B = 0
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+           | ( 1 << RXCIE0 )                    // enable receive complete interrupts
+           | ( 0 << TXCIE0 )                    // no transmit complete interrupts
+           | ( 0 << UDRIE0 )                    // no data register empty interrupts
+
+#else // defined( PRJ_UART0_USE_POLLED_MODE )
+
+           | ( 0 << RXCIE0 )                    // no interrupts
+           | ( 0 << TXCIE0 )
+           | ( 0 << UDRIE0 )
+
+#endif
+
+           | ( 1 << RXEN0  )                    // receiver enabled
+           | ( 1 << TXEN0  )                    // transmitter enabled
+           | ( 0 << UCSZ02 )                    // eight data bits
+           | ( 0 << RXB80  )                    // rx ninth-bit (ro)
+           | ( 0 << TXB80  )                    // tx ninth-bit
+           ;
+        
+    UCSR0C = 0
+        
+           | ( 1 << UMSEL01 )                   // asynchronous mode
+           | ( 1 << UMSEL00 )
+           | ( 0 << UPM01  )                    // parity mode disabled
+           | ( 0 << UPM00  )
+           | ( 0 << USBS0  )                    // one stop bit
+           | ( 1 << UCSZ01 )                    // eight data bits
+           | ( 1 << UCSZ00 )
+           | ( 0 << UCPOL0 )                    // unused in async mode
+           ;
+        
+
+    //-------------------------------------------------------------------------------------
+
+#elif defined( __AVR_ATmega128__ )
+
+    UCSR0A = 0;
+
+    UCSR0B = 0
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+           | ( 1 << RXCIE0 )                    // enable receive complete interrupts
+           | ( 0 << TXCIE0 )                    // no transmit complete interrupts
+           | ( 0 << UDRIE0 )                    // no data register empty interrupts
+
+#else // defined( PRJ_UART0_USE_POLLED_MODE )
+
+           | ( 0 << RXCIE0 )                    // no interrupts
+           | ( 0 << TXCIE0 )
+           | ( 0 << UDRIE0 )
+
+#endif
+
+           | ( 1 << RXEN0  )                    // receiver enabled
+           | ( 1 << TXEN0  )                    // transmitter enabled
+           | ( 0 << UCSZ02 )                    // eight data bits
+           | ( 0 << RXB80  )                    // rx ninth-bit (ro)
+           | ( 0 << TXB80  )                    // tx ninth-bit
+           ;
+        
+    UCSR0C = 0
+        
+           | ( 0 << UMSEL0 )                    // asynchronous mode
+           | ( 0 << UPM01  )                    // parity mode disabled
+           | ( 0 << UPM00  )
+           | ( 0 << USBS0  )                    // one stop bit
+           | ( 1 << UCSZ01 )                    // eight data bits
+           | ( 1 << UCSZ00 )
+           | ( 0 << UCPOL0 )                    // unused in async mode
+           ;
+        
+
+#endif  // #if defined( ...processor selection... )
+
+#if defined( PRJ_UART0_INITIAL_BAUDRATE )
+
+    uart0_set_baudrate( PRJ_UART0_INITIAL_BAUDRATE );
+
+#endif
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+void uart0_set_baudregisters( uint8_t highbyte, uint8_t lowbyte )
+{
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+    UBRRH = highbyte;   // the caller is required to mask off the top bits
+    UBRRL = lowbyte;
+    
+    //-------------------------------------------------------------------------------------
+
+#elif defined( __AVR_ATmega88__ ) \
+      || defined( __AVR_ATmega168__ ) \
+      || defined( __AVR_ATmega128__ )
+
+    UBRR0H = highbyte;  // the caller is required to mask off the top bits
+    UBRR0L = lowbyte;
+    
+#endif
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+bool uart0_is_char_available()
+{
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+    return ! uart0_rx_buffer.is_empty();
+
+#else   // defined( PRJ_UART0_USE_POLLED_MODE )
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+        return ( UCSRA & ( 1 << RXC ) ) != 0;
+
+
+#elif defined( __AVR_ATmega88__ ) \
+      || defined( __AVR_ATmega168__ ) \
+      || defined( __AVR_ATmega128__ )
+
+        return ( UCSR0A & ( 1 << RXC0 ) ) != 0;
+
+#endif
+
+#endif  // #if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+uint8_t uart0_read()
+{
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+    return uart0_rx_buffer.wait_and_pop();
+    
+#else   // defined( PRJ_UART0_USE_POLLED_MODE )
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+    while ( ! ( UCSRA & ( 1 << RXC ) ) ) ;
+    return UDR;
+
+#elif defined( __AVR_ATmega88__ ) \
+      || defined( __AVR_ATmega168__ ) \
+      || defined( __AVR_ATmega128__ )
+
+    while ( ! ( UCSR0A & ( 1 << RXC0 ) ) ) ;
+    return UDR0;
+
+#endif
+
+#endif  // #if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+#if defined( PRJ_UART0_EXTENDED_READ_WRITE )
+
+void uart0_read( uint8_t* data, uint8_t len )
+{
+    while ( len > 0 )
+    {
+        *data++ = uart0_read();
+        --len;
+    }
+}
+
+#endif  // PRJ_UART0_EXTENDED_READ_WRITE
+
+
+// ----------------------------------------------------------------------------------------
+    
+void uart0_write( uint8_t data )
+{
+
+#if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+    //--    Wait for space in the buffer.
+
+    uart0_tx_buffer.wait_and_push( data );
+
+    //--    Enable UDRE interrupt, its handler will stuff bytes to the UART h/w.
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+    UCSRB |= ( 1 << UDRIE );
+
+#elif defined( __AVR_ATmega88__ ) \
+      || defined( __AVR_ATmega168__ ) \
+      || defined( __AVR_ATmega128__ )
+
+    UCSR0B |= ( 1 << UDRIE0 );
+
+#endif
+
+#else   // defined( PRJ_UART0_USE_POLLED_MODE )
+
+#if defined( __AVR_ATmega8__ ) || defined( __AVR_ATmega16__ )
+
+    while ( ! ( UCSRA & ( 1 << UDRE ) ) ) ;
+    UDR = data;
+
+#elif defined( __AVR_ATmega88__ ) \
+      || defined( __AVR_ATmega168__ ) \
+      || defined( __AVR_ATmega128__ )
+
+    while ( ! ( UCSR0A & ( 1 << UDRE0 ) ) ) ;
+    UDR0 = data;
+
+#endif
+
+#endif  // #if defined( PRJ_UART0_USE_INTERRUPT_MODE )
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+#if defined( PRJ_UART0_EXTENDED_READ_WRITE )
+
+void uart0_write( const uint8_t* data, uint8_t len )
+{
+    while ( len > 0 )
+    {
+        uart0_write( *data++ );
+        --len;
+    }
+}
+
+void uart0_write( const char* str )
+{
+    while ( *str != '\0' )
+    {
+        uart0_write( static_cast< uint8_t >( *str++ ) );
+    }
+}
+
+#endif  // PRJ_UART0_EXTENDED_READ_WRITE
+
+
+// ----------------------------------------------------------------------------------------
+//  These functions use pgm_read_byte. Two things to know about pgm_read_byte:
+//
+//  1. it's a macro so don't use inline post/pre-increment
+//  2. it's only able to access the lower 64K; see <avr/pgmspace.h> for more info
+//
+
+#if defined( PRJ_UART0_EXTENDED_READ_WRITE )
+
+void uart0_write_pgm( const prog_uint8_t* data, uint8_t len )
+{
+
+    while ( len > 0 )
+    {
+        uart0_write( pgm_read_byte( data ) );
+        data++;
+        --len;
+    }
+}
+
+void uart0_write_pgm( const prog_char* str )
+{
+    char c;
+
+    while ( ( c = static_cast< char >( pgm_read_byte( str ) ) ) != '\0' )
+    {
+        uart0_write( c );
+        str++;
+    }
+}
+
+#endif  // PRJ_UART0_EXTENDED_READ_WRITE
+
+
+// ----------------------------------------------------------------------------------------
+
+#endif  // PRJ_UART0_USE_INTERRUPT_MODE || PRJ_UART0_USE_POLLED_MODE
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_UART1_USE_INTERRUPT_MODE ) || defined( PRJ_UART1_USE_POLLED_MODE )
+
+
+// TODO ...
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_UART1_USE_INTERRUPT_MODE )
+
+static cbytebuffer< PRJ_UART1_BUFFER_SIZE > uart1_rx_buffer;
+static cbytebuffer< PRJ_UART1_BUFFER_SIZE > uart1_tx_buffer;
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_UART1_USE_INTERRUPT_MODE )
+
+#if defined( __AVR_ATmega128__ )
+
+ISR( USART1_RX_vect )
+
+#endif
+{
+
+#if defined( __AVR_ATmega128__ )
+
+    uint8_t data = UDR1;
+
+#endif
+
+    // TODO: error checking in the USRC register, after reading UDR
+
+    if ( uart1_rx_buffer.is_full() )
+    {
+        // overflow error
+
+        // TODO
+    }
+    else
+    {
+        uart1_rx_buffer.push( data );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_UART1_USE_INTERRUPT_MODE )
+
+#if defined( __AVR_ATmega128__ )
+
+ISR( USART1_UDRE_vect )
+
+#endif
+
+{
+    if ( ! uart1_tx_buffer.is_empty() )
+    {
+
+#if defined( __AVR_ATmega128__ )
+
+        UDR1 = uart1_tx_buffer.pop();
+
+#endif
+
+    }
+    else
+    {
+        // tx buffer empty, disable the interrupt
+
+#if defined( __AVR_ATmega128__ )
+
+        UCSR1B &= ~( 1 << UDRIE1 );
+
+#endif
+
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+void uart1_init()
+{
+
+#if defined( __AVR_ATmega128__ )
+    
+    UCSR1A = 0;
+
+    UCSR1B = 0
+
+#if defined( PRJ_UART1_USE_INTERRUPT_MODE )
+
+           | ( 1 << RXCIE1 )                    // enable receive complete interrupts
+           | ( 0 << TXCIE1 )                    // no transmit complete interrupts
+           | ( 0 << UDRIE1 )                    // no data register empty interrupts
+
+#else // defined( PRJ_UART1_USE_POLLED_MODE )
+
+           | ( 0 << RXCIE1 )                    // no interrupts
+           | ( 0 << TXCIE1 )
+           | ( 0 << UDRIE1 )
+
+#endif
+
+           | ( 1 << RXEN1  )                    // receiver enabled
+           | ( 1 << TXEN1  )                    // transmitter enabled
+           | ( 0 << UCSZ12 )                    // eight data bits
+           | ( 0 << RXB81  )                    // rx ninth-bit (ro)
+           | ( 0 << TXB81  )                    // tx ninth-bit
+           ;
+        
+    UCSR0C = 0
+        
+           | ( 0 << UMSEL1 )                    // asynchronous mode
+           | ( 0 << UPM11  )                    // parity mode disabled
+           | ( 0 << UPM10  )
+           | ( 0 << USBS1  )                    // one stop bit
+           | ( 1 << UCSZ11 )                    // eight data bits
+           | ( 1 << UCSZ10 )
+           | ( 0 << UCPOL1 )                    // unused in async mode
+           ;
+        
+
+#endif  // #if defined( ...processor selection... )
+
+#if defined( PRJ_UART1_INITIAL_BAUDRATE )
+
+    uart1_set_baudrate( PRJ_UART1_INITIAL_BAUDRATE );
+
+#endif
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+void uart1_set_baudregisters( uint8_t highbyte, uint8_t lowbyte )
+{
+
+#if defined( __AVR_ATmega128__ )
+
+    UBRR1H = highbyte;  // the caller is required to mask off the top bits
+    UBRR1L = lowbyte;
+    
+#endif
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+bool uart1_is_char_available()
+{
+
+#if defined( PRJ_UART1_USE_INTERRUPT_MODE )
+
+    return ! uart1_rx_buffer.is_empty();
+
+#else   // defined( PRJ_UART1_USE_POLLED_MODE )
+
+#if defined( __AVR_ATmega128__ )
+
+        return ( UCSR1A & ( 1 << RXC1 ) ) != 0;
+
+#endif
+
+#endif  // #if defined( PRJ_UART1_USE_INTERRUPT_MODE )
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+uint8_t uart1_read()
+{
+
+#if defined( PRJ_UART1_USE_INTERRUPT_MODE )
+
+    return uart1_rx_buffer.wait_and_pop();
+    
+#else   // defined( PRJ_UART1_USE_POLLED_MODE )
+
+#if defined( __AVR_ATmega128__ )
+
+    while ( ! ( UCSR1A & ( 1 << RXC1 ) ) ) ;
+    return UDR1;
+
+#endif
+
+#endif  // #if defined( PRJ_UART1_USE_INTERRUPT_MODE )
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+#if defined( PRJ_UART1_EXTENDED_READ_WRITE )
+
+void uart1_read( uint8_t* data, uint8_t len )
+{
+    while ( len > 0 )
+    {
+        *data++ = uart1_read();
+        --len;
+    }
+}
+
+#endif  // PRJ_UART1_EXTENDED_READ_WRITE
+
+
+// ----------------------------------------------------------------------------------------
+    
+void uart1_write( uint8_t data )
+{
+
+#if defined( PRJ_UART1_USE_INTERRUPT_MODE )
+
+    //--    Wait for space in the buffer.
+
+    uart1_tx_buffer.wait_and_push( data );
+
+    //--    Enable UDRE interrupt, its handler will stuff bytes to the UART h/w.
+
+#if defined( __AVR_ATmega128__ )
+
+    UCSR1B |= ( 1 << UDRIE1 );
+
+#endif
+
+#else   // defined( PRJ_UART1_USE_POLLED_MODE )
+
+#if defined( __AVR_ATmega128__ )
+
+    while ( ! ( UCSR1A & ( 1 << UDRE1 ) ) ) ;
+    UDR1 = data;
+
+#endif
+
+#endif  // #if defined( PRJ_UART1_USE_INTERRUPT_MODE )
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+#if defined( PRJ_UART1_EXTENDED_READ_WRITE )
+
+void uart1_write( const uint8_t* data, uint8_t len )
+{
+    while ( len > 0 )
+    {
+        uart1_write( *data++ );
+        --len;
+    }
+}
+
+void uart1_write( const char* str )
+{
+    while ( *str != '\0' )
+    {
+        uart1_write( static_cast< uint8_t >( *str++ ) );
+    }
+}
+
+#endif  // PRJ_UART1_EXTENDED_READ_WRITE
+
+
+// ----------------------------------------------------------------------------------------
+//  These functions use pgm_read_byte. Two things to know about pgm_read_byte:
+//
+//  1. it's a macro so don't use inline post/pre-increment
+//  2. it's only able to access the lower 64K; see <avr/pgmspace.h> for more info
+//
+
+#if defined( PRJ_UART1_EXTENDED_READ_WRITE )
+
+void uart1_write_pgm( const prog_uint8_t* data, uint8_t len )
+{
+
+    while ( len > 0 )
+    {
+        uart1_write( pgm_read_byte( data ) );
+        data++;
+        --len;
+    }
+}
+
+void uart1_write_pgm( const prog_char* str )
+{
+    char c;
+
+    while ( ( c = static_cast< char >( pgm_read_byte( str ) ) ) != '\0' )
+    {
+        uart1_write( c );
+        str++;
+    }
+}
+
+#endif  // PRJ_UART1_EXTENDED_READ_WRITE
+
+
+// ----------------------------------------------------------------------------------------
+
+#endif  // PRJ_UART1_USE_INTERRUPT_MODE || PRJ_UART1_USE_POLLED_MODE
+
+
+// ----------------------------------------------------------------------------------------
+//  end of uart.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/device/uart.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,188 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/device/uart.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides the interface for the UART library.
+//
+//  Copyright (C) 2008 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_DEVICE_UART_H )
+#define BCDRL_AVR_DEVICE_UART_H
+
+
+#include <stdint.h>
+#include <avr/pgmspace.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  enable uart0 by using one (and only one) of:
+//  
+//      + PRJ_UART0_USE_INTERRUPT_MODE
+//      + PRJ_UART0_USE_POLLED_MODE
+//
+//  enable uart1 by using one (and only one) of:
+//
+//      + PRJ_UART1_USE_INTERRUPT_MODE
+//      + PRJ_UART1_USE_POLLED_MODE
+//
+//  optionally set an initial baud rate with:
+//  
+//      + PRJ_UART0_INITIAL_BAUDRATE
+//      + PRJ_UART1_INITIAL_BAUDRATE
+//
+//  enable the "extended" read and write modes with:
+//
+//      + PRJ_UART0_EXTENDED_READ_WRITE
+//      + PRJ_UART1_EXTENDED_READ_WRITE
+//
+//  if using INTERRUPT_MODE then optionally define:
+//
+//      + PRJ_UART0_BUFFER_SIZE <int>
+//      + PRJ_UART1_BUFFER_SIZE <int>
+//
+// ----------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------------------
+//  uart*_init
+//
+//      Initialize the specified UART h/w; call this once, before doing any serial i/o.
+//
+//      If PRJ_UART*_INITIAL_BAUDRATE is defined then the intial baudrate will be set by
+//      this function. If not set, the caller is responsible for setting a proper value.
+//
+
+void uart0_init();
+void uart1_init();
+
+
+// ----------------------------------------------------------------------------------------
+//  uart*_set_baudrate
+//
+//      Use this macro to set the desired baud rate for a specified UART. Everything else
+//      is computed at compile-time for you.
+//
+//      Example: uart0_set_baudrate( 9600 );
+//
+
+#define uart0_set_baudrate( baudrate ) \
+            uart0_set_baudregisters( \
+            ( ( ( PRJ_CPU_FREQ / ( (baudrate) * 16L ) - 1 ) >> 8 ) & 0x0F ), \
+            ( ( ( PRJ_CPU_FREQ / ( (baudrate) * 16L ) - 1 ) ) ) & 0xFF )
+
+#define uart1_set_baudrate( baudrate ) \
+            uart1_set_baudregisters( \
+            ( ( ( PRJ_CPU_FREQ / ( (baudrate) * 16L ) - 1 ) >> 8 ) & 0x0F ), \
+            ( ( ( PRJ_CPU_FREQ / ( (baudrate) * 16L ) - 1 ) ) ) & 0xFF )
+
+
+// ----------------------------------------------------------------------------------------
+//  uart*_set_baudregisters
+//
+//      Set the high and low bytes of the UART baud rate registers. Either compute them
+//      directly (correctly masking the high byte to account for only modifying the low
+//      four bits) or use the set_baudrate macro defined above.
+//
+
+void uart0_set_baudregisters( uint8_t highbyte, uint8_t lowbyte );
+void uart1_set_baudregisters( uint8_t highbyte, uint8_t lowbyte );
+
+
+// ----------------------------------------------------------------------------------------
+//  uart*_is_char_available
+//
+//      Returns true if a character is available.
+//
+
+bool uart0_is_char_available();
+bool uart1_is_char_available();
+
+
+// ----------------------------------------------------------------------------------------
+//  uart*_read
+//
+//      Read a character from the UART. Blocks until a character is available.
+//
+
+uint8_t uart0_read();
+uint8_t uart1_read();
+
+
+// ----------------------------------------------------------------------------------------
+//  uart*_read
+//
+//      These functions are only available if PRJ_UART*_EXTENDED_READ_WRITE is defined.
+//      
+
+void uart0_read( const uint8_t* data, uint8_t len );
+void uart1_read( const uint8_t* data, uint8_t len );
+
+
+// ----------------------------------------------------------------------------------------
+//  uart*_write
+//
+//      Write a character to the UART buffer. In "polled" mode this function blocks
+//      until the character can be written to the h/w buffe. In "interrupt" mode this
+//      function blocks only if there is no buffer space available.
+//
+
+void uart0_write( uint8_t data );
+void uart1_write( uint8_t data );
+
+
+// ----------------------------------------------------------------------------------------
+//  uart*_write
+//
+//      These functions are only available if PRJ_UART*_EXTENDED_READ_WRITE is defined.
+//      
+
+void uart0_write( const uint8_t* data, uint8_t len );
+void uart0_write( const char* str );
+
+void uart1_write( const uint8_t* data, uint8_t len );
+void uart1_write( const char* str );
+
+
+// ----------------------------------------------------------------------------------------
+//  uart*_write_pgm
+//
+//      Write bytes stored in "program memory" to the UART buffer. These functions can
+//      only access the lower 64k of memory, see the implementation for details.
+//
+//      These functions are only available if PRJ_UART*_EXTENDED_READ_WRITE is defined.
+//
+
+void uart0_write_pgm( const prog_uint8_t* data, uint8_t len );
+void uart0_write_pgm( const prog_char* str );
+
+void uart1_write_pgm( const prog_uint8_t* data, uint8_t len );
+void uart1_write_pgm( const prog_char* str );
+
+
+#endif  // #if !defined( BCDRL_AVR_DEVICE_UART_H )
+// ----------------------------------------------------------------------------------------
+//  end of uart.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/jamdefs	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,41 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr/jamdefs
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Copyright (C) 2008 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /packages/avr/jamdefs" ; }
+
+
+# -----------------------------------------------------------------------------------------
+
+DefinePackages TOP packages avr : can common device redir ;
+
+
+# -----------------------------------------------------------------------------------------
+
+SubIncludeJamdefs TOP packages avr : lcd sensors ;
+
+
+# -----------------------------------------------------------------------------------------
+
Binary file main/packages/avr/lcd/.DS_Store has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/lcd/cfax/cfax.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,948 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/lcd/cfax/cfax.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file implements support for the Crystal Fontz CFAX 128x64.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+//  Portions copied from "CFAX_LCD_Example.c" provided by Spark Fun Electronics.
+//  See http://www.sparkfun.com/datasheets/LCD/CFAX_LCD_Example.c
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "cfax.h"
+
+#include <avr/io.h>
+
+#include "packages/avr/device/spinwait.h"
+#include "packages/avr/device/adc.h"
+
+#include "project_defs.h"
+
+
+#if defined( PRJ_CFAX_ENABLE )
+
+
+// ----------------------------------------------------------------------------------------
+
+#if !defined( PRJ_CFAX_DATA_PORT )
+#error PRJ_CFAX_DATA_PORT is required!
+#endif
+
+#if !defined( PRJ_CFAX_DATA_PORT_PINS )
+#error PRJ_CFAX_DATA_PORT_PINS is required!
+#endif
+
+#if !defined( PRJ_CFAX_DATA_DDR )
+#error PRJ_CFAX_DATA_DDR is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RSTB_PORT )
+#error PRJ_CFAX_CONTROL_RSTB_PORT is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RSTB_PIN )
+#error PRJ_CFAX_CONTROL_RSTB_PIN is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RSTB_DDR )
+#error PRJ_CFAX_CONTROL_RSTB_DDR is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RS_PORT )
+#error PRJ_CFAX_CONTROL_RS_PORT is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RS_PIN )
+#error PRJ_CFAX_CONTROL_RS_PIN is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RS_DDR )
+#error PRJ_CFAX_CONTROL_RS_DDR is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RD_PORT )
+#error PRJ_CFAX_CONTROL_RD_PORT is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RD_PIN )
+#error PRJ_CFAX_CONTROL_RD_PIN is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RD_DDR )
+#error PRJ_CFAX_CONTROL_RD_DDR is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RW_PORT )
+#error PRJ_CFAX_CONTROL_RW_PORT is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RW_PIN )
+#error PRJ_CFAX_CONTROL_RW_PIN is required!
+#endif
+
+#if !defined( PRJ_CFAX_CONTROL_RW_DDR )
+#error PRJ_CFAX_CONTROL_RW_DDR is required!
+#endif
+
+#if defined( PRJ_CFAX_INC_TOUCHSCREEN )
+
+#if !defined( PRJ_CFAX_TOUCHSCREEN_PORT )
+#error PRJ_CFAX_TOUCHSCREEN_PORT is required!
+#endif
+
+#if !defined( PRJ_CFAX_TOUCHSCREEN_DDR )
+#error PRJ_CFAX_TOUCHSCREEN_DDR is required!
+#endif
+
+#if !defined( PRJ_CFAX_TOUCHSCREEN_PIN_1 )
+#error PRJ_CFAX_TOUCHSCREEN_PIN_1 is required!
+#endif
+
+#if !defined( PRJ_CFAX_TOUCHSCREEN_PIN_2 )
+#error PRJ_CFAX_TOUCHSCREEN_PIN_2 is required!
+#endif
+
+#if !defined( PRJ_CFAX_TOUCHSCREEN_PIN_3 )
+#error PRJ_CFAX_TOUCHSCREEN_PIN_3 is required!
+#endif
+
+#if !defined( PRJ_CFAX_TOUCHSCREEN_PIN_4 )
+#error PRJ_CFAX_TOUCHSCREEN_PIN_4 is required!
+#endif
+
+#if !defined( PRJ_CFAX_TOUCHSCREEN_ADC_CH_1 )
+#error PRJ_CFAX_TOUCHSCREEN_ADC_CH_1 is required!
+#endif
+
+#if !defined( PRJ_CFAX_TOUCHSCREEN_ADC_CH_2 )
+#error PRJ_CFAX_TOUCHSCREEN_ADC_CH_2 is required!
+#endif
+
+#if !defined( PRJ_CFAX_TOUCHSCREEN_ADC_CH_3 )
+#error PRJ_CFAX_TOUCHSCREEN_ADC_CH_3 is required!
+#endif
+
+#if !defined( PRJ_CFAX_TOUCHSCREEN_ADC_CH_4 )
+#error PRJ_CFAX_TOUCHSCREEN_ADC_CH_4 is required!
+#endif
+
+#endif // #if defined( PRJ_CFAX_INC_TOUCHSCREEN )
+
+#if defined( PRJ_CFAX_INC_WRITE_CSTRINGS ) || defined( PRJ_CFAX_INC_WRITE_PGM_CSTRINGS )
+#if !defined( PRJ_CFAX_INC_WRITE_CHAR )
+#define PRJ_CFAX_INC_WRITE_CHAR
+#endif
+#endif
+
+#if defined( PRJ_CFAX_INC_DRAWING ) || defined( PRJ_CFAX_INC_BITMAPS )
+#define PRJ_CFAX_INC_SET_PIXEL
+#endif
+
+#if !defined( PRJ_CFAX_DEFAULT_CONTRAST )
+#define PRJ_CFAX_DEFAULT_CONTRAST 38
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+const uint8_t CFAX_MAX_HORIZONTAL_PIXELS   = 128;
+const uint8_t CFAX_MAX_VERTICAL_PIXELS     =  64;
+const uint8_t CFAX_MAX_VERTICAL_PAGES      = 8;
+const uint8_t CFAX_HORIZONTAL_PIXEL_OFFSET = ( 132 - 128 );
+
+const uint8_t CFAX_MAX_HORIZONTAL_CHARS = ( CFAX_MAX_HORIZONTAL_PIXELS / 6 );
+const uint8_t CFAX_MAX_VERTICAL_CHARS   = CFAX_MAX_VERTICAL_PAGES;
+
+const uint8_t CFAX_COMMAND_SEL_COLUMN_LSB = 0x00;
+const uint8_t CFAX_COMMAND_SEL_COLUMN_MSB = 0x10;
+const uint8_t CFAX_COMMAND_SEL_PAGE       = 0xb0;
+
+const uint8_t CFAX_COMMAND_IDL = 0x40;
+
+const uint8_t CFAX_COMMAND_VREF = 0x81;
+
+const uint8_t CFAX_COMMAND_ADC_OFF = 0xa0;
+const uint8_t CFAX_COMMAND_ADC_ON  = 0xa1;
+
+const uint8_t CFAX_COMMAND_BAS_OFF = 0xa2;
+const uint8_t CFAX_COMMAND_BAS_ON  = 0xa3;
+
+const uint8_t CFAX_COMMAND_DON_OFF = 0xae;
+const uint8_t CFAX_COMMAND_DON_ON  = 0xaf;
+
+const uint8_t CFAX_COMMAND_SHL_ON  = 0xc8;
+const uint8_t CFAX_COMMAND_SHL_OFF = 0xc0;
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_ICONS )
+
+static const prog_uint8_t cfax_icon_ids[] =
+{
+    0x07,   // maple leaf
+    0x11,   // document
+    0x18,   // battery outline
+    0x16,   // battery level 1
+    0x15,   // battery level 2
+    0x17,   // battery levle 3
+    0x28,   // terminal / computer
+    0x33,   // antenna
+    0x3c,   // speaker
+    0x39,   // speaker tick top-left
+    0x41,   // speaker tick bottom-right
+    0x49,   // telephone
+    0x54,   // letter
+    0x5f,   // bell
+    0x6a,   // clock
+    0x75,   // caution triangle
+    0x7f    // spinner
+};
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_WRITE_CHAR )
+
+typedef prog_uint8_t cfax_glyph_t[ 5 ];
+
+static const cfax_glyph_t glyphs[] =
+{
+    { 0x00, 0x00, 0x00, 0x00, 0x00 },   // space, ascii 0x20
+    { 0x00, 0x00, 0x4f, 0x00, 0x00 },   // !
+    { 0x00, 0x07, 0x00, 0x07, 0x00 },   // "
+    { 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // #
+    { 0x24, 0x2a, 0x7f, 0x2a, 0x12 },   // $
+    { 0x23, 0x13, 0x08, 0x64, 0x62 },   // %
+    { 0x00, 0x02, 0x05, 0x02, 0x00 },   // &
+    { 0x00, 0x05, 0x03, 0x00, 0x00 },   // '
+    { 0x1C, 0x22, 0x41, 0x00, 0x00 },   // (
+    { 0x00, 0x00, 0x41, 0x22, 0x1C },   // )
+    { 0x14, 0x08, 0x3E, 0x08, 0x14 },   // *
+    { 0x08, 0x08, 0x3E, 0x08, 0x08 },   // +
+    { 0x00, 0x50, 0x30, 0x00, 0x00 },   // ,
+    { 0x08, 0x08, 0x08, 0x08, 0x08 },   // -
+    { 0x00, 0x60, 0x60, 0x00, 0x00 },   // .
+    { 0x20, 0x10, 0x08, 0x04, 0x02 },   // /
+    { 0x3e, 0x51, 0x49, 0x45, 0x3e },   // 0
+    { 0x00, 0x42, 0x7f, 0x40, 0x00 },   // 1
+    { 0x42, 0x61, 0x51, 0x49, 0x46 },   // 2
+    { 0x21, 0x41, 0x45, 0x4B, 0x31 },   // 3
+    { 0x18, 0x14, 0x12, 0x7f, 0x10 },   // 4
+    { 0x27, 0x45, 0x45, 0x45, 0x39 },   // 5
+    { 0x3c, 0x4a, 0x49, 0x49, 0x30 },   // 6
+    { 0x01, 0x71, 0x09, 0x05, 0x03 },   // 7
+    { 0x36, 0x49, 0x49, 0x49, 0x36 },   // 8
+    { 0x06, 0x49, 0x49, 0x49, 0x36 },   // 9
+    { 0x00, 0x36, 0x36, 0x00, 0x00 },   // :
+    { 0x00, 0x56, 0x36, 0x00, 0x00 },   // ;
+    { 0x08, 0x14, 0x22, 0x41, 0x00 },   // <
+    { 0x14, 0x14, 0x14, 0x14, 0x14 },   // =
+    { 0x00, 0x41, 0x22, 0x14, 0x08 },   // >
+    { 0x02, 0x01, 0x51, 0x09, 0x06 },   // ?
+    { 0x32, 0x49, 0x79, 0x41, 0x3e },   // @
+    { 0x7e, 0x11, 0x11, 0x11, 0x7e },   // A
+    { 0x7f, 0x49, 0x49, 0x49, 0x36 },   // B
+    { 0x3e, 0x41, 0x41, 0x41, 0x22 },   // C
+    { 0x7f, 0x41, 0x41, 0x22, 0x1c },   // D
+    { 0x7f, 0x49, 0x49, 0x49, 0x41 },   // E
+    { 0x7f, 0x09, 0x09, 0x09, 0x01 },   // F
+    { 0x3e, 0x41, 0x49, 0x49, 0x7A },   // G
+    { 0x7f, 0x08, 0x08, 0x08, 0x7f },   // H
+    { 0x00, 0x41, 0x7f, 0x41, 0x00 },   // I
+    { 0x20, 0x40, 0x41, 0x3f, 0x01 },   // J
+    { 0x7f, 0x08, 0x14, 0x22, 0x41 },   // K
+    { 0x7f, 0x40, 0x40, 0x40, 0x40 },   // L
+    { 0x7f, 0x02, 0x0c, 0x02, 0x7f },   // M
+    { 0x7f, 0x04, 0x08, 0x10, 0x7f },   // N
+    { 0x3e, 0x41, 0x41, 0x41, 0x3e },   // O
+    { 0x7f, 0x09, 0x09, 0x09, 0x06 },   // P
+    { 0x3e, 0x41, 0x51, 0x21, 0x5e },   // Q
+    { 0x7f, 0x09, 0x19, 0x29, 0x46 },   // R
+    { 0x46, 0x49, 0x49, 0x49, 0x31 },   // S
+    { 0x01, 0x01, 0x7f, 0x01, 0x01 },   // T
+    { 0x3f, 0x40, 0x40, 0x40, 0x3f },   // U
+    { 0x1f, 0x20, 0x40, 0x20, 0x1f },   // V
+    { 0x3f, 0x40, 0x38, 0x40, 0x3f },   // W
+    { 0x63, 0x14, 0x08, 0x14, 0x63 },   // X
+    { 0x07, 0x08, 0x70, 0x08, 0x07 },   // Y
+    { 0x61, 0x51, 0x49, 0x45, 0x43 },   // Z
+    { 0x7f, 0x41, 0x41, 0x00, 0x00 },   // [
+    { 0x02, 0x04, 0x08, 0x10, 0x20 },   // \ (backslash)
+    { 0x00, 0x00, 0x41, 0x41, 0x7f },   // ]
+    { 0x04, 0x02, 0x01, 0x02, 0x04 },   // ^
+    { 0x40, 0x40, 0x40, 0x40, 0x40 },   // _
+    { 0x00, 0x01, 0x02, 0x04, 0x00 },   // `
+    { 0x20, 0x54, 0x54, 0x54, 0x78 },   // a
+    { 0x7f, 0x48, 0x44, 0x44, 0x38 },   // b
+    { 0x38, 0x44, 0x44, 0x44, 0x20 },   // c
+    { 0x38, 0x44, 0x44, 0x48, 0x7f },   // d
+    { 0x38, 0x54, 0x54, 0x54, 0x18 },   // e
+    { 0x08, 0x7e, 0x09, 0x01, 0x02 },   // f
+    { 0x0c, 0x52, 0x52, 0x52, 0x3e },   // g
+    { 0x7f, 0x08, 0x04, 0x04, 0x78 },   // h
+    { 0x00, 0x44, 0x7d, 0x40, 0x00 },   // i
+    { 0x00, 0x20, 0x40, 0x44, 0x3d },   // j
+    { 0x7f, 0x10, 0x28, 0x44, 0x00 },   // k
+    { 0x00, 0x41, 0x7f, 0x40, 0x00 },   // l
+    { 0x7c, 0x04, 0x18, 0x04, 0x78 },   // m
+    { 0x7c, 0x08, 0x04, 0x04, 0x78 },   // n
+    { 0x38, 0x44, 0x44, 0x44, 0x38 },   // o
+    { 0x7c, 0x14, 0x14, 0x14, 0x08 },   // p
+    { 0x08, 0x14, 0x14, 0x18, 0x7c },   // q
+    { 0x7c, 0x08, 0x04, 0x04, 0x08 },   // r
+    { 0x48, 0x54, 0x54, 0x54, 0x20 },   // s
+    { 0x04, 0x3f, 0x44, 0x40, 0x20 },   // t
+    { 0x3c, 0x40, 0x40, 0x20, 0x7c },   // u
+    { 0x1c, 0x20, 0x40, 0x20, 0x1c },   // v
+    { 0x3c, 0x40, 0x30, 0x40, 0x3c },   // w
+    { 0x44, 0x28, 0x10, 0x28, 0x44 },   // x
+    { 0x0c, 0x50, 0x50, 0x50, 0x3c },   // y
+    { 0x44, 0x64, 0x54, 0x4C, 0x44 },   // z
+    { 0x08, 0x36, 0x41, 0x00, 0x00 },   // {
+    { 0x00, 0x00, 0x7f, 0x00, 0x00 },   // |
+    { 0x00, 0x00, 0x41, 0x36, 0x08 },   // }
+    { 0x00, 0x08, 0x04, 0x08, 0x04 },   // ~
+    { 0x00, 0x7e, 0x7e, 0x7e, 0x7e }    // DEL
+};
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+inline static void pin_rstb_on()
+{
+    PRJ_CFAX_CONTROL_RSTB_PORT |= ( 1 << PRJ_CFAX_CONTROL_RSTB_PIN );
+}
+
+inline static void pin_rstb_off()
+{
+    PRJ_CFAX_CONTROL_RSTB_PORT &= ~( 1 << PRJ_CFAX_CONTROL_RSTB_PIN );
+}
+
+inline static void pin_rs_on()
+{
+    PRJ_CFAX_CONTROL_RS_PORT |= ( 1 << PRJ_CFAX_CONTROL_RS_PIN );
+}
+
+inline static void pin_rs_off()
+{
+    PRJ_CFAX_CONTROL_RS_PORT &= ~( 1 << PRJ_CFAX_CONTROL_RS_PIN );
+}
+
+inline static void pin_rd_on()
+{
+    PRJ_CFAX_CONTROL_RD_PORT |= ( 1 << PRJ_CFAX_CONTROL_RD_PIN );
+}
+
+inline static void pin_rd_off()
+{
+    PRJ_CFAX_CONTROL_RD_PORT &= ~( 1 << PRJ_CFAX_CONTROL_RD_PIN );
+}
+
+inline static void pin_rw_on()
+{
+    PRJ_CFAX_CONTROL_RW_PORT |= ( 1 << PRJ_CFAX_CONTROL_RW_PIN );
+}
+
+inline static void pin_rw_off()
+{
+    PRJ_CFAX_CONTROL_RW_PORT &= ~( 1 << PRJ_CFAX_CONTROL_RW_PIN );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static void send_command( uint8_t cmd )
+{
+    PRJ_CFAX_DATA_DDR  = 0xff;
+    PRJ_CFAX_DATA_PORT = cmd;
+    
+    pin_rs_off();
+    pin_rw_off();
+    pin_rd_on();
+    pin_rd_off();
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static void write_lcd_page( uint8_t page, uint8_t column, uint8_t data )
+{
+    send_command( CFAX_COMMAND_SEL_COLUMN_MSB | ( column >> 4 ) );
+    send_command( CFAX_COMMAND_SEL_COLUMN_LSB | ( column & 0x0f ) );
+    send_command( CFAX_COMMAND_SEL_PAGE | page );
+    
+    PRJ_CFAX_DATA_DDR  = 0xff;
+    PRJ_CFAX_DATA_PORT = data;
+
+    pin_rs_on();
+    pin_rw_off();
+    pin_rd_on();
+    pin_rd_off();
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static uint8_t read_lcd_page( uint8_t page, uint8_t column )
+{
+    send_command( CFAX_COMMAND_SEL_COLUMN_MSB | ( column >> 4 ) );
+    send_command( CFAX_COMMAND_SEL_COLUMN_LSB | ( column & 0x0f ) );
+    send_command( CFAX_COMMAND_SEL_PAGE | page );
+    
+    PRJ_CFAX_DATA_DDR  = 0x00;
+    PRJ_CFAX_DATA_PORT = 0xff;
+
+    pin_rs_on();
+    pin_rw_on();
+    pin_rd_on();
+    pin_rd_off();
+    pin_rd_on();
+
+    uint8_t data = PRJ_CFAX_DATA_PORT_PINS;
+
+    pin_rd_off();
+
+    return data;
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+void cfax_init()
+{
+    //--    Initialize the data port and control pins.
+
+    PRJ_CFAX_DATA_DDR = 0xff;
+
+    PRJ_CFAX_CONTROL_RSTB_DDR |= ( 1 << PRJ_CFAX_CONTROL_RSTB_PIN );
+    PRJ_CFAX_CONTROL_RS_DDR   |= ( 1 << PRJ_CFAX_CONTROL_RS_PIN );
+    PRJ_CFAX_CONTROL_RD_DDR   |= ( 1 << PRJ_CFAX_CONTROL_RD_PIN );
+    PRJ_CFAX_CONTROL_RW_DDR   |= ( 1 << PRJ_CFAX_CONTROL_RW_PIN );
+
+    //--    Reset the display.
+
+    pin_rstb_off();
+    spinwait_delay_ms( 10 );
+
+    pin_rstb_on();
+    spinwait_delay_ms( 10 );
+
+    //--    Set up the hardware.
+
+    send_command( CFAX_COMMAND_IDL | 0x00 );
+    send_command( CFAX_COMMAND_BAS_ON );
+
+    send_command( CFAX_COMMAND_ADC_ON );    // flip the horizontal pixels
+
+    send_command(0x2F); //Turn on internal power control
+
+    send_command(0x26); //Pseudo-Contrast 7 = dark 6 = OK - First Choice
+
+    //--    Default contrast setting.
+
+    cfax_set_contrast( PRJ_CFAX_DEFAULT_CONTRAST );
+
+    //--    Clear the screen memory.
+
+    cfax_clear_screen();
+
+#if defined( CFAX_INC_ICONS )
+
+    cfax_clear_icons();
+    
+#endif
+
+    //--    Turn on the display.
+
+    send_command( CFAX_COMMAND_DON_ON );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+void cfax_clear_screen()
+{
+    //--    Clear all the pixels.
+
+    for ( uint8_t page = 0; page < CFAX_MAX_VERTICAL_PAGES; page++ )
+    {
+        for ( uint8_t column = CFAX_HORIZONTAL_PIXEL_OFFSET;
+             column < ( CFAX_MAX_HORIZONTAL_PIXELS + CFAX_HORIZONTAL_PIXEL_OFFSET );
+             column++ )
+        {
+            write_lcd_page( page, column, 0x00 );
+        }
+    }
+
+    //--    Clear the icons too, unless there is explicit support for that feature.
+
+#if !defined( PRJ_CFAX_INC_ICONS )
+
+    for ( uint8_t column = CFAX_HORIZONTAL_PIXEL_OFFSET;
+         column < ( CFAX_MAX_HORIZONTAL_PIXELS + CFAX_HORIZONTAL_PIXEL_OFFSET );
+         column++ )
+    {
+        write_lcd_page( CFAX_MAX_VERTICAL_PAGES, column, 0x00 );
+    }
+
+#endif
+
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_ICONS )
+
+void cfax_clear_icons()
+{
+    for ( uint8_t column = CFAX_HORIZONTAL_PIXEL_OFFSET;
+         column < ( CFAX_MAX_HORIZONTAL_PIXELS + CFAX_HORIZONTAL_PIXEL_OFFSET );
+         column++ )
+    {
+        write_lcd_page( CFAX_MAX_VERTICAL_PAGES, column, 0x00 );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+void cfax_set_display( bool state )
+{
+    send_command( state ? CFAX_COMMAND_DON_ON :  CFAX_COMMAND_DON_OFF );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+void cfax_set_contrast( uint8_t contrast )
+{
+    send_command( CFAX_COMMAND_VREF );  // contrast
+    send_command( contrast ); 
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_ICONS )
+
+void cfax_set_icon( cfax_icon_t icon_id, bool state )
+{
+    uint8_t icon_index
+        = pgm_read_byte_near( &cfax_icon_ids[ static_cast< uint8_t >( icon_id ) ] );
+
+    write_lcd_page( 8, icon_index, ( state ? 0x01 : 0x00 ) );
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_WRITE_CHAR )
+
+void cfax_write( char c, uint8_t x, uint8_t y )
+{
+    x %= ( CFAX_MAX_HORIZONTAL_PIXELS / ( sizeof( cfax_glyph_t ) + 1 ) );
+    y %= CFAX_MAX_VERTICAL_PAGES;
+
+    // glyphs are stored starting with the space character: ASCII 32 = 0x20
+
+    if ( c < 0x20 )
+    {
+        c = 0x7f;   // generic character glyph
+    }
+
+    c -= 0x20;
+    
+    const prog_uint8_t* this_glyph
+      = reinterpret_cast< const prog_uint8_t* >( &glyphs[ static_cast< uint8_t >( c ) ] );
+
+    // the glyph data does not store the blank column on the right edge, so pad by one
+
+    uint8_t pixel_column = x * ( sizeof( cfax_glyph_t ) + 1 );
+
+    // offset due to the flipped horizontal orientation
+    pixel_column += CFAX_HORIZONTAL_PIXEL_OFFSET;
+
+    for ( uint8_t i = 0; i < sizeof( cfax_glyph_t ); i++ )
+    {
+        uint8_t data = pgm_read_byte_near( this_glyph++ );
+        write_lcd_page( y, pixel_column++, data );
+    }
+
+    write_lcd_page( y, pixel_column, 0x00 );
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_WRITE_CSTRINGS )
+
+void cfax_write( const char* str, uint8_t x, uint8_t y )
+{
+    while ( *str )
+    {
+        cfax_write( *str++, x++, y );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_WRITE_PGM_CSTRINGS )
+
+void cfax_write_pgm( const prog_char* str, uint8_t x, uint8_t y )
+{
+    for ( ;; )
+    {
+        char c = static_cast< char >( pgm_read_byte_near( str++ ) );
+
+        if ( c == '\0' )
+        {
+            return;
+        }
+
+        cfax_write( c, x++, y );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_SET_PIXEL )
+
+void cfax_set_pixel( uint8_t x, uint8_t y, bool state )
+{
+    x %= CFAX_MAX_HORIZONTAL_PIXELS;
+    y %= CFAX_MAX_VERTICAL_PIXELS;
+
+    // offset due to the flipped horizontal orientation
+    x += CFAX_HORIZONTAL_PIXEL_OFFSET;
+
+    uint8_t page  = y / 8;
+    uint8_t pixel = y % 8;
+
+    uint8_t data = read_lcd_page( page, x );
+
+    if ( state )
+    {
+        data |= ( 1 << pixel );
+    }
+    else
+    {
+        data &= ~( 1 << pixel );
+    }
+
+    write_lcd_page( page, x, data );
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_DRAWING )
+
+void cfax_line_h( uint8_t x, uint8_t y, uint8_t len, bool state )
+{
+    while ( len-- )
+    {
+        cfax_set_pixel( x++, y, state );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_DRAWING )
+
+void cfax_line_v( uint8_t x, uint8_t y, uint8_t len, bool state )
+{
+    while ( len-- )
+    {
+        cfax_set_pixel( x, y++, state );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_DRAWING )
+
+void cfax_rect( uint8_t x, uint8_t y, uint8_t w, uint8_t h )
+{
+    cfax_line_h( x, y, w, true );
+    --h;
+
+    uint8_t right_x = x + w - 1;
+
+    while ( h-- )
+    {
+        cfax_set_pixel( x, y, true );
+        cfax_set_pixel( right_x, y, true );
+        y++;
+    }
+
+    cfax_line_h( x, y, w, true );
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_DRAWING )
+
+void cfax_fill( uint8_t x, uint8_t y, uint8_t w, uint8_t h )
+{
+    while ( h-- )
+    {
+        cfax_line_h( x, y++, w, true );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_DRAWING )
+
+void cfax_erase( uint8_t x, uint8_t y, uint8_t w, uint8_t h )
+{
+    while ( h-- )
+    {
+        cfax_line_h( x, y++, w, false );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_DRAWING )
+
+void cfax_line( uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, bool state )
+{
+    //--    Bresenham's line rasterization algorithm: 
+    //      http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html
+
+    int16_t dy = y1 - y0;
+    int16_t dx = x1 - x0;
+    int8_t  step_x = 1;
+    int8_t  step_y = 1;
+
+    if ( dy < 0 )
+    {
+        dy *= -1;
+        step_y = -1;
+    }
+
+    if ( dx < 0 )
+    {
+        dx *= -1;
+        step_x = -1;
+    }
+
+    dy <<= 1;
+    dx <<= 1;
+
+    cfax_set_pixel( x0, y0, state );
+
+    if ( dx > dy )
+    {
+        int16_t fraction = dy - ( dx >> 1 );
+
+        while ( x0 != x1 )
+        {
+            if ( fraction >= 0 ) 
+            {
+                y0 += step_y;
+                fraction -= dx;
+            }
+
+            x0 += step_x;
+            fraction += dy;
+
+            cfax_set_pixel( x0, y0, state );
+        }
+    }
+    else
+    {
+        int16_t fraction = dx - ( dy >> 1 );
+
+        while ( y0 != y1 )
+        {
+            if ( fraction >= 0 )
+            {
+                x0 += step_x;
+                fraction -= dy;
+            }
+
+            y0 += step_y;
+            fraction += dx;
+
+            cfax_set_pixel( x0, y0, state );
+        }
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_BITMAPS )
+
+void cfax_bitmap
+    (
+        uint8_t x,
+        uint8_t y,
+        uint8_t w,
+        uint8_t h,
+        const prog_uint8_t* pixels
+    )
+{
+    while ( h-- )
+    {
+        uint8_t right_x = x + w - 1;
+        uint8_t pix_bit = 0x00;
+        uint8_t data    = 0x00;
+
+        for ( uint8_t i = x; i <= right_x; i++ )
+        {
+            if ( pix_bit == 0x00 )
+            {
+                data = pgm_read_byte_near( pixels++ );
+                pix_bit = 0x80;
+            }
+
+            cfax_set_pixel( i, y, ( ( data & pix_bit ) != 0x00 ) );
+            pix_bit >>= 1;
+        }
+
+        y++;
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_CFAX_INC_TOUCHSCREEN )
+
+bool cfax_touchscreen( uint8_t* x, uint8_t* y )
+{
+    //--    Read the x value by flipping TS1 and TS3 to outputs and driving TS3 high.
+    //      The x value can be sampled on TS2.
+
+    PRJ_CFAX_TOUCHSCREEN_DDR &=
+        ~( ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_2 ) | ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_4 ) );
+
+    PRJ_CFAX_TOUCHSCREEN_DDR |=
+        ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_1 ) | ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_3 );
+
+    PRJ_CFAX_TOUCHSCREEN_PORT |= ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_1 );
+
+    PRJ_CFAX_TOUCHSCREEN_PORT &=
+        ~( ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_2 )
+         | ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_3 )
+         | ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_4 ) );
+
+    uint16_t valueX = 0;
+
+    for ( uint8_t i = 0; i < 8; i++ )
+    {
+        valueX += adc_read( PRJ_CFAX_TOUCHSCREEN_ADC_CH_2 );
+    }
+
+    valueX /= 30;   // scaling determined experimentally
+
+    //--    Read the y value by flipping TS2 and TS4 to outputs and driving TS2 high.
+    //      The y value can be sampled on TS1.
+
+    PRJ_CFAX_TOUCHSCREEN_DDR &=
+        ~( ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_1 ) | ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_3 ) );
+
+    PRJ_CFAX_TOUCHSCREEN_DDR |=
+        ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_2 ) | ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_4 );
+
+    PRJ_CFAX_TOUCHSCREEN_PORT |= ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_2 );
+
+    PRJ_CFAX_TOUCHSCREEN_PORT &=
+        ~( ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_1 ) 
+         | ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_3 ) 
+         | ( 1 << PRJ_CFAX_TOUCHSCREEN_PIN_4 ) );
+
+    uint16_t valueY = 0;
+
+    for ( uint8_t i = 0; i < 8; i++ )
+    {
+        valueY += adc_read( PRJ_CFAX_TOUCHSCREEN_ADC_CH_1 );
+    }
+
+    valueY /= 27;   // scaling determined experimentally
+
+    *x = valueX;
+    *y = valueY;
+
+    if ( ( valueX < 5 ) && ( valueY < 5 ) )
+    {
+        return false;
+    }
+
+    return true;
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#endif  // PRJ_CFAX_ENABLE
+
+
+// ----------------------------------------------------------------------------------------
+//  end of cfax.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/lcd/cfax/cfax.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,339 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/lcd/cfax/cfax.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file implements support for the Crystal Fontz CFAX 128x64.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_CFAX_H )
+#define BCDRL_AVR_CFAX_H
+
+
+#include <stdint.h>
+#include <avr/pgmspace.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  enable support for the CFAX 128x64 Graphic LCD with:
+//
+//      + PRJ_CFAX_ENABLE
+//
+//  specify the data port (all eight pins) for communications with:
+//
+//      + PRJ_CFAX_DATA_PORT
+//      + PRJ_CFAX_DATA_PORT_PINS
+//      + PRJ_CFAX_DATA_DDR
+//
+//  specify the control pins with:
+//
+//      + PRJ_CFAX_CONTROL_RSTB_PORT
+//      + PRJ_CFAX_CONTROL_RSTB_PIN
+//      + PRJ_CFAX_CONTROL_RSTB_DDR
+//
+//      + PRJ_CFAX_CONTROL_RS_PORT
+//      + PRJ_CFAX_CONTROL_RS_PIN
+//      + PRJ_CFAX_CONTROL_RS_DDR
+//
+//      + PRJ_CFAX_CONTROL_RD_PORT
+//      + PRJ_CFAX_CONTROL_RD_PIN
+//      + PRJ_CFAX_CONTROL_RD_DDR
+//
+//      + PRJ_CFAX_CONTROL_RW_PORT
+//      + PRJ_CFAX_CONTROL_RW_PIN
+//      + PRJ_CFAX_CONTROL_RW_DDR
+//
+//  specify the (optional) touch screen with:
+//
+//      + PRJ_CFAX_INC_TOUCHSCREEN
+//
+//      + PRJ_CFAX_TOUCHSCREEN_PORT
+//      + PRJ_CFAX_TOUCHSCREEN_DDR
+//      + PRJ_CFAX_TOUCHSCREEN_PIN_1
+//      + PRJ_CFAX_TOUCHSCREEN_PIN_2
+//      + PRJ_CFAX_TOUCHSCREEN_PIN_3
+//      + PRJ_CFAX_TOUCHSCREEN_PIN_4
+//      + PRJ_CFAX_TOUCHSCREEN_ADC_CH_1
+//      + PRJ_CFAX_TOUCHSCREEN_ADC_CH_2
+//      + PRJ_CFAX_TOUCHSCREEN_ADC_CH_3
+//      + PRJ_CFAX_TOUCHSCREEN_ADC_CH_4
+//
+//  optional features can be enabled with one or more of the following:
+//
+//      + PRJ_CFAX_DEFAULT_CONTRAST <int>
+//
+//      + PRJ_CFAX_INC_ICONS
+//      + PRJ_CFAX_INC_WRITE_CHAR
+//      + PRJ_CFAX_INC_WRITE_CSTRINGS
+//      + PRJ_CFAX_INC_WRITE_PGM_CSTRINGS
+//      + PRJ_CFAX_INC_SET_PIXEL
+//      + PRJ_CFAX_INC_DRAWING
+//      + PRJ_CFAX_INC_BITMAPS
+//
+// ----------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------------------
+//  typedefs and constants
+//
+
+const uint8_t CFAX_NUM_ICONS = 17;
+
+typedef enum
+{
+    cfax_icon_maple_leaf,
+    cfax_icon_document,
+    cfax_icon_battery_outline,
+    cfax_icon_battery_level_1,
+    cfax_icon_battery_level_2,
+    cfax_icon_battery_level_3,
+    cfax_icon_terminal,
+    cfax_icon_antenna,
+    cfax_icon_speaker,
+    cfax_icon_speaker_tick_1,
+    cfax_icon_speaker_tick_2,
+    cfax_icon_telephone,
+    cfax_icon_letter,
+    cfax_icon_bell,
+    cfax_icon_clock,
+    cfax_icon_caution,
+    cfax_icon_spinner
+
+}   cfax_icon_t;
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_init
+//
+//      Initialize the CFAX driver package, setting up the hardware and clearing the
+//      display. Call this function prior to any other.
+//
+
+void cfax_init();
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_clear_screen
+//
+//      Erase the entire screen. If icon support is enabled this does *not* clear them
+//      automatically. If text lcd emulation support is enabled then the cursor position
+//      is reset to the upper left corner (0,0).
+//
+
+void cfax_clear_screen();
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_clear_icons
+//
+//      Turn off all icons.
+//
+//      This function is only available if PRJ_CFAX_INC_ICONS is defined.
+//
+
+void cfax_clear_icons();
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_set_display
+//
+//      Turn on or off the display. This does not clear the screen, just disables the
+//      active display.
+//
+
+void cfax_set_display( bool state );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_set_contrast
+//
+//      Set the contrast of the display.
+//
+
+void cfax_set_contrast( uint8_t contrast );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_set_icon
+//
+//      Turn on or off the specified icon.
+//
+//      This function is only available if PRJ_CFAX_INC_ICONS is defined.
+//
+
+void cfax_set_icon( cfax_icon_t icon_id, bool state );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_write
+//
+//      Write a character to the display in the *character* row and column. The display
+//      can support 8 rows by 20 columns.
+//
+//      This function is only available if PRJ_CFAX_INC_WRITE_CHAR is defined.
+//
+
+void cfax_write( char c, uint8_t x, uint8_t y );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_write
+//
+//      Write a string to the display in the *character* row and column. The display
+//      can support 8 rows by 20 columns.
+//
+//      This function is only available if PRJ_CFAX_INC_WRITE_CSTRINGS is defined.
+//
+
+void cfax_write( const char* str, uint8_t x, uint8_t y );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_write_pgm
+//
+//      Write a string from flash memory to the display in the *character* row and column.
+//      The display can support 8 rows by 20 columns.
+//
+//      This function is only available if PRJ_CFAX_INC_WRITE_PGM_CSTRINGS is defined.
+//
+
+void cfax_write_pgm( const char* str, uint8_t x, uint8_t y );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_set_pixel
+//
+//      Turn on or off a specific pixel. The display supports 64 rows by 128 columns.
+//
+//      This function is only available if PRJ_CFAX_INC_SET_PIXEL is defined.
+//
+
+void cfax_set_pixel( uint8_t x, uint8_t y, bool state );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_line_h
+//
+//      Turn on or off a row of pixels.
+//
+//      This function is only available if PRJ_CFAX_INC_DRAWING is defined.
+//
+
+void cfax_line_h( uint8_t x, uint8_t y, uint8_t len, bool state );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_line_v
+//
+//      Turn on or off a column of pixels.
+//
+//      This function is only available if PRJ_CFAX_INC_DRAWING is defined.
+//
+
+void cfax_line_v( uint8_t x, uint8_t y, uint8_t len, bool state );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_rect
+//
+//      Turn on the frame (edge) pixels of a rectangular region.
+//
+//      This function is only available if PRJ_CFAX_INC_DRAWING is defined.
+//
+
+void cfax_rect( uint8_t x, uint8_t y, uint8_t w, uint8_t h );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_fill
+//
+//      Turn on all the pixels inside of a rectangular region.
+//
+//      This function is only available if PRJ_CFAX_INC_DRAWING is defined.
+//
+
+void cfax_fill( uint8_t x, uint8_t y, uint8_t w, uint8_t h );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_erase
+//
+//      Turn off all the pixels inside of a rectangular region.
+//
+//      This function is only available if PRJ_CFAX_INC_DRAWING is defined.
+//
+
+void cfax_erase( uint8_t x, uint8_t y, uint8_t w, uint8_t h );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_line
+//
+//      Turn on or off the pixels in a line between two points. This is much more
+//      expensive for horizontal or vertical lines; prefer to use the optimized
+//      functions (cfax_line_h, cfax_line_v) for those cases when possible.
+//
+//      This function is only available if PRJ_CFAX_INC_DRAWING is defined.
+//
+
+void cfax_line( uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, bool state );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_bitmap
+//
+//      Paint an image at the specified pixel location. The pixel data must be stored in
+//      flash memory and be organized by rows, padded to whole bytes per row.
+//
+//      This function is only available if PRJ_CFAX_INC_BITMAPS is defined.
+//
+
+void cfax_bitmap
+    (
+        uint8_t x,
+        uint8_t y,
+        uint8_t w,
+        uint8_t h,
+        const prog_uint8_t* pixels
+    );
+
+
+// ----------------------------------------------------------------------------------------
+//  cfax_touchscreen
+//
+//      Read the touch screen. Returns false if the screen is not pressed. The resulting
+//      (x, y) pair is clamped to (0-64, 0-32).
+//
+//      This function is only available if PRJ_CFAX_INC_TOUCHSCREEN is defined.
+//
+
+bool cfax_touchscreen( uint8_t* x, uint8_t* y );
+
+
+#endif  // #if !defined( BCDRL_AVR_CFAX_H )
+// ----------------------------------------------------------------------------------------
+//  end of cfax.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/lcd/cfax/jamfile	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,40 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr/lcd/cfax/jamfile
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Copyright (C) 2007 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /packages/avr/lcd/cfax/jamfile" ; }
+
+SubDir TOP packages avr lcd cfax ;
+
+
+# -----------------------------------------------------------------------------------------
+
+PackageSources
+    cfax.cpp
+    ;
+    
+# -----------------------------------------------------------------------------------------
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/lcd/jamdefs	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,35 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr/jamdefs
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Copyright (C) 2007 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /packages/avr/lcd/jamdefs" ; }
+
+
+# -----------------------------------------------------------------------------------------
+
+DefinePackages TOP packages avr lcd : cfax sfe569 ;
+
+# -----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/lcd/sfe569/jamfile	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,40 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr/lcd/sfe569/jamfile
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Copyright (C) 2007 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /packages/avr/lcd/sfe569/jamfile" ; }
+
+SubDir TOP packages avr lcd sfe569 ;
+
+
+# -----------------------------------------------------------------------------------------
+
+PackageSources
+    sfe569.cpp
+    ;
+    
+# -----------------------------------------------------------------------------------------
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/lcd/sfe569/sfe569.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,896 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/lcd/sfe569/sfe569.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file implements support for the SparkFun 128x128 Color LCD (#LCD-000569).
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+//  Portions copied from "Nokia-like Color LCD Sample" written by Cathy Saxton.
+//  See http://www.idleloop.com/robotics/ColorLCD/
+//
+//  Portions copied from "Nokia 6100 LCD Display Driver" written by James P. Lynch.
+//  See http:// ... (todo fill this in from the SFE site)
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "sfe569.h"
+
+#include <avr/io.h>
+
+#include "packages/avr/device/spinwait.h"
+
+#include "project_defs.h"
+
+
+#if defined( PRJ_SFE569_ENABLE )
+
+
+// ----------------------------------------------------------------------------------------
+
+#if !defined( PRJ_SFE569_CLOCK_PORT )
+#error PRJ_SFE569_CLOCK_PORT is required!
+#endif
+
+#if !defined( PRJ_SFE569_CLOCK_PIN )
+#error PRJ_SFE569_CLOCK_PIN is required!
+#endif
+
+#if !defined( PRJ_SFE569_CLOCK_DDR )
+#error PRJ_SFE569_CLOCK_DDR is required!
+#endif
+
+#if !defined( PRJ_SFE569_DATA_PORT )
+#error PRJ_SFE569_DATA_PORT is required!
+#endif
+
+#if !defined( PRJ_SFE569_DATA_PIN )
+#error PRJ_SFE569_DATA_PIN is required!
+#endif
+
+#if !defined( PRJ_SFE569_DATA_DDR )
+#error PRJ_SFE569_DATA_DDR is required!
+#endif
+
+#if !defined( PRJ_SFE569_RESET_PORT )
+#error PRJ_SFE569_RESET_PORT is required!
+#endif
+
+#if !defined( PRJ_SFE569_RESET_PIN )
+#error PRJ_SFE569_RESET_PIN is required!
+#endif
+
+#if !defined( PRJ_SFE569_RESET_DDR )
+#error PRJ_SFE569_RESET_DDR is required!
+#endif
+
+#if !defined( PRJ_SFE569_SELECT_PORT )
+#error PRJ_SFE569_SELECT_PORT is required!
+#endif
+
+#if !defined( PRJ_SFE569_SELECT_PIN )
+#error PRJ_SFE569_SELECT_PIN is required!
+#endif
+
+#if !defined( PRJ_SFE569_SELECT_DDR )
+#error PRJ_SFE569_SELECT_DDR is required!
+#endif
+
+#if defined( PRJ_SFE569_INC_WRITE_CSTRINGS ) || defined( PRJ_SFE569_INC_WRITE_PGM_CSTRINGS )
+#if !defined( PRJ_SFE569_INC_WRITE_CHAR )
+#define PRJ_SFE569_INC_WRITE_CHAR
+#endif
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+const uint8_t SFE569_MAX_HORIZONTAL_PIXELS   = 128;
+const uint8_t SFE569_MAX_VERTICAL_PIXELS     = 128;
+const uint8_t SFE569_HORIZONTAL_PIXEL_OFFSET = 1;
+const uint8_t SFE569_VERTICAL_PIXEL_OFFSET   = 3;
+
+const uint8_t SFE569_COMMAND_CASET    = 0x15;
+const uint8_t SFE569_COMMAND_PWRCTR   = 0x20;
+const uint8_t SFE569_COMMAND_NOP      = 0x25;
+const uint8_t SFE569_COMMAND_PASET    = 0x75;
+const uint8_t SFE569_COMMAND_RAMWR    = 0x5c;
+const uint8_t SFE569_COMMAND_VOLCTR   = 0x81;
+const uint8_t SFE569_COMMAND_TMPGRD   = 0x82;
+const uint8_t SFE569_COMMAND_SLPOUT   = 0x94;
+const uint8_t SFE569_COMMAND_SLPIN    = 0x95;
+const uint8_t SFE569_COMMAND_DISNOR   = 0xa6;
+const uint8_t SFE569_COMMAND_DISINV   = 0xa7;
+const uint8_t SFE569_COMMAND_PTLIN    = 0xa8;
+const uint8_t SFE569_COMMAND_PTLOUT   = 0xa9;
+const uint8_t SFE569_COMMAND_DISOFF   = 0xae;
+const uint8_t SFE569_COMMAND_DISON    = 0xaf;
+const uint8_t SFE569_COMMAND_COMSCN   = 0xbb;
+const uint8_t SFE569_COMMAND_DATCTL   = 0xbc;
+const uint8_t SFE569_COMMAND_DISCTL   = 0xca;
+const uint8_t SFE569_COMMAND_RGBSET8  = 0xce;
+const uint8_t SFE569_COMMAND_OSCON    = 0xd1;
+const uint8_t SFE569_COMMAND_OSCOFF   = 0xd2;
+
+
+// ----------------------------------------------------------------------------------------
+//
+//  This is an 8x6 monospaced font, organized as one byte per horizontal row.
+//
+
+#if defined( PRJ_SFE569_INC_WRITE_CHAR )
+
+typedef prog_uint8_t sfe569_glyph_t[ 8 ];
+
+const uint8_t SFE569_GLYPH_HEIGHT = 8;
+const uint8_t SFE569_GLYPH_WIDTH  = 6;
+
+const uint8_t SFE569_MAX_HORIZONTAL_CHARS
+    = ( SFE569_MAX_HORIZONTAL_PIXELS / SFE569_GLYPH_WIDTH );
+
+const uint8_t SFE569_MAX_VERTICAL_CHARS
+    = ( SFE569_MAX_VERTICAL_PIXELS / SFE569_GLYPH_HEIGHT );
+
+static const sfe569_glyph_t glyphs[] =
+{
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },     // space, ascii 0x20
+    { 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x00 },     // !
+    { 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00 },     // "
+    { 0x28, 0x28, 0x7c, 0x28, 0x7c, 0x28, 0x28, 0x00 },     // #
+    { 0x10, 0x3c, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00 },     // $
+    { 0x60, 0x64, 0x08, 0x10, 0x20, 0x4c, 0x0c, 0x00 },     // %
+    { 0x10, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 },     // &
+    { 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 },     // '
+    { 0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00 },     // (
+    { 0x10, 0x08, 0x04, 0x04, 0x04, 0x08, 0x10, 0x00 },     // )
+    { 0x00, 0x10, 0x54, 0x38, 0x54, 0x10, 0x00, 0x00 },     // *
+    { 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00 },     // +
+    { 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 0x00 },     // ,
+    { 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00 },     // -
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00 },     // .
+    { 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00 },     // /
+    { 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38, 0x00 },     // 0
+    { 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 },     // 1
+    { 0x38, 0x44, 0x04, 0x08, 0x10, 0x20, 0x7c, 0x00 },     // 2
+    { 0x7c, 0x08, 0x10, 0x08, 0x04, 0x44, 0x38, 0x00 },     // 3
+    { 0x08, 0x18, 0x28, 0x48, 0x7c, 0x08, 0x08, 0x00 },     // 4
+    { 0x7c, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00 },     // 5
+    { 0x18, 0x20, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00 },     // 6
+    { 0x7c, 0x04, 0x08, 0x10, 0x20, 0x20, 0x20, 0x00 },     // 7
+    { 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00 },     // 8
+    { 0x38, 0x44, 0x44, 0x38, 0x04, 0x04, 0x38, 0x00 },     // 9
+    { 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, 0x00 },     // :
+    { 0x00, 0x30, 0x30, 0x00, 0x30, 0x10, 0x20, 0x00 },     // ;
+    { 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00 },     // <
+    { 0x00, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x00, 0x00 },     // =
+    { 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00 },     // >
+    { 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00 },     // ?
+    { 0x38, 0x44, 0x04, 0x34, 0x54, 0x54, 0x38, 0x00 },     // @
+    { 0x38, 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x00 },     // A
+    { 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, 0x00 },     // B
+    { 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00 },     // C
+    { 0x70, 0x48, 0x44, 0x44, 0x44, 0x48, 0x70, 0x00 },     // D
+    { 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7c, 0x00 },     // E
+    { 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00 },     // F
+    { 0x38, 0x44, 0x40, 0x5c, 0x44, 0x44, 0x3c, 0x00 },     // G
+    { 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x00 },     // H
+    { 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 },     // I
+    { 0x1c, 0x08, 0x08, 0x08, 0x08, 0x48, 0x30, 0x00 },     // J
+    { 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00 },     // K
+    { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x00 },     // L
+    { 0x44, 0x6c, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00 },     // M
+    { 0x44, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x44, 0x00 },     // N
+    { 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 },     // O
+    { 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00 },     // P
+    { 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00 },     // Q
+    { 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00 },     // R
+    { 0x3c, 0x40, 0x40, 0x38, 0x04, 0x04, 0x78, 0x00 },     // S
+    { 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00 },     // T
+    { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 },     // U
+    { 0x44, 0x44, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00 },     // V
+    { 0x44, 0x44, 0x44, 0x54, 0x54, 0x54, 0x28, 0x00 },     // W
+    { 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00 },     // X
+    { 0x44, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00 },     // Y
+    { 0x7c, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7c, 0x00 },     // Z
+    { 0x70, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70, 0x00 },     // [
+    { 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00 },     // \ (backslash)
+    { 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1c, 0x00 },     // ]
+    { 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00 },     // ^
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00 },     // _
+    { 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },     // `
+    { 0x00, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00 },     // a
+    { 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x78, 0x00 },     // b
+    { 0x00, 0x00, 0x38, 0x40, 0x40, 0x44, 0x38, 0x00 },     // c
+    { 0x04, 0x04, 0x34, 0x4c, 0x44, 0x44, 0x3c, 0x00 },     // d
+    { 0x00, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x38, 0x00 },     // e
+    { 0x18, 0x24, 0x20, 0x70, 0x20, 0x20, 0x20, 0x00 },     // f
+    { 0x00, 0x3c, 0x44, 0x44, 0x3c, 0x04, 0x38, 0x00 },     // g
+    { 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00 },     // h
+    { 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00 },     // i
+    { 0x04, 0x00, 0x0c, 0x04, 0x04, 0x24, 0x18, 0x00 },     // j
+    { 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00 },     // k
+    { 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 },     // l
+    { 0x00, 0x00, 0x68, 0x54, 0x54, 0x44, 0x44, 0x00 },     // m
+    { 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00 },     // n
+    { 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00 },     // o
+    { 0x00, 0x00, 0x78, 0x44, 0x78, 0x40, 0x40, 0x00 },     // p
+    { 0x00, 0x00, 0x34, 0x4c, 0x3c, 0x04, 0x04, 0x00 },     // q
+    { 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00 },     // r
+    { 0x00, 0x00, 0x38, 0x40, 0x38, 0x04, 0x78, 0x00 },     // s
+    { 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00 },     // t
+    { 0x00, 0x00, 0x44, 0x44, 0x44, 0x4c, 0x34, 0x00 },     // u
+    { 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00 },     // v
+    { 0x00, 0x00, 0x44, 0x44, 0x54, 0x54, 0x28, 0x00 },     // w
+    { 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00 },     // x
+    { 0x00, 0x00, 0x44, 0x44, 0x3c, 0x04, 0x38, 0x00 },     // y
+    { 0x00, 0x00, 0x7c, 0x08, 0x10, 0x20, 0x7c, 0x00 },     // z
+    { 0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x10, 0x00 },     // {
+    { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00 },     // |
+    { 0x10, 0x08, 0x08, 0x04, 0x08, 0x08, 0x10, 0x00 },     // }
+    { 0x00, 0x00, 0x14, 0x28, 0x00, 0x00, 0x00, 0x00 },     // ~
+    { 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x00 }      // DEL
+};
+
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+void send_nine_bits( uint8_t ninth_bit, uint8_t low_eight_bits )
+{
+    //--    Set the ninth bit.
+
+    if ( ninth_bit )
+    {
+        PRJ_SFE569_DATA_PORT |= ( 1 << PRJ_SFE569_DATA_PIN );
+    }
+    else
+    {
+        PRJ_SFE569_DATA_PORT &= ~( 1 << PRJ_SFE569_DATA_PIN );
+    }
+
+    //--    Clock line goes low to signal data ready, delay, then raise it again.
+
+    PRJ_SFE569_CLOCK_PORT &= ~( 1 << PRJ_SFE569_CLOCK_PIN );
+
+    asm( "nop" );
+    asm( "nop" );
+    
+    PRJ_SFE569_CLOCK_PORT |= ( 1 << PRJ_SFE569_CLOCK_PIN );
+
+    asm( "nop" );
+    asm( "nop" );
+
+    for ( uint8_t i = 0; i < 8; i++ )
+    {
+        if ( low_eight_bits & 0x80 )
+        {
+            PRJ_SFE569_DATA_PORT |= ( 1 << PRJ_SFE569_DATA_PIN );
+        }
+        else
+        {
+            PRJ_SFE569_DATA_PORT &= ~( 1 << PRJ_SFE569_DATA_PIN );
+        }
+
+        low_eight_bits <<= 1;
+
+        //--    Clock line goes low to signal data ready, delay, then raise it again.
+
+        PRJ_SFE569_CLOCK_PORT &= ~( 1 << PRJ_SFE569_CLOCK_PIN );
+        
+        asm( "nop" );
+        asm( "nop" );
+
+        PRJ_SFE569_CLOCK_PORT |= ( 1 << PRJ_SFE569_CLOCK_PIN );
+
+        asm( "nop" );
+        asm( "nop" );
+    }
+}
+
+inline void send_command( uint8_t cmd )
+{
+    send_nine_bits( 0x00, cmd );
+}
+
+inline void send_data( uint8_t data )
+{
+    send_nine_bits( 0xff, data );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static void select_controller()
+{
+    PRJ_SFE569_SELECT_PORT &= ~( 1 << PRJ_SFE569_SELECT_PIN );
+    asm( "nop" );
+    asm( "nop" );
+}
+
+static void deselect_controller()
+{
+    PRJ_SFE569_SELECT_PORT |= ( 1 << PRJ_SFE569_SELECT_PIN );
+    asm( "nop" );
+    asm( "nop" );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+void sfe569_init()
+{
+    //--    Initialize the various pins.
+
+    PRJ_SFE569_CLOCK_DDR |= ( 1 << PRJ_SFE569_CLOCK_PIN );
+    PRJ_SFE569_CLOCK_PORT |= ( 1 << PRJ_SFE569_CLOCK_PIN );
+
+    PRJ_SFE569_DATA_DDR |= ( 1 << PRJ_SFE569_DATA_PIN );
+    PRJ_SFE569_DATA_PORT &= ~( 1 << PRJ_SFE569_DATA_PIN );
+
+    PRJ_SFE569_RESET_DDR |= ( 1 << PRJ_SFE569_RESET_PIN );
+    PRJ_SFE569_RESET_PORT |= ( 1 << PRJ_SFE569_RESET_PIN );
+
+    PRJ_SFE569_SELECT_DDR |= ( 1 << PRJ_SFE569_SELECT_PIN );
+    PRJ_SFE569_SELECT_PORT |= ( 1 << PRJ_SFE569_SELECT_PIN );
+
+    //--    Reset the display.
+
+    spinwait_delay_us( 5 );
+    PRJ_SFE569_RESET_PORT &= ~( 1 << PRJ_SFE569_RESET_PIN );
+    spinwait_delay_us( 5 );
+    PRJ_SFE569_RESET_PORT |= ( 1 << PRJ_SFE569_RESET_PIN );
+    spinwait_delay_ms( 2 );
+
+    //--    Configure the display controller. Mostly copied from example code and reading
+    //      the EPSON S1D15G00 data sheet from SparkFun.
+
+    select_controller();
+
+    send_command( SFE569_COMMAND_DISCTL );
+    send_data( 0x00 );    // CL div ratio 2; F1, F2 switching 8H (default)
+    send_data( 0x20 );    // 132 / 4 - 1 = 32 (0x20)
+    send_data( 0x0a );    // Inverse highlight (default)
+
+    send_command( SFE569_COMMAND_COMSCN );
+    send_data( 0x01 );    // COM1-80: 1->80; COM81-160: 160<-81
+
+    send_command( SFE569_COMMAND_OSCON );
+    send_command( SFE569_COMMAND_SLPOUT );
+
+    send_command( SFE569_COMMAND_VOLCTR );
+    send_data( 28 );
+    send_data( 3 );
+
+    send_command( SFE569_COMMAND_TMPGRD );
+    send_data( 0 ); // default
+
+    send_command( SFE569_COMMAND_PWRCTR );
+    send_data( 0x0f );  // full power control set enabled
+
+    send_command( SFE569_COMMAND_DISINV );
+    send_command( SFE569_COMMAND_PTLOUT );
+    
+    send_command( SFE569_COMMAND_DATCTL );
+    send_data( 0x00 );    // normal orientation; scan across cols, then rows
+    send_data( 0x00 );    // RGB arrangement (RGB all rows/cols)
+    send_data( 0x01 );    // 8 bit-color display
+    
+    send_command( SFE569_COMMAND_RGBSET8 );
+    send_data( 0x00 );    // 000 RED
+    send_data( 0x02 );    // 001  
+    send_data( 0x04 );    // 010
+    send_data( 0x06 );    // 011
+    send_data( 0x08 );    // 100
+    send_data( 0x0a );    // 101
+    send_data( 0x0c );    // 110
+    send_data( 0x0f );    // 111
+    send_data( 0x00 );    // 000 GREEN
+    send_data( 0x02 );    // 001  
+    send_data( 0x04 );    // 010
+    send_data( 0x06 );    // 011
+    send_data( 0x08 );    // 100
+    send_data( 0x0a );    // 101
+    send_data( 0x0c );    // 110
+    send_data( 0x0f );    // 111
+    send_data( 0x00 );    //  00 BLUE
+    send_data( 0x06 );    //  01
+    send_data( 0x09 );    //  10
+    send_data( 0x0f );    //  11
+
+    deselect_controller();
+    spinwait_delay_ms( 100 );
+
+    sfe569_fill_screen( sfe569_color_black );
+
+    select_controller();
+    send_command( SFE569_COMMAND_DISON );
+    deselect_controller();
+}
+
+
+// ----------------------------------------------------------------------------------------
+//  Prepare to write to the display memory to a given rectangle.
+//
+
+static void prep_page_col_address( uint8_t x, uint8_t dx, uint8_t y, uint8_t dy )
+{
+    send_command( SFE569_COMMAND_PASET );
+    send_data( y );
+    send_data( y + dy );
+
+    send_command( SFE569_COMMAND_CASET );
+    send_data( x );
+    send_data( x + dx );
+
+    send_command( SFE569_COMMAND_RAMWR );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+void sfe569_fill_screen( sfe569_color_t color )
+{
+    select_controller();
+
+    //--    Set the page and column addressing to 0 - 131.
+
+    prep_page_col_address( 0, ( 132 - 1 ), 0, ( 132 - 1 ) );
+
+    for ( uint16_t i = 0; i < ( 132 * 132 ); i++ ) 
+    {
+        send_data( color );
+    }
+
+    deselect_controller();
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_WRITE_CHAR )
+
+void sfe569_write
+    (
+        char           c, 
+        uint8_t        x, 
+        uint8_t        y, 
+        sfe569_color_t fg_color,
+        sfe569_color_t bg_color 
+    )
+{
+    //--    Convert the glyph coordinates to pixel coordinates.
+
+    x %= SFE569_MAX_HORIZONTAL_CHARS;
+    x *= SFE569_GLYPH_WIDTH;
+    x += SFE569_HORIZONTAL_PIXEL_OFFSET;
+
+    y %= SFE569_MAX_VERTICAL_CHARS;
+    y *= SFE569_GLYPH_HEIGHT;
+    y += SFE569_VERTICAL_PIXEL_OFFSET;
+
+    //--    Glyphs are stored starting with the space character: ASCII 32 = 0x20.
+
+    if ( c < 0x20 )
+    {
+        c = 0x7f;   // generic character glyph
+    }
+
+    c -= 0x20;
+    
+    const prog_uint8_t* this_glyph
+      = reinterpret_cast< const prog_uint8_t* >( &glyphs[ static_cast< uint8_t >( c ) ] );
+
+    //--    Write the glyph pixels at the specified location.
+
+    select_controller();
+    
+    prep_page_col_address( x, SFE569_GLYPH_WIDTH - 1, y, SFE569_GLYPH_HEIGHT - 1 );
+
+    for ( uint8_t i = 0; i < SFE569_GLYPH_HEIGHT; i++ )
+    {
+        uint8_t data = pgm_read_byte_near( this_glyph++ );
+
+        for ( uint8_t j = 0; j < SFE569_GLYPH_WIDTH; j++ )
+        {
+            if ( data & 0x80 )
+            {
+                send_data( fg_color );
+            }
+            else
+            {
+                send_data( bg_color );
+            }
+            data <<= 1;
+        }
+    }
+
+    deselect_controller();
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_WRITE_CSTRINGS )
+
+void sfe569_write
+    ( 
+        const char*    str, 
+        uint8_t        x, 
+        uint8_t        y, 
+        sfe569_color_t fg_color,
+        sfe569_color_t bg_color 
+    )
+{
+    while ( *str )
+    {
+        sfe569_write( *str++, x++, y, fg_color, bg_color );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_WRITE_PGM_CSTRINGS )
+
+void sfe569_write_pgm
+    ( 
+        const prog_char* str, 
+        uint8_t          x, 
+        uint8_t          y, 
+        sfe569_color_t   fg_color,
+        sfe569_color_t   bg_color 
+    )
+{
+    for ( ;; )
+    {
+        char c = static_cast< char >( pgm_read_byte_near( str++ ) );
+
+        if ( c == '\0' )
+        {
+            return;
+        }
+
+        sfe569_write( c, x++, y, fg_color, bg_color );
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_SET_PIXEL )
+
+void sfe569_set_pixel( uint8_t x, uint8_t y, sfe569_color_t color )
+{
+    x %= SFE569_MAX_HORIZONTAL_PIXELS;
+    x += SFE569_HORIZONTAL_PIXEL_OFFSET;
+    y %= SFE569_MAX_VERTICAL_PIXELS;
+    y += SFE569_VERTICAL_PIXEL_OFFSET;
+
+    select_controller();
+    
+    prep_page_col_address( x, 0, y, 0 );
+    send_data( color );
+    
+    deselect_controller();
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_DRAWING )
+
+void sfe569_line_h( uint8_t x, uint8_t y, uint8_t len, sfe569_color_t color )
+{
+    x %= SFE569_MAX_HORIZONTAL_PIXELS;
+    y %= SFE569_MAX_VERTICAL_PIXELS;
+    
+    if ( len + x > SFE569_MAX_HORIZONTAL_PIXELS )
+    {
+        len = SFE569_MAX_HORIZONTAL_PIXELS - x;
+    }
+
+    x += SFE569_HORIZONTAL_PIXEL_OFFSET;
+    y += SFE569_VERTICAL_PIXEL_OFFSET;
+
+    select_controller();
+    
+    prep_page_col_address( x, len - 1, y, 0 );
+    
+    while ( len-- )
+    {
+        send_data( color );
+    }
+
+    deselect_controller();
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_DRAWING )
+
+void sfe569_line_v( uint8_t x, uint8_t y, uint8_t len, sfe569_color_t color )
+{
+    x %= SFE569_MAX_HORIZONTAL_PIXELS;
+    y %= SFE569_MAX_VERTICAL_PIXELS;
+    
+    if ( len + y > SFE569_MAX_VERTICAL_PIXELS )
+    {
+        len = SFE569_MAX_VERTICAL_PIXELS - y;
+    }
+
+    x += SFE569_HORIZONTAL_PIXEL_OFFSET;
+    y += SFE569_VERTICAL_PIXEL_OFFSET;
+
+    select_controller();
+    
+    prep_page_col_address( x, 0, y, len - 1 );
+    
+    while ( len-- )
+    {
+        send_data( color );
+    }
+
+    deselect_controller();
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_DRAWING )
+
+void sfe569_rect( uint8_t x, uint8_t y, uint8_t w, uint8_t h, sfe569_color_t color )
+{
+    sfe569_line_h( x, y, w, color );
+    sfe569_line_h( x, y + h - 1, w, color );
+    sfe569_line_v( x, y, h - 1, color );
+    sfe569_line_v( x + w - 1, y, h - 1, color );
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_DRAWING )
+
+void sfe569_fill( uint8_t x, uint8_t y, uint8_t w, uint8_t h, sfe569_color_t color )
+{
+    x %= SFE569_MAX_HORIZONTAL_PIXELS;
+    y %= SFE569_MAX_VERTICAL_PIXELS;
+    
+    if ( w + x > SFE569_MAX_HORIZONTAL_PIXELS )
+    {
+        w = SFE569_MAX_HORIZONTAL_PIXELS - x;
+    }
+
+    if ( h + y > SFE569_MAX_VERTICAL_PIXELS )
+    {
+        h = SFE569_MAX_VERTICAL_PIXELS - y;
+    }
+
+    x += SFE569_HORIZONTAL_PIXEL_OFFSET;
+    y += SFE569_VERTICAL_PIXEL_OFFSET;
+
+    select_controller();
+    
+    prep_page_col_address( x, w - 1, y, h - 1 );
+    
+    for ( uint16_t i = 0; i < static_cast< uint16_t >( h * w ); i++ )
+    {
+        send_data( color );
+    }
+
+    deselect_controller();
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_DRAWING )
+
+void sfe569_line( uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, sfe569_color_t color )
+{
+    //--    Bresenham's line rasterization algorithm: 
+    //      http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html
+
+    int16_t dy = y1 - y0;
+    int16_t dx = x1 - x0;
+    int8_t  step_x = 1;
+    int8_t  step_y = 1;
+
+    if ( dy < 0 )
+    {
+        dy *= -1;
+        step_y = -1;
+    }
+
+    if ( dx < 0 )
+    {
+        dx *= -1;
+        step_x = -1;
+    }
+
+    dy <<= 1;
+    dx <<= 1;
+
+    sfe569_set_pixel( x0, y0, color );
+
+    if ( dx > dy )
+    {
+        int16_t fraction = dy - ( dx >> 1 );
+
+        while ( x0 != x1 )
+        {
+            if ( fraction >= 0 ) 
+            {
+                y0 += step_y;
+                fraction -= dx;
+            }
+
+            x0 += step_x;
+            fraction += dy;
+
+            sfe569_set_pixel( x0, y0, color );
+        }
+    }
+    else
+    {
+        int16_t fraction = dx - ( dy >> 1 );
+
+        while ( y0 != y1 )
+        {
+            if ( fraction >= 0 )
+            {
+                x0 += step_x;
+                fraction -= dy;
+            }
+
+            y0 += step_y;
+            fraction += dx;
+
+            sfe569_set_pixel( x0, y0, color );
+        }
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_IMAGEMASK )
+
+void sfe569_imagemask
+    (
+        uint8_t             x,
+        uint8_t             y,
+        uint8_t             w,
+        uint8_t             h,
+        sfe569_color_t      fg_color,
+        sfe569_color_t      bg_color,
+        const prog_uint8_t* pixels
+    )
+{
+    x %= SFE569_MAX_HORIZONTAL_PIXELS;
+    x += SFE569_HORIZONTAL_PIXEL_OFFSET;
+    
+    y %= SFE569_MAX_VERTICAL_PIXELS;
+    y += SFE569_VERTICAL_PIXEL_OFFSET;
+
+    select_controller();
+    
+    prep_page_col_address( x, w - 1, y, h - 1 );
+    
+    while ( h-- )
+    {
+        uint8_t pix_bit = 0x00;
+        uint8_t data    = 0x00;
+
+        for ( uint8_t i = 0; i < w; i++ )
+        {
+            if ( pix_bit == 0x00 )
+            {
+                data = pgm_read_byte_near( pixels++ );
+                pix_bit = 0x80;
+            }
+
+            if ( data & pix_bit )
+            {
+                send_data( fg_color );
+            }
+            else
+            {
+                send_data( bg_color );
+            }
+
+            pix_bit >>= 1;
+        }
+    }
+
+    deselect_controller();
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_SFE569_INC_COLORIMAGE )
+
+void sfe569_colorimage
+    (
+        uint8_t x,
+        uint8_t y,
+        uint8_t w,
+        uint8_t h,
+        const prog_uint8_t* pixels
+    )
+{
+    x %= SFE569_MAX_HORIZONTAL_PIXELS;
+    x += SFE569_HORIZONTAL_PIXEL_OFFSET;
+    
+    y %= SFE569_MAX_VERTICAL_PIXELS;
+    y += SFE569_VERTICAL_PIXEL_OFFSET;
+
+    select_controller();
+    
+    prep_page_col_address( x, w - 1, y, h - 1 );
+    
+    while ( h-- )
+    {
+        for ( uint8_t i = 0; i < w; i++ )
+        {
+            send_data( pgm_read_byte_near( pixels++ ) );
+        }
+    }
+
+    deselect_controller();
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#endif  // #if defined( PRJ_SFE569_ENABLE )
+
+
+// ----------------------------------------------------------------------------------------
+//  end of sfe569.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/lcd/sfe569/sfe569.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,293 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/lcd/sfe569/sfe569.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file implements support for the SparkFun 128x128 Color LCD (#LCD-000569).
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_SFE569_H )
+#define BCDRL_AVR_SFE569_H
+
+
+#include <stdint.h>
+#include <avr/pgmspace.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  enable support for the SFE 128x128 Color LCD with:
+//
+//      + PRJ_SFE569_ENABLE
+//
+//  specify the serial clock pin with:
+//
+//      + PRJ_SFE569_CLOCK_PORT
+//      + PRJ_SFE569_CLOCK_PIN
+//      + PRJ_SFE569_CLOCK_DDR
+//
+//  specify the serial data pin with:
+//
+//      + PRJ_SFE569_DATA_PORT
+//      + PRJ_SFE569_DATA_PIN
+//      + PRJ_SFE569_DATA_DDR
+//
+//  specify the chip select pin with:
+//
+//      + PRJ_SFE569_SELECT_PORT
+//      + PRJ_SFE569_SELECT_PIN
+//      + PRJ_SFE569_SELECT_DDR
+//
+//  specify the RESET pin with:
+//
+//      + PRJ_SFE569_RESET_PORT
+//      + PRJ_SFE569_RESET_PIN
+//      + PRJ_SFE569_RESET_DDR
+//
+//  optional features can be enabled with one or more of the following:
+//
+//      + PRJ_SFE569_INC_WRITE_CHAR
+//      + PRJ_SFE569_INC_WRITE_CSTRINGS
+//      + PRJ_SFE569_INC_WRITE_PGM_CSTRINGS
+//      + PRJ_SFE569_INC_SET_PIXEL
+//      + PRJ_SFE569_INC_DRAWING
+//      + PRJ_SFE569_INC_IMAGEMASK
+//      + PRJ_SFE569_INC_COLORIMAGE
+//
+// ----------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_color_t
+//
+//      The display driver uses 8-bit color values, packed as: RRRGGGBB
+//
+
+typedef uint8_t sfe569_color_t;
+
+const sfe569_color_t sfe569_color_black   = 0x00;
+const sfe569_color_t sfe569_color_white   = 0xff;
+const sfe569_color_t sfe569_color_red     = 0xe0;
+const sfe569_color_t sfe569_color_green   = 0x1c;
+const sfe569_color_t sfe569_color_blue    = 0x03;
+const sfe569_color_t sfe569_color_cyan    = 0x1f;
+const sfe569_color_t sfe569_color_magenta = 0xe3;
+const sfe569_color_t sfe569_color_yellow  = 0xfc;
+const sfe569_color_t sfe569_color_brown   = 0xa5;
+const sfe569_color_t sfe569_color_orange  = 0xf4;
+const sfe569_color_t sfe569_color_pink    = 0xee;
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_init
+//
+//      Initialize the Color LCD driver package, setting up the hardware and clearing the
+//      display. Call this function prior to any other.
+//
+
+void sfe569_init();
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_fill_screen
+//
+//      Fill the entire screen with the specified color. Use this function to erase the
+//      screen by filling it with "sfe569_color_black".
+//
+
+void sfe569_fill_screen( sfe569_color_t color );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_write
+//
+//      Write a character to the display in the *character* row and column. The display
+//      can support 16 rows by 21 columns.
+//
+//      This function is only available if PRJ_SFE569_INC_WRITE_CHAR is defined.
+//
+
+void sfe569_write
+    (
+        char           c, 
+        uint8_t        x, 
+        uint8_t        y, 
+        sfe569_color_t fg_color,
+        sfe569_color_t bg_color 
+    );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_write
+//
+//      Write a string to the display in the *character* row and column. The display
+//      can support 16 rows by 21 columns.
+//
+//      This function is only available if PRJ_SFE569_INC_WRITE_CSTRINGS is defined.
+//
+
+void sfe569_write
+    ( 
+        const char*    str, 
+        uint8_t        x, 
+        uint8_t        y, 
+        sfe569_color_t fg_color,
+        sfe569_color_t bg_color 
+    );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_write_pgm
+//
+//      Write a string from flash memory to the display in the *character* row and column.
+//      The display can support 16 rows by 21 columns.
+//
+//      This function is only available if PRJ_SFE569_INC_WRITE_PGM_CSTRINGS is defined.
+//
+
+void sfe569_write_pgm
+    ( 
+        const prog_char* str, 
+        uint8_t          x, 
+        uint8_t          y, 
+        sfe569_color_t   fg_color,
+        sfe569_color_t   bg_color 
+    );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_set_pixel
+//
+//      Paint a specific pixel. The display supports 128 rows by 128 columns.
+//
+//      This function is only available if PRJ_SFE569_INC_SET_PIXEL is defined.
+//
+
+void sfe569_set_pixel( uint8_t x, uint8_t y, sfe569_color_t color );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_line_h
+//
+//      Paint a row of pixels.
+//
+//      This function is only available if PRJ_SFE569_INC_DRAWING is defined.
+//
+
+void sfe569_line_h( uint8_t x, uint8_t y, uint8_t len, bool state );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_line_v
+//
+//      Paint a column of pixels.
+//
+//      This function is only available if PRJ_SFE569_INC_DRAWING is defined.
+//
+
+void sfe569_line_v( uint8_t x, uint8_t y, uint8_t len, bool state );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_rect
+//
+//      Paint the frame (edge) pixels of a rectangular region.
+//
+//      This function is only available if PRJ_SFE569_INC_DRAWING is defined.
+//
+
+void sfe569_rect( uint8_t x, uint8_t y, uint8_t w, uint8_t h, sfe569_color_t color );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_fill
+//
+//      Turn on all the pixels inside of a rectangular region.
+//
+//      This function is only available if PRJ_SFE569_INC_DRAWING is defined.
+//
+
+void sfe569_fill( uint8_t x, uint8_t y, uint8_t w, uint8_t h, sfe569_color_t color );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_line
+//
+//      Turn on or off the pixels in a line between two points. This is much more
+//      expensive for horizontal or vertical lines; prefer to use the optimized
+//      functions (sfe569_line_h, sfe569_line_v) for those cases when possible.
+//
+//      This function is only available if PRJ_SFE569_INC_DRAWING is defined.
+//
+
+void sfe569_line( uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, sfe569_color_t color );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_imagemask
+//
+//      Paint pixels with the specified color using the 1-bit image as a mask, at the
+//      specified pixel location. The pixel data must be stored in flash memory and be 
+//      organized by rows, padded to whole bytes per row.
+//
+//      This function is only available if PRJ_SFE569_INC_IMAGEMASK is defined.
+//
+
+void sfe569_imagemask
+    (
+        uint8_t             x,
+        uint8_t             y,
+        uint8_t             w,
+        uint8_t             h,
+        sfe569_color_t      fg_color,
+        sfe569_color_t      bg_color,
+        const prog_uint8_t* pixels
+    );
+
+
+// ----------------------------------------------------------------------------------------
+//  sfe569_colorimage
+//
+//      Paint an image at the specified pixel location. The pixel data must be stored in
+//      flash memory and be organized by rows, padded to an even number of bytes per row.
+//      Each pixel must the 8-bit format: RRRGGGBB.
+//
+//      This function is only available if PRJ_SFE569_INC_COLORIMAGE is defined.
+//
+
+void sfe569_colorimage
+    (
+        uint8_t x,
+        uint8_t y,
+        uint8_t w,
+        uint8_t h,
+        const prog_uint8_t* pixels
+    );
+
+
+#endif  // #if !defined( BCDRL_AVR_SFE569_H )
+// ----------------------------------------------------------------------------------------
+//  end of sfe569.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/redir/jamfile	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,40 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr/redir/jamfile
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Copyright (C) 2007 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /packages/avr/redir/jamfile" ; }
+
+SubDir TOP packages avr redir ;
+
+
+# -----------------------------------------------------------------------------------------
+
+PackageSources
+    redir.cpp
+    ;
+    
+# -----------------------------------------------------------------------------------------
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/redir/redir.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,316 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/redir/redir.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides redirection support for the C library standard input/output.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "redir.h"
+
+#include <stdio.h>
+
+#include "packages/avr/can/can_messages.h"
+#include "packages/avr/can/mcp2515.h"
+#include "packages/avr/device/hwdefs.h"
+#include "packages/avr/device/spinwait.h"
+#include "packages/avr/device/uart.h"
+
+
+// ----------------------------------------------------------------------------------------
+
+#include "project_defs.h"
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_REDIR_VIA_UART0 )
+#if defined( PRJ_REDIR_VIA_UART1 ) || defined( PRJ_REDIR_VIA_MCP2515_CAN )
+#error Too many STDIO output options selected!
+#endif
+#if !defined( HW_HAS_UART0 )
+#error Target hardware does not support UART0!
+#endif
+#endif
+
+#if defined( PRJ_REDIR_VIA_UART1 )
+#if defined( PRJ_REDIR_VIA_UART0 ) || defined( PRJ_REDIR_VIA_MCP2515_CAN )
+#error Too many STDIO output options selected!
+#endif
+#if !defined( HW_HAS_UART1 )
+#error Target hardware does not support UART1!
+#endif
+#endif
+
+#if defined( PRJ_REDIR_VIA_MCP2515_CAN )
+#if defined( PRJ_REDIR_VIA_UART0 ) || defined( PRJ_REDIR_VIA_UART1 )
+#error Too many STDIO output options selected!
+#endif
+#endif
+
+#if defined( PRJ_REDIR_VIA_MCP2515_CAN )
+#if !defined( PRJ_REDIR_CAN_PUTCHAR_NODE )
+#error PRJ_REDIR_CAN_PUTCHAR_NODE is required!
+#endif
+#if !defined( PRJ_REDIR_CAN_PUTCHAR_NODE )
+#error PRJ_REDIR_CAN_PUTCHAR_NODE is required!
+#endif
+#if !defined( PRJ_REDIR_CAN_THIS_NODE )
+#error PRJ_REDIR_CAN_THIS_NODE is required!
+#endif
+#if !defined( PRJ_REDIR_CAN_BUFFER_SIZE )
+#define PRJ_REDIR_CAN_BUFFER_SIZE 16
+#endif
+#if ( PRJ_REDIR_CAN_BUFFER_SIZE == 0 )
+#error PRJ_REDIR_CAN_BUFFER_SIZE cannot be zero!
+#endif
+#endif
+
+#if defined( PRJ_REDIR_CAN_BUFFER_MASK )
+#undef PRJ_REDIR_CAN_BUFFER_MASK
+#endif
+#define PRJ_REDIR_CAN_BUFFER_MASK ( PRJ_REDIR_CAN_BUFFER_SIZE - 1 )
+
+#if defined( PRJ_REDIR_VIA_UART0 )    \
+    || defined( PRJ_REDIR_VIA_UART1 ) \
+    || defined( PRJ_REDIR_VIA_MCP2515_CAN )
+    
+#define STDIO_INCLUDE_FUNCTIONS
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_REDIR_VIA_MCP2515_CAN )
+
+static uint8_t can_tx_buffer[ PRJ_REDIR_CAN_BUFFER_SIZE ];
+static uint8_t can_tx_used;
+
+static volatile uint8_t can_rx_buffer[ PRJ_REDIR_CAN_BUFFER_SIZE ];
+static volatile uint8_t can_rx_head;
+static volatile uint8_t can_rx_tail;
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( STDIO_INCLUDE_FUNCTIONS )
+
+static int stdio_putchar( char c, FILE* f )
+{
+    (void) f;
+
+#if defined( PRJ_REDIR_OUTPUT_DO_AUTO_CRLF )
+    
+    if ( c == '\n' )
+    {
+        putchar( '\r' );
+    }
+    
+#endif
+
+#if defined( PRJ_REDIR_VIA_UART0 )
+    
+    uart0_write( static_cast< uint8_t >( c ) );
+    
+#elif defined( PRJ_REDIR_VIA_UART1 )
+    
+    uart1_write( static_cast< uint8_t >( c ) );
+    
+#elif defined( PRJ_REDIR_VIA_MCP2515_CAN )
+    
+    can_tx_buffer[ can_tx_used++ ] = static_cast< uint8_t >( c );
+    
+    bool wait_for_completion = ( c == '\n' );
+
+    if ( can_tx_used >= array_sizeof( can_tx_buffer ) )
+    {
+        wait_for_completion = true;
+    }
+
+    for ( ;; )
+    {
+        if ( can_send( PRJ_REDIR_CAN_THIS_NODE,
+                       PRJ_REDIR_CAN_PUTCHAR_NODE,
+                       can_msgid_stdio,
+                       can_tx_buffer,
+                       can_tx_used ) )
+        {
+            can_tx_used = 0;
+            break;
+        }
+
+        if ( ! wait_for_completion )
+        {
+            break;
+        }
+
+        spinwait_delay_ms( 1 );
+    }
+    
+#endif
+    
+    return 0;
+}
+
+#endif
+
+    
+// ----------------------------------------------------------------------------------------
+
+#if defined( STDIO_INCLUDE_FUNCTIONS )
+
+static int stdio_getchar( FILE* f )
+{
+    (void) f;
+
+#if defined( PRJ_REDIR_VIA_UART0 )
+
+#if !defined( PRJ_REDIR_INPUT_BLOCKING_GETCHAR )
+    
+    if ( ! uart0_is_char_available() )
+    {
+        return _FDEV_EOF;
+    }
+
+#endif
+    
+    return ( static_cast< int >( uart0_read() ) & 0x00FF );
+
+#elif defined( PRJ_REDIR_VIA_UART1 )
+
+#if !defined( PRJ_REDIR_INPUT_BLOCKING_GETCHAR )
+    
+    if ( ! uart1_is_char_available() )
+    {
+        return _FDEV_EOF;
+    }
+
+#endif
+    
+    return ( static_cast< int >( uart1_read() ) & 0x00FF );
+    
+#elif defined( PRJ_REDIR_VIA_MCP2515_CAN )
+    
+    if ( can_rx_head != can_rx_tail )
+    {
+        can_rx_tail = ( can_rx_tail + 1 ) & PRJ_REDIR_CAN_BUFFER_MASK;
+        return ( static_cast< int >( can_rx_buffer[ can_rx_tail ] ) & 0x00FF );
+    }
+            
+    return _FDEV_EOF;
+
+#endif
+
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( STDIO_INCLUDE_FUNCTIONS )
+
+void redir_initialize()
+{
+
+#if !defined( PRJ_REDIR_CALLER_WILL_INIT_TRANSPORT_PKG )
+
+#if defined( PRJ_REDIR_VIA_UART0 )
+
+    uart0_init();
+
+#if defined( PRJ_REDIR_UART_BAUDRATE )
+
+    uart0_set_baudrate( PRJ_REDIR_UART_BAUDRATE );
+
+#endif
+
+#elif defined( PRJ_REDIR_VIA_UART1 )
+
+    uart1_init();
+
+#if defined( PRJ_REDIR_UART_BAUDRATE )
+
+    uart1_set_baudrate( PRJ_REDIR_UART_BAUDRATE );
+
+#endif
+
+#elif defined( PRJ_REDIR_VIA_MCP2515_CAN )
+
+    if ( ! mcp2515_init() )
+    {
+        // initialization error
+
+        // TODO
+    }
+
+#endif
+
+#endif // #if !defined( PRJ_REDIR_CALLER_WILL_INIT_TRANSPORT_PKG )
+
+    static FILE stdio_stream;
+
+    fdev_setup_stream( &stdio_stream, stdio_putchar, stdio_getchar, _FDEV_SETUP_RW );
+    stdout = &stdio_stream;
+    stdin  = &stdio_stream;
+
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( STDIO_INCLUDE_FUNCTIONS ) && defined( PRJ_REDIR_VIA_MCP2515_CAN )
+
+void redir_recv_can_stdio( const uint8_t* data_ptr, uint8_t len )
+{
+    for ( ; len > 0; len--, data_ptr++ )
+    {
+        uint8_t rx_head = ( can_rx_head + 1 ) & PRJ_REDIR_CAN_BUFFER_MASK;
+        uint8_t data    = *data_ptr;
+
+        if ( rx_head != can_rx_tail )
+        {
+            can_rx_head = rx_head;
+            can_rx_buffer[ rx_head ] = data;
+        }
+        else
+        {
+            // overflow error
+
+            // TODO
+        }
+    }
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+//  end of redir.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/redir/redir.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,89 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/redir/redir.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file provides redirection support for the C library standard input/output.
+//
+//  Copyright (C) 2007 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_REDIR_REDIR_H )
+#define BCDRL_AVR_REDIR_REDIR_H
+
+
+#include <stdint.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  define only one (or none) of the following:
+//
+//      PRJ_REDIR_VIA_UART0
+//      PRJ_REDIR_VIA_UART1
+//      PRJ_REDIR_VIA_MCP2515_CAN
+//
+//  for any option, optionally define these values:
+//
+//      PRJ_REDIR_CALLER_WILL_INIT_TRANSPORT_PKG
+//      PRJ_REDIR_OUTPUT_DO_AUTO_CRLF
+//
+//  for the UART options, optionally define these values:
+//
+//      PRJ_REDIR_UART_BAUDRATE <int>
+//      PRJ_REDIR_INPUT_BLOCKING_GETCHAR
+//
+//  for the CAN options, define these required values:
+//
+//      PRJ_REDIR_CAN_PUTCHAR_NODE
+//      PRJ_REDIR_CAN_THIS_NODE
+//
+//  for the CAN options, optionally define these values:
+//
+//      PRJ_REDIR_CAN_BUFFER_SIZE <int>
+//
+// ----------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------------------
+//  redir_initialize
+//
+//      Initialize the STDIO handlers according to the project_defs.h specification.
+//
+
+void redir_initialize();
+
+
+// ----------------------------------------------------------------------------------------
+//  redir_recv_can_stdio
+//
+//      Process the reception of a CAN message id: can_msgid_stdio.
+//
+
+void redir_recv_can_stdio( const uint8_t* data_ptr, uint8_t len );
+
+
+#endif  // #if !defined( BCDRL_AVR_REDIR_REDIR_H )
+// ----------------------------------------------------------------------------------------
+//  end of redir.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/sensors/avrcam/avrcam.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,586 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/sensors/avrcam/avrcam.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file implements support for the JROBOT AVRcam.
+//
+//  Copyright (C) 2009 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "avrcam.h"
+
+#include "packages/common/util/misc.h"
+
+#include "packages/avr/device/spinwait.h"
+#include "packages/avr/device/uart.h"
+
+#include <stdio.h>
+#include <avr/pgmspace.h>
+
+
+// ----------------------------------------------------------------------------------------
+
+#include "project_defs.h"
+
+
+// ----------------------------------------------------------------------------------------
+
+#if !defined( PRJ_AVRCAM_USE_UART0 ) && !defined( PRJ_AVRCAM_USE_UART1 )
+#error One of PRJ_AVRCAM_USE_UART0 or PRJ_AVRCAM_USE_UART1 is required!
+#endif
+
+#if defined( PRJ_AVRCAM_USE_UART0 ) && defined( PRJ_AVRCAM_USE_UART1 )
+#error Only one of PRJ_AVRCAM_USE_UART0 or PRJ_AVRCAM_USE_UART1 can be defined!
+#endif
+
+#if defined( PRJ_AVRCAM_USE_UART0 ) && defined( PRJ_REDIR_VIA_UART0 )
+#error STDIO redirection conflicts with AVRcam use of UART0!
+#endif
+
+#if defined( PRJ_AVRCAM_USE_UART1 ) && defined( PRJ_REDIR_VIA_UART1 )
+#error STDIO redirection conflicts with AVRcam use of UART1!
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+    
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING )
+
+static volatile avrcam_track_data_t* g_tracking_data_ptr;
+static volatile uint8_t              g_tracking_num_data;
+static volatile uint8_t              g_tracking_slot_index;
+
+static volatile uint8_t g_tracking_state;
+
+static volatile uint8_t g_tracking_color;
+static volatile uint8_t g_tracking_ulx;
+static volatile uint8_t g_tracking_uly;
+static volatile uint8_t g_tracking_lrx;
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING_CLIP )
+
+static volatile uint8_t g_track_clip_ulx;
+static volatile uint8_t g_track_clip_uly;
+static volatile uint8_t g_track_clip_lrx;
+static volatile uint8_t g_track_clip_lry;
+
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING_CLIP
+
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING
+
+
+// ----------------------------------------------------------------------------------------
+    
+static bool receive_line( char* str, uint8_t str_size )
+{
+    uint8_t idle_count   = 0;
+    bool    data_overrun = false;
+
+    for ( ;; )
+    {
+        char c;
+
+#if defined( PRJ_AVRCAM_USE_UART0 )
+
+        if ( uart0_is_char_available() )
+        {
+            c = static_cast< char >( uart0_read() );
+
+#elif defined( PRJ_AVRCAM_USE_UART1 )
+
+        if ( uart1_is_char_available() )
+        {
+            c = static_cast< char >( uart1_read() );
+
+#endif
+            
+//if ( idle_count > 0 )
+//{
+//    printf_P( PSTR("...idle_count = %d\n"), idle_count );
+//}
+            idle_count = 0;
+
+            if ( ( c == '\015' ) || ( c == '\012' ) )
+            {
+                *str = '\0';
+                return data_overrun ? false : true;
+            }
+
+            if ( str_size > 1 )
+            {
+                *str = c;
+                str++;
+                str_size--;
+            }
+            else
+            {
+                data_overrun = true;
+            }
+        }
+        else
+        {
+            if ( ++idle_count > 125 )
+            {
+                return false;
+            }
+
+            spinwait_delay_ms( 5 );
+        }
+    }
+
+    return false;
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+static void flush_input()
+{
+    uint8_t idle_count = 0;
+
+    for ( ;; )
+    {
+
+#if defined( PRJ_AVRCAM_USE_UART0 )
+
+        if ( uart0_is_char_available() )
+        {
+            uart0_read();
+
+#elif defined( PRJ_AVRCAM_USE_UART1 )
+
+        if ( uart1_is_char_available() )
+        {
+            uart1_read();
+
+#endif
+            
+            idle_count = 0;
+        }
+        else
+        {
+            if ( ++idle_count > 125 )
+            {
+                return;
+            }
+        }
+    }
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+#if 0
+static bool read_data( uint8_t* buf, uint16_t buf_size )
+{
+    uint8_t idle_count = 0;
+
+    for ( uint16_t i = 0; i < buf_size; i++ )
+    {
+        uint8_t c;
+
+#if defined( PRJ_AVRCAM_USE_UART0 )
+
+        if ( uart0_is_char_available() )
+        {
+            c = uart0_read();
+
+#elif defined( PRJ_AVRCAM_USE_UART1 )
+
+        if ( uart1_is_char_available() )
+        {
+            c = uart1_read();
+
+#endif
+
+            idle_count = 0;
+
+            *buf = c;
+            buf++;
+        }
+        else
+        {
+            if ( ++idle_count > 125 )
+            {
+                return false;
+            }
+
+            spinwait_delay_us( 10 );
+        }
+    }
+
+    return true;
+}
+#endif
+
+
+// ----------------------------------------------------------------------------------------
+    
+static bool send_command( char cmdchar0, char cmdchar1 )
+{
+
+#if defined( PRJ_AVRCAM_USE_UART0 )
+
+    uart0_write( cmdchar0 );
+    uart0_write( cmdchar1 );
+    uart0_write( '\015' );
+
+#elif defined( PRJ_AVRCAM_USE_UART1 )
+    
+    uart1_write( cmdchar0 );
+    uart1_write( cmdchar1 );
+    uart1_write( '\015' );
+
+#endif
+
+    char ack_buffer[ 6 ] = { 0 };
+
+    if ( ! receive_line( ack_buffer, sizeof( ack_buffer ) ) )
+    {
+        return false;
+    }
+
+    if ( ( ack_buffer[ 0 ] != 'A'  ) || 
+         ( ack_buffer[ 1 ] != 'C'  ) ||
+         ( ack_buffer[ 2 ] != 'K'  ) ||
+         ( ack_buffer[ 3 ] != '\0' ) )
+    {
+        return false;
+    }
+
+    return true;
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+bool avrcam_init()
+{
+
+#if defined( PRJ_AVRCAM_USE_UART0 )
+
+    uart0_init();
+    uart0_set_baudrate( 115200 );
+
+#elif defined( PRJ_AVRCAM_USE_UART1 )
+    
+    uart1_init();
+    uart1_set_baudrate( 115200 );
+
+#endif
+
+    UCSR1A = ( 1 << U2X1 );
+    UCSR1B = ( 1 << RXCIE1 ) | ( 1 << RXEN1 ) | ( 1 << TXEN1 ) | ( 0 << UCSZ12 );
+    UCSR1C = ( 0 << UMSEL1 ) | ( 0 << UPM11  ) | ( 0 << UPM10  )
+           | ( 0 << USBS1  ) | ( 1 << UCSZ11 ) | ( 1 << UCSZ10 );
+    UBRR1H =  0;
+    UBRR1L = 16;
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING )
+
+    g_tracking_data_ptr = 0;
+
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING_CLIP )
+
+    g_track_clip_ulx = 0;
+    g_track_clip_uly = 0;
+    g_track_clip_lrx = 255;
+    g_track_clip_lry = 255;
+    
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING_CLIP
+
+    return avrcam_ping();
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+bool avrcam_ping()
+{
+    send_command( 'D', 'T' );
+    send_command( 'R', 'S' );
+    flush_input();
+    return send_command( 'P', 'G' );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_AVRCAM_ENABLE_GETVERSION )
+
+bool avrcam_get_version(  char* verstr, uint8_t str_size )
+{
+    if ( ! send_command( 'G', 'V' ) )
+    {
+        return false;
+    }
+
+    return receive_line( verstr, str_size );
+}
+
+#endif  // PRJ_AVRCAM_ENABLE_GETVERSION
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING_CLIP )
+
+void avrcam_set_tracking_clip( uint8_t ulx, uint8_t uly, uint8_t lrx, uint8_t lry )
+{
+    g_track_clip_ulx = ulx;
+    g_track_clip_uly = uly;
+    g_track_clip_lrx = lrx;
+    g_track_clip_lry = lry;
+}
+
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING_CLIP
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING )
+
+bool avrcam_start_tracking( avrcam_track_data_t* data, uint8_t num_data )
+{
+    if ( data == 0 || num_data == 0 )
+    {
+        g_tracking_data_ptr = 0;
+        return false;
+    }
+
+    if ( ! send_command( 'E', 'T' ) )
+    {
+        return false;
+    }
+
+    g_tracking_data_ptr = data;
+    g_tracking_num_data = num_data;
+    g_tracking_state    = 0;
+
+    return true;
+}
+
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING )
+
+bool avrcam_update_tracking()
+{
+    if ( g_tracking_data_ptr == 0 )
+    {
+        return false;
+    }
+
+    bool result = false;
+
+#if defined( PRJ_AVRCAM_USE_UART0 )
+
+    while ( uart0_is_char_available() )
+    {
+        uint8_t c = uart0_read();
+
+#elif defined( PRJ_AVRCAM_USE_UART1 )
+
+    while ( uart1_is_char_available() )
+    {
+        uint8_t c = uart1_read();
+
+#endif
+            
+//printf_P( PSTR("%02x "), c );
+
+        switch ( g_tracking_state )
+        {
+            case 0: // looking for the start of the frame
+
+                if ( c == 0x0a )
+                {
+                    g_tracking_slot_index = 0;
+                    g_tracking_state = 1;
+                }
+                break;
+
+            case 1: // read the tracked object count
+
+                g_tracking_state = 2; // we ignore this value
+                break;
+
+            case 2: // read the color index
+
+                if ( c == 0xff ) // end of tracked objects
+                {
+                    volatile avrcam_track_data_t* slot_ptr = g_tracking_data_ptr;
+                    slot_ptr += g_tracking_slot_index;
+
+                    while ( g_tracking_slot_index < g_tracking_num_data )
+                    {
+                        slot_ptr->id = 0;
+                        slot_ptr++;
+                        g_tracking_slot_index++;
+                    }
+
+//            for ( uint8_t i = 0; i < g_tracking_num_data; i++ )
+//            {
+//                printf_P( PSTR("index: %d color: %d ul(%d,%d) lr(%d,%d)\n"), i, g_tracking_data_ptr[ i ].id,
+//                      g_tracking_data_ptr[ i ].ul_x, g_tracking_data_ptr[ i ].ul_y, g_tracking_data_ptr[ i ].lr_x, g_tracking_data_ptr[ i ].lr_y );
+//            }
+                    result = true;
+
+                    g_tracking_state = 0; // wait for the start of the next frame
+                }
+                else
+                {
+                    g_tracking_color = c;
+                    g_tracking_state = 3;
+                }
+                break;
+
+            case 3: // read the ulx value
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING_CLIP )
+
+                if ( c > g_track_clip_lrx )
+                {
+                    // completely outside the frame
+                    g_tracking_color = 0;
+                }
+                else
+                {
+                    // top edge clipped to frame
+                    g_tracking_ulx = util_max( c, g_track_clip_ulx );
+                }
+
+#else
+                
+                g_tracking_ulx = c;
+
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING_CLIP
+
+                g_tracking_state = 4;
+                break;
+
+            case 4: // read the uly value
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING_CLIP )
+
+                if ( c > g_track_clip_lry )
+                {
+                    // completely outside the frame
+                    g_tracking_color = 0;
+                }
+                else
+                {
+                    // left edge clipped to frame
+                    g_tracking_uly = util_max( c, g_track_clip_uly );
+                }
+
+#else
+
+                g_tracking_uly = c;
+
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING_CLIP
+
+                g_tracking_state = 5;
+                break;
+
+            case 5: // read the lrx value
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING_CLIP )
+
+                // bottom edge clipped to frame
+                g_tracking_lrx = util_min( c, g_track_clip_lrx );
+
+#else
+                
+                g_tracking_lrx = c;
+
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING_CLIP
+
+                g_tracking_state = 6;
+                break;
+
+            case 6: // read the lry value, save color info
+
+                if ( g_tracking_color > 0 && g_tracking_slot_index < g_tracking_num_data )
+                {
+                    volatile avrcam_track_data_t* slot_ptr = g_tracking_data_ptr;
+                    slot_ptr += g_tracking_slot_index;
+
+                    slot_ptr->id   = g_tracking_color;
+                    slot_ptr->ul_x = g_tracking_ulx;
+                    slot_ptr->ul_y = g_tracking_uly;
+                    slot_ptr->lr_x = g_tracking_lrx;
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING_CLIP )
+
+                    // right edge clipped to frame
+                    slot_ptr->lr_y = util_min( c, g_track_clip_lry );
+
+#else
+
+                    slot_ptr->lr_y = c;
+
+#endif
+
+                    g_tracking_slot_index++;
+                }
+
+                g_tracking_state = 2; // handle the next target
+                break;
+
+            default:
+
+                g_tracking_state = 0; // wait for the start of the next frame
+                break;
+        }
+    }
+
+    return result;
+}
+
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING
+
+
+// ----------------------------------------------------------------------------------------
+
+#if defined( PRJ_AVRCAM_ENABLE_TRACKING )
+
+void avrcam_stop_tracking()
+{
+    g_tracking_data_ptr = 0;
+
+    send_command( 'D', 'T' );
+    flush_input();
+}
+
+#endif  // PRJ_AVRCAM_ENABLE_TRACKING
+
+
+// ----------------------------------------------------------------------------------------
+//  end of avrcam.cpp
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/sensors/avrcam/avrcam.h	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,164 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/sensors/avrcam/avrcam.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file implements support for the JROBOT AVRcam.
+//
+//  Copyright (C) 2009 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#if !defined( BCDRL_AVR_SENSORS_AVRCAM_H )
+#define BCDRL_AVR_SENSORS_AVRCAM_H
+
+
+#include <stdint.h>
+
+
+// ----------------------------------------------------------------------------------------
+//  definitions from "project_defs.h"
+//
+//  specify the UART port to use with one (and only one) of:
+//
+//      + PRJ_AVRCAM_USE_UART0
+//      + PRJ_AVRCAM_USE_UART1
+//
+//  enable AVRcam commands with one or more of:
+//
+//      + PRJ_AVRCAM_ENABLE_GETVERSION
+//      + PRJ_AVRCAM_ENABLE_TRACKING
+//      + PRJ_AVRCAM_ENABLE_TRACKING_CLIP
+//      + PRJ_AVRCAM_ENABLE_FRAMEGRAB
+//
+//  enable the debug support with:
+//
+//      + PRJ_AVRCAM_ENABLE_DEBUG
+//
+// ----------------------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------------------
+//  notes
+//
+//      Commands sent to the AVRcam (such as PING) will return true if the response is
+//      the expected ACK. If the response is something else, or the AVRcam does not
+//      respond within 1.25ms the result will be false.
+//
+// ----------------------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------------------
+//  avrcam_init
+//
+//      Initialize the AVRcam h/w according to the project_defs.h specification. This
+//      will send a PING command to the camera to test connectivity.
+//
+//      Returns true if the initialization was successful.
+//
+
+bool avrcam_init();
+
+    
+// ----------------------------------------------------------------------------------------
+//  avrcam_ping
+//
+//      Returns true if the PING command is successful.
+//
+
+bool avrcam_ping();
+
+
+// ----------------------------------------------------------------------------------------
+//  avrcam_get_version
+//
+//      Retrieve the version of the firmware in the AVRcam. The version string will be
+//      valid only if the result is true.
+//
+//      Only compiled if PRJ_AVRCAM_ENABLE_GETVERSION is defined.
+//
+
+bool avrcam_get_version( char* verstr, uint8_t str_size );
+
+
+// ----------------------------------------------------------------------------------------
+//  avrcam_set_tracking_clip
+//
+//      Restrict the resulting rectangles from color blob tracking to the given area.
+//      For best results call this before avrcam_start_tracking(). 
+//
+//      Only compiled if PRJ_AVRCAM_ENABLE_TRACKING_CLIP is defined.
+//
+
+void avrcam_set_tracking_clip( uint8_t ulx, uint8_t uly, uint8_t lrx, uint8_t lry );
+
+
+// ----------------------------------------------------------------------------------------
+//  avrcam_start_tracking
+//
+//      Start tracking color blobs. Returns true if tracking is now enabled. The results
+//      will be stored in the provided structure, althougth no results will be available
+//      immediately. Call avrcam_update_tracking() regularly to update the results.
+//
+//      Only compiled if PRJ_AVRCAM_ENABLE_TRACKING is defined.
+//
+
+typedef struct
+{
+    uint8_t id; // color table index: 1, 2, etc. not valid if 0
+    uint8_t ul_x, ul_y, lr_x, lr_y; // ul = 0,0
+
+} avrcam_track_data_t;
+
+bool avrcam_start_tracking( avrcam_track_data_t* data, uint8_t num_data );
+
+
+// ----------------------------------------------------------------------------------------
+//  avrcam_update_tracking
+//
+//      Process tracking data and populate the structure set by avrcam_start_tracking()
+//      as color blob information is received. Returns true if any entries in the table
+//      are updated.
+//
+//      This function should be called on average every millisecond (1 kHz).
+//
+//      Has no effect if avrcam_start_tracking() was never called, or if tracking was
+//      stopped by calling avrcam_stop_tracking(). The result will always be false.
+//
+//      Only compiled if PRJ_AVRCAM_ENABLE_TRACKING is defined.
+//
+
+bool avrcam_update_tracking();
+
+
+// ----------------------------------------------------------------------------------------
+//  avrcam_stop_tracking
+//
+//      Turn off the color blob tracking function.
+//
+//      Only compiled if PRJ_AVRCAM_ENABLE_TRACKING is defined.
+//
+
+void avrcam_stop_tracking();
+
+
+#endif  // #if defined( BCDRL_AVR_SENSORS_AVRCAM_H )
+// ----------------------------------------------------------------------------------------
+//  end of avrcam.h
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/sensors/avrcam/jamfile	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,40 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr/sensors/avrcam/jamfile
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Copyright (C) 2009 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /packages/avr/sensors/avrcam/jamfile" ; }
+
+SubDir TOP packages avr sensors avrcam ;
+
+
+# -----------------------------------------------------------------------------------------
+
+PackageSources
+    avrcam.cpp
+    ;
+    
+# -----------------------------------------------------------------------------------------
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/sensors/jamdefs	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,35 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr/sensors/jamdefs
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Copyright (C) 2009 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /packages/avr/sensors/jamdefs" ; }
+
+
+# -----------------------------------------------------------------------------------------
+
+DefinePackages TOP packages avr sensors : avrcam sca3000 ;
+
+# -----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/sensors/sca3000/jamfile	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,40 @@
+# -----------------------------------------------------------------------------------------
+#
+#   avr/sensors/sca3000/jamfile
+#
+#   Bob Cook Development, Robotics Library
+#   http://www.bobcookdev.com/rl/
+#
+#   Copyright (C) 2008 Bob Cook
+#
+#       This program is free software; you can redistribute it and/or modify it
+#       under the terms of the GNU General Public License as published by the
+#       Free Software Foundation; either version 2 of the License, or (at your
+#       option) any later version.
+#     
+#       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, write to the Free Software Foundation, Inc., 
+#       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# -----------------------------------------------------------------------------------------
+
+
+if $(TRACE) { echo "trace /packages/avr/sensors/sca3000/jamfile" ; }
+
+SubDir TOP packages avr sensors sca3000 ;
+
+
+# -----------------------------------------------------------------------------------------
+
+PackageSources
+    sca3000.cpp
+    ;
+    
+# -----------------------------------------------------------------------------------------
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/packages/avr/sensors/sca3000/sca3000.cpp	Sat Apr 17 11:53:09 2010 -0700
@@ -0,0 +1,360 @@
+// ----------------------------------------------------------------------------------------
+//
+//  avr/sensors/sca3000/sca3000.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+//    
+//  This file implements support for the VTI SCA3000-D01 accelerometer via SPI.
+//
+//  Copyright (C) 2008 Bob Cook
+//
+//      This program is free software; you can redistribute it and/or modify it
+//      under the terms of the GNU General Public License as published by the
+//      Free Software Foundation; either version 2 of the License, or (at your
+//      option) any later version.
+//    
+//      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, write to the Free Software Foundation, Inc., 
+//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// ----------------------------------------------------------------------------------------
+
+
+#include "sca3000.h"
+
+#include <avr/io.h>
+
+#include "packages/avr/device/spi.h"
+#include "packages/avr/device/spinwait.h"
+
+
+// ----------------------------------------------------------------------------------------
+
+#include "project_defs.h"
+
+#if defined( PRJ_SCA3000_ENABLE_DEBUG )
+
+#include <stdio.h>
+#include <avr/pgmspace.h>
+#include "packages/common/util/printutils.h"
+
+#endif
+
+
+#if defined( PRJ_SCA3000_ENABLE )
+
+
+// ----------------------------------------------------------------------------------------
+
+#if !defined( PRJ_SCA3000_SELECT_DDR )
+#error PRJ_SCA3000_SELECT_DDR is required!
+#endif
+
+#if !defined( PRJ_SCA3000_SELECT_PORT )
+#error PRJ_SCA3000_SELECT_PORT is required!
+#endif
+
+#if !defined( PRJ_SCA3000_SELECT_PIN )
+#error PRJ_SCA3000_SELECT_PIN is required!
+#endif
+
+#if defined( PRJ_SCA3000_USE_HW_RESET )
+
+#if !defined( PRJ_SCA3000_RESET_DDR )
+#error PRJ_SCA3000_RESET_DDR is required!
+#endif
+
+#if !defined( PRJ_SCA3000_RESET_PORT )
+#error PRJ_SCA3000_RESET_PORT is required!
+#endif
+
+#if !defined( PRJ_SCA3000_RESET_PIN )
+#error PRJ_SCA3000_RESET_PIN is required!
+#endif
+
+#endif  // PRJ_SCA3000_USE_HW_RESET
+
+
+// ----------------------------------------------------------------------------------------
+//  SCA3000 register definitions
+
+const uint8_t SCA3000_REGISTER_REVID  = 0x00;
+const uint8_t SCA3000_REGISTER_STATUS = 0x02;
+
+const uint8_t SCA3000_REGISTER_X_LSB = 0x04;
+const uint8_t SCA3000_REGISTER_X_MSB = 0x05;
+const uint8_t SCA3000_REGISTER_Y_LSB = 0x06;
+const uint8_t SCA3000_REGISTER_Y_MSB = 0x07;
+const uint8_t SCA3000_REGISTER_Z_LSB = 0x08;
+const uint8_t SCA3000_REGISTER_Z_MSB = 0x09;
+
+const uint8_t SCA3000_REGISTER_TEMP_LSB = 0x12;
+const uint8_t SCA3000_REGISTER_TEMP_MSB = 0x13;
+
+const uint8_t SCA3000_REGISTER_MODE = 0x14;
+
+const uint8_t SCA3000_REGISTER_INT_STATUS = 0x16;
+const uint8_t SCA3000_REGISTER_INT_MASK   = 0x21;
+
+
+// ----------------------------------------------------------------------------------------
+    
+inline void device_select()
+{
+    PRJ_SCA3000_SELECT_PORT &= ~( 1 << PRJ_SCA3000_SELECT_PIN );
+}
+
+inline void device_unselect()
+{
+    PRJ_SCA3000_SELECT_PORT |= ( 1 << PRJ_SCA3000_SELECT_PIN );
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static uint8_t read_8bit_register( uint8_t address )
+{
+    uint8_t result;
+
+    device_select();
+
+    spi_write( address << 2 );  // bit 1 = 0 for read, bit 0 is always 0
+    result = spi_read();
+
+    device_unselect();
+
+    return result;
+}
+
+
+// ----------------------------------------------------------------------------------------
+
+static uint16_t read_16bit_register( uint8_t address )
+{
+    uint16_t result;
+
+    device_select();
+
+    spi_write( address << 2 );  // bit 1 = 0 for read, bit 0 is always 0
+    result = spi_read() << 8;
+    result |= spi_read();
+
+    device_unselect();
+
+    return result;
+}
+
+
+// ----------------------------------------------------------------------------------------
+//
+//  The high nibble is 011x when out of range on the positive side.
+//  The high nibble is 100x when out of range on the negative side.
+//
+
+static int16_t read_axis_value( uint8_t msb_address )
+{
+    uint16_t raw = read_16bit_register( msb_address );
+
+    if ( ( raw & 0xE000 ) == 0x6000 )
+    {
+        return 23032;  // max positive value 2303.25 mg (rounded down)
+    }
+
+    if ( ( raw & 0xE000 ) == 0x8000 )
+    {
+        return -23040;  // max negative value -2304.00 mg
+    }
+
+    bool is_negative = false;
+
+    if ( ( raw & 0x8000 ) == 0x8000 )
+    {
+        raw = ~raw;
+        is_negative = true;
+    }
+
+    raw >>= 3; // least significant 3 bits are ignored
+
+    bool add_pt_75 = ( raw & 0x0001 ) != 0;
+    raw >>= 1;
+
+    bool add_1_pt_5 = ( raw & 0x0001 ) != 0;
+    raw >>= 1;
+
+    int16_t result = 0;
+    int16_t bit_scaling_factor = 3;
+
+    for ( uint8_t i = 0; i < 10; i++ )
+    {
+        if ( ( raw & 0x0001 ) != 0 )
+        {
+            result += bit_scaling_factor;
+        }
+        raw >>= 1;
+        bit_scaling_factor *= 2;
+    }
+
+    result *= 10;
+
+    if ( add_1_pt_5 )
+    {
+        result += 15;
+    }
+
+    if ( add_pt_75 )
+    {
+        result += 8; // 7.5 rounded up
+    }
+
+    if ( is_negative )
+    {
+        result *= -1;
+    }
+
+    return result;
+}
+
+
+// ----------------------------------------------------------------------------------------
+    
+bool sca3000_init()
+{
+    //--    Configure the SPI hardware; the caller might have done it but it doesn't
+    //      hurt to do it again.
+
+    spi_init();
+
+    //--    Configure our select line.
+
+    PRJ_SCA3000_SELECT_DDR |= ( 1 << PRJ_SCA3000_SELECT_PIN );
+    device_unselect();
+
+    //--    Configure our reset line (if supplied); it should be pulled high normally.
+
+#if defined( PRJ_SCA3000_USE_HW_RESET )
+
+    PRJ_SCA3000_RESET_DDR  |= ( 1 << PRJ_SCA3000_RESET_PIN );
+    PRJ_SCA3000_RESET_PORT |= ( 1 << PRJ_SCA3000_RESET_PIN );
+
+#endif
+
+    return true;