[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