[garmindev] 01/12: Imported Upstream version 0.3.0

Jaromír Mikeš mira-guest at moszumanska.debian.org
Sat Apr 25 15:28:42 UTC 2015


This is an automated email from the git hooks/post-receive script.

mira-guest pushed a commit to branch master
in repository garmindev.

commit 22d3e92c7bb3f4d4bcdc7bdf0c921912db01153f
Author: Jaromír Mikeš <mira.mikes at seznam.cz>
Date:   Sat Apr 25 17:27:46 2015 +0200

    Imported Upstream version 0.3.0
---
 BCPP_HOWTO                                      |    6 +
 CMakeLists.txt                                  |   61 ++
 CPackConfig.cmake                               |   23 +
 ConfigureChecks.cmake                           |   28 +
 DefineOptions.cmake                             |    3 +
 Doxyfile                                        |  316 ++++++
 GarminDev.kdevelop.pcs                          |  Bin 0 -> 306938 bytes
 LICENSE                                         |  248 +++++
 bcpp.config                                     |  112 +++
 changelog.txt                                   |   32 +
 cmake/CMakeLists.txt                            |    1 +
 cmake/Modules/CMakeLists.txt                    |   23 +
 cmake/Modules/COPYING-CMAKE-SCRIPTS             |   22 +
 cmake/Modules/DefineCMakeDefaults.cmake         |   28 +
 cmake/Modules/DefineCompilerFlags.cmake         |   13 +
 cmake/Modules/DefineInstallationPaths.cmake     |  126 +++
 cmake/Modules/FindGDAL.cmake                    |   81 ++
 cmake/Modules/FindPROJ.cmake                    |   87 ++
 cmake/Modules/FindUSB.cmake                     |   80 ++
 cmake/Modules/FindXercesC.cmake                 |  101 ++
 cmake/Modules/MacroCopyFile.cmake               |   33 +
 cmake/Modules/MacroEnsureOutOfSourceBuild.cmake |   17 +
 config.h.cmake                                  |   20 +
 src/CMakeLists.txt                              |   40 +
 src/CSerial.cpp                                 |  805 ++++++++++++++++
 src/CSerial.h                                   |  114 +++
 src/CTcp.cpp                                    |  259 +++++
 src/CTcp.h                                      |   91 ++
 src/CUSB.cpp                                    |  449 +++++++++
 src/CUSB.h                                      |  144 +++
 src/CUSB_MacOSX.cpp                             |  731 ++++++++++++++
 src/CUSB_win32.cpp                              |  429 +++++++++
 src/EtrexH/CDevice.cpp                          |  583 ++++++++++++
 src/EtrexH/CDevice.h                            |   58 ++
 src/EtrexH/CMakeLists.txt                       |   31 +
 src/EtrexH/EHSerial.cpp                         |   72 ++
 src/EtrexH/EHSerial.h                           |   44 +
 src/EtrexH/loader.cpp                           |   68 ++
 src/EtrexLegend/CDevice.cpp                     |  791 +++++++++++++++
 src/EtrexLegend/CDevice.h                       |   60 ++
 src/EtrexLegend/CMakeLists.txt                  |   31 +
 src/EtrexLegend/loader.cpp                      |   83 ++
 src/EtrexLegendC/CDevice.cpp                    | 1076 +++++++++++++++++++++
 src/EtrexLegendC/CDevice.h                      |   82 ++
 src/EtrexLegendC/CMakeLists.txt                 |   31 +
 src/EtrexLegendC/loader.cpp                     |   90 ++
 src/GPSMap60CSx/CDevice.cpp                     | 1165 +++++++++++++++++++++++
 src/GPSMap60CSx/CDevice.h                       |   84 ++
 src/GPSMap60CSx/CMakeLists.txt                  |   39 +
 src/GPSMap60CSx/loader.cpp                      |  233 +++++
 src/GPSMap76/CDevice.cpp                        |  773 +++++++++++++++
 src/GPSMap76/CDevice.h                          |   59 ++
 src/GPSMap76/CMakeLists.txt                     |   31 +
 src/GPSMap76/loader.cpp                         |   76 ++
 src/Garmin.cpp                                  |  409 ++++++++
 src/Garmin.h                                    |  308 ++++++
 src/IDevice.h                                   |  576 +++++++++++
 src/IDeviceDefault.cpp                          |  380 ++++++++
 src/IDeviceDefault.h                            |  128 +++
 src/ILink.cpp                                   |   35 +
 src/ILink.h                                     |   84 ++
 src/Platform.h                                  |  322 +++++++
 src/whatGarmin/CDevice.cpp                      |  195 ++++
 src/whatGarmin/CDevice.h                        |   49 +
 src/whatGarmin/CMakeLists.txt                   |   17 +
 src/whatGarmin/loader.cpp                       |   40 +
 66 files changed, 12626 insertions(+)

diff --git a/BCPP_HOWTO b/BCPP_HOWTO
new file mode 100644
index 0000000..0b0e608
--- /dev/null
+++ b/BCPP_HOWTO
@@ -0,0 +1,6 @@
+To beautify all source code do:
+
+cd src
+find ./ -name "*.h" -exec bcpp -fnc ../bcpp.config -fi {} \;
+find ./ -name "*.cpp" -exec bcpp -fnc ../bcpp.config -fi {} \;
+rm *.orig
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..9152e4d
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,61 @@
+project(GarminDev)
+set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/qlandkartegt)
+
+cmake_minimum_required(VERSION 2.6)
+if(COMMAND cmake_policy)
+cmake_policy(SET CMP0003 NEW)
+endif(COMMAND cmake_policy)
+
+#this one is for the API version check
+set(VER_MAJOR     01)
+set(VER_MINOR     16)
+
+#this one is for the release version
+set(PACKAGE_VER_MAJOR     0)
+set(PACKAGE_VER_MINOR     3)
+set(PACKAGE_VER_PATCH     0)
+
+
+add_definitions(-DVER_MAJOR=${VER_MAJOR} -DVER_MINOR=${VER_MINOR})
+
+# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
+set(CMAKE_MODULE_PATH
+  ${CMAKE_SOURCE_DIR}/cmake/Modules
+)
+
+# add definitions
+include(DefineCMakeDefaults)
+include(DefineCompilerFlags)
+include(DefineInstallationPaths)
+include(DefineOptions.cmake)
+include(CPackConfig.cmake)
+
+# disallow in-source build
+include(MacroEnsureOutOfSourceBuild)
+macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source build. Please create a separate build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there.")
+
+# config.h generation
+include(ConfigureChecks.cmake)
+configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+include_directories(
+  ${CMAKE_BINARY_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+find_package(USB REQUIRED)
+
+add_subdirectory(./src)
+add_subdirectory(./src/GPSMap60CSx)
+add_subdirectory(./src/GPSMap76)
+add_subdirectory(./src/EtrexLegendC)
+add_subdirectory(./src/EtrexLegend)
+add_subdirectory(./src/EtrexH)
+add_subdirectory(./src/whatGarmin)
+
+install(
+    DIRECTORY
+        ${LIBRARY_OUTPUT_PATH}
+    DESTINATION
+        ${LIB_INSTALL_DIR}
+)
diff --git a/CPackConfig.cmake b/CPackConfig.cmake
new file mode 100644
index 0000000..3af8766
--- /dev/null
+++ b/CPackConfig.cmake
@@ -0,0 +1,23 @@
+include(InstallRequiredSystemLibraries)
+
+# For help take a look at:
+# http://www.cmake.org/Wiki/CMake:CPackConfiguration
+
+### general settings
+string(TOLOWER ${APPLICATION_NAME} CPACK_PACKAGE_NAME)
+set(CPACK_PACKAGE_VENDOR "GarminDev")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Garmin Device Pugins for QLandkarte (GT)")
+
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
+
+set(CPACK_PACKAGE_VERSION "${PACKAGE_VER_MAJOR}.${PACKAGE_VER_MINOR}.${PACKAGE_VER_PATCH}")
+
+set(CPACK_GENERATOR "TGZ")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
+
+### source package settings
+set(CPACK_SOURCE_GENERATOR "TGZ")
+set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;tags;cscope.*")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
+
+include(CPack)
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
new file mode 100644
index 0000000..0ca4542
--- /dev/null
+++ b/ConfigureChecks.cmake
@@ -0,0 +1,28 @@
+include(CheckIncludeFile)
+include(CheckSymbolExists)
+include(CheckFunctionExists)
+include(CheckLibraryExists)
+include(CheckTypeSize)
+include(CheckCXXSourceCompiles)
+include(TestBigEndian)
+
+set(PACKAGE ${APPLICATION_NAME})
+set(VERSION ${APPLICATION_VERSION})
+set(DATADIR ${DATA_INSTALL_DIR})
+set(LIBDIR ${LIB_INSTALL_DIR})
+set(PLUGINDIR "${PLUGIN_INSTALL_DIR}")
+set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
+
+set(BINARYDIR ${CMAKE_BINARY_DIR})
+set(SOURCEDIR ${CMAKE_SOURCE_DIR})
+
+set(SHARED_LIB_EXT ".dll")
+if (UNIX AND NOT WIN32)
+  set(SHARED_LIB_EXT ".so")
+endif (UNIX AND NOT WIN32)
+
+check_include_file(stdint.h HAVE_STDINT_H)
+check_include_file(inttypes.h HAVE_INTTYPES_H)
+check_include_file(byteswap.h HAVE_BYTESWAP_H)
+
+test_big_endian(HAVE_BIGENDIAN)
diff --git a/DefineOptions.cmake b/DefineOptions.cmake
new file mode 100644
index 0000000..f06a5ae
--- /dev/null
+++ b/DefineOptions.cmake
@@ -0,0 +1,3 @@
+option(WITH_LOG4C "Build csync without log4c" ON)
+option(UNIT_TESTING "Build with unit tests" OFF)
+option(MEM_NULL_TESTS "Enable NULL memory testing" OFF)
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..19df53d
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,316 @@
+# Doxyfile 1.5.6-KDevelop
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING      = UTF-8
+PROJECT_NAME           = GarminDev
+PROJECT_NUMBER         = $VERSION$
+OUTPUT_DIRECTORY       = 
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = YES
+STRIP_FROM_PATH        = /home/oeichler/Documents/
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = NO
+QT_AUTOBRIEF           = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = NO
+INHERIT_DOCS           = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 8
+ALIASES                = 
+OPTIMIZE_OUTPUT_FOR_C  = NO
+OPTIMIZE_OUTPUT_JAVA   = NO
+OPTIMIZE_FOR_FORTRAN   = NO
+OPTIMIZE_OUTPUT_VHDL   = NO
+BUILTIN_STL_SUPPORT    = NO
+CPP_CLI_SUPPORT        = NO
+SIP_SUPPORT            = NO
+IDL_PROPERTY_SUPPORT   = YES
+DISTRIBUTE_GROUP_DOC   = NO
+SUBGROUPING            = YES
+TYPEDEF_HIDES_STRUCT   = NO
+SYMBOL_CACHE_SIZE      = 0
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = YES
+EXTRACT_PRIVATE        = YES
+EXTRACT_STATIC         = YES
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = NO
+EXTRACT_ANON_NSPACES   = NO
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = YES
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_GROUP_NAMES       = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_DIRECTORIES       = YES
+SHOW_FILES             = YES
+SHOW_NAMESPACES        = YES
+FILE_VERSION_FILTER    = 
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = /home/oeichler/data/cpp/GarminDev
+INPUT_ENCODING         = UTF-8
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.d \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.m \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.f90 \
+                         *.f \
+                         *.vhd \
+                         *.vhdl \
+                         *.C \
+                         *.CC \
+                         *.C++ \
+                         *.II \
+                         *.I++ \
+                         *.H \
+                         *.HH \
+                         *.H++ \
+                         *.CS \
+                         *.PHP \
+                         *.PHP3 \
+                         *.M \
+                         *.MM \
+                         *.PY \
+                         *.F90 \
+                         *.F \
+                         *.VHD \
+                         *.VHDL \
+                         *.C \
+                         *.H \
+                         *.tlh \
+                         *.diff \
+                         *.patch \
+                         *.moc \
+                         *.xpm \
+                         *.dox
+RECURSIVE              = yes
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = 
+EXCLUDE_SYMBOLS        = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = *
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = 
+INPUT_FILTER           = 
+FILTER_PATTERNS        = 
+FILTER_SOURCE_FILES    = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = NO
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION    = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS              = NO
+VERBATIM_HEADERS       = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = NO
+COLS_IN_ALPHA_INDEX    = 5
+IGNORE_PREFIX          = 
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+GENERATE_DOCSET        = NO
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+HTML_DYNAMIC_SECTIONS  = NO
+CHM_FILE               = 
+HHC_LOCATION           = 
+QTHELP_FILE            = 
+QTHELP_CONFIG          = 
+DOXYGEN2QTHELP_LOC     = 
+GENERATE_CHI           = NO
+CHM_INDEX_ENCODING     = 
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NONE
+TREEVIEW_WIDTH         = 250
+FORMULA_FONTSIZE       = 10
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = NO
+USE_PDFLATEX           = NO
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = yes
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = NO
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = 
+EXPAND_AS_DEFINED      = 
+SKIP_FUNCTION_MACROS   = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = GarminDev.tag
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = NO
+MSCGEN_PATH            = 
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = YES
+DOT_FONTNAME           = FreeSans
+DOT_FONTPATH           = 
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = NO
+CALLER_GRAPH           = NO
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = YES
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               = 
+DOTFILE_DIRS           = 
+DOT_GRAPH_MAX_NODES    = 50
+MAX_DOT_GRAPH_DEPTH    = 1000
+DOT_TRANSPARENT        = NO
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = NO
diff --git a/GarminDev.kdevelop.pcs b/GarminDev.kdevelop.pcs
new file mode 100644
index 0000000..ac91777
Binary files /dev/null and b/GarminDev.kdevelop.pcs differ
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e13dd59
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,248 @@
+  <h1>The GNU General Public License (GPL)</h1>
+<h2>Version 2, June 1991</h2>
+<p><tt></p>
+<p> Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA</p>
+<p> Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.</p>
+<p>		<strong>
+<p>Preamble</p>
+<p></strong></p>
+<p>The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.</p>
+<p>When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.</p>
+<p>
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.</p>
+<p>For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.</p>
+<p>We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.</p>
+<p>Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.</p>
+<p>Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.</p>
+<p>The precise terms and conditions for copying, distribution and
+modification follow.</p>
+<p>		    <strong>
+<p>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</p>
+<p></strong></p>
+<p><strong>0</strong>. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".</p>
+<p>Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.</p>
+<p><strong>1</strong>. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.</p>
+<p>You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.</p>
+<p>  <strong>2</strong>. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:</p>
+<blockquote>
+<p>a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.</p>
+<p>b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.</p>
+<p>c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)</p>
+</p></blockquote>
+<p>These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.</p>
+<p>Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.</p>
+<p>In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.</p>
+<p><strong>3</strong>. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:</p>
+<blockquote>
+<p>a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,</p>
+<p> b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,</p>
+<p>c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)</p>
+</p></blockquote>
+<p>The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.</p>
+<p>If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.</p>
+<p><strong>4</strong>. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.</p>
+<p> <strong>5</strong>. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.</p>
+<p><strong>6</strong>. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.</p>
+<p><strong>7</strong>. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.</p>
+<p>If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.</p>
+<p>It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.</p>
+<p>
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.</p>
+<p>  <strong>8</strong>. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.</p>
+<p>
+  <strong>9</strong>. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.</p>
+<p>Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.</p>
+<p><strong>10</strong>. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.</p>
+<p><strong>NO WARRANTY</strong></p>
+<p><strong>11</strong>. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.</p>
+<p><strong>12</strong>. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.</p>
+<p>END OF TERMS AND CONDITIONS</p>
\ No newline at end of file
diff --git a/bcpp.config b/bcpp.config
new file mode 100644
index 0000000..2af7342
--- /dev/null
+++ b/bcpp.config
@@ -0,0 +1,112 @@
+; This file contains configuration parameters that are used
+; within the bcpp program.
+
+; There are two types of parameter types : Boolean, and Integer.
+; Boolean types can have only two valid values [On, Yes, or Off, No].
+; Integer types can have a valid range of 0 - 5000.
+
+;------------------------------------------------------------------------
+; This parameter specifies how many lines separate between two
+; functions.
+;------------------------------------------------------------------------
+  function_spacing            = 2        ; Integer
+
+;------------------------------------------------------------------------
+; Specifies whether to use tabs in indenting code.
+;------------------------------------------------------------------------
+  use_tabs                    = no      ; Boolean
+
+;------------------------------------------------------------------------
+; Specifies how many spaces to indent. This parameter is also used
+; for tab indenting, as 1 tab may be worth 8 spaces if so desired.
+; This parameter is used to position comments in TAB mode, and expanding
+; of tabs within code!
+;------------------------------------------------------------------------
+  indent_spacing              = 4        ; Integer
+
+;------------------------------------------------------------------------
+; Specifies whether to indent preprocessor controls to match the code
+;------------------------------------------------------------------------
+  indent_preprocessor         = no      ; Boolean
+
+;------------------------------------------------------------------------
+; Specifies whether to indent embedded SQL statements
+;------------------------------------------------------------------------
+  indent_exec_sql             = yes      ; Boolean
+
+;------------------------------------------------------------------------
+; Defines at what start position comments that have code on the
+; same line to be placed.
+;------------------------------------------------------------------------
+  comments_with_code          = 33       ; Integer
+
+;------------------------------------------------------------------------
+; Defines at what start position comments with no code start.
+;------------------------------------------------------------------------
+  comments_with_nocode        = 0        ; Integer
+
+;------------------------------------------------------------------------
+; Set this option to ON turns off setting indentation position of parameter
+; "comments_with_nocode". Indentation is then set according to code
+; position.
+;------------------------------------------------------------------------
+  leave_comments_nocode       = yes      ; Boolean
+
+;------------------------------------------------------------------------
+; Use this option is used to change non-ascii (non-printable) chars to
+; octal notation if they lie within quotes. Either
+; Ascii_Chars_Only, XOR Leave_Graphic_Chars parameters need to be set
+; as a True value for this parameter to take effect.
+;------------------------------------------------------------------------
+  NonAscii_Quotes_to_Octal    = yes      ; Boolean
+
+;------------------------------------------------------------------------
+; Setting this parameter to yes will strip non-printable characters
+; from the source files, but leave any character that are IBM
+; graphics alone. Any non-printable characters that lie within
+; quotes will be transformed into octal/character notation, if
+; NonAscii_Quotes_To_Octal parameter is set to True.
+;------------------------------------------------------------------------
+;  leave_graphic_chars        = no       ; Boolean
+
+;------------------------------------------------------------------------
+; Setting this parameter to yes will strip any non-printable,
+; non-ascii characters from the input file. Any non-printable
+; octal/character notation if NonAscii_Quotes_To_Octal is set to
+; True. Comment out this parameter if you are using
+; Leave_Graphic_Chars parameter, as this parameter will override
+; it.
+;------------------------------------------------------------------------
+  ascii_chars_only            = yes      ; Boolean
+
+;------------------------------------------------------------------------
+; This parameter will place open braces on a new line after it's
+; associated code if set on/yes. Else the brace will be place on
+; next above line if possible, with it's code.
+;------------------------------------------------------------------------
+  place_brace_on_new_line     = no      ; Boolean
+
+;------------------------------------------------------------------------
+; This parameter will stop output from the program corrupting output
+; that may exit from the program via the standard output.
+; If this parameter is set to off/no then no output is generated from
+; the program, unless an error is encountered
+;------------------------------------------------------------------------
+  program_output              = yes      ; Boolean
+
+
+;------------------------------------------------------------------------
+; Specifies what the internal memory requirements will be in size of the
+; line processing buffer. This essentially is used only for open brace
+; relocation in kernighan/ritchie style.
+;------------------------------------------------------------------------
+  Queue_Buffer                = 1000    ; Integer
+
+;------------------------------------------------------------------------
+; If this option is set to true then the input file will be backup into a
+; another file with a ".bac" extension added to the end of the file
+; name.
+;------------------------------------------------------------------------
+  Backup_File                 = yes   ; Boolean
+
+
diff --git a/changelog.txt b/changelog.txt
new file mode 100644
index 0000000..3cf28bc
--- /dev/null
+++ b/changelog.txt
@@ -0,0 +1,32 @@
+--- 2009.06.22 ---
+
+Request #4:
+Add support for Etrex Summit HC
+
+
+
+--- 2009.05.05 ---
+
+Request #3:
+GPSMap60SCx: Add track upload
+
+
+
+--- 2009.03.22 ---
+
+Request #2:
+Add dependency check for libusb
+
+
+
+--- 2009.03.09 ---
+
+Request #1:
+Initial Release
+
+
+
+
+
+
+
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
new file mode 100644
index 0000000..5e1202b
--- /dev/null
+++ b/cmake/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(Modules)
diff --git a/cmake/Modules/CMakeLists.txt b/cmake/Modules/CMakeLists.txt
new file mode 100644
index 0000000..f4a32dd
--- /dev/null
+++ b/cmake/Modules/CMakeLists.txt
@@ -0,0 +1,23 @@
+# install the cmake files
+
+file(GLOB cmakeFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.cmake")
+
+set(module_install_dir ${DATA_INSTALL_DIR}/cmake/modules )
+
+install(
+  FILES
+    ${cmakeFiles}
+  DESTINATION
+  ${module_install_dir}
+)
+# the files listed here will be removed by remove_obsoleted_cmake_files.cmake, Alex
+set(FILES_TO_REMOVE
+)
+
+install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/remove_files.cmake )
+
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/remove_files.cmake "#generated by cmake, dont edit\n\n")
+foreach ( _current_FILE ${FILES_TO_REMOVE})
+   file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/remove_files.cmake "message(STATUS \"Removing ${module_install_dir}/${_current_FILE}\" )\n" )
+   file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/remove_files.cmake "exec_program( ${CMAKE_COMMAND} ARGS -E remove ${module_install_dir}/${_current_FILE} OUTPUT_VARIABLE _dummy)\n" )
+endforeach ( _current_FILE)
diff --git a/cmake/Modules/COPYING-CMAKE-SCRIPTS b/cmake/Modules/COPYING-CMAKE-SCRIPTS
new file mode 100644
index 0000000..4b41776
--- /dev/null
+++ b/cmake/Modules/COPYING-CMAKE-SCRIPTS
@@ -0,0 +1,22 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products 
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/cmake/Modules/DefineCMakeDefaults.cmake b/cmake/Modules/DefineCMakeDefaults.cmake
new file mode 100644
index 0000000..79df274
--- /dev/null
+++ b/cmake/Modules/DefineCMakeDefaults.cmake
@@ -0,0 +1,28 @@
+# Always include srcdir and builddir in include path
+# This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in
+# about every subdir
+# since cmake 2.4.0
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+# Put the include dirs which are in the source or build tree
+# before all other include dirs, so the headers in the sources
+# are prefered over the already installed ones
+# since cmake 2.4.1
+set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
+
+# Use colored output
+# since cmake 2.4.0
+set(CMAKE_COLOR_MAKEFILE ON)
+
+# Define the generic version of the libraries here
+set(GENERIC_LIB_VERSION "0.1.0")
+set(GENERIC_LIB_SOVERSION "0")
+
+# Set the default build type to release with debug info
+if (NOT CMAKE_BUILD_TYPE)
+  set(CMAKE_BUILD_TYPE RelWithDebInfo
+    CACHE STRING
+      "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
+    FORCE
+  )
+endif (NOT CMAKE_BUILD_TYPE)
diff --git a/cmake/Modules/DefineCompilerFlags.cmake b/cmake/Modules/DefineCompilerFlags.cmake
new file mode 100644
index 0000000..f0df53b
--- /dev/null
+++ b/cmake/Modules/DefineCompilerFlags.cmake
@@ -0,0 +1,13 @@
+# define system dependent compiler flags
+
+include(CheckCXXCompilerFlag)
+
+# with -fPIC
+if(UNIX AND NOT WIN32)
+  if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+    check_cxx_compiler_flag("-fPIC" WITH_FPIC)
+    if(WITH_FPIC)
+      ADD_DEFINITIONS(-fPIC)
+    endif(WITH_FPIC)
+  endif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+endif(UNIX AND NOT WIN32)
diff --git a/cmake/Modules/DefineInstallationPaths.cmake b/cmake/Modules/DefineInstallationPaths.cmake
new file mode 100644
index 0000000..bd906d8
--- /dev/null
+++ b/cmake/Modules/DefineInstallationPaths.cmake
@@ -0,0 +1,126 @@
+if (UNIX)
+  IF (NOT APPLICATION_NAME)
+    MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME")
+    SET(APPLICATION_NAME ${PROJECT_NAME})
+  ENDIF (NOT APPLICATION_NAME)
+
+  STRING(TOLOWER ${APPLICATION_NAME} _APPLICATION_NAME)
+
+  # Suffix for Linux
+  SET(LIB_SUFFIX
+    CACHE STRING "Define suffix of directory name (32/64)"
+  )
+
+  SET(EXEC_INSTALL_PREFIX
+    "${CMAKE_INSTALL_PREFIX}"
+    CACHE PATH  "Base directory for executables and libraries"
+    FORCE
+  )
+  SET(SHARE_INSTALL_PREFIX
+    "${CMAKE_INSTALL_PREFIX}/share"
+    CACHE PATH "Base directory for files which go to share/"
+    FORCE
+  )
+  SET(DATA_INSTALL_PREFIX
+    "${SHARE_INSTALL_PREFIX}/"
+    CACHE PATH "The parent directory where applications can install their data" FORCE)
+
+  # The following are directories where stuff will be installed to
+  SET(BIN_INSTALL_DIR
+    "${EXEC_INSTALL_PREFIX}/bin"
+    CACHE PATH "The ${_APPLICATION_NAME} binary install dir (default prefix/bin)"
+    FORCE
+  )
+  SET(SBIN_INSTALL_DIR
+    "${EXEC_INSTALL_PREFIX}/sbin"
+    CACHE PATH "The ${_APPLICATION_NAME} sbin install dir (default prefix/sbin)"
+    FORCE
+  )
+  SET(LIB_INSTALL_DIR
+    "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}"
+    CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)"
+    FORCE
+  )
+  SET(LIBEXEC_INSTALL_DIR
+    "${EXEC_INSTALL_PREFIX}/libexec"
+    CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)"
+    FORCE
+  )
+  SET(PLUGIN_INSTALL_DIR
+    "${LIB_INSTALL_DIR}/${_APPLICATION_NAME}"
+    CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${_APPLICATION_NAME})"
+    FORCE
+  )
+  SET(INCLUDE_INSTALL_DIR
+    "${CMAKE_INSTALL_PREFIX}/include"
+    CACHE PATH "The subdirectory to the header prefix (default prefix/include)"
+    FORCE
+  )
+
+  SET(DATA_INSTALL_DIR
+    "${DATA_INSTALL_PREFIX}"
+    CACHE PATH "The parent directory where applications can install their data (default prefix/share/${_APPLICATION_NAME})"
+    FORCE
+  )
+  SET(HTML_INSTALL_DIR
+    "${DATA_INSTALL_PREFIX}/doc/HTML"
+    CACHE PATH "The HTML install dir for documentation (default data/doc/html)"
+    FORCE
+  )
+  SET(ICON_INSTALL_DIR
+    "${DATA_INSTALL_PREFIX}/icons"
+    CACHE PATH "The icon install dir (default data/icons/)"
+    FORCE
+  )
+  SET(SOUND_INSTALL_DIR
+    "${DATA_INSTALL_PREFIX}/sounds"
+    CACHE PATH "The install dir for sound files (default data/sounds)"
+    FORCE
+  )
+
+  SET(LOCALE_INSTALL_DIR
+    "${SHARE_INSTALL_PREFIX}/locale"
+    CACHE PATH "The install dir for translations (default prefix/share/locale)"
+    FORCE
+  )
+
+  SET(XDG_APPS_DIR
+    "${SHARE_INSTALL_PREFIX}/applications/"
+    CACHE PATH "The XDG apps dir"
+    FORCE
+  )
+  SET(XDG_DIRECTORY_DIR
+    "${SHARE_INSTALL_PREFIX}/desktop-directories"
+    CACHE PATH "The XDG directory"
+    FORCE
+  )
+
+  SET(SYSCONF_INSTALL_DIR
+    "${EXEC_INSTALL_PREFIX}/etc"
+    CACHE PATH "The ${_APPLICATION_NAME} sysconfig install dir (default prefix/etc)"
+    FORCE
+  )
+  SET(MAN_INSTALL_DIR
+    "${SHARE_INSTALL_PREFIX}/man"
+    CACHE PATH "The ${_APPLICATION_NAME} man install dir (default prefix/man)"
+    FORCE
+  )
+  SET(INFO_INSTALL_DIR
+    "${SHARE_INSTALL_PREFIX}/info"
+    CACHE PATH "The ${_APPLICATION_NAME} info install dir (default prefix/info)"
+    FORCE
+  )
+endif (UNIX)
+
+if (WIN32)
+  # Same same
+  SET(BIN_INSTALL_DIR .)
+  SET(SBIN_INSTALL_DIR .)
+  SET(LIB_INSTALL_DIR .)
+  SET(PLUGIN_INSTALL_DIR plugins)
+  SET(HTML_INSTALL_DIR doc/HTML)
+  SET(ICON_INSTALL_DIR .)
+  SET(SOUND_INSTALL_DIR .)
+  SET(LOCALE_INSTALL_DIR lang)
+endif (WIN32)
+
diff --git a/cmake/Modules/FindGDAL.cmake b/cmake/Modules/FindGDAL.cmake
new file mode 100644
index 0000000..b64bf31
--- /dev/null
+++ b/cmake/Modules/FindGDAL.cmake
@@ -0,0 +1,81 @@
+# - Try to find GDAL
+# Once done this will define
+#
+#  GDAL_FOUND - system has GDAL
+#  GDAL_INCLUDE_DIRS - the GDAL include directory
+#  GDAL_LIBRARIES - Link these to use GDAL
+#  GDAL_DEFINITIONS - Compiler switches required for using GDAL
+#
+#  Copyright (c) 2006 Andreas Schneider <mail at cynapses.org>
+#
+#  Redistribution and use is allowed according to the terms of the New
+#  BSD license.
+#  For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+
+if (GDAL_LIBRARIES AND GDAL_INCLUDE_DIRS)
+  # in cache already
+  set(GDAL_FOUND TRUE)
+else (GDAL_LIBRARIES AND GDAL_INCLUDE_DIRS)
+  find_path(GDAL_INCLUDE_DIR
+    NAMES
+      gdal.h
+    PATHS
+        /usr/include
+        /usr/local/include
+        /opt/local/include
+        /sw/include
+        /usr/include/gdal
+        /usr/local/include/gdal
+        /opt/local/include/gdal
+        /sw/include/gdal
+        C:/Progra~1/FWTools2.2.8/include
+        C:/Progra~1/FWTools2.1.0/include      
+  )
+
+  # debian uses version suffixes
+  # add suffix evey new release
+  find_library(GDAL_LIBRARY
+    NAMES
+        gdal
+        gdal1.3.2
+        gdal1.4.0
+        gdal1.5.0
+        gdal
+        gdal_i   
+    PATHS
+      /usr/lib
+      /usr/local/lib
+      /opt/local/lib
+      /sw/lib
+      C:/Progra~1/FWTools2.2.8/lib
+      C:/Progra~1/FWTools2.1.0/lib
+  )
+
+  set(GDAL_INCLUDE_DIRS
+    ${GDAL_INCLUDE_DIR}
+  )
+  set(GDAL_LIBRARIES
+    ${GDAL_LIBRARY}
+)
+
+  if (GDAL_INCLUDE_DIRS AND GDAL_LIBRARIES)
+     set(GDAL_FOUND TRUE)
+  endif (GDAL_INCLUDE_DIRS AND GDAL_LIBRARIES)
+
+  if (GDAL_FOUND)
+    if (NOT GDAL_FIND_QUIETLY)
+      message(STATUS "Found GDAL: ${GDAL_LIBRARIES}")
+    endif (NOT GDAL_FIND_QUIETLY)
+  else (GDAL_FOUND)
+    if (GDAL_FIND_REQUIRED)
+      message(FATAL_ERROR "Could not find GDAL")
+    endif (GDAL_FIND_REQUIRED)
+  endif (GDAL_FOUND)
+
+  # show the GDAL_INCLUDE_DIRS and GDAL_LIBRARIES variables only in the advanced view
+  mark_as_advanced(GDAL_INCLUDE_DIRS GDAL_LIBRARIES)
+
+endif (GDAL_LIBRARIES AND GDAL_INCLUDE_DIRS)
+
diff --git a/cmake/Modules/FindPROJ.cmake b/cmake/Modules/FindPROJ.cmake
new file mode 100644
index 0000000..1508ba4
--- /dev/null
+++ b/cmake/Modules/FindPROJ.cmake
@@ -0,0 +1,87 @@
+# - Try to find PROJ
+# Once done this will define
+#
+#  PROJ_FOUND - system has PROJ
+#  PROJ_INCLUDE_DIRS - the PROJ include directory
+#  PROJ_LIBRARIES - Link these to use PROJ
+#  PROJ_DEFINITIONS - Compiler switches required for using PROJ
+#
+#  Copyright (c) 2009 Andreas Schneider <mail at cynapses.org>
+#
+#  Redistribution and use is allowed according to the terms of the New
+#  BSD license.
+#  For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+
+if (PROJ_LIBRARIES AND PROJ_INCLUDE_DIRS)
+  # in cache already
+  set(PROJ_FOUND TRUE)
+else (PROJ_LIBRARIES AND PROJ_INCLUDE_DIRS)
+
+  find_path(PROJ_INCLUDE_DIR
+    NAMES
+      projects.h
+    PATHS
+        /usr/include
+        /usr/local/include
+        /opt/local/include
+        /sw/include
+        C:/Progra~1/FWTools2.2.8/include
+        C:/Progra~1/FWTools2.1.0/include
+    PATH_SUFFIXES
+        proj4
+
+  )
+  mark_as_advanced(PROJ_INCLUDE_DIR)
+
+  find_library(LIBPROJ_LIBRARY
+    NAMES
+        proj
+        proj
+        proj_i
+    PATHS
+        /usr/lib
+        /usr/local/lib
+        /opt/local/lib
+        /sw/lib
+        C:/Progra~1/FWTools2.2.8/lib
+        C:/Progra~1/FWTools2.1.0/lib
+     
+  )
+  mark_as_advanced(LIBPROJ_LIBRARY)
+
+  if (LIBPROJ_LIBRARY)
+    set(LIBPROJ_FOUND TRUE)
+  endif (LIBPROJ_LIBRARY)
+
+  set(PROJ_INCLUDE_DIRS
+    ${PROJ_INCLUDE_DIR}
+  )
+
+  if (LIBPROJ_FOUND)
+    set(PROJ_LIBRARIES
+      ${PROJ_LIBRARIES}
+      ${LIBPROJ_LIBRARY}
+    )
+  endif (LIBPROJ_FOUND)
+
+  if (PROJ_INCLUDE_DIRS AND PROJ_LIBRARIES)
+     set(PROJ_FOUND TRUE)
+  endif (PROJ_INCLUDE_DIRS AND PROJ_LIBRARIES)
+
+  if (PROJ_FOUND)
+    if (NOT PROJ_FIND_QUIETLY)
+      message(STATUS "Found PROJ: ${PROJ_LIBRARIES}")
+    endif (NOT PROJ_FIND_QUIETLY)
+  else (PROJ_FOUND)
+    if (PROJ_FIND_REQUIRED)
+      message(FATAL_ERROR "Could not find PROJ")
+    endif (PROJ_FIND_REQUIRED)
+  endif (PROJ_FOUND)
+
+  # show the PROJ_INCLUDE_DIRS and PROJ_LIBRARIES variables only in the advanced view
+  mark_as_advanced(PROJ_INCLUDE_DIRS PROJ_LIBRARIES)
+
+endif (PROJ_LIBRARIES AND PROJ_INCLUDE_DIRS)
+
diff --git a/cmake/Modules/FindUSB.cmake b/cmake/Modules/FindUSB.cmake
new file mode 100644
index 0000000..d0b28d4
--- /dev/null
+++ b/cmake/Modules/FindUSB.cmake
@@ -0,0 +1,80 @@
+# - Try to find USB
+# Once done this will define
+#
+#  USB_FOUND - system has USB
+#  USB_INCLUDE_DIRS - the USB include directory
+#  USB_LIBRARIES - Link these to use USB
+#  USB_DEFINITIONS - Compiler switches required for using USB
+#
+#  Copyright (c) 2009 Andreas Schneider <mail at cynapses.org>
+#
+#  Redistribution and use is allowed according to the terms of the New
+#  BSD license.
+#  For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+
+if (USB_LIBRARIES AND USB_INCLUDE_DIRS)
+  # in cache already
+  set(USB_FOUND TRUE)
+else (USB_LIBRARIES AND USB_INCLUDE_DIRS)
+
+  find_path(USB_INCLUDE_DIR
+    NAMES
+      usb.h
+    PATHS
+        /usr/include
+        /usr/local/include
+        /opt/local/include
+        /sw/include
+    PATH_SUFFIXES
+        usb
+
+  )
+  mark_as_advanced(USB_INCLUDE_DIR)
+
+  find_library(LIBUSB_LIBRARY
+    NAMES
+        usb
+    PATHS
+        /usr/lib
+        /usr/local/lib
+        /opt/local/lib
+        /sw/lib
+  )
+  mark_as_advanced(LIBUSB_LIBRARY)
+
+  if (LIBUSB_LIBRARY)
+    set(LIBUSB_FOUND TRUE)
+  endif (LIBUSB_LIBRARY)
+
+  set(USB_INCLUDE_DIRS
+    ${USB_INCLUDE_DIR}
+  )
+
+  if (LIBUSB_FOUND)
+    set(USB_LIBRARIES
+      ${USB_LIBRARIES}
+      ${LIBUSB_LIBRARY}
+    )
+  endif (LIBUSB_FOUND)
+
+  if (USB_INCLUDE_DIRS AND USB_LIBRARIES)
+     set(USB_FOUND TRUE)
+  endif (USB_INCLUDE_DIRS AND USB_LIBRARIES)
+
+  if (USB_FOUND)
+    if (NOT USB_FIND_QUIETLY)
+      message(STATUS "Found USB: ${USB_LIBRARIES}")
+    endif (NOT USB_FIND_QUIETLY)
+  else (USB_FOUND)
+    if (USB_FIND_REQUIRED)
+      message(FATAL_ERROR "Could not find Libusb. Are the lib and the headers installed?")
+    endif (USB_FIND_REQUIRED)
+  endif (USB_FOUND)
+
+  # show the USB_INCLUDE_DIRS and USB_LIBRARIES variables only in the advanced view
+  mark_as_advanced(USB_INCLUDE_DIRS USB_LIBRARIES)
+
+endif (USB_LIBRARIES AND USB_INCLUDE_DIRS)
+
diff --git a/cmake/Modules/FindXercesC.cmake b/cmake/Modules/FindXercesC.cmake
new file mode 100644
index 0000000..978036c
--- /dev/null
+++ b/cmake/Modules/FindXercesC.cmake
@@ -0,0 +1,101 @@
+# - Try to find XercesC
+# Once done this will define
+#
+#  XERCESC_FOUND - system has XercesC
+#  XERCESC_INCLUDE_DIRS - the XercesC include directory
+#  XERCESC_LIBRARIES - Link these to use XercesC
+#  XERCESC_DEFINITIONS - Compiler switches required for using XercesC
+#
+#  Copyright (c) 2009 Andreas Schneider <mail at cynapses.org>
+#
+#  Redistribution and use is allowed according to the terms of the New
+#  BSD license.
+#  For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+
+if (XERCESC_LIBRARIES AND XERCESC_INCLUDE_DIRS)
+  # in cache already
+  set(XERCESC_FOUND TRUE)
+else (XERCESC_LIBRARIES AND XERCESC_INCLUDE_DIRS)
+
+  find_path(XERCESC_INCLUDE_DIR
+    NAMES
+      xercesc/util/XercesVersion.hpp
+    PATHS
+      /usr/include
+      /usr/local/include
+      /opt/local/include
+      /sw/include
+      C:/progra~1/xerces-c_2_8_0/include
+  )
+  mark_as_advanced(XERCESC_INCLUDE_DIR)
+
+  find_library(XERCES-C_LIBRARY
+    NAMES
+      xerces-c
+      xerces-c_2
+    PATHS
+      /usr/lib
+      /usr/local/lib
+      /opt/local/lib
+      /sw/lib
+      C:/progra~1/xerces-c_2_8_0/lib
+  )
+  mark_as_advanced(XERCES-C_LIBRARY)
+  find_library(XERCES-DEPDOM_LIBRARY
+    NAMES
+      xerces-depdom
+      xerces-depdom_2
+    PATHS
+      /usr/lib
+      /usr/local/lib
+      /opt/local/lib
+      /sw/lib
+      C:/progra~1/xerces-c_2_8_0/lib      
+  )
+  mark_as_advanced(XERCES-DEPDOM_LIBRARY)
+
+  if (XERCES-C_LIBRARY)
+    set(XERCES-C_FOUND TRUE)
+  endif (XERCES-C_LIBRARY)
+  if (XERCES-DEPDOM_LIBRARY)
+    set(XERCES-DEPDOM_FOUND TRUE)
+  endif (XERCES-DEPDOM_LIBRARY)
+
+  set(XERCESC_INCLUDE_DIRS
+    ${XERCESC_INCLUDE_DIR}
+  )
+
+  if (XERCES-C_FOUND)
+    set(XERCESC_LIBRARIES
+      ${XERCESC_LIBRARIES}
+      ${XERCES-C_LIBRARY}
+    )
+  endif (XERCES-C_FOUND)
+  if (XERCES-DEPDOM_FOUND)
+    set(XERCESC_LIBRARIES
+      ${XERCESC_LIBRARIES}
+      ${XERCES-DEPDOM_LIBRARY}
+    )
+  endif (XERCES-DEPDOM_FOUND)
+
+  if (XERCESC_INCLUDE_DIRS AND XERCESC_LIBRARIES)
+     set(XERCESC_FOUND TRUE)
+  endif (XERCESC_INCLUDE_DIRS AND XERCESC_LIBRARIES)
+
+  if (XERCESC_FOUND)
+    if (NOT XercesC_FIND_QUIETLY)
+      message(STATUS "Found XercesC: ${XERCESC_LIBRARIES}")
+    endif (NOT XercesC_FIND_QUIETLY)
+  else (XERCESC_FOUND)
+    if (XercesC_FIND_REQUIRED)
+      message(FATAL_ERROR "Could not find XercesC")
+    endif (XercesC_FIND_REQUIRED)
+  endif (XERCESC_FOUND)
+
+  # show the XERCESC_INCLUDE_DIRS and XERCESC_LIBRARIES variables only in the advanced view
+  mark_as_advanced(XERCESC_INCLUDE_DIRS XERCESC_LIBRARIES)
+
+endif (XERCESC_LIBRARIES AND XERCESC_INCLUDE_DIRS)
+
diff --git a/cmake/Modules/MacroCopyFile.cmake b/cmake/Modules/MacroCopyFile.cmake
new file mode 100644
index 0000000..cee1cae
--- /dev/null
+++ b/cmake/Modules/MacroCopyFile.cmake
@@ -0,0 +1,33 @@
+# - macro_copy_file(_src _dst)
+# Copies a file to ${_dst} only if ${_src} is different (newer) than ${_dst}
+#
+# Example:
+# macro_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/icon.png ${CMAKE_CURRENT_BINARY_DIR}/.)
+# Copies file icon.png to ${CMAKE_CURRENT_BINARY_DIR} directory
+#
+# Copyright (c) 2006-2007  Wengo
+# Copyright (c) 2006-2008  Andreas Schneider <mail at cynapses.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING file.
+
+
+macro (macro_copy_file _src _dst)
+  # Removes all path containing .svn or CVS or CMakeLists.txt during the copy
+  if (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*")
+
+    if (CMAKE_VERBOSE_MAKEFILE)
+      message(STATUS "Copy file from ${_src} to ${_dst}")
+    endif (CMAKE_VERBOSE_MAKEFILE)
+
+    # Creates directory if necessary
+    get_filename_component(_path ${_dst} PATH)
+    file(MAKE_DIRECTORY ${_path})
+
+    execute_process(
+      COMMAND
+        ${CMAKE_COMMAND} -E copy_if_different ${_src} ${_dst}
+      OUTPUT_QUIET
+    )
+  endif (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*")
+endmacro (macro_copy_file)
diff --git a/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake b/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake
new file mode 100644
index 0000000..a2e9480
--- /dev/null
+++ b/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake
@@ -0,0 +1,17 @@
+# - MACRO_ENSURE_OUT_OF_SOURCE_BUILD(<errorMessage>)
+# MACRO_ENSURE_OUT_OF_SOURCE_BUILD(<errorMessage>)
+
+# Copyright (c) 2006, Alexander Neundorf, <neundorf at kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+macro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage)
+
+   string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource)
+   if (_insource)
+     message(SEND_ERROR "${_errorMessage}")
+     message(FATAL_ERROR "Remove the file CMakeCache.txt in ${CMAKE_SOURCE_DIR} first.")
+   endif (_insource)
+
+endmacro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD)
diff --git a/config.h.cmake b/config.h.cmake
new file mode 100644
index 0000000..f281bfb
--- /dev/null
+++ b/config.h.cmake
@@ -0,0 +1,20 @@
+#cmakedefine PACKAGE ${APPLICATION_NAME}
+#cmakedefine VERSION ${APPLICATION_VERSION}
+#cmakedefine LOCALEDIR ${LOCALE_INSTALL_DIR}
+#cmakedefine DATADIR ${SHARE_INSTALL_PREFIX}
+#cmakedefine LIBDIR ${LIB_INSTALL_DIR}
+#cmakedefine PLUGINDIR ${PLUGINDIR}
+#cmakedefine SYSCONFDIR ${SYSCONFDIR}
+#cmakedefine BINARYDIR ${BINARYDIR}
+#cmakedefine SOURCEDIR ${SOURCEDIR}
+
+#cmakedefine SHARED_LIB_EXT ${SHARED_LIB_EXT}
+
+#cmakedefine HAVE_STDINT_H 1
+#cmakedefine HAVE_INTTYPES_H 1
+#cmakedefine HAVE_BYTESWAP_H 1
+
+#cmakedefine HAVE_BIGENDIAN 1
+
+/* TODO add a check */
+#define CAN_UNALIGNED 1
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..bd207bc
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,40 @@
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+set(SRCS
+#    CTcp.cpp
+    Garmin.cpp
+    IDeviceDefault.cpp
+    ILink.cpp
+)
+
+set(HDRS
+    Platform.h
+    CSerial.h
+#    CTcp.h
+    CUSB.h
+    Garmin.h
+    IDeviceDefault.h
+    IDevice.h
+    ILink.h
+)
+
+if(UNIX)
+    set(SRCS ${SRCS} CUSB.cpp CSerial.cpp)
+endif(UNIX)
+
+if(APPLE)
+    set(SRCS ${SRCS} CUSB_MacOSX.cpp CSerial.cpp)
+endif(APPLE)
+
+if(WIN32)
+	add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
+    set(SRCS ${SRCS} CUSB_win32.cpp)
+endif(WIN32)
+
+add_library(garmin STATIC ${SRCS} ${HDRS})
+
+if(UNIX)
+    SET_TARGET_PROPERTIES( garmin PROPERTIES COMPILE_FLAGS -fPIC)
+    install(FILES IDevice.h DESTINATION /usr/include/garmin/)
+endif(UNIX)
diff --git a/src/CSerial.cpp b/src/CSerial.cpp
new file mode 100644
index 0000000..6458108
--- /dev/null
+++ b/src/CSerial.cpp
@@ -0,0 +1,805 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+    Cleanups and godparenthood by Frank Seidel (fseidel at suse.de, frank at f-seidel.de)
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifdef WIN32
+// because of filename of com-port
+#undef UNICODE
+#endif
+
+#include "CSerial.h"
+#include "IDevice.h"
+#include "Platform.h"
+
+#include <iostream>
+#include <sstream>
+#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+using namespace Garmin;
+using namespace std;
+
+#undef DBG
+
+#define DBG_LINE_SIZE 16
+
+#define SERIAL_PACKET_MAX_SIZE 255
+#define DLE 16
+#define ETX 3
+
+CSerial::CSerial(const std::string& port)
+#ifdef WIN32
+: hCom(0)
+#else
+: port_fd(-1)
+#endif
+, productId(0)
+, softwareVersion(0)
+, protocolArraySize(-1)
+, port(port)
+, readtimeout_ms( 1000)
+{
+#ifdef WIN32
+#else
+    FD_ZERO(&fds_read);
+#endif
+}
+
+
+CSerial::~CSerial()
+{
+    CSerial::close();
+}
+
+
+#ifdef WIN32
+void CSerial::open()
+{
+#if defined(WORDS_BIGENDIAN) || !defined(CAN_UNALIGNED)
+    throw exce_t(errOpen, "The serial driver still needs to be ported to your platform.");
+#endif
+    DCB dcb;
+    WCHAR comname[100];
+    COMMTIMEOUTS timeouts;
+
+    if( hCom > 0 && hCom != INVALID_HANDLE_VALUE) {
+        return;
+    }
+
+    // on my system this one didn't work when make debug was done, so I just #undef-ed UNICODE at top of file
+    //    MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, port.c_str(), strlen(port.c_str()),
+    //        comname, 100);
+    //    hCom= CreateFile( comname, //port.c_str(), // use for example \\.\COM10 for higher ports
+                                 // use for example \\.\COM10 for higher ports
+    hCom= CreateFile( port.c_str(),
+        GENERIC_READ | GENERIC_WRITE,
+        0,                       // exclusive access
+        NULL,                    // no security
+        OPEN_EXISTING,
+        0,                       // no overlapped I/O
+        NULL);                   // null template
+    if( hCom == INVALID_HANDLE_VALUE) {
+        stringstream msg;
+        msg << "Failed to open serial device " << port.c_str() << " Errorcode: " <<
+            GetLastError();
+        throw exce_t(errOpen,msg.str());
+    }
+    timeouts.ReadIntervalTimeout = MAXDWORD;
+    timeouts.ReadTotalTimeoutMultiplier = 0;
+    timeouts.ReadTotalTimeoutConstant = 0;
+    timeouts.WriteTotalTimeoutMultiplier = 0;
+    timeouts.WriteTotalTimeoutConstant = 0;
+    if (!SetCommTimeouts( hCom, &timeouts)) {
+        stringstream msg;
+        msg << "Failed to SetCommTimeouts for " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+    }
+                                 // set buffer sizes
+    if( !SetupComm( hCom, 600, 600)) {
+        stringstream msg;
+        msg << "Failed to set buffersize for " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+    }
+                                 // get default values
+    if( !GetCommState( hCom, &dcb)) {
+        stringstream msg;
+        msg << "Failed to get parameters for " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+    }
+    dcb.BaudRate= 9600;
+    dcb.fOutxCtsFlow= 0;
+    dcb.fOutxDsrFlow= 0;
+    dcb.fOutX= 0;
+    dcb.fInX= 0;
+    dcb.ByteSize= 8;
+    dcb.Parity= NOPARITY;
+    dcb.StopBits= ONESTOPBIT;
+    dcb.fAbortOnError= TRUE;
+    if( !SetCommState( hCom, &dcb)) {
+        stringstream msg;
+        msg << "Failed to set parameters for " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+    }
+}
+
+
+#else
+// UNIX:
+void CSerial::open()
+{
+#if defined(WORDS_BIGENDIAN) || !defined(CAN_UNALIGNED)
+    throw exce_t(errOpen, "The serial driver still needs to be ported to your platform.");
+#endif
+    struct termios tty;
+    if (port_fd >= 0)
+        return;
+
+    port_fd = ::open(port.c_str(), O_RDWR);
+    if (port_fd < 0) {
+        stringstream msg;
+        msg << "Failed to open serial device " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+    }
+
+    if (tcgetattr(port_fd, &gps_ttysave) < 0) {
+        stringstream msg;
+        msg << "Failed to get parameters for " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+    }
+
+    memset(&tty, 0, sizeof(tty));
+    tty.c_cflag &= ~CSIZE;
+    tty.c_cflag |= ( CREAD | CS8 | CLOCAL );
+
+    tty.c_lflag = 0;
+    tty.c_iflag = 0;
+    tty.c_oflag = 0;
+    tty.c_cc[VMIN] = 1;
+    tty.c_cc[VTIME] = 0;
+
+    if ( cfsetispeed( &tty, B9600 ) == -1 )
+        cout << "WARNING: CSerial could not set initial input baud rate" << endl;
+    if ( cfsetospeed( &tty, B9600 ) == -1 )
+        cout << "WARNING: CSerial could not set initial output baud rate" << endl;
+
+    if(tcsetattr(port_fd, TCSANOW, &tty) < 0) {
+        stringstream msg;
+        msg << "Failed to set parameters for " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+    }
+
+    FD_SET(port_fd, &fds_read);
+
+    // tcgetattr, cfgetispeed, cfgetospeed should get called and every parameter checked!
+
+    //     syncup();
+
+}
+#endif
+
+#ifdef WIN32
+void CSerial::close()
+{
+    CloseHandle( hCom);
+    // FIXME: don't care for now resetting up previous bitrate etc...
+    hCom= 0;
+}
+
+
+#else
+// UNIX
+void CSerial::close()
+{
+    if (port_fd >= 0) {
+        tcsetattr(port_fd, TCSAFLUSH, &gps_ttysave);
+    }
+    ::close(port_fd);
+    port_fd = -1;
+    FD_ZERO(&fds_read);
+}
+#endif
+
+void CSerial::debug(const char * /*mark*/, const Packet_t& /*data*/)
+{
+#ifndef DBG
+    return;
+#else
+    unsigned i;
+    unsigned bytes = DBG_LINE_SIZE;
+    char buf[DBG_LINE_SIZE + 1];
+    memset(buf,0x20,sizeof(buf));
+    buf[DBG_LINE_SIZE] = 0;
+
+    cout << mark << endl << "     ";
+
+    const uint8_t * pData = (const uint8_t*)&data;
+
+    for(i = 0; i < (data.size + GUSB_HEADER_SIZE); ++i) {
+        if(i && !(i % DBG_LINE_SIZE)) {
+            cout << " " << buf << endl << "     ";
+            memset(buf,0x20,sizeof(buf));buf[DBG_LINE_SIZE] = 0;
+            bytes = DBG_LINE_SIZE;
+        }
+
+        cout.width(2);
+        cout.fill('0');
+        cout << hex << (unsigned)pData[i] << " ";
+
+        if(isprint(pData[i])) {
+            buf[i%DBG_LINE_SIZE] = pData[i];
+        }
+        else {
+            buf[i%DBG_LINE_SIZE] = '.';
+        }
+
+        --bytes;
+
+    }
+    for(i = 0; i < bytes; i++)
+        cout << "   ";
+    cout << " " << buf << dec << endl;
+#endif
+}
+
+
+// input: packet
+// returns: <0 error, 0= nothing received, >0 count of data 0..255
+int CSerial::read(Packet_t& data)
+{
+    int res;
+
+    data.type = 0;
+    data.id   = 0;
+    data.size = 0;
+
+    res = serial_read(data, readtimeout_ms);
+
+    if (res > 0)
+        serial_send_ack(data.id);
+
+    return res;
+}
+
+
+// input: packet
+// returns: <0 error, 0= nothing received, >0 count of data 0..255
+int CSerial::read(char* data)
+{
+    uint8_t byte;
+    int bytes_received = 0;
+
+    while (serial_char_read( &byte, readtimeout_ms)) {
+        data[bytes_received++] = byte;
+        if (byte == 10)          //read until carriage return
+            break;
+        if (bytes_received > 255)// buffer full
+            break;
+    }                            //chars ready
+
+    return bytes_received;
+}
+
+
+// FIXME: needs better error handling!
+// input: packet
+void CSerial::write(const Packet_t& data)
+{
+    serial_write(data);
+
+    if (serial_check_ack(data.id)) {
+        cout << endl << "Serial: resending packet\n";
+        serial_write(data);      // just try again
+        if (serial_check_ack(data.id))
+            throw exce_t(errWrite,"serial_send_packet failed");
+    }
+}
+
+
+// in: bitrate, example: 115200
+// returns: 0=success, <0 error
+int CSerial::setBitrate(uint32_t bitrate)
+{
+                                 // pid_change_bitrate ?
+    Packet_t gpack_change_bitrate(0, 0x30);
+    static Packet_t test_packet(0, Pid_Command_Data);
+    static Packet_t pingpacket(0, Pid_Command_Data);
+    Packet_t response;
+    uint32_t device_bitrate = 0;
+    pingpacket.size = 2;
+    *(uint16_t*)pingpacket.payload = 0x003a;
+#ifdef WIN32
+    DCB dcb;
+#else
+    struct termios tty;
+    speed_t speed = B9600;
+
+    switch (bitrate) {
+        case 9600: speed = B9600; break;
+        case 19200: speed = B19200; break;
+        case 38400: speed = B38400; break;
+        case 57600: speed = B57600; break;
+        case 115200: speed = B115200; break;
+        default:                 // throw "unsupported bitrate";
+            return -1;
+            break;
+    }
+#endif
+    *(uint32_t*)gpack_change_bitrate.payload = bitrate;
+    gpack_change_bitrate.size = 4;
+
+    test_packet.size = 2;
+    *test_packet.payload = 14;
+    CSerial::write(test_packet);
+    //read units response
+    while (CSerial::read(response))
+        if (response.id == 38 && response.size == 4)
+            break;
+
+    //send change bitrate request
+    CSerial::write(gpack_change_bitrate);
+
+    //read units response to speed request
+    while (CSerial::read(response)) {
+        if (response.id == 0x31 && response.size == 4) {
+            device_bitrate = *(uint32_t*)response.payload;
+            break;
+        }
+    }
+
+    //check if speed is ok for unit
+    if (bitrate * 1.02 < device_bitrate || bitrate > device_bitrate * 1.02) {
+        cout << "WARNING: Bitrate not supported or differs too much" << endl;
+        cout << bitrate << " chosen, device wants " << device_bitrate << endl;
+        cout << "please report this problem to the author of your units driver" << endl;
+        return -1;               // FIXME: throw warning
+    }
+#ifdef WIN32
+    Sleep( 100);
+                                 // get default values
+    if( !GetCommState( hCom, &dcb)) {
+        cerr << "error getting port state" << endl;
+        return( -1);
+    }
+    dcb.BaudRate= bitrate;
+
+    if( !SetCommState( hCom, &dcb)) {
+        cerr << "error setting up bitrate " << bitrate << endl;
+        return( -1);
+    }
+
+#else
+    // UNIX
+    //wait 100 millisecs here, just in case TCSADRAIN doesn't work
+    usleep(100000);
+    if (tcgetattr(port_fd, &tty) < 0) {
+        // throw "Failed to get parameters for serial port";
+        return -1;
+    }
+    cfsetispeed(&tty, speed);
+    cfsetospeed(&tty, speed);
+
+    cerr << "Changing speed to " << bitrate << endl;
+    if(tcsetattr(port_fd, TCSADRAIN, &tty) < 0) {
+        // throw "Failed to set parameters/bitrate for serial port";
+        return -1;
+    }
+#endif
+
+    CSerial::write(pingpacket);
+    CSerial::write(pingpacket);
+    CSerial::write(pingpacket);
+
+    return 0;
+}
+
+
+int CSerial::syncup(int responseCount)
+{
+    Packet_t command;
+    Packet_t response;
+    /* speed improvement when remembering last numer of packets
+       to this request as we will not run in long timeout
+       if syncup should be called a second time */
+    static int last_response = 0;
+    int counter = 0;
+
+    if (!last_response && responseCount > 0)
+        last_response = responseCount;
+
+    command.type = 0;
+    command.id   = Pid_Product_Rqst;
+    command.size = 0;
+
+    CSerial::write(command);
+
+    protocolArraySize = 0;
+    while(CSerial::read(response)) {
+        if(response.id == Pid_Product_Data) {
+            //TODO read data
+            Product_Data_t * pData = (Product_Data_t*)response.payload;
+            productId       = pData->product_id;
+            softwareVersion = pData->software_version;
+            productString   = pData->str;
+#ifdef DBG
+            cout << hex << productId << " " << dec << softwareVersion << " " << productString << endl;
+#endif
+        }
+        /* TODO
+                    if(response.id == Pid_Ext_Product_Data){
+                        //TODO read data
+                    }
+        */
+
+        if(response.id == Pid_Protocol_Array) {
+            //TODO read data
+            Protocol_Data_t * pData = (Protocol_Data_t*)response.payload;
+            for(uint32_t i = 0; i < response.size; i += sizeof(Protocol_Data_t)) {
+#ifdef DBG
+                cout << "Protocol: "<< (char)pData->tag <<  dec << pData->data << endl;
+#endif
+                ++protocolArraySize;
+                protocolArray[protocolArraySize].tag = pData->tag;
+                protocolArray[protocolArraySize].data = pData->data;
+                ++pData;
+            }
+            ++protocolArraySize;
+#ifdef DBG
+            cout << "protocolArraySize:" << protocolArraySize << endl;
+#endif
+        }
+
+        ++counter;
+        if (last_response && counter == last_response)
+            break;
+    }
+    if (!last_response)
+        last_response = counter;
+
+    return counter;
+}
+
+
+//********************************************************************
+
+// garmin daten entsprechend linkprotokoll verpacken:
+// DLE, packet_ID, Size, 0-255 bytes, checksum, DLE, ETX
+// If any byte in size/data/checksum is DLE (16dez) -> insert add DLE
+void CSerial::serial_write(const Packet_t& data)
+{
+    static uint8_t buff[(SERIAL_PACKET_MAX_SIZE * 2) + 9];
+    int res,i;
+    uint8_t checksum = 0;
+    int bindex = 3;
+#ifdef WIN32
+    DWORD bytes_written = 0;
+#endif
+
+    if (data.id > 255 || data.size > 255) {
+        cerr << "data.id or data.size to big " << data.id << " " << data.size << endl;
+        return;
+    }
+
+    buff[0] = (uint8_t) DLE;
+
+    checksum -= (uint8_t) data.id;
+    buff[1] = (uint8_t) data.id; // packet id
+    // DLE stuffing not needed with packed id, according to iop_spec.pdf
+
+    checksum -= (uint8_t) data.size;
+                                 // packet size
+    buff[2] = (uint8_t) data.size;
+    if (buff[2] == DLE) {
+        buff[3] = (uint8_t) DLE;
+        bindex++;
+    }
+
+    for (i = 0; i < (int) data.size; ++i) {
+        checksum -= (uint8_t) data.payload[i];
+        buff[bindex] = data.payload[i];
+        if (buff[bindex++] == DLE)
+            buff[bindex++] = (uint8_t) DLE;
+    }
+
+    buff[bindex] = checksum;
+    if (buff[bindex++] == DLE)
+        buff[bindex++] = (uint8_t) DLE;
+
+    buff[bindex++] = (uint8_t) DLE;
+    buff[bindex++] = (uint8_t) ETX;
+
+#ifdef WIN32
+    res = WriteFile( hCom, buff, bindex, &bytes_written, NULL);
+    if (res) {
+        res = bytes_written;
+    }
+    else {
+        res = -1;
+    }
+#else
+    res = ::write(port_fd, buff, bindex);
+#endif
+
+    debug("s <<",data);
+
+    if (res < 0)
+        cerr << "serial write failed" << endl;
+    else if (res != bindex)
+        cerr << "serial write was incomplete!" << endl;
+
+    // FIXME: todo I don't know if this is applicable to serial connections
+#if 0
+    /*
+           The Garmin protocol requires that packets that are exactly
+           a multiple of the max tx size be followed by a zero length
+           packet.
+    */
+    if (size && !(size % max_tx_size)) {
+        ::usb_bulk_write(udev,epBulkOut,(char*)&data,0,3000);
+#ifdef DBG
+        cout << "b << zero size packet to terminate" << endl;
+#endif
+    }
+    if (res < 0) {
+        stringstream msg;
+        msg << "Serial write failed";
+        // FIXME:        throw msg.str().c_str();
+    }
+#endif
+}
+
+
+#ifdef WIN32
+int CSerial::serial_char_read( uint8_t *byte, unsigned milliseconds)
+{
+    DWORD result;
+    DWORD BytesRead;
+
+    int tries = milliseconds / 20;
+
+    while (tries > 0) {
+        tries--;
+        result= ReadFile( hCom, byte, 1, &BytesRead, NULL);
+        if (BytesRead == 1) {
+            return (1);
+            break;
+        }
+        Sleep( 20);
+
+    }
+    return (0);
+}
+
+
+#else
+// UNIX
+// check if data available and read one byte
+int CSerial::serial_char_read( uint8_t *byte, unsigned milliseconds)
+{
+    //fds_read has always set port_fd
+    struct timeval stimeout;
+
+    // according to man select: the timeout structure might be modified after select()
+    stimeout.tv_sec = milliseconds / 1000;
+    stimeout.tv_usec = (milliseconds % 1000) * 1000;
+
+    select(port_fd+1, &fds_read, NULL, NULL, &stimeout);
+
+    if (FD_ISSET(port_fd, &fds_read)) {
+        //ready in time
+        if (::read(port_fd, byte, 1) != 1) {
+            cerr << "Serial read char failed" << endl;
+            return 0;
+        }
+        else {
+            return 1;
+        }
+    }
+    else
+        //timed out
+                                 //set port_fd again
+        FD_SET(port_fd, &fds_read);
+
+    return 0;
+}
+#endif
+
+// check for ack for command cmd
+// 0 = success, <0 = error
+int CSerial::serial_check_ack(uint8_t cmd)
+{
+    Packet_t response;
+    int count;
+
+    while ((count = serial_read(response)) > 0) {
+        if (response.id == Pid_Ack_Byte && response.payload[0] == cmd)
+            return 0;
+        else if (response.id == Pid_Nak_Byte && response.payload[0] == cmd) {
+            cerr << "CMD " << cmd << ": got NAK, ignoring\n";
+        }
+        else {
+            cerr << "Got unexpected packet: id=" << response.id;
+            for (unsigned n = 0; n < response.size; n++)
+                cerr << ' ' << response.payload[n];
+            cerr << '\n';
+        }
+    }
+
+    return  -1;                  // no input data
+}
+
+
+// ack senden
+void CSerial::serial_send_ack(uint8_t cmd)
+{
+    static Packet_t ack_packet(0,Pid_Ack_Byte);
+    ack_packet.payload[0] = cmd;
+    ack_packet.payload[1] = (uint8_t) 0;
+    ack_packet.size = 2;
+    serial_write(ack_packet);
+
+}
+
+
+// nak senden
+void CSerial::serial_send_nak(uint8_t cmd)
+{
+    static Packet_t nak_packet(0,Pid_Nak_Byte);
+    nak_packet.payload[0] = cmd;
+    nak_packet.payload[1] = (uint8_t) 0;
+    nak_packet.size = 2;
+    serial_write(nak_packet);
+
+                                 // FIXME:
+    cout << endl << "sent nak_packet" << endl;
+}
+
+
+// garmin daten entsprechend linkprotokoll auspacken:
+// returns received bytecount of data (0..255)
+int CSerial::serial_read(Packet_t& data, unsigned milliseconds)
+{
+    uint8_t byte;
+    int check_for_dledle = 0;    // next byte should be DLE
+                                 // without inserted "double" DLEs
+    unsigned int bytes_received = 0;
+    uint8_t checksum = 0;
+    int i = 0;
+    int ready = 0;
+
+    data.type = 0;
+    data.id   = 0;
+    data.size = 0;
+
+    while (serial_char_read( &byte, milliseconds)) {
+                                 // this one first
+        if (check_for_dledle) {
+            if (DLE == byte) {
+                check_for_dledle = 0;
+            }
+            else {
+                cout << endl << "ERROR: DLE stuffing error" << endl;
+                return -1;       // FIXME: protocol error
+            }
+        }
+        else if (0 == bytes_received) {
+            if (byte == DLE) {
+                bytes_received++;
+            }
+            else {
+                cout << endl << "ERROR: start byte isn't DLE" << endl;
+                return -1;       // FIXME: protocol error
+            }
+        }
+        else if (1 == bytes_received) {
+            data.id = byte;
+            bytes_received++;
+            checksum -= byte;
+        }
+        else if (2 == bytes_received) {
+            data.size = byte;
+            bytes_received++;
+            checksum -= byte;
+            if (DLE == byte) {
+                check_for_dledle = 1;
+            }
+        }                        // databytes
+        else if (bytes_received < data.size + 3) {
+            data.payload[i] = byte;
+            i++;
+            bytes_received++;
+            checksum -= byte;
+            if (DLE == byte) {
+                check_for_dledle = 1;
+            }
+        }                        // checksum
+        else if (bytes_received == data.size + 3) {
+            bytes_received++;
+            if (checksum != byte) {
+                cout << endl << "ERROR: checksum wrong" << endl;
+                return -1;       // FIXME: checksum error
+            }
+            if (DLE == byte) {
+                check_for_dledle = 1;
+            }
+        }                        // DLE
+        else if (bytes_received == data.size + 4) {
+            if (byte == DLE) {
+                bytes_received++;
+            }
+            else {
+                cout << endl << "ERROR: end byte1 isn't DLE" << endl;
+                return -1;       // FIXME: protocol error
+            }
+        }                        // ETX
+        else if (bytes_received == data.size + 5) {
+            if (byte == ETX) {
+                bytes_received++;
+                ready = 1;
+                break;
+            }
+            else {
+                cout << endl << "ERROR: end byte2 isn't ETX" << endl;
+                return -1;       // FIXME: protocol error
+            }
+        }
+    }                            //chars ready
+
+    debug("r >>", data);
+
+    if (!ready) {
+        data.id   = 0;
+        data.size = 0;
+    }
+
+    return static_cast<int>(data.size);
+}
+
+
+uint16_t CSerial::getDataType(int data_no, char tag, uint16_t protocol)
+{
+    // Find the right tag D<Data_no> for <tag><protocol>
+    for (uint32_t i=0; i < protocolArraySize-1-data_no; i++) {
+        if ((char)protocolArray[i].tag == tag) {
+            if (protocolArray[i].data == protocol) {
+                // accept data_no=-1 as a protocol verification only
+                if (data_no == -1) return (uint16_t) 1;
+                if ((char)protocolArray[i+1+data_no].tag == 'D') {
+                    return protocolArray[i+1+data_no].data;
+                }
+            }
+        }
+    }
+    return (uint16_t) 0;
+}
+
+
+void CSerial::readTimeout( uint32_t milliseconds)
+{
+    readtimeout_ms= milliseconds;
+}
diff --git a/src/CSerial.h b/src/CSerial.h
new file mode 100644
index 0000000..fecb3c7
--- /dev/null
+++ b/src/CSerial.h
@@ -0,0 +1,114 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef CSERIAL_H
+#define CSERIAL_H
+
+#include <string>
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <termios.h>
+#endif
+#include <time.h>
+#include <sys/types.h>
+#include <sys/time.h>
+//#include <stdint.h>
+#include "ILink.h"
+#include "Garmin.h"
+
+namespace Garmin
+{
+    /// Garmin's serial protocol
+    /**
+        This should be kept common to all serial devices. However
+        if your device does not fit into the protocol implementation
+        at all, subclass it and make your fixes.
+    */
+    class CSerial : public ILink
+    {
+        public:
+            CSerial(const std::string& port);
+            virtual ~CSerial();
+
+            /// see ILink::open()
+            void open();
+            /// see ILink::close()
+            void close();
+            /// see ILink::read()
+            int read(Packet_t& data);
+            /// see ILink::write()
+            void write(const Packet_t& data);
+            /// sync. up sequence
+            /**
+                This must be called prior to any other request.
+
+                @param responseCount Number of response packets to expect
+
+                @return Actual retrieved number of response packets to product_request
+            */
+            virtual int syncup(int responseCount = 0);
+
+            int read(char *data);
+
+            uint16_t getProductId(){return productId;}
+            int16_t  getSoftwareVersion(){return softwareVersion;}
+            const std::string& getProductString(){return productString;}
+            uint16_t getDataType(int data_no, char tag, uint16_t protocol);
+
+            // in: bitrate, example: 115200
+            // returns: 0=success, <0 error
+            int setBitrate( uint32_t bitrate);
+            void readTimeout( uint32_t milliseconds);
+
+        protected:
+
+            int serial_char_read( uint8_t *byte, unsigned milliseconds);
+            int serial_read(Packet_t& data, unsigned milliseconds = 1000);
+            void serial_write(const Packet_t& data);
+
+            int serial_check_ack( uint8_t cmd);
+            void serial_send_ack( uint8_t cmd);
+            void serial_send_nak( uint8_t cmd);
+
+            virtual void debug(const char * mark, const Garmin::Packet_t& data);
+
+#ifdef WIN32
+            HANDLE hCom;
+#else
+            // file descripor for serial port
+            int port_fd;
+            struct termios gps_ttysave;
+            fd_set fds_read;
+            int interface;
+#endif
+            uint16_t productId;
+            int16_t  softwareVersion;
+            std::string productString;
+            uint32_t protocolArraySize;
+            Protocol_Data_t protocolArray[GUSB_PAYLOAD_SIZE];
+
+            std::string port;
+            uint32_t readtimeout_ms;
+    };
+
+}
+#endif                           //CSERIAL_H
diff --git a/src/CTcp.cpp b/src/CTcp.cpp
new file mode 100644
index 0000000..0dee0c9
--- /dev/null
+++ b/src/CTcp.cpp
@@ -0,0 +1,259 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Juan Pablo Daniel Borgna jpdborgna at e-mips.com.ar
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "CTcp.h"
+#include "IDevice.h"
+#include "Platform.h"
+
+#include <iostream>
+#include <sstream>
+#include <assert.h>
+#include <errno.h>
+#ifndef WIN32
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#endif
+
+#include <time.h>
+
+using namespace Garmin;
+using namespace std;
+
+#undef DBG
+
+#define DBG_LINE_SIZE 16
+
+#define MAX_SIZE 255
+#define TIMEOUT 5
+
+static int my_close( int fd)
+{
+    return( close( fd));
+}
+
+
+static ssize_t my_read(int fd, void *buf, size_t count)
+{
+    return( recv( fd, (char *) buf, count,0));
+}
+
+
+static ssize_t my_write(int fd, const void *buf, size_t count)
+{
+    return( send( fd, (char *) buf, count,0));
+}
+
+
+CTcp::CTcp(const std::string& port)
+: sock_fd(-1)
+, productId(0)
+, softwareVersion(0)
+, port(port)
+{
+}
+
+
+CTcp::~CTcp()
+{
+    close();
+}
+
+
+struct in_addr *  CTcp::atoaddr(char *address)
+{
+    struct hostent *host;
+    static struct in_addr saddr;
+
+    /* First try it as aaa.bbb.ccc.ddd. */
+    saddr.s_addr = inet_addr(address);
+    if ((int )saddr.s_addr != -1) {
+        return &saddr;
+    }
+    host = gethostbyname(address);
+    if (host != NULL) {
+        return (struct in_addr *) *host->h_addr_list;
+    }
+    return NULL;
+}
+
+
+void CTcp::open()
+{
+#if defined(WORDS_BIGENDIAN) || !defined(CAN_UNALIGNED)
+    throw exce_t(errOpen, "The TCP driver still needs to be ported to your platform.");
+#endif
+    uint16_t lport = -1;
+    struct in_addr *addr;
+    struct sockaddr_in address;
+    char conn[255],*service,*errpos;
+
+#ifdef WIN32
+    WSADATA wsaData;
+    WORD wVersionRequested;
+    int err;
+
+                                 // 2.0 and above version of WinSock
+    wVersionRequested = MAKEWORD( 2, 0 );
+    err = WSAStartup( wVersionRequested, &wsaData );
+    if ( err != 0 ) {
+        stringstream msg;
+        msg << "Couldn't not find a usable WinSock DLL, WSAStartup, error= " << err;
+        throw exce_t(errOpen,msg.str());
+    }
+#endif
+
+    if (sock_fd >= 0)
+        return;
+
+    strcpy(conn,port.c_str());
+
+    service=strstr(conn,":")+1;
+
+    lport = strtol(service,&errpos,0);
+    if ( (errpos[0] != 0) || (lport == 0) ) {
+        stringstream msg;
+        msg << "Invalid port number " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+        return;                  /* Invalid port address */
+    }
+    lport = htons(lport);
+
+    *(service-1)=0;
+
+    addr = atoaddr(conn);
+    if (addr == NULL) {
+        stringstream msg;
+        msg << "Failed to resolve addres " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+        return;
+    }
+
+    memset((char *) &address, 0, sizeof(address));
+    address.sin_family = AF_INET;
+    address.sin_port = (lport);
+    address.sin_addr.s_addr = addr->s_addr;
+
+    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
+
+    if (connect(sock_fd, (struct sockaddr *) &address, sizeof(address)) < 0) {
+        stringstream msg;
+        msg << "Couldn't connect to " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+        return;
+    }
+
+    if (sock_fd < 0) {
+        stringstream msg;
+        msg << "Failed to open socket device " << port.c_str();
+        throw exce_t(errOpen,msg.str());
+    }
+}
+
+
+void CTcp::close()
+{
+#ifdef WIN32
+    WSACleanup();
+#endif
+
+    my_close (sock_fd);
+    sock_fd= -1;
+}
+
+
+int CTcp::read(char * data)
+{
+    int bytes_read;
+    size_t total_count = 0;
+    char *current_position;
+    char last_read = 0;
+    time_t starttime;
+    starttime= time_now();
+
+    current_position = data;
+
+    while (last_read != 10 && (time_now() < starttime + TIMEOUT)) {
+        bytes_read = my_read(sock_fd, &last_read, 1);
+        if (bytes_read <= 0) {
+            return -1;
+        }
+        if ( (total_count < MAX_SIZE) && (last_read != 10) && (last_read !=13) ) {
+            current_position[0] = last_read;
+            current_position++;
+            total_count++;
+        }
+    }
+
+    current_position[0] = 0;
+    return total_count;
+}
+
+
+void CTcp::write(char* data)
+{
+    size_t bytes_sent = 0;
+    int this_write;
+    int count=strlen(data);
+
+    if (data[count]!=10) {
+        data[count]=10;
+        data[count+1]=0;
+        count++;
+    }
+
+    while (bytes_sent < (size_t) count) {
+        do
+        this_write = my_write(sock_fd, data, count - bytes_sent);
+        while ( (this_write < 0) && (errno == EINTR) );
+        if (this_write <= 0)
+            return;              // this_write;
+        bytes_sent += this_write;
+        data += this_write;
+    }
+    return;
+}
+
+
+// check if data available
+int CTcp::sock_chars_ready( void)
+{
+    fd_set fds_read;
+    struct timeval time;
+    FD_ZERO( &fds_read);
+    FD_SET( sock_fd, &fds_read);
+    time.tv_sec= 0;
+    time.tv_usec= 1000;
+    select( sock_fd+1, &fds_read, NULL, NULL, &time);
+    if (FD_ISSET( sock_fd, &fds_read)) {
+        return 1;
+    }
+    return 0;
+}
+
+
+time_t CTcp::time_now( void)
+{
+    time_t seconds= 0;
+    time( &seconds);             // FIXME: handle error case
+    return( seconds);
+}
diff --git a/src/CTcp.h b/src/CTcp.h
new file mode 100644
index 0000000..972cac1
--- /dev/null
+++ b/src/CTcp.h
@@ -0,0 +1,91 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Juan Pablo Daniel Borgna jpdborgna at e-mips.com.ar
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef CTCP_H
+#define CTCP_H
+
+#include <string>
+#include "ILink.h"
+#include "Garmin.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifndef WIN32
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#endif
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+
+namespace Garmin
+{
+    class CTcp : public ILink
+    {
+        public:
+            CTcp(const std::string& port);
+            virtual ~CTcp();
+
+            /// see ILink::open()
+            void open();
+            /// see ILink::close()
+            void close();
+            /// see ILink::read()
+            int read(char *data);
+            /// see ILink::write()
+            void write(char *data);
+
+            int read(Packet_t& data){data=data;return -1;};
+            /// see ILink::write()
+            void write(const Packet_t& /*data*/){;return;};
+
+            uint16_t getProductId(){return productId;}
+            int16_t  getSoftwareVersion(){return softwareVersion;}
+            const std::string& getProductString(){return productString;}
+
+        protected:
+
+            struct in_addr * atoaddr(char *address);
+            int sock_chars_ready( void);
+            time_t time_now( void);
+            int sock_read(char * data);
+            void sock_write(const char * data);
+
+            // file descripor for socket
+            int sock_fd;
+
+            uint16_t productId;
+            int16_t  softwareVersion;
+            std::string productString;
+
+            std::string port;
+    };
+
+}
+#endif                           //CSERIAL_H
diff --git a/src/CUSB.cpp b/src/CUSB.cpp
new file mode 100644
index 0000000..791b2e0
--- /dev/null
+++ b/src/CUSB.cpp
@@ -0,0 +1,449 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "CUSB.h"
+#include "IDevice.h"
+#include "Platform.h"
+
+#include <iostream>
+#include <sstream>
+#include <assert.h>
+#include <errno.h>
+
+using namespace Garmin;
+using namespace std;
+
+#ifndef ETIMEDOUT                // included for windows by dr, copied from pthread.h
+#  define ETIMEDOUT 10060        /* This is the value in winsock.h. */
+#endif
+
+#define EA(x) (x & USB_ENDPOINT_ADDRESS_MASK)
+
+#define GUSB_DATA_AVAILABLE     2
+#define GUSB_SESSION_START      5
+#define GUSB_SESSION_STARTED    6
+
+#define USB_TIMEOUT 30000
+
+#undef DBG
+
+#define DBG_LINE_SIZE 16
+
+CUSB::CUSB()
+: busses(0)
+, udev(0)
+, theInterface(-1)
+, epBulkIn(-1)
+, epBulkOut(-1)
+, epIntrIn(-1)
+, max_tx_size(0)
+, doBulkRead(false)
+, productId(0)
+, softwareVersion(0)
+, protocolArraySize(-1)
+{
+    usb_init();
+    usb_find_busses();
+    usb_find_devices();
+    busses = usb_get_busses();
+}
+
+
+CUSB::~CUSB()
+{
+    close();
+}
+
+
+void CUSB::open()
+{
+    assert(busses);
+
+    usb_bus *bus = 0;
+
+    for(bus = busses; bus; bus = bus->next) {
+        struct usb_device * dev = 0;
+        for (dev = bus->devices; dev; dev = dev->next) {
+#ifdef DBG
+            cout << hex << dev->descriptor.idVendor << " " << dev->descriptor.idProduct << endl;
+#endif
+            if(dev->descriptor.idVendor == GARMIN_VID) {
+
+                if(dev->descriptor.idProduct == G60CSX_PID) {
+                    start(dev);
+                    break;
+                }
+            }
+        }
+    }
+
+    if(udev == 0) {
+        throw exce_t(errOpen,"Is the unit connected?");
+    }
+}
+
+
+void CUSB::close()
+{
+    if(udev) {
+        usb_release_interface(udev, theInterface);
+        usb_close(udev);
+        udev = 0;
+    }
+}
+
+
+void CUSB::close2()
+{
+    if(udev) {
+        usb_release_interface(udev, theInterface);
+        usb_reset(udev);
+        udev = 0;
+    }
+}
+
+
+void CUSB::debug(const char * mark, const Packet_t& data)
+{
+#ifndef DBG
+    return;
+#endif
+    unsigned i;
+    uint32_t size;
+    unsigned bytes = DBG_LINE_SIZE;
+    char buf[DBG_LINE_SIZE + 1];
+    memset(buf,0x20,sizeof(buf));buf[DBG_LINE_SIZE] = 0;
+
+    cout << mark << endl << "     ";
+
+    const uint8_t * pData = (const uint8_t*)&data;
+
+    size = gar_endian(uint32_t, data.size);
+    if(size > GUSB_MAX_BUFFER_SIZE) {
+        cerr << "WARNING! Data size " << data.size << " exceeds buffer size." << endl;
+        cerr << "Truncate to " << GUSB_MAX_BUFFER_SIZE << "." << endl;
+        size = GUSB_PAYLOAD_SIZE;
+    }
+
+    for(i = 0; i < (size + GUSB_HEADER_SIZE); ++i) {
+        if(i && !(i % DBG_LINE_SIZE)) {
+            cout << " " << buf << endl << "     ";
+            memset(buf,0x20,sizeof(buf));buf[DBG_LINE_SIZE] = 0;
+            bytes = DBG_LINE_SIZE;
+        }
+
+        cout.width(2);
+        cout.fill('0');
+        cout << hex << (unsigned)pData[i] << " ";
+
+        if(isprint(pData[i])) {
+            buf[i%DBG_LINE_SIZE] = pData[i];
+        }
+        else {
+            buf[i%DBG_LINE_SIZE] = '.';
+        }
+
+        --bytes;
+
+    }
+    for(i=0; i < bytes; i++) cout << "   ";
+    cout << " " << buf << dec << endl;
+
+}
+
+
+int CUSB::read(Packet_t& data)
+{
+    int res;
+
+    data.type = 0;
+    data.id   = 0;
+    data.size = 0;
+
+    if(doBulkRead) {
+        res = ::usb_bulk_read(udev,epBulkIn,(char*)&data,sizeof(data),USB_TIMEOUT);
+
+        if (res > 0)
+            debug("b >>", data);
+
+#if defined(WORDS_BIGENDIAN)
+        // endian fix for id and size
+        data.id = gar_endian(uint16_t, data.id);
+        data.size = gar_endian(uint32_t, data.size);
+#endif                   // big endian platform
+    }
+    else {
+        res = ::usb_interrupt_read(udev,epIntrIn,(char*)&data,sizeof(data),USB_TIMEOUT);
+
+        if (res > 0)
+            debug("i >>", data);
+
+#if defined(WORDS_BIGENDIAN)
+        // endian fix for id and size
+        data.id = gar_endian(uint16_t, data.id);
+        data.size = gar_endian(uint32_t, data.size);
+#endif                   // big endian platform
+    }
+
+    // Some devices sending data on the interrupt pipe seem
+    // to timeout occasionally. It seems to be save to ignore this
+    // timeout.
+    if(res == -ETIMEDOUT && !doBulkRead) {
+        res = 0;
+    }
+
+    // switch to bulk pipe
+    if((res > 0) && (data.id == GUSB_DATA_AVAILABLE)) {
+        doBulkRead = true;
+    }
+
+    // switch to interrupt pipe on errors or zero size packages
+    if(res <= 0) {
+        doBulkRead = false;
+    }
+
+    if(res < 0) {
+        stringstream msg;
+        msg << "USB read failed:" << usb_strerror();
+        throw exce_t(errRead,msg.str());
+    }
+
+    return res;
+}
+
+
+void CUSB::write(const Packet_t& data)
+{
+    unsigned size = GUSB_HEADER_SIZE + data.size;
+    char * src;
+
+#if defined(WORDS_BIGENDIAN)
+    // make a local copy for swapping the header
+    Packet_t real_cmnd(data.type, gar_endian(uint16_t, data.id));
+    real_cmnd.size = gar_endian(uint32_t, data.size);
+
+    // copy payload (if any)
+    if (data.size > 0)
+        memcpy(real_cmnd.payload, data.payload, data.size);
+
+    // send the tweaked packet
+    src = (char *) &real_cmnd;
+#else
+    src = (char *) &data;
+#endif                       // big endian platform
+
+    int res = ::usb_bulk_write(udev,epBulkOut,src,size,USB_TIMEOUT);
+
+    debug("b <<", (Packet_t &) *src);
+
+    if(res < 0) {
+        stringstream msg;
+        msg << "USB bulk write failed:" << usb_strerror();
+        throw exce_t(errWrite,msg.str());
+    }
+
+    /*
+       The Garmin protocol requires that packets that are exactly
+       a multiple of the max tx size be followed by a zero length
+       packet.
+    */
+    if (size && !(size % max_tx_size)) {
+        ::usb_bulk_write(udev,epBulkOut,(char*)&data,0,USB_TIMEOUT);
+#ifdef DBG
+        cout << "b << zero size packet to terminate" << endl;
+#endif
+    }
+}
+
+
+void CUSB::start(struct usb_device *dev)
+{
+    int i;
+    if(udev) return;
+
+    udev = usb_open(dev);
+    if(udev == 0) {
+        stringstream msg;
+        msg << "Failed to open USB device: " << usb_strerror();
+        throw exce_t(errOpen,msg.str());
+    }
+
+    if (usb_set_configuration(udev, dev->config->bConfigurationValue) < 0) {
+        stringstream msg;
+#if __linux__
+        char drvnm[128];
+        drvnm[0] = 0;
+        msg << "Failed to configure USB: " << usb_strerror();
+
+        usb_get_driver_np(udev, 0, drvnm, sizeof(drvnm)-1);
+
+        if(strlen(drvnm) != 0) {
+            msg << "\n\nThe kernel driver '" << drvnm << "' is blocking. "
+                << "Please use 'rmmod " << drvnm << "' as root to remove it temporarily. "
+                << "You might consider to add 'blacklist " << drvnm << "' to your "
+                << "modeprobe.conf, to remove the module permanently.";
+        }
+        throw exce_t(errOpen,msg.str());
+#endif
+
+        msg << "Failed to configure USB: " << usb_strerror();
+        throw exce_t(errOpen,msg.str());
+    }
+
+    theInterface = dev->config->interface->altsetting->bInterfaceNumber;
+    if (usb_claim_interface(udev, theInterface) < 0) {
+        stringstream msg;
+        msg << "Failed to claim USB interface: " << usb_strerror();
+        throw exce_t(errOpen,msg.str());
+    }
+
+    max_tx_size = dev->descriptor.bMaxPacketSize0;
+#ifdef DBG
+    cout << "  max. packet size:" << max_tx_size << endl;
+#endif
+
+    for (i = 0; i < dev->config->interface->altsetting->bNumEndpoints; i++) {
+        struct usb_endpoint_descriptor * ep;
+        ep = &dev->config->interface->altsetting->endpoint[i];
+
+        switch (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) {
+
+            case USB_ENDPOINT_TYPE_BULK:
+                if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+#ifdef DBG
+                    cout << "  epBulkIn " << hex << EA(ep->bEndpointAddress) << endl;
+#endif
+                    epBulkIn = EA(ep->bEndpointAddress);
+                }
+                else {
+#ifdef DBG
+                    cout << "  epBulkOut " << hex << EA(ep->bEndpointAddress) << endl;
+#endif
+                    epBulkOut = EA(ep->bEndpointAddress);
+                }
+                break;
+
+            case USB_ENDPOINT_TYPE_INTERRUPT:
+                if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+#ifdef DBG
+                    cout << "  epIntrIn " << hex << EA(ep->bEndpointAddress) << endl;
+#endif
+                    epIntrIn = EA(ep->bEndpointAddress);
+                }
+                break;
+        }
+    }
+
+    if ((epBulkIn > 0) && (epBulkOut > 0) && (epIntrIn > 0)) {
+        return;
+    }
+
+    throw exce_t(errOpen,"Failed to identify USB endpoints for this device.");
+}
+
+
+void CUSB::syncup(void)
+{
+    static const Packet_t gpack_session_start(GUSB_PROTOCOL_LAYER,GUSB_SESSION_START);
+    Packet_t response;
+
+    int i, res;
+    for(i=0; i<10; ++i) {
+        write(gpack_session_start);
+        if((res = read(response)) > 0) break;
+    }
+    if(res == 0) {
+        throw exce_t(errSync,"Failed to sync. up with device");
+    }
+
+    if(response.id == GUSB_SESSION_STARTED) {
+        Packet_t command;
+        Packet_t response;
+
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Product_Rqst;
+        command.size = 0;
+
+        write(command);
+
+        protocolArraySize = 0;
+        while(read(response)) {
+            if(response.id == Pid_Product_Data) {
+                //TODO read data
+                Product_Data_t * pData = (Product_Data_t*)response.payload;
+                productId       = gar_load(uint16_t, pData->product_id);
+                softwareVersion = gar_load(int16_t, pData->software_version);
+                productString   = pData->str;
+#ifdef DBG
+                cout << "Product: " << hex << productId << " " << dec << softwareVersion << " " << productString << endl;
+#endif
+            }
+
+            if(response.id == Pid_Ext_Product_Data) {
+                //TODO read data
+            }
+
+            if(response.id == Pid_Protocol_Array) {
+                // note: we cannot use a Protocol_Data_t here due to alignment issues
+                // on some platforms...
+                uint8_t * p = response.payload;
+                for(uint32_t i = 0; i < response.size; i += sizeof(Protocol_Data_t)) {
+                    uint8_t  pr_tag = *p++;
+                    uint16_t pr_data = gar_ptr_load(uint16_t, p);
+                    p += 2;
+#ifdef DBG
+                    cout << "Protocol: "<< (char)pr_tag <<  dec << pr_data << endl;
+#endif
+                    ++protocolArraySize;
+                    protocolArray[protocolArraySize].tag = pr_tag;
+                    protocolArray[protocolArraySize].data = pr_data;
+                }
+                ++protocolArraySize;
+#ifdef DBG
+                cout << "protocolArraySize:" << protocolArraySize << endl;
+#endif
+                //
+                if(!doBulkRead) return;
+            }
+        }
+        return;
+    }
+
+    throw exce_t(errSync,"Failed to sync. up with device");
+}
+
+
+uint16_t CUSB::getDataType(int data_no, char tag, uint16_t protocol)
+{
+    // Find the right tag D<Data_no> for <tag><protocol>
+    for (uint32_t i=0; i < protocolArraySize-1-data_no; i++) {
+        if ((char)protocolArray[i].tag == tag) {
+            if (protocolArray[i].data == protocol) {
+                // accept data_no=-1 as a protocol verification only
+                if (data_no == -1) return (uint16_t) 1;
+                if ((char)protocolArray[i+1+data_no].tag == 'D') {
+                    return protocolArray[i+1+data_no].data;
+                }
+            }
+        }
+    }
+    return (uint16_t) 0;
+}
diff --git a/src/CUSB.h b/src/CUSB.h
new file mode 100644
index 0000000..43df5a3
--- /dev/null
+++ b/src/CUSB.h
@@ -0,0 +1,144 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef CUSB_H
+#define CUSB_H
+
+#include <string>
+#ifdef __APPLE__
+#  include <pthread.h>
+#  include <IOKit/IOTypes.h>
+#  include <IOKit/usb/IOUSBLib.h>
+#elif WIN32
+#  include <windows.h>
+#else
+#  include <usb.h>
+#endif
+#include "ILink.h"
+#include "Garmin.h"
+
+#define GARMIN_VID 0x91e
+/// is this really special for the 60CSx or valid for all devices?
+#define G60CSX_PID 0x3
+
+#define GUSB_PROTOCOL_LAYER     0
+#define GUSB_APPLICATION_LAYER  20
+#define GUSB_SESSION_START      5
+
+namespace Garmin
+{
+    /// Garmin's USB protocol
+    /**
+        This should be kept common to all USB devices. However
+        if your device does not fit into the protocol implementation
+        at all, subclass it and make your fixes.
+    */
+    class CUSB : public ILink
+    {
+        public:
+            CUSB();
+            virtual ~CUSB();
+
+            /// see ILink::open()
+            void open();
+            /// see ILink::close()
+            void close();
+            void close2();
+            /// see ILink::read()
+            int read(Packet_t& data);
+            /// see ILink::write()
+            void write(const Packet_t& data);
+            /// sync. up sequence
+            /**
+                This must be called prior to any other request.
+            */
+            virtual void syncup();
+
+            uint16_t getProductId(){return productId;}
+            int16_t  getSoftwareVersion(){return softwareVersion;}
+            const std::string& getProductString(){return productString;}
+            uint16_t getDataType(int data_no, char tag, uint16_t protocol);
+
+            bool bulkReadActive(){return doBulkRead;}
+
+        protected:
+#ifdef __APPLE__
+            virtual void start(void);
+#else
+            virtual void start(struct usb_device *dev);
+#endif
+            virtual void debug(const char * mark, const Garmin::Packet_t& data);
+
+#ifdef __APPLE__
+            UInt8 epBulkIn;
+            UInt8 epBulkOut;
+            UInt8 epIntrIn;
+#else
+            /// pointer to all bus definitions
+            struct usb_bus * busses;
+#ifdef WIN32
+            /// the device handler for the Garmin unit
+            HANDLE udev;
+            DWORD gUSBPacketSize;
+#else
+            struct usb_dev_handle * udev;
+#endif
+
+            int theInterface;
+            int epBulkIn;
+            int epBulkOut;
+            int epIntrIn;
+#endif
+
+            int max_tx_size;
+            /// switch between interrupt or bulk endpoint during receive
+            /**
+                This is used by usb_read() internally
+            */
+            bool doBulkRead;
+
+            uint16_t productId;
+            int16_t  softwareVersion;
+            std::string productString;
+            uint32_t protocolArraySize;
+            Protocol_Data_t protocolArray[GUSB_PAYLOAD_SIZE];
+
+#ifdef __APPLE__
+        private:
+            friend void * readIntrPipe(void *);
+
+            // use the IOKit framework USB implementation on MacOS X
+            mach_port_t masterPort;
+            io_service_t usbDevRef;
+            IOUSBDeviceInterface **usbDev;
+            io_service_t usbInterfaceRef;
+            IOUSBInterfaceInterface182 **usbIntf;
+
+            // run reads from the interrupt pipe in a separate thread
+            pthread_t ir_thread;
+            pthread_mutex_t ir_mutex;
+            pthread_cond_t ir_cond;
+            struct readIntrCmnd_t * readIntrCmnd;
+#endif
+    };
+
+}
+#endif                           //CUSB_H
diff --git a/src/CUSB_MacOSX.cpp b/src/CUSB_MacOSX.cpp
new file mode 100644
index 0000000..07527ac
--- /dev/null
+++ b/src/CUSB_MacOSX.cpp
@@ -0,0 +1,731 @@
+/* -*-mode:c++; c-basic-offset:4; -*- */
+/**********************************************************************************************
+Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+USB Interface for MacOS X
+Written by (C) Albrecht Dre <albrecht.dress at arcor.de> 2008
+
+Based upon the CUSB.cpp source file and the examples provided by Apple with XCode
+
+Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+or one of its subsidiaries.
+
+Apple is a registered trademark by Apple, Inc.
+**********************************************************************************************/
+#include <mach/mach.h>
+#include <CoreFoundation/CFNumber.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/usb/IOUSBLib.h>
+
+#include "CUSB.h"
+#include "IDevice.h"
+#include "../Platform.h"
+
+#include <iostream>
+#include <sstream>
+#include <assert.h>
+#include <errno.h>
+#include <sys/time.h>
+
+using namespace Garmin;
+using namespace std;
+
+#define GUSB_DATA_AVAILABLE     2
+#define GUSB_SESSION_START      5
+#define GUSB_SESSION_STARTED    6
+
+#undef DBG
+
+#define DBG_LINE_SIZE 16
+
+namespace Garmin
+{
+
+    struct readIntrCmnd_t
+    {
+        void * data;
+        UInt32 * size;
+        IOReturn * result;
+    };
+
+    void * readIntrPipe(void * ptr) {
+        CUSB * usb = (CUSB *) ptr;
+
+        do {
+            // wait for a command
+            pthread_mutex_lock(&usb->ir_mutex);
+            while (usb->readIntrCmnd == 0)
+                pthread_cond_wait(&usb->ir_cond, &usb->ir_mutex);
+
+            // eject from the thread if requested
+            if (usb->readIntrCmnd == (struct readIntrCmnd_t *) (-1)) {
+                pthread_mutex_unlock(&usb->ir_mutex);
+                return NULL;
+            }
+
+            // perform the read
+            pthread_mutex_unlock(&usb->ir_mutex);
+            *usb->readIntrCmnd->result =
+                (*(usb->usbIntf))->ReadPipe(usb->usbIntf, usb->epIntrIn, usb->readIntrCmnd->data,
+                usb->readIntrCmnd->size);
+
+            // notify caller
+            pthread_mutex_lock(&usb->ir_mutex);
+            usb->readIntrCmnd = 0;
+            pthread_cond_broadcast(&usb->ir_cond);
+            pthread_mutex_unlock(&usb->ir_mutex);
+        } while (1);
+        // never reached
+    }
+
+    // Helper: create an IOKit error string
+    class MacErrStr: public string
+    {
+        public:
+            MacErrStr(IOReturn val) {
+                if (val == kIOReturnSuccess) {
+                    assign("no error");
+                    return;
+                }
+
+                assign("[");
+
+                // get the system
+                switch (val & system_emask) {
+                    case sys_iokit:
+                        append("IOKit"); break;
+                    default:
+                        stringstream msg;
+                        msg << "system " << hex << err_get_system(val);
+                        append(msg.str());
+                }
+
+                // get the subsystem
+                switch (val & sub_emask) {
+                    case sub_iokit_common:
+                        append("/common"); break;
+                    case sub_iokit_usb:
+                        append("/usb"); break;
+                    default:
+                        stringstream msg;
+                        msg << "/sub " << hex << err_get_sub(val);
+                        append(msg.str());
+                }
+
+                // append the error code (too many to decode them - there should be a system function!)
+                stringstream msg;
+                msg << "] code 0x" << hex << err_get_code(val);
+                append(msg.str());
+            }
+
+            ~MacErrStr() {}
+    };
+}
+
+
+CUSB::CUSB()
+: epBulkIn(0),
+epBulkOut(0),
+epIntrIn(0),
+max_tx_size(-1),
+doBulkRead(false),
+productId(0),
+softwareVersion(0),
+protocolArraySize(-1),
+masterPort(0),
+usbDevRef(0),
+usbDev(0),
+usbInterfaceRef(0),
+usbIntf(0),
+ir_thread(0),
+readIntrCmnd(0)
+{
+    kern_return_t err;
+
+    // create the mutex and the condition for the interrupt pipe
+    if (pthread_mutex_init(&ir_mutex, NULL) != 0)
+        throw exce_t(errOpen, "Failed to initialise mutex.");
+    if (pthread_cond_init(&ir_cond, NULL) != 0)
+        throw exce_t(errOpen, "Failed to initialise condition variable.");
+
+    // open the master port
+    if ((err = IOMasterPort(MACH_PORT_NULL, &masterPort))) {
+        stringstream msg;
+        msg << "Error " << MacErrStr(err) << " creating master port.";
+        throw exce_t(errOpen, msg.str());
+    }
+
+    // launch the thread for reading from the interrupt pipe
+    if (pthread_create(&ir_thread, NULL, &readIntrPipe, this) != 0)
+        throw exce_t(errOpen, "Failed to launch read thread.");
+}
+
+
+CUSB::~CUSB()
+{
+    close();
+
+    // terminate the interrupt pipe read thread
+    if (ir_thread) {
+        pthread_mutex_lock(&ir_mutex);
+        readIntrCmnd = (struct readIntrCmnd_t *) (-1);
+        pthread_cond_signal(&ir_cond);
+        pthread_mutex_unlock(&ir_mutex);
+        pthread_join(ir_thread, NULL);
+    }
+    pthread_cond_destroy(&ir_cond);
+    pthread_mutex_destroy(&ir_mutex);
+    if (masterPort)
+        mach_port_deallocate(mach_task_self(), masterPort);
+    masterPort = 0;
+}
+
+
+void CUSB::open()
+{
+    CFMutableDictionaryRef matchingDict;
+    SInt32 idVal;
+    CFNumberRef numberRef;
+
+    // create a matching dictionary
+    if (!(matchingDict = IOServiceMatching(kIOUSBDeviceClassName)))
+        throw exce_t(errOpen, "Cannot create matching dictionary.");
+
+    // configure the dictionary
+    idVal = GARMIN_VID;
+    if (!(numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idVal))) {
+        CFRelease(matchingDict);
+        throw exce_t(errOpen, "Cannot configure matching dictionary.");
+    }
+    CFDictionaryAddValue(matchingDict, CFSTR(kUSBVendorID), numberRef);
+    CFRelease(numberRef);
+    idVal = G60CSX_PID;
+    if (!(numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idVal))) {
+        CFRelease(matchingDict);
+        throw exce_t(errOpen, "Cannot configure matching dictionary.");
+    }
+    CFDictionaryAddValue(matchingDict, CFSTR(kUSBProductID), numberRef);
+    CFRelease(numberRef);
+
+    // get matching device (note: call consumes the matchingDict, so we must not unref it)
+    // FIXME - at this point we get only the first Garmin...
+    if ((usbDevRef = IOServiceGetMatchingService(masterPort, matchingDict)))
+        start();
+    else
+        throw exce_t(errOpen, "No Garmin device found, is the unit connected?");
+}
+
+
+void CUSB::close()
+{
+    // release interface
+    if (usbIntf) {
+        IOReturn err;
+
+        if ((err = (*usbIntf)->USBInterfaceClose(usbIntf)) != kIOReturnSuccess) {
+#ifdef DBG
+            cout << "Error " << MacErrStr(err) << " closing USB interface." << endl;
+#endif
+        }
+        if ((err = (*usbIntf)->Release(usbIntf)) != kIOReturnSuccess) {
+#ifdef DBG
+            cout << "Error " << MacErrStr(err) << " releasing USB interface." << endl;
+#endif
+        }
+    }
+    usbIntf = 0;
+
+    if (usbInterfaceRef)
+        IOObjectRelease(usbInterfaceRef);
+    usbInterfaceRef = 0;
+
+    // release USB device
+    if (usbDev) {
+        IOReturn err;
+
+        if ((err = (*usbDev)->USBDeviceClose(usbDev)) != kIOReturnSuccess) {
+#ifdef DBG
+            cout << "Error " << MacErrStr(err) << " closing USB device." << endl;
+#endif
+        }
+        if ((err = (*usbDev)->Release(usbDev)) != kIOReturnSuccess) {
+#ifdef DBG
+            cout << "Error " << MacErrStr(err) << " releasing USB device." << endl;
+#endif
+        }
+    }
+    usbDev = 0;
+
+    // release matching device
+    if (usbDevRef)
+        IOObjectRelease(usbDevRef);
+    usbDevRef = 0;
+}
+
+
+void CUSB::close2()
+{
+    close();
+}
+
+
+void CUSB::debug(const char * mark, const Packet_t& data)
+{
+#ifndef DBG
+    return;
+#endif
+    unsigned i;
+    uint32_t size;
+    unsigned bytes = DBG_LINE_SIZE;
+    char buf[DBG_LINE_SIZE + 1];
+
+    memset(buf, 0x20, sizeof(buf));
+    buf[DBG_LINE_SIZE] = 0;
+
+    cout << mark << endl << "     ";
+
+    const uint8_t * pData = (const uint8_t*) &data;
+
+    size = gar_endian(uint32_t, data.size);
+    if (size > GUSB_MAX_BUFFER_SIZE) {
+        cerr << "WARNING! Data size " << data.size << " exceeds buffer size." << endl;
+        cerr << "Truncate to " << GUSB_MAX_BUFFER_SIZE << "." << endl;
+        size = GUSB_PAYLOAD_SIZE;
+    }
+
+    for (i = 0; i < (size + GUSB_HEADER_SIZE); ++i) {
+        if (i && !(i % DBG_LINE_SIZE)) {
+            cout << " " << buf << endl << "     ";
+            memset(buf, 0x20, sizeof(buf));
+            buf[DBG_LINE_SIZE] = 0;
+            bytes = DBG_LINE_SIZE;
+        }
+
+        cout.width(2);
+        cout.fill('0');
+        cout << hex << (unsigned) pData[i] << " ";
+
+        if (isprint(pData[i]))
+            buf[i % DBG_LINE_SIZE] = pData[i];
+        else
+            buf[i % DBG_LINE_SIZE] = '.';
+
+        --bytes;
+
+    }
+    for (i = 0; i < bytes; i++) cout << "   ";
+    cout << " " << buf << dec << endl;
+
+}
+
+
+int CUSB::read(Packet_t& data)
+{
+    IOReturn res;
+    UInt32 size = sizeof(Packet_t);
+
+    data.type = 0;
+    data.id   = 0;
+    data.size = 0;
+
+    if (doBulkRead)
+        res = (*usbIntf)->ReadPipeTO(usbIntf, epBulkIn, (void *) &data, &size, 3000, 4000);
+    else {
+        // tell the thread to read from the interrupt pipe
+        pthread_mutex_lock(&ir_mutex);
+        struct readIntrCmnd_t readCmnd;
+        readCmnd.data = (void *) &data;
+        readCmnd.result = &res;
+        readCmnd.size = &size;
+        readIntrCmnd = &readCmnd;
+        pthread_cond_broadcast(&ir_cond);
+        pthread_mutex_unlock(&ir_mutex);
+
+        // set the timeout - MacOS X doesn't have clock_gettime?!? That's against the POSIX standard!
+        struct timeval tv;
+        gettimeofday(&tv, 0);
+        struct timespec wait_until;
+        wait_until.tv_sec = tv.tv_sec + 3;
+        wait_until.tv_nsec = tv.tv_usec * 1000;
+
+        // wait for the thread, abort on timeout
+        pthread_mutex_lock(&ir_mutex);
+        while (readIntrCmnd != 0 && pthread_cond_timedwait(&ir_cond, &ir_mutex, &wait_until) == 0);
+        if (readIntrCmnd != 0) {
+            (*usbIntf)->AbortPipe(usbIntf, epIntrIn);
+            (*usbIntf)->ClearPipeStall(usbIntf, epIntrIn);
+            pthread_cond_wait(&ir_cond, &ir_mutex);
+        }
+        pthread_mutex_unlock(&ir_mutex);
+    }
+
+    if (res == kIOReturnSuccess && size > 0) {
+        debug(doBulkRead ? "b >>" : "i >>", data);
+
+#if defined(WORDS_BIGENDIAN)
+        // endian fix for id and size
+        data.id = gar_endian(uint16_t, data.id);
+        data.size = gar_endian(uint32_t, data.size);
+#endif                   // big endian platform
+
+        // switch to bulk pipe
+        if (size > 0 && data.id == GUSB_DATA_AVAILABLE)
+            doBulkRead = true;
+    }
+
+    // switch to interrupt pipe on errors or zero size packages
+    if (size == 0 || res != kIOReturnSuccess)
+        doBulkRead = false;
+
+    if (res != kIOReturnSuccess) {
+        stringstream msg;
+        msg << "USB read failed: error " << MacErrStr(res);
+        throw exce_t(errRead, msg.str());
+    }
+
+    return size;
+}
+
+
+void CUSB::write(const Packet_t& data)
+{
+    UInt32 size = GUSB_HEADER_SIZE + data.size;
+    IOReturn res;
+    char * src;
+
+#if defined(WORDS_BIGENDIAN)
+    // make a local copy for swapping the header
+    Packet_t real_cmnd(data.type, gar_endian(uint16_t, data.id));
+    real_cmnd.size = gar_endian(uint32_t, data.size);
+
+    // copy payload (if any)
+    if (data.size > 0)
+        memcpy(real_cmnd.payload, data.payload, data.size);
+
+    // send the tweaked packet
+    src = (char *) &real_cmnd;
+#else
+    src = (char *) &data;
+#endif                       // big endian platform
+
+    res = (*usbIntf)->WritePipeTO(usbIntf, epBulkOut, (void *) src, size, 3000, 4000);
+
+    debug("b <<", (Packet_t &) *src);
+
+    if (res != kIOReturnSuccess) {
+        stringstream msg;
+        msg << "USB bulk write failed: error " << MacErrStr(res);
+        throw exce_t(errWrite, msg.str());
+    }
+
+    /*
+      The Garmin protocol requires that packets that are exactly
+      a multiple of the max tx size be followed by a zero length
+      packet.
+    */
+    if (size && !(size % max_tx_size)) {
+        (*usbIntf)->WritePipeTO(usbIntf, epBulkOut, (void *) src, 0, 1000, 2000);
+#ifdef DBG
+        cout << "b << zero size packet to terminate" << endl;
+#endif
+    }
+}
+
+
+void CUSB::start(void)
+{
+    if (usbDev)
+        return;
+
+    // deal with the device: create plug-in
+    IOReturn err;
+    IOCFPlugInInterface **iodev;
+    SInt32 score;
+
+    err = IOCreatePlugInInterfaceForService(usbDevRef, kIOUSBDeviceUserClientTypeID,
+        kIOCFPlugInInterfaceID, &iodev, &score);
+    if ((err != kIOReturnSuccess) || !iodev) {
+        stringstream msg;
+        msg << "Garmin USB device: error " << MacErrStr(err) << " creating plugin.";
+        throw exce_t(errOpen, msg.str());
+    }
+
+    // query the interface
+    err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
+        (void **) &usbDev);
+    IODestroyPlugInInterface(iodev);
+    if ((err != kIOReturnSuccess) || !usbDev) {
+        stringstream msg;
+        msg << "Garmin USB device: error " << MacErrStr(err) << " creating device interface.";
+        throw exce_t(errOpen, msg.str());
+    }
+
+    // open the interface
+    if ((err = (*usbDev)->USBDeviceOpen(usbDev)) != kIOReturnSuccess) {
+        (*usbDev)->Release(usbDev);
+        usbDev = 0;
+        stringstream msg;
+        msg << "Garmin USB device: error " << MacErrStr(err) << " opening USB device.";
+        throw exce_t(errOpen, msg.str());
+    }
+
+    // get configurations
+    UInt8 numConf;
+
+    err = (*usbDev)->GetNumberOfConfigurations(usbDev, &numConf);
+    if ((err != kIOReturnSuccess) || !numConf) {
+        stringstream msg;
+        msg << "Garmin USB device: error " << MacErrStr(err) << " reading configurations.";
+        throw exce_t(errOpen, msg.str());
+    }
+#ifdef DBG
+    cout << "Garmin USB device: found " << unsigned(numConf) << " configurations" << endl;
+#endif
+
+    // get the first configuration
+    IOUSBConfigurationDescriptorPtr confDesc;
+
+    if ((err = (*usbDev)->GetConfigurationDescriptorPtr(usbDev, 0, &confDesc)) !=
+    kIOReturnSuccess) {
+        stringstream msg;
+        msg << "Garmin USB device: error " << MacErrStr(err) << " reading first configuration.";
+        throw exce_t(errOpen, msg.str());
+    }
+
+    // set the first configuration
+    if ((err = (*usbDev)->SetConfiguration(usbDev, confDesc->bConfigurationValue)) !=
+    kIOReturnSuccess) {
+        stringstream msg;
+        msg << "Garmin USB device: error " << MacErrStr(err) << " setting configuration.";
+        throw exce_t(errOpen, msg.str());
+    }
+
+    // find the interface
+    IOUSBFindInterfaceRequest interfaceRequest;
+
+                                 // requested class
+    interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+                                 // requested subclass
+    interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+                                 // requested protocol
+    interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+                                 // requested alt setting
+    interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+    io_iterator_t iterator;
+
+    if ((err = (*usbDev)->CreateInterfaceIterator(usbDev, &interfaceRequest, &iterator)) !=
+    kIOReturnSuccess) {
+        stringstream msg;
+        msg << "Garmin USB device: error " << MacErrStr(err) << " creating interface iterator.";
+        throw exce_t(errOpen, msg.str());
+    }
+
+    if (!(usbInterfaceRef = IOIteratorNext(iterator))) {
+        IOObjectRelease(iterator);
+        throw exce_t(errOpen, "Garmin USB device: cannot find USB interface.");
+    }
+    IOObjectRelease(iterator);
+
+    // deal with the interface: create interface plug-in
+    err = IOCreatePlugInInterfaceForService(usbInterfaceRef, kIOUSBInterfaceUserClientTypeID,
+        kIOCFPlugInInterfaceID, &iodev, &score);
+    if ((err != kIOReturnSuccess) || !iodev) {
+        stringstream msg;
+        msg << "Garmin USB device interface: error " << MacErrStr(err) << " creating plugin.";
+        throw exce_t(errOpen, msg.str());
+    }
+
+    // query interface
+    err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
+        (void **) &usbIntf);
+    IODestroyPlugInInterface(iodev);
+    if ((err != kIOReturnSuccess) || !usbIntf) {
+        stringstream msg;
+        msg << "Garmin USB device interface: error " << MacErrStr(err) << " creating device interface.";
+        throw exce_t(errOpen, msg.str());
+    }
+
+    // open interface
+    if ((err = (*usbIntf)->USBInterfaceOpen(usbIntf)) != kIOReturnSuccess) {
+        (*usbIntf)->Release(usbIntf);
+        usbIntf = 0;
+        stringstream msg;
+        msg << "Garmin USB device interface: error " << MacErrStr(err) << " opening USB device interface.";
+        throw exce_t(errOpen, msg.str());
+    }
+
+    // get endpoints
+    UInt8 numEP;
+
+    if ((err = (*usbIntf)->GetNumEndpoints(usbIntf, &numEP)) != kIOReturnSuccess) {
+        stringstream msg;
+        msg << "Garmin USB device interface: error " << MacErrStr(err) << " reading number of endpoints.";
+        throw exce_t(errOpen, msg.str());
+    }
+#ifdef DBG
+    cout << "Garmin USB device interface: found " << unsigned(numEP) << " endpoints." << endl;
+#endif
+
+    // identify bulk in, bulk out and interrupt in endpoints
+    int i;
+
+    for (i = 1; i <= numEP; i++) {
+        UInt8 direction;
+        UInt8 number;
+        UInt8 transferType;
+        UInt8 interval;
+        UInt16 maxPacketSize;
+
+        if ((err =
+            (*usbIntf)->GetPipeProperties(usbIntf, i, &direction, &number,
+            &transferType, &maxPacketSize, &interval)) !=
+        kIOReturnSuccess) {
+            stringstream msg;
+            msg << "Garmin USB device interface: error " << MacErrStr(err) << " reading properties of endpoint "
+                << i << ".";
+            throw exce_t(errOpen, msg.str());
+        }
+#ifdef DBG
+        cout << "endpoint " << i << ": dir 0x" << hex << unsigned(direction) << ", number 0x" <<
+            hex << unsigned(number) << ", type 0x" << hex << unsigned(transferType) << ", max size " <<
+            dec << maxPacketSize << ", interval 0x" << hex << unsigned(interval);
+#endif
+        if (transferType == kUSBBulk) {
+            switch (direction) {
+                case kUSBIn:
+#ifdef DBG
+                    cout << " ---> use as BULK IN pipe" << endl;
+#endif
+                    epBulkIn = i;
+                    break;
+
+                case kUSBOut:
+#ifdef DBG
+                    cout << " ---> use as BULK OUT pipe" << endl;
+#endif
+                    epBulkOut = i;
+                    max_tx_size = maxPacketSize;
+                    break;
+
+                default:
+#ifdef DBG
+                    cout << " ---> no idea what I should do with it" << endl;
+#endif
+                    break;
+            }
+        }
+        else if (transferType == kUSBInterrupt && (direction == kUSBIn)) {
+#ifdef DBG
+            cout << " ---> use as INTR IN pipe" << endl;
+#endif
+            epIntrIn = i;
+        }
+        else {
+#ifdef DBG
+            cout << " ---> no idea what I should do with it" << endl;
+#endif
+        }
+    }
+
+    if (!epBulkIn || !epBulkOut || !epIntrIn || max_tx_size <= 0)
+        throw exce_t(errOpen,"Garmin USB device interface: failed to identify USB endpoints.");
+}
+
+
+void CUSB::syncup(void)
+{
+    static const Packet_t gpack_session_start(GUSB_PROTOCOL_LAYER, GUSB_SESSION_START);
+    Packet_t response;
+
+    write(gpack_session_start);
+    read(response);
+    if (response.id == GUSB_SESSION_STARTED) {
+        Packet_t command;
+        Packet_t response;
+
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Product_Rqst;
+        command.size = 0;
+
+        write(command);
+
+        protocolArraySize = 0;
+        while (read(response)) {
+            if (response.id == Pid_Product_Data) {
+                //TODO read data
+                Product_Data_t * pData = (Product_Data_t*)response.payload;
+                productId       = gar_load(uint16_t, pData->product_id);
+                softwareVersion = gar_load(int16_t, pData->software_version);
+                productString   = pData->str;
+#ifdef DBG
+                cout << "Product: " << hex << productId << " " << dec << softwareVersion <<
+                    " " << productString << endl;
+#endif
+            }
+
+            if (response.id == Pid_Ext_Product_Data) {
+                //TODO read data
+            }
+
+            if (response.id == Pid_Protocol_Array) {
+                // note: we cannot use a Protocol_Data_t here due to alignment issues
+                // on some platforms...
+                uint8_t * p = response.payload;
+                for (uint32_t i = 0; i < response.size; i += sizeof(Protocol_Data_t)) {
+                    uint8_t  pr_tag = *p++;
+                    uint16_t pr_data = gar_ptr_load(uint16_t, p);
+                    p += 2;
+#ifdef DBG
+                    cout << "Protocol: "<< (char)pr_tag <<  dec << pr_data << endl;
+#endif
+                    ++protocolArraySize;
+                    protocolArray[protocolArraySize].tag = pr_tag;
+                    protocolArray[protocolArraySize].data = pr_data;
+                }
+                ++protocolArraySize;
+#ifdef DBG
+                cout << "protocolArraySize:" << protocolArraySize << endl;
+#endif
+                //
+                if (!doBulkRead) return;
+            }
+        }
+        return;
+    }
+
+    throw exce_t(errSync,"Failed to sync. up with device");
+}
+
+
+uint16_t CUSB::getDataType(int data_no, char tag, uint16_t protocol)
+{
+    // Find the right tag D<Data_no> for <tag><protocol>
+    for (uint32_t i = 0; i < protocolArraySize - 1 - data_no; i++) {
+        if ((char) protocolArray[i].tag == tag) {
+            if (protocolArray[i].data == protocol) {
+                // accept data_no=-1 as a protocol verification only
+                if (data_no == -1)
+                    return (uint16_t) 1;
+                if ((char) protocolArray[i + 1 + data_no].tag == 'D')
+                    return protocolArray[i + 1 + data_no].data;
+            }
+        }
+    }
+    return (uint16_t) 0;
+}
diff --git a/src/CUSB_win32.cpp b/src/CUSB_win32.cpp
new file mode 100644
index 0000000..40ff632
--- /dev/null
+++ b/src/CUSB_win32.cpp
@@ -0,0 +1,429 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "CUSB.h"
+#include "IDevice.h"
+
+#include <iostream>
+#include <sstream>
+#include <assert.h>
+#include <errno.h>
+
+//#include <windows.h>
+#include <initguid.h>
+#include <setupapi.h>            // You may need to explicitly link with setupapi.lib
+#include <winioctl.h>
+
+// {2C9C45C2-8E7D-4C08-A12D-816BBAE722C0}
+DEFINE_GUID(GARMIN_GUID,               0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81, 0x6b, 0xba, 0xe7, 0x22, 0xc0);
+DEFINE_GUID(GUID_DEVINTERFACE_GRMNUSB, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81, 0x6b, 0xba, 0xe7, 0x22, 0xc0);
+
+#define IOCTL_ASYNC_IN        CTL_CODE (FILE_DEVICE_UNKNOWN, 0x850, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_USB_PACKET_SIZE CTL_CODE (FILE_DEVICE_UNKNOWN, 0x851, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define MAX_BUFFER_SIZE 4096
+#define ASYNC_DATA_SIZE 64
+
+using namespace Garmin;
+using namespace std;
+
+#define GUSB_DATA_AVAILABLE     2
+#define GUSB_SESSION_START      5
+#define GUSB_SESSION_STARTED    6
+
+#undef DBG
+
+#define DBG_LINE_SIZE 16
+
+CUSB::CUSB()
+: busses(0)
+, udev(0)
+//, theInterface(-1)
+, max_tx_size(0)
+, epBulkIn(-1)
+, epBulkOut(-1)
+, epIntrIn(-1)
+, doBulkRead(false)
+, productId(0)
+, softwareVersion(0)
+{
+}
+
+
+CUSB::~CUSB()
+{
+    close();
+}
+
+
+void CUSB::open()
+{
+    // Make all the necessary Windows calls to get a handle
+    // to our USB device
+    DWORD theBytesReturned = 0;
+
+    PSP_INTERFACE_DEVICE_DETAIL_DATA theDevDetailData = 0;
+    SP_DEVINFO_DATA theDevInfoData = { sizeof( SP_DEVINFO_DATA ) };
+
+    Packet_t theStartSessionPacket = Packet_t(0,5);
+    Packet_t thePacket = Packet_t();
+
+    HDEVINFO theDevInfo;
+    //	SP_DEVICE_INTERFACE_DATA devinterface;
+
+    theDevInfo = ::SetupDiGetClassDevs( (GUID *) &GARMIN_GUID, NULL, NULL,
+        DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
+
+    if (theDevInfo == INVALID_HANDLE_VALUE) {
+        throw exce_t(errOpen,"Is the Garmin USB driver installed?");
+    }
+    SP_DEVICE_INTERFACE_DATA theInterfaceData;
+    theInterfaceData.cbSize = sizeof( theInterfaceData );
+
+    if( !SetupDiEnumDeviceInterfaces( theDevInfo,
+        NULL,
+        (GUID*) &GUID_DEVINTERFACE_GRMNUSB,
+        0,
+        &theInterfaceData ) &&
+    GetLastError() == ERROR_NO_MORE_ITEMS ) {
+        udev = 0;
+        return;
+    }
+
+    SetupDiGetDeviceInterfaceDetail(
+        theDevInfo,
+        &theInterfaceData,
+        NULL,
+        0,
+        &theBytesReturned,
+        NULL );
+
+    theDevDetailData =
+        (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc( theBytesReturned );
+    theDevDetailData->cbSize = sizeof( SP_INTERFACE_DEVICE_DETAIL_DATA );
+
+    SetupDiGetDeviceInterfaceDetail( theDevInfo,
+        &theInterfaceData,
+        theDevDetailData,
+        theBytesReturned,
+        NULL,
+        &theDevInfoData );
+
+    udev = CreateFile(
+        theDevDetailData->DevicePath,
+        GENERIC_READ | GENERIC_WRITE,
+        0,
+        NULL,
+        OPEN_EXISTING,
+        FILE_ATTRIBUTE_NORMAL,
+        NULL );
+
+    free( theDevDetailData );
+
+    if(udev == NULL) {
+        throw exce_t(errOpen,"Is the unit connected?");
+    }
+    if(udev == INVALID_HANDLE_VALUE) {
+        throw exce_t(errOpen,"The unit seems to be connected with something else?");
+    }
+
+    // Get the USB packet size, which we need for sending packets
+    gUSBPacketSize = 0;
+    DeviceIoControl( udev,
+        IOCTL_USB_PACKET_SIZE,
+        0,
+        0,
+        &gUSBPacketSize,
+        sizeof( gUSBPacketSize ),
+        &theBytesReturned,
+        NULL );
+
+    // Tell the device that we are starting a session.
+    /*	write( theStartSessionPacket );
+
+        // Wait until the device is ready to start the session
+
+        for( ; ; )
+            {
+            read( thePacket );
+
+            if( thePacket.type == 0 &&
+                thePacket.id == 6 )
+                {
+                break;
+                }
+
+    //	    free( thePacket );
+            }
+
+    //	free( thePacket );
+
+    */
+}
+
+
+void CUSB::close()
+{
+    if(udev) {
+        CloseHandle(udev);
+        udev = 0;
+    }
+}
+
+
+void CUSB::close2()
+{
+    if(udev) {
+        CloseHandle(udev);
+        udev = 0;
+    }
+}
+
+
+void CUSB::debug(const char * mark, const Packet_t& data)
+{
+#ifndef DBG
+    return;
+#endif
+    unsigned i;
+    uint32_t size;
+    unsigned bytes = DBG_LINE_SIZE;
+    char buf[DBG_LINE_SIZE + 1];
+    memset(buf,0x20,sizeof(buf));buf[DBG_LINE_SIZE] = 0;
+
+    cout << mark << endl << "     ";
+
+    const uint8_t * pData = (const uint8_t*)&data;
+
+    size = data.size;
+    if(size > GUSB_MAX_BUFFER_SIZE) {
+        cerr << "WARNING! Data size " << data.size << " exceeds buffer size." << endl;
+        cerr << "Truncate to " << GUSB_MAX_BUFFER_SIZE << "." << endl;
+        size = GUSB_PAYLOAD_SIZE;
+    }
+
+    for(i = 0; i < (size + GUSB_HEADER_SIZE); ++i) {
+        if(i && !(i % DBG_LINE_SIZE)) {
+            cout << " " << buf << endl << "     ";
+            memset(buf,0x20,sizeof(buf));buf[DBG_LINE_SIZE] = 0;
+            bytes = DBG_LINE_SIZE;
+        }
+
+        cout.width(2);
+        cout.fill('0');
+        cout << hex << (unsigned)pData[i] << " ";
+
+        if(isprint(pData[i])) {
+            buf[i%DBG_LINE_SIZE] = pData[i];
+        }
+        else {
+            buf[i%DBG_LINE_SIZE] = '.';
+        }
+
+        --bytes;
+
+    }
+    for(i=0; i < bytes; i++) cout << "   ";
+    cout << " " << buf << dec << endl;
+
+}
+
+
+int CUSB::read(Packet_t& data)
+{
+    int res=0;
+
+    data.type = 0;
+    data.id   = 0;
+    data.size = 0;
+    DWORD theBytesReturned = 0;
+    BOOL ok = true;
+
+    if(doBulkRead) {
+        ok = ReadFile( udev, &data, MAX_BUFFER_SIZE, &theBytesReturned, NULL );
+        if ( theBytesReturned <= 0 ) doBulkRead = false;
+#ifdef WIN_DEBUG
+        FILE *fp = NULL;
+        fp = fopen( "report.txt","a");
+        if (fp != NULL) {
+            fprintf(fp,"CUSB::read bulk type=%d, id=%d, ret=%d\n",data.type,data.id,theBytesReturned);
+            fclose(fp);
+        }
+#endif                   // WIN_DEBUG
+    }
+    else {
+        DeviceIoControl( udev, IOCTL_ASYNC_IN, 0, 0, &data,
+            ASYNC_DATA_SIZE, &theBytesReturned, NULL );
+        if( data.type == 0 && data.id == GUSB_DATA_AVAILABLE ) {
+            doBulkRead = true;
+            data.type = 0;
+            data.id   = 0;
+            ok = ReadFile( udev, &data, MAX_BUFFER_SIZE, &theBytesReturned, NULL );
+        }
+
+    }
+
+    if ( !ok ) {
+        stringstream msg;
+        msg << "USB ReadFile failed:" ;
+        throw exce_t(errRead,msg.str());
+    }
+
+    /*
+        // Some devices sending data on the interrupt pipe seem
+        // to timeout occasionally. It seems to be save to ignore this
+        // timeout.
+        if(res == -ETIMEDOUT && !doBulkRead){
+             res = 0;
+        }
+
+        // switch to bulk pipe
+        if((res > 0) && (data.id == GUSB_DATA_AVAILABLE)){
+            doBulkRead = true;
+        }
+
+        // switch to interrupt pipe on errors or zero size packages
+        if(res <= 0){
+            doBulkRead = false;
+        }
+    */
+    res = 1;
+    return res;
+}
+
+
+void CUSB::write(const Packet_t& data)
+{
+    //	unsigned l = sizeof(data);
+    DWORD theBytesToWrite = GUSB_HEADER_SIZE + data.size;
+    DWORD theBytesReturned = 0;
+
+    WriteFile( udev, &data, theBytesToWrite, &theBytesReturned, NULL );
+    if ( theBytesReturned != theBytesToWrite ) {
+        stringstream msg;
+        msg << "USB bulk write failed:" ;
+        throw exce_t(errWrite,msg.str());
+    }
+
+    // If the packet size was an exact multiple of the USB packet
+    // size, we must make a final write call with no data
+
+    if( theBytesToWrite % gUSBPacketSize == 0 ) {
+        WriteFile( udev, 0, 0, &theBytesReturned, NULL );
+    }
+}
+
+
+void CUSB::start(struct usb_device *dev)
+{
+    if(udev) return;
+
+    if(udev == 0) {
+        stringstream msg;
+        msg << "Failed to open USB device: " ;
+        throw exce_t(errOpen,msg.str());
+    }
+
+}
+
+
+void CUSB::syncup(void)
+{
+    static const Packet_t gpack_session_start(GUSB_PROTOCOL_LAYER,GUSB_SESSION_START);
+    Packet_t response;
+
+    protocolArraySize = 0;
+
+    write(gpack_session_start);
+    read(response);
+    if(response.id == GUSB_SESSION_STARTED) {
+        Packet_t command;
+        Packet_t response;
+
+        command.type = GUSB_APPLICATION_LAYER;
+        command.b1 = 0; command.b2 = 0; command.b3 = 0;
+        command.id   = Pid_Product_Rqst;
+        command.b6 = 0; command.b7 = 0;
+        command.size = 0;
+
+        write(command);
+
+        while(read(response)) {
+            if(response.id == Pid_Product_Data) {
+                //TODO read data
+                Product_Data_t * pData = (Product_Data_t*)response.payload;
+                productId       = pData->product_id;
+                softwareVersion = pData->software_version;
+                productString   = pData->str;
+#ifdef DBG
+                cout << hex << productId << " " << dec << softwareVersion << " " << productString << endl;
+#endif
+            }
+
+            if(response.id == Pid_Ext_Product_Data) {
+                //TODO read data
+            }
+
+                                 // This should mark the end
+            if(response.id == Pid_Protocol_Array) {
+                //TODO read data
+
+                Protocol_Data_t * pData = (Protocol_Data_t*)response.payload;
+                for(uint32_t i = 0; i < response.size; i += sizeof(Protocol_Data_t)) {
+#ifdef WIN_DEBUG
+                    qDebug() << "Protocol: "<< (char)pData->tag <<  dec << pData->data << endl;
+#endif
+                    ++protocolArraySize;
+                    protocolArray[protocolArraySize].tag = pData->tag;
+                    protocolArray[protocolArraySize].data = pData->data;
+                    ++pData;
+                }
+                ++protocolArraySize;
+#ifdef WIN_DEBUG
+                qDebug() << "protocolArraySize:" << protocolArraySize << endl;
+#endif
+
+                return;          // let's leave, even so it is a strange ending
+            }
+        }
+        return;
+    }
+
+    throw exce_t(errSync,"Failed to sync. up with device");
+}
+
+
+uint16_t CUSB::getDataType(int data_no, char tag, uint16_t protocol)
+{
+    // Find the right tag D<Data_no> for <tag><protocol>
+    for (uint32_t i=0; i < protocolArraySize-1-data_no; i++) {
+        if ((char)protocolArray[i].tag == tag) {
+            if (protocolArray[i].data == protocol) {
+                // accept data_no=-1 as a protocol verification only
+                if (data_no == -1) return (uint16_t) 1;
+                if ((char)protocolArray[i+1+data_no].tag == 'D') {
+                    return protocolArray[i+1+data_no].data;
+                }
+            }
+        }
+    }
+    return (uint16_t) 0;
+}
diff --git a/src/EtrexH/CDevice.cpp b/src/EtrexH/CDevice.cpp
new file mode 100644
index 0000000..f63e141
--- /dev/null
+++ b/src/EtrexH/CDevice.cpp
@@ -0,0 +1,583 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Frank Seidel <frank at f-seidel.de>
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "CDevice.h"
+
+#include "../Platform.h"
+
+#include <Garmin.h>
+
+#include <cstdio>
+#include <iostream>
+#include <sstream>
+
+using namespace EtrexH;
+using namespace Garmin;
+using namespace std;
+
+#define GARMIN_EH_DFLTBITRATE 9600
+#define GARMIN_EH_HIBITRATE 57600
+
+#define CMD_TRANSFER_SCREEN 32
+#define PID_SCREENDATA 69
+
+#define PROGR_CALLBACK(state,message) \
+callback ( state,0,0,0,message )
+
+#define PROGR_CANCEL_CALLBACK(state,message,cancel) \
+callback ( state,0,cancel,0,message )
+
+namespace EtrexH
+{
+    static const char _clrtbl[1024]= {
+        -127,-127,-127,0,-60,-60,-60,0,90,90,90,0,0,0,0,0,-117,0,0,0,
+        -76,0,0,0,-43,0,0,0,-1,0,0,0,0,48,0,0,32,48,0,0,
+        65,48,0,0,106,48,0,0,-117,48,0,0,-76,48,0,0,-43,48,0,0,
+        -1,48,0,0,0,101,0,0,32,101,0,0,65,101,0,0,106,101,0,0,
+        -117,101,0,0,-76,101,0,0,-43,101,0,0,-1,101,0,0,0,-107,0,0,
+        32,-107,0,0,65,-107,0,0,106,-107,0,0,-117,-107,0,0,-76,-107,0,0,
+        -43,-107,0,0,-1,-107,0,0,0,-54,0,0,32,-54,0,0,65,-54,0,0,
+        106,-54,0,0,-117,-54,0,0,-76,-54,0,0,-43,-54,0,0,-1,-54,0,0,
+        0,-1,0,0,32,-1,0,0,65,-1,0,0,106,-1,0,0,-117,-1,0,0,
+        -76,-1,0,0,-43,-1,0,0,-1,-1,0,0,0,0,57,0,32,0,57,0,
+        65,0,57,0,106,0,57,0,-117,0,57,0,-76,0,57,0,-43,0,57,0,
+        -1,0,57,0,0,48,57,0,32,48,57,0,65,48,57,0,106,48,57,0,
+        -117,48,57,0,-76,48,57,0,-43,48,57,0,-1,48,57,0,0,101,57,0,
+        32,101,57,0,65,101,57,0,106,101,57,0,-117,101,57,0,-76,101,57,0,
+        -43,101,57,0,-1,101,57,0,0,-107,57,0,32,-107,57,0,65,-107,57,0,
+        106,-107,57,0,-117,-107,57,0,-76,-107,57,0,-43,-107,57,0,-1,-107,57,0,
+        0,-54,57,0,32,-54,57,0,65,-54,57,0,106,-54,57,0,-117,-54,57,0,
+        -76,-54,57,0,-43,-54,57,0,-1,-54,57,0,0,-1,57,0,32,-1,57,0,
+        65,-1,57,0,106,-1,57,0,-117,-1,57,0,-76,-1,57,0,-43,-1,57,0,
+        -1,-1,57,0,0,0,123,0,32,0,123,0,65,0,123,0,106,0,123,0,
+        -117,0,123,0,-76,0,123,0,-43,0,123,0,-1,0,123,0,0,48,123,0,
+        32,48,123,0,65,48,123,0,106,48,123,0,-117,48,123,0,-76,48,123,0,
+        -43,48,123,0,-1,48,123,0,0,101,123,0,32,101,123,0,65,101,123,0,
+        106,101,123,0,-117,101,123,0,-76,101,123,0,-43,101,123,0,-1,101,123,0,
+        0,-107,123,0,32,-107,123,0,65,-107,123,0,106,-107,123,0,-117,-107,123,0,
+        -76,-107,123,0,-43,-107,123,0,-1,-107,123,0,0,-54,123,0,32,-54,123,0,
+        65,-54,123,0,106,-54,123,0,-117,-54,123,0,-76,-54,123,0,-43,-54,123,0,
+        -1,-54,123,0,0,-1,123,0,32,-1,123,0,65,-1,123,0,106,-1,123,0,
+        -117,-1,123,0,-76,-1,123,0,-43,-1,123,0,-1,-1,123,0,0,0,-67,0,
+        32,0,-67,0,65,0,-67,0,106,0,-67,0,-117,0,-67,0,-76,0,-67,0,
+        -43,0,-67,0,-1,0,-67,0,0,48,-67,0,32,48,-67,0,65,48,-67,0,
+        106,48,-67,0,-117,48,-67,0,-76,48,-67,0,-43,48,-67,0,-1,48,-67,0,
+        0,101,-67,0,32,101,-67,0,65,101,-67,0,106,101,-67,0,-117,101,-67,0,
+        -76,101,-67,0,-43,101,-67,0,-1,101,-67,0,0,-107,-67,0,32,-107,-67,0,
+        65,-107,-67,0,106,-107,-67,0,-117,-107,-67,0,-76,-107,-67,0,-43,-107,-67,0,
+        -1,-107,-67,0,0,-54,-67,0,32,-54,-67,0,65,-54,-67,0,106,-54,-67,0,
+        -117,-54,-67,0,-76,-54,-67,0,-43,-54,-67,0,-1,-54,-67,0,0,-1,-67,0,
+        32,-1,-67,0,65,-1,-67,0,106,-1,-67,0,-117,-1,-67,0,-76,-1,-67,0,
+        -43,-1,-67,0,-1,-1,-67,0,0,0,-1,0,32,0,-1,0,65,0,-1,0,
+        106,0,-1,0,-117,0,-1,0,-76,0,-1,0,-43,0,-1,0,-1,0,-1,0,
+        0,48,-1,0,32,48,-1,0,65,48,-1,0,106,48,-1,0,-117,48,-1,0,
+        -76,48,-1,0,-43,48,-1,0,-1,48,-1,0,0,101,-1,0,32,101,-1,0,
+        65,101,-1,0,106,101,-1,0,-117,101,-1,0,-76,101,-1,0,-43,101,-1,0,
+        -1,101,-1,0,0,-107,-1,0,32,-107,-1,0,65,-107,-1,0,106,-107,-1,0,
+        -117,-107,-1,0,-76,-107,-1,0,-43,-107,-1,0,-1,-107,-1,0,0,-54,-1,0,
+        32,-54,-1,0,65,-54,-1,0,106,-54,-1,0,-117,-54,-1,0,-76,-54,-1,0,
+        -43,-54,-1,0,-1,-54,-1,0,0,-1,-1,0,32,-1,-1,0,65,-1,-1,0,
+        106,-1,-1,0,-117,-1,-1,0,-76,-1,-1,0,-43,-1,-1,0,-1,-1,-1,0,
+        -1,-1,-1,0,-26,-26,-26,0,-43,-43,-43,0,-59,-59,-59,0,-76,-76,-76,0,
+        -92,-92,-92,0,-108,-108,-108,0,-125,-125,-125,0,115,115,115,0,98,98,98,0,
+        82,82,82,0,65,65,65,0,49,49,49,0,32,32,32,0,16,16,16,0,
+        0,0,0,0
+    };
+}
+
+
+CDevice::CDevice(uint16_t id)
+: serial ( 0 ),
+pScreen ( 0 ),
+devId ( 0 )
+{
+    if ( id == GARMIN_ETREXEURO ) {
+        copyright = "<h1>QLandkarte Device Driver for Etrex Euro</h1>"
+            "<h2>Driver I/F Ver. " INTERFACE_VERSION "</h2>"
+            "<p>© 2007 by Frank Seidel (frank at f-seidel.de)</p>"
+            "<p>Info for Etrex Euro support by Martin Ereth (martin.ereth at arcor.de)</p>"
+            "<p>This driver 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. </p>";
+    }
+    else {
+        copyright = "<h1>QLandkarte Device Driver for Etrex H</h1>"
+            "<h2>Driver I/F Ver. " INTERFACE_VERSION "</h2>"
+            "<p>© 2007 by Frank Seidel (frank at f-seidel.de)</p>"
+            "<p>This driver 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. </p>";
+    }
+
+    //set ProductId
+    devId = id;
+}
+
+
+CDevice::~CDevice()
+{
+    if ( pScreen )
+        delete[] pScreen;
+}
+
+
+void CDevice::_acquire()
+{
+    int foundProducts = 0;
+    uint16_t myid = 0;
+
+#if defined(WORDS_BIGENDIAN) || !defined(CAN_UNALIGNED)
+    throw exce_t(errSync, "This device has not yet been ported to your platform.");
+#endif
+    PROGR_CALLBACK ( 0,"acquiring" );
+
+    serial = new EHSerial ( port );
+
+    PROGR_CALLBACK ( 1,"acquiring ...");
+
+    serial->open();
+    serial->syncup();
+
+    serial->setBitrate(GARMIN_EH_DFLTBITRATE);
+
+    //ProductID
+    myid = serial->getProductId();
+
+    //Etrex H product string
+    if ( strncmp ( serial->getProductString().c_str(), "eTrex H Software", 16 ) == 0 ) {
+        if ( myid == GARMIN_ETREXH && devId == GARMIN_ETREXH ) {
+            foundProducts++;
+        }
+    }
+    //Etrex Euro product string
+    if ( strncmp ( serial->getProductString().c_str(), "eTrex Euro Software", 19 ) == 0 ) {
+        if ( myid == GARMIN_ETREXEURO && devId == GARMIN_ETREXEURO ) {
+            foundProducts++;
+        }
+    }
+    //check
+    if ( foundProducts != 1 ) {
+        PROGR_CALLBACK ( 100,"error occured" );
+
+        throw exce_t ( errSync,"Error while probing for eTrex H and eTrex Euro unit detected, according to ProductString and Id. Please retry to select other device driver." );
+    }
+}
+
+
+void CDevice::_downloadWaypoints ( list<Garmin::Wpt_t>& waypoints )
+{
+    waypoints.clear();
+    if ( serial == 0 )
+        return;
+
+    PROGR_CALLBACK ( 2,"Downloading waypoints ..." );
+
+    Packet_t command;
+    Packet_t response;
+
+    unsigned int nwpts = 0;
+    unsigned int cnt = 0;
+
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    command.payload[0] = Cmnd_Transfer_Wpt;
+    command.payload[1] = 0x00;
+    serial->write ( command );
+
+    PROGR_CALLBACK ( 5,"Downloading waypoints ..." );
+
+    while ( 1 ) {
+        if ( !serial->read ( response ) ) {
+            cout << "No response from Garmin eTrex H unit. repeating..." << endl;
+            continue;
+        }
+
+        if ( response.id == Pid_Records )
+            nwpts = *(uint16_t*)response.payload;
+
+        if ( response.id == Pid_Wpt_Data ) {
+            D108_Wpt_t * srcWpt = ( D108_Wpt_t* ) response.payload;
+            waypoints.push_back ( Wpt_t() );
+            Wpt_t& tarWpt = waypoints.back();
+
+            tarWpt << *srcWpt;
+
+            ++cnt;
+            if (nwpts)
+                PROGR_CALLBACK ( 5 + ( cnt * 94 / nwpts ),"Downloading waypoints ..." );
+        }
+
+        if ( response.id == Pid_Xfer_Cmplt )
+            break;
+    }
+
+    PROGR_CALLBACK( 100,"Download complete" );
+}
+
+
+void CDevice::_uploadWaypoints ( std::list<Garmin::Wpt_t>& waypoints )
+{
+    if ( serial == 0 )
+        return;
+
+    PROGR_CALLBACK ( 2,"Uploading waypoints ..." );
+
+    list<Wpt_t>::const_iterator wpt = waypoints.begin();
+
+    Packet_t command;
+    Packet_t response;
+
+    unsigned int packcntr = 0;
+    unsigned int npacks = waypoints.size();
+
+    //transmit waypoints
+    //announce number of records
+    command.id   = Pid_Records;
+    command.size = 2;
+    * ( uint16_t* ) command.payload = waypoints.size();
+    serial->write ( command );
+
+    PROGR_CALLBACK ( 5,"Uploading waypoints ..." );
+
+    wpt = waypoints.begin();
+    while ( wpt != waypoints.end() ) {
+        ++packcntr;
+
+        command.id   = Pid_Wpt_Data;
+
+        D108_Wpt_t * p = ( D108_Wpt_t * ) command.payload;
+        command.size = *wpt >> *p;
+
+        serial->write ( command );
+
+        ++wpt;
+
+        if ( npacks )
+            PROGR_CALLBACK ( 5 + (packcntr * 94 / npacks),"Uploading waypoints ..." );
+    }
+
+    //announce number of records
+    command.id   = Pid_Xfer_Cmplt;
+    command.size = 2;
+    command.payload[0] = Cmnd_Transfer_Wpt;
+    command.payload[1] = 0x00;
+    serial->write ( command );
+
+    PROGR_CALLBACK ( 100,"Upload complete" );
+}
+
+
+void CDevice::_downloadTracks ( std::list<Garmin::Track_t>& tracks )
+{
+    tracks.clear();
+    if ( serial == 0 )
+        return;
+
+    PROGR_CALLBACK ( 2,"Downloading tracks ..." );
+
+    serial->setBitrate(GARMIN_EH_HIBITRATE);
+
+    Packet_t command;
+    Packet_t response;
+
+    unsigned int npacks = 0;
+    unsigned int packcntr = 0;
+
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    command.payload[0] = Cmnd_Transfer_Trk;
+    command.payload[1] = 0x00;
+    serial->write ( command );
+
+    PROGR_CALLBACK ( 3,"Downloading tracks ..." );
+
+    int         trackidx = 0;
+    string      name;
+    Track_t *   track = 0;
+
+    while ( 1 ) {
+        if ( !serial->read ( response ) ) {
+            cout << "No response from Garmin eTrex H unit. repeating..." << endl;
+            continue;
+        }
+
+        if ( response.id == Pid_Records )
+            npacks = *(uint16_t*)response.payload;
+
+        if ( response.id == Pid_Trk_Hdr ) {
+            ++packcntr;
+            trackidx = 0;
+            D310_Trk_Hdr_t * hdr = ( D310_Trk_Hdr_t* ) response.payload;
+            tracks.push_back ( Track_t() );
+            track = &tracks.back();
+
+            *track << *hdr;
+            name  = hdr->ident;
+
+        }
+
+        if ( response.id == Pid_Trk_Data ) {
+            ++packcntr;
+            D301_Trk_t * data = ( D301_Trk_t* ) response.payload;
+            TrkPt_t pt;
+            if ( data->new_trk ) {
+                if ( trackidx ) {
+                    tracks.push_back ( Track_t() );
+                    Track_t& t = tracks.back();
+                    t.color = track->color;
+                    t.dspl = track->dspl;
+                    char str[512];
+                    sprintf ( str,"%s_%d",name.c_str(),trackidx++ );
+                    t.ident = str;
+                    track = &t;
+                }
+                else {
+                    ++trackidx;
+                }
+            }
+
+            pt << *data;
+            track->track.push_back ( pt );
+        }
+
+        if ( npacks )
+            PROGR_CALLBACK ( 3 + (packcntr * 96 / npacks),"Downloading tracks ..." );
+
+        if ( response.id == Pid_Xfer_Cmplt )
+            break;
+    }
+
+    serial->setBitrate(GARMIN_EH_DFLTBITRATE);
+
+    PROGR_CALLBACK ( 100,"Download complete" );
+}
+
+
+void CDevice::_uploadRoutes(list<Garmin::Route_t>& routes)
+{
+    if (serial == 0)
+        return;
+
+    int canceled = 0;
+
+    PROGR_CANCEL_CALLBACK ( 0,"Uploading Routes ...",&canceled );
+
+    Packet_t command;
+    Packet_t response;
+
+    list<Garmin::Route_t>::const_iterator route = routes.begin();
+
+    unsigned int nroutes = routes.size();
+    unsigned int ncntr = 0;
+
+    PROGR_CANCEL_CALLBACK ( 1,"Uploading Routes ...",&canceled );
+
+    while(route != routes.end() && !canceled) {
+        ++ncntr;
+
+        //announce number of records
+        uint16_t nrec = route->route.size() * 2;
+        uint16_t recsent = 0;
+        command.id   = Pid_Records;
+        command.size = 2;
+        *(uint16_t*)command.payload = nrec;
+        serial->write(command);
+
+        // write route header
+        command.id   = Pid_Rte_Hdr;
+        D202_Rte_Hdr_t * r = (D202_Rte_Hdr_t *)command.payload;
+        command.size = *route >> *r;
+        serial->write(command);
+        ++recsent;
+
+        vector<RtePt_t>::const_iterator rtept = route->route.begin();
+
+        command.id   = Pid_Rte_Wpt_Data;
+        D108_Wpt_t * p = (D108_Wpt_t *)command.payload;
+        command.size = *rtept >> *p;
+        serial->write(command);
+        ++recsent;
+
+        ++rtept;
+
+        if ( nroutes && nrec )
+            PROGR_CANCEL_CALLBACK ( 2+(ncntr-1)*97/nroutes+(recsent*97)/(nrec*nroutes),
+                "Uploading Routes ...", &canceled );
+
+        while (rtept != route->route.end() && !canceled) {
+            command.id   = Pid_Rte_Link_Data;
+            D210_Rte_Link_t * l = (D210_Rte_Link_t *)command.payload;
+            command.size = *rtept >> *l;
+            serial->write(command);
+            ++recsent;
+
+            command.id   = Pid_Rte_Wpt_Data;
+            D108_Wpt_t * p = (D108_Wpt_t *)command.payload;
+            command.size = *rtept >> *p;
+            serial->write(command);
+            ++recsent;
+
+            ++rtept;
+
+            if ( nroutes && nrec )
+                PROGR_CANCEL_CALLBACK ( 2+(ncntr-1)*97/nroutes+(recsent*97)/(nrec*nroutes),
+                    "Uploading Routes ...",&canceled );
+        }
+
+        // finish block
+        command.id   = Pid_Xfer_Cmplt;
+        command.size = 2;
+        *(uint16_t*)command.payload = Cmnd_Transfer_Rte;
+        serial->write(command);
+        ++route;
+
+        if ( nroutes )
+            PROGR_CALLBACK ( 2 + ncntr * 97 / nroutes,"Uploading routes ..." );
+    }
+
+    PROGR_CANCEL_CALLBACK ( 100,"Uploading routes ...",&canceled );
+}
+
+
+void CDevice::_screenshot ( char *& clrtbl, char *& data, int& width, int& height )
+{
+    if ( serial == 0 )
+        return;
+
+    PROGR_CALLBACK ( 2,"Downloading screenshot ..." );
+
+    Packet_t command;
+    Packet_t response;
+
+    int bperpixel = 0;
+    int pixperpacket = 0;
+    int slines = 0;
+    int swidth = 0;
+    int spackets = 0;
+    long screenbytes = 0;
+    int fetchedpackets = 0;
+    unsigned long rawoffset = 0;
+    char *rawbuffer = NULL;
+
+    memcpy ( aClrtbl,_clrtbl,sizeof ( aClrtbl ) );
+
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    command.payload[0] = CMD_TRANSFER_SCREEN;
+    command.payload[1] = 0x00;
+    serial->write ( command );
+
+    PROGR_CALLBACK ( 3,"Downloading screenshot ..." );
+
+    //collect data from unit
+    while ( serial->read ( response ) ) {
+
+        if ( response.id == PID_SCREENDATA ) {
+            if ( response.payload[0] == 0 ) {
+                //get meta-data with payload size 40
+                bperpixel = response.payload[12];
+                slines = response.payload[20];
+                swidth = response.payload[16];
+                pixperpacket = response.payload[8];
+                screenbytes = ( bperpixel * swidth * slines ) / 8L;
+                spackets = ( swidth * slines ) / ( pixperpacket * ( 8 / bperpixel ) );
+
+                rawbuffer = new char[screenbytes];
+                if ( rawbuffer == NULL ) {
+                    PROGR_CALLBACK ( 100,"error occured" );
+                    throw exce_t ( errSync,"Could not allocate memory for raw display data from unit." );
+                    return;
+                }
+
+                PROGR_CALLBACK ( 5,"Downloading screenshot ..." );
+            }
+            else {
+                //get image-data
+                ++fetchedpackets;
+
+                rawoffset = response.payload[4] + ( response.payload[5] << 8 )
+                    + ( response.payload[6] << 16 ) + ( response.payload[7] << 24 );
+
+                memcpy ( rawbuffer + rawoffset, response.payload + 8, pixperpacket );
+
+                PROGR_CALLBACK ( 5 + (fetchedpackets * 85 / spackets),"Downloading screenshot ..." );
+
+                if ( fetchedpackets == spackets )
+                    break;
+            }
+        }
+    }
+
+    if ( pScreen )
+        delete[] pScreen;
+    pScreen = new char[swidth * slines];
+
+    //reorder and extract pixel data
+    unsigned long mask = 0x03L;
+    char pcolor = 0;
+    int pX = 63;
+    int pY = 127;
+
+    for ( int bnum=0; bnum < screenbytes; bnum += ( pixperpacket / 8 ) ) {
+        unsigned long curdat = * ( ( unsigned long* ) ( rawbuffer + bnum ) );
+
+        for ( int bitshift = 0; bitshift < pixperpacket; bitshift += bperpixel ) {
+            pcolor = ( ( curdat & mask ) >> bitshift ) & 3;
+
+            pScreen[pX + ( pY * slines ) ] = pcolor;
+
+            --pY;
+            if ( pY < 0 ) {
+                --pX;
+                pY = 127;
+
+                PROGR_CALLBACK ( 90 + ((63 - pX) * 9 / 63),"Processing data ..." );
+            }
+
+            mask <<= 2;
+        }
+
+        mask = 0x03L;
+    }
+
+    clrtbl  = aClrtbl;
+    data    = pScreen;
+    width   = slines;
+    height  = swidth;
+
+    if ( rawbuffer )
+        delete[] rawbuffer;
+
+    PROGR_CALLBACK ( 100,"Completed screenshot" );
+}
+
+
+void CDevice::_release()
+{
+    if ( serial == 0 )
+        return;
+
+    serial->close();
+    delete serial;
+    serial = 0;
+}
diff --git a/src/EtrexH/CDevice.h b/src/EtrexH/CDevice.h
new file mode 100644
index 0000000..7a3da35
--- /dev/null
+++ b/src/EtrexH/CDevice.h
@@ -0,0 +1,58 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Frank Seidel <frank at f-seidel.de>
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef CDEVICE_H
+#define CDEVICE_H
+
+#include "EHSerial.h"
+#include "IDeviceDefault.h"
+
+#define GARMIN_ETREXH 696
+#define GARMIN_ETREXEURO 156
+
+namespace EtrexH
+{
+    class CDevice : public Garmin::IDeviceDefault
+    {
+        public:
+            CDevice(uint16_t id);
+            virtual ~CDevice();
+
+        private:
+            void _acquire();
+            void _downloadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            void _uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            void _downloadTracks(std::list<Garmin::Track_t>& tracks);
+            void _uploadRoutes(std::list<Garmin::Route_t>& routes);
+            void _screenshot(char *& clrtbl, char *& data, int& width, int& height);
+            void _release();
+
+            Garmin::EHSerial *serial;
+
+            char aClrtbl[0x100 * 4];
+            char *pScreen;
+
+            //extension for multimodels (first Etrex Euro)
+            uint16_t devId;
+    };
+
+}
+#endif                           //CDEVICE_H
diff --git a/src/EtrexH/CMakeLists.txt b/src/EtrexH/CMakeLists.txt
new file mode 100644
index 0000000..2b8dcd5
--- /dev/null
+++ b/src/EtrexH/CMakeLists.txt
@@ -0,0 +1,31 @@
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+set(SRCS
+    loader.cpp
+    CDevice.cpp
+    EHSerial.cpp
+)
+
+set(HDRS
+    CDevice.h
+    EHSerial.h
+)
+
+include_directories(../)
+add_library(EtrexH SHARED ${SRCS} ${HDRS})
+target_link_libraries(EtrexH garmin usb pthread)
+
+set(ALIASES
+    EtrexEuro
+)
+
+foreach(var ${ALIASES})
+    message(" ${var}")
+    add_custom_command( TARGET EtrexH
+                        POST_BUILD
+                        COMMAND ln ARGS -sf libEtrexH.so lib${var}.so
+                        WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH}
+                        )
+endforeach(var)
+
diff --git a/src/EtrexH/EHSerial.cpp b/src/EtrexH/EHSerial.cpp
new file mode 100644
index 0000000..d8b5db7
--- /dev/null
+++ b/src/EtrexH/EHSerial.cpp
@@ -0,0 +1,72 @@
+/**********************************************************************************************
+    Copyright (C) 2008 Frank Seidel <fseidel at suse.de>
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "EHSerial.h"
+
+using namespace Garmin;
+using namespace std;
+
+EHSerial::EHSerial(const std::string& port)
+: CSerial(port)
+{
+
+}
+
+
+EHSerial::~EHSerial()
+{
+    EHSerial::close();
+}
+
+
+void EHSerial::syncup()
+{
+    Packet_t command;
+    Packet_t response;
+    static int last_response = 2;//only right for current etrex h
+    int counter = 0;
+
+    command.type = 0;
+    command.id   = Pid_Product_Rqst;
+    command.size = 0;
+
+    EHSerial::write(command);
+
+    while(EHSerial::read(response)) {
+        if(response.id == Pid_Product_Data) {
+            Product_Data_t * pData = (Product_Data_t*)response.payload;
+            productId       = pData->product_id;
+            softwareVersion = pData->software_version;
+            productString   = pData->str;
+        }
+
+        if(response.id == Pid_Protocol_Array) {
+            Protocol_Data_t * pData = (Protocol_Data_t*)response.payload;
+            for(uint32_t i = 0; i < response.size; i += sizeof(Protocol_Data_t)) {
+                ++pData;
+            }
+        }
+
+        ++counter;
+        if (last_response && counter == last_response)
+            break;
+    }
+}
diff --git a/src/EtrexH/EHSerial.h b/src/EtrexH/EHSerial.h
new file mode 100644
index 0000000..9f0cf5b
--- /dev/null
+++ b/src/EtrexH/EHSerial.h
@@ -0,0 +1,44 @@
+/**********************************************************************************************
+    Copyright (C) 2008 Frank Seidel <fseidel at suse.de>
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "CSerial.h"
+
+#include <string>
+#include <ILink.h>
+#include "Garmin.h"
+
+#ifndef EHSERIAL_H
+#define EHSERIAL_H
+
+namespace Garmin
+{
+    class EHSerial : public CSerial
+    {
+        public:
+            EHSerial(const std::string& port);
+            ~EHSerial();
+
+            void syncup(void);
+
+    };
+
+}
+#endif                           //EHSERIAL_H
diff --git a/src/EtrexH/loader.cpp b/src/EtrexH/loader.cpp
new file mode 100644
index 0000000..074c0df
--- /dev/null
+++ b/src/EtrexH/loader.cpp
@@ -0,0 +1,68 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Frank Seidel <frank at f-seidel.de>
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "config.h"
+#include "CDevice.h"
+
+namespace EtrexH
+{
+    static CDevice * device = 0;
+}
+
+
+#ifdef WIN32
+#define WIN_EXPORT __declspec(dllexport)
+#else
+#define WIN_EXPORT
+#endif
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexH(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(EtrexH::device == 0) {
+        EtrexH::device = new EtrexH::CDevice(GARMIN_ETREXH);
+    }
+    else {
+        delete EtrexH::device;
+        EtrexH::device = new EtrexH::CDevice(GARMIN_ETREXH);
+    }
+
+    return EtrexH::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexEuro(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(EtrexH::device == 0) {
+        EtrexH::device = new EtrexH::CDevice(GARMIN_ETREXEURO);
+    }
+    else {
+        delete EtrexH::device;
+        EtrexH::device = new EtrexH::CDevice(GARMIN_ETREXEURO);
+    }
+
+    return EtrexH::device;
+}
diff --git a/src/EtrexLegend/CDevice.cpp b/src/EtrexLegend/CDevice.cpp
new file mode 100644
index 0000000..c90a36f
--- /dev/null
+++ b/src/EtrexLegend/CDevice.cpp
@@ -0,0 +1,791 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "../Platform.h"
+#include "CDevice.h"
+#include <Garmin.h>
+
+#include <cstdio>
+#include <iostream>
+#include <sstream>
+
+using namespace EtrexLegend;
+using namespace Garmin;
+using namespace std;
+
+#define GRMN_ETREX_LEGEND  411
+
+#define MAP_UPLOAD_BITRATE 115200// or 57600, 38400, 19200, 9600
+
+#define WAYPOINT_DL_BITRATE 57600
+#define TRACK_DL_BITRATE 57600
+#define GRMN_DEFAULT_BITRATE 9600
+
+#define PROGR_CALLBACK(state,message) \
+callback ( state,0,0,0,message )
+
+#define PROGR_CANCEL_CALLBACK(state,message,cancel) \
+callback ( state,0,cancel,0,message )
+
+CDevice::CDevice()
+: serial(0)
+{
+    supportsMaps = true;
+}
+
+
+CDevice::~CDevice()
+{
+
+}
+
+
+const string& CDevice::getCopyright()
+{
+    copyright = "<h1>QLandkarte Device Driver for EtrexLegend (EXPERIMENTAL)</h1>"
+        "<h2>Driver I/F Ver. " INTERFACE_VERSION "</h2>"
+        "<p>© 2007 by Oliver Eichler (oliver.eichler at gmx.de)</p>"
+        "<p>modified 2007 by Andreas Stenglein to work with serial eTrex Legend</p>"
+        "<p>This driver 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. </p>";
+    return copyright;
+}
+
+
+void CDevice::_acquire()
+{
+#if defined(WORDS_BIGENDIAN) || !defined(CAN_UNALIGNED)
+    throw exce_t(errSync, "This device has not yet been ported to your platform.");
+#endif
+    PROGR_CALLBACK ( 0,"acquiring" );
+
+    serial = new CSerial(port);
+
+    PROGR_CALLBACK ( 1,"acquiring ...");
+
+    serial->open();
+    serial->syncup();
+
+    if(strncmp(serial->getProductString().c_str(), devname.c_str(), devname.size()) != 0) {
+        string msg = "No " + devname + " unit detected. Please retry to select other device driver.";
+        throw exce_t(errSync,msg);
+    }
+
+    if(devid) {
+        if(serial->getProductId() != devid) {
+            string msg = "No " + devname + " unit detected. Please retry to select other device driver.";
+            throw exce_t(errSync,msg);
+        }
+    }
+    else {
+        string msg = "No " + devname + " unit detected. Please retry to select other device driver.";
+        throw exce_t(errSync,msg);
+    }
+
+}
+
+
+void CDevice::_uploadMap(const uint8_t * mapdata, uint32_t size, const char * key)
+{
+    if(supportsMaps == false) {
+        IDeviceDefault::_uploadMap(mapdata, size, key);
+        return;
+    }
+    if(serial == 0) return;
+    int ready= 0;
+    int cancel = 0;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+    // read SD Ram capacity
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    serial->write(command);
+
+                                 // FIXME:
+    while(serial->read(response) > 0) {
+
+        if(response.id == Pid_Capacity_Data) {
+            cout << "free memory: " << dec << (((uint32_t*)response.payload)[1] / (1024*1024)) << " MB" << endl;
+            uint32_t memory = ((uint32_t*)response.payload)[1];
+            if(memory < size) {
+                stringstream msg;
+                msg << "Failed to send map: Unit has not enought memory (available/needed): " << memory << "/" << size << " bytes";
+                throw exce_t(errBlocked,msg.str());
+            }
+        }
+    }
+
+#ifdef EXPERIMENTAL
+    // KEY_UPLOAD: UNTESTED: someone should check how/if this works
+    // send unlock key if present
+    if(key) {
+        command.id   = Pid_Tx_Unlock_Key;
+        command.size = strlen(key) + 1;
+        memcpy(command.payload,key,command.size);
+
+        serial->write(command);
+
+                                 // FIXME:
+        while(serial->read(response) > 0 ) {
+            if(response.id == Pid_Ack_Unlock_key) {
+                //TODO read data
+            }
+        }
+
+    }
+#endif
+
+    if (serial->setBitrate( MAP_UPLOAD_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+
+    // switch to map transfer mode erase old map(?)
+    command.id   = 75;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    serial->write(command);
+
+    ready= 0;
+    serial->readTimeout( 5000);
+    while(!ready && serial->read(response) > 0) {
+        if(response.id == 74) {
+            ready= 1;
+            //TODO read data
+        }
+    }
+    serial->readTimeout( 1000);
+
+    callback(0,0,&cancel,"Upload maps ...",0);
+
+    uint32_t total  = size;
+    uint32_t offset = 0, chunkSize;
+    command.id   = 36;
+    // USB:    transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes
+    // Serial: transfer file by chunks of 0xfe - sizeof(offset) =  0xfa = 250 bytes
+    while(size && !cancel) {
+        chunkSize       = (size < (254 - sizeof(offset))) ? size : (254 - sizeof(offset));
+        command.size    = chunkSize + sizeof(offset);
+
+        *(uint32_t*)command.payload = offset;
+        memcpy(command.payload + sizeof(offset),mapdata,chunkSize);
+        size    -= chunkSize;
+        mapdata += chunkSize;
+        offset  += chunkSize;
+
+        serial->write(command);
+        // set progress
+        double progress = ((total - size) * 100.0) / total;
+        callback(progress,0,&cancel,0,"Transfering map data.");
+
+    }
+
+    callback(100,0,&cancel,0,"done");
+
+    // terminate map transfer mode (?)
+    command.id   = 45;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    serial->write(command);
+}
+
+
+void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key)
+{
+    if(supportsMaps == false) {
+        IDeviceDefault::_uploadMap( filename, size, key);
+        return;
+    }
+    if(serial == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+    int cancel = 0;
+    int ready= 0;
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+    // read SD Ram capacity
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    serial->write(command);
+
+    while(serial->read(response) > 0) {
+        if(response.id == Pid_Capacity_Data) {
+            cout << "free memory: " << dec << (((uint32_t*)response.payload)[1] / (1024*1024)) << " MB" << endl;
+            uint32_t memory = ((uint32_t*)response.payload)[1];
+            if(memory < size) {
+                stringstream msg;
+                msg << "Failed to send map: Unit has not enought memory (available/needed): " << memory << "/" << size << " bytes";
+                throw exce_t(errRuntime,msg.str());
+            }
+        }
+    }
+
+#ifdef EXPERIMENTAL
+    // KEY_UPLOAD: UNTESTED: someone should check how/if this works
+    // send unlock key if present
+    if(key) {
+        command.id   = Pid_Tx_Unlock_Key;
+        command.size = strlen(key) + 1;
+        memcpy(command.payload,key,command.size);
+
+        serial->write(command);
+
+        while(serial->read(response) > 0) {
+            if(response.id == Pid_Ack_Unlock_key) {
+                //TODO read data
+            }
+        }
+
+    }
+#endif
+
+    if (serial->setBitrate( MAP_UPLOAD_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+
+    // switch to map transfer mode erase old map(?)
+    command.id   = 75;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    serial->write(command);
+
+    ready= 0;
+    serial->readTimeout( 5000);
+    while(!ready && serial->read(response) > 0) {
+        if(response.id == 74) {
+            ready = 1;
+            //TODO read data
+        }
+    }
+    serial->readTimeout( 1000);
+
+    callback(0,0,&cancel,"Upload maps ...",0);
+
+    FILE *fid = fopen(filename,"r");
+    if(fid == NULL) {
+        stringstream msg;
+        msg << "Failed to send map: Can't open  " << filename;
+        throw exce_t(errRuntime,msg.str());
+    }
+
+    uint32_t total  = size;
+    uint32_t offset = 0, chunkSize;
+    uint8_t  buffer[GUSB_PAYLOAD_SIZE - sizeof(offset)];
+
+    command.id   = 36;
+    // USB:    transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes
+    // Serial: transfer file by chunks of 0xfe - sizeof(offset) =  0xfa = 250 bytes
+    while(size && !cancel) {
+        chunkSize       = (size < (254 - sizeof(offset))) ? size : (254 - sizeof(offset));
+        command.size    = chunkSize + sizeof(offset);
+
+        fread(buffer, chunkSize, 1, fid);
+
+        *(uint32_t*)command.payload = offset;
+        memcpy(command.payload + sizeof(offset),buffer,chunkSize);
+        size    -= chunkSize;
+        offset  += chunkSize;
+
+        serial->write(command);
+
+        double progress = ((total - size) * 100.0) / total;
+        callback(progress,0,&cancel,0,"Transfering map data.");
+    }
+
+    callback(100,0,&cancel,0,"done");
+
+    // terminate map transfer mode (?)
+    command.id   = 45;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    serial->write(command);
+}
+
+
+void CDevice::_queryMap(std::list<Map_t>& maps)
+{
+    maps.clear();
+    if(supportsMaps == false) {
+        IDeviceDefault::_queryMap(maps);
+        return;
+    }
+    if(serial == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+    // Request map overview table
+    command.id   = 0x59;
+    command.size = 19;
+    Map_Request_t * req = (Map_Request_t*)command.payload;
+    req->dummy1 = 0;
+    req->dummy2 = 10;
+    strcpy(req->section,"MAPSOURC.MPS");
+    serial->write(command);
+
+    uint32_t size   = 1024;
+    uint32_t fill   = 0;
+    char * pData    = (char*)calloc(1,size);
+
+    while(serial->read(response)) {
+        // acknowledge request (???)
+        if(response.id == 0x5B) {
+            //TODO: read data
+        }
+
+        // chunk of MAPSOURC.MPS section
+        // Each chunk is prepended by a chunk counter of type uint8_t.
+        // This has to be skipped. That's why the peculiar math.
+        if(response.id == 0x5A) {
+            // realloc memory if chunk does not fit
+            if((fill +  response.size - 1) > size) {
+                size += size;
+                pData = (char*)realloc(pData,size);
+            }
+
+            memcpy(&pData[fill], response.payload + 1, response.size - 1);
+
+            fill += response.size - 1;
+        }
+    }
+
+    Map_Info_t * pInfo = (Map_Info_t*)pData;
+    while(pInfo->tok == 0x4C) {
+        Map_t m;
+        char * pStr = pInfo->name1;
+        m.mapName = pStr;
+        pStr += strlen(pStr) + 1;
+        m.tileName = pStr;
+
+        maps.push_back(m);
+
+        pInfo =  (Map_Info_t*)(((char*)pInfo) + pInfo->size + sizeof(pInfo->tok) + sizeof(pInfo->size));
+    }
+
+    free(pData);
+}
+
+
+void CDevice::_downloadWaypoints(list<Garmin::Wpt_t>& waypoints)
+{
+    waypoints.clear();
+    if(serial == 0) return;
+
+    PROGR_CALLBACK ( 2,"Downloading waypoints ..." );
+
+    Packet_t command;
+    Packet_t response;
+
+    unsigned int nwpts = 0;
+    unsigned int cnt = 0;
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( WAYPOINT_DL_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+#endif
+    // request waypoints
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Wpt;
+    serial->write(command);
+
+    PROGR_CALLBACK ( 5,"Downloading waypoints ..." );
+
+    while(1) {
+        if(!serial->read(response)) continue;
+
+        if(response.id == Pid_Records) {
+            nwpts = *(uint16_t*)response.payload;
+#ifdef DBG_SHOW_WAYPOINT
+            cout << "number of waypoints:" << *(int16_t*)response.payload << endl;
+#endif
+        }
+
+        if(response.id == Pid_Wpt_Data) {
+            D108_Wpt_t * srcWpt = (D108_Wpt_t*)response.payload;
+            waypoints.push_back(Wpt_t());
+            Wpt_t& tarWpt = waypoints.back();
+
+            tarWpt << *srcWpt;
+
+            ++cnt;
+            if (nwpts)
+                PROGR_CALLBACK ( 5 + ( cnt * 94 / nwpts ),"Downloading waypoints ..." );
+        }
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+
+    }
+
+#if 0
+    // etrex Legend doesn't have a beeper
+    // unsupported by etrex Legend ?
+    // request proximity waypoints
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Prx;
+    serial->write(command);
+
+    while(1) {
+
+        if(!serial->read(response)) continue;
+
+        if(response.id == Pid_Records) {
+            //TODO read data
+#ifdef DBG_SHOW_WAYPOINT
+            cout << "number of proximity waypoints:" << *(int16_t*)response.payload << endl;
+#endif
+        }
+
+        if(response.id == Pid_Prx_Wpt_Data) {
+            D108_Wpt_t * srcWpt = (D108_Wpt_t*)response.payload;
+            waypoints.push_back(Wpt_t());
+            Wpt_t& tarWpt = waypoints.back();
+
+            tarWpt << *srcWpt;
+        }
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+
+    }
+#endif
+
+#ifdef DBG_SHOW_WAYPOINT
+    list<Wpt_t>::const_iterator wpt = waypoints.begin();
+    while(wpt != waypoints.end()) {
+        cout << "-------------------------" << endl;
+        cout << "class      " << hex << (int)wpt->wpt_class << endl;
+        cout << "dspl_color " << hex << (int)wpt->dspl_color << endl;
+        cout << "dspl_attr  " << hex << (int)wpt->dspl_attr << endl;
+        cout << "smbl       " << dec <<(int)wpt->smbl << endl;
+        cout << "lat        " << wpt->lat << endl;
+        cout << "lon        " << wpt->lon << endl;
+        cout << "alt        " << wpt->alt << endl;
+        cout << "dpth       " << wpt->dpth << endl;
+        cout << "dist       " << wpt->dist << endl;
+        cout << "state      " << wpt->state << endl;
+        cout << "cc         " << wpt->cc << endl;
+        cout << "ete        " << wpt->ete << endl;
+        cout << "temp       " << wpt->temp << endl;
+        cout << "time       " << wpt->time << endl;
+        cout << "category   " << wpt->wpt_cat << endl;
+        cout << "ident      " << wpt->ident << endl;
+        cout << "comment    " << wpt->comment << endl;
+        cout << "facility   " << wpt->facility << endl;
+        cout << "city       " << wpt->city << endl;
+        cout << "addr       " << wpt->addr << endl;
+        cout << "crossroad  " << wpt->crossroad << endl;
+
+        ++wpt;
+    }
+#endif
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( GRMN_DEFAULT_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+#endif
+    PROGR_CALLBACK( 100,"Download complete" );
+}
+
+
+void CDevice::_uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints)
+{
+    if(serial == 0) return;
+
+    PROGR_CALLBACK ( 2,"Uploading waypoints ..." );
+
+    //     uint16_t prx_wpt_cnt = 0;
+    list<Wpt_t>::const_iterator wpt = waypoints.begin();
+
+    // does etrex Legend support prx waypoints?
+    while(wpt != waypoints.end()) {
+#if 0
+        if(wpt->dist != 1e25f) ++prx_wpt_cnt;
+#endif
+        ++wpt;
+    }
+
+    Packet_t command;
+    Packet_t response;
+
+    unsigned int packcntr = 0;
+    unsigned int npacks = waypoints.size();
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( WAYPOINT_DL_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+#endif
+#if 0
+    // transmit proximity waypoints first
+    if(prx_wpt_cnt) {
+        //announce number of records
+        command.id   = Pid_Records;
+        command.size = 2;
+        *(uint16_t*)command.payload = prx_wpt_cnt;
+        serial->write(command);
+
+        wpt = waypoints.begin();
+        while(wpt != waypoints.end()) {
+            if(wpt->dist != 1e25f) {
+                command.id   = Pid_Prx_Wpt_Data;
+
+                D108_Wpt_t * p = (D108_Wpt_t *)command.payload;
+                command.size = *wpt >> *p;
+
+                serial->write(command);
+
+            }
+            ++wpt;
+        }
+
+        //announce number of records
+        command.id   = Pid_Xfer_Cmplt;
+        command.size = 2;
+        *(uint16_t*)command.payload = Cmnd_Transfer_Prx;
+        serial->write(command);
+
+    }
+#endif
+
+    //transmit _all_ waypoints
+    //announce number of records
+    command.id   = Pid_Records;
+    command.size = 2;
+    *(uint16_t*)command.payload = waypoints.size();
+    serial->write(command);
+
+    PROGR_CALLBACK ( 5,"Uploading waypoints ..." );
+
+    wpt = waypoints.begin();
+    while(wpt != waypoints.end()) {
+        ++packcntr;
+
+        command.id   = Pid_Wpt_Data;
+
+        D108_Wpt_t * p = (D108_Wpt_t *)command.payload;
+        command.size = *wpt >> *p;
+
+        serial->write(command);
+
+        ++wpt;
+
+        if ( npacks )
+            PROGR_CALLBACK ( 5 + (packcntr * 94 / npacks),"Uploading waypoints ..." );
+    }
+
+    //announce number of records
+    command.id   = Pid_Xfer_Cmplt;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Wpt;
+    serial->write(command);
+
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( GRMN_DEFAULT_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+#endif
+    PROGR_CALLBACK ( 100,"Upload complete" );
+}
+
+
+void CDevice::_downloadTracks(std::list<Garmin::Track_t>& tracks)
+{
+    tracks.clear();
+    if(serial == 0) return;
+
+    PROGR_CALLBACK ( 2,"Downloading tracks ..." );
+
+    Packet_t command;
+    Packet_t response;
+
+    unsigned int npacks = 0;
+    unsigned int packcntr = 0;
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( TRACK_DL_BITRATE)) {
+        throw exce_t(errBlocked, "Failed to change serial link to xxx bit per second");
+    }
+#endif
+
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Trk;
+    serial->write(command);
+
+    PROGR_CALLBACK ( 3,"Downloading tracks ..." );
+
+    int         trackidx = 0;
+    string      name;
+    Track_t *   track = 0;
+    while(1) {
+
+        if(!serial->read(response)) continue;
+
+        if ( response.id == Pid_Records )
+            npacks = *(uint16_t*)response.payload;
+
+        if(response.id == Pid_Trk_Hdr) {
+            ++packcntr;
+            trackidx = 0;
+            D310_Trk_Hdr_t * hdr = (D310_Trk_Hdr_t*)response.payload;
+            tracks.push_back(Track_t());
+            track = &tracks.back();
+
+            *track << *hdr;
+            name  = hdr->ident;
+
+        }
+
+        if(response.id == Pid_Trk_Data) {
+            ++packcntr;
+            D301_Trk_t * data = (D301_Trk_t*)response.payload;
+            TrkPt_t pt;
+            if(data->new_trk) {
+                if(trackidx) {
+                    tracks.push_back(Track_t());
+                    Track_t& t = tracks.back();
+                    t.color = track->color;
+                    t.dspl = track->dspl;
+                    char str[256];
+                    sprintf(str,"%s_%d",name.c_str(),trackidx++);
+                    t.ident = str;
+                    track = &t;
+                }
+                else {
+                    ++trackidx;
+                }
+            }
+
+            pt << *data;
+            track->track.push_back(pt);
+        }
+
+        if ( npacks )
+            PROGR_CALLBACK ( 3 + (packcntr * 96 / npacks),"Downloading tracks ..." );
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+    }
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( GRMN_DEFAULT_BITRATE)) {
+        throw exce_t(errBlocked, "Failed to change serial link to xxx bit per second");
+    }
+#endif
+    PROGR_CALLBACK ( 100,"Download complete" );
+}
+
+
+void CDevice::_release()
+{
+    if(serial == 0) return;
+
+    serial->close();
+    delete serial;
+    serial = 0;
+}
+
+
+// just copied from GPSMAP60CSX driver, 20081006
+void CDevice::_getDevProperties(Garmin::DevProperties_t& dev_properties)
+{
+    if(serial == 0) return;
+    Packet_t command;
+    Packet_t response;
+
+    // ask for SD Ram capacity
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    serial->write(command);
+
+    // try to read SD Ram capacity
+    uint32_t memory = 0;
+    uint16_t tile_limit = 0;
+    while(serial->read(response)) {
+        if(response.id == Pid_Capacity_Data) {
+            tile_limit = ((uint16_t*)response.payload)[1];
+            memory = ((uint32_t*)response.payload)[1];
+        }
+    }
+    if(tile_limit == 0) {
+        throw exce_t(errRuntime,"Failed to send map: Unable to find the tile limit of the GPS");
+    }
+    if(memory == 0) {
+        throw exce_t(errRuntime,"Failed to send map: Unable to find the available memory of the GPS");
+    }
+
+    // add to the properties list
+    properties.memory_limit = memory;
+    properties.set.item.memory_limit = 1;
+    properties.maps_limit = tile_limit;
+    properties.set.item.maps_limit = 1;
+
+    // return the properties
+    dev_properties = properties;
+}
diff --git a/src/EtrexLegend/CDevice.h b/src/EtrexLegend/CDevice.h
new file mode 100644
index 0000000..9b36caf
--- /dev/null
+++ b/src/EtrexLegend/CDevice.h
@@ -0,0 +1,60 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef CDEVICE_H
+#define CDEVICE_H
+
+#include "IDeviceDefault.h"
+#include "CSerial.h"
+
+namespace EtrexLegend
+{
+
+    class CDevice : public Garmin::IDeviceDefault
+    {
+        public:
+            CDevice();
+            virtual ~CDevice();
+
+            std::string devname;
+            uint32_t devid;
+            bool supportsMaps;   // Does this device support map upload/download
+
+            const std::string& getCopyright();
+
+        private:
+            void _acquire();
+            void _uploadMap(const uint8_t * mapdata, uint32_t size, const char * key);
+            void _uploadMap(const char * filename, uint32_t size, const char * key);
+            void _queryMap(std::list<Garmin::Map_t>& maps);
+            void _downloadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            void _uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            void _downloadTracks(std::list<Garmin::Track_t>& tracks);
+
+            void _getDevProperties(Garmin::DevProperties_t& dev_properties);
+
+            void _release();
+
+            Garmin::CSerial * serial;
+    };
+
+}
+#endif                           //CDEVICE_H
diff --git a/src/EtrexLegend/CMakeLists.txt b/src/EtrexLegend/CMakeLists.txt
new file mode 100644
index 0000000..e3aff9c
--- /dev/null
+++ b/src/EtrexLegend/CMakeLists.txt
@@ -0,0 +1,31 @@
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+set(SRCS
+    loader.cpp
+    CDevice.cpp
+)
+
+set(HDRS
+    CDevice.h
+)
+
+include_directories(../ ${USB_INCLUDE_DIRS})
+add_library(EtrexLegend SHARED ${SRCS} ${HDRS})
+target_link_libraries(EtrexLegend garmin ${USB_LIBRARIES} pthread)
+
+set(ALIASES
+    EtrexVista
+    EtrexClassic
+)
+
+
+foreach(var ${ALIASES})
+    message(" ${var}")
+    add_custom_command( TARGET EtrexLegend
+                        POST_BUILD
+                        COMMAND ln ARGS -sf libEtrexLegend.so lib${var}.so
+                        WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH}
+                        )
+endforeach(var)
+
diff --git a/src/EtrexLegend/loader.cpp b/src/EtrexLegend/loader.cpp
new file mode 100644
index 0000000..bd909a4
--- /dev/null
+++ b/src/EtrexLegend/loader.cpp
@@ -0,0 +1,83 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "config.h"
+#include "CDevice.h"
+
+namespace EtrexLegend
+{
+    static CDevice * device = 0;
+}
+
+
+#ifdef WIN32
+#define WIN_EXPORT __declspec(dllexport)
+#else
+#define WIN_EXPORT
+#endif
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexLegend(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(EtrexLegend::device == 0) {
+        EtrexLegend::device = new EtrexLegend::CDevice();
+    }
+    EtrexLegend::device->devname = "eTrex Legend";
+    EtrexLegend::device->devid = 411;
+    return EtrexLegend::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexVista(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(EtrexLegend::device == 0) {
+        EtrexLegend::device = new EtrexLegend::CDevice();
+    }
+    EtrexLegend::device->devname = "eTrex Vista";
+    EtrexLegend::device->devid = 169;
+    return EtrexLegend::device;
+}
+
+
+// I went back-and-forth on where to put the eTrex Classic
+// (https://buy.garmin.com/shop/shop.do?cID=167&pID=6403).  Visually,
+// and feature capabilities, it is probably close to the eTrex H.  However,
+// the eTrex Classic is of the same vintage as the eTrex Legend and eTrex Vista.
+// So, as far as firmware (and serial communications go), it is closer to those.
+// Therefore, I put it here.
+extern "C" WIN_EXPORT Garmin::IDevice * const initEtrexClassic(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(EtrexLegend::device == 0) {
+        EtrexLegend::device = new EtrexLegend::CDevice();
+    }
+    EtrexLegend::device->devname = "eTrex";
+    EtrexLegend::device->devid = 130;
+    EtrexLegend::device->supportsMaps = false;
+    return EtrexLegend::device;
+}
diff --git a/src/EtrexLegendC/CDevice.cpp b/src/EtrexLegendC/CDevice.cpp
new file mode 100644
index 0000000..abcc4c5
--- /dev/null
+++ b/src/EtrexLegendC/CDevice.cpp
@@ -0,0 +1,1076 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+                       bzrudi (bzrudi at users.sourceforge.net)
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "../Platform.h"
+#include "CDevice.h"
+#include <Garmin.h>
+
+#include <cstdio>
+#include <errno.h>
+#include <iostream>
+#include <sstream>
+#include <stdio.h>
+
+using namespace EtrexLegendC;
+using namespace Garmin;
+using namespace std;
+
+namespace EtrexLegendC
+{
+
+    static const char _clrtbl[1024]= {
+        0,0,0,0,32,0,0,0,65,0,0,0,106,0,0,0,-117,0,0,0,
+        -76,0,0,0,-43,0,0,0,-1,0,0,0,0,48,0,0,32,48,0,0,
+        65,48,0,0,106,48,0,0,-117,48,0,0,-76,48,0,0,-43,48,0,0,
+        -1,48,0,0,0,101,0,0,32,101,0,0,65,101,0,0,106,101,0,0,
+        -117,101,0,0,-76,101,0,0,-43,101,0,0,-1,101,0,0,0,-107,0,0,
+        32,-107,0,0,65,-107,0,0,106,-107,0,0,-117,-107,0,0,-76,-107,0,0,
+        -43,-107,0,0,-1,-107,0,0,0,-54,0,0,32,-54,0,0,65,-54,0,0,
+        106,-54,0,0,-117,-54,0,0,-76,-54,0,0,-43,-54,0,0,-1,-54,0,0,
+        0,-1,0,0,32,-1,0,0,65,-1,0,0,106,-1,0,0,-117,-1,0,0,
+        -76,-1,0,0,-43,-1,0,0,-1,-1,0,0,0,0,57,0,32,0,57,0,
+        65,0,57,0,106,0,57,0,-117,0,57,0,-76,0,57,0,-43,0,57,0,
+        -1,0,57,0,0,48,57,0,32,48,57,0,65,48,57,0,106,48,57,0,
+        -117,48,57,0,-76,48,57,0,-43,48,57,0,-1,48,57,0,0,101,57,0,
+        32,101,57,0,65,101,57,0,106,101,57,0,-117,101,57,0,-76,101,57,0,
+        -43,101,57,0,-1,101,57,0,0,-107,57,0,32,-107,57,0,65,-107,57,0,
+        106,-107,57,0,-117,-107,57,0,-76,-107,57,0,-43,-107,57,0,-1,-107,57,0,
+        0,-54,57,0,32,-54,57,0,65,-54,57,0,106,-54,57,0,-117,-54,57,0,
+        -76,-54,57,0,-43,-54,57,0,-1,-54,57,0,0,-1,57,0,32,-1,57,0,
+        65,-1,57,0,106,-1,57,0,-117,-1,57,0,-76,-1,57,0,-43,-1,57,0,
+        -1,-1,57,0,0,0,123,0,32,0,123,0,65,0,123,0,106,0,123,0,
+        -117,0,123,0,-76,0,123,0,-43,0,123,0,-1,0,123,0,0,48,123,0,
+        32,48,123,0,65,48,123,0,106,48,123,0,-117,48,123,0,-76,48,123,0,
+        -43,48,123,0,-1,48,123,0,0,101,123,0,32,101,123,0,65,101,123,0,
+        106,101,123,0,-117,101,123,0,-76,101,123,0,-43,101,123,0,-1,101,123,0,
+        0,-107,123,0,32,-107,123,0,65,-107,123,0,106,-107,123,0,-117,-107,123,0,
+        -76,-107,123,0,-43,-107,123,0,-1,-107,123,0,0,-54,123,0,32,-54,123,0,
+        65,-54,123,0,106,-54,123,0,-117,-54,123,0,-76,-54,123,0,-43,-54,123,0,
+        -1,-54,123,0,0,-1,123,0,32,-1,123,0,65,-1,123,0,106,-1,123,0,
+        -117,-1,123,0,-76,-1,123,0,-43,-1,123,0,-1,-1,123,0,0,0,-67,0,
+        32,0,-67,0,65,0,-67,0,106,0,-67,0,-117,0,-67,0,-76,0,-67,0,
+        -43,0,-67,0,-1,0,-67,0,0,48,-67,0,32,48,-67,0,65,48,-67,0,
+        106,48,-67,0,-117,48,-67,0,-76,48,-67,0,-43,48,-67,0,-1,48,-67,0,
+        0,101,-67,0,32,101,-67,0,65,101,-67,0,106,101,-67,0,-117,101,-67,0,
+        -76,101,-67,0,-43,101,-67,0,-1,101,-67,0,0,-107,-67,0,32,-107,-67,0,
+        65,-107,-67,0,106,-107,-67,0,-117,-107,-67,0,-76,-107,-67,0,-43,-107,-67,0,
+        -1,-107,-67,0,0,-54,-67,0,32,-54,-67,0,65,-54,-67,0,106,-54,-67,0,
+        -117,-54,-67,0,-76,-54,-67,0,-43,-54,-67,0,-1,-54,-67,0,0,-1,-67,0,
+        32,-1,-67,0,65,-1,-67,0,106,-1,-67,0,-117,-1,-67,0,-76,-1,-67,0,
+        -43,-1,-67,0,-1,-1,-67,0,0,0,-1,0,32,0,-1,0,65,0,-1,0,
+        106,0,-1,0,-117,0,-1,0,-76,0,-1,0,-43,0,-1,0,-1,0,-1,0,
+        0,48,-1,0,32,48,-1,0,65,48,-1,0,106,48,-1,0,-117,48,-1,0,
+        -76,48,-1,0,-43,48,-1,0,-1,48,-1,0,0,101,-1,0,32,101,-1,0,
+        65,101,-1,0,106,101,-1,0,-117,101,-1,0,-76,101,-1,0,-43,101,-1,0,
+        -1,101,-1,0,0,-107,-1,0,32,-107,-1,0,65,-107,-1,0,106,-107,-1,0,
+        -117,-107,-1,0,-76,-107,-1,0,-43,-107,-1,0,-1,-107,-1,0,0,-54,-1,0,
+        32,-54,-1,0,65,-54,-1,0,106,-54,-1,0,-117,-54,-1,0,-76,-54,-1,0,
+        -43,-54,-1,0,-1,-54,-1,0,0,-1,-1,0,32,-1,-1,0,65,-1,-1,0,
+        106,-1,-1,0,-117,-1,-1,0,-76,-1,-1,0,-43,-1,-1,0,-1,-1,-1,0,
+        -1,-1,-1,0,-26,-26,-26,0,-43,-43,-43,0,-59,-59,-59,0,-76,-76,-76,0,
+        -92,-92,-92,0,-108,-108,-108,0,-125,-125,-125,0,115,115,115,0,98,98,98,0,
+        82,82,82,0,65,65,65,0,49,49,49,0,32,32,32,0,16,16,16,0,
+        0,0,0,0
+    };
+
+    class CMutexLocker
+    {
+        public:
+            CMutexLocker(pthread_mutex_t& mutex)
+            : mutex(mutex) {
+                pthread_mutex_lock(&mutex);
+            }
+
+            ~CMutexLocker() {
+                pthread_mutex_unlock(&mutex);
+            }
+        private:
+            pthread_mutex_t& mutex;
+
+    };
+
+    void * rtThread(void *ptr) {
+        cout << "start thread" << endl;
+        Packet_t command;
+        Packet_t response;
+
+        CDevice * dev = (CDevice*)ptr;
+        CMutexLocker lock(dev->mutex);
+        try
+        {
+            pthread_mutex_lock(&dev->dataMutex);
+            dev->_acquire();
+
+            command.type = GUSB_APPLICATION_LAYER;
+            command.id   = Pid_Command_Data;
+            command.size = 2;
+            *(uint16_t*)command.payload = Cmnd_Start_Pvt_Data;
+            dev->usb->write(command);
+
+            while(dev->doRealtimeThread) {
+                pthread_mutex_unlock(&dev->dataMutex);
+
+                if(dev->usb->read(response)) {
+                    if(response.id == Pid_Pvt_Data) {
+                        D800_Pvt_Data_t * srcPvt = (D800_Pvt_Data_t*)response.payload;
+                        pthread_mutex_lock(&dev->dataMutex);
+                        dev->PositionVelocityTime << *srcPvt;
+                        pthread_mutex_unlock(&dev->dataMutex);
+                    }
+                }
+
+                pthread_mutex_lock(&dev->dataMutex);
+            }
+
+            command.type = GUSB_APPLICATION_LAYER;
+            command.id   = Pid_Command_Data;
+            command.size = 2;
+            *(uint16_t*)command.payload = Cmnd_Stop_Pvt_Data;
+            dev->usb->write(command);
+
+            dev->_release();
+            pthread_mutex_unlock(&dev->dataMutex);
+        }
+        catch(exce_t& e) {
+            pthread_mutex_trylock(&dev->dataMutex);
+            dev->lasterror = "Realtime thread failed. " + e.msg;
+            dev->doRealtimeThread = false;
+            pthread_mutex_unlock(&dev->dataMutex);
+        }
+        cout << "stop thread" << endl;
+        return 0;
+    }
+
+}
+
+
+CDevice::CDevice()
+: devid(0)
+, usb(0)
+, doRealtimeThread(false)
+{
+    pthread_mutex_init(&dataMutex, NULL);
+}
+
+
+CDevice::~CDevice()
+{
+}
+
+
+const string& CDevice::getCopyright()
+{
+    copyright = "<h1>QLandkarte Device Driver for Garmin " + devname + "</h1>"
+        "<h2>Driver I/F Ver. " INTERFACE_VERSION "</h2>"
+        "<p>© 2007 by bzrudi (bzrudi at users.sourceforge.net)</p>"
+        "<p>This driver 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. </p>";
+    return copyright;
+}
+
+
+void CDevice::_acquire()
+{
+#if defined(WORDS_BIGENDIAN) || !defined(CAN_UNALIGNED)
+    throw exce_t(errSync, "This device has not yet been ported to your platform.");
+#endif
+    usb = new CUSB();
+    usb->open();
+
+    /**
+    Workaround for faulty Etrex Legend C session start. Needs to be called
+    3 times. Please refer to GPSBabel gusb_reset_toggles() function
+    in gpslibusb.c.
+    **/
+    Packet_t command;
+    command.type = GUSB_PROTOCOL_LAYER;
+    command.id   = GUSB_SESSION_START;
+    command.size = 0;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+    usb->write(command);
+    /**
+    Now we call syncup() which takes care of the third try in session start
+    **/
+    usb->syncup();
+
+    if(strncmp(usb->getProductString().c_str(), devname.c_str(), devname.size()) != 0) {
+        string msg = "No " + devname + " unit detected. Please retry to select other device driver.";
+        throw exce_t(errSync,msg);
+    }
+}
+
+
+void CDevice::_uploadMap(const uint8_t * mapdata, uint32_t size, const char * key)
+{
+    if(usb == 0) return;
+    Packet_t command;
+    Packet_t response;
+    int cancel = 0;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    // read SD Ram capacity
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == Pid_Capacity_Data) {
+            cout << "free memory: " << dec << (((uint32_t*)response.payload)[1] / (1024*1024)) << " MB" << endl;
+            uint32_t memory = ((uint32_t*)response.payload)[1];
+            if(memory < size) {
+                stringstream msg;
+                msg << "Failed to send map: Unit has not enought memory (available/needed): " << memory << "/" << size << " bytes";
+                throw exce_t(errRuntime,msg.str());
+            }
+        }
+    }
+
+    // send unlock key if present
+    if(key) {
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Tx_Unlock_Key;
+        command.size = strlen(key) + 1;
+        memcpy(command.payload,key,command.size);
+
+        usb->write(command);
+
+        while(usb->read(response)) {
+            if(response.id == Pid_Ack_Unlock_key) {
+                //TODO read data
+            }
+        }
+
+    }
+
+    // switch to map transfer mode erase old map(?)
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 75;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == 74) {
+            //TODO read data
+        }
+    }
+
+    callback(0,0,&cancel,"Upload maps ...",0);
+
+    uint32_t total  = size;
+    uint32_t offset = 0, chunkSize;
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 36;
+    // transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes
+    while(size && !cancel) {
+        chunkSize       = (size < (GUSB_PAYLOAD_SIZE - sizeof(offset))) ? size : (GUSB_PAYLOAD_SIZE - sizeof(offset));
+        command.size    = chunkSize + sizeof(offset);
+
+        *(uint32_t*)command.payload = offset;
+        memcpy(command.payload + sizeof(offset),mapdata,chunkSize);
+        size    -= chunkSize;
+        mapdata += chunkSize;
+        offset  += chunkSize;
+
+        usb->write(command);
+
+        double progress = ((total - size) * 100.0) / total;
+        callback(progress,0,&cancel,0,"Transfering map data.");
+    }
+
+    callback(100,0,&cancel,0,"done");
+
+    // terminate map transfer mode (?)
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 45;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    usb->write(command);
+}
+
+
+void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key)
+{
+    if(usb == 0) return;
+    Packet_t command;
+    Packet_t response;
+    int cancel = 0;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    // read SD Ram capacity
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == Pid_Capacity_Data) {
+            cout << "free memory: " << dec << (((uint32_t*)response.payload)[1] / (1024*1024)) << " MB" << endl;
+            uint32_t memory = ((uint32_t*)response.payload)[1];
+            if(memory < size) {
+                stringstream msg;
+                msg << "Failed to send map: Unit has not enought memory (available/needed): " << memory << "/" << size << " bytes";
+                throw exce_t(errRuntime,msg.str());
+            }
+        }
+    }
+
+    // send unlock key if present
+    if(key) {
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Tx_Unlock_Key;
+        command.size = strlen(key) + 1;
+        memcpy(command.payload,key,command.size);
+
+        usb->write(command);
+
+        while(usb->read(response)) {
+            if(response.id == Pid_Ack_Unlock_key) {
+                //TODO read data
+            }
+        }
+
+    }
+
+    // switch to map transfer mode erase old map(?)
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 75;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == 74) {
+            //TODO read data
+        }
+    }
+
+    callback(0,0,&cancel,"Upload maps ...",0);
+
+    FILE *fid = fopen(filename,"r");
+    if(fid == NULL) {
+        stringstream msg;
+        msg << "Failed to send map: Can't open  " << filename;
+        throw exce_t(errRuntime,msg.str());
+    }
+
+    uint32_t total  = size;
+    uint32_t offset = 0, chunkSize;
+    uint8_t  buffer[GUSB_PAYLOAD_SIZE - sizeof(offset)];
+
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 36;
+    // transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes
+    while(size && !cancel) {
+        chunkSize       = (size < (GUSB_PAYLOAD_SIZE - sizeof(offset))) ? size : (GUSB_PAYLOAD_SIZE - sizeof(offset));
+        command.size    = chunkSize + sizeof(offset);
+
+        fread(buffer, chunkSize, 1, fid);
+
+        *(uint32_t*)command.payload = offset;
+        memcpy(command.payload + sizeof(offset),buffer,chunkSize);
+        size    -= chunkSize;
+        offset  += chunkSize;
+
+        usb->write(command);
+
+        double progress = ((total - size) * 100.0) / total;
+        callback(progress,0,&cancel,0,"Transfering map data.");
+    }
+
+    callback(100,0,&cancel,0,"done");
+
+    // terminate map transfer mode (?)
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 45;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    usb->write(command);
+}
+
+
+void CDevice::_queryMap(std::list<Map_t>& maps)
+{
+    maps.clear();
+    if(usb == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    // Request map overview table
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x59;
+    command.size = 19;
+    Map_Request_t * req = (Map_Request_t*)command.payload;
+    req->dummy1 = 0;
+    req->dummy2 = 10;
+    strcpy(req->section,"MAPSOURC.MPS");
+    usb->write(command);
+
+    uint32_t size   = 1024;
+    uint32_t fill   = 0;
+    char * pData    = (char*)calloc(1,size);
+
+    while(usb->read(response)) {
+        // acknowledge request (???)
+        if(response.id == 0x5B) {
+            //TODO: read data
+        }
+
+        // chunk of MAPSOURC.MPS section
+        // Each chunk is prepended by a chunk counter of type uint8_t.
+        // This has to be skipped. That's why the peculiar math.
+        if(response.id == 0x5A) {
+            // realloc memory if chunk does not fit
+            if((fill +  response.size - 1) > size) {
+                size += size;
+                pData = (char*)realloc(pData,size);
+            }
+
+            memcpy(&pData[fill], response.payload + 1, response.size - 1);
+
+            fill += response.size - 1;
+        }
+    }
+
+    Map_Info_t * pInfo = (Map_Info_t*)pData;
+    while(pInfo->tok == 0x4C) {
+        Map_t m;
+        char * pStr = pInfo->name1;
+        m.mapName = pStr;
+        pStr += strlen(pStr) + 1;
+        m.tileName = pStr;
+
+        maps.push_back(m);
+
+        pInfo =  (Map_Info_t*)(((char*)pInfo) + pInfo->size + sizeof(pInfo->tok) + sizeof(pInfo->size));
+    }
+
+    free(pData);
+
+}
+
+
+void CDevice::_downloadWaypoints(list<Garmin::Wpt_t>& waypoints)
+{
+    waypoints.clear();
+    if(usb == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    // request waypoints
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Wpt;
+    usb->write(command);
+
+    while(1) {
+        if(!usb->read(response)) continue;
+
+        if(response.id == Pid_Records) {
+#ifdef DBG_SHOW_WAYPOINT
+            cout << "number of waypoints:" << *(int16_t*)response.payload << endl;
+#endif
+        }
+
+        if(response.id == Pid_Wpt_Data) {
+            D109_Wpt_t * srcWpt = (D109_Wpt_t*)response.payload;
+            waypoints.push_back(Wpt_t());
+            Wpt_t& tarWpt = waypoints.back();
+
+            tarWpt << *srcWpt;
+        }
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+
+    }
+
+    // request proximity waypoints
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Prx;
+    usb->write(command);
+
+    while(1) {
+
+        if(!usb->read(response)) continue;
+
+        if(response.id == Pid_Records) {
+            //TODO read data
+#ifdef DBG_SHOW_WAYPOINT
+            cout << "number of proximity waypoints:" << *(int16_t*)response.payload << endl;
+#endif
+        }
+
+        if(response.id == Pid_Prx_Wpt_Data) {
+            D109_Wpt_t * srcWpt = (D109_Wpt_t*)response.payload;
+            waypoints.push_back(Wpt_t());
+            Wpt_t& tarWpt = waypoints.back();
+
+            tarWpt << *srcWpt;
+        }
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+
+    }
+
+#ifdef DBG_SHOW_WAYPOINT
+    list<Wpt_t>::const_iterator wpt = waypoints.begin();
+    while(wpt != waypoints.end()) {
+        cout << "-------------------------" << endl;
+        cout << "class      " << hex << (int)wpt->wpt_class << endl;
+        cout << "dspl_color " << hex << (int)wpt->dspl_color << endl;
+        cout << "dspl_attr  " << hex << (int)wpt->dspl_attr << endl;
+        cout << "smbl       " << dec <<(int)wpt->smbl << endl;
+        cout << "lat        " << wpt->lat << endl;
+        cout << "lon        " << wpt->lon << endl;
+        cout << "alt        " << wpt->alt << endl;
+        cout << "dpth       " << wpt->dpth << endl;
+        cout << "dist       " << wpt->dist << endl;
+        cout << "state      " << wpt->state << endl;
+        cout << "cc         " << wpt->cc << endl;
+        cout << "ete        " << wpt->ete << endl;
+        cout << "temp       " << wpt->temp << endl;
+        cout << "time       " << wpt->time << endl;
+        cout << "category   " << wpt->wpt_cat << endl;
+        cout << "ident      " << wpt->ident << endl;
+        cout << "comment    " << wpt->comment << endl;
+        cout << "facility   " << wpt->facility << endl;
+        cout << "city       " << wpt->city << endl;
+        cout << "addr       " << wpt->addr << endl;
+        cout << "crossroad  " << wpt->crossroad << endl;
+
+        ++wpt;
+    }
+#endif
+
+}
+
+
+void CDevice::_uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints)
+{
+    if(usb == 0) return;
+    // count number of proximity waypoints
+    uint16_t prx_wpt_cnt = 0;
+    list<Wpt_t>::const_iterator wpt = waypoints.begin();
+    while(wpt != waypoints.end()) {
+        if(wpt->dist != 1e25f) ++prx_wpt_cnt;
+        ++wpt;
+    }
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    // transmit proximity waypoints first
+    if(prx_wpt_cnt) {
+        //announce number of records
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Records;
+        command.size = 2;
+        *(uint16_t*)command.payload = prx_wpt_cnt;
+        usb->write(command);
+
+        wpt = waypoints.begin();
+        while(wpt != waypoints.end()) {
+            if(wpt->dist != 1e25f) {
+                command.type = GUSB_APPLICATION_LAYER;
+                command.id   = Pid_Prx_Wpt_Data;
+
+                D109_Wpt_t * p = (D109_Wpt_t *)command.payload;
+                command.size = *wpt >> *p;
+
+                usb->write(command);
+
+            }
+            ++wpt;
+        }
+
+        //announce number of records
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Xfer_Cmplt;
+        command.size = 2;
+        *(uint16_t*)command.payload = Cmnd_Transfer_Prx;
+        usb->write(command);
+
+    }
+
+    //transmit _all_ waypoints
+    //announce number of records
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Records;
+    command.size = 2;
+    *(uint16_t*)command.payload = waypoints.size();
+    usb->write(command);
+
+    wpt = waypoints.begin();
+    while(wpt != waypoints.end()) {
+
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Wpt_Data;
+
+        D109_Wpt_t * p = (D109_Wpt_t *)command.payload;
+        command.size = *wpt >> *p;
+
+        usb->write(command);
+
+        ++wpt;
+    }
+
+    //announce number of records
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Xfer_Cmplt;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Wpt;
+    usb->write(command);
+
+}
+
+
+void CDevice::_downloadTracks(std::list<Garmin::Track_t>& tracks)
+{
+    tracks.clear();
+    if(usb == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Trk;
+    usb->write(command);
+
+    int         trackidx = 0;
+    string      name;
+    Track_t *   track = 0;
+    while(1) {
+
+        if(!usb->read(response)) continue;
+
+        if(response.id == Pid_Trk_Hdr) {
+            trackidx = 0;
+            D312_Trk_Hdr_t * hdr = (D312_Trk_Hdr_t*)response.payload;
+            tracks.push_back(Track_t());
+            track = &tracks.back();
+
+            *track << *hdr;
+            name  = hdr->ident;
+
+        }
+
+        if(response.id == Pid_Trk_Data) {
+            D301_Trk_t * data = (D301_Trk_t*)response.payload;
+            TrkPt_t pt;
+            if(data->new_trk) {
+                if(trackidx) {
+                    tracks.push_back(Track_t());
+                    Track_t& t = tracks.back();
+                    t.color = track->color;
+                    t.dspl = track->dspl;
+                    char str[256];
+                    sprintf(str,"%s_%d",name.c_str(),trackidx++);
+                    t.ident = str;
+                    track = &t;
+                }
+                else {
+                    ++trackidx;
+                }
+            }
+
+            pt << *data;
+            track->track.push_back(pt);
+        }
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+    }
+}
+
+
+void CDevice::_uploadRoutes(list<Garmin::Route_t>& routes)
+{
+    if(usb == 0) return;
+    // count number of proximity waypoints
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    list<Garmin::Route_t>::const_iterator route = routes.begin();
+    while(route != routes.end()) {
+        //announce number of records
+        // D202_Rte_Hdr_t + (D110_Wpt_t + D210_Tre_Link_t) * number of route points
+        uint16_t nrec = 1 + route->route.size() * 2;
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Records;
+        command.size = 2;
+        *(uint16_t*)command.payload = nrec;
+        usb->write(command);
+
+        // write route header
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Rte_Hdr;
+        D202_Rte_Hdr_t * r = (D202_Rte_Hdr_t *)command.payload;
+        command.size = *route >> *r;
+        usb->write(command);
+
+        vector<RtePt_t>::const_iterator rtept = route->route.begin();
+
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Rte_Wpt_Data;
+        D109_Wpt_t * p = (D109_Wpt_t *)command.payload;
+        command.size = *rtept >> *p;
+        usb->write(command);
+
+        ++rtept;
+
+        while(rtept != route->route.end()) {
+
+            command.type = GUSB_APPLICATION_LAYER;
+            command.id   = Pid_Rte_Link_Data;
+            D210_Rte_Link_t * l = (D210_Rte_Link_t *)command.payload;
+            command.size = *rtept >> *l;
+            usb->write(command);
+
+            command.type = GUSB_APPLICATION_LAYER;
+            command.id   = Pid_Rte_Wpt_Data;
+            D109_Wpt_t * p = (D109_Wpt_t *)command.payload;
+            command.size = *rtept >> *p;
+            usb->write(command);
+
+            ++rtept;
+        }
+
+        // finish block
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Xfer_Cmplt;
+        command.size = 2;
+        *(uint16_t*)command.payload = Cmnd_Transfer_Rte;
+        usb->write(command);
+        ++route;
+    }
+
+}
+
+
+void CDevice::_uploadCustomIcons(list<Garmin::Icon_t>& icons)
+{
+    if(usb == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    list<Garmin::Icon_t>::const_iterator icon = icons.begin();
+    while(icon != icons.end()) {
+        uint32_t tan = 0;
+
+        // get tan
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Req_Icon_Id;
+        command.size = 2;
+        *(uint16_t*)command.payload = icon->idx + 1;
+        usb->write(command);
+
+        while(usb->read(response)) {
+            if(response.id == Pid_Ack_Icon_Id) {
+                tan = *(uint32_t*)response.payload;
+            }
+        }
+
+        // request color table
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Req_Clr_Tbl;
+        command.size = 4;
+        *(uint32_t*)command.payload = tan;
+        usb->write(command);
+
+        while(usb->read(response)) {
+            if(response.id == Pid_Ack_Clr_Tbl) {
+                // send back color table
+                command = response;
+            }
+        }
+
+        usb->write(command);
+        while(usb->read(response)) {
+            if(response.id == Pid_Req_Clr_Tbl) {
+                // TODO: ignore?
+            }
+        }
+
+        // send icon data
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Icon_Data;
+        command.size = 0x104;
+        *(uint32_t*)command.payload = tan;
+        memcpy(command.payload + sizeof(tan),icon->data,sizeof(icon->data));
+        usb->write(command);
+
+        while(usb->read(response)) {
+            if(response.id == Pid_Ack_Icon_Data) {
+                // TODO: ignore?
+            }
+        }
+
+        ++icon;
+    }
+}
+
+
+void CDevice::_screenshot(char *& clrtbl, char *& data, int& width, int& height)
+{
+    if(usb == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    uint32_t tan = 0;
+
+    // get tan
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Req_Icon_Id;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == Pid_Ack_Icon_Id) {
+            tan = *(uint32_t*)response.payload;
+        }
+    }
+
+    // request color table
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Req_Clr_Tbl;
+    command.size = 4;
+    *(uint32_t*)command.payload = tan;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == Pid_Ack_Clr_Tbl) {
+            // send back color table
+            memcpy(aClrtbl,_clrtbl,sizeof(aClrtbl));
+            command = response;
+        }
+    }
+
+    usb->write(command);
+    while(usb->read(response)) {
+        if(response.id == Pid_Req_Clr_Tbl) {
+            // TODO: ignore?
+        }
+    }
+
+    char buffer[SCREEN_WIDTH * SCREEN_HEIGHT];
+    char * pData = buffer;
+    uint32_t byteCnt;
+    uint32_t byteCntTotal = 0;
+
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Ack_Icon_Data;
+    command.size = 4;
+    *(uint32_t*)command.payload = tan;
+    usb->write(command);
+
+    // loop will end after reception of Pid_Icon_Data with length of 4 (tan only)
+    // or too much data
+    while(1) {
+        if(!usb->read(response)) {
+            usb->write(command);
+            continue;
+        }
+
+        if(response.id == Pid_Icon_Data) {
+            if(response.size == sizeof(tan)) break;
+            byteCnt = response.size - sizeof(tan);
+            memcpy(pData,response.payload + sizeof(tan), byteCnt);
+            pData += byteCnt;
+            byteCntTotal += byteCnt;
+            if(byteCntTotal > sizeof(buffer)) break;
+        }
+    }
+
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x373;
+    command.size = 4;
+    *(uint32_t*)command.payload = tan;
+    usb->write(command);
+
+    for(int r = 0; r < SCREEN_HEIGHT; ++r) {
+        for(int c = 0; c < SCREEN_WIDTH; ++c) {
+            aScreen[r * SCREEN_WIDTH + c] = buffer[(SCREEN_HEIGHT - 1 - r)*SCREEN_WIDTH + c];
+        }
+    }
+
+    clrtbl  = aClrtbl;
+    data    = aScreen;
+    width   = SCREEN_WIDTH;
+    height  = SCREEN_HEIGHT;
+}
+
+
+void CDevice::_setRealTimeMode(bool on)
+{
+    CMutexLocker lock(dataMutex);
+    if(doRealtimeThread == on) return;
+    doRealtimeThread = on;
+    if(doRealtimeThread) {
+        pthread_create(&thread,NULL,rtThread, this);
+    }
+
+}
+
+
+void CDevice::_getRealTimePos(Garmin::Pvt_t& pvt)
+{
+    if(pthread_mutex_trylock(&mutex) != EBUSY) {
+        pthread_mutex_unlock(&mutex);
+        throw exce_t(errRuntime,lasterror);
+    }
+
+    CMutexLocker lock(dataMutex);
+    pvt = PositionVelocityTime;
+}
+
+
+void CDevice::_release()
+{
+    if(usb == 0) return;
+
+    usb->close();
+    delete usb;
+    usb = 0;
+}
+
+
+void CDevice::_getDevProperties(Garmin::DevProperties_t& dev_properties)
+{
+    if(usb == 0) return;
+    Packet_t command;
+    Packet_t response;
+
+    // ask for SD Ram capacity
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    usb->write(command);
+
+    // try to read SD Ram capacity
+    uint32_t memory = 0;
+    uint16_t tile_limit = 0;
+    while(usb->read(response)) {
+        if(response.id == Pid_Capacity_Data) {
+            tile_limit = ((uint16_t*)response.payload)[1];
+            memory = ((uint32_t*)response.payload)[1];
+        }
+    }
+    if(tile_limit == 0) {
+        throw exce_t(errRuntime,"Failed to send map: Unable to find the tile limit of the GPS");
+    }
+    if(memory == 0) {
+        throw exce_t(errRuntime,"Failed to send map: Unable to find the available memory of the GPS");
+    }
+
+    // add to the properties list
+    properties.memory_limit = memory;
+    properties.set.item.memory_limit = 1;
+    properties.maps_limit = tile_limit;
+    properties.set.item.maps_limit = 1;
+
+    // return the properties
+    dev_properties = properties;
+}
diff --git a/src/EtrexLegendC/CDevice.h b/src/EtrexLegendC/CDevice.h
new file mode 100644
index 0000000..871a7b3
--- /dev/null
+++ b/src/EtrexLegendC/CDevice.h
@@ -0,0 +1,82 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+                       bzrudi (bzrudi at users.sourceforge.net)
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef CDEVICE_H
+#define CDEVICE_H
+
+#include "IDeviceDefault.h"
+#include "CUSB.h"
+
+#define SCREEN_WIDTH  176
+#define SCREEN_HEIGHT 220
+
+namespace EtrexLegendC
+{
+
+    class CDevice : public Garmin::IDeviceDefault
+    {
+        public:
+            CDevice();
+            virtual ~CDevice();
+
+            std::string devname;
+
+            uint32_t devid;
+
+            const std::string& getCopyright();
+
+        private:
+            friend void * rtThread(void *ptr);
+
+            void _acquire();
+            void _uploadMap(const uint8_t * mapdata, uint32_t size, const char * key);
+            void _uploadMap(const char * filename, uint32_t size, const char * key);
+            void _queryMap(std::list<Garmin::Map_t>& maps);
+            void _downloadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            void _uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            void _downloadTracks(std::list<Garmin::Track_t>& tracks);
+            void _uploadRoutes(std::list<Garmin::Route_t>& routes);
+            void _uploadCustomIcons(std::list<Garmin::Icon_t>& icons);
+            void _screenshot(char *& clrtbl, char *& data, int& width, int& height);
+
+            void _getDevProperties(Garmin::DevProperties_t& dev_properties);
+
+            void _setRealTimeMode(bool on);
+            void _getRealTimePos(Garmin::Pvt_t& pvt);
+            void _release();
+
+            Garmin::CUSB * usb;
+            /// realtime mode thread
+            pthread_t thread;
+            /// mutex to serialize any data access
+            pthread_mutex_t dataMutex;
+            /// keep alive flag for the realtime mode thread
+            bool doRealtimeThread;
+
+            Garmin::Pvt_t PositionVelocityTime;
+
+            char aClrtbl[0x100 * 4];
+            char aScreen[SCREEN_WIDTH * SCREEN_HEIGHT];
+    };
+
+}
+#endif                           //CDEVICE_H
diff --git a/src/EtrexLegendC/CMakeLists.txt b/src/EtrexLegendC/CMakeLists.txt
new file mode 100644
index 0000000..9877730
--- /dev/null
+++ b/src/EtrexLegendC/CMakeLists.txt
@@ -0,0 +1,31 @@
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+set(SRCS
+    loader.cpp
+    CDevice.cpp
+)
+
+set(HDRS
+    CDevice.h
+)
+
+include_directories(../ ${USB_INCLUDE_DIRS})
+add_library(EtrexLegendC SHARED ${SRCS} ${HDRS})
+target_link_libraries(EtrexLegendC garmin ${USB_LIBRARIES} pthread)
+
+set(ALIASES
+    EtrexVistaC
+    GPSMap60CS
+    GPSMap76CS
+)
+
+foreach(var ${ALIASES})
+    message(" ${var}")
+    add_custom_command( TARGET EtrexLegendC
+                        POST_BUILD
+                        COMMAND ln ARGS -sf libEtrexLegendC.so lib${var}.so
+                        WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH}
+                        )
+endforeach(var)
+
diff --git a/src/EtrexLegendC/loader.cpp b/src/EtrexLegendC/loader.cpp
new file mode 100644
index 0000000..a2be2aa
--- /dev/null
+++ b/src/EtrexLegendC/loader.cpp
@@ -0,0 +1,90 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "config.h"
+#include "CDevice.h"
+
+namespace EtrexLegendC
+{
+    static CDevice * device = 0;
+}
+
+
+#ifdef WIN32
+#define WIN_EXPORT __declspec(dllexport)
+#else
+#define WIN_EXPORT
+#endif
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexLegendC(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(EtrexLegendC::device == 0) {
+        EtrexLegendC::device = new EtrexLegendC::CDevice();
+    }
+    EtrexLegendC::device->devname = "Etrex Legend C";
+    EtrexLegendC::device->devid   = 0x013b;
+    return EtrexLegendC::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initGPSMap60CS(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(EtrexLegendC::device == 0) {
+        EtrexLegendC::device = new EtrexLegendC::CDevice();
+    }
+    EtrexLegendC::device->devname = "GPSMap60CS";
+    EtrexLegendC::device->devid   = 0x0123;
+    return EtrexLegendC::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initGPSMap76CS(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(EtrexLegendC::device == 0) {
+        EtrexLegendC::device = new EtrexLegendC::CDevice();
+    }
+    EtrexLegendC::device->devname = "GPSMap76CS";
+    EtrexLegendC::device->devid   = 0x0123;
+    return EtrexLegendC::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexVistaC(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(EtrexLegendC::device == 0) {
+        EtrexLegendC::device = new EtrexLegendC::CDevice();
+    }
+    EtrexLegendC::device->devname = "Etrex Vista C";
+    EtrexLegendC::device->devid   = 0x013b;
+    return EtrexLegendC::device;
+}
diff --git a/src/GPSMap60CSx/CDevice.cpp b/src/GPSMap60CSx/CDevice.cpp
new file mode 100644
index 0000000..6139cdf
--- /dev/null
+++ b/src/GPSMap60CSx/CDevice.cpp
@@ -0,0 +1,1165 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "../Platform.h"
+#include "CDevice.h"
+#include <Garmin.h>
+
+#include <cstdio>
+#include <errno.h>
+#include <iostream>
+#include <sstream>
+#include <stdio.h>
+
+using namespace GPSMap60CSx;
+using namespace Garmin;
+using namespace std;
+
+namespace GPSMap60CSx
+{
+
+    static const char _clrtbl[1024]= {
+        0,0,0,0,32,0,0,0,65,0,0,0,106,0,0,0,-117,0,0,0,
+        -76,0,0,0,-43,0,0,0,-1,0,0,0,0,48,0,0,32,48,0,0,
+        65,48,0,0,106,48,0,0,-117,48,0,0,-76,48,0,0,-43,48,0,0,
+        -1,48,0,0,0,101,0,0,32,101,0,0,65,101,0,0,106,101,0,0,
+        -117,101,0,0,-76,101,0,0,-43,101,0,0,-1,101,0,0,0,-107,0,0,
+        32,-107,0,0,65,-107,0,0,106,-107,0,0,-117,-107,0,0,-76,-107,0,0,
+        -43,-107,0,0,-1,-107,0,0,0,-54,0,0,32,-54,0,0,65,-54,0,0,
+        106,-54,0,0,-117,-54,0,0,-76,-54,0,0,-43,-54,0,0,-1,-54,0,0,
+        0,-1,0,0,32,-1,0,0,65,-1,0,0,106,-1,0,0,-117,-1,0,0,
+        -76,-1,0,0,-43,-1,0,0,-1,-1,0,0,0,0,57,0,32,0,57,0,
+        65,0,57,0,106,0,57,0,-117,0,57,0,-76,0,57,0,-43,0,57,0,
+        -1,0,57,0,0,48,57,0,32,48,57,0,65,48,57,0,106,48,57,0,
+        -117,48,57,0,-76,48,57,0,-43,48,57,0,-1,48,57,0,0,101,57,0,
+        32,101,57,0,65,101,57,0,106,101,57,0,-117,101,57,0,-76,101,57,0,
+        -43,101,57,0,-1,101,57,0,0,-107,57,0,32,-107,57,0,65,-107,57,0,
+        106,-107,57,0,-117,-107,57,0,-76,-107,57,0,-43,-107,57,0,-1,-107,57,0,
+        0,-54,57,0,32,-54,57,0,65,-54,57,0,106,-54,57,0,-117,-54,57,0,
+        -76,-54,57,0,-43,-54,57,0,-1,-54,57,0,0,-1,57,0,32,-1,57,0,
+        65,-1,57,0,106,-1,57,0,-117,-1,57,0,-76,-1,57,0,-43,-1,57,0,
+        -1,-1,57,0,0,0,123,0,32,0,123,0,65,0,123,0,106,0,123,0,
+        -117,0,123,0,-76,0,123,0,-43,0,123,0,-1,0,123,0,0,48,123,0,
+        32,48,123,0,65,48,123,0,106,48,123,0,-117,48,123,0,-76,48,123,0,
+        -43,48,123,0,-1,48,123,0,0,101,123,0,32,101,123,0,65,101,123,0,
+        106,101,123,0,-117,101,123,0,-76,101,123,0,-43,101,123,0,-1,101,123,0,
+        0,-107,123,0,32,-107,123,0,65,-107,123,0,106,-107,123,0,-117,-107,123,0,
+        -76,-107,123,0,-43,-107,123,0,-1,-107,123,0,0,-54,123,0,32,-54,123,0,
+        65,-54,123,0,106,-54,123,0,-117,-54,123,0,-76,-54,123,0,-43,-54,123,0,
+        -1,-54,123,0,0,-1,123,0,32,-1,123,0,65,-1,123,0,106,-1,123,0,
+        -117,-1,123,0,-76,-1,123,0,-43,-1,123,0,-1,-1,123,0,0,0,-67,0,
+        32,0,-67,0,65,0,-67,0,106,0,-67,0,-117,0,-67,0,-76,0,-67,0,
+        -43,0,-67,0,-1,0,-67,0,0,48,-67,0,32,48,-67,0,65,48,-67,0,
+        106,48,-67,0,-117,48,-67,0,-76,48,-67,0,-43,48,-67,0,-1,48,-67,0,
+        0,101,-67,0,32,101,-67,0,65,101,-67,0,106,101,-67,0,-117,101,-67,0,
+        -76,101,-67,0,-43,101,-67,0,-1,101,-67,0,0,-107,-67,0,32,-107,-67,0,
+        65,-107,-67,0,106,-107,-67,0,-117,-107,-67,0,-76,-107,-67,0,-43,-107,-67,0,
+        -1,-107,-67,0,0,-54,-67,0,32,-54,-67,0,65,-54,-67,0,106,-54,-67,0,
+        -117,-54,-67,0,-76,-54,-67,0,-43,-54,-67,0,-1,-54,-67,0,0,-1,-67,0,
+        32,-1,-67,0,65,-1,-67,0,106,-1,-67,0,-117,-1,-67,0,-76,-1,-67,0,
+        -43,-1,-67,0,-1,-1,-67,0,0,0,-1,0,32,0,-1,0,65,0,-1,0,
+        106,0,-1,0,-117,0,-1,0,-76,0,-1,0,-43,0,-1,0,-1,0,-1,0,
+        0,48,-1,0,32,48,-1,0,65,48,-1,0,106,48,-1,0,-117,48,-1,0,
+        -76,48,-1,0,-43,48,-1,0,-1,48,-1,0,0,101,-1,0,32,101,-1,0,
+        65,101,-1,0,106,101,-1,0,-117,101,-1,0,-76,101,-1,0,-43,101,-1,0,
+        -1,101,-1,0,0,-107,-1,0,32,-107,-1,0,65,-107,-1,0,106,-107,-1,0,
+        -117,-107,-1,0,-76,-107,-1,0,-43,-107,-1,0,-1,-107,-1,0,0,-54,-1,0,
+        32,-54,-1,0,65,-54,-1,0,106,-54,-1,0,-117,-54,-1,0,-76,-54,-1,0,
+        -43,-54,-1,0,-1,-54,-1,0,0,-1,-1,0,32,-1,-1,0,65,-1,-1,0,
+        106,-1,-1,0,-117,-1,-1,0,-76,-1,-1,0,-43,-1,-1,0,-1,-1,-1,0,
+        -1,-1,-1,0,-26,-26,-26,0,-43,-43,-43,0,-59,-59,-59,0,-76,-76,-76,0,
+        -92,-92,-92,0,-108,-108,-108,0,-125,-125,-125,0,115,115,115,0,98,98,98,0,
+        82,82,82,0,65,65,65,0,49,49,49,0,32,32,32,0,16,16,16,0,
+        0,0,0,0
+    };
+
+    class CMutexLocker
+    {
+        public:
+            CMutexLocker(pthread_mutex_t& mutex)
+            : mutex(mutex) {
+                pthread_mutex_lock(&mutex);
+            }
+
+            ~CMutexLocker() {
+                pthread_mutex_unlock(&mutex);
+            }
+        private:
+            pthread_mutex_t& mutex;
+
+    };
+
+    void * rtThread(void *ptr) {
+        cout << "start thread" << endl;
+        Packet_t command;
+        Packet_t response;
+
+        CDevice * dev = (CDevice*)ptr;
+        CMutexLocker lock(dev->mutex);
+        try
+        {
+            pthread_mutex_lock(&dev->dataMutex);
+            dev->_acquire();
+
+            command.type = GUSB_APPLICATION_LAYER;
+            command.id   = Pid_Command_Data;
+            command.size = 2;
+            *(uint16_t*)command.payload = Cmnd_Start_Pvt_Data;
+            dev->usb->write(command);
+
+            while(dev->doRealtimeThread) {
+                pthread_mutex_unlock(&dev->dataMutex);
+
+                if(dev->usb->read(response)) {
+                    if(response.id == Pid_Pvt_Data) {
+                        D800_Pvt_Data_t * srcPvt = (D800_Pvt_Data_t*)response.payload;
+                        pthread_mutex_lock(&dev->dataMutex);
+                        dev->PositionVelocityTime << *srcPvt;
+                        pthread_mutex_unlock(&dev->dataMutex);
+                    }
+                }
+
+                pthread_mutex_lock(&dev->dataMutex);
+            }
+
+            command.type = GUSB_APPLICATION_LAYER;
+            command.id   = Pid_Command_Data;
+            command.size = 2;
+            *(uint16_t*)command.payload = Cmnd_Stop_Pvt_Data;
+            dev->usb->write(command);
+
+            dev->_release();
+            pthread_mutex_unlock(&dev->dataMutex);
+        }
+        catch(exce_t& e) {
+            pthread_mutex_trylock(&dev->dataMutex);
+            dev->lasterror = "Realtime thread failed. " + e.msg;
+            dev->doRealtimeThread = false;
+            pthread_mutex_unlock(&dev->dataMutex);
+        }
+        cout << "stop thread" << endl;
+        return 0;
+    }
+
+}
+
+
+CDevice::CDevice()
+: devid(0)
+, usb(0)
+, doRealtimeThread(false)
+, pScreen(0)
+{
+    pthread_mutex_init(&dataMutex, NULL);
+}
+
+
+CDevice::~CDevice()
+{
+    if(pScreen) delete [] pScreen;
+}
+
+
+const string& CDevice::getCopyright()
+{
+    copyright = "<h1>QLandkarte Device Driver for Garmin " + devname + "</h1>"
+        "<h2>Driver I/F Ver. " INTERFACE_VERSION "</h2>"
+        "<p>© 2007 by Oliver Eichler (oliver.eichler at gmx.de)</p>"
+        "<p>© Venture HC Screenshot support by Torsten Reuschel (me at fuesika.de)</p>"
+        "<p>This driver 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. </p>";
+    return copyright;
+}
+
+
+void CDevice::_acquire()
+{
+#if defined(WORDS_BIGENDIAN) || !defined(CAN_UNALIGNED)
+    throw exce_t(errSync, "This device has not yet been ported to your platform.");
+#endif
+    usb = new CUSB();
+    usb->open();
+    if(devid == 0x01a5) {
+        Packet_t command;
+        command.type = GUSB_PROTOCOL_LAYER;
+        command.id   = GUSB_SESSION_START;
+        command.size = 0;
+        *(uint16_t*)command.payload = 0x0000;
+        usb->write(command);
+        usb->write(command);
+    }
+    usb->syncup();
+
+    if(strncmp(usb->getProductString().c_str(), devname.c_str(), devname.size()) != 0) {
+        string msg = "No " + devname + " unit detected. Please retry to select other device driver.";
+        throw exce_t(errSync,msg);
+    }
+}
+
+
+void CDevice::_uploadMap(const uint8_t * mapdata, uint32_t size, const char * key)
+{
+    if(usb == 0) return;
+    Packet_t command;
+    Packet_t response;
+    int cancel = 0;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    // read SD Ram capacity
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == Pid_Capacity_Data) {
+            cout << "free memory: " << dec << (((uint32_t*)response.payload)[1] / (1024*1024)) << " MB" << endl;
+            uint32_t memory = ((uint32_t*)response.payload)[1];
+            if(memory < size) {
+                stringstream msg;
+                msg << "Failed to send map: Unit has not enought memory (available/needed): " << memory << "/" << size << " bytes";
+                throw exce_t(errRuntime,msg.str());
+            }
+        }
+    }
+
+    // send unlock key if present
+    if(key) {
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Tx_Unlock_Key;
+        command.size = strlen(key) + 1;
+        memcpy(command.payload,key,command.size);
+
+        usb->write(command);
+
+        while(usb->read(response)) {
+            if(response.id == Pid_Ack_Unlock_key) {
+                //TODO read data
+            }
+        }
+
+    }
+
+    // switch to map transfer mode erase old map(?)
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 75;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == 74) {
+            //TODO read data
+        }
+    }
+
+    callback(0,0,&cancel,"Upload maps ...",0);
+
+    uint32_t total  = size;
+    uint32_t offset = 0, chunkSize;
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 36;
+    // transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes
+    while(size && !cancel) {
+        chunkSize       = (size < (GUSB_PAYLOAD_SIZE - sizeof(offset))) ? size : (GUSB_PAYLOAD_SIZE - sizeof(offset));
+        command.size    = chunkSize + sizeof(offset);
+
+        *(uint32_t*)command.payload = offset;
+        memcpy(command.payload + sizeof(offset),mapdata,chunkSize);
+        size    -= chunkSize;
+        mapdata += chunkSize;
+        offset  += chunkSize;
+
+        usb->write(command);
+
+        double progress = ((total - size) * 100.0) / total;
+        callback(progress,0,&cancel,0,"Transfering map data.");
+    }
+
+    callback(100,0,&cancel,0,"done");
+
+    // terminate map transfer mode (?)
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 45;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    usb->write(command);
+}
+
+
+void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key)
+{
+    if(usb == 0) return;
+    Packet_t command;
+    Packet_t response;
+    int cancel = 0;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    // read SD Ram capacity
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == Pid_Capacity_Data) {
+            cout << "free memory: " << dec << (((uint32_t*)response.payload)[1] / (1024*1024)) << " MB" << endl;
+            uint32_t memory = ((uint32_t*)response.payload)[1];
+            if(memory < size) {
+                stringstream msg;
+                msg << "Failed to send map: Unit has not enought memory (available/needed): " << memory << "/" << size << " bytes";
+                throw exce_t(errRuntime,msg.str());
+            }
+        }
+    }
+
+    // send unlock key if present
+    if(key) {
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Tx_Unlock_Key;
+        command.size = strlen(key) + 1;
+        memcpy(command.payload,key,command.size);
+
+        usb->write(command);
+
+        while(usb->read(response)) {
+            if(response.id == Pid_Ack_Unlock_key) {
+                //TODO read data
+            }
+        }
+
+    }
+
+    // switch to map transfer mode erase old map(?)
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 75;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == 74) {
+            //TODO read data
+        }
+    }
+
+    callback(0,0,&cancel,"Upload maps ...",0);
+
+    FILE *fid = fopen(filename,"r");
+    if(fid == NULL) {
+        stringstream msg;
+        msg << "Failed to send map: Can't open  " << filename;
+        throw exce_t(errRuntime,msg.str());
+    }
+
+    uint32_t total  = size;
+    uint32_t offset = 0, chunkSize;
+    uint8_t  buffer[GUSB_PAYLOAD_SIZE - sizeof(offset)];
+
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 36;
+    // transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes
+    while(size && !cancel) {
+        chunkSize       = (size < (GUSB_PAYLOAD_SIZE - sizeof(offset))) ? size : (GUSB_PAYLOAD_SIZE - sizeof(offset));
+        command.size    = chunkSize + sizeof(offset);
+
+        fread(buffer, chunkSize, 1, fid);
+
+        *(uint32_t*)command.payload = offset;
+        memcpy(command.payload + sizeof(offset),buffer,chunkSize);
+        size    -= chunkSize;
+        offset  += chunkSize;
+
+        usb->write(command);
+
+        double progress = ((total - size) * 100.0) / total;
+        callback(progress,0,&cancel,0,"Transfering map data.");
+    }
+
+    callback(100,0,&cancel,0,"done");
+
+    // terminate map transfer mode (?)
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 45;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    usb->write(command);
+}
+
+
+void CDevice::_queryMap(std::list<Map_t>& maps)
+{
+    maps.clear();
+    if(usb == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    // Request map overview table
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x59;
+    command.size = 19;
+    Map_Request_t * req = (Map_Request_t*)command.payload;
+    req->dummy1 = 0;
+    req->dummy2 = 10;
+    strcpy(req->section,"MAPSOURC.MPS");
+    usb->write(command);
+
+    uint32_t size   = 1024;
+    uint32_t fill   = 0;
+    char * pData    = (char*)calloc(1,size);
+
+    while(usb->read(response)) {
+        // acknowledge request (???)
+        if(response.id == 0x5B) {
+            //TODO: read data
+        }
+
+        // chunk of MAPSOURC.MPS section
+        // Each chunk is prepended by a chunk counter of type uint8_t.
+        // This has to be skipped. That's why the peculiar math.
+        if(response.id == 0x5A) {
+            // realloc memory if chunk does not fit
+            if((fill +  response.size - 1) > size) {
+                size += size;
+                pData = (char*)realloc(pData,size);
+            }
+
+            memcpy(&pData[fill], response.payload + 1, response.size - 1);
+
+            fill += response.size - 1;
+        }
+    }
+
+    Map_Info_t * pInfo = (Map_Info_t*)pData;
+    while(pInfo->tok == 0x4C) {
+        Map_t m;
+        char * pStr = pInfo->name1;
+        m.mapName = pStr;
+        pStr += strlen(pStr) + 1;
+        m.tileName = pStr;
+
+        maps.push_back(m);
+
+        pInfo =  (Map_Info_t*)(((char*)pInfo) + pInfo->size + sizeof(pInfo->tok) + sizeof(pInfo->size));
+    }
+
+    free(pData);
+
+}
+
+
+void CDevice::_downloadWaypoints(list<Garmin::Wpt_t>& waypoints)
+{
+    waypoints.clear();
+    if(usb == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    // request waypoints
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Wpt;
+    usb->write(command);
+
+    while(1) {
+        if(!usb->read(response)) continue;
+
+        if(response.id == Pid_Records) {
+#ifdef DBG_SHOW_WAYPOINT
+            cout << "number of waypoints:" << *(int16_t*)response.payload << endl;
+#endif
+        }
+
+        if(response.id == Pid_Wpt_Data) {
+            D110_Wpt_t * srcWpt = (D110_Wpt_t*)response.payload;
+            waypoints.push_back(Wpt_t());
+            Wpt_t& tarWpt = waypoints.back();
+
+            tarWpt << *srcWpt;
+        }
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+
+    }
+
+    // request proximity waypoints
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Prx;
+    usb->write(command);
+
+    while(1) {
+
+        if(!usb->read(response)) continue;
+
+        if(response.id == Pid_Records) {
+            //TODO read data
+#ifdef DBG_SHOW_WAYPOINT
+            cout << "number of proximity waypoints:" << *(int16_t*)response.payload << endl;
+#endif
+        }
+
+        if(response.id == Pid_Prx_Wpt_Data) {
+            D110_Wpt_t * srcWpt = (D110_Wpt_t*)response.payload;
+            waypoints.push_back(Wpt_t());
+            Wpt_t& tarWpt = waypoints.back();
+
+            tarWpt << *srcWpt;
+        }
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+
+    }
+
+#ifdef DBG_SHOW_WAYPOINT
+    list<Wpt_t>::const_iterator wpt = waypoints.begin();
+    while(wpt != waypoints.end()) {
+        cout << "-------------------------" << endl;
+        cout << "class      " << hex << (int)wpt->wpt_class << endl;
+        cout << "dspl_color " << hex << (int)wpt->dspl_color << endl;
+        cout << "dspl_attr  " << hex << (int)wpt->dspl_attr << endl;
+        cout << "smbl       " << dec <<(int)wpt->smbl << endl;
+        cout << "lat        " << wpt->lat << endl;
+        cout << "lon        " << wpt->lon << endl;
+        cout << "alt        " << wpt->alt << endl;
+        cout << "dpth       " << wpt->dpth << endl;
+        cout << "dist       " << wpt->dist << endl;
+        cout << "state      " << wpt->state << endl;
+        cout << "cc         " << wpt->cc << endl;
+        cout << "ete        " << wpt->ete << endl;
+        cout << "temp       " << wpt->temp << endl;
+        cout << "time       " << wpt->time << endl;
+        cout << "category   " << wpt->wpt_cat << endl;
+        cout << "ident      " << wpt->ident << endl;
+        cout << "comment    " << wpt->comment << endl;
+        cout << "facility   " << wpt->facility << endl;
+        cout << "city       " << wpt->city << endl;
+        cout << "addr       " << wpt->addr << endl;
+        cout << "crossroad  " << wpt->crossroad << endl;
+
+        ++wpt;
+    }
+#endif
+
+}
+
+
+void CDevice::_uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints)
+{
+    if(usb == 0) return;
+    // count number of proximity waypoints
+    uint16_t prx_wpt_cnt = 0;
+    list<Wpt_t>::const_iterator wpt = waypoints.begin();
+    while(wpt != waypoints.end()) {
+        if(wpt->dist != 1e25f) ++prx_wpt_cnt;
+        ++wpt;
+    }
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    // transmit proximity waypoints first
+    if(prx_wpt_cnt) {
+        //announce number of records
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Records;
+        command.size = 2;
+        *(uint16_t*)command.payload = prx_wpt_cnt;
+        usb->write(command);
+
+        wpt = waypoints.begin();
+        while(wpt != waypoints.end()) {
+            if(wpt->dist != 1e25f) {
+                command.type = GUSB_APPLICATION_LAYER;
+                command.id   = Pid_Prx_Wpt_Data;
+
+                D110_Wpt_t * p = (D110_Wpt_t *)command.payload;
+                command.size = *wpt >> *p;
+
+                usb->write(command);
+
+            }
+            ++wpt;
+        }
+
+        //announce number of records
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Xfer_Cmplt;
+        command.size = 2;
+        *(uint16_t*)command.payload = Cmnd_Transfer_Prx;
+        usb->write(command);
+
+    }
+
+    //transmit _all_ waypoints
+    //announce number of records
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Records;
+    command.size = 2;
+    *(uint16_t*)command.payload = waypoints.size();
+    usb->write(command);
+
+    wpt = waypoints.begin();
+    while(wpt != waypoints.end()) {
+
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Wpt_Data;
+
+        D110_Wpt_t * p = (D110_Wpt_t *)command.payload;
+        command.size = *wpt >> *p;
+
+        usb->write(command);
+
+        ++wpt;
+    }
+
+    //announce number of records
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Xfer_Cmplt;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Wpt;
+    usb->write(command);
+
+}
+
+
+void CDevice::_downloadTracks(std::list<Garmin::Track_t>& tracks)
+{
+    tracks.clear();
+    if(usb == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Trk;
+    usb->write(command);
+
+    int         trackidx = 0;
+    string      name;
+    Track_t *   track = 0;
+    while(1) {
+
+        if(!usb->read(response)) continue;
+
+        if(response.id == Pid_Trk_Hdr) {
+            trackidx = 0;
+            D312_Trk_Hdr_t * hdr = (D312_Trk_Hdr_t*)response.payload;
+            tracks.push_back(Track_t());
+            track = &tracks.back();
+
+            *track << *hdr;
+            name  = hdr->ident;
+
+        }
+
+        if(response.id == Pid_Trk_Data) {
+            D302_Trk_t * data = (D302_Trk_t*)response.payload;
+            TrkPt_t pt;
+            if(data->new_trk) {
+                if(trackidx) {
+                    tracks.push_back(Track_t());
+                    Track_t& t = tracks.back();
+                    t.color = track->color;
+                    t.dspl = track->dspl;
+                    char str[256];
+                    sprintf(str,"%s_%d",name.c_str(),trackidx++);
+                    t.ident = str;
+                    track = &t;
+                }
+                else {
+                    ++trackidx;
+                }
+            }
+
+            pt << *data;
+            track->track.push_back(pt);
+        }
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+    }
+}
+
+
+void CDevice::_uploadTracks(std::list<Garmin::Track_t>& tracks)
+{
+    if(usb == 0) return;
+
+    if(devid == 0x0231) return IDeviceDefault::_uploadTracks(tracks);
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    list<Track_t>::const_iterator track = tracks.begin();
+    while(track != tracks.end()) {
+        //announce number of records
+        // D312_Rte_Hdr_t + D302_Trk_t * number of track points
+        uint16_t nrec = 1 + track->track.size() * 1;
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Records;
+        command.size = 2;
+        *(uint16_t*)command.payload = nrec;
+        usb->write(command);
+
+        // write track header
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Trk_Hdr;
+        D312_Trk_Hdr_t * r = (D312_Trk_Hdr_t *)command.payload;
+        command.size = *track >> *r;
+
+        usb->write(command);
+
+        vector<TrkPt_t>::const_iterator trkpt = track->track.begin();
+
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Trk_Data;
+        D302_Trk_t * p = (D302_Trk_t *)command.payload;
+        command.size = *trkpt >> *p;
+//        cout << "lat      " << trkpt->lat << endl;
+//        cout << "lon      " << trkpt->lon << endl;
+//        cout << "time      " << trkpt->time << endl;
+//        cout << "alt      " << trkpt->alt << endl;
+//        cout << "size      " << command.size << endl;
+
+        usb->write(command);
+
+        ++trkpt;
+
+        while(trkpt != track->track.end()) {
+
+            command.type = GUSB_APPLICATION_LAYER;
+            command.id   = Pid_Trk_Data;
+            D302_Trk_t * p = (D302_Trk_t *)command.payload;
+            command.size = *trkpt >> *p;
+            usb->write(command);
+
+            ++trkpt;
+        }
+
+        // finish block
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Xfer_Cmplt;
+        command.size = 2;
+        *(uint16_t*)command.payload = Cmnd_Transfer_Trk;
+        usb->write(command);
+        ++track;
+    }
+
+}
+
+
+void CDevice::_uploadRoutes(list<Garmin::Route_t>& routes)
+{
+    if(usb == 0) return;
+
+    if(devid == 0x0231) return IDeviceDefault::_uploadRoutes(routes);
+
+    // count number of proximity waypoints
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    list<Garmin::Route_t>::const_iterator route = routes.begin();
+    while(route != routes.end()) {
+        //announce number of records
+        // D202_Rte_Hdr_t + (D110_Wpt_t + D210_Tre_Link_t) * number of route points
+        uint16_t nrec = 1 + route->route.size() * 2;
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Records;
+        command.size = 2;
+        *(uint16_t*)command.payload = nrec;
+        usb->write(command);
+
+        // write route header
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Rte_Hdr;
+        D202_Rte_Hdr_t * r = (D202_Rte_Hdr_t *)command.payload;
+        command.size = *route >> *r;
+        usb->write(command);
+
+        vector<RtePt_t>::const_iterator rtept = route->route.begin();
+
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Rte_Wpt_Data;
+        D110_Wpt_t * p = (D110_Wpt_t *)command.payload;
+        command.size = *rtept >> *p;
+        usb->write(command);
+
+        ++rtept;
+
+        while(rtept != route->route.end()) {
+
+            command.type = GUSB_APPLICATION_LAYER;
+            command.id   = Pid_Rte_Link_Data;
+            D210_Rte_Link_t * l = (D210_Rte_Link_t *)command.payload;
+            command.size = *rtept >> *l;
+            usb->write(command);
+
+            command.type = GUSB_APPLICATION_LAYER;
+            command.id   = Pid_Rte_Wpt_Data;
+            D110_Wpt_t * p = (D110_Wpt_t *)command.payload;
+            command.size = *rtept >> *p;
+            usb->write(command);
+
+            ++rtept;
+        }
+
+        // finish block
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Xfer_Cmplt;
+        command.size = 2;
+        *(uint16_t*)command.payload = Cmnd_Transfer_Rte;
+        usb->write(command);
+        ++route;
+    }
+
+}
+
+
+void CDevice::_uploadCustomIcons(list<Garmin::Icon_t>& icons)
+{
+    if(usb == 0) return;
+
+    if(devid == 0x0231) return IDeviceDefault::_uploadCustomIcons(icons);
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    list<Garmin::Icon_t>::const_iterator icon = icons.begin();
+    while(icon != icons.end()) {
+        uint32_t tan = 0;
+
+        // get tan
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Req_Icon_Id;
+        command.size = 2;
+        *(uint16_t*)command.payload = icon->idx + 1;
+        usb->write(command);
+
+        while(usb->read(response)) {
+            if(response.id == Pid_Ack_Icon_Id) {
+                tan = *(uint32_t*)response.payload;
+            }
+        }
+
+        // request color table
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Req_Clr_Tbl;
+        command.size = 4;
+        *(uint32_t*)command.payload = tan;
+        usb->write(command);
+
+        while(usb->read(response)) {
+            if(response.id == Pid_Ack_Clr_Tbl) {
+                // send back color table
+                command = response;
+            }
+        }
+
+        usb->write(command);
+        while(usb->read(response)) {
+            if(response.id == Pid_Req_Clr_Tbl) {
+                // TODO: ignore?
+            }
+        }
+
+        // send icon data
+        command.type = GUSB_APPLICATION_LAYER;
+        command.id   = Pid_Icon_Data;
+        command.size = 0x104;
+        *(uint32_t*)command.payload = tan;
+        memcpy(command.payload + sizeof(tan),icon->data,sizeof(icon->data));
+        usb->write(command);
+
+        while(usb->read(response)) {
+            if(response.id == Pid_Ack_Icon_Data) {
+                // TODO: ignore?
+            }
+        }
+
+        ++icon;
+    }
+}
+
+
+void CDevice::_screenshot(char *& clrtbl, char *& data, int& width, int& height)
+{
+    if(usb == 0) return;
+
+    if(devid == 0x0231) return IDeviceDefault::_screenshot(clrtbl, data, width, height);
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    usb->write(command);
+
+    uint32_t tan = 0;
+
+    // get tan
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Req_Icon_Id;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == Pid_Ack_Icon_Id) {
+            tan = *(uint32_t*)response.payload;
+        }
+    }
+
+    // request color table
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Req_Clr_Tbl;
+    command.size = 4;
+    *(uint32_t*)command.payload = tan;
+    usb->write(command);
+
+    while(usb->read(response)) {
+        if(response.id == Pid_Ack_Clr_Tbl) {
+            // send back color table
+            memcpy(aClrtbl,_clrtbl,sizeof(aClrtbl));
+            command = response;
+        }
+    }
+
+    usb->write(command);
+    while(usb->read(response)) {
+        if(response.id == Pid_Req_Clr_Tbl) {
+            // TODO: ignore?
+        }
+    }
+
+    char buffer[400 * 400];
+    char * pData = buffer;
+    uint32_t byteCnt;
+    uint32_t byteCntTotal = 0;
+
+    if(pScreen == 0) {
+        pScreen = new char[screenwidth * screenheight];
+    }
+
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Ack_Icon_Data;
+    command.size = 4;
+    *(uint32_t*)command.payload = tan;
+    usb->write(command);
+
+    // loop will end after reception of Pid_Icon_Data with length of 4 (tan only)
+    // or too much data
+    while(1) {
+        if(!usb->read(response)) {
+            usb->write(command);
+            continue;
+        }
+
+        if(response.id == Pid_Icon_Data) {
+            if(response.size == sizeof(tan)) break;
+            byteCnt = response.size - sizeof(tan);
+            memcpy(pData,response.payload + sizeof(tan), byteCnt);
+            pData += byteCnt;
+            byteCntTotal += byteCnt;
+            if(byteCntTotal > sizeof(buffer)) break;
+        }
+    }
+
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = 0x373;
+    command.size = 4;
+    *(uint32_t*)command.payload = tan;
+    usb->write(command);
+
+    if(devid == 0x0312 || devid == 0x02b6) {
+        for(int r = 0; r < screenheight; ++r) {
+            for(int c = 0; c < screenwidth; ++c) {
+                pScreen[r * screenwidth + c] = buffer[(r + 1) * screenwidth - c - 1];
+            }
+        }
+    }
+    else {
+        for(int r = 0; r < screenheight; ++r) {
+            for(int c = 0; c < screenwidth; ++c) {
+                pScreen[r * screenwidth + c] = buffer[(screenheight - 1 - r) * screenwidth + c];
+            }
+        }
+    }
+
+    clrtbl  = aClrtbl;
+    data    = pScreen;
+    width   = screenwidth;
+    height  = screenheight;
+}
+
+
+void CDevice::_setRealTimeMode(bool on)
+{
+    CMutexLocker lock(dataMutex);
+    if(doRealtimeThread == on) return;
+    doRealtimeThread = on;
+    if(doRealtimeThread) {
+        pthread_create(&thread,NULL,rtThread, this);
+    }
+
+}
+
+
+void CDevice::_getRealTimePos(Garmin::Pvt_t& pvt)
+{
+    if(pthread_mutex_trylock(&mutex) != EBUSY) {
+        pthread_mutex_unlock(&mutex);
+        throw exce_t(errRuntime,lasterror);
+    }
+
+    CMutexLocker lock(dataMutex);
+    pvt = PositionVelocityTime;
+}
+
+
+void CDevice::_release()
+{
+    if(usb == 0) return;
+
+    usb->close2();
+    delete usb;
+    usb = 0;
+}
+
+
+void CDevice::_getDevProperties(Garmin::DevProperties_t& dev_properties)
+{
+    if(usb == 0) return;
+    Packet_t command;
+    Packet_t response;
+
+    // ask for SD Ram capacity
+    command.type = GUSB_APPLICATION_LAYER;
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    usb->write(command);
+
+    // try to read SD Ram capacity
+    uint32_t memory = 0;
+    uint16_t tile_limit = 0;
+    while(usb->read(response)) {
+        if(response.id == Pid_Capacity_Data) {
+            tile_limit = ((uint16_t*)response.payload)[1];
+            memory = ((uint32_t*)response.payload)[1];
+        }
+    }
+    if(tile_limit == 0) {
+        throw exce_t(errRuntime,"Failed to send map: Unable to find the tile limit of the GPS");
+    }
+    if(memory == 0) {
+        throw exce_t(errRuntime,"Failed to send map: Unable to find the available memory of the GPS");
+    }
+
+    // add to the properties list
+    properties.memory_limit = memory;
+    properties.set.item.memory_limit = 1;
+    properties.maps_limit = tile_limit;
+    properties.set.item.maps_limit = 1;
+
+    // return the properties
+    dev_properties = properties;
+}
diff --git a/src/GPSMap60CSx/CDevice.h b/src/GPSMap60CSx/CDevice.h
new file mode 100644
index 0000000..348227a
--- /dev/null
+++ b/src/GPSMap60CSx/CDevice.h
@@ -0,0 +1,84 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef CDEVICE_H
+#define CDEVICE_H
+
+#include "IDeviceDefault.h"
+#include "CUSB.h"
+
+namespace GPSMap60CSx
+{
+
+    class CDevice : public Garmin::IDeviceDefault
+    {
+        public:
+            CDevice();
+            virtual ~CDevice();
+
+            std::string devname;
+            uint32_t devid;
+            uint16_t screenwidth;
+            uint16_t screenheight;
+
+            const std::string& getCopyright();
+
+        private:
+            friend void * rtThread(void *ptr);
+
+            void _acquire();
+            void _uploadMap(const uint8_t * mapdata, uint32_t size, const char * key);
+            void _uploadMap(const char * filename, uint32_t size, const char * key);
+            void _queryMap(std::list<Garmin::Map_t>& maps);
+            void _downloadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            void _uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            void _downloadTracks(std::list<Garmin::Track_t>& tracks);
+	    void _uploadTracks(std::list<Garmin::Track_t>& tracks);
+            void _uploadRoutes(std::list<Garmin::Route_t>& routes);
+            void _uploadCustomIcons(std::list<Garmin::Icon_t>& icons);
+            void _screenshot(char *& clrtbl, char *& data, int& width, int& height);
+
+            void _getDevProperties(Garmin::DevProperties_t& dev_properties);
+
+            void _setRealTimeMode(bool on);
+            void _getRealTimePos(Garmin::Pvt_t& pvt);
+            void _release();
+
+            Garmin::CUSB * usb;
+
+            /// realtime mode thread
+            pthread_t thread;
+            /// mutex to serialize any data access
+            pthread_mutex_t dataMutex;
+            /// keep alive flag for the realtime mode thread
+            bool doRealtimeThread;
+
+            Garmin::Pvt_t PositionVelocityTime;
+
+            char aClrtbl[0x100 * 4];
+
+            //TODO: aScreen should be calculated from the actual screensize, this is just a static 400x400
+            char * pScreen;
+
+    };
+
+}
+#endif                           //CDEVICE_H
diff --git a/src/GPSMap60CSx/CMakeLists.txt b/src/GPSMap60CSx/CMakeLists.txt
new file mode 100644
index 0000000..85d6ec9
--- /dev/null
+++ b/src/GPSMap60CSx/CMakeLists.txt
@@ -0,0 +1,39 @@
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+set(SRCS
+    loader.cpp
+    CDevice.cpp
+)
+
+set(HDRS
+    CDevice.h
+)
+
+include_directories(../ ${USB_INCLUDE_DIRS})
+add_library(GPSMap60CSx SHARED ${SRCS} ${HDRS})
+target_link_libraries(GPSMap60CSx garmin ${USB_LIBRARIES} pthread)
+
+set(ALIASES
+    GPSMap60Cx
+    GPSMap60
+    EtrexVentureCx
+    EtrexVistaCx
+    GPSMap76CSx
+    EtrexVentureHC
+    EtrexSummitHC
+    EtrexVistaHCx
+    EtrexLegendHCx
+    GPSMap76Cx
+    Quest
+)
+
+foreach(var ${ALIASES})
+    message(" ${var}")
+    add_custom_command( TARGET GPSMap60CSx
+                        POST_BUILD
+                        COMMAND ln ARGS -sf libGPSMap60CSx.so lib${var}.so
+                        WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH}
+                        )
+endforeach(var)
+
diff --git a/src/GPSMap60CSx/loader.cpp b/src/GPSMap60CSx/loader.cpp
new file mode 100644
index 0000000..664c844
--- /dev/null
+++ b/src/GPSMap60CSx/loader.cpp
@@ -0,0 +1,233 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "config.h"
+#include "CDevice.h"
+
+namespace GPSMap60CSx
+{
+    static CDevice * device = 0;
+}
+
+
+#ifdef WIN32
+#define WIN_EXPORT __declspec(dllexport)
+#else
+#define WIN_EXPORT
+#endif
+
+extern "C" WIN_EXPORT Garmin::IDevice * initQuest(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "Quest SYS";
+    GPSMap60CSx::device->devid          = 0x0231;
+    GPSMap60CSx::device->screenwidth    = 240;
+    GPSMap60CSx::device->screenheight   = 160;
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initGPSMap76CSx(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "GPSMap76CSX";
+    GPSMap60CSx::device->devid          = 0x0124;
+    GPSMap60CSx::device->screenwidth    = 160;
+    GPSMap60CSx::device->screenheight   = 240;
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initGPSMap76Cx(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "GPSMap76CX";
+    GPSMap60CSx::device->devid          = 0x0124;
+    GPSMap60CSx::device->screenwidth    = 160;
+    GPSMap60CSx::device->screenheight   = 240;
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initGPSMap60CSx(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "GPSMap60CSX";
+    GPSMap60CSx::device->screenwidth    = 160;
+    GPSMap60CSx::device->screenheight   = 240;
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initGPSMap60Cx(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "GPSMap60CX";
+    GPSMap60CSx::device->devid          = 0x0124;
+    GPSMap60CSx::device->screenwidth    = 160;
+    GPSMap60CSx::device->screenheight   = 240;
+
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initGPSMap60(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "GPSMap60";
+    GPSMap60CSx::device->devid          = 0x0134;
+    GPSMap60CSx::device->screenwidth    = 160;
+    GPSMap60CSx::device->screenheight   = 240;
+
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexVentureCx(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "eTrex VentureCx";
+    GPSMap60CSx::device->devid          = 0x01a5;
+    GPSMap60CSx::device->screenwidth    = 176;
+    GPSMap60CSx::device->screenheight   = 220;
+
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexVistaCx(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "eTrex VistaCx";
+    GPSMap60CSx::device->devid          = 0x01a5;
+    GPSMap60CSx::device->screenwidth    = 176;
+    GPSMap60CSx::device->screenheight   = 220;
+
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexVentureHC(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "eTrex Venture HC";
+    //     GPSMap60CSx::device->devid          = 0x0312;
+    GPSMap60CSx::device->screenwidth    = 176;
+    GPSMap60CSx::device->screenheight   = 220;
+
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexVistaHCx(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "eTrex Vista HCx";
+    GPSMap60CSx::device->devid          = 0x02b6;
+    GPSMap60CSx::device->screenwidth    = 176;
+    GPSMap60CSx::device->screenheight   = 220;
+
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexLegendHCx(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "eTrex Legend HCx";
+    GPSMap60CSx::device->devid          = 0x0694;
+    GPSMap60CSx::device->screenwidth    = 176;
+    GPSMap60CSx::device->screenheight   = 220;
+
+    return GPSMap60CSx::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initEtrexSummitHC(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap60CSx::device == 0) {
+        GPSMap60CSx::device = new GPSMap60CSx::CDevice();
+    }
+    GPSMap60CSx::device->devname        = "eTrex Summit HC";
+    //   GPSMap60CSx::device->devid          = 0x0694;
+    GPSMap60CSx::device->screenwidth    = 176;
+    GPSMap60CSx::device->screenheight   = 220;
+
+    return GPSMap60CSx::device;
+}
diff --git a/src/GPSMap76/CDevice.cpp b/src/GPSMap76/CDevice.cpp
new file mode 100644
index 0000000..e98084f
--- /dev/null
+++ b/src/GPSMap76/CDevice.cpp
@@ -0,0 +1,773 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+
+#include "../Platform.h"
+#include "CDevice.h"
+#include <Garmin.h>
+
+#include <cstdio>
+#include <iostream>
+#include <sstream>
+
+using namespace GPSMap76;
+using namespace Garmin;
+using namespace std;
+
+#define MAP_UPLOAD_BITRATE 115200// or 57600, 38400, 19200, 9600
+
+#define WAYPOINT_DL_BITRATE 57600
+#define TRACK_DL_BITRATE 57600
+#define GRMN_DEFAULT_BITRATE 9600
+
+#define PROGR_CALLBACK(state,message) \
+callback ( state,0,0,0,message )
+
+#define PROGR_CANCEL_CALLBACK(state,message,cancel) \
+callback ( state,0,cancel,0,message )
+
+CDevice::CDevice()
+: serial(0)
+{
+
+}
+
+
+CDevice::~CDevice()
+{
+
+}
+
+
+const string& CDevice::getCopyright()
+{
+    copyright = "<h1>QLandkarte Device Driver for GPSMap76 (EXPERIMENTAL)</h1>"
+        "<h2>Driver I/F Ver. " INTERFACE_VERSION "</h2>"
+        "<p>© 2007 by Oliver Eichler (oliver.eichler at gmx.de)</p>"
+        "<p>modified 2008 by Andreas Stenglein to work with serial GPSMap76</p>"
+        "<p>This driver 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. </p>";
+    return copyright;
+}
+
+
+void CDevice::_acquire()
+{
+#if defined(WORDS_BIGENDIAN) || !defined(CAN_UNALIGNED)
+    throw exce_t(errSync, "This device has not yet been ported to your platform.");
+#endif
+    PROGR_CALLBACK ( 0,"acquiring" );
+
+    serial = new CSerial(port);
+
+    PROGR_CALLBACK ( 1,"acquiring ...");
+
+    serial->open();
+    serial->syncup();
+
+    if(strncmp(serial->getProductString().c_str(), devname.c_str(), devname.size()) != 0) {
+        string msg = "No " + devname + " unit detected. Please retry to select other device driver.";
+        throw exce_t(errSync,msg);
+    }
+
+    if(devid) {
+        if(serial->getProductId() != devid) {
+            string msg = "No " + devname + " unit detected. Please retry to select other device driver.";
+            throw exce_t(errSync,msg);
+        }
+    }
+    else {
+        string msg = "No " + devname + " unit detected. Please retry to select other device driver.";
+        throw exce_t(errSync,msg);
+    }
+
+}
+
+
+void CDevice::_uploadMap(const uint8_t * mapdata, uint32_t size, const char * /*key*/)
+{
+    if(serial == 0) return;
+    int ready= 0;
+    int cancel = 0;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+    // read SD Ram capacity
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    serial->write(command);
+
+                                 // FIXME:
+    while(serial->read(response) > 0) {
+
+        if(response.id == Pid_Capacity_Data) {
+            cout << "free memory: " << dec << (((uint32_t*)response.payload)[1] / (1024*1024)) << " MB" << endl;
+            uint32_t memory = ((uint32_t*)response.payload)[1];
+            if(memory < size) {
+                stringstream msg;
+                msg << "Failed to send map: Unit has not enought memory (available/needed): " << memory << "/" << size << " bytes";
+                throw exce_t(errBlocked,msg.str());
+            }
+        }
+    }
+
+#ifdef EXPERIMENTAL
+    // KEY_UPLOAD: UNTESTED: someone should check how/if this works
+    // send unlock key if present
+    if(key) {
+        command.id   = Pid_Tx_Unlock_Key;
+        command.size = strlen(key) + 1;
+        memcpy(command.payload,key,command.size);
+
+        serial->write(command);
+
+                                 // FIXME:
+        while(serial->read(response) > 0 ) {
+            if(response.id == Pid_Ack_Unlock_key) {
+                //TODO read data
+            }
+        }
+
+    }
+#endif
+
+    if (serial->setBitrate( MAP_UPLOAD_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+
+    // switch to map transfer mode erase old map(?)
+    command.id   = 75;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    serial->write(command);
+
+    ready= 0;
+    serial->readTimeout( 5000);
+    while(!ready && serial->read(response) > 0) {
+        if(response.id == 74) {
+            ready= 1;
+            //TODO read data
+        }
+    }
+    serial->readTimeout( 1000);
+
+    callback(0,0,&cancel,"Upload maps ...",0);
+
+    uint32_t total  = size;
+    uint32_t offset = 0, chunkSize;
+    command.id   = 36;
+    // USB:    transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes
+    // Serial: transfer file by chunks of 0xfe - sizeof(offset) =  0xfa = 250 bytes
+    while(size && !cancel) {
+        chunkSize       = (size < (254 - sizeof(offset))) ? size : (254 - sizeof(offset));
+        command.size    = chunkSize + sizeof(offset);
+
+        *(uint32_t*)command.payload = offset;
+        memcpy(command.payload + sizeof(offset),mapdata,chunkSize);
+        size    -= chunkSize;
+        mapdata += chunkSize;
+        offset  += chunkSize;
+
+        serial->write(command);
+        // set progress
+        double progress = ((total - size) * 100.0) / total;
+        callback(progress,0,&cancel,0,"Transfering map data.");
+
+    }
+
+    callback(100,0,&cancel,0,"done");
+
+    // terminate map transfer mode (?)
+    command.id   = 45;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    serial->write(command);
+}
+
+
+void CDevice::_uploadMap(const char * filename, uint32_t size, const char * key)
+{
+    if(serial == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+    int cancel = 0;
+    int ready= 0;
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+    // read SD Ram capacity
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    serial->write(command);
+
+    while(serial->read(response) > 0) {
+        if(response.id == Pid_Capacity_Data) {
+            cout << "free memory: " << dec << (((uint32_t*)response.payload)[1] / (1024*1024)) << " MB" << endl;
+            uint32_t memory = ((uint32_t*)response.payload)[1];
+            if(memory < size) {
+                stringstream msg;
+                msg << "Failed to send map: Unit has not enought memory (available/needed): " << memory << "/" << size << " bytes";
+                throw exce_t(errRuntime,msg.str());
+            }
+        }
+    }
+
+#ifdef EXPERIMENTAL
+    // KEY_UPLOAD: UNTESTED: someone should check how/if this works
+    // send unlock key if present
+    if(key) {
+        command.id   = Pid_Tx_Unlock_Key;
+        command.size = strlen(key) + 1;
+        memcpy(command.payload,key,command.size);
+
+        serial->write(command);
+
+        while(serial->read(response) > 0) {
+            if(response.id == Pid_Ack_Unlock_key) {
+                //TODO read data
+            }
+        }
+
+    }
+#endif
+
+    if (serial->setBitrate( MAP_UPLOAD_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+
+    // switch to map transfer mode erase old map(?)
+    command.id   = 75;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    serial->write(command);
+
+    ready= 0;
+    serial->readTimeout( 5000);
+    while(!ready && serial->read(response) > 0) {
+        if(response.id == 74) {
+            ready = 1;
+            //TODO read data
+        }
+    }
+    serial->readTimeout( 1000);
+
+    callback(0,0,&cancel,"Upload maps ...",0);
+
+    FILE *fid = fopen(filename,"r");
+    if(fid == NULL) {
+        stringstream msg;
+        msg << "Failed to send map: Can't open  " << filename;
+        throw exce_t(errRuntime,msg.str());
+    }
+
+    uint32_t total  = size;
+    uint32_t offset = 0, chunkSize;
+    uint8_t  buffer[GUSB_PAYLOAD_SIZE - sizeof(offset)];
+
+    command.id   = 36;
+    // USB:    transfer file by chunks of 0x1000 - 0x0000C - sizeof(offset) = 0x0FF0 bytes
+    // Serial: transfer file by chunks of 0xfe - sizeof(offset) =  0xfa = 250 bytes
+    while(size && !cancel) {
+        chunkSize       = (size < (254 - sizeof(offset))) ? size : (254 - sizeof(offset));
+        command.size    = chunkSize + sizeof(offset);
+
+        fread(buffer, chunkSize, 1, fid);
+
+        *(uint32_t*)command.payload = offset;
+        memcpy(command.payload + sizeof(offset),buffer,chunkSize);
+        size    -= chunkSize;
+        offset  += chunkSize;
+
+        serial->write(command);
+
+        double progress = ((total - size) * 100.0) / total;
+        callback(progress,0,&cancel,0,"Transfering map data.");
+    }
+
+    callback(100,0,&cancel,0,"done");
+
+    // terminate map transfer mode (?)
+    command.id   = 45;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x000A;
+    serial->write(command);
+}
+
+
+void CDevice::_queryMap(std::list<Map_t>& maps)
+{
+    maps.clear();
+    if(serial == 0) return;
+
+    Packet_t command;
+    Packet_t response;
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+    // Request map overview table
+    command.id   = 0x59;
+    command.size = 19;
+    Map_Request_t * req = (Map_Request_t*)command.payload;
+    req->dummy1 = 0;
+    req->dummy2 = 10;
+    strcpy(req->section,"MAPSOURC.MPS");
+    serial->write(command);
+
+    uint32_t size   = 1024;
+    uint32_t fill   = 0;
+    char * pData    = (char*)calloc(1,size);
+
+    while(serial->read(response)) {
+        // acknowledge request (???)
+        if(response.id == 0x5B) {
+            //TODO: read data
+        }
+
+        // chunk of MAPSOURC.MPS section
+        // Each chunk is prepended by a chunk counter of type uint8_t.
+        // This has to be skipped. That's why the peculiar math.
+        if(response.id == 0x5A) {
+            // realloc memory if chunk does not fit
+            if((fill +  response.size - 1) > size) {
+                size += size;
+                pData = (char*)realloc(pData,size);
+            }
+
+            memcpy(&pData[fill], response.payload + 1, response.size - 1);
+
+            fill += response.size - 1;
+        }
+    }
+
+    Map_Info_t * pInfo = (Map_Info_t*)pData;
+    while(pInfo->tok == 0x4C) {
+        Map_t m;
+        char * pStr = pInfo->name1;
+        m.mapName = pStr;
+        pStr += strlen(pStr) + 1;
+        m.tileName = pStr;
+
+        maps.push_back(m);
+
+        pInfo =  (Map_Info_t*)(((char*)pInfo) + pInfo->size + sizeof(pInfo->tok) + sizeof(pInfo->size));
+    }
+
+    free(pData);
+}
+
+
+void CDevice::_downloadWaypoints(list<Garmin::Wpt_t>& waypoints)
+{
+    waypoints.clear();
+    if(serial == 0) return;
+
+    PROGR_CALLBACK ( 2,"Downloading waypoints ..." );
+
+    Packet_t command;
+    Packet_t response;
+
+    unsigned int nwpts = 0;
+    unsigned int cnt = 0;
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( WAYPOINT_DL_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+#endif
+    // request waypoints
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Wpt;
+    serial->write(command);
+
+    PROGR_CALLBACK ( 5,"Downloading waypoints ..." );
+
+    while(1) {
+        if(!serial->read(response)) continue;
+
+        if(response.id == Pid_Records) {
+            nwpts = *(uint16_t*)response.payload;
+#ifdef DBG_SHOW_WAYPOINT
+            cout << "number of waypoints:" << *(int16_t*)response.payload << endl;
+#endif
+        }
+
+        if(response.id == Pid_Wpt_Data) {
+            D109_Wpt_t * srcWpt = (D109_Wpt_t*)response.payload;
+            waypoints.push_back(Wpt_t());
+            Wpt_t& tarWpt = waypoints.back();
+
+            tarWpt << *srcWpt;
+
+            ++cnt;
+            if (nwpts)
+                PROGR_CALLBACK ( 5 + ( cnt * 94 / nwpts ),"Downloading waypoints ..." );
+        }
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+
+    }
+
+    // unsupported by etrex Legend ?
+#if 1
+    // request proximity waypoints
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Prx;
+    serial->write(command);
+
+    while(1) {
+
+        if(!serial->read(response)) continue;
+
+        if(response.id == Pid_Records) {
+            //TODO read data
+#ifdef DBG_SHOW_WAYPOINT
+            cout << "number of proximity waypoints:" << *(int16_t*)response.payload << endl;
+#endif
+        }
+
+        if(response.id == Pid_Prx_Wpt_Data) {
+            D109_Wpt_t * srcWpt = (D109_Wpt_t*)response.payload;
+            waypoints.push_back(Wpt_t());
+            Wpt_t& tarWpt = waypoints.back();
+
+            tarWpt << *srcWpt;
+        }
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+
+    }
+#endif
+
+#ifdef DBG_SHOW_WAYPOINT
+    list<Wpt_t>::const_iterator wpt = waypoints.begin();
+    while(wpt != waypoints.end()) {
+        cout << "-------------------------" << endl;
+        cout << "class      " << hex << (int)wpt->wpt_class << endl;
+        cout << "dspl_color " << hex << (int)wpt->dspl_color << endl;
+        cout << "dspl_attr  " << hex << (int)wpt->dspl_attr << endl;
+        cout << "smbl       " << dec <<(int)wpt->smbl << endl;
+        cout << "lat        " << wpt->lat << endl;
+        cout << "lon        " << wpt->lon << endl;
+        cout << "alt        " << wpt->alt << endl;
+        cout << "dpth       " << wpt->dpth << endl;
+        cout << "dist       " << wpt->dist << endl;
+        cout << "state      " << wpt->state << endl;
+        cout << "cc         " << wpt->cc << endl;
+        cout << "ete        " << wpt->ete << endl;
+        cout << "temp       " << wpt->temp << endl;
+        cout << "time       " << wpt->time << endl;
+        cout << "category   " << wpt->wpt_cat << endl;
+        cout << "ident      " << wpt->ident << endl;
+        cout << "comment    " << wpt->comment << endl;
+        cout << "facility   " << wpt->facility << endl;
+        cout << "city       " << wpt->city << endl;
+        cout << "addr       " << wpt->addr << endl;
+        cout << "crossroad  " << wpt->crossroad << endl;
+
+        ++wpt;
+    }
+#endif
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( GRMN_DEFAULT_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+#endif
+    PROGR_CALLBACK( 100,"Download complete" );
+}
+
+
+void CDevice::_uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints)
+{
+    if(serial == 0) return;
+
+    PROGR_CALLBACK ( 2,"Uploading waypoints ..." );
+
+    uint16_t prx_wpt_cnt = 0;
+    list<Wpt_t>::const_iterator wpt = waypoints.begin();
+
+    // does etrex Legend support prx waypoints?
+    while(wpt != waypoints.end()) {
+        if(wpt->dist != 1e25f) ++prx_wpt_cnt;
+        ++wpt;
+    }
+
+    Packet_t command;
+    Packet_t response;
+
+    unsigned int packcntr = 0;
+    unsigned int npacks = waypoints.size();
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( WAYPOINT_DL_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+#endif
+    // transmit proximity waypoints first
+    if(prx_wpt_cnt) {
+        //announce number of records
+        command.id   = Pid_Records;
+        command.size = 2;
+        *(uint16_t*)command.payload = prx_wpt_cnt;
+        serial->write(command);
+
+        wpt = waypoints.begin();
+        while(wpt != waypoints.end()) {
+            if(wpt->dist != 1e25f) {
+                command.id   = Pid_Prx_Wpt_Data;
+
+                D109_Wpt_t * p = (D109_Wpt_t *)command.payload;
+                command.size = *wpt >> *p;
+
+                serial->write(command);
+
+            }
+            ++wpt;
+        }
+
+        //announce number of records
+        command.id   = Pid_Xfer_Cmplt;
+        command.size = 2;
+        *(uint16_t*)command.payload = Cmnd_Transfer_Prx;
+        serial->write(command);
+
+    }
+
+    //transmit _all_ waypoints
+    //announce number of records
+    command.id   = Pid_Records;
+    command.size = 2;
+    *(uint16_t*)command.payload = waypoints.size();
+    serial->write(command);
+
+    PROGR_CALLBACK ( 5,"Uploading waypoints ..." );
+
+    wpt = waypoints.begin();
+    while(wpt != waypoints.end()) {
+        ++packcntr;
+
+        command.id   = Pid_Wpt_Data;
+
+        D109_Wpt_t * p = (D109_Wpt_t *)command.payload;
+        command.size = *wpt >> *p;
+
+        serial->write(command);
+
+        ++wpt;
+
+        if ( npacks )
+            PROGR_CALLBACK ( 5 + (packcntr * 94 / npacks),"Uploading waypoints ..." );
+    }
+
+    //announce number of records
+    command.id   = Pid_Xfer_Cmplt;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Wpt;
+    serial->write(command);
+
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( GRMN_DEFAULT_BITRATE)) {
+        throw exce_t(errBlocked,"Failed to change serial link to xxx bit per second");
+    }
+#endif
+    PROGR_CALLBACK ( 100,"Upload complete" );
+}
+
+
+void CDevice::_downloadTracks(std::list<Garmin::Track_t>& tracks)
+{
+    tracks.clear();
+    if(serial == 0) return;
+
+    PROGR_CALLBACK ( 2,"Downloading tracks ..." );
+
+    Packet_t command;
+    Packet_t response;
+
+    unsigned int npacks = 0;
+    unsigned int packcntr = 0;
+
+    // ???
+    command.id   = 0x1C;
+    command.size = 2;
+    *(uint16_t*)command.payload = 0x0000;
+    serial->write(command);
+
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( TRACK_DL_BITRATE)) {
+        throw exce_t(errBlocked, "Failed to change serial link to xxx bit per second");
+    }
+#endif
+
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Trk;
+    serial->write(command);
+
+    PROGR_CALLBACK ( 3,"Downloading tracks ..." );
+
+    int         trackidx = 0;
+    string      name;
+    Track_t *   track = 0;
+    while(1) {
+
+        if(!serial->read(response)) continue;
+
+        if ( response.id == Pid_Records )
+            npacks = *(uint16_t*)response.payload;
+
+        if(response.id == Pid_Trk_Hdr) {
+            ++packcntr;
+            trackidx = 0;
+            D310_Trk_Hdr_t * hdr = (D310_Trk_Hdr_t*)response.payload;
+            tracks.push_back(Track_t());
+            track = &tracks.back();
+
+            *track << *hdr;
+            name  = hdr->ident;
+
+        }
+
+        if(response.id == Pid_Trk_Data) {
+            ++packcntr;
+            D301_Trk_t * data = (D301_Trk_t*)response.payload;
+            TrkPt_t pt;
+            if(data->new_trk) {
+                if(trackidx) {
+                    tracks.push_back(Track_t());
+                    Track_t& t = tracks.back();
+                    t.color = track->color;
+                    t.dspl = track->dspl;
+                    char str[256];
+                    sprintf(str,"%s_%d",name.c_str(),trackidx++);
+                    t.ident = str;
+                    track = &t;
+                }
+                else {
+                    ++trackidx;
+                }
+            }
+
+            pt << *data;
+            track->track.push_back(pt);
+        }
+
+        if ( npacks )
+            PROGR_CALLBACK ( 3 + (packcntr * 96 / npacks),"Downloading tracks ..." );
+
+        if(response.id == Pid_Xfer_Cmplt) {
+            break;
+        }
+    }
+#ifdef EXPERIMENTAL
+    if (serial->setBitrate( GRMN_DEFAULT_BITRATE)) {
+        throw exce_t(errBlocked, "Failed to change serial link to xxx bit per second");
+    }
+#endif
+    PROGR_CALLBACK ( 100,"Download complete" );
+}
+
+
+void CDevice::_release()
+{
+    if(serial == 0) return;
+
+    serial->close();
+    delete serial;
+    serial = 0;
+}
+
+
+// just copied from GPSMAP60CSX driver, 20081006
+void CDevice::_getDevProperties(Garmin::DevProperties_t& dev_properties)
+{
+    if(serial == 0) return;
+    Packet_t command;
+    Packet_t response;
+
+    // ask for SD Ram capacity
+    command.id   = Pid_Command_Data;
+    command.size = 2;
+    *(uint16_t*)command.payload = Cmnd_Transfer_Mem;
+    serial->write(command);
+
+    // try to read SD Ram capacity
+    uint32_t memory = 0;
+    uint16_t tile_limit = 0;
+    while(serial->read(response)) {
+        if(response.id == Pid_Capacity_Data) {
+            tile_limit = ((uint16_t*)response.payload)[1];
+            memory = ((uint32_t*)response.payload)[1];
+        }
+    }
+    if(tile_limit == 0) {
+        throw exce_t(errRuntime,"Failed to send map: Unable to find the tile limit of the GPS");
+    }
+    if(memory == 0) {
+        throw exce_t(errRuntime,"Failed to send map: Unable to find the available memory of the GPS");
+    }
+
+    // add to the properties list
+    properties.memory_limit = memory;
+    properties.set.item.memory_limit = 1;
+    properties.maps_limit = tile_limit;
+    properties.set.item.maps_limit = 1;
+
+    // return the properties
+    dev_properties = properties;
+}
diff --git a/src/GPSMap76/CDevice.h b/src/GPSMap76/CDevice.h
new file mode 100644
index 0000000..08cdbd0
--- /dev/null
+++ b/src/GPSMap76/CDevice.h
@@ -0,0 +1,59 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef CDEVICE_H
+#define CDEVICE_H
+
+#include "IDeviceDefault.h"
+#include "CSerial.h"
+
+namespace GPSMap76
+{
+
+    class CDevice : public Garmin::IDeviceDefault
+    {
+        public:
+            CDevice();
+            virtual ~CDevice();
+
+            std::string devname;
+            uint32_t devid;
+
+            const std::string& getCopyright();
+
+        private:
+            void _acquire();
+            void _uploadMap(const uint8_t * mapdata, uint32_t size, const char * key);
+            void _uploadMap(const char * filename, uint32_t size, const char * key);
+            void _queryMap(std::list<Garmin::Map_t>& maps);
+            void _downloadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            void _uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            void _downloadTracks(std::list<Garmin::Track_t>& tracks);
+
+            void _getDevProperties(Garmin::DevProperties_t& dev_properties);
+
+            void _release();
+
+            Garmin::CSerial * serial;
+    };
+
+}
+#endif                           //CDEVICE_H
diff --git a/src/GPSMap76/CMakeLists.txt b/src/GPSMap76/CMakeLists.txt
new file mode 100644
index 0000000..dbb7bd0
--- /dev/null
+++ b/src/GPSMap76/CMakeLists.txt
@@ -0,0 +1,31 @@
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+set(SRCS
+    loader.cpp
+    CDevice.cpp
+)
+
+set(HDRS
+    CDevice.h
+)
+
+include_directories(../)
+add_library(GPSMap76 SHARED ${SRCS} ${HDRS})
+target_link_libraries(GPSMap76 garmin pthread)
+
+set(ALIASES
+    GPSMap76S
+    Rino120
+)
+
+
+foreach(var ${ALIASES})
+    message(" ${var}")
+    add_custom_command( TARGET GPSMap76
+                        POST_BUILD
+                        COMMAND ln ARGS -sf libGPSMap76.so lib${var}.so
+                        WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH}
+                        )
+endforeach(var)
+
diff --git a/src/GPSMap76/loader.cpp b/src/GPSMap76/loader.cpp
new file mode 100644
index 0000000..95baeb7
--- /dev/null
+++ b/src/GPSMap76/loader.cpp
@@ -0,0 +1,76 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "config.h"
+#include "CDevice.h"
+
+namespace GPSMap76
+{
+    static CDevice * device = 0;
+}
+
+
+#ifdef WIN32
+#define WIN_EXPORT __declspec(dllexport)
+#else
+#define WIN_EXPORT
+#endif
+
+extern "C" WIN_EXPORT Garmin::IDevice * initGPSMap76(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap76::device == 0) {
+        GPSMap76::device = new GPSMap76::CDevice();
+    }
+    GPSMap76::device->devname = "GPSMAP 76";
+    GPSMap76::device->devid = 439;
+    return GPSMap76::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initGPSMap76S(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap76::device == 0) {
+        GPSMap76::device = new GPSMap76::CDevice();
+    }
+    GPSMap76::device->devname = "GPSMAP 76S";
+    GPSMap76::device->devid = 194;
+    return GPSMap76::device;
+}
+
+
+extern "C" WIN_EXPORT Garmin::IDevice * initRino120(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(GPSMap76::device == 0) {
+        GPSMap76::device = new GPSMap76::CDevice();
+    }
+    GPSMap76::device->devname = "Rino 120";
+    GPSMap76::device->devid = 264;
+    return GPSMap76::device;
+}
diff --git a/src/Garmin.cpp b/src/Garmin.cpp
new file mode 100644
index 0000000..4bf4479
--- /dev/null
+++ b/src/Garmin.cpp
@@ -0,0 +1,409 @@
+/* -*-mode:c++; c-style:k&r; c-basic-offset:4; -*- */
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include <math.h>
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "Garmin.h"
+#include "IDevice.h"
+
+#define INT32_TO_DEG(x) ((double)((int32_t)(x)) * 360.0 / 4294967296.0)
+#define DEG_TO_INT32(x) ((int32_t)((x) * 4294967296.0/360.0 + 0.5))
+
+#define FLOAT64_TO_DEG(x) ((x) * 180.0/M_PI)
+
+namespace Garmin
+{
+    // note: all D1xx_Wpt_t are properly aligned, so we can use the simple macros here
+    void operator<<(Wpt_t& tar, const D108_Wpt_t& src) {
+        tar.wpt_class    = src.wpt_class;
+        tar.dspl_color   = src.color;
+        tar.dspl_attr    = src.dspl;
+        tar.smbl         = gar_endian(uint16_t, src.smbl);
+        tar.lat          = INT32_TO_DEG(gar_endian(int32_t, src.lat));
+        tar.lon          = INT32_TO_DEG(gar_endian(int32_t, src.lon));
+        tar.alt          = gar_endian(float, src.alt);
+        tar.dpth         = gar_endian(float, src.dpth);
+        tar.dist         = gar_endian(float, src.dist);
+        tar.state[0]     = src.state[0];
+        tar.state[1]     = src.state[1];
+        tar.state[2]     = 0;
+        tar.cc[0]        = src.cc[0];
+        tar.cc[1]        = src.cc[1];
+        tar.cc[2]        = 0;
+        tar.ete          = 0;    // not available
+
+        const char* p = src.str;
+        tar.ident = p;
+        p += strlen(p) + 1;
+        tar.comment = p;
+        p += strlen(p) + 1;
+        tar.facility = p;
+        p += strlen(p) + 1;
+        tar.city = p;
+        p += strlen(p) + 1;
+        tar.addr = p;
+        p += strlen(p) + 1;
+        tar.crossroad = p;
+    }
+
+    int operator>>(const Wpt_t& src, D108_Wpt_t& tar) {
+        tar.wpt_class    = src.wpt_class;
+        tar.color        = src.dspl_color;
+        tar.dspl         = src.dspl_attr;
+        tar.attr         = 0x60; // according to iop_spec.pdf
+        tar.smbl         = gar_endian(uint16_t, src.smbl);
+        tar.subclass[0]  = 0x00;
+        tar.subclass[1]  = 0x00;
+        tar.subclass[2]  = 0x00;
+        tar.subclass[3]  = 0x00;
+        tar.subclass[4]  = 0x00;
+        tar.subclass[5]  = 0x00;
+        tar.subclass[6]  = 0xFF;
+        tar.subclass[7]  = 0xFF;
+        tar.subclass[8]  = 0xFF;
+        tar.subclass[9]  = 0xFF;
+        tar.subclass[10] = 0xFF;
+        tar.subclass[11] = 0xFF;
+        tar.subclass[12] = 0xFF;
+        tar.subclass[13] = 0xFF;
+        tar.subclass[14] = 0xFF;
+        tar.subclass[15] = 0xFF;
+        tar.subclass[16] = 0xFF;
+        tar.subclass[17] = 0xFF;
+        tar.lat          = gar_endian(int32_t, DEG_TO_INT32(src.lat));
+        tar.lon          = gar_endian(int32_t, DEG_TO_INT32(src.lon));
+        tar.alt          = gar_endian(float, src.alt);
+        tar.dpth         = gar_endian(float, src.dpth);
+        tar.dist         = gar_endian(float, src.dist);
+        tar.state[0]     = src.state[0];
+        tar.state[1]     = src.state[1];
+        tar.state[2]     = 0;
+        tar.cc[0]        = src.cc[0];
+        tar.cc[1]        = src.cc[1];
+        tar.cc[2]        = 0;
+
+        char * pStr     = tar.str;
+
+        strcpy(pStr,src.ident.c_str());
+        pStr += src.ident.length() + 1;
+        strcpy(pStr,src.comment.c_str());
+        pStr += src.comment.length() + 1;
+        strcpy(pStr,src.facility.c_str());
+        pStr += src.facility.length() + 1;
+        strcpy(pStr,src.city.c_str());
+        pStr += src.city.length() + 1;
+        strcpy(pStr,src.addr.c_str());
+        pStr += src.addr.length() + 1;
+        strcpy(pStr,src.crossroad.c_str());
+        pStr += src.crossroad.length() + 1;
+
+                                 // size of packet
+        return pStr - (char*)&tar.wpt_class;
+    }
+
+    void operator<<(Wpt_t& tar, const D109_Wpt_t& src) {
+        tar.wpt_class    = src.wpt_class;
+        tar.dspl_color   = src.dspl_color & 0x1F;
+        tar.dspl_attr    = (src.dspl_color & 0x70) >> 5;
+        tar.smbl         = gar_endian(uint16_t, src.smbl);
+        tar.lat          = INT32_TO_DEG(gar_endian(int32_t, src.lat));
+        tar.lon          = INT32_TO_DEG(gar_endian(int32_t, src.lon));
+        tar.alt          = gar_endian(float, src.alt);
+        tar.dpth         = gar_endian(float, src.dpth);
+        tar.dist         = gar_endian(float, src.dist);
+        tar.state[0]     = src.state[0];
+        tar.state[1]     = src.state[1];
+        tar.state[2]     = 0;
+        tar.cc[0]        = src.cc[0];
+        tar.cc[1]        = src.cc[1];
+        tar.cc[2]        = 0;
+        tar.ete          = gar_endian(uint32_t, src.ete);
+
+        const char* p = src.str;
+        tar.ident = p;
+        p += strlen(p) + 1;
+        tar.comment = p;
+        p += strlen(p) + 1;
+        tar.facility = p;
+        p += strlen(p) + 1;
+        tar.city = p;
+        p += strlen(p) + 1;
+        tar.addr = p;
+        p += strlen(p) + 1;
+        tar.crossroad = p;
+    }
+
+    int operator>>(const Wpt_t& src, D109_Wpt_t& tar) {
+        tar.dtyp         = 0x01;
+        tar.wpt_class    = src.wpt_class;
+        tar.dspl_color   = (src.dspl_color | (src.dspl_attr << 5)) & 0x7F;
+        tar.attr         = 0x70;
+        tar.smbl         = gar_endian(uint16_t, src.smbl);
+        tar.subclass[0]  = 0x00;
+        tar.subclass[1]  = 0x00;
+        tar.subclass[2]  = 0x00;
+        tar.subclass[3]  = 0x00;
+        tar.subclass[4]  = 0x00;
+        tar.subclass[5]  = 0x00;
+        tar.subclass[6]  = 0xFF;
+        tar.subclass[7]  = 0xFF;
+        tar.subclass[8]  = 0xFF;
+        tar.subclass[9]  = 0xFF;
+        tar.subclass[10] = 0xFF;
+        tar.subclass[11] = 0xFF;
+        tar.subclass[12] = 0xFF;
+        tar.subclass[13] = 0xFF;
+        tar.subclass[14] = 0xFF;
+        tar.subclass[15] = 0xFF;
+        tar.subclass[16] = 0xFF;
+        tar.subclass[17] = 0xFF;
+        tar.lat          = gar_endian(int32_t, DEG_TO_INT32(src.lat));
+        tar.lon          = gar_endian(int32_t, DEG_TO_INT32(src.lon));
+        tar.alt          = gar_endian(float, src.alt);
+        tar.dpth         = gar_endian(float, src.dpth);
+        tar.dist         = gar_endian(float, src.dist);
+        tar.state[0]     = src.state[0];
+        tar.state[1]     = src.state[1];
+        tar.state[2]     = 0;
+        tar.cc[0]        = src.cc[0];
+        tar.cc[1]        = src.cc[1];
+        tar.cc[2]        = 0;
+        tar.ete          = gar_endian(uint32_t, src.ete);
+
+        char * pStr     = tar.str;
+
+        strcpy(pStr,src.ident.c_str());
+        pStr += src.ident.length() + 1;
+        strcpy(pStr,src.comment.c_str());
+        pStr += src.comment.length() + 1;
+        strcpy(pStr,src.facility.c_str());
+        pStr += src.facility.length() + 1;
+        strcpy(pStr,src.city.c_str());
+        pStr += src.city.length() + 1;
+        strcpy(pStr,src.addr.c_str());
+        pStr += src.addr.length() + 1;
+        strcpy(pStr,src.crossroad.c_str());
+        pStr += src.crossroad.length() + 1;
+
+        return pStr - (char*)&tar.dtyp;
+    }
+
+    void operator<<(Wpt_t& tar, const D110_Wpt_t& src) {
+        tar.wpt_class    = src.wpt_class;
+        tar.dspl_color   = src.dspl_color & 0x1F;
+        tar.dspl_attr    = (src.dspl_color & 0x60) >> 5;
+        tar.smbl         = gar_endian(uint16_t, src.smbl);
+        tar.lat          = INT32_TO_DEG(gar_endian(int32_t, src.lat));
+        tar.lon          = INT32_TO_DEG(gar_endian(int32_t, src.lon));
+        tar.alt          = gar_endian(float, src.alt);
+        tar.dpth         = gar_endian(float, src.dpth);
+        tar.dist         = gar_endian(float, src.dist);
+        tar.state[0]     = src.state[0];
+        tar.state[1]     = src.state[1];
+        tar.state[2]     = 0;
+        tar.cc[0]        = src.cc[0];
+        tar.cc[1]        = src.cc[1];
+        tar.cc[2]        = 0;
+        tar.ete          = gar_endian(uint32_t, src.ete);
+        tar.temp         = gar_endian(float, src.temp);
+        tar.time         = gar_endian(uint32_t, src.time);
+        tar.wpt_cat      = gar_endian(uint16_t, src.wpt_cat);
+
+        const char* p = src.str;
+        tar.ident = p;
+        p += strlen(p) + 1;
+        tar.comment = p;
+        p += strlen(p) + 1;
+        tar.facility = p;
+        p += strlen(p) + 1;
+        tar.city = p;
+        p += strlen(p) + 1;
+        tar.addr = p;
+        p += strlen(p) + 1;
+        tar.crossroad = p;
+    }
+
+    int operator>>(const Wpt_t& src, D110_Wpt_t& tar) {
+        tar.dtyp         = 0x01;
+        tar.wpt_class    = src.wpt_class;
+        tar.dspl_color   = (src.dspl_color | (src.dspl_attr << 5)) & 0x7F;
+        tar.attr         = 0x80;
+        tar.smbl         = gar_endian(uint16_t, src.smbl);
+        tar.subclass[0]  = 0x00;
+        tar.subclass[1]  = 0x00;
+        tar.subclass[2]  = 0x00;
+        tar.subclass[3]  = 0x00;
+        tar.subclass[4]  = 0x00;
+        tar.subclass[5]  = 0x00;
+        tar.subclass[6]  = 0xFF;
+        tar.subclass[7]  = 0xFF;
+        tar.subclass[8]  = 0xFF;
+        tar.subclass[9]  = 0xFF;
+        tar.subclass[10] = 0xFF;
+        tar.subclass[11] = 0xFF;
+        tar.subclass[12] = 0xFF;
+        tar.subclass[13] = 0xFF;
+        tar.subclass[14] = 0xFF;
+        tar.subclass[15] = 0xFF;
+        tar.subclass[16] = 0xFF;
+        tar.subclass[17] = 0xFF;
+        tar.lat          = gar_endian(int32_t, DEG_TO_INT32(src.lat));
+        tar.lon          = gar_endian(int32_t, DEG_TO_INT32(src.lon));
+        tar.alt          = gar_endian(float, src.alt);
+        tar.dpth         = gar_endian(float, src.dpth);
+        tar.dist         = gar_endian(float, src.dist);
+        tar.state[0]     = src.state[0];
+        tar.state[1]     = src.state[1];
+        tar.state[2]     = 0;
+        tar.cc[0]        = src.cc[0];
+        tar.cc[1]        = src.cc[1];
+        tar.cc[2]        = 0;
+        tar.ete          = gar_endian(uint32_t, src.ete);
+        tar.temp         = gar_endian(float, src.temp);
+        tar.time         = gar_endian(uint32_t, src.time);
+        tar.wpt_cat      = gar_endian(uint16_t, src.wpt_cat);
+
+        char * pStr     = tar.str;
+
+        strcpy(pStr,src.ident.c_str());
+        pStr += src.ident.length() + 1;
+        strcpy(pStr,src.comment.c_str());
+        pStr += src.comment.length() + 1;
+        strcpy(pStr,src.facility.c_str());
+        pStr += src.facility.length() + 1;
+        strcpy(pStr,src.city.c_str());
+        pStr += src.city.length() + 1;
+        strcpy(pStr,src.addr.c_str());
+        pStr += src.addr.length() + 1;
+        strcpy(pStr,src.crossroad.c_str());
+        pStr += src.crossroad.length() + 1;
+
+        return pStr - (char*)&tar.dtyp;
+    }
+
+    // same as D312, but without color=16=transparent
+    void operator<<(Track_t& tar, const D310_Trk_Hdr_t& src) {
+        tar.dspl     = src.dspl;
+        tar.color    = src.color;
+        tar.ident    = src.ident;
+    }
+
+    void operator<<(Track_t& tar, const D312_Trk_Hdr_t& src) {
+        tar.dspl     = src.dspl;
+        tar.color    = src.color;
+        tar.ident    = src.ident;
+    }
+
+    int operator>>(const Track_t& src, D312_Trk_Hdr_t& tar) {
+        tar.dspl     = src.dspl;
+        tar.color    = src.color;
+
+        char * pIdent     = tar.ident;
+
+        strcpy(pIdent,src.ident.c_str());
+        pIdent += src.ident.length() + 1;
+
+        return pIdent - (char*)&tar.dspl;
+    }
+
+    void operator<<(TrkPt_t& tar, const D301_Trk_t& src) {
+        tar.lat      = INT32_TO_DEG(gar_endian(int32_t, src.lat));
+        tar.lon      = INT32_TO_DEG(gar_endian(int32_t, src.lon));
+        tar.time     = gar_endian(uint32_t, src.time);
+        tar.alt      = gar_endian(float, src.alt);
+        tar.dpth     = gar_endian(float, src.dpth);
+    }
+
+    void operator<<(TrkPt_t& tar, const D302_Trk_t& src) {
+        tar.lat      = INT32_TO_DEG(gar_endian(int32_t, src.lat));
+        tar.lon      = INT32_TO_DEG(gar_endian(int32_t, src.lon));
+        tar.time     = gar_endian(uint32_t, src.time);
+        tar.alt      = gar_endian(float, src.alt);
+        tar.dpth     = gar_endian(float, src.dpth);
+    }
+
+    int operator>>(const TrkPt_t& src, D302_Trk_t& tar) {
+        tar.lat      = gar_endian(int32_t, DEG_TO_INT32(src.lat)); 
+        tar.lon      = gar_endian(int32_t, DEG_TO_INT32(src.lon));
+        tar.time     = gar_endian(uint32_t, src.time);
+        tar.alt      = gar_endian(float, src.alt);
+//        tar.dpth     = gar_endian(float, src.dpth);
+        return (char*)&tar.alt - (char*)&tar.lat + 1;
+    }
+
+    void operator<<(Pvt_t& tar, const D800_Pvt_Data_t& src) {
+        // note: some fields are mis-aligned, so we have to use gar_load_* there ...
+        tar.alt         = gar_endian(float, src.alt);
+        tar.msl_hght    = gar_load(float, src.msl_hght);
+
+        tar.epe         = gar_endian(float, src.epe);
+        tar.eph         = gar_endian(float, src.eph);
+        tar.epv         = gar_endian(float, src.epv);
+        tar.fix         = gar_endian(uint16_t, src.fix);
+        tar.lat         = FLOAT64_TO_DEG(gar_load(double, src.lat));
+        tar.lon         = FLOAT64_TO_DEG(gar_load(double, src.lon));
+
+        tar.tow         = gar_load(double, src.tow);
+        tar.wn_days     = gar_endian(uint32_t, src.wn_days);
+        tar.leap_scnds  = gar_endian(int16_t, src.leap_scnds);
+
+        tar.north       = gar_load(float, src.north);
+        tar.east        = gar_load(float, src.east);
+        tar.up          = gar_load(float, src.up);
+
+    }
+
+    int  operator>>(const Route_t& src, D202_Rte_Hdr_t& tar) {
+        char * pStr     = tar.ident;
+        strcpy(pStr,src.ident.c_str());
+        return src.ident.size() + 1;
+    }
+
+    int  operator>>(const RtePt_t& src, D210_Rte_Link_t& tar) {
+        tar.rte_class = gar_endian(uint16_t, src.rte_class);
+        tar.subclass_1 = gar_endian(uint16_t, src.subclass_1);
+        tar.subclass_2 = gar_endian(uint32_t, src.subclass_2);
+        tar.subclass_3 = gar_endian(uint32_t, src.subclass_3);
+        tar.subclass_4 = gar_endian(uint32_t, src.subclass_4);
+        tar.subclass_5 = gar_endian(uint32_t, src.subclass_5);
+
+        char * pStr     = tar.ident;
+        *pStr++ = 0;
+
+        return pStr - (char*)&tar.rte_class;
+    }
+
+    int  operator<<(Map_t& tar, const Map_Info_t& src) {
+        const char * pStr = src.name1;
+        tar.mapName = pStr;
+        pStr += strlen(pStr) + 1;
+        tar.tileName = pStr;
+
+        // return the src record size
+        uint16_t entry_size = gar_load(uint16_t, src.size);
+        return sizeof(src.tok) + sizeof(src.size) + entry_size;
+    }
+
+}
diff --git a/src/Garmin.h b/src/Garmin.h
new file mode 100644
index 0000000..1393f62
--- /dev/null
+++ b/src/Garmin.h
@@ -0,0 +1,308 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef GARMIN_H
+#define GARMIN_H
+
+#include <string.h>
+#include "Platform.h"
+
+namespace Garmin
+{
+#pragma pack(1)
+
+    /*
+     * Important notice:  The packed structs below contain data in little endian, and accessing
+     * them directly may fail if the machine does not support unaligned accesses.  Either use
+     * the overloaded operators << and >> to move the data into the properly aligned internal
+     * structures or access the data using the macros from ../Platform.h.
+     */
+
+    // note: no << or >> operator available, be sure to access the fields properly
+    struct Product_Data_t
+    {
+        uint16_t product_id;
+        int16_t  software_version;
+        char     str[1];
+    };
+
+    // note: no << or >> operator available, be sure to access the fields properly
+    struct Protocol_Data_t
+    {
+        uint8_t  tag;
+        uint16_t data;
+    };
+
+    struct D108_Wpt_t
+    {
+        uint8_t  wpt_class;
+        uint8_t  color;
+        uint8_t  dspl;
+        uint8_t  attr;
+        uint16_t smbl;
+        uint8_t  subclass[18];
+        int32_t  lat;
+        int32_t  lon;
+        float    alt;
+        float    dpth;
+        float    dist;
+        char     state[2];
+        char     cc[2];
+        char     str[1];
+    };
+
+    struct D109_Wpt_t
+    {
+        uint8_t  dtyp;
+        uint8_t  wpt_class;
+        uint8_t  dspl_color;
+        uint8_t  attr;
+        uint16_t smbl;
+        uint8_t  subclass[18];
+        int32_t  lat;
+        int32_t  lon;
+        float    alt;
+        float    dpth;
+        float    dist;
+        char     state[2];
+        char     cc[2];
+        uint32_t ete;
+        char     str[1];
+    };
+
+    struct D110_Wpt_t
+    {
+        uint8_t  dtyp;
+        uint8_t  wpt_class;
+        uint8_t  dspl_color;
+        uint8_t  attr;
+        uint16_t smbl;
+        uint8_t  subclass[18];
+        int32_t  lat;
+        int32_t  lon;
+        float    alt;
+        float    dpth;
+        float    dist;
+        char     state[2];
+        char     cc[2];
+        uint32_t ete;
+        float    temp;
+        uint32_t time;
+        uint16_t wpt_cat;
+        char     str[1];
+    };
+
+    struct D202_Rte_Hdr_t
+    {
+        char     ident[1];
+    };
+
+    struct D210_Rte_Link_t
+    {
+        uint16_t rte_class;
+        uint16_t subclass_1;
+        uint32_t subclass_2;
+        uint32_t subclass_3;
+        uint32_t subclass_4;
+        uint32_t subclass_5;
+        char     ident[1];
+    };
+
+    struct D301_Trk_t
+    {
+        int32_t  lat;
+        int32_t  lon;
+        uint32_t time;
+        float    alt;
+        float    dpth;
+        uint8_t  new_trk;
+    };
+
+    struct D302_Trk_t
+    {
+        int32_t  lat;
+        int32_t  lon;
+        uint32_t time;
+        float    alt;
+        float    dpth;
+        float    temp;
+        uint8_t  new_trk;
+    };
+
+    // same as D312, but without color=16=transparent
+    struct D310_Trk_Hdr_t
+    {
+        uint8_t  dspl;
+        uint8_t  color;
+        char     ident[1];
+    };
+
+    struct D312_Trk_Hdr_t
+    {
+        uint8_t  dspl;
+        uint8_t  color;
+        char     ident[1];
+    };
+
+    // note: no << or >> operator available, be sure to access the fields properly
+    struct Map_Request_t
+    {
+        uint32_t dummy1;
+        uint16_t dummy2;
+        char     section[13];
+    };
+
+    struct Map_Info_t
+    {
+        uint8_t  tok;            ///< should be 0x4c
+        uint16_t size;           ///< total entry size will be size + sizeof(tok) + sizeof(size)
+        uint16_t product;        ///< product code as it can be found in the registry
+        uint16_t dummy;          ///< country / char. set?
+        uint32_t mapId;          ///< same id as in tdb and map filename
+        char     name1[1];
+        /*
+        There are several 0 terminated strings:
+        "map name"
+        "tile name"
+        */
+    };
+    /*
+    quint32 ???                 ///< the map id as it is used in the FAT table
+    quint32 ???                 ///< always 0x00000000 (end token?)
+    */
+
+    struct D800_Pvt_Data_t
+    {
+        float    alt;
+        float    epe;
+        float    eph;
+        float    epv;
+        uint16_t fix;
+        double   tow;
+        double   lat;
+        double   lon;
+        float    east;
+        float    north;
+        float    up;
+        float    msl_hght;
+        int16_t  leap_scnds;
+        uint32_t wn_days;
+    };
+
+#pragma pack()
+
+    // ---------------------------------------------------------------------------------------
+
+    enum serial_e
+    {
+        Pid_Ack_Byte           = 6
+        ,Pid_Nak_Byte           = 21
+    };
+
+    enum L000_e
+    {
+        Pid_Protocol_Array     = 253
+        ,Pid_Product_Rqst       = 254
+        ,Pid_Product_Data       = 255
+        ,Pid_Ext_Product_Data   = 248
+    };
+
+    enum L001_e
+    {
+        Pid_Command_Data       = 10
+                                 //0x0C
+        ,Pid_Xfer_Cmplt         = 12
+        ,Pid_Prx_Wpt_Data       = 19
+        ,Pid_Wpt_Data           = 35
+                                 //0x1B
+        ,Pid_Records            = 27
+                                 //0x1D
+        ,Pid_Rte_Hdr            = 29
+                                 //0x1E
+        ,Pid_Rte_Wpt_Data       = 30
+        ,Pid_Trk_Data           = 34
+        ,Pid_Pvt_Data           = 51
+                                 //????
+        ,Pid_Capacity_Data      = 95
+                                 //0x62
+        ,Pid_Rte_Link_Data      = 98
+        ,Pid_Trk_Hdr            = 99
+                                 //????
+        ,Pid_Tx_Unlock_Key      = 108
+                                 //????
+        ,Pid_Ack_Unlock_key     = 109
+
+        ,Pid_Req_Icon_Id        = 0x371
+        ,Pid_Ack_Icon_Id        = 0x372
+
+        ,Pid_Req_Clr_Tbl        = 0x376
+        ,Pid_Ack_Clr_Tbl        = 0x377
+        ,Pid_Icon_Data          = 0x375
+        ,Pid_Ack_Icon_Data      = 0x374
+
+    };
+
+    enum A010_e
+    {
+        Cmnd_Abort_Transfer    = 0
+        ,Cmnd_Transfer_Prx      = 3
+        ,Cmnd_Transfer_Rte      = 4
+        ,Cmnd_Transfer_Trk      = 6
+        ,Cmnd_Transfer_Wpt      = 7
+        ,Cmnd_Transfer_Mem      = 63
+        ,Cmnd_Start_Pvt_Data    = 49
+        ,Cmnd_Stop_Pvt_Data     = 50
+    };
+
+    struct Wpt_t;
+
+    extern void operator<<(Wpt_t& tar, const D108_Wpt_t& src);
+    extern int  operator>>(const Wpt_t& src, D108_Wpt_t& tar);
+
+    extern void operator<<(Wpt_t& tar, const D109_Wpt_t& src);
+    extern int  operator>>(const Wpt_t& src, D109_Wpt_t& tar);
+
+    extern void operator<<(Wpt_t& tar, const D110_Wpt_t& src);
+    extern int  operator>>(const Wpt_t& src, D110_Wpt_t& tar);
+
+    struct Track_t;
+    struct TrkPt_t;
+
+    extern void operator<<(Track_t& tar, const D310_Trk_Hdr_t& src);
+    extern void operator<<(Track_t& tar, const D312_Trk_Hdr_t& src);
+    extern int  operator>>(const Track_t& src, D312_Trk_Hdr_t& tar);
+
+    extern void operator<<(TrkPt_t& tar, const D301_Trk_t& src);
+    extern void operator<<(TrkPt_t& tar, const D302_Trk_t& src);
+    extern int  operator>>(const TrkPt_t& src, D302_Trk_t& tar);
+
+    struct Pvt_t;
+    extern void operator<<(Pvt_t& tar, const D800_Pvt_Data_t& src);
+
+    struct Route_t;
+    extern int  operator>>(const Route_t& src, D202_Rte_Hdr_t& tar);
+    struct RtePt_t;
+    extern int  operator>>(const RtePt_t& src, D210_Rte_Link_t& tar);
+
+    struct Map_t;
+    extern int operator<<(Map_t& tar, const Map_Info_t& src);
+}
+#endif                           //GARMIN_H
diff --git a/src/IDevice.h b/src/IDevice.h
new file mode 100644
index 0000000..10762f6
--- /dev/null
+++ b/src/IDevice.h
@@ -0,0 +1,576 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+
+#ifndef IDEVICE_H
+#define IDEVICE_H
+
+// need integer type definitions with fixed width
+#ifdef HAVE_INTTYPES_H
+#  include <inttypes.h>
+#elif HAVE_STDINT_H
+#  include <stdint.h>
+#elif WIN32
+
+typedef __int8  int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8     uint8_t;
+typedef unsigned __int16    uint16_t;
+typedef unsigned __int32    uint32_t;
+typedef unsigned __int64    uint64_t;
+
+#else
+#  error neither inttypes.h nor stdint.h are available
+#endif
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _MKSTR_1
+#define _MKSTR_1(x)    #x
+#define _MKSTR(x)      _MKSTR_1(x)
+#endif
+
+#define INTERFACE_VERSION "01.16"
+
+namespace Garmin
+{
+
+    /// common waypoint structure application side
+    /**
+        This structure has to be used to exchange a waypoint to QLandkarte.
+        If an item is missing you can simply add it. This structure must
+        never be copied assuming a certain alignment.
+
+        Most values are the same like the ones used in the waypoint data
+        structures used by Garmin.
+    */
+    struct Wpt_t
+    {
+        Wpt_t()
+            : wpt_class(0)
+            , dspl_color(0)
+            , dspl_attr(0)
+            , smbl(8287)
+            , lat(1000.0f)
+            , lon(1000.0f)
+            , alt(1.0e25f)
+            , dpth(1.0e25f)
+            , dist(1.0e25f)
+            , ete(0xFFFFFFFF)
+            , temp(1.0e25f)
+            , time(0xFFFFFFFF)
+        , wpt_cat(0) {
+            strncpy(state,"  ", 3);
+            strncpy(cc,"  ",3);
+
+        }
+        /// same as Garmin spec.
+        uint8_t  wpt_class;
+        /// bit 0..4 of dspl_color
+        uint8_t  dspl_color;
+        /// bit 5..6 of dspl_color
+        uint8_t  dspl_attr;
+        /// same as Garmin spec.
+        uint16_t smbl;
+        /// the latitude as degrees
+        double   lat;
+        /// the longitude as degrees
+        double   lon;
+        /// same as Garmin spec.
+        float    alt;
+        /// same as Garmin spec.
+        float    dpth;
+        /// same as Garmin spec.
+        float    dist;
+        /// same as Garmin spec.
+        char     state[3];
+        /// same as Garmin spec.
+        char     cc[3];
+        /// same as Garmin spec.
+        uint32_t ete;
+        /// same as Garmin spec.
+        float    temp;
+        /// same as Garmin spec.
+        uint32_t time;
+        /// same as Garmin spec.
+        uint16_t wpt_cat;
+        /// same as Garmin spec.
+        std::string ident;
+        /// same as Garmin spec.
+        std::string comment;
+        /// same as Garmin spec.
+        std::string facility;
+        /// same as Garmin spec.
+        std::string city;
+        /// same as Garmin spec.
+        std::string addr;
+        /// same as Garmin spec.
+        std::string crossroad;
+    };
+
+    /// common route point structure application side
+    /**
+        This structure has to be used to exchange a waypoint to QLandkarte.
+        If an item is missing you can simply add it. This structure must
+        never be copied assuming a certain alignment.
+
+        Most values are the same like the ones used in the waypoint and
+        route point data structures used by Garmin.
+
+        It adds link information.  For more complex route operations, it
+        is critical to note that this refers to the link with the *previous*
+        waypoint.   For example, when a route is inverted, the link information
+        must be transfered to the previous point first.
+    */
+
+    struct RtePt_t : public Wpt_t
+    {
+        RtePt_t()
+            : rte_class(3)
+            , subclass_1(0x0000)
+            , subclass_2(0x00000000)
+            , subclass_3(0xFFFFFFFF)
+            , subclass_4(0xFFFFFFFF)
+            , subclass_5(0xFFFFFFFF)
+            {}
+
+        uint16_t rte_class;
+
+        uint16_t subclass_1;
+        uint32_t subclass_2;
+        uint32_t subclass_3;
+        uint32_t subclass_4;
+        uint32_t subclass_5;
+
+        std::string ident;
+    };
+
+    /// common route structure application side
+    /**
+        This structure has to be used to exchange a track to QLandkarte.
+        If an item is missing you can simply add it. This structure must
+        never be copied assuming a certain alignment.
+
+        Most values are the same like the ones used in the point data
+        structures used by Garmin.
+    */
+
+    struct Route_t
+    {
+        /// same as Garmin spec.
+        std::string ident;
+        /// route points
+        std::vector<RtePt_t> route;
+    };
+
+    /// common track point structure application side
+    /**
+        This structure has to be used to exchange a track point to QLandkarte.
+        If an item is missing you can simply add it. This structure must
+        never be copied assuming a certain alignment.
+
+        Most values are the same like the ones used in the track point data
+        structures used by Garmin.
+    */
+    struct TrkPt_t
+    {
+        TrkPt_t()
+            : lat(0.0)
+            , lon(0.0)
+            , time(0)
+            , alt(1e25f)
+        , dpth(1e25f) {
+
+        }
+        /// the latitude as degrees
+        double   lat;
+        /// the longitude as degrees
+        double   lon;
+        /// the time in sec. as specified by Garmin
+        uint32_t time;
+        /// same as Garmin spec.
+        float    alt;
+        /// same as Garmin spec.
+        float    dpth;
+    };
+
+    /// common track structure application side
+    /**
+        This structure has to be used to exchange a track to QLandkarte.
+        If an item is missing you can simply add it. This structure must
+        never be copied assuming a certain alignment.
+
+        Most values are the same like the ones used in the point data
+        structures used by Garmin.
+    */
+    struct Track_t
+    {
+        Track_t()
+            : dspl(true)
+        , color(0xFF) {
+
+        }
+        /// same as Garmin spec.
+        bool    dspl;
+        /// same as Garmin spec.
+        uint8_t color;
+        /// same as Garmin spec.
+        std::string ident;
+        /// trackpoints
+        std::vector<TrkPt_t> track;
+    };
+
+    struct Map_t
+    {
+        std::string mapName;
+        std::string tileName;
+    };
+
+    struct Pvt_t
+    {
+        /// same as Garmin spec.
+        float    alt;
+        /// same as Garmin spec.
+        float    epe;
+        /// same as Garmin spec.
+        float    eph;
+        /// same as Garmin spec.
+        float    epv;
+        /// same as Garmin spec.
+        uint16_t fix;
+        /// same as Garmin spec.
+        double   tow;
+        /// the latitude as degrees
+        double   lat;
+        /// the longitude as degrees
+        double   lon;
+        /// same as Garmin spec.
+        float    east;
+        /// same as Garmin spec.
+        float    north;
+        /// same as Garmin spec.
+        float    up;
+        /// same as Garmin spec.
+        float    msl_hght;
+        /// same as Garmin spec.
+        int16_t  leap_scnds;
+        /// same as Garmin spec.
+        uint32_t wn_days;
+    };
+
+    struct Icon_t
+    {
+        Icon_t(){ memset(data,0,sizeof(data));}
+        /// custom icon index (0..511)
+        uint16_t idx;
+        /// the bitmap's color table
+        char clrtbl[0x400];
+        /// the bitmap's image data
+        char data[0x100];
+    };
+
+    /// device property structure application side
+    /**
+        This structure is used to account for device properties such as
+        the available memory and maximum number of maps.  If a property is
+        missing, it can be added.  Both the item must be added and a still
+        undefined bit in dev_property_list_t may have to be allocated to
+        indicate that the property has indeed been set to a meaningful value.
+    */
+    // boolean quantitities in the form of a bit field
+    struct dev_property_list_t
+    {
+        uint32_t memory_limit: 1;
+        uint32_t maps_limit: 1;
+        uint32_t allow_duplicated_map_IDs: 1;
+        uint32_t routes_limit: 1;
+        uint32_t route_pts_limit: 1;
+        uint32_t waypts_limit: 1;
+        uint32_t tracks_limit: 1;
+        uint32_t track_pts_limit: 1;
+        uint32_t screen_size: 1;
+        uint32_t pvt_requestable: 1;
+        uint32_t custom_POI_limit: 1;
+        uint32_t protocols_requestable: 1;
+        uint32_t protocols_set: 1;
+        uint32_t product_ID: 1;
+        uint32_t product_string: 1;
+        uint32_t read_trailing_packets: 1;
+        uint32_t undefined: 15;
+        uint32_t ext_dev_properties: 1;
+    };
+    // make the bit field addressable as a single integer
+    union device_properties_union_t
+    {
+        uint32_t all;
+        dev_property_list_t item;
+    };
+    // the device properties structure
+    struct DevProperties_t
+    {
+        /// bit encoded list of properties that have been set by the driver
+        device_properties_union_t set;
+        /// maximum map upload (GMAPSUPP.IMG) size in bytes (0 for no upload)
+        uint64_t memory_limit;
+        /// maximum number of map tiles allowed for upload
+        uint32_t maps_limit;
+        /// maximum number of routes
+        uint32_t routes_limit;
+        /// maximum number of points in a route
+        uint32_t route_pts_limit;
+        /// maximum number of waypoints
+        uint32_t waypts_limit;
+        /// maximum number of tracks
+        uint32_t tracks_limit;
+        /// maximum number of track points
+        uint32_t track_pts_limit;
+        /// screen size
+        uint32_t screenwidth, screenheight;
+        /// screen pixel order
+        uint32_t pixel_order;
+        /// maximum number of POI
+        uint32_t custom_POI_limit;
+        /// official protocols
+        uint32_t L_Link;
+        uint32_t A_Cmd;
+        uint32_t A_Wpt, D_Wpt[3];
+        uint32_t A_Prox_Wpt, D_Prox_Wpt[3];
+        uint32_t A_Rt, D_Rt[3];
+        uint32_t A_Trk, D_Trk[3];
+        uint32_t A_Pvt, D_Pvt[3];
+        /// inferred protocols
+        uint32_t Q_Map_Limits;
+        uint32_t Q_Map_Upload;
+        uint32_t Q_Map_Info_Download;
+        uint32_t Q_Screenshot;
+        uint32_t Q_Custom_Icons;
+        /// product_ID
+        uint32_t product_ID;
+        /// product_string
+        const char * product_string;
+    };
+
+    /// exception error code
+    enum exce_e
+    {
+        errOpen                  ///< error during opening the link
+        ,errSync                 ///< error during sync. up sequence
+        ,errWrite                ///< error during write access
+        ,errRead                 ///< error during read access
+        ,errNotImpl              ///< error because of missing implementation
+        ,errRuntime              ///< error during operation
+        ,errBlocked              ///< error because access is blocked by another process
+    };
+
+    /// exception type
+    struct exce_t
+    {
+
+        exce_t(exce_e err, const std::string& msg) : err(err), msg(msg) {}
+        exce_e err;
+        std::string msg;
+    };
+
+    /// interface class for device driver plugins
+    /**
+        This is the common interface to all devices. The application uses
+        this definition to gain access to the plugin. Thus if you are an
+        application programmer simply load the plugin, resolve and call
+        the init function. The object you will get will be of type IDevice.
+        There is no need to link against libgarmin.a.
+
+        If you are a plugin programmer you will rather use IDeviceDefault, than
+        IDevice. The inheritance chain will look like:
+
+        IDevice -> IDefaultDevice -> CDevice
+
+        Thus if you miss a public method you have to add it here as pure virtual
+        and as a default implementation to IDeviceDefault.
+
+        NOTE: If you change this interface you _must_ increment the version
+        number defined by INTERFACE_VERSION. This is important to prevent
+        crashes due to different interface definitions.
+
+        Most likely your device driver will implement the protected methods with
+        leading '_' of IDeviceDefault.
+    */
+    class IDevice
+    {
+        public:
+            IDevice()
+                : _callback_(0), _self_(0){};
+            virtual ~IDevice(){};
+
+            /// setup gui callback for user interaction
+            /**
+                If you use the driver from a GUI you might want to react on some events or show
+                the progress of the current operation. The registered callback will be for progress
+                status as well as for user interaction depending on the parameters.
+
+                The callback will require a progress dialog if the parameter "progress" is set to anthing
+                else than -1. Developers using this callback to show a progress status should make sure:
+
+                * The first call must have a progress of 0 and a title is set.
+                * Subsequent calls have a progress from 0..100. The msg parameter can be set.
+                * The last call must have a progress of 100.
+
+                If you supply a pointer to a cancel variable from the first call on, you can cancel the
+                operation if the value of the variable changes from 0 to 1.
+
+                Developers implementing the callback function must make sure:
+
+                * A progress of 0 will setup the progress dialog. Any subsequent progress of 0
+                  is handled like any other progress. The dialog's title is set.
+                  If there is a pointer to a cancel variable the dialog should provide a way to
+                  cancel the operation. The dialog must make sure ther pointer is valid for
+                  subsequent calls. The operation is canceled if "*cancel = 1;"
+                * Any subsequent call can have a message parameter, but it mustn't have one.
+                * A progress of 100 should remove the progress dialog. There can be subsequent
+                  calls with a progress of 100.
+
+                A progress of -1 will create a blocking message box. Depending on the pointers ok
+                and cancel the dialog should show ok and cancel button. The integer variables will
+                be set to true or false according to the button pressed.
+
+                The supplied void pointer will be passed to every callback call and is free to be used
+                by the GUI for what ever purpose it needs.
+
+            */
+            void setGuiCallback(void (*func)(int /*progress*/, int * /*ok*/, int * /*cancel*/, const char * /*title*/, const char * /*msg*/, void * /*self*/), void * p) {
+            _self_        = p;
+            _callback_    = func;
+    }
+
+    /// upload a single map file to device
+    /**
+        This will handle just a single file. Map tiles must be concatenated into
+        one big file (gmapsupp.img). If the file containes tiles with locked data
+        an array of 25 ASCII digits has to be passed as key.
+
+        @param mapdata pointer to the gmapsupp.img data array
+        @param size the size of the gmapsupp.img data array
+        @param key pointer to 25 digit key or 0 for no key
+    */
+    virtual void uploadMap(const uint8_t * mapdata, uint32_t size, const char * key) = 0;
+
+    /// alternative map uppload API
+    /**
+        This will handle just a single file. Map tiles must be concatenated into
+        one big file (gmapsupp.img). If the file containes tiles with locked data
+        an array of 25 ASCII digits has to be passed as key.
+
+        @param mapdata pointer to the gmapsupp.img data array
+        @param size the size of the gmapsupp.img data array
+        @param key pointer to 25 digit key or 0 for no key
+    */
+    virtual void uploadMap(const char * filename, uint32_t size, const char * key) = 0;
+
+    /// query loaded map list
+    /**
+        This is not a real download of maps as just the information about the
+        loaded maps is transfered.
+    */
+    virtual void queryMap(std::list<Map_t>& maps) = 0;
+
+    /// download waypoints from device
+    /**
+        @param waypoints list object to receive waypoints
+    */
+    virtual void downloadWaypoints(std::list<Garmin::Wpt_t>& waypoints) = 0;
+
+    /// upload waypoints to device
+    /**
+        @param waypoints list of waypoints to send
+    */
+    virtual void uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints) = 0;
+
+    /// download track from device
+    /**
+        @param tracks list object to receive tracks
+    */
+    virtual void downloadTracks(std::list<Garmin::Track_t>& tracks) = 0;
+
+    /// upload track to device
+    /**
+        @param tracks list of tracks to send
+    */
+    virtual void uploadTracks(std::list<Garmin::Track_t>& tracks) = 0;
+
+    /// upload route to device
+    /**
+        @param routes list of routes
+    */
+    virtual void uploadRoutes(std::list<Garmin::Route_t>& routes) = 0;
+
+    /// upload custom icons to device
+    /**
+        @param routes list of icons
+    */
+    virtual void uploadCustomIcons(std::list<Garmin::Icon_t>& icons) = 0;
+
+    /// download a screenshot from the device
+    /**
+        @param clrtbl a pointer reference to be set to the downloaded color table of size 0x100
+        @param data a pointer reference to be set to the downloaded image data array of size width x height
+        @param width a integer reference to store the image width at
+        @param height a integer reference to store the image height at
+    */
+    virtual void screenshot(char *& clrtbl, char *& data, int& width, int& height) = 0;
+
+    /// switch device into realtime position mode
+    virtual void setRealTimeMode(bool on) = 0;
+
+    /// request real time position
+    virtual void getRealTimePos(Garmin::Pvt_t& pvt) = 0;
+
+    /// get the device's properties.
+    virtual void getDevProperties(Garmin::DevProperties_t& properties) = 0;
+
+    /// get the copyright notice of this driver
+    virtual const std::string& getCopyright() = 0;
+
+    /// get reason string for last exception
+    virtual const std::string& getLastError() = 0;
+
+    /// set port string used for communication
+    /**
+        This should be called prior to an operation. As an operation will
+        create a new ILink object, a changed port setting will apply imediately.
+        If the ILink object does not need any port settings this value is ignored.
+    */
+    virtual void setPort(const char * port) = 0;
+
+    protected:
+        /// see setGuiCallback()
+        void (*_callback_)(int /*progress*/, int * /*ok*/, int * /*cancel*/, const char * /*title*/, const char * /*msg*/, void * /*self*/);
+        /// see setGuiCallback()
+        void * _self_;
+};
+
+}
+#endif                           //IDEVICE_H
diff --git a/src/IDeviceDefault.cpp b/src/IDeviceDefault.cpp
new file mode 100644
index 0000000..9e4bea5
--- /dev/null
+++ b/src/IDeviceDefault.cpp
@@ -0,0 +1,380 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+
+#include "config.h"
+#include "IDeviceDefault.h"
+
+#include <iostream>
+
+using namespace Garmin;
+using namespace std;
+
+IDeviceDefault::IDeviceDefault()
+{
+    pthread_mutex_init(&mutex, NULL);
+}
+
+
+IDeviceDefault::~IDeviceDefault()
+{
+
+}
+
+
+void IDeviceDefault::callback(int progress, int * ok, int * cancel, const char * title, const char * msg)
+{
+    if(_callback_) {
+        _callback_(progress,ok,cancel,title,msg,_self_);
+    }
+}
+
+
+void IDeviceDefault::setPort(const char * p)
+{
+    port = p;
+}
+
+
+void IDeviceDefault::uploadMap(const uint8_t * mapdata, uint32_t size, const char * key)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _uploadMap(mapdata, size, key);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to upload maps. " + e.msg;
+        throw (int)e.err;
+    }
+}
+
+
+void IDeviceDefault::uploadMap(const char * filename, uint32_t size, const char * key)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _uploadMap(filename, size, key);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to upload maps. " + e.msg;
+        throw (int)e.err;
+    }
+}
+
+
+void IDeviceDefault::queryMap(std::list<Map_t>& maps)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _queryMap(maps);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to query loaded maps. " + e.msg;
+        throw (int)e.err;
+    }
+}
+
+
+void IDeviceDefault::downloadWaypoints(std::list<Garmin::Wpt_t>& waypoints)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _downloadWaypoints(waypoints);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to download waypoints. " + e.msg;
+        throw (int)e.err;
+    }
+}
+
+
+void IDeviceDefault::uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _uploadWaypoints(waypoints);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to upload waypoints. " + e.msg;
+        throw (int)e.err;
+    }
+}
+
+
+void IDeviceDefault::downloadTracks(std::list<Garmin::Track_t>& tracks)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _downloadTracks(tracks);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to download tracks. " + e.msg;
+        throw (int)e.err;
+    }
+
+}
+
+void IDeviceDefault::uploadTracks(std::list<Garmin::Track_t>& tracks)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _uploadTracks(tracks);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to upload tracks. " + e.msg;
+        throw (int)e.err;
+    }
+
+}
+
+
+void IDeviceDefault::uploadRoutes(std::list<Garmin::Route_t>& routes)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _uploadRoutes(routes);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to upload routes. " + e.msg;
+        throw (int)e.err;
+    }
+
+}
+
+
+void IDeviceDefault::uploadCustomIcons(std::list<Garmin::Icon_t>& icons)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _uploadCustomIcons(icons);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to upload icons. " + e.msg;
+        throw (int)e.err;
+    }
+
+}
+
+
+void IDeviceDefault::screenshot(char *& clrtbl, char *& data, int& width, int& height)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _screenshot(clrtbl, data, width, height);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to download screenshot. " + e.msg;
+        throw (int)e.err;
+    }
+
+}
+
+
+void IDeviceDefault::setRealTimeMode(bool on)
+{
+    lasterror = "";
+    try
+    {
+        _setRealTimeMode(on);
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to change real time mode. " + e.msg;
+        throw (int)e.err;
+    }
+}
+
+
+void IDeviceDefault::getRealTimePos(Garmin::Pvt_t& pvt)
+{
+    // don't reset last error because it might hold the reason,
+    // why the realtime thread died.
+    //lasterror = "";
+    try
+    {
+        _getRealTimePos(pvt);
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to request real time position. " + e.msg;
+        throw (int)e.err;
+    }
+}
+
+
+void IDeviceDefault::getDevProperties(Garmin::DevProperties_t& dev_properties)
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _getDevProperties(dev_properties);
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Failed to obtain GPS properties. " + e.msg;
+        throw (int)e.err;
+    }
+}
+
+
+const std::string& IDeviceDefault::getCopyright()
+{
+    return copyright;
+}
+
+
+const std::string& IDeviceDefault::getLastError()
+{
+    return lasterror;
+}
+
+
+void IDeviceDefault::_uploadMap(const uint8_t * , uint32_t , const char * )
+{
+    throw exce_t(errNotImpl,"uploadMap(): this method is not implemented for your device.");
+}
+
+
+void IDeviceDefault::_uploadMap(const char * , uint32_t , const char * )
+{
+    throw exce_t(errNotImpl,"uploadMap(): this method is not implemented for your device.");
+}
+
+
+void IDeviceDefault::_queryMap(std::list<Map_t>& )
+{
+    throw exce_t(errNotImpl,"queryMap(): this method is not implemented for your device.");
+}
+
+
+void IDeviceDefault::_downloadWaypoints(std::list<Garmin::Wpt_t>& )
+{
+    throw exce_t(errNotImpl,"downloadWaypoints(): this method is not implemented for your device.");
+}
+
+
+void IDeviceDefault::_uploadWaypoints(std::list<Garmin::Wpt_t>& )
+{
+    throw exce_t(errNotImpl,"uploadWaypoints(): this method is not implemented for your device.");
+}
+
+
+void IDeviceDefault::_downloadTracks(std::list<Garmin::Track_t>& )
+{
+    throw exce_t(errNotImpl,"downloadTracks(): this method is not implemented for your device.");
+}
+
+void IDeviceDefault::_uploadTracks(std::list<Garmin::Track_t>& )
+{
+    throw exce_t(errNotImpl,"uploadTracks(): this method is not implemented for your device.");
+}
+
+void IDeviceDefault::_uploadRoutes(std::list<Garmin::Route_t>& )
+{
+    throw exce_t(errNotImpl,"uploadRoutes(): this method is not implemented for your device.");
+}
+
+
+void IDeviceDefault::_uploadCustomIcons(std::list<Garmin::Icon_t>& )
+{
+    throw exce_t(errNotImpl,"uploadCustomIcons(): this method is not implemented for your device.");
+}
+
+
+void IDeviceDefault::_screenshot(char *& /*clrtbl*/, char *& /*data*/, int& /*width*/, int& /*height*/)
+{
+    throw exce_t(errNotImpl,"screenshot(): this method is not implemented for your device.");
+}
+
+
+void IDeviceDefault::_setRealTimeMode(bool)
+{
+    throw exce_t(errNotImpl,"setRealTimeMode(): this method is not implemented for your device.");
+}
+
+
+void IDeviceDefault::_getRealTimePos(Garmin::Pvt_t&)
+{
+    throw exce_t(errNotImpl,"getRealTimePos(): this method is not implemented for your device.");
+}
+
+
+void IDeviceDefault::_getDevProperties(Garmin::DevProperties_t& dev_properties)
+{
+    // mark all properties as not having been set to meaningful values
+    properties.set.all = (uint32_t) 0;
+
+    // return a copy of the device properties block
+    dev_properties = properties;
+}
diff --git a/src/IDeviceDefault.h b/src/IDeviceDefault.h
new file mode 100644
index 0000000..ab068bc
--- /dev/null
+++ b/src/IDeviceDefault.h
@@ -0,0 +1,128 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef IDEVICEDEFAULT_H
+#define IDEVICEDEFAULT_H
+#include <pthread.h>
+#include <errno.h>
+
+#include "IDevice.h"
+
+namespace Garmin
+{
+    /// default implementation of a device driver
+    /**
+        Please refer to IDevice for documentation on the public interface.
+        The default implementation of all methods is to throw an exception,
+        to signal that a real implementation is missing. If your device lacks
+        a ceratin feature simply do not implement the corresponding '_' method.
+    */
+    class IDeviceDefault : public IDevice
+    {
+        public:
+            IDeviceDefault();
+            virtual ~IDeviceDefault();
+            /// see IDevice::uploadMap()
+            virtual void uploadMap(const uint8_t * mapdata, uint32_t size, const char * key);
+            virtual void uploadMap(const char * filename, uint32_t size, const char * key);
+            /// see IDevice::queryMap()
+            virtual void queryMap(std::list<Map_t>& maps);
+            /// see IDevice::downloadWaypoints()
+            virtual void downloadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            /// see IDevice::uploadWaypoints()
+            virtual void uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            /// see IDevice::downloadTracks()
+            virtual void downloadTracks(std::list<Garmin::Track_t>& tracks);
+            /// see IDevice::uploadTracks()
+            virtual void uploadTracks(std::list<Garmin::Track_t>& tracks);
+            /// see IDevice::uploadRoutes()
+            virtual void uploadRoutes(std::list<Garmin::Route_t>& routes);
+            /// see IDevice::uploadCustomIcons()
+            virtual void uploadCustomIcons(std::list<Garmin::Icon_t>& icons);
+            /// see IDevice::screenshot()
+            virtual void screenshot(char *& clrtbl, char *& data, int& width, int& height);
+            /// see IDevice::setRealTimeMode()
+            virtual void setRealTimeMode(bool on);
+            /// see IDevice::getRealTimePos()
+            virtual void getRealTimePos(Garmin::Pvt_t& pvt);
+            /// see IDevice::getDevProperties()
+            virtual void getDevProperties(Garmin::DevProperties_t& dev_properties);
+            /// see IDevice::getCopyright()
+            virtual const std::string& getCopyright();
+            /// see IDevice::getLastError()
+            virtual const std::string& getLastError();
+            /// see IDevice::setPort()
+            virtual void setPort(const char * p);
+
+            /// device interface access mutex
+            pthread_mutex_t mutex;
+
+        protected:
+            virtual void _acquire() = 0;
+
+            virtual void _uploadMap(const uint8_t * mapdata, uint32_t size, const char * key);
+            virtual void _uploadMap(const char * filename, uint32_t size, const char * key);
+            virtual void _queryMap(std::list<Map_t>& maps);
+            virtual void _downloadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            virtual void _uploadWaypoints(std::list<Garmin::Wpt_t>& waypoints);
+            virtual void _downloadTracks(std::list<Garmin::Track_t>& tracks);
+            virtual void _uploadTracks(std::list<Garmin::Track_t>& tracks);
+            virtual void _uploadRoutes(std::list<Garmin::Route_t>& routes);
+            virtual void _uploadCustomIcons(std::list<Garmin::Icon_t>& icons);
+            virtual void _screenshot(char *& clrtbl, char *& data, int& width, int& height);
+            virtual void _setRealTimeMode(bool on);
+            virtual void _getRealTimePos(Garmin::Pvt_t& pvt);
+            virtual void _getDevProperties(Garmin::DevProperties_t& dev_properties);
+
+            virtual void _release() = 0;
+
+            void callback(int progress, int * ok, int * cancel, const char * title, const char * msg);
+
+            /// the copyright information
+            std::string copyright;
+            /// error message of last error
+            std::string lasterror;
+            /// serial port string
+            std::string port;
+
+            /// device properties
+            Garmin::DevProperties_t properties;
+
+    };
+
+    class CMutexLocker
+    {
+        public:
+            CMutexLocker(pthread_mutex_t& mutex)
+            : mutex(mutex) {
+                if(pthread_mutex_trylock(&mutex) == EBUSY) throw exce_t(errBlocked,"Access is blocked by another function.");
+            }
+
+            ~CMutexLocker() {
+                pthread_mutex_unlock(&mutex);
+            }
+        private:
+            pthread_mutex_t& mutex;
+
+    };
+
+}
+#endif                           //IDEVICEDEFAULT_H
diff --git a/src/ILink.cpp b/src/ILink.cpp
new file mode 100644
index 0000000..bbf8b07
--- /dev/null
+++ b/src/ILink.cpp
@@ -0,0 +1,35 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "ILink.h"
+
+using namespace Garmin;
+
+ILink::ILink()
+{
+
+}
+
+
+ILink::~ILink()
+{
+
+}
diff --git a/src/ILink.h b/src/ILink.h
new file mode 100644
index 0000000..d26133e
--- /dev/null
+++ b/src/ILink.h
@@ -0,0 +1,84 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+
+#ifndef ILINK_H
+#define ILINK_H
+#include "Platform.h"
+
+#define GUSB_MAX_BUFFER_SIZE    0x1000
+#define GUSB_HEADER_SIZE        0x000C
+#define GUSB_PAYLOAD_SIZE       (GUSB_MAX_BUFFER_SIZE - GUSB_HEADER_SIZE)
+
+namespace Garmin
+{
+#pragma pack(1)
+    struct Packet_t
+    {
+        Packet_t(uint8_t type, uint16_t id)
+            : type(type), b1(0), b2(0), b3(0), id(id), b6(0), b7(0), size(0){}
+        Packet_t()
+            : type(0), b1(0), b2(0), b3(0), id(0), b6(0), b7(0), size(0){}
+        uint8_t  type;
+        uint8_t  b1;
+        uint8_t  b2;
+        uint8_t  b3;
+        uint16_t id;
+        uint8_t  b6;
+        uint8_t  b7;
+        uint32_t size;
+        uint8_t  payload[GUSB_PAYLOAD_SIZE+4];
+    };
+#ifdef WIN32
+#pragma pack()
+#else
+#pragma pack(0)
+#endif
+
+    /// Base class for all link objects
+    /**
+        Use CUSB and CSerial to exchange messages with your
+        device.
+
+        Do not forget that you communicate to a plug-n-play device.
+        The user might disconnect without notice. Another
+        application might access the device, too. Thus open the link for
+        each exchange and close it after the exchange. The _acquire() and
+        _release()  method of the driver implementation shoud be a good
+        place to use open() and close().
+
+    */
+    class ILink
+    {
+        public:
+            ILink();
+            virtual ~ILink();
+
+            virtual void open() = 0;
+            virtual void close() = 0;
+
+            virtual int read(Packet_t& data) = 0;
+            virtual void write(const Packet_t& data) = 0;
+
+    };
+
+}
+#endif                           //ILINK_H
diff --git a/src/Platform.h b/src/Platform.h
new file mode 100644
index 0000000..76d121a
--- /dev/null
+++ b/src/Platform.h
@@ -0,0 +1,322 @@
+/* -*-mode:c++; c-style:k&r; c-basic-offset:4; -*- */
+/**********************************************************************************************
+    Copyright (C) 2008 Albrecht Dre <albrecht.dress at arcor.de>
+
+    This file contains macros for platform-independant access of data stored in little-endian
+    format.
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+    =============================================================
+    Why does this file exist, and what should hackers do with it?
+    -------------------------------------------------------------
+
+    1. Background
+
+    Garmin stores data in map files and in their devices in little-endian format.  The data
+    is usually packed, i.e. it is not guaranteed that multi-byte data is aligned at 16, 32 or
+    64 bit boundaries.  This is fine as long as you run QLandkarte (or any derived software)
+    on a little-endian machine which accepts accessing unaligned data.
+
+    The `configure' script in the top-level folder tries to detect if your machine is a
+    little endian (like Intel or ARM) or a big endian (like PowerPC or Sparc).  In the latter
+    case, it defines the macro WORDS_BIGENDIAN.  In an other test, it checks if your machine
+    supports accessing unaligned memory (like Intel or PowerPC) or if such accesses would fail
+    (as an ARM or Sparc).  If unaligned accesses are supported, the macro CAN_UNALIGNED will
+    be defined.  Of course, the file config.h from the top-level folder has to be included.
+
+    2. How to access data
+
+    To work around these problems, this file defines a number of access macros.  On machines
+    which do not need them, they always expand to nothing, but they are *absolutely* necessary
+    on others.  So *never* access multi-byte elements without using these macros.
+
+    2.1 Load data from Garmin
+
+    The following rules apply if you want to access data in a source coming from a Garmin
+    device or file:
+
+    (a) the source is a constant or an aligned 16, 32 or 64-bit value
+
+    Always use the macro
+        gar_endian(<type>, <source>)
+    where type may be int16_t, int32_t, int64_t, uint16_t, uint32_t, uint64_t, float or double.
+    The returned value will explicitly be cast'ed to <type>.
+
+    (b) the source is an unaligned 16, 32 or 64-bit value
+
+    Always use the macro
+        gar_load(<type>, <source>)
+    where type may be int16_t, int32_t, int64_t, uint16_t, uint32_t, uint64_t, float or double.
+    The returned value will explicitly be cast'ed to <type>.
+
+    (c) the source is a pointer
+
+    Always use the macro
+        gar_ptr_load(<type>, <pointer>)
+    where type may be int16_t, int32_t, int64_t, uint16_t, uint32_t, uint64_t, float or double
+    or the special Garmin types int24_t or uint24_t.  The returned value will be of type <type>
+    except for the Garmin types int24_t or uint24_t which will be int32_t or uint32_t,
+    respectively, but have the uppermost 8 bits always set to 0.
+
+    2.2 Store data to Garmin
+
+    (a) the destination is a variable
+
+    For unaligned variables, use the macro
+        gar_store(<type>, <destination>, <source>)
+    where type may be int16_t, int32_t, int64_t, uint16_t, uint32_t, uint64_t, float or double.
+    if the valiable is aligned, use "destination = gar_endian(type, source)" which is faster.
+
+    (b) the destination is a pointer
+
+    For unaligned pointer destinations, use the macro
+        gar_ptr_store(<type>, <pointer>, <source>)
+    where type may be int16_t, int32_t, int64_t, uint16_t, uint32_t, uint64_t, float or double
+    or the special Garmin types int24_t or uint24_t.  For a standard type and an aligned pointer
+    destination, use "*(type *)(ptr) = gar_endian(type, source)" which is faster.
+
+**********************************************************************************************/
+#ifndef __PLATFORM_H__
+#define __PLATFORM_H__
+
+// include platform setup (WORDS_BIGENDIAN, CAN_UNALIGNED)
+#include "config.h"
+
+// need integer type definitions with fixed width
+#ifdef HAVE_INTTYPES_H
+#  include <inttypes.h>
+#elif HAVE_STDINT_H
+#  include <stdint.h>
+#elif WIN32
+typedef __int8  int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8     uint8_t;
+typedef unsigned __int16    uint16_t;
+typedef unsigned __int32    uint32_t;
+typedef unsigned __int64    uint64_t;
+
+#else
+#  error neither inttypes.h nor stdint.h are available
+#endif
+#include <string.h>
+
+// --------------------------------------------------------------------------------------------
+// macros to fix the endianess of the constant or properly aligned argument x of type t
+
+#if !defined(HAVE_BIGENDIAN)
+
+// little endian platform: just return the argument
+#define gar_endian(t, x)            (t)(x)
+
+#else
+
+// big endian platform
+#define gar_endian(t, x)            (__gar_endian_ ## t(x))
+
+#if defined(HAVE_BYTESWAP_H)
+
+// platform has byteswap.h
+#include <byteswap.h>
+#define __gar_endian_int16_t(x)     (int16_t)(bswap_16(x))
+#define __gar_endian_int32_t(x)     (int32_t)(bswap_32(x))
+#define __gar_endian_int64_t(x)     (int64_t)(bswap_64(x))
+#define __gar_endian_uint16_t(x)    (uint16_t)(bswap_16(x))
+#define __gar_endian_uint32_t(x)    (uint32_t)(bswap_32(x))
+#define __gar_endian_uint64_t(x)    (uint64_t)(bswap_64(x))
+
+#else
+
+// generic platform - define swapping
+#define __gar_endian_uint16_t(x)    (uint16_t)((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))
+#define __gar_endian_uint32_t(x)    (uint32_t)((((x) & 0xff000000u) >> 24) | \
+(((x) & 0x00ff0000u) >>  8) | \
+(((x) & 0x0000ff00u) <<  8) | \
+(((x) & 0x000000ffu) << 24))
+#define __gar_endian_uint64_t(x)    (uint64_t)((((x) & 0xff00000000000000ull) >> 56) | \
+(((x) & 0x00ff000000000000ull) >> 40) | \
+(((x) & 0x0000ff0000000000ull) >> 24) | \
+(((x) & 0x000000ff00000000ull) >> 8) | \
+(((x) & 0x00000000ff000000ull) << 8) | \
+(((x) & 0x0000000000ff0000ull) << 24) | \
+(((x) & 0x000000000000ff00ull) << 40) | \
+(((x) & 0x00000000000000ffull) << 56))
+#define __gar_endian_int16_t(x)     (int16_t)((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))
+#define __gar_endian_int32_t(x)     (int32_t)((((x) & 0xff000000u) >> 24) | \
+(((x) & 0x00ff0000u) >>  8) | \
+(((x) & 0x0000ff00u) <<  8) | \
+(((x) & 0x000000ffu) << 24))
+#define __gar_endian_int64_t(x)     (int64_t)((((x) & 0xff00000000000000ull) >> 56) | \
+(((x) & 0x00ff000000000000ull) >> 40) | \
+(((x) & 0x0000ff0000000000ull) >> 24) | \
+(((x) & 0x000000ff00000000ull) >> 8) | \
+(((x) & 0x00000000ff000000ull) << 8) | \
+(((x) & 0x0000000000ff0000ull) << 24) | \
+(((x) & 0x000000000000ff00ull) << 40) | \
+(((x) & 0x00000000000000ffull) << 56))
+#endif                           // !HAVE_BYTESWAP_H
+
+static inline float
+__gar_endian_float(float x)
+{
+    uint32_t __uv = gar_endian(uint32_t, *(uint32_t *)&x);
+    return *(float *) &__uv;
+}
+
+
+static inline double
+__gar_endian_double(double x)
+{
+    uint64_t __uv = gar_endian(uint64_t, *(uint64_t *)&x);
+    return *(double *) &__uv;
+}
+#endif                           // WORDS_BIGENDIAN
+
+// --------------------------------------------------------------------------------------------
+// macros to deal with pointers or unaligned arguments
+
+// load argument of type t from pointer p
+#define gar_ptr_load(t, p)          __gar_ptr_load_ ## t((p))
+
+// store argument src of type t in in the location to which the pointer p points
+#define gar_ptr_store(t, p, src)    __gar_ptr_store_ ## t((p), (src))
+
+#if defined(CAN_UNALIGNED) && !defined(HAVE_BIGENDIAN)
+
+// load argument x of type t - noop with proper cast
+#define gar_load(t, x)              (t)(x)
+
+// store argument src of type t in the variable dst of type t - just assign
+#define gar_store(t, dst, src)      (dst) = (src)
+
+// load from pointer - simply map memory
+#define __gar_ptr_load_int16_t(p)   (*((int16_t *)(p)))
+#define __gar_ptr_load_int32_t(p)   (*((int32_t *)(p)))
+#define __gar_ptr_load_int64_t(p)   (*((int64_t *)(p)))
+#define __gar_ptr_load_uint16_t(p)  (*((uint16_t *)(p)))
+#define __gar_ptr_load_uint32_t(p)  (*((uint32_t *)(p)))
+#define __gar_ptr_load_uint64_t(p)  (*((uint64_t *)(p)))
+#define __gar_ptr_load_float(p)     (*((float *)(p)))
+#define __gar_ptr_load_double(p)    (*((double *)(p)))
+// special Garmin types - map memory and clear extra bits
+#define __gar_ptr_load_uint24_t(p)  (__gar_ptr_load_uint32_t(p) & 0x00FFFFFFu)
+#define __gar_ptr_load_int24_t(p)   (__gar_ptr_load_int32_t(p) & 0x00FFFFFFu)
+
+// store data to pointer - just assign after a proper cast
+#define __gar_ptr_store_int16_t(p, src)     (*((int16_t *)(p))) = (src)
+#define __gar_ptr_store_int32_t(p, src)     (*((int32_t *)(p))) = (src)
+#define __gar_ptr_store_int64_t(p, src)     (*((int64_t *)(p))) = (src)
+#define __gar_ptr_store_uint16_t(p, src)    (*((uint16_t *)(p))) = (src)
+#define __gar_ptr_store_uint32_t(p, src)    (*((uint32_t *)(p))) = (src)
+#define __gar_ptr_store_uint64_t(p, src)    (*((uint64_t *)(p))) = (src)
+#define __gar_ptr_store_float(p, src)       (*((float *)(p))) = (src)
+#define __gar_ptr_store_double(p, src)      (*((double *)(p))) = (src)
+// special Garmin types - use memcpy
+#define __gar_ptr_store_uint24_t(p, src) \
+do \
+{ \
+    __gar_ptr_store_uint16_t(p, src & 0xfffu); \
+    p[2] = src >> 16; \
+} while (0)
+#define __gar_ptr_store_int24_t(p, src) \
+__gar_ptr_store_uint24_t(p, src)
+
+#else                            // machine is either Big Endian or does not support unaligned accesses
+
+// load argument x of type t - call pointer load macro
+#define gar_load(t, x)              gar_ptr_load(t, (uint8_t *)&(x))
+
+// store argument src of type t in the variable dst of type t - call pointer store macro
+#define gar_store(t, dst, src)      gar_ptr_store(t, (uint8_t *)&(dst), src)
+
+// load from pointer - read'n'shift bytes
+#define __gar_ptr_load_int16_t(p)   ((int16_t)((p)[0] | ((p)[1] << 8)))
+#define __gar_ptr_load_int24_t(p)   ((int32_t)((p)[0] | ((p)[1] << 8) | \
+((p)[2] << 16)))
+#define __gar_ptr_load_int32_t(p)   ((int32_t)((p)[0] | ((p)[1] << 8) | \
+((p)[2] << 16) | ((p)[3] << 24)))
+#define __gar_ptr_load_int64_t(p)   ((int64_t)gar_ptr_load_int32(p) | \
+(((int64_t)gar_ptr_load_int32((p) + 4)) << 32))
+#define __gar_ptr_load_uint16_t(p)  ((uint16_t)((p)[0] | ((p)[1] << 8)))
+#define __gar_ptr_load_uint24_t(p)  ((uint32_t)((p)[0] | ((p)[1] << 8) | \
+((p)[2] << 16)))
+#define __gar_ptr_load_uint32_t(p)  ((uint32_t)((p)[0] | ((p)[1] << 8) | \
+((p)[2] << 16) | ((p)[3] << 24)))
+#define __gar_ptr_load_uint64_t(p)  ((uint64_t)__gar_ptr_load_uint32_t(p) | \
+(((uint64_t)__gar_ptr_load_uint32_t((p) + 4)) << 32))
+static inline float
+__gar_ptr_load_float(uint8_t * p)
+{
+    uint32_t __uv = gar_ptr_load(uint32_t, p);
+    return *(float *) &__uv;
+}
+
+
+static inline double
+__gar_ptr_load_double(uint8_t * p)
+{
+    uint64_t __uv = gar_ptr_load(uint64_t, p);
+    return *(double *) &__uv;
+}
+
+
+// macros to store data - use memcpy to store data to pointer
+#define __gar_ptr_store_uint16_t(p, src) \
+do \
+{ \
+    p[0] = src & 0xffu; \
+    p[1] = (src >> 8) & 0xffu; \
+} while (0)
+#define __gar_ptr_store_uint24_t(p, src) \
+do \
+{ \
+    p[0] = src & 0xffu; \
+    p[1] = (src >> 8) & 0xffu; \
+    p[2] = (src >> 16) & 0xffu; \
+} while (0)
+#define __gar_ptr_store_uint32_t(p, src) \
+do \
+{ \
+    p[0] = src & 0xffu; \
+    p[1] = (src >> 8) & 0xffu; \
+    p[2] = (src >> 16) & 0xffu; \
+    p[3] = (src >> 24) & 0xffu; \
+} while (0)
+#define __gar_ptr_store_uint64_t(p, src) \
+do \
+{ \
+    __gar_ptr_store_uint32_t(p, src & 0xffffffffu); \
+    __gar_ptr_store_uint32_t(p + 4, src >> 32); \
+} while (0)
+#define __gar_ptr_store_int16_t(p, src) __gar_ptr_store_uint16_t(p, src)
+#define __gar_ptr_store_int24_t(p, src) __gar_ptr_store_uint24_t(p, src)
+#define __gar_ptr_store_int32_t(p, src) __gar_ptr_store_uint32_t(p, src)
+#define __gar_ptr_store_int64_t(p, src) __gar_ptr_store_uint64_t(p, src)
+#define __gar_ptr_store_float(p, src) \
+do \
+{ \
+    float __fv = gar_endian(float, src); \
+    memcpy(p, &__fv, 4); \
+} while (0)
+#define __gar_ptr_store_double(p, src) \
+do \
+{ \
+    _double __dv = gar_endian(double, src); \
+    memcpy(p, &__dv, 8); \
+} while (0)
+#endif                           // cannot unaligned or big endian
+#endif                           // __PLATFORM_H__
diff --git a/src/whatGarmin/CDevice.cpp b/src/whatGarmin/CDevice.cpp
new file mode 100644
index 0000000..c3f09fc
--- /dev/null
+++ b/src/whatGarmin/CDevice.cpp
@@ -0,0 +1,195 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+  LvD: whatGarmin is a query version that tries to find info about the
+       device and writes it to the terminal screen.
+
+       This assumes that the connected unit is a Garmin one and that
+       the basic USB syncup can be achieved.
+
+       Tell the user to download waypoints to use this, then turn off the
+       unit.
+
+  LvD: EOT
+
+**********************************************************************************************/
+#include "../Platform.h"
+#include "CDevice.h"
+#include <Garmin.h>
+
+#include <cstdio>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+using namespace whatGarmin;
+using namespace Garmin;
+using namespace std;
+
+CDevice::CDevice()
+: usb(0)
+{
+    copyright = "<h1>QLandkarte Dummy Device Driver whatGarmin</h1>"
+        "<h2>Driver I/F Ver. " INTERFACE_VERSION "</h2>"
+        "<p>© 2007 by Oliver Eichler (oliver.eichler at gmx.de)</p>"
+        "<p>© 2007 by Leon van Dommelen (dommelen at eng.fsu.edu)</p>"
+        "<p>This driver 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. </p>";
+}
+
+
+CDevice::~CDevice()
+{
+
+}
+
+
+void CDevice::_acquire()
+{
+    // activate the driver
+    usb = new CUSB();
+    usb->open();
+    usb->syncup();
+
+    // product data
+    ostringstream note;
+
+    // output the product name
+    cout << "Product name: " << usb->getProductString().c_str() << endl;
+    note  << "\n\n" << usb->getProductString().c_str();
+
+    // output the product ID
+    cout << "  product ID: " << usb->getProductId();
+    note  << "\nproduct ID: " <<  usb->getProductId();
+
+    // See what protocols are there
+
+    // link protocol
+    if (usb->getDataType(-1,'L',(uint16_t)1)) {
+        cout << "  supports link protocol L001" << endl;
+        note  << "\nlink protocol L001";
+    }
+    if (usb->getDataType(-1,'L',(uint16_t)2)) {
+        cout << "  supports link protocol L002" << endl;
+        note  << "\nlink protocol L002";
+    }
+
+    // command protocol
+    if (usb->getDataType(-1,'A',(uint16_t)10)) {
+        cout << "  supports command protocol A010" << endl;
+        note  << "\ncommand protocol A010";
+    }
+    if (usb->getDataType(-1,'A',(uint16_t)11)) {
+        cout << "  supports command protocol A011" << endl;
+        note  << "\ncommand protocol A011";
+    }
+
+    // waypoint transfer protocol
+    if (usb->getDataType(0,'A',(uint16_t)100)) {
+        cout << "  supports waypoint transfer protocol A100 with D0=" << usb->getDataType(0,'A',(uint16_t)100) << endl;
+        note  << "\nwaypoint protocol A100 D" << usb->getDataType(0,'A',(uint16_t)100);
+    }
+    if (usb->getDataType(0,'A',(uint16_t)101)) {
+        cout << "  supports waypoint transfer protocol A101 with D0=" << usb->getDataType(0,'A',(uint16_t)101) << endl;
+        note  << "\nwaypoint protocol A101 D" << usb->getDataType(0,'A',(uint16_t)101);
+    }
+
+    // proximity waypoint transfer protocol
+    if (usb->getDataType(0,'A',(uint16_t)400)) {
+        cout << "  supports proximity waypoint transfer protocol A400 with D0=" << usb->getDataType(0,'A',(uint16_t)400) << endl;
+        note  << "\nproximity waypoint protocol A400 D" << usb->getDataType(0,'A',(uint16_t)400);
+    }
+
+    // track log transfer protocol
+    if (usb->getDataType(0,'A',(uint16_t)300)) {
+        cout << "  supports track log transfer protocol A300 with D0=" << usb->getDataType(0,'A',(uint16_t)300) << endl;
+        note  << "\ntrack log protocol A300 D" << usb->getDataType(0,'A',(uint16_t)300);
+    }
+    if (usb->getDataType(0,'A',(uint16_t)301)) {
+        cout << "  supports track log transfer protocol A301 with D0=" << usb->getDataType(0,'A',(uint16_t)301) << " D1=" << usb->getDataType(1,'A',(uint16_t)301) << endl;
+        note  << "\ntrack log protocol A301 D" << usb->getDataType(0,'A',(uint16_t)301) << " D" << usb->getDataType(1,'A',(uint16_t)301);
+    }
+    if (usb->getDataType(0,'A',(uint16_t)302)) {
+        cout << "  supports track log transfer protocol A302 with D0=" << usb->getDataType(0,'A',(uint16_t)302) << " D1=" << usb->getDataType(1,'A',(uint16_t)302) << endl;
+        note  << "\ntrack log protocol A302 D" << usb->getDataType(0,'A',(uint16_t)302) << " D" << usb->getDataType(1,'A',(uint16_t)302);
+    }
+
+    // route transfer protocol
+    if (usb->getDataType(0,'A',(uint16_t)200)) {
+        cout << "  supports route transfer protocol A200 with D0=" << usb->getDataType(0,'A',(uint16_t)200) << " D1=" << usb->getDataType(1,'A',(uint16_t)200) << endl;
+        note  << "\nroute protocol A200 D" << usb->getDataType(0,'A',(uint16_t)200) << " D" << usb->getDataType(1,'A',(uint16_t)200);
+    }
+    if (usb->getDataType(0,'A',(uint16_t)201)) {
+        cout << "  supports route transfer protocol A201 with D0=" << usb->getDataType(0,'A',(uint16_t)201) << " D1=" << usb->getDataType(1,'A',(uint16_t)201)  << " D2=" << usb->getDataType(2,'A',(uint16_t)201) << endl;
+        note  << "\nroute protocol A201 D" << usb->getDataType(0,'A',(uint16_t)201) << " D" << usb->getDataType(1,'A',(uint16_t)201) << " D" << usb->getDataType(2,'A',(uint16_t)201);
+    }
+
+    // PVT protocol
+    if (usb->getDataType(0,'A',(uint16_t)800)) {
+        cout << "  supports Position/Velocity/Time protocol A800 with D0=" << usb->getDataType(0,'A',(uint16_t)800) << endl;
+        note  << "\nPVT protocol A800 D" << usb->getDataType(0,'A',(uint16_t)800);
+    }
+
+    // end of data
+    cout << "Product Data End: " << usb->getProductString().c_str() << endl;
+
+    // abort any action
+    cout << note.str() << endl;
+    throw exce_t(errSync,note.str());
+}
+
+
+void CDevice::_getDevProperties(Garmin::DevProperties_t& /*dev_properties*/)
+{
+    throw exce_t(errSync,"This method is not implemented for whatGarmin.");
+}
+
+
+void CDevice::_release()
+{
+    if(usb == 0) return;
+
+    // close by resetting device
+    usb->close2();
+
+    delete usb;
+    usb = 0;
+}
+
+
+const std::string& CDevice::getCopyright()
+{
+    lasterror = "";
+    try
+    {
+        CMutexLocker lock(mutex);
+        _acquire();
+        _release();
+    }
+    catch(exce_t& e) {
+        if(e.err != errBlocked) _release();
+        lasterror = "Protocol dump: " + e.msg;
+        throw (int)e.err;
+    }
+
+    return copyright;
+}
diff --git a/src/whatGarmin/CDevice.h b/src/whatGarmin/CDevice.h
new file mode 100644
index 0000000..deeb84e
--- /dev/null
+++ b/src/whatGarmin/CDevice.h
@@ -0,0 +1,49 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#ifndef CDEVICE_H
+#define CDEVICE_H
+
+#include "IDeviceDefault.h"
+#include "CUSB.h"
+
+namespace whatGarmin
+{
+
+    class CDevice : public Garmin::IDeviceDefault
+    {
+        public:
+            CDevice();
+            virtual ~CDevice();
+
+            const std::string& getCopyright();
+
+        private:
+
+            void _acquire();
+            void _getDevProperties(Garmin::DevProperties_t& dev_properties);
+            void _release();
+
+            Garmin::CUSB * usb;
+    };
+
+}
+#endif                           //CDEVICE_H
diff --git a/src/whatGarmin/CMakeLists.txt b/src/whatGarmin/CMakeLists.txt
new file mode 100644
index 0000000..2d1b338
--- /dev/null
+++ b/src/whatGarmin/CMakeLists.txt
@@ -0,0 +1,17 @@
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+set(SRCS
+    loader.cpp
+    CDevice.cpp
+)
+
+set(HDRS
+    CDevice.h
+)
+
+include_directories(../ ${USB_INCLUDE_DIRS})
+add_library(whatGarmin SHARED ${SRCS} ${HDRS})
+target_link_libraries(whatGarmin garmin ${USB_LIBRARIES} pthread)
+
+
diff --git a/src/whatGarmin/loader.cpp b/src/whatGarmin/loader.cpp
new file mode 100644
index 0000000..3e25802
--- /dev/null
+++ b/src/whatGarmin/loader.cpp
@@ -0,0 +1,40 @@
+/**********************************************************************************************
+    Copyright (C) 2007 Oliver Eichler oliver.eichler at gmx.de
+
+    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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
+  or one of its subsidiaries.
+
+**********************************************************************************************/
+#include "config.h"
+#include "CDevice.h"
+
+namespace whatGarmin
+{
+    static CDevice * device = 0;
+}
+
+
+extern "C" Garmin::IDevice * initwhatGarmin(const char * version)
+{
+    if(strncmp(version,INTERFACE_VERSION,5) != 0) {
+        return 0;
+    }
+    if(whatGarmin::device == 0) {
+        whatGarmin::device = new whatGarmin::CDevice();
+    }
+    return whatGarmin::device;
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/garmindev.git



More information about the Pkg-grass-devel mailing list