--- /dev/null
+/*
+Copyright (c) 2005, David M Howard (daveh at dmh2000.com)
+All rights reserved.
+
+This product is licensed for use and distribution under the BSD Open Source License:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
--- /dev/null
+# Doxyfile 1.3.8\r
+\r
+# This file describes the settings to be used by the documentation system\r
+# doxygen (www.doxygen.org) for a project\r
+#\r
+# All text after a hash (#) is considered a comment and will be ignored\r
+# The format is:\r
+# TAG = value [value, ...]\r
+# For lists items can also be appended using:\r
+# TAG += value [value, ...]\r
+# Values that contain spaces should be placed between quotes (" ")\r
+\r
+#---------------------------------------------------------------------------\r
+# Project related configuration options\r
+#---------------------------------------------------------------------------\r
+\r
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded \r
+# by quotes) that should identify the project.\r
+\r
+PROJECT_NAME = NMEAP\r
+\r
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. \r
+# This could be handy for archiving the generated documentation or \r
+# if some version control system is used.\r
+\r
+PROJECT_NUMBER = 0.1\r
+\r
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) \r
+# base path where the generated documentation will be put. \r
+# If a relative path is entered, it will be relative to the location \r
+# where doxygen was started. If left blank the current directory will be used.\r
+\r
+OUTPUT_DIRECTORY = doc\r
+\r
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create \r
+# 4096 sub-directories (in 2 levels) under the output directory of each output \r
+# format and will distribute the generated files over these directories. \r
+# Enabling this option can be useful when feeding doxygen a huge amount of source \r
+# files, where putting all generated files in the same directory would otherwise \r
+# cause performance problems for the file system.\r
+\r
+CREATE_SUBDIRS = NO\r
+\r
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all \r
+# documentation generated by doxygen is written. Doxygen will use this \r
+# information to generate all constant output in the proper language. \r
+# The default language is English, other supported languages are: \r
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, \r
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, \r
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, \r
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, \r
+# Swedish, and Ukrainian.\r
+\r
+OUTPUT_LANGUAGE = English\r
+\r
+# This tag can be used to specify the encoding used in the generated output. \r
+# The encoding is not always determined by the language that is chosen, \r
+# but also whether or not the output is meant for Windows or non-Windows users. \r
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES \r
+# forces the Windows encoding (this is the default for the Windows binary), \r
+# whereas setting the tag to NO uses a Unix-style encoding (the default for \r
+# all platforms other than Windows).\r
+\r
+USE_WINDOWS_ENCODING = NO\r
+\r
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will \r
+# include brief member descriptions after the members that are listed in \r
+# the file and class documentation (similar to JavaDoc). \r
+# Set to NO to disable this.\r
+\r
+BRIEF_MEMBER_DESC = YES\r
+\r
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend \r
+# the brief description of a member or function before the detailed description. \r
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the \r
+# brief descriptions will be completely suppressed.\r
+\r
+REPEAT_BRIEF = YES\r
+\r
+# This tag implements a quasi-intelligent brief description abbreviator \r
+# that is used to form the text in various listings. Each string \r
+# in this list, if found as the leading text of the brief description, will be \r
+# stripped from the text and the result after processing the whole list, is used \r
+# as the annotated text. Otherwise, the brief description is used as-is. If left \r
+# blank, the following values are used ("$name" is automatically replaced with the \r
+# name of the entity): "The $name class" "The $name widget" "The $name file" \r
+# "is" "provides" "specifies" "contains" "represents" "a" "an" "the"\r
+\r
+ABBREVIATE_BRIEF = \r
+\r
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then \r
+# Doxygen will generate a detailed section even if there is only a brief \r
+# description.\r
+\r
+ALWAYS_DETAILED_SEC = NO\r
+\r
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited \r
+# members of a class in the documentation of that class as if those members were \r
+# ordinary class members. Constructors, destructors and assignment operators of \r
+# the base classes will not be shown.\r
+\r
+INLINE_INHERITED_MEMB = NO\r
+\r
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full \r
+# path before files name in the file list and in the header files. If set \r
+# to NO the shortest path that makes the file name unique will be used.\r
+\r
+FULL_PATH_NAMES = NO\r
+\r
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \r
+# can be used to strip a user-defined part of the path. Stripping is \r
+# only done if one of the specified strings matches the left-hand part of \r
+# the path. The tag can be used to show relative paths in the file list. \r
+# If left blank the directory from which doxygen is run is used as the \r
+# path to strip.\r
+\r
+STRIP_FROM_PATH = \r
+\r
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of \r
+# the path mentioned in the documentation of a class, which tells \r
+# the reader which header file to include in order to use a class. \r
+# If left blank only the name of the header file containing the class \r
+# definition is used. Otherwise one should specify the include paths that \r
+# are normally passed to the compiler using the -I flag.\r
+\r
+STRIP_FROM_INC_PATH = \r
+\r
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \r
+# (but less readable) file names. This can be useful is your file systems \r
+# doesn't support long names like on DOS, Mac, or CD-ROM.\r
+\r
+SHORT_NAMES = NO\r
+\r
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen \r
+# will interpret the first line (until the first dot) of a JavaDoc-style \r
+# comment as the brief description. If set to NO, the JavaDoc \r
+# comments will behave just like the Qt-style comments (thus requiring an \r
+# explicit @brief command for a brief description.\r
+\r
+JAVADOC_AUTOBRIEF = NO\r
+\r
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen \r
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// \r
+# comments) as a brief description. This used to be the default behaviour. \r
+# The new default is to treat a multi-line C++ comment block as a detailed \r
+# description. Set this tag to YES if you prefer the old behaviour instead.\r
+\r
+MULTILINE_CPP_IS_BRIEF = NO\r
+\r
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen \r
+# will output the detailed description near the top, like JavaDoc.\r
+# If set to NO, the detailed description appears after the member \r
+# documentation.\r
+\r
+DETAILS_AT_TOP = NO\r
+\r
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented \r
+# member inherits the documentation from any documented member that it \r
+# re-implements.\r
+\r
+INHERIT_DOCS = YES\r
+\r
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC \r
+# tag is set to YES, then doxygen will reuse the documentation of the first \r
+# member in the group (if any) for the other members of the group. By default \r
+# all members of a group must be documented explicitly.\r
+\r
+DISTRIBUTE_GROUP_DOC = NO\r
+\r
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. \r
+# Doxygen uses this value to replace tabs by spaces in code fragments.\r
+\r
+TAB_SIZE = 8\r
+\r
+# This tag can be used to specify a number of aliases that acts \r
+# as commands in the documentation. An alias has the form "name=value". \r
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to \r
+# put the command \sideeffect (or @sideeffect) in the documentation, which \r
+# will result in a user-defined paragraph with heading "Side Effects:". \r
+# You can put \n's in the value part of an alias to insert newlines.\r
+\r
+ALIASES = \r
+\r
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources \r
+# only. Doxygen will then generate output that is more tailored for C. \r
+# For instance, some of the names that are used will be different. The list \r
+# of all members will be omitted, etc.\r
+\r
+OPTIMIZE_OUTPUT_FOR_C = YES\r
+\r
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources \r
+# only. Doxygen will then generate output that is more tailored for Java. \r
+# For instance, namespaces will be presented as packages, qualified scopes \r
+# will look different, etc.\r
+\r
+OPTIMIZE_OUTPUT_JAVA = NO\r
+\r
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of \r
+# the same type (for instance a group of public functions) to be put as a \r
+# subgroup of that type (e.g. under the Public Functions section). Set it to \r
+# NO to prevent subgrouping. Alternatively, this can be done per class using \r
+# the \nosubgrouping command.\r
+\r
+SUBGROUPING = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# Build related configuration options\r
+#---------------------------------------------------------------------------\r
+\r
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in \r
+# documentation are documented, even if no documentation was available. \r
+# Private class members and static file members will be hidden unless \r
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\r
+\r
+EXTRACT_ALL = YES\r
+\r
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class \r
+# will be included in the documentation.\r
+\r
+EXTRACT_PRIVATE = YES\r
+\r
+# If the EXTRACT_STATIC tag is set to YES all static members of a file \r
+# will be included in the documentation.\r
+\r
+EXTRACT_STATIC = YES\r
+\r
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) \r
+# defined locally in source files will be included in the documentation. \r
+# If set to NO only classes defined in header files are included.\r
+\r
+EXTRACT_LOCAL_CLASSES = YES\r
+\r
+# This flag is only useful for Objective-C code. When set to YES local \r
+# methods, which are defined in the implementation section but not in \r
+# the interface are included in the documentation. \r
+# If set to NO (the default) only methods in the interface are included.\r
+\r
+EXTRACT_LOCAL_METHODS = NO\r
+\r
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all \r
+# undocumented members of documented classes, files or namespaces. \r
+# If set to NO (the default) these members will be included in the \r
+# various overviews, but no documentation section is generated. \r
+# This option has no effect if EXTRACT_ALL is enabled.\r
+\r
+HIDE_UNDOC_MEMBERS = NO\r
+\r
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all \r
+# undocumented classes that are normally visible in the class hierarchy. \r
+# If set to NO (the default) these classes will be included in the various \r
+# overviews. This option has no effect if EXTRACT_ALL is enabled.\r
+\r
+HIDE_UNDOC_CLASSES = NO\r
+\r
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all \r
+# friend (class|struct|union) declarations. \r
+# If set to NO (the default) these declarations will be included in the \r
+# documentation.\r
+\r
+HIDE_FRIEND_COMPOUNDS = NO\r
+\r
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any \r
+# documentation blocks found inside the body of a function. \r
+# If set to NO (the default) these blocks will be appended to the \r
+# function's detailed documentation block.\r
+\r
+HIDE_IN_BODY_DOCS = NO\r
+\r
+# The INTERNAL_DOCS tag determines if documentation \r
+# that is typed after a \internal command is included. If the tag is set \r
+# to NO (the default) then the documentation will be excluded. \r
+# Set it to YES to include the internal documentation.\r
+\r
+INTERNAL_DOCS = NO\r
+\r
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate \r
+# file names in lower-case letters. If set to YES upper-case letters are also \r
+# allowed. This is useful if you have classes or files whose names only differ \r
+# in case and if your file system supports case sensitive file names. Windows \r
+# and Mac users are advised to set this option to NO.\r
+\r
+CASE_SENSE_NAMES = NO\r
+\r
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen \r
+# will show members with their full class and namespace scopes in the \r
+# documentation. If set to YES the scope will be hidden.\r
+\r
+HIDE_SCOPE_NAMES = NO\r
+\r
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen \r
+# will put a list of the files that are included by a file in the documentation \r
+# of that file.\r
+\r
+SHOW_INCLUDE_FILES = YES\r
+\r
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] \r
+# is inserted in the documentation for inline members.\r
+\r
+INLINE_INFO = YES\r
+\r
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen \r
+# will sort the (detailed) documentation of file and class members \r
+# alphabetically by member name. If set to NO the members will appear in \r
+# declaration order.\r
+\r
+SORT_MEMBER_DOCS = YES\r
+\r
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the \r
+# brief documentation of file, namespace and class members alphabetically \r
+# by member name. If set to NO (the default) the members will appear in \r
+# declaration order.\r
+\r
+SORT_BRIEF_DOCS = NO\r
+\r
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be \r
+# sorted by fully-qualified names, including namespaces. If set to \r
+# NO (the default), the class list will be sorted only by class name, \r
+# not including the namespace part. \r
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\r
+# Note: This option applies only to the class list, not to the \r
+# alphabetical list.\r
+\r
+SORT_BY_SCOPE_NAME = NO\r
+\r
+# The GENERATE_TODOLIST tag can be used to enable (YES) or \r
+# disable (NO) the todo list. This list is created by putting \todo \r
+# commands in the documentation.\r
+\r
+GENERATE_TODOLIST = YES\r
+\r
+# The GENERATE_TESTLIST tag can be used to enable (YES) or \r
+# disable (NO) the test list. This list is created by putting \test \r
+# commands in the documentation.\r
+\r
+GENERATE_TESTLIST = YES\r
+\r
+# The GENERATE_BUGLIST tag can be used to enable (YES) or \r
+# disable (NO) the bug list. This list is created by putting \bug \r
+# commands in the documentation.\r
+\r
+GENERATE_BUGLIST = YES\r
+\r
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or \r
+# disable (NO) the deprecated list. This list is created by putting \r
+# \deprecated commands in the documentation.\r
+\r
+GENERATE_DEPRECATEDLIST= YES\r
+\r
+# The ENABLED_SECTIONS tag can be used to enable conditional \r
+# documentation sections, marked by \if sectionname ... \endif.\r
+\r
+ENABLED_SECTIONS = \r
+\r
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines \r
+# the initial value of a variable or define consists of for it to appear in \r
+# the documentation. If the initializer consists of more lines than specified \r
+# here it will be hidden. Use a value of 0 to hide initializers completely. \r
+# The appearance of the initializer of individual variables and defines in the \r
+# documentation can be controlled using \showinitializer or \hideinitializer \r
+# command in the documentation regardless of this setting.\r
+\r
+MAX_INITIALIZER_LINES = 30\r
+\r
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated \r
+# at the bottom of the documentation of classes and structs. If set to YES the \r
+# list will mention the files that were used to generate the documentation.\r
+\r
+SHOW_USED_FILES = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to warning and progress messages\r
+#---------------------------------------------------------------------------\r
+\r
+# The QUIET tag can be used to turn on/off the messages that are generated \r
+# by doxygen. Possible values are YES and NO. If left blank NO is used.\r
+\r
+QUIET = NO\r
+\r
+# The WARNINGS tag can be used to turn on/off the warning messages that are \r
+# generated by doxygen. Possible values are YES and NO. If left blank \r
+# NO is used.\r
+\r
+WARNINGS = YES\r
+\r
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings \r
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will \r
+# automatically be disabled.\r
+\r
+WARN_IF_UNDOCUMENTED = YES\r
+\r
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for \r
+# potential errors in the documentation, such as not documenting some \r
+# parameters in a documented function, or documenting parameters that \r
+# don't exist or using markup commands wrongly.\r
+\r
+WARN_IF_DOC_ERROR = YES\r
+\r
+# The WARN_FORMAT tag determines the format of the warning messages that \r
+# doxygen can produce. The string should contain the $file, $line, and $text \r
+# tags, which will be replaced by the file and line number from which the \r
+# warning originated and the warning text.\r
+\r
+WARN_FORMAT = "$file:$line: $text"\r
+\r
+# The WARN_LOGFILE tag can be used to specify a file to which warning \r
+# and error messages should be written. If left blank the output is written \r
+# to stderr.\r
+\r
+WARN_LOGFILE = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the input files\r
+#---------------------------------------------------------------------------\r
+\r
+# The INPUT tag can be used to specify the files and/or directories that contain \r
+# documented source files. You may enter file names like "myfile.cpp" or \r
+# directories like "/usr/src/myproject". Separate the files or directories \r
+# with spaces.\r
+\r
+INPUT = inc/nmeap.h\r
+\r
+# If the value of the INPUT tag contains directories, you can use the \r
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \r
+# and *.h) to filter out the source-files in the directories. If left \r
+# blank the following patterns are tested: \r
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp \r
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm\r
+\r
+FILE_PATTERNS = *.h\r
+\r
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories \r
+# should be searched for input files as well. Possible values are YES and NO. \r
+# If left blank NO is used.\r
+\r
+RECURSIVE = YES\r
+\r
+# The EXCLUDE tag can be used to specify files and/or directories that should \r
+# excluded from the INPUT source files. This way you can easily exclude a \r
+# subdirectory from a directory tree whose root is specified with the INPUT tag.\r
+\r
+EXCLUDE = \r
+\r
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories \r
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.\r
+\r
+EXCLUDE_SYMLINKS = NO\r
+\r
+# If the value of the INPUT tag contains directories, you can use the \r
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude \r
+# certain files from those directories.\r
+\r
+EXCLUDE_PATTERNS = \r
+\r
+# The EXAMPLE_PATH tag can be used to specify one or more files or \r
+# directories that contain example code fragments that are included (see \r
+# the \include command).\r
+\r
+EXAMPLE_PATH = \r
+\r
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the \r
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \r
+# and *.h) to filter out the source-files in the directories. If left \r
+# blank all files are included.\r
+\r
+EXAMPLE_PATTERNS = \r
+\r
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be \r
+# searched for input files to be used with the \include or \dontinclude \r
+# commands irrespective of the value of the RECURSIVE tag. \r
+# Possible values are YES and NO. If left blank NO is used.\r
+\r
+EXAMPLE_RECURSIVE = NO\r
+\r
+# The IMAGE_PATH tag can be used to specify one or more files or \r
+# directories that contain image that are included in the documentation (see \r
+# the \image command).\r
+\r
+IMAGE_PATH = \r
+\r
+# The INPUT_FILTER tag can be used to specify a program that doxygen should \r
+# invoke to filter for each input file. Doxygen will invoke the filter program \r
+# by executing (via popen()) the command <filter> <input-file>, where <filter> \r
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an \r
+# input file. Doxygen will then use the output that the filter program writes \r
+# to standard output. If FILTER_PATTERNS is specified, this tag will be \r
+# ignored.\r
+\r
+INPUT_FILTER = \r
+\r
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern \r
+# basis. Doxygen will compare the file name with each pattern and apply the \r
+# filter if there is a match. The filters are a list of the form: \r
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further \r
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER \r
+# is applied to all files.\r
+\r
+FILTER_PATTERNS = \r
+\r
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using \r
+# INPUT_FILTER) will be used to filter the input files when producing source \r
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).\r
+\r
+FILTER_SOURCE_FILES = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to source browsing\r
+#---------------------------------------------------------------------------\r
+\r
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will \r
+# be generated. Documented entities will be cross-referenced with these sources. \r
+# Note: To get rid of all source code in the generated output, make sure also \r
+# VERBATIM_HEADERS is set to NO.\r
+\r
+SOURCE_BROWSER = NO\r
+\r
+# Setting the INLINE_SOURCES tag to YES will include the body \r
+# of functions and classes directly in the documentation.\r
+\r
+INLINE_SOURCES = NO\r
+\r
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct \r
+# doxygen to hide any special comment blocks from generated source code \r
+# fragments. Normal C and C++ comments will always remain visible.\r
+\r
+STRIP_CODE_COMMENTS = NO\r
+\r
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) \r
+# then for each documented function all documented \r
+# functions referencing it will be listed.\r
+\r
+REFERENCED_BY_RELATION = YES\r
+\r
+# If the REFERENCES_RELATION tag is set to YES (the default) \r
+# then for each documented function all documented entities \r
+# called/used by that function will be listed.\r
+\r
+REFERENCES_RELATION = YES\r
+\r
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen \r
+# will generate a verbatim copy of the header file for each class for \r
+# which an include is specified. Set to NO to disable this.\r
+\r
+VERBATIM_HEADERS = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the alphabetical class index\r
+#---------------------------------------------------------------------------\r
+\r
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index \r
+# of all compounds will be generated. Enable this if the project \r
+# contains a lot of classes, structs, unions or interfaces.\r
+\r
+ALPHABETICAL_INDEX = NO\r
+\r
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then \r
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns \r
+# in which this list will be split (can be a number in the range [1..20])\r
+\r
+COLS_IN_ALPHA_INDEX = 5\r
+\r
+# In case all classes in a project start with a common prefix, all \r
+# classes will be put under the same header in the alphabetical index. \r
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that \r
+# should be ignored while generating the index headers.\r
+\r
+IGNORE_PREFIX = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the HTML output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will \r
+# generate HTML output.\r
+\r
+GENERATE_HTML = YES\r
+\r
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `html' will be used as the default path.\r
+\r
+HTML_OUTPUT = html\r
+\r
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for \r
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank \r
+# doxygen will generate files with .html extension.\r
+\r
+HTML_FILE_EXTENSION = .html\r
+\r
+# The HTML_HEADER tag can be used to specify a personal HTML header for \r
+# each generated HTML page. If it is left blank doxygen will generate a \r
+# standard header.\r
+\r
+HTML_HEADER = \r
+\r
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for \r
+# each generated HTML page. If it is left blank doxygen will generate a \r
+# standard footer.\r
+\r
+HTML_FOOTER = \r
+\r
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading \r
+# style sheet that is used by each HTML page. It can be used to \r
+# fine-tune the look of the HTML output. If the tag is left blank doxygen \r
+# will generate a default style sheet. Note that doxygen will try to copy \r
+# the style sheet file to the HTML output directory, so don't put your own \r
+# stylesheet in the HTML output directory as well, or it will be erased!\r
+\r
+HTML_STYLESHEET = \r
+\r
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, \r
+# files or namespaces will be aligned in HTML using tables. If set to \r
+# NO a bullet list will be used.\r
+\r
+HTML_ALIGN_MEMBERS = YES\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files \r
+# will be generated that can be used as input for tools like the \r
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) \r
+# of the generated HTML documentation.\r
+\r
+GENERATE_HTMLHELP = NO\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can \r
+# be used to specify the file name of the resulting .chm file. You \r
+# can add a path in front of the file if the result should not be \r
+# written to the html output directory.\r
+\r
+CHM_FILE = \r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can \r
+# be used to specify the location (absolute path including file name) of \r
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run \r
+# the HTML help compiler on the generated index.hhp.\r
+\r
+HHC_LOCATION = \r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag \r
+# controls if a separate .chi index file is generated (YES) or that \r
+# it should be included in the master .chm file (NO).\r
+\r
+GENERATE_CHI = NO\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag \r
+# controls whether a binary table of contents is generated (YES) or a \r
+# normal table of contents (NO) in the .chm file.\r
+\r
+BINARY_TOC = NO\r
+\r
+# The TOC_EXPAND flag can be set to YES to add extra items for group members \r
+# to the contents of the HTML help documentation and to the tree view.\r
+\r
+TOC_EXPAND = NO\r
+\r
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at \r
+# top of each HTML page. The value NO (the default) enables the index and \r
+# the value YES disables it.\r
+\r
+DISABLE_INDEX = NO\r
+\r
+# This tag can be used to set the number of enum values (range [1..20]) \r
+# that doxygen will group on one line in the generated HTML documentation.\r
+\r
+ENUM_VALUES_PER_LINE = 4\r
+\r
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be\r
+# generated containing a tree-like index structure (just like the one that \r
+# is generated for HTML Help). For this to work a browser that supports \r
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, \r
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are \r
+# probably better off using the HTML help feature.\r
+\r
+GENERATE_TREEVIEW = NO\r
+\r
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be \r
+# used to set the initial width (in pixels) of the frame in which the tree \r
+# is shown.\r
+\r
+TREEVIEW_WIDTH = 250\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the LaTeX output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will \r
+# generate Latex output.\r
+\r
+GENERATE_LATEX = NO\r
+\r
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `latex' will be used as the default path.\r
+\r
+LATEX_OUTPUT = latex\r
+\r
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be \r
+# invoked. If left blank `latex' will be used as the default command name.\r
+\r
+LATEX_CMD_NAME = latex\r
+\r
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to \r
+# generate index for LaTeX. If left blank `makeindex' will be used as the \r
+# default command name.\r
+\r
+MAKEINDEX_CMD_NAME = makeindex\r
+\r
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact \r
+# LaTeX documents. This may be useful for small projects and may help to \r
+# save some trees in general.\r
+\r
+COMPACT_LATEX = NO\r
+\r
+# The PAPER_TYPE tag can be used to set the paper type that is used \r
+# by the printer. Possible values are: a4, a4wide, letter, legal and \r
+# executive. If left blank a4wide will be used.\r
+\r
+PAPER_TYPE = a4wide\r
+\r
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX \r
+# packages that should be included in the LaTeX output.\r
+\r
+EXTRA_PACKAGES = \r
+\r
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for \r
+# the generated latex document. The header should contain everything until \r
+# the first chapter. If it is left blank doxygen will generate a \r
+# standard header. Notice: only use this tag if you know what you are doing!\r
+\r
+LATEX_HEADER = \r
+\r
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated \r
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will \r
+# contain links (just like the HTML output) instead of page references \r
+# This makes the output suitable for online browsing using a pdf viewer.\r
+\r
+PDF_HYPERLINKS = NO\r
+\r
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of \r
+# plain latex in the generated Makefile. Set this option to YES to get a \r
+# higher quality PDF documentation.\r
+\r
+USE_PDFLATEX = NO\r
+\r
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. \r
+# command to the generated LaTeX files. This will instruct LaTeX to keep \r
+# running if errors occur, instead of asking the user for help. \r
+# This option is also used when generating formulas in HTML.\r
+\r
+LATEX_BATCHMODE = NO\r
+\r
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not \r
+# include the index chapters (such as File Index, Compound Index, etc.) \r
+# in the output.\r
+\r
+LATEX_HIDE_INDICES = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the RTF output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output \r
+# The RTF output is optimized for Word 97 and may not look very pretty with \r
+# other RTF readers or editors.\r
+\r
+GENERATE_RTF = NO\r
+\r
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `rtf' will be used as the default path.\r
+\r
+RTF_OUTPUT = rtf\r
+\r
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact \r
+# RTF documents. This may be useful for small projects and may help to \r
+# save some trees in general.\r
+\r
+COMPACT_RTF = NO\r
+\r
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated \r
+# will contain hyperlink fields. The RTF file will \r
+# contain links (just like the HTML output) instead of page references. \r
+# This makes the output suitable for online browsing using WORD or other \r
+# programs which support those fields. \r
+# Note: wordpad (write) and others do not support links.\r
+\r
+RTF_HYPERLINKS = NO\r
+\r
+# Load stylesheet definitions from file. Syntax is similar to doxygen's \r
+# config file, i.e. a series of assignments. You only have to provide \r
+# replacements, missing definitions are set to their default value.\r
+\r
+RTF_STYLESHEET_FILE = \r
+\r
+# Set optional variables used in the generation of an rtf document. \r
+# Syntax is similar to doxygen's config file.\r
+\r
+RTF_EXTENSIONS_FILE = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the man page output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will \r
+# generate man pages\r
+\r
+GENERATE_MAN = NO\r
+\r
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `man' will be used as the default path.\r
+\r
+MAN_OUTPUT = man\r
+\r
+# The MAN_EXTENSION tag determines the extension that is added to \r
+# the generated man pages (default is the subroutine's section .3)\r
+\r
+MAN_EXTENSION = .3\r
+\r
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, \r
+# then it will generate one additional man file for each entity \r
+# documented in the real man page(s). These additional files \r
+# only source the real man page, but without them the man command \r
+# would be unable to find the correct page. The default is NO.\r
+\r
+MAN_LINKS = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the XML output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_XML tag is set to YES Doxygen will \r
+# generate an XML file that captures the structure of \r
+# the code including all documentation.\r
+\r
+GENERATE_XML = NO\r
+\r
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `xml' will be used as the default path.\r
+\r
+XML_OUTPUT = xml\r
+\r
+# The XML_SCHEMA tag can be used to specify an XML schema, \r
+# which can be used by a validating XML parser to check the \r
+# syntax of the XML files.\r
+\r
+XML_SCHEMA = \r
+\r
+# The XML_DTD tag can be used to specify an XML DTD, \r
+# which can be used by a validating XML parser to check the \r
+# syntax of the XML files.\r
+\r
+XML_DTD = \r
+\r
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will \r
+# dump the program listings (including syntax highlighting \r
+# and cross-referencing information) to the XML output. Note that \r
+# enabling this will significantly increase the size of the XML output.\r
+\r
+XML_PROGRAMLISTING = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options for the AutoGen Definitions output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will \r
+# generate an AutoGen Definitions (see autogen.sf.net) file \r
+# that captures the structure of the code including all \r
+# documentation. Note that this feature is still experimental \r
+# and incomplete at the moment.\r
+\r
+GENERATE_AUTOGEN_DEF = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the Perl module output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will \r
+# generate a Perl module file that captures the structure of \r
+# the code including all documentation. Note that this \r
+# feature is still experimental and incomplete at the \r
+# moment.\r
+\r
+GENERATE_PERLMOD = NO\r
+\r
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate \r
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able \r
+# to generate PDF and DVI output from the Perl module output.\r
+\r
+PERLMOD_LATEX = NO\r
+\r
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be \r
+# nicely formatted so it can be parsed by a human reader. This is useful \r
+# if you want to understand what is going on. On the other hand, if this \r
+# tag is set to NO the size of the Perl module output will be much smaller \r
+# and Perl will parse it just the same.\r
+\r
+PERLMOD_PRETTY = YES\r
+\r
+# The names of the make variables in the generated doxyrules.make file \r
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. \r
+# This is useful so different doxyrules.make files included by the same \r
+# Makefile don't overwrite each other's variables.\r
+\r
+PERLMOD_MAKEVAR_PREFIX = \r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration options related to the preprocessor \r
+#---------------------------------------------------------------------------\r
+\r
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will \r
+# evaluate all C-preprocessor directives found in the sources and include \r
+# files.\r
+\r
+ENABLE_PREPROCESSING = YES\r
+\r
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro \r
+# names in the source code. If set to NO (the default) only conditional \r
+# compilation will be performed. Macro expansion can be done in a controlled \r
+# way by setting EXPAND_ONLY_PREDEF to YES.\r
+\r
+MACRO_EXPANSION = NO\r
+\r
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES \r
+# then the macro expansion is limited to the macros specified with the \r
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.\r
+\r
+EXPAND_ONLY_PREDEF = NO\r
+\r
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files \r
+# in the INCLUDE_PATH (see below) will be search if a #include is found.\r
+\r
+SEARCH_INCLUDES = YES\r
+\r
+# The INCLUDE_PATH tag can be used to specify one or more directories that \r
+# contain include files that are not input files but should be processed by \r
+# the preprocessor.\r
+\r
+INCLUDE_PATH = \r
+\r
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard \r
+# patterns (like *.h and *.hpp) to filter out the header-files in the \r
+# directories. If left blank, the patterns specified with FILE_PATTERNS will \r
+# be used.\r
+\r
+INCLUDE_FILE_PATTERNS = \r
+\r
+# The PREDEFINED tag can be used to specify one or more macro names that \r
+# are defined before the preprocessor is started (similar to the -D option of \r
+# gcc). The argument of the tag is a list of macros of the form: name \r
+# or name=definition (no spaces). If the definition and the = are \r
+# omitted =1 is assumed.\r
+\r
+PREDEFINED = \r
+\r
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then \r
+# this tag can be used to specify a list of macro names that should be expanded. \r
+# The macro definition that is found in the sources will be used. \r
+# Use the PREDEFINED tag if you want to use a different macro definition.\r
+\r
+EXPAND_AS_DEFINED = \r
+\r
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then \r
+# doxygen's preprocessor will remove all function-like macros that are alone \r
+# on a line, have an all uppercase name, and do not end with a semicolon. Such \r
+# function macros are typically used for boiler-plate code, and will confuse the \r
+# parser if not removed.\r
+\r
+SKIP_FUNCTION_MACROS = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration::additions related to external references \r
+#---------------------------------------------------------------------------\r
+\r
+# The TAGFILES option can be used to specify one or more tagfiles. \r
+# Optionally an initial location of the external documentation \r
+# can be added for each tagfile. The format of a tag file without \r
+# this location is as follows: \r
+# TAGFILES = file1 file2 ... \r
+# Adding location for the tag files is done as follows: \r
+# TAGFILES = file1=loc1 "file2 = loc2" ... \r
+# where "loc1" and "loc2" can be relative or absolute paths or \r
+# URLs. If a location is present for each tag, the installdox tool \r
+# does not have to be run to correct the links.\r
+# Note that each tag file must have a unique name\r
+# (where the name does NOT include the path)\r
+# If a tag file is not located in the directory in which doxygen \r
+# is run, you must also specify the path to the tagfile here.\r
+\r
+TAGFILES = \r
+\r
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create \r
+# a tag file that is based on the input files it reads.\r
+\r
+GENERATE_TAGFILE = \r
+\r
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed \r
+# in the class index. If set to NO only the inherited external classes \r
+# will be listed.\r
+\r
+ALLEXTERNALS = NO\r
+\r
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed \r
+# in the modules index. If set to NO, only the current project's groups will \r
+# be listed.\r
+\r
+EXTERNAL_GROUPS = YES\r
+\r
+# The PERL_PATH should be the absolute path and name of the perl script \r
+# interpreter (i.e. the result of `which perl').\r
+\r
+PERL_PATH = /usr/bin/perl\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration options related to the dot tool \r
+#---------------------------------------------------------------------------\r
+\r
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will \r
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or \r
+# super classes. Setting the tag to NO turns the diagrams off. Note that this \r
+# option is superseded by the HAVE_DOT option below. This is only a fallback. It is \r
+# recommended to install and use dot, since it yields more powerful graphs.\r
+\r
+CLASS_DIAGRAMS = YES\r
+\r
+# If set to YES, the inheritance and collaboration graphs will hide \r
+# inheritance and usage relations if the target is undocumented \r
+# or is not a class.\r
+\r
+HIDE_UNDOC_RELATIONS = YES\r
+\r
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is \r
+# available from the path. This tool is part of Graphviz, a graph visualization \r
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section \r
+# have no effect if this option is set to NO (the default)\r
+\r
+HAVE_DOT = NO\r
+\r
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen \r
+# will generate a graph for each documented class showing the direct and \r
+# indirect inheritance relations. Setting this tag to YES will force the \r
+# the CLASS_DIAGRAMS tag to NO.\r
+\r
+CLASS_GRAPH = YES\r
+\r
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen \r
+# will generate a graph for each documented class showing the direct and \r
+# indirect implementation dependencies (inheritance, containment, and \r
+# class references variables) of the class with other documented classes.\r
+\r
+COLLABORATION_GRAPH = YES\r
+\r
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and \r
+# collaboration diagrams in a style similar to the OMG's Unified Modeling \r
+# Language.\r
+\r
+UML_LOOK = NO\r
+\r
+# If set to YES, the inheritance and collaboration graphs will show the \r
+# relations between templates and their instances.\r
+\r
+TEMPLATE_RELATIONS = NO\r
+\r
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT \r
+# tags are set to YES then doxygen will generate a graph for each documented \r
+# file showing the direct and indirect include dependencies of the file with \r
+# other documented files.\r
+\r
+INCLUDE_GRAPH = YES\r
+\r
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and \r
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each \r
+# documented header file showing the documented files that directly or \r
+# indirectly include this file.\r
+\r
+INCLUDED_BY_GRAPH = YES\r
+\r
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will \r
+# generate a call dependency graph for every global function or class method. \r
+# Note that enabling this option will significantly increase the time of a run. \r
+# So in most cases it will be better to enable call graphs for selected \r
+# functions only using the \callgraph command.\r
+\r
+CALL_GRAPH = NO\r
+\r
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen \r
+# will graphical hierarchy of all classes instead of a textual one.\r
+\r
+GRAPHICAL_HIERARCHY = YES\r
+\r
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images \r
+# generated by dot. Possible values are png, jpg, or gif\r
+# If left blank png will be used.\r
+\r
+DOT_IMAGE_FORMAT = png\r
+\r
+# The tag DOT_PATH can be used to specify the path where the dot tool can be \r
+# found. If left blank, it is assumed the dot tool can be found on the path.\r
+\r
+DOT_PATH = \r
+\r
+# The DOTFILE_DIRS tag can be used to specify one or more directories that \r
+# contain dot files that are included in the documentation (see the \r
+# \dotfile command).\r
+\r
+DOTFILE_DIRS = \r
+\r
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width \r
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than \r
+# this value, doxygen will try to truncate the graph, so that it fits within \r
+# the specified constraint. Beware that most browsers cannot cope with very \r
+# large images.\r
+\r
+MAX_DOT_GRAPH_WIDTH = 1024\r
+\r
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height \r
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than \r
+# this value, doxygen will try to truncate the graph, so that it fits within \r
+# the specified constraint. Beware that most browsers cannot cope with very \r
+# large images.\r
+\r
+MAX_DOT_GRAPH_HEIGHT = 1024\r
+\r
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the \r
+# graphs generated by dot. A depth value of 3 means that only nodes reachable \r
+# from the root by following a path via at most 3 edges will be shown. Nodes that \r
+# lay further from the root node will be omitted. Note that setting this option to \r
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also \r
+# note that a graph may be further truncated if the graph's image dimensions are \r
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). \r
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.\r
+\r
+MAX_DOT_GRAPH_DEPTH = 0\r
+\r
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will \r
+# generate a legend page explaining the meaning of the various boxes and \r
+# arrows in the dot generated graphs.\r
+\r
+GENERATE_LEGEND = YES\r
+\r
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will \r
+# remove the intermediate dot files that are used to generate \r
+# the various graphs.\r
+\r
+DOT_CLEANUP = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration::additions related to the search engine \r
+#---------------------------------------------------------------------------\r
+\r
+# The SEARCHENGINE tag specifies whether or not a search engine should be \r
+# used. If set to NO the values of all tags below this one will be ignored.\r
+\r
+SEARCHENGINE = NO\r
--- /dev/null
+# rules
+export CC=gcc
+export CDEFS = -DNDEBUG
+
+# directories
+BASE :=$(shell pwd)
+export SRC=$(BASE)/src
+export TST=$(BASE)/tst
+export INC=$(BASE)/inc
+export LIB=$(BASE)/lib
+
+all :
+ cd $(SRC) && $(MAKE) all
+ cd $(TST) && $(MAKE) all
+
+
+clean :
+ cd $(SRC) && $(MAKE) clean
+ cd $(TST) && $(MAKE) clean
+
+doc :
+ doxygen
+
--- /dev/null
+NMEAP is licensed under the BSD Open Source License. See the file COPYING for terms of the license
+
+VERSION 0.2 - bug fixes and tutorial
+ a. fixed a bug in test3.c
+ b. added a tutorial in doc/tutorial.html
+
+Installation:
+
+Unpack the tarball or zip file into the desired working directory.
+
+Building:
+
+Under Linux, execute 'make' from the top level directory.
+
+Under Win32, execute 'nmake -f win32.mak' from the top level directory
+
+Using:
+
+This library is statically linked to the application. Just include it in
+your linker command line. See the file 'nmeap.h' and the examples in the
+'tst' directory for usage instructions.
+
+
+
--- /dev/null
+<html>\r
+<body>\r
+<h1>NMEAP TUTORIAL AND REFERENCE</h1>\r
+<hr />\r
+<pre>\r
+copyright (c) 2005 David M. Howard\r
+This work is licensed under the Creative Commons Attribution License.\r
+To view a copy of this license, visit\r
+http://creativecommons.org/licenses/by/2.0/ or send a letter to\r
+Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305,USA\r
+You are free:\r
+ * to copy, distribute, display, and perform the work\r
+ * to make derivative works\r
+ * to make commercial use of the work\r
+Under the following conditions:\r
+Attribution. You must give the original author credit.\r
+ * For any reuse or distribution, you must make clear to others the\r
+ license terms of this work.\r
+ * Any of these conditions can be waived if you get permission from\r
+ the author.\r
+</pre> \r
+<hr />\r
+<h2>Table Of Contents</h2>\r
+<ol>\r
+<li><a href="#c1">Installing the Source Code</a></li>\r
+<li><a href="#c2">Building the Library</a></li>\r
+<li><a href="#c3">Description and Examples</a></li>\r
+<li><a href="#c4">API Documentation</a></li>\r
+</ol>\r
+<a name="c1"> </a>\r
+</a><h2>1. Installing the source code</h2>\r
+Get the source code from <a href="http://sourceforge.net/projects/nmeap/">NMEAP at sourceforge.net</a>\r
+<pre>\r
+\r
+Linux:\r
+ expand the tarball to a directory of your choice.\r
+ >tar --gzip -xf [tarball name]\r
+ >cd [nmeap...]\r
+ \r
+Windows:\r
+ use Winzip to unzip the zipfile to a directory of your choice\r
+ \r
+</pre>\r
+\r
+<a name="c2"> </a>\r
+<h2>2. Building the library </h2>\r
+<pre>\r
+\r
+Linux:\r
+ >cd [working directory]\r
+ >make\r
+ This builds a static library named libnmeap.a in the 'lib' directory. there is no option for a dynamic library. \r
+ This thing is so small that it isn't worth the trouble. It also builds the test/examples programs in\r
+ 'tst'.\r
+ \r
+Windows:\r
+ >cd [working directory]\r
+ >nmake -f win32.mak\r
+ Again, this builds a static library names libnmeap.lib in the 'lib' direcotry, plus the test programs in 'tst'\r
+</pre>\r
+<a name="c3"> </a>\r
+<h2>3. Description and Examples</h2>\r
+<p>The NMEA-0183 standard specifies how the output is formatted for GPS data output, usually on a serial port. The data \r
+consists of 'sentences' delimited by CR/LF end of line markers. A lot has been written about the format, so this document\r
+won't cover the specifics. A good place to start is the <a href="http://vancouver-webpages.com/peter/nmeafaq.txt">NMEA FAQ</a> \r
+maintained by Peter Bennett.</p> \r
+<p>NMEAP is an extensible C language parser library that takes NMEA sentences as input and spits out the decoded data as output. You link\r
+NMEAP in to your application, set it up, initialize it and feed it bytes. It signals you when it has found a complete valid sentence and \r
+provides the parsed out data to you. Parsing NMEA-0183 is pretty easy but it has a few tricky bits. The value of NMEAP is not that it is\r
+rocket science to write an NMEA parser, but that it provides a relatively efficient implementation that works, along with an\r
+extension framework to add more sentence parsers without hacking the base source code.</p>\r
+<p>An NMEA 'sentence' has the following format:</p>\r
+<pre>\r
+ $name,data1,data2,...,dataN*XX[CR/LF]\r
+ OR\r
+ $name,data1,data2,...,dataN[CR/LF]\r
+ \r
+where\r
+ header := a 5 digit sentence identifier. all ASCII upper case. e.g. GPGGA\r
+ data1..dataN := some number of data elements, all ASCII numbers or letters, in all kinds of weird formats.\r
+ fields can be empty, in which case 2 commas will be side by side.\r
+ normally data fields are identified by their position in the sentence. \r
+ *XX := a '*' plus two ASCII hex digits of checksum. this field is optional.\r
+ [CR/LF] := end of line is terminated by a carriage return/linefeed pair.\r
+ \r
+example from the <a href="http://vancouver-webpages.com/peter/nmeafaq.txt">NMEA FAQ</a>:\r
+ $GPGGA,123519,4807.038,N,01131.324,E,1,08,0.9,545.4,M,46.9,M,,*42\r
+</pre> \r
+<p>The NMEAP parser works as follows:\r
+<ol>\r
+ <li>the application sets up the parser and specifies which sentences are to be parsed\r
+ and what is to be done with the output data from the parser.</li>\r
+ <li>the application reads raw bytes from its IO device and passes the bytes to the parser,\r
+ either byte by byte or as a buffer/length pair.</li>\r
+ <li>nmeap:\r
+ <ul>\r
+ <li>runs the input bytes through a lexical scanner that recognizes complete and valid sentences</li>\r
+ <li>when a sentence is recognized, a second lexical scanner divides the sentence into discrete tokens.</li>\r
+ <li>the name field is matched internally to a sentence parser for that name</li>\r
+ <li> the sentence parser picks out the data strings and decodes them into an nmeap or user \r
+ defined data structure with normal data types such as integer, float, double etc. </li>\r
+ <li>notifies the client application that a sentence was found and decoded, either thru a callout \r
+ to an event handler (ala Expat) or via a return code and a shared data structure, or both.</li>\r
+ </ul>\r
+ </li>\r
+</ol>\r
+<h4>Sentence Parsers</h4>\r
+<p>Most of the work in NMEAP is done by the sentence parsers. Each type of NMEA sentence string has an associated parser. NMEAP provides\r
+standard ones, and the user can add more in a systematic way.\r
+The sentence parser is responsible for knowing the token position of the data elements and whatever format they \r
+are in. There are functions in nmeap to decode standard data element formats. If something is nonstandard, \r
+the sentence parser decodes it. Each sentence parser has a 'struct' type associated with it\r
+that the decoded data gets poked into an instance of that data structure, which is provided by the client application when nmeap is set\r
+up.</p>\r
+<h4>Memory Allocation</h4>\r
+<p>All memory allocation is done by the application. Several data items are required. The application can declare them statically or use\r
+malloc or whatever. NMEAP doesn't do any memory allocation on its own. This is an important requirement for portability and especially in\r
+embedded systems where memory allocation needs to be tightly defined and controlled.\r
+</p>\r
+<h4>Threads</h4>\r
+<p>NMEAP as implemented is not meant to be called from multiple threads. It expects to execute within the context of a single thread. The sentence callouts execute\r
+in the context of the thread of the nmeap client thread. Given how nmeap works, it doesn't really make sense to make nmeap thread-safe\r
+because the usage pattern is intrinsically single thread. If one wanted to, one could add some mutex locking within the nmeap function\r
+calls to make it thread safe. In a multithreaded environment, a more likely approach to thread-safety is to put synchronization in the client side of the application,\r
+within the sentence parser callouts or inline handling of sentence data.\r
+</p>\r
+<h4>IO</h4>\r
+<p>NMEAP is IO agnostic. That is a pompous way of saying that NMEAP doesn't do the IO, the client application does it. There are way too\r
+many IO schemes to handle to keep it portable, especially in the embedded world. That said, the example programs contain a Linux and a Win32 specific\r
+program that includes serial IO for those two platforms.\r
+</p>\r
+\r
+<h4>Examples</h4>\r
+Look at the code for the following example programs to see the usage patterns. The are all located in the\r
+'tst' directory. There are big, obvious comments delineating the steps to setting up and using NMEAP.\r
+The IO is simulated in the samples. Follow the comments in the code\r
+to see the sequence of operations to setup and run the parser. When you are ready just plug in your own IO.\r
+<ol>\r
+ <li>tst/test1.c Setup for standard GGA and RMC sentences with byte by byte IO (easiest to code up)</li>\r
+ <li>tst/test2.c Setup for standard GGA and RMC sentences with block IO (more efficient from a system call standpoint)</li>\r
+ <li>tst/test3.c Adding a custom parser</li>\r
+ <li>tst/wingps.c A console program that reads a serial port and writes the decoded data to standard out for WIN32 applications</li>\r
+</ol>\r
+<a name="c4"> </a>\r
+<h3>API Documentation</h3>\r
+The documentation for the actual API is in <a href="www.doxygen.org">Doxygen<a> HTML format and is contained in the 'doc' directory of\r
+the source distribution. Or, all the external data structures, constants and functions are defined in 'inc/nmeap.h'. \r
+\r
+<p>END</p>\r
+</body>\r
+</html>\r
--- /dev/null
+/*
+Copyright (c) 2005, David M Howard (daveh at dmh2000.com)
+All rights reserved.
+
+This product is licensed for use and distribution under the BSD Open Source License.
+see the file COPYING for more details.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef __NMEAP_H__
+#define __NMEAP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+============================================
+COMPILE TIME CONFIGURATION CONSTANTS
+============================================
+*/
+
+/* these constants affect the size of the context object. tweak them as desired but know what you are doing */
+
+/** maximum number of sentence parsers supported */
+#define NMEAP_MAX_SENTENCES 8
+/** length of sentence name. leave this at 5 unless you really know what you are doing */
+#define NMEAP_MAX_SENTENCE_NAME_LENGTH 5
+/** max length of a complete sentence. the standard says 82 bytes, but its probably better to go at least 128 since
+ * some units don't adhere to the 82 bytes especially for proprietary sentences */
+#define NMEAP_MAX_SENTENCE_LENGTH 255
+/** max tokens in one sentence. 24 is enough for any standard sentence */
+#define NMEAP_MAX_TOKENS 24
+
+/* predefined message ID's */
+
+/* GGA MESSAGE ID */
+#define NMEAP_GPGGA 1
+/* RMC MESSAGE ID */
+#define NMEAP_GPRMC 2
+
+/** user defined parsers should make ID numbers using NMEAP_USER as the base value, plus some increment */
+#define NMEAP_USER 100
+
+/* forward references */
+struct nmeap_context;
+struct nmeap_sentence;
+
+/*
+============================================
+CALLOUTS
+============================================
+*/
+
+/**
+ * sentence callout function type
+ * a callout is fired for each registered sentence type
+ * the callout gets the object context and a pointer to sentence specific data.
+ * the callout must cast the 'sentence_data' to the appropriate type for that callout
+ * @param context nmea object context
+ * @param sentence_data sentence specific data
+*/
+typedef void (*nmeap_callout_t)(struct nmeap_context *context,void *sentence_data,void *user_data);
+
+/**
+ * sentence parser function type
+ * stored in the object context and called internally when the sentence name matches
+ * the specified value
+ * the callout gets the object context and a pointer to sentence specific data.
+ * the callout must cast the 'sentence_data' to the appropriate type for that callout
+ * @param context nmea object context
+ * @param sentence_data sentence specific data
+ * @return id of sentence (each sentence parser knows its own ID)
+*/
+typedef int (*nmeap_sentence_parser_t)(struct nmeap_context *context,struct nmeap_sentence *sentence);
+
+
+/* ==== opaque types === */
+#include "nmeap_def.h"
+
+
+/*
+============================================
+STANDARD SENTENCE DATA STRUCTURES
+============================================
+*/
+
+/** extracted data from a GGA message */
+struct nmeap_gga {
+ double latitude;
+ double longitude;
+ double altitude;
+ unsigned long time;
+ int satellites;
+ int quality;
+ double hdop;
+ double geoid;
+};
+typedef struct nmeap_gga nmeap_gga_t;
+
+/** extracted data from an RMC message */
+struct nmeap_rmc {
+ unsigned long time;
+ char warn;
+ double latitude;
+ double longitude;
+ double speed;
+ double course;
+ unsigned long date;
+ double magvar;
+};
+
+typedef struct nmeap_rmc nmeap_rmc_t;
+
+/*
+============================================
+METHODS
+============================================
+*/
+
+/**
+ * initialize an NMEA parser. call this function to initialize a user allocated context object
+ * @param context nmea object context. allocated by user statically or dynamically.
+ * @param user_data pointer to user defined data
+ * @return 0 if ok, -1 if initialization failed
+ */
+int nmeap_init(nmeap_context_t *context,void *user_data);
+
+/**
+ * register an NMEA sentence parser
+ * @param context nmea object context
+ * @param sentence_name string matching the sentence name for this parser. e.g. "GPGGA". not including the '$'
+ * @param sentence_parser parser function for this sentence
+ * @param sentence_callout callout triggered when this sentence is received and parsed.
+ * if null, no callout is triggered for this sentence
+ * @param sentence_data user allocated sentence specific data defined by the application. the parser uses
+ this data item to store the extracted data. This data object needs to persist over the life
+ of the parser, so be careful if allocated on the stack.
+ * @return 0 if registered ok, -1 if registration failed
+ */
+int nmeap_addParser(nmeap_context_t *context,
+ const char *sentence_name,
+ nmeap_sentence_parser_t sentence_parser,
+ nmeap_callout_t sentence_callout,
+ void *sentence_data
+ );
+
+/**
+ * parse a buffer of nmea data.
+ * @param context nmea object context
+ * @param buffer buffer of input characters
+ * @param length [in,out] pointer to length of buffer. on return, contains number of characters not used for
+ * the current sentence
+ * @return -1 if error, 0 if the data did not complete a sentence, sentence code if a sentence was found in the stream
+ */
+int nmeap_parseBuffer(nmeap_context_t *context,const char *buffer,int *length);
+
+/**
+ * parse one character of nmea data.
+ * @param context nmea object context
+ * @param ch input character
+ * @return -1 if error, 0 if the data did not complete a sentence, sentence code if a sentence was found in the stream
+ */
+int nmeap_parse(nmeap_context_t *context,char ch);
+
+
+/**
+ * built-in parser for GGA sentences.
+ * @param context nmea object context
+ * @param sentence sentence object for this parser
+ */
+int nmeap_gpgga(nmeap_context_t *context,nmeap_sentence_t *sentence);
+
+/**
+ * built-in parser for RMC sentences.
+ * @param context nmea object context
+ * @param sentence sentence object for this parser
+ */
+int nmeap_gprmc(nmeap_context_t *context,nmeap_sentence_t *sentence);
+
+/**
+ * extract latitude from 2 tokens in ddmm.mmmm,h format.
+ * @param plat pointer to token with numerical latitude
+ * @param phem pointer to token with hemisphere
+ * @return latitude in degrees and fractional degrees
+ */
+double nmeap_latitude(const char *plat,const char *phem);
+
+
+/**
+ * extract longitude from 2 tokens in ddmm.mmmm,h format.
+ * @param plat pointer to token with numerical longitude
+ * @param phem pointer to token with hemisphere
+ * @return longitude in degrees and fractional degrees
+ */
+double nmeap_longitude(const char *plat,const char *phem);
+
+#ifdef __cplusplus
+} // extern C
+#endif
+
+
+#endif
+
--- /dev/null
+/*
+Copyright (c) 2005, David M Howard (daveh at dmh2000.com)
+All rights reserved.
+
+This product is licensed for use and distribution under the BSD Open Source License.
+see the file COPYING for more details.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef __NMEAP_DEF_H__
+#define __NMEAP_DEF_H__
+
+/**
+ * context for a single sentence
+ */
+typedef struct nmeap_sentence {
+ char name[NMEAP_MAX_SENTENCE_NAME_LENGTH + 1];
+ int id;
+ nmeap_sentence_parser_t parser;
+ nmeap_callout_t callout;
+ void *data;
+} nmeap_sentence_t;
+
+/**
+ * parser context
+ */
+struct nmeap_context {
+ /** support up to 8 sentences */
+ nmeap_sentence_t sentence[NMEAP_MAX_SENTENCES]; /* sentence descriptors */
+ int sentence_count; /* number of initialized descriptors */
+
+ /** sentence input buffer */
+ char input[NMEAP_MAX_SENTENCE_LENGTH + 1]; /* input line buffer */
+ int input_count; /* index into 'input */
+ int input_state; /* current lexical scanner state */
+ char input_name[6]; /* sentence name */
+ char icks; /* input checksum */
+ char ccks; /* computed checksum */
+
+ /* tokenization */
+ char *token[NMEAP_MAX_TOKENS]; /* list of delimited tokens */
+ int tokens; /* list of tokens */
+
+ /** errors and debug. optimize these as desired */
+ unsigned long msgs; /* count of good messages */
+ unsigned long err_hdr; /* header error */
+ unsigned long err_ovr; /* overrun error */
+ unsigned long err_unk; /* unknown error */
+ unsigned long err_id; /* bad character in id */
+ unsigned long err_cks; /* bad checksum */
+ unsigned long err_crl; /* expecting cr or lf, got something else */
+ char debug_input[NMEAP_MAX_SENTENCE_LENGTH + 1]; /* input line buffer for debug */
+
+ /** opaque user data */
+ void *user_data;
+};
+
+typedef struct nmeap_context nmeap_context_t;
+
+#endif /* __NMEAP_DEF_H__ */
--- /dev/null
+# specify compiler flags
+CFLAGS = -I $(INC) $(CDEFS) -g -O0 -Werror -Wall
+
+# set library name
+LIBNAME = libnmeap.a
+
+COBJ = nmeap01.o
+
+INCLUDES= $(INC)/nmeap.h $(INC)/nmeap_def.h
+
+# build everything
+all : $(LIB)/$(LIBNAME)
+
+# build the library
+$(LIB)/$(LIBNAME) : $(COBJ)
+ -$(RM) $(LIB)/$(LIBNAME)
+ $(AR) -q $(LIB)/$(LIBNAME) $(COBJ)
+
+# build all c files into .o files
+$(COBJ): %.o: %.c
+ $(CC) -c $(CFLAGS) $(SRC)/$< -o $@
+
+# erase all intermediate and output files
+clean :
+ -$(RM) *.o
+ -$(RM) *~
+ -$(RM) $(LIB)/$(LIBNAME)
+
+# include file dependencies
+$(COBJ) : $(INCLUDES)
+
--- /dev/null
+INCLUDES= ..\inc\nmeap.h ..\inc\nmeap_def.h\r
+CSRC = nmeap01.c\r
+LIBNAME = ..\lib\libnmeap.lib\r
+\r
+# build everything\r
+all : $(LIBNAME)\r
+\r
+$(LIBNAME) : nmeap01.obj\r
+ -erase $(LIBNAME)\r
+ lib /OUT:$(LIBNAME) nmeap01.obj\r
+\r
+nmeap01.obj : nmeap01.c $(INCLUDES)\r
+ cl /DNDEBUG /c /I..\inc nmeap01.c\r
+\r
+# erase all intermediate and output files\r
+clean :\r
+ -erase *.obj\r
+ -erase $(LIBNAME)\r
+\r
+\r
--- /dev/null
+/*
+Copyright (c) 2005, David M Howard (daveh at dmh2000.com)
+All rights reserved.
+
+This product is licensed for use and distribution under the BSD Open Source License.
+see the file COPYING for more details.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/**
+ * nmeap01.c
+ * nmeap gps data parser
+ *
+ * see the file COPYING for terms of the licnese
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include "nmeap.h"
+
+/* this only works if you are sure you have an upper case hex digit */
+#define HEXTOBIN(ch) ((ch <= '9') ? ch - '0' : ch - ('A' - 10))
+
+/* forward references */
+int nmeap_init(nmeap_context_t *context,void *user_data);
+int nmeap_addParser(nmeap_context_t *context,
+ const char *sentence_name,
+ nmeap_sentence_parser_t sentence_parser,
+ nmeap_callout_t sentence_callout,
+ void *sentence_data
+ );
+int nmeap_tokenize(nmeap_context_t *context);
+int nmeap_process(nmeap_context_t *context);
+int nmeap_parse(nmeap_context_t *context,char ch);
+int nmeap_parseBuffer(nmeap_context_t *context,const char *buffer,int *length);
+
+/**
+ * get a latitude out of a pair of nmea tokens
+ */
+double nmeap_latitude(const char *plat,const char *phem)
+{
+ double lat;
+ int deg;
+ double min;
+ int ns;
+
+ assert(plat != 0);
+ assert(phem != 0);
+
+ if (*plat == 0) {
+ return 0.0;
+ }
+ if (*phem == 0) {
+ return 0.0;
+ }
+
+ /* north lat is +, south lat is - */
+ if (*phem == 'N') {
+ ns = 1;
+ }
+ else {
+ ns = -1;
+ }
+
+ /* latitude is degrees, minutes, fractional minutes */
+ /* no validation is performed on the token. it better be good.*/
+ /* if it comes back 0.0 then probably the token was bad */
+ lat = atof(plat);
+
+ /* extract the degree part */
+ deg = (int)(lat / 100.0);
+
+ /* mask out the degrees */
+ min = lat - (deg * 100.0);
+
+ /* compute the actual latitude in degrees.decimal-degrees */
+ lat = (deg + (min / 60.0)) * ns;
+
+ return lat;
+}
+
+/**
+ * get a longitude out of a pair of nmea tokens
+ */
+double nmeap_longitude(const char *plon,const char *phem)
+{
+ double lon;
+ int deg;
+ double min;
+ int ew;
+
+ assert(plon != 0);
+ assert(phem != 0);
+
+ if (*plon == 0) {
+ return 0.0;
+ }
+ if (*phem == 0) {
+ return 0.0;
+ }
+
+ /* west long is negative, east long is positive */
+ if (*phem == 'E') {
+ ew = 1;
+ }
+ else {
+ ew = -1;
+ }
+
+ /* longitude is degrees, minutes, fractional minutes */
+ /* no validation is performed on the token. it better be good.*/
+ /* if it comes back 0.0 then probably the token was bad */
+ lon = atof(plon);
+
+ /* extract the degree part */
+ deg = (int)(lon / 100.0);
+
+ /* mask out the degrees */
+ min = lon - (deg * 100.0);
+
+ /* compute the actual lonitude in degrees.decimal-degrees */
+ lon = (deg + (min / 60.0)) * ew;
+
+
+ return lon;
+}
+
+/**
+ * get an altitude longitude out of a pair of nmea tokens
+ * ALTITUDE is returned in METERS
+ */
+double nmeap_altitude(const char *palt,const char *punits)
+{
+ double alt;
+
+ if (*palt == 0) {
+ return 0.0;
+ }
+
+ /* convert with no error checking */
+ alt = atof(palt);
+
+ if (*punits == 'M') {
+ /* already in meters */
+ }
+ else if (*punits == 'F') {
+ /* convert to feet */
+ alt = alt * 3.2808399;
+ }
+
+ return alt;
+}
+
+/**
+ * initialize an NMEA parser
+ */
+int nmeap_init(nmeap_context_t *context,void *user_data)
+{
+ assert(context != 0);
+
+ memset(context,0,sizeof(*context));
+
+ context->user_data = user_data;
+
+ return 0;
+}
+
+
+/**
+ * register an NMEA sentence parser
+ */
+int nmeap_addParser(nmeap_context_t *context,
+ const char *sentence_name,
+ nmeap_sentence_parser_t sentence_parser,
+ nmeap_callout_t sentence_callout,
+ void *sentence_data
+ )
+{
+ nmeap_sentence_t *s = 0;
+
+ /* runtime error */
+ assert(context != 0);
+
+ /* sentence capacity overflow */
+ if (context->sentence_count >= NMEAP_MAX_SENTENCES) {
+ return -1;
+ }
+
+ /* point at next empty sentence buffer */
+ s = &context->sentence[context->sentence_count];
+
+ /* advance sentence data count */
+ context->sentence_count++;
+
+ /* clear the sentence data */
+ memset(s,0,sizeof(*s));
+
+ /* name */
+ strncpy(s->name,sentence_name,NMEAP_MAX_SENTENCE_NAME_LENGTH);
+
+ /* parser */
+ s->parser = sentence_parser;
+
+ /* callout */
+ s->callout = sentence_callout;
+
+ /* data */
+ s->data = sentence_data;
+
+ return 0;
+}
+
+/**
+ * tokenize a buffer
+ */
+int nmeap_tokenize(nmeap_context_t *context)
+{
+ char *s;
+ int tokens;
+ int state;
+
+ /* first token is header. assume it is there */
+ tokens = 0;
+ s = context->input;
+ context->token[tokens] = s;
+
+ /* get rest of tokens */
+ tokens = 1;
+ state = 0;
+ while((*s != 0)&&(tokens < NMEAP_MAX_TOKENS)) {
+ switch(state) {
+ case 0:
+ /* looking for end of a token */
+ if (*s == ',') {
+ /* delimit at the comma */
+ *s = 0;
+ /* new token */
+ state = 1;
+ }
+ break;
+ case 1:
+ /* start of next token, might be another comma */
+ context->token[tokens++] = s;
+ if (*s == ',') {
+ /* delimit at the comma */
+ *s = 0;
+ }
+ else {
+ /* not a comma */
+ state = 0;
+ }
+ break;
+ default:
+ state = 0;
+ break;
+ }
+
+ // next character
+ s++;
+ }
+ return tokens;
+}
+
+/**
+ * process a sentence
+ */
+int nmeap_process(nmeap_context_t *context)
+{
+ int id;
+ int i;
+ nmeap_sentence_t *s;
+
+ /* copy the input to a debug buffer */
+ /* remove debug_input when everything is working. */
+ strncpy(context->debug_input,context->input,sizeof(context->debug_input));
+
+ /* tokenize the input */
+ context->tokens = nmeap_tokenize(context);
+
+ /* try to find a matching sentence parser */
+ /* this search is O(n). it has a lot of potential for optimization, at the expense of complexity, if you have a lot of sentences */
+ /* binary search instead of linear (have to keep sentences in sorted order) O(NlogN) */
+ /* OR, when sentences are added, create a TRIE structure to find the names with a constant time search O(5) */
+ for(i=0;i<context->sentence_count;i++) {
+ s = &context->sentence[i];
+ assert(s != 0);
+ if (strncmp(context->input_name,s->name,5) == 0) {
+ /* found a match, call its parser */
+ id = (*context->sentence[i].parser)(context,s);
+ if (id > 0) {
+ break;
+ }
+ }
+ }
+
+ return id;
+}
+
+/**
+ +-5-+ +---+
+ v | v |
+ +------+ +------+ +------+ +------+ +------+
+ | 0 |--$--> |1-hdr |--alnum--> |2-data|----\r-->| 6-LF |---\n--->| done |--> 0
+ +------+ +------+ +------+ +------+ +------+
+ | ^
+ * +--------\r-------+
+ V |
+ +------+ +------+ +------+
+ |3-cks |--xdigit-->|4-cks |-xdigit->| 5-CR |
+ +------+ +------+ +------+
+
+return to start conditions:
+1. buffer overflow
+2. invalid character for state
+
+checksum calculation
+two hex digits represent the XOR of all characters between, but not
+including, the "$" and "*". A checksum is required on some
+sentences.
+
+*/
+int nmeap_parse(nmeap_context_t *context,char ch)
+{
+ int status = 0;
+
+ /* check for input buffer overrun first to avoid duplicating code in the
+ individual states
+ */
+ if (context->input_count >= (sizeof(context->input)-1)) {
+ /* input buffer overrun, restart state machine */
+ context->input_state = 0;
+ /* reset input count */
+ context->input_count = 0;
+ }
+
+ /* store the byte */
+ context->input[context->input_count] = ch;
+
+ /* next buffer position */
+ context->input_count++;
+
+ /* run it through the lexical scanner */
+ switch(context->input_state) {
+ /* LOOKING FOR $ */
+ case 0:
+ if (ch == '$') {
+ /*look for id */
+ context->input_state = 1;
+ context->ccks = 0;
+ context->icks = 0;
+ }
+ else {
+ /* header error, start over */
+ context->err_hdr++;
+ context->input_state = 0;
+ context->input_count = 0;
+ }
+ break;
+ /* LOOKING FOR 5 CHARACTER SENTENCE ID */
+ case 1:
+ /* allow numbers even though it isn't usually done */
+ /* a proprietary id might have a numeral */
+ if (isalnum(ch)) {
+ /* store name separately */
+ context->input_name[context->input_count - 2] = ch;
+ /* checksum */
+ context->ccks ^= ch;
+ /* end of header? */
+ if (context->input_count >= 6) {
+ /* yes, get body */
+ context->input_state = 2;
+ }
+ }
+ else {
+ /* bad character, start over */
+ context->err_id++;
+ context->input_state = 0;
+ context->input_count = 0;
+ }
+ break;
+ /* LOOKING FOR CR OR CHECKSUM INDICATOR */
+ case 2:
+ if (ch == '*') {
+ /* this sentence has a checksum */
+ context->input_state = 3;
+ }
+ else if (ch == '\r') {
+ /* carriage return, no checksum, force a match */
+ context->icks = 0;
+ context->ccks = 0;
+ context->input_state = 6;
+ }
+ else {
+ /* continue accumulating data */
+ /* checksum */
+ context->ccks ^= ch;
+ }
+ break;
+ /* LOOKING FOR FIRST CHECKSUM CHARACTER */
+ case 3:
+ /* must be upper case hex digit */
+ if (isxdigit(ch) && (ch <= 'F')) {
+ /* got first checksum byte */
+ context->input_state = 4;
+ context->icks = HEXTOBIN(ch) << 4;
+ }
+ else {
+ /* input error, restart */
+ context->err_cks++;
+ context->input_state = 0;
+ context->input_count = 0;
+ }
+ break;
+ /* LOOKING FOR SECOND CHECKSUM CHARACTER */
+ case 4:
+ /* must be upper case hex digit */
+ if (isxdigit(ch) && (ch <= 'F')) {
+ /* got second checksum byte */
+ context->input_state = 5;
+ context->icks += HEXTOBIN(ch);
+ }
+ else {
+ /* input error, restart */
+ context->err_cks++;
+ context->input_state = 0;
+ context->input_count = 0;
+ }
+ break;
+ /* LOOKING FOR CR */
+ case 5:
+ if (ch == '\r') {
+ /* carriage return */
+ context->input_state = 6;
+ }
+ else {
+ /* input error, restart */
+ context->err_crl++;
+ context->input_state = 0;
+ context->input_count = 0;
+ }
+ break;
+ /* LOOKING FOR LINE FEED */
+ case 6:
+ if (ch == '\n') {
+ /* linefeed, line complete */
+
+ /* delimit buffer */
+ context->input[context->input_count] = 0;
+
+ /* if the checksums match, process the sentence */
+ if (context->ccks == context->icks) {
+ /* process */
+ status = nmeap_process(context);
+
+ /* count good messages */
+ context->msgs++;
+ }
+ else {
+ /* count checksum errors */
+ context->err_cks++;
+ }
+
+ /* restart next time */
+ context->input_state = 0;
+ context->input_count = 0;
+ }
+ else {
+ /* input error, restart */
+ context->err_crl++;
+ context->input_state = 0;
+ context->input_count = 0;
+ }
+ break;
+ default:
+ context->err_unk++;
+ context->input_state = 0;
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * parse a buffer of nmea data
+ */
+int nmeap_parseBuffer(nmeap_context_t *context,const char *buffer,int *length)
+{
+ int i;
+ int status;
+ int rem;
+ int tlen;
+
+ tlen = *length;
+ rem = *length;
+ status = 0;
+ /* for each byte in the buffer */
+ for(i=0;i<tlen;i++) {
+ /* decrement remaining byte count */
+ rem--;
+ /* parse the byte */
+ status = nmeap_parse(context,buffer[i]);
+ if (status != 0) {
+ /* message found or error */
+ break;
+ }
+ }
+
+ /* return remaining byte count */
+ *length = rem;
+
+ return status;
+}
+
+/**
+ * standard GPGGA sentence parser
+ */
+int nmeap_gpgga(nmeap_context_t *context,nmeap_sentence_t *sentence)
+{
+#ifndef NDEBUG
+ int i;
+#endif
+
+ /* get pointer to sentence data */
+ nmeap_gga_t *gga = (nmeap_gga_t *)sentence->data;
+
+ /* if there is a data element, extract data from the tokens */
+ if (gga != 0) {
+ gga->latitude = nmeap_latitude(context->token[2],context->token[3]);
+ gga->longitude = nmeap_longitude(context->token[4],context->token[5]);
+ gga->altitude = nmeap_altitude(context->token[9],context->token[10]);
+ gga->time = atoi(context->token[1]);
+ gga->satellites = atoi(context->token[7]);
+ gga->quality = atoi(context->token[6]);
+ gga->hdop = atof(context->token[8]);
+ gga->geoid = nmeap_altitude(context->token[11],context->token[12]);
+ }
+
+#ifndef NDEBUG
+ /* print raw input string */
+ printf("%s",context->debug_input);
+
+ /* print some validation data */
+ printf("%s==%s %02x==%02x\n",context->input_name,sentence->name,context->icks,context->ccks);
+
+ /* print the tokens */
+ for(i=0;i<context->tokens;i++) {
+ printf("%d:%s\n",i,context->token[i]);
+ }
+#endif
+
+ /* if the sentence has a callout, call it */
+ if (sentence->callout != 0) {
+ (*sentence->callout)(context,gga,context->user_data);
+ }
+
+ return NMEAP_GPGGA;
+}
+
+/**
+ * standard GPRMCntence parser
+ */
+int nmeap_gprmc(nmeap_context_t *context,nmeap_sentence_t *sentence)
+{
+#ifndef NDEBUG
+ int i;
+#endif
+
+ /* get pointer to sentence data */
+ nmeap_rmc_t *rmc = (nmeap_rmc_t *)sentence->data;
+
+ /* if there is a data element, use it */
+ if (rmc != 0) {
+ /* extract data from the tokens */
+ rmc->time = atoi(context->token[1]);
+ rmc->warn = *context->token[2];
+ rmc->latitude = nmeap_latitude(context->token[3],context->token[4]);
+ rmc->longitude = nmeap_longitude(context->token[5],context->token[6]);
+ rmc->speed = atof(context->token[7]);
+ rmc->course = atof(context->token[8]);
+ rmc->date = atoi(context->token[9]);
+ rmc->magvar = atof(context->token[10]);
+ }
+
+#ifndef NDEBUG
+ /* print raw input string */
+ printf("%s",context->debug_input);
+
+ /* print some validation data */
+ printf("%s==%s %02x==%02x\n",context->input_name,sentence->name,context->icks,context->ccks);
+
+ /* print the tokens */
+ for(i=0;i<context->tokens;i++) {
+ printf("%d:%s\n",i,context->token[i]);
+ }
+#endif
+
+ /* if the sentence has a callout, call it */
+ if (sentence->callout != 0) {
+ (*sentence->callout)(context,rmc,context->user_data);
+ }
+
+ return NMEAP_GPRMC;
+}
+
+
--- /dev/null
+all : test1 test2 test3
+
+test1 : $(LIB)/libnmeap.a $(TST)/test1.c
+ gcc -g -O0 -I $(INC) $(CDEFS) -Wall -Werror -o test1 $(TST)/test1.c $(LIB)/libnmeap.a
+
+test2 : $(LIB)/libnmeap.a $(TST)/test2.c
+ gcc -g -O0 -I $(INC) $(CDEFS) -Wall -Werror -o test2 $(TST)/test2.c $(LIB)/libnmeap.a
+
+test3 : $(LIB)/libnmeap.a $(TST)/test3.c
+ gcc -g -O0 -I $(INC) $(CDEFS) -Wall -Werror -o test3 $(TST)/test3.c $(LIB)/libnmeap.a
+
+clean:
+ -$(RM) test1
+ -$(RM) test2
+ -$(RM) test3
+
+
--- /dev/null
+/*
+Copyright (c) 2005, David M Howard (daveh at dmh2000.com)
+All rights reserved.
+
+This product is licensed for use and distribution under the BSD Open Source License.
+see the file COPYING for more details.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/*
+========================================================================================================
+EXAMPLE : SETUP FOR GGA AND RMC SENTENCES WITH CHARACTER BY CHARACTER IO
+=======================================================================================================
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nmeap.h"
+
+nmeap_gga_t g_gga;
+
+char test_vector[] = {
+"$GPGGA,123519,3929.946667,N,11946.086667,E,1,08,0.9,545.4,M,46.9,M,,*4A\r\n" /* good */
+"$xyz,1234,asdfadfasdfasdfljsadfkjasdfk\r\n" /* junk */
+"$GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68\r\n" /* good */
+"$GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*48\r\n" /* checksum error */
+};
+
+char *pvec = test_vector;
+
+/** simulate character by character IO */
+int readchar()
+{
+ int ch;
+ if (*pvec == 0) {
+ ch = -1;
+ }
+ else {
+ ch = *pvec++;
+ }
+ return ch;
+}
+
+/** do something with the GGA data */
+static void print_gga(nmeap_gga_t *gga)
+{
+ printf("found GPGGA message %.6f %.6f %.0f %lu %d %d %f %f\n",
+ gga->latitude ,
+ gga->longitude,
+ gga->altitude ,
+ gga->time ,
+ gga->satellites,
+ gga->quality ,
+ gga->hdop ,
+ gga->geoid
+ );
+}
+
+/** called when a gpgga message is received and parsed */
+static void gpgga_callout(nmeap_context_t *context,void *data,void *user_data)
+{
+ nmeap_gga_t *gga = (nmeap_gga_t *)data;
+
+ printf("-------------callout\n");
+ print_gga(gga);
+}
+
+
+/** do something with the RMC data */
+static void print_rmc(nmeap_rmc_t *rmc)
+{
+ printf("found GPRMC Message %lu %c %.6f %.6f %f %f %lu %f\n",
+ rmc->time,
+ rmc->warn,
+ rmc->latitude,
+ rmc->longitude,
+ rmc->speed,
+ rmc->course,
+ rmc->date,
+ rmc->magvar
+ );
+}
+
+/** called when a gprmc message is received and parsed */
+static void gprmc_callout(nmeap_context_t *context,void *data,void *user_data)
+{
+ nmeap_rmc_t *rmc = (nmeap_rmc_t *)data;
+
+ printf("-------------callout\n");
+ print_rmc(rmc);
+}
+
+/* ---------------------------------------------------------------------------------------*/
+/* STEP 1 : allocate the data structures. be careful if you put them on the stack because */
+/* they need to be live for the duration of the parser */
+/* ---------------------------------------------------------------------------------------*/
+static nmeap_context_t nmea; /* parser context */
+static nmeap_gga_t gga; /* this is where the data from GGA messages will show up */
+static nmeap_rmc_t rmc; /* this is where the data from RMC messages will show up */
+static int user_data; /* user can pass in anything. typically it will be a pointer to some user data */
+
+int main(int argc,char *argv[])
+{
+ int status;
+ char ch;
+
+ /* ---------------------------------------*/
+ /*STEP 2 : initialize the nmea context */
+ /* ---------------------------------------*/
+ status = nmeap_init(&nmea,(void *)&user_data);
+ if (status != 0) {
+ printf("nmeap_init %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 3 : add standard GPGGA parser */
+ /* -------------------------------------- */
+ status = nmeap_addParser(&nmea,"GPGGA",nmeap_gpgga,gpgga_callout,&gga);
+ if (status != 0) {
+ printf("nmeap_add %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 4 : add standard GPRMC parser */
+ /* -------------------------------------- */
+ status = nmeap_addParser(&nmea,"GPRMC",nmeap_gprmc,gprmc_callout,&rmc);
+ if (status != 0) {
+ printf("nmeap_add %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 5 : process input until done */
+ /* -------------------------------------- */
+ for(;;) {
+ /* ---------------------------------------*/
+ /*STEP 6 : get a byte at a time */
+ /* -------------------------------------- */
+ ch = readchar();
+ if (ch <= 0) {
+ break;
+ }
+
+ /* --------------------------------------- */
+ /*STEP 7 : pass it to the parser */
+ /* status indicates whether a complete msg */
+ /* arrived for this byte */
+ /* NOTE : in addition to the return status */
+ /* the message callout will be fired when */
+ /* a complete message is processed */
+ /* --------------------------------------- */
+ status = nmeap_parse(&nmea,ch);
+
+ /* ---------------------------------------*/
+ /*STEP 8 : process the return code */
+ /* -------------------------------------- */
+ switch(status) {
+ case NMEAP_GPGGA:
+ /* GOT A GPGGA MESSAGE */
+ printf("-------------switch\n");
+ print_gga(&gga);
+ printf("-------------\n");
+ break;
+ case NMEAP_GPRMC:
+ /* GOT A GPRMC MESSAGE */
+ printf("-------------switch\n");
+ print_rmc(&rmc);
+ printf("-------------\n");
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
--- /dev/null
+/*
+Copyright (c) 2005, David M Howard (daveh at dmh2000.com)
+All rights reserved.
+
+This product is licensed for use and distribution under the BSD Open Source License.
+see the file COPYING for more details.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/*
+========================================================================================================
+EXAMPLE : SETUP FOR GGA AND RMC SENTENCES WITH CHARACTER BY CHARACTER IO
+=======================================================================================================
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nmeap.h"
+
+nmeap_gga_t g_gga;
+
+char test_vector[] = {
+"$GPGGA,123519,3929.946667,N,11946.086667,E,1,08,0.9,545.4,M,46.9,M,,*4A\r\n" /* good */
+"$xyz,1234,asdfadfasdfasdfljsadfkjasdfk\r\n" /* junk */
+"$GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68\r\n" /* good */
+"$GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*48\r\n" /* checksum error */
+};
+
+char *pvec = test_vector;
+
+/** simulate block IO */
+int readbuffer(char *buffer,int len)
+{
+ int i;
+
+ if (*pvec == 0) {
+ // end of file
+ return -1;
+ }
+
+ for(i=0;i<len;i++) {
+ /* quit when no more data */
+ if (*pvec == 0) {
+ break;
+ }
+ buffer[i] = *pvec++;
+ }
+ return i;
+}
+
+/** do something with the GGA data */
+static void print_gga(nmeap_gga_t *gga)
+{
+ printf("found GPGGA message %.6f %.6f %.0f %lu %d %d %f %f\n",
+ gga->latitude ,
+ gga->longitude,
+ gga->altitude ,
+ gga->time ,
+ gga->satellites,
+ gga->quality ,
+ gga->hdop ,
+ gga->geoid
+ );
+}
+
+/** called when a gpgga message is received and parsed */
+static void gpgga_callout(nmeap_context_t *context,void *data,void *user_data)
+{
+ nmeap_gga_t *gga = (nmeap_gga_t *)data;
+
+ printf("-------------callout\n");
+ print_gga(gga);
+}
+
+
+/** do something with the RMC data */
+static void print_rmc(nmeap_rmc_t *rmc)
+{
+ printf("found GPRMC Message %lu %c %.6f %.6f %f %f %lu %f\n",
+ rmc->time,
+ rmc->warn,
+ rmc->latitude,
+ rmc->longitude,
+ rmc->speed,
+ rmc->course,
+ rmc->date,
+ rmc->magvar
+ );
+}
+
+/** called when a gprmc message is received and parsed */
+static void gprmc_callout(nmeap_context_t *context,void *data,void *user_data)
+{
+ nmeap_rmc_t *rmc = (nmeap_rmc_t *)data;
+
+ printf("-------------callout\n");
+ print_rmc(rmc);
+}
+
+/* ---------------------------------------------------------------------------------------*/
+/* STEP 1 : allocate the data structures. be careful if you put them on the stack because */
+/* they need to be live for the duration of the parser */
+/* ---------------------------------------------------------------------------------------*/
+static nmeap_context_t nmea; /* parser context */
+static nmeap_gga_t gga; /* this is where the data from GGA messages will show up */
+static nmeap_rmc_t rmc; /* this is where the data from RMC messages will show up */
+static int user_data; /* user can pass in anything. typically it will be a pointer to some user data */
+
+int main(int argc,char *argv[])
+{
+ int status;
+ int rem;
+ int offset;
+ int len;
+ char buffer[32];
+
+ /* ---------------------------------------*/
+ /*STEP 2 : initialize the nmea context */
+ /* ---------------------------------------*/
+ status = nmeap_init(&nmea,(void *)&user_data);
+ if (status != 0) {
+ printf("nmeap_init %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 3 : add standard GPGGA parser */
+ /* -------------------------------------- */
+ status = nmeap_addParser(&nmea,"GPGGA",nmeap_gpgga,gpgga_callout,&gga);
+ if (status != 0) {
+ printf("nmeap_add %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 4 : add standard GPRMC parser */
+ /* -------------------------------------- */
+ status = nmeap_addParser(&nmea,"GPRMC",nmeap_gprmc,gprmc_callout,&rmc);
+ if (status != 0) {
+ printf("nmeap_add %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 5 : process input until done */
+ /* -------------------------------------- */
+ for(;;) {
+ /* ---------------------------------------*/
+ /*STEP 6 : get a buffer of input */
+ /* -------------------------------------- */
+ len = rem = readbuffer(buffer,sizeof(buffer));
+ if (len <= 0) {
+ break;
+ }
+
+ /* ----------------------------------------------*/
+ /*STEP 7 : process input until buffer is used up */
+ /* --------------------------------------------- */
+ offset = 0;
+ while(rem > 0) {
+ /* --------------------------------------- */
+ /*STEP 8 : pass it to the parser */
+ /* status indicates whether a complete msg */
+ /* arrived for this byte */
+ /* NOTE : in addition to the return status */
+ /* the message callout will be fired when */
+ /* a complete message is processed */
+ /* --------------------------------------- */
+ status = nmeap_parseBuffer(&nmea,&buffer[offset],&rem);
+ offset += (len - rem);
+
+ /* ---------------------------------------*/
+ /*STEP 9 : process the return code */
+ /* -------------------------------------- */
+ switch(status) {
+ case NMEAP_GPGGA:
+ printf("-------------switch\n");
+ print_gga(&gga);
+ printf("-------------\n");
+ break;
+ case NMEAP_GPRMC:
+ printf("-------------switch\n");
+ print_rmc(&rmc);
+ printf("-------------\n");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
--- /dev/null
+/*
+Copyright (c) 2005, David M Howard (daveh at dmh2000.com)
+All rights reserved.
+
+This product is licensed for use and distribution under the BSD Open Source License.
+see the file COPYING for more details.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/*
+========================================================================================================
+EXAMPLE : SETUP FOR GGA AND RMC SENTENCES + A CUSTOM SENTENCE PARSER WITH CHARACTER BY CHARACTER IO
+=======================================================================================================
+*/
+
+
+/*
+$PGRMF
+
+GARMIN PROPRIETARY GPS Position Fix Data
+
+$PGRMF,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15*HH
+1 = GPS week number
+2 = GPS seconds in current week
+3 = UTC date, ddmmyy format
+4 = UTC time, hhmmss format
+5 = GPS leap second count
+6 = Latitude, dddmm.mmmm format
+7 = Latitude hemisphere, N or S
+8 = Longitude, dddmm.mmmm format
+9 = Longitude hemisphere, E or W
+10 = Mode (M=Manual, A=Automatic)
+11 = Fix type (0=No fix, 1=2D fix, 2=3D fix)
+12 = Speed over ground, kilometres / hour
+13 = Course over ground, degrees true
+14 = PDOP (Position dilution of precision), rounded to nearest integer
+15 = TDOP (Time dilution of precision), rounded to nearest integer
+HH = Checksum
+*/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "nmeap.h"
+
+nmeap_gga_t g_gga;
+
+char test_vector[] = {
+"$GPGGA,123519,3929.946667,N,11946.086667,E,1,08,0.9,545.4,M,46.9,M,,*4A\r\n"
+"$GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68\r\n"
+"$PGRMF,1,100,191105,123519,13,3929.946667,N,12311.12,W,A,2,100.1,181.2,3,8*35\r\n"
+};
+
+char *pvec = test_vector;
+
+/** simulate character by character IO */
+int readchar()
+{
+ int ch;
+ if (*pvec == 0) {
+ ch = -1;
+ }
+ else {
+ ch = *pvec++;
+ }
+ return ch;
+}
+/* --------------------------------------------------------------*/
+/*STEP 1a : define a data structure to contain the sentence data */
+/* ------------------------------------------------------------- */
+struct garmin_rmf {
+ /* field position in sentence */
+ int week; /* 1 = GPS week number */
+ int seconds_of_week; /* 2 = GPS seconds in current week */
+ unsigned long date; /* 3 = UTC date, ddmmyy format */
+ unsigned long time; /* 4 = UTC time, hhmmss format */
+ int leap; /* 5 = GPS leap second count */
+ double lat; /* 6,7 = Latitude, dddmm.mmmm format (north positive) */
+ double lon; /* 8,9 = Longitude, dddmm.mmmm format (east positive) */
+ int mode; /* 10 = Mode (M=Manual, A=Automatic) */
+ int fix; /* 11 = Fix type (0=No fix, 1=2D fix, 2=3D fix) */
+ double speed; /* 12 = Speed over ground, kilometres / hour */
+ double course; /* 13 = Course over ground, degrees true */
+ int pdop; /* 14 = PDOP (Position dilution of precision), rounded to nearest integer */
+ int tdop; /* 15 = TDOP (Time dilution of precision), rounded to nearest integer */
+};
+typedef struct garmin_rmf garmin_rmf_t;
+
+/* --------------------------------------------------------------*/
+/*STEP 1b : define an id value for the message */
+/* ------------------------------------------------------------- */
+#define GARMIN_PGRMF (NMEAP_USER + 0)
+
+
+/* --------------------------------------------------------------*/
+/* STEP 1c : write the sentence parser */
+/* ------------------------------------------------------------- */
+int custom_pgrmf(nmeap_context_t *context,nmeap_sentence_t *sentence)
+{
+#ifndef NDEBUG
+ int i;
+#endif
+
+ /* get pointer to sentence data */
+ garmin_rmf_t *rmf = (garmin_rmf_t *)sentence->data;
+
+ if (rmf != 0) {
+ /* if the sentence has a data storage element, use it */
+
+
+ /* extract data from the tokens */
+ rmf->week = atoi(context->token[1]);
+ rmf->seconds_of_week = atoi(context->token[2]);
+ rmf->date = (unsigned long)atol(context->token[3]);
+ rmf->time = (unsigned long)atol(context->token[4]);
+ rmf->leap = atoi(context->token[5]);
+ rmf->lat = nmeap_latitude(context->token[6],context->token[7]);
+ rmf->lon = nmeap_longitude(context->token[8],context->token[9]);
+ rmf->mode = atoi(context->token[10]);
+ rmf->fix = atoi(context->token[11]);
+ rmf->speed = atof(context->token[12]);
+ rmf->course = atof(context->token[13]);
+ rmf->pdop = atoi(context->token[14]);
+ rmf->tdop = atoi(context->token[15]);
+ }
+ /* else there was no data element to store into */
+
+#ifndef NDEBUG
+ /* print raw input string */
+ printf("%s",context->debug_input);
+
+ /* print some validation data */
+ printf("%s==%s %02x==%02x\n",context->input_name,sentence->name,context->icks,context->ccks);
+
+ /* print the tokens */
+ for(i=0;i<context->tokens;i++) {
+ printf("%d:%s\n",i,context->token[i]);
+ }
+#endif
+
+ /* if the sentence has a callout, call it */
+ if (sentence->callout != 0) {
+ (*sentence->callout)(context,rmf,context->user_data);
+ }
+
+ return GARMIN_PGRMF;
+}
+
+
+/* -------------------------------------------------------------*/
+/*STEP 2 : write a function to do something with the data */
+/* ------------------------------------------------------------ */
+static void print_pgrmf(garmin_rmf_t *rmf)
+{
+ assert(rmf != 0);
+
+ printf(" w sec date time lp lat lon m f spd crs p t\n");
+ printf("found PGRMF message %d %d %lu %lu %d %.6f %.6f %d %d %.2f %.2f %d %d\n",
+ rmf->week,
+ rmf->seconds_of_week,
+ rmf->date,
+ rmf->time,
+ rmf->leap,
+ rmf->lat,
+ rmf->lon,
+ rmf->mode,
+ rmf->fix,
+ rmf->speed,
+ rmf->course,
+ rmf->pdop,
+ rmf->tdop
+ );
+}
+
+/* -------------------------------------------------------------*/
+/*STEP 3 : if using the callout method, write the callout */
+/* ------------------------------------------------------------ */
+static void pgrmf_callout(nmeap_context_t *context,void *data,void *user_data)
+{
+ garmin_rmf_t *rmf = (garmin_rmf_t *)data;
+
+ printf("-------------callout\n");
+ print_pgrmf(rmf);
+}
+
+
+/* ---------------------------------------------------------------------------------------*/
+/* STEP 4 : allocate the data structures. be careful if you put them on the stack because */
+/* they need to be live for the duration of the parser */
+/* ---------------------------------------------------------------------------------------*/
+static nmeap_context_t nmea; /* parser context */
+static nmeap_gga_t gga; /* this is where the data from GGA messages will show up */
+static nmeap_rmc_t rmc; /* this is where the data from RMC messages will show up */
+static garmin_rmf_t rmf; /* this is where the data from RMF messages will show up */
+static int user_data; /* user can pass in anything. typically it will be a pointer to some user data */
+
+int main(int argc,char *argv[])
+{
+ int status;
+ char ch;
+
+ /* ---------------------------------------*/
+ /*STEP 5 : initialize the nmea context */
+ /* ---------------------------------------*/
+ status = nmeap_init(&nmea,(void *)&user_data);
+ if (status != 0) {
+ printf("nmeap_init %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 6 : add standard GPGGA parser */
+ /* (no callout this time) */
+ /* -------------------------------------- */
+ status = nmeap_addParser(&nmea,"GPGGA",nmeap_gpgga,0,&gga);
+ if (status != 0) {
+ printf("nmeap_add %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 7 : add standard GPRMC parser */
+ /* (no callout this time) */
+ /* -------------------------------------- */
+ status = nmeap_addParser(&nmea,"GPRMC",nmeap_gprmc,0,&rmc);
+ if (status != 0) {
+ printf("nmeap_add %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 8 : ADD THE CUSTOM PARSER */
+ /* with callout ) */
+ /* -------------------------------------- */
+ status = nmeap_addParser(&nmea,"PGRMF",custom_pgrmf,pgrmf_callout,&rmf);
+ if (status != 0) {
+ printf("nmeap_add %d\n",status);
+ exit(1);
+ }
+ /* ---------------------------------------*/
+ /*STEP 9 : process input until done */
+ /* -------------------------------------- */
+ for(;;) {
+ /* ---------------------------------------*/
+ /*STEP 10: get a byte at a time */
+ /* -------------------------------------- */
+ ch = readchar();
+ if (ch <= 0) {
+ break;
+ }
+
+ /* --------------------------------------- */
+ /*STEP 11: pass it to the parser */
+ /* status indicates whether a complete msg */
+ /* arrived for this byte */
+ /* NOTE : in addition to the return status */
+ /* the message callout will be fired when */
+ /* a complete message is processed */
+ /* --------------------------------------- */
+ status = nmeap_parse(&nmea,ch);
+
+ /* ---------------------------------------*/
+ /*STEP 12 : process the return code */
+ /* -------------------------------------- */
+ switch(status) {
+ case NMEAP_GPGGA:
+ /* GOT A GPGGA MESSAGE */
+ printf("-------------switch\n");
+ printf("GPGGA\n");
+ printf("-------------\n");
+ break;
+ case NMEAP_GPRMC:
+ /* GOT A GPRMC MESSAGE */
+ printf("-------------switch\n");
+ printf("GPRMC\n");
+ printf("-------------\n");
+ break;
+ case GARMIN_PGRMF:
+ /* GOT A PGRMF MESSAGE */
+ printf("-------------switch\n");
+ print_pgrmf(&rmf);
+ printf("-------------\n");
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
--- /dev/null
+INCLUDES= ..\inc\nmeap.h ..\inc\nmeap_def.h\r
+CSRC = nmeap01.c\r
+LIBNAME = ..\lib\libnmeap.lib\r
+\r
+# build everything\r
+all : test1.exe test2.exe test3.exe wingps.exe \r
+\r
+test1.exe : test1.c $(LIBNAME)\r
+ cl /DNDEBUG /c /I..\inc test1.c\r
+ link /OUT:test1.exe test1.obj $(LIBNAME) \r
+ \r
+test2.exe : test2.c $(LIBNAME)\r
+ cl /DNDEBUG /c /I..\inc test2.c\r
+ link /OUT:test2.exe test2.obj $(LIBNAME)\r
+ \r
+test3.exe : test3.c $(LIBNAME)\r
+ cl /DNDEBUG /c /I..\inc test3.c\r
+ link /OUT:test3.exe test3.obj $(LIBNAME)\r
+ \r
+wingps.exe : wingps.c $(LIBNAME)\r
+ cl /DNDEBUG /c /I..\inc wingps.c\r
+ link /OUT:wingps.exe wingps.obj $(LIBNAME)\r
+\r
+# erase all intermediate and output files\r
+clean :\r
+ -erase *.obj\r
+ -erase *.exe\r
+\r
+\r
--- /dev/null
+/*
+Copyright (c) 2005, David M Howard (daveh at dmh2000.com)
+All rights reserved.
+
+This product is licensed for use and distribution under the BSD Open Source License.
+see the file COPYING for more details.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/*
+========================================================================================================
+EXAMPLE : SETUP FOR GGA AND RMC SENTENCES WITH SERIAL IO FOR WIN32
+=======================================================================================================
+*/
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nmeap.h"
+
+/** open a serial port */
+static HANDLE openPort(const char *port,int baud)
+{
+ HANDLE h;
+ DCB dcb;
+ COMMTIMEOUTS tmo;
+ int status;
+
+ /* open the port */
+ h = CreateFile( port,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ 0,
+ OPEN_EXISTING,
+ 0,
+ 0);
+ if (h == INVALID_HANDLE_VALUE) {
+ /* quit on error */
+ return h;
+ }
+
+
+ /* read current configuration */
+ status = GetCommState(h,&dcb);
+ if (status == 0) {
+ CloseHandle(h);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ /* set the baud rate and other parameters */
+ dcb.BaudRate = baud;
+ dcb.ByteSize = 8;
+ dcb.Parity = NOPARITY;
+ dcb.StopBits = ONESTOPBIT;
+
+ /* set configuration */
+ status = SetCommState(h, &dcb);
+ if (status == 0) {
+ CloseHandle(h);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ /* read timeout configuration */
+ status = GetCommTimeouts(h,&tmo);
+ if (status == 0) {
+ CloseHandle(h);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ /* set to indefinite blocking */
+ tmo.ReadIntervalTimeout = 0;
+ tmo.ReadTotalTimeoutConstant = 0;
+ tmo.ReadTotalTimeoutMultiplier = 0;
+ status = SetCommTimeouts(h,&tmo);
+ if (status == 0) {
+ CloseHandle(h);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ return h;
+}
+
+/** read a byte (blocking) */
+static int readPort(HANDLE h)
+{
+ BOOL status;
+ char ch;
+ DWORD count;
+ status = ReadFile(h,&ch,1,&count,0);
+ if (status == 0) {
+ return -1;
+ }
+
+ return (int)ch;
+}
+
+
+static void closePort(HANDLE h)
+{
+ CloseHandle(h);
+}
+
+
+/** print current data */
+static void printGps(nmeap_gga_t *gga,nmeap_rmc_t *rmc)
+{
+ printf("%lu %lu %.6f %.6f %.0f %f %f %d %d\n",
+ gga->time,
+ rmc->date,
+ gga->latitude ,
+ gga->longitude,
+ gga->altitude ,
+ rmc->course,
+ rmc->speed,
+ gga->satellites,
+ gga->quality
+ );
+}
+
+/* ---------------------------------------------------------------------------------------*/
+/* STEP 1 : allocate the data structures. be careful if you put them on the stack because */
+/* they need to be live for the duration of the parser */
+/* ---------------------------------------------------------------------------------------*/
+static nmeap_context_t nmea; /* parser context */
+static nmeap_gga_t gga; /* this is where the data from GGA messages will show up */
+static nmeap_rmc_t rmc; /* this is where the data from RMC messages will show up */
+static int user_data; /* user can pass in anything. typically it will be a pointer to some user data */
+
+int main(int argc,char *argv[])
+{
+ int status;
+ char ch;
+ const char *port;
+ int baud;
+ HANDLE h;
+
+ /* require both arguments */
+ if (argc != 3) {
+ printf("%s <comport> <baud>\n",argv[0]);
+ return 1;
+ }
+
+ /* serial port argument */
+ port = argv[1];
+
+ /* baud rate argument */
+ status = sscanf(argv[2],"%d",&baud);
+ if (status != 1) {
+ printf("%s <comport> <baud>\n",argv[0]);
+ printf("invalid <baud> : %s\n",argv[2]);
+ return 1;
+ }
+
+ /** open the serial port */
+ h = openPort(port,baud);
+ if (h == INVALID_HANDLE_VALUE) {
+ printf("can't open port : %s\n",port);
+ return 1;
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 2 : initialize the nmea context */
+ /* ---------------------------------------*/
+ status = nmeap_init(&nmea,(void *)&user_data);
+ if (status != 0) {
+ printf("nmeap_init %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 3 : add standard GPGGA parser */
+ /* -------------------------------------- */
+ status = nmeap_addParser(&nmea,"GPGGA",nmeap_gpgga,0,&gga);
+ if (status != 0) {
+ printf("nmeap_add %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 4 : add standard GPRMC parser */
+ /* -------------------------------------- */
+ status = nmeap_addParser(&nmea,"GPRMC",nmeap_gprmc,0,&rmc);
+ if (status != 0) {
+ printf("nmeap_add %d\n",status);
+ exit(1);
+ }
+
+ /* ---------------------------------------*/
+ /*STEP 5 : process input until done */
+ /* -------------------------------------- */
+ for(;;) {
+ /* ---------------------------------------*/
+ /*STEP 6 : get a byte at a time */
+ /* -------------------------------------- */
+ ch = readPort(h);
+ if (ch <= 0) {
+ break;
+ }
+
+ /* --------------------------------------- */
+ /*STEP 7 : pass it to the parser */
+ /* status indicates whether a complete msg */
+ /* arrived for this byte */
+ /* NOTE : in addition to the return status */
+ /* the message callout will be fired when */
+ /* a complete message is processed */
+ /* --------------------------------------- */
+ status = nmeap_parse(&nmea,ch);
+
+ /* ---------------------------------------*/
+ /*STEP 8 : process the return code */
+ /* -------------------------------------- */
+ switch(status) {
+ case NMEAP_GPGGA:
+ /* GOT A GPGGA MESSAGE */
+ printGps(&gga,&rmc);
+ break;
+ case NMEAP_GPRMC:
+ /* GOT A GPRMC MESSAGE */
+ printGps(&gga,&rmc);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* close and quit */
+ closePort(h);
+
+ return 0;
+}
--- /dev/null
+# directories
+SRC=src
+TST=tst
+
+all :
+ cd $(SRC)
+ $(MAKE) -f nmeap.mak all
+ cd ..\$(TST)
+ $(MAKE) -f tst.mak all
+ cd ..
+
+
+clean :
+ cd $(SRC)
+ $(MAKE) -f nmeap.mak clean
+ cd ..\$(TST)
+ $(MAKE) -f tst.mak clean
+ cd ..
+
+doc :
+ doxygen
+